status alerts grace period 10 mins

This commit is contained in:
2026-09-10 20:46:31 +02:00
parent c23350400c
commit d74634331c
3 changed files with 139 additions and 10 deletions
+33 -9
View File
@@ -71,6 +71,7 @@ SHUTDOWN_COMMAND = "sudo /usr/sbin/shutdown -h now"
REMOTE_SHUTDOWN_RUNTIME_SECONDS = 5 * 60
LOCAL_SHUTDOWN_RUNTIME_SECONDS = 200
BATTERY_CHARGE_MEAN_SAMPLES = 10
STATUS_ALERT_DELAY_SECONDS = 10 * 60
GRAPH_COLOR_ARGS = [
"--color", "BACK#F7F5EFFF",
@@ -486,6 +487,36 @@ def crossed_below(previous, current, threshold):
)
def process_status_alert(previous, current_status):
"""Notify only after a new status persists for ten minutes across runs."""
# Older state files only have the latest observed status.
confirmed = previous.get("confirmed_status", previous.get("status"))
pending = previous.get("pending_status")
pending_since = previous.get("pending_status_since")
if not confirmed:
confirmed = current_status
pending = pending_since = None
elif current_status == confirmed:
pending = pending_since = None
elif current_status:
now = time.time()
if current_status != pending or pending_since is None:
pending = current_status
pending_since = now
elif now - pending_since >= STATUS_ALERT_DELAY_SECONDS:
notify(f"UPS status changed: {confirmed} -> {current_status}")
confirmed = current_status
pending = pending_since = None
return {
"confirmed_status": confirmed,
"pending_status": pending,
"pending_status_since": pending_since,
}
def battery_charge_history(previous, current_charge):
"""Return up to the last 10 valid battery-charge measurements."""
@@ -585,18 +616,10 @@ def process_alerts(current):
current_runtime = current.get("battery_runtime")
shutdown_sent = previous.get("remote_shutdown_sent", False)
local_shutdown_sent = previous.get("local_shutdown_sent", False)
status_alert_state = process_status_alert(previous, current_status)
# An empty state is the initial baseline, not an alert condition.
if previous:
if (
previous_status
and current_status
and current_status != previous_status
):
notify(
f"UPS status changed: {previous_status} -> {current_status}"
)
if current_charge_mean is not None and (
previous_charge_mean is None
or crossed_below(previous_charge_mean, current_charge_mean, 50)
@@ -673,6 +696,7 @@ def process_alerts(current):
# Keep the last valid reading when NUT temporarily omits a value.
state = {
**status_alert_state,
"status": current_status or previous_status,
"battery_charge": (
current_charge if current_charge is not None else previous_charge