Skip to main content

UMEC MQTT v3 — normative reference

This document fixes only fields and limits confirmed by the current bridge contract and JSON Schema. A field not described here is not a public contract.

JSON-RPC envelope​

FieldTypeRequiredRule
jsonrpcstringyesexactly "2.0"
idnumberyescorrelation ID; command ID is deduplicated for 300 seconds per tenant/deviceId
methodstringyesinventory, state, config, command, ack
paramsobjectyescontains at least timestamp
params.timestampintegeryesUnix epoch milliseconds
params.deviceobjectnodevice section of a message
params.modulesarraynomodule sections of a message

The top-level object does not allow extra fields. Schema: umec-mqtt-v3.schema.json.

Methods and direction​

MethodDirectionPayload policy
inventoryD2Pidentity/schema description; it does not confirm measurement freshness
stateD2Pmeasured state, delta or full snapshot
configP2Dconfiguration/control prepared by the platform
commandP2Dwritable parameter or action command
ackP2Dacknowledgement/result flow

Every flow uses QoS 1 and retain=false. An MQTT message is at most 1 MiB. The sum of sensors, parameters and errors in device and modules is at most 1000.

State​

{
"jsonrpc": "2.0",
"id": 1001,
"method": "state",
"params": {
"timestamp": 1760000000000,
"device": {
"id": "<deviceId>",
"sensors": [{"id": "temperature", "value": 21.6}],
"parameters": [{"id": "target", "value": 22}],
"errors": []
},
"modules": []
}
}

This is a conformance shape: replace values and codes with the specific device schema. The bridge keeps observed state distinct from inventory; offline/unavailable state must not fabricate a source timestamp or a history datapoint.

Inventory​

{
"jsonrpc": "2.0",
"id": 1002,
"method": "inventory",
"params": {"timestamp": 1760000000000, "device": {"id": "<deviceId>"}, "modules": []}
}

Inventory reconciles identity/schema. It is not a replacement for state and does not make a controller or sensor fresh.

Config, command and ACK​

P2D config/commands keep device controls at the top level of params; do not use legacy params.device for those messages. Every writable parameter, module parameter and action command is a separate request with an independent numeric ID.

{
"jsonrpc": "2.0",
"id": 2001,
"method": "command",
"params": {"timestamp": 1760000000000}
}

The successful admission response has shape { "accepted": 1 }. applied needs a matching state echo. If a command is invalid, ACL-denied or cannot be applied, use a JSON-RPC error rather than a success object.

ACL​

PrincipalPermittedProhibited
devicewrite only <tenant>/<deviceId>/d2p; read only <tenant>/<deviceId>/p2danother device, reverse direction, wildcard
ingestread only its D2P topicP2D and publish
publisher/serverwrite only its P2D topicD2P and subscribe

An ACL rule contains neither + nor #, has exactly three topic segments and its tenant/deviceId match its principal scope.

Retry and timeout​

Timeout and retry must be bounded by the device policy. Persist id, sent time and terminal result. Retry only an idempotent command with the same ID; escalate a command with an unknown effect. Do not log payload values, passwords, tokens or private keys.

Release verification​

  1. Validate every JSON object against the schema.
  2. Check topic, QoS 1, retain false and payload ≤1 MiB.
  3. Check actual device ACL without wildcard.
  4. Exercise D2P inventory/state, P2D command and matching state echo in staging.
  5. Rotate credentials via the provisioning flow; revoke old credentials before publishing the new pair.