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