Skip to main content

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.

This is the default

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 createdOn the node, at first setupAt manufacture, by host tooling
Per-device flashing stepNoneYes — one image per device
Node IDAssigned by the cloudChosen by the tooling
Requires BLE provisioningYesNo
Requires a claiming-capable phone appYesNo
Works on POSIX buildsNo — ESP-IDF onlyYes
Enable withCONFIG_ESP_RMAKER_ASSISTED_CLAIMCONFIG_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_ENABLED for 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, version 1.0, capability claim. 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 posts RMAKER_EVENT_CLAIM_FAILED and aborts startup with an explanatory error.

Configuration

Under RMNG Configuration → ESP RainMaker Claiming:

OptionDefaultMeaning
CONFIG_ESP_RMAKER_ASSISTED_CLAIMy when BLE is onEnable 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.

An OTA does not rewrite the partition table

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.

  1. esp_rmaker_pre_prov_init() — if the node has no certificate, generate or load the private key and register the rmaker_claim endpoint. If it already has one, claiming is skipped entirely.
  2. Provisioning runs. The phone app drives claiming over BLE, typically before it sends the network credentials.
  3. esp_rmaker_pre_prov_deinit() — wait for claiming to complete, then persist and clean up.
  4. 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:

EventWhen
RMAKER_EVENT_CLAIM_STARTEDClaiming began. Only posted when claiming is enabled and the node is not already claimed.
RMAKER_EVENT_CLAIM_SUCCESSFULCertificate and node ID have been persisted.
RMAKER_EVENT_CLAIM_FAILEDClaiming 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:

KeyAfter clear-claim-data
node_id, client_cert, client_key, mqtt_hosterased — re-obtained by claiming
randomkept — the PoP and the BLE device name derive from it
codesign_certkept — cannot be regenerated on the node
client_user, client_passkept
Destructive, and it applies to pre-flashed credentials too

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

SymptomCause
"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 hangThere 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 IDClaiming did not complete; the node is using a pre-existing or fallback node ID.
Build fails naming four MBEDTLS_* optionsA project disabled one by hand. See mbedTLS requirements.
Claim succeeds, then fails on a later boot with no spaceThe fctry partition is too small. Use 24 KB — see Partition table.