diff --git a/examples/CI-Eng-Sample/02_item_df.qli b/examples/CI-Eng-Sample/02_item_df.qli index d689ea3..96b754c 100644 --- a/examples/CI-Eng-Sample/02_item_df.qli +++ b/examples/CI-Eng-Sample/02_item_df.qli @@ -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 diff --git a/examples/CI-Eng-Sample/91_remove_item_df.qli b/examples/CI-Eng-Sample/91_remove_item_df.qli index bf4d425..ddd4a6c 100644 --- a/examples/CI-Eng-Sample/91_remove_item_df.qli +++ b/examples/CI-Eng-Sample/91_remove_item_df.qli @@ -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" diff --git a/examples/CI-Eng-Sample/displays/trend_feed.ps1 b/examples/CI-Eng-Sample/displays/trend_feed.ps1 deleted file mode 100644 index 37049e4..0000000 --- a/examples/CI-Eng-Sample/displays/trend_feed.ps1 +++ /dev/null @@ -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 -} diff --git a/examples/CI-Eng-Sample/feed/cieng_feed.ps1 b/examples/CI-Eng-Sample/feed/cieng_feed.ps1 new file mode 100644 index 0000000..b1128ca --- /dev/null +++ b/examples/CI-Eng-Sample/feed/cieng_feed.ps1 @@ -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() +} diff --git a/examples/CI-Eng-Sample/feed/cieng_feed_start.cmd b/examples/CI-Eng-Sample/feed/cieng_feed_start.cmd new file mode 100644 index 0000000..022d6c9 --- /dev/null +++ b/examples/CI-Eng-Sample/feed/cieng_feed_start.cmd @@ -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 diff --git a/examples/CI-Eng-Sample/feed/install_feed.ps1 b/examples/CI-Eng-Sample/feed/install_feed.ps1 new file mode 100644 index 0000000..adcd746 --- /dev/null +++ b/examples/CI-Eng-Sample/feed/install_feed.ps1 @@ -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