From e62d83b02478897f331f2b58556c9e560babaf6b Mon Sep 17 00:00:00 2001 From: cliu Date: Thu, 1 Oct 2026 15:47:38 +1000 Subject: [PATCH] Add operator layout CIENG_Operator and navigation display CIENG_Menu to CI-Eng-Sample Co-Authored-By: Claude Opus 5.5 --- examples/CI-Eng-Sample/README.md | 360 +++++++++--------- .../CI-Eng-Sample/displays/CIENG_Menu.xml | 97 +++++ .../CI-Eng-Sample/displays/CIENG_Tank.xml | 53 +-- .../displays/deploy_displays.cmd | 2 + .../displays/remove_displays.cmd | 4 +- .../CI-Eng-Sample/layouts/CIENG_Operator.xml | 184 +++++++++ examples/CI-Eng-Sample/layouts/layout.ps1 | 34 ++ 7 files changed, 536 insertions(+), 198 deletions(-) create mode 100644 examples/CI-Eng-Sample/displays/CIENG_Menu.xml create mode 100644 examples/CI-Eng-Sample/layouts/CIENG_Operator.xml create mode 100644 examples/CI-Eng-Sample/layouts/layout.ps1 diff --git a/examples/CI-Eng-Sample/README.md b/examples/CI-Eng-Sample/README.md index 79861a1..146dc5e 100644 --- a/examples/CI-Eng-Sample/README.md +++ b/examples/CI-Eng-Sample/README.md @@ -1,173 +1,187 @@ -# CI-Eng-Sample - -A small, invented sample project that anyone with this repo can load into a CI Server -**R1.03** test system. Skills use its names in their examples, and every skill task is -re-tested against it so that no other project is needed. - -Built and tested on CI Server R1.03.00 (unlicensed test system), 2026-09-30. - -## Load and remove - -Test systems only: loading writes to the CI Server database. CI Server must be running. -From an elevated prompt, call the scripts by full path (a bare `load.cmd` may not be found -from the current folder): - -``` -cmd /c "\examples\CI-Eng-Sample\load.cmd" -cmd /c "\examples\CI-Eng-Sample\remove.cmd" -``` - -- Each step prints a summary and writes a `.qlo` listing; check that `Errors` is 0. -- **Restart CI Server after loading** (stop, then start the CI Service): a new storage group - stores no history until CI Server restarts. -- `load.cmd` on a system that already has the project reports `Exists` and changes nothing. -- `remove.cmd` takes about 1½ minutes: a storage group can only be deleted after its stop time - has passed, so the script sets a stop time one minute ahead and waits. Removing the group - also deletes its history. - -## Current contents - -| Name | Kind | Details | -|---|---|---| -| `CI-Eng-Sample` | Section | Top level | -| `CI-Eng-Sample.TANK1`, `.PUMP1`, `.SYSTEM` | Sections | Tank, pump, system monitoring | -| `CI-Eng-Sample.TANK1.LEVEL` | Item, Real | %, format `999.9`, limits LL 10 / L 20 / H 80 / HH 90, scale 0–100, stored in `CIENG_EVENT`; alarming on (ack type `CIENG_ACK`, area `CIENG_TANKS`; `16_item_alarm_df.qli`) | -| `CI-Eng-Sample.TANK1.INFLOW` | Item, Real | m3/h, format `9999.9`, scale 0–500, stored in `CIENG_EVENT` | -| `CI-Eng-Sample.PUMP1.RUNNING` | Item, Boolean | | -| `CI-Eng-Sample.PUMP1.MODE` | Item, Integer | 0 manual, 1 auto | -| `CI-Eng-Sample.SYSTEM.CPU_LOAD` | Item, Real | Target for `intcpumon` | -| `CI-Eng-Sample.SYSTEM.DISK_C` | Item, Real | Target for `intdskmon` (reports **used** %) | -| `CI-Eng-Sample.SYSTEM.PING_LOCALHOST` | Item, Integer | Target for `inttcpmon` (1 = reachable) | -| `CI-Eng-Sample.SYSTEM.PROC_ALM` | Item, Integer | Target for `intmon` (1 = `alm` process running) | -| `CI-Eng-Sample.PUMP1.RUNNING.RUN_SECONDS` | Sub-item, Integrator | Running time in seconds (adds value × integration granule, `itm_int_secs` in `itm.sup`, default 1 s) | -| `CI-Eng-Sample.TANK1.LEVEL.MAX` | Sub-item, Min-Max | Highest level seen | -| `CI-Eng-Sample.DEMO` | Section | Tutorial examples | -| `CI-Eng-Sample.DEMO.COUNTER` | Item, Integer | Counts 1…100, one step per second, written by `DEMO.INCR1` | -| `CIENG_1S` | Trigger group | Every second | -| `CIENG_INCR` | Class (traditional) | Increments `DEMO.COUNTER`, wraps at 100; compiled on load | -| `CI-Eng-Sample.DEMO.INCR1` | Object | Instance of `CIENG_INCR` | -| `CI-Eng-Sample.TEMPLATES` | Section | Template items for classes | -| `CI-Eng-Sample.TEMPLATES.TPL_REAL` | Item, Real | Template for items that objects create (format `9999.9`, scale 0–1000) | -| `CIENG_TANK` | Class (traditional) | Prompt *Tank capacity (m3)*; signal `LEVEL` = `.LEVEL` (trigger on value); creates `.VOLUME` from `TPL_REAL`; volume = level × capacity / 100; logs when the level crosses 80; refuses capacity ≤ 0 | -| `CI-Eng-Sample.TANK1.CALC` | Object | `CIENG_TANK`, capacity 200; creates section `TANK1.CALC` and item `TANK1.CALC.VOLUME` | -| `CIENG_JFLOW` | Class (Java) | Attaches `.INFLOW`; creates `.sPerMin` = inflow / 60; logs each change | -| `CI-Eng-Sample.TANK1.JFLOW` | Object | `CIENG_JFLOW`; creates item `TANK1.JFLOW.sPerMin` (mixed case, as the Java identifier) | -| `CIENG_EVENT` | Item storage group | Event/Item, lifetime 1 week, rollover 1 day | -| `CIENG_SCAN10S` | Item storage group | Scan/Time every 10 s with quality, priority 10 (source for aggregation), lifetime 1 day, rollover 1 hour; `TANK1.LEVEL`, `TANK1.INFLOW` | -| `CIENG_AGG` | Item storage group | Aggregation 30 min + hourly, lifetime 4 weeks, rollover 1 week; `TANK1.LEVEL` max/min/average (read with `INTERPOLATION = "30Minutes"` / `"Hour"`, `ATTRIBUTE = "Maximum"` …) | -| `CI-Eng-Sample.PLC1` | Section | Modbus loopback station | -| `CI-Eng-Sample.PLC1.COMM_OK` | Item, Boolean | Status item of station `CIENG_PLC` (1 = communicating, status 22 when off-scan) | -| `CI-Eng-Sample.PLC1.SETPOINT` / `.READBACK` | Items, Integer | Written to holding register 1 (`RO:1`) / read from input register 1 (`RI:1`), same memory | -| `CI-Eng-Sample.PLC1.CMD` / `.FEEDBACK` | Items, Boolean | Written to coil 1 (`DO:1`) / read from input bit 1 (`DI:1`), same memory | -| `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_ACK` | Acknowledgement type | Every alarm needs an acknowledgement; return to normal automatic only if the alarm was acknowledged (same matrix as `MANUAL`) | -| `CIENG_TANKS` | Area of interest | Label for tank items (`TANK1.LEVEL` `AOI_1`) | -| `CIENG_TANK1` | Alarm selection area | `SECTION = "CI-Eng-Sample.TANK1"`, compiled on load | -| `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 -deleted with the objects; they are not in `02_item_df.qli`. - -All items except `PLC1.*` are internal (no station). The `PLC1` station talks to CI Server's own Modbus slave mirror (see below), so no PLC is needed either. -New items start with status 13 (`NOT INIT`) until a value is written. - -## Files - -| File | Purpose | -|---|---| -| `01_section_df.qli` | Sections (`SECTION_DF`); parents before children | -| `02_item_df.qli` | Items (`ITEM_DF`) | -| `02b_sub_item_df.qli` | Sub-items (`SUB_ITEM_DF`) | -| `03_his_group_df.qli` | Item storage groups (`HIS_GROUP_DF`): event, scan, aggregation | -| `04_item_his_df.qli` | Items in the storage group (`ITEM_HIS_DF`, name `:`) | -| `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 | -| `01b_alarm_df.qli` | Alarm definitions: acknowledgement type, area of interest, alarm selection area (`ALARM_ACK_DF`, `ALARM_AOI_DF`, `ALARM_ASA_DF`) | -| `16_item_alarm_df.qli` | Switch on alarming for `TANK1.LEVEL` (loaded with `dssqld -m`) | -| `equipment/eqpciengslv_start.cmd`, `_stop.cmd` | Start/stop the Modbus slave mirror (copy to `tls\com`) | -| `76_`…`93_remove_*.qli` | Names to delete, in reverse order (alarm definitions last, `93`) | -| `load.cmd`, `remove.cmd` | Run the steps in the right order | -| `displays/CIENG_Tank.xml` | Display (HTML mode): title, number field on `TANK1.LEVEL`, alarm overview, trend of `TANK1.LEVEL` | -| `displays/deploy_displays.cmd`, `remove_displays.cmd` | Copy the display into the operator interface and export its HTML version / delete both | -| `monitoring/*.sup.txt` | Setup-file lines for the monitoring processes (not applied by `load.cmd`) | - -## Modbus slave mirror (for station CIENG_PLC) - -`CIENG_PLC` reads and writes CI Server's own Modbus slave: `eqpmdcmem` (slave memory) and -`eqpmdcslvtcp` (Modbus TCP on port 5020). Without them the station reports bad communication -(`COMM_OK` = 0) but everything loads. To start them with CI Server, an administrator copies -`equipment/eqpciengslv_start.cmd` and `eqpciengslv_stop.cmd` to `%TLS_ROOT_PATH%\tls\com`; -for a quick test they can also be started by hand from a normal prompt: - -``` -start eqpmdcmem -n EQPMDCMEM -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. - -## Alarms (TANK1.LEVEL) - -`TANK1.LEVEL` raises HIGH above 80 (Alarm 2, priority 2) and HIGH HIGH above 90 (Alarm 3, -priority 1). To try it on a test system: `itmval -p -n CI-Eng-Sample.TANK1.LEVEL -v 85`, export -`ALARM_CURRENT` (filter on `ITEM_NAME`), acknowledge with `dssqld -m` on `ALARM_CURRENT` -(`NAME`, `ACK` 1), write the level back below 80. See skill `alarm-management`, task -`item-alarming.md`. - -## Display (optional) - -After `load.cmd`, run `displays\deploy_displays.cmd` (no admin rights) and open -`http://localhost:8080/mobileoperator/?d=CIENG_Tank` (CI Server login), or open `CIENG_Tank` in -CI View / the Edit Module. `displays emove_displays.cmd` deletes it again. See skill -`graphics`. - -## Monitoring processes (optional) - -`monitoring/` holds the lines to add to the setup files in `%TLS_ROOT_PATH%\tls\sup\` so that -`intcpumon`, `intdskmon`, `inttcpmon`, `intmon` and `intspawn` write into the `SYSTEM` items. -These change the system's own setup files: back the files up first and restore them after -testing. See the `system-management` skill, task `monitoring-processes.md`. - -## Planned additions - -| Phase | Adds | -|---|---| -| 10 | A symbol (the display `CIENG_Tank` exists) | -| 11 | A report | - -## Rules - -- Test systems only; invented names only, no real plant or customer data. -- Keep the load order: sections → template items → classes (compiled) → objects → other - items → storage groups → items in storage groups (IM 36K10J10 §5.6). Keep `remove.cmd` in - reverse order. -- Every file notes the CI Server version it was built and tested on. +# CI-Eng-Sample + +A small, invented sample project that anyone with this repo can load into a CI Server +**R1.03** test system. Skills use its names in their examples, and every skill task is +re-tested against it so that no other project is needed. + +Built and tested on CI Server R1.03.00 (unlicensed test system), 2026-09-30. + +## Load and remove + +Test systems only: loading writes to the CI Server database. CI Server must be running. +From an elevated prompt, call the scripts by full path (a bare `load.cmd` may not be found +from the current folder): + +``` +cmd /c "\examples\CI-Eng-Sample\load.cmd" +cmd /c "\examples\CI-Eng-Sample\remove.cmd" +``` + +- Each step prints a summary and writes a `.qlo` listing; check that `Errors` is 0. +- **Restart CI Server after loading** (stop, then start the CI Service): a new storage group + stores no history until CI Server restarts. +- `load.cmd` on a system that already has the project reports `Exists` and changes nothing. +- `remove.cmd` takes about 1½ minutes: a storage group can only be deleted after its stop time + has passed, so the script sets a stop time one minute ahead and waits. Removing the group + also deletes its history. + +## Current contents + +| Name | Kind | Details | +|---|---|---| +| `CI-Eng-Sample` | Section | Top level | +| `CI-Eng-Sample.TANK1`, `.PUMP1`, `.SYSTEM` | Sections | Tank, pump, system monitoring | +| `CI-Eng-Sample.TANK1.LEVEL` | Item, Real | %, format `999.9`, limits LL 10 / L 20 / H 80 / HH 90, scale 0–100, stored in `CIENG_EVENT`; alarming on (ack type `CIENG_ACK`, area `CIENG_TANKS`; `16_item_alarm_df.qli`) | +| `CI-Eng-Sample.TANK1.INFLOW` | Item, Real | m3/h, format `9999.9`, scale 0–500, stored in `CIENG_EVENT` | +| `CI-Eng-Sample.PUMP1.RUNNING` | Item, Boolean | | +| `CI-Eng-Sample.PUMP1.MODE` | Item, Integer | 0 manual, 1 auto | +| `CI-Eng-Sample.SYSTEM.CPU_LOAD` | Item, Real | Target for `intcpumon` | +| `CI-Eng-Sample.SYSTEM.DISK_C` | Item, Real | Target for `intdskmon` (reports **used** %) | +| `CI-Eng-Sample.SYSTEM.PING_LOCALHOST` | Item, Integer | Target for `inttcpmon` (1 = reachable) | +| `CI-Eng-Sample.SYSTEM.PROC_ALM` | Item, Integer | Target for `intmon` (1 = `alm` process running) | +| `CI-Eng-Sample.PUMP1.RUNNING.RUN_SECONDS` | Sub-item, Integrator | Running time in seconds (adds value × integration granule, `itm_int_secs` in `itm.sup`, default 1 s) | +| `CI-Eng-Sample.TANK1.LEVEL.MAX` | Sub-item, Min-Max | Highest level seen | +| `CI-Eng-Sample.DEMO` | Section | Tutorial examples | +| `CI-Eng-Sample.DEMO.COUNTER` | Item, Integer | Counts 1…100, one step per second, written by `DEMO.INCR1` | +| `CIENG_1S` | Trigger group | Every second | +| `CIENG_INCR` | Class (traditional) | Increments `DEMO.COUNTER`, wraps at 100; compiled on load | +| `CI-Eng-Sample.DEMO.INCR1` | Object | Instance of `CIENG_INCR` | +| `CI-Eng-Sample.TEMPLATES` | Section | Template items for classes | +| `CI-Eng-Sample.TEMPLATES.TPL_REAL` | Item, Real | Template for items that objects create (format `9999.9`, scale 0–1000) | +| `CIENG_TANK` | Class (traditional) | Prompt *Tank capacity (m3)*; signal `LEVEL` = `.LEVEL` (trigger on value); creates `.VOLUME` from `TPL_REAL`; volume = level × capacity / 100; logs when the level crosses 80; refuses capacity ≤ 0 | +| `CI-Eng-Sample.TANK1.CALC` | Object | `CIENG_TANK`, capacity 200; creates section `TANK1.CALC` and item `TANK1.CALC.VOLUME` | +| `CIENG_JFLOW` | Class (Java) | Attaches `.INFLOW`; creates `.sPerMin` = inflow / 60; logs each change | +| `CI-Eng-Sample.TANK1.JFLOW` | Object | `CIENG_JFLOW`; creates item `TANK1.JFLOW.sPerMin` (mixed case, as the Java identifier) | +| `CIENG_EVENT` | Item storage group | Event/Item, lifetime 1 week, rollover 1 day | +| `CIENG_SCAN10S` | Item storage group | Scan/Time every 10 s with quality, priority 10 (source for aggregation), lifetime 1 day, rollover 1 hour; `TANK1.LEVEL`, `TANK1.INFLOW` | +| `CIENG_AGG` | Item storage group | Aggregation 30 min + hourly, lifetime 4 weeks, rollover 1 week; `TANK1.LEVEL` max/min/average (read with `INTERPOLATION = "30Minutes"` / `"Hour"`, `ATTRIBUTE = "Maximum"` …) | +| `CI-Eng-Sample.PLC1` | Section | Modbus loopback station | +| `CI-Eng-Sample.PLC1.COMM_OK` | Item, Boolean | Status item of station `CIENG_PLC` (1 = communicating, status 22 when off-scan) | +| `CI-Eng-Sample.PLC1.SETPOINT` / `.READBACK` | Items, Integer | Written to holding register 1 (`RO:1`) / read from input register 1 (`RI:1`), same memory | +| `CI-Eng-Sample.PLC1.CMD` / `.FEEDBACK` | Items, Boolean | Written to coil 1 (`DO:1`) / read from input bit 1 (`DI:1`), same memory | +| `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_ACK` | Acknowledgement type | Every alarm needs an acknowledgement; return to normal automatic only if the alarm was acknowledged (same matrix as `MANUAL`) | +| `CIENG_TANKS` | Area of interest | Label for tank items (`TANK1.LEVEL` `AOI_1`) | +| `CIENG_TANK1` | Alarm selection area | `SECTION = "CI-Eng-Sample.TANK1"`, compiled on load | +| `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 +deleted with the objects; they are not in `02_item_df.qli`. + +All items except `PLC1.*` are internal (no station). The `PLC1` station talks to CI Server's own Modbus slave mirror (see below), so no PLC is needed either. +New items start with status 13 (`NOT INIT`) until a value is written. + +## Files + +| File | Purpose | +|---|---| +| `01_section_df.qli` | Sections (`SECTION_DF`); parents before children | +| `02_item_df.qli` | Items (`ITEM_DF`) | +| `02b_sub_item_df.qli` | Sub-items (`SUB_ITEM_DF`) | +| `03_his_group_df.qli` | Item storage groups (`HIS_GROUP_DF`): event, scan, aggregation | +| `04_item_his_df.qli` | Items in the storage group (`ITEM_HIS_DF`, name `:`) | +| `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 | +| `01b_alarm_df.qli` | Alarm definitions: acknowledgement type, area of interest, alarm selection area (`ALARM_ACK_DF`, `ALARM_AOI_DF`, `ALARM_ASA_DF`) | +| `16_item_alarm_df.qli` | Switch on alarming for `TANK1.LEVEL` (loaded with `dssqld -m`) | +| `equipment/eqpciengslv_start.cmd`, `_stop.cmd` | Start/stop the Modbus slave mirror (copy to `tls\com`) | +| `76_`…`93_remove_*.qli` | Names to delete, in reverse order (alarm definitions last, `93`) | +| `load.cmd`, `remove.cmd` | Run the steps in the right order | +| `displays/CIENG_Tank.xml` | Display (HTML mode): title, number field on `TANK1.LEVEL`, alarm overview, trend of `TANK1.LEVEL`, button *Operator layout* | +| `displays/CIENG_Menu.xml` | Navigation display (200 x 700): *Tank 1*, *Current Alarm* (main frame), *Tank 1 popup* (layout `popup`) | +| `layouts/CIENG_Operator.xml`, `layouts/layout.ps1` | Operator layout block and the script that adds/removes it in `Layouts.xml` | +| `displays/deploy_displays.cmd`, `remove_displays.cmd` | Copy the displays into the operator interface and export their HTML versions / delete them | +| `monitoring/*.sup.txt` | Setup-file lines for the monitoring processes (not applied by `load.cmd`) | + +## Modbus slave mirror (for station CIENG_PLC) + +`CIENG_PLC` reads and writes CI Server's own Modbus slave: `eqpmdcmem` (slave memory) and +`eqpmdcslvtcp` (Modbus TCP on port 5020). Without them the station reports bad communication +(`COMM_OK` = 0) but everything loads. To start them with CI Server, an administrator copies +`equipment/eqpciengslv_start.cmd` and `eqpciengslv_stop.cmd` to `%TLS_ROOT_PATH%\tls\com`; +for a quick test they can also be started by hand from a normal prompt: + +``` +start eqpmdcmem -n EQPMDCMEM +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. + +## Alarms (TANK1.LEVEL) + +`TANK1.LEVEL` raises HIGH above 80 (Alarm 2, priority 2) and HIGH HIGH above 90 (Alarm 3, +priority 1). To try it on a test system: `itmval -p -n CI-Eng-Sample.TANK1.LEVEL -v 85`, export +`ALARM_CURRENT` (filter on `ITEM_NAME`), acknowledge with `dssqld -m` on `ALARM_CURRENT` +(`NAME`, `ACK` 1), write the level back below 80. See skill `alarm-management`, task +`item-alarming.md`. + +## Displays and layout (optional) + +No admin rights needed. After `load.cmd`: + +1. `displays\deploy_displays.cmd` copies `CIENG_Tank` and `CIENG_Menu` into the operator + interface and creates their HTML versions. +2. `powershell -ExecutionPolicy Bypass -File layouts\layout.ps1` adds the layout + `CIENG_Operator` to `Layouts.xml` (first run saves `Layouts-before-CIENG.xml`). + **Restart the Operator Interface** afterwards: it reads the layouts only at start. +3. Operator Interface (desktop): open `CIENG_Tank` from the display box and click + **Operator layout** - a second window opens with the sample menu (File / View / Displays), + toolbar, `CIENG_Menu` on the left, `CIENG_Tank` in the main frame `default` and the alarm + banner. HTML display (web): `http://localhost:8080/mobileoperator/?d=CIENG_Tank&l=CIENG_Operator` + (CI Server login). + +Remove: `layouts\layout.ps1 -Remove` (restores the file exactly) and +`displays\remove_displays.cmd`. Close the displays in the Edit Module first. See skill +`graphics`. + +## Monitoring processes (optional) + +`monitoring/` holds the lines to add to the setup files in `%TLS_ROOT_PATH%\tls\sup\` so that +`intcpumon`, `intdskmon`, `inttcpmon`, `intmon` and `intspawn` write into the `SYSTEM` items. +These change the system's own setup files: back the files up first and restore them after +testing. See the `system-management` skill, task `monitoring-processes.md`. + +## Planned additions + +| Phase | Adds | +|---|---| +| 10 | A symbol and a faceplate popup (displays and the operator layout exist) | +| 11 | A report | + +## Rules + +- Test systems only; invented names only, no real plant or customer data. +- Keep the load order: sections → template items → classes (compiled) → objects → other + items → storage groups → items in storage groups (IM 36K10J10 §5.6). Keep `remove.cmd` in + reverse order. +- Every file notes the CI Server version it was built and tested on. diff --git a/examples/CI-Eng-Sample/displays/CIENG_Menu.xml b/examples/CI-Eng-Sample/displays/CIENG_Menu.xml new file mode 100644 index 0000000..85dac15 --- /dev/null +++ b/examples/CI-Eng-Sample/displays/CIENG_Menu.xml @@ -0,0 +1,97 @@ + + + + + + true + 200 + 700 + 2 + + + + + + + + + + + 500 + true + false + + 2 + Overview + Always shown + true + 10.0 + + + 3 + Rough + Shown when viewing viewing a large area + true + 25.0 + + + 4 + Standard + Shown when using the default view setting + true + 100.0 + + + 5 + Detail + Shown only when viewing a small area + true + 400.0 + + + 6 + Intricacies + Shown only when viewing a very small area + true + 1000.0 + + + 1 + Layer1 + + 3 + + + + + \ No newline at end of file diff --git a/examples/CI-Eng-Sample/displays/CIENG_Tank.xml b/examples/CI-Eng-Sample/displays/CIENG_Tank.xml index 4582d2e..ab44bb9 100644 --- a/examples/CI-Eng-Sample/displays/CIENG_Tank.xml +++ b/examples/CI-Eng-Sample/displays/CIENG_Tank.xml @@ -1,12 +1,23 @@ - + + + + + + + + + + + + true 1984 760 - 4 + 8 @@ -59,7 +70,7 @@ 1 Layer1 - 4 + 5 7 CI-Eng-Sample Tank 1 @@ -92,9 +103,7 @@ 9 - - - + 10 @@ -107,9 +116,7 @@ 0 0 - - - + @@ -198,9 +205,7 @@ true 0 true - - - + 256 @@ -468,20 +473,20 @@ 344.0 0.0 0.0 + + + \ No newline at end of file diff --git a/examples/CI-Eng-Sample/displays/deploy_displays.cmd b/examples/CI-Eng-Sample/displays/deploy_displays.cmd index 84e5039..0d32b6e 100644 --- a/examples/CI-Eng-Sample/displays/deploy_displays.cmd +++ b/examples/CI-Eng-Sample/displays/deploy_displays.cmd @@ -7,4 +7,6 @@ cd /d "%~dp0" set WAP=%TLS_WAP_PATH% if not defined TLS_WAP_PATH set WAP=C:\Users\Public\Yokogawa\tls\wap copy /y CIENG_Tank.xml "%WAP%\cfg\operatorInterfaces\DEPLOY\displays\" +copy /y CIENG_Menu.xml "%WAP%\cfg\operatorInterfaces\DEPLOY\displays\" call jwuiutl.cmd -e HTML -i -f DEPLOY CIENG_Tank +call jwuiutl.cmd -e HTML -i -f DEPLOY CIENG_Menu diff --git a/examples/CI-Eng-Sample/displays/remove_displays.cmd b/examples/CI-Eng-Sample/displays/remove_displays.cmd index 27c4096..51c164a 100644 --- a/examples/CI-Eng-Sample/displays/remove_displays.cmd +++ b/examples/CI-Eng-Sample/displays/remove_displays.cmd @@ -1,7 +1,9 @@ @echo off rem Remove the CI-Eng-Sample displays (operator interface and HTML version). CI Server R1.03.00. -rem Close CIENG_Tank in the Edit Module first. +rem Close CIENG_Tank and CIENG_Menu in the Edit Module first. set WAP=%TLS_WAP_PATH% if not defined TLS_WAP_PATH set WAP=C:\Users\Public\Yokogawa\tls\wap del /q "%WAP%\cfg\operatorInterfaces\DEPLOY\displays\CIENG_Tank.xml" del /q "%WAP%\mobileoperator\operatorInterfaces\DEPLOY\displays\CIENG_Tank.html" +del /q "%WAP%\cfg\operatorInterfaces\DEPLOY\displays\CIENG_Menu.xml" +del /q "%WAP%\mobileoperator\operatorInterfaces\DEPLOY\displays\CIENG_Menu.html" diff --git a/examples/CI-Eng-Sample/layouts/CIENG_Operator.xml b/examples/CI-Eng-Sample/layouts/CIENG_Operator.xml new file mode 100644 index 0000000..205b5ca --- /dev/null +++ b/examples/CI-Eng-Sample/layouts/CIENG_Operator.xml @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CI-Eng-Sample/layouts/layout.ps1 b/examples/CI-Eng-Sample/layouts/layout.ps1 new file mode 100644 index 0000000..18d6129 --- /dev/null +++ b/examples/CI-Eng-Sample/layouts/layout.ps1 @@ -0,0 +1,34 @@ +# Add or remove the CI-Eng-Sample layout block in Layouts.xml (CI Server R1.03.00). +# Usage: powershell -ExecutionPolicy Bypass -File layout.ps1 [-Remove] +# The block between is inserted after +# the last layout (before the translations; an existing block is replaced). The first run +# saves Layouts-before-CIENG.xml next to Layouts.xml. +# No admin rights needed. Reopen the Operator Interface (or View > Reload All) afterwards. +param([switch]$Remove) + +$wap = $env:TLS_WAP_PATH +if (-not $wap) { $wap = 'C:\Users\Public\Yokogawa\tls\wap' } +$file = Join-Path $wap 'cfg\operatorInterfaces\DEPLOY\layouts\Layouts.xml' +$backup = Join-Path $wap 'cfg\operatorInterfaces\DEPLOY\layouts\Layouts-before-CIENG.xml' +$block = Join-Path $PSScriptRoot 'CIENG_Operator.xml' + +if (-not (Test-Path $file)) { throw "Not found: $file" } +if (-not (Test-Path $backup)) { Copy-Item -LiteralPath $file -Destination $backup } + +$text = [IO.File]::ReadAllText($file) +$pattern = '(?s)[ \t]*\r?\n?' +$text = [regex]::Replace($text, $pattern, '') + +if (-not $Remove) { + $add = [IO.File]::ReadAllText($block) -replace '(?. + $m = [regex]::Match($text, '(?m)^[ \t]*') } + if ($end -lt 0) { throw 'No in Layouts.xml' } + $text = $text.Substring(0, $end) + $add + $text.Substring($end) +} + +# Check that the result is still well-formed XML before writing it. +[xml]$null = $text +[IO.File]::WriteAllText($file, $text, (New-Object Text.UTF8Encoding($false))) +if ($Remove) { 'CIENG_Operator layout removed' } else { 'CIENG_Operator layout added' }