nixos/preload: init
[NixPkgs.git] / nixos / modules / services / home-automation / ebusd.nix
blob519d116e0e55c64df12446e86adbfc4c80f05016
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.ebusd;
8   package = pkgs.ebusd;
10   arguments = [
11     "${package}/bin/ebusd"
12     "--foreground"
13     "--updatecheck=off"
14     "--device=${cfg.device}"
15     "--port=${toString cfg.port}"
16     "--configpath=${cfg.configpath}"
17     "--scanconfig=${cfg.scanconfig}"
18     "--log=main:${cfg.logs.main}"
19     "--log=network:${cfg.logs.network}"
20     "--log=bus:${cfg.logs.bus}"
21     "--log=update:${cfg.logs.update}"
22     "--log=other:${cfg.logs.other}"
23     "--log=all:${cfg.logs.all}"
24   ] ++ lib.optionals cfg.readonly [
25     "--readonly"
26   ] ++ lib.optionals cfg.mqtt.enable [
27     "--mqtthost=${cfg.mqtt.host}"
28     "--mqttport=${toString cfg.mqtt.port}"
29     "--mqttuser=${cfg.mqtt.user}"
30     "--mqttpass=${cfg.mqtt.password}"
31   ] ++ lib.optionals cfg.mqtt.home-assistant [
32     "--mqttint=${package}/etc/ebusd/mqtt-hassio.cfg"
33     "--mqttjson"
34   ] ++ lib.optionals cfg.mqtt.retain [
35     "--mqttretain"
36   ] ++ cfg.extraArguments;
38   usesDev = hasPrefix "/" cfg.device;
40   command = concatStringsSep " " arguments;
44   meta.maintainers = with maintainers; [ nathan-gs ];
46   options.services.ebusd = {
47     enable = mkEnableOption (lib.mdDoc "ebusd service");
49     device = mkOption {
50       type = types.str;
51       default = "";
52       example = "IP:PORT";
53       description = lib.mdDoc ''
54         Use DEV as eBUS device [/dev/ttyUSB0].
55         This can be either:
56           enh:DEVICE or enh:IP:PORT for enhanced device (only adapter v3 and newer),
57           ens:DEVICE for enhanced high speed serial device (only adapter v3 and newer with firmware since 20220731),
58           DEVICE for serial device (normal speed, for all other serial adapters like adapter v2 as well as adapter v3 in non-enhanced mode), or
59           [udp:]IP:PORT for network device.
60         https://github.com/john30/ebusd/wiki/2.-Run#device-options
61       '';
62     };
64     port = mkOption {
65       default = 8888;
66       type = types.port;
67       description = lib.mdDoc ''
68         The port on which to listen on
69       '';
70     };
72     readonly = mkOption {
73       type = types.bool;
74       default = false;
75       description = lib.mdDoc ''
76          Only read from device, never write to it
77       '';
78     };
80     configpath = mkOption {
81       type = types.str;
82       default = "https://cfg.ebusd.eu/";
83       description = lib.mdDoc ''
84         Read CSV config files from PATH (local folder or HTTPS URL) [https://cfg.ebusd.eu/]
85       '';
86     };
88     scanconfig = mkOption {
89       type = types.str;
90       default = "full";
91       description = lib.mdDoc ''
92         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).
93         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,
94         see [Automatic configuration](https://github.com/john30/ebusd/wiki/4.7.-Automatic-configuration).
95       '';
96     };
98     logs = {
99       main = mkOption {
100         type = types.enum [ "error" "notice" "info" "debug"];
101         default = "info";
102         description = lib.mdDoc ''
103           Only write log for matching AREAs (main|network|bus|update|other|all) below or equal to LEVEL (error|notice|info|debug) [all:notice].
104         '';
105       };
107       network = mkOption {
108         type = types.enum [ "error" "notice" "info" "debug"];
109         default = "info";
110         description = lib.mdDoc ''
111           Only write log for matching AREAs (main|network|bus|update|other|all) below or equal to LEVEL (error|notice|info|debug) [all:notice].
112         '';
113       };
115       bus = mkOption {
116         type = types.enum [ "error" "notice" "info" "debug"];
117         default = "info";
118         description = lib.mdDoc ''
119           Only write log for matching AREAs (main|network|bus|update|other|all) below or equal to LEVEL (error|notice|info|debug) [all:notice].
120         '';
121       };
123       update = mkOption {
124         type = types.enum [ "error" "notice" "info" "debug"];
125         default = "info";
126         description = lib.mdDoc ''
127           Only write log for matching AREAs (main|network|bus|update|other|all) below or equal to LEVEL (error|notice|info|debug) [all:notice].
128         '';
129       };
131       other = mkOption {
132         type = types.enum [ "error" "notice" "info" "debug"];
133         default = "info";
134         description = lib.mdDoc ''
135           Only write log for matching AREAs (main|network|bus|update|other|all) below or equal to LEVEL (error|notice|info|debug) [all:notice].
136         '';
137       };
139       all = mkOption {
140         type = types.enum [ "error" "notice" "info" "debug"];
141         default = "info";
142         description = lib.mdDoc ''
143           Only write log for matching AREAs (main|network|bus|update|other|all) below or equal to LEVEL (error|notice|info|debug) [all:notice].
144         '';
145       };
146     };
148     mqtt = {
150       enable = mkOption {
151         type = types.bool;
152         default = false;
153         description = lib.mdDoc ''
154           Adds support for MQTT
155         '';
156       };
158       host = mkOption {
159         type = types.str;
160         default = "localhost";
161         description = lib.mdDoc ''
162           Connect to MQTT broker on HOST.
163         '';
164       };
166       port = mkOption {
167         default = 1883;
168         type = types.port;
169         description = lib.mdDoc ''
170           The port on which to connect to MQTT
171         '';
172       };
174       home-assistant = mkOption {
175         type = types.bool;
176         default = false;
177         description = lib.mdDoc ''
178           Adds the Home Assistant topics to MQTT, read more at [MQTT Integration](https://github.com/john30/ebusd/wiki/MQTT-integration)
179         '';
180       };
182       retain = mkOption {
183         type = types.bool;
184         default = false;
185         description = lib.mdDoc ''
186           Set the retain flag on all topics instead of only selected global ones
187         '';
188       };
190       user = mkOption {
191         type = types.str;
192         description = lib.mdDoc ''
193           The MQTT user to use
194         '';
195       };
197       password = mkOption {
198         type = types.str;
199         description = lib.mdDoc ''
200           The MQTT password.
201         '';
202       };
204     };
206     extraArguments = mkOption {
207       type = types.listOf types.str;
208       default = [];
209       description = lib.mdDoc ''
210         Extra arguments to the ebus daemon
211       '';
212     };
214   };
216   config = mkIf (cfg.enable) {
218     systemd.services.ebusd = {
219       description = "EBUSd Service";
220       wantedBy = [ "multi-user.target" ];
221       after = [ "network.target" ];
222       serviceConfig = {
223         ExecStart = command;
224         DynamicUser = true;
225         Restart = "on-failure";
227         # Hardening
228         CapabilityBoundingSet = "";
229         DeviceAllow = lib.optionals usesDev [
230           cfg.device
231         ] ;
232         DevicePolicy = "closed";
233         LockPersonality = true;
234         MemoryDenyWriteExecute = false;
235         NoNewPrivileges = true;
236         PrivateDevices = usesDev;
237         PrivateUsers = true;
238         PrivateTmp = true;
239         ProtectClock = true;
240         ProtectControlGroups = true;
241         ProtectHome = true;
242         ProtectHostname = true;
243         ProtectKernelLogs = true;
244         ProtectKernelModules = true;
245         ProtectKernelTunables = true;
246         ProtectProc = "invisible";
247         ProcSubset = "pid";
248         ProtectSystem = "strict";
249         RemoveIPC = true;
250         RestrictAddressFamilies = [
251           "AF_INET"
252           "AF_INET6"
253         ];
254         RestrictNamespaces = true;
255         RestrictRealtime = true;
256         RestrictSUIDSGID = true;
257         SupplementaryGroups = [
258           "dialout"
259         ];
260         SystemCallArchitectures = "native";
261         SystemCallFilter = [
262           "@system-service @pkey"
263           "~@privileged @resources"
264         ];
265         UMask = "0077";
266       };
267     };
269   };