python312Packages.dissect-extfs: 3.11 -> 3.12
[NixPkgs.git] / nixos / modules / services / home-automation / ebusd.nix
blob97d1e2796adab7a48e71ee0f7a333507aad6ff28
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.ebusd;
7 in
9   meta.maintainers = with maintainers; [ nathan-gs ];
11   options.services.ebusd = {
12     enable = mkEnableOption "ebusd, a daemon for communication with eBUS heating systems";
14     package = mkPackageOption pkgs "ebusd" { };
16     device = mkOption {
17       type = types.str;
18       default = "";
19       example = "IP:PORT";
20       description = ''
21         Use DEV as eBUS device [/dev/ttyUSB0].
22         This can be either:
23           enh:DEVICE or enh:IP:PORT for enhanced device (only adapter v3 and newer),
24           ens:DEVICE for enhanced high speed serial device (only adapter v3 and newer with firmware since 20220731),
25           DEVICE for serial device (normal speed, for all other serial adapters like adapter v2 as well as adapter v3 in non-enhanced mode), or
26           [udp:]IP:PORT for network device.
28         Source: <https://github.com/john30/ebusd/wiki/2.-Run#device-options>
29       '';
30     };
32     port = mkOption {
33       default = 8888;
34       type = types.port;
35       description = ''
36         The port on which to listen on
37       '';
38     };
40     readonly = mkOption {
41       type = types.bool;
42       default = false;
43       description = ''
44          Only read from device, never write to it
45       '';
46     };
48     configpath = mkOption {
49       type = types.str;
50       default = "https://cfg.ebusd.eu/";
51       description = ''
52         Directory to read CSV config files from. This can be a local folder or a URL.
53       '';
54     };
56     scanconfig = mkOption {
57       type = types.str;
58       default = "full";
59       description = ''
60         Pick CSV config files matching initial scan ("none" or empty for no initial scan message, "full" for full scan, or a single hex address to scan, default is to send a broadcast ident message).
61         If combined with --checkconfig, you can add scan message data as arguments for checking a particular scan configuration, e.g. "FF08070400/0AB5454850303003277201". For further details on this option,
62         see [Automatic configuration](https://github.com/john30/ebusd/wiki/4.7.-Automatic-configuration).
63       '';
64     };
66     logs = let
67       # "all" must come first so it can be overridden by more specific areas
68       areas = [ "all" "main" "network" "bus" "update" "other" ];
69       levels = [ "none" "error" "notice" "info" "debug" ];
70     in listToAttrs (map (area: nameValuePair area (mkOption {
71       type = types.enum levels;
72       default = "notice";
73       example = "debug";
74       description = ''
75         Only write log for matching `AREA`s (${concatStringsSep "|" areas}) below or equal to `LEVEL` (${concatStringsSep "|" levels})
76       '';
77     })) areas);
79     mqtt = {
80       enable = mkEnableOption "support for MQTT";
82       host = mkOption {
83         type = types.str;
84         default = "localhost";
85         description = ''
86           Connect to MQTT broker on HOST.
87         '';
88       };
90       port = mkOption {
91         default = 1883;
92         type = types.port;
93         description = ''
94           The port on which to connect to MQTT
95         '';
96       };
98       home-assistant = mkOption {
99         type = types.bool;
100         default = false;
101         description = ''
102           Adds the Home Assistant topics to MQTT, read more at [MQTT Integration](https://github.com/john30/ebusd/wiki/MQTT-integration)
103         '';
104       };
106       retain = mkEnableOption "set the retain flag on all topics instead of only selected global ones";
108       user = mkOption {
109         type = types.str;
110         description = ''
111           The MQTT user to use
112         '';
113       };
115       password = mkOption {
116         type = types.str;
117         description = ''
118           The MQTT password.
119         '';
120       };
121     };
123     extraArguments = mkOption {
124       type = types.listOf types.str;
125       default = [];
126       description = ''
127         Extra arguments to the ebus daemon
128       '';
129     };
130   };
132   config = let
133     usesDev = hasPrefix "/" cfg.device;
134   in mkIf cfg.enable {
135     systemd.services.ebusd = {
136       description = "EBUSd Service";
137       wantedBy = [ "multi-user.target" ];
138       after = [ "network.target" ];
139       serviceConfig = {
140         ExecStart = let
141           args = cli.toGNUCommandLineShell { optionValueSeparator = "="; } (foldr (a: b: a // b) { } [
142             {
143               inherit (cfg) device port configpath scanconfig readonly;
144               foreground = true;
145               updatecheck = "off";
146               log = mapAttrsToList (name: value: "${name}:${value}") cfg.logs;
147               mqttretain = cfg.mqtt.retain;
148             }
149             (optionalAttrs cfg.mqtt.enable {
150               mqtthost  = cfg.mqtt.host;
151               mqttport  = cfg.mqtt.port;
152               mqttuser  = cfg.mqtt.user;
153               mqttpass  = cfg.mqtt.password;
154             })
155             (optionalAttrs cfg.mqtt.home-assistant {
156               mqttint = "${cfg.package}/etc/ebusd/mqtt-hassio.cfg";
157               mqttjson = true;
158             })
159           ]);
160         in "${cfg.package}/bin/ebusd ${args} ${escapeShellArgs cfg.extraArguments}";
162         DynamicUser = true;
163         Restart = "on-failure";
165         # Hardening
166         CapabilityBoundingSet = "";
167         DeviceAllow = optionals usesDev [ cfg.device ];
168         DevicePolicy = "closed";
169         LockPersonality = true;
170         MemoryDenyWriteExecute = false;
171         NoNewPrivileges = true;
172         PrivateDevices = usesDev;
173         PrivateUsers = true;
174         PrivateTmp = true;
175         ProtectClock = true;
176         ProtectControlGroups = true;
177         ProtectHome = true;
178         ProtectHostname = true;
179         ProtectKernelLogs = true;
180         ProtectKernelModules = true;
181         ProtectKernelTunables = true;
182         ProtectProc = "invisible";
183         ProcSubset = "pid";
184         ProtectSystem = "strict";
185         RemoveIPC = true;
186         RestrictAddressFamilies = [
187           "AF_INET"
188           "AF_INET6"
189         ];
190         RestrictNamespaces = true;
191         RestrictRealtime = true;
192         RestrictSUIDSGID = true;
193         SupplementaryGroups = [ "dialout" ];
194         SystemCallArchitectures = "native";
195         SystemCallFilter = [
196           "@system-service @pkey"
197           "~@privileged @resources"
198         ];
199         UMask = "0077";
200       };
201     };
202   };