← API Reference Home
ESP RainMaker Neo User MQTT API 0.8.0

MQTT API definitions for ESP RainMaker Neo platform — User (mobile app / web client) perspective.

This spec documents every MQTT topic a user publishes to or subscribes to, for controlling devices and receiving real-time state updates.

Authentication Flow

Users connect to AWS IoT Core over WebSocket with SigV4 (not X.509 certificates):

  1. Login — Authenticate with Cognito User Pool → receive ID Token
  2. Get IdentityPOST /v1/user/credentials with ID Token → receive Cognito Identity ID + temporary AWS credentials
  3. Assume IoT RolePOST /v1/user/assume_role → receive scoped temporary credentials restricted to the user's groups/subgroups. To request S3/KVS credentials instead, call POST /v1/groups/{group_id}/nodes/{node_id}/assumed-roles with { "services": ["s3"|"kvs"] } — the response scopes to that single node and contains no IoT/MQTT permissions.
  4. Connect — WebSocket MQTT to wss://<iot-endpoint>:443/mqtt using a SigV4-signed request with the scoped credentials, and an MQTT client id of user:<email|phone>:<session> (see Client ID below)

Client ID

The MQTT client id must be user:<login-username>:<session>, where <login-username> is the caller's own login email or phone number and <session> is unique per app session (a random number or timestamp is fine — it need not be secret).

The vended session policy scopes iot:Connect to client/user:<login-username>:*, so:

  • the bare user:<login-username> form (no session suffix) is rejected — the connect fails with AWS_ERROR_MQTT_UNEXPECTED_HANGUP;
  • a client can only connect as its own username — the : delimiter cannot appear in an email or E.164 phone number, so the wildcard never matches another user;
  • the per-session suffix lets a user's concurrent sessions (e.g. phone + dashboard) coexist instead of kicking each other off (MQTT enforces a unique client id per endpoint).

Access Control

Topic-level access is enforced via IAM session policies scoped to the user's group/subgroup membership.

Servers

  • mqtt://{iot-endpoint}-ats.iot.{region}.amazonaws.com/mqttproduction

    AWS IoT Core endpoint (WebSocket + SigV4 authentication)

    Security:
    • HTTP API key
      • Name: X-Amz-Signature
      • In: query

      WebSocket MQTT connection authenticated via AWS SigV4 with Cognito-issued temporary credentials. The full SigV4 handshake uses several query parameters (X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-SignedHeaders, X-Amz-Signature, X-Amz-Security-Token); X-Amz-Signature is declared here as the canonical identifier for the scheme.

Operations

  • SEND rainmaker/nodes/{nodeId}/user/{shadowName}/params

    [User → Device] Send parameter control commands to a specific device.

    User sends parameter control commands to a specific device

    Operation IDpublishDeviceControl

    Available only on servers:

    object
    nodeId
    required
    string

    Unique device identifier (Thing Name / Node ID)

      Examples values:
    • "ABCDEF1234567890"
    • "ESP32_Light_001"
    shadowName
    required
    string

    Named shadow identifier: params-<group_id>[-<sub1>-<sub2>-…]. Subgroup IDs are sorted alphabetically. Derived from the device's group membership. For unassociated nodes (no group), the shadow name is params- (empty suffix).

      Examples values:
    • "params-grp_abc123"
    • "params-grp_abc123-sub_floor2-sub_room1"
    • "params-"

    Accepts the following message:

    controlCommand

    Parameter update command sent by user to device(s) — device-name addressed

    Message IDcontrolCommand

    Same format for unicast and group params broadcast.

    Default data model: { "<device_name>": { "<param>": <value> } }. Matter data model: { "<endpoint_hex>": { "c": { "s|c": { "<cluster_hex>": { "c": { "<cmd_hex>": "0x<TLV>" } } } } } }.

    object

    Examples

  • SEND rainmaker/nodes/groups/{groupId}/control

    [User → All devices in group] Device-type-addressed control commands. Each receiving node applies the payload only to its own devices whose type matches a top-level key.

    User sends device-type-addressed control commands to all devices in a group

    Operation IDpublishGroupControlBroadcast

    Available only on servers:

    object
    groupId
    required
    string

    Group ID for group-wide operations

      Examples values:
    • "grp_abc123"
    • "grp_office_main"

    Accepts the following message:

    groupControl

    Control command broadcast to all nodes in a group or subgroup

    Message IDgroupControl

    Control payload broadcast on rainmaker/nodes/groups/{groupId}/control (group) or rainmaker/nodes/groups/{groupId}/subgroups/{subgroupId}/control (subgroup).

    Default data model: top-level keys are device types (e.g. esp.device.light). Each device's value is an object that holds nested sub-keys describing what to apply — currently only params is defined, with room for additional sub-keys (e.g. cmd, meta) in future without another topic rename. Receiving nodes apply the payload only to their own devices that match the listed device types; other devices are ignored.

    Matter data model: command invocations only. Same nested structure as the unicast ParamControl message, except the top-level endpoint key is the wildcard endpoint "0xffff" (not a specific endpoint): 0xffff → c → s|c → cluster → c → { command hex → TLV hex }. Each node invokes the command on every endpoint that supports the addressed cluster + command, resolved from its own support list.

    object

    Default: map of device type → control envelope. Matter: the unicast ParamControl command structure.

    Examples

  • SEND rainmaker/nodes/groups/{groupId}/subgroups/{subgroupId}/control

    [User → All devices in subgroup] Device-type-addressed control commands for one specific subgroup. Same payload shape as the group-level groupControlBroadcast channel.

    User sends device-type-addressed control commands to all devices in a subgroup

    Operation IDpublishSubgroupControlBroadcast

    Available only on servers:

    object
    groupId
    required
    string

    Group ID for group-wide operations

      Examples values:
    • "grp_abc123"
    • "grp_office_main"
    subgroupId
    required
    string

    Subgroup ID for subgroup-scoped operations

      Examples values:
    • "sub_room1"
    • "sub_floor2"

    Accepts the following message:

    subgroupControl

    Control command broadcast to all nodes in a group or subgroup

    Message IDsubgroupControl

    Control payload broadcast on rainmaker/nodes/groups/{groupId}/control (group) or rainmaker/nodes/groups/{groupId}/subgroups/{subgroupId}/control (subgroup).

    Default data model: top-level keys are device types (e.g. esp.device.light). Each device's value is an object that holds nested sub-keys describing what to apply — currently only params is defined, with room for additional sub-keys (e.g. cmd, meta) in future without another topic rename. Receiving nodes apply the payload only to their own devices that match the listed device types; other devices are ignored.

    Matter data model: command invocations only. Same nested structure as the unicast ParamControl message, except the top-level endpoint key is the wildcard endpoint "0xffff" (not a specific endpoint): 0xffff → c → s|c → cluster → c → { command hex → TLV hex }. Each node invokes the command on every endpoint that supports the addressed cluster + command, resolved from its own support list.

    object

    Default: map of device type → control envelope. Matter: the unicast ParamControl command structure.

    Examples

  • RECEIVE $aws/things/{nodeId}/shadow/name/{shadowName}/update/documents

    [Shadow → User] Full shadow document on every state change. Contains both current and previous state. User subscribes to receive real-time state updates from devices.

    User receives real-time device state changes (shadow update documents)

    Operation IDsubscribeShadowUpdate

    Available only on servers:

    object
    nodeId
    required
    string

    Unique device identifier (Thing Name / Node ID)

      Examples values:
    • "ABCDEF1234567890"
    • "ESP32_Light_001"
    shadowName
    required
    string

    Named shadow identifier: params-<group_id>[-<sub1>-<sub2>-…]. Subgroup IDs are sorted alphabetically. Derived from the device's group membership. For unassociated nodes (no group), the shadow name is params- (empty suffix).

      Examples values:
    • "params-grp_abc123"
    • "params-grp_abc123-sub_floor2-sub_room1"
    • "params-"

    Accepts the following message:

    shadowDocuments

    Full shadow document after state change

    Message IDshadowDocuments

    Contains both current and previous full shadow state. Used by apps to detect exactly what changed.

    object

    Examples

  • RECEIVE $aws/things/{nodeId}/shadow/name/{shadowName}/update/delta

    [Shadow → User] Shadow delta — contains only the difference between desired and reported state. Useful for tracking pending commands.

    User receives shadow delta (desired vs. reported difference)

    Operation IDsubscribeShadowDelta

    Available only on servers:

    object
    nodeId
    required
    string

    Unique device identifier (Thing Name / Node ID)

      Examples values:
    • "ABCDEF1234567890"
    • "ESP32_Light_001"
    shadowName
    required
    string

    Named shadow identifier: params-<group_id>[-<sub1>-<sub2>-…]. Subgroup IDs are sorted alphabetically. Derived from the device's group membership. For unassociated nodes (no group), the shadow name is params- (empty suffix).

      Examples values:
    • "params-grp_abc123"
    • "params-grp_abc123-sub_floor2-sub_room1"
    • "params-"

    Accepts the following message:

    delta

    Difference between desired and reported state

    Message IDdelta

    Contains only the fields where desired differs from reported. Useful for tracking commands that haven't been applied yet.

    object

    Examples

  • RECEIVE $aws/things/{nodeId}/shadow/name/{shadowName}/update/accepted

    [Shadow → User] Confirmation that a shadow update was accepted by AWS IoT.

    User receives confirmation that a shadow update was accepted

    Operation IDsubscribeShadowUpdateAccepted

    Available only on servers:

    object
    nodeId
    required
    string

    Unique device identifier (Thing Name / Node ID)

      Examples values:
    • "ABCDEF1234567890"
    • "ESP32_Light_001"
    shadowName
    required
    string

    Named shadow identifier: params-<group_id>[-<sub1>-<sub2>-…]. Subgroup IDs are sorted alphabetically. Derived from the device's group membership. For unassociated nodes (no group), the shadow name is params- (empty suffix).

      Examples values:
    • "params-grp_abc123"
    • "params-grp_abc123-sub_floor2-sub_room1"
    • "params-"

    Accepts the following message:

    accepted

    Shadow update accepted confirmation

    Message IDaccepted
    object

    Examples

  • RECEIVE $aws/things/{nodeId}/shadow/name/{shadowName}/update/rejected

    [Shadow → User] Rejection of a shadow update (e.g. version conflict).

    User receives rejection of a shadow update

    Operation IDsubscribeShadowUpdateRejected

    Available only on servers:

    object
    nodeId
    required
    string

    Unique device identifier (Thing Name / Node ID)

      Examples values:
    • "ABCDEF1234567890"
    • "ESP32_Light_001"
    shadowName
    required
    string

    Named shadow identifier: params-<group_id>[-<sub1>-<sub2>-…]. Subgroup IDs are sorted alphabetically. Derived from the device's group membership. For unassociated nodes (no group), the shadow name is params- (empty suffix).

      Examples values:
    • "params-grp_abc123"
    • "params-grp_abc123-sub_floor2-sub_room1"
    • "params-"

    Accepts the following message:

    rejected

    Shadow update rejected

    Message IDrejected
    object

    Examples

  • SEND $aws/things/{nodeId}/shadow/name/{shadowName}/get

    [User → Shadow] Request the current shadow document, e.g. to fetch device state on connect or app resume. The document is returned on .../get/accepted. The update/* topics above only fire on subsequent changes, so this round-trip is how an app reads current state.

    User requests the current shadow document (response on get/accepted)

    Operation IDpublishShadowGet

    Available only on servers:

    object
    nodeId
    required
    string

    Unique device identifier (Thing Name / Node ID)

      Examples values:
    • "ABCDEF1234567890"
    • "ESP32_Light_001"
    shadowName
    required
    string

    Named shadow identifier: params-<group_id>[-<sub1>-<sub2>-…]. Subgroup IDs are sorted alphabetically. Derived from the device's group membership. For unassociated nodes (no group), the shadow name is params- (empty suffix).

      Examples values:
    • "params-grp_abc123"
    • "params-grp_abc123-sub_floor2-sub_room1"
    • "params-"

    Accepts the following message:

    get
    Message IDget
    object

    Empty JSON

    Examples

  • RECEIVE $aws/things/{nodeId}/shadow/name/{shadowName}/get/accepted

    [Shadow → User] Current shadow document returned in response to a get.

    User receives the current shadow document in response to a get

    Operation IDsubscribeShadowGetAccepted

    Available only on servers:

    object
    nodeId
    required
    string

    Unique device identifier (Thing Name / Node ID)

      Examples values:
    • "ABCDEF1234567890"
    • "ESP32_Light_001"
    shadowName
    required
    string

    Named shadow identifier: params-<group_id>[-<sub1>-<sub2>-…]. Subgroup IDs are sorted alphabetically. Derived from the device's group membership. For unassociated nodes (no group), the shadow name is params- (empty suffix).

      Examples values:
    • "params-grp_abc123"
    • "params-grp_abc123-sub_floor2-sub_room1"
    • "params-"

    Accepts the following message:

    getAccepted

    Shadow update accepted confirmation

    Message IDgetAccepted
    object

    Examples

Messages

  • #1paramControlMessage

    Parameter update command sent by user to device(s) — device-name addressed

    Message IDparamControlMessage

    Same format for unicast and group params broadcast.

    Default data model: { "<device_name>": { "<param>": <value> } }. Matter data model: { "<endpoint_hex>": { "c": { "s|c": { "<cluster_hex>": { "c": { "<cmd_hex>": "0x<TLV>" } } } } } }.

    object
  • #2groupControlMessage

    Control command broadcast to all nodes in a group or subgroup

    Message IDgroupControlMessage

    Control payload broadcast on rainmaker/nodes/groups/{groupId}/control (group) or rainmaker/nodes/groups/{groupId}/subgroups/{subgroupId}/control (subgroup).

    Default data model: top-level keys are device types (e.g. esp.device.light). Each device's value is an object that holds nested sub-keys describing what to apply — currently only params is defined, with room for additional sub-keys (e.g. cmd, meta) in future without another topic rename. Receiving nodes apply the payload only to their own devices that match the listed device types; other devices are ignored.

    Matter data model: command invocations only. Same nested structure as the unicast ParamControl message, except the top-level endpoint key is the wildcard endpoint "0xffff" (not a specific endpoint): 0xffff → c → s|c → cluster → c → { command hex → TLV hex }. Each node invokes the command on every endpoint that supports the addressed cluster + command, resolved from its own support list.

    object

    Default: map of device type → control envelope. Matter: the unicast ParamControl command structure.

  • #3shadowUpdateDocumentsMessage

    Full shadow document after state change

    Message IDshadowUpdateDocumentsMessage

    Contains both current and previous full shadow state. Used by apps to detect exactly what changed.

    object
  • #4shadowDeltaMessage

    Difference between desired and reported state

    Message IDshadowDeltaMessage

    Contains only the fields where desired differs from reported. Useful for tracking commands that haven't been applied yet.

    object
  • #5shadowUpdateAcceptedMessage

    Shadow update accepted confirmation

    Message IDshadowUpdateAcceptedMessage
    object
  • #6shadowUpdateRejectedMessage

    Shadow update rejected

    Message IDshadowUpdateRejectedMessage
    object

Schemas

  • object

    AWS IoT Shadow document structure