# ups ## Purpose Polls a local NUT (Network UPS Tools) daemon for battery status and publishes power state transitions onto the MQTT bus. When the UPS runs below a configured critical-runtime threshold, triggers a graceful shutdown of the host. ## Key files - `vigilar/ups/monitor.py` — `UPSMonitor`: NUT client, status parser, transition detection, MQTT publisher - `vigilar/ups/shutdown.py` — `ShutdownSequence`: publishes `SYSTEM_SHUTDOWN` and executes the OS shutdown - `vigilar/ups/__init__.py` ## MQTT topics **Subscribes:** none **Publishes:** - `vigilar/ups/status` (every poll; status, battery charge %, runtime seconds, input voltage, load %) - `vigilar/ups/power_loss` (transition `OL -> OB`/`LB`) - `vigilar/ups/restored` (transition back to `OL`) - `vigilar/ups/low_battery` (charge below `low_battery_threshold_pct`) - `vigilar/ups/critical` (runtime below `critical_runtime_threshold_s`, triggers shutdown) - `vigilar/system/shutdown` (published by `ShutdownSequence`) ## Database tables - `events` — writes `POWER_LOSS`, `POWER_RESTORED`, `LOW_BATTERY` rows via `insert_event` - `system_events` — writes operator-facing notices (`"Power loss detected — running on battery"`, critical shutdown messages) ## Depends on - External NUT daemon reachable at `[ups] nut_host:nut_port` via the `pynut2` client - `storage` — `insert_event`, `insert_system_event` ## Consumed by - `events` — classifies `vigilar/ups/*` into `POWER_LOSS` / `LOW_BATTERY` / `POWER_RESTORED` - `alerts` — receives those classified events through rule actions - `main` supervisor — reacts to `SYSTEM_SHUTDOWN` so all subsystems can drain cleanly ## Notes The critical shutdown trigger fires when the UPS is not online AND `battery.runtime < ups.critical_runtime_threshold_s` AND no shutdown has already been triggered. The low-battery alert fires when `battery.charge < ups.low_battery_threshold_pct` while off mains. NUT reconnection uses exponential backoff capped at 120 seconds, so the monitor survives a temporary NUT restart without the supervisor having to restart it.