666 lines
19 KiB
Nix
666 lines
19 KiB
Nix
{ pkgs, config, lib, ... }:
|
|
let unstablePkgs = import <nixpkgs-unstable> { };
|
|
in {
|
|
|
|
imports = [
|
|
#./home-assistant/mpd.nix
|
|
#./home-assistant/timer.nix
|
|
./home-assistant/chaospott.nix
|
|
./home-assistant/kodi.nix
|
|
./home-assistant/mqtt.nix
|
|
./home-assistant/sonoff.nix
|
|
./home-assistant/stocks.nix
|
|
./home-assistant/weather.nix
|
|
./home-assistant/workday.nix
|
|
./home-assistant/zigbee2mqtt.nix
|
|
];
|
|
|
|
services.homeAssistantConfig = {
|
|
|
|
# turn on to edit GUI
|
|
# lovelace = {};
|
|
|
|
homeassistant = {
|
|
latitude = 51.444847;
|
|
longitude = 6.967006;
|
|
elevation = 116;
|
|
|
|
auth_providers = [{
|
|
type = "trusted_networks";
|
|
trusted_networks =
|
|
[ config.module.cluster.services.tinc."private".networkSubnet ];
|
|
}];
|
|
};
|
|
|
|
prometheus.namespace = "hass";
|
|
|
|
# manual state
|
|
# ------------
|
|
input_select.situation = {
|
|
icon = "mdi:brightness-auto";
|
|
options = [
|
|
# it is dark outside and I want it to be bright inside
|
|
"dark"
|
|
# it is bright outside, so no need to be bright inside
|
|
"bright"
|
|
# it is dark ouside, but I don't want it bright inside
|
|
"essential"
|
|
];
|
|
};
|
|
input_boolean.situation_toggle.icon = "mdi:toggle-switch";
|
|
|
|
# enable presents_tracking
|
|
input_boolean.presents_tracking.icon = "mdi:account";
|
|
input_select.room_present = {
|
|
icon = "mdi:map-marker";
|
|
options = [
|
|
"kitchen_room_present"
|
|
"bath_room_present"
|
|
"living_room_present"
|
|
"bed_room_present"
|
|
"floor_room_present"
|
|
"bath_room_present"
|
|
"outside"
|
|
];
|
|
};
|
|
|
|
automation = let
|
|
|
|
# a help function that flattens even 2 times
|
|
flatMap = function: list: lib.flatten (map function (lib.flatten list));
|
|
|
|
allRooms =
|
|
[ "living_room" "floor_room" "bath_room" "bed_room" "kitchen_room" ];
|
|
|
|
# presents <-> absents : light settings
|
|
# -------------------------------------
|
|
roomSwitches = let
|
|
roomPresents = {
|
|
# group of the room that should be turned on
|
|
roomGroup,
|
|
# group of the room that should be turned off
|
|
turnOffGroup ? roomGroup,
|
|
# group of the room that that indicates presents in the room
|
|
presentsGroup,
|
|
# global situation
|
|
situation,
|
|
# brightness for dimable lights
|
|
brightness ? 255 }: [
|
|
{
|
|
alias =
|
|
"presents in ${presentsGroup} -> turn lights on in ${roomGroup} for ${situation}";
|
|
trigger = {
|
|
platform = "state";
|
|
entity_id = "group.${presentsGroup}";
|
|
from = "off";
|
|
to = "on";
|
|
};
|
|
condition = {
|
|
condition = "template";
|
|
value_template =
|
|
"{{ states( 'input_select.situation' ) == '${situation}' }}";
|
|
};
|
|
action = [
|
|
{
|
|
service = "switch.turn_on";
|
|
data.entity_id = "group.${roomGroup}";
|
|
}
|
|
{
|
|
service = "light.turn_on";
|
|
data = {
|
|
entity_id = "group.${roomGroup}";
|
|
brightness = brightness;
|
|
};
|
|
}
|
|
];
|
|
}
|
|
{
|
|
alias =
|
|
"absents in ${presentsGroup} -> turn lights off ${turnOffGroup} in ${situation}";
|
|
trigger = map (minutes: {
|
|
platform = "state";
|
|
entity_id = "group.${presentsGroup}";
|
|
from = "on";
|
|
to = "off";
|
|
for.seconds = minutes * 60;
|
|
}) [ 2 5 10 15 20 25 30 35 40 45 50 55 ];
|
|
condition = {
|
|
condition = "and";
|
|
conditions = [
|
|
{
|
|
condition = "template";
|
|
value_template =
|
|
"{{ states( 'input_select.situation' ) == '${situation}' }}";
|
|
}
|
|
{
|
|
condition = "or";
|
|
conditions = [
|
|
{
|
|
condition = "template";
|
|
value_template =
|
|
"{{ states( 'input_select.room_present' ) != '${presentsGroup}' }}";
|
|
}
|
|
{
|
|
condition = "template";
|
|
value_template =
|
|
"{{ states( 'input_boolean.presents_tracking' ) == 'off' }}";
|
|
}
|
|
];
|
|
}
|
|
];
|
|
};
|
|
action = [
|
|
{
|
|
service = "switch.turn_off";
|
|
data.entity_id = "group.${turnOffGroup}";
|
|
}
|
|
{
|
|
service = "light.turn_off";
|
|
data.entity_id = "group.${turnOffGroup}";
|
|
}
|
|
];
|
|
}
|
|
{
|
|
alias =
|
|
"finally absents in ${presentsGroup} -> turn lights off ${turnOffGroup} in ${situation}";
|
|
trigger = [{
|
|
platform = "state";
|
|
entity_id = "group.${presentsGroup}";
|
|
from = "on";
|
|
to = "off";
|
|
for.seconds = 60 * 60;
|
|
}];
|
|
condition = {
|
|
condition = "template";
|
|
value_template =
|
|
"{{ states( 'input_select.situation' ) == '${situation}' }}";
|
|
};
|
|
action = [
|
|
{
|
|
service = "switch.turn_off";
|
|
data.entity_id = "group.${turnOffGroup}";
|
|
}
|
|
{
|
|
service = "light.turn_off";
|
|
data.entity_id = "group.${turnOffGroup}";
|
|
}
|
|
];
|
|
}
|
|
];
|
|
onOffArguments = flatMap (name: [
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
roomGroup = "${name}_lights";
|
|
situation = "dark";
|
|
}
|
|
{
|
|
brightness = 30;
|
|
presentsGroup = "${name}_present";
|
|
roomGroup = "${name}_essential";
|
|
situation = "essential";
|
|
turnOffGroup = "${name}_lights";
|
|
}
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
roomGroup = "${name}_bright";
|
|
turnOffGroup = "${name}_lights";
|
|
situation = "bright";
|
|
}
|
|
]) allRooms;
|
|
in (flatMap roomPresents onOffArguments);
|
|
|
|
roomPresentSwitches = let
|
|
|
|
allRoomPresentGroups = map (name: "${name}_present") allRooms;
|
|
|
|
switchPresentsTracking =
|
|
# group to determine presents
|
|
presentGroup:
|
|
let
|
|
otherRoomPresentGroups =
|
|
(builtins.filter (name: name != presentGroup)
|
|
allRoomPresentGroups) ++ [ "outside" ];
|
|
in [
|
|
{
|
|
alias =
|
|
"select ${presentGroup} if all other rooms are longer not present/active";
|
|
trigger = {
|
|
platform = "state";
|
|
entity_id = "group.${presentGroup}";
|
|
from = "on";
|
|
to = "off";
|
|
for.seconds = (2 * 60) - 15;
|
|
};
|
|
condition = {
|
|
condition = "and";
|
|
conditions = flatMap (otherRoomPresent: {
|
|
condition = "state";
|
|
entity_id = "group.${otherRoomPresent}";
|
|
state = "off";
|
|
for.seconds = 1 * 60;
|
|
}) otherRoomPresentGroups;
|
|
};
|
|
action = [{
|
|
service = "input_select.select_option";
|
|
data = {
|
|
entity_id = "input_select.room_present";
|
|
option = presentGroup;
|
|
};
|
|
}];
|
|
}
|
|
{
|
|
alias =
|
|
"select ${presentGroup} if no other room is present/active but ${presentGroup} is";
|
|
trigger = {
|
|
platform = "time_pattern";
|
|
minutes = "/1";
|
|
};
|
|
condition = {
|
|
condition = "and";
|
|
conditions = [{
|
|
condition = "state";
|
|
entity_id = "group.${presentGroup}";
|
|
state = "on";
|
|
for.seconds = 1 * 60;
|
|
}] ++ (flatMap (otherRoomPresent: {
|
|
condition = "state";
|
|
entity_id = "group.${otherRoomPresent}";
|
|
state = "off";
|
|
for.seconds = 1 * 60;
|
|
}) otherRoomPresentGroups);
|
|
};
|
|
action = [{
|
|
service = "input_select.select_option";
|
|
data = {
|
|
entity_id = "input_select.room_present";
|
|
option = presentGroup;
|
|
};
|
|
}];
|
|
}
|
|
{
|
|
alias = "select ${presentGroup} when entering the room";
|
|
trigger = {
|
|
platform = "state";
|
|
entity_id = "group.${presentGroup}";
|
|
from = "off";
|
|
to = "on";
|
|
};
|
|
action = [{
|
|
service = "input_select.select_option";
|
|
data = {
|
|
entity_id = "input_select.room_present";
|
|
option = presentGroup;
|
|
};
|
|
}];
|
|
}
|
|
];
|
|
in (flatMap switchPresentsTracking allRoomPresentGroups)
|
|
++ (switchPresentsTracking "outside");
|
|
|
|
# change light scene in rooms when changing situation
|
|
# ---------------------------------------------------
|
|
situationSwitches = let
|
|
situationSwitch = {
|
|
# old group to turn off
|
|
fromRoomGroup,
|
|
# new group to turn on
|
|
toRoomGroup,
|
|
# group to determine presents
|
|
presentsGroup,
|
|
# old situation
|
|
fromSituation,
|
|
# new situation
|
|
toSituation,
|
|
# brightness for dimable lights
|
|
brightness ? 255 }: [
|
|
{
|
|
alias =
|
|
"${fromSituation} -> ${toSituation} for ${fromRoomGroup} -> ${toRoomGroup} on";
|
|
trigger = {
|
|
platform = "state";
|
|
entity_id = "input_select.situation";
|
|
from = fromSituation;
|
|
to = toSituation;
|
|
};
|
|
condition = {
|
|
condition = "state";
|
|
entity_id = "group.${presentsGroup}";
|
|
state = "on";
|
|
};
|
|
action = [
|
|
{
|
|
service = "switch.turn_off";
|
|
data.entity_id = "group.${fromRoomGroup}";
|
|
}
|
|
{
|
|
service = "light.turn_off";
|
|
data.entity_id = "group.${fromRoomGroup}";
|
|
}
|
|
{
|
|
service = "switch.turn_on";
|
|
data.entity_id = "group.${toRoomGroup}";
|
|
}
|
|
{
|
|
service = "light.turn_on";
|
|
data = {
|
|
entity_id = "group.${toRoomGroup}";
|
|
brightness = brightness;
|
|
};
|
|
}
|
|
];
|
|
}
|
|
{
|
|
alias =
|
|
"${fromSituation} -> ${toSituation} for ${fromRoomGroup} -> ${toRoomGroup} off";
|
|
trigger = {
|
|
platform = "state";
|
|
entity_id = "input_select.situation";
|
|
from = fromSituation;
|
|
to = toSituation;
|
|
};
|
|
condition = {
|
|
condition = "state";
|
|
entity_id = "group.${presentsGroup}";
|
|
state = "off";
|
|
};
|
|
action = [
|
|
{
|
|
service = "switch.turn_off";
|
|
data.entity_id = "group.${fromRoomGroup}";
|
|
}
|
|
{
|
|
service = "light.turn_off";
|
|
data.entity_id = "group.${fromRoomGroup}";
|
|
}
|
|
];
|
|
}
|
|
];
|
|
allArguments = flatMap (name: [
|
|
# essential <-> dark
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
fromSituation = "dark";
|
|
toSituation = "essential";
|
|
fromRoomGroup = "${name}_lights";
|
|
toRoomGroup = "${name}_essential";
|
|
brightness = 30;
|
|
}
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
fromSituation = "essential";
|
|
toSituation = "dark";
|
|
fromRoomGroup = "${name}_essential";
|
|
toRoomGroup = "${name}_lights";
|
|
}
|
|
# bright <-> dark
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
fromSituation = "dark";
|
|
toSituation = "bright";
|
|
fromRoomGroup = "${name}_lights";
|
|
toRoomGroup = "${name}_bright";
|
|
}
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
fromSituation = "bright";
|
|
toSituation = "dark";
|
|
fromRoomGroup = "${name}_bright";
|
|
toRoomGroup = "${name}_lights";
|
|
}
|
|
# bright <-> essential
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
fromSituation = "bright";
|
|
toSituation = "essential";
|
|
fromRoomGroup = "${name}_bright";
|
|
toRoomGroup = "${name}_essential";
|
|
brightness = 30;
|
|
}
|
|
{
|
|
presentsGroup = "${name}_present";
|
|
fromSituation = "essential";
|
|
toSituation = "bright";
|
|
fromRoomGroup = "${name}_essential";
|
|
toRoomGroup = "${name}_bright";
|
|
}
|
|
]) allRooms;
|
|
in flatMap situationSwitch allArguments;
|
|
|
|
in situationSwitches ++ roomSwitches ++ roomPresentSwitches ++ [
|
|
|
|
# control situation with buttons
|
|
{
|
|
alias = "set essential";
|
|
trigger = {
|
|
platform = "state";
|
|
entity_id = "input_boolean.situation_toggle";
|
|
from = "off";
|
|
to = "on";
|
|
};
|
|
action = {
|
|
service = "input_select.select_option";
|
|
data = {
|
|
entity_id = "input_select.situation";
|
|
option = "essential";
|
|
};
|
|
};
|
|
}
|
|
{
|
|
alias = "unset essential";
|
|
trigger = {
|
|
platform = "state";
|
|
entity_id = "input_boolean.situation_toggle";
|
|
from = "on";
|
|
to = "off";
|
|
};
|
|
action = {
|
|
service = "input_select.select_option";
|
|
data = {
|
|
entity_id = "input_select.situation";
|
|
option = "dark";
|
|
};
|
|
};
|
|
}
|
|
];
|
|
|
|
group = let
|
|
create_room = { name, description }: {
|
|
"${name}" = {
|
|
name = "${description}";
|
|
view = false;
|
|
control = "hidden";
|
|
entities = [ ];
|
|
};
|
|
"${name}_lights" = {
|
|
name = "${description} Beleuchtung";
|
|
view = false;
|
|
entities = [ ];
|
|
};
|
|
"${name}_present" = {
|
|
control = "hidden";
|
|
name = "${description} Anwesend";
|
|
view = false;
|
|
entities = [ ];
|
|
};
|
|
"${name}_essential" = {
|
|
control = "hidden";
|
|
name = "${description} Minimale Beleuchtung";
|
|
view = false;
|
|
entities = [ ];
|
|
};
|
|
"${name}_bright" = {
|
|
control = "hidden";
|
|
name = "${description} Tages Beleuchtung";
|
|
view = false;
|
|
entities = [ ];
|
|
};
|
|
"view_${name}" = {
|
|
name = description;
|
|
view = true;
|
|
entities = [
|
|
"group.${name}"
|
|
"group.${name}_bright"
|
|
"group.${name}_essential"
|
|
"group.${name}_lights"
|
|
"group.${name}_present"
|
|
];
|
|
};
|
|
};
|
|
create_rooms = rooms:
|
|
lib.foldr (a: b: a // b) { } (map create_room rooms);
|
|
# rooms
|
|
# -----
|
|
in (create_rooms [
|
|
{
|
|
name = "floor_room";
|
|
description = "Flur";
|
|
}
|
|
{
|
|
name = "bed_room";
|
|
description = "Schlafzimmer";
|
|
}
|
|
{
|
|
name = "living_room";
|
|
description = "Wohnzimmer";
|
|
}
|
|
{
|
|
name = "kitchen_room";
|
|
description = "Küche";
|
|
}
|
|
{
|
|
name = "bath_room";
|
|
description = "Klo";
|
|
}
|
|
]) // {
|
|
view_rooms = {
|
|
name = "Räume";
|
|
view = true;
|
|
entities = [
|
|
"group.today"
|
|
"group.floor_room"
|
|
"group.bed_room"
|
|
"group.living_room"
|
|
"group.kitchen_room"
|
|
"group.bath_room"
|
|
"group.outside"
|
|
];
|
|
};
|
|
|
|
all_room_presents = {
|
|
name = "Alle Anwesenheits Raum Sensoren";
|
|
entities = [
|
|
"group.floor_room_present"
|
|
"group.bed_room_present"
|
|
"group.living_room_present"
|
|
"group.kitchen_room_present"
|
|
"group.bath_room_present"
|
|
"group.outside"
|
|
];
|
|
};
|
|
|
|
outside = {
|
|
control = "hidden";
|
|
name = "Draußen";
|
|
view = false;
|
|
entities = [ ];
|
|
};
|
|
|
|
# overview
|
|
# --------
|
|
all_sensors = {
|
|
name = "Alle Sensoren";
|
|
control = "hidden";
|
|
};
|
|
today = {
|
|
control = "hidden";
|
|
name = "Today";
|
|
view = false;
|
|
entities = [
|
|
"input_select.situation"
|
|
"input_select.room_present"
|
|
"input_boolean.presents_tracking"
|
|
];
|
|
};
|
|
view_overview = {
|
|
name = "Übersicht";
|
|
view = true;
|
|
entities = [ "group.today" ];
|
|
};
|
|
|
|
# other stuff
|
|
# -----------
|
|
tv = {
|
|
name = "TV";
|
|
view = false;
|
|
};
|
|
all_lights = {
|
|
name = "Alle Lampen";
|
|
view = false;
|
|
};
|
|
unknown = {
|
|
control = "hidden";
|
|
name = "Not Used";
|
|
view = false;
|
|
entities = [ ];
|
|
};
|
|
|
|
};
|
|
|
|
script.turn_all_off.sequence = [ ];
|
|
script.turn_all_lights_off.sequence = [ ];
|
|
|
|
};
|
|
|
|
services.home-assistant = {
|
|
enable = true;
|
|
package = unstablePkgs.home-assistant.override {
|
|
python3 = unstablePkgs.python37;
|
|
extraPackages = python: [
|
|
# todo : check which is still needed
|
|
python.netdisco
|
|
python.xmltodict
|
|
python.mpd2
|
|
|
|
# for mqtt
|
|
python.hbmqtt
|
|
python.paho-mqtt
|
|
|
|
# needed for platform workday
|
|
#(python.buildPythonPackage rec {
|
|
# pname = "holidays";
|
|
# version = "0.9.10";
|
|
# src = python.fetchPypi {
|
|
# inherit pname version;
|
|
# sha256 =
|
|
# "9f06d143eb708e8732230260636938f2f57114e94defd8fa2082408e0d422d6f";
|
|
# };
|
|
# doCheck = false;
|
|
# buildInputs = [ pkgs.dateutils ];
|
|
# propagatedBuildInputs = [ python."python-dateutil" python."six" ];
|
|
# meta = with pkgs.stdenv.lib; {
|
|
# homepage = "https://github.com/dr-prodigy/python-holidays";
|
|
# license = licenses.mit;
|
|
# description = "Generate and work with holidays in Python";
|
|
# maintainers = with maintainers; [ mrVanDalo ];
|
|
# };
|
|
#})
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
# host nginx setup
|
|
services.nginx = {
|
|
enable = true;
|
|
recommendedProxySettings = true;
|
|
virtualHosts = {
|
|
"iot.pepe.private" = {
|
|
serverAliases = [ "hass.pepe.private" "home.pepe.private" ];
|
|
locations."/" = { proxyPass = "http://pepe.private:8123"; };
|
|
};
|
|
};
|
|
};
|
|
|
|
}
|