CPI Documentation
Device Protocol

Device Protocol

MQTT message formats, topic structure, HMAC signing, and protocol specification for CPI device communication.

Topic Structure

All MQTT topics follow the prefix pattern cpi/{deviceId}/:

TopicDirectionDescription
cpi/{deviceId}/telemetryDevice → PlatformSensor data readings
cpi/{deviceId}/statusDevice → PlatformDevice online/offline status
cpi/{deviceId}/commandsPlatform → DeviceRemote commands
cpi/{deviceId}/ackDevice → PlatformCommand acknowledgments

The deviceId is a UUID assigned during device registration.

Protocol Version

Current protocol version: 1.0

All messages are JSON-encoded UTF-8 strings published with QoS 1. Maximum message size: 8KB (enforced by Mosquitto).

Message Formats

Telemetry

Published by the device to report sensor readings.

{
  "ts": 1700000000000,
  "nonce": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "data": {
    "temperature": 22.5,
    "humidity": 45.2,
    "pressure": 1013.25
  },
  "sig": "a1b2c3d4...64-hex-chars"
}
FieldTypeDescription
tsintegerMillisecond epoch timestamp
noncestringUUID v4, unique per message
dataobjectKey-value sensor readings (string keys, numeric values)
sigstringHMAC-SHA256 hex signature

The data object supports arbitrary keys. Common examples: temperature, humidity, pressure, voltage, current, rpm.

Status

Published by the device to report connectivity state.

{
  "ts": 1700000000000,
  "nonce": "d1e2f3a4-b5c6-7890-d1e2-f3a4b5c67890",
  "status": "ONLINE",
  "sig": "b2c3d4e5...64-hex-chars"
}
Status ValueWhen to Publish
ONLINEOn successful MQTT connection
OFFLINEAs MQTT Last Will and Testament (LWT)
MAINTENANCEDuring firmware update or calibration
ERROROn device error requiring attention

Set OFFLINE as the MQTT LWT message so it's automatically published if the device disconnects unexpectedly.

Command (Platform → Device)

Received by the device on the commands topic.

{
  "cmdId": "e5f6a7b8-c9d0-1234-e5f6-a7b8c9d01234",
  "ts": 1700000000000,
  "action": "REBOOT",
  "payload": {},
  "sig": "c3d4e5f6...64-hex-chars"
}
ActionPayloadDescription
REBOOT{}Restart the device
SET_CONFIG{ "interval": 5000 }Update device configuration
FIRMWARE_UPDATE{ "url": "...", "version": "2.0" }Trigger OTA update
IDENTIFY{}Blink LED or signal physically

Command ACK (Device → Platform)

Sent by the device to acknowledge command receipt and completion.

{
  "cmdId": "e5f6a7b8-c9d0-1234-e5f6-a7b8c9d01234",
  "status": "COMPLETED",
  "ts": 1700000000000,
  "sig": "d4e5f6a7...64-hex-chars"
}
ACK StatusMeaning
RECEIVEDCommand received, queued for execution
IN_PROGRESSCommand is being executed
COMPLETEDCommand executed successfully
FAILEDCommand execution failed

HMAC Signing

Every message must include an HMAC-SHA256 signature computed with the device's hmacSecret.

Signing Process

  1. Construct the signing string by joining fields with | (pipe)
  2. Compute HMAC-SHA256 of the string using the hmacSecret
  3. Encode as lowercase hex (64 characters)
  4. Include as the sig field

Signature Strings

Message TypeSigning String
Telemetry{deviceId}|{ts}|{nonce}|{JSON.stringify(data)}
Status{deviceId}|{ts}|{nonce}|{JSON.stringify({status})}
Command{deviceId}|{cmdId}|{ts}|{action}|{JSON.stringify(payload)}
ACK{deviceId}|{cmdId}|{ts}|{status}

JSON serialization must be compact — no extra whitespace. JavaScript JSON.stringify() is compact by default. Python requires json.dumps(data, separators=(',', ':')).

Validation Rules

  • Timestamp tolerance: ±5 minutes (300,000 ms) from server time
  • Nonce uniqueness: Duplicate nonces rejected within 5-minute window
  • HMAC enforcement: In production (REQUIRE_HMAC_SIGNATURES=true), unsigned messages from non-PENDING devices are rejected

Rate Limiting

10 authentication failures in 5 minutes triggers automatic device suspension. The device must be reactivated by an admin.

Connection Limits

Enforced by Mosquitto:

ParameterValue
Max connections500
Max message size8 KB
Max inflight messages20
Max queued messages1000

On this page