#!/usr/bin/python -u

'''
--------------------------------------------------------------------------------
    Type:           Python 3.x script
    Author:         Milan Toman (milan.v.toman@gmail.com)
    Description:    Weather station (davis vantage vue) collector, coupled with
                    the infamous arduino source on
                    http://wp.spoton.cz/2017/11/24/davis-vantague-vue-arduino-and-a-raspberry-pi-3/
                    en-fucking-joy


    influxDB SCHEMA:

    DB weather

    measure temphumi
    ----------------
      temperature | humidity | external, internal | pressure
      ---------------------------------------------------------
      field         field      tag                  field


--------------------------------------------------------------------------------
            Import libraries
--------------------------------------------------------------------------------
'''
# mandatory
import requests
import sys
import os
import re
import textwrap
import argparse
import time
import datetime
import serial
import simplejson as json
import influxdb
import configparser


# optionally, future modules, locally available, I hate dependencies
from pprint import pprint
_SCRIPT_PATH = os.path.dirname(os.path.abspath(sys.argv[0]))
sys.path.append(_SCRIPT_PATH + "/lib")

#import ventilLogger


'''
--------------------------------------------------------------------------------
            Define variables
--------------------------------------------------------------------------------
'''
config = configparser.ConfigParser()
config.read(_SCRIPT_PATH + "/../web/config/plutonium.ini")

_VERSION = 1.0
_NAME = u"Vantage Vue external measure enrichment"
_LOG_DIR = _SCRIPT_PATH + '/log/'
_LOG_FILE_ROOT = re.sub(u'./', '', sys.argv[0])
_LOG_FILE = _LOG_DIR + _LOG_FILE_ROOT + u'.log'
_DEBUG_FILE = _LOG_DIR + _LOG_FILE_ROOT + u'.dbg'
# finite loop implementation, tout for 43200 cycles
tout = 0

_ABS_ZERO = 273.15
_HEIGHT = 455
_EXT_MEASURE_DEVICE = '/dev/ttyUSBext'
pressure_adjusted = 0

influx_weather_write = []

influx_host = config['InfluxDB']['_influx_host']
influx_port = config['InfluxDB']['_influx_port']
influx_user = config['InfluxDB']['_influx_user']
influx_pwd = config['InfluxDB']['_influx_pwd']
weather_db = config['InfluxDB']['_influx_weather_db']
status_db = config['InfluxDB']['_influx_status_db']

'''
--------------------------------------------------------------------------------
            Set up logging - disabled, need to enable this iin future
--------------------------------------------------------------------------------
'''


'''
--------------------------------------------------------------------------------
            Setup arguments and Options - not edited, sample shite
--------------------------------------------------------------------------------
'''
desc = u'''\
DESCRIPTION:
    Vantage Vue pressure enrichment script
    
    '''
epi = u'''\
    ERROR CODES:
        ?

    EXAMPLES:
        ?

    '''
formatter = argparse.RawDescriptionHelpFormatter
arg_parser = argparse.ArgumentParser(description = desc,
                                     formatter_class = formatter,
                                     epilog = textwrap.dedent(epi))
args = arg_parser.parse_args()

'''
--------------------------------------------------------------------------------
            Generic, standalone functions
--------------------------------------------------------------------------------
'''
# Obvious shit, set up the client class
influx_weather_client = influxdb.client.InfluxDBClient(
    influx_host, influx_port, influx_user, influx_pwd, weather_db
)


'''
--------------------------------------------------------------------------------
            Classes
--------------------------------------------------------------------------------
'''

class extDataDecode(object):
    def __init__(self):
        __name__ = u'Davis external data decoder'
        self.height = _HEIGHT
        self.temp_dict = {}
        
    def load_external_data(self):
        # Data external to the ISS
        self.pressure = float(external_data['P'])
        self.inside_temp = round(float(external_data['T']), 2)
        self.inside_hum = external_data['H']

    def adjust_pressure(self, temp):
        sh = 0.0065 * self.height
        base = 1 - (sh) / (temp + sh + _ABS_ZERO)
        result = round(self.pressure * pow(base, -5.257), 2)
        return result


class DBwriter(object):
    def __init__(self):
        __name__ = "Database writer class, Influx"

    def construct(self, connector, measurement, fields, tags):
        """ Takes values in a writes them to influxdb

        requires:   list(connector): connector with all ticks to be written
                                     at once
                    str(measurement): the measurement ID to be written
                    dict(fields): fields to be written in one tick
                    dict(tags): tags to be written with the fields

        returns:    list(result_connector)
        """
        result_connector = connector
        result_connector.append({"measurement": measurement,
                                 "fields": fields,
                                 "tags": tags}
                               )
        return result_connector


'''
--------------------------------------------------------------------------------
            Main
--------------------------------------------------------------------------------
'''
if '__main__':
    davis_decoder = extDataDecode()
    davis_writer = DBwriter()
    try:
        with serial.Serial(_EXT_MEASURE_DEVICE, 9600) as data:
            # Now, let it run a couple times, end and restart via systemd
            while tout < 400:
                line = data.readline()
                #print(line)
                external_data = 0
                try:
                    external_data = eval(line)
                except SyntaxError as e_syntax:
                    print("ERROR (syntax): {}".format(e_syntax))
                except TypeError as e_type:
                    print("ERROR (Type): {}".format(e_type))
                except ValueError as e_value:
                    print("ERROR (Type): {}".format(e_value))
                if external_data != 0:
                    # Get data external to the ISS, from local PCB / internal
                    # sensors and create base values for influx writing
                    davis_decoder.load_external_data()
                    influx_weather_write = davis_writer.construct(
                        influx_weather_write,
                        "temphumi",
                        {"pressure": davis_decoder.pressure},
                        {"type" : "raw"}
                    )
                    influx_weather_write = davis_writer.construct(
                        influx_weather_write,
                        "temphumi",
                        {"pressure": davis_decoder.inside_temp},
                        {"type" : "internal"}
                    )
                    influx_weather_write = davis_writer.construct(
                        influx_weather_write,
                        "temphumi",
                        {"pressure": davis_decoder.inside_hum},
                        {"type" : "internal"}
                    )
                    # Write the whole blob into Influx DB
                    influx_weather_client.write_points(influx_weather_write)
                    tout = tout + 1
                    time.sleep(1)
                else:
                    print("No data here, mate.")
    except serial.serialutil.SerialException as e:
        print("Serial Error {}".format(e))
