Add report device, destination and three reports to CI-Eng-Sample

CIENG_FILE (file device built for the node at load time), CIENG_TANK1
(ad hoc with item parameter, daily 06:00), CIENG_INFLOW_HI (item trigger)
and CIENG_HTML (HTML, cursor loop, logbook). remove.cmd clears the
schedule first, since a scheduled report cannot be deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Clio Liu 2026-10-01 16:17:02 +10:00
parent c761b20257
commit 84228490dd
10 changed files with 205 additions and 3 deletions

View file

@ -1 +1,2 @@
*.qlo
17_printer_df.qli

View file

@ -0,0 +1,16 @@
# Build 17_printer_df.qli from 17_printer_df.tpl for this system (CI-Eng-Sample, CI Server R1.03.00).
# The printer device needs the CI Server node name ("<node>:FILE") and a literal output path,
# so they are filled in here: node name from LOCAL_NODE_DF, path from %TLS_LST_PATH%.
# Called by load.cmd; needs CI Server running.
$ErrorActionPreference = 'Stop'
Set-Location -LiteralPath $PSScriptRoot
$null = & dssqld -e 17_node.qlo -d LOCAL_NODE_DF -c
$node = $null
foreach ($row in (Import-Csv 17_node.qlo)) { if ($row.NAME -eq 'THIS_NODE') { $node = $row.NODE_NAME } }
Remove-Item 17_node.qlo
if (-not $node) { throw 'Node name not found in LOCAL_NODE_DF' }
$lst = $env:TLS_LST_PATH
if (-not $lst) { throw 'TLS_LST_PATH is not set' }
$text = (Get-Content -Raw 17_printer_df.tpl).Replace('<NODE>', $node).Replace('<LST>', $lst)
Set-Content -Encoding ascii -NoNewline -Path 17_printer_df.qli -Value $text
Write-Output "17_printer_df.qli: node $node, path $lst"

View file

@ -0,0 +1,23 @@
@LANGUAGE
ENGLISH
@VERSION
1.03.00
! CI-Eng-Sample report output device and destination, CI Server R1.03.00.
! TEMPLATE: load.cmd replaces <NODE> with the CI Server node name (LOCAL_NODE_DF NODE_NAME) and
! <LST> with %TLS_LST_PATH%, writes 17_printer_df.qli and loads that. The output type must be
! "<node>:FILE" (PRINTER_TYPE_DF) and the path must be a literal path (no %variables%).
! Every printed report overwrites <LST>\cieng_report.txt.
@FIELDS
NAME,DESCRIPTION,OUTPUT_TYPE,PARAMETERS,SUSPEND
@PRINTER_DEV_DF
"CIENG_FILE","CI-Eng-Sample report file","<NODE>:FILE","PATH,""<LST>"",FILE,""cieng_report.txt"",OVERWRITE,""Yes""",0
! Destination used by the sample reports; visible to operators (PRINTER_OPER_DEST_DF).
@FIELDS
NAME,DESCRIPTION,PRIMARY_DEVICE,POLICY,ALLOW_OPERATOR,PRIORITY
@PRINTER_DEST_DF
"CIENG_FILE","CI-Eng-Sample report file","CIENG_FILE","None",1,0

View file

@ -0,0 +1,82 @@
@LANGUAGE
ENGLISH
@VERSION
1.03.00
! CI-Eng-Sample reports (REPORT_DF), CI Server R1.03.00. Load after 17_printer_df (destination).
! Each report gets a storage group of type Report with the same name (lifetime = LIFE_TIME,
! rollover = GENERATION_INTERVAL, so a schedule must be at least 10 minutes).
! Report names: at most 16 characters.
!
! CIENG_TANK1 : values of all TANK1 items plus last-hour statistics of one item (parameter
! @p0, picked from a list of TANK1 items); daily at 06:00 local time and ad hoc.
! The activation time lies in the past; CI Server moves it to the next 06:00.
! CORRECT_DAYLIGHT 1 keeps 06:00 across daylight-saving changes (with 0 the
! interval runs in UTC and 06:00 in January became 05:00 in October).
! CIENG_INFLOW_HI: generated 5 s after TANK1.INFLOW rises above 400 (only when the condition
! becomes true, not again while it stays above).
! CIENG_HTML : HTML output (CONTAINS_HTML is set automatically), cursor loop, logbook text.
@FIELDS
NAME,DESCRIPTION,PRIORITY,ADHOC_ENABLED,LOGBOOK_ENABLED,LIFE_TIME,ACTIVATION_TIME,GENERATION_INTERVAL,CORRECT_DAYLIGHT,DEST_NAME,ADHOC_DEST,PARAM_PROMPT_1,QUERY
@REPORT_DF
"CIENG_TANK1","CI-Eng-Sample tank 1 values",0,1,1,"1 Weeks","01-01-2026 06:00:00","1 Days",1,"CIENG_FILE","CIENG_FILE","[ITEM:NAME like ""CI-Eng-Sample.TANK1.*""]Item for statistics:",\
@"
/* CI-Eng-Sample: current values of tank 1, then last-hour statistics of one item */
column v as '9999.9' heading 'Value';
select name, item_value v, status from item_val where name like 'CI-Eng-Sample.TANK1.%';
select '';
if @p0 = '' then
set @item 'CI-Eng-Sample.TANK1.LEVEL';
else
set @item @p0;
endif;
select 'Last hour: ' || @item;
column n heading 'Samples';
column mi as '9999.9' heading 'Min';
column ma as '9999.9' heading 'Max';
column av as '9999.9' heading 'Average';
select count(item_value) n, min(item_value) mi, max(item_value) ma, avg(item_value) av
from item_history where item_name = @item and sample_time > @date - 3600;
"@
@FIELDS
NAME,DESCRIPTION,PRIORITY,ADHOC_ENABLED,LIFE_TIME,TRIGGER_ITEM,TRIGGER_CON_1,TRIGGER_VAL_1,DELAY,DEST_NAME,ADHOC_DEST,QUERY
@REPORT_DF
"CIENG_INFLOW_HI","CI-Eng-Sample tank 1 inflow above 400",0,1,"1 Weeks","CI-Eng-Sample.TANK1.INFLOW","Greater Than",400,"5 Seconds","CIENG_FILE","CIENG_FILE",\
@"
column t as 'DD-MMM-YYYY hh:mm:ss';
select 'Tank 1 inflow high: ' || char(gpv_value('CI-Eng-Sample.TANK1.INFLOW', 0), '%.1f') || ' m3/h at', @date t;
"@
@FIELDS
NAME,DESCRIPTION,PRIORITY,ADHOC_ENABLED,LOGBOOK_ENABLED,LIFE_TIME,ADHOC_DEST,LOGBOOK,QUERY
@REPORT_DF
"CIENG_HTML","CI-Eng-Sample tank 1 as HTML",0,1,1,"1 Weeks","CIENG_FILE",@"
Sample logbook text
"@,\
@"
/* HTML output: no header/footer, no page breaks */
header '';
footer '';
set @page_size 0;
set @width 512;
select '<HTML><BODY><H3>CI-Eng-Sample tank 1</H3><TABLE BORDER=1>';
set @n '';
set @v 0.;
declare @c is select name, item_value from item_val where name like 'CI-Eng-Sample.TANK1.%';
open @c;
loop
fetch @c into @n, @v;
if @rqlcount = 0 then
exit;
endif;
select '<TR><TD>' || @n || '</TD><TD>' || char(@v, '%.1f') || '</TD></TR>';
endloop;
close @c;
declare;
select '</TABLE><P>Logbook: ' || logbook_text('CIENG_HTML') || '</P></BODY></HTML>';
"@

View file

@ -0,0 +1,15 @@
@LANGUAGE
ENGLISH
@VERSION
1.03.00
! Remove CI-Eng-Sample reports. Also deletes each report's storage group (its generated
! reports) and logbook file (tls\dat\<report>.lbk).
@FIELDS
NAME
@REPORT_DF
"CIENG_TANK1"
"CIENG_INFLOW_HI"
"CIENG_HTML"

View file

@ -0,0 +1,13 @@
@LANGUAGE
ENGLISH
@VERSION
1.03.00
! Stop the schedule of CIENG_TANK1 (load with dssqld -m before 83_remove_report_df):
! a report with an active schedule cannot be deleted (RPT-E-ACTIVE).
@FIELDS
NAME,ACTIVATION_TIME,GENERATION_INTERVAL
@REPORT_DF
"CIENG_TANK1","",""

View file

@ -0,0 +1,19 @@
@LANGUAGE
ENGLISH
@VERSION
1.03.00
! Remove the CI-Eng-Sample report destination, then its device (after 83_remove_report_df).
! The output file %TLS_LST_PATH%\cieng_report.txt is not deleted (remove.cmd deletes it).
@FIELDS
NAME
@PRINTER_DEST_DF
"CIENG_FILE"
@FIELDS
NAME
@PRINTER_DEV_DF
"CIENG_FILE"

View file

@ -73,6 +73,10 @@ cmd /c "<repo>\examples\CI-Eng-Sample\remove.cmd"
| `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. |
| `CIENG_FILE` | Printer device + destination | FILE output to `%TLS_LST_PATH%\cieng_report.txt` (overwritten by each printed report); destination visible to operators |
| `CIENG_TANK1` | Report | Values of the `TANK1` items + last-hour statistics of one item (ad-hoc parameter, pick list of `TANK1` items, default `LEVEL`); daily 06:00 local time and ad hoc; output `CIENG_FILE`; lifetime 1 week |
| `CIENG_INFLOW_HI` | Report | Generated 5 s after `TANK1.INFLOW` rises above 400; output `CIENG_FILE` |
| `CIENG_HTML` | Report | Ad hoc; `TANK1` values as an HTML table (cursor loop) plus the logbook text |
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`.
@ -96,8 +100,11 @@ New items start with status 13 (`NOT INIT`) until a value is written.
| `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`) |
| `17_printer_df.tpl`, `17_printer_df.ps1` | Report file device and destination; the script fills in this system's node name and `%TLS_LST_PATH%` and writes `17_printer_df.qli` (not in the repo) |
| `18_report_df.qli` | Reports (`REPORT_DF`, RQL in the `QUERY` memo) |
| `83a_stop_report_df.qli` | Clears the schedule of `CIENG_TANK1` before removal (a scheduled report cannot be deleted) |
| `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`) |
| `76_`…`93_remove_*.qli` | Names to delete, in reverse order (reports and printer `83`/`84` first, 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`) |
@ -171,12 +178,26 @@ Remove: `layouts\layout.ps1 -Remove` (restores the file exactly) and
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`.
## Reports
No admin rights needed. `load.cmd` creates the device, destination and three reports; each report
gets its own storage group of type *Report*. Try them (skill `reporting`, task `define-reports.md`):
- Ad hoc: `REPORT_DF` `NAME,PARAM_VALUE_1,GENERATE` = `"CIENG_TANK1","CI-Eng-Sample.TANK1.INFLOW",1`
with `dssqld -m`, or in the Engineering Module *Configuration > Reporting > Reports* › right-click
› *Generate*. The output lands in `%TLS_LST_PATH%\cieng_report.txt` and in `REPORT_VAL`.
- Trigger: `itmval -p -n CI-Eng-Sample.TANK1.INFLOW -v 450` → `CIENG_INFLOW_HI` 5 s later; write a
value below 400 before the next test.
- `CIENG_TANK1` also runs every day at 06:00 (local time).
`remove.cmd` clears the schedule, removes the reports (with their generated reports and logbook
files), the destination and device, and deletes `cieng_report.txt`.
## Planned additions
| Phase | Adds |
|---|---|
| 10 | A symbol and a faceplate popup (displays and the operator layout exist) |
| 11 | A report |
## Rules

View file

@ -37,3 +37,8 @@ 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
rem Alarming: switch on alarms for TANK1.LEVEL (modify existing record)
dssqld -m 16_item_alarm_df.qli -l 16_item_alarm_df.qlo
rem Reports: file output device and destination (17_printer_df.qli is built for this node
rem from 17_printer_df.tpl), then the report definitions.
powershell -NoProfile -ExecutionPolicy Bypass -File 17_printer_df.ps1
dssqld -i 17_printer_df.qli -l 17_printer_df.qlo
dssqld -i 18_report_df.qli -l 18_report_df.qlo

View file

@ -1,10 +1,17 @@
@echo off
rem Remove CI-Eng-Sample from a CI Server R1.03 TEST system (also deletes its history).
rem Run in an elevated prompt while CI Server is running; call this script by full path.
rem Order: object, class, trigger group, storage links, stop + delete storage groups, items, sections (children first).
rem Order: reports, printer, OPC UA, Modbus, auth group, object, class, trigger group, storage links, stop + delete storage groups, items, sections (children first).
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"
rem Reports first (they refer to TANK1.INFLOW and the destination), then destination and device.
rem A scheduled report cannot be deleted, so its schedule is cleared first.
dssqld -m 83a_stop_report_df.qli -l 83a_stop_report_df.qlo
dssqld -r 83_remove_report_df.qli -l 83_remove_report_df.qlo
dssqld -r 84_remove_printer_df.qli -l 84_remove_printer_df.qlo
if exist "%TLS_LST_PATH%\cieng_report.txt" del "%TLS_LST_PATH%\cieng_report.txt"
if exist 17_printer_df.qli del 17_printer_df.qli
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