Installation
MacTools OPC-UA Explorer is a native macOS app built with Rust and Tauri. It runs natively on Apple Silicon and Intel Macs — no Rosetta, no Parallels, no Java (unlike UA Expert), no Eclipse. One-time purchase, no subscription.
Download
- Direct purchase: buy direct ($14.99 one-time) — you receive a download link by email
- Product page: /opcua-explorer/
System Requirements
| Requirement | Minimum |
|---|---|
| macOS | 12 Monterey or newer (Apple Silicon & Intel) |
| Network | Reachability to the OPC-UA server on TCP/4840 |
| Certificates | For SignAndEncrypt, the app generates a self-signed client cert in its keychain on first launch |
First Launch
If you downloaded the direct build outside the App Store, macOS Gatekeeper may block the unsigned binary on first run. Right-click the app, choose Open, then confirm. This is only required once.
opc.tcp://192.168.1.50:4840 — the scheme is opc.tcp, not tcp. Pasting 192.168.1.50:4840 without the scheme will fail.
Quick Start
1. Connect to an OPC-UA server (2 minutes)
This is the most common path — connecting to a PLC, an OPC server (Kepware, Matrikon), or a modern controller's built-in UA server.
- Open the app and create a new Endpoint.
- Enter the endpoint URL:
opc.tcp://<ip>:4840. - Set the Security Mode. Start with
Noneto confirm reachability, then switch toSignAndEncrypt+Basic256Sha256for production servers. - Set authentication:
Anonymousfor most PLCs, orUsername/Passwordif the server enforces it. - Click Connect. The server's address space loads into the browse tree.
If the connection hangs or fails, jump to Troubleshooting — the most frequent cause is a security-mode mismatch or a server that only accepts signed certificates.
2. Browse the address space
- Expand
Objects→ the vendor's folder (e.g.Siemens,AllenBradley,Server). - Drill into the variable folders. Each node shows its NodeId (e.g.
ns=3;s="DataBlock"."Temperature"), data type, and current value. - The
Valuecolumn shows the last read. Right-click a node to read it once, subscribe, or write.
3. Subscribe to a variable (live updates)
- Right-click a Variable node → Subscribe.
- The node is added to the monitored-items list with a default publishing interval of 500 ms and sampling interval of 1000 ms.
- Values stream in the live-values panel; the timestamp and status code are shown alongside the value so you can see stale data.
4. Write a value
- Right-click a writable Variable → Write.
- Enter the value in the correct data type (the app validates against the node's
DataType— don't write a decimal into an Int16 node). - Confirm. A
Good (0x00000000)status means the server accepted it; anything else is an error (see Troubleshooting).
Configuration
Endpoint Settings
| Parameter | Options |
|---|---|
| Endpoint URL | opc.tcp://<host>:4840 (default port 4840) |
| Security Mode | None, Sign, SignAndEncrypt |
| Security Policy | None, Basic128Rsa15, Basic256, Basic256Sha256, Aes128Sha256RsaOaep, Aes256Sha256RsaPss |
| Authentication | Anonymous, Username/Password, Certificate |
| Session timeout | Default 600000 ms (10 min) — shorter if the server kills idle sessions |
Security Matrix
Security mode and policy must both match what the server's GetEndpoints advertises. A mismatch produces a BadSecurityChecksFailed or BadSecurityPolicyRejected on connect.
| Combination | When to Use |
|---|---|
| None + None | Isolated OT network, quick commissioning only. No encryption, no auth. |
| SignAndEncrypt + Basic256Sha256 | The modern default. Required by OPC UA Part 2 conformance since 2018. Use this if the server supports it. |
| SignAndEncrypt + Basic128Rsa15 | Legacy servers (older Kepware, early S7-1500 firmware). Deprecated but still common. |
| Sign + Basic256 | Rare — integrity without confidentiality. Only if the server rejects encryption. |
NodeIds
A NodeId uniquely identifies a node in the address space. It has a namespace index and an identifier that can be numeric, string, GUID, or opaque.
| Format | Example | Meaning |
|---|---|---|
| String | ns=2;s=Temperature | Namespace 2, string identifier "Temperature" |
| Numeric | ns=0;i=2258 | Namespace 0 (OPC standard), numeric 2258 = Server.ServerStatus.CurrentTime |
| Siemens | ns=3;s="DB1"."Temperature" | Siemens symbol notation inside a data block |
Subscription Tuning
| Parameter | Default | Guidance |
|---|---|---|
| Publishing interval | 500 ms | How often the server publishes a notification. Lower = more traffic. 100–250 ms for fast process; 1000–5000 ms for temps. |
| Sampling interval | 1000 ms | How often the server samples the source. Must be ≤ publishing interval or you'll miss updates. |
| Queue size | 10 | How many value changes queue between publishes. Increase for bursty signals. |
| Discard policy | Oldest | When the queue fills, drop the oldest changes (keep newest) or the newest (keep oldest). |
| Monitoring mode | Reporting | Reporting (push on change), Sampling (sample but don't push), Disabled. |
Data Types
The app validates writes against the node's DataType. Common built-in types: Boolean, SByte/Byte, Int16/UInt16, Int32/UInt32, Int64/UInt64, Float, Double, String, DateTime, ByteString. Structured types (ExtensionObjects) are read-only in browse mode.
Key Features
Full address-space browse
Walk the tree from Objects, Types, and Views with reference following (HierarchicalReferences by default). Every node shows its NodeClass (Object, Variable, Method), DataType, AccessLevel, and current value inline — no separate read call per node.
Subscriptions with status codes
Every monitored value carries its OPC status code and source timestamp. A reading of Good with a 2-hour-old timestamp means the source went stale; a BadCommunicationError means the underlying PLC lost its connection. The value alone is not enough — the status is.
Method (function) calls
Browse to a Method node, supply its InputArguments, and invoke it server-side. Useful for triggering a recipe start, acknowledging an alarm, or running a diagnostic routine exposed by the server.
Historical read (HDA)
If a Variable is historized (HistoryRead = true), read its raw or processed history over a time range without a separate HDA server — the app uses the standard HistoryRead service on the same session.
Certificate management
For SignAndEncrypt, the app generates a self-signed client certificate and stores it in the macOS keychain. On first secure connect, the server is likely to reject the unknown cert — accept it (or have the admin trust your client cert in the server's trust list), and subsequent connects succeed.
Decoded service-level traffic
The traffic panel decodes OPC-UA services (Browse, Read, Write, Publish, CreateMonitoredItems) with their StatusCode, so you can see exactly which monitored item returned BadNodeIdUnknown or which write returned BadUserAccessDenied.
Troubleshooting
Common OPC-UA status codes
| Code | Name | Likely Cause |
|---|---|---|
| 0x80010000 | BadInternalError | Server hit an unexpected fault — check server logs |
| 0x803B0000 | BadSecurityChecksFailed | Signature didn't verify — wrong security mode/policy, or clock skew > a few minutes |
| 0x803D0000 | BadSecurityPolicyRejected | Server doesn't accept the policy you selected — call GetEndpoints to list supported ones |
| 0x801F0000 | BadUserAccessDenied | Authenticated user lacks permission for that node's read/write |
| 0x80350000 | BadIdentityTokenRejected | Username/password wrong, or server requires a different auth scheme |
| 0x803E0000 | BadCertificateUnknown | Server doesn't trust your client cert — add it to the server's trusted list |
| 0x80340000 | BadNoMatch | NodeId doesn't exist — wrong namespace or the symbol was renamed |
Connection refused / timeout on TCP/4840
Symptom: "Connection refused" or no response.
Fix: Confirm the server listens on 4840 and reachable. From Terminal:
nc -zv 192.168.1.50 4840
If nc fails, the server is offline, on another subnet, or behind a firewall. Siemens S7-1500 UA server must be explicitly enabled in TIA Portal (Protection & Security → "Permit access with OPC UA").
BadCertificateUnknown on first secure connect
Symptom: SignAndEncrypt connect fails with BadCertificateUnknown or BadCertificateUntrusted.
Fix: The server received your client certificate but doesn't trust it. Every UA server has a rejected/trusted certificate store. Find your client cert in the server's rejected folder (Kepware: in the Management Console; Siemens: under Certificate Management) and move it to Trusted. Then re-connect.
Subscription shows no updates
Symptom: You subscribed to a variable but the live panel shows a single value with no refresh.
Fix: Check the monitoring mode — if it's Disabled, the server isn't sampling. Confirm the publishing interval isn't absurdly long. Then verify the value is actually changing at the source — a static temperature reads once and never updates because nothing changed. The status code Good with a recent timestamp confirms the subscription is alive.
Write returns BadUserAccessDenied
Symptom: Reads succeed but writes return 0x801F0000 BadUserAccessDenied.
Fix: The node's AccessLevel or UserAccessLevel doesn't include CurrentWrite for your authenticated user. Either connect with higher-privilege credentials, or have the server admin raise the user's write permission on that node. The app shows the AccessLevel bitmask in the browse view — check that bit 1 (CurrentWrite) is set.
BadNodeIdUnknown after a server restart
Symptom: A NodeId that worked yesterday now returns BadNodeIdUnknown.
Fix: String NodeIds are volatile on some servers — they shift when the PLC program is recompiled or a new DB is added, renumbering namespaces. Re-browse to find the new NodeId. For stable addressing, prefer numeric NodeIds where the server assigns fixed identifiers, or use the server's import/export for NodeId mappings.
Support
- Email: support@voltrus.id
- Product page: /opcua-explorer/
When reporting a connection issue, attach the decoded traffic log (with IPs redacted), the server's GetEndpoints response, and the exact security mode/policy you used.