#!/usr/bin/python
#
# pyownet documentation:
#
#     http://pyownet.readthedocs.org/en/latest/
#

import sys
import os
import time
import signal
import math
import threading
import logging
import datetime
import platform
import argparse
import traceback
import configparser
import pyownet
import paho.mqtt.client as mqtt

terminate = threading.Event()
logger = None

mqtt_client = None
mqtt_topic = None

def delay(interval):
    return interval - (time.time() % interval)

def mqtt_on_connect(client, userdata, flags, rc):
    logger.debug('on_connect: userdata=%s rc=%d' % (userdata,  rc))

def mqtt_on_message(client, userdata, message):
    logger.debug('on_message: %s %s %d' %
                 (message.topic, message.payload.decode("utf-8"),
                  message.qos[0]))

def mqtt_on_publish(client, userdata, mid):
    logger.debug('on_publish: userdata=%s mid=%d' % (userdata, mid))

def mqtt_on_log(client, userdata, level, message):
    logger.debug('on_log: userdata=%s level=%s message=%s' %
                 (userdata, level, message))

def dewpoint(temperature, humidity):
    kelvins = temperature + 273.15
    dewpoint = kelvins / ((-0.0001846 * math.log(humidity / 100.0) * kelvins) + 1.0)
    dewpoint = dewpoint - 273.15
    return dewpoint

def signal_handler(signum, frame):
    terminate.set()
    mqtt_client.disconnect()

if __name__ == '__main__':

    parser = argparse.ArgumentParser(description='One-Wire Weather Sensor Data Collector')
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='Use verbose logging.')
    parser.add_argument('-c', '--file', action='store',
                        default='/etc/sensors/sensors_1-wire.conf',
                        help='Configuration file.')
    arguments = parser.parse_args()

    configuration = configparser.ConfigParser()
    configuration.read(arguments.file)

    interval = int(configuration['collector'].get('interval', '60'))

    level = int(configuration['logging'].get('level', '40'))
    logger = logging.getLogger(__name__)
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(logging.Formatter('%(asctime)s %(message)s'))
    logger.addHandler(handler)
    logger.setLevel(level)

    sensors = configuration._sections['sensors']

    dewpoint_sensor = None
    try:
        dewpoint_sensor = configuration['calculate'].get('dewpoint', None)
        if dewpoint_sensor:
            dewpoint_temperature = dewpoint_sensor + '/temperature'
            dewpoint_humidity = dewpoint_sensor + '/humidity'
    except KeyError as e:
        pass

    owserver_host = configuration['owserver'].get('host', 'localhost')
    owserver_port = int(configuration['owserver'].get('port', '4304'))
    owproxy = pyownet.protocol.proxy(host=owserver_host, port=owserver_port)

    mqtt_topic = configuration['mqtt'].get('topic', 'home/sensor/1-wire')
    mqtt_host = configuration['mqtt'].get('host', 'localhost')
    mqtt_port = int(configuration['mqtt'].get('port', '1883'))
    mqtt_client = mqtt.Client(platform.node() + ':sensors_1-wire' , True)
    mqtt_client.on_message = mqtt_on_message
    mqtt_client.on_connect = mqtt_on_connect
    mqtt_client.on_publish = mqtt_on_publish
    #mqtt_client.on_log = mqtt_on_log
    mqtt_client.loop_start()
    mqtt_client.connect(mqtt_host, mqtt_port, 60)

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    time.sleep(delay(interval))
    while not terminate.is_set():

        now = time.time()
        values = {}

        for sensor, address in sensors.items():
            if address == 'datetime':
                values[sensor] = now
            else:
                value = owproxy.read(address)
                values[sensor] = float(value.decode('utf-8').strip())

            if dewpoint_sensor and dewpoint_temperature in values and dewpoint_humidity in values:
                value = dewpoint(values[dewpoint_temperature], values[dewpoint_humidity])
                values[dewpoint_sensor + '/dewpoint'] = value

            for sensor, value in values.items():
                mqtt_client.publish(mqtt_topic + '/' + sensor, str(round(value, 3)))

        terminate.wait(delay(interval))

    logger.info('Terminating')
    sys.exit(0)
