Skip to content

Instantly share code, notes, and snippets.

@lloesche
Created November 24, 2024 13:12
Show Gist options
  • Save lloesche/45b6162a0bfd2ab18387f3d4ed70157a to your computer and use it in GitHub Desktop.
Save lloesche/45b6162a0bfd2ab18387f3d4ed70157a to your computer and use it in GitHub Desktop.
Power Management Script for Raspberry PI UPS Shield Geekworm x1200
#!/usr/bin/env python3
import os
import dbus
import gpiod
import time
import logging
from argparse import ArgumentParser, Namespace
from datetime import datetime
PLD_PIN = 6
GPIO_CHIP = "gpiochip0"
def parse_args() -> Namespace:
parser = ArgumentParser(description="Monitor UPS power status.")
parser.add_argument(
"--enable-shutdown",
action="store_true",
help="Enable shutdown on power outage.",
)
parser.add_argument(
"--wait-time",
type=int,
default=300,
help="Wait time (in seconds) before shutting down on power loss.",
)
return parser.parse_args()
def system_shutdown() -> None:
bus = dbus.SystemBus()
systemd = bus.get_object("org.freedesktop.systemd1", "/org/freedesktop/systemd1")
manager = dbus.Interface(systemd, "org.freedesktop.systemd1.Manager")
manager.Halt()
def ensure_root() -> None:
if os.geteuid() != 0:
logging.fatal("Error: This script must be run as root.")
exit(1)
def monitor_power(enable_shutdown: bool, waittime: int) -> None:
chip = gpiod.Chip(GPIO_CHIP)
pld_line = chip.get_line(PLD_PIN)
pld_line.request(consumer="PLD", type=gpiod.LINE_REQ_DIR_IN)
last_state = None
power_loss_time = None
try:
while True:
pld_state = pld_line.get_value()
if pld_state != last_state:
last_state = pld_state
if pld_state == 1:
logging.info("AC Power OK, Power Adapter OK")
power_loss_time = None
else:
logging.info("AC Power Loss OR Power Adapter Failure")
power_loss_time = datetime.now()
if power_loss_time:
elapsed_time = datetime.now() - power_loss_time
if elapsed_time.total_seconds() > waittime:
if enable_shutdown:
logging.critical(
f"Power outage lasted for {elapsed_time.total_seconds()} seconds. Shutting down now."
)
system_shutdown()
break
else:
logging.info(
f"Power outage lasted for {elapsed_time.total_seconds()} seconds, but shutdown is disabled."
)
time.sleep(5)
finally:
pld_line.release()
def main():
logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")
ensure_root()
args = parse_args()
monitor_power(enable_shutdown=args.enable_shutdown, waittime=args.wait_time)
if __name__ == "__main__":
main()
[Unit]
Description=UPS Monitor Service
After=network.target
[Service]
ExecStart=/usr/local/sbin/upsmon --enable-shutdown
Restart=on-failure
User=root
Group=root
[Install]
WantedBy=multi-user.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment