From 148508af86277b88f9576fd93b4facf3c7cf84ac Mon Sep 17 00:00:00 2001 From: cliu Date: Thu, 1 Oct 2026 14:50:13 +1000 Subject: [PATCH] Add display CIENG_Tank with deploy and remove scripts to CI-Eng-Sample Co-Authored-By: Claude Opus 5.5 --- examples/CI-Eng-Sample/README.md | 337 ++++++------ .../CI-Eng-Sample/displays/CIENG_Tank.xml | 487 ++++++++++++++++++ .../displays/deploy_displays.cmd | 10 + .../displays/remove_displays.cmd | 7 + 4 files changed, 677 insertions(+), 164 deletions(-) create mode 100644 examples/CI-Eng-Sample/displays/CIENG_Tank.xml create mode 100644 examples/CI-Eng-Sample/displays/deploy_displays.cmd create mode 100644 examples/CI-Eng-Sample/displays/remove_displays.cmd diff --git a/examples/CI-Eng-Sample/README.md b/examples/CI-Eng-Sample/README.md index b8a370f..79861a1 100644 --- a/examples/CI-Eng-Sample/README.md +++ b/examples/CI-Eng-Sample/README.md @@ -1,164 +1,173 @@ -# 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 | -| `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`. - -## 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 display and symbol | -| 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` | +| `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. diff --git a/examples/CI-Eng-Sample/displays/CIENG_Tank.xml b/examples/CI-Eng-Sample/displays/CIENG_Tank.xml new file mode 100644 index 0000000..4582d2e --- /dev/null +++ b/examples/CI-Eng-Sample/displays/CIENG_Tank.xml @@ -0,0 +1,487 @@ + + + + + + true + 1984 + 760 + 4 + + + + + + + + + + + 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 + + 4 + + 7 + CI-Eng-Sample Tank 1 + + true + 124.734375 + 36.953125 + 5.3125 + 5.3125 + 52.375 + 52.375 + 0.0 + 0.0 + + + 8 + + + + + 0.0 + + + CI-Eng-Sample.TANK1.LEVEL + 1.1.268.0.0.1.1.7 + ItemValue + + + + + + 9 + + + + + + 10 + + + + false + -1 + true + + 0 + 0 + + + + + + + + + + false + + @NULL + false + 0 + 0 + 800 + 400 + false + + + + + + + true + @NULL + + + + + false + false + true + + true + true + false + true + + + + + + 0.2705882352941177 + + + true + false + true + false + false + false + false + false + 5 + 0 + 0 + true + true + false + + + + true + true + 0 + + 0 + 50 + true + + + false + + + + + + + + + + + + + + + true + true + 0 + true + + + + + 256 + + + @NULL + true + true + + false + 0 + true + true + true + @NULL + @NULL + 0 + NaN + NaN + false + + <description>Tank 1 level (%)</description> + <legendText/> + <titlePlacement>0</titlePlacement> + <titleRotation>0</titleRotation> + <labelRotation>0</labelRotation> + <majorGridVisible>false</majorGridVisible> + <minorGridVisible>false</minorGridVisible> + <lowHighLimitGridVisible>false</lowHighLimitGridVisible> + <lowHighLimitGridAreaVisible>false</lowHighLimitGridAreaVisible> + <lowLowHighHighLimitGridVisible>false</lowLowHighHighLimitGridVisible> + <majorGridColor>@NULL</majorGridColor> + <minorGridColor>@NULL</minorGridColor> + <lowHighLimitGridColor>@NULL</lowHighLimitGridColor> + <lowHighLimitGridAreaColor>@NULL</lowHighLimitGridAreaColor> + <lowLowHighHighLimiGridColor>@NULL</lowLowHighHighLimiGridColor> + <majorGridStroke type="stroke" width="0.1"/> + <minorGridStroke type="stroke" width="0.1"/> + <lowHighLimitGridStroke type="stroke" width="0.1"/> + <lowLowHighHighLimiGridStroke type="stroke" width="0.1"/> + <lowLimit>20.0</lowLimit> + <highLimit>80.0</highLimit> + <lowLowLimit>10.0</lowLowLimit> + <highHighLimit>90.0</highHighLimit> + <annotationVisible>false</annotationVisible> + <timeShift>0</timeShift> + </pen> + <pen type="pen"> + <type>256</type> + <color type="colorSet" r="241" g="76" b="20"/> + <stroke type="stroke" width="1.5"/> + <paint>@NULL</paint> + <visible>true</visible> + <visibleLegend>true</visibleLegend> + <source type="sourceID" uri=""/> + <axisVisible>false</axisVisible> + <axisPosition>0</axisPosition> + <labelVisible>true</labelVisible> + <majorTickVisible>true</majorTickVisible> + <minorTickVisible>true</minorTickVisible> + <axisColor>@NULL</axisColor> + <labelColor>@NULL</labelColor> + <scaleRangeType>0</scaleRangeType> + <minimum>NaN</minimum> + <maximum>NaN</maximum> + <procentual>false</procentual> + <title/> + <description/> + <legendText/> + <titlePlacement>0</titlePlacement> + <titleRotation>0</titleRotation> + <labelRotation>0</labelRotation> + <majorGridVisible>false</majorGridVisible> + <minorGridVisible>false</minorGridVisible> + <lowHighLimitGridVisible>false</lowHighLimitGridVisible> + <lowHighLimitGridAreaVisible>false</lowHighLimitGridAreaVisible> + <lowLowHighHighLimitGridVisible>false</lowLowHighHighLimitGridVisible> + <majorGridColor>@NULL</majorGridColor> + <minorGridColor>@NULL</minorGridColor> + <lowHighLimitGridColor>@NULL</lowHighLimitGridColor> + <lowHighLimitGridAreaColor>@NULL</lowHighLimitGridAreaColor> + <lowLowHighHighLimiGridColor>@NULL</lowLowHighHighLimiGridColor> + <majorGridStroke type="stroke" width="0.1"/> + <minorGridStroke type="stroke" width="0.1"/> + <lowHighLimitGridStroke type="stroke" width="0.1"/> + <lowLowHighHighLimiGridStroke type="stroke" width="0.1"/> + <lowLimit>NaN</lowLimit> + <highLimit>NaN</highLimit> + <lowLowLimit>NaN</lowLowLimit> + <highHighLimit>NaN</highHighLimit> + <annotationVisible>false</annotationVisible> + <timeShift>0</timeShift> + </pen> + <pen type="pen"> + <type>256</type> + <color type="colorSet" r="127" g="255" b="0"/> + <stroke type="stroke" width="1.5"/> + <paint>@NULL</paint> + <visible>true</visible> + <visibleLegend>true</visibleLegend> + <source type="sourceID" uri=""/> + <axisVisible>false</axisVisible> + <axisPosition>0</axisPosition> + <labelVisible>true</labelVisible> + <majorTickVisible>true</majorTickVisible> + <minorTickVisible>true</minorTickVisible> + <axisColor>@NULL</axisColor> + <labelColor>@NULL</labelColor> + <scaleRangeType>0</scaleRangeType> + <minimum>NaN</minimum> + <maximum>NaN</maximum> + <procentual>false</procentual> + <title/> + <description/> + <legendText/> + <titlePlacement>0</titlePlacement> + <titleRotation>0</titleRotation> + <labelRotation>0</labelRotation> + <majorGridVisible>false</majorGridVisible> + <minorGridVisible>false</minorGridVisible> + <lowHighLimitGridVisible>false</lowHighLimitGridVisible> + <lowHighLimitGridAreaVisible>false</lowHighLimitGridAreaVisible> + <lowLowHighHighLimitGridVisible>false</lowLowHighHighLimitGridVisible> + <majorGridColor>@NULL</majorGridColor> + <minorGridColor>@NULL</minorGridColor> + <lowHighLimitGridColor>@NULL</lowHighLimitGridColor> + <lowHighLimitGridAreaColor>@NULL</lowHighLimitGridAreaColor> + <lowLowHighHighLimiGridColor>@NULL</lowLowHighHighLimiGridColor> + <majorGridStroke type="stroke" width="0.1"/> + <minorGridStroke type="stroke" width="0.1"/> + <lowHighLimitGridStroke type="stroke" width="0.1"/> + <lowLowHighHighLimiGridStroke type="stroke" width="0.1"/> + <lowLimit>NaN</lowLimit> + <highLimit>NaN</highLimit> + <lowLowLimit>NaN</lowLowLimit> + <highHighLimit>NaN</highHighLimit> + <annotationVisible>false</annotationVisible> + <timeShift>0</timeShift> + </pen> + <pen type="pen"> + <type>256</type> + <color type="colorSet" r="0" g="0" b="139"/> + <stroke type="stroke" width="1.5"/> + <paint>@NULL</paint> + <visible>true</visible> + <visibleLegend>true</visibleLegend> + <source type="sourceID" uri=""/> + <axisVisible>false</axisVisible> + <axisPosition>0</axisPosition> + <labelVisible>true</labelVisible> + <majorTickVisible>true</majorTickVisible> + <minorTickVisible>true</minorTickVisible> + <axisColor>@NULL</axisColor> + <labelColor>@NULL</labelColor> + <scaleRangeType>0</scaleRangeType> + <minimum>NaN</minimum> + <maximum>NaN</maximum> + <procentual>false</procentual> + <title/> + <description/> + <legendText/> + <titlePlacement>0</titlePlacement> + <titleRotation>0</titleRotation> + <labelRotation>0</labelRotation> + <majorGridVisible>false</majorGridVisible> + <minorGridVisible>false</minorGridVisible> + <lowHighLimitGridVisible>false</lowHighLimitGridVisible> + <lowHighLimitGridAreaVisible>false</lowHighLimitGridAreaVisible> + <lowLowHighHighLimitGridVisible>false</lowLowHighHighLimitGridVisible> + <majorGridColor>@NULL</majorGridColor> + <minorGridColor>@NULL</minorGridColor> + <lowHighLimitGridColor>@NULL</lowHighLimitGridColor> + <lowHighLimitGridAreaColor>@NULL</lowHighLimitGridAreaColor> + <lowLowHighHighLimiGridColor>@NULL</lowLowHighHighLimiGridColor> + <majorGridStroke type="stroke" width="0.1"/> + <minorGridStroke type="stroke" width="0.1"/> + <lowHighLimitGridStroke type="stroke" width="0.1"/> + <lowLowHighHighLimiGridStroke type="stroke" width="0.1"/> + <lowLimit>NaN</lowLimit> + <highLimit>NaN</highLimit> + <lowLowLimit>NaN</lowLowLimit> + <highHighLimit>NaN</highHighLimit> + <annotationVisible>false</annotationVisible> + <timeShift>0</timeShift> + </pen> + <pen type="pen"> + <type>256</type> + <color type="colorSet" r="199" g="9" b="16"/> + <stroke type="stroke" width="1.5"/> + <paint>@NULL</paint> + <visible>true</visible> + <visibleLegend>true</visibleLegend> + <source type="sourceID" uri=""/> + <axisVisible>false</axisVisible> + <axisPosition>0</axisPosition> + <labelVisible>true</labelVisible> + <majorTickVisible>true</majorTickVisible> + <minorTickVisible>true</minorTickVisible> + <axisColor>@NULL</axisColor> + <labelColor>@NULL</labelColor> + <scaleRangeType>0</scaleRangeType> + <minimum>NaN</minimum> + <maximum>NaN</maximum> + <procentual>false</procentual> + <title/> + <description/> + <legendText/> + <titlePlacement>0</titlePlacement> + <titleRotation>0</titleRotation> + <labelRotation>0</labelRotation> + <majorGridVisible>false</majorGridVisible> + <minorGridVisible>false</minorGridVisible> + <lowHighLimitGridVisible>false</lowHighLimitGridVisible> + <lowHighLimitGridAreaVisible>false</lowHighLimitGridAreaVisible> + <lowLowHighHighLimitGridVisible>false</lowLowHighHighLimitGridVisible> + <majorGridColor>@NULL</majorGridColor> + <minorGridColor>@NULL</minorGridColor> + <lowHighLimitGridColor>@NULL</lowHighLimitGridColor> + <lowHighLimitGridAreaColor>@NULL</lowHighLimitGridAreaColor> + <lowLowHighHighLimiGridColor>@NULL</lowLowHighHighLimiGridColor> + <majorGridStroke type="stroke" width="0.1"/> + <minorGridStroke type="stroke" width="0.1"/> + <lowHighLimitGridStroke type="stroke" width="0.1"/> + <lowLowHighHighLimiGridStroke type="stroke" width="0.1"/> + <lowLimit>NaN</lowLimit> + <highLimit>NaN</highLimit> + <lowLowLimit>NaN</lowLowLimit> + <highHighLimit>NaN</highHighLimit> + <annotationVisible>false</annotationVisible> + <timeShift>0</timeShift> + </pen> + <penPanelLayout type="xyPenPanelLayout"> + <Height>417</Height> + <AutoSize>true</AutoSize> + <SplitLocation>-1</SplitLocation> + <column index="0" visible="true" width="20"/> + <column index="1" visible="true" width="20"/> + <column index="2" visible="true" width="150"/> + <column index="3" visible="true" width="120"/> + <column index="4" visible="true" width="60"/> + <column index="5" visible="false" width="120"/> + <column index="6" visible="false" width="120"/> + <column index="7" visible="false" width="60"/> + <column index="8" visible="true" width="60"/> + <column index="9" visible="true" width="60"/> + <column index="10" visible="false" width="20"/> + <column index="11" visible="true" width="90"/> + <column index="12" visible="false" width="130"/> + <column index="13" visible="true" width="200"/> + <column index="14" visible="false" width="240"/> + <column index="15" visible="false" width="280"/> + </penPanelLayout> + <timeRange type="timeRangeLast" count="1"> + <type type="timeUnit" value="TimeUnitHour"/> + </timeRange> + <updateInterval>30</updateInterval> + <fillHistory>true</fillHistory> + <updating>false</updating> + </chartPanel> + </config> + <x>472.0</x> + <y>588.0</y> + <top>172.0</top> + <bottom>172.0</bottom> + <left>344.0</left> + <right>344.0</right> + <rotation>0.0</rotation> + <shear>0.0</shear> + <data type="data"> + <action type="actionInternalServiced"/> + <action type="actionConnectTo"> + <property type="property" name="chart.attribute[00]"/> + <filter type="filter"> + <value>0.0</value> + </filter> + <connection type="connection"> + <itemName>CI-Eng-Sample.TANK1.LEVEL</itemName> + <itemId>1.1.268.0.0.1.1.7</itemId> + <itemAttribute>ItemValue</itemAttribute> + </connection> + </action> + </data> + </chart> + </coreObjectDefinition> +</visualization> \ 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 new file mode 100644 index 0000000..84e5039 --- /dev/null +++ b/examples/CI-Eng-Sample/displays/deploy_displays.cmd @@ -0,0 +1,10 @@ +@echo off +rem Deploy the CI-Eng-Sample displays into the operator interface (deployment DEPLOY). +rem CI Server R1.03.00. Load the sample (load.cmd) first; no admin rights needed. +rem Copies the display XML, then creates the HTML (Mobile Operator) version with jwuiutl; +rem without -o the HTML goes to %TLS_WAP_PATH%\mobileoperator\operatorInterfaces\DEPLOY. +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\" +call jwuiutl.cmd -e HTML -i -f DEPLOY CIENG_Tank diff --git a/examples/CI-Eng-Sample/displays/remove_displays.cmd b/examples/CI-Eng-Sample/displays/remove_displays.cmd new file mode 100644 index 0000000..27c4096 --- /dev/null +++ b/examples/CI-Eng-Sample/displays/remove_displays.cmd @@ -0,0 +1,7 @@ +@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. +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"