Compare commits
4 Commits
bf72a0c213
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1458dc282d | |||
| f419890f65 | |||
| ac985ececa | |||
| d48a34f579 |
@@ -2,3 +2,4 @@ NTFY_Token=
|
|||||||
device_name=
|
device_name=
|
||||||
logging_level=DEBUG
|
logging_level=DEBUG
|
||||||
shutdown_timer=30
|
shutdown_timer=30
|
||||||
|
HA_Token=
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
.env
|
.env
|
||||||
|
venv
|
||||||
140
main.py
140
main.py
@@ -30,9 +30,18 @@ if not logger.handlers:
|
|||||||
ntfy_token = os.environ['NTFY_Token']
|
ntfy_token = os.environ['NTFY_Token']
|
||||||
device_name = os.environ['device_name']
|
device_name = os.environ['device_name']
|
||||||
shutdown_timer = int(os.environ['shutdown_timer'])
|
shutdown_timer = int(os.environ['shutdown_timer'])
|
||||||
|
ha_token = os.environ['HA_Token']
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
#Globals
|
||||||
running = True
|
running = True
|
||||||
|
|
||||||
|
inverter_online = True
|
||||||
|
last_online = time.monotonic()
|
||||||
|
|
||||||
|
grid_online = True
|
||||||
|
|
||||||
|
|
||||||
def handle_shutdown(signum, frame):
|
def handle_shutdown(signum, frame):
|
||||||
global running
|
global running
|
||||||
logger.info("Received shutdown signal, exiting...")
|
logger.info("Received shutdown signal, exiting...")
|
||||||
@@ -41,71 +50,120 @@ def handle_shutdown(signum, frame):
|
|||||||
signal.signal(signal.SIGTERM, handle_shutdown)
|
signal.signal(signal.SIGTERM, handle_shutdown)
|
||||||
signal.signal(signal.SIGINT, handle_shutdown)
|
signal.signal(signal.SIGINT, handle_shutdown)
|
||||||
|
|
||||||
|
def send_message(title: str, text: str):
|
||||||
def main():
|
|
||||||
with serial.Serial(device_name, 115200, timeout=1) as ser:
|
|
||||||
shutdown_triggered = False
|
|
||||||
inverter_online = True
|
|
||||||
last_online = time.monotonic()
|
|
||||||
receiving_data = True
|
|
||||||
last_logged = -1
|
|
||||||
try:
|
try:
|
||||||
while running:
|
requests.post("https://ntfy.fieryeagle.org/Internet-Alerts",
|
||||||
line = ser.readline().decode(errors="ignore").strip()
|
data=text.encode("utf-8"),
|
||||||
|
headers={
|
||||||
|
"Title": title,
|
||||||
|
"Authorization": f"Bearer {ntfy_token}"
|
||||||
|
},
|
||||||
|
timeout=5)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to send notification: {e}")
|
||||||
|
|
||||||
if line != "" and not receiving_data:
|
def check_inverter(status: bool):
|
||||||
receiving_data = True
|
global inverter_online
|
||||||
logger.info("Serial data restored")
|
global last_online
|
||||||
|
|
||||||
if line == "0":
|
if status:
|
||||||
|
logger.debug("Inverter Online")
|
||||||
if not inverter_online:
|
if not inverter_online:
|
||||||
logger.info("Inverter restored")
|
logger.info("Inverter restored")
|
||||||
inverter_online = True
|
inverter_online = True
|
||||||
last_online = time.monotonic()
|
last_online = time.monotonic()
|
||||||
|
return True
|
||||||
elif line == "1":
|
|
||||||
if inverter_online:
|
|
||||||
inverter_online = False
|
|
||||||
logger.info("Running on UPS reserve")
|
|
||||||
|
|
||||||
elif line == "":
|
|
||||||
if receiving_data:
|
|
||||||
receiving_data = False
|
|
||||||
logger.warning("No serial data")
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Unexpected serial data: {line}")
|
if inverter_online:
|
||||||
|
logger.info("Running on UPS reserve")
|
||||||
|
inverter_online = False
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_grid(status: bool):
|
||||||
|
global grid_online
|
||||||
|
|
||||||
|
if status:
|
||||||
|
logger.debug("Grid Online")
|
||||||
|
if not grid_online:
|
||||||
|
logger.info("Grid restored")
|
||||||
|
send_message("Grid back online", "Systems restored")
|
||||||
|
try:
|
||||||
|
requests.post("https://home.fieryeagle.org/api/states/binary_sensor.grid_power",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {ha_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
json={"state": "on"},
|
||||||
|
timeout=5
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Could not update HA sensor: {e}")
|
||||||
|
grid_online = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
else:
|
||||||
|
if grid_online:
|
||||||
|
logger.info("Running on Inverter reserve")
|
||||||
|
send_message("Grid power offline", "Running on Inverter reserve")
|
||||||
|
try:
|
||||||
|
requests.post("https://home.fieryeagle.org/api/states/binary_sensor.grid_power",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {ha_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
json={"state": "off"},
|
||||||
|
timeout=5
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Could not update HA sensor: {e}")
|
||||||
|
grid_online = False
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
shutdown_triggered = False
|
||||||
|
try:
|
||||||
|
with serial.Serial(device_name, 115200, timeout=1) as ser:
|
||||||
|
global last_online
|
||||||
|
|
||||||
|
last_logged = -1
|
||||||
|
|
||||||
|
while running:
|
||||||
|
line = ser.readline().decode(errors="ignore").strip()
|
||||||
|
if line == "":
|
||||||
|
logger.warning("No serial data")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if line not in ("00", "01", "10", "11"):
|
||||||
|
logger.warning(f"Invalid serial data: {line}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
inverter_status = line[0] == "0"
|
||||||
|
grid_status = line[1] == "0"
|
||||||
|
|
||||||
|
check_inverter(inverter_status)
|
||||||
|
check_grid(grid_status)
|
||||||
|
|
||||||
if not inverter_online:
|
if not inverter_online:
|
||||||
sec = int(time.monotonic() - last_online)
|
sec = int(time.monotonic() - last_online)
|
||||||
|
|
||||||
if sec % 10 == 0 and sec != last_logged:
|
if sec != last_logged:
|
||||||
logger.info(f"Offline for {sec}s")
|
logger.info(f"Offline for {sec}s")
|
||||||
last_logged = sec
|
last_logged = sec
|
||||||
|
|
||||||
if sec >= shutdown_timer:
|
if sec >= shutdown_timer:
|
||||||
shutdown_triggered = True
|
shutdown_triggered = True
|
||||||
break
|
break
|
||||||
|
except serial.SerialException as e:
|
||||||
|
logger.error(f"Serial error: {e}")
|
||||||
|
|
||||||
if shutdown_triggered:
|
if shutdown_triggered:
|
||||||
logger.info(f"Inverter offline for {shutdown_timer} seconds")
|
logger.info(f"Inverter offline for {shutdown_timer} seconds")
|
||||||
try:
|
send_message("Inverter offline", "Hydrogen running on reserve power, shutting down")
|
||||||
requests.post(
|
|
||||||
"https://ntfy.fieryeagle.org/Internet-Alerts",
|
|
||||||
data="Inverter offline, shutting down".encode("utf-8"),
|
|
||||||
headers={
|
|
||||||
"Title": "Hydrogen running on reserve power",
|
|
||||||
"Authorization": f"Bearer {ntfy_token}"
|
|
||||||
},
|
|
||||||
timeout=5
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to send notification: {e}")
|
|
||||||
os.system("shutdown now")
|
os.system("shutdown now")
|
||||||
else:
|
else:
|
||||||
logger.info("Exited cleanly (service stop)")
|
logger.info("Exited cleanly (service stop)")
|
||||||
except serial.SerialException as e:
|
|
||||||
logger.error(f"Serial device error: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
Reference in New Issue
Block a user