| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- import time
- import datetime
- import re
- # 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
- dev_model = ""
- dev_type = ""
- output = []
- perfdata = []
- data = {}
- in_device = 0
- # ## 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()
- for line in info:
- if len(line) == 4 and line[2] == 'TYPE':
- if line[0] == item:
- dev_type = line[3]
- in_device = 1
- elif in_device == 1:
- break
- elif in_device == 1:
- if line[1] == 'model':
- dev_model = line[2]
- 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':
- # convert hours to minutes
- data[line[3]]['value']=(int(line[4])*60)+int(line[6])
- # mostly config mistake or incorrect agent output
- if in_device == 0:
- return (3, "UNKNOWN - unable to parse %s (type: %s, model: %s)" % (item, dev_type, dev_model ))
- # ##################################################################
- ## 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),
- ('R-tempOffset', 'tempOffset', 'K', 'Clima', 1, 0),
- ## MAX!
- ('desiredTemperature', 'desiredtemp', u'°C', '', 1, 1),
- ('mode', 'mode', '', '', 0, 0),
- ('window', 'window', '', '', 1, 0),
- ('groupid', 'groupid', '', '', 1, 0),
- ## MilightDevice, WifiLight, ...
- ('brightness', 'brightness', u'%', '', 1, 1),
- ('brightness_on', 'brightness_on', u'%', '', 0, 1),
- ('ct', 'ct', 'K', '', 1, 1),
- ('hsv', 'hsv', '', '', 0, 0),
- ('transitionInProgress','transitionInProgress', '', '', 0, 0),
- ('hue', 'hue', '', '', 0, 0),
- ('saturation', 'saturation', '', '', 0, 1),
- ('RGB', 'RGB', '', '', 1, 0),
- ## 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),
- ## ESPEasy
- ('presence', 'presence', '', '', 1, 1),
- ## XiaomiFlowerSens
- ('fertility', 'fertility', '', '', 1, 1),
- ('lux', 'lux', 'lx', '', 1, 1),
- ('moisture', 'moisture', u'%', '', 1, 1),
- ## MQTT2
- ('LWT', 'LWT', '', '', 1, 0),
- ## key title unit channel show perfd
- ## ------- ------- ------- ------- ---- -----
- ## LUXTRONIK2
- ('ambientTemperature', 'ambientTemperature', u'°C', '', 1, 1),
- ('averageAmbientTemperature', 'averageAmbientTemperature', u'°C', '', 0, 1),
- ('hotWaterTemperature', 'hotWaterTemperature', u'°C', '', 1, 1),
- ('hotWaterTemperatureTarget', 'hotWaterTemperatureTarget', u'°C', '', 0, 1),
- ('heatingSystemCircPump', 'heatingSystemCircPump', '', '', 0, 1),
- ('opModeHeating', 'opModeHeating', '', '', 0, 0),
- ('opModeHotWater', 'opModeHotWater', '', '', 0, 0),
- ('opStateHeatPump1', 'opStateHeatPump1', '', '', 0, 0),
- ('hotGasTemperature', 'hotGasTemperature', u'°C', '', 1, 1),
- ('flowTemperature', 'flowTemperature', u'°C', '', 1, 1),
- ('returnTemperature', 'returnTemperature', u'°C', '', 1, 1),
- ('returnTemperatureTarget', 'returnTemperatureTarget', u'°C', '', 0, 1),
- # ('counterHours2ndHeatSource1', 'counterHours2ndHeatSource1', '', '', 0, 0),
- # ('counterHours2ndHeatSource2', 'counterHours2ndHeatSource2', '', '', 0, 0),
- ('counterHoursHeatPump', 'counterHoursHeatPump', '', '', 1, 1),
- ('counterHoursHeating', 'counterHoursHeating', '', '', 1, 1),
- ('counterHoursHotWater', 'counterHoursHotWater', '', '', 1, 1),
- ]:
- ## reset
- display_value = ""
- ignoreit = ""
- # var_data_age = ""
- fetch_plain = None
- ## 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)
- var_params = '%s_params' % title
- ## set upper level to default values if exist else we set to null
- if eval("var_max") in params:
- upper_warn, upper_crit = params[eval("var_max")]
- else:
- upper_warn, upper_crit = 0, 0
- ## set lower level to default values if exist else we set to null
- if eval("var_min") in params:
- lower_warn, lower_crit = params[eval("var_min")]
- else:
- lower_warn, lower_crit = 0, 0
- ## set plain text variables to default
- if eval("var_plain") in params:
- fetch_plain = params[eval("var_plain")]
- # print var_data_age
- # if params[eval("desiredtemp_date")]:
- # print desiredtemp_date
- # pass
- # except:
- # pass
- for param_group in params.keys():
- ## just loop over param categories (WATO)
- ## all categories need to named "*_params"
- if re.match('[a-z]+_params', param_group) is not None:
- ## loop over sub-categories
- for param_subgroup in params[param_group]:
- ## get configuration from WATO
- ## we create the runtime variable "fetch_params"
- try:
- ## like: fetch_params = params["climate_params"]
- fetch_params = params[param_group][param_subgroup]
- except:
- pass
- ## get minimal thresholds
- try:
- if eval("var_min") in fetch_params:
- ## like: if level_temperature_min in fetch_params["climate_params"]:
- lower_warn, lower_crit = fetch_params[eval("var_min")]
- except:
- pass
- ## get maximal thresholds
- try:
- ## like: if level_temperature_max in fetch_params[]:
- if eval("var_max") in fetch_params:
- upper_warn, upper_crit = fetch_params[eval("var_max")]
- except:
- pass
- ## get plain text
- try:
- ## like: if level_temperature_min in fetch_params[]:
- if eval("var_plain") in fetch_params:
- fetch_plain = fetch_params[eval("var_plain")]
- except:
- pass
-
- ## not used (yet)
- # 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 )
- # 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:
- ## calulate warn level for dewpoint
- if key == 'dewpoint':
- upper_warn = float(data['temperature']['value']) - upper_warn
- upper_crit = float(data['temperature']['value']) - upper_crit
- ## ignore humidity by default if dewpoint is given
- 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 ( (upper_crit != 0 and float(value) >= upper_crit) or (lower_crit != 0 and float(value) <= lower_crit) ) and not ignoreit:
- if upper_crit != 0 and float(value) >= upper_crit:
- display_value = ('%s%s (warn/crit at %s%s/%s%s) (!!)' % ( value, unit, upper_warn, unit, upper_crit, unit))
- elif float(value) <= lower_crit:
- display_value = ('%s%s (warn/crit at %s%s/%s%s) (!!)' % ( value, unit, lower_warn, unit, lower_crit, unit))
- errorlevel = 2
- ## check warning level (max/min)
- elif ( (upper_warn != 0 and float(value) >= upper_warn) or (lower_warn != 0 and float(value) <= lower_warn) ) and not ignoreit:
- if upper_warn != 0 and float(value) >= upper_warn:
- display_value = ('%s%s (warn/crit at %s%s/%s%s) (!)' % ( value, unit, upper_warn, unit, upper_crit, unit))
- elif float(value) <= lower_warn:
- display_value = ('%s%s (warn/crit at %s%s/%s%s) (!)' % ( value, unit, lower_warn, unit, lower_crit, unit))
- warnlevel = 1
- elif fetch_plain:
- ## just alert if value not identic or ignored
- if value == fetch_plain or fetch_plain == "ignore":
- if show:
- display_value = ('%s%s' % ( value, unit ))
- if perfd:
- perfdata.append( ( title, 1, "" ) )
- else:
- display_value = ("%s (expected: %s) (!!)" % (value, fetch_plain))
- errorlevel = 2
- if perfd:
- perfdata.append( ( title, 0, "" ) )
- ## define output
- elif show:
- display_value = ('%s%s' % ( value, unit))
- ## define perfdata (just add numeric values)
- if perfd and not fetch_plain:
- ## transform on/off (HomeMatic/MAX desiredTemp)
- if value == "off" or value == "on":
- value = 0
- perfdata.append( ( title, value, upper_warn, upper_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.3, 2.1), # warn/crit for max. temperature
- "level_download_min" : (10.0, 8.0), # warn/crit for min download (speedtest)
- "level_upload_min" : (1.5, 1.0), # warn/crit for min upload (speedtest)
- "level_ping_max" : (100, 150), # warn/crit for ping (speedtest)
- "var_activity" : ("alive"), # default for alive
- "var_presence" : ("present"), # default for presence
- "var_contact" : ("ignore"), # default for contact
- "var_battery" : ("ok"), # default for battery
- "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
- "var_controlMode" : ("auto"), # controlMode
- "var_RGB_color" : ("ignore"), # RGB color hexcode
- "var_brightness" : ("ignore"), # color brightness
- "var_state" : ("ignore"), # reading state
- ## MAX!
- "var_mode" : ("auto"), # like controlMode on HomeMatic devices
- "var_window" : ("ignore"), # like contact on HomeMatic devices
- ## MQTT2
- "var_lwt" : ("ignore"), # LWT - the last will
- ## LUXTRONIK2
- "level_ambientTemperature_max" : (26, 30), # warn/crit for max. ambientTemperature
- "level_ambientTemperature_min" : (15, 12), # warn/crit for min. ambientTemperature
- "level_averageAmbientTemperature_max" : (26, 30), # warn/crit for max. averageAmbientTemperature
- "level_averageAmbientTemperature_min" : (15, 12), # warn/crit for min. averageAmbientTemperature
- "level_hotWaterTemperature_max" : (60, 65), # warn/crit for max hotWaterTemperature
- "level_hotWaterTemperature_min" : (40, 37), # warn/crit for min hotWaterTemperature
- # "level_hotGasTemperature_max" : (26, 30), # warn/crit for max hotWaterTemperature
- # "level_hotGasTemperature_min" : (15, 12), # warn/crit for min hotWaterTemperature
- # "level_returnTemperature_max" : (35, 38), # warn/crit for max hotWaterTemperature
- # "level_returnTemperature_min" : (25, 23), # warn/crit for min hotWaterTemperature
- # "level_flowTemperature_max" : (35, 38), # warn/crit for max hotWaterTemperature
- # "level_flowTemperature_min" : (25, 23), # warn/crit for min hotWaterTemperatur
- "var_heatingSystemCircPump" : ("ignore"), # default for heatingSystemCircPump
- "var_opStateHeatPump1" : ("ignore"), # default for opStateHeatPump1
- "var_opModeHeating" : ("Automatik"), # default for opModeHeating
- "var_opModeHotWater" : ("Automatik"), # default for opModeHotWater
- ##
- "level_moisture_min" : (20, 10), # warn/crit for moisture
-
- }
- 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",
- }
|