1 {config, pkgs, lib, ...}:
6 cfg = config.services.zwave-js;
7 mergedConfigFile = "/run/zwave-js/config.json";
8 settingsFormat = pkgs.formats.json {};
10 options.services.zwave-js = {
11 enable = mkEnableOption (mdDoc "the zwave-js server on boot");
13 package = mkPackageOptionMD pkgs "zwave-js-server" { };
18 description = mdDoc ''
19 Port for the server to listen on.
23 serialPort = mkOption {
25 description = mdDoc ''
26 Serial port device path for Z-Wave controller.
28 example = "/dev/ttyUSB0";
31 secretsConfigFile = mkOption {
33 description = mdDoc ''
34 JSON file containing secret keys. A dummy example:
39 "S0_Legacy": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
40 "S2_Unauthenticated": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
41 "S2_Authenticated": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
42 "S2_AccessControl": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
48 <https://zwave-js.github.io/node-zwave-js/#/getting-started/security-s2>
49 for details. This file will be merged with the module-generated config
50 file (taking precedence).
52 Z-Wave keys can be generated with:
54 {command}`< /dev/urandom tr -dc A-F0-9 | head -c32 ;echo`
58 A file in the nix store should not be used since it will be readable to
62 example = "/secrets/zwave-js-keys.json";
66 type = lib.types.submodule {
67 freeformType = settingsFormat.type;
73 default = "/var/cache/zwave-js";
75 description = lib.mdDoc "Cache directory";
81 description = mdDoc ''
82 Configuration settings for the generated config
87 extraFlags = lib.mkOption {
88 type = with lib.types; listOf str;
90 example = [ "--mock-driver" ];
91 description = lib.mdDoc ''
92 Extra flags to pass to command
97 config = mkIf cfg.enable {
98 systemd.services.zwave-js = let
99 configFile = settingsFormat.generate "zwave-js-config.json" cfg.settings;
101 wantedBy = [ "multi-user.target" ];
102 after = [ "network.target" ];
103 description = "Z-Wave JS Server";
106 /bin/sh -c "${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${configFile} ${cfg.secretsConfigFile} > ${mergedConfigFile}"
108 ExecStart = lib.concatStringsSep " " [
109 "${cfg.package}/bin/zwave-server"
110 "--config ${mergedConfigFile}"
111 "--port ${toString cfg.port}"
113 (escapeShellArgs cfg.extraFlags)
115 Restart = "on-failure";
117 SupplementaryGroups = [ "dialout" ];
118 CacheDirectory = "zwave-js";
119 RuntimeDirectory = "zwave-js";
122 CapabilityBoundingSet = "";
123 DeviceAllow = [cfg.serialPort];
124 DevicePolicy = "closed";
126 LockPersonality = true;
127 MemoryDenyWriteExecute = false;
128 NoNewPrivileges = true;
132 ProtectControlGroups = true;
134 ProtectHostname = true;
135 ProtectKernelLogs = true;
136 ProtectKernelModules = true;
138 RestrictNamespaces = true;
139 RestrictRealtime = true;
140 RestrictSUIDSGID = true;
141 SystemCallArchitectures = "native";
143 "@system-service @pkey"
144 "~@privileged @resources"
151 meta.maintainers = with lib.maintainers; [ graham33 ];