Read-only re-check on the shared R1.05 test server plus a diff of the R1.03 and R1.05 manual editions. - installation-security: R1.05 OS list, Defender exceptions, IT security 2.0/3.0, LAPS, automatic configuration merge (jupgutl), PRM chapter, port 34597; setup_check.ps1 gets -Version (default 1.05.00). - data-access: L45 renumbered (new ch. 4 RESTful API), extended OPC UA functions off by default, OPC UA methods (OPCUAC_METHOD_CALL2_DF), Information Model Mapper, ServerConfig.xml in %TLS_SAV_PATH%. - equipment: Modbus unchanged; IEC 104/61850 run as EQT managers (eqtdbg, eqtfrcscn), IEC 61850 report control blocks, upgrade steps. - Issues ISS-076..090; R1.05 notes on ISS-003/008/032/034/061; progress and version-differences updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
194 lines
11 KiB
Markdown
194 lines
11 KiB
Markdown
---
|
||
task: OPC UA client to an OPC UA server by quick load (loopback to CI Server's own OPC UA server)
|
||
version: R1.05 (first written for R1.03)
|
||
source: IM 36K10L45-01EN 5th ed. (Feb. 2026) §10, §11; IM 36K10E20-01EN 4th ed. (Feb. 2026) §2; practiced on CI-Eng-Sample 2026-10-01 on R1.03 (station CIENG_UA; full remove/reload; point also configured in the Engineering Module by the user and compared)
|
||
status: verified on R1.03 (§1–§6). R1.05 (2026-10-08, read-only): line/station/subscription/point dataset definitions identical to R1.03, PKI folders and client setup files checked; the loopback itself was not re-run on the shared R1.05 test server. §7 (methods) from docs.
|
||
---
|
||
|
||
# OPC UA client to an OPC UA server
|
||
|
||
Worked example: CI-Eng-Sample station `CIENG_UA`, CI Server's OPC UA client reading
|
||
`CI-Eng-Sample.TANK1.LEVEL` back through CI Server's **own** OPC UA server
|
||
(`examples/CI-Eng-Sample/12_`–`15_*.qli`, removal `76_`–`78_`). For a real server, replace the
|
||
endpoint, security settings and node IDs.
|
||
|
||
## 1. Server side: make the data visible
|
||
|
||
On the CI Server OPC UA server an item is reachable only when the item has **OPC visible** and
|
||
**Read** (Write to allow writing) and every parent section is OPC visible
|
||
(`12_opc_visible_df.qli`, loaded with `dssqld -m`):
|
||
|
||
```
|
||
@FIELDS
|
||
NAME,OPC_VISIBLE
|
||
|
||
@SECTION_DF
|
||
"CI-Eng-Sample",1
|
||
"CI-Eng-Sample.TANK1",1
|
||
|
||
@FIELDS
|
||
NAME,OPC_VISIBLE,OPC_READ,OPC_WRITE
|
||
|
||
@ITEM_DF
|
||
"CI-Eng-Sample.TANK1.LEVEL",1,1,0
|
||
```
|
||
|
||
Visible without Read: the item shows when browsing, but browsing into it fails
|
||
(`UncertainNotAllNodesAvailable`, client message `OPXC-E-BRW_NODE`; verified). By the manual,
|
||
Read is also what allows reading the value.
|
||
These flags also apply to the OPC DA and A&E servers.
|
||
|
||
## 2. Client configuration (quick load, in this order)
|
||
|
||
1. **Line** (`OPCUAC_LINE_DF`): loading it creates and starts the client process
|
||
`EQUIPMENT_MAN` (must start with `OPX`, ≤ 11 characters) — wait ~10 s before the station.
|
||
```
|
||
"CIENG_UA_LINE","CI-Eng-Sample OPC UA loopback line","OPXCIENG"
|
||
```
|
||
The process reads `tls\sup\<process>.sup` (here `opxcieng.sup`), else the template
|
||
`epauac_eqp.sup` (IM 36K10L45 5th ed. §10.11; the R1.03 manual named a non-existent
|
||
`opxuac.sup`, ISS-084). On the R1.03 test system `opxcieng.sup` appeared as an exact copy of
|
||
the template. R1.05 template changes (verified 2026-10-08, ISS-083): new
|
||
`OPXC_ENABLE_EXTENDED_FUNC` (NO; YES needed for OPC UA alarms), `OPXC_BASE_MODEL_CHANGE_EVENT`
|
||
(NO), `OPXC_DISABLE_SAV_FILE` (NO), `OPXC_ALARM_TIME_ATTRIBUTE`, hidden
|
||
`OPXC_CERT_EXP_PERIOD_WARN` (2 months), and `OPXC_SERVICE_CALL_TIME_OUT` 60 s (manual: 10 s).
|
||
A per-process file copied from R1.03 lacks these keywords, so their defaults apply.
|
||
2. **Station** (`OPCUAC_STATION_DF`), **subscription** (`OPCUAC_SUBSCRIPTION_DF`, name
|
||
`<station>:<subscription>`), **points** (`OPCUAC_POINT_DF`, name `<station>:<point>`) —
|
||
see `14_opcua_station_df.qli`:
|
||
- Station: `LINE`, `USER_ANONYMOUS` 1 (or `USER_NAME`/`USER_PASSWORD`),
|
||
`MSG_SECURITY_01_MODE` `SignAndEncrypt`, `MSG_SECURITY_01_POLICY` `Basic256Sha256`,
|
||
`SERVER_01_ENDPOINT` `opc.tcp://localhost:34493`, `STATUS_ITEM` (1 = connected; a Boolean
|
||
item worked on R1.03). `SERVER_01_NAME`/`_URI` may stay empty. The R1.05 OPC Interface
|
||
manual (IM 36K10E20 4th ed. §2.1.2) lists states 0–5 for this item (0 preparing,
|
||
1 connected, 2 comm error/reconnecting, 3 connect failed, 4 server shutdown received,
|
||
5 connection recreated) while IM 36K10L45 §10.9.2 still calls it Boolean; not re-tested on
|
||
R1.05 (ISS-080). An Integer item shows all states.
|
||
- Subscription: `REQUESTED_PUBLISH_INTERVAL` 1000.
|
||
- Point: `SUBSCRIPTION`, `EXTERNAL_RELATION` (`Input`, `Output`, `Input + Output`),
|
||
`OPC_NAMESPACE` (namespace **URI**, not index), `OPC_NODE_ID_TYPE` (`STRING`, `NUMERIC`,
|
||
`GUID`), `OPC_NODE_ID`.
|
||
3. **Items** (`ITEM_DF` with `STATION` and `POINT`), e.g. `CI-Eng-Sample.UA.LEVEL_COPY` →
|
||
`CIENG_UA`, `LEVEL`.
|
||
|
||
## 3. Node IDs
|
||
|
||
| Target | Namespace | Type | Node ID |
|
||
|---|---|---|---|
|
||
| Value of a CI Server item (by name — survives recreating the item) | `urn:Yokogawa:CI_SERVER_OPC_UA_SERVER` | STRING | `{"0":"Value","itnm":"<Section>.<Tag>"}` |
|
||
| Value of a CI Server item (by namespace id) | same | STRING | `{"0":"Value","nsid":"<n>"}` |
|
||
| Server state (any OPC UA server; good connection test, 0 = Running) | `http://opcfoundation.org/UA/` | NUMERIC | `2259` |
|
||
|
||
In a `.qli` file double the quotes inside the field:
|
||
`"{""0"":""Value"",""itnm"":""CI-Eng-Sample.TANK1.LEVEL""}"`.
|
||
|
||
Pitfalls found on the test system:
|
||
- Namespace `http://www.yokogawa.com/CI_Server/` (the one the manual shows) holds only the
|
||
**types**; with it the point is silently not monitored (ISS-032).
|
||
- In the Engineering Module's *Browse path*, **expand the item and pick its `Value` node**
|
||
(`Objects/<Section>/…/<Tag>/Value`, node ID `{"0":"Value","nsid":"<n>"}`); verified by the
|
||
user: *Last value* and *Data type* filled at once. Picking the item itself stores the
|
||
**object** (`{"nsid":"<n>"}`), which has no value (status 13, never monitored) (ISS-033).
|
||
For quick load prefer `{"0":"Value","itnm":"<item>"}`: it does not depend on `nsid`.
|
||
- `nsid` numbers change when the item is deleted and created again (e.g. sample reload).
|
||
|
||
A point that is not accepted shows `REVISED_SAMPLING_INTERVAL` 0 in `OPCUAC_POINT_DF` and the
|
||
log line `Can't find Point [<point>] in subscription` when changed; a monitored point gets the
|
||
revised interval (e.g. 1000).
|
||
|
||
**Browse the server from the command line** (station connected): export `OPCUAC_TAG_DF` with
|
||
a filter; start with an empty path, then `Objects`:
|
||
|
||
```
|
||
@SELECT
|
||
'OPC_STATION_NAME = "CIENG_UA" and OPC_TAG_PATH = "Objects"'
|
||
@OPCUAC_TAG_DF
|
||
```
|
||
|
||
Each record shows display name, namespace URI and node ID (inside `OPC_TAG_INFO`). Deeper
|
||
paths were not found yet on R1.03 (`Objects.CI-Eng-Sample` returned nothing).
|
||
|
||
R1.05: `OPCUAC_TAG_DF` (and `OPCUAC_TAG_CMPN_DF`) have two new Boolean fields, `REBROWSE`
|
||
(ask the server again) and `READ_NODE_INFO` (read node attributes while browsing; switching it
|
||
off is faster on slow links) (installed `opcuac_tag_df.dss`, verified 2026-10-08; not tried).
|
||
The point form has the matching *Read additional node information* check box, and F5 in the
|
||
expanded *Browse path* list rebrowses (IM 36K10E20 4th ed. §2.1.5).
|
||
|
||
**Data types (IM 36K10L45 5th ed. §10.3.4, from docs):** UInt32, Int64 and UInt64 map to Real
|
||
(no negatives for unsigned, no decimals), DateTime/UtcTime to String in the form
|
||
`YYYY-MM-DDThh:mm:ss.sssZ`, ExtensionObject only for EURange / EngineeringUnits, enumerations as
|
||
their Int32 value; one array element per point. A value that cannot be converted is logged and
|
||
the item gets status Bad.
|
||
|
||
**Model change events (IM 36K10L45 5th ed. §10.5, from docs):** the client reacts to the
|
||
server's `GeneralModelChangeEvent` (node or reference added: the point is recreated; deleted: the
|
||
item goes offline; external alarms are refreshed with ConditionRefresh). The coarse
|
||
`BaseModelChangeEvent` (recreate everything) is handled only with
|
||
`OPXC_BASE_MODEL_CHANGE_EVENT = YES`. Events within 10 s are handled once; the server must
|
||
support Read and Browse.
|
||
|
||
## 4. Certificate exchange (first connection; the user does it)
|
||
|
||
| Step | Where it shows | What the user does |
|
||
|---|---|---|
|
||
| 1. Client rejects the server | `OPXC-E-CER_NO_TRU … BadCertificateUntrusted` in `umhlog.log`; file `<thumbprint>.der` in `%TLS_ALLUSERS_PATH%\pki\opxuac\pkiclient\rejected` | Trust it: Engineering Module *OPC UA Client → Certificates → Rejected* → *Trusted*, or move the file to `…\pkiclient\trusted\certs` |
|
||
| 2. Server rejects the client | client log `BadSecurityChecksFailed`; file `CI_SERVER_OPCUA_CLIENT_<PROCESS> [<thumbprint>].der` in `…\pki\opxuas\pkiserver\rejected` (folder created now) | Move it to `…\pki\opxuas\pkiserver\trusted\certs` |
|
||
|
||
PowerShell: file names with `[ ]` need `-LiteralPath`, otherwise `Move-Item` silently does
|
||
nothing:
|
||
|
||
```powershell
|
||
Move-Item -LiteralPath "<rejected folder>\<file>.der" -Destination "<trusted folder>\"
|
||
```
|
||
|
||
The client retries every ~35 s (`OPXC_STATION_CON_TRY_INTERVAL` 30 s); then `OPXC-I-SRV_CONN`
|
||
and the status item goes to 1. Certificates and trust stay when the line is removed and loaded
|
||
again (verified: reload connected within 5 s without a new exchange). For an external server,
|
||
its certificate arrives the same way; the client certificate
|
||
(`…\pkiclient\own\certs\<host>_<PROCESS>.der`) must be trusted on that server.
|
||
|
||
From R1.05 the client warns in the Historical Alarm Overview and the UMH message log before its
|
||
own or the server's certificate expires (IM 36K10E20 4th ed. §2.2; lead time
|
||
`OPXC_CERT_EXP_PERIOD_WARN`, 2 months in the installed template). The own certificates made at
|
||
installation were valid for 5 years on the R1.05 test server (verified 2026-10-08).
|
||
|
||
## 5. Check
|
||
|
||
- `itmval -g -n CI-Eng-Sample.UA.COMM_OK` → 1; `UA.SRV_STATE` → 0 status 9;
|
||
`UA.LEVEL_COPY` follows `TANK1.LEVEL` within ~1 s (verified 55, 62.5, 71, 33, 44.4).
|
||
- Client log: `%TLS_LOG_PATH%\<PROCESS>.log` (`Successfully connected station`, errors with
|
||
status codes); server logs `OPXUAS.log`, `OpxUas_Sdk.log` (`CreateMonitoredItems`).
|
||
- Off-scan/on-scan: `OPCUAC_STATION_DF` `ON_SCAN` 0/1 with `dssqld -m` disconnects/reconnects.
|
||
|
||
## 6. Remove
|
||
|
||
Items (`76_`), then points, subscription, station (`77_`), then the line (`78_`, stops the
|
||
client process). Reset the OPC flags only if they were not there before.
|
||
|
||
## 7. Calling a method on an external OPC UA server (R1.04+, from docs)
|
||
|
||
Source: IM 36K10L45 5th ed. §10.6, App. 1.3–1.4; IM 36K10E20 4th ed. §2.1.6. Not practiced.
|
||
Installed on R1.05 (verified 2026-10-08): dataset `OPCUAC_METHOD_CALL2_DF`, loader
|
||
`opcuac_method_u0104`, AOG displays `AOG_UAC_Method_Demo`, `AOG_UAC_Method_Call`,
|
||
`AOG_UAC_MethodArg_Call(2)` with their symbols.
|
||
|
||
1. **Class** for the method object (sample Java class `UAC_MTD_JBASE`): attribute `MTD_KEY`
|
||
(holds the method name) and signals `MTD_TRG` (0 idle/done, 1 call, 2 failed), `MTD_RET`
|
||
(result code as text; its quality holds the numeric code), `MTD_IN_ARG_0…` and
|
||
`MTD_OUT_ARG_0…` (at most 10 each, same order and types as on the server). These names are
|
||
reserved in that class. Use a class with a unique name per method object (App. 1.4).
|
||
2. **Method** under the station (Engineering Module *Methods → Add method*, dataset
|
||
`OPCUAC_METHOD_CALL2_DF`, name `<station>:<method>`): `OPC_NAMESPACE`, `OPC_NODE_ID_TYPE`,
|
||
`OPC_NODE_ID`. If the server does not browse its method nodes: parent object node ID by hand
|
||
(`MANUAL_OBJ_OPC_NODE_ID`, `OBJ_OPC_NAMESPACE`, `OBJ_OPC_NODE_ID_TYPE`, `OBJ_OPC_NODE_ID`) and
|
||
argument types by hand (`MANUAL_ARGUMENT_CONFIGURATION`, `ARGUMENT_IN_n_TYPE` / `…OUT…`).
|
||
3. **Point**, one per method: *Input + Output*, namespace `CIX_UAC_MTD`, type STRING, node ID
|
||
`CIX_UAC_MTD`; connect it to the object's `MTD_TRG` signal (*Connected I/O point*). Set
|
||
`MTD_KEY` to the method name. The process area goes on `MTD_TRG` (the method form no longer
|
||
has one). `MTD_TRG` shows status UPD_OFFLINE.
|
||
4. **Symbol and display** for the class (see the AOG demo display), then trigger from there.
|
||
|
||
Upgrade from R1.03 (App. 1.3): R1.03 methods called through dataset fields
|
||
(`OPCUAC_METHOD_CALL_IN_DF` / `…_OUT_DF`, both gone in R1.05) stop working. Rebuild the class
|
||
with the `MTD_*` members (*Extended reset enabled*, then reset), rebuild symbols and displays,
|
||
and re-save (or copy and re-add) any method with String or Boolean input arguments.
|