Phase 14: Trend settings (desktop and web) and the HTML trend fix #16

Merged
cliu merged 4 commits from docs/phase-14-trends into main 2026-10-02 14:08:55 +10:00
6 changed files with 2684 additions and 3 deletions
Showing only changes of commit f612adb56e - Show all commits

View file

@ -114,6 +114,9 @@ New items start with status 13 (`NOT INIT`) until a value is written.
| `19b_audit_item_df.qli` | *Audit trailing wanted* for `PUMP1.MODE` (loaded with `dssqld -m`) |
| `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/CIENG_TrendLab.xml` | Trend lab (1000 x 860, HTML mode): trend of `TANK1.LEVEL` (no history group, value axis) and `TANK1.INFLOW` (`CIENG_EVENT`), live, last hour, padded with 48 spare pens so it draws in the browser; Micro Trend of both items (ISS-055) |
| `displays/add_trend_spares.ps1` | Pads every trend in a display file to 50 visible pens (web workaround, ISS-041); safe to run again |
| `displays/trend_feed.ps1` | Writes sine-wave test values to `TANK1.LEVEL` / `TANK1.INFLOW` every 5 s (`-Seconds`, default 3600) |
| `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`) |
@ -161,8 +164,8 @@ priority 1). To try it on a test system: `itmval -p -n CI-Eng-Sample.TANK1.LEVEL
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.
1. `displays\deploy_displays.cmd` copies `CIENG_Tank`, `CIENG_Menu` and `CIENG_TrendLab` 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.
@ -172,6 +175,12 @@ No admin rights needed. After `load.cmd`:
banner. HTML display (web): `http://localhost:8080/mobileoperator/?d=CIENG_Tank&l=CIENG_Operator`
(CI Server login).
Trends: `TANK1.LEVEL` and `TANK1.INFLOW` are internal items and stay `NOT INIT` after a CI
Server start, so trends stay empty. `powershell -ExecutionPolicy Bypass -File
displays\trend_feed.ps1 -Seconds 3600` writes test values every 5 s. `CIENG_TrendLab` (also
in the browser: `?d=CIENG_TrendLab`) shows the trend padded to 50 pens, which the HTML display
needs to draw (ISS-041); `CIENG_Tank`'s trend has 1 pen and draws only on the desktop.
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`.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
# Pad every trend (chart) in a display file to 50 visible pens so it also draws in the HTML
# display (web client). CI Server R1.03.00: the web trend always builds 50 data columns but only
# labels the visible pens with an item; with fewer than 50 such pens it draws nothing (ISS-041).
#
# Spare pens copy the first real pen's source, are scaled far outside the data (manual scale
# 1E30..2E30, so the line is clipped), hidden from the legend and get blank, unique legend texts
# (1, 2, 3 ... spaces) because the web legend ignores "Show in legend". Empty pens are removed.
# Run it again after editing the trend in the Edit Module (it only adds what is missing).
#
# Usage: powershell -ExecutionPolicy Bypass -File add_trend_spares.ps1 -Path <display>.xml
param([Parameter(Mandatory = $true)][string]$Path)
$target = 50
$text = [IO.File]::ReadAllText($Path)
$nl = "`r`n"
if (-not $text.Contains($nl)) { $nl = "`n" }
function Set-Tag([string]$pen, [string]$tag, [string]$value) {
$rx = New-Object Text.RegularExpressions.Regex ("<$tag>[^<]*</$tag>|<$tag/>")
return $rx.Replace($pen, "<$tag>$value</$tag>", 1)
}
$panelRx = New-Object Text.RegularExpressions.Regex '(?s)<chartPanel>.*?</chartPanel>'
$penRx = New-Object Text.RegularExpressions.Regex '(?s)[ \t]*<pen type="pen">.*?</pen>\r?\n?'
$changed = 0
$text = $panelRx.Replace($text, {
param($m)
$panel = $m.Value
$pens = $penRx.Matches($panel)
if ($pens.Count -eq 0) { return $panel }
$real = @(); $spareCount = 0
foreach ($p in $pens) {
$v = $p.Value
$empty = $v.Contains('uri=""')
$isSpare = $v.Contains('<minimum>1.0E30</minimum>')
if ($isSpare) { $spareCount++ }
elseif (-not $empty) { $real += $v }
}
if ($real.Count -eq 0) { return $panel }
$visibleReal = 0
foreach ($v in $real) { if ($v.Contains('<visible>true</visible>')) { $visibleReal++ } }
$need = $target - $visibleReal
if ($need -lt 0) { $need = 0 }
$template = $real[0]
$spares = @()
for ($i = 1; $i -le $need; $i++) {
$s = $template
$s = Set-Tag $s 'legendText' (' ' * $i)
$s = Set-Tag $s 'description' ''
$s = Set-Tag $s 'type' '1'
$s = Set-Tag $s 'visible' 'true'
$s = Set-Tag $s 'visibleLegend' 'false'
$s = Set-Tag $s 'axisVisible' 'false'
$s = Set-Tag $s 'scaleRangeType' '1'
$s = Set-Tag $s 'minimum' '1.0E30'
$s = Set-Tag $s 'maximum' '2.0E30'
$s = Set-Tag $s 'procentual' 'false'
$s = Set-Tag $s 'annotationVisible' 'false'
foreach ($g in @('majorGridVisible', 'minorGridVisible', 'lowHighLimitGridVisible', 'lowHighLimitGridAreaVisible', 'lowLowHighHighLimitGridVisible')) { $s = Set-Tag $s $g 'false' }
$s = (New-Object Text.RegularExpressions.Regex '<stroke type="stroke" width="[^"]*"').Replace($s, '<stroke type="stroke" width="0.0"', 1)
$s = (New-Object Text.RegularExpressions.Regex '<paint type="paint">.*?</paint>(?=\s*<visible>)', 'Singleline').Replace($s, '<paint>@NULL</paint>', 1)
$spares += $s
}
# rebuild: real pens first, then spares, at the place of the first pen
$first = $pens[0].Index
$last = $pens[$pens.Count - 1]
$before = $panel.Substring(0, $first)
$after = $panel.Substring($last.Index + $last.Length)
$body = ''
foreach ($v in $real) { $body += $v }
foreach ($v in $spares) { $body += $v }
$panel = $before + $body + $after
$panel = (New-Object Text.RegularExpressions.Regex '<maximumPens>\d+</maximumPens>').Replace($panel, "<maximumPens>$target</maximumPens>", 1)
$script:changed++
Write-Host ("Trend {0}: {1} real pen(s), {2} old spare(s) replaced, {3} spare(s) written" -f $script:changed, $real.Count, $spareCount, $need)
return $panel
})
[IO.File]::WriteAllText($Path, $text)
Write-Host "Done: $changed trend(s) in $Path"

View file

@ -8,5 +8,7 @@ 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\"
copy /y CIENG_TrendLab.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
call jwuiutl.cmd -e HTML -i -f DEPLOY CIENG_TrendLab

View file

@ -1,9 +1,11 @@
@echo off
rem Remove the CI-Eng-Sample displays (operator interface and HTML version). CI Server R1.03.00.
rem Close CIENG_Tank and CIENG_Menu in the Edit Module first.
rem Close CIENG_Tank, CIENG_Menu and CIENG_TrendLab 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"
del /q "%WAP%\cfg\operatorInterfaces\DEPLOY\displays\CIENG_TrendLab.xml"
del /q "%WAP%\mobileoperator\operatorInterfaces\DEPLOY\displays\CIENG_TrendLab.html"

View file

@ -0,0 +1,16 @@
# Feed test values into the CI-Eng-Sample tank items so trends have a moving line.
# CI Server R1.03.00. TANK1.LEVEL and TANK1.INFLOW are internal items: after a restart they
# stay NOT INIT until something writes them. Writes every 5 s with itmval; stop with Ctrl+C.
# LEVEL = 50 +/- 25 % (period 10 min, stays inside the L 20 / H 80 alarm limits)
# INFLOW = 250 +/- 150 m3/h (period 4 min)
param([int]$Seconds = 3600)
$end = (Get-Date).AddSeconds($Seconds)
while ((Get-Date) -lt $end) {
$t = [double]((Get-Date) - (Get-Date).Date).TotalSeconds
$level = [math]::Round(50 + 25 * [math]::Sin(2 * [math]::PI * $t / 600), 1)
$inflow = [math]::Round(250 + 150 * [math]::Sin(2 * [math]::PI * $t / 240), 1)
itmval -p -n CI-Eng-Sample.TANK1.LEVEL -v $level > $null
itmval -p -n CI-Eng-Sample.TANK1.INFLOW -v $inflow > $null
Start-Sleep -Seconds 5
}