# 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, 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 (values not yet seen, ISS-040) | | `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.