Industrial connectors for Unreal Engine 5.8
Plant data,
as Blueprint tags.
Five connectors that read live values from the equipment you already run — PLCs, brokers and OPC UA servers — and publish them into Unreal as named tags you can bind to. No middleware, no bridge service, no polling loop to write.
| Tag | Value | Quality | Updated |
|---|
The connectors
Pick the protocol your plant speaks
Each is a separate product and installs on its own. Nothing else to buy, nothing else to enable.
Modbus TCP
FC 1 · 2 · 3 · 4 · 5 · 6
Reads coils, discrete inputs and registers straight off a PLC, and writes single coils and registers back. Framing is hand-rolled over Unreal's sockets.
DetailsREST
JSON over HTTP
Polls an HTTP endpoint and flattens the JSON into tags — nested objects become dotted names, arrays become indexed ones.
DetailsMQTT
Topics · Sparkplug B
Subscribes to broker topics and derives tag names from the topic hierarchy. Decodes Sparkplug B payloads, resolving metric aliases against birth messages.
DetailsAMQP
0-9-1 · RabbitMQ
Consumes a queue and publishes each message as tags, taking the tag name from the routing key.
DetailsOPC UA
Subscriptions · Sign & Encrypt
Subscribes to server nodes with polling as a fallback, and supports encrypted channels with client certificate identity.
DetailsIn every connector
The parts nobody enjoys writing twice
Tag registry
A Game Instance Subsystem holding every value the connector has seen. Bind On Tag Updated, or read a tag by name. Connectors are kept alive by the registry, so one created in a Blueprint survives without being stored in a variable.
Reconnect that behaves
Fixed or exponential backoff with a delay ceiling, an optional attempt limit, and jitter — so a hundred clients pointed at one PLC don't retry in lockstep as it reboots. An outage reports twice: when it starts and when it gives up.
Credentials by reference
A config stores where a secret lives — an environment variable name or a file path — never the secret. Configs get exported, diffed and committed; a password inside one leaks the first time that happens.
Deduplication
Suppress broadcasts when a value hasn't changed, with a numeric deadband to absorb sensor noise. The deadband compares against the last broadcast value, so a reading creeping just under the threshold still reports eventually.
Writing, not just reading
Every connector sends as well as receives — Modbus writes registers and coils, OPC UA writes nodes, MQTT and AMQP publish, REST issues a request on demand. Writes are queued from the game thread and executed on the worker, so a Blueprint never blocks on a network round trip, and the call reports whether it was accepted rather than pretending it was delivered.
Runtime log level
Set verbosity from Blueprint using the familiar debug/info/warn/error/critical names. Works in packaged builds, where there is no console to type into.
Readable source
Full C++ ships with every connector, commented to explain why rather than what. Automated tests come with it — run them yourself from the Session Frontend.
Connector
Modbus TCP
Polls coils, discrete inputs, holding registers and input registers from a Modbus TCP device using a register map you define, and publishes each entry as a tag. Writes single coils and single registers back.
| Function codes | Read 0x01 0x02 0x03 0x04, write 0x05 0x06 |
|---|---|
| Framing | MBAP over Unreal's own sockets |
| Data types | UInt16, Int16, UInt32, Int32, Float32, with configurable word order |
| Read strategy | Adjacent registers coalesced into as few requests as the device allows |
| Writes | Queued from the game thread, executed on the worker, echo verified |
| Authentication | None — the protocol carries no identity |
| Third-party code | None redistributed |
// One entry in the register map Address 2 // zero-based protocol address Type Float32 Word Order HighFirst Tag Name oven.temp_c Function ReadHoldingRegisters
40001 is address 0, and the conversion is subtract 40001 rather than 40000. Vendors are inconsistent about this, and some document the raw address already. If every tag reads like its neighbour, the base is the first thing to check.Getting started
- Enable the plugin. Install it from Fab, then in the editor open Edit → Plugins, search for Digital Factory Modbus, enable it and restart.
- Start the simulator. In a console, from the plugin's
Content/Python/folder, runpython modbus_sim.py. It listens on127.0.0.1:502and needs nothing but Python 3. For a Fab install, the plugin folder is under your engine'sEngine/Plugins/Marketplace/. - Open the Level Blueprint and, from
Event BeginPlay, add Get Digital Factory Modbus Data Subsystem. That is the tag registry: every value the connector reads lands there. - Bind the two events before connecting, so neither the first value nor a failure goes unseen. Bind Event to On Tag Updated with a custom event that breaks the tag and prints its
Raw Tag Nameand theTo Display String (Digital Factory Value)of itsValue. Then Bind Event to On Connector Error and print the message — every diagnostic arrives there. - Create and connect. Add Make Digital Factory Modbus Config, add one entry to
Registersand give it aTag Name— every other default already matches the simulator's register 0. Feed it to Create Modbus Connector, then call Connect and print its return value:falsemeans the config was unusable, and the log says why. - Press Play.
counterprints once a second, climbing by one — the same number the simulator's console shows it serving.
// Level Blueprint, in execution order Event BeginPlay → Get Digital Factory Modbus Data Subsystem → Bind Event to On Tag Updated → Bind Event to On Connector Error → Create Modbus Connector ← Make … Modbus Config → Connect → Print String // the On Tag Updated event Break Digital Factory Modbus Tag Value → Raw Tag Name, To Display String (Value) → Print String
// Make Digital Factory Modbus Config Host 127.0.0.1 default Port 502 default Registers[0] Tag Name counter Function ReadHoldingRegisters default Address 0 default Data Type UInt16 default
Testing without hardware
Content/Python/modbus_sim.py ships with the plugin: a Python server that serves changing values and prints what it served — decoded back out of the response bytes rather than recomputed, so the console and Unreal genuinely agree rather than merely appearing to. Standard library only, so there is nothing to install.
It answers reads and writes both. A written value is remembered from then on, so the register stops moving and reads back what you wrote: a simulator that accepted a write and carried on generating would be indistinguishable from one that discarded it.
Public simulators such as diagslave also work, but their register tables start at zero and stay there — which looks exactly like a broken decode.
python modbus_sim.py # listening on 127.0.0.1:502 # holding / input registers 0 UInt16 counter, +1/s 1 Int16 sine, -1000..1000 2-3 Float32 20.0..25.0, high word first 4-5 UInt32 +10/s, high word first # coils / discrete inputs 0 toggles once per second 1 always on 2 always off
Screenshots
Captured against Content/Python/modbus_sim.py, which ships with this connector — so every frame below is reproducible on your own machine with nothing else installed.
What this connector doesn't do
- Win64 only. That is what the descriptor declares, and the only platform built or tested.
- Discrete inputs and input registers are read-only. That is the protocol, not the plugin. Writes cover single coils (
0x05) and single holding registers (0x06). - Modbus TCP carries no identity. There is no authentication and no encryption in the protocol to expose, so anyone who can reach the port can read and write. Put it on a segment you trust.
- Tag quality stays
Unknown. Modbus has no quality field, and reportingGoodwould be inventing data. Nothing setsStaleyet either, so a device that stops answering leaves its last values sitting there looking current. - Values are stored as
double. No practical limit at 16 and 32 bits — noted because it is the same storage every connector in the range uses.
Support
Questions, bug reports and licence queries go to info@edelmeier.com. Name the connector — Digital Factory Modbus TCP — and your engine version. The five are sold, versioned and updated separately, so which one you have changes the answer.
Connector
REST
Polls a JSON-over-HTTP endpoint on an interval and flattens the response into tags. For the MES, historian or line-controller that already exposes an API.
| Transport | Unreal's own HTTP stack |
|---|---|
| Flattening | Nested objects to dotted names, arrays to bracketed indices |
| Root path | Scope the walk to a nested object with a dotted path |
| Nulls | Published as an empty value, never dropped — so a source that stops reporting is distinguishable from one that hasn't changed |
| Sending | Send Request — one GET, POST or PUT on demand, outside the polling loop, reusing the configured endpoint and credentials |
| Authentication | Basic, Bearer token, or API key in a named header |
| Third-party code | None redistributed |
// Response { "line1": { "sensors": [ { "temp": 20.4 } ], "vibration": null } } // Tags produced line1.sensors[0].temp 20.4 line1.vibration (empty, quality Unknown)
Unknown rather than Bad: plenty of systems use null to mean something specific — a drive at standstill, a probe not fitted — and calling that a fault would be our inference, not the source's statement.Getting started
- Enable the plugin. Install it from Fab, then in the editor open Edit → Plugins, search for Digital Factory REST, enable it and restart.
- Start the simulator. In a console, from the plugin's
Content/Python/folder, runpython rest_sim.py. It serves onhttp://127.0.0.1:18080and needs nothing but Python 3. For a Fab install, the plugin folder is under your engine'sEngine/Plugins/Marketplace/. - Open the Level Blueprint and, from
Event BeginPlay, add Get Digital Factory RESTData Subsystem. That is the tag registry: every value the connector reads lands there. - Bind the two events before connecting, so neither the first value nor a failure goes unseen. Bind Event to On Tag Updated with a custom event that breaks the tag and prints its
Raw Tag Nameand theTo Display String (Digital Factory Value)of itsValue. Then Bind Event to On Connector Error and print the message — every diagnostic arrives there. - Create and connect. Add Make Digital Factory RESTConfig and set
Urltohttp://127.0.0.1:18080/api/telemetry—GET, a one-second poll and no credentials are all defaults. Feed it to Create RESTConnector, then call Connect and print its return value:falsemeans the config was unusable, and the log says why. - Press Play. Tags such as
plant.line1.sensors[0].tempandplant.line1.oven.setpoint_cprint on every poll. Wait a minute andplant.line2.vibration_mm_sgoes empty for eight seconds while its neighbours carry on — that is a reported null, working.
// Level Blueprint, in execution order Event BeginPlay → Get Digital Factory RESTData Subsystem → Bind Event to On Tag Updated → Bind Event to On Connector Error → Create RESTConnector ← Make … RESTConfig → Connect → Print String // the On Tag Updated event Break Digital Factory RESTTag Value → Raw Tag Name, To Display String (Value) → Print String
// Make Digital Factory RESTConfig Url http://127.0.0.1:18080/api/telemetry Verb GET default Poll Interval Seconds 1.0 default Credentials Scheme None default
Testing without a server of your own
Content/Python/rest_sim.py ships with the plugin: a JSON endpoint serving changing plant telemetry. Standard library only, so there is nothing to install on a machine you would rather not install anything on.
It is built around the awkward cases rather than the tidy ones — nested objects and an array for dotted and indexed names, every value type in one payload, a nested path worth aiming Response Root Path at, and optional bearer-token auth that refuses anything else with a 401 naming the header it wanted.
One sensor reports null for eight seconds each minute while the rest of the document keeps going, so you can watch a single tag go empty beside its neighbours. That case is invisible in a connector that drops nulls, which is exactly why it is worth being able to produce on demand.
Any other JSON endpoint works too. Prefer this one for anything you intend to keep: a public API rate-limits, changes its schema without telling you, and eventually stops existing.
# no auth python rest_sim.py # require Authorization: Bearer s3cret python rest_sim.py --token s3cret # listening on http://127.0.0.1:18080 # endpoints / the whole document /api/telemetry the same, for a config that wants a path /api/setpoint POST or PUT {"value": 214.5}; comes back in the next poll as plant.line1.oven.setpoint_c /health {"ok": true}, no auth # a scoped walk: set Response Root # Path to plant.line1 and the prefix # disappears from every tag name
Screenshots
Captured against Content/Python/rest_sim.py, which ships with this connector — so every frame below is reproducible on your own machine with nothing else installed.
What this connector doesn't do
- Win64 only. That is what the descriptor declares, and the only platform built or tested.
- Polling only. No websockets, no server-sent events. The connector re-reads on the interval you set, so the shortest delay you can have is that interval.
Response Root Pathscopes to an object, not a value. It narrows the walk to a sub-document; it cannot pick out a single leaf.- Tag quality stays
Unknown. HTTP carries no quality field. Nothing setsStaleyet, so an endpoint that stops changing and one that stops responding look alike. - Values are stored as
double. JSON integers above 253 lose precision — worth knowing if a payload carries identifiers or counters that large.
Support
Questions, bug reports and licence queries go to info@edelmeier.com. Name the connector — Digital Factory REST — and your engine version. The five are sold, versioned and updated separately, so which one you have changes the answer.
Connector
MQTT
Subscribes to broker topics and publishes arriving messages as tags, deriving tag names from the topic hierarchy. Decodes Sparkplug B payloads where your edge nodes publish them.
| Client | Eclipse Paho MQTT C, under the Eclipse Distribution License 1.0 |
|---|---|
| Payload formats | Raw, JSON, and Sparkplug B |
| Sparkplug B | Metric aliases resolved against birth messages; sequence gaps reported; alias table dropped when a node reports death |
| Tag naming | Group, node, device and metric — so two devices publishing the same metric name don't collide |
| Publishing | Publish and Publish Bytes — topic, payload, QoS 0–2, optional retain |
| Authentication | Username and password |
| Encryption | None in this release |
// Subscribe to the whole namespace, not just data Topic Filter spBv1.0/# Payload Format SparkplugB // DDATA carries an alias, never a name. // Names arrive only in birth messages, so // subscribing to data alone leaves every // value permanently unidentifiable.
Getting started
- Enable the plugin. Install it from Fab, then in the editor open Edit → Plugins, search for Digital Factory MQTT, enable it and restart.
- Start a broker and publish one message. Any MQTT broker works; Eclipse Mosquitto is the easiest, and on Windows its installer registers it as a service, so it may already be running. Publish with the retain flag,
-r, as shown opposite: MQTT is push-only, so nothing arrives until something publishes, and a retained message is replayed to the connector the moment it subscribes. - Open the Level Blueprint and, from
Event BeginPlay, add Get Digital Factory MQTTData Subsystem. That is the tag registry: every value the connector receives lands there. - Bind the two events before connecting, so neither the first value nor a failure goes unseen. Bind Event to On Tag Updated with a custom event that breaks the tag and prints its
Raw Tag Nameand theTo Display String (Digital Factory Value)of itsValue. Then Bind Event to On Connector Error and print the message — every diagnostic arrives there. - Create and connect. Add Make Digital Factory MQTTConfig, add one entry to
Topicsand set itsTopic Filtertodfp/test/#— the broker addresstcp://127.0.0.1:1883and theJsonpayload format are defaults. Feed it to Create MQTTConnector, then call Connect and print its return value:falsemeans the config was unusable — an emptyTopic Filteris the usual cause — and the log says why. - Press Play.
dfp.test.line1.tempprints21.5. Publish todfp/test/line2and a second set of tags appears with no change to the config — that is the wildcard fanning out.
Then Sparkplug B. Add a second entry to Topics with Topic Filter spBv1.0/# and Payload Format SparkplugB, and from the plugin's Content/Python/ folder run python sparkplug_sim.py. It publishes real birth and data messages through mosquitto_pub, so that has to be on your PATH. Expect PlantA.Edge1.Press01.Pressure, .Cycles and .Running — names resolved from aliases the data messages never spell out. For a Fab install, the plugin folder is under your engine's Engine/Plugins/Marketplace/.
# retained, so it replays when the connector subscribes mosquitto_pub -r -t dfp/test/line1 -m "{\"temp\":21.5}" # arrives as dfp.test.line1.temp 21.5
// Level Blueprint, in execution order Event BeginPlay → Get Digital Factory MQTTData Subsystem → Bind Event to On Tag Updated → Bind Event to On Connector Error → Create MQTTConnector ← Make … MQTTConfig → Connect → Print String // the On Tag Updated event Break Digital Factory MQTTTag Value → Raw Tag Name, To Display String (Value) → Print String
// Make Digital Factory MQTTConfig Server Uri tcp://127.0.0.1:1883 default Topics[0] Topic Filter dfp/test/# Payload Format Json default Topics[1] for Sparkplug B Topic Filter spBv1.0/# Payload Format SparkplugB
Screenshots
Captured against Eclipse Mosquitto, a third-party broker, with Sparkplug payloads produced by Content/Python/sparkplug_sim.py, which ships with this connector. Mosquitto is not included and is not required — any MQTT broker will do.
What this connector doesn't do
- Win64 only. That is what the descriptor declares, and the only platform built or tested.
- No TLS.
ssl://fails outright: no TLS backend is compiled, so credentials and payloads cross the wire in the clear. Fine against a broker on the same machine, unsuitable for a plant network. - Sparkplug B is decode-only. Reading works; issuing
NCMDorDCMDdoes not, because that needs a protobuf encoder and this release ships only a decoder. Raw MQTT publishing is available on the same connector — it is Sparkplug's command semantics specifically that are absent. - With
Clean Sessionon, QoS 1 and 2 protect a live connection only. Queuing across a disconnect needsClean Sessionoff and a fixedClient Id; a generated one gets a new queue every time. - Tag quality stays
Unknown. MQTT carries no quality field. Nothing setsStaleyet, so a topic that goes quiet keeps its last value. - Values are stored as
double. Sparkpluglongmetrics above 253 lose precision.
Support
Questions, bug reports and licence queries go to info@edelmeier.com. Name the connector — Digital Factory MQTT — and your engine version. The five are sold, versioned and updated separately, so which one you have changes the answer.
Connector
AMQP
Consumes a queue on a RabbitMQ broker and publishes each message as tags, taking the tag name from the message's routing key.
| Protocol version | AMQP 0-9-1 |
|---|---|
| Library | rabbitmq-c, under the MIT licence |
| Model | Consumes an existing queue; declares no queues or exchanges of its own |
| Payload formats | Raw and JSON |
| Publishing | Publish — exchange, routing key, body, optional persistence |
| Acknowledgement | Automatic, or manual with a prefetch limit when losing a message matters |
| Authentication | Username and password |
| Encryption | None in this release — TLS sources are excluded from the build entirely |
Getting started
- Enable the plugin. Install it from Fab, then in the editor open Edit → Plugins, search for Digital Factory AMQP, enable it and restart.
- Start RabbitMQ and give it a queue. RabbitMQ is not included; Docker is the quickest way to run it, as shown opposite. Then, from the plugin's
Content/Python/folder, runpython amqp_setup.py: it creates the queuedfp.tags, binds it forline1.#and publishes test messages into it. They wait in the queue, so it does not matter that the connector starts later. The connector itself never declares queues — in a plant, that belongs to whoever runs the broker. For a Fab install, the plugin folder is under your engine'sEngine/Plugins/Marketplace/. - Open the Level Blueprint and, from
Event BeginPlay, add Get Digital Factory AMQPData Subsystem. That is the tag registry: every value the connector consumes lands there. - Bind the two events before connecting, so neither the first value nor a failure goes unseen. Bind Event to On Tag Updated with a custom event that breaks the tag and prints its
Raw Tag Nameand theTo Display String (Digital Factory Value)of itsValue. Then Bind Event to On Connector Error and print the message — every diagnostic arrives there. - Create and connect. Add Make Digital Factory AMQPConfig, set
Queue Nametodfp.tags, and underCredentialschooseUsername Passwordwith userdfpand the secret shown opposite. Host, port, virtual host and theJsonpayload format are defaults. Feed it to Create AMQPConnector, then call Connect and print its return value:falsemeans the config was unusable, and the log says why. - Press Play.
line1.machine2.temp,line1.machine2.okandline1.machine3.tempprint — the routing key and the JSON keys, joined — and the queue depth in RabbitMQ's management page athttp://localhost:15672drops to zero.
guest account from anywhere but localhost, and a container reached through a published port arrives from Docker's own network — so guest fails exactly like a wrong password. That is why the container is started with a dfp user. Inline Development Only is for this first run; for anything real, set Source to Environment Variable and put the variable's name in Value.# one command docker run -d --name dfp-rabbit -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=dfp -e RABBITMQ_DEFAULT_PASS=dfp rabbitmq:3-management # then, from Content/Python python amqp_setup.py
// Level Blueprint, in execution order Event BeginPlay → Get Digital Factory AMQPData Subsystem → Bind Event to On Tag Updated → Bind Event to On Connector Error → Create AMQPConnector ← Make … AMQPConfig → Connect → Print String // the On Tag Updated event Break Digital Factory AMQPTag Value → Raw Tag Name, To Display String (Value) → Print String
// Make Digital Factory AMQPConfig Host 127.0.0.1 default Port 5672 default Virtual Host / default Queue Name dfp.tags Payload Format Json default Credentials Scheme Username Password Username dfp Secret Source Inline Development Only Value dfp
Screenshots
Captured against RabbitMQ, a third-party broker, with the queue and messages set up by Content/Python/amqp_setup.py, which ships with this connector. RabbitMQ is not included and is not required — though it is the broker this connector targets, since AMQP 0-9-1 is what it speaks.
What this connector doesn't do
- Win64 only. That is what the descriptor declares, and the only platform built or tested.
- This is AMQP 0-9-1, not AMQP 1.0. It speaks to RabbitMQ. It cannot talk to Azure Service Bus, Solace or IBM MQ, which are 1.0 — a different protocol that happens to share a name.
- No TLS. Credentials cross the wire in the clear via SASL PLAIN. Same caveat as MQTT: local broker fine, plant network no.
- Publishing returns “queued”, not “delivered”. Publisher confirms are not enabled, so a successful return means the broker accepted the frame, not that anything consumed it.
- Tag quality stays
Unknown. AMQP carries no quality field. Nothing setsStaleyet, so a queue that stops delivering keeps its last values. - Values are stored as
double. Integers above 253 in a JSON body lose precision.
Support
Questions, bug reports and licence queries go to info@edelmeier.com. Name the connector — Digital Factory AMQP — and your engine version. The five are sold, versioned and updated separately, so which one you have changes the answer.
Connector
OPC UA
Connects to OPC UA servers and publishes node values as tags. Subscribes by default, with polling available for servers that limit subscription counts. Implements an OPC UA client using the open62541 stack.
| Stack | open62541 v1.5.6, under MPL-2.0 |
|---|---|
| Data delivery | Subscriptions with configurable publishing interval, sampling interval and queue size; polling as a fallback |
| Security modes | None, Sign, and Sign & Encrypt |
| Security policies | Basic256Sha256, Aes128Sha256RsaOaep, Aes256Sha256RsaPss |
| Writing | Write Bool, Write Number, Write String — the numeric type is stated by the caller, because the server checks it |
| Quality | Mapped from the server's status code by severity, including the informational Good_ sub-codes |
| Identity | Anonymous, or username and password; client certificate with trust list and optional revocation lists |
| Certificates | Generate Self Signed Certificate in Blueprint — OPC UA authenticates both ends, so a client needs one of its own |
| Crypto library | The OpenSSL that ships with Unreal Engine; nothing new is redistributed |
| Value conversion | Scalars only; arrays and structs are skipped with a warning |
// Use the endpoint URL your server advertises, // verbatim -- including the path. Ports vary by // product and version; do not assume a default. Endpoint opc.tcp://HOST:PORT/PATH Security SignAndEncrypt Policy Basic256Sha256 Node Id ns=3;i=1001
Basic128Rsa15 and Basic256 are absent by choice — the stack is built without them. Password-protected private keys are also unsupported, since the password would have to live somewhere the config could reach it, which defeats protecting the key.Getting started
- Enable the plugin. Install it from Fab, then in the editor open Edit → Plugins, search for Digital Factory OPC UA, enable it and restart.
- Start a server. Any OPC UA server works; the free Prosys OPC UA Simulation Server is the easiest, and is not included. Recent versions ship with unencrypted endpoints switched off, so in its Expert Mode enable
SecurityPolicy Nonefor this first connection. Note the endpoint it reports — typicallyopc.tcp://your-host-name:53530/OPCUA/SimulationServer. - Open the Level Blueprint and, from
Event BeginPlay, add Get Digital Factory OPCUAData Subsystem. That is the tag registry: every value the connector reads lands there. - Bind the two events before connecting, so neither the first value nor a failure goes unseen. Bind Event to On Tag Updated with a custom event that breaks the tag and prints its
Raw Tag Nameand theTo Display String (Digital Factory Value)of itsValue. Then Bind Event to On Connector Error and print the message — every diagnostic arrives there. - Create and connect. Add Make Digital Factory OPCUAConfig and paste the server's endpoint into
Endpoint Url, host name and all — notlocalhost. Add one entry toNodes: namespace3, identifier typeNumeric, identifier1001, which is Prosys' counter. Security policyNoneand anonymous credentials are defaults. Feed it to Create OPCUAConnector, then call Connect and print its return value:falsemeans the config was unusable, and the log says why. - Press Play.
counterprints each time the server's value changes, with qualityGood— the one connector whose quality comes from the source rather than stayingUnknown.
Sign & Encrypt needs a client certificate and a trust exchange with the server — generate it with Generate Self Signed Certificate, let the first connection be rejected, then trust it on the server. The user guide that ships with the plugin walks through it under Getting connected the first time, and the screenshots below show it against this same server.// Level Blueprint, in execution order Event BeginPlay → Get Digital Factory OPCUAData Subsystem → Bind Event to On Tag Updated → Bind Event to On Connector Error → Create OPCUAConnector ← Make … OPCUAConfig → Connect → Print String // the On Tag Updated event Break Digital Factory OPCUATag Value → Raw Tag Name, To Display String (Value) → Print String
// Make Digital Factory OPCUAConfig Endpoint Url opc.tcp://HOST:53530/OPCUA/SimulationServer Security Policy None default Credentials Scheme None default Nodes[0] Tag Name counter Namespace Index 3 default is 2 Identifier Type Numeric default is String Identifier 1001
Screenshots
Captured against the Prosys OPC UA Simulation Server, a third-party product of Prosys OPC Ltd. It is not included with this connector and is not required to use it — any OPC UA server will do. It appears here because the screenshots show a real session with a real server rather than a mock-up, and the certificate trust dialog in particular is that server's own.
What this connector doesn't do
- Win64 only. That is what the descriptor declares, and the only platform built or tested.
- Scalars only. Arrays and structures are skipped with a warning rather than half-converted.
- Values are stored as
double.Int64above 253 loses precision. - Quality is real here, but
Staleis not. This is the one connector that reports quality properly, mapped from the server's status code. What it still does not do is notice absence: nothing setsStale, so a node that stops arriving keeps its last value and its last quality.
Support
Questions, bug reports and licence queries go to info@edelmeier.com. Name the connector — Digital Factory OPC UA — and your engine version. The five are sold, versioned and updated separately, so which one you have changes the answer.
Licensing
What you're redistributing
Every connector ships full C++ source and a licence inventory naming each third-party component, its version, its upstream commit and its terms. Nothing here requires your project to be licensed under anything.
| Connector | Third-party component | Licence |
|---|---|---|
| Modbus TCP | None | — |
| REST | None | — |
| AMQP | rabbitmq-c | MIT |
| MQTT | Eclipse Paho MQTT C | Eclipse Distribution License 1.0 (BSD-3-Clause) |
| OPC UA | open62541 | MPL-2.0 — file-level, does not extend to your code |
No GPL or LGPL anywhere
Audited specifically, because copyleft of that strength would prevent redistribution inside a proprietary project at all. Two licence documents in the tree contain the words "GNU General Public License" — both inside a definition of the term "Secondary License", not as a dependency.
MPL-2.0 is file-level
Its obligations attach to the open62541 files themselves and do not extend to code that merely links against them — the decisive difference from GPL. The sources ship unmodified, with SHA-256 hashes published so you can verify that.
Built with AI assistance
A material portion of the C++ was written with a large language model, and the Fab listings are tagged accordingly. Every connector has been verified against real servers and brokers, not only against its own tests.