|
|
@@ -0,0 +1,311 @@
|
|
|
+#!/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]
|
|
|
+
|
|
|
+ if ourstatus == 0:
|
|
|
+ return (3, "UNKNOWN - %s - %s " % (device, dewpoint))
|
|
|
+
|
|
|
+ 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),
|
|
|
+ ]:
|
|
|
+ ## 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
|
|
|
+ "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",
|
|
|
+}
|