Control Relays
Use device.operation.execute to control one or multiple relays. All relay changes in one request are sent as one command.
The batch consumes one device-operation allowance. Do not send consecutive messages only to target different relay indexes.
Permission
device:controlRequest
{
"type": "request",
"requestId": "req_relay_001",
"topic": "device.operation.execute",
"data": {
"deviceId": "abc123456789",
"idempotencyKey": "idem_relay_001",
"operation": {
"name": "device.relay.set",
"params": {
"relays": [
{ "index": 1, "action": "ON" },
{ "index": 2, "action": "OFF" }
]
}
}
}
}For a single relay, send a relays array with one item.
params Fields
| Field | Type | Required | Description |
|---|---|---|---|
relays | array | Yes | Non-empty relay operation list |
relays[].index | integer | Yes | Relay index starting at 1; indexes must be unique |
relays[].action | string | Yes | ON, OFF, or JOG |
JOG uses the jog duration stored on the device.
Reply
{
"type": "reply",
"requestId": "req_relay_001",
"code": "COMMAND_ACCEPTED",
"message": "Command accepted.",
"data": {
"command": {
"id": "cmd_01HX...",
"deviceId": "abc123456789",
"operation": "device.relay.set",
"status": "SUCCESS",
"params": {
"relays": [
{ "index": 1, "action": "ON" },
{ "index": 2, "action": "OFF" }
]
},
"createdAt": "2026-07-15T08:30:00Z"
},
"state": {
"deviceId": "abc123456789",
"status": "ONLINE",
"peripherals": {
"relays": [
{ "index": 1, "on": true },
{ "index": 2, "on": false }
],
"digitalInputs": [
{ "index": 1, "active": false }
],
"analogInputs": [],
"sensors": []
},
"stateUpdatedAt": "2026-07-15T08:30:00Z"
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
data.command | object | Yes | The command and its current status |
data.command.id | string | Yes | Command ID for REST result queries |
data.command.operation | string | Yes | Fixed as device.relay.set |
data.command.params.relays | array | Yes | Normalized relay operations |
data.command.status | string | Yes | SENT, SUCCESS, FAILED, or TIMEOUT |
data.state | object | No | Latest runtime state included in the device acknowledgement |
data.state.peripherals | object | No | May include relays, digital inputs, analog inputs, and sensors |
state is returned only when the device response includes usable state. Do not issue another state query only to fill this field. Listen for device.state.changed for later changes.
Idempotency and Retries
- Reuse
idempotencyKeywhen retrying because no definitive reply was received. - Generate a new key for a new operation.
- Reusing the original key after
TIMEOUTdoes not control the device again; use a new key only for a new physical operation. - Reusing a key with different parameters returns
IDEMPOTENCY_CONFLICT. requestIdcorrelates messages on the current connection and does not replace the idempotency key.
Possible errors include INVALID_REQUEST, AUTH_SCOPE_DENIED, DEVICE_NOT_FOUND, DEVICE_BUSY, DEVICE_OFFLINE, IDEMPOTENCY_CONFLICT, COMMAND_REJECTED, RATE_LIMITED, GATEWAY_UNAVAILABLE, and INTERNAL_ERROR.
REST equivalent: Execute Relay Command.
