Skip to main content

Firmware Pre-Production Checklist

Before finalizing your firmware, ensure the following steps are completed.

Creating a Project​

While standard examples are useful starting points, create a copy tailored to your use case and maintain it separately to avoid conflicts due to esp-rainmaker code updates. It is recommended to track project-specific changes using a version control system like Git.

Claiming​

Claiming is not available on private RainMaker deployments. Please use the RainMaker Admin CLI to generate the credentials for the factory partition. Additionally, disable these config options in your project's sdkconfig.defaults to save flash memory:

CONFIG_ESP_RMAKER_ASSISTED_CLAIM
CONFIG_ESP_RMAKER_SELF_CLAIM

Using Pre-Provisioned Modules​

Espressif offers modules that are pre-provisioned with a unique private key and device certificate during module manufacturing. Since the device credentials are already available on the module, no key/certificate generation or flashing is required on the production line, significantly reducing the manufacturing complexity.

Espressif provides a pre-provisioning manifest file for such modules, which can be registered with your RainMaker deployment either from the dashboard or using the esp-rainmaker-admin-cli.

note

The key type and the mechanism used to protect the private key depend on the SoC:

SoCKey type and protection
ESP32, ESP32-C2 / ESP8684Private key stored in the esp_secure_cert partition, protected using Secure Boot and Flash Encryption
ESP32-C3 / ESP8685, ESP32-C6, ESP32-S2, ESP32-S3RSA private key protected using the DS peripheral (key material encrypted using eFuse)
ESP32-C5, ESP32-H2ECDSA private key protected using the ECDSA peripheral (key material in eFuse)

Please reach out to Espressif for SoCs not listed here.

To use such modules with your RainMaker firmware, set the following config options in your project's sdkconfig.defaults:

CONFIG_ESP_RMAKER_NO_CLAIM=y
CONFIG_ESP_RMAKER_USE_ESP_SECURE_CERT_MGR=y
CONFIG_ESP_RMAKER_READ_MQTT_HOST_FROM_CONFIG=y
CONFIG_ESP_RMAKER_READ_NODE_ID_FROM_CERT_CN=y
CONFIG_ESP_RMAKER_MQTT_HOST=<customer-deployment-mqtt-host>
CONFIG_APP_PROV_SECURITY_VERSION_1=y
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=y
  • CONFIG_ESP_RMAKER_NO_CLAIM: Disables the claiming workflows, since the device credentials are already present on the module and do not need to be fetched.
  • CONFIG_ESP_RMAKER_USE_ESP_SECURE_CERT_MGR: Reads the private key and device certificate from the pre-provisioned esp_secure_cert partition using the esp_secure_cert_mgr component, instead of the RainMaker factory partition.
  • CONFIG_ESP_RMAKER_READ_MQTT_HOST_FROM_CONFIG: Picks up the MQTT host from the firmware configuration, since the pre-provisioned module does not have any deployment-specific MQTT host information.
  • CONFIG_ESP_RMAKER_READ_NODE_ID_FROM_CERT_CN: Uses the Common Name (CN) field of the device certificate as the RainMaker node ID.
  • CONFIG_ESP_RMAKER_MQTT_HOST: The MQTT host of your RainMaker deployment, which will be used because of CONFIG_ESP_RMAKER_READ_MQTT_HOST_FROM_CONFIG above.
  • CONFIG_APP_PROV_SECURITY_VERSION_1: Uses security version 1 for Wi-Fi provisioning. Security version 2 (the default) requires a proof of possession (PoP), which is typically not available for pre-provisioned modules. See the note on PoP below.
  • CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: Required for SoCs that use the DS peripheral. For challenge-response based user-node mapping, the node signs the challenge using RSA-PSS through the DS peripheral, and the PSS support in the DS driver is compiled only when TLS 1.3 is enabled. Without this option, user-node mapping fails at runtime on such modules.

Additionally, start the provisioning with app_network_start(POP_TYPE_NONE) in your application code. Standard RainMaker modules have a fctry partition which, apart from the device credentials (private key, certificate, and MQTT host), also holds a random byte string used to generate the provisioning name and the proof of possession (PoP). Pre-provisioned modules do not ship with a populated fctry partition, so POP_TYPE_RANDOM cannot be used. More importantly, at manufacturing time there is typically no unique per-device data linked to the node ID, neither the MAC address nor a random byte stream, from which a PoP could be generated and shared with the end user (for example, as a QR code on the packaging). Hence, security version 1 without PoP is recommended. If you can manage such a mapping yourself (for example, by recording the MAC address or a custom PoP against the node ID during production), POP_TYPE_MAC or POP_TYPE_CUSTOM can be used instead, with either security version. The provisioning name is derived from the Wi-Fi MAC address by default, so device discovery keeps working even with the PoP type set to POP_TYPE_NONE. Refer to PoP of Provisioning for more details about the PoP types.

Partition Table​

On pre-provisioned modules, the esp_secure_cert partition is located at offset 0xD000 with a size of 8 KB (0x2000). Your partition table must have a matching entry. All RainMaker example partition tables already include it:

# Name,           Type, SubType, Offset,  Size,   Flags
esp_secure_cert, 0x3F, , 0xD000, 0x2000, encrypted

The encrypted flag ensures that the partition gets encrypted when Flash Encryption is enabled, and is ignored otherwise. Some early pre-provisioned modules used the partition name pre_prov instead. Refer to the esp_secure_cert_app README if your modules have this partition.

Validating the Secure Cert Partition​

Depending on the SoC (see the table above), the private key is stored in the esp_secure_cert partition in one of three ways:

  1. Plaintext: The private key itself resides inside the esp_secure_cert partition and is protected by Flash Encryption.
  2. DS Peripheral: The partition holds the private key encrypted for the DS (Digital Signature) peripheral, along with the ID of the eFuse key block used for it. The key that decrypts it is stored in eFuse and is used only inside the DS peripheral, so the plaintext RSA key is never exposed.
  3. ECDSA Peripheral: The entire 256-bit private key is burnt into an eFuse key block. The partition holds only the ID of that eFuse key block.

Since the partition contents differ between these, validating one path does not confirm the sanity of the others. Each type of partition needs to be validated independently. The esp_secure_cert_app example demonstrates how to verify all three types of partitions.

To test the DS or ECDSA peripheral path specifically:

  1. Follow this guide to generate the esp_secure_cert partition. For the DS peripheral, use this command. For the ECDSA peripheral, use the CSV based configuration with priv_key_type set to ecdsa_peripheral.
  2. Verify the generated partition using the esp_secure_cert_app example, which works directly with it.
  3. The generated partition can also be tested directly with the RainMaker firmware, which will then use the DS or ECDSA peripheral path.

Note that the tool sets up the key for development purposes, so the same key can be reused across development iterations.

Provisioning QR Code​

In the developer use case, the provisioning QR code is shown on the serial terminal. However, in production environment, the QR code needs to be generated outside the device. The RainMaker Admin CLI can generate these QR codes.

Over the Air Updates (OTA)​

OTA firmware updates are enabled by default in the switch and led_light examples. Here is a code snippet:

esp_rmaker_ota_config_t ota_config = {
.server_cert = ESP_RMAKER_OTA_DEFAULT_SERVER_CERT,
};
esp_rmaker_ota_enable(&ota_config, OTA_USING_PARAMS);

This configuration is for OTA using parameters, suitable for makers. For dashboard-driven upgrades, change OTA_USING_PARAMS to OTA_USING_TOPICS.

esp_rmaker_ota_enable(&ota_config, OTA_USING_TOPICS);

Refer to this guide for more details on OTA. Only the Superadmin user can access the dashboard for OTA operations.

Timezones​

If you plan to use scheduling, please ensure that a timezone is set in your firmware or the timezone service is added for runtime timezone configuration. More information is available here. Most examples include the timezone service by default.

Scheduling​

To enable scheduling in your firmware, add it explicitly using the appropriate API. Refer to this guide for more information. Timezones are mandatory for scheduling to function correctly. Most examples include the scheduling service by default.

Max Supported Schedules​

Go to idf.py menuconfig > ESP RainMaker Config > ESP RainMaker Scheduling > Maximum Schedules, configure the maximum number of supported schedules using the CONFIG_ESP_RMAKER_SCHEDULING_MAX_SCHEDULES option. The default value was 5 earlier, but is now 10. If this is insufficient, you can increase it. Note that all scheduling information is reported as a RainMaker "parameter", with a hard limit of 8 KB on the total size of all parameters combined, as we use AWS IoT Shadow to maintain parameter values in the cloud.

Local Control​

ESP RainMaker offers a local control facility, providing:

  • Faster response
  • Lower cost (by avoiding REST API calls)

Refer to this guide for instructions on enabling local control. Before enabling, make sure to review the security considerations.

On this page