1{ config, lib, pkgs, options }: 2 3let 4 cfg = config.services.prometheus.exporters.rtl_433; 5in 6{ 7 port = 9550; 8 9 extraOpts = let 10 mkMatcherOptionType = field: description: with lib.types; 11 listOf (submodule { 12 options = { 13 name = lib.mkOption { 14 type = str; 15 description = "Name to match."; 16 }; 17 "${field}" = lib.mkOption { 18 type = int; 19 inherit description; 20 }; 21 location = lib.mkOption { 22 type = str; 23 description = "Location to match."; 24 }; 25 }; 26 }); 27 in 28 { 29 rtl433Flags = lib.mkOption { 30 type = lib.types.str; 31 default = "-C si"; 32 example = "-C si -R 19"; 33 description = '' 34 Flags passed verbatim to rtl_433 binary. 35 Having <literal>-C si</literal> (the default) is recommended since only Celsius temperatures are parsed. 36 ''; 37 }; 38 channels = lib.mkOption { 39 type = mkMatcherOptionType "channel" "Channel to match."; 40 default = []; 41 example = [ 42 { name = "Acurite"; channel = 6543; location = "Kitchen"; } 43 ]; 44 description = '' 45 List of channel matchers to export. 46 ''; 47 }; 48 ids = lib.mkOption { 49 type = mkMatcherOptionType "id" "ID to match."; 50 default = []; 51 example = [ 52 { name = "Nexus"; id = 1; location = "Bedroom"; } 53 ]; 54 description = '' 55 List of ID matchers to export. 56 ''; 57 }; 58 }; 59 60 serviceOpts = { 61 serviceConfig = { 62 # rtl-sdr udev rules make supported USB devices +rw by plugdev. 63 SupplementaryGroups = "plugdev"; 64 ExecStart = let 65 matchers = (map (m: 66 "--channel_matcher '${m.name},${toString m.channel},${m.location}'" 67 ) cfg.channels) ++ (map (m: 68 "--id_matcher '${m.name},${toString m.id},${m.location}'" 69 ) cfg.ids); in '' 70 ${pkgs.prometheus-rtl_433-exporter}/bin/rtl_433_prometheus \ 71 -listen ${cfg.listenAddress}:${toString cfg.port} \ 72 -subprocess "${pkgs.rtl_433}/bin/rtl_433 -F json ${cfg.rtl433Flags}" \ 73 ${lib.concatStringsSep " \\\n " matchers} \ 74 ${lib.concatStringsSep " \\\n " cfg.extraFlags} 75 ''; 76 }; 77 }; 78}