heater fiddeling around with stuff
This commit is contained in:
parent
9a9f5f58b1
commit
cf61334f5e
9 changed files with 171 additions and 49 deletions
|
@ -6,7 +6,7 @@ in {
|
||||||
#./home-assistant/mpd.nix
|
#./home-assistant/mpd.nix
|
||||||
#./home-assistant/timer.nix
|
#./home-assistant/timer.nix
|
||||||
./home-assistant/light-control.nix
|
./home-assistant/light-control.nix
|
||||||
./home-assistant/heater-control.nix
|
./home-assistant/iot-control.nix
|
||||||
./home-assistant/chaospott.nix
|
./home-assistant/chaospott.nix
|
||||||
./home-assistant/kodi.nix
|
./home-assistant/kodi.nix
|
||||||
./home-assistant/mqtt.nix
|
./home-assistant/mqtt.nix
|
||||||
|
|
|
@ -6,6 +6,7 @@ let unstable = import <nixpkgs-unstable> { };
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
./mqtt.nix
|
./mqtt.nix
|
||||||
|
./zigbee2mqtt/service.nix
|
||||||
./zigbee2mqtt/buttons.nix
|
./zigbee2mqtt/buttons.nix
|
||||||
./zigbee2mqtt/configurationHelper.nix
|
./zigbee2mqtt/configurationHelper.nix
|
||||||
./zigbee2mqtt/doors.nix
|
./zigbee2mqtt/doors.nix
|
||||||
|
@ -18,7 +19,7 @@ in {
|
||||||
./zigbee2mqtt/temperatur.nix
|
./zigbee2mqtt/temperatur.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
services.zigbee2mqtt = {
|
custom.services.zigbee2mqtt = {
|
||||||
enable = true;
|
enable = true;
|
||||||
#package = pkgs.own_zigbee2mqtt;
|
#package = pkgs.own_zigbee2mqtt;
|
||||||
#package = unstable.zigbee2mqtt;
|
#package = unstable.zigbee2mqtt;
|
||||||
|
@ -77,9 +78,9 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.zigbee2mqtt.environment = {
|
#systemd.services.zigbee2mqtt.environment = {
|
||||||
ZIGBEE2MQTT_DATA = "/var/lib/zigbee2mqtt";
|
# ZIGBEE2MQTT_DATA = "/var/lib/zigbee2mqtt";
|
||||||
};
|
#};
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -89,7 +90,7 @@ in {
|
||||||
serverAliases = [ "zigbee.pepe.private" ];
|
serverAliases = [ "zigbee.pepe.private" ];
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://localhost:${
|
proxyPass = "http://localhost:${
|
||||||
toString config.services.zigbee2mqtt.config.frontend.port
|
toString config.custom.services.zigbee2mqtt.config.frontend.port
|
||||||
}";
|
}";
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,10 +3,10 @@ let
|
||||||
|
|
||||||
# https://www.zigbee2mqtt.io/devices/E1757.html
|
# https://www.zigbee2mqtt.io/devices/E1757.html
|
||||||
allDevices = {
|
allDevices = {
|
||||||
"fyrtur1" = { id = "0x680ae2fffe64fa40"; }; # office
|
"office_fyrtur_1" = { id = "0x680ae2fffe64fa40"; };
|
||||||
"fyrtur2" = { id = "0x680ae2fffe6e9f41"; }; # bed room
|
"office_fyrtur_2" = { id = "0x680ae2fffe91d234"; };
|
||||||
"fyrtur3" = { id = "0x680ae2fffe8f6411"; }; # (retoure)
|
"bedroom_fyrtur_1" = { id = "0x680ae2fffe6e9f41"; };
|
||||||
"fyrtur4" = { id = "0x680ae2fffe91d234"; }; # office (close to kitchen)
|
"broken_fyrtur_1" = { id = "0x680ae2fffe8f6411"; };
|
||||||
};
|
};
|
||||||
|
|
||||||
# -t "zigbee2mqtt/fyrtur1/set" -m '{"position":100}'
|
# -t "zigbee2mqtt/fyrtur1/set" -m '{"position":100}'
|
||||||
|
|
|
@ -3,10 +3,10 @@ let
|
||||||
|
|
||||||
# https://www.zigbee2mqtt.io/devices/SPZB0001.html
|
# https://www.zigbee2mqtt.io/devices/SPZB0001.html
|
||||||
allDevices = {
|
allDevices = {
|
||||||
"heater1" = { id = "0x00158d00032f5ee4"; }; # office
|
"office_heater_1" = { id = "0x00158d00032f5ee4"; }; # office
|
||||||
"heater2" = { id = "0x00158d00032f5f9f"; }; # office (kitchen)
|
"office_heater_2" = { id = "0x00158d00032f5f9f"; }; # office (kitchen)
|
||||||
"heater3" = { id = "0x00158d00032f6d1e"; }; # bed room
|
"bedroom_heater_1" = { id = "0x00158d00032f6d1e"; }; # bed room
|
||||||
"heater4" = { id = "0x00158d00032f604d"; }; # abstell raum
|
"storage_heater_1" = { id = "0x00158d00032f604d"; }; # abstell raum
|
||||||
};
|
};
|
||||||
|
|
||||||
# -t "zigbee2mqtt/heater3/set" -m '{"system_mode":"auto","current_heating_setpoint":23}'
|
# -t "zigbee2mqtt/heater3/set" -m '{"system_mode":"auto","current_heating_setpoint":23}'
|
||||||
|
@ -27,9 +27,9 @@ in {
|
||||||
"battery_low"
|
"battery_low"
|
||||||
"eurotronic_host_flags"
|
"eurotronic_host_flags"
|
||||||
"eurotronic_system_mode"
|
"eurotronic_system_mode"
|
||||||
"occupied_heating_setpoint"
|
#"occupied_heating_setpoint"
|
||||||
#"pi_heating_demand"
|
#"pi_heating_demand"
|
||||||
"unoccupied_heating_setpoint"
|
#"unoccupied_heating_setpoint"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}) allDevices;
|
}) allDevices;
|
||||||
|
|
118
configs/pepe/home-assistant/zigbee2mqtt/service.nix
Normal file
118
configs/pepe/home-assistant/zigbee2mqtt/service.nix
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.custom.services.zigbee2mqtt;
|
||||||
|
|
||||||
|
configJSON = pkgs.writeText "configuration.json" (builtins.toJSON
|
||||||
|
(recursiveUpdate cfg.config config.services.zigbee2mqtt.config));
|
||||||
|
configFile =
|
||||||
|
pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } ''
|
||||||
|
${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out
|
||||||
|
'';
|
||||||
|
|
||||||
|
# the default config contains all required settings,
|
||||||
|
# so the service starts up without crashing.
|
||||||
|
defaultConfig = {
|
||||||
|
homeassistant = false;
|
||||||
|
permit_join = false;
|
||||||
|
mqtt = {
|
||||||
|
base_topic = "zigbee2mqtt";
|
||||||
|
server = "mqtt://localhost:1883";
|
||||||
|
};
|
||||||
|
serial.port = "/dev/ttyACM0";
|
||||||
|
# put device configuration into separate file because configuration.yaml
|
||||||
|
# is copied from the store on startup
|
||||||
|
devices = "devices.yaml";
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
options.custom.services.zigbee2mqtt = {
|
||||||
|
enable = mkEnableOption "enable zigbee2mqtt service";
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
description = "ignored";
|
||||||
|
default = pkgs.zigbee2mqtt.override { dataDir = cfg.dataDir; };
|
||||||
|
defaultText = "pkgs.zigbee2mqtt";
|
||||||
|
type = types.package;
|
||||||
|
};
|
||||||
|
|
||||||
|
dataDir = mkOption {
|
||||||
|
description = "Zigbee2mqtt data directory";
|
||||||
|
default = "/var/lib/zigbee2mqtt";
|
||||||
|
type = types.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkOption {
|
||||||
|
default = { };
|
||||||
|
type = with types; nullOr attrs;
|
||||||
|
example = literalExample ''
|
||||||
|
{
|
||||||
|
homeassistant = config.services.home-assistant.enable;
|
||||||
|
permit_join = true;
|
||||||
|
serial = {
|
||||||
|
port = "/dev/ttyACM1";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Your <filename>configuration.yaml</filename> as a Nix attribute set.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.enable) {
|
||||||
|
|
||||||
|
virtualisation.oci-containers.containers.zigbee2mqtt = {
|
||||||
|
image = "koenkk/zigbee2mqtt:1.18.1";
|
||||||
|
volumes = [
|
||||||
|
"${cfg.dataDir}:/app/data"
|
||||||
|
#"/run/udev:/run/udev:ro"
|
||||||
|
];
|
||||||
|
extraOptions = [
|
||||||
|
"--device=${cfg.config.serial.port}" # /dev/ttyUSB0
|
||||||
|
"--network=host"
|
||||||
|
#"--privileged=true"
|
||||||
|
];
|
||||||
|
environment = { TZ = "Europe/Amsterdam"; };
|
||||||
|
#ports = [ "127.0.0.1:${toString frontPort}:80" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# create config before staring container
|
||||||
|
systemd.services.docker-zigbee2mqtt = {
|
||||||
|
preStart = ''
|
||||||
|
cp --no-preserve=mode ${configFile} "${cfg.dataDir}/configuration.yaml"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
#systemd.services.zigbee2mqtt = {
|
||||||
|
# description = "Zigbee2mqtt Service";
|
||||||
|
# wantedBy = [ "multi-user.target" ];
|
||||||
|
# after = [ "network.target" ];
|
||||||
|
# environment.ZIGBEE2MQTT_DATA = cfg.dataDir;
|
||||||
|
# serviceConfig = {
|
||||||
|
# ExecStart = "${cfg.package}/bin/zigbee2mqtt";
|
||||||
|
# User = "zigbee2mqtt";
|
||||||
|
# WorkingDirectory = cfg.dataDir;
|
||||||
|
# Restart = "on-failure";
|
||||||
|
# ProtectSystem = "strict";
|
||||||
|
# ReadWritePaths = cfg.dataDir;
|
||||||
|
# PrivateTmp = true;
|
||||||
|
# RemoveIPC = true;
|
||||||
|
# };
|
||||||
|
# preStart = ''
|
||||||
|
# cp --no-preserve=mode ${configFile} "${cfg.dataDir}/configuration.yaml"
|
||||||
|
# '';
|
||||||
|
#};
|
||||||
|
|
||||||
|
#users.users.zigbee2mqtt = {
|
||||||
|
# home = cfg.dataDir;
|
||||||
|
# createHome = true;
|
||||||
|
# group = "zigbee2mqtt";
|
||||||
|
# extraGroups = [ "dialout" ];
|
||||||
|
# uid = config.ids.uids.zigbee2mqtt;
|
||||||
|
#};
|
||||||
|
|
||||||
|
#users.groups.zigbee2mqtt.gid = config.ids.gids.zigbee2mqtt;
|
||||||
|
};
|
||||||
|
}
|
|
@ -25,7 +25,6 @@ in {
|
||||||
gwenview
|
gwenview
|
||||||
skanlite
|
skanlite
|
||||||
|
|
||||||
|
|
||||||
#(tor-browser-bundle-bin.overrideAttrs (old: {
|
#(tor-browser-bundle-bin.overrideAttrs (old: {
|
||||||
# #version = "10.0.13";
|
# #version = "10.0.13";
|
||||||
# src = pkgs.fetchurl {
|
# src = pkgs.fetchurl {
|
||||||
|
|
|
@ -17,9 +17,8 @@ class Position(Enum):
|
||||||
|
|
||||||
class Fyrtur:
|
class Fyrtur:
|
||||||
|
|
||||||
def __init__(self, topic, set_topic, top, bottom):
|
def __init__(self, topic, top, bottom):
|
||||||
self.topic = topic
|
self.topic = topic
|
||||||
self.set_topic = set_topic
|
|
||||||
self.top = top
|
self.top = top
|
||||||
self.bottom = bottom
|
self.bottom = bottom
|
||||||
self.current_position = 100
|
self.current_position = 100
|
||||||
|
@ -31,9 +30,9 @@ class Fyrtur:
|
||||||
def needs_publish(self):
|
def needs_publish(self):
|
||||||
return self.wanted_position != self.current_position
|
return self.wanted_position != self.current_position
|
||||||
|
|
||||||
def payload(self):
|
def topic_and_payload_for_set(self):
|
||||||
payload = {"position": self.wanted_position}
|
payload = {"position": self.wanted_position}
|
||||||
return json.dumps(payload)
|
return ("%s/set" % self.topic), json.dumps(payload)
|
||||||
|
|
||||||
|
|
||||||
class FyrturWatcher:
|
class FyrturWatcher:
|
||||||
|
@ -61,14 +60,15 @@ class FyrturWatcher:
|
||||||
def publish(self, client):
|
def publish(self, client):
|
||||||
for fyrtur in self.fyrturs.values():
|
for fyrtur in self.fyrturs.values():
|
||||||
if fyrtur.needs_publish():
|
if fyrtur.needs_publish():
|
||||||
client.publish(fyrtur.set_topic, fyrtur.payload())
|
topic, payload = fyrtur.topic_and_payload_for_set()
|
||||||
|
client.publish(topic, payload)
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
|
|
||||||
watcher = FyrturWatcher({
|
watcher = FyrturWatcher({
|
||||||
"office1": Fyrtur(topic="zigbee2mqtt/fyrtur1", set_topic="zigbee2mqtt/fyrtur1/set", top=100, bottom=16),
|
"office1": Fyrtur(topic="zigbee2mqtt/office_fyrtur_1", top=100, bottom=16),
|
||||||
"office2": Fyrtur(topic="zigbee2mqtt/fyrtur4", set_topic="zigbee2mqtt/fyrtur4/set", top=100, bottom=22),
|
"office2": Fyrtur(topic="zigbee2mqtt/office_fyrtur_2", top=100, bottom=22),
|
||||||
"bedroom": Fyrtur(topic="zigbee2mqtt/fyrtur2", set_topic="zigbee2mqtt/fyrtur2/set", top=100, bottom=16),
|
"bedroom": Fyrtur(topic="zigbee2mqtt/bedroom_fyrtur_1", top=100, bottom=16),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +83,6 @@ def on_connect(client, _userdata, _flags, rc):
|
||||||
client.subscribe("control/lights/set")
|
client.subscribe("control/lights/set")
|
||||||
for topic in watcher.get_topics():
|
for topic in watcher.get_topics():
|
||||||
client.subscribe(topic)
|
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.
|
||||||
|
@ -110,7 +109,7 @@ def update_scene(client):
|
||||||
watcher.update("office1", Position.DOWN)
|
watcher.update("office1", Position.DOWN)
|
||||||
watcher.update("office2", Position.DOWN)
|
watcher.update("office2", Position.DOWN)
|
||||||
watcher.update("bedroom", Position.DOWN)
|
watcher.update("bedroom", Position.DOWN)
|
||||||
elif scene in ["default", "up-bright", "up-dark"]:
|
elif scene in ["default", "up-bright", "up-dark" "outside"]:
|
||||||
watcher.update("office1", Position.UP)
|
watcher.update("office1", Position.UP)
|
||||||
watcher.update("office2", Position.UP)
|
watcher.update("office2", Position.UP)
|
||||||
watcher.update("bedroom", Position.UP)
|
watcher.update("bedroom", Position.UP)
|
||||||
|
|
|
@ -6,23 +6,12 @@ from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
class Heater:
|
class Heater:
|
||||||
def __init__(self, topic, set_topic):
|
def __init__(self, topic):
|
||||||
self.not_initialized_yet = True
|
self.not_initialized_yet = True
|
||||||
self.wanted_temperature = 15
|
self.wanted_temperature = 10
|
||||||
self.actual_temperature = 15
|
self.actual_temperature = 10
|
||||||
self.set_topic = set_topic
|
|
||||||
self.topic = topic
|
self.topic = topic
|
||||||
|
|
||||||
def payload(self):
|
|
||||||
payload = {
|
|
||||||
"system_mode": "auto",
|
|
||||||
"current_heating_setpoint": self.wanted_temperature,
|
|
||||||
#"occupied_heating_setpoint": self.wanted_temperature,
|
|
||||||
#"unoccupied_heating_setpoint": self.wanted_temperature,
|
|
||||||
"eurotronic_host_flags": {"window_open": True}
|
|
||||||
}
|
|
||||||
return json.dumps(payload)
|
|
||||||
|
|
||||||
def needs_publish(self):
|
def needs_publish(self):
|
||||||
if self.not_initialized_yet:
|
if self.not_initialized_yet:
|
||||||
return True
|
return True
|
||||||
|
@ -40,10 +29,25 @@ class Heater:
|
||||||
|
|
||||||
def topic_and_payload_for_query(self):
|
def topic_and_payload_for_query(self):
|
||||||
payload = {
|
payload = {
|
||||||
"current_heating_setpoint": ""
|
"current_heating_setpoint": "",
|
||||||
|
"occupied_heating_setpoint": "",
|
||||||
|
"unoccupied_heating_setpoint": "",
|
||||||
|
"local_temperature": "",
|
||||||
|
#"pi_heating_demand": "",
|
||||||
|
#"system_mode": "",
|
||||||
}
|
}
|
||||||
return ("%s/get" % self.topic), json.dumps(payload)
|
return ("%s/get" % self.topic), json.dumps(payload)
|
||||||
|
|
||||||
|
def topic_and_payload_for_set(self):
|
||||||
|
payload = {
|
||||||
|
"system_mode": "auto",
|
||||||
|
#"current_heating_setpoint": str(self.wanted_temperature),
|
||||||
|
"occupied_heating_setpoint": str(self.wanted_temperature),
|
||||||
|
"unoccupied_heating_setpoint": str(self.wanted_temperature),
|
||||||
|
"eurotronic_host_flags": {"window_open": True}
|
||||||
|
}
|
||||||
|
return ("%s/set" % self.topic), json.dumps(payload)
|
||||||
|
|
||||||
|
|
||||||
class Watcher:
|
class Watcher:
|
||||||
|
|
||||||
|
@ -53,7 +57,8 @@ class Watcher:
|
||||||
def publish(self, client):
|
def publish(self, client):
|
||||||
for heater in self.heater.values():
|
for heater in self.heater.values():
|
||||||
if heater.needs_publish():
|
if heater.needs_publish():
|
||||||
client.publish(heater.set_topic, heater.payload())
|
topic, payload = heater.topic_and_payload_for_set()
|
||||||
|
client.publish(topic, payload)
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
def update(self, name, temperature):
|
def update(self, name, temperature):
|
||||||
|
@ -78,9 +83,9 @@ class Watcher:
|
||||||
scene = "default"
|
scene = "default"
|
||||||
|
|
||||||
watcher = Watcher({
|
watcher = Watcher({
|
||||||
"office1": Heater(topic="zigbee2mqtt/heater1", set_topic="zigbee2mqtt/heater1/set"),
|
"office1": Heater(topic="zigbee2mqtt/office_heater_1"),
|
||||||
"office2": Heater(topic="zigbee2mqtt/heater2", set_topic="zigbee2mqtt/heater2/set"),
|
"office2": Heater(topic="zigbee2mqtt/office_heater_2"),
|
||||||
"bedroom": Heater(topic="zigbee2mqtt/heater3", set_topic="zigbee2mqtt/heater3/set"),
|
"bedroom": Heater(topic="zigbee2mqtt/bedroom_heater_1"),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,7 +114,6 @@ def on_message(client, _userdata, msg):
|
||||||
else:
|
else:
|
||||||
print("got %s" % topic)
|
print("got %s" % topic)
|
||||||
watcher.update_actual_heating_point_for_topic(topic, payload)
|
watcher.update_actual_heating_point_for_topic(topic, payload)
|
||||||
# watcher.publish(client)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_message(msg):
|
def parse_message(msg):
|
||||||
|
@ -122,7 +126,7 @@ def update_scene(client):
|
||||||
if scene in ["night", "outside"]:
|
if scene in ["night", "outside"]:
|
||||||
watcher.update("office1", 10)
|
watcher.update("office1", 10)
|
||||||
watcher.update("office2", 10)
|
watcher.update("office2", 10)
|
||||||
watcher.update("bedroom", 13)
|
watcher.update("bedroom", 10)
|
||||||
elif scene in ["default", "up-bright", "up-dark", "half", "down"]:
|
elif scene in ["default", "up-bright", "up-dark", "half", "down"]:
|
||||||
watcher.update("office1", 26)
|
watcher.update("office1", 26)
|
||||||
watcher.update("office2", 26)
|
watcher.update("office2", 26)
|
||||||
|
@ -130,7 +134,7 @@ def update_scene(client):
|
||||||
else:
|
else:
|
||||||
watcher.update("office1", 10)
|
watcher.update("office1", 10)
|
||||||
watcher.update("office2", 10)
|
watcher.update("office2", 10)
|
||||||
watcher.update("bedroom", 13)
|
watcher.update("bedroom", 10)
|
||||||
|
|
||||||
watcher.publish(client)
|
watcher.publish(client)
|
||||||
|
|
||||||
|
@ -138,6 +142,7 @@ def update_scene(client):
|
||||||
def loop_thread(client):
|
def loop_thread(client):
|
||||||
while True:
|
while True:
|
||||||
watcher.publish(client)
|
watcher.publish(client)
|
||||||
|
watcher.pull_values(client)
|
||||||
time.sleep(120)
|
time.sleep(120)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue