State Management
Incoming State Modifications
These are requests to change one or more logical device parameters from sources external to the node.
Source: User applications, Alexa, Google Home, or cloud automations etc.
Topic: See Parameters to Node topic (The group-specific params topic)
{thing_name}: see “Thing Name”.See named shadows for
{shadow_name}convention.
Payload Specification: A JSON object where keys are logical device ids and values are objects of parameter-value pairs.
{ "<device id>": { "<parameter id>": <new value>, // ... other parameters for this device }, // ... other devices with modified parameters }
Node Action: Upon receiving this message, the node should apply the changes and then report its new state.
Group Control Modifications
Requests to change parameters on all devices of a given type within a group or subgroup, addressed by device type rather than device id.
Source: Cloud group/subgroup control flows.
Topic: See Group Control Broadcast and Group Control Subgroup.
Payload Specification: Top-level keys are device types (not device ids). Each value is a control envelope; only the
paramsenvelope is currently defined. Insideparams, keys are parameter types and values are the new param values.{ "<device type>": { "params": { "<parameter type>": <new value>, // ... other parameter types for this device type } }, // ... other device types }
Example:
{ "esp.device.light": { "params": { "esp.param.power": true, "esp.param.brightness": 75 } }, "esp.device.fan": { "params": { "esp.param.power": false } } }
Node Action: Apply the changes and then report new state. For each top-level device-type key matching a device on the node, apply the params to every such device. Device-types not present on the node are ignored. A device-type entry without a
paramsenvelope is silently skipped (reserved for future envelopes). Cross-device-type filtering is enforced on the node.
Outgoing State Reporting
Reporting online state
The node should set a state variable online = true to signal that it is in a state to receive commands (i.e. all subscriptions and initial handshake is complete). This is part of the shadow payloads. Clearing it is a cloud responsibility — see When online = false is Set.
Node Online/Offline State Management
Conditions for Setting online = true
The node sets online = true only after all of the following conditions are met:
SDK Started: the start task has completed, which implies the MQTT connection was established (see Initialization and Startup Sequence)
Node Registered: a node has been registered with the SDK
Cloud Subscription: Successful subscription to from_cloud topic
Params Subscription: Successful subscription to the Parameters to Node topic and to every applicable group control topic — the params flag is only set once the last of those SUBACKs arrives
The check runs on each event that could satisfy it. All checks must pass before the node reports online = true in both named and indexed shadows; if any check fails, the local online flag is cleared instead (without publishing online = false).
When online = false is Set
The cloud sets online = false when it detects the node has disconnected (via AWS IoT presence events). The node never publishes it: on an MQTT disconnection it clears its local online flag only.
Online State and Operations
online = true signals readiness, but gates nothing on the node. Parameter updates are received and processed, and state changes are reported, regardless of the flag — including before it is set and after a disconnection clears it.
Shadows
State reporting is done by reporting on two AWS IoT shadows per node. (With CONFIG_RMNG_BRIDGE_ENABLED, each bridged child is a cloud Thing of its own and so has its own pair of shadows, reported over the bridge’s connection.)
Shadow Update Behavior
Shadow updates are triggered when:
Parameter values change (local or remote)
Node configuration changes (
ncfg_verupdate, queued after the cloud acknowledgessetNodeConfig)Online state changes
Node tags are updated (indexed shadow only)
Notification settings do not trigger a report on their own: notify is attached to the next report that carries parameter updates.
Update Timing:
Coalescing Window: A state change schedules the report after
CONFIG_RMAKER_STATE_REPORT_DELAY_MS(default 500 ms). Any further change inside that window restarts the timer, so a burst of updates collapses into one reportBatching: All changes pending when the timer fires go into a single shadow update per shadow
Separate Updates: Named shadow and indexed shadow are published as two independent MQTT messages
Partial Updates:
Delta Updates: Only changed parameters are included in shadow updates (not full state)
Selective Reporting:
Named shadow includes all changed parameters
Indexed shadow includes only changed parameters with
indexedproperty. Theparamsobject is omitted entirely when none of the pending changes areindexed
Empty Payloads Skipped: A shadow whose payload carries nothing beyond the
state.reportedwrapper is not publishedFull State on Startup: On initial connection, full state is reported to both shadows
Update Frequency and Throttling:
Coalescing Only: Beyond the coalescing window above there is no rate limit on shadow updates
MQTT Budgeting Impact: If MQTT budgeting is enabled, shadow updates may be dropped when budget is exhausted
Multiple Changes: Multiple parameter changes trigger a single shadow update containing all changes
Shadow Update Acknowledgment:
QoS 1: Shadow updates use QoS 1 for at least-once delivery
Accepted Topics: The node subscribes to the shadow
get/acceptedtopics (see Shadow Topics) but does not require acknowledgment before proceedingPublish Failure: A publish that fails synchronously keeps the node’s pending-update list and change flags, so the retry repeats the original scope rather than escalating to a full report (see Error Handling and Recovery Strategies)
PUBACK Failure: A failed shadow PUBACK schedules a subsequent full state report, retried with exponential backoff (base = the coalescing delay, ×2 per attempt, capped at 5 minutes, with up to 1 s of jitter). For the indexed shadow the pending node-tag checksum is not committed, so the tag set is re-emitted in that full report
Named Shadow
This shadow represents the complete state of the node within its group context.
Shadow Name:
params-{group_info_str}{group_info_str}: see “Group Info String”.
Purpose: Contains the full reported state of all logical device parameters. This is the primary source of truth for the node’s state.
Update Topic: See Named Shadow Update topic
{thing_name}: see “Thing Name”.
Payload Specification: The wrapper is always
state.reportedwith optionalonline,ncfg_ver, andnotify.paramsis device id → { parameter id → value }:{ "state": { "reported": { // include to report current status of node "online": true, // include if node configuration has been updated "ncfg_ver": <node configuration checksum>, // include if any parameters are updated "params": { <device id>: { <parameter id>: <parameter value>, // ... other updated parameters for this device }, // ... other devices with updated parameters // include if any notification setting is enabled "notify": <notify_payload> } } } }
ncfg_ver: The SHA-256 checksum of the node configuration payload, as a 64-character lowercase hex string (no0x). It is a change token, not a timestamp — the cloud compares it for equality and needs no valid wall clock on the node. It is emitted on the next state report after the cloud has acknowledged the correspondingsetNodeConfigfor that configuration.notifyis nested insideparams, and is therefore only emitted when the report also carries at least one parameter update.
Notify Payload
The notify field in the named shadow provides metadata about notification-related configurations and settings. This allows the cloud to track notification preferences and versions without requiring separate MQTT communications.
Purpose: Contains notification configuration state and version information for various notification services.
Scope: Named shadow only, and only for the device’s own node. The indexed shadow never carries
notify.When emitted: Only when at least one notification integration is enabled (
alexaorgva). If all are disabled, the wholenotifyobject is omitted.Payload Structure:
{
"version": <version number>,
<notification type>: <configuration value>,
// ... additional notification types as needed
}
Field |
Description |
Type |
|---|---|---|
|
Millisecond monotonic timestamp divided by 10, i.e., in hundredths of a second. Uniqueness is the only requirement, so this is deliberately not gated on time synchronisation — before the clock is valid it is boot-relative rather than a UNIX timestamp. The version number must change from the previous update in order to trigger cloud actions. |
integer |
|
Indicates whether Alexa notifications are enabled for this node. Follows the value received from getAlexaEn. |
boolean |
|
Indicates whether Google Voice Assistant notifications are enabled for this node. Follows the value received from getGVAEn. |
boolean |
Both alexa and gva are always present whenever notify is emitted, even when only one of them is enabled.
Note: Additional notification types may be added in the future to support other smart home platforms or custom notification services.
Migration on group information change
The group information can be modified at any time, e.g., when the node is moved from one group to another. When this happens, based on the new group information, the node migrates the named shadow document:
Delete the old named shadow document (publish
{}to the old delete topic), while the old group info string is still in effect.Unsubscribe from the old params topic, the old group control topics and the old named shadow
get/acceptedtopic.Persist the new group info string, which is what constructs the new named shadow name.
Re-subscribe on the new group info string and send a full state update (as per start-up), which creates the new named shadow document.
Two special cases:
Primary group ID changed: step 4 is not run inline. Instead the node forces an MQTT reconnect so the broker re-evaluates the device’s IoT policy for the new primary group, and the reconnect path performs the subscriptions and the full report.
Group info unchanged: if the node is not currently subscribed to the params topic (for example after a restart where the string was already in NVS), step 4 is still run so the subscriptions and full report are established.
The indexed shadow is never migrated: its name is static (iparams).
Indexed Shadow
This shadow holds a small, curated subset of the node’s state for fast querying and filtering by the backend.
Shadow Name:
iparams(static)Unlike named shadows, this indexed shadow is not accessed by the user and has no group/subgroup IDs in its name for access control.
Purpose: Contains only parameters with the
indexedproperty in the node configuration, as well as top-level node tags.Update Topic: See Indexed Shadow Update topic
{thing_name}: see “Thing Name”.
Payload Specification: Same wrapper as the named shadow, with
data,online,ncfg_verandparams. There is nonotifyin the indexed shadow.paramsis device id → { parameter id → value }, restricted to parameters with theindexedproperty.{ "state": { "reported": { // include if the node's tag set has changed "data": { "device": { "t": { // node-updated tags go here <tag name>: <tag value> } } }, // include to report current status of node "online": true, // include if node configuration has been updated "ncfg_ver": <node configuration checksum>, // include if any indexed parameters are updated "params": { /* structure as above, indexed params only */ } } } }
online and ncfg_ver carry exactly the same values as in the named shadow — both shadows are populated from the same pending-update list in one pass.