feat(nut): report outage duration and battery % in ntfy

ONBATT records the epoch start time and appends current battery
charge; ONLINE appends battery charge and the total outage duration
(HH:mm:ss) computed from the recorded start, then clears the state.
State lives in /run so it self-clears on reboot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Clément Désiles
2026-06-29 23:50:48 +02:00
parent 21f47196cf
commit 501f4e1f87
2 changed files with 35 additions and 0 deletions
+5
View File
@@ -61,3 +61,8 @@ nut_ntfy_server: https://ntfy.jokester.fr
# Path of the deployed NOTIFYCMD wrapper. # Path of the deployed NOTIFYCMD wrapper.
nut_notify_script_path: /usr/local/bin/ups-notify nut_notify_script_path: /usr/local/bin/ups-notify
# Where ups-notify records the epoch timestamp of the last ONBATT event, so the
# ONLINE notification can report total outage duration. Lives under /run so it
# is cleared on reboot (stale outage state is meaningless after a reboot).
nut_outage_state_file: /run/ups-notify-outage
+30
View File
@@ -14,15 +14,34 @@ NTFY_TOKEN="{{ nut_ntfy_token }}"
NTFY_TOKEN="" NTFY_TOKEN=""
{% endif %} {% endif %}
UPS_NAME="{{ nut_ups_name }}"
OUTAGE_STATE_FILE="{{ nut_outage_state_file }}"
MESSAGE="${1:-UPS event}" MESSAGE="${1:-UPS event}"
EVENT="${NOTIFYTYPE:-UNKNOWN}" EVENT="${NOTIFYTYPE:-UNKNOWN}"
HOST="$(uname -n)" HOST="$(uname -n)"
# Current battery charge (%) as reported by the UPS. Empty if unavailable.
battery_charge() {
upsc "${UPS_NAME}@localhost" battery.charge 2>/dev/null | head -n1
}
# Format a duration in whole seconds as HH:mm:ss.
format_duration() {
local total="$1"
printf '%02d:%02d:%02d' $((total / 3600)) $(((total % 3600) / 60)) $((total % 60))
}
case "$EVENT" in case "$EVENT" in
ONBATT) ONBATT)
# Record when line power was lost so ONLINE can report outage duration.
date +%s > "$OUTAGE_STATE_FILE" 2>/dev/null || \
logger -t ups-notify "Failed to write outage state file $OUTAGE_STATE_FILE"
TITLE="UPS on battery — $HOST" TITLE="UPS on battery — $HOST"
PRIORITY="urgent" PRIORITY="urgent"
TAGS="warning,electric_plug" TAGS="warning,electric_plug"
charge="$(battery_charge)"
[[ -n "$charge" ]] && MESSAGE="$MESSAGE (battery ${charge}%)"
;; ;;
LOWBATT) LOWBATT)
TITLE="UPS low battery — $HOST" TITLE="UPS low battery — $HOST"
@@ -38,6 +57,17 @@ case "$EVENT" in
TITLE="UPS back on line power — $HOST" TITLE="UPS back on line power — $HOST"
PRIORITY="default" PRIORITY="default"
TAGS="white_check_mark,zap" TAGS="white_check_mark,zap"
charge="$(battery_charge)"
[[ -n "$charge" ]] && MESSAGE="$MESSAGE (battery ${charge}%)"
if [[ -r "$OUTAGE_STATE_FILE" ]]; then
start="$(cat "$OUTAGE_STATE_FILE" 2>/dev/null)"
if [[ "$start" =~ ^[0-9]+$ ]]; then
elapsed=$(( $(date +%s) - start ))
(( elapsed < 0 )) && elapsed=0
MESSAGE="$MESSAGE — outage lasted $(format_duration "$elapsed")"
fi
rm -f "$OUTAGE_STATE_FILE" 2>/dev/null || true
fi
;; ;;
COMMBAD|NOCOMM) COMMBAD|NOCOMM)
TITLE="UPS communication lost — $HOST" TITLE="UPS communication lost — $HOST"