nixfiles/nixos/gensokyo/home-assistant.nix
2023-02-06 10:58:51 -08:00

429 lines
12 KiB
Nix
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ config, lib, tf, ... }: let
inherit (lib.attrsets) attrNames filterAttrs mapAttrs' nameValuePair;
inherit (lib.strings) hasPrefix;
in {
# MDNS
services.avahi.enable = true;
networking.firewall = {
allowedTCPPorts = [
8123 # Home Assistant
21036 # HomeKit
];
allowedUDPPorts = [
5353 # MDNS
];
allowedUDPPortRanges = [
{ from = 32768; to = 60999; } # Chromecast
];
};
networks.gensokyo = {
tcp = [
# Home Assistant
8123
# Tewi Homekit
21063
];
udp = [
# Chromecast
[ 32768 60999 ]
# MDNS
5353
];
};
secrets.variables.ha-integration = {
path = "gensokyo/home-assistant";
field = "notes";
};
secrets.files.ha-integration = {
text = tf.variables.ha-integration.ref;
owner = "hass";
group = "hass";
};
secrets.variables.latitude = {
path = "gensokyo/home-assistant";
field = "latitude";
};
secrets.variables.longitude = {
path = "gensokyo/home-assistant";
field = "longitude";
};
secrets.variables.elevation = {
path = "gensokyo/home-assistant";
field = "elevation";
};
secrets.variables.iphone-se-irk = {
path = "gensokyo/home-assistant";
field = "iphone-se-irk";
};
secrets.variables.companion-pixel6 = {
path = "gensokyo/home-assistant";
field = "companion-pixel6";
};
secrets.variables.tile-bee = {
path = "gensokyo/home-assistant";
field = "tile-bee";
};
secrets.variables.tile-kat-wallet = {
path = "gensokyo/home-assistant";
field = "tile-kat-wallet";
};
secrets.variables.tile-kat-keys = {
path = "gensokyo/home-assistant";
field = "tile-kat-keys";
};
secrets.variables.mpd-shanghai-password = {
path = "gensokyo/abby";
field = "mpd";
};
secrets.files.home-assistant-secrets = {
text = let
espresenceDevices = {
iphone-se-irk = tf.variables.iphone-se-irk.ref;
companion-pixel6 = tf.variables.companion-pixel6.ref;
tile-kat-wallet = tf.variables.tile-kat-wallet.ref;
tile-kat-keys = tf.variables.tile-kat-keys.ref;
tile-bee = tf.variables.tile-bee.ref;
};
in builtins.toJSON ({
latitude = tf.variables.latitude.ref;
longitude = tf.variables.longitude.ref;
elevation = tf.variables.elevation.ref;
mpd-shanghai-password = tf.variables.mpd-shanghai-password.ref;
} // espresenceDevices // mapAttrs' (key: device_id:
nameValuePair "${key}-topic" "espresense/devices/${device_id}"
) espresenceDevices);
owner = "hass";
group = "hass";
};
systemd.services.home-assistant = {
preStart = lib.mkBefore ''
cp --no-preserve=mode ${config.secrets.files.home-assistant-secrets.path} ${config.services.home-assistant.configDir}/secrets.yaml
cp --no-preserve=mode ${config.secrets.files.ha-integration.path} ${config.services.home-assistant.configDir}/integration.yaml
# UI-editable config files
touch ${config.services.home-assistant.configDir}/{automations,scenes,scripts,manual}.yaml
'';
};
services.home-assistant = {
enable = true;
config = {
homeassistant = {
name = "Gensokyo";
unit_system = "metric";
latitude = "!secret latitude";
longitude = "!secret longitude";
elevation = "!secret elevation";
currency = "CAD";
time_zone = "America/Vancouver";
external_url = "https://home.gensokyo.zone";
packages = {
manual = "!include manual.yaml";
};
};
frontend = {
themes = "!include_dir_merge_named themes";
};
powercalc = {
};
utility_meter = {
};
withings = {
use_webhook = true;
};
logger = {
default = "info";
};
http = {
cors_allowed_origins = [
"https://google.com"
"https://www.home-assistant.io"
];
use_x_forwarded_for = "true";
trusted_proxies = [
"127.0.0.0/24"
"200::/7"
"100.64.0.0/10"
"fd7a:115c:a1e0:ab12::/64"
];
};
recorder = {
db_url = "postgresql://@/hass";
auto_purge = true;
purge_keep_days = 14;
commit_interval = 1;
exclude = {
domains = [
"automation"
"updater"
];
entity_globs = [
"sensor.weather_*"
"sensor.date_*"
];
entities = [
"sun.sun"
"sensor.last_boot"
"sensor.date"
"sensor.time"
];
event_types = [
"call_service"
];
};
};
google_assistant = {
project_id = "gensokyo-5cfaf";
service_account = "!include integration.yaml";
report_state = true;
exposed_domains = [
"scene"
"script"
"climate"
#"sensor"
];
entity_config = let
hidden = "XYZ";
in {
# bedroom entities
"light.bedside_lamp".expose = true;
"light.bedroom_strip".expose = true;
"light.bedroom_overhead".expose = true;
"light.bed_side_overhead".room = hidden;
"light.closet_side_overhead".room = hidden;
"light.pc_side_overhead".room = hidden;
"light.closet_overhead".expose = true;
"light.closet_overhead_left".room = hidden;
"light.closet_overhead_right".room = hidden;
"fan.bedroom_purifier" = {
expose = true;
aliases = [
"FÖRNUFTIG"
"Bedroom Air Purifier"
];
};
"fan.bedroom_floor".expose = true;
"switch.swb1_relay_3".expose = true;
"switch.swb1_relay_4".expose = true;
# living room entities
"light.dining_overhead".expose = true;
"light.living_cluster".expose = true;
"light.living_overhead".room = hidden;
"light.tv_overhead".room = hidden;
"light.couch_overhead_left".room = hidden;
"light.couch_overhead_right".room = hidden;
"light.tv_bias" = {
room = hidden;
aliases = [
"Bias Lighting"
"TV Backlight"
];
};
"light.living_bookshelf".room = hidden;
# midea
"climate.living_ac".aliases = [
"AC"
"Midea"
];
"sensor.living_ac_outdoor_temperature".expose = false;
# kitchen
"light.kitchen_overhead".expose = true;
"light.kitchen_overhead_inner".room = hidden;
"light.kitchen_overhead_middle".room = hidden;
"light.kitchen_overhead_outer".room = hidden;
# balcony
"light.outdoor_strip".expose = true;
"light.lantern".expose = true;
# foyer
"light.entry_overhead".expose = true;
"light.entry_overhead_left".room = hidden;
"light.entry_overhead_right".room = hidden;
# shanghai systemd
"switch.shanghai_graphical".expose = true;
"switch.shanghai_mradio".expose = true;
"switch.shanghai_vm_goliath1650".expose = true;
"switch.shanghai_vm_goliath3080".expose = true;
"switch.shanghai_vm_hourai1650".expose = true;
"switch.shanghai_vm_hourai3080".expose = true;
"cover.shanghai_dpms" = {
expose = true;
aliases = [
"DPMS"
];
};
};
};
homekit = {
name = "Tewi";
port = 21063;
ip_address = "10.1.1.38";
filter = let
inherit (config.services.home-assistant.config) google_assistant;
entities = filterAttrs (_: entity: entity.expose or true) google_assistant.entity_config;
in {
include_domains = google_assistant.exposed_domains;
include_entities = attrNames (removeAttrs entities [
# HomeKit is able to group lights together, no need to use the google hack here
"light.living_cluster"
"light.bedroom_overhead"
"light.closet_overhead"
"light.kitchen_overhead"
"light.entry_overhead"
]);
};
entity_config = {
"switch.swb1_relay_3".type = "outlet";
"switch.swb1_relay_4".type = "outlet";
};
};
tts = [{
platform = "google_translate";
service_name = "google_say";
}];
# https://nixos.wiki/wiki/Home_Assistant#Combine_declarative_and_UI_defined_automations
"automation manual" = [ ];
"automation ui" = "!include automations.yaml";
# https://nixos.wiki/wiki/Home_Assistant#Combine_declarative_and_UI_defined_scenes
"scene manual" = [];
"scene ui" = "!include scenes.yaml";
"script manual" = [];
"script ui" = "!include scripts.yaml";
counter = {};
device_tracker = {};
energy = {};
group = {};
history = {};
image = {};
input_boolean = {};
input_button = {};
input_datetime = {};
input_number = {};
input_select = {};
input_text = {};
logbook = {};
schedule = {};
map = {};
media_source = {};
media_player = [
{
platform = "mpd";
name = "Shanghai MPD";
host = "10.1.1.32";
password = "!secret mpd-shanghai-password";
}
];
mobile_app = {};
my = {};
person = {};
ssdp = {};
switch = {};
stream = {};
sun = {};
system_health = {};
tag = {};
template = {};
tile = {};
timer = {};
webhook = {};
wake_on_lan = {};
zeroconf = {};
zone = {};
sensor = let
mkESPresenceBeacon = { device_id, ... }@args: {
platform = "mqtt_room";
state_topic = if hasPrefix "!secret" device_id
then "${device_id}-topic"
else "espresense/devices/${device_id}";
} // args;
in [
(mkESPresenceBeacon {
device_id = "!secret iphone-se-irk";
name = "iPhone SE";
timeout = 2;
away_timeout = 120;
})
(mkESPresenceBeacon {
device_id = "!secret companion-pixel6";
name = "Kat's Pixel 6";
timeout = 5;
away_timeout = 120;
})
(mkESPresenceBeacon {
device_id = "name:galaxy-watch-active";
name = "Galaxy Watch Active";
})
(mkESPresenceBeacon {
device_id = "3003c8383b6c";
name = "MT7922 BT";
})
(mkESPresenceBeacon {
device_id = "d8f8833681ba";
name = "AX210 BT";
})
(mkESPresenceBeacon {
device_id = "md:03ff:6";
name = "Kat's Smartwatch";
})
(mkESPresenceBeacon {
device_id = "!secret tile-bee";
name = "Bee";
})
(mkESPresenceBeacon {
device_id = "!secret tile-kat-wallet";
name = "Kat's Wallet";
})
(mkESPresenceBeacon {
device_id = "!secret tile-kat-keys";
name = "Girlwife";
})
];
};
extraPackages = python3Packages: with python3Packages; [
psycopg2
aiohomekit
securetar
getmac # for upnp integration
(aiogithubapi.overrideAttrs (_: { doInstallCheck = false; }))
];
extraComponents = [
"automation"
"scene"
"script"
"zha"
"esphome"
"apple_tv"
"spotify"
"default_config"
"brother"
"ipp"
"cast"
"plex"
"met"
"google"
"google_assistant"
"google_cloud"
"google_translate"
"homekit"
"mpd"
"mqtt"
"tile"
"wake_on_lan"
"withings"
"zeroconf"
];
};
}