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