1{ config, pkgs, lib, ... }:
2
3with lib;
4
5let
6 cfg = config.hardware.openrazer;
7 kernelPackages = config.boot.kernelPackages;
8
9 toPyBoolStr = b: if b then "True" else "False";
10
11 daemonExe = "${pkgs.openrazer-daemon}/bin/openrazer-daemon --config ${daemonConfFile}";
12
13 daemonConfFile = pkgs.writeTextFile {
14 name = "razer.conf";
15 text = ''
16 [General]
17 verbose_logging = ${toPyBoolStr cfg.verboseLogging}
18
19 [Startup]
20 sync_effects_enabled = ${toPyBoolStr cfg.syncEffectsEnabled}
21 devices_off_on_screensaver = ${toPyBoolStr cfg.devicesOffOnScreensaver}
22 mouse_battery_notifier = ${toPyBoolStr cfg.mouseBatteryNotifier}
23
24 [Statistics]
25 key_statistics = ${toPyBoolStr cfg.keyStatistics}
26 '';
27 };
28
29 dbusServiceFile = pkgs.writeTextFile rec {
30 name = "org.razer.service";
31 destination = "/share/dbus-1/services/${name}";
32 text = ''
33 [D-BUS Service]
34 Name=org.razer
35 Exec=${daemonExe}
36 SystemdService=openrazer-daemon.service
37 '';
38 };
39
40 drivers = [
41 "razerkbd"
42 "razermouse"
43 "razerfirefly"
44 "razerkraken"
45 "razermug"
46 "razercore"
47 ];
48in
49{
50 options = {
51 hardware.openrazer = {
52 enable = mkEnableOption (lib.mdDoc ''
53 OpenRazer drivers and userspace daemon.
54 '');
55
56 verboseLogging = mkOption {
57 type = types.bool;
58 default = false;
59 description = lib.mdDoc ''
60 Whether to enable verbose logging. Logs debug messages.
61 '';
62 };
63
64 syncEffectsEnabled = mkOption {
65 type = types.bool;
66 default = true;
67 description = lib.mdDoc ''
68 Set the sync effects flag to true so any assignment of
69 effects will work across devices.
70 '';
71 };
72
73 devicesOffOnScreensaver = mkOption {
74 type = types.bool;
75 default = true;
76 description = lib.mdDoc ''
77 Turn off the devices when the systems screensaver kicks in.
78 '';
79 };
80
81 mouseBatteryNotifier = mkOption {
82 type = types.bool;
83 default = true;
84 description = lib.mdDoc ''
85 Mouse battery notifier.
86 '';
87 };
88
89 keyStatistics = mkOption {
90 type = types.bool;
91 default = false;
92 description = lib.mdDoc ''
93 Collects number of keypresses per hour per key used to
94 generate a heatmap.
95 '';
96 };
97
98 users = mkOption {
99 type = with types; listOf str;
100 default = [];
101 description = lib.mdDoc ''
102 Usernames to be added to the "openrazer" group, so that they
103 can start and interact with the OpenRazer userspace daemon.
104 '';
105 };
106 };
107 };
108
109 config = mkIf cfg.enable {
110 boot.extraModulePackages = [ kernelPackages.openrazer ];
111 boot.kernelModules = drivers;
112
113 # Makes the man pages available so you can successfully run
114 # > systemctl --user help openrazer-daemon
115 environment.systemPackages = [ pkgs.python3Packages.openrazer-daemon.man ];
116
117 services.udev.packages = [ kernelPackages.openrazer ];
118 services.dbus.packages = [ dbusServiceFile ];
119
120 # A user must be a member of the openrazer group in order to start
121 # the openrazer-daemon. Therefore we make sure that the group
122 # exists.
123 users.groups.openrazer = {
124 members = cfg.users;
125 };
126
127 systemd.user.services.openrazer-daemon = {
128 description = "Daemon to manage razer devices in userspace";
129 unitConfig.Documentation = "man:openrazer-daemon(8)";
130 # Requires a graphical session so the daemon knows when the screensaver
131 # starts. See the 'devicesOffOnScreensaver' option.
132 wantedBy = [ "graphical-session.target" ];
133 partOf = [ "graphical-session.target" ];
134 serviceConfig = {
135 Type = "dbus";
136 BusName = "org.razer";
137 ExecStart = "${daemonExe} --foreground";
138 Restart = "always";
139 };
140 };
141 };
142
143 meta = {
144 maintainers = with lib.maintainers; [ roelvandijk ];
145 };
146}