Skip to content

Connectors

A connector backs data model nodes with a real system. The node API does not change: a variable is still read with read(), written with write() and subscribed to in the same way, whether it holds a simulated value or maps onto an OPC UA node or an MQTT topic.

This is what lets control software developed against a simulated plant be pointed at real equipment without being rewritten.

Two connectors are implemented: OPC UA and MQTT.

How a model uses one

A model declares its connectors at the top level, then attaches nodes to them. A node inherits connector_name from its ancestors, so tagging the root folder is usually enough. remote_resource_spec says where on the remote system that particular node lives.

connectors:
  - !!OpcUaConnector
    name: "opc_ua_server"
    ip: "127.0.0.1"
    port: 4840

root:
  !!FolderNode
  name: "Objects"
  connector_name: "opc_ua_server"
  children:
    - !!NumericalVariableNode
      name: "Temperature"
      default_value: 20.0
    - !!BooleanVariableNode
      name: "StartCommand"
      default_value: false
      remote_resource_spec:
        !!OpcUaRemoteResourceSpec
        node_id: "ns=2;s=StartCommand"

OPC UA

Variables map to OPC UA nodes; reads and writes are performed against them, and method calls are performed against OPC UA method nodes.

The connector is built on asyncua, pinned at 1.1.6.

Runnable examples, including an OPC UA server to test against, are in examples/opcua/ and examples/ice/.

MQTT

Variables map to MQTT topics. A read returns the last payload received on the subscribe topic; a write publishes to the publish topic.

connectors:
  - !!MqttConnector
    name: "mqtt_broker"
    ip: "127.0.0.1"
    port: 1883
    topic_prefix: "machines/boiler-1"
    payload_codec: "string"

root:
  !!FolderNode
  name: "Objects"
  connector_name: "mqtt_broker"
  children:
    - !!BooleanVariableNode
      name: "StartCommand"
      default_value: false
      remote_resource_spec:
        !!MqttRemoteResourceSpec
        subscribe_topic: "plant/line-1/start/state"
        publish_topic: "plant/line-1/start/set"

Payloads are encoded with one of three codecs, selected by payload_codec:

Codec Behaviour
string (default) Strings, integers, floats and booleans as UTF-8 scalars. Values received on a subscription are parsed according to the data model node's type.
json JSON.
msgpack MessagePack.

For anything else, MqttConnector accepts payload_serializer and payload_deserializer callables from Python.

Beyond ip, port and topic_prefix, the connector accepts username, password, client_id, keepalive, qos and retain, and each of the connection settings has an _env_var variant (ip_env_var, port_env_var, username_env_var, password_env_var) that reads the value from an environment variable instead — so credentials need not be committed alongside the model.

Two current limitations

Warning

Method calls are not supported by the MQTT connector. A model reached over MQTT can expose variables, not operations.

Topic wildcards are not supported in remote resource specs. Each node names its own topics.

Choosing between them

OPC UA is the richer fit: it has a node model close to the data model's own, and it carries methods as well as variables. MQTT suits equipment and gateways that already publish to a broker, where only telemetry and simple commands are needed.

Both connectors are asynchronous underneath, and both present the same synchronous node API.