diff --git a/power.py b/power.py index c4249a2..4dd69d7 100644 --- a/power.py +++ b/power.py @@ -4,11 +4,14 @@ import logging import smtplib import asyncio import discord +from ping3 import ping from nut2 import PyNUTClient from proxmoxer import ProxmoxAPI from email.mime.text import MIMEText +from wakeonlan import send_magic_packet from logging.handlers import TimedRotatingFileHandler +# Config ups_id = config.UPS_ID gmail_user = config.GMAIL_USER gmail_password = config.GMAIL_PASS @@ -22,6 +25,13 @@ pve_user = config.PVE_USER pve_pass = config.PVE_PASS pve_nodes = ['pve', 'c530'] +wol_targets = { + 'host1': {'mac': config.HOST1_MAC, 'ip': config.HOST1_IP}, + 'host2': {'mac': config.HOST2_MAC, 'ip': config.HOST2_IP}, + 'host3': {'mac': config.HOST3_MAC, 'ip': config.HOST3_IP} +} + +# Log Setup def setup_logging(): logger = logging.getLogger('powerlog') logger.setLevel(logging.INFO) @@ -42,6 +52,44 @@ def setup_logging(): logger = setup_logging() +# Email +def send_email(subject, body): + msg = MIMEText(body) + msg['Subject'] = subject + msg['From'] = gmail_user + msg['To'] = recipient_email + try: + with smtplib.SMTP('smtp.gmail.com', 587) as server: + server.starttls() + server.login(gmail_user, gmail_password) + server.send_message(msg) + logger.info(f"Email message sent: {subject}") + except Exception as e: + logger.info(f"Failed to send email: {e}") + +intents = discord.Intents.default() +client = discord.Client(intents=intents) + +# Discord +def send_discord(message): + async def message_send(): + intents = discord.Intents.default() + client = discord.Client(intents=intents) + @client.event + async def on_ready(): + logger.info(f"Client connected as {client.user}") + try: + user = await client.fetch_user(user_id) + await user.send(message) + logger.info(f"Discord message sent: {message}") + except Exception as e: + logger.error(e) + finally: + await client.close() + await client.start(bot_token) + asyncio.run(message_send()) + +# Server Power Management proxmox = ProxmoxAPI(pve_host, user=pve_user, password=pve_pass, verify_ssl=False) def shutdown_pve(node): @@ -63,46 +111,31 @@ def monitor_ups(): logger.error(f"Error communicating with NUT: {e}") return None -def send_email(subject, body): - msg = MIMEText(body) - msg['Subject'] = subject - msg['From'] = gmail_user - msg['To'] = recipient_email - try: - with smtplib.SMTP('smtp.gmail.com', 587) as server: - server.starttls() - server.login(gmail_user, gmail_password) - server.send_message(msg) - logger.info(f"Email message sent: {subject}") - except Exception as e: - logger.info(f"Failed to send email: {e}") - -intents = discord.Intents.default() -client = discord.Client(intents=intents) - -def send_discord(message): - async def message_send(): - intents = discord.Intents.default() - client = discord.Client(intents=intents) - @client.event - async def on_ready(): - logger.info(f"Client connected as {client.user}") - try: - user = await client.fetch_user(user_id) - await user.send(message) - logger.info(f"Discord message sent: {message}") - except Exception as e: - logger.error(e) - finally: - await client.close() - await client.start(bot_token) - asyncio.run(message_send()) +def wake_up(battery): + if battery > 90: + for target, addr in wol_targets.items(): + mac = addr['mac'] + ip = addr['ip'] + while True: + response = ping(ip) + if response: + logger.info(response) + logger.info(f"Host {mac} at {ip} is up. Ping {response}.") + time.sleep(5) + break + else: + send_magic_packet(mac) + logger.warning(f"Host {mac} at {ip} is offline. Sending magic packet.") + time.sleep(10) +# Status Communications def pwr_online(battery): message = f"{ups_id} UPS power has been restored. {battery}% charge remaining." logger.info(message) send_email(f"{ups_id}: Power On Line", message) send_discord(message) + if ups_id == "Server": + wake_up(battery) def pwr_offline(battery): message = f"{ups_id} UPS is running on battery power! {battery}% charge remaining." @@ -122,9 +155,10 @@ def batt_crit(battery): send_email(f"{ups_id} battery critical!!", message) send_discord(message) +# Main Loop def main(): logger.info("Starting UPS monitoring service.") - prev_status = None + prev_status = "OL" while True: ups_data = monitor_ups() if ups_data: @@ -134,7 +168,7 @@ def main(): if status == "OB DISCHRG": pwr_offline(battery) elif status == "OL" or status == "OL CHRG": - pwr_online(battery) + pwr_online(battery) else: logger.info(f"UPS status changed to: {status}") prev_status = status