Appearance
Telemetry
Status packets
The status packet (internally called the heartbeat) is the primary telemetry message. It's published to /cbox/{DEVICE_ID}/status every 20 seconds, and immediately whenever a relay changes state.
json
{
"deviceId": "CBOX-00001",
"type": "heartbeat",
"time": "2024-01-15T14:30:45.123Z",
"timeU": 1705329045,
"uptime": 3600,
"fwVer": "v1.2.3",
"heartbeat": 123,
"dcOk": true,
"batt": { "V": 3.85, "pc": 75, "conn": true, "status": "charging" },
"intMeter": { "status": "present", "V": 230.50, "I": 2.45, "f": 50.02, "PkW": 0.56, "EkWHr": 123.45 },
"extMeter": { "status": "not_present", "V": 0.00, "I": 0.00, "f": 0.00, "PkW": 0.00, "EkWHr": 0.00 },
"network": {
"activeIf": "ethernet",
"conn": true,
"failoverCount": 0,
"ifs": {
"ethernet": { "state": "got_ip", "ip": "192.168.1.100", "gw": "192.168.1.1", "ok": true },
"wifi": { "state": "got_ip", "ssid": "MyWiFiNetwork", "rssi": -65, "ip": "192.168.1.101", "gw": "192.168.1.1" },
"mobile": { "state": "got_ip", "rssi": -75, "ip": "10.0.0.2" }
}
},
"health": { "uptime": 3600, "freeHeap": 65432, "minFreeHeap": 45000, "largestFreeBlock": 64000, "tasks": 12, "lastReset": "power_on" },
"ota": { "size": 1048576, "received": 524288 },
"cert": { "daysToRenewal": 180, "expires": "2026-12-30T00:00:00Z" },
"hasAlerts": true,
"diag": false,
"relays": [0, 1, 0, 1, 0, 0],
"rlyCfgV": 0
}Field reference
| Section | Field | Description |
|---|---|---|
| — | type | "heartbeat" for the 20s packet, "rlyStatus" when returned on request, "rlyDelta" for the lightweight relay-change message below |
| — | fwVer | Firmware version, e.g. "v1.2.3" |
| — | relays | Relay output states — numeric array, 0=OFF / 1=ON, index is the 0-based relay number (up to 6 on CoppelBox units) |
| — | rlyCfgV | Relay config version counter — increments on every config change; compare against your cached value to detect a stale relay config |
batt | V, pc, conn, status | Battery voltage (V), percentage (0–100), connected flag, and state (charging/discharging/full/low/critical) |
intMeter / extMeter | status, V, I, f, PkW, EkWHr | Internal / external power meter: presence, voltage (Vrms), current (Arms), frequency (Hz), active power (kW), cumulative energy (kWh) |
network | activeIf, conn, failoverCount, ifs | Active interface (ethernet/wifi/mobile/none), connectivity flag, failover count, and per-interface state/IP/signal detail |
health | freeHeap, minFreeHeap, largestFreeBlock, tasks, lastReset | Free heap memory, its low-water-mark, largest contiguous block, FreeRTOS task count, and the restart reason for the last reboot |
ota | size, received | Firmware download progress in bytes; both zero when no update is in progress |
cert | daysToRenewal, expires | Days until the device's operational certificate expires, and its expiry timestamp. Omitted only when both values are unavailable. |
| — | hasAlerts | true if any alert is currently in alert or warning state — see Alerts for the full detail on that topic |
| — | diag | true if diagnostic publishing is currently enabled on the device |
Relay delta
A lightweight message published immediately on a relay state change, to /cbox/{DEVICE_ID}/status with type: "rlyDelta":
json
{
"deviceId": "CBOX-00001",
"type": "rlyDelta",
"time": "2024-01-15T14:30:45.123Z",
"timeU": 1705329045,
"uptime": 3600,
"relays": [0, 1, 0, 1, 0, 0]
}Relay config
Published to /cbox/{DEVICE_ID}/config (not /status) on every MQTT connect and after any relay configuration change, with type: "relayConfig". Contains the full per-relay label, description, hardware type, mode, and pulse settings — use this to resolve relays[N]/rlyCfgV in the status packet to a human-readable label. See MQTT API for the topic.
Power data
Real-time power readings are in the status packet's intMeter/extMeter fields above. Separately, buffered historical samples are published to /cbox/{DEVICE_ID}/power:
json
{
"deviceId": "CBOX-00001",
"type": "powerHistory",
"ts": 1705329045,
"int": { "V": 230.5, "I": 2.45, "PkW": 0.56 },
"ext": { "V": 230.1, "I": 1.23, "PkW": 0.28 }
}ts— Unix timestamp when the sample was capturedint/ext— voltage (V), current (I), and active power (PkW) for the internal / external meter (each field omitted if that meter isn't available)
Samples are published individually, not as arrays, and are buffered locally on the device when MQTT is disconnected — up to five samples are synced per heartbeat interval once connectivity is restored, so a period offline doesn't create a permanent gap in the historical record.
Publish cadence
| Message | Topic | Cadence |
|---|---|---|
| Status packet (heartbeat) | /status | Every 20 seconds |
| Relay delta | /status | Immediately on any relay state change |
| Relay config | /config | On MQTT connect + after any config change |
| Power history | /power | Buffered; up to 5 samples synced per heartbeat interval |
| Alerts | /alerts | Immediately on fault/warning; resent every 60s (critical) or 300s (high/medium) while unacknowledged |
| Ivy Board telemetry | /ivy | Every 60 seconds (if an Ivy Board is fitted) |
| Diagnostics | /diag | Every 60 seconds, only when explicitly enabled (set_diag_publish command; off by default) |