From d4d6c7a830c7cd0b005d76f841bc07f0a878ddd3 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 27 May 2025 15:10:20 +0200 Subject: [PATCH] Add esphome module --- hosts/aluminium/services/esphome/default.nix | 59 +++-------- hosts/aluminium/services/esphome/devices/.env | 2 + .../services/esphome/devices/.gitignore | 5 + .../services/esphome/devices/justfile | 1 + hosts/iron/services/esphome/default.nix | 91 ++-------------- hosts/iron/services/esphome/devices/.env | 2 +- hosts/iron/services/esphome/devices/justfile | 18 +--- modules/default.nix | 1 + modules/esphome/default.nix | 100 ++++++++++++++++++ modules/esphome/devices/justfile | 17 +++ 10 files changed, 154 insertions(+), 142 deletions(-) create mode 100644 hosts/aluminium/services/esphome/devices/.env create mode 100644 hosts/aluminium/services/esphome/devices/.gitignore create mode 120000 hosts/aluminium/services/esphome/devices/justfile mode change 100644 => 120000 hosts/iron/services/esphome/devices/justfile create mode 100644 modules/esphome/default.nix create mode 100644 modules/esphome/devices/justfile diff --git a/hosts/aluminium/services/esphome/default.nix b/hosts/aluminium/services/esphome/default.nix index 14d791a..1f4c754 100644 --- a/hosts/aluminium/services/esphome/default.nix +++ b/hosts/aluminium/services/esphome/default.nix @@ -1,57 +1,28 @@ -{ lib, pkgs, config, ... }: +{ pkgs +, config +, ... +}: let inherit (config.networking) ports; - cfgdir = pkgs.stdenvNoCC.mkDerivation { - name = "esphome-config"; - src = ./devices; - dontBuild = true; - installPhase = '' - mkdir $out - cp -r * $out - ''; - }; in { sops.secrets.esphome = { sopsFile = ../../secrets.yaml; + restartUnits = [ config.systemd.services.esphome.name ]; }; - services.esphome = { + jalr.esphome = { enable = true; - address = "127.0.0.1"; port = ports.esphome.tcp; - package = pkgs.esphome; - }; - - systemd.services.esphome = { - environment = { - "PLATFORMIO_CORE_DIR" = lib.mkForce "/tmp/.platformio"; - }; - serviceConfig = { - BindPaths = [ - "/var/lib/esphome" - "/var/lib/private/esphome" - ]; - BindReadOnlyPaths = [ - "/nix/store" - "${cfgdir}" - ]; - DeviceAllow = [ - "char-ttyACM rw" - "char-ttyAMA rw" - "char-ttyUSB rw" - ]; - ExecStartPre = [ - "${pkgs.rsync}/bin/rsync -a --delete --exclude=.esphome --exclude=.platformio --exclude=.gitignore '${cfgdir}/' '/var/lib/esphome/'" - "${pkgs.coreutils}/bin/ln -snf '%d/secrets.yaml' '/var/lib/esphome/secrets.yaml'" - ]; - LoadCredential = "secrets.yaml:${config.sops.secrets.esphome.path}"; - PrivateTmp = true; - RootDirectory = "/run/esphome"; - RuntimeDirectory = "esphome"; - StateDirectory = "esphome"; - SupplementaryGroups = [ "dialout" ]; - WorkingDirectory = lib.mkForce "/tmp"; + secretsFile = config.sops.secrets.esphome.path; + configDir = pkgs.stdenvNoCC.mkDerivation { + name = "esphome-config"; + src = ./devices; + dontBuild = true; + installPhase = '' + mkdir $out + cp -r * $out + ''; }; }; } diff --git a/hosts/aluminium/services/esphome/devices/.env b/hosts/aluminium/services/esphome/devices/.env new file mode 100644 index 0000000..640bd9c --- /dev/null +++ b/hosts/aluminium/services/esphome/devices/.env @@ -0,0 +1,2 @@ +ESPHOME_HOST="jalr-k.duckdns.org" +ESPHOME_SECRETS_FILE="esphome_${ESPHOME_HOST}_secrets.yaml" diff --git a/hosts/aluminium/services/esphome/devices/.gitignore b/hosts/aluminium/services/esphome/devices/.gitignore new file mode 100644 index 0000000..d8b4157 --- /dev/null +++ b/hosts/aluminium/services/esphome/devices/.gitignore @@ -0,0 +1,5 @@ +# Gitignore settings for ESPHome +# This is an example and may include too much for your use-case. +# You can modify this file to suit your needs. +/.esphome/ +/secrets.yaml diff --git a/hosts/aluminium/services/esphome/devices/justfile b/hosts/aluminium/services/esphome/devices/justfile new file mode 120000 index 0000000..68d1c45 --- /dev/null +++ b/hosts/aluminium/services/esphome/devices/justfile @@ -0,0 +1 @@ +../../../../../modules/esphome/devices/justfile \ No newline at end of file diff --git a/hosts/iron/services/esphome/default.nix b/hosts/iron/services/esphome/default.nix index 8e6ce2b..1f4c754 100644 --- a/hosts/iron/services/esphome/default.nix +++ b/hosts/iron/services/esphome/default.nix @@ -1,24 +1,9 @@ -{ lib -, pkgs +{ pkgs , config , ... }: let inherit (config.networking) ports; - cfgdir = pkgs.stdenvNoCC.mkDerivation { - name = "esphome-config"; - src = ./devices; - dontBuild = true; - installPhase = '' - mkdir $out - cp -r * $out - ''; - }; - cfg = config.services.esphome; - esphomeParams = - if cfg.enableUnixSocket - then "--socket /run/esphome/esphome.sock" - else "--address ${cfg.address} --port ${toString cfg.port}"; in { sops.secrets.esphome = { @@ -26,72 +11,18 @@ in restartUnits = [ config.systemd.services.esphome.name ]; }; - services.esphome = { + jalr.esphome = { enable = true; - address = "127.0.0.1"; port = ports.esphome.tcp; - package = pkgs.esphome; - }; - - systemd.services.esphome = { - environment = { - "PLATFORMIO_CORE_DIR" = lib.mkForce "/var/cache/esphome/.platformio"; - }; - serviceConfig = { - BindReadOnlyPaths = [ - "/nix/store" - "%d/secrets.yaml:/run/esphome/config/secrets.yaml" - "/etc/resolv.conf" - "/etc/ssl" - "/etc/static/ssl" - ]; - TemporaryFileSystem = [ - "/var/lib" - ]; - ExecPaths = [ - "-+/var/cache/esphome/.platformio/packages/" - ]; - DeviceAllow = [ - "char-ttyACM rw" - "char-ttyAMA rw" - "char-ttyUSB rw" - ]; - ExecStartPre = [ - (pkgs.writeShellScript "esphome-exec-start-pre" '' - if ! [ -d "$CACHE_DIRECTORY/.platformio/packages" ]; then - mkdir -p "$CACHE_DIRECTORY/.platformio/packages" - exit 1 - fi - mkdir -p "$CACHE_DIRECTORY/.esphome" - for linked in \ - .esphome \ - .gitignore - do - ln -s "$CACHE_DIRECTORY/$linked" "/run/esphome/config/$linked" - done - ${pkgs.rsync}/bin/rsync \ - -a \ - --delete \ - --checksum \ - --exclude secrets.yaml \ - --exclude=.esphome \ - --exclude=.platformio \ - --exclude=.gitignore \ - '${cfgdir}/' /run/esphome/config/ - '') - ]; - ExecStart = lib.mkForce "${cfg.package}/bin/esphome dashboard ${esphomeParams} /run/esphome/config"; - LoadCredential = "secrets.yaml:${config.sops.secrets.esphome.path}"; - PrivateTmp = true; - RootDirectory = "%t/esphome/chroot"; - RuntimeDirectory = [ - "esphome/chroot" - "esphome/config" - ]; - StateDirectory = lib.mkForce [ ]; - CacheDirectory = "esphome"; - SupplementaryGroups = [ "dialout" ]; - WorkingDirectory = lib.mkForce "/run/esphome/config"; + secretsFile = config.sops.secrets.esphome.path; + configDir = pkgs.stdenvNoCC.mkDerivation { + name = "esphome-config"; + src = ./devices; + dontBuild = true; + installPhase = '' + mkdir $out + cp -r * $out + ''; }; }; } diff --git a/hosts/iron/services/esphome/devices/.env b/hosts/iron/services/esphome/devices/.env index 2eee41c..10c24e2 100644 --- a/hosts/iron/services/esphome/devices/.env +++ b/hosts/iron/services/esphome/devices/.env @@ -1,2 +1,2 @@ -ESPHOME_HOST="192.168.42.1" +ESPHOME_HOST="jalr-bw.duckdns.org" ESPHOME_SECRETS_FILE="esphome_${ESPHOME_HOST}_secrets.yaml" diff --git a/hosts/iron/services/esphome/devices/justfile b/hosts/iron/services/esphome/devices/justfile deleted file mode 100644 index fb628ca..0000000 --- a/hosts/iron/services/esphome/devices/justfile +++ /dev/null @@ -1,17 +0,0 @@ -import '../../../../../justfile' -set dotenv-load - -download: - rsync \ - -r \ - --rsync-path='sudo rsync' \ - --exclude '/build' \ - --exclude '/.esphome' \ - --exclude '.gitignore' \ - --exclude 'secrets.yaml' \ - 192.168.42.1:/var/lib/esphome/ ./ - -download-secrets: - umask 0077 && ssh 192.168.42.1 sudo cat /run/secrets/esphome > "/dev/shm/${ESPHOME_SECRETS_FILE}" - ln -sf "/dev/shm/${ESPHOME_SECRETS_FILE}" "{{justfile_directory()}}/secrets.yaml" - diff --git a/hosts/iron/services/esphome/devices/justfile b/hosts/iron/services/esphome/devices/justfile new file mode 120000 index 0000000..68d1c45 --- /dev/null +++ b/hosts/iron/services/esphome/devices/justfile @@ -0,0 +1 @@ +../../../../../modules/esphome/devices/justfile \ No newline at end of file diff --git a/modules/default.nix b/modules/default.nix index ff6f458..80aac79 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -24,6 +24,7 @@ ./debug.nix ./dji-goggles.nix ./dns.nix + ./esphome ./fish.nix ./fonts.nix ./gnome.nix diff --git a/modules/esphome/default.nix b/modules/esphome/default.nix new file mode 100644 index 0000000..9bf4609 --- /dev/null +++ b/modules/esphome/default.nix @@ -0,0 +1,100 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.jalr.esphome; + esphomeParams = + if config.services.esphome.enableUnixSocket + then "--socket /run/esphome/esphome.sock" + else "--address ${config.services.esphome.address} --port ${toString config.services.esphome.port}"; +in +{ + options.jalr.esphome = with lib; with lib.types; { + enable = mkEnableOption "ESPHome"; + port = mkOption { + description = "TCP port for esphome dashboard."; + type = port; + }; + configDir = mkOption { + type = path; + description = "Location of the device configuration"; + }; + secretsFile = mkOption { + type = path; + description = "Location of the secrets file"; + }; + }; + + config = lib.mkIf cfg.enable { + services.esphome = { + enable = true; + address = "127.0.0.1"; + inherit (cfg) port; + package = pkgs.esphome; + }; + + systemd.services.esphome = { + environment = { + "PLATFORMIO_CORE_DIR" = lib.mkForce "/var/cache/esphome/.platformio"; + }; + serviceConfig = { + BindReadOnlyPaths = [ + "/nix/store" + "%d/secrets.yaml:/run/esphome/config/secrets.yaml" + "/etc/resolv.conf" + "/etc/ssl" + "/etc/static/ssl" + ]; + TemporaryFileSystem = [ + "/var/lib" + ]; + ExecPaths = [ + "-+/var/cache/esphome/.platformio/packages/" + ]; + DeviceAllow = [ + "char-ttyACM rw" + "char-ttyAMA rw" + "char-ttyUSB rw" + ]; + ExecStartPre = [ + (pkgs.writeShellScript "esphome-exec-start-pre" '' + if ! [ -d "$CACHE_DIRECTORY/.platformio/packages" ]; then + mkdir -p "$CACHE_DIRECTORY/.platformio/packages" + exit 1 + fi + mkdir -p "$CACHE_DIRECTORY/.esphome" + for linked in \ + .esphome \ + .gitignore + do + ln -s "$CACHE_DIRECTORY/$linked" "/run/esphome/config/$linked" + done + ${pkgs.rsync}/bin/rsync \ + -a \ + --delete \ + --checksum \ + --exclude secrets.yaml \ + --exclude=.esphome \ + --exclude=.platformio \ + --exclude=.gitignore \ + '${cfg.configDir}/' /run/esphome/config/ + '') + ]; + ExecStart = lib.mkForce "${config.services.esphome.package}/bin/esphome dashboard ${esphomeParams} /run/esphome/config"; + LoadCredential = "secrets.yaml:${cfg.secretsFile}"; + PrivateTmp = true; + RootDirectory = "%t/esphome/chroot"; + RuntimeDirectory = [ + "esphome/chroot" + "esphome/config" + ]; + StateDirectory = lib.mkForce [ ]; + CacheDirectory = "esphome"; + SupplementaryGroups = [ "dialout" ]; + WorkingDirectory = lib.mkForce "/run/esphome/config"; + }; + }; + }; +} diff --git a/modules/esphome/devices/justfile b/modules/esphome/devices/justfile new file mode 100644 index 0000000..2c86b69 --- /dev/null +++ b/modules/esphome/devices/justfile @@ -0,0 +1,17 @@ +import '../../../../../justfile' +set dotenv-load + +download: + rsync \ + -r \ + --rsync-path='sudo rsync' \ + --exclude '/build' \ + --exclude '/.esphome' \ + --exclude '.gitignore' \ + --exclude 'secrets.yaml' \ + ${ESPHOME_HOST}:/var/lib/esphome/ ./ + +download-secrets: + umask 0077 && ssh ${ESPHOME_HOST} sudo cat /run/secrets/esphome > "/dev/shm/${ESPHOME_SECRETS_FILE}" + ln -sf "/dev/shm/${ESPHOME_SECRETS_FILE}" "{{justfile_directory()}}/secrets.yaml" +