This repository has been archived by the owner on Sep 30, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
rtl_433_graphite_relay.py
executable file
·119 lines (87 loc) · 3.23 KB
/
rtl_433_graphite_relay.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python
"""Graphite(Carbon) monitoring relay for rtl_433."""
# Start rtl_433 (rtl_433 -F syslog::1433), then this script
# Option: PEP 3143 - Standard daemon process library
# (use Python 3.x or pip install python-daemon)
# import daemon
from __future__ import print_function
from __future__ import with_statement
import socket
import time
import json
UDP_IP = "127.0.0.1"
UDP_PORT = 1433
GRAPHITE_HOST = "127.0.0.1"
GRAPHITE_PORT = 2003
GRAPHITE_PREFIX = "rtlsdr."
class GraphiteUdpClient(object):
def __init__(self, host='localhost', port=2003, ipv6=False):
"""Create a new client."""
fam = socket.AF_INET6 if ipv6 else socket.AF_INET
family, _, _, _, addr = socket.getaddrinfo(
host, port, fam, socket.SOCK_DGRAM)[0]
self._addr = addr
self._sock = socket.socket(family, socket.SOCK_DGRAM)
def _send(self, message):
"""Send raw data to graphite."""
try:
self._sock.sendto(message, self._addr)
except (socket.error, RuntimeError):
pass
def push(self, path, value, timestamp=None):
"""Send a value to graphite."""
if not timestamp:
timestamp = int(time.time())
message = "{0} {1} {2}".format(path, value, timestamp)
self._send(message)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# allow multiple sockets to use the same PORT number
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
sock.bind((UDP_IP, UDP_PORT))
def sanitize(text):
return text.replace(" ", "_").replace("/", "_").replace(".", "_").replace("&", "")
def parse_syslog(line):
"""Try to extract the payload from a syslog line."""
line = line.decode("ascii") # also UTF-8 if BOM
if line.startswith("<"):
# fields should be "<PRI>VER", timestamp, hostname, command, pid, mid, sdata, payload
fields = line.split(None, 7)
line = fields[-1]
return line
def rtl_433_probe():
graphite = GraphiteUdpClient(host=GRAPHITE_HOST,
port=GRAPHITE_PORT)
while True:
line, addr = sock.recvfrom(1024)
try:
line = parse_syslog(line)
data = json.loads(line)
now = int(time.time())
label = sanitize(data["model"])
if "channel" in data:
label += ".CH" + str(data["channel"])
elif "id" in data:
label += ".ID" + str(data["id"])
path = GRAPHITE_PREFIX + label
if "battery" in data:
if data["battery"] == "OK":
graphite.push(path + '.battery', 1, now)
else:
graphite.push(path + '.battery', 0, now)
if "humidity" in data:
graphite.push(path + '.humidity', data["humidity"], now)
graphite.push(path + '.temperature', data["temperature_C"], now)
# graphite.commit() # for Pickle protocol only
except KeyError:
pass
except ValueError:
pass
def run():
# with daemon.DaemonContext(files_preserve=[sock]):
# detach_process=True
# uid
# gid
# working_directory
rtl_433_probe()
if __name__ == "__main__":
run()