fix(ups): testul lunar de baterie nu putea da alarma niciodata
Verdictul se calcula din CHARGE_DROP, dar la acest UPS battery.charge nu e o masuratoare independenta: driverul nutdrv_qx / Voltronic-QS-Hex o deduce liniar din tensiune intre battery.voltage.low (20.8V) si .high (26.0V). Verificat pe toate probele din 11 luni: 25.76V -> 95.4% -> raportat 95%. Traduse in tensiune, pragurile vechi cereau o cadere de 3.70V pentru FAIR (primul prag care trimite severity warning) si 4.74V pentru POOR, intr-un test de 40 de secunde. Maximul observat in 11 luni a fost 2.59V. De asta raportul a iesit EXCELLENT 11 luni la rand si ar fi facut-o si cu bateria pe moarte. Evaluarea se face acum pe tendinta: mediana ultimelor 3 rulari fata de mediana primelor 6, plus o plasa de siguranta pe tensiune absoluta (<25.0V forteaza FAIR, <24.0V forteaza POOR). Fereastra de 3 impiedica o luna atipica sa declanseze singura alarma - verificat pe feb 2026 (2.59V), care nu bascuelaza verdictul. Istoricul se tine in /var/log/ups-battery-trend.csv, populat cu cele 14 rulari extrase din jurnal (2025-10-06 -> 2026-08-01), ca linia de baza sa fie valida imediat si nu peste 9 luni. Starea la zi: baza 1.82V, recent 2.12V, raport 1.16x -> EXCELLENT. Cresterea de ~16% in 10 luni e reala dar sub banda de avertizare; FAIR s-ar da la 2.73V. Instalat pe pvemini in /opt/scripts/, verificat cap-coada cu testul de baterie anulat, ca sa nu descarce bateria: tendinta calculata corect, template-urile regenerate cu campurile noi, notificarea PVE::Notify trimisa cu succes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RRyaDj39hPQ89SZS6URRpS
This commit is contained in:
@@ -10,12 +10,17 @@ Ghid complet pentru înlocuirea bateriei UPS când cluster-ul Proxmox este compl
|
||||
|
||||
### Indicatori din Testele Lunare:
|
||||
|
||||
Verdictul lunar se dă pe **tendința căderii de tensiune** față de linia de bază a
|
||||
bateriei, nu pe praguri absolute de încărcare (vezi
|
||||
[UPS-MONTHLY-TEST.md](UPS-MONTHLY-TEST.md#evaluare-sănătate-baterie) pentru de ce).
|
||||
|
||||
| Indicator | Acțiune |
|
||||
|-----------|---------|
|
||||
| **Health: POOR** (charge drop > 55%) | ⚠️ URGENT - Înlocuiește IMEDIAT |
|
||||
| **Health: FAIR** (charge drop 35-55%) | 📅 Planifică în 1-3 luni |
|
||||
| **Health: GOOD** (charge drop 15-35%) | ✅ Monitorizează lunar |
|
||||
| **Health: EXCELLENT** (charge drop < 15%) | ✅ Baterie OK |
|
||||
| **Health: POOR** (≥ 2.0x față de bază, sau minim < 24.0V) | ⚠️ URGENT - Înlocuiește IMEDIAT |
|
||||
| **Health: FAIR** (1.5-2.0x, sau minim < 25.0V) | 📅 Planifică în 1-3 luni |
|
||||
| **Health: GOOD** (1.25-1.5x) | ✅ Monitorizează lunar |
|
||||
| **Health: EXCELLENT** (< 1.25x) | ✅ Baterie OK |
|
||||
| **Health: BASELINE** | Se colectează istoric, sub 9 rulări |
|
||||
|
||||
### Alte Semne:
|
||||
|
||||
@@ -341,7 +346,18 @@ tail -30 /var/log/ups-monthly-test.log | grep -A 5 "Sănătate baterie"
|
||||
```
|
||||
|
||||
**Așteptat pentru baterie nouă:**
|
||||
- Charge drop: < 10% (EXCELLENT)
|
||||
- Raport față de linia de bază: < 1.25x (EXCELLENT)
|
||||
|
||||
**După înlocuire, linia de bază trebuie resetată** — altfel bateria nouă se compară
|
||||
cu media celei vechi și verdictul iese fals de bun:
|
||||
|
||||
```bash
|
||||
mv /var/log/ups-battery-trend.csv /var/log/ups-battery-trend.csv.$(date +%Y%m%d).vechi
|
||||
# primele 9 rulări vor raporta BASELINE, apoi verdictul redevine valid
|
||||
```
|
||||
|
||||
Notează data înlocuirii în acest document — jurnalul nu o conține, iar vârsta
|
||||
bateriei nu se poate deduce din software.
|
||||
- Voltage drop: 1-2V
|
||||
- Recuperare rapidă: < 60 secunde
|
||||
|
||||
|
||||
@@ -47,24 +47,90 @@ Script automat pentru testarea lunară a bateriei UPS care rulează pe data de 1
|
||||
|
||||
## Evaluare Sănătate Baterie
|
||||
|
||||
Scriptul evaluează sănătatea bateriei bazat pe scăderea încărcării în timpul testului:
|
||||
**Evaluarea se face pe tendință, nu pe praguri absolute.** Din 2026-08-27; înainte
|
||||
se folosea scăderea încărcării față de praguri fixe, care nu funcționa — vezi
|
||||
[De ce s-a schimbat metoda](#de-ce-sa-schimbat-metoda) mai jos.
|
||||
|
||||
| Scădere Încărcare | Sănătate | Status | Acțiune Necesară |
|
||||
|-------------------|----------|--------|------------------|
|
||||
| < 10% | **EXCELLENT** | ✅ Verde | Nicio acțiune necesară |
|
||||
| 10-30% | **GOOD** | ✅ Verde | Continuă monitorizarea |
|
||||
| 30-50% | **FAIR** | ⚠️ Galben | Planifică înlocuire în 3-6 luni |
|
||||
| > 50% | **POOR** | 🔴 Roșu | **URGENT: Înlocuiește bateria!** |
|
||||
### Metoda
|
||||
|
||||
### Exemple de rezultate reale:
|
||||
Se măsoară **căderea de tensiune sub sarcină** în cele ~40 de secunde de test și se
|
||||
compară cu linia de bază a acestei baterii:
|
||||
|
||||
**Test 1 (2025-10-06 20:45):**
|
||||
- Scădere încărcare: 0% (charge reporting delay)
|
||||
- Scădere tensiune: 1.64V (27.88V → 26.24V)
|
||||
- Evaluare: **EXCELLENT**
|
||||
- Recuperare: 30 secunde la 100%
|
||||
- **linia de bază** = mediana primelor 6 rulări înregistrate, adică bateria în cea
|
||||
mai bună stare pe care o avem măsurată;
|
||||
- **valoarea recentă** = mediana ultimelor 3 rulări, ca o lună atipică (frig,
|
||||
sarcină mare) să nu declanșeze singură o alarmă;
|
||||
- **raportul** dintre ele urcă pe măsură ce crește rezistența internă a bateriei,
|
||||
ceea ce dă avertisment cu luni înainte de cedare.
|
||||
|
||||
**Notă:** UPS-ul raportează uneori încărcarea cu întârziere. Scăderea tensiunii este un indicator mai precis al capacității bateriei.
|
||||
| Raport față de bază | Sănătate | Severitate email | Acțiune |
|
||||
|---------------------|----------|------------------|---------|
|
||||
| < 1.25x | **EXCELLENT** | info | Nicio acțiune |
|
||||
| 1.25 – 1.50x | **GOOD** | info | Uzură normală, urmărește lunar |
|
||||
| 1.50 – 2.00x | **FAIR** | ⚠️ warning | Planifică înlocuirea în 3-6 luni |
|
||||
| ≥ 2.00x | **POOR** | 🔴 error | **URGENT: înlocuiește bateria** |
|
||||
|
||||
Peste asta există o **plasă de siguranță pe tensiune absolută**, pentru cazul în
|
||||
care bateria cedează brusc, înainte să apuce mediana să urce:
|
||||
|
||||
| Minim atins în test | Efect |
|
||||
|---------------------|-------|
|
||||
| < 25.0 V | forțează cel puțin **FAIR** |
|
||||
| < 24.0 V | forțează **POOR** direct |
|
||||
|
||||
Până se strâng 9 rulări (6 pentru bază + 3 pentru fereastra recentă), verdictul
|
||||
este **BASELINE** — se colectează date, severitate `info`.
|
||||
|
||||
### Fișierul de tendință
|
||||
|
||||
`/var/log/ups-battery-trend.csv`, câte o linie per rulare:
|
||||
|
||||
```
|
||||
date,voltage_drop,min_voltage,charge_drop,before_load,after_load,duration
|
||||
2026-08-01,2.12,25.76,5,10,12,40
|
||||
```
|
||||
|
||||
Se poate reconstrui oricând din jurnal cu
|
||||
`/opt/scripts/ups-battery-trend-backfill.sh --force`. A fost populat inițial cu
|
||||
14 rulări extrase din `/var/log/ups-monthly-test.log` (2025-10-06 → 2026-08-01),
|
||||
ca linia de bază să fie validă imediat și nu peste 9 luni.
|
||||
|
||||
### Starea la 2026-08-27
|
||||
|
||||
| Perioadă | Cădere de tensiune |
|
||||
|----------|--------------------|
|
||||
| oct–dec 2025 (linia de bază) | 1.41 – 2.00 V, mediană **1.82 V** |
|
||||
| iun–aug 2026 (recent) | 2.12 – 2.23 V, mediană **2.12 V** |
|
||||
|
||||
Raport **1.16x** → **EXCELLENT**. Creșterea de ~16% în 10 luni e reală, dar sub
|
||||
banda de avertizare. Alarma (FAIR) s-ar da la o cădere de ~2.73 V.
|
||||
|
||||
### De ce s-a schimbat metoda
|
||||
|
||||
`battery.charge` **nu e o măsurătoare independentă** la acest UPS. Driverul
|
||||
`nutdrv_qx` / `Voltronic-QS-Hex` nu are contor de coulombi; deduce încărcarea
|
||||
liniar din tensiune, între `battery.voltage.low` (20.8 V) și `battery.voltage.high`
|
||||
(26.0 V):
|
||||
|
||||
```
|
||||
charge = (V - 20.8) / (26.0 - 20.8) * 100
|
||||
```
|
||||
|
||||
Verificat pe toate probele din 11 luni: 25.76 V → 95.4% → raportat 95%;
|
||||
25.29 V → 86.3% → raportat 86%. Se potrivește exact de fiecare dată.
|
||||
|
||||
Pragurile vechi, traduse înapoi în tensiune, cereau:
|
||||
|
||||
| Prag vechi | Însemna cădere de | Observat în 11 luni |
|
||||
|------------|-------------------|---------------------|
|
||||
| GOOD (drop 15%) | 2.66 V | maxim 2.59 V |
|
||||
| FAIR (drop 35%) | **3.70 V** | niciodată |
|
||||
| POOR (drop 55%) | **4.74 V** | niciodată |
|
||||
|
||||
EXCELLENT și GOOD sunt amândouă severitate `info`, deci primul prag care chiar
|
||||
trimite un avertisment era FAIR, la o cădere de 3.70 V într-un test de 40 de
|
||||
secunde. O baterie ajunsă acolo e practic un rezistor. De asta testul a raportat
|
||||
**EXCELLENT 11 luni la rând** și ar fi făcut-o și cu bateria pe moarte.
|
||||
|
||||
## Instalare
|
||||
|
||||
@@ -396,11 +462,14 @@ Recuperare: 25% în 300 secunde
|
||||
| Indicator | Bun | Acceptabil | Critic |
|
||||
|-----------|-----|------------|--------|
|
||||
| **Vârstă baterie** | < 2 ani | 2-4 ani | > 4 ani |
|
||||
| **Scădere încărcare** | < 10% | 10-50% | > 50% |
|
||||
| **Scădere tensiune** | < 2V | 2-5V | > 5V |
|
||||
| **Raport față de linia de bază** | < 1.25x | 1.25-2.0x | > 2.0x |
|
||||
| **Tensiune minimă în test** | > 25.0V | 24.0-25.0V | < 24.0V |
|
||||
| **Timp recuperare** | < 1 min | 1-5 min | > 5 min |
|
||||
| **Teste failed** | 0 | 1-2 | > 3 |
|
||||
|
||||
Scăderea încărcării nu mai e criteriu — la acest UPS e tensiunea rescalată, nu o
|
||||
măsurătoare separată.
|
||||
|
||||
### Factori care afectează durata de viață:
|
||||
|
||||
- **Temperatură:** Ideal 20-25°C (fiecare +10°C reduce durata cu 50%)
|
||||
|
||||
102
proxmox/cluster/ups/scripts/ups-battery-trend-backfill.sh
Normal file
102
proxmox/cluster/ups/scripts/ups-battery-trend-backfill.sh
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Reconstruiește /var/log/ups-battery-trend.csv din jurnalul testelor lunare.
|
||||
#
|
||||
# De ce există: ups-monthly-test.sh evaluează sănătatea bateriei comparând
|
||||
# căderea de tensiune cu linia de bază a acestei baterii. Fără istoric, linia de
|
||||
# bază s-ar forma abia după 9 rulări, adică 9 luni. Jurnalul conține însă deja
|
||||
# măsurătorile, din 2025-10-06 încoace — se extrag de acolo.
|
||||
#
|
||||
# Rulare unică. Refuză să suprascrie un CSV existent fără --force, ca să nu
|
||||
# reseteze din greșeală linia de bază acumulată.
|
||||
#
|
||||
# Creat: 2026-08-27
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
LOGFILE="${LOGFILE:-/var/log/ups-monthly-test.log}"
|
||||
TRENDFILE="${TRENDFILE:-/var/log/ups-battery-trend.csv}"
|
||||
FORCE=0
|
||||
DRY_RUN=0
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--force) FORCE=1 ;;
|
||||
--dry-run) DRY_RUN=1 ;;
|
||||
*) echo "Argument necunoscut: $arg" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -f "$LOGFILE" ]; then
|
||||
echo "EROARE: nu găsesc jurnalul $LOGFILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f "$TRENDFILE" ] && [ "$FORCE" -eq 0 ] && [ "$DRY_RUN" -eq 0 ]; then
|
||||
echo "EROARE: $TRENDFILE există deja. Folosește --force ca să-l reconstruiești." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parserul lucrează doar cu tipare ASCII — etichetele cu diacritice din jurnal
|
||||
# ("Scădere tensiune") nu se pot potrivi portabil în awk pe toate locale-urile,
|
||||
# așa că valorile se recalculează din before/min, care apar fără diacritice.
|
||||
parse_log() {
|
||||
awk '
|
||||
function num(s) { gsub(/[^0-9.]/, "", s); return s }
|
||||
|
||||
/UPS MONTHLY BATTERY TEST - START/ {
|
||||
active = 1; phase = 0
|
||||
bch = ""; bv = ""; bl = ""; mc = ""; mv = ""; al = ""; dur = ""; d = ""
|
||||
next
|
||||
}
|
||||
!active { next }
|
||||
|
||||
/Step 1:/ { phase = 1; next }
|
||||
/Step 3:/ { phase = 3; d = substr($1, 2); next }
|
||||
/Step 4:/ { phase = 4; next }
|
||||
|
||||
phase == 1 && /Battery Charge:/ { bch = num($NF); next }
|
||||
phase == 1 && /Battery Voltage:/ { bv = num($(NF-1)); next }
|
||||
phase == 1 && /Load:/ { bl = num($NF); next }
|
||||
|
||||
/Minimum Charge:/ { mc = num($NF); next }
|
||||
/Minimum Voltage:/ { mv = num($(NF-1)); next }
|
||||
|
||||
phase == 4 && /Load:/ { al = num($NF); next }
|
||||
|
||||
/ test: [0-9]+ secunde/ { dur = num($(NF-1)); next }
|
||||
|
||||
/UPS MONTHLY BATTERY TEST - COMPLETE/ {
|
||||
active = 0
|
||||
# Blocurile din versiunile vechi de script nu au minimele — se sar.
|
||||
if (d != "" && mv != "" && bv != "") {
|
||||
vd = bv - mv
|
||||
cd = (bch != "" && mc != "") ? bch - mc : ""
|
||||
printf "%s,%.2f,%s,%s,%s,%s,%s\n", d, vd, mv, cd, bl, al, dur
|
||||
}
|
||||
next
|
||||
}
|
||||
' "$LOGFILE"
|
||||
}
|
||||
|
||||
ROWS=$(parse_log)
|
||||
COUNT=$(printf '%s\n' "$ROWS" | grep -c ',' || true)
|
||||
|
||||
if [ "$COUNT" -eq 0 ]; then
|
||||
echo "EROARE: nu s-a extras nicio rulare din $LOGFILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
echo "date,voltage_drop,min_voltage,charge_drop,before_load,after_load,duration"
|
||||
printf '%s\n' "$ROWS"
|
||||
echo "--- $COUNT rulari extrase (dry-run, nimic scris) ---" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
{
|
||||
echo "date,voltage_drop,min_voltage,charge_drop,before_load,after_load,duration"
|
||||
printf '%s\n' "$ROWS"
|
||||
} > "$TRENDFILE"
|
||||
|
||||
echo "Scris $COUNT rulari in $TRENDFILE"
|
||||
@@ -12,6 +12,7 @@
|
||||
# Autor: Claude Code
|
||||
|
||||
LOGFILE="/var/log/ups-monthly-test.log"
|
||||
TRENDFILE="/var/log/ups-battery-trend.csv"
|
||||
UPS_NAME="nutdev1"
|
||||
UPS_USER="admin"
|
||||
UPS_PASS="parola99"
|
||||
@@ -25,6 +26,41 @@ log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOGFILE
|
||||
}
|
||||
|
||||
# Câte rulări formează linia de bază și câte intră în fereastra recentă.
|
||||
# Baza = primele rulări înregistrate, adică bateria în starea ei cea mai bună
|
||||
# pe care o avem măsurată. Fereastra recentă e mediană pe 3, ca o lună
|
||||
# atipică (frig, sarcină mare) să nu declanșeze singură o alarmă.
|
||||
BASELINE_RUNS=6
|
||||
TREND_WINDOW=3
|
||||
|
||||
# Adaugă rularea curentă în fișierul de tendință
|
||||
append_trend() {
|
||||
if [ ! -f "$TRENDFILE" ]; then
|
||||
echo "date,voltage_drop,min_voltage,charge_drop,before_load,after_load,duration" > "$TRENDFILE"
|
||||
fi
|
||||
echo "$(date '+%Y-%m-%d'),$1,$2,$3,$4,$5,$6" >> "$TRENDFILE"
|
||||
}
|
||||
|
||||
# Numărul de rulări înregistrate (fără antet)
|
||||
trend_rows() {
|
||||
tail -n +2 "$TRENDFILE" 2>/dev/null | grep -c ',' || echo 0
|
||||
}
|
||||
|
||||
# Mediana coloanei voltage_drop. $1 = head|tail (cele mai vechi / cele mai noi),
|
||||
# $2 = câte rânduri. head/tail se aplică pe ordinea cronologică, sortarea abia
|
||||
# după — altfel s-ar lua cele mai mici valori, nu cele mai vechi.
|
||||
trend_median() {
|
||||
local mode="$1" n="$2"
|
||||
tail -n +2 "$TRENDFILE" 2>/dev/null | cut -d, -f2 | grep -E '^[0-9]+\.?[0-9]*$' \
|
||||
| { if [ "$mode" = "head" ]; then head -n "$n"; else tail -n "$n"; fi; } \
|
||||
| sort -g \
|
||||
| awk '{v[NR]=$1} END {
|
||||
if (NR == 0) { print "" ; exit }
|
||||
if (NR % 2) printf "%.2f", v[(NR+1)/2]
|
||||
else printf "%.2f", (v[NR/2] + v[NR/2+1]) / 2
|
||||
}'
|
||||
}
|
||||
|
||||
# Funcție pentru crearea template-urilor de notificare
|
||||
create_templates() {
|
||||
mkdir -p $TEMPLATE_DIR
|
||||
@@ -51,6 +87,9 @@ TEST RESULTS:
|
||||
-------------
|
||||
Battery Charge Drop: {{ charge_drop }}%
|
||||
Battery Voltage Drop: {{ voltage_drop }}V
|
||||
Baseline Voltage Drop: {{ baseline_drop }}V ({{ baseline_runs }} rulari de referinta)
|
||||
Recent Median (3 run): {{ recent_drop }}V
|
||||
Trend vs Baseline: {{ trend_ratio }}x
|
||||
Minimum Charge Reached: {{ min_charge }}%
|
||||
Minimum Voltage: {{ min_voltage }}V
|
||||
Recovery Time: {{ recovery_time }}s
|
||||
@@ -136,6 +175,14 @@ EOFTEMPLATE
|
||||
<div class="metric-label">Recovery Time</div>
|
||||
<div class="metric-value">{{ recovery_time }}s</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">Trend vs Baseline</div>
|
||||
<div class="metric-value">{{ trend_ratio }}x</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">Baseline Drop</div>
|
||||
<div class="metric-value">{{ baseline_drop }}V</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
@@ -183,8 +230,11 @@ EOFTEMPLATE
|
||||
}
|
||||
|
||||
# Verifică și creează template-urile dacă nu există
|
||||
if [ ! -f "$TEMPLATE_DIR/ups-battery-test-subject.txt.hbs" ]; then
|
||||
log "Creating notification templates..."
|
||||
# Template-urile se rescriu și dacă sunt dintr-o versiune veche, fără câmpurile
|
||||
# de tendință — altfel raportul ar ieși cu metrici lipsă.
|
||||
if [ ! -f "$TEMPLATE_DIR/ups-battery-test-subject.txt.hbs" ] || \
|
||||
! grep -q 'trend_ratio' "$TEMPLATE_DIR/ups-battery-test-body.txt.hbs" 2>/dev/null; then
|
||||
log "Creating/updating notification templates..."
|
||||
create_templates
|
||||
fi
|
||||
|
||||
@@ -302,41 +352,117 @@ log " Durată test: $TEST_DURATION secunde"
|
||||
log " Scădere încărcare: $CHARGE_DROP% (de la $BEFORE_CHARGE% la $MIN_CHARGE%)"
|
||||
log " Scădere tensiune: $VOLTAGE_DROP V (de la $BEFORE_VOLTAGE V la $MIN_VOLTAGE V)"
|
||||
|
||||
# 6. Evaluare sănătate baterie
|
||||
# 6. Evaluare sănătate baterie — pe tendință, nu pe prag absolut
|
||||
#
|
||||
# De ce nu pe prag absolut: driverul nu măsoară încărcarea, o deduce liniar din
|
||||
# tensiune între battery.voltage.low (20.8V) și .high (26.0V). Un CHARGE_DROP de
|
||||
# 15% înseamnă deci o cădere sub ~25.2V, iar 55% înseamnă sub ~23.1V — într-un
|
||||
# test de 40 de secunde. O baterie ajunsă acolo e deja moartă. Pragurile vechi
|
||||
# nu se puteau atinge, așa că verdictul a ieșit EXCELLENT 11 luni la rând.
|
||||
#
|
||||
# Ce se măsoară în schimb: căderea de tensiune sub sarcină, comparată cu linia de
|
||||
# bază a acestei baterii. Rezistența internă crește pe măsură ce bateria
|
||||
# îmbătrânește, deci raportul crește lent și dă avertisment din timp.
|
||||
|
||||
append_trend "$VOLTAGE_DROP" "$MIN_VOLTAGE" "$CHARGE_DROP" "$BEFORE_LOAD" "$AFTER_LOAD" "$TEST_DURATION"
|
||||
|
||||
TREND_ROWS=$(trend_rows)
|
||||
BASELINE_DROP=$(trend_median head $BASELINE_RUNS)
|
||||
RECENT_DROP=$(trend_median tail $TREND_WINDOW)
|
||||
BASELINE_RUNS_USED=$BASELINE_RUNS
|
||||
if [ "$TREND_ROWS" -lt "$BASELINE_RUNS" ]; then
|
||||
BASELINE_RUNS_USED=$TREND_ROWS
|
||||
fi
|
||||
|
||||
TREND_RATIO="n/a"
|
||||
if [ -n "$BASELINE_DROP" ] && [ -n "$RECENT_DROP" ]; then
|
||||
TREND_RATIO=$(awk -v r="$RECENT_DROP" -v b="$BASELINE_DROP" \
|
||||
'BEGIN { if (b > 0) printf "%.2f", r / b; else print "n/a" }')
|
||||
fi
|
||||
|
||||
log ""
|
||||
log "Step 5b: Tendință față de linia de bază..."
|
||||
log " Rulări înregistrate: $TREND_ROWS (fișier: $TRENDFILE)"
|
||||
log " Linie de bază (mediana primelor $BASELINE_RUNS_USED): ${BASELINE_DROP:-n/a} V"
|
||||
log " Recent (mediana ultimelor $TREND_WINDOW): ${RECENT_DROP:-n/a} V"
|
||||
log " Raport: ${TREND_RATIO}x"
|
||||
|
||||
BATTERY_HEALTH="UNKNOWN"
|
||||
HEALTH_CLASS="fair"
|
||||
HEALTH_EMOJI="[INFO]"
|
||||
HEALTH_DESCRIPTION=""
|
||||
RECOMMENDATIONS=""
|
||||
|
||||
if [ "$CHARGE_DROP" -lt 15 ]; then
|
||||
BATTERY_HEALTH="EXCELLENT"
|
||||
HEALTH_CLASS="excellent"
|
||||
HEALTH_EMOJI="[OK]"
|
||||
HEALTH_DESCRIPTION="Battery is in excellent condition with minimal discharge during test."
|
||||
RECOMMENDATIONS="<ul><li>✅ Battery is healthy and functioning normally</li><li>Continue monthly testing</li><li>No action required</li></ul>"
|
||||
log " Sănătate baterie: EXCELENTĂ (scădere < 15%)"
|
||||
elif [ "$CHARGE_DROP" -lt 35 ]; then
|
||||
BATTERY_HEALTH="GOOD"
|
||||
# Praguri de tensiune absolută, ca plasă de siguranță. Nu înlocuiesc tendința —
|
||||
# prind cazul în care bateria cedează brusc, înainte să apuce media să urce.
|
||||
FLOOR=$(awk -v v="$MIN_VOLTAGE" 'BEGIN {
|
||||
if (v == "" ) { print "none" }
|
||||
else if (v < 24.0) { print "critical" }
|
||||
else if (v < 25.0) { print "warn" }
|
||||
else { print "none" }
|
||||
}')
|
||||
|
||||
if [ "$TREND_ROWS" -lt $((BASELINE_RUNS + TREND_WINDOW)) ] && [ "$FLOOR" = "none" ]; then
|
||||
BATTERY_HEALTH="BASELINE"
|
||||
HEALTH_CLASS="good"
|
||||
HEALTH_EMOJI="[OK]"
|
||||
HEALTH_DESCRIPTION="Battery shows normal wear but performs adequately."
|
||||
RECOMMENDATIONS="<ul><li>Battery is functioning well</li><li>Monitor monthly for degradation trends</li><li>No immediate action needed</li></ul>"
|
||||
log " Sănătate baterie: BUNĂ (scădere 15-35%)"
|
||||
elif [ "$CHARGE_DROP" -lt 55 ]; then
|
||||
BATTERY_HEALTH="FAIR"
|
||||
HEALTH_CLASS="fair"
|
||||
HEALTH_EMOJI="[WARNING]"
|
||||
HEALTH_DESCRIPTION="Battery shows significant wear and should be monitored closely."
|
||||
RECOMMENDATIONS="<ul><li>⚠️ Battery is aging</li><li>Plan replacement in 3-6 months</li><li>Increase monitoring frequency</li><li>Order replacement battery soon</li></ul>"
|
||||
log " Sănătate baterie: ACCEPTABILĂ (scădere 35-55%)"
|
||||
else
|
||||
HEALTH_EMOJI="[INFO]"
|
||||
HEALTH_DESCRIPTION="Se colectează linia de bază. Verdictul pe tendință apare după $((BASELINE_RUNS + TREND_WINDOW)) rulări (acum: $TREND_ROWS)."
|
||||
RECOMMENDATIONS="<ul><li>Istoric insuficient pentru o comparație pe tendință</li><li>Rulări înregistrate: $TREND_ROWS din $((BASELINE_RUNS + TREND_WINDOW)) necesare</li><li>Nicio acțiune necesară</li></ul>"
|
||||
log " Sănătate baterie: BASELINE (istoric insuficient)"
|
||||
elif [ "$FLOOR" = "critical" ]; then
|
||||
BATTERY_HEALTH="POOR"
|
||||
HEALTH_CLASS="poor"
|
||||
HEALTH_EMOJI="[CRITICAL]"
|
||||
HEALTH_DESCRIPTION="Battery is critically weak and requires immediate replacement!"
|
||||
RECOMMENDATIONS="<ul><li>🔴 <strong>URGENT:</strong> Battery needs immediate replacement!</li><li>Order new battery NOW</li><li>UPS may not provide adequate protection</li><li>Risk of unexpected shutdown</li></ul>"
|
||||
log " Sănătate baterie: SLABĂ (scădere > 55%) - NECESITĂ ÎNLOCUIRE!"
|
||||
HEALTH_DESCRIPTION="Tensiunea a coborât sub 24.0V într-un test de $TEST_DURATION secunde. Bateria nu mai susține sarcina."
|
||||
RECOMMENDATIONS="<ul><li>🔴 <strong>URGENT:</strong> înlocuiește bateria acum</li><li>Minim atins: ${MIN_VOLTAGE}V (cutoff UPS: 20.8V)</li><li>Autonomia reală e de ordinul secundelor, nu al minutelor</li><li>Shutdown-ul orchestrat s-ar putea să nu apuce să termine</li></ul>"
|
||||
log " Sănătate baterie: SLABĂ (minim ${MIN_VOLTAGE}V < 24.0V) - NECESITĂ ÎNLOCUIRE!"
|
||||
elif [ "$TREND_RATIO" = "n/a" ]; then
|
||||
BATTERY_HEALTH="UNKNOWN"
|
||||
HEALTH_CLASS="fair"
|
||||
HEALTH_EMOJI="[WARNING]"
|
||||
HEALTH_DESCRIPTION="Nu s-a putut calcula tendința (fișier de tendință gol sau corupt)."
|
||||
RECOMMENDATIONS="<ul><li>Verifică $TRENDFILE</li><li>Verifică dacă upsc întoarce battery.voltage</li></ul>"
|
||||
log " Sănătate baterie: NECUNOSCUTĂ (tendință incalculabilă)"
|
||||
else
|
||||
RATIO_CLASS=$(awk -v r="$TREND_RATIO" -v f="$FLOOR" 'BEGIN {
|
||||
c = (r < 1.25) ? 1 : (r < 1.50) ? 2 : (r < 2.00) ? 3 : 4
|
||||
if (f == "warn" && c < 3) c = 3
|
||||
print c
|
||||
}')
|
||||
case "$RATIO_CLASS" in
|
||||
1)
|
||||
BATTERY_HEALTH="EXCELLENT"
|
||||
HEALTH_CLASS="excellent"
|
||||
HEALTH_EMOJI="[OK]"
|
||||
HEALTH_DESCRIPTION="Căderea de tensiune sub sarcină e la nivelul liniei de bază (${TREND_RATIO}x). Bateria nu dă semne de îmbătrânire."
|
||||
RECOMMENDATIONS="<ul><li>✅ Bateria e sănătoasă</li><li>Recent ${RECENT_DROP}V față de baza ${BASELINE_DROP}V</li><li>Nicio acțiune necesară</li></ul>"
|
||||
log " Sănătate baterie: EXCELENTĂ (${TREND_RATIO}x față de bază)"
|
||||
;;
|
||||
2)
|
||||
BATTERY_HEALTH="GOOD"
|
||||
HEALTH_CLASS="good"
|
||||
HEALTH_EMOJI="[OK]"
|
||||
HEALTH_DESCRIPTION="Căderea de tensiune a crescut cu 25-50% față de linia de bază (${TREND_RATIO}x). Uzură normală."
|
||||
RECOMMENDATIONS="<ul><li>Îmbătrânire vizibilă, dar în limite normale</li><li>Recent ${RECENT_DROP}V față de baza ${BASELINE_DROP}V</li><li>Urmărește lunar; la 1.5x se planifică înlocuirea</li></ul>"
|
||||
log " Sănătate baterie: BUNĂ (${TREND_RATIO}x față de bază)"
|
||||
;;
|
||||
3)
|
||||
BATTERY_HEALTH="FAIR"
|
||||
HEALTH_CLASS="fair"
|
||||
HEALTH_EMOJI="[WARNING]"
|
||||
HEALTH_DESCRIPTION="Căderea de tensiune s-a mărit de ${TREND_RATIO}x față de linia de bază. Rezistența internă a crescut semnificativ."
|
||||
RECOMMENDATIONS="<ul><li>⚠️ Planifică înlocuirea în 3-6 luni</li><li>Recent ${RECENT_DROP}V față de baza ${BASELINE_DROP}V</li><li>Minim atins în test: ${MIN_VOLTAGE}V</li><li>Comandă bateriile de schimb (2x 12V 7Ah)</li></ul>"
|
||||
log " Sănătate baterie: ACCEPTABILĂ (${TREND_RATIO}x față de bază)"
|
||||
;;
|
||||
*)
|
||||
BATTERY_HEALTH="POOR"
|
||||
HEALTH_CLASS="poor"
|
||||
HEALTH_EMOJI="[CRITICAL]"
|
||||
HEALTH_DESCRIPTION="Căderea de tensiune s-a dublat față de linia de bază (${TREND_RATIO}x). Bateria și-a pierdut capacitatea."
|
||||
RECOMMENDATIONS="<ul><li>🔴 <strong>URGENT:</strong> înlocuiește bateria</li><li>Recent ${RECENT_DROP}V față de baza ${BASELINE_DROP}V</li><li>Autonomia nu mai acoperă procedura de shutdown orchestrat</li><li>Vezi proxmox/cluster/ups/docs/UPS-BATTERY-REPLACEMENT.md</li></ul>"
|
||||
log " Sănătate baterie: SLABĂ (${TREND_RATIO}x față de bază) - NECESITĂ ÎNLOCUIRE!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 7. Monitorizare recuperare (30 secunde)
|
||||
@@ -355,9 +481,9 @@ END_TIME=$(date +%s)
|
||||
RUNTIME=$((END_TIME - START_TIME))
|
||||
|
||||
# 9. Determină severity pentru notificare
|
||||
if [ "$BATTERY_HEALTH" = "EXCELLENT" ] || [ "$BATTERY_HEALTH" = "GOOD" ]; then
|
||||
if [ "$BATTERY_HEALTH" = "EXCELLENT" ] || [ "$BATTERY_HEALTH" = "GOOD" ] || [ "$BATTERY_HEALTH" = "BASELINE" ]; then
|
||||
SEVERITY="info"
|
||||
elif [ "$BATTERY_HEALTH" = "FAIR" ]; then
|
||||
elif [ "$BATTERY_HEALTH" = "FAIR" ] || [ "$BATTERY_HEALTH" = "UNKNOWN" ]; then
|
||||
SEVERITY="warning"
|
||||
else
|
||||
SEVERITY="error"
|
||||
@@ -385,6 +511,10 @@ my \$template_data = {
|
||||
'health_description' => '$HEALTH_DESCRIPTION',
|
||||
'charge_drop' => '$CHARGE_DROP',
|
||||
'voltage_drop' => '$VOLTAGE_DROP',
|
||||
'baseline_drop' => '${BASELINE_DROP:-n/a}',
|
||||
'recent_drop' => '${RECENT_DROP:-n/a}',
|
||||
'trend_ratio' => '$TREND_RATIO',
|
||||
'baseline_runs' => '$BASELINE_RUNS_USED',
|
||||
'min_charge' => '$MIN_CHARGE',
|
||||
'min_voltage' => '$MIN_VOLTAGE',
|
||||
'before_charge' => '$BEFORE_CHARGE',
|
||||
@@ -429,6 +559,7 @@ log "UPS MONTHLY BATTERY TEST - COMPLETE"
|
||||
log "Sănătate baterie: $BATTERY_HEALTH"
|
||||
log "Scădere încărcare: $CHARGE_DROP%"
|
||||
log "Scădere tensiune: $VOLTAGE_DROP V"
|
||||
log "Linie de bază: ${BASELINE_DROP:-n/a} V | recent: ${RECENT_DROP:-n/a} V | raport: ${TREND_RATIO}x"
|
||||
log "Timp total: $RUNTIME secunde"
|
||||
log "========================================"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user