1{ config, pkgs, lib, ... }:
2
3with lib;
4
5let
6 cfg = config.services.clight;
7
8 toConf = v:
9 if builtins.isFloat v then toString v
10 else if isInt v then toString v
11 else if isBool v then boolToString v
12 else if isString v then ''"${escape [''"''] v}"''
13 else if isList v then "[ " + concatMapStringsSep ", " toConf v + " ]"
14 else if isAttrs v then "\n{\n" + convertAttrs v + "\n}"
15 else abort "clight.toConf: unexpected type (v = ${v})";
16
17 getSep = v:
18 if isAttrs v then ":"
19 else "=";
20
21 convertAttrs = attrs: concatStringsSep "\n" (mapAttrsToList
22 (name: value: "${toString name} ${getSep value} ${toConf value};")
23 attrs);
24
25 clightConf = pkgs.writeText "clight.conf" (convertAttrs
26 (filterAttrs
27 (_: value: value != null)
28 cfg.settings));
29in {
30 options.services.clight = {
31 enable = mkOption {
32 type = types.bool;
33 default = false;
34 description = ''
35 Whether to enable clight or not.
36 '';
37 };
38
39 temperature = {
40 day = mkOption {
41 type = types.int;
42 default = 5500;
43 description = ''
44 Colour temperature to use during the day, between
45 <literal>1000</literal> and <literal>25000</literal> K.
46 '';
47 };
48 night = mkOption {
49 type = types.int;
50 default = 3700;
51 description = ''
52 Colour temperature to use at night, between
53 <literal>1000</literal> and <literal>25000</literal> K.
54 '';
55 };
56 };
57
58 settings = let
59 validConfigTypes = with types; oneOf [ int str bool float ];
60 collectionTypes = with types; oneOf [ validConfigTypes (listOf validConfigTypes) ];
61 in mkOption {
62 type = with types; attrsOf (nullOr (either collectionTypes (attrsOf collectionTypes)));
63 default = {};
64 example = { captures = 20; gamma_long_transition = true; ac_capture_timeouts = [ 120 300 60 ]; };
65 description = ''
66 Additional configuration to extend clight.conf. See
67 <link xlink:href="https://github.com/FedeDP/Clight/blob/master/Extra/clight.conf"/> for a
68 sample configuration file.
69 '';
70 };
71 };
72
73 config = mkIf cfg.enable {
74 boot.kernelModules = [ "i2c_dev" ];
75 environment.systemPackages = with pkgs; [ clight clightd ];
76 services.dbus.packages = with pkgs; [ clight clightd ];
77 services.upower.enable = true;
78
79 services.clight.settings = {
80 gamma.temp = with cfg.temperature; mkDefault [ day night ];
81 } // (optionalAttrs (config.location.provider == "manual") {
82 daytime.latitude = mkDefault config.location.latitude;
83 daytime.longitude = mkDefault config.location.longitude;
84 });
85
86 services.geoclue2.appConfig.clightc = {
87 isAllowed = true;
88 isSystem = true;
89 };
90
91 systemd.services.clightd = {
92 requires = [ "polkit.service" ];
93 wantedBy = [ "multi-user.target" ];
94
95 description = "Bus service to manage various screen related properties (gamma, dpms, backlight)";
96 serviceConfig = {
97 Type = "dbus";
98 BusName = "org.clightd.clightd";
99 Restart = "on-failure";
100 RestartSec = 5;
101 ExecStart = ''
102 ${pkgs.clightd}/bin/clightd
103 '';
104 };
105 };
106
107 systemd.user.services.clight = {
108 after = [ "upower.service" "clightd.service" ];
109 wants = [ "upower.service" "clightd.service" ];
110 partOf = [ "graphical-session.target" ];
111 wantedBy = [ "graphical-session.target" ];
112
113 description = "C daemon to adjust screen brightness to match ambient brightness, as computed capturing frames from webcam";
114 serviceConfig = {
115 Restart = "on-failure";
116 RestartSec = 5;
117 ExecStart = ''
118 ${pkgs.clight}/bin/clight --conf-file ${clightConf}
119 '';
120 };
121 };
122 };
123}