feat(ups): ramura "pe baterie" se poate testa fara scoaterea din priza
Lantul de protectie are doua jumatati. Prima - "UPS-ul chiar raporteaza trecerea pe baterie?" - e deja dovedita de perechile de evenimente Kernel-Power 105 de la panele reale din 2026. A doua - decizie, alerta, oprirea curata a Oracle - nu avea cum sa fie exercitata decat asteptand o pana. Acum monitorul accepta un SIMULARE.json care suprascrie citirea de alimentare. Doua garzi, ca un fisier uitat sa nu opreasca serverul pe date inventate: "expira" e obligatoriu si e sters automat la depasire, iar oprirea e in gol daca nu se cere explicit "dryRun": false. Cat e activa, fiecare ciclu scrie WARN in log si -Mode Status o afiseaza. test-battery.ps1 conduce simularea si urmareste logul; sterge fisierul si daca e intrerupt. Cu -ConfirmReal 'DA-OPRESTE-SERVERUL' devine repetitie reala pentru o fereastra de mentenanta - singurul mod de a masura cat dureaza shutdown immediate pe baza de productie, informatie de care depinde alegerea pragurilor. Validat in gol pe 27.08.2026: detectie la 15:36:09 + email de pana, apoi exact trei cicluri de confirmare, declansare pe pragul de 35% la 15:36:40 si secventa parcursa integral. Oracle a ramas Running. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RRyaDj39hPQ89SZS6URRpS
This commit is contained in:
@@ -113,6 +113,61 @@ function Get-PowerReading {
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Simulare - testarea ramurii "pe baterie" fara sa scoti UPS-ul din priza
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# Cat timp exista SIMULARE.json langa config.json, citirea reala e suprascrisa
|
||||
# cu valorile din el. Doua garzi, ca un fisier uitat sa nu opreasca serverul pe
|
||||
# date inventate:
|
||||
# - "expira" e OBLIGATORIU; fara el fisierul e ignorat, iar la depasire e sters;
|
||||
# - oprirea e in gol (dry-run) daca nu se cere explicit "dryRun": false.
|
||||
|
||||
function Get-Simulation {
|
||||
param([string]$Path)
|
||||
|
||||
if (-not (Test-Path -LiteralPath $Path)) { return $null }
|
||||
|
||||
try {
|
||||
$s = Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json
|
||||
} catch {
|
||||
Write-Log "SIMULARE.json nu se poate citi, il ignor: $($_.Exception.Message)" -Level WARN
|
||||
return $null
|
||||
}
|
||||
|
||||
if (-not ($s.PSObject.Properties.Name -contains 'expira') -or -not $s.expira) {
|
||||
Write-Log 'SIMULARE.json nu are camp "expira" - ignorat, ca sa nu ramana activ la nesfarsit' -Level WARN
|
||||
return $null
|
||||
}
|
||||
|
||||
if ((Get-Date) -gt [datetime]$s.expira) {
|
||||
Write-Log 'SIMULARE.json a expirat - il sterg si revin la citirea reala' -Level WARN
|
||||
Remove-Item -LiteralPath $Path -Force -ErrorAction SilentlyContinue
|
||||
return $null
|
||||
}
|
||||
|
||||
return $s
|
||||
}
|
||||
|
||||
function Merge-Simulation {
|
||||
param([object]$Reading, [object]$Sim)
|
||||
|
||||
$o = $Reading.PSObject.Copy()
|
||||
$map = @{
|
||||
onBattery = 'OnBattery'
|
||||
percent = 'Percent'
|
||||
runtimeSec = 'RuntimeSec'
|
||||
upsPresent = 'UpsPresent'
|
||||
}
|
||||
foreach ($k in $map.Keys) {
|
||||
if ($Sim.PSObject.Properties.Name -contains $k) {
|
||||
$o.($map[$k]) = $Sim.$k
|
||||
}
|
||||
}
|
||||
$o.AcKnown = $true
|
||||
return $o
|
||||
}
|
||||
|
||||
function Get-UpsDeviceInfo {
|
||||
# Confirmare a doua, din WMI - folosita doar in alerte si in modul Status,
|
||||
# ca sa nu interogam WMI la fiecare ciclu.
|
||||
@@ -425,6 +480,17 @@ function Invoke-Cycle {
|
||||
$now = Get-Date
|
||||
$r = Get-PowerReading
|
||||
|
||||
# --- simulare (daca e activa, suprascrie citirea reala) -----------------
|
||||
$sim = Get-Simulation -Path $script:SimPath
|
||||
if ($sim) {
|
||||
$r = Merge-Simulation -Reading $r -Sim $sim
|
||||
$simDryRun = $true
|
||||
if ($sim.PSObject.Properties.Name -contains 'dryRun') { $simDryRun = [bool]$sim.dryRun }
|
||||
if ($simDryRun) { $DryRun = $true }
|
||||
Write-Log ("SIMULARE ACTIVA pana la {0} (dryRun={1}): onBattery={2} percent={3} upsPresent={4}" -f `
|
||||
$sim.expira, $simDryRun, $r.OnBattery, $r.Percent, $r.UpsPresent) -Level WARN
|
||||
}
|
||||
|
||||
# --- comunicatia cu UPS-ul ---------------------------------------------
|
||||
if (-not $r.UpsPresent) {
|
||||
$script:CommsMissCount++
|
||||
@@ -529,6 +595,7 @@ Urmeaza un email si atunci.
|
||||
|
||||
$cfg = Get-Config -Path $ConfigPath
|
||||
$script:LogDir = $cfg.logPath
|
||||
$script:SimPath = Join-Path (Split-Path -Parent $ConfigPath) 'SIMULARE.json'
|
||||
$script:OnBatteryCount = 0
|
||||
$script:CommsMissCount = 0
|
||||
|
||||
@@ -540,6 +607,13 @@ switch ($Mode) {
|
||||
Write-Host ''
|
||||
$st = Get-State -Path $cfg.stateFile
|
||||
Write-Host "Stare salvata : power=$($st.powerState) comms=$($st.commsState) onBatterySince=$($st.onBatterySince)"
|
||||
if (Test-Path -LiteralPath $script:SimPath) {
|
||||
Write-Host "SIMULARE : ACTIVA -> $script:SimPath"
|
||||
Get-Content -LiteralPath $script:SimPath -Raw | ForEach-Object { " $_" }
|
||||
}
|
||||
if (Test-Path -LiteralPath (Join-Path (Split-Path -Parent $ConfigPath) 'DEZACTIVAT')) {
|
||||
Write-Host 'AUTOMATISM : DEZARMAT (exista fisierul DEZACTIVAT)'
|
||||
}
|
||||
try {
|
||||
$task = Get-ScheduledTask -TaskName 'ROMFAST UPS Monitor' -ErrorAction Stop
|
||||
$info = Get-ScheduledTaskInfo -TaskName 'ROMFAST UPS Monitor'
|
||||
|
||||
Reference in New Issue
Block a user