1. Design Goals
EnvelopeJson pursues three things:
- Stable: wire format has
schema_version, facilitating long-term evolution - Routable:
event.kindis a stable discriminator field (Required for mixed topic scenarios) - Payload untagged: Business data is placed in
payload.data, no longer nested enum tag, reducing coupling
2. JSON Shape (schema_version = 1)
json
{
"schema_version": 1,
"event": { "kind": "telemetry" },
"envelope": {
"ts_ms": 1734870900000,
"app": { "id": 1, "name": "my-app", "plugin_type": "kafka" },
"device": { "id": 1001, "name": "dev-1", "type": "pump-v1" }
},
"payload": {
"data": {}
}
}Important Constraint
payload.data internally will not have enum tag again (e.g., shape like {"Telemetry": {...}} will not appear). The only discriminator field is event.kind.
3. event.kind Enum Values (snake_case)
3.1 uplink (Gateway → Platform)
device_connecteddevice_disconnectedtelemetryattributesalarmrpc_responsewrite_point_response
3.2 downlink (Platform → Gateway)
write_pointcommand_receivedrpc_response_received
WARNING
Different plugins may only implement some of these event types. You should refer to specific plugin documentation.
4. envelope Meta Information
envelope field is optional (downlink minimal input can be without it), uplink usually carries:
ts_ms: Millisecond timestamp (Telemetry/Attributes use collection time; Online/Offline events may use "Current Time")app: app id/name/plugin_typedevice: device id/name/type (typeof Telemetry/Attributes may be empty)
5. What is inside payload.data
Specific fields of payload.data depend on event type (Corresponding to specific structure of NorthwardData or NorthwardEvent).
Best Practice
In initial integration, fix using EnvelopeJson first, make the link run through and stable observable; confirm correct before considering Kv/TimeseriesRows/MappedJson.
