1{ config, lib, pkgs, ... }:
2
3let
4 cfg = config.services.hardware.lcd;
5 pkg = lib.getBin pkgs.lcdproc;
6
7 serverCfg = pkgs.writeText "lcdd.conf" ''
8 [server]
9 DriverPath=${pkg}/lib/lcdproc/
10 ReportToSyslog=false
11 Bind=${cfg.serverHost}
12 Port=${toString cfg.serverPort}
13 ${cfg.server.extraConfig}
14 '';
15
16 clientCfg = pkgs.writeText "lcdproc.conf" ''
17 [lcdproc]
18 Server=${cfg.serverHost}
19 Port=${toString cfg.serverPort}
20 ReportToSyslog=false
21 ${cfg.client.extraConfig}
22 '';
23
24 serviceCfg = {
25 DynamicUser = true;
26 Restart = "on-failure";
27 Slice = "lcd.slice";
28 };
29
30in with lib; {
31
32 meta.maintainers = with maintainers; [ peterhoeg ];
33
34 options = with types; {
35 services.hardware.lcd = {
36 serverHost = mkOption {
37 type = str;
38 default = "localhost";
39 description = "Host on which LCDd is listening.";
40 };
41
42 serverPort = mkOption {
43 type = int;
44 default = 13666;
45 description = "Port on which LCDd is listening.";
46 };
47
48 server = {
49 enable = mkOption {
50 type = bool;
51 default = false;
52 description = "Enable the LCD panel server (LCDd)";
53 };
54
55 openPorts = mkOption {
56 type = bool;
57 default = false;
58 description = "Open the ports in the firewall";
59 };
60
61 usbPermissions = mkOption {
62 type = bool;
63 default = false;
64 description = ''
65 Set group-write permissions on a USB device.
66 </para>
67 <para>
68 A USB connected LCD panel will most likely require having its
69 permissions modified for lcdd to write to it. Enabling this option
70 sets group-write permissions on the device identified by
71 <option>services.hardware.lcd.usbVid</option> and
72 <option>services.hardware.lcd.usbPid</option>. In order to find the
73 values, you can run the <command>lsusb</command> command. Example
74 output:
75 </para>
76 <para>
77 <literal>
78 Bus 005 Device 002: ID 0403:c630 Future Technology Devices International, Ltd lcd2usb interface
79 </literal>
80 </para>
81 <para>
82 In this case the vendor id is 0403 and the product id is c630.
83 '';
84 };
85
86 usbVid = mkOption {
87 type = str;
88 default = "";
89 description = "The vendor ID of the USB device to claim.";
90 };
91
92 usbPid = mkOption {
93 type = str;
94 default = "";
95 description = "The product ID of the USB device to claim.";
96 };
97
98 usbGroup = mkOption {
99 type = str;
100 default = "dialout";
101 description = "The group to use for settings permissions. This group must exist or you will have to create it.";
102 };
103
104 extraConfig = mkOption {
105 type = lines;
106 default = "";
107 description = "Additional configuration added verbatim to the server config.";
108 };
109 };
110
111 client = {
112 enable = mkOption {
113 type = bool;
114 default = false;
115 description = "Enable the LCD panel client (LCDproc)";
116 };
117
118 extraConfig = mkOption {
119 type = lines;
120 default = "";
121 description = "Additional configuration added verbatim to the client config.";
122 };
123
124 restartForever = mkOption {
125 type = bool;
126 default = true;
127 description = "Try restarting the client forever.";
128 };
129 };
130 };
131 };
132
133 config = mkIf (cfg.server.enable || cfg.client.enable) {
134 networking.firewall.allowedTCPPorts = mkIf (cfg.server.enable && cfg.server.openPorts) [ cfg.serverPort ];
135
136 services.udev.extraRules = mkIf (cfg.server.enable && cfg.server.usbPermissions) ''
137 ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="${cfg.server.usbVid}", ATTRS{idProduct}=="${cfg.server.usbPid}", MODE="660", GROUP="${cfg.server.usbGroup}"
138 '';
139
140 systemd.services = {
141 lcdd = mkIf cfg.server.enable {
142 description = "LCDproc - server";
143 wantedBy = [ "lcd.target" ];
144 serviceConfig = serviceCfg // {
145 ExecStart = "${pkg}/bin/LCDd -f -c ${serverCfg}";
146 SupplementaryGroups = cfg.server.usbGroup;
147 };
148 };
149
150 lcdproc = mkIf cfg.client.enable {
151 description = "LCDproc - client";
152 after = [ "lcdd.service" ];
153 wantedBy = [ "lcd.target" ];
154 # Allow restarting for eternity
155 startLimitIntervalSec = lib.mkIf cfg.client.restartForever 0;
156 serviceConfig = serviceCfg // {
157 ExecStart = "${pkg}/bin/lcdproc -f -c ${clientCfg}";
158 # If the server is being restarted at the same time, the client will
159 # fail as it cannot connect, so space it out a bit.
160 RestartSec = "5";
161 };
162 };
163 };
164
165 systemd.targets.lcd = {
166 description = "LCD client/server";
167 after = [ "lcdd.service" "lcdproc.service" ];
168 wantedBy = [ "multi-user.target" ];
169 };
170 };
171}