Node and Cloud Backend Communication Protocol

The communication between the node and cloud backend is encrypted using TLS over MQTT, and their identities are mutually authenticated using X.509 certificates. The private key used for the node connection is automatically generated on the node.

During the first Wi-Fi provisioning, ESP32-C3 obtains a certificate through Assisted Claiming, and saves it in its flash. The process for ESP32-C3 to use Assisted Claiming is shown in Figure 9.7.

Figure 9.7. ESP32-C3 Assisted Claiming
  1. ESP32-C3 generates an RSA2048 private key, uses its MAC address as the initial node ID, and then sends relevant messages to the smartphone app.

  2. During the first provisioning, the app and the Claiming Service authenticate each other's identity. Once the authentication is successful, the receiving server issues a node ID, which is then forwarded by the app to ESP32-C3.

  3. ESP32-C3 generates a CSR with the CN field set as the node ID. Then, the CSR is forwarded by the app to the Claiming Service.

  4. The Claiming Service verifies the CSR and issues the certificate, which is then forwarded by the app to ESP32-C3.

The node ID serves not only as a means of identifying a node during certificate application but also as a way to map to a user and filter MQTT messages. For example, a node can only subscribe to topics with a specific prefix (node/<node_id>/*) and publish messages to those topics.

ESP RainMaker defines some default messages, including configuration messages, control messages, status messages, initial status messages, mapping messages, OTA upgrade messages, and warning messages. These messages are packaged in JSON and sent to the cloud backend over MQTT.

The configuration message is published by nodes through node/<node_id>/config. It contains information about the node itself, its attributes, devices, device attributes, services, and parameters. Here is an example.

//Configuration message for led_light
{
    "node_id": "xxxxxxxxxx",                    //Node ID
    "config_version": "2020-03-20",             //Configuration version
    "info": {                                   //Node information
        "name": "ESP RainMaker Device",
        "fw_version": "1.0",
        "type": "Lightbulb",
        "model": "led_light"
    },
    "devices": [                                //Devices of this node
        {
            "name": "Light",
            "type": "esp.device.lightbulb",
            "primary": "Power",
            "params": [                         //Device parameters
            {
                "name": "Name",
                "type": "esp.param.name",
                "data_type": "string",
                "properties": ["read", "write"]
            },
            {
                "name": "Power",
                "type": "esp.param.power",
                "data_type": "bool",
                "properties": ["read", "write"],
                "ui_type": "esp.ui.toggle"
            },
            ......
            ]
        }
        ],
        "services": [                               //Node services
        {
            "name": "OTA",
            "type": "esp.service.ota",
            "params": [
            {
                "name": "Status",
                "type": "esp.param.ota_status",
                "data_type": "string",
                "properties": ["read"]
            }
            ......
            ]
        }
    ]
}

The smartphone app can obtain the unique identifier of the product by parsing node_id, the device information and number by parsing devices, the services by parsing the services, and the read and write permissions of the app by parsing properties. If ui_type of params in devices is set, the app will display the corresponding UI. For more information on the use of standard parameters, standard devices, and standard UI, please refer to Section 9.4.7.

The downlink control message is used by the app and third-party applications to control nodes. It contains device parameters that need to be updated. To receive such messages, a node needs to subscribe to the topic node/<node_id>/remote. Here is an example of control messages.

{
    "Light": {
        "Power": false
    }
}

A node can actively report its status messages through the topic node/<node_id>/params/local. The cloud backend will cache the parameters in the message and push them to the clients that have enabled the push function.

The mapping message is used to map nodes to users. An unmapped node needs to be mapped to a user first to ensure that only that user has access to it. The mapping request occurs during the Wi-Fi configuration phase. During Wi-Fi provisioning, the device receives the user ID and security key from the smartphone. Once the node is connected to the cloud backend, it will concatenate the user ID and security key with its own node ID and send them to the cloud backend. Here is an example of mapping messages.

{
    "node_id": "112233AABBCC",
    "user_id": "02e95749-8d9d-4b8e-972c-43325ad27c63",
    "secret_key": "9140ef1d-72be-48d5-a6a1-455a27d77dee"
}

After receiving the above message, the cloud backend will check whether it receives the same security key from the app. If yes, it will map the user to the device. The mapping process is shown in Figure 9.8.

Figure 9.8. Mapping process

The OTA upgrade message is used to implement OTA upgrades for nodes. It uses three MQTT topics: node/<node_id>/otafetch, node/<node_id>/status, and node/<node_id>/otaurl. These topics respectively report OTA upgrade status, distribute OTA upgrade firmware, and query OTA upgrade tasks. The code is as follows:

//Distribute OTA upgrade firmware
{
    "url": "<ota_image_url>",
    "ota_job_id": "<ota_job_id>",
    "file_size": "<num_bytes>"
}

//Query OTA upgrade tasks
{
    "node_id": "<node_id>",
    "fw_version": "<fw_version>"
}

//Report OTA upgrade status
{
    "ota_job_id": "<ota_job_id>",
    "status": "<in-progress/success/fail>",
    "additional_info": "<additional_info>"
}

The warning message is a type of push messages used to notify and remind users. A node can publish warning messages via the topic node/<node_id>/alert. After receiving a warning message, the app pushes it to the smartphone notification bar. All the data in the cloud backend have push properties, and the use of this topic explicitly marks the data as a notification that needs to be actively pushed to the smartphone's notification bar. Here is an example of warning messages.

{
    "esp.alert.str": "alert"
}