Skip to content

Technical Standards

MicroDCS is built around open standards for messaging, payload modeling, observability, and industrial domain semantics. This page summarizes the main standards used by the framework and explains how they are applied in the current architecture.

MQTT v5

MQTT v5 is the primary transport for event-driven communication in MicroDCS. The framework uses MQTT features not just for message delivery, but also for request-response flows, delivery coordination, scaling, and time-bounded processing.

Standard: MQTT Version 5.0

Request / Response

MQTT v5 supports request-response interaction through Response Topic and Correlation Data. The Request Response Information and Response Information fields standardize the communication channel, but not the full response-handling behavior. In practice, brokers such as Mosquitto transport these attributes without managing the response flow for the application. MicroDCS therefore creates an instance-specific response channel and subscribes to it at startup to handle error and correlation backchannels. Published request-response messages are also expected to target topics with active subscribers, which corresponds to successful delivery with PUBACK=0x00.

The MQTT Correlation Data field in request/response flows carries the CE id of the originating request event. Because a request is a root event it has no causationid, so the mapper falls back to id (see CloudEvents MQTT mapping below). The responder echoes Correlation Data back unchanged, allowing the requester to match the response to its original request.

  sequenceDiagram
  autonumber
      participant Device
      participant Device Connector
      participant Broker
      participant DCS
      Note over Device, Device Connector: Device Connector is optional
      Device Connector->>Broker: Subscribe<br/>[topic: mydevice/event]
      DCS->>Broker: Subscribe<br/>[topic: +/event]
      DCS->>Broker: Subscribe<br/>[topic: dcs/errors/<dcs_id>]
      Device->>Device Connector: Request<br/>[any protocol]
      Device Connector->>Broker: Request<br/>[topic: mydevice/event<br/>responsetopic: mydevice/command<br/>correlationdata: <cid>]
      Broker->>DCS: Request [topic: mydevice/event<br/>responsetopic: mydevice/command<br/>correlationdata: <cid>]
      DCS->>Broker: Response [topic: mydevice/command<br/>responsetopic:dcs/errors/<dcs_id><br/>correlationdata: <cid>]
      opt Error Response
        Broker->>DCS: Error Response [topic:dcs/errors/<dcs_id><br/>correlationdata: <cid>]
      end
      Broker->>Device Connector: Response [topic: mydevice/command<br/>responsetopic:dcs/errors/<dcs_id><br/>correlationdata: <cid>]
      Device Connector->>Device: Response<br/>[any protocol]

Message Expiry Interval

MQTT v5 introduced Message Expiry Interval so publishers can set a bounded lifetime for time-sensitive messages. This helps reclaim control over message flow once a message is no longer useful. Depending on timing and broker behavior, the broker may discard the message before delivery, or the receiver may discard it after inspecting the remaining interval.

  sequenceDiagram
      participant Publisher
      participant Broker
      participant Subscriber
      activate Broker
      activate Publisher
      activate Subscriber
      Subscriber->>Broker: Disconnect
      deactivate Subscriber
      Publisher->>Broker: Publish<br/>[topic: demo<br/>correlationdata: <cid><br/>messageexpiryinterval: 10]
      activate Publisher
      Publisher->>Publisher: MessageExpirationTask<br/>[correlationdata: <cid>,<br/>timer: 10]
      Note over Broker: After 10s
      Publisher->>Publisher: HandleExpiration
      deactivate Publisher
      Publisher->>Broker: Publish<br/>[topic: demo<br/>correlationdata: <cid><br/>messageexpiryinterval: 60]
      activate Publisher
      Publisher->>Publisher: MessageExpirationTask<br/>[correlationdata: <cid><br/>timer: 60]
      Note over Broker: After 30s
      Subscriber->>Broker: Connect
      activate Subscriber
      Broker->>Subscriber: Publish<br/>[topic: demo<br/>correlationdata: <cid><br/>messageexpiryinterval: 30]
      Subscriber->>Broker: Publish<br/>[topic: demo<br/>correlationdata: <cid><br/>messageexpiryinterval: 60]
      Broker->>Publisher: Publish<br/>[topic: demo<br/>correlationdata: <cid><br/>messageexpiryinterval: 60]
      Publisher->>Publisher: StopExpirationTask
      deactivate Publisher
      deactivate Subscriber
      deactivate Publisher
      deactivate Broker

Shared Subscriptions

To achieve higher availability or scale out processing across multiple container instances or MQTT clients, MicroDCS can use MQTT v5 shared subscriptions. A shared subscription is identified through a special topic-filter format: $share/{ShareName}/{filter}.

  • $share is a literal string that marks the Topic Filter as being a Shared Subscription Topic Filter.
  • {ShareName} is a character string that does not include "/", "+" or "#"
  • {filter} The remainder of the string has the same syntax and semantics as a Topic Filter in a non-shared subscription.

With QoS 1, shared subscriptions provide load balancing so each message is delivered to one client in the shared group. They do not eliminate duplicate delivery, however. Publishers may resend when acknowledgments are missing, so consumers still need deduplication based on message identity or payload semantics.

Quality of Service

The QoS level used to deliver an Application Message outbound to the Client could differ from that of the inbound Application Message.

Setting a response topic in the application sets QoS=1 (at least once delivery) where we want to make sure it arrives at the destination, otherwise its a QoS=0 (at most once delivery) notification that can be lost.

Retained Messages

MQTT retained messages allow the broker to store the last message published to a topic with the RETAIN flag set. When a new client subscribes to that topic, the broker delivers the stored message immediately — the subscriber does not need to wait for the next publish.

MicroDCS uses retained messages for the northbound MES publishing interface. The Job Order Publisher maintains per-job and per-scope retained topics so that a reconnecting MES client can recover full state without replaying the event stream.

Retained topics use MQTT v5 MessageExpiryInterval to auto-expire stale data (default 48 hours, configurable via APP_PUBLISHER_RETAINED_TTL_SECONDS). Deleting a retained topic is done by publishing a zero-byte retained message to the same topic, which instructs the broker to discard the stored message.

See Machinery Jobs – MES Northbound Publishing for the full topic layout and payload schemas.

MessagePack-RPC

MessagePack-RPC is supported as an additional transport option where a lightweight binary RPC channel is preferred. MicroDCS also supports outgoing CloudEvents over MessagePack by publishing RPC NOTIFICATION frames to connected clients.

CloudEvents

CloudEvents provides the common event envelope used across transports. It allows MicroDCS to carry typed payloads, metadata, tracing information, and delivery attributes in a consistent way.

Overview and Spec

MQTT and MessagePack

CloudEvents defines an MQTT binding, which MicroDCS uses as the basis for transport mapping.

Because MicroDCS targets MQTT v5, it implements the binding in Binary Content Mode:

  • datacontenttype is mapped to the MQTT v5 ContentType property.
  • expiryinterval is mapped to MessageExpiryInterval.
  • All other CloudEvent attributes — including id, source, subject, type, dataschema, correlationid, causationid, and entries in custommetadata — are transported as MQTT UserProperty fields using the attribute name unchanged, as required by the CloudEvents MQTT binding spec.
  • Other MQTT-specific properties are read from and written to transportmetadata.

As a secondary mapping for request/response flows, the MQTT Correlation Data property is populated with causationid if present, falling back to id for root/initiating events (causationid ?? id). This lets MQTT-native consumers match a response to its originating request without parsing UserProperty fields, while the primary CE attributes remain intact in UserProperty. The responder echoes Correlation Data back unchanged, as required by the MQTT v5 spec.

Note: despite the name similarity, the MQTT Correlation Data field does not correspond to the CE correlationid attribute. correlationid is a group-level transaction tag shared by all events in a flow and is carried exclusively as a UserProperty. Correlation Data is a per-request/response matching token that corresponds semantically to causationid.

For MessagePack transport, the CloudEvent is sent as a structured object, with custommetadata serialized into individual attributes. Transport-specific metadata is carried separately alongside the CloudEvent.

JSON Schema

JSON Schema is used to define application payload models that can be turned into typed Python dataclasses.

OpenTelemetry

OpenTelemetry provides the tracing and metrics foundation for runtime observability across handlers and processors.

IEC 61131-3 SFC

The SFC recipe schema uses IEC 61131-3 Sequential Function Chart terminology — steps, transitions, action qualifiers (N, P, S, R, L, D, etc.), and selection/simultaneous divergence — to define machine-readable recipes without the graphical/PLC baggage of PLCopen TC6 XML. See SFC Engine for the recipe format and engine architecture.