grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / hardware / bluetooth.nix
bloba73cc970576a018dc27a6c57a878ece11511ce84
1 { config, lib, pkgs, ... }:
2 let
3   cfg = config.hardware.bluetooth;
4   package = cfg.package;
6   inherit (lib)
7     mkDefault mkEnableOption mkIf mkOption mkPackageOption
8     mkRenamedOptionModule mkRemovedOptionModule
9     concatStringsSep escapeShellArgs literalExpression
10     optional optionals optionalAttrs recursiveUpdate types;
12   cfgFmt = pkgs.formats.ini { };
14   defaults = {
15     General.ControllerMode = "dual";
16     Policy.AutoEnable = cfg.powerOnBoot;
17   };
19   hasDisabledPlugins = builtins.length cfg.disabledPlugins > 0;
23   imports = [
24     (mkRenamedOptionModule [ "hardware" "bluetooth" "config" ] [ "hardware" "bluetooth" "settings" ])
25     (mkRemovedOptionModule [ "hardware" "bluetooth" "extraConfig" ] ''
26       Use hardware.bluetooth.settings instead.
28       This is part of the general move to use structured settings instead of raw
29       text for config as introduced by RFC0042:
30       https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md
31     '')
32   ];
34   ###### interface
36   options = {
38     hardware.bluetooth = {
39       enable = mkEnableOption "support for Bluetooth";
41       hsphfpd.enable = mkEnableOption "support for hsphfpd[-prototype] implementation";
43       powerOnBoot = mkOption {
44         type = types.bool;
45         default = true;
46         description = "Whether to power up the default Bluetooth controller on boot.";
47       };
49       package = mkPackageOption pkgs "bluez" { };
51       disabledPlugins = mkOption {
52         type = types.listOf types.str;
53         default = [ ];
54         description = "Built-in plugins to disable";
55       };
57       settings = mkOption {
58         type = cfgFmt.type;
59         default = { };
60         example = {
61           General = {
62             ControllerMode = "bredr";
63           };
64         };
65         description = "Set configuration for system-wide bluetooth (/etc/bluetooth/main.conf).";
66       };
68       input = mkOption {
69         type = cfgFmt.type;
70         default = { };
71         example = {
72           General = {
73             IdleTimeout = 30;
74             ClassicBondedOnly = true;
75           };
76         };
77         description = "Set configuration for the input service (/etc/bluetooth/input.conf).";
78       };
80       network = mkOption {
81         type = cfgFmt.type;
82         default = { };
83         example = {
84           General = {
85             DisableSecurity = true;
86           };
87         };
88         description = "Set configuration for the network service (/etc/bluetooth/network.conf).";
89       };
90     };
91   };
93   ###### implementation
95   config = mkIf cfg.enable {
96     environment.systemPackages = [ package ]
97       ++ optional cfg.hsphfpd.enable pkgs.hsphfpd;
99     environment.etc."bluetooth/input.conf".source =
100       cfgFmt.generate "input.conf" cfg.input;
101     environment.etc."bluetooth/network.conf".source =
102       cfgFmt.generate "network.conf" cfg.network;
103     environment.etc."bluetooth/main.conf".source =
104       cfgFmt.generate "main.conf" (recursiveUpdate defaults cfg.settings);
105     services.udev.packages = [ package ];
106     services.dbus.packages = [ package ]
107       ++ optional cfg.hsphfpd.enable pkgs.hsphfpd;
108     systemd.packages = [ package ];
110     systemd.services = {
111       bluetooth =
112         let
113           # `man bluetoothd` will refer to main.conf in the nix store but bluez
114           # will in fact load the configuration file at /etc/bluetooth/main.conf
115           # so force it here to avoid any ambiguity and things suddenly breaking
116           # if/when the bluez derivation is changed.
117           args = [ "-f" "/etc/bluetooth/main.conf" ]
118             ++ optional hasDisabledPlugins
119             "--noplugin=${concatStringsSep "," cfg.disabledPlugins}";
120         in
121         {
122           wantedBy = [ "bluetooth.target" ];
123           aliases = [ "dbus-org.bluez.service" ];
124           serviceConfig.ExecStart = [
125             ""
126             "${package}/libexec/bluetooth/bluetoothd ${escapeShellArgs args}"
127           ];
128           # restarting can leave people without a mouse/keyboard
129           unitConfig.X-RestartIfChanged = false;
130         };
131     }
132     // (optionalAttrs cfg.hsphfpd.enable {
133       hsphfpd = {
134         after = [ "bluetooth.service" ];
135         requires = [ "bluetooth.service" ];
136         wantedBy = [ "bluetooth.target" ];
138         description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices";
139         serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl";
140       };
141     });
143     systemd.user.services = {
144       obex.aliases = [ "dbus-org.bluez.obex.service" ];
145     }
146     // optionalAttrs cfg.hsphfpd.enable {
147       telephony_client = {
148         wantedBy = [ "default.target" ];
150         description = "telephony_client for hsphfpd";
151         serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl";
152       };
153     };
154   };