[Sub] Sync recipe templates request

The device should delete all recipes and create new ones based on the recipe templates provided in the request.

Request Topic and Payload

Topic

things5-production/v1/devices/<device-id>/cmd/sync_recipe_templates_v2_req

Payload Representation

{
    "cookbook_sync_log_id": "7dc14fd9-8438-4771-9b13-e98d1a9d8c6e",
    "request_id": "UUID sent in the request",
    "manifest_url":
  "https://things5.s3.eu-west-1.amazonaws.com/cookbook-syncs/2729d40a-8e33-4ec6-aa8c-b1050c3f19a6/manifest.json?X-Amz-Algorithm=...&X-Amz-Signature=...",
    "expires_at": 1779711048527
  }

Payload Parameters

namedescriptionexample
cookbook_sync_log_idthis id should be sent back with the response
request_idthe request id to be sent back by the device when sending the response
manifest_urlpre-signed HTTPS URL to download the manifest (see below)
expires_atUnix epoch in milliseconds after which manifest_url is no longer valid1779711048527

🚧

The device must download the manifest from manifest_url before expires_at, then download each recipe it needs.

Manifest

The device downloads the manifest from the manifest_url it received over MQTT. It lists every recipe in the cookbook.

Representation

{  
    "manifest_version": 1,  
    "cookbook_sync_id": "2729d40a-8e33-4ec6-aa8c-b1050c3f19a6",  
    "recipes": [  
      {  
        "index": 1,  
        "id": "a43c7763-3b95-4707-9fac-86b48348f00c",  
        "hash": "79779ed2a4f18bc80500110ea96afb50614e06d2c1e21aefc9fac5d82b030a32",  
        "hash_version": 1,  
        "url": "https://things5.s3.eu-west-1.amazonaws.com/cookbook-syncs/2729d40a-8e33-4ec6-aa8c-b1050c3f19a6/recipes/1.json"  
      }  
    ]  
  }

Parameters

namedescriptionexample
manifest_versionversion of the manifest format1
cookbook_sync_idid of this sync
recipesarray of recipe entries
recipes[].indexposition of the recipe in the cookbook1
recipes[].idrecipe template id
recipes[].hashcontent fingerprint of the recipe (lowercase hex SHA-256)
recipes[].hash_versionalgorithm version of hash1
recipes[].urlHTTPS URL to download the recipe template

📘

Skipping unchanged recipes

hash is a content fingerprint of the recipe. Before downloading url, compare it against the recipe already stored on the device:

  • same hash → the recipe is unchanged, skip the download;
  • different or missing hash → download url;
  • hash_version the device does not implement → treat the recipe as changed and download url.

Only name, description, machine_model_id, phases and metadata contribute to the hash. Editing who last changed a recipe or when does not change it, so a re-sync re-downloads only recipes whose content actually changed.

Recipe Template

The device downloads each recipe from its recipes[].url. The content fields are identical to the recipe objects v1 sends inline; v2 adds id, machine_model_id, hash and hash_version.

Representation

{
    "id": "a43c7763-3b95-4707-9fac-86b48348f00c",
    "index": 1,
    "name": "Pollo con patate al cuore",
    "description": "Recipe description",
    "machine_model_id": "c8cfe490-843f-c4e5-0772-41849ae0af0f",
    "hash": "79779ed2a4f18bc80500110ea96afb50614e06d2c1e21aefc9fac5d82b030a32",
    "hash_version": 1,
    "phases": [
      {
        "dosages": [
          [
            {
              "name": "yeast",
              "quantity": "5.5",
              "metadata": [
                { "name": "type", "value": "1", "type": "integer" },
                { "name": "temperature", "value": "20", "type": "integer" }
              ]
            }
          ]
        ],
        "values": [
          { "name": "evaporator_fan_speed", "value": "4", "type": "integer" },
          { "name": "cell_temperature", "value": "-20", "type": "integer" }
        ]
      },
      {
        "values": [
          { "name": "evaporator_fan_speed", "value": "2", "type": "integer" },
          { "name": "core_temperature", "value": "-5", "type": "integer" },
          { "name": "cell_temperature", "value": "-20", "type": "integer" }
        ] 
      },
      {
        "values": [
          { "name": "evaporator_fan_speed", "value": "1", "type": "integer" },
          { "name": "core_temperature", "value": "-5", "type": "integer" },
          { "name": "cell_temperature", "value": "-20", "type": "integer" }
        ]
      },
      {
        "values": [
          { "name": "evaporator_fan_speed", "value": "0", "type": "integer" },
          { "name": "cell_temperature", "value": "-10", "type": "integer" }
        ] 
      } 
    ],
    "metadata": [
      { "name": "image_path", "value": "../images/fish.jpg", "type": "string" },
      { "name": "index_in_list", "value": "6", "type": "integer" }
    ] 
  } 

Parameters

namedescriptionexample
idrecipe template id
indexposition of the recipe in the cookbook1
namerecipe namePollo con patate al cuore
descriptionrecipe description
machine_model_idmachine model the recipe targets
hashcontent fingerprint (lowercase hex SHA-256)
hash_versionalgorithm version of hash1
phasesthe cooking program
metadataarbitrary recipe metadata

📘

Response has to be sent into the sync recipe templates response.