Troubleshooting
Start with the symptom. Most problems fall into one of four buckets: the node has no identity, the node has no time, the node has no network, or your callback isn't doing what you think it is.
First moves
Three checks, in this order, resolve most reports:
1. Does the node have an identity?
> get-node-id
Nothing, or an error, means the node has no credentials. With claiming on (the default) the claim never completed — see Assisted claiming. With claiming off, the factory NVS partition is missing or unreadable — see Factory NVS. Either way, no amount of resetting fixes it. This is the single most common cause of "my board does nothing".
2. Does the node have time?
> local-time
A 1970 date or a failure means time sync has not completed. Schedules will never fire and timeseries timestamps will be wrong. See Time and timezone.
3. Does your write path work at all?
> set-param Light Power true
This drives the same path a cloud write takes — parse, callback, hardware, report — with no network involved. If this fails, the problem is in your firmware, not in the cloud.
All three come from the serial console.
Connectivity
Boots, but never attempts TLS. The node has no credentials. If claiming is enabled, the
claim never completed — see Assisted claiming.
With CONFIG_ESP_RMAKER_ASSISTED_CLAIM=n, either no factory NVS was flashed, or the partition label
or namespace does not match CONFIG_ESP_RMAKER_FACTORY_PARTITION_NAME and _NAMESPACE.
TLS handshake fails. Wrong mqtt_host, or the certificate is not registered in this
deployment.
Connects, but the cloud does not know the node. It was never registered.
factory_nvs_gen generates credentials
but does not register them — use a batch flow.
Hangs at startup with no error. CONFIG_MBEDTLS_HAVE_TIME_DATE is set and NTP is
unreachable, so the synchronous time flow blocks indefinitely. See
Time and timezone.
Connects, then messages stop arriving. The MQTT budget is exhausted, and publishes are dropped rather than queued. See Configure and build.
Blocked behind a corporate firewall. Use port 443 (CONFIG_ESP_RMAKER_MQTT_PORT_443, the
default) rather than 8883.
Provisioning
Device does not appear in the phone app. Provisioning has probably already completed —
try a network reset. Otherwise check that the configured transport was actually built
(CONFIG_BT_ENABLED and CONFIG_BT_NIMBLE_ENABLED for BLE).
Device appears, but the session fails. Wrong PoP. After
CONFIG_APP_NETWORK_PROV_MAX_POP_MISMATCH attempts — five by default — provisioning stops
until the node reboots.
Provisioning stopped advertising. CONFIG_APP_NETWORK_PROV_TIMEOUT_PERIOD elapsed, 30
minutes by default. Reboot to restart it.
Credentials were accepted, then erased. The connection failed
CONFIG_APP_NETWORK_PROV_MAX_RETRY_CNT times — three by default — so the SDK erases them and
restarts provisioning. Usually a wrong password, or an access point that was briefly down.
QR code will not scan. Try CONFIG_APP_NETWORK_PROV_COMPACT_QR=y; the compact format is
much smaller.
User-node association fails. The certificate on the device does not match the registered one, or the node was flashed with another node's factory image.
Resets
BOOT button: two-stage hold
Most examples use the shared app_button helper on the BOOT button. GPIO and polarity are configurable — the default is GPIO 9 on esp32c3/c6/c2/h2, GPIO 28 on esp32c5, GPIO 0 elsewhere, active low. Hold-to-reset itself lives in the separate app_reset component, which app_button registers on the button for you.
With CONFIG_APP_RESET_ENABLED=y (the default), holding the button gives a two-stage reset:
| Hold duration | What happens |
|---|---|
| ~5 seconds | Network reset threshold. The firmware gives an indication; release here to clear network credentials only. |
| ~10 seconds | Factory reset threshold. A further indication; release after this point for a factory reset. |
| Option | Default |
|---|---|
CONFIG_APP_BUTTON_GPIO_NUM | Per-target BOOT button |
CONFIG_APP_BUTTON_IS_ACTIVE_HIGH | n |
CONFIG_APP_BUTTON_SHORT_PRESS_TIME_MS | 50 |
CONFIG_APP_BUTTON_LONG_PRESS_TIME_MS | 1000 |
CONFIG_APP_RESET_NETWORK_TIME_MS | 5000 |
CONFIG_APP_RESET_FACTORY_TIME_MS | 10000 |
CONFIG_APP_RESET_REBOOT_S | 2 |
Change them under ESP RainMaker App Reset Configuration → Button Reset Configuration — a top-level menu, not under Component config — or set CONFIG_APP_RESET_ENABLED=n to disable long-hold resets entirely (your example's short/long press actions still apply).
What resets do not clear
A factory reset clears RainMaker Neo data and network credentials. It does not touch the fctry partition — node ID, client certificate and key, MQTT host. That is deliberate: those are the node's permanent identity. The one command that does clear them is clear-claim-data, after which a claiming-enabled node re-claims and a pre-flashed node needs its image re-flashed. See Re-claiming a node and System service.
If you need a reset that also clears persisted parameters but keeps network credentials, that is the data reset — reset-data on the console, or esp_rmaker_system_ctrl_data_reset().
Schedules and automations
| Symptom | Likely cause |
|---|---|
| Schedules never fire | No time sync. Check local-time first |
| Schedules fire at the wrong hour | Timezone not set, or set only as TZ-POSIX with no IANA name. Prefer writing TZ |
| Schedules fire but nothing changes | Your write callback does not handle that parameter type, or rejects the value. Reproduce with set-param |
| Some schedules silently missing | CONFIG_RMAKER_SCHEDULING_MAX_SCHEDULES reached (default 10) |
| Automation triggers never notify | The parameter is not being updated through esp_rmaker_param_update() |
See Schedules and automations.
State reporting
| Symptom | Likely cause |
|---|---|
| App shows the device on when it is off | Your callback updated the parameter after a failed hardware write. Only report on success |
| Renaming the device in the app does nothing | A bulk write callback is registered and does not handle ESP_RMAKER_PARAM_NAME. See Callbacks and events |
| Local changes never reach the app | You changed hardware state without calling esp_rmaker_param_update(). Read callbacks are never invoked, so nothing will ask you |
| Updates arrive late | The 500 ms coalescing window (CONFIG_RMAKER_STATE_REPORT_DELAY_MS). Use esp_rmaker_param_update_and_report() where latency is user-visible |
| Timeseries graphs empty or start at 1970 | No time sync, or the queue overflowed (CONFIG_RMAKER_TIMESERIES_DATA_QUEUE_LENGTH) |
| Some values missing from the dashboard search | Missing PROP_FLAG_INDEXED |
OTA
Covered in detail at OTA → Troubleshooting. The two that catch everyone:
- Job rejected immediately — the new version is not higher than what is running. Bump
PROJECT_VER. - Update succeeds, old firmware returns — nothing marked the image valid inside
CONFIG_RMNG_OTA_ROLLBACK_WAIT_PERIOD. Check yourota_diagcallback.
Build problems
| Symptom | Likely cause |
|---|---|
| POSIX: CMake reports missing Python modules | The virtual environment is not activated. See Set up POSIX |
POSIX: FetchContent fails on first configure | No network access — mbedTLS, Unity, and protobuf-c are fetched at configure time |
ESP-IDF: component esp_rmaker_neo not found | Fix the path: entries in main/idf_component.yml, or set EXTRA_COMPONENT_DIRS |
| ESP-IDF: build fails on an older IDF | The minimum supported ESP-IDF is v6.0.2 — check out v6.0.2 or later |
| Console option cannot be enabled | CONFIG_RMNG_HOST_CTRL=y with the console on UART0 — they conflict |
| Stack overflow in the local-control HTTP task | Raise CONFIG_ESP_RMAKER_LOCAL_CTRL_STACK_SIZE |
| Work-queue failures with a bridge | Raise CONFIG_RMAKER_WORK_QUEUE_TASK_QUEUE_SIZE to at least 2× the child count |
Running low on memory
- Drop the serial console (
CONFIG_RMNG_CONSOLE_ENABLED=n) — worth doing in production anyway. - Do not link
esp_rmaker_neo_otaif you genuinely do not need OTA. (You almost certainly do need OTA.) - Reduce
CONFIG_RMAKER_TIMESERIES_DATA_QUEUE_LENGTHandCONFIG_RMAKER_SCHEDULING_MAX_SCHEDULESto what you actually use. - Build with
CONFIG_COMPILER_OPTIMIZATION_SIZE=y(the examples do). - Turn on
CONFIG_RMNG_HEAP_MONITORINGtemporarily to find where it goes. - Remember that provisioning is the peak — the SDK already frees provisioning resources afterwards via the pre-provisioning split, so do not defeat that by holding BLE open.
Related
- Serial console
- Firmware specifications → Error Handling — retry strategies and recovery flows
- Firmware specifications → MQTT Connection
- Pre-production checklist