Pre-production checklist
Work through this before you build the image that goes onto hardware you cannot get back. Most items are one Kconfig line; the cost of missing one is a field recall.
Project hygiene
- Your project lives in your own repository, not in
esp-rainmaker-neo-firmware/examples/. The SDK is a pinned dependency. See Start your own project. - The SDK is pinned to a tag or commit, not tracking a branch.
-
sdkconfigis gitignored and every setting you depend on is insdkconfig.defaults(plus per-target variants). A configuration that only exists on one developer's machine is a configuration you will lose. -
PROJECT_VERis set and part of your release process. It must increase on every release or OTA will reject your updates. See OTA. -
project(<name>)is your product name, notlight. It becomes the OTA image name and the reported node model.
OTA — get this right first
If OTA does not work, nothing else on this list can be fixed after shipping.
-
esp_rmaker_neo_otais linked andesp_rmaker_ota_enable()is called beforeesp_rmaker_start(). - An
ota_diagcallback is provided and it verifies something real. Withota_diag = NULLno rollback is ever performed, so a firmware that boots but cannot connect will never be reverted. See Rollback and diagnostics. - Rollback is enabled —
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE(implied byCONFIG_RMNG_OTA_FORCE_ENABLE_ROLLBACK, defaulty) — and the partition table has two app slots. -
CONFIG_RMNG_OTA_SIGNATURE_VERIFY_ENABLE=y, with acodesign_certprovisioned in factory NVS. Without it a node will flash whatever image a job document points at. - You have performed a real end-to-end OTA on production hardware: upload, job, download, flash, reboot, validate.
- You have performed a deliberately failing OTA and confirmed the rollback recovered the device.
-
CONFIG_RMNG_OTA_REQUEST_TIMEOUT_MSsuits your worst-case network, not your desk Wi-Fi.
Identity and manufacturing
- You have decided how nodes get credentials — assisted claiming (the default) or pre-flashed factory NVS — and the Kconfig matches that decision.
- If claiming: the shipping phone app supports claiming, provisioning is BLE, and you have claimed a device end to end on production hardware.
- If pre-flashing: factory NVS is generated and flashed per device, each device got its own image — not a copy of one — and every node is registered with the cloud.
factory_nvs_genalone does not register; usefactory_autoregor the dashboard. -
CONFIG_ESP_RMAKER_FACTORY_PARTITION_NAMEand_NAMESPACEmatch the labels used by your generation tooling and the name inpartitions.csv. - The
fctrypartition is large enough — 24 KB (0x6000) when claiming is enabled, since credentials are written at runtime; enough for the generated blob plus any codesign certificate when pre-flashing. - Only the capabilities you use are enabled at registration (
s3,kvs,bridge). Each attaches a server-side policy. - Private keys and factory binaries are in secure storage, are not in git, and access is logged.
- QR codes are generated off-device and printed on labels or packaging — not read off the serial console.
Lock down debug surfaces
-
CONFIG_RMNG_CONSOLE_ENABLED=n, or at leastCONFIG_RMNG_CONSOLE_PARAM_CMDS_ENABLED=n. An exposed UART withreset-to-factoryandset-paramon it is a real attack surface. -
CONFIG_RMNG_HOST_CTRL=n. Remote control is a test harness; it has no place in shipping firmware. -
CONFIG_RMNG_TESTING=n. - Local control keeps its PoP.
CONFIG_ESP_RMAKER_LOCAL_CTRL_SEC_VERSION_2is the default — keep it. Security 1 withCONFIG_ESP_RMAKER_LOCAL_CTRL_SEC1_POP=nruns without a proof of possession, which means anyone on the LAN can control the device. See Local control. - Provisioning uses Security 2 (
CONFIG_APP_PROV_SECURITY_VERSION_2, the default) and a PoP.CONFIG_APP_NETWORK_POP_TYPE_NONEis a development setting. -
CONFIG_APP_NETWORK_PROV_TIMEOUT_PERIODis non-zero. A device that advertises for provisioning forever is a device anyone can claim. -
CONFIG_APP_NETWORK_PROV_MAX_POP_MISMATCHis non-zero, so brute-forcing the PoP is bounded. - Log level is reduced. Verbose logging costs flash, time, and leaks internals over the UART.
- Consider ESP-IDF flash encryption and secure boot. They are outside RainMaker Neo, but this is the point in the process to decide. See the ESP-IDF security documentation.
Behaviour on real networks
- MQTT budgeting matches your traffic. Defaults are
100messages with1revived every5seconds. If your device reports faster than that sustained, raise the budget or slow the reporting — over-budget messages are dropped, including state reports and timeseries. See Configure and build. - Timeseries queue length suits your sampling rate. A full queue drops data points silently.
- You have tested with the internet down, and the device still works locally and recovers cleanly when it comes back.
- You have tested a slow, lossy link, not just a good one.
-
CONFIG_MBEDTLS_HAVE_TIME_DATEand your time-sync flow are a deliberate choice. With it set, a node that cannot reach NTP hangs at startup. See Time and timezone. - MQTT port 443 unless you have a specific reason for 8883 — 443 gets through more firewalls.
- Wi-Fi retry behaviour is sane.
CONFIG_APP_NETWORK_PROV_MAX_RETRY_CNTerases credentials after this many failures; make sure that is the behaviour you want on a router that is briefly down.
Data model
- Standard device and parameter types are used wherever one fits. Custom types work, but lose phone-app UI and voice-assistant support. See Data model.
- A primary parameter is assigned on every device, so app tiles and voice commands resolve.
- No device or parameter ID contains a
.— it breaks timeseries paths. -
PROP_FLAG_PERSISTis on the values that must survive a power cut, and off the ones that would wear NVS. -
PROP_FLAG_INDEXEDis only on slow-changing values. Every update writes the indexed shadow too. - Cumulative vs simple timeseries flags are correct for each parameter.
- The
Nameparameter is handled if you use a bulk write callback — otherwise renaming silently stops working. See Callbacks and events. - Write callbacks confirm before reporting. Don't update a parameter after a failed hardware write.
Recovery paths
Assume something will go wrong in the field and the user cannot reach a serial port.
- The system service is enabled with all three flags, so a user can reboot, network-reset, and factory-reset from the app. See System service.
- A
network_reset_fnis registered, or the reset paths fail. - There is a physical reset path — a long button hold, like the examples' two-stage
app_resethold. See Troubleshooting. - Reset event handlers leave the hardware safe — motors parked, heaters off — within the configured delay.
- You have verified that a factory reset makes the device re-provisionable by a different account.
Before you press go
- Build a release image from a clean checkout at a tagged commit and confirm it works on production hardware.
- Flash a device with the release image and a production factory partition and take it through the whole user journey: provision, associate, control, schedule, OTA.
- Record which SDK commit, ESP-IDF release, and target each release image was built against.
Related
- Configure and build — where every option here lives
- OTA firmware updates
- Device credentials
- Troubleshooting