#!/usr/bin/env python # -*- coding: utf-8 -*- import time import datetime # Example for output from agent # --------------------------------------------------------- #<<>> #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', '', '', 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", }