1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 canonicalHandlers = {
8 powerEvent = {
9 event = "button/power.*";
10 action = config.services.acpid.powerEventCommands;
11 };
12
13 lidEvent = {
14 event = "button/lid.*";
15 action = config.services.acpid.lidEventCommands;
16 };
17
18 acEvent = {
19 event = "ac_adapter.*";
20 action = config.services.acpid.acEventCommands;
21 };
22 };
23
24 acpiConfDir = pkgs.runCommand "acpi-events" {}
25 ''
26 mkdir -p $out
27 ${
28 # Generate a configuration file for each event. (You can't have
29 # multiple events in one config file...)
30 let f = name: handler:
31 ''
32 fn=$out/${name}
33 echo "event=${handler.event}" > $fn
34 echo "action=${pkgs.writeShellScriptBin "${name}.sh" handler.action }/bin/${name}.sh '%e'" >> $fn
35 '';
36 in concatStringsSep "\n" (mapAttrsToList f (canonicalHandlers // config.services.acpid.handlers))
37 }
38 '';
39
40in
41
42{
43
44 ###### interface
45
46 options = {
47
48 services.acpid = {
49
50 enable = mkOption {
51 type = types.bool;
52 default = false;
53 description = "Whether to enable the ACPI daemon.";
54 };
55
56 logEvents = mkOption {
57 type = types.bool;
58 default = false;
59 description = "Log all event activity.";
60 };
61
62 handlers = mkOption {
63 type = types.attrsOf (types.submodule {
64 options = {
65 event = mkOption {
66 type = types.str;
67 example = [ "button/power.*" "button/lid.*" "ac_adapter.*" "button/mute.*" "button/volumedown.*" "cd/play.*" "cd/next.*" ];
68 description = "Event type.";
69 };
70
71 action = mkOption {
72 type = types.lines;
73 description = "Shell commands to execute when the event is triggered.";
74 };
75 };
76 });
77
78 description = ''
79 Event handlers.
80
81 <note><para>
82 Handler can be a single command.
83 </para></note>
84 '';
85 default = {};
86 example = {
87 ac-power = {
88 event = "ac_adapter/*";
89 action = ''
90 vals=($1) # space separated string to array of multiple values
91 case ''${vals[3]} in
92 00000000)
93 echo unplugged >> /tmp/acpi.log
94 ;;
95 00000001)
96 echo plugged in >> /tmp/acpi.log
97 ;;
98 *)
99 echo unknown >> /tmp/acpi.log
100 ;;
101 esac
102 '';
103 };
104 };
105 };
106
107 powerEventCommands = mkOption {
108 type = types.lines;
109 default = "";
110 description = "Shell commands to execute on a button/power.* event.";
111 };
112
113 lidEventCommands = mkOption {
114 type = types.lines;
115 default = "";
116 description = "Shell commands to execute on a button/lid.* event.";
117 };
118
119 acEventCommands = mkOption {
120 type = types.lines;
121 default = "";
122 description = "Shell commands to execute on an ac_adapter.* event.";
123 };
124
125 };
126
127 };
128
129
130 ###### implementation
131
132 config = mkIf config.services.acpid.enable {
133
134 systemd.services.acpid = {
135 description = "ACPI Daemon";
136
137 wantedBy = [ "multi-user.target" ];
138 after = [ "systemd-udev-settle.service" ];
139
140 path = [ pkgs.acpid ];
141
142 serviceConfig = {
143 Type = "forking";
144 };
145
146 unitConfig = {
147 ConditionVirtualization = "!systemd-nspawn";
148 ConditionPathExists = [ "/proc/acpi" ];
149 };
150
151 script = "acpid ${optionalString config.services.acpid.logEvents "--logevents"} --confdir ${acpiConfDir}";
152 };
153
154 };
155
156}