Assisted claiming
Claiming is how a node obtains its cloud credentials — private key, certificate, and node ID — at first setup instead of having them pre-flashed at manufacture.
With assisted claiming, the node generates its own key pair and a Certificate Signing Request, and the phone app relays them to the claiming service over the BLE provisioning session. The service returns a certificate and a cloud-assigned node ID, which the node stores in its factory partition under the same NVS keys the factory tooling would have written. Everything downstream reads credentials exactly as before.
Assisted claiming is enabled automatically whenever BLE is enabled — which is the case in every example's sdkconfig.defaults. You do not need to pre-flash a factory NVS image for the node to get credentials. Set CONFIG_ESP_RMAKER_ASSISTED_CLAIM=n to opt out and go back to pre-flashing.
The term will be familiar if you have used ESP RainMaker before. ESP RainMaker Neo implements assisted claiming; pre-flashing credentials at manufacture is the alternative, covered by the factory tooling.
Claiming or pre-flashing
Pick one per product.
| Assisted claiming (default) | Pre-flashed factory NVS | |
|---|---|---|
| Credentials created | On the node, at first setup | At manufacture, by host tooling |
| Per-device flashing step | None | Yes — one image per device |
| Node ID | Assigned by the cloud | Chosen by the tooling |
| Requires BLE provisioning | Yes | No |
| Requires a claiming-capable phone app | Yes | No |
| Works on POSIX builds | No — ESP-IDF only | Yes |
| Enable with | CONFIG_ESP_RMAKER_ASSISTED_CLAIM | CONFIG_ESP_RMAKER_ASSISTED_CLAIM=n |
Choose assisted claiming when your devices are provisioned by a phone app over BLE and you would rather not run a per-device flashing step in manufacturing.
Choose pre-flashing when any of these apply: you provision over SoftAP, the device has no BLE, you build POSIX firmware, you need to know node IDs before the device ships, or your factory flow already writes per-device data. See Factory NVS and the CLI batch flow.
Requirements and limits
- BLE provisioning only. Claiming rides on the provisioning session, so a node provisioned over SoftAP, or an Ethernet-only node, cannot be assisted-claimed. The Kconfig option depends on
BT_ENABLEDfor this reason. - ESP-IDF only. The POSIX provisioning backend is a stub, so POSIX builds must pre-flash credentials.
- A phone app that supports claiming. The node advertises app-info label
rmaker, version1.0, capabilityclaim. An app that does not drive the exchange leaves the node unclaimed, and startup fails with an explanatory error rather than hanging. - No timeout, but no unbounded wait either. The node waits for the app for as long as the provisioning session lasts — a rejected certificate or an explicit abort does not end the wait, since both are retryable. It never waits past the end of the session: the claim endpoint disappears with it (for example on the provisioning timeout,
CONFIG_APP_NETWORK_PROV_TIMEOUT_PERIOD), so the node postsRMAKER_EVENT_CLAIM_FAILEDand aborts startup with an explanatory error.
Configuration
Under RMNG Configuration → ESP RainMaker Claiming:
| Option | Default | Meaning |
|---|---|---|
CONFIG_ESP_RMAKER_ASSISTED_CLAIM | y when BLE is on | Enable assisted claiming. Set to n when credentials are pre-flashed. |
The key type is not configurable: claiming always generates an ECDSA P-256 key, because the claiming service only accepts ECDSA CSRs. Key generation takes well under a second and produces a ~230 byte PEM key.
mbedTLS requirements
Generating a CSR needs MBEDTLS_PEM_WRITE_C, MBEDTLS_PK_WRITE_C, MBEDTLS_X509_CREATE_C, and MBEDTLS_X509_CSR_WRITE_C.
These are handled for you. Enabling claiming selects RMAKER_CRYPTO_CSR_GENERATION — the esp_rmaker_neo_common capability flag that compiles the key and CSR generators — which in turn selects MBEDTLS_X509_CREATE_C, and that pulls in MBEDTLS_X509_CSR_WRITE_C. MBEDTLS_PEM_WRITE_C and MBEDTLS_PK_WRITE_C already default to y.
If a project disables one of them by hand, the build fails with an explicit message naming all four rather than a confusing compile or link error.
Partition table
Claiming writes credentials at runtime, so the fctry partition needs room for a private key (~230 bytes), a certificate (~1.2 kB), the node ID, and 64 random bytes, plus NVS rewrite overhead. The examples use 24 KB:
fctry, data, nvs, 0x3E0000, 0x6000,
12 KB (0x3000) is the three-sector NVS minimum and is enough for pre-flashed credentials, but it leaves very little headroom. Do not go below 24 KB when claiming is enabled.
A device already in the field with a 12 KB fctry keeps it after updating to a build with claiming enabled, so the certificate write can fail at the last step of an otherwise successful claim. Enabling claiming for an existing product line means re-flashing those devices, not just shipping them new firmware.
Where it fits in the startup sequence
Claiming is driven entirely from the existing pre-provisioning hooks — an application that already calls app_network_provision() needs no code changes.
esp_rmaker_pre_prov_init()— if the node has no certificate, generate or load the private key and register thermaker_claimendpoint. If it already has one, claiming is skipped entirely.- Provisioning runs. The phone app drives claiming over BLE, typically before it sends the network credentials.
esp_rmaker_pre_prov_deinit()— wait for claiming to complete, then persist and clean up.esp_rmaker_node_init()— reads the freshly stored credentials, including the cloud-assigned node ID.
Because credentials are in place before esp_rmaker_node_init() runs, there is no node-ID change to propagate and no MQTT re-initialisation. See Code basics for why the pre-provisioning split exists.
Events
Posted on the RMAKER_EVENT base, all with NULL event data:
| Event | When |
|---|---|
RMAKER_EVENT_CLAIM_STARTED | Claiming began. Only posted when claiming is enabled and the node is not already claimed. |
RMAKER_EVENT_CLAIM_SUCCESSFUL | Certificate and node ID have been persisted. |
RMAKER_EVENT_CLAIM_FAILED | Claiming failed, or the phone app aborted it. |
Worth handling: the claiming exchange can be slow, and a device that looks dead during setup generates support calls. Drive a status LED off these. See Callbacks and events.
On reboot
A claimed node has a certificate, so claiming stays dormant: no key generation, no endpoint, nothing to wait for. Startup goes straight to MQTT.
If an unclaimed node reboots, its private key is reused rather than regenerated — the key is persisted as soon as it is generated, so a retried claim does not pay for key generation again. The key is only regenerated if it cannot be parsed, or if it is not an ECDSA P-256 key (for example one persisted by an older firmware) on a node that is not yet claimed.
Re-claiming a node
The clear-claim-data console command erases the credentials claiming owns and reboots, after which the node claims again from scratch:
> clear-claim-data
Erasing claim data (node ID, certificate, private key, MQTT host) from the factory partition...
Claim data erased. The node will be claimed again after rebooting.
Only the keys claiming writes are erased, so the node can rebuild exactly what it removed:
| Key | After clear-claim-data |
|---|---|
node_id, client_cert, client_key, mqtt_host | erased — re-obtained by claiming |
random | kept — the PoP and the BLE device name derive from it |
codesign_cert | kept — cannot be regenerated on the node |
client_user, client_pass | kept |
On a node whose credentials were flashed at manufacture, the erased keys will have to be re-flashed — claiming can only replace them when it is enabled and the node can reach a claiming-capable app.
Note the asymmetry with the other resets: reset-to-factory does not touch the factory partition, only RainMaker Neo's own runtime data and the network credentials — it preserves the PoP and the claim. Use it to re-provision a node; use clear-claim-data to re-claim one. See System service.
Troubleshooting
| Symptom | Cause |
|---|---|
| "Node was provisioned without assisted claiming" | The app never started claiming. Confirm BLE provisioning was used (not SoftAP) and that the phone app supports claiming. Provisioning again is not enough on its own: the node now has network credentials, so it will connect instead of re-entering provisioning. Clear them first with reset-to-factory. |
| Claiming appears to hang | There is no claiming timeout while provisioning is live, by design. Check the app is still connected. |
| "started assisted claiming but never delivered the certificate" | The app sent ClaimStart and the network credentials, but never came back with the certificate — typically its own call to the claiming service failed, or it was killed mid-claim. The node cannot recover on its own, since the claim endpoint disappears with the provisioning session. Clear the network credentials with reset-to-factory and provision again. |
| "Claim verify response has no MQTT host." | The claim is rejected with InvalidParam. The node requests the MQTT host ("send_mqtt_host":true) and treats it as mandatory — there is no configured fallback. Check that the claiming service and the phone app relay mqtt_host in the claim/verify response. |
| Node ID is a MAC address, not a cloud-assigned ID | Claiming did not complete; the node is using a pre-existing or fallback node ID. |
Build fails naming four MBEDTLS_* options | A project disabled one by hand. See mbedTLS requirements. |
| Claim succeeds, then fails on a later boot with no space | The fctry partition is too small. Use 24 KB — see Partition table. |
Related
- Device credentials — how identity, network credentials, and user association differ
- Factory NVS — the pre-flashing alternative, and the NVS key layout claiming writes into
- Firmware specifications → Provisioning — the
rmaker_claimendpoint wire format - ESP RainMaker → Claiming — the ESP RainMaker Classic concept, including host-driven and self claiming