135 lines
5.8 KiB
Python
Executable File
135 lines
5.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
hier die verbindungen zu HA aufbauen etc
|
|
außerdem das vergleichen der werte und dass anstoßen der updates
|
|
"""
|
|
import asyncio
|
|
import os
|
|
from typing import Dict
|
|
|
|
from fritzbox import FritzBox
|
|
from homeassistant import HomeAssistantAPI
|
|
import logging
|
|
import json
|
|
|
|
sensor_mappings = {}
|
|
thermostate_mappings = {}
|
|
|
|
async def handle_event(idx: int):
|
|
logging.debug(f"Wait for events for {idx}")
|
|
|
|
while event := await ha.events[idx].get():
|
|
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}")
|
|
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["attributes"]["temperature"]) * 2) / 2
|
|
if therm_temp != sensor_temp:
|
|
logging.info(f"{therm_name}: {therm_temp}")
|
|
logging.info(f"{sensor}: {sensor_state['attributes']['temperature']} ({sensor_temp})")
|
|
fb.correct_offset(therm_name, sensor_temp)
|
|
|
|
elif entity_id in sensor_mappings.keys():
|
|
sensor_temp = round(float(new_state["attributes"]["temperature"]) * 2) / 2
|
|
"""
|
|
fb.login()
|
|
logged = False
|
|
"""
|
|
for thermostate in sensor_mappings[entity_id]:
|
|
therm_state = await ha.get_device_state(thermostate)
|
|
if therm_state["state"] == "unavailable":
|
|
continue
|
|
therm_temp = float(therm_state["attributes"]["current_temperature"])
|
|
therm_name = therm_state["attributes"]["friendly_name"]
|
|
if therm_temp != sensor_temp:
|
|
logging.info(f"{therm_name}: {therm_temp}")
|
|
logging.info(f"{entity_id}: {new_state['attributes']['temperature']} ({sensor_temp})")
|
|
fb.correct_offset(therm_name, sensor_temp)
|
|
"""
|
|
current_temp, current_offset, id, name = fb.get_device_data(name=thermostate)
|
|
if not logged:
|
|
logging.info(
|
|
f"Current measurement from {entity_id}: {new_state['attributes']['temperature']} ({rounded})")
|
|
logged = True
|
|
logging.info(f"Current measurement from {thermostate}: {current_temp}")
|
|
new_offset = current_offset + rounded - current_temp
|
|
if new_offset != current_offset:
|
|
old_offset = current_offset
|
|
logging.debug(f"Set offset for {thermostate} from {current_offset} to {new_offset}")
|
|
fb.set_offset(current_temp, new_offset, id, name)
|
|
current_temp, current_offset, id, name = fb.get_device_data(name=thermostate)
|
|
logging.debug(f"Target: {new_offset} ; Set: {current_offset}")
|
|
if new_offset == current_offset:
|
|
logging.info(f"Adjustet offset from {old_offset} to {new_offset}")
|
|
else:
|
|
logging.warning(f"Failed to adjust offset from {old_offset} to {new_offset}")
|
|
fb.logout()
|
|
"""
|
|
|
|
|
|
async def init(ha: HomeAssistantAPI):
|
|
await ha.connect()
|
|
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..")
|
|
asyncio.get_running_loop().stop()
|
|
|
|
|
|
async def migrate_config(config_path: str, ha: HomeAssistantAPI):
|
|
config = json.load(open(config_path))
|
|
therm_ids = {}
|
|
for state in await ha.get_states():
|
|
if state["entity_id"].startswith("climate.") and "friendly_name" in state["attributes"].keys():
|
|
therm_ids[state["attributes"]["friendly_name"]] = state["entity_id"]
|
|
|
|
mappings = []
|
|
for mapping in config["mappings"]:
|
|
if not mapping["thermostate"].startswith("climate."):
|
|
mapping["thermostate"] = therm_ids[mapping["thermostate"]]
|
|
mappings.append(mapping)
|
|
config["mappings"] = mappings
|
|
json.dump(open(config_path), config)
|
|
|
|
return config
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format="[%(asctime)s] [%(levelname)s] %(message)s")
|
|
config_path = "/data/options.json"
|
|
config_path = "options.json"
|
|
config = json.load(open(config_path))
|
|
logging.debug(config)
|
|
|
|
loop = asyncio.get_event_loop()
|
|
fb = FritzBox(config["fritzbox"]["url"], config["fritzbox"]["password"])
|
|
supervisor_url = "ws://supervisor/core/websocket"
|
|
supervisor_url = "ws://192.168.124.187:8123/api/websocket"
|
|
ha = HomeAssistantAPI(os.environ["SUPERVISOR_TOKEN"], supervisor_url)
|
|
|
|
if '"thermostate": "climate.' not in open(config_path).read():
|
|
config = loop.run_until_complete(migrate_config(config_path, ha))
|
|
logging.info(config)
|
|
exit()
|
|
|
|
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"]
|
|
|
|
loop.create_task(init(ha))
|
|
try:
|
|
loop.run_forever()
|
|
except KeyboardInterrupt:
|
|
pass
|