Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
626b8edc88
|
|||
c5ed655399
|
|||
007ce16618
|
|||
12bcbfcca4
|
|||
da5506f432
|
|||
f107f6b74c
|
|||
1b3ae9725e
|
|||
3a8377176f
|
|||
d314ef37e4
|
@ -17,7 +17,8 @@ data:
|
||||
{
|
||||
"general_off": "heating/system/general_off",
|
||||
"maintenance_mode": "heating/system/maintenance_mode",
|
||||
"status": "heating/system/status"
|
||||
"status": "heating/system/status",
|
||||
"cmd": "heating/command/all"
|
||||
}
|
||||
STATUS_TOPIC: "heating/status"
|
||||
CONTEXT_TOPIC_PREFIX: "heating/context/"
|
||||
@ -30,32 +31,35 @@ data:
|
||||
"patty": {
|
||||
"windows": {
|
||||
"garden_right": { "topic": "homegear/instance1/plain/18/1/STATE", "label": "Garten rechts", "converter": "max" },
|
||||
"garden_left": { "topic": "homegear/instance1/plain/22/1/STATE", "label": "Garten links", "converter": "max" }
|
||||
"garden_left": { "topic": "homegear/instance1/plain/22/1/STATE", "label": "Garten links", "converter": "max" },
|
||||
"street": { "topic": "zigbee2mqtt/0x00158d000af457cf", "label": "Strasse", "converter": "aqara" }
|
||||
},
|
||||
"output_topic": "heating/homegear/instance1/set/39/1/SET_TEMPERATURE",
|
||||
"output_topic": "homegear/instance1/set/39/1/SET_TEMPERATURE",
|
||||
"output_converter": "max"
|
||||
},
|
||||
"kueche": {
|
||||
"windows": {
|
||||
"garden_window": { "topic": "homegear/instance1/plain/37/1/STATE", "label": "Garten Fenster", "converter": "max" },
|
||||
"garden_door": { "topic": "homegear/instance1/plain/36/1/STATE", "label": "Garten Tuer", "converter": "max" },
|
||||
"street_right": { "topic": "homegear/instance1/plain/38/1/STATE", "label": "Strasse rechts", "converter": "max" },
|
||||
"street_left": { "topic": "homegear/instance1/plain/13/1/STATE", "label": "Strasse links", "converter": "max" }
|
||||
"garden_window": { "topic": "zigbee2mqtt/0x00158d008b332785", "label": "Garten Fenster", "converter": "aqara" },
|
||||
"garden_door": { "topic": "zigbee2mqtt/0x00158d008b332788", "label": "Garten Tuer", "converter": "aqara" },
|
||||
"street_right": { "topic": "zigbee2mqtt/0x00158d008b151803", "label": "Strasse rechts", "converter": "aqara" },
|
||||
"street_left": { "topic": "zigbee2mqtt/0x00158d008b331d0b", "label": "Strasse links", "converter": "aqara" }
|
||||
},
|
||||
"output_topic": "heating/homegear/instance1/set/40/1/SET_TEMPERATURE",
|
||||
"output_converter": "max"
|
||||
"output_topic": "zigbee2mqtt/0x94deb8fffe2e5c06/set",
|
||||
"output_converter": "brennenstuhl"
|
||||
},
|
||||
"bad_oben": {
|
||||
"windows": {
|
||||
"street": { "topic": "zigbee2mqtt/0x00158d008b333aec", "label": "Strasse links", "converter": "aqara" }
|
||||
},
|
||||
"output_topic": "heating/homegear/instance1/set/41/1/SET_TEMPERATURE",
|
||||
"output_topic": "homegear/instance1/set/41/1/SET_TEMPERATURE",
|
||||
"output_converter": "max"
|
||||
},
|
||||
"schlafzimmer": {
|
||||
"windows": {
|
||||
"street": { "topic": "homegear/instance1/plain/52/1/STATE", "label": "Strasse", "converter": "max" }
|
||||
},
|
||||
"output_topic": "heating/homegear/instance1/set/42/1/SET_TEMPERATURE",
|
||||
"output_topic": "homegear/instance1/set/42/1/SET_TEMPERATURE",
|
||||
"feedback_topic": "homegear/instance1/jsonobj/42/1",
|
||||
"output_converter": "max"
|
||||
},
|
||||
"wolfgang": {
|
||||
@ -70,7 +74,7 @@ data:
|
||||
"street_right": { "topic": "homegear/instance1/plain/26/1/STATE", "label": "Strasse rechts", "converter": "max" },
|
||||
"street_left": { "topic": "homegear/instance1/plain/27/1/STATE", "label": "Strasse links", "converter": "max" }
|
||||
},
|
||||
"output_topic": "heating/homegear/instance1/set/45/1/SET_TEMPERATURE",
|
||||
"output_topic": "homegear/instance1/set/45/1/SET_TEMPERATURE",
|
||||
"output_converter": "max"
|
||||
},
|
||||
"wohnzimmer": {
|
||||
@ -78,14 +82,14 @@ data:
|
||||
"garden_right": { "topic": "homegear/instance1/plain/28/1/STATE", "label": "Garten rechts", "converter": "max" },
|
||||
"garden_left": { "topic": "homegear/instance1/plain/29/1/STATE", "label": "Garten links", "converter": "max" }
|
||||
},
|
||||
"output_topic": "heating/homegear/instance1/set/46/1/SET_TEMPERATURE",
|
||||
"output_topic": "homegear/instance1/set/46/1/SET_TEMPERATURE",
|
||||
"output_converter": "max"
|
||||
},
|
||||
"bad_unten": {
|
||||
"windows": {
|
||||
"street": { "topic": "homegear/instance1/plain/44/1/STATE", "label": "Strasse", "converter": "max" }
|
||||
},
|
||||
"output_topic": "heating/homegear/instance1/set/48/1/SET_TEMPERATURE",
|
||||
"output_topic": "homegear/instance1/set/48/1/SET_TEMPERATURE",
|
||||
"output_converter": "max"
|
||||
}
|
||||
}
|
||||
|
12
env-test
12
env-test
@ -2,15 +2,15 @@ export MQTT_BROKER="172.23.1.102"
|
||||
export MQTT_PORT=1883
|
||||
export MQTT_CLIENT_PREFIX="MyMQTTClient"
|
||||
export BOX_TOPIC_PREFIXES='{
|
||||
"high_temp": "xheating/config/high_temp/",
|
||||
"cmd": "xheating/command/"
|
||||
"high_temp": "heating/config/high_temp/",
|
||||
"cmd": "heating/command/"
|
||||
}'
|
||||
export CENTRAL_TOPICS='{
|
||||
"general_off": "xheating/system/general_off",
|
||||
"maintenance_mode": "xheating/system/maintenance_mode",
|
||||
"status": "xheating/system/status"
|
||||
"general_off": "heating/system/general_off",
|
||||
"maintenance_mode": "heating/system/maintenance_mode",
|
||||
"status": "heating/system/status"
|
||||
}'
|
||||
export CONTEXT_TOPIC_PREFIX='xheating/context/'
|
||||
export CONTEXT_TOPIC_PREFIX='heating/context/'
|
||||
export STATUS_TOPIC="heating/status"
|
||||
export OFF_TEMPERATURE="5.0"
|
||||
export LOW_TEMPERATURE="15.0"
|
||||
|
26
src/box.py
26
src/box.py
@ -10,6 +10,7 @@ class Context:
|
||||
maintenance_mode: bool = field(default=False)
|
||||
overwrite_window: bool = field(default=False)
|
||||
window_state: dict = field(default_factory=dict)
|
||||
feedback: dict = field(default_factory=dict)
|
||||
mode: str = field(default='off')
|
||||
output_temperature: str = field(default='0')
|
||||
|
||||
@ -24,6 +25,8 @@ class Box:
|
||||
self.windows = box_config['windows']
|
||||
self.output_converter = box_config['output_converter']
|
||||
self.output_topic = box_config['output_topic']
|
||||
# we use get here since this key is optional
|
||||
self.feedback_topic = box_config.get('feedback_topic')
|
||||
self.config = config
|
||||
|
||||
self.context = Context(high_temperature=config.DEFAULT_HIGH_TEMPERATURE,
|
||||
@ -70,14 +73,16 @@ class Box:
|
||||
|
||||
try:
|
||||
# match topic to find operation to be executed
|
||||
send_command = True
|
||||
match topic_key.split('/'):
|
||||
case [ primary_key, sub_key ] if primary_key == 'window':
|
||||
self.context.window_state[sub_key] = CONVERTERS["window_contact_input"][self.windows[sub_key]["converter"]](payload)
|
||||
case [ primary_key ] if primary_key == 'high_temp':
|
||||
self.context.high_temperature = payload
|
||||
case [ primary_key ] if primary_key == 'cmd':
|
||||
if payload in ('high', 'low', 'off'):
|
||||
self.context.mode = payload
|
||||
p = payload.lower()
|
||||
if p in ('high', 'low', 'off'):
|
||||
self.context.mode = p
|
||||
else:
|
||||
raise Exception(f"Invalid cmd '{payload}'")
|
||||
case [ primary_key ] if primary_key == 'overwrite_window':
|
||||
@ -87,7 +92,12 @@ class Box:
|
||||
case [ primary_key ] if primary_key == 'maintenance_mode':
|
||||
self.context.maintenance_mode = payload.lower() == 'true'
|
||||
case [ primary_key ] if primary_key == 'status':
|
||||
send_command = False
|
||||
pass
|
||||
case [ primary_key ] if primary_key == 'feedback':
|
||||
# merge the both dicts
|
||||
self.context.feedback |= json.loads(payload)
|
||||
send_command = False
|
||||
case _:
|
||||
raise Error(f"Unexcepted topic_key: {topic_key}, {payload}")
|
||||
|
||||
@ -95,12 +105,14 @@ class Box:
|
||||
self._calculate_output_temperature()
|
||||
|
||||
|
||||
# publish output temperature
|
||||
result_message = CONVERTERS["target_temperature_output"][self.output_converter](self.context.output_temperature)
|
||||
publish_topic = self.output_topic
|
||||
self.mqtt_client.publish(publish_topic, result_message)
|
||||
logger.info(f"[Box {self.id}] Result published on '{publish_topic}': {result_message}")
|
||||
if send_command:
|
||||
# publish output temperature
|
||||
result_message = CONVERTERS["target_temperature_output"][self.output_converter](self.context.output_temperature)
|
||||
publish_topic = self.output_topic
|
||||
self.mqtt_client.publish(publish_topic, result_message)
|
||||
logger.info(f"[Box {self.id}] Result published on '{publish_topic}': {result_message}")
|
||||
|
||||
# send context in any case
|
||||
context_topic = f"{self.config.CONTEXT_TOPIC_PREFIX}{self.id}"
|
||||
self.mqtt_client.publish(context_topic, str(self.context))
|
||||
except Exception as e:
|
||||
|
@ -1,3 +1,5 @@
|
||||
import json
|
||||
|
||||
CONVERTERS = {
|
||||
"target_temperature_output": {
|
||||
"max": lambda x: x,
|
||||
|
@ -44,6 +44,14 @@ def on_connect(client, userdata, flags, reason_code, properties):
|
||||
client.subscribe(topic)
|
||||
topic_mapping[topic] = (box, topic_key)
|
||||
logger.info(f"[{box.id}] Subscribed to '{topic}' (Key: '{topic_key}')")
|
||||
|
||||
# Subscribe feedback topic if one is available
|
||||
if box.feedback_topic:
|
||||
topic = box.feedback_topic
|
||||
topic_key = "feedback"
|
||||
client.subscribe(topic)
|
||||
topic_mapping[topic] = (box, topic_key)
|
||||
logger.info(f"[{box.id}] Subscribed to '{topic}' (Key: '{topic_key}')")
|
||||
|
||||
# Subscribe to central topics and create mappings
|
||||
for central_key, central_topic in config.CENTRAL_TOPICS.items():
|
||||
|
Reference in New Issue
Block a user