introduced fyrtur-control
This commit is contained in:
parent
0e1f0572cf
commit
4003c41c3d
5 changed files with 205 additions and 287 deletions
|
@ -54,22 +54,18 @@ in {
|
|||
# all scenes
|
||||
input_select.scene = {
|
||||
icon = "mdi:brightness-auto";
|
||||
options = [ "default" "night" "outside" "cooking" ];
|
||||
options = [ "up-bright" "up-dark" "half" "down" "night" "outside" ];
|
||||
};
|
||||
# scenes controlled by buttons
|
||||
input_select.scene_button = {
|
||||
icon = "mdi:brightness-auto";
|
||||
options = [ "default" "night" ];
|
||||
options = [ "up-dark" "night" ];
|
||||
};
|
||||
input_boolean.situation_toggle.icon = "mdi:toggle-switch";
|
||||
input_boolean.printer_toggle.icon = "mdi:toggle-switch";
|
||||
|
||||
input_boolean.windows_up.icon = "mdi:toggle-switch";
|
||||
|
||||
# heater scenes
|
||||
#input_select.heater_state.options = [ "off" "on1" "on2" "on3" ];
|
||||
#input_select.heater_state_memory.options = [ "off" "on1" "on2" "on3" ];
|
||||
|
||||
automation = [
|
||||
|
||||
{
|
||||
|
@ -152,28 +148,7 @@ in {
|
|||
entity_id = "input_select.scene";
|
||||
option = "outside";
|
||||
};
|
||||
}
|
||||
#{
|
||||
# service = "input_select.select_option";
|
||||
# data_template = {
|
||||
# entity_id = "input_select.heater_state_memory";
|
||||
# option = ''
|
||||
# {% if not is_state("input_select.heater_state", "off") %}
|
||||
# {{ states('input_select.heater_state') }}
|
||||
# {%- else -%}
|
||||
# {{ states('input_select.heater_state_memory') }}
|
||||
# {%- endif %}
|
||||
# '';
|
||||
# };
|
||||
#}
|
||||
#{
|
||||
# service = "input_select.select_option";
|
||||
# data = {
|
||||
# entity_id = "input_select.heater_state";
|
||||
# option = "off";
|
||||
# };
|
||||
#}
|
||||
];
|
||||
}];
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -202,155 +177,11 @@ in {
|
|||
service = "input_select.select_option";
|
||||
data = {
|
||||
entity_id = "input_select.scene";
|
||||
option = "default";
|
||||
option = "up-dark";
|
||||
};
|
||||
}
|
||||
#{
|
||||
# service = "input_select.select_option";
|
||||
# data_template = {
|
||||
# entity_id = "input_select.heater_state";
|
||||
# option = "{{ states('input_select.heater_state_memory') }}";
|
||||
# };
|
||||
#}
|
||||
];
|
||||
}
|
||||
|
||||
# window roles
|
||||
{
|
||||
alias = "windows state = down in the evening";
|
||||
trigger = [{
|
||||
platform = "sun";
|
||||
event = "sunset";
|
||||
offset = "+00:01:00"; # 10 min after sunset
|
||||
}];
|
||||
action = [{
|
||||
service = "input_boolean.turn_off";
|
||||
data.entity_id = "input_boolean.windows_up";
|
||||
}];
|
||||
}
|
||||
{
|
||||
alias = "windows state = up in the morning";
|
||||
trigger = [{
|
||||
platform = "time";
|
||||
at = "08:30:00";
|
||||
}];
|
||||
action = [{
|
||||
service = "input_boolean.turn_on";
|
||||
data.entity_id = "input_boolean.windows_up";
|
||||
}];
|
||||
}
|
||||
{
|
||||
alias = "handle windows up state";
|
||||
trigger = [
|
||||
#{
|
||||
# platform = "time_pattern";
|
||||
# minutes = "/5"; # every 5 minutes
|
||||
#}
|
||||
{
|
||||
platform = "state";
|
||||
entity_id = "input_boolean.windows_up";
|
||||
}
|
||||
];
|
||||
action = [{
|
||||
service = "script.turn_on";
|
||||
data_template.entity_id = ''
|
||||
{% if is_state('input_boolean.windows_up','on') -%}
|
||||
script.fyrtur_up
|
||||
{%- else -%}
|
||||
script.fyrtur_down
|
||||
{%- endif %}
|
||||
'';
|
||||
}];
|
||||
}
|
||||
|
||||
# heater
|
||||
#{
|
||||
# alias = "heater state = on1 in the morning";
|
||||
# trigger = [{
|
||||
# platform = "time";
|
||||
# at = "09:00:00";
|
||||
# }];
|
||||
# action = [
|
||||
# {
|
||||
# service = "input_select.select_option";
|
||||
# data = {
|
||||
# entity_id = "input_select.heater_state";
|
||||
# option = "on1";
|
||||
# };
|
||||
# }
|
||||
# {
|
||||
# service = "input_select.select_option";
|
||||
# data = {
|
||||
# entity_id = "input_select.heater_state_memory";
|
||||
# option = "on1";
|
||||
# };
|
||||
# }
|
||||
# ];
|
||||
#}
|
||||
#{
|
||||
# alias = "heater state = on2 in the early evening";
|
||||
# trigger = [{
|
||||
# platform = "time";
|
||||
# at = "22:30:00";
|
||||
# }];
|
||||
# action = [
|
||||
# {
|
||||
# service = "input_select.select_option";
|
||||
# data = {
|
||||
# entity_id = "input_select.heater_state";
|
||||
# option = "on2";
|
||||
# };
|
||||
# }
|
||||
# {
|
||||
# service = "input_select.select_option";
|
||||
# data = {
|
||||
# entity_id = "input_select.heater_state_memory";
|
||||
# option = "on2";
|
||||
# };
|
||||
# }
|
||||
# ];
|
||||
#}
|
||||
#{
|
||||
# alias = "heater state = off in the evening";
|
||||
# trigger = [{
|
||||
# platform = "time";
|
||||
# at = "23:30:00";
|
||||
# }];
|
||||
# action = [
|
||||
# {
|
||||
# service = "input_select.select_option";
|
||||
# data = {
|
||||
# entity_id = "input_select.heater_state";
|
||||
# option = "off";
|
||||
# };
|
||||
# }
|
||||
# {
|
||||
# service = "input_select.select_option";
|
||||
# data = {
|
||||
# entity_id = "input_select.heater_state_memory";
|
||||
# option = "off";
|
||||
# };
|
||||
# }
|
||||
# ];
|
||||
#}
|
||||
#{
|
||||
# alias = "handle heater state";
|
||||
# trigger = [
|
||||
# {
|
||||
# platform = "time_pattern";
|
||||
# minutes = "/10"; # every 5 minutes
|
||||
# }
|
||||
# {
|
||||
# platform = "state";
|
||||
# entity_id = "input_select.heater_state";
|
||||
# }
|
||||
# ];
|
||||
# action = [{
|
||||
# service = "script.turn_on";
|
||||
# data_template.entity_id =
|
||||
# "script.heater_{{ states('input_select.heater_state') }}";
|
||||
# }];
|
||||
#}
|
||||
];
|
||||
|
||||
group = let
|
||||
|
@ -405,111 +236,6 @@ in {
|
|||
|
||||
};
|
||||
|
||||
script = let
|
||||
# delay in seconds
|
||||
delay = 2;
|
||||
|
||||
heater_on = heater: temperatur: {
|
||||
service = "mqtt.publish";
|
||||
data_template = {
|
||||
topic = "zigbee2mqtt/${heater}/set"; # office
|
||||
payload_template = builtins.toJSON {
|
||||
system_mode = "auto";
|
||||
current_heating_setpoint = toString temperatur;
|
||||
eurotronic_host_flags.window_open = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
#heater_off = heater: {
|
||||
# service = "mqtt.publish";
|
||||
# data_template = {
|
||||
# topic = "zigbee2mqtt/${heater}/set"; # office
|
||||
# payload_template = ''{"system_mode":"off"}'';
|
||||
# };
|
||||
#};
|
||||
|
||||
hot = 23;
|
||||
cold = 14;
|
||||
|
||||
fyrtur_command = device: position: {
|
||||
service = "mqtt.publish";
|
||||
data_template = {
|
||||
topic = "zigbee2mqtt/${device}/set";
|
||||
payload_template = ''{"position":"${toString position}"}'';
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
#heater_off = {
|
||||
# sequence = [
|
||||
# (heater_on "heater1" 5) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater2" 5) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater3" 5) # bed room
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater4" 5) # storage room
|
||||
# ];
|
||||
#};
|
||||
#heater_on1 = {
|
||||
# sequence = [
|
||||
# (heater_on "heater1" hot) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater2" hot) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater3" cold) # bed room
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater4" cold) # storage room
|
||||
# ];
|
||||
#};
|
||||
#heater_on2 = {
|
||||
# sequence = [
|
||||
# (heater_on "heater1" hot) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater2" hot) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater3" hot) # bed room
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater4" cold) # storage room
|
||||
# ];
|
||||
#};
|
||||
#heater_on3 = {
|
||||
# sequence = [
|
||||
# (heater_on "heater1" cold) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater2" cold) # office
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater3" hot) # bed room
|
||||
# { delay = delay; }
|
||||
# (heater_on "heater4" cold) # storage room
|
||||
# ];
|
||||
#};
|
||||
|
||||
fyrtur_up = {
|
||||
sequence = [
|
||||
(fyrtur_command "fyrtur1" 100)
|
||||
{ delay = delay; }
|
||||
(fyrtur_command "fyrtur2" 100)
|
||||
{ delay = delay; }
|
||||
(fyrtur_command "fyrtur3" 100)
|
||||
{ delay = delay; }
|
||||
(fyrtur_command "fyrtur4" 100)
|
||||
];
|
||||
};
|
||||
|
||||
fyrtur_down = {
|
||||
sequence = [
|
||||
(fyrtur_command "fyrtur1" 16)
|
||||
{ delay = delay; }
|
||||
(fyrtur_command "fyrtur2" 16)
|
||||
{ delay = delay; }
|
||||
(fyrtur_command "fyrtur3" 22)
|
||||
{ delay = delay; }
|
||||
(fyrtur_command "fyrtur4" 22)
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -14,4 +14,19 @@
|
|||
${myPython}/bin/python heater.py
|
||||
'';
|
||||
};
|
||||
|
||||
users.users.fyrtur-control = { };
|
||||
|
||||
systemd.services.fyrtur-control = {
|
||||
enable = true;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = { User = "fyrtur-control"; };
|
||||
script =
|
||||
let myPython = pkgs.python3.withPackages (ps: with ps; [ paho-mqtt ]);
|
||||
in ''
|
||||
cd ${<mqtt>}
|
||||
${myPython}/bin/python fyrtur.py
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,9 +10,40 @@
|
|||
};
|
||||
scenes = [
|
||||
{
|
||||
name = "default";
|
||||
ignored_sensors =
|
||||
[ "zigbee2mqtt/door_sensor_5" "zigbee2mqtt/door_sensor_1" ];
|
||||
name = "up-dark";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "half";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "down";
|
||||
ignored_sensors = [
|
||||
"zigbee2mqtt/door_sensor_1"
|
||||
"zigbee2mqtt/door_sensor_4"
|
||||
"zigbee2mqtt/door_sensor_5"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "up-bright";
|
||||
disabled_switches = [
|
||||
"zigbee2mqtt/led_1"
|
||||
"zigbee2mqtt/led_2"
|
||||
"zigbee2mqtt/light_2"
|
||||
"zigbee2mqtt/light_4"
|
||||
"zigbee2mqtt/light_5"
|
||||
"zigbee2mqtt/light_7"
|
||||
];
|
||||
ignored_sensors = [ "zigbee2mqtt/door_sensor_4" ];
|
||||
}
|
||||
{
|
||||
name = "outside";
|
||||
|
|
150
mqtt/fyrtur.py
Normal file
150
mqtt/fyrtur.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
import time
|
||||
from enum import Enum
|
||||
from typing import Dict
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
import threading
|
||||
|
||||
# initial scene
|
||||
from heater.modules.heater import Heater
|
||||
from heater.modules.watcher import Watcher
|
||||
|
||||
scene = "up-dark"
|
||||
|
||||
|
||||
class Position(Enum):
|
||||
UP = 1
|
||||
DOWN = 2
|
||||
HALF = 3
|
||||
|
||||
|
||||
class Fyrtur:
|
||||
|
||||
def __init__(self, topic, set_topic, top, bottom):
|
||||
self.topic = topic
|
||||
self.set_topic = set_topic
|
||||
self.top = top
|
||||
self.bottom = bottom
|
||||
self.current_position = 100
|
||||
self.wanted_position = 100
|
||||
|
||||
def update_position(self, payload):
|
||||
self.current_position = payload["position"]
|
||||
|
||||
def needs_publish(self):
|
||||
return self.wanted_position != self.current_position
|
||||
|
||||
def payload(self):
|
||||
payload = {"position": self.wanted_position}
|
||||
return json.dumps(payload)
|
||||
|
||||
|
||||
class FyrturWatcher:
|
||||
def __init__(self, fyrturs: Dict[str, Fyrtur]):
|
||||
self.fyrturs = fyrturs
|
||||
|
||||
def get_topics(self):
|
||||
return [fyrtur.topic for fyrtur in self.fyrturs.values()]
|
||||
|
||||
def update_position(self, topic, payload):
|
||||
for fyrtur in self.fyrturs.values():
|
||||
if fyrtur.topic == topic:
|
||||
fyrtur.update_position(payload)
|
||||
return
|
||||
|
||||
def update(self, name, position : Position):
|
||||
fyrtur: Fyrtur = self.fyrturs.get(name)
|
||||
if position == Position.UP:
|
||||
fyrtur.wanted_position = fyrtur.top
|
||||
elif position == Position.DOWN:
|
||||
fyrtur.wanted_position = fyrtur.bottom
|
||||
elif position == Position.HALF:
|
||||
fyrtur.wanted_position = round((fyrtur.top - fyrtur.bottom) / 2)
|
||||
|
||||
def publish(self, client):
|
||||
for fyrtur in self.fyrturs.values():
|
||||
if fyrtur.needs_publish():
|
||||
client.publish(fyrtur.set_topic, fyrtur.payload())
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
|
||||
watcher = FyrturWatcher({
|
||||
"office1": Fyrtur(topic="zigbee2mqtt/fyrtur1", set_topic="zigbee2mqtt/fyrtur1/set", top=100, bottom=16),
|
||||
"office2": Fyrtur(topic="zigbee2mqtt/fyrtur4", set_topic="zigbee2mqtt/fyrtur4/set", top=100, bottom=22),
|
||||
"bedroom": Fyrtur(topic="zigbee2mqtt/fyrtur2", set_topic="zigbee2mqtt/fyrtur2/set", top=100, bottom=16),
|
||||
})
|
||||
|
||||
|
||||
# The callback for when the client receives a CONNACK response from the server.
|
||||
def on_connect(client, _userdata, _flags, rc):
|
||||
print("Connected with result code " + str(rc))
|
||||
|
||||
threading.Thread(target=loop_thread, args=(client,), daemon=True).start()
|
||||
|
||||
# Subscribing in on_connect() means that if we lose the connection and
|
||||
# reconnect then subscriptions will be renewed.
|
||||
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.
|
||||
def on_message(client, _userdata, msg):
|
||||
global scene
|
||||
(topic, payload) = parse_message(msg)
|
||||
if topic == "control/lights/set":
|
||||
print("set scene %s -> %s" % (scene, payload['scene']))
|
||||
scene = payload['scene']
|
||||
update_scene(client)
|
||||
else:
|
||||
print("got %s" % topic)
|
||||
watcher.update_position(topic, payload)
|
||||
|
||||
|
||||
def parse_message(msg):
|
||||
m_decode = str(msg.payload.decode("utf-8", "ignore"))
|
||||
payload = json.loads(m_decode) # decode json data
|
||||
return msg.topic, payload
|
||||
|
||||
|
||||
def update_scene(client):
|
||||
if scene in ["night", "down"]:
|
||||
watcher.update("office1", Position.DOWN)
|
||||
watcher.update("office2", Position.DOWN)
|
||||
watcher.update("bedroom", Position.DOWN)
|
||||
elif scene in ["default", "up-bright", "up-dark"]:
|
||||
watcher.update("office1", Position.UP)
|
||||
watcher.update("office2", Position.UP)
|
||||
watcher.update("bedroom", Position.UP)
|
||||
elif scene in ["half"]:
|
||||
watcher.update("office1", Position.HALF)
|
||||
watcher.update("office2", Position.HALF)
|
||||
watcher.update("bedroom", Position.HALF)
|
||||
else:
|
||||
watcher.update("office1", Position.DOWN)
|
||||
watcher.update("office2", Position.DOWN)
|
||||
watcher.update("bedroom", Position.DOWN)
|
||||
|
||||
watcher.publish(client)
|
||||
|
||||
|
||||
def loop_thread(client):
|
||||
while True:
|
||||
watcher.publish(client)
|
||||
time.sleep(120)
|
||||
|
||||
|
||||
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
|
||||
# handles reconnecting.
|
||||
# Other loop*() functions are available that give a threaded interface and a
|
||||
# manual interface.
|
||||
mqttClient.loop_forever()
|
|
@ -52,18 +52,14 @@ def parse_message(msg):
|
|||
|
||||
|
||||
def update_scene(client):
|
||||
if scene == "night":
|
||||
if scene in ["night", "outside"]:
|
||||
watcher.update("office1", 10)
|
||||
watcher.update("office2", 10)
|
||||
watcher.update("bedroom", 13)
|
||||
elif scene == "default":
|
||||
elif scene in ["default", "up-bright", "up-dark", "half", "down"]:
|
||||
watcher.update("office1", 23)
|
||||
watcher.update("office2", 23)
|
||||
watcher.update("bedroom", 18)
|
||||
elif scene == "outside":
|
||||
watcher.update("office1", 10)
|
||||
watcher.update("office2", 10)
|
||||
watcher.update("bedroom", 13)
|
||||
else:
|
||||
watcher.update("office1", 10)
|
||||
watcher.update("office2", 10)
|
||||
|
|
Loading…
Reference in a new issue