update heater control
This commit is contained in:
parent
957c3fc2bc
commit
0e1f0572cf
7 changed files with 120 additions and 32 deletions
|
@ -10,7 +10,8 @@
|
||||||
script =
|
script =
|
||||||
let myPython = pkgs.python3.withPackages (ps: with ps; [ paho-mqtt ]);
|
let myPython = pkgs.python3.withPackages (ps: with ps; [ paho-mqtt ]);
|
||||||
in ''
|
in ''
|
||||||
${myPython}/bin/python ${<mqtt/heater.py>}
|
cd ${<mqtt>}
|
||||||
|
${myPython}/bin/python heater.py
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
3
mqtt/.gitignore
vendored
3
mqtt/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
venv
|
venv
|
||||||
|
**/__pycache__
|
|
@ -1,11 +1,21 @@
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
import json
|
import json
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
# initial scene
|
# initial scene
|
||||||
|
from heater.modules.heater import Heater
|
||||||
|
from heater.modules.watcher import Watcher
|
||||||
|
|
||||||
scene = "default"
|
scene = "default"
|
||||||
|
|
||||||
|
watcher = Watcher({
|
||||||
|
"office1": Heater(topic="zigbee2mqtt/heater1", set_topic="zigbee2mqtt/heater1/set"),
|
||||||
|
"office2": Heater(topic="zigbee2mqtt/heater2", set_topic="zigbee2mqtt/heater2/set"),
|
||||||
|
"bedroom": Heater(topic="zigbee2mqtt/heater3", set_topic="zigbee2mqtt/heater3/set"),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# The callback for when the client receives a CONNACK response from the server.
|
# The callback for when the client receives a CONNACK response from the server.
|
||||||
def on_connect(client, _userdata, _flags, rc):
|
def on_connect(client, _userdata, _flags, rc):
|
||||||
|
@ -16,16 +26,23 @@ def on_connect(client, _userdata, _flags, rc):
|
||||||
# Subscribing in on_connect() means that if we lose the connection and
|
# Subscribing in on_connect() means that if we lose the connection and
|
||||||
# reconnect then subscriptions will be renewed.
|
# reconnect then subscriptions will be renewed.
|
||||||
client.subscribe("control/lights/set")
|
client.subscribe("control/lights/set")
|
||||||
|
for topic in watcher.get_topics():
|
||||||
|
client.subscribe(topic)
|
||||||
|
watcher.pull_values(client)
|
||||||
|
|
||||||
|
|
||||||
# The callback for when a PUBLISH message is received from the server.
|
# The callback for when a PUBLISH message is received from the server.
|
||||||
def on_message(client, _userdata, msg):
|
def on_message(client, _userdata, msg):
|
||||||
global scene
|
global scene
|
||||||
(topic, payload) = parse_message(msg)
|
(topic, payload) = parse_message(msg)
|
||||||
print("set scene %s -> %s" % (scene, payload['scene']))
|
if topic == "control/lights/set":
|
||||||
scene = payload['scene']
|
print("set scene %s -> %s" % (scene, payload['scene']))
|
||||||
publish_heater_depending_on_scene(client)
|
scene = payload['scene']
|
||||||
# print(topic + " " + payload['scene'])
|
update_scene(client)
|
||||||
|
else:
|
||||||
|
print("got %s" % topic)
|
||||||
|
watcher.update_actual_heating_point_for_topic(topic, payload)
|
||||||
|
#watcher.publish(client)
|
||||||
|
|
||||||
|
|
||||||
def parse_message(msg):
|
def parse_message(msg):
|
||||||
|
@ -34,43 +51,39 @@ def parse_message(msg):
|
||||||
return msg.topic, payload
|
return msg.topic, payload
|
||||||
|
|
||||||
|
|
||||||
mqttClient = mqtt.Client()
|
def update_scene(client):
|
||||||
mqttClient.on_connect = on_connect
|
|
||||||
mqttClient.on_message = on_message
|
|
||||||
mqttClient.username_pw_set("homeassistant", password="password")
|
|
||||||
|
|
||||||
mqttClient.connect("pepe.private", 1883, 60)
|
|
||||||
|
|
||||||
|
|
||||||
def publish_heater(client, temperature=10):
|
|
||||||
payload = {
|
|
||||||
"system_mode": "auto",
|
|
||||||
"current_heating_setpoint": str(temperature),
|
|
||||||
"eurotronic_host_flags": {"window_open": True}
|
|
||||||
}
|
|
||||||
client.publish("zigbee2mqtt/heater1/set", json.dumps(payload))
|
|
||||||
client.publish("zigbee2mqtt/heater2/set", json.dumps(payload))
|
|
||||||
client.publish("zigbee2mqtt/heater3/set", json.dumps(payload))
|
|
||||||
|
|
||||||
|
|
||||||
def publish_heater_depending_on_scene(client):
|
|
||||||
if scene == "night":
|
if scene == "night":
|
||||||
publish_heater(client, 12)
|
watcher.update("office1", 10)
|
||||||
|
watcher.update("office2", 10)
|
||||||
|
watcher.update("bedroom", 13)
|
||||||
elif scene == "default":
|
elif scene == "default":
|
||||||
publish_heater(client, 26)
|
watcher.update("office1", 23)
|
||||||
|
watcher.update("office2", 23)
|
||||||
|
watcher.update("bedroom", 18)
|
||||||
elif scene == "outside":
|
elif scene == "outside":
|
||||||
publish_heater(client, 10)
|
watcher.update("office1", 10)
|
||||||
|
watcher.update("office2", 10)
|
||||||
|
watcher.update("bedroom", 13)
|
||||||
else:
|
else:
|
||||||
publish_heater(client, 10)
|
watcher.update("office1", 10)
|
||||||
|
watcher.update("office2", 10)
|
||||||
|
watcher.update("bedroom", 13)
|
||||||
|
|
||||||
|
watcher.publish(client)
|
||||||
|
|
||||||
|
|
||||||
def loop_thread(client):
|
def loop_thread(client):
|
||||||
while True:
|
while True:
|
||||||
publish_heater_depending_on_scene(client)
|
watcher.publish(client)
|
||||||
time.sleep(300)
|
time.sleep(120)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
mqttClient = mqtt.Client()
|
||||||
|
mqttClient.on_connect = on_connect
|
||||||
|
mqttClient.on_message = on_message
|
||||||
|
mqttClient.username_pw_set("homeassistant", password="password")
|
||||||
|
mqttClient.connect("pepe.private", 1883, 60)
|
||||||
# Blocking call that processes network traffic, dispatches callbacks and
|
# Blocking call that processes network traffic, dispatches callbacks and
|
||||||
# handles reconnecting.
|
# handles reconnecting.
|
||||||
# Other loop*() functions are available that give a threaded interface and a
|
# Other loop*() functions are available that give a threaded interface and a
|
||||||
|
|
0
mqtt/heater/__init__.py
Normal file
0
mqtt/heater/__init__.py
Normal file
0
mqtt/heater/modules/__init__.py
Normal file
0
mqtt/heater/modules/__init__.py
Normal file
39
mqtt/heater/modules/heater.py
Normal file
39
mqtt/heater/modules/heater.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class Heater:
|
||||||
|
def __init__(self, topic, set_topic):
|
||||||
|
self.not_initialized_yet = True
|
||||||
|
self.wanted_temperature = 15
|
||||||
|
self.actual_temperature = 15
|
||||||
|
self.set_topic = set_topic
|
||||||
|
self.topic = topic
|
||||||
|
|
||||||
|
def payload(self):
|
||||||
|
payload = {
|
||||||
|
"system_mode": "auto",
|
||||||
|
"current_heating_setpoint": str(self.wanted_temperature),
|
||||||
|
"eurotronic_host_flags": {"window_open": True}
|
||||||
|
}
|
||||||
|
return json.dumps(payload)
|
||||||
|
|
||||||
|
def needs_publish(self):
|
||||||
|
if self.not_initialized_yet:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return self.wanted_temperature != self.actual_temperature
|
||||||
|
|
||||||
|
def update_actual_heating_point(self, payload):
|
||||||
|
heating_setpoint = int(payload["current_heating_setpoint"])
|
||||||
|
if self.not_initialized_yet:
|
||||||
|
self.not_initialized_yet = False
|
||||||
|
self.wanted_temperature = heating_setpoint
|
||||||
|
print("%s: update wanted temperature %d" % (self.topic, self.actual_temperature))
|
||||||
|
self.actual_temperature = heating_setpoint
|
||||||
|
print("%s: update actual temperature %d" % (self.topic, self.actual_temperature))
|
||||||
|
|
||||||
|
def topic_and_payload_for_query(self):
|
||||||
|
payload = {
|
||||||
|
"current_heating_setpoint": ""
|
||||||
|
}
|
||||||
|
return ("%s/get" % self.topic), json.dumps(payload)
|
34
mqtt/heater/modules/watcher.py
Normal file
34
mqtt/heater/modules/watcher.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import time
|
||||||
|
from typing import List, Dict
|
||||||
|
|
||||||
|
from heater.modules.heater import Heater
|
||||||
|
|
||||||
|
|
||||||
|
class Watcher:
|
||||||
|
|
||||||
|
def __init__(self, heater: Dict[str, Heater]):
|
||||||
|
self.heater = heater
|
||||||
|
|
||||||
|
def publish(self, client):
|
||||||
|
for heater in self.heater.values():
|
||||||
|
if heater.needs_publish():
|
||||||
|
client.publish(heater.set_topic, heater.payload())
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
def update(self, name, temperature):
|
||||||
|
heater: Heater = self.heater.get(name)
|
||||||
|
heater.wanted_temperature = temperature
|
||||||
|
|
||||||
|
def get_topics(self):
|
||||||
|
return [heater.topic for heater in self.heater.values()]
|
||||||
|
|
||||||
|
def update_actual_heating_point_for_topic(self, topic, payload):
|
||||||
|
for heater in self.heater.values():
|
||||||
|
if heater.topic == topic:
|
||||||
|
heater.update_actual_heating_point(payload)
|
||||||
|
return
|
||||||
|
|
||||||
|
def pull_values(self, client):
|
||||||
|
for heater in self.heater.values():
|
||||||
|
topic, payload = heater.topic_and_payload_for_query()
|
||||||
|
client.publish(topic, payload)
|
Loading…
Reference in a new issue