Skip to main content

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 durationWhat happens
~5 secondsNetwork reset threshold. The firmware gives an indication; release here to clear network credentials only.
~10 secondsFactory reset threshold. A further indication; release after this point for a factory reset.
OptionDefault
CONFIG_APP_BUTTON_GPIO_NUMPer-target BOOT button
CONFIG_APP_BUTTON_IS_ACTIVE_HIGHn
CONFIG_APP_BUTTON_SHORT_PRESS_TIME_MS50
CONFIG_APP_BUTTON_LONG_PRESS_TIME_MS1000
CONFIG_APP_RESET_NETWORK_TIME_MS5000
CONFIG_APP_RESET_FACTORY_TIME_MS10000
CONFIG_APP_RESET_REBOOT_S2

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

The factory partition survives every reset

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 resetreset-data on the console, or esp_rmaker_system_ctrl_data_reset().

Schedules and automations

SymptomLikely cause
Schedules never fireNo time sync. Check local-time first
Schedules fire at the wrong hourTimezone not set, or set only as TZ-POSIX with no IANA name. Prefer writing TZ
Schedules fire but nothing changesYour write callback does not handle that parameter type, or rejects the value. Reproduce with set-param
Some schedules silently missingCONFIG_RMAKER_SCHEDULING_MAX_SCHEDULES reached (default 10)
Automation triggers never notifyThe parameter is not being updated through esp_rmaker_param_update()

See Schedules and automations.

State reporting

SymptomLikely cause
App shows the device on when it is offYour callback updated the parameter after a failed hardware write. Only report on success
Renaming the device in the app does nothingA bulk write callback is registered and does not handle ESP_RMAKER_PARAM_NAME. See Callbacks and events
Local changes never reach the appYou changed hardware state without calling esp_rmaker_param_update(). Read callbacks are never invoked, so nothing will ask you
Updates arrive lateThe 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 1970No time sync, or the queue overflowed (CONFIG_RMAKER_TIMESERIES_DATA_QUEUE_LENGTH)
Some values missing from the dashboard searchMissing 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 your ota_diag callback.

Build problems

SymptomLikely cause
POSIX: CMake reports missing Python modulesThe virtual environment is not activated. See Set up POSIX
POSIX: FetchContent fails on first configureNo network access — mbedTLS, Unity, and protobuf-c are fetched at configure time
ESP-IDF: component esp_rmaker_neo not foundFix the path: entries in main/idf_component.yml, or set EXTRA_COMPONENT_DIRS
ESP-IDF: build fails on an older IDFThe minimum supported ESP-IDF is v6.0.2 — check out v6.0.2 or later
Console option cannot be enabledCONFIG_RMNG_HOST_CTRL=y with the console on UART0 — they conflict
Stack overflow in the local-control HTTP taskRaise CONFIG_ESP_RMAKER_LOCAL_CTRL_STACK_SIZE
Work-queue failures with a bridgeRaise 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_ota if you genuinely do not need OTA. (You almost certainly do need OTA.)
  • Reduce CONFIG_RMAKER_TIMESERIES_DATA_QUEUE_LENGTH and CONFIG_RMAKER_SCHEDULING_MAX_SCHEDULES to what you actually use.
  • Build with CONFIG_COMPILER_OPTIMIZATION_SIZE=y (the examples do).
  • Turn on CONFIG_RMNG_HEAP_MONITORING temporarily 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.