Version: 1.2.0
UA-Bridge includes a full-featured OPC-UA client supporting the OPC-UA binary protocol over TCP.
| Setting | Description | Default |
|---|---|---|
| Connection Name | A unique, human-readable name for the connection | (required) |
| Endpoint URL | Full OPC-UA endpoint,
e.g. opc.tcp://192.168.1.10:4840 |
(required) |
| Security Mode | None, Sign, or
Sign & Encrypt |
None |
| Security Policy | None, Basic256Sha256,
Basic128Rsa15, Basic256,
Basic128 |
None |
| Authentication | Anonymous or Username/Password |
Anonymous |
| Session Timeout | Time in milliseconds before the session expires if idle | 60000 ms |
| Auto-Connect | Automatically connect to this server on application startup | false |
| Certificate File | Path to the client X.509 certificate file (.pem,
.crt, .der) |
(optional) |
| Private Key File | Path to the client private key file (.pem) |
(optional) |
| Private Key Passphrase | Passphrase to decrypt an encrypted private key | (optional) |
| Accept Unknown Certs | Automatically accept server certificates not in the trust store | false |
When connecting, UA-Bridge performs endpoint discovery to identify available security configurations on the server. It logs available security modes and policies to help diagnose connection issues.
After connecting, you can interactively browse the server’s address space:
NodeId,
BrowseName, NodeClass, and
TypeDefinition for each nodeSubscriptions allow you to monitor OPC-UA variables for real-time data changes.
The Free Edition enforces a global limit of 100 subscribed variables across all connections. When the limit is reached, a warning message is displayed.
When a monitored item value changes, the following data is captured:
| Field | Description |
|---|---|
connectionId |
Identifier of the OPC-UA connection |
connectionName |
Human-readable connection name |
nodeId |
OPC-UA Node ID (e.g., ns=2;s=Temperature) |
displayName |
Display name of the variable |
value |
Current value (number, string, boolean, or object) |
serverTimestamp |
Timestamp assigned by the OPC-UA server |
sourceTimestamp |
Timestamp assigned by the data source |
statusCode |
OPC-UA status code (e.g., Good, Bad) |
This data is simultaneously:
Modify subscription parameters on the fly:
Publish OPC-UA data changes to one or more MQTT brokers in real time.
mqtt://,
mqtts:// (TLS), ws://, wss://
(WebSocket)Published topics follow a hierarchical structure:
{baseTopic}/{connectionName}/{OPC browsePath...}/{displayName}
Example:
opcuadt/opcsrv1/Objects/Server/ServerStatus
Each message body is a JSON object with the full data change payload.
{
"connectionId": 1766761871040,
"connectionName": "test",
"nodeId": "ns=0;i=2256",
"displayName": "ServerStatus",
"value": {
"startTime": "2026-02-18T18:37:38.742Z",
"currentTime": "2026-02-21T19:10:59.095Z",
"state": "Running",
"buildInfo": {
"productUri": "https://github.com/riclolsen/json-scada/",
"manufacturerName": "JSON-SCADA Project",
"productName": "{json:scada} - OPC-UA Server",
"softwareVersion": "0.1.3",
"buildNumber": "0.1.3",
"buildDate": "2020-02-01T00:00:00.000Z"
},
"secondsTillShutdown": 0,
"shutdownReason": {}
},
"serverTimestamp": "2026-02-21T19:10:59.094Z",
"sourceTimestamp": "2026-02-21T19:10:59.094Z",
"statusCode": {
"value": 0
}
}
When a connection is lost:
connected,
disconnected, reconnecting,
error)Store OPC-UA data changes in PostgreSQL databases for long-term historical analysis.
value_jsonb (JSONB) – Complete value for complex
typesvalue_double (DOUBLE PRECISION) – Numeric values for
efficient queriesvalue_string (TEXT) – String representation for all
typesVACUUM ANALYZEThe table name is configurable (default:
opcua_data):
CREATE TABLE IF NOT EXISTS opcua_data (
id SERIAL PRIMARY KEY,
connection_id TEXT,
node_id TEXT,
display_name TEXT,
value_jsonb JSONB,
value_double DOUBLE PRECISION,
value_string TEXT,
server_timestamp TIMESTAMP,
source_timestamp TIMESTAMP,
status_code TEXT,
created_at TIMESTAMP DEFAULT NOW()
);| Column | Type | Description |
|---|---|---|
id |
SERIAL |
Auto-incrementing primary key |
connection_id |
TEXT |
The numeric ID of the source OPC-UA connection |
node_id |
TEXT |
OPC-UA Node ID string (e.g., "ns=2;s=Temperature") |
display_name |
TEXT |
Human-readable variable name as reported by the server |
value_jsonb |
JSONB |
Full value as JSON. Supports arrays and complex objects |
value_double |
DOUBLE |
Numeric representation; booleans as
1.0/0.0; NULL for
non-numeric |
value_string |
TEXT |
String representation of the value |
server_timestamp |
TIMESTAMP |
Timestamp assigned by the OPC-UA server |
source_timestamp |
TIMESTAMP |
Timestamp assigned by the data source (sensor/PLC) |
status_code |
TEXT |
OPC-UA status code name (e.g., "Good",
"BadNodeIdUnknown") |
created_at |
TIMESTAMP |
Row insertion time |
The following example uses the SQL INSERT format as produced by the application:
INSERT INTO "public"."opcua_data"
("id", "connection_id", "node_id", "display_name",
"value_jsonb", "value_double", "value_string",
"server_timestamp", "source_timestamp", "status_code", "created_at")
VALUES
('1', '1040', 'ns=0;i=2254', 'ServerArray',
'["urn:instance-20211207-0955:NodeOPCUA-Server"]', null,
'["urn:instance-20211207-0955:NodeOPCUA-Server"]',
'2026-02-21 18:53:03.724', '2026-02-19 09:11:59.729',
'Good', '2026-02-21 17:53:03.929459');Tabular view of typical rows collected from a running system:
| connection_id | node_id | display_name | value_jsonb | value_double | value_string | server_timestamp | status_code |
|---|---|---|---|---|---|---|---|
| 1040 | ns=2;i=3001 | Temperature | 23.5 | 23.5 | 23.5 | 2026-02-21 18:53:04.000 | Good |
| 1040 | ns=2;i=3002 | Pressure | 101.325 | 101.325 | 101.325 | 2026-02-21 18:53:05.000 | Good |
| 1040 | ns=2;i=3003 | ValveOpen | true | 1.0 | true | 2026-02-21 18:53:06.000 | Good |
| 1040 | ns=2;i=3004 | AlarmState | “Normal” | NULL | Normal | 2026-02-21 18:53:07.000 | Good |
Note: The three
value_*columns allow flexible querying – usevalue_doublefor numeric aggregations (WHERE value_double IS NOT NULL),value_stringfor text values, andvalue_jsonbfor complex structured objects (e.g., arrays likeServerArrayabove). When a value is non-numeric (arrays, strings),value_doubleisNULL.
Write OPC-UA data changes directly to Google Sheets spreadsheets.
ConnectionName|NodeId combination (latest value
dashboard)Each row written to Google Sheets contains these columns:
| Column | Header | Type | Description |
|---|---|---|---|
| A | Connection Name | String | Name of the source OPC-UA connection |
| B | Display Name | String | Human-readable variable name from the OPC-UA server |
| C | Node ID | String | OPC-UA Node ID (e.g., ns=2;s=Temperature) |
| D | Timestamp | String | ISO 8601 timestamp of the value change (e.g.,
2026-02-21T12:00:00.000Z) |
| E | Value | Mixed | The value – numbers and booleans are written as-is; strings are
written as text; objects are serialized to JSON (internal _
prefixed properties and functions are stripped) |
| F | Status | String | OPC-UA status code (e.g., Good) |
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | Production Line A | Temperature | ns=2;s=Temperature | 2026-02-21T12:00:00.000Z | 23.5 | Good |
| 2 | Production Line A | Pressure | ns=2;s=Pressure | 2026-02-21T12:00:01.234Z | 101.325 | Good |
| 3 | Production Line A | ValveOpen | ns=2;s=ValveOpen | 2026-02-21T12:00:02.567Z | true | Good |
| 4 | Production Line B | MotorSpeed | ns=3;s=MotorSpeed | 2026-02-21T12:00:03.890Z | 1480 | Good |
| 5 | Production Line A | AlarmState | ns=2;s=AlarmState | 2026-02-21T12:00:04.123Z | Normal | Good |
Append mode: Each of these rows is added sequentially – the sheet grows over time as a time-series log.
Update mode: Row 1 and row 2 would be overwritten with new values on subsequent data changes (matched byConnection Name | Node ID).
All data changes from all OPC-UA subscriptions are automatically stored in a local SQLite database.
{userData}/opcua-data.sqlite
(typically %APPDATA%\ua-bridge\opcua-data.sqlite)DELETE + VACUUMCREATE TABLE IF NOT EXISTS opc_data_changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
connectionId INTEGER,
nodeId TEXT,
displayName TEXT,
value REAL|TEXT,
serverTimestamp INTEGER,
sourceTimestamp INTEGER,
statusCode INTEGER
);| Column | Type | Description |
|---|---|---|
id |
INTEGER |
Auto-incrementing primary key |
connectionId |
INTEGER |
Numeric ID of the source OPC-UA connection |
nodeId |
TEXT |
OPC-UA Node ID string (e.g., ns=2;s=Temperature) |
displayName |
TEXT |
Human-readable variable name |
value |
REAL,TEXT |
Numeric values; non-numeric values are stored as a JSON string |
serverTimestamp |
INTEGER |
Server-assigned timestamp in Unix epoch milliseconds |
sourceTimestamp |
INTEGER |
Source-assigned timestamp in Unix epoch milliseconds |
statusCode |
INTEGER |
OPC-UA status code numeric value (e.g., 0 for
Good) |
| id | connId | nodeId | name | value | serverTimestamp | sourceTimestamp | code |
|---|---|---|---|---|---|---|---|
| 1 | 1 | ns=2;s=Temperature | Temp | 23.5 | 1740142800000 | 1740142800000 | 0 |
| 2 | 1 | ns=2;s=Pressure | Pres | 101.325 | 1740142801000 | 1740142801000 | 0 |
| 3 | 1 | ns=2;s=ValveOpen | Valve | 1.0 | 1740142802000 | 1740142801500 | 0 |
| 4 | 2 | ns=3;s=MotorSpeed | Speed | 1480.0 | 1740142803000 | 1740142802800 | 0 |
| 5 | 1 | ns=2;s=AlarmState | Alarm | “Normal” | 1740142804000 | 1740142803900 | 0 |
Note: The
valuecolumn stores numeric values asREAL. Non-numeric values (strings, objects) are stored as their JSON representation. Booleantrue/falsevalues are stored as1.0/0.0. The Visualize page only charts rows where value is a number.
You can query the SQLite database directly using the
sqlite3 command-line tool:
sqlite3 "%APPDATA%\ua-bridge\opcua-data.sqlite"-- View recent readings with human-readable timestamps
SELECT connectionId, nodeId, displayName, value,
DATETIME(serverTimestamp/1000, 'unixepoch', 'localtime') AS time
FROM opc_data_changes
ORDER BY id DESC
LIMIT 20;
-- Compute average temperature over the last hour
SELECT AVG(value) AS avg_temp
FROM opc_data_changes
WHERE displayName = 'Temperature'
AND typeof(value) = 'real'
AND serverTimestamp >= (CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER) - 3600000);
-- Count records per connection
SELECT connectionId, COUNT(*) AS record_count
FROM opc_data_changes
GROUP BY connectionId;The Dashboard page provides an at-a-glance overview:
The Explore page (lazy-loaded for performance) provides:
Each OPC-UA connection maintains its own log buffer (up to 10,000 entries).
| Level | Usage |
|---|---|
info |
Successful operations, data changes, connections |
warning |
Health check anomalies, session warnings |
error |
Connection failures, subscription errors |
UA-Bridge configurations can be saved to and loaded from JSON files.
config.json state to a user-selected fileconfig.json, and restarts the application.json
extensionAll connection types feature robust auto-reconnection:
| Connection Type | Base Delay | Max Delay |
|---|---|---|
| OPC-UA | 2 s | 60 s |
| MQTT | 2 s | 60 s |
| PostgreSQL | 5 s | 60 s |
All reconnection logic respects manual disconnect flags – once a user explicitly disconnects, auto-reconnection is suppressed until they manually reconnect.
VACUUM to reclaim disk spaceVACUUM ANALYZE to reclaim space and update
statisticslocalStorage and applied on startup| Shortcut | Action |
|---|---|
Ctrl+O |
Open Project |
Ctrl+S |
Save Project As |
F11 |
Toggle Fullscreen |
Escape |
Close active modal dialog |
Tab / Shift+Tab |
Navigate within modals (focus-trapped) |
Version: 1.2.0
Application-wide settings are managed from the
Settings page and stored in the
appSettings section of config.json.
| Setting | Type | Default | Range | Description |
|---|---|---|---|---|
dataRetention |
Number | 30 |
0 - 365 | Number of days to retain historical data. Set to 0 to
disable cleanup. |
theme |
String | light |
– | UI theme (light or dark). Stored
separately in localStorage. |
config.json when
modifiedNote: The
dataRetentionvalue affects both the built-in SQLite database and all active PostgreSQL connections.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| Connection Name | Yes | String | – | Unique name for this connection |
| Endpoint URL | Yes | String | – | OPC-UA server endpoint (opc.tcp://host:port) |
| Security Mode | Yes | Select | None |
None, Sign, or
Sign & Encrypt |
| Security Policy | Yes | Select | None |
None, Basic256Sha256,
Basic128Rsa15, Basic256,
Basic128 |
| Authentication Method | Yes | Select | Anonymous |
Anonymous or Username/Password |
| Username | No | String | – | Required when auth method is Username/Password |
| Password | No | String | – | Required when auth method is Username/Password |
| Auto-Connect | No | Boolean | false |
Connect automatically on app startup |
| Session Timeout | No | Number | 60000 |
Session timeout in milliseconds |
When Security Mode is set to Sign or
Sign & Encrypt, additional fields appear:
| Parameter | Required | Type | Description |
|---|---|---|---|
| Client Certificate File | No | File Path | Path to client X.509 certificate (.pem,
.crt, .der) |
| Client Private Key File | No | File Path | Path to client private key (.pem) |
| Private Key Passphrase | No | String | Passphrase if the private key is encrypted |
| Automatically Accept Unknown Certificates | No | Boolean | Skip server certificate validation (WARNING: insecure) |
File Selection: Use the
...button to open a file browser dialog for selecting certificate and key files.
The endpoint URL must follow the OPC-UA TCP URI scheme:
opc.tcp://<hostname>:<port>[/<path>]
Valid examples:
opc.tcp://localhost:4840
opc.tcp://192.168.1.100:4840
opc.tcp://plc-server.local:4840/UAServer
| Security Mode | Compatible Policies | Use Case |
|---|---|---|
None |
None (only) |
Development, trusted networks |
Sign |
Basic256Sha256, Basic128Rsa15,
Basic256, Basic128 |
Message integrity |
Sign & Encrypt |
Basic256Sha256, Basic128Rsa15,
Basic256, Basic128 |
Full message confidentiality |
Recommendation: For production environments, use
Sign & EncryptwithBasic256Sha256.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| Connection Name | Yes | String | – | Human-readable name |
| Host | Yes | String | – | Broker hostname or IP address |
| Port | Yes | Number | 1883 |
Broker port (1883 for MQTT, 8883 for MQTTS) |
| Protocol | Yes | Select | mqtt |
mqtt, mqtts, ws,
wss |
| Username | No | String | – | Broker authentication username |
| Password | No | String | – | Broker authentication password |
| Topic | Yes | String | opcua/data |
Base topic for published messages |
| Retain | No | Boolean | false |
Retain the last message for each topic on the broker |
For mqtts or wss protocols:
| Parameter | Required | Type | Description |
|---|---|---|---|
| CA Certificate | No | File Path | Path to Certificate Authority file for server verification |
| Client Certificate | No | File Path | Path to client certificate for mutual TLS |
| Client Key | No | File Path | Path to client private key for mutual TLS |
| Reject Unauthorized | No | Boolean | Set to false for self-signed certificates (default:
true) |
The actual published topic for each data point is constructed as:
{baseTopic}/{connectionName}/{browsePath}/{displayName}
Where:
baseTopic is the configured topicconnectionName is the name of the OPC-UA
connectionbrowsePath is the browse path from the OPC-UA address
spacedisplayName is the display name of the variable
node| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| Connection Name | Yes | String | – | Human-readable name |
| Host | Yes | String | localhost |
Database server hostname or IP |
| Port | Yes | Number | 5432 |
Database server port |
| Database | Yes | String | – | Target database name |
| Username | Yes | String | – | Database user |
| Password | Yes | String | – | Database password |
| Table Name | No | String | opcua_data |
Table to store data in |
| Parameter | Required | Type | Description |
|---|---|---|---|
| Enable SSL | No | Boolean | Enable SSL/TLS for the database connection |
| CA Certificate | No | File Path | Path to CA certificate file |
| Client Certificate | No | File Path | Path to client certificate for mutual TLS |
| Client Key | No | File Path | Path to client private key for mutual TLS |
| Reject Unauthorized | No | Boolean | Reject connections with invalid certificates (default:
true) |
When connecting, UA-Bridge performs the following steps:
postgres system database and queries
pg_catalog.pg_databaseCREATE DATABASE <name> if the target database doesn’t
existpostgres and connects to the target databaseCREATE TABLE IF NOT EXISTS with the configured or default
table nameNote: The service user must have
CREATEDBprivilege or the target database must already exist.
Before configuring a Google Sheets output, you need:
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
| Connection Name | Yes | String | – | Human-readable name |
| Spreadsheet ID | Yes | String | – | The ID from the Google Sheets URL |
| Sheet Name / Range | Yes | String | Sheet1!A:A |
Target sheet name and column range |
| Write Mode | Yes | Select | update |
append (add rows) or update (replace
rows) |
| Key File Path | Yes | File Path | – | Path to the Google service account JSON key file |
The Spreadsheet ID is found in the URL of your Google Sheet:
https://docs.google.com/spreadsheets/d/{SPREADSHEET_ID}/edit
ConnectionName|NodeId
combination| Platform | Path |
|---|---|
| Windows | %APPDATA%\ua-bridge\config.json |
| Windows (UWP) | %LOCALAPPDATA%\Packages\{pkg}\LocalCache\Roaming\ua-bridge\config.json |
{
"opcuaConnections": [
{
"id": 1,
"name": "Production Line PLC",
"endpoint": "opc.tcp://192.168.1.100:4840",
"securityMode": "None",
"securityPolicy": "None",
"authenticationMethod": "Anonymous",
"username": "",
"password": "",
"autoConnect": true,
"certificateFile": "",
"privateKeyFile": "",
"privateKeyPassphrase": "",
"automaticallyAcceptUnknownCertificate": false,
"sessionTimeout": 60000
}
],
"mqttConnections": [
{
"id": "uuid-1",
"name": "Central MQTT Broker",
"host": "broker.local",
"port": 1883,
"protocol": "mqtt",
"username": "",
"password": "",
"topic": "factory/opcua",
"retain": false,
"caCert": "",
"clientCert": "",
"clientKey": "",
"rejectUnauthorized": true
}
],
"postgresConnections": [
{
"id": "uuid-2",
"name": "Historian Database",
"host": "db.local",
"port": 5432,
"database": "process_data",
"username": "opcua_writer",
"password": "secret",
"tableName": "opcua_data",
"ssl": false,
"sslCaCert": "",
"sslClientCert": "",
"sslClientKey": "",
"sslRejectUnauthorized": true
}
],
"googlesheetsConnections": [
{
"id": "uuid-3",
"name": "Monitoring Dashboard",
"spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
"range": "Sheet1!A:A",
"writeMode": "update",
"keyFilePath": "C:\\keys\\service-account.json"
}
],
"subscriptions": [],
"appSettings": {
"autoConnect": false,
"logLevel": "info",
"maxConnections": 10,
"dataRetention": 30,
"enableNotifications": true
}
}| Action | Menu / Shortcut | Description |
|---|---|---|
| Save Project As | Ctrl+S |
Exports config.json to a user-chosen file location |
| Open Project | Ctrl+O |
Imports a .json file, replaces
config.json, restarts the app |
Format: The project file is a standard JSON file with the same schema as
config.json.
| Resource | Location |
|---|---|
| Configuration File | {userData}/config.json |
| SQLite Database | {userData}/opcua-data.sqlite |
| Application Logs | In-memory only (per connection, 10,000 max) |
| Temporary Private Keys | {os.tmpdir()}/opcua_pk_<random>.pem |
%APPDATA%\ua-bridge\C:\Users\<user>\AppData\Local\Packages\<packageFamily>\LocalCache\Roaming\ua-bridge\UA-Bridge automatically detects whether it’s running as a UWP app and uses the appropriate data path.
Version: 1.2.0
This example walks through connecting to a local OPC-UA simulation server.
Start the application. You’ll land on the OPC-UA (Connections) page.
Click “Add Connection”
Enter the connection details:
| Field | Value |
|---|---|
| Connection Name | Local Simulator |
| Endpoint URL | opc.tcp://localhost:4840 |
| Security Mode | None |
| Security Policy | None |
| Authentication | Anonymous |
Click “Add Connection”
Click the Connect button (plug icon) next to your new connection. The status indicator will turn green when connected. If it doesn’t turn green, check the logs for errors.
Root -> Objects ->
etc.You should now see live data values updating in the subscriptions panel.
Select multiple variables by clicking a node in the browse tree, then click “Add Child Variables to Subscription”. All child nodes will be subscribed at once.
The following defaults are used for new subscriptions:
Publishing Interval: 5,000 ms
Queue Size: 10
Discard Policy: Discard Oldest
Timestamps: Both (server + source)
Use the Edit Subscription option to change:
Once subscribed, every value change is automatically:
OPC-UA Server
|
v
UA-Bridge (Main Process)
|
+--+ SQLite DB (always)
+--+ UI / Renderer (always)
+--+ MQTT Brokers (if configured)
+--+ PostgreSQL DBs (if configured)
+--+ Google Sheets (if configured)
Go to the Output Destinations page
Click “Add MQTT Connection”
Enter:
| Field | Value |
|---|---|
| Connection Name | Factory MQTT Broker |
| Host | mqtt-broker.factory.local |
| Port | 1883 |
| Protocol | mqtt |
| Topic | factory/opcua/data |
| Retain | true |
Click “Save Connection”
Click Connect on the MQTT connection. The status will update to “Connected”.
Subscribe to topics on the MQTT broker using any MQTT client:
mosquitto_sub -h mqtt-broker.factory.local -t "factory/opcua/data/#" -vYou should see messages like:
factory/opcua/data/LocalSimulator/Objects/Simulation/Temperature
{
"connectionId":1,
"connectionName":"Local Simulator",
"nodeId":"ns=2;s=Temperature",
"displayName":"Temperature",
"value":23.5,
"serverTimestamp":"2026-02-21T12:00:00.000Z",
"sourceTimestamp":"2026-02-21T12:00:00.000Z",
"statusCode":"Good"
}
Ensure PostgreSQL is running and accessible. The database user needs either:
CREATEDB privilege (UA-Bridge will auto-create the
database), orGo to Output Destinations
Click “Add PostgreSQL Connection”
Enter:
| Field | Value |
|---|---|
| Name | Process Historian |
| Host | db-server.local |
| Port | 5432 |
| Database | process_data |
| Username | opcua_writer |
| Password | secure_password |
| Table Name | opcua_data |
Click “Save Connection”
After connecting, check the database:
SELECT * FROM opcua_data ORDER BY created_at DESC LIMIT 10;Expected result:
| id | connection_id | node_id | display_name | value_jsonb | value_double | value_string | server_timestamp | status_code |
|---|---|---|---|---|---|---|---|---|
| 1 | 1 | ns=2;s=Temp | Temperature | 23.5 | 23.5 | 23.5 | 2026-02-21 18:53:04.00 | Good |
Obs.: Not all columns are shown in the example table.
Go to Output Destinations
Click “Add Google Sheets Connection”
Enter:
| Field | Value |
|---|---|
| Connection Name | Plant Dashboard |
| Spreadsheet ID | 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms |
| Sheet / Range | LiveData!A:A |
| Write Mode | update |
| Key File Path | C:\Keys\plant-monitor-sa.json |
Click “Save Connection”
Click Connect. Data changes will begin appearing in your spreadsheet:
| A (Connection) | B (Display Name) | C (Node ID) | D (Timestamp) | E (Value) | F (Status) |
|---|---|---|---|---|---|
| Local Simulator | Temperature | ns=2;s=Temperature | 2026-02-21T12:00:00.000Z | 23.5 | Good |
| Local Simulator | Pressure | ns=2;s=Pressure | 2026-02-21T12:00:01.234Z | 101.3 | Good |
Tip: In Update mode, each
ConnectionName|NodeIdcombination occupies exactly one row. New values overwrite the previous entry, creating a real-time “current values” view.
.pem format).pem format, optionally
encrypted)Click “Add Connection”
Enter:
| Field | Value |
|---|---|
| Connection Name | Secure PLC |
| Endpoint URL | opc.tcp://plc.factory.local:4840 |
| Security Mode | Sign & Encrypt |
| Security Policy | Basic256Sha256 |
| Authentication | Username/Password |
| Username | operator |
| Password | secure_pass |
| Certificate File | C:\Certs\client-cert.pem |
| Private Key File | C:\Certs\client-key.pem |
| Private Key Passphrase | my_key_password |
| Accept Unknown Certs | [ ] (unchecked for production) |
Click “Add Connection”
Security Note: Only check “Accept Unknown Certificates” in development or when connecting to servers with self-signed certificates on trusted networks.
Go to Output Destinations -> “Add MQTT Connection”
Enter:
| Field | Value |
|---|---|
| Connection Name | Secure Cloud Broker |
| Host | cloud-mqtt.example.com |
| Port | 8883 |
| Protocol | mqtts |
| Username | device01 |
| Password | device_secret |
| Topic | plant/opcua |
| CA Certificate | C:\Certs\mqtt-ca.pem |
| Client Certificate | C:\Certs\mqtt-client.pem |
| Client Key | C:\Certs\mqtt-client-key.pem |
| Reject Unauthorized | [x] enabled |
Click “Save Connection”
For self-signed certificates: Uncheck
Reject Unauthorizedto skip CA validation. This is insecure and should only be used in development.
factory-floor-config.json).json project file{
"opcuaConnections": [
{
"id": 1,
"name": "PLC Line A",
"endpoint": "opc.tcp://192.168.1.10:4840",
"securityMode": "None",
"securityPolicy": "None",
"authenticationMethod": "Anonymous",
"autoConnect": true,
"sessionTimeout": 60000
},
{
"id": 2,
"name": "PLC Line B",
"endpoint": "opc.tcp://192.168.1.11:4840",
"securityMode": "None",
"securityPolicy": "None",
"authenticationMethod": "Anonymous",
"autoConnect": true,
"sessionTimeout": 60000
}
],
"mqttConnections": [
{
"id": "mqtt-1",
"name": "Factory MQTT",
"host": "mqtt.factory.local",
"port": 1883,
"protocol": "mqtt",
"topic": "factory/data",
"retain": true
}
],
"postgresConnections": [
{
"id": "pg-1",
"name": "Historian",
"host": "historian.factory.local",
"port": 5432,
"database": "process_data",
"username": "opcua",
"password": "secret",
"tableName": "sensor_data"
}
],
"appSettings": {
"dataRetention": 90
}
}| Data Store | Records Affected | Followed By |
|---|---|---|
| SQLite (built-in) | opc_data_changes where
serverTimestamp < cutoff |
VACUUM |
| PostgreSQL | All records where created_at < cutoff |
VACUUM ANALYZE |
Click “Show Database File” from the Dashboard or use OPC data options to open Windows Explorer at the database location. You can then query the SQLite file directly:
sqlite3 "%APPDATA%\ua-bridge\opcua-data.sqlite"For MS Store version (UWP):
sqlite3 "%LOCALAPPDATA%\Packages\{pkg}\LocalCache\Roaming\ua-bridge\config.json"Use the SQLite Output “Show File” button to open Windows Explorer at the exact database file location.
-- View recent temperature readings
SELECT displayName, value,
datetime(serverTimestamp/1000, 'unixepoch', 'localtime') as time
FROM opc_data_changes
WHERE displayName LIKE '%Temperature%'
ORDER BY id DESC
LIMIT 20;
-- Count records per connection
SELECT connectionId, COUNT(*) as record_count
FROM opc_data_changes
GROUP BY connectionId;To free disk space, use the “Empty Data” button, which performs:
DELETE FROM opc_data_changes;
VACUUM;A manufacturing plant with:
+----------------------------+
| UA-Bridge |
| |
| OPC-UA Connections: |
| +-- PLC Line A |---> opc.tcp://192.168.1.10:4840
| +-- PLC Line B |---> opc.tcp://192.168.1.11:4840
| |
| Output Destinations: |
| +-- MQTT: SCADA |---> mqtt://scada-broker:1883
| | Topic: plant/opcua |
| +-- PostgreSQL: Historian |---> postgres://db-server:5432/process_data
| | Table: sensor_data |
| +-- Google Sheets: KPIs |---> Spreadsheet: "Plant KPIs"
| Mode: update |
| |
| Settings: |
| +-- Retention: 90 days |
+----------------------------+
opc.tcp://192.168.1.10:4840)opc.tcp://192.168.1.11:4840)plant/opcua with retain enabledprocess_data, table to
sensor_dataupdate modeCtrl+S and save as
plant-config.jsonAll data from both PLCs will now automatically flow to the MQTT broker, PostgreSQL database, and Google Sheet simultaneously, with automatic reconnection and 90-day retention management.
| Issue | Cause | Solution |
|---|---|---|
| Connection immediately fails | Wrong endpoint URL or server not running | Verify the endpoint format (opc.tcp://...) |
| “Maximum subscription limit” | Free edition 100-variable limit reached | Remove unused subscriptions or upgrade to Pro |
| MQTT messages not appearing | Topic mismatch | Check the base topic; actual topics include connection and node names |
| PostgreSQL permission denied | User lacks CREATEDB or table privileges | Grant privileges or pre-create the database and table |
| Google Sheets API error | Service account not shared on spreadsheet | Share the spreadsheet with the service account email (Editor) |
| Private key decryption fails | Wrong passphrase | Verify the passphrase matches the one used to encrypt the key |
| Auto-reconnect not working | Manually disconnected | Manually reconnect; auto-reconnect is suppressed after manual disconnect |
| Data not appearing in charts | Non-numeric values | The Visualize page only displays numeric (REAL)
values |
Each connection maintains up to 10,000 log entries. Open the log viewer: