at 24.11-pre 4.2 kB view raw
1{ config, lib, pkgs, ... }: 2 3let 4 cfg = config.services.deconz; 5 name = "deconz"; 6 stateDir = "/var/lib/${name}"; 7 # ref. upstream deconz.service 8 capabilities = 9 lib.optionals (cfg.httpPort < 1024 || cfg.wsPort < 1024) [ "CAP_NET_BIND_SERVICE" ] 10 ++ lib.optionals (cfg.allowRebootSystem) [ "CAP_SYS_BOOT" ] 11 ++ lib.optionals (cfg.allowRestartService) [ "CAP_KILL" ] 12 ++ lib.optionals (cfg.allowSetSystemTime) [ "CAP_SYS_TIME" ]; 13in 14{ 15 options.services.deconz = { 16 17 enable = lib.mkEnableOption "deCONZ, a Zigbee gateway for use with ConBee hardware (https://phoscon.de/en/conbee2)"; 18 19 package = lib.mkOption { 20 type = lib.types.package; 21 default = pkgs.deconz; 22 defaultText = lib.literalExpression "pkgs.deconz"; 23 description = "Which deCONZ package to use."; 24 }; 25 26 device = lib.mkOption { 27 type = lib.types.nullOr lib.types.str; 28 default = null; 29 description = '' 30 Force deCONZ to use a specific USB device (e.g. /dev/ttyACM0). By 31 default it does a search. 32 ''; 33 }; 34 35 listenAddress = lib.mkOption { 36 type = lib.types.str; 37 default = "127.0.0.1"; 38 description = '' 39 Pin deCONZ to the network interface specified through the provided IP 40 address. This applies for the webserver as well as the websocket 41 notifications. 42 ''; 43 }; 44 45 httpPort = lib.mkOption { 46 type = lib.types.port; 47 default = 80; 48 description = "TCP port for the web server."; 49 }; 50 51 wsPort = lib.mkOption { 52 type = lib.types.port; 53 default = 443; 54 description = "TCP port for the WebSocket."; 55 }; 56 57 openFirewall = lib.mkEnableOption "opening up the service ports in the firewall"; 58 59 allowRebootSystem = lib.mkEnableOption "rebooting the system"; 60 61 allowRestartService = lib.mkEnableOption "killing/restarting processes"; 62 63 allowSetSystemTime = lib.mkEnableOption "setting the system time"; 64 65 extraArgs = lib.mkOption { 66 type = lib.types.listOf lib.types.str; 67 default = [ ]; 68 example = [ 69 "--dbg-info=1" 70 "--dbg-err=2" 71 ]; 72 description = '' 73 Extra command line arguments for deCONZ, see 74 https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/deCONZ-command-line-parameters. 75 ''; 76 }; 77 }; 78 79 config = lib.mkIf cfg.enable { 80 81 networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 82 cfg.httpPort 83 cfg.wsPort 84 ]; 85 86 services.udev.packages = [ cfg.package ]; 87 88 systemd.services.deconz = { 89 description = "deCONZ Zigbee gateway"; 90 wantedBy = [ "multi-user.target" ]; 91 preStart = '' 92 # The service puts a nix store path reference in here, and that path can 93 # be garbage collected. Ensure the file gets "refreshed" on every start. 94 rm -f ${stateDir}/.local/share/dresden-elektronik/deCONZ/zcldb.txt 95 ''; 96 postStart = '' 97 # Delay signalling service readiness until it's actually up. 98 while ! "${lib.getExe pkgs.curl}" -sSfL -o /dev/null "http://${cfg.listenAddress}:${toString cfg.httpPort}"; do 99 echo "Waiting for TCP port ${toString cfg.httpPort} to be open..." 100 sleep 1 101 done 102 ''; 103 environment = { 104 HOME = stateDir; 105 XDG_RUNTIME_DIR = "/run/${name}"; 106 }; 107 serviceConfig = { 108 ExecStart = 109 "${lib.getExe cfg.package}" 110 + " -platform minimal" 111 + " --http-listen=${cfg.listenAddress}" 112 + " --http-port=${toString cfg.httpPort}" 113 + " --ws-port=${toString cfg.wsPort}" 114 + " --auto-connect=1" 115 + (lib.optionalString (cfg.device != null) " --dev=${cfg.device}") 116 + " " + (lib.escapeShellArgs cfg.extraArgs); 117 Restart = "on-failure"; 118 AmbientCapabilities = capabilities; 119 CapabilityBoundingSet = capabilities; 120 UMask = "0027"; 121 DynamicUser = true; 122 RuntimeDirectory = name; 123 RuntimeDirectoryMode = "0700"; 124 StateDirectory = name; 125 WorkingDirectory = stateDir; 126 # For access to /dev/ttyACM0 (ConBee). 127 SupplementaryGroups = [ "dialout" ]; 128 ProtectHome = true; 129 }; 130 }; 131 }; 132}