New version : Oin Thermostat
This commit is contained in:
parent
cb53e91a4d
commit
a0e7ea91aa
8 changed files with 363 additions and 455 deletions
118
oin_thermostat/mqtt.py
Normal file
118
oin_thermostat/mqtt.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
from .screen import Screen
|
||||
from .select import Selector
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HAClient:
|
||||
def __init__(self, entity, secondary_entities=[]):
|
||||
self.entity = entity
|
||||
self.secondary_entities = secondary_entities
|
||||
|
||||
self.state_topic = "oin/state"
|
||||
self.availability_topic = "oin/availability"
|
||||
|
||||
self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
||||
self.client.username_pw_set(username="oin", password="n+Bi58l7LxbH5nEJ")
|
||||
|
||||
self.screen = Screen()
|
||||
self.selector = Selector(self.send_data)
|
||||
|
||||
@property
|
||||
def ha_options(self):
|
||||
return {
|
||||
"dev": {
|
||||
"ids": "oin",
|
||||
"name": "Oin",
|
||||
},
|
||||
"o": {
|
||||
"name": "Oin",
|
||||
},
|
||||
"availability_topic": self.availability_topic,
|
||||
"state_topic": self.state_topic,
|
||||
"cmps": self.selector.ha_options,
|
||||
}
|
||||
|
||||
def connect(self):
|
||||
logger.debug("Connecting to HA...")
|
||||
self.client.will_set(self.availability_topic, "offline", retain=True)
|
||||
self.client.connect("homeassistant.local", 1883, 60)
|
||||
|
||||
self.subscribe(entity_topic(self.entity), self.state_update)
|
||||
for entity in self.secondary_entities:
|
||||
self.subscribe(entity_topic(entity, "state"), self.secondary_state_update)
|
||||
|
||||
self.publish("homeassistant/device/oin/config", self.ha_options, retain=True)
|
||||
self.client.publish(self.availability_topic, "online", retain=True)
|
||||
|
||||
def publish(self, topic, data, **kwargs):
|
||||
logger.debug(f"Sending message on topic <{topic}>: {json.dumps(data)}")
|
||||
self.client.publish(topic, json.dumps(data), **kwargs)
|
||||
|
||||
def subscribe(self, topic, callback):
|
||||
logger.debug(f"Subscribe to <{topic}>")
|
||||
self.client.subscribe(topic)
|
||||
self.client.message_callback_add(topic, callback)
|
||||
|
||||
def unsubscribe(self, topic):
|
||||
logger.debug(f"Unsubscribe from <{topic}>")
|
||||
self.client.unsubscribe(topic)
|
||||
|
||||
def loop(self):
|
||||
logger.info("Starting MQTT client loop")
|
||||
self.client.loop_forever()
|
||||
|
||||
def state_update(self, client: mqtt.Client, userdata, message: mqtt.MQTTMessage):
|
||||
logger.debug(f"Message received on topic <{message.topic}>: {message.payload}.")
|
||||
|
||||
subtopic = message.topic.rsplit("/", maxsplit=1)[1]
|
||||
|
||||
match subtopic:
|
||||
case "current_temperature":
|
||||
self.screen.value = parse(message)
|
||||
case "temperature":
|
||||
if (value := parse(message)) != self.selector.temperature:
|
||||
self.screen.tmp_value = value
|
||||
self.selector.temperature = value
|
||||
case "hvac_action":
|
||||
self.screen.mode = parse(message)
|
||||
case "preset_modes":
|
||||
if (value := parse(message)) != self.selector.preset_modes:
|
||||
self.selector.preset_modes = value
|
||||
case "preset_mode":
|
||||
if (value := parse(message)) != self.selector.mode:
|
||||
self.selector.mode = value
|
||||
case "state":
|
||||
match message.payload.decode():
|
||||
case "heat":
|
||||
self.selector.switch = True
|
||||
case "off":
|
||||
self.selector.switch = False
|
||||
|
||||
def secondary_state_update(
|
||||
self, client: mqtt.Client, userdata, message: mqtt.MQTTMessage
|
||||
):
|
||||
logger.debug(f"Message received on topic <{message.topic}>: {message.payload}.")
|
||||
|
||||
_, grp, ent, subtopic = message.topic.split("/")
|
||||
idx = self.secondary_entities.index(f"{grp}.{ent}")
|
||||
|
||||
if subtopic == "state":
|
||||
self.screen.secondary |= {idx: message.payload.decode()}
|
||||
|
||||
def send_data(self, data):
|
||||
self.publish(self.state_topic, data)
|
||||
|
||||
|
||||
def parse(message):
|
||||
return json.loads(message.payload.decode())
|
||||
|
||||
|
||||
def entity_topic(entity, subtopic="#"):
|
||||
topic = entity.replace(".", "/")
|
||||
return f"homeassistant/{topic}/{subtopic}"
|
Reference in a new issue