1{
2 config,
3 lib,
4 pkgs,
5 utils,
6 ...
7}:
8let
9 inherit (lib)
10 getExe
11 mkEnableOption
12 mkIf
13 mkOption
14 mkPackageOption
15 ;
16
17 cfg = config.services.evcc;
18
19 format = pkgs.formats.yaml { };
20 configFile = format.generate "evcc.yml" cfg.settings;
21
22 package = pkgs.evcc;
23in
24
25{
26 meta.maintainers = with lib.maintainers; [ hexa ];
27
28 options.services.evcc = with lib.types; {
29 enable = mkEnableOption "EVCC, the extensible EV Charge Controller and Home Energy Management System";
30
31 package = mkPackageOption pkgs "evcc" { };
32
33 extraArgs = mkOption {
34 type = listOf str;
35 default = [ ];
36 description = ''
37 Extra arguments to pass to the `evcc` executable.
38 '';
39 };
40
41 environmentFile = mkOption {
42 type = nullOr path;
43 default = null;
44 example = /run/keys/evcc;
45 description = ''
46 File with environment variables to pass into the runtime environment.
47
48 Useful to pass secrets into the configuration, that get applied using `envsubst`.
49 '';
50 };
51
52 settings = mkOption {
53 type = format.type;
54 description = ''
55 evcc configuration as a Nix attribute set. Supports substitution of secrets using `envsubst` from the `environmentFile`.
56
57 Check for possible options in the sample [evcc.dist.yaml](https://github.com/andig/evcc/blob/${package.version}/evcc.dist.yaml).
58 '';
59 };
60 };
61
62 config = mkIf cfg.enable {
63 systemd.services.evcc = {
64 wants = [ "network-online.target" ];
65 after = [
66 "network-online.target"
67 "mosquitto.target"
68 ];
69 wantedBy = [
70 "multi-user.target"
71 ];
72 environment.HOME = "/var/lib/evcc";
73 path = with pkgs; [
74 getent
75 ];
76 serviceConfig = {
77 EnvironmentFile = lib.optionals (cfg.environmentFile != null) [ cfg.environmentFile ];
78 ExecStartPre = utils.escapeSystemdExecArgs [
79 (getExe pkgs.envsubst)
80 "-i"
81 configFile
82 "-o"
83 "/run/evcc/config.yaml"
84 ];
85 ExecStart = utils.escapeSystemdExecArgs (
86 [
87 (getExe cfg.package)
88 "--config=/run/evcc/config.yaml"
89 ]
90 ++ cfg.extraArgs
91 );
92 CapabilityBoundingSet = [ "" ];
93 DeviceAllow = [
94 "char-ttyUSB"
95 ];
96 DevicePolicy = "closed";
97 DynamicUser = true;
98 LockPersonality = true;
99 MemoryDenyWriteExecute = true;
100 PrivateTmp = true;
101 PrivateUsers = true;
102 ProcSubset = "pid";
103 ProtectClock = true;
104 ProtectControlGroups = true;
105 ProtectHome = true;
106 ProtectHostname = true;
107 ProtectKernelLogs = true;
108 ProtectKernelModules = true;
109 ProtectKernelTunables = true;
110 ProtectProc = "invisible";
111 Restart = "on-failure";
112 RestrictAddressFamilies = [
113 "AF_INET"
114 "AF_INET6"
115 "AF_UNIX"
116 "AF_NETLINK"
117 ];
118 RestrictNamespaces = true;
119 RestrictRealtime = true;
120 RuntimeDirectory = "evcc";
121 StateDirectory = "evcc";
122 SystemCallArchitectures = "native";
123 SystemCallFilter = [
124 "@system-service"
125 "~@privileged"
126 ];
127 UMask = "0077";
128 User = "evcc";
129 };
130 };
131 };
132
133 meta.buildDocsInSandbox = false;
134}