#!/usr/bin/env python3

"""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)
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_ok" in data:
                graphite.push(path + '.battery', data["battery_ok"], 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()
