From 4164383dd4f63c5725f099e618665fe0130b49ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Forsman?= Date: Sun, 17 Sep 2023 20:03:50 +0200 Subject: [PATCH] nixos/deconz: init Add a NixOS module for the deCONZ Zigbee gateway service. --- nixos/modules/module-list.nix | 1 + nixos/modules/services/networking/deconz.nix | 125 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 nixos/modules/services/networking/deconz.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 9b347527ab01..f7549a6a0b0f 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -882,6 +882,7 @@ ./services/networking/croc.nix ./services/networking/dae.nix ./services/networking/dante.nix + ./services/networking/deconz.nix ./services/networking/dhcpcd.nix ./services/networking/dnscache.nix ./services/networking/dnscrypt-proxy2.nix diff --git a/nixos/modules/services/networking/deconz.nix b/nixos/modules/services/networking/deconz.nix new file mode 100644 index 000000000000..1fe103733212 --- /dev/null +++ b/nixos/modules/services/networking/deconz.nix @@ -0,0 +1,125 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.deconz; + name = "deconz"; + stateDir = "/var/lib/${name}"; + # ref. upstream deconz.service + capabilities = + lib.optionals (cfg.httpPort < 1024 || cfg.wsPort < 1024) [ "CAP_NET_BIND_SERVICE" ] + ++ lib.optionals (cfg.allowRebootSystem) [ "CAP_SYS_BOOT" ] + ++ lib.optionals (cfg.allowRestartService) [ "CAP_KILL" ] + ++ lib.optionals (cfg.allowSetSystemTime) [ "CAP_SYS_TIME" ]; +in +{ + options.services.deconz = { + + enable = lib.mkEnableOption "deCONZ, a Zigbee gateway for use with ConBee hardware (https://phoscon.de/en/conbee2)"; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.deconz; + defaultText = lib.literalExpression "pkgs.deconz"; + description = "Which deCONZ package to use."; + }; + + device = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + Force deCONZ to use a specific USB device (e.g. /dev/ttyACM0). By + default it does a search. + ''; + }; + + listenAddress = lib.mkOption { + type = lib.types.str; + default = "127.0.0.1"; + description = '' + Pin deCONZ to the network interface specified through the provided IP + address. This applies for the webserver as well as the websocket + notifications. + ''; + }; + + httpPort = lib.mkOption { + type = lib.types.port; + default = 80; + description = "TCP port for the web server."; + }; + + wsPort = lib.mkOption { + type = lib.types.port; + default = 443; + description = "TCP port for the WebSocket."; + }; + + openFirewall = lib.mkEnableOption "open up the service ports in the firewall"; + + allowRebootSystem = lib.mkEnableOption "allow rebooting the system"; + + allowRestartService = lib.mkEnableOption "allow killing/restarting processes"; + + allowSetSystemTime = lib.mkEnableOption "allow setting the system time"; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ + "--dbg-info=1" + "--dbg-err=2" + ]; + description = '' + Extra command line arguments for deCONZ, see + https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/deCONZ-command-line-parameters. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ + cfg.httpPort + cfg.wsPort + ]; + + services.udev.packages = [ cfg.package ]; + + systemd.services.deconz = { + description = "deCONZ Zigbee gateway"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + # The service puts a nix store path reference in here, and that path can + # be garbage collected. Ensure the file gets "refreshed" on every start. + rm -f ${stateDir}/.local/share/dresden-elektronik/deCONZ/zcldb.txt + ''; + environment = { + HOME = stateDir; + XDG_RUNTIME_DIR = "/run/${name}"; + }; + serviceConfig = { + ExecStart = + "${lib.getExe cfg.package}" + + " -platform minimal" + + " --http-listen=${cfg.listenAddress}" + + " --http-port=${toString cfg.httpPort}" + + " --ws-port=${toString cfg.wsPort}" + + " --auto-connect=1" + + (lib.optionalString (cfg.device != null) " --dev=${cfg.device}") + + " " + (lib.escapeShellArgs cfg.extraArgs); + Restart = "on-failure"; + AmbientCapabilities = capabilities; + CapabilityBoundingSet = capabilities; + UMask = "0027"; + DynamicUser = true; + RuntimeDirectory = name; + RuntimeDirectoryMode = "0700"; + StateDirectory = name; + WorkingDirectory = stateDir; + # For access to /dev/ttyACM0 (ConBee). + SupplementaryGroups = [ "dialout" ]; + ProtectHome = true; + }; + }; + }; +}