#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import datetime

# Example for output from agent
# ---------------------------------------------------------
#<<<fhem>>>
#Detected devices: Bad.Temp Dachboden.Temp Gaestezimmer.Temp Partyraum.Temp Schlafzimmer.Temp  
#Bad.Temp                                  Bad.Temp                         TYPE                 LaCrosse
#                     2016-11-16 08:39:41  Bad.Temp                         battery              ok
#                     2016-11-16 08:39:41  Bad.Temp                         dewpoint             15.1
#                     2016-11-16 08:39:41  Bad.Temp                         humdiff              0
#                     2016-11-16 08:39:41  Bad.Temp                         humidity             83
#eg.bad.waschmaschine_pwr                  eg.bad.waschmaschine_pwr         TYPE                 Revolt
#                     2016-11-15 16:54:48  eg.bad.waschmaschine_pwr         avgpower             263.19
#                     2016-11-16 09:18:07  eg.bad.waschmaschine_pwr         current              0
#                     2016-11-16 09:18:07  eg.bad.waschmaschine_pwr         energy               9.27
#                     2016-11-16 09:18:07  eg.bad.waschmaschine_pwr         frequency            50
#                     2016-11-16 09:18:07  eg.bad.waschmaschine_pwr         pf                   0
#                     2016-11-16 09:18:07  eg.bad.waschmaschine_pwr         power                0
#                     2016-11-16 09:18:07  eg.bad.waschmaschine_pwr         state                P:   0.0 E:   9.27 V: 226 C:   0.00 F: 50 Pf: 0.00
#                     2016-11-16 09:18:07  eg.bad.waschmaschine_pwr         voltage              226
#eg.wz.heizung                             eg.wz.heizung                    TYPE                 CUL_HM
#                                          eg.wz.heizung                    model                HM-CC-RT-DN
#                     2016-11-15 09:46:13  eg.wz.heizung                    Activity             alive
#                     2016-11-15 23:03:10  eg.wz.heizung                    CommandAccepted      yes
#                     2016-11-07 06:01:06  eg.wz.heizung                    D-firmware           1.4
#                     2016-11-07 06:01:06  eg.wz.heizung                    D-serialNr           MEQ0252852
#                     2016-11-07 06:04:23  eg.wz.heizung                    PairedTo             0x5FF2BE
#                     2016-11-07 06:04:23  eg.wz.heizung                    R-backOnTime         10 s
#                     2016-11-07 06:04:23  eg.wz.heizung                    R-btnLock            on
## ---------------------------------------------------------

def inventory_fhem(info):
        # Detected devices: Bad.Temp Dachboden.Temp Gaestezimmer.Temp
        line = info[0]
        if len(line) > 2:
                for device in line[2:]:
                        yield device, {}

def check_fhem(item, params, info):
        # [[u'Detected', u'fhem:', u'Bad.Temp', u'Dachboden.Temp', u'Gaestezimmer.Temp', u'Partyraum.Temp', u'Schlafzimmer.Temp'], [u'Bad.Temp', u'TYPE', u'LaCrosse'], [u'2016-07-14', u'13:15:07', u'state', u'T:', u'21.4', u'H:', u'77'], [u'2016-07-14', u'13:15:07', u'dewpoint', u'17.2'], [u'Dachboden.Temp', u'TYPE', u'LaCrosse'], [u'2016-07-14', u'13:15:10', u'state', u'T:', u'23.5', u'H:', u'53'], [u'2016-07-14', u'13:15:10', u'dewpoint', u'13.4'], [u'Gaestezimmer.Temp', u'TYPE', u'LaCrosse'], [u'2016-07-14', u'13:15:10', u'state', u'T:', u'22.8', u'H:', u'66'], [u'2016-07-14', u'13:15:10', u'dewpoint', u'16.1'], [u'Partyraum.Temp', u'TYPE', u'LaCrosse'], [u'2016-07-14', u'13:15:12', u'state', u'T:', u'23', u'H:', u'59'], [u'2016-07-14', u'13:15:12', u'dewpoint', u'14.6'], [u'Schlafzimmer.Temp', u'TYPE', u'LaCrosse'], [u'2016-07-14', u'13:15:08', u'state', u'T:', u'22.8', u'H:', u'59'], [u'2016-07-14', u'13:15:08', u'dewpoint', u'14.4']]

        fwarn, fcrit = None, None

        if "level_data_age" in params:
                dage_warn, dage_crit = params["level_data_age"]
        if "level_temp_max" in params:
                tmax_warn, tmax_crit = params["level_temp_max"]
        if "level_temp_min" in params:
                tmin_warn, tmin_crit = params["level_temp_min"]


        # See if any checks are diabled (set to 0)
#        if dage_warn != None and dage_warn == 0:
#                dage_warn = None;
#        if dage_crit != None and dage_crit == 0:
#                dage_crit = None;
#        if cbwarn != None and cbwarn == 0:
#                cbwarn = None;
#        if cbcrit != None and cbcrit == 0:
#                cbcrit = None;
        

        errorlevel, warnlevel = 0, 0

        model = ""
        output = []
        data = {}

#        ## bugfix, at beginning all timestamp up-to-date 
#        ## necessary because some devices don't send all data (weather-provider has no battery)
#        battery_timestamp, dewpoint_timespamp, state_timestamp = time.time(), time.time(), time.time()

        errorlevel = 0
        ourstatus = 0
        device = ""
        for line in info:
                if len(line) == 4 and line[2] == 'TYPE':
                        if line[0] == item:
                                dev_type = line[3]
                                ourstatus = 1
                        elif ourstatus == 1:
                                break
                elif ourstatus == 1:
#                        if line[0] == model:
#                                model = line[0]
                        if len(line) > 3 and line[3] != 'null':
                                data[line[3]] = {}
                                data[line[3]]['value']=line[4]
                                data[line[3]]['time']=( "%s %s" % (line[0], line[1]))
                                data[line[3]]['channel'] = line[2]
                                ## needed for traffic
                                if len(line) > 6:
                                        if line[5] == 'hour':
#                                                hour2min=
                                                data[line[3]]['value']=(int(line[4])*60)+int(line[6])

        # mostly config mistake or incorrect agent output
        if ourstatus == 0:
                return (3, "UNKNOWN - unable to parse %s" % (item))

        perfdata = []

# ##################################################################

        ## key          => variable_name
        ## title        => readable output
        ## unit         => °C, &, V., kmh, ... (for output)
        ## channel      => filter for channel (HomeMatic)
        ## show         => print if no error
        ## perfd        => print perfdata
        for key, title, unit, channel, show, perfd in [
             ##  key                    title                   unit                channel            show        perfd
             ##  -------                -------                 -------             -------            ----        -----
                ('temperature',         'temperature',          u'°C',              '',                1,          1),
                ('desired-temp',        'desiredtemp',          u'°C',              '',                1,          1),
                ('humidity',            'humidity',             u'%',               '',                1,          1),
                ('dewpoint',            'dewpoint',             u'°C',              '',                1,          1),
                ('contact',             'contact',              '',                 '',                1,          1),
                ('valveposition',       'valveposition',        u'%',               '',                1,          1),
                ('battery',             'battery',              '',                 '',                1,          0),
                ('batteryLevel',        'batteryLevel',         'V',                '',                1,          1),
                ('controlMode',         'controlMode',          '',                 'Clima',           0,          0),
                ('Activity',            'activity',             '',                 '',                0,          1),
                ('power',               'power',                'kWh',              '',                1,          1),
                ('energy',              'energy',               'W',                '',                1,          1),
                ('voltage',             'voltage',              'V',                '',                1,          1),
                ## HomeMatic
                ('measured-temp',       'temperature',          u'°C',              '',                1,          1),
                ('actuator',            'valveposition',        u'%',               '',                1,          1),
                ('R-btnLock',           'btnLock',              '',                 '',                0,          0),
                ('R-globalBtnLock',     'globalBtnLock',        '',                 '',                0,          0),
                ('R-modusBtnLock',      'modusBtnLock',         '',                 '',                0,          0),
                ## MilightDevice (and others?)
                ('brightness',          'brightness',           u'%',               '',                1,          1),
                ('brightness_on',       'brightness_on',        u'%',               '',                0,          1),
                ('ct',                  'ct',                   'K',                '',                1,          1),
                ('hsv',                 'hsv',                  '',                 '',                0,          0),
                ('transitionInProgress','transitionInProgress', '',                 '',                0,          1),
                ## MiLightBridge
                ('protocol',            'protocol',             '',                 '',                0,          0),
                ('checkInterval',       'checkInterval',        's',                '',                0,          0),
                ('sendInterval',        'sendInterval',         's',                '',                0,          0),
                ## Speedtest
                ('download',            'download',             'Mbit/s',           '',                1,          1),
                ('ping',                'ping',                 'ms',               '',                1,          1),
                ('state',               'state',                '',                 '',                1,          0),
                ('upload',              'upload',               'Mbit/s',           '',                1,          1),
#               ('path',                'path',                 '',                 '',                0,          0),
                ## TRAFFIC
                ('delay',               'delay',                'min',              '',                1,          1),
                ('distance',            'distance',             'km',               '',                1,          1),
                ('duration',            'duration',             'mins',             '',                1,          1),
                ('duration_in_traffic', 'duration_in_traffic',  'mins',             '',                1,          1),




        ]:
          ## reset
          display_value = "" 
          ignoreit        = ""
#          var_data_age = ""


          ## check if device output data (temperature, humidity, ... )
          try:
                if data[key]['value']:
                    value = data[key]['value']

                    ## build dynamic variable names ...
                    var_max = 'level_%s_max' % title
                    var_min = 'level_%s_min' % title
                    var_data_age = '%s_date' % title
                    var_plain = 'var_%s' % title        ## e.g. contact: open (var_plain => open)

        #            print var_data_age
        #                    if  params[eval("desiredtemp_date")]:
        #                        print desiredtemp_date
        #                      pass
        #            except:
        #                   pass

                    try:
                        if params[eval("var_max")]:
                                ## check the difference between dewpoint and temperature
                                if key == 'dewpoint':
                                        max_warn_dewpoint, max_crit_dewpoint = params[eval("var_max")]
                                        max_warn = float(data['temperature']['value']) - max_warn_dewpoint
                                        max_crit = float( data['temperature']['value']) - max_crit_dewpoint
                                else:   
                                        max_warn, max_crit = params[eval("var_max")]
                        pass
                    except:
                        max_warn, max_crit = 0, 0
                        pass
                    try:
                        if params[eval("var_min")]:
                                min_warn, min_crit = params[eval("var_min")]
                        pass
                    except:
                        min_warn, min_crit = 0, 0
                        pass
                    try:
                        if params[eval("var_plain")]:
                                var_plain = params[eval("var_plain")]
                        pass
                    except:
                        var_plain = None
                        pass

                    try:
                        if eval(var_data_age) and eval(var_data_age) != "":
                                local_timestamp = time.time()
                                var_data_timestamp = time.mktime(datetime.datetime.strptime(eval(var_data_age) , "%Y-%m-%d %H:%M:%S").timetuple())
                                data_age = int( ( local_timestamp - var_data_timestamp ) / 60 )
                        pass
                    except:
                        ## bugfix, at beginning all timestamp up-to-date 
                        ## necessary because some devices don't send all data (weather-provider has no battery)
                        data_age = 0
                        pass


        #            if data_age > dage_crit:
        ##                 print ("data_age = %s, dage_crit = %s" % (data_age, dage_crit))
        #                        display_value = ("data to old [" + str(data_age)  + "min] (!!)")
        #                 errorlevel = 2
        #            elif data_age > dage_crit: 
        #                 display_value = ("data to old [" + str(data_age)  + "min] (!)")
        #                 warnlevel = 1
        #            else:

                    if key == 'humidity' and params['var_dewpoint_override'] == 'true':
                        ignoreit = 'true'


                    ## there are sometime duplicate keys on channel like controlmode in '_Clima' and '_Climate' 
                    ## Just filter out some HomeMatic-channel
                    if channel == '' or data[key]['channel'] == "%s_%s" % (item, channel):
                            ## check critical level (max/min)
                            if ( (max_crit != 0 and float(value) >= max_crit) or (min_crit != 0 and float(value) <= min_crit) ) and not ignoreit:
                                if max_crit != 0 and float(value) >= max_crit:
                                        display_value = ('%s%s (warn/crit at %s%s/%s%s) (!!)' % ( value, unit, max_warn, unit, max_crit, unit))
                                elif float(value) <= min_crit:
                                        display_value = ('%s%s (warn/crit at %s%s/%s%s) (!!)' % ( value, unit, min_warn, unit, min_crit, unit)) 
                                errorlevel = 2
                            ## check warning level (max/min)
                            elif ( (max_warn != 0 and float(value) >= max_warn) or (min_warn != 0 and float(value) <= min_warn) ) and not ignoreit:
                                if max_warn != 0 and float(value) >= max_warn:
                                        display_value = ('%s%s (warn/crit at %s%s/%s%s) (!)' % ( value, unit, max_warn, unit, max_crit, unit))
                                elif float(value) <= min_warn:
                                        display_value = ('%s%s (warn/crit at %s%s/%s%s) (!)' % ( value, unit, min_warn, unit, min_crit, unit))
                                warnlevel = 1
                            elif var_plain:
                                ## just alert if value not identic or ignored
                                if value == var_plain or var_plain == "ignore":
                                        if show:
                                                display_value = ('%s%s' % ( value, unit ))
                                        if perfd:
                                                perfdata.append( ( key , 1, ""  ) )
                                else:
                                        display_value = ("%s (expected: %s) (!!)" % (value, var_plain))
                                        errorlevel = 2
                                        if perfd:
                                                perfdata.append( ( key, 0, "" ) )
                            ## define output
                            elif show:
                                display_value = ('%s%s' % ( value, unit ))

                            ## define perfdata (just add numeric values)
                            if perfd and not var_plain:
                                perfdata.append( ( title, value, max_warn, max_crit, "", "" ) )


                            ## not used (yet)
#                            if data_age > dage_crit:
#                                 display_value += (" (data obsolet: %s min) (warn/crit at %s/%smin) (!!)" % (str(data_age), dage_warn, dage_crit))
#                                 errorlevel = 2
#                            elif data_age > dage_warn:
#                                 display_value += (" (data obsolet: %s min) (warn/crit at %s/%smin) (!)" % (str(data_age), dage_warn, dage_crit)) 
#                                 warnlevel = 1


                            if display_value != "":
                                output.append('%s: %s' % (title, display_value))
                pass

          except:
                pass



# ##################################################################

          if errorlevel > 1:
                exitcode = 2
          elif warnlevel > 0:
                exitcode = 1
          else:
                exitcode = 0

        return exitcode, ', '.join(output), perfdata


factory_settings["fhem_default_params"] = {
        "level_data_age"               : (30, 90),         # warn/crit for data age (min)
        "level_temperature_max"        : (26, 30),         # warn/crit for max. temperature
        "level_temperature_min"        : (15, 12),         # warn/crit for min. temperature
        "level_humidity_max"           : (70, 80),         # warn/crit for max. humidity
        "level_humidity_min"           : (50, 45),         # warn/crit for min. humidity
        "level_dewpoint_max"           : (3, 1),           # warn/crit for diff to temperatur (exp. 17°C (dewp) vs 20°C(temp))
        "level_batteryLevel_min"       : (2.1, 2.3),       # warn/crit for max. temperature
        "level_download_min"           : (10, 8),           # warn/crit for min download (speedtest)
        "level_upload_min"             : (1.5, 1),           # warn/crit for min upload (speedtest)
        "level_ping"                   : (100, 150),       # warn/crit for ping (speedtest)
        "var_activity"                 : ("alive"),        # default for alive
        "var_contact"                  : ("ignore"),       # default for contact
        "var_dewpoint_override"        : ("true"),         # don't alert humidity if dewpoint given
        "var_btnLock"                  : ("ignore"),       # simple button lock
        "var_globalBtnLock"            : ("ignore"),       # full button lock
        "var_modusBtnLock"             : ("ignore"),       # modus button lock
}

check_info['fhem'] = {
    "check_function"          : check_fhem,
    "inventory_function"      : inventory_fhem,
    "service_description"     : "FHEM %s",
    "has_perfdata"            : True,
    "group"                   : "fhem",
    "default_levels_variable" : "fhem_default_params",
}


