├── systemd-tmpfiles.rtl433.conf ├── rtl433.service ├── rtl433json_to_influx.service ├── README.md └── rtl433json_to_influx.py /systemd-tmpfiles.rtl433.conf: -------------------------------------------------------------------------------- 1 | p /run/rtl433 0660 rtl433sdr rtl433sdr - 2 | -------------------------------------------------------------------------------- /rtl433.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=rtl_433 3 | 4 | [Service] 5 | ExecStart=/home/rtl433sdr/bin/rtl_433 -q -s 1024000 -F json:/run/rtl433 -M utc -G 6 | # with systemd >= 232 use named fds, as per 7 | User=rtl433sdr 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | 12 | -------------------------------------------------------------------------------- /rtl433json_to_influx.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=rtl_433 JSON to InfluxDB 3 | 4 | [Service] 5 | ExecStart=/usr/bin/python3 /home/rtl433sdr/bin/rtl433json_to_influx.py /run/rtl433 6 | # with systemd >= 232 use named fds, as per 7 | User=rtl433sdr 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rtl_433 to InfluxDB 2 | 3 | dump everything your rtl-sdr receives on 433MHz into an InfluxDB for easy graphing 4 | 5 | ## prerequisites 6 | 7 | - a systemd linux distro 8 | - python3 9 | - an rtl-sdr and [rtl_433](https://github.com/merbanan/rtl_433) 10 | - InfluxDB and [influxdb-python(3)](https://github.com/influxdata/influxdb-python) 11 | 12 | ## setup 13 | 14 | - setup [rtl_433](https://github.com/merbanan/rtl_433) with your rtl-sdr 15 | - I assume you use a separate unix user `rtl433sdr` for that, and the compiled binary is (symlinked) in `~rtl433sdr/bin/rtl_433` 16 | - install [InfluxDB](https://github.com/influxdata/influxdb) and [influxdb-python3](https://github.com/influxdata/influxdb-python) 17 | - create a database `rtl433` where all the stuff goes 18 | - setup the service. You may use symlinks instead of copying the files 19 | ~~~sh 20 | cp systemd-tmpfiles.rtl433.conf /etc/tmpfiles.d/ 21 | cp rtl433.service /etc/systemd/system/ 22 | cp rtl433json_to_influx.service /etc/systemd/system/ 23 | cp rtl433json_to_influx.py ~rtl433sdr/bin/ 24 | systemctl daemon-reload 25 | systemd-tmpfiles --create 26 | systemctl start rtl433 rtl433json_to_influx 27 | systemctl enable rtl433 rtl433json_to_influx 28 | ~~~ 29 | 30 | ## graphing 31 | 32 | Leave it running overnight, then setup [Grafana](https://github.com/grafana/grafana) and look what you find inside the `rtl433` database! 33 | 34 | -------------------------------------------------------------------------------- /rtl433json_to_influx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | from json.decoder import JSONDecodeError 4 | from influxdb import InfluxDBClient 5 | import sys 6 | from datetime import datetime 7 | import itertools 8 | 9 | 10 | mappings = { 11 | 'maybetemp': None, 12 | 'temperature': None, 13 | 'temperature_C': None, 14 | 'temperature_C1': None, 15 | 'temperature_C2': None, 16 | 'temperature_2_C': None, 17 | 'temperature_1_C': None, 18 | 'temperature_F': None, 19 | 'ptemperature_C': None, 20 | 21 | 'pressure_bar': None, 22 | 'pressure_hPa': None, 23 | 'pressure_PSI': None, 24 | 25 | 'humidity': None, 26 | 'phumidity': None, 27 | 'moisture': None, 28 | 29 | 'windstrength': None, 30 | 'gust': None, 31 | 'average': None, 32 | 'speed': None, 33 | 'wind_gust': None, 34 | 'wind_speed': None, 35 | 36 | 'winddirection': None, 37 | 'direction': None, 38 | 'wind_direction': None, 39 | 'wind_dir_deg': None, 40 | 'wind_dir': None, 41 | 42 | 'battery': None, 43 | 'battery_mV': None, 44 | 45 | 'rain': None, 46 | 'rain_rate': None, 47 | 'total_rain': None, 48 | 'rain_total': None, 49 | 'rainfall_accumulation': None, 50 | 'raincounter_raw': None, 51 | 52 | 'status': None, 53 | 'state': None, 54 | 'tristate': str, 55 | 'button1': None, 56 | 'button2': None, 57 | 'button3': None, 58 | 'button4': None, 59 | 'flags': lambda x: int(str(x), base=16), 60 | 'event': lambda x: int(str(x), base=16), 61 | 'cmd': None, 62 | 'cmd_id': None, 63 | 'code': None, 64 | 'power0': None, 65 | 'power1': None, 66 | 'power2': None, 67 | 'dim_value': None, 68 | 'depth': None, 69 | 'depth_cm': None, 70 | 'energy': None, 71 | 'data': None, 72 | 'repeat': None, 73 | 'current': None, 74 | 'interval': None, 75 | 76 | 'heating': None, 77 | 'heating_temp': None, 78 | 'water': None, 79 | } 80 | 81 | client = InfluxDBClient('localhost', 8086, 'root', 'root', 'rtl433') 82 | source = sys.stdin 83 | if sys.argv[1:]: 84 | files = map(lambda name : open(name, 'r'), sys.argv[1:]) 85 | source = itertools.chain.from_iterable(files) 86 | for line in source: 87 | try: 88 | json_in = json.loads(line) 89 | except JSONDecodeError as e: 90 | print("error {} decoding {}".format(e, line.strip()), file=sys.stderr) 91 | continue 92 | 93 | if not 'model' in json_in: 94 | continue 95 | time = json_in.pop('time') if 'time' in json_in else datetime.now().isoformat() 96 | 97 | json_out = { 98 | 'measurement': json_in.pop('model'), 99 | 'time': time, # TODO: timezone? 100 | 'tags': {}, 101 | 'fields': {}, 102 | } 103 | for n, mapping in mappings.items(): 104 | if n in json_in: 105 | mapping = mapping or (lambda x : x) 106 | try: 107 | value = json_in.pop(n) 108 | json_out['fields'][n] = mapping(value) 109 | except Exception as e: 110 | print('error {} mapping {}'.format(e, value)) 111 | continue 112 | json_out['tags'] = json_in # the remainder 113 | 114 | if not len(json_out['fields']): 115 | continue # invalid: we have no data #TODO: notify about error 116 | 117 | try: 118 | client.write_points([json_out]) 119 | except Exception as e: 120 | print("error {} writing {}".format(e, json_out), file=sys.stderr) 121 | 122 | --------------------------------------------------------------------------------