diff --git a/examples/CI-Eng-Sample/01_section_df.qli b/examples/CI-Eng-Sample/01_section_df.qli index b8a5ad1..a2fa557 100644 --- a/examples/CI-Eng-Sample/01_section_df.qli +++ b/examples/CI-Eng-Sample/01_section_df.qli @@ -16,3 +16,4 @@ NAME,SECTION_PATH,SECTION_NAME,DESCRIPTION "CI-Eng-Sample.SYSTEM","CI-Eng-Sample","SYSTEM","Sample system monitoring" "CI-Eng-Sample.DEMO","CI-Eng-Sample","DEMO","Tutorial examples (class/object)" "CI-Eng-Sample.PLC1","CI-Eng-Sample","PLC1","Modbus loopback station CIENG_PLC" +"CI-Eng-Sample.UA","CI-Eng-Sample","UA","OPC UA loopback station CIENG_UA" diff --git a/examples/CI-Eng-Sample/02_item_df.qli b/examples/CI-Eng-Sample/02_item_df.qli index 6f78b41..d689ea3 100644 --- a/examples/CI-Eng-Sample/02_item_df.qli +++ b/examples/CI-Eng-Sample/02_item_df.qli @@ -21,3 +21,4 @@ LOW_LOW_LIMIT,LOW_LIMIT,HIGH_LIMIT,HIGH_HIGH_LIMIT,SCALE_LOW_LIMIT,SCALE_HIGH_LI "CI-Eng-Sample.SYSTEM.PROC_ALM","ALARM process (alm) running, from intmon","Integer","9",0,0,0,0,0,1 "CI-Eng-Sample.DEMO.COUNTER","Counter 1..100 driven by object DEMO.INCR1","Integer","999",0,0,0,0,0,100 "CI-Eng-Sample.PLC1.COMM_OK","Station CIENG_PLC communication (1 = good), status item","Boolean","",0,0,0,0,0,0 +"CI-Eng-Sample.UA.COMM_OK","Station CIENG_UA communication (1 = good), status item","Boolean","",0,0,0,0,0,0 diff --git a/examples/CI-Eng-Sample/12_opc_visible_df.qli b/examples/CI-Eng-Sample/12_opc_visible_df.qli new file mode 100644 index 0000000..1a9da98 --- /dev/null +++ b/examples/CI-Eng-Sample/12_opc_visible_df.qli @@ -0,0 +1,20 @@ +@LANGUAGE +ENGLISH + +@VERSION +1.03.00 + +! Make sections and TANK1.LEVEL visible (read-only) to OPC clients (OPC UA/DA/A&E servers). Load with dssqld -m. +! Every parent section must be OPC visible too. +@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 diff --git a/examples/CI-Eng-Sample/13_opcua_line_df.qli b/examples/CI-Eng-Sample/13_opcua_line_df.qli new file mode 100644 index 0000000..a3d8d18 --- /dev/null +++ b/examples/CI-Eng-Sample/13_opcua_line_df.qli @@ -0,0 +1,12 @@ +@LANGUAGE +ENGLISH + +@VERSION +1.03.00 + +! OPC UA client line; loading it creates and starts the client process OPXCIENG (name must start with OPX) +@FIELDS +NAME,DESCRIPTION,EQUIPMENT_MAN + +@OPCUAC_LINE_DF +"CIENG_UA_LINE","CI-Eng-Sample OPC UA loopback line","OPXCIENG" diff --git a/examples/CI-Eng-Sample/14_opcua_station_df.qli b/examples/CI-Eng-Sample/14_opcua_station_df.qli new file mode 100644 index 0000000..37d9f89 --- /dev/null +++ b/examples/CI-Eng-Sample/14_opcua_station_df.qli @@ -0,0 +1,27 @@ +@LANGUAGE +ENGLISH + +@VERSION +1.03.00 + +! OPC UA loopback: CI Server OPC UA client -> own OPC UA server (opc.tcp://localhost:34493) +! First connection needs a one-time certificate exchange (see README). +! CI Server entities: namespace urn:Yokogawa:CI_SERVER_OPC_UA_SERVER, string node id {"0":"Value","itnm":""} +@FIELDS +NAME,DESCRIPTION,LINE,USER_ANONYMOUS,MSG_SECURITY_01_MODE,MSG_SECURITY_01_POLICY,SERVER_01_ENDPOINT,STATUS_ITEM + +@OPCUAC_STATION_DF +"CIENG_UA","Loopback to own OPC UA server","CIENG_UA_LINE",1,"SignAndEncrypt","Basic256Sha256","opc.tcp://localhost:34493","CI-Eng-Sample.UA.COMM_OK" + +@FIELDS +NAME,STATION_NAME,SUBSCRIPTION_NAME,REQUESTED_PUBLISH_INTERVAL,DESCRIPTION + +@OPCUAC_SUBSCRIPTION_DF +"CIENG_UA:CIENG_SUB","CIENG_UA","CIENG_SUB",1000,"1 s subscription" + +@FIELDS +NAME,STATION,POINT,DESCRIPTION,SUBSCRIPTION,EXTERNAL_RELATION,OPC_NAMESPACE,OPC_NODE_ID_TYPE,OPC_NODE_ID + +@OPCUAC_POINT_DF +"CIENG_UA:LEVEL","CIENG_UA","LEVEL","TANK1.LEVEL via own OPC UA server","CIENG_SUB","Input","urn:Yokogawa:CI_SERVER_OPC_UA_SERVER","STRING","{""0"":""Value"",""itnm"":""CI-Eng-Sample.TANK1.LEVEL""}" +"CIENG_UA:SRV_STATE","CIENG_UA","SRV_STATE","Server/ServerStatus/State (0 = Running)","CIENG_SUB","Input","http://opcfoundation.org/UA/","NUMERIC","2259" diff --git a/examples/CI-Eng-Sample/15_item_opcua_df.qli b/examples/CI-Eng-Sample/15_item_opcua_df.qli new file mode 100644 index 0000000..8dcec98 --- /dev/null +++ b/examples/CI-Eng-Sample/15_item_opcua_df.qli @@ -0,0 +1,13 @@ +@LANGUAGE +ENGLISH + +@VERSION +1.03.00 + +! Items connected to OPC UA points of station CIENG_UA +@FIELDS +NAME,DESCRIPTION,ITEM_REP,VALUE_FORMAT,STATION,POINT + +@ITEM_DF +"CI-Eng-Sample.UA.LEVEL_COPY","TANK1.LEVEL read back through OPC UA","Real","999.9","CIENG_UA","LEVEL" +"CI-Eng-Sample.UA.SRV_STATE","OPC UA server state (0 = Running)","Integer","9","CIENG_UA","SRV_STATE" diff --git a/examples/CI-Eng-Sample/76_remove_item_opcua_df.qli b/examples/CI-Eng-Sample/76_remove_item_opcua_df.qli new file mode 100644 index 0000000..e5fdf27 --- /dev/null +++ b/examples/CI-Eng-Sample/76_remove_item_opcua_df.qli @@ -0,0 +1,13 @@ +@LANGUAGE +ENGLISH + +@VERSION +1.03.00 + +! Remove items connected to OPC UA points +@FIELDS +NAME + +@ITEM_DF +"CI-Eng-Sample.UA.LEVEL_COPY" +"CI-Eng-Sample.UA.SRV_STATE" diff --git a/examples/CI-Eng-Sample/77_remove_opcua_station_df.qli b/examples/CI-Eng-Sample/77_remove_opcua_station_df.qli new file mode 100644 index 0000000..37d8eb7 --- /dev/null +++ b/examples/CI-Eng-Sample/77_remove_opcua_station_df.qli @@ -0,0 +1,25 @@ +@LANGUAGE +ENGLISH + +@VERSION +1.03.00 + +! Remove OPC UA points, subscription, station +@FIELDS +NAME + +@OPCUAC_POINT_DF +"CIENG_UA:LEVEL" +"CIENG_UA:SRV_STATE" + +@FIELDS +NAME + +@OPCUAC_SUBSCRIPTION_DF +"CIENG_UA:CIENG_SUB" + +@FIELDS +NAME + +@OPCUAC_STATION_DF +"CIENG_UA" diff --git a/examples/CI-Eng-Sample/78_remove_opcua_line_df.qli b/examples/CI-Eng-Sample/78_remove_opcua_line_df.qli new file mode 100644 index 0000000..1bc3ffc --- /dev/null +++ b/examples/CI-Eng-Sample/78_remove_opcua_line_df.qli @@ -0,0 +1,12 @@ +@LANGUAGE +ENGLISH + +@VERSION +1.03.00 + +! Remove the OPC UA client line (stops process OPXCIENG) +@FIELDS +NAME + +@OPCUAC_LINE_DF +"CIENG_UA_LINE" diff --git a/examples/CI-Eng-Sample/91_remove_item_df.qli b/examples/CI-Eng-Sample/91_remove_item_df.qli index 5c33008..bf4d425 100644 --- a/examples/CI-Eng-Sample/91_remove_item_df.qli +++ b/examples/CI-Eng-Sample/91_remove_item_df.qli @@ -19,4 +19,5 @@ NAME "CI-Eng-Sample.SYSTEM.PROC_ALM" "CI-Eng-Sample.DEMO.COUNTER" "CI-Eng-Sample.PLC1.COMM_OK" +"CI-Eng-Sample.UA.COMM_OK" "CI-Eng-Sample.TEMPLATES.TPL_REAL" diff --git a/examples/CI-Eng-Sample/92_remove_section_df.qli b/examples/CI-Eng-Sample/92_remove_section_df.qli index 7070088..5ad8ce6 100644 --- a/examples/CI-Eng-Sample/92_remove_section_df.qli +++ b/examples/CI-Eng-Sample/92_remove_section_df.qli @@ -13,6 +13,7 @@ NAME "CI-Eng-Sample.PUMP1" "CI-Eng-Sample.SYSTEM" "CI-Eng-Sample.PLC1" +"CI-Eng-Sample.UA" "CI-Eng-Sample.DEMO" "CI-Eng-Sample.TEMPLATES" "CI-Eng-Sample" diff --git a/examples/CI-Eng-Sample/README.md b/examples/CI-Eng-Sample/README.md index dab3942..5f84a03 100644 --- a/examples/CI-Eng-Sample/README.md +++ b/examples/CI-Eng-Sample/README.md @@ -60,6 +60,13 @@ cmd /c "\examples\CI-Eng-Sample\remove.cmd" | `CIENG_MB_LINE` | Modbus line (TCP/IP) | Equipment manager `EQPCIENG` (created and started by loading the line) | | `CIENG_PLC` | Modbus station | Open Modbus/TCP to `localhost:5020`, unit 1, output method *On change and connect* | | `CIENG_SCAN1S` | Modbus scan type | 1000 ms | +| `CI-Eng-Sample.UA` | Section | OPC UA loopback station | +| `CI-Eng-Sample.UA.COMM_OK` | Item, Boolean | Status item of station `CIENG_UA` (1 = connected) | +| `CI-Eng-Sample.UA.LEVEL_COPY` | Item, Real | `TANK1.LEVEL` read back through CI Server's own OPC UA server | +| `CI-Eng-Sample.UA.SRV_STATE` | Item, Integer | OPC UA server state node (ns 0, i=2259), 0 = Running | +| `CIENG_UA_LINE` | OPC UA client line | Client process `OPXCIENG` (created and started by loading the line) | +| `CIENG_UA` | OPC UA station | `opc.tcp://localhost:34493`, Basic256Sha256 / SignAndEncrypt, anonymous; subscription `CIENG_SUB` (1 s); points `LEVEL`, `SRV_STATE` | +| OPC visible | Flags | Sections `CI-Eng-Sample`, `TANK1` and item `TANK1.LEVEL` are OPC visible, item read-only (`12_opc_visible_df.qli`) | | `CIENG_VIEWER` | Authorization group | Read-only: `ITEM_READ`, `SECTION_READ`, `ALARM_CURRENT_READ`, `ALARM_CHRONO_READ`. No users are created by the sample. | Items created by objects (`TANK1.CALC.VOLUME`, `TANK1.JFLOW.sPerMin`) and their sections are @@ -80,6 +87,8 @@ New items start with status 13 (`NOT INIT`) until a value is written. | `05_trigger_df.qli`, `06_class_df.qli`, `07_object_df.qli` | Trigger group; classes (source in the `METHOD` memo, `@"` … `"@`, `COMPILE` 1; Traditional and Java); objects (`ATTR_VALUE_1` = prompt answer) | | `08_auth_group_df.qli` | Authorization group (`AUTH_GROUP_DF`) | | `09_modbus_line_df.qli`, `10_modbus_station_df.qli`, `11_item_eqp_df.qli` | Modbus line; station, scan type, points; items connected to points | +| `12_opc_visible_df.qli` | OPC visible / read flags (loaded with `dssqld -m`) | +| `13_opcua_line_df.qli`, `14_opcua_station_df.qli`, `15_item_opcua_df.qli` | OPC UA client line; station, subscription, points; connected items | | `equipment/eqpciengslv_start.cmd`, `_stop.cmd` | Start/stop the Modbus slave mirror (copy to `tls\com`) | | `80_`…`92_remove_*.qli` | Names to delete, in reverse order | | `load.cmd`, `remove.cmd` | Run the steps in the right order | @@ -101,6 +110,22 @@ start eqpmdcslvtcp -n EQPMDCSLVTCP -p 5020 Remove the two files from `tls\com` when the sample is removed. See skill `equipment`, task `modbus-station.md`. +## OPC UA loopback (station CIENG_UA) + +`CIENG_UA` is CI Server's OPC UA client connected to CI Server's own OPC UA server, so no +external server is needed. The **first** connection on a system needs a one-time certificate +exchange, done by the user (skill `data-access`, task `opcua-client.md` §4): + +1. After loading, the client logs `OPXC-E-CER_NO_TRU`; trust the server certificate in + `%TLS_ALLUSERS_PATH%\pki\opxuac\pkiclient\rejected` (Engineering Module, or move it to + `…\pkiclient\trusted\certs`). +2. The server then rejects the client; move `CI_SERVER_OPCUA_CLIENT_OPXCIENG […].der` from + `%TLS_ALLUSERS_PATH%\pki\opxuas\pkiserver\rejected` to `…\pkiserver\trusted\certs` + (PowerShell: `Move-Item -LiteralPath`, the name contains brackets). + +Then `UA.COMM_OK` = 1 and `UA.LEVEL_COPY` follows `TANK1.LEVEL`. The trust is kept when the +sample is removed and loaded again. + ## Monitoring processes (optional) `monitoring/` holds the lines to add to the setup files in `%TLS_ROOT_PATH%\tls\sup\` so that diff --git a/examples/CI-Eng-Sample/load.cmd b/examples/CI-Eng-Sample/load.cmd index bfa4197..58bf228 100644 --- a/examples/CI-Eng-Sample/load.cmd +++ b/examples/CI-Eng-Sample/load.cmd @@ -24,3 +24,12 @@ echo Waiting 15 seconds for equipment manager EQPCIENG to start... powershell -NoProfile -Command "Start-Sleep -Seconds 15" dssqld -i 10_modbus_station_df.qli -l 10_modbus_station_df.qlo dssqld -i 11_item_eqp_df.qli -l 11_item_eqp_df.qlo +rem OPC: make TANK1.LEVEL and its sections visible to OPC clients (modify existing records) +dssqld -m 12_opc_visible_df.qli -l 12_opc_visible_df.qlo +rem OPC UA loopback: client line (starts OPXCIENG), station/subscription/points, connected items. +rem The first connection needs a one-time certificate exchange (see README). +dssqld -i 13_opcua_line_df.qli -l 13_opcua_line_df.qlo +echo Waiting 10 seconds for OPC UA client OPXCIENG to start... +powershell -NoProfile -Command "Start-Sleep -Seconds 10" +dssqld -i 14_opcua_station_df.qli -l 14_opcua_station_df.qlo +dssqld -i 15_item_opcua_df.qli -l 15_item_opcua_df.qlo diff --git a/examples/CI-Eng-Sample/remove.cmd b/examples/CI-Eng-Sample/remove.cmd index c354c05..486236c 100644 --- a/examples/CI-Eng-Sample/remove.cmd +++ b/examples/CI-Eng-Sample/remove.cmd @@ -5,6 +5,9 @@ rem Order: object, class, trigger group, storage links, stop + delete storage gr rem A storage group with an active unit cannot be deleted (HIS-E-GROUPHASUNT), so the rem group first gets a stop time one minute ahead; the script waits until it has passed. cd /d "%~dp0" +dssqld -r 76_remove_item_opcua_df.qli -l 76_remove_item_opcua_df.qlo +dssqld -r 77_remove_opcua_station_df.qli -l 77_remove_opcua_station_df.qlo +dssqld -r 78_remove_opcua_line_df.qli -l 78_remove_opcua_line_df.qlo dssqld -r 80_remove_item_eqp_df.qli -l 80_remove_item_eqp_df.qlo dssqld -r 81_remove_modbus_station_df.qli -l 81_remove_modbus_station_df.qlo dssqld -r 82_remove_modbus_line_df.qli -l 82_remove_modbus_line_df.qlo