This is a development version of the documentation. Content may change without notice.
Voke Documentation
PLC / Devices

Overview

How PLCs connect to Voke — transport, topics, auth listeners, and the template-driven decode model.

What lives where

Plant — the MQTT bridge. One plant row in Voke = one MQTT client credential. The PLC connects to Mosquitto as this plant identity and publishes all telemetry under the cpi/{plantId}/ topic prefix.

Sub-devices — cabinets, meters, inverters, and batteries that sit logically underneath the plant. Sub-devices never open their own MQTT connections. The PLC collects their readings and bundles everything into a single snapshot envelope published on the plant's telemetry topic.

DeviceTemplates — signal catalogues configured in Voke admin. Each template maps either bit positions (binary signals for cabinets) or field names (numeric signals for meters, inverters, and batteries) to human-readable metric names. Template-driven decode happens entirely on the API side. The PLC emits raw bitmasks and numeric field dictionaries; Voke's SubDeviceTelemetryService resolves the template for each externalId in the snapshot and decodes signals there. The PLC firmware has no awareness of signal names or storage schemas.


Integration surface

DimensionDetail
TransportMQTT 5 over TLS
ListenersmTLS (8886 prod / 8883 dev), JWT (8887 prod / 8884 dev), PASSWORD (8885 both)
Topic prefixcpi/{plantId}/
Subtopicstelemetry, command, ack, alarm — all singular
Payload formatJSON (compact, UTF-8)
Message size limit8 KB (Mosquitto message_size_limit)
HMAC signingRequired for mTLS and JWT devices; optional for PASSWORD devices per ACL policy

Topic summary

DirectionTopicDescription
PLC → Vokecpi/{plantId}/telemetrySnapshot envelope with sub-device readings
Voke → PLCcpi/{plantId}/commandCommand envelope from Voke
PLC → Vokecpi/{plantId}/ackCommand acknowledgement
PLC → Vokecpi/{plantId}/alarmDevice-originated alarm event

Auth listeners

Three separate Mosquitto listeners handle different credential types. Pick one per plant:

ListenerPort (prod)Port (dev)Credential
mTLS88868883Client certificate (Voke PKI)
JWT88878884RS256 JWT; username = plantId
PASSWORD88858885username = plantId, password via Voke admin

All three listeners use server-side TLS. mTLS additionally requires a client certificate signed by the Voke CA. See Auth methods for a full comparison.


Architecture

Loading diagram...

The API ingestion path:

  1. PLC publishes a snapshot to cpi/{plantId}/telemetry.
  2. Mosquitto forwards it to MqttService inside the API container over the internal listener (port 1883).
  3. SubDeviceTelemetryService receives the message, batch-resolves all externalId values in devices[] to SubDevice rows, and batch-preloads their DeviceTemplate records.
  4. Each sub-device's payload is decoded using its template (bit positions for cabinets, field names for meters, inverters, and batteries).
  5. Decoded readings are written to TimescaleDB as individual telemetry rows.
  6. Decoded signals are re-broadcast over Socket.IO sub-device:telemetry to the plant:{plantId} room for live dashboard updates.
  7. For plants enrolled in ESM trading, the API forwards aggregated readings to the partner's AMQP queue.

Contract in three bullets

  • Publish snapshots to cpi/{plantId}/telemetry. Flat envelope: {ts, n, sig, timestamp, devices: [...]}.
  • Subscribe to cpi/{plantId}/command. Execute the command. Ack on cpi/{plantId}/ack.
  • Raise device-originated fault events on cpi/{plantId}/alarm.

Next steps

On this page