2024-11-12 00:01:19 +01:00

126 lines
4.8 KiB
Python
Executable File

#!/usr/bin/env python3
import asyncio
import json
import logging
import os
import sys
from fritzbox import FritzBox
from homeassistant import HomeAssistantAPI
sensor_mappings = {}
thermostate_mappings = {}
async def handle_event(idx: int):
global ha, fb
logging.debug(f"Wait for events for {idx}")
while event := await ha.events[idx].get():
try:
entity_id = event["data"]["entity_id"]
if (
entity_id in sensor_mappings.keys()
or entity_id in thermostate_mappings.keys()
):
state = await ha.get_device_state(entity_id)
new_state = event["data"]["new_state"]
logging.info(
f"received changed state from {entity_id} {entity_id in thermostate_mappings.keys()} {state['state']} {entity_id in sensor_mappings.keys()}"
)
if (
entity_id in thermostate_mappings.keys()
and state["state"] != "unavailable"
):
therm_temp = new_state["attributes"]["current_temperature"]
therm_name = new_state["attributes"]["friendly_name"]
sensor = thermostate_mappings[entity_id]
sensor_state = await ha.get_device_state(sensor)
sensor_temp = round(float(sensor_state["state"]) * 2) / 2
logging.info(f"temps: {therm_temp} {sensor_temp}")
if therm_temp != sensor_temp:
logging.info(
f"{therm_name}: {therm_temp}\n{sensor}: {sensor_state['state']} ({sensor_temp})"
)
fb.correct_offset(therm_name, sensor_temp)
elif entity_id in sensor_mappings.keys():
logging.info(f"here {sensor_mappings} {entity_id}")
logging.info(f"{new_state}")
sensor_temp = round(float(new_state["state"]) * 2) / 2
logging.info(f"entry: {sensor_mappings[entity_id]}")
for thermostate in sensor_mappings[entity_id]:
logging.info(thermostate)
therm_state = await ha.get_device_state(thermostate)
logging.info(f"{thermostate} {therm_state}")
if therm_state["state"] == "unavailable":
continue
therm_temp = float(
therm_state["attributes"]["current_temperature"]
)
therm_name = therm_state["attributes"]["friendly_name"]
logging.info(f"Temps: {therm_temp} {sensor_temp}")
if therm_temp != sensor_temp:
logging.info(
f"{therm_name}: {therm_temp}\n{entity_id}: {new_state['state']} ({sensor_temp})"
)
fb.correct_offset(therm_name, sensor_temp)
except KeyError:
pass
async def init(ha: HomeAssistantAPI, fb: FritzBox):
if not await ha.connect():
return
logging.debug("Subscribe")
state_changed_id = await ha.subscribe_event("state_changed")
logging.debug(state_changed_id)
asyncio.create_task(handle_event(state_changed_id))
fb.login()
await ha.wait_for_close()
logging.info("Websocket closed, shutting down..")
async def main():
config_path = sys.argv[1]
config = json.load(open(config_path))
level = logging.INFO
if "log_level" in config:
print(f"Setting log_level {config['log_level']}")
if config["log_level"] == "DEBUG":
level = logging.DEBUG
logging.basicConfig(
level=level, format="[%(asctime)s] [%(levelname)s] %(message)s"
)
logging.debug(config)
global fb
fb = FritzBox(
url=config["fritzbox"]["url"],
user=config["fritzbox"]["username"],
password=config["fritzbox"]["password"],
update_timeout=config["update_timeout"],
dry_run=False,
)
supervisor_url = "ws://supervisor/core/websocket"
if "SUPERVISOR_URL" in os.environ:
supervisor_url = os.environ["SUPERVISOR_URL"]
supervisor_token = os.environ["SUPERVISOR_TOKEN"]
global ha
ha = HomeAssistantAPI(supervisor_token, supervisor_url)
for mapping in config["mappings"]:
if mapping["sensor"] not in sensor_mappings.keys():
sensor_mappings[mapping["sensor"]] = []
sensor_mappings[mapping["sensor"]].append(mapping["thermostate"])
thermostate_mappings[mapping["thermostate"]] = mapping["sensor"]
logging.debug(f"Mappings: {sensor_mappings} {thermostate_mappings}")
try:
await init(ha, fb)
except KeyboardInterrupt:
pass
asyncio.run(main())