feat: home-assistant + tewi

This commit is contained in:
Kat Inskip 2022-09-16 23:23:58 -07:00
parent 57e48cd9a8
commit ec7571171b
Signed by: kat
GPG key ID: 465E64DECEA8CF0F
15 changed files with 322 additions and 113 deletions

7
nixos/gui/nextcloud.nix Normal file
View file

@ -0,0 +1,7 @@
{ config, ... }: {
services.gnome = {
gnome-keyring.enable = true;
};
security.pam.services.lightdm.enableGnomeKeyring = true;
programs.seahorse.enable = true;
}

View file

@ -1,10 +1,11 @@
{ config, lib, tf, pkgs, meta, ... }: with lib;
{
options.network = with lib; {
routeDefault = mkOption {
default = true;
type = types.bool;
{ config, lib, tf, pkgs, meta, ... }: with lib; let
in {
options = with lib; {
network = {
routeDefault = mkOption {
default = true;
type = types.bool;
};
};
};
@ -31,12 +32,29 @@
};
};
kw.secrets.variables.tailscale-authkey = {
path = "secrets/tailscale";
field = "password";
deploy.tf = {
variables.tailscale-apikey = {
value.shellCommand = "${meta.kw.secrets.command} secrets/tailscale -f api_key";
sensitive = true;
export = true;
};
providers.tailscale = {
inputs = {
api_key = tf.variables.tailscale-apikey.ref;
tailnet = "inskip.me";
};
};
variables.tailscale-authkey.export = true;
resources.tailnet_key = {
provider = "tailscale";
type = "tailnet_key";
inputs = {
reusable = false;
ephemeral = false;
preauthorized = true;
};
};
};
deploy.tf.variables.tailscale-authkey.export = true;
networking.firewall = {
trustedInterfaces = [ "tailscale0" ];
@ -71,7 +89,7 @@
fi
# otherwise authenticate with tailscale
${tailscale}/bin/tailscale up -authkey ${tf.variables.tailscale-authkey.get}
${tailscale}/bin/tailscale up -authkey ${tf.resources.tailnet_key.getAttr "key"}
'';
};
};

View file

@ -1,107 +1,83 @@
{ config, lib, ... }: {
{ config, lib, tf, ... }: {
kw.secrets.variables.ha-integration = {
path = "secrets/home-assistant";
field = "notes";
};
secrets.files.ha-integration = {
text = tf.variables.ha-integration.ref;
owner = "hass";
group = "hass";
};
systemd.services.home-assistant = {
preStart = lib.mkBefore ''
rm ${config.services.home-assistant.configDir}/integration.json
cp --no-preserve=mode ${config.secrets.files.ha-integration.path} ${config.services.home-assistant.configDir}/integration.json
'';
};
services.home-assistant = {
enable = true;
config = {
automation = "automations.yaml";
config = null;
counter = null;
device_tracker = null;
dhcp = null;
energy = null;
frontend = { themes = "themes"; };
google_assistant = null;
group = "groups.yaml";
history = null;
homeassistant = {
external_url = "https://home.gensokyo.zone";
packages = "packages";
default_config = {};
google_assistant = {
project_id = "gensokyo-5cfaf";
service_account = "!include integration.json";
};
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"
];
use_x_forwarded_for = true;
};
image = null;
input_boolean = null;
input_datetime = null;
input_number = null;
input_select = null;
input_text = null;
logbook = null;
homeassistant = {
name = "Gensokyo";
unit_system = "metric";
external_url = "https://home.gensokyo.zone";
};
logger = {
default = "info";
};
device_tracker = null;
map = null;
media_source = null;
mobile_app = null;
my = null;
person = null;
recorder = {
auto_purge = true;
commit_interval = 1;
exclude = {
domains = [
"automation"
"updater"
];
entities = [
"sun.sun"
"sensor.last_boot"
"sensor.date"
"sensor.time"
];
entity_globs = [
"sensor.weather_*"
"sensor.date_*"
];
event_types = [
"call_service"
];
};
purge_keep_days = 14;
db_url = "postgresql://@/hass";
};
homekit = {
name = "Tewi";
port = 21063;
ip_address = "10.1.1.38";
};
scene = "scenes.yaml";
script = "scripts.yaml";
ssdp = null;
stream = null;
sun = null;
switch = null;
system_health = null;
tag = null;
template = null;
timer = null;
tts = [{
platform = "google_translate";
service_name = "google_say";
}];
wake_on_lan = null;
webhook = null;
zeroconf = null;
zone = null;
};
extraPackages = python3Packages: with python3Packages; [
psycopg2
securetar
];
extraComponents = [
"zha"
"esphome"
"apple_tv"
"spotify"
"default_config"
"cast"
"plex"
"google"
"google_assistant"
"google_cloud"
"google_translate"
"homekit"
"mqtt"
"wake_on_lan"
"zeroconf"
"esphome"
"apple_tv"
"spotify"
"default_config"
"cast"
"plex"
"met"
"google"
"google_assistant"
"google_cloud"
"google_translate"
"homekit"
"mqtt"
"wake_on_lan"
"zeroconf"
];
};
}
}

View file

@ -4,12 +4,23 @@
field = "z2m";
};
kw.secrets.variables.hass-pass = {
path = "secrets/mosquitto";
field = "hass";
};
secrets.files.z2m-pass = {
text = tf.variables.z2m-pass.ref;
owner = "mosquitto";
group = "mosquitto";
};
secrets.files.hass-pass = {
text = tf.variables.hass-pass.ref;
owner = "mosquitto";
group = "mosquitto";
};
services.mosquitto = {
enable = true;
persistence = true;
@ -18,10 +29,16 @@
"pattern readwrite #"
];
users = {
hass = {
passwordFile = config.secrets.files.hass-pass.path;
acl = [
"readwrite #"
];
};
z2m = {
passwordFile = config.secrets.files.z2m-pass.path;
acl = [
"topic readwrite zigbee2mqtt/#"
"readwrite #"
];
};
};

View file

@ -0,0 +1,69 @@
{ config, lib, pkgs, tf, ... }:
with lib;
{
secrets.files.dns_creds = {
text = ''
RFC2136_NAMESERVER='${tf.variables.katdns-address.ref}'
RFC2136_TSIG_ALGORITHM='hmac-sha512.'
RFC2136_TSIG_KEY='${tf.variables.katdns-name.ref}'
RFC2136_TSIG_SECRET='${tf.variables.katdns-key.ref}'
'';
};
network.firewall = {
public.tcp.ports = [ 443 80 ];
private.tcp.ports = [ 443 80 ];
};
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
commonHttpConfig = ''
map $scheme $hsts_header {
https "max-age=31536000; includeSubdomains; preload";
}
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
#add_header X-Frame-Options DENY;
#add_header X-Content-Type-Options nosniff;
#add_header X-XSS-Protection "1; mode=block";
#proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
'';
clientMaxBodySize = "512m";
virtualHosts = {
"gensokyo.zone" = {
forceSSL = true;
enableACME = true;
locations."/" = {
root = pkgs.gensokyoZone;
};
};
"home.${config.network.dns.domain}" = {
forceSSL = true;
enableACME = true;
locations = {
"/" = {
proxyPass = "http://127.0.0.1:8123";
extraConfig = ''
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
'';
};
};
};
};
};
security.acme = {
defaults.email = config.network.dns.email;
#email = config.network.dns.email;
acceptTerms = true;
};
}

View file

@ -1,11 +1,13 @@
{ meta, config, lib, pkgs, modulesPath, ... }:
{
imports = [
imports = with meta; [
(modulesPath + "/installer/scan/not-detected.nix")
nixos.network
./home-assistant.nix
./zigbee2mqtt.nix
./mosquitto.nix
./postgres.nix
];
deploy.tf = {
@ -29,6 +31,9 @@
};
network = {
firewall = {
public.interfaces = lib.singleton "eno1";
};
addresses = {
private = {
enable = true;

View file

@ -0,0 +1,13 @@
{ config, pkgs, ... }: {
services.postgresql = {
enable = true;
package = pkgs.postgresql_14;
ensureDatabases = [ "hass" ];
ensureUsers = [{
name = "hass";
ensurePermissions = {
"DATABASE hass" = "ALL PRIVILEGES";
};
}];
};
}

View file

@ -6,8 +6,13 @@
log_level = "info";
network_key = "!secret network_key";
};
mqtt = {
server = "mqtt://127.0.0.1:1883";
user = "z2m";
password = tf.variables.z2m-mqtt-password.ref;
};
homeassistant = true;
permit_join = true;
permit_join = false;
frontend = {
port = 8072;
};
@ -18,6 +23,11 @@
};
};
kw.secrets.variables.z2m-mqtt-password = {
path = "secrets/mosquitto";
field = "z2m";
};
kw.secrets.variables.z2m-network-key = {
path = "secrets/zigbee2mqtt";
field = "password";
@ -40,6 +50,6 @@
cp --no-preserve=mode ${config.secrets.files.zigbee2mqtt-secret.path} "${cfg.dataDir}/secret.yaml"
'';
network.firewall.public.tcp.ports = [ 8123 8072 1883 ];
network.firewall.public.tcp.ports = [ 8123 8072 1883 21064 21063 ];
network.firewall.private.tcp.ports = [ 8123 ];
}