initial commit
This commit is contained in:
159
nut_interface.py
Normal file
159
nut_interface.py
Normal file
@@ -0,0 +1,159 @@
|
||||
import asyncio
|
||||
|
||||
from time import sleep as s
|
||||
|
||||
from loguru import logger as logging
|
||||
from nut2 import PyNUTClient, PyNUTError
|
||||
|
||||
|
||||
class NUT:
|
||||
statuses = {
|
||||
"ALARM": "ALARM",
|
||||
"BOOST": "Voltage Boost Active",
|
||||
"BYPASS": "Bypass Active",
|
||||
"CAL": "Runtime Calibration",
|
||||
"CHRG": "Battery Charging",
|
||||
"COMM": "Communications Active",
|
||||
"DISCHRG": "Battery Discharging",
|
||||
"FSD": "Forced Shutdown",
|
||||
"LB": "Low Battery",
|
||||
"NOCOMM": "Communications Lost",
|
||||
"OB": "On Battery",
|
||||
"OFF": "Offline",
|
||||
"OL": "Online",
|
||||
"OVER": "Overloaded",
|
||||
"RB": "Battery Needs Replaced",
|
||||
"TEST": "Under Test",
|
||||
"TRIM": "Voltage Trim Active"
|
||||
}
|
||||
|
||||
events = {
|
||||
"blackout": ("Blackout", "Utility power has been lost."),
|
||||
"brown": ("Brownout", "Utility power is experiencing a brownout."),
|
||||
"overvolt": ("Overvoltage", "Utility power is experiencing an overvoltage."),
|
||||
"overload": ("Output Overloaded", "The UPS is overloaded. (Output load: {l}%)"),
|
||||
"low_batt": ("Low Battery", "The UPS battery is running low."),
|
||||
"minor": ("Minor Event", "An event has occurred.")
|
||||
}
|
||||
|
||||
def __init__(self, host=None, port=None, login=None, password=None, **kwargs):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.login = login
|
||||
self.password = password
|
||||
if self.host:
|
||||
self.client = PyNUTClient(
|
||||
host=self.host,
|
||||
port=self.port,
|
||||
login=self.login,
|
||||
password=self.password
|
||||
)
|
||||
else:
|
||||
self.client = PyNUTClient(login=self.login, password=self.password)
|
||||
self.ups = kwargs.get("ups")
|
||||
self.ups = "ups1" if self.ups is None else self.ups
|
||||
self.events_override = None
|
||||
|
||||
def _reconnect(self):
|
||||
self.client._connect()
|
||||
|
||||
def set_ups(self, ups):
|
||||
self.ups = ups
|
||||
|
||||
@staticmethod
|
||||
def nut_func(func):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
while True:
|
||||
try:
|
||||
return func(self, *args, **kwargs)
|
||||
except EOFError:
|
||||
self._reconnect()
|
||||
continue
|
||||
return wrapper
|
||||
|
||||
@nut_func
|
||||
def get_info(self):
|
||||
return self.client.list_vars(self.ups)
|
||||
|
||||
@nut_func
|
||||
def get_status(self):
|
||||
stat = ", ".join([f"{self.statuses.get(i)}" for i in self.client.get(self.ups, "ups.status").split(" ")])
|
||||
return stat
|
||||
|
||||
def override_events(self, events):
|
||||
self.events_override = events
|
||||
|
||||
def check_for_events(self) -> dict:
|
||||
if self.events_override:
|
||||
return self.events_override
|
||||
events = {}
|
||||
|
||||
info = self.get_info()
|
||||
voltage = float(info['input.voltage'])
|
||||
charge = float(info['battery.charge'])
|
||||
|
||||
# Check for brownout
|
||||
events['brown'] = 85.0 < voltage < 110.0
|
||||
|
||||
# Check for overvoltage
|
||||
events['overvolt'] = voltage > 130.0
|
||||
|
||||
# Check for blackout
|
||||
events['blackout'] = voltage < 85.0
|
||||
|
||||
# Check for overload
|
||||
events['overload'] = float(info['ups.load']) > 95.0
|
||||
|
||||
# Check for low battery
|
||||
events['low_batt'] = charge < 20.0
|
||||
|
||||
# Check for minor event
|
||||
events['minor'] = 'DISCHRG' in info['ups.status'] and not events['brown'] and not events['blackout']\
|
||||
and not events['overvolt']
|
||||
|
||||
return events
|
||||
|
||||
@nut_func
|
||||
def get_output_watts(self):
|
||||
max_watts = int(self.client.get(self.ups, "ups.realpower.nominal"))
|
||||
return max_watts * (int(self.client.get(self.ups, "ups.load")) / 100.0)
|
||||
|
||||
@nut_func
|
||||
def get_max_watts(self):
|
||||
return int(self.client.get(self.ups, "ups.realpower.nominal"))
|
||||
|
||||
@nut_func
|
||||
def get_input_voltage(self):
|
||||
return float(self.client.get(self.ups, "input.voltage"))
|
||||
|
||||
@nut_func
|
||||
def get_battery_charge(self):
|
||||
return float(self.client.get(self.ups, "battery.charge"))
|
||||
|
||||
@nut_func
|
||||
def set_beeper(self, beeper):
|
||||
self.client.run_command(self.ups, "beeper.enable" if beeper else "beeper.disable")
|
||||
|
||||
@nut_func
|
||||
def run_self_test(self):
|
||||
self.client.run_command(self.ups, "test.battery.start.quick")
|
||||
|
||||
@nut_func
|
||||
async def get_self_test_results(self):
|
||||
while True:
|
||||
if "DISCHRG" not in self.client.get(self.ups, "ups.status")\
|
||||
and self.client.get(self.ups, "ups.test.result") != "In progress":
|
||||
await asyncio.sleep(0.2)
|
||||
else:
|
||||
break
|
||||
while True:
|
||||
if self.client.get(self.ups, "ups.test.result") == "In progress":
|
||||
await asyncio.sleep(0.2)
|
||||
else:
|
||||
break
|
||||
return self.client.get(self.ups, "ups.test.result")
|
||||
|
||||
@nut_func
|
||||
async def shutdown(self, timer=5):
|
||||
await asyncio.sleep(timer)
|
||||
self.client.run_command(self.ups, "shutdown.return")
|
||||
Reference in New Issue
Block a user