A Windows desktop application that bridges legacy OPC DA (Data Access, COM/DCOM-based) servers to modern OPC UA (Unified Architecture, TCP-based) clients. It sits between an existing OPC DA server (e.g. an HMI, SCADA, or PLC driver package) and any OPC UA client, exposing the DA tags as UA variables — read, write, and status included — without requiring changes to the DA side.
This is useful when you have older industrial equipment or software that only speaks OPC DA (which requires DCOM and typically only works machine-to-machine on the same Windows domain) and you want to reach it from modern OPC UA clients, historians, or cloud gateways that don't support DCOM.
The application is a single-file Python/PyQt5 GUI (opc_da2ua.py) with two
main halves:
- OPC UA server — an asyncua
server running on a background thread with its own asyncio event loop. It
exposes one OPC UA address-space node tree per configured DA server, with
a
Folder_*sub-node per tag folder and one variable per tag. - OPC DA worker threads — one dedicated thread per configured DA server,
using OpenOPC-DA (COM/DCOM) to
connect to that server and read/write tags. Each worker owns its own COM
apartment (
pythoncom.CoInitialize), since COM objects are thread-affine.
Data flows in both directions:
- DA → UA: each worker polls (or subscribes to) its tags on an interval, and pushes changed values directly into the UA address space in batches.
- UA → DA: a background monitor task watches the UA address space for values written by external UA clients and queues them for the corresponding DA worker to write back to the DA server. A short-lived "recently written by DA" cache prevents the gateway from echoing its own DA→UA updates back to DA as if they were external writes.
Other notable behavior:
- Tag data types are auto-detected: each DA server is probed once at
startup (one read per tag) to pick a matching OPC UA
VariantType(Boolean/Int64/Double/String/DateTime), falling back to Double if the probe fails. - DA servers can be polled at a fixed interval ("Polling" mode) or via DA-side change subscriptions ("Subscription" mode), configurable per gateway instance in Preferences.
- Connections are periodically and automatically re-established (default every 1.5 hours) to avoid long-lived DCOM connections going stale; broken connections are retried automatically every 5 seconds.
- Optional SSL/TLS on the OPC UA endpoint using a self-signed certificate that's generated automatically on first run (regenerable from Preferences).
- Idle OPC UA client sessions are reaped automatically, and periodic garbage collection + memory diagnostics run in the background — useful for long-running, unattended deployments with large tag counts.
- All activity is logged to both a rotatable log file and a log pane in the GUI, with configurable verbosity.
- Tree view (top) — hierarchical view of configured DA servers → folders → tags, with live connection status per server.
- Gateway Log (bottom) — live log output, mirrored to the log file.
- Start / Stop Gateway buttons — start or stop the OPC UA server and all DA worker threads.
- File menu — load/save the tag configuration as CSV.
- Edit menu — add/edit/delete servers and tags; open Preferences.
- Toolbar — quick access to the above, plus a manual "Force GC" action for memory diagnostics.
- Double-clicking a tag in the tree opens a DA Monitor dialog: a live, independent view of that tag's raw value/quality/timestamp straight from the DA server, useful for diagnosing whether a data problem is on the DA side or in the gateway itself.
- OS: Windows Server 2012 R2 or later (also runs on Windows 8.1, 10, 11,
and Server 2016/2019/2022). The published build (see Releases/
dist) is a single 32-bit executable compatible with all of the above. - OPC DA server access: the OPC DA server you want to bridge must already be installed and running, and reachable via DCOM from the machine running this gateway (same machine, or DCOM configured for remote access across machines/domains).
- 32-bit Python 3.12, if running/building from source rather than the
prebuilt executable. 32-bit is required because the OPC DA COM interface
(
OpenOPC-DA) only works with a 32-bit process. - OPC DA servers are registered COM components — the gateway must run on a machine where that COM registration is visible (typically the same machine as the DA server, or one where the DA vendor's client components are installed).
If you have the built opc_da2ua.exe (see build.ps1 below), no Python
install is required on the target machine:
- Copy
opc_da2ua.exeto the target Windows machine. - Run it. On first launch it unpacks to a temporary folder, so allow a few extra seconds of startup time.
- The app creates
gateway.log,gateway_prefs.json, and (if SSL is enabled)server_cert.pem/server_key.pemnext to wherever it's run from — run it from a writable, persistent folder rather than a temporary/Downloads-type location.
# One-time: create the venv and install dependencies (32-bit Python 3.12 required)
.\build.ps1 venv
# Activate the venv
.\venv\Scripts\Activate.ps1
# Run the app
python opc_da2ua.pybuild.ps1 looks for a 32-bit Python 3.12 install at one of:
%LOCALAPPDATA%\Programs\Python\Python312-32\python.exeC:\Python312-32\python.exeC:\Program Files (x86)\Python312-32\python.exe- or the path in the
PYTHON312_32_EXEenvironment variable (useful for CI)
If it's not found, install the 32-bit (x86) Python 3.12 installer from python.org, selecting "Install for all users" and "Add Python 3.12 to PATH".
.\build.ps1 # builds venv (if needed) + dist\opc_da2ua.exe via Nuitka
.\build.ps1 clean # removes venv/ and build outputThe build uses Nuitka --onefile mode to produce a
single self-contained .exe in dist\.
You can configure everything from the GUI (Edit → Add Server…, Edit →
Add Tag…), or prepare a CSV up front and load it with File → Load
CSV…. The CSV format (default filename tags.csv, loaded automatically on
startup if present) has three columns:
server_name,folder,da_tag
Matrikon.OPC.Simulation.1,ProcessData,Random.Real4
Matrikon.OPC.Simulation.1,ProcessData,Random.Int4
Matrikon.OPC.Simulation.1,Alarms,Bucket Brigade.Int4server_name— the DA server's COM ProgID, not a hostname/IP (e.g.Matrikon.OPC.Simulation.1,KEPware.KEPServerEX.V4, or a vendor-specific gateway ID). You need to know this ahead of time from the DA server's documentation or its own configuration tool.folder— an arbitrary grouping label; each distinct folder becomes its own OPC UA namespace/sub-node under that server. Defaults toDefaultif left blank.da_tag— the exact DA item/tag name as exposed by that server.
Use File → Save CSV / Save CSV As… to persist changes you make in the GUI back to a CSV file.
Once at least one server/tag is configured, click ▶ Start Gateway. This:
- Generates a self-signed certificate on first run (if not already present).
- Starts the OPC UA server at
opc.tcp://0.0.0.0:4840/freeopcua/server/. - Probes each configured DA server to determine tag types.
- Starts one background worker thread per DA server to bridge data.
Connect any OPC UA client (e.g. UaExpert) to opc.tcp://<host>:4840/freeopcua/server/
to browse and interact with the bridged tags.
Accessible via Edit → Preferences… (or Ctrl+,):
| Setting | Description |
|---|---|
| Log level | Info / Warning / Error / Verbose (Verbose adds per-request OPC UA protocol tracing) |
| Log every OPC UA request | Extra tracing for Browse/Read/Write/Subscribe, off by default (can flood the log) |
| Log file | Path to the log file (default gateway.log) |
| Enable SSL/TLS | Encrypts the OPC UA endpoint with a self-signed cert (requires restarting the gateway); certificate can be regenerated from this dialog |
| DA mode | Polling (reads all tags on an interval) or Subscription (DA server pushes changes) |
| Poll interval | Seconds between polling reads / subscription check interval (default 0.5s) |
| Chunk size | Number of tags read per DA batch (default 500) |
| Connection reinit interval | Seconds between forced DA reconnects, 0 to disable (default 5400 = 1.5h) |
| Max log lines in GUI | Caps the log pane to avoid unbounded memory growth on long runs |
Preferences are persisted to gateway_prefs.json next to the executable.
| File | Purpose |
|---|---|
gateway.log |
Rolling application log (also mirrored in the GUI's Gateway Log pane) |
gateway_prefs.json |
Saved Preferences dialog settings |
tags.csv |
Default server/folder/tag configuration, loaded automatically on startup if present |
server_cert.pem / server_key.pem |
Self-signed TLS certificate/key, generated automatically when SSL is first enabled |
- "Connect [ServerName] failed" in the log — the COM ProgID is wrong, or the DA server isn't running/registered, or DCOM security doesn't allow this machine/user to access it. Verify the ProgID and DCOM permissions with the DA server vendor's own test client first.
- A tag never appears / stays at its fallback default — the initial type
probe couldn't read it (bad quality or DA error) and fell back to a
Double. Double-click the tag to open the DA Monitor and check its raw quality directly from the DA server. - Values not updating from an OPC UA client write — writes are queued
and applied by the DA worker on its next cycle; check the log for
Queued write/ write-failure messages, and confirm the tag isn't read-only on the DA side. - High memory over long runs — use the toolbar's 🧹 Force GC action and check the Verbose log level for memory/object-growth diagnostics; the connection reinit interval and idle-session reaping are designed to keep long-running instances stable.
Apache License 2.0 — see LICENSE.