1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8with lib;
9
10let
11 cfg = config.services.bcg;
12 configFile = (pkgs.formats.yaml {}).generate "bcg.conf.yaml" (
13 filterAttrsRecursive (n: v: v != null) {
14 inherit (cfg) device name mqtt;
15 retain_node_messages = cfg.retainNodeMessages;
16 qos_node_messages = cfg.qosNodeMessages;
17 base_topic_prefix = cfg.baseTopicPrefix;
18 automatic_remove_kit_from_names = cfg.automaticRemoveKitFromNames;
19 automatic_rename_kit_nodes = cfg.automaticRenameKitNodes;
20 automatic_rename_generic_nodes = cfg.automaticRenameGenericNodes;
21 automatic_rename_nodes = cfg.automaticRenameNodes;
22 }
23 );
24in
25{
26 options = {
27 services.bcg = {
28 enable = mkEnableOption "BigClown gateway";
29 package = mkPackageOption pkgs [ "python3Packages" "bcg" ] { };
30 environmentFiles = mkOption {
31 type = types.listOf types.path;
32 default = [];
33 example = [ "/run/keys/bcg.env" ];
34 description = ''
35 File to load as environment file. Environment variables from this file
36 will be interpolated into the config file using envsubst with this
37 syntax: `$ENVIRONMENT` or `''${VARIABLE}`.
38 This is useful to avoid putting secrets into the nix store.
39 '';
40 };
41 verbose = mkOption {
42 type = types.enum ["CRITICAL" "ERROR" "WARNING" "INFO" "DEBUG"];
43 default = "WARNING";
44 description = "Verbosity level.";
45 };
46 device = mkOption {
47 type = types.str;
48 description = "Device name to configure gateway to use.";
49 };
50 name = mkOption {
51 type = with types; nullOr str;
52 default = null;
53 description = ''
54 Name for the device.
55
56 Supported variables:
57 * `{ip}` IP address
58 * `{id}` The ID of the connected usb-dongle or core-module
59
60 `null` can be used for automatic detection from gateway firmware.
61 '';
62 };
63 mqtt = {
64 host = mkOption {
65 type = types.str;
66 default = "127.0.0.1";
67 description = "Host where MQTT server is running.";
68 };
69 port = mkOption {
70 type = types.port;
71 default = 1883;
72 description = "Port of MQTT server.";
73 };
74 username = mkOption {
75 type = with types; nullOr str;
76 default = null;
77 description = "MQTT server access username.";
78 };
79 password = mkOption {
80 type = with types; nullOr str;
81 default = null;
82 description = "MQTT server access password.";
83 };
84 cafile = mkOption {
85 type = with types; nullOr str;
86 default = null;
87 description = "Certificate Authority file for MQTT server access.";
88 };
89 certfile = mkOption {
90 type = with types; nullOr str;
91 default = null;
92 description = "Certificate file for MQTT server access.";
93 };
94 keyfile = mkOption {
95 type = with types; nullOr str;
96 default = null;
97 description = "Key file for MQTT server access.";
98 };
99 };
100 retainNodeMessages = mkOption {
101 type = types.bool;
102 default = false;
103 description = "Specify that node messages should be retaied in MQTT broker.";
104 };
105 qosNodeMessages = mkOption {
106 type = types.int;
107 default = 1;
108 description = "Set the guarantee of MQTT message delivery.";
109 };
110 baseTopicPrefix = mkOption {
111 type = types.str;
112 default = "";
113 description = "Topic prefix added to all MQTT messages.";
114 };
115 automaticRemoveKitFromNames = mkOption {
116 type = types.bool;
117 default = true;
118 description = "Automatically remove kits.";
119 };
120 automaticRenameKitNodes = mkOption {
121 type = types.bool;
122 default = true;
123 description = "Automatically rename kit's nodes.";
124 };
125 automaticRenameGenericNodes = mkOption {
126 type = types.bool;
127 default = true;
128 description = "Automatically rename generic nodes.";
129 };
130 automaticRenameNodes = mkOption {
131 type = types.bool;
132 default = true;
133 description = "Automatically rename all nodes.";
134 };
135 rename = mkOption {
136 type = with types; attrsOf str;
137 default = {};
138 description = "Rename nodes to different name.";
139 };
140 };
141 };
142
143 config = mkIf cfg.enable {
144 environment.systemPackages = with pkgs; [
145 python3Packages.bcg
146 python3Packages.bch
147 ];
148
149 systemd.services.bcg = let
150 envConfig = cfg.environmentFiles != [];
151 finalConfig = if envConfig
152 then "\${RUNTIME_DIRECTORY}/bcg.config.yaml"
153 else configFile;
154 in {
155 description = "BigClown Gateway";
156 wantedBy = [ "multi-user.target" ];
157 wants = [ "network-online.target" ] ++ lib.optional config.services.mosquitto.enable "mosquitto.service";
158 after = [ "network-online.target" ];
159 preStart = mkIf envConfig ''
160 umask 077
161 ${pkgs.envsubst}/bin/envsubst -i "${configFile}" -o "${finalConfig}"
162 '';
163 serviceConfig = {
164 EnvironmentFile = cfg.environmentFiles;
165 ExecStart = "${cfg.package}/bin/bcg -c ${finalConfig} -v ${cfg.verbose}";
166 RuntimeDirectory = "bcg";
167 };
168 };
169 };
170}