Zigbee Through-RPC
The Zigbee Through-RPC Command Protocol exposes three RPC methods that allow external clients (HTTP, WebSocket, MQTT) to directly issue ZCL (Zigbee Cluster Library) commands to any Zigbee device on the network.
The following methods are available:
Zigbee.SendCommand— send a raw ZCL cluster commandZigbee.ReadAttr— read a ZCL attribute valueZigbee.WriteAttr— write a ZCL attribute value
Common Parameters
Addressing
Zigbee.SendCommand supports three addressing modes. Zigbee.ReadAttr and Zigbee.WriteAttr only support unicast.
Unicast — send to a single device. Requires dst_addr and dst_ep. Waits for a ZCL response.
Group multicast — send to all devices that are members of a Zigbee group. Set dst_group to the group ID (0x0001–0xFFF7). Fire-and-forget, no ZCL response.
Bound devices (indirect) — send to all matching entries in the sending device's binding table. Set dst_group to 65535 (0xFFFF). Fire-and-forget, no ZCL response.
| Property | Type | Description |
|---|---|---|
| uint16 | 16-bit short network address. Required for unicast. Mutually exclusive with |
| uint8 | Target endpoint number. Required for unicast, ignored for group/broadcast. |
| uint16 | Group ID ( |
| uint16 | ZCL Cluster ID (e.g. |
| uint16 | Zigbee application profile ID. Optional, default |
dst_addr is the 16-bit short address assigned to the device during Zigbee network joining. It is not the 64-bit IEEE/MAC address.
Payload Encoding
All binary payloads and attribute values are passed as lowercase hex strings (e.g. "0100" = bytes 0x01 0x00). Multi-byte values follow little-endian byte order per the ZCL specification. Omit the field or pass "" for an empty payload.
Timeout
All methods accept an optional timeout_ms parameter (default 10000 ms) that controls how long to wait for a response from the end device.
Methods
Zigbee.SendCommand
Send a raw ZCL cluster command to a Zigbee device.
Request
| Property | Type | Description |
|---|---|---|
| uint16 | Short network address. Required for unicast, mutually exclusive with |
| uint8 | Target endpoint. Required for unicast, ignored for group/broadcast. |
| uint16 | Group ID or broadcast address. Optional, mutually exclusive with |
| uint16 | ZCL Cluster ID |
| uint8 | ZCL Command ID within the cluster |
| string | Command payload as a hex string. Optional, default |
| uint16 | Zigbee application profile ID. Optional, default |
| uint32 | Response timeout in milliseconds. Optional, default |
Response
| Property | Type | Description |
|---|---|---|
| bool |
|
| string | ZCL status code name (e.g. |
Zigbee.ReadAttr
Read a single ZCL attribute from a Zigbee device.
Request
| Property | Type | Description |
|---|---|---|
| uint16 | Short Zigbee network address of the target device |
| uint8 | Target endpoint number |
| uint16 | ZCL Cluster ID |
| uint16 | Attribute ID to read |
| uint16 | Zigbee application profile ID. Optional, default |
| uint32 | Response timeout in milliseconds. Optional, default |
Response
| Property | Type | Description |
|---|---|---|
| bool |
|
| uint8 | ZCL attribute data type code (present on success) |
| string | Raw attribute value as a hex string (present on success) |
| uint8 | Length of the value in bytes (present on success) |
ZCL Data Types
Common ZCL data type codes returned in the type field:
| Value | Description |
|---|---|
| Boolean — 1 byte |
| uint8 — 1 byte |
| uint16 — 2 bytes |
| uint32 — 4 bytes |
| int16 — 2 bytes |
| character string — variable length |
Zigbee.WriteAttr
Write a value to a single ZCL attribute on a Zigbee device.
Request
| Property | Type | Description |
|---|---|---|
| uint16 | Short Zigbee network address of the target device |
| uint8 | Target endpoint number |
| uint16 | ZCL Cluster ID |
| uint16 | Attribute ID to write |
| uint8 | ZCL attribute data type code — must match the ZCL-defined type of the target attribute |
| string | Value to write as a hex string |
| uint16 | Zigbee application profile ID. Optional, default |
| uint32 | Response timeout in milliseconds. Optional, default |
Response
| Property | Type | Description |
|---|---|---|
| bool |
|
| string | ZCL status code name (e.g. |
Errors
All methods return errors in the response body. Common failure scenarios:
| Error | Condition |
|---|---|
|
|
|
|
|
|
When a command is sent successfully but the device responds with an error or does not respond in time, the HTTP status is 200 but the response body contains "success": false with the relevant ZCL status code:
{"success": false, "status": "ZB_ZCL_STATUS_FAIL"}
Examples
Zigbee.SendCommand — On/Off/Toggle
The On/Off cluster (cluster: 6) uses cmd to select the operation: 0 = off, 1 = on, 2 = toggle.
- Turn On (cmd: 1)
- Turn Off (cmd: 0)
- Toggle (cmd: 2)
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_addr=12345&dst_ep=1&cluster=6&cmd=1
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":1}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":1}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
{
"id": 1,
"params": {
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
}
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_addr=12345&dst_ep=1&cluster=6&cmd=0
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":0}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":0}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
{
"id": 1,
"params": {
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
}
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_addr=12345&dst_ep=1&cluster=6&cmd=2
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":2}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":2}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
{
"id": 1,
"params": {
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
}
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
Zigbee.SendCommand — Move to Level (50%, 1s transition)
The payload "800a00" encodes level 0x80 (128 = 50%) followed by transition time 0x000a (10 × 100ms = 1 second) in little-endian byte order.
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_addr=12345&dst_ep=1&cluster=8&cmd=4&payload="800a00"
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_addr":12345,"dst_ep":1,"cluster":8,"cmd":4,"payload":"800a00"}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_addr":12345,"dst_ep":1,"cluster":8,"cmd":4,"payload":"800a00"}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
{
"id": 1,
"params": {
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
}
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
Zigbee.SendCommand — Custom Profile (Shelly endpoint)
When targeting the Shelly custom endpoint (dst_ep: 239 / 0xEF), set profile_id to 49153 (0xC001). Without this, the packet will be dropped by the target device because the APS profile does not match.
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_addr=12345&dst_ep=239&cluster=64517&cmd=7&payload="ffff00"&profile_id=49153
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_addr":12345,"dst_ep":239,"cluster":64517,"cmd":7,"payload":"ffff00","profile_id":49153}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_addr":12345,"dst_ep":239,"cluster":64517,"cmd":7,"payload":"ffff00","profile_id":49153}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
{
"id": 1,
"params": {
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
}
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
Zigbee.SendCommand — Group Multicast
Turn off all devices in group 1. No ZCL response — fire-and-forget.
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_group=1&cluster=6&cmd=0
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_group":1,"cluster":6,"cmd":0}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_group":1,"cluster":6,"cmd":0}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
null
{
"id": 1,
"params": null
}
null
Zigbee.SendCommand — Bound Devices (Indirect)
Turn off all bound devices via the binding table (dst_group: 65535). Fire-and-forget.
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_group=65535&cluster=6&cmd=0
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_group":65535,"cluster":6,"cmd":0}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_group":65535,"cluster":6,"cmd":0}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
null
{
"id": 1,
"params": null
}
null
Zigbee.SendCommand — Custom Timeout
- Zigbee.SendCommand HTTP GET Request
- Zigbee.SendCommand Curl Request
- Zigbee.SendCommand Mos Request
http://192.168.33.1/rpc/Zigbee.SendCommand?dst_addr=12345&dst_ep=1&cluster=6&cmd=1&timeout_ms=5000
curl -X POST -d '{"id":1,"method":"Zigbee.SendCommand","params":{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":1,"timeout_ms":5000}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.SendCommand '{"dst_addr":12345,"dst_ep":1,"cluster":6,"cmd":1,"timeout_ms":5000}'
Response
- Zigbee.SendCommand HTTP GET Response
- Zigbee.SendCommand Curl Response
- Zigbee.SendCommand Mos Response
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
{
"id": 1,
"params": {
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
}
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
Zigbee.ReadAttr — On/Off State (cluster 6, attr 0)
A response value of "01" means the light is currently on.
- Zigbee.ReadAttr HTTP GET Request
- Zigbee.ReadAttr Curl Request
- Zigbee.ReadAttr Mos Request
http://192.168.33.1/rpc/Zigbee.ReadAttr?dst_addr=12345&dst_ep=1&cluster=6&attr=0
curl -X POST -d '{"id":1,"method":"Zigbee.ReadAttr","params":{"dst_addr":12345,"dst_ep":1,"cluster":6,"attr":0}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.ReadAttr '{"dst_addr":12345,"dst_ep":1,"cluster":6,"attr":0}'
Response
- Zigbee.ReadAttr HTTP GET Response
- Zigbee.ReadAttr Curl Response
- Zigbee.ReadAttr Mos Response
{
"success": true,
"type": 16,
"value": "01",
"len": 1
}
{
"id": 1,
"params": {
"success": true,
"type": 16,
"value": "01",
"len": 1
}
}
{
"success": true,
"type": 16,
"value": "01",
"len": 1
}
Zigbee.WriteAttr — Identify Time = 10s (cluster 3, attr 0)
The value "0a00" encodes 10 seconds as a uint16 in little-endian byte order.
- Zigbee.WriteAttr HTTP GET Request
- Zigbee.WriteAttr Curl Request
- Zigbee.WriteAttr Mos Request
http://192.168.33.1/rpc/Zigbee.WriteAttr?dst_addr=12345&dst_ep=1&cluster=3&attr=0&type=33&value="0a00"
curl -X POST -d '{"id":1,"method":"Zigbee.WriteAttr","params":{"dst_addr":12345,"dst_ep":1,"cluster":3,"attr":0,"type":33,"value":"0a00"}}' http://${SHELLY}/rpc
mos --port ${PORT} call Zigbee.WriteAttr '{"dst_addr":12345,"dst_ep":1,"cluster":3,"attr":0,"type":33,"value":"0a00"}'
Response
- Zigbee.WriteAttr HTTP GET Response
- Zigbee.WriteAttr Curl Response
- Zigbee.WriteAttr Mos Response
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
{
"id": 1,
"params": {
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}
}
{
"success": true,
"status": "ZB_ZCL_STATUS_SUCCESS"
}