Sample: merged live-data feed (cieng_feed.ps1) replaces trend_feed.ps1

- feed/cieng_feed.ps1: -Seconds (default, LEVEL +/-25 %), -UntilFlag (DEMO.FEED_ON for the
  display Start/Stop), -Alarms (+/-33 %, crosses L/H), -System (SYSTEM.* items, skipped while
  the monitoring processes run); single-copy lock; log in %TLS_LST_PATH%\cieng_feed.log
- feed/cieng_feed_start.cmd, feed/install_feed.ps1: installed to C:\Users\Public\CI-Eng-Sample\feed
  (outside the CI Server package) for the server-side display command
- Item CI-Eng-Sample.DEMO.FEED_ON in 02_item_df.qli / 91_remove_item_df.qli
- Tested on CI Server R1.03.00 2026-10-06: default run, single copy, start wrapper with flag
  stop, system items written and skipped with a monitor process present

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Clio Liu 2026-10-06 10:15:14 +11:00
parent a298fdebc1
commit d299bdf312
6 changed files with 105 additions and 16 deletions

View file

@ -20,5 +20,6 @@ LOW_LOW_LIMIT,LOW_LIMIT,HIGH_LIMIT,HIGH_HIGH_LIMIT,SCALE_LOW_LIMIT,SCALE_HIGH_LI
"CI-Eng-Sample.SYSTEM.PING_LOCALHOST","localhost reachable, from inttcpmon","Integer","9",0,0,0,0,0,1
"CI-Eng-Sample.SYSTEM.PROC_ALM","ALARM process (alm) running, from intmon","Integer","9",0,0,0,0,0,1
"CI-Eng-Sample.DEMO.COUNTER","Counter 1..100 driven by object DEMO.INCR1","Integer","999",0,0,0,0,0,100
"CI-Eng-Sample.DEMO.FEED_ON","Live-data feed running (1 = on), written by feed\cieng_feed.ps1","Boolean","",0,0,0,0,0,0
"CI-Eng-Sample.PLC1.COMM_OK","Station CIENG_PLC communication (1 = good), status item","Boolean","",0,0,0,0,0,0
"CI-Eng-Sample.UA.COMM_OK","Station CIENG_UA communication (1 = good), status item","Boolean","",0,0,0,0,0,0

View file

@ -18,6 +18,7 @@ NAME
"CI-Eng-Sample.SYSTEM.PING_LOCALHOST"
"CI-Eng-Sample.SYSTEM.PROC_ALM"
"CI-Eng-Sample.DEMO.COUNTER"
"CI-Eng-Sample.DEMO.FEED_ON"
"CI-Eng-Sample.PLC1.COMM_OK"
"CI-Eng-Sample.UA.COMM_OK"
"CI-Eng-Sample.TEMPLATES.TPL_REAL"

View file

@ -1,16 +0,0 @@
# 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
}

View file

@ -0,0 +1,79 @@
# CI-Eng-Sample live data: writes test values into the sample items so displays, trends and alarms
# move (internal items stay NOT INIT after a CI Server start). CI Server R1.03.00. Replaces
# displays\trend_feed.ps1. Not part of the CI Server package: installed with install_feed.ps1 into
# C:\Users\Public\CI-Eng-Sample\feed, from where the display button "Start" runs it.
#
# Usage: powershell -ExecutionPolicy Bypass -File cieng_feed.ps1 [-Seconds 3600] [-UntilFlag] [-Alarms] [-System] [-Cycle 5]
# (default) run for -Seconds (3600)
# -UntilFlag run while CI-Eng-Sample.DEMO.FEED_ON = 1 (display buttons Start / Stop); sets it to 1
# at start and 0 at the end
# -Alarms LEVEL 50 +/- 33 % (crosses L 20 and H 80: alarms that need an acknowledgement);
# without it 50 +/- 25 % (stays inside the limits)
# -System also write SYSTEM.CPU_LOAD / DISK_C / PING_LOCALHOST / PROC_ALM with this PC's real
# values - skipped automatically while the monitoring processes (intcpumon, intdskmon,
# inttcpmon, intmon; see ..\monitoring) are running, so they do not overwrite each other
# Every cycle (default 5 s): TANK1.LEVEL (sine, 10 min), TANK1.INFLOW (250 +/- 150 m3/h, 4 min);
# PUMP1.RUNNING = 1 while INFLOW > 250, only in auto mode (PUMP1.MODE = 1).
# Only one copy runs at a time; log: %TLS_LST_PATH%\cieng_feed.log (start / stop lines).
param([int]$Seconds = 3600, [switch]$UntilFlag, [switch]$Alarms, [switch]$System, [int]$Cycle = 5)
$itmval = 'itmval'
if ($env:TLS_ROOT_PATH) {
$exe = Join-Path $env:TLS_ROOT_PATH 'tls\exe\itmval.exe'
if (Test-Path $exe) { $itmval = $exe }
}
$S = 'CI-Eng-Sample.'
$logDir = $env:TLS_LST_PATH
if (-not $logDir) { $logDir = $PSScriptRoot }
$log = Join-Path $logDir 'cieng_feed.log'
function Get-Val([string]$name) {
$out = & $itmval -g -n ($S + $name) 2>$null
foreach ($l in $out) { if ($l -match '^Value\s*=\s*(.+)$') { return $Matches[1].Trim() } }
return $null
}
function Put([string]$name, $value) { & $itmval -p -n ($S + $name) -v $value > $null 2>&1 }
function Write-Log([string]$text) {
try { Add-Content -Path $log -Value ('{0} {1}' -f (Get-Date -Format s), $text) } catch { }
}
$created = $false
$mutex = New-Object Threading.Mutex($true, 'Global\CIENG_FEED', [ref]$created)
if (-not $created) { Write-Log 'already running - this copy exits'; exit 0 }
$amp = 25
if ($Alarms) { $amp = 33 }
$monitors = @('intcpumon', 'intdskmon', 'inttcpmon', 'intmon')
$mode = 'seconds=' + $Seconds
if ($UntilFlag) { $mode = 'until FEED_ON = 0' }
$end = (Get-Date).AddSeconds($Seconds)
try {
Write-Log ('start ({0}, alarms={1}, system={2}, user {3})' -f $mode, [bool]$Alarms, [bool]$System, [Environment]::UserName)
if ($UntilFlag) { Put 'DEMO.FEED_ON' 1 }
while ($true) {
if ($UntilFlag) { if ((Get-Val 'DEMO.FEED_ON') -ne '1') { break } }
elseif ((Get-Date) -ge $end) { break }
$t = [double]((Get-Date) - (Get-Date).Date).TotalSeconds
$level = [math]::Round(50 + $amp * [math]::Sin(2 * [math]::PI * $t / 600), 1)
$inflow = [math]::Round(250 + 150 * [math]::Sin(2 * [math]::PI * $t / 240), 1)
Put 'TANK1.LEVEL' $level
Put 'TANK1.INFLOW' $inflow
if ((Get-Val 'PUMP1.MODE') -eq '1') { Put 'PUMP1.RUNNING' ([int]($inflow -gt 250)) }
if ($System -and -not (Get-Process -Name $monitors -ErrorAction SilentlyContinue)) {
try {
$cpus = @(Get-CimInstance Win32_Processor)
$cpu = 0; foreach ($c in $cpus) { $cpu += $c.LoadPercentage }; $cpu = $cpu / [math]::Max(1, $cpus.Count)
Put 'SYSTEM.CPU_LOAD' ([math]::Round($cpu, 1))
$d = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='C:'"
Put 'SYSTEM.DISK_C' ([math]::Round(100 * ($d.Size - $d.FreeSpace) / $d.Size, 1))
Put 'SYSTEM.PING_LOCALHOST' ([int](Test-Connection -ComputerName localhost -Count 1 -Quiet))
Put 'SYSTEM.PROC_ALM' ([int]([bool](Get-Process alm -ErrorAction SilentlyContinue)))
} catch { }
}
Start-Sleep -Seconds $Cycle
}
} finally {
if ($UntilFlag) { Put 'DEMO.FEED_ON' 0 }
Write-Log 'stop'
$mutex.ReleaseMutex()
}

View file

@ -0,0 +1,6 @@
@echo off
rem Starts cieng_feed.ps1 in the background (CI Server R1.03.00). Called by the display button
rem "Start" (server-side command, runs as the CI Server service account CIX_PROCESS) from the
rem fixed install folder C:\Users\Public\CI-Eng-Sample\feed (install_feed.ps1). Returns at once;
rem the feed runs until the button "Stop" writes CI-Eng-Sample.DEMO.FEED_ON = 0.
start "" /b powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0cieng_feed.ps1" -UntilFlag -Alarms -System

View file

@ -0,0 +1,18 @@
# Install or remove the CI-Eng-Sample live-data feed (CI Server R1.03.00).
# Copies cieng_feed.ps1 and cieng_feed_start.cmd to C:\Users\Public\CI-Eng-Sample\feed: a fixed folder
# outside the CI Server installation (the feed is not part of the CI Server package) that the CI
# Server service account can read. The display button "Start" calls the .cmd there.
# No admin rights needed. Usage: powershell -ExecutionPolicy Bypass -File install_feed.ps1 [-Remove]
param([switch]$Remove)
$dest = 'C:\Users\Public\CI-Eng-Sample\feed'
if ($Remove) {
if (Test-Path $dest) { Remove-Item -LiteralPath $dest -Recurse -Force }
$parent = Split-Path $dest
if ((Test-Path $parent) -and -not (Get-ChildItem -LiteralPath $parent -Force)) { Remove-Item -LiteralPath $parent -Force }
'Feed removed from ' + $dest
return
}
New-Item -ItemType Directory -Force -Path $dest > $null
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'cieng_feed.ps1') -Destination $dest -Force
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'cieng_feed_start.cmd') -Destination $dest -Force
'Feed installed in ' + $dest