nix-config/config/services/homeassistant.nix

522 lines
14 KiB
Nix
Raw Permalink Normal View History

2025-01-04 23:25:48 +01:00
{
config,
2025-01-07 21:23:06 +01:00
globals,
2025-01-04 23:25:48 +01:00
nodes,
2025-01-05 22:27:49 +01:00
lib,
2025-01-09 13:58:51 +01:00
pkgs,
2025-01-04 23:25:48 +01:00
...
}:
{
environment.persistence."/persist".directories = [
2025-01-09 13:58:51 +01:00
{
directory = "/var/lib/private/esphome";
mode = "0700";
}
2025-01-04 23:25:48 +01:00
{
directory = config.services.home-assistant.configDir;
user = "hass";
group = "hass";
mode = "0700";
}
];
2025-01-09 13:58:51 +01:00
services.esphome = {
enable = true;
address = "0.0.0.0";
port = 3001;
#allowedDevices = lib.mkForce ["/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0"];
# TODO instead deny the zigbee device
};
2025-01-04 23:25:48 +01:00
wireguard.services = {
client.via = "nucnix";
2025-01-09 13:58:51 +01:00
firewallRuleForNode.${globals.services.nginx.host}.allowedTCPPorts = [
3000
3001
];
2025-01-04 23:25:48 +01:00
};
networking.nftables.firewall.zones.devices.interfaces = [ "mv-devices" ];
2025-01-13 21:28:06 +01:00
networking.nftables.firewall.zones.iot.interfaces = [ "mv-iot" ];
networking.nftables.firewall = {
rules = {
2025-01-13 21:28:06 +01:00
mqtt = {
from = [
"devices"
"iot"
];
to = [ "local" ];
allowedTCPPorts = [ 1883 ];
};
homematic = {
from = [
"devices"
];
to = [ "local" ];
allowedTCPPorts = [ 45053 ];
};
2025-01-13 21:28:06 +01:00
mdns = {
from = [
"devices"
"iot"
];
to = [ "local" ];
allowedUDPPorts = [ 5353 ];
};
};
};
2025-01-13 21:28:06 +01:00
age.secrets.mosquitto-pw-home_assistant = {
mode = "440";
owner = "hass";
group = "mosquitto";
generator.script = "alnum";
};
services.mosquitto = {
enable = true;
persistence = true;
listeners = [
{
acl = [ "pattern readwrite #" ];
users = {
home_assistant = {
passwordFile = config.age.secrets.mosquitto-pw-home_assistant.path;
acl = [ "readwrite #" ];
};
};
settings.allow_anonymous = false;
}
];
};
2025-01-04 23:25:48 +01:00
services.home-assistant = {
enable = true;
extraComponents = [
"radio_browser"
"met"
"esphome"
"fritzbox"
2025-01-07 21:23:06 +01:00
"homematic"
2025-01-04 23:25:48 +01:00
"soundtouch"
"spotify"
"matter"
2025-01-07 21:23:06 +01:00
"esphome"
2025-01-04 23:25:48 +01:00
#"zha"
"mqtt"
"ollama"
2025-01-09 13:58:51 +01:00
"solaredge"
];
customComponents = with pkgs.home-assistant-custom-components; [
homematicip_local
2025-01-04 23:25:48 +01:00
];
2025-01-12 14:47:09 +01:00
customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
bubble-card
weather-card
mini-graph-card
card-mod
mushroom
multiple-entity-row
button-card
2025-01-12 22:11:22 +01:00
weather-chart-card
hourly-weather
2025-01-12 14:47:09 +01:00
];
2025-01-04 23:25:48 +01:00
config = {
http = {
server_host = [ "0.0.0.0" ];
server_port = 3000;
use_x_forwarded_for = true;
trusted_proxies = [ nodes.nucnix-nginx.config.wireguard.services.ipv4 ];
};
2025-01-12 14:47:09 +01:00
lovelace.mode = "yaml";
2025-01-04 23:25:48 +01:00
homeassistant = {
name = "!secret ha_name";
latitude = "!secret ha_latitude";
longitude = "!secret ha_longitude";
elevation = "!secret ha_elevation";
currency = "EUR";
time_zone = "Europe/Berlin";
unit_system = "metric";
#external_url = "https://";
packages = {
manual = "!include manual.yaml";
};
};
default_config = { };
### Components not from default_config
frontend = {
2025-01-12 14:47:09 +01:00
themes = "!include_dir_merge_named themes";
2025-01-04 23:25:48 +01:00
};
"automation ui" = "!include automations.yaml";
2025-01-04 23:25:48 +01:00
2025-01-05 22:27:49 +01:00
# influxdb = {
# api_version = 2;
# host = globals.services.influxdb.domain;
# port = "443";
# max_retries = 10;
# ssl = true;
# verify_ssl = true;
# token = "!secret influxdb_token";
# organization = "home";
# bucket = "home_assistant";
# };
2025-01-10 16:36:07 +01:00
# Modbus Varta element backup
modbus = {
name = "mb_varta";
type = "tcp";
host = "10.99.30.20"; # replace with your ip of the your varta;
port = 502;
delay = 1;
timeout = 3;
message_wait_milliseconds = 250;
sensors =
### EMS Software Version { not for Varta link;
[
{
name = "mb_varta_EMS";
slave = 1;
address = 1000;
count = 17;
data_type = "string";
precision = 0;
scale = 1;
}
### ENS Software Version { not for Varta link;
{
name = "mb_varta_ENS";
slave = 1;
address = 1017;
count = 17;
data_type = "string";
precision = 0;
scale = 1;
}
### Software Version { not for Varta link;
{
name = "mb_varta_software";
slave = 1;
address = 1034;
count = 17;
data_type = "string";
precision = 0;
scale = 1;
}
### Table version;
{
name = "mb_varta_table_version";
slave = 1;
address = 1051;
data_type = "uint16";
precision = "0";
scale = 1;
### timestamp {- not working;
}
{
name = "mb_varta_timestamp";
slave = 1;
address = 1052;
data_type = "uint32";
swap = "word";
precision = 0;
scale = 1;
}
### Serial Number;
{
name = "mb_varta_serial";
slave = 1;
address = 1054;
count = 10;
data_type = "string";
precision = 0;
scale = 1;
}
### Number of Battery Modules installed;
{
name = "mb_varta_installed_batteries";
slave = 1;
address = 1064;
data_type = "uint16";
precision = 0;
scale = 1;
}
### State;
{
name = "mb_varta_state";
slave = 1;
address = 1065;
data_type = "uint16";
precision = 0;
scale = 1;
unit_of_measurement = "State";
}
### Active Power { positive=charge / negative: discharge;
{
name = "mb_varta_active_power";
slave = 1;
address = 1066;
data_type = "int16";
precision = 0;
scale = 1;
device_class = "power";
unit_of_measurement = "W";
}
### Apparent Power { positive=charge / negative: discharge;
{
name = "mb_varta_apparent_power";
slave = 1;
address = 1067;
data_type = "int16";
precision = 0;
scale = 1;
device_class = "apparent_power";
unit_of_measurement = "VA";
}
### State of Charge;
{
name = "mb_varta_SOC";
slave = 1;
address = 1068;
data_type = "uint16";
precision = 0;
scale = 1;
device_class = "battery";
unit_of_measurement = "%";
}
### energy counter AC{>DC - not sure if correct;
{
name = "mb_varta_ACDC";
slave = 1;
address = 1069;
data_type = "uint32";
swap = "word";
precision = 0;
scale = 1;
device_class = "energy";
unit_of_measurement = "Wh";
state_class = "total_increasing";
}
### Installed capacity;
{
name = "mb_varta_capacity";
slave = 1;
address = 1071;
data_type = "uint16";
precision = 0;
scale = 10;
device_class = "energy";
unit_of_measurement = "Wh";
}
### Grid Power;
{
name = "mb_varta_grid_power";
slave = 1;
address = 1078;
data_type = "int16";
precision = 0;
scale = 1;
device_class = "power";
unit_of_measurement = "W";
}
### Active Power Exponent;
{
name = "mb_varta_active_power_exponent";
slave = 1;
address = 2066;
data_type = "int16";
device_class = "power";
}
### Apparent Power Exponent;
{
name = "mb_varta_apparent_power_exponent";
slave = 1;
address = 2067;
data_type = "int16";
device_class = "power";
}
### Enegrey Counter Exponent;
{
name = "mb_varta_energy_counter_exponent";
slave = 1;
address = 2069;
data_type = "int16";
device_class = "power";
}
### Capacity Counter Exponent;
{
name = "mb_varta_capacity_exponent";
slave = 1;
address = 2071;
data_type = "int16";
device_class = "power";
}
### Grid Power Exponent;
{
name = "mb_varta_grid_power_exponent";
slave = 1;
address = 2078;
data_type = "int16";
device_class = "power";
}
2025-01-10 16:36:07 +01:00
];
};
# Varta input/output
template.sensor = [
{
name = "Varta Input Power";
unit_of_measurement = "W";
state_class = "measurement";
device_class = "power";
state = ''
{% if states('sensor.mb_varta_active_power') | float(0) >= 0 %}
{% set varta_in = states('sensor.mb_varta_active_power') | float(0) %}
{% else %}
{% set varta_in = 0 %}
{% endif %}
{{ varta_in }}
'';
}
{
name = "Varta Output Power";
unit_of_measurement = "W";
state_class = "measurement";
device_class = "power";
state = ''
{% if states('sensor.mb_varta_active_power') | float(0) <= 0 %}
{% set varta_out = states('sensor.mb_varta_active_power') | float(0) *-1 %}
{% else %}
{% set varta_out = 0 %}
{% endif %}
{{ varta_out }}
'';
}
];
##Grid
sensor = {
platform = "template";
sensors = {
mb_varta_status = {
friendly_name = "Varta Status";
value_template = ''
{% set mapper = {
'0' : 'Busy',
'1' : 'Run',
'2' : 'Charge',
'3' : 'Discharge',
'4' : 'Standby',
'5' : 'Error',
'6' : 'Service',
'7' : 'Islanding' } %}
{% set state = states.sensor.mb_varta_state.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
'';
};
};
};
2025-01-04 23:25:48 +01:00
};
extraPackages =
python3Packages: with python3Packages; [
psycopg2
gtts
2025-01-07 21:23:06 +01:00
fritzconnection
adguardhome
2025-01-09 13:58:51 +01:00
aiosolaredge
zlib-ng
stringcase
hahomematic
pymodbus
2025-01-13 21:28:06 +01:00
hatasmota
2025-01-04 23:25:48 +01:00
];
};
2025-01-07 21:23:06 +01:00
networking.hosts = {
"${nodes.${globals.services.adguardhome.host}.config.wireguard.services.ipv4}" = [
"adguardhome.internal"
];
"${nodes.${globals.services.ollama.host}.config.wireguard.services.ipv4}" = [
"ollama.internal"
];
2025-01-07 21:23:06 +01:00
};
2025-01-05 22:27:49 +01:00
age.secrets."home-assistant-secrets.yaml" = {
2025-01-09 13:58:51 +01:00
rekeyFile = config.node.secretsDir + "/secrets.yaml.age";
2025-01-05 22:27:49 +01:00
owner = "hass";
};
2025-01-12 14:47:09 +01:00
systemd.services.home-assistant.preStart =
let
modules = [
(pkgs.fetchFromGitHub {
owner = "catppuccin";
repo = "home-assistant";
rev = "e877188ca467e7bbe8991440f6b5f6b3d30347fc";
hash = "sha256-eUqYlaXNLPfaKn3xcRm5AQwTOKf70JF8cepibBb9KXc=";
})
(pkgs.fetchFromGitHub {
owner = "flejz";
repo = "hass-cyberpunk-2077-theme";
rev = "78077ad6298a5bbbc8de4c72858b43cedebaae12";
hash = "sha256-gSlykxPBKji7hAX9E2L7dDtK3zNcRvRjCq2+apgMjFg=";
})
(pkgs.fetchFromGitHub {
owner = "Madelena";
repo = "Metrology-for-Hass";
rev = "3e858768d5afba3f83de0d3fe836336cb20f11ea";
hash = "sha256-IBKIB5KandpjWyVQYXuUvTL3gHHjTLr7saskkqq3A0w=";
})
2025-01-16 21:10:45 +01:00
(pkgs.fetchFromGitHub {
owner = "ricardoquecria";
repo = "caule-themes-pack-1";
rev = "0ec8a4b7acf63d8618bcf2fdd968d6256e998acb";
hash = "sha256-biNz3ZO3nFfEgchoPu9M3lXiTj9BDxkUaZiCNq0Jy8M=";
})
(pkgs.fetchFromGitHub {
owner = "TilmanGriesel";
repo = "graphite";
rev = "bce4342b9f2423a14a09af703f6d22f9660d764e";
hash = "sha256-ZniV5Sw00ml1AaPx7oQZ1oorj01TLamrZV/a2wS8jVg=";
})
(pkgs.fetchFromGitHub {
owner = "am80l";
repo = "sundown";
rev = "bdfa827a2d3e524dae9637724053bf19567bbe5b";
hash = "sha256-PpqufsjWukAM/gQpet/m+n2+nQQWGVeow6F4yXI+oG8=";
})
(pkgs.fetchFromGitHub {
owner = "bbbenji";
repo = "synthwave-hass";
rev = "332617a96c3325dd845f90ff79f2a1f995a5006b";
hash = "sha256-zi6VNhKUlqy4VAMMqGL09V6RdIKxikkkEPp3+GyYhmg=";
})
2025-01-12 14:47:09 +01:00
];
in
lib.mkBefore (
''
if [[ -e ${config.services.home-assistant.configDir}/secrets.yaml ]]; then
rm ${config.services.home-assistant.configDir}/secrets.yaml
fi
2025-01-05 22:27:49 +01:00
2025-01-12 14:47:09 +01:00
cat ${
config.age.secrets."home-assistant-secrets.yaml".path
} > ${config.services.home-assistant.configDir}/secrets.yaml
touch -a ${config.services.home-assistant.configDir}/{automations,scenes,scripts,manual}.yaml
mkdir -p ${config.services.home-assistant.configDir}/themes
''
+ lib.concatStringsSep "\n" (
lib.flip map modules (x: ''
for i in ${x}/themes/*; do
ln -fFns "$i" ${config.services.home-assistant.configDir}/themes/"$(basename "$i")"
done
for i in ${x}/www/*; do
ln -fFns "$i" ${config.services.home-assistant.configDir}/www/"$(basename "$i")"
done
'')
)
);
2025-01-05 22:27:49 +01:00
2025-01-04 23:25:48 +01:00
}