at master 4.1 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.mkPackageOption pkgs "deconz" { }; 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 + " " 117 + (lib.escapeShellArgs cfg.extraArgs); 118 Restart = "on-failure"; 119 AmbientCapabilities = capabilities; 120 CapabilityBoundingSet = capabilities; 121 UMask = "0027"; 122 DynamicUser = true; 123 RuntimeDirectory = name; 124 RuntimeDirectoryMode = "0700"; 125 StateDirectory = name; 126 SuccessExitStatus = [ 143 ]; 127 WorkingDirectory = stateDir; 128 # For access to /dev/ttyACM0 (ConBee). 129 SupplementaryGroups = [ "dialout" ]; 130 ProtectHome = true; 131 }; 132 }; 133 }; 134}