summary refs log tree commit diff
path: root/nixos/modules/services/hardware/lcd.nix
blob: dc8595ea60cde09196e8fee38d816925742bce95 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
{ config, lib, pkgs, ... }:

let
  cfg = config.services.hardware.lcd;
  pkg = lib.getBin pkgs.lcdproc;

  serverCfg = pkgs.writeText "lcdd.conf" ''
    [server]
    DriverPath=${pkg}/lib/lcdproc/
    ReportToSyslog=false
    Bind=${cfg.serverHost}
    Port=${toString cfg.serverPort}
    ${cfg.server.extraConfig}
  '';

  clientCfg = pkgs.writeText "lcdproc.conf" ''
    [lcdproc]
    Server=${cfg.serverHost}
    Port=${toString cfg.serverPort}
    ReportToSyslog=false
    ${cfg.client.extraConfig}
  '';

  serviceCfg = {
    DynamicUser = true;
    Restart = "on-failure";
    Slice = "lcd.slice";
  };

in with lib; {

  meta.maintainers = with maintainers; [ peterhoeg ];

  options = with types; {
    services.hardware.lcd = {
      serverHost = mkOption {
        type = str;
        default = "localhost";
        description = "Host on which LCDd is listening.";
      };

      serverPort = mkOption {
        type = int;
        default = 13666;
        description = "Port on which LCDd is listening.";
      };

      server = {
        enable = mkOption {
          type = bool;
          default = false;
          description = "Enable the LCD panel server (LCDd)";
        };

        openPorts = mkOption {
          type = bool;
          default = false;
          description = "Open the ports in the firewall";
        };

        usbPermissions = mkOption {
          type = bool;
          default = false;
          description = ''
            Set group-write permissions on a USB device.
            </para>
            <para>
            A USB connected LCD panel will most likely require having its
            permissions modified for lcdd to write to it. Enabling this option
            sets group-write permissions on the device identified by
            <option>services.hardware.lcd.usbVid</option> and
            <option>services.hardware.lcd.usbPid</option>. In order to find the
            values, you can run the <command>lsusb</command> command. Example
            output:
            </para>
            <para>
            <literal>
            Bus 005 Device 002: ID 0403:c630 Future Technology Devices International, Ltd lcd2usb interface
            </literal>
            </para>
            <para>
            In this case the vendor id is 0403 and the product id is c630.
          '';
        };

        usbVid = mkOption {
          type = str;
          default = "";
          description = "The vendor ID of the USB device to claim.";
        };

        usbPid = mkOption {
          type = str;
          default = "";
          description = "The product ID of the USB device to claim.";
        };

        usbGroup = mkOption {
          type = str;
          default = "dialout";
          description = "The group to use for settings permissions. This group must exist or you will have to create it.";
        };

        extraConfig = mkOption {
          type = lines;
          default = "";
          description = "Additional configuration added verbatim to the server config.";
        };
      };

      client = {
        enable = mkOption {
          type = bool;
          default = false;
          description = "Enable the LCD panel client (LCDproc)";
        };

        extraConfig = mkOption {
          type = lines;
          default = "";
          description = "Additional configuration added verbatim to the client config.";
        };

        restartForever = mkOption {
          type = bool;
          default = true;
          description = "Try restarting the client forever.";
        };
      };
    };
  };

  config = mkIf (cfg.server.enable || cfg.client.enable) {
    networking.firewall.allowedTCPPorts = mkIf (cfg.server.enable && cfg.server.openPorts) [ cfg.serverPort ];

    services.udev.extraRules = mkIf (cfg.server.enable && cfg.server.usbPermissions) ''
      ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="${cfg.server.usbVid}", ATTRS{idProduct}=="${cfg.server.usbPid}", MODE="660", GROUP="${cfg.server.usbGroup}"
    '';

    systemd.services = {
      lcdd = mkIf cfg.server.enable {
        description = "LCDproc - server";
        wantedBy = [ "lcd.target" ];
        serviceConfig = serviceCfg // {
          ExecStart = "${pkg}/bin/LCDd -f -c ${serverCfg}";
          SupplementaryGroups = cfg.server.usbGroup;
        };
      };

      lcdproc = mkIf cfg.client.enable {
        description = "LCDproc - client";
        after = [ "lcdd.service" ];
        wantedBy = [ "lcd.target" ];
        # Allow restarting for eternity
        startLimitIntervalSec = lib.mkIf cfg.client.restartForever 0;
        serviceConfig = serviceCfg // {
          ExecStart = "${pkg}/bin/lcdproc -f -c ${clientCfg}";
          # If the server is being restarted at the same time, the client will
          # fail as it cannot connect, so space it out a bit.
          RestartSec = "5";
        };
      };
    };

    systemd.targets.lcd = {
      description = "LCD client/server";
      after = [ "lcdd.service" "lcdproc.service" ];
      wantedBy = [ "multi-user.target" ];
    };
  };
}