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