scripts/ups-monitor.sh

#!/usr/bin/env bash
# scripts/ups-monitor.sh
# Log apcaccess status to /var/log/ups.log and shut the host down
# cleanly if the battery drops below SHUTDOWN_PCT while on battery.
#
# Ran from cron every minute. apcupsd's own killpower handles the last
# mile; this is only a safety net for the case where apcupsd died.

set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
. "${HERE}/lib/log.sh"

LOG="${UPS_LOG:-/var/log/ups.log}"
SHUTDOWN_PCT="${SHUTDOWN_PCT:-15}"

if ! command -v apcaccess >/dev/null 2>&1; then
    exit 0
fi

status=$(apcaccess status 2>/dev/null || true)
if [[ -z "${status}" ]]; then
    log_warn "apcaccess returned empty output"
    exit 0
fi

state=$(awk -F: '/^STATUS/ {gsub(/^ +/,"",$2); print $2; exit}' <<<"${status}")
charge=$(awk -F: '/^BCHARGE/ {gsub(/[^0-9.]/,"",$2); print $2; exit}' <<<"${status}")
linev=$(awk -F: '/^LINEV/ {gsub(/[^0-9.]/,"",$2); print $2; exit}' <<<"${status}")

printf '%s state=%s charge=%s line=%s\n' \
    "$(date -u +%FT%TZ)" "${state:-?}" "${charge:-?}" "${linev:-?}" >> "${LOG}"

if [[ "${state:-}" == *"ONBATT"* ]]; then
    # awk comparison keeps this portable across weird decimal locales.
    if [[ -n "${charge:-}" ]] && \
        awk -v c="${charge}" -v t="${SHUTDOWN_PCT}" 'BEGIN{exit !(c+0 < t+0)}'; then
        log_err "battery ${charge}% on battery, shutting down"
        systemctl poweroff --no-wall
    fi
fi