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.