From f816402fd0b1266d0bf3e7fc028b60da87f7ff5a Mon Sep 17 00:00:00 2001 From: Alexandre Macabies Date: Sat, 29 Aug 2020 01:28:51 +0200 Subject: [PATCH 1/5] rtl-sdr: use hardened udev rules rtl-sdr latest release 0.6.0 is from 2018. Six months ago master received a patch[1] to use improved udev rules that chown to plugdev instead of making the devices world-read-writable. This change backports [1] as an upstream patch. [1] https://osmocom.org/projects/rtl-sdr/repository/revisions/b2814731563be4d5a0a68554ece6454a2c63af12 --- pkgs/applications/radio/rtl-sdr/default.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkgs/applications/radio/rtl-sdr/default.nix b/pkgs/applications/radio/rtl-sdr/default.nix index 8fb5154ff78870..7e044296b02cc6 100644 --- a/pkgs/applications/radio/rtl-sdr/default.nix +++ b/pkgs/applications/radio/rtl-sdr/default.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchgit, cmake, pkgconfig, libusb1 }: +{ stdenv, fetchgit, fetchpatch, cmake, pkgconfig, libusb1 }: stdenv.mkDerivation rec { pname = "rtl-sdr"; @@ -10,6 +10,12 @@ stdenv.mkDerivation rec { sha256 = "0lmvsnb4xw4hmz6zs0z5ilsah5hjz29g1s0050n59fllskqr3b8k"; }; + patches = [ (fetchpatch { + name = "hardened-udev-rules.patch"; + url = "https://osmocom.org/projects/rtl-sdr/repository/revisions/b2814731563be4d5a0a68554ece6454a2c63af12/diff?format=diff"; + sha256 = "0ns740s2rys4glq4la4bh0sxfv1mn61yfjns2yllhx70rsb2fqrn"; + }) ]; + nativeBuildInputs = [ pkgconfig cmake ]; buildInputs = [ libusb1 ]; From b9750a9b5769bd0669a9b1facc1d1b55c2e1c5f1 Mon Sep 17 00:00:00 2001 From: Alexandre Macabies Date: Sat, 29 Aug 2020 02:12:07 +0200 Subject: [PATCH 2/5] nixos/hardware/rtl-sdr: new module This is a very thin module to ensure "plugdev" user exists and some udev rules are enabled, a prerequisite for using rtl-sdr. --- nixos/modules/hardware/rtl-sdr.nix | 20 ++++++++++++++++++++ nixos/modules/module-list.nix | 1 + 2 files changed, 21 insertions(+) create mode 100644 nixos/modules/hardware/rtl-sdr.nix diff --git a/nixos/modules/hardware/rtl-sdr.nix b/nixos/modules/hardware/rtl-sdr.nix new file mode 100644 index 00000000000000..77c8cb59a3d587 --- /dev/null +++ b/nixos/modules/hardware/rtl-sdr.nix @@ -0,0 +1,20 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.hardware.rtl-sdr; + +in { + options.hardware.rtl-sdr = { + enable = lib.mkEnableOption '' + Enables rtl-sdr udev rules and ensures 'plugdev' group exists. + This is a prerequisite to using devices supported by rtl-sdr without + being root, since rtl-sdr USB descriptors will be owned by plugdev + through udev. + ''; + }; + + config = lib.mkIf cfg.enable { + services.udev.packages = [ pkgs.rtl-sdr ]; + users.groups.plugdev = {}; + }; +} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 13b53168b31806..8bf781a6a61a91 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -59,6 +59,7 @@ ./hardware/pcmcia.nix ./hardware/printers.nix ./hardware/raid/hpsa.nix + ./hardware/rtl-sdr.nix ./hardware/steam-hardware.nix ./hardware/system-76.nix ./hardware/tuxedo-keyboard.nix From 86fb21cde5d4c89fa3f10a77a79c6e46b45ff478 Mon Sep 17 00:00:00 2001 From: Alexandre Macabies Date: Fri, 28 Aug 2020 03:08:21 +0200 Subject: [PATCH 3/5] maintainers: add zopieux --- maintainers/maintainer-list.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 608f28dbadb59a..9705df49199bbf 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -9522,6 +9522,12 @@ githubId = 1069303; name = "Kim Simmons"; }; + zopieux = { + email = "zopieux@gmail.com"; + github = "zopieux"; + githubId = 81353; + name = "Alexandre Macabies"; + }; zowoq = { email = "59103226+zowoq@users.noreply.github.com"; github = "zowoq"; From af28dac3ac66a51113b7b39cc6a056bba53945cb Mon Sep 17 00:00:00 2001 From: Alexandre Macabies Date: Fri, 28 Aug 2020 03:13:25 +0200 Subject: [PATCH 4/5] prometheus-rtl_433-exporter: init at 641a1f5 --- .../prometheus/rtl_433-exporter.nix | 26 +++++++++++++++++++ pkgs/top-level/all-packages.nix | 1 + 2 files changed, 27 insertions(+) create mode 100644 pkgs/servers/monitoring/prometheus/rtl_433-exporter.nix diff --git a/pkgs/servers/monitoring/prometheus/rtl_433-exporter.nix b/pkgs/servers/monitoring/prometheus/rtl_433-exporter.nix new file mode 100644 index 00000000000000..502ce8e0d43e39 --- /dev/null +++ b/pkgs/servers/monitoring/prometheus/rtl_433-exporter.nix @@ -0,0 +1,26 @@ +{ lib, buildGoModule, fetchFromGitHub, bash, nixosTests }: + +buildGoModule rec { + pname = "rtl_433-exporter"; + version = "0.1"; + + src = fetchFromGitHub { + owner = "mhansen"; + repo = "rtl_433_prometheus"; + rev = "v${version}"; + sha256 = "1998gvfa5310bxhi6kfv8bn99369dxph3pwrpp335997b25lc2w2"; + }; + + postPatch = "substituteInPlace rtl_433_prometheus.go --replace /bin/bash ${bash}/bin/bash"; + + vendorSha256 = "03mnmzq72844hzyw7iq5g4gm1ihpqkg4i9dgj2yln1ghwk843hq6"; + + passthru.tests = { inherit (nixosTests.prometheus-exporters) rtl_433; }; + + meta = with lib; { + description = "Prometheus time-series DB exporter for rtl_433 433MHz radio packet decoder"; + homepage = "https://github.com/mhansen/rtl_433_prometheus"; + license = licenses.mit; + maintainers = with maintainers; [ zopieux ]; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 5d4f035ae02946..7a9291d6fd76cf 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -17012,6 +17012,7 @@ in prometheus-pushgateway = callPackage ../servers/monitoring/prometheus/pushgateway.nix { }; prometheus-redis-exporter = callPackage ../servers/monitoring/prometheus/redis-exporter.nix { }; prometheus-rabbitmq-exporter = callPackage ../servers/monitoring/prometheus/rabbitmq-exporter.nix { }; + prometheus-rtl_433-exporter = callPackage ../servers/monitoring/prometheus/rtl_433-exporter.nix { }; prometheus-snmp-exporter = callPackage ../servers/monitoring/prometheus/snmp-exporter.nix { }; prometheus-tor-exporter = callPackage ../servers/monitoring/prometheus/tor-exporter.nix { }; prometheus-statsd-exporter = callPackage ../servers/monitoring/prometheus/statsd-exporter.nix { }; From 121bc17ab970108a9b2c587f88fe9eafd87d0a8b Mon Sep 17 00:00:00 2001 From: Alexandre Macabies Date: Fri, 28 Aug 2020 23:10:58 +0200 Subject: [PATCH 5/5] nixos/prometheus-rtl_433-exporter: new module --- .../monitoring/prometheus/exporters.nix | 3 + .../prometheus/exporters/rtl_433.nix | 78 +++++++++++++++++++ nixos/tests/prometheus-exporters.nix | 31 ++++++++ 3 files changed, 112 insertions(+) create mode 100644 nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index cc71451bf2067a..6cbf9ac70b391e 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -42,6 +42,7 @@ let "postgres" "redis" "rspamd" + "rtl_433" "snmp" "surfboard" "tor" @@ -226,6 +227,8 @@ in services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey; })] ++ [(mkIf config.services.rspamd.enable { services.prometheus.exporters.rspamd.url = mkDefault "http://localhost:11334/stat"; + })] ++ [(mkIf config.services.prometheus.exporters.rtl_433.enable { + hardware.rtl-sdr.enable = mkDefault true; })] ++ [(mkIf config.services.nginx.enable { systemd.services.prometheus-nginx-exporter.after = [ "nginx.service" ]; systemd.services.prometheus-nginx-exporter.requires = [ "nginx.service" ]; diff --git a/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix b/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix new file mode 100644 index 00000000000000..01e420db389784 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs, options }: + +let + cfg = config.services.prometheus.exporters.rtl_433; +in +{ + port = 9550; + + extraOpts = let + mkMatcherOptionType = field: description: with lib.types; + listOf (submodule { + options = { + name = lib.mkOption { + type = str; + description = "Name to match."; + }; + "${field}" = lib.mkOption { + type = int; + inherit description; + }; + location = lib.mkOption { + type = str; + description = "Location to match."; + }; + }; + }); + in + { + rtl433Flags = lib.mkOption { + type = lib.types.str; + default = "-C si"; + example = "-C si -R 19"; + description = '' + Flags passed verbatim to rtl_433 binary. + Having -C si (the default) is recommended since only Celsius temperatures are parsed. + ''; + }; + channels = lib.mkOption { + type = mkMatcherOptionType "channel" "Channel to match."; + default = []; + example = [ + { name = "Acurite"; channel = 6543; location = "Kitchen"; } + ]; + description = '' + List of channel matchers to export. + ''; + }; + ids = lib.mkOption { + type = mkMatcherOptionType "id" "ID to match."; + default = []; + example = [ + { name = "Nexus"; id = 1; location = "Bedroom"; } + ]; + description = '' + List of ID matchers to export. + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + # rtl-sdr udev rules make supported USB devices +rw by plugdev. + SupplementaryGroups = "plugdev"; + ExecStart = let + matchers = (map (m: + "--channel_matcher '${m.name},${toString m.channel},${m.location}'" + ) cfg.channels) ++ (map (m: + "--id_matcher '${m.name},${toString m.id},${m.location}'" + ) cfg.ids); in '' + ${pkgs.prometheus-rtl_433-exporter}/bin/rtl_433_prometheus \ + -listen ${cfg.listenAddress}:${toString cfg.port} \ + -subprocess "${pkgs.rtl_433}/bin/rtl_433 -F json ${cfg.rtl433Flags}" \ + ${lib.concatStringsSep " \\\n " matchers} \ + ${lib.concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index fdcc40721324e1..3d4da621b7446a 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -536,6 +536,37 @@ let ''; }; + rtl_433 = { + exporterConfig = { + enable = true; + }; + metricProvider = { + # Mock rtl_433 binary to return a dummy metric stream. + nixpkgs.overlays = [ (self: super: { + rtl_433 = self.runCommand "rtl_433" {} '' + mkdir -p "$out/bin" + cat < "$out/bin/rtl_433" + #!/bin/sh + while true; do + printf '{"time" : "2020-04-26 13:37:42", "model" : "zopieux", "id" : 55, "channel" : 3, "temperature_C" : 18.000}\n' + sleep 4 + done + EOF + chmod +x "$out/bin/rtl_433" + ''; + }) ]; + }; + exporterTest = '' + wait_for_unit("prometheus-rtl_433-exporter.service") + wait_for_open_port(9550) + wait_until_succeeds( + "curl -sSf localhost:9550/metrics | grep -q '{}'".format( + 'rtl_433_temperature_celsius{channel="3",id="55",location="",model="zopieux"} 18' + ) + ) + ''; + }; + snmp = { exporterConfig = { enable = true;