#!/usr/bin/python3 -u # -*- coding: utf-8 -*- # import serial import time from time import localtime, strftime from datetime import datetime import configparser from influxdb import InfluxDBClient import os import sys import paho.mqtt.client as mqtt import yaml import json #import math #import numpy as np #import httplib # Change working dir to the same dir as this script os.chdir(sys.path[0]) config = configparser.ConfigParser() config.read('jeelinklog.ini') serialport = config['jeelink'].get('serialport') serialbaud = int(config['jeelink'].get('baudrate')) mqtt_topic_prefix = config['mqtt'].get('topic_prefix') topic_prefix_outside_temphum = config['mqtt'].get('topic_prefix_outside_temphum') mqtt_topic_atemp = config['mqtt'].get('topic_outside_temp') mqtt_topic_ahum = config['mqtt'].get('topic_outside_hum') mqtt_topic_domoticz_in = "domoticz/in" mqtt_subtopic_notify = config['mqtt'].get('subtopic_notify') logfile_new_sensors = config['main'].get('logfile_new_sensors') path_new_sensors_folder = config['main'].get('path_new_sensors_folder') log_path = config['main'].get('log_path') if not os.path.exists(log_path): os.makedirs(log_path) verbosemode = False #sensors_conf_file = "/home/pi/jeelink_sensors.csv" sensordata_maxage = int(config['sensors'].get('data_maxage')) #minUpdateInterval = 60 #aTempHumPublishInterval = 60 #override_updateinterval_on_change = False #atemp_sensor_idx = 94 #atemp_sensor_idx_2 = 113 average_value_steps = int(config['sensors'].get('average_value_steps')) if average_value_steps == 0: average_value_steps = 1 if len(sys.argv) > 1 and str(sys.argv[1]) == "-v": verbosemode = True def touch(fname, times=None): with open(fname, 'a'): os.utime(fname, times) def on_connect(client, userdata, flags, rc): if verbosemode: print("MQTT connected with result code " + str(rc) + "\n") #client.subscribe("wetter/atemp") def on_disconnect(client, userdata, rc): if rc != 0: print("Unexpected MQTT disconnection. Will auto-reconnect\n") #def on_message(client, userdata, msg): # #print(msg.topic + " " + str(msg.payload)) # global atemp # atemp = msg.payload # dont edit below #starting values only.. ##atemp = 61 ##ahum = 101 ##atemp1 = 61 ##ahum1 = 101 ##atemp2 = 61 ##ahum2 = 101 ##atemp_last = 61 ##ahum_last = 101 checkLastUpdateInterval = 60 checkLastUpdateInterval_lastRun = 0 lastPublishTime = 0 lastStoreTime = 0 sensors = dict() sensors_id_to_name = dict() #sensors_idx = dict() sensors_lastTemp = dict() sensors_lastHum = dict() sensors_lastUpdate = dict() sensors_lastReceivedValue_temp = dict() sensors_lastReceivedTime = dict() sensors_lastValues_temp = dict() sensors_lastValues_hum = dict() sensors_lastAvgValue_temp = dict() sensors_lastAvgValue_hum = dict() sensors_lastValues_lastIndex = dict() #sensors_unavailable = dict() sensors_batteryState = dict() sensors_new_alreadyNotified = dict() sensors_outside_sensors = [] outSens_lastRun = 0 outSens_interval = 120 influx_default_fieldname_temperature = 'Temperature' influx_default_fieldname_humidity = 'Humidity' influx_default_datatype_temperature = 'float' influx_default_datatype_temperature = 'int' sensors_yaml = yaml.load(open(config['main'].get('sensors_config_yml')), Loader=yaml.FullLoader) def list_duplicates(seq): seen = set() seen_add = seen.add # adds all elements it doesn't know yet to seen and all other to seen_twice seen_twice = set( x for x in seq if x in seen or seen_add(x) ) # turn the set into a list (as requested) return list( seen_twice ) if verbosemode: print("JeeLink2MQTT by Flo Kra") print("=======================================================================") print("loading InfluxDB configuration...") influxdb_yaml = yaml.load(open(config['main'].get('influx_config_yml')), Loader=yaml.SafeLoader) if verbosemode: print("InfluxDB Instances:") print(json.dumps(influxdb_yaml, indent=4)) influxclient = dict() for instance in influxdb_yaml: i_host = influxdb_yaml[instance].get('host', None) i_port = int(influxdb_yaml[instance].get('port', 8086)) i_username = influxdb_yaml[instance].get('username', None) i_password = influxdb_yaml[instance].get('password', None) i_database = influxdb_yaml[instance].get('database', None) if i_host != None and i_database != None: if i_username != None and i_password != None: influxclient[instance] = InfluxDBClient(i_host, i_port, i_username, i_password, i_database) else: influxclient[instance] = InfluxDBClient(i_host, i_port, i_database) if verbosemode: print("loading sensors configuration: ") print(json.dumps(sensors_yaml, indent=3)) for key in sensors_yaml: #print(key, '->', sensors_yaml[key]) if verbosemode: print("Sensor name:", key) sensorName = key if sensors_yaml[key].get('LaCrosseID'): if verbosemode: print("LaCrosseID:", sensors_yaml[key].get('LaCrosseID')) sensorId = sensors_yaml[key].get('LaCrosseID') sensors_id_to_name[sensorId] = sensorName if sensors_yaml[key].get('DomoticzIdx'): if verbosemode: print("DomoticzIdx:", sensors_yaml[key].get('DomoticzIdx')) #sensors_idx[sensorId] = sensors_yaml[key].get('DomoticzIdx') if sensors_yaml[key].get('Topic_Temp'): if verbosemode: print("Topic_Temp:", sensors_yaml[key].get('Topic_Temp')) if sensors_yaml[key].get('Topic_Hum'): if verbosemode: print("Topic_Hum:", sensors_yaml[key].get('Topic_Hum')) if sensors_yaml[key].get('InfluxDB_Instance'): if verbosemode: print("InfluxDB_Instance:", sensors_yaml[key].get('InfluxDB_Instance')) if sensors_yaml[key].get('InfluxDB_Instance') not in influxdb_yaml: print("Error: invalid InfluxDB instance '" + sensors_yaml[key].get('InfluxDB_Instance') + "' configured for sensor '" + sensorName + "'") if sensors_yaml[key].get('isOutsideTempSensor'): if verbosemode: print("isOutsideTempSensor:", sensors_yaml[key].get('isOutsideTempSensor')) sensors_outside_sensors.append(sensorId) else: print("WARNING: Sensor " + key + " has no LaCrosseID!") if verbosemode: print() #print(json.dumps(sensor)) #print("sensors_id_to_name =",sensors_id_to_name) #print("outside sensors: ", sensors_outside_sensors) if verbosemode: print("\n") mqttc = mqtt.Client() mqttc.on_connect = on_connect mqttc.on_disconnect = on_disconnect ##mqttc.on_message = on_message if config['mqtt'].get('user') != "" and config['mqtt'].get('password') != "": mqttc.username_pw_set(config['mqtt'].get('user'), config['mqtt'].get('password')) mqttc.connect(config['mqtt'].get('server'), config['mqtt'].getint('port'), 60) mqttc.loop_start() #mqttc.loop_forever() ser = serial.Serial(port=serialport, baudrate = serialbaud, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=1) checkLastUpdateInterval_lastRun = time.time() # first check after timeout expired try: while True: msg_was_sent = 0 #clear serial buffer to remove junk and noise ser.flushInput() #read buffer until cr/lf serLine = ser.readline().strip() # catch exception on invalid char coming in: UnicodeDecodeError: 'ascii' codec can't decode byte 0xf4 in position 6: ordinal not in range(128) try: serLine = serLine.decode('ascii') except: serLine = "" if(serLine): if serLine.find('OK 9') != -1: if verbosemode: print(serLine + " = LaCrosse sensor") # uns interessieren nur reinkommende Zeilen die mit "OK 9 " beginnen # 0 1 2 3 4 5 6 # OK 9 ID XXX XXX XXX XXX # | | | | | | | # | | | | | | --- Humidity incl. WeakBatteryFlag # | | | | | |------ Temp * 10 + 1000 LSB # | | | | |---------- Temp * 10 + 1000 MSB # | | | |-------------- Sensor type (1 or 2) +128 if NewBatteryFlag # | | |----------------- Sensor ID # | |------------------- fix "9" # |---------------------- fix "OK" serLineParts = serLine.split(' ') #addr = serLineParts[2] #addr = "{0:x}".format(int(serLineParts[2])) #addr = hex((int(serLineParts[2]))) addr = int(serLineParts[2]) addrhex = "{0:x}".format(int(serLineParts[2])) lastUpdate = sensors_lastUpdate.get(addr, None) lastTemp = sensors_lastTemp.get(addr, None) lastHum = sensors_lastHum.get(addr, None) currentsensor_name = sensors_id_to_name.get(addr, None) # extract sensor data received from JeeLink if int(serLineParts[3]) >= 128: batt_new = 1 type = int(serLineParts[3]) - 128 else: batt_new = 0 type = int(serLineParts[3]) temp = (int(serLineParts[4])*256 + int(serLineParts[5]) - 1000)/10.0 if int(serLineParts[6]) >= 128: batt_low = 1 hum = int(serLineParts[6]) - 128 else: batt_low = 0 hum = int(serLineParts[6]) if hum > 100: hum = 100 if batt_new == 1: sensors_batteryState[addr] = 2 elif batt_low == 1: sensors_batteryState[addr] = 1 else: sensors_batteryState[addr] = 0 lastValues_lastIndex = sensors_lastValues_lastIndex.get(addr, None) if sensors_lastValues_temp.get(addr, None) == None: sensors_lastValues_temp[addr] = [None] * average_value_steps if sensors_lastValues_hum.get(addr, None) == None: sensors_lastValues_hum[addr] = [None] * average_value_steps data_okay = False if sensors_lastReceivedValue_temp.get(addr, None) == None: # this is the first time we receive from that sensor in that session if verbosemode: print("first received from sensor",str(addr)) sensors_lastReceivedValue_temp[addr] = temp sensors_lastReceivedTime[addr] = int(time.time()) #lastValues_lastIndex = 0 else: lastValue = sensors_lastReceivedValue_temp.get(addr, None) max_off_value = float(config['sensors'].get('max_off_value')) ignore_off_value_timeout = int(config['sensors'].get('ignore_off_value_timeout')) if lastValue != None and ((temp >= (lastValue - max_off_value) and temp <= (lastValue + max_off_value)) or ((int(time.time()) - sensors_lastReceivedTime.get(addr)) > ignore_off_value_timeout)): # discard off values sensors_lastReceivedValue_temp[addr] = temp sensors_lastReceivedTime[addr] = int(time.time()) #print("Last Value=",lastValue,"currValue=",temp) data_okay = True else: if verbosemode: print("skipped sensor reading - Last Value=",lastValue,"currValue=",temp) if data_okay: if lastValues_lastIndex == None: lastValues_lastIndex = 0 elif lastValues_lastIndex == (average_value_steps - 1): lastValues_lastIndex = 0 else: lastValues_lastIndex += 1 if verbosemode: print("lastValues_lastIndex =", lastValues_lastIndex) sensors_lastValues_lastIndex[addr] = lastValues_lastIndex sensors_lastValues_temp[addr][lastValues_lastIndex] = temp sensors_lastValues_hum[addr][lastValues_lastIndex] = hum sensors_lastUpdate[addr] = int(time.time()) if verbosemode: print("sensors_lastValues_temp =", sensors_lastValues_temp[addr]) if currentsensor_name is None: if batt_new == 1 and not sensors_new_alreadyNotified.get('addr', False): notifystr = "NEW sensor with ID " + str(addr) mqttc.publish(mqtt_topic_prefix+"/" + mqtt_subtopic_notify, notifystr, qos=0, retain=False) if not os.path.exists(log_path+'/new'): os.makedirs(log_path+'/new') fname = log_path + '/new/' + str(addr) if not os.path.exists(fname): try: touch(fname) except: pass try: f = open(log_path+'/'+logfile_new_sensors, 'a') f.write(str(datetime.now())+": "+notifystr+"\n") f.close() except: # guat dann hoit ned... pass sensors_new_alreadyNotified[addr] = True else: if not os.path.exists(log_path+'/unknown'): os.makedirs(log_path+'/unknown') fname = log_path + '/unknown/' + str(addr) if not os.path.exists(fname): try: touch(fname) except: pass if verbosemode: print("unknown sensor ID " + str(addr)) if verbosemode: print("addr: " + str(addr) + " = 0x" + str(addrhex) + " batt_new: " + str(batt_new) + " type: " + str(type) + " batt_low: " + str(batt_low) + " temp: " + str(temp) + " hum: " + str(hum) + " Name: " + str(currentsensor_name)) print() #if senddata: # sensors_lastUpdate[str(addr)] = int(time.time()) # sensors_lastTemp[str(addr)] = temp # sensors_lastHum[str(addr)] = hum # # isAtemp = False # if int(currentsensor_idx) == atemp_sensor_idx: # atemp1 = temp # ahum1 = hum # isAtemp = True # elif int(currentsensor_idx) == atemp_sensor_idx_2: # atemp2 = temp # ahum2 = hum # isAtemp = True # # if isAtemp: # if atemp1 <= atemp2: # atemp = atemp1 # ahum = ahum1 # else: # atemp = atemp2 # ahum = ahum2 # # if atemp < 61 and ahum < 101: # if atemp != atemp_last or ahum != ahum_last or ((time.time() - atemphum_lastUpdate) > aTempHumPublishInterval): # atemphum_lastUpdate = time.time() # atemp_last = atemp # ahum_last = ahum # mqttc.publish(mqtt_topic_atemp, str(atemp), qos=0, retain=True) # mqttc.publish(mqtt_topic_ahum, str(ahum), qos=0, retain=True) # mqttc.publish(mqtt_topic_atemphum_lastUpdate, strftime("%Y-%m-%d %H:%M:%S", localtime()), qos=0, retain=False) # # domoticz_json = "{\"idx\":" + str(currentsensor_idx) + ",\"nvalue\":0,\"svalue\":\"" + str(temp) + ";" + str(hum) + ";1\"}" # #if verbosemode: # # print(domoticz_json) # mqttc.publish(mqtt_topic_domoticz_in, domoticz_json, qos=0, retain=False) # # mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/temperature", str(temp), qos=0, retain=False) # mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/humidity", str(hum), qos=0, retain=False) # mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/battery", str(batterystate), qos=0, retain=False) # mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/lastUpdate", strftime("%Y-%m-%d %H:%M:%S", localtime()), qos=0, retain=False) # mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/availability", "available", qos=0, retain=False) # # lacrosse_json = "{\"temperature\":" + str(temp) + ", \"humidity\":" + str(hum) + ", \"battery\":\"" + str(batterystate) + "\"}" # mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/json", lacrosse_json, qos=0, retain=False) # # tmptext = str(temp) + "° " + str(hum) + "%" # mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/TempHumText", tmptext, qos=0, retain=False) # # if verbosemode: # print("MQTT published") # # try: # touch("/tmp/jeelink2mqtt_running") # except: # # guat dann ned... # pass # #else: # if verbosemode: # if currentsensor_name is None: # print("MQTT published") # else: # print("MQTT publishing surpressed (interval not expired)") # # #if verbosemode: # print("\n") # publish on MQTT on set interval publishNow = False if (int(time.time()) - lastPublishTime) > int(config['sensors'].get('publish_interval')): if lastPublishTime == 0: lastPublishTime = int(time.time()) else: publishNow = True lastPublishTime = int(time.time()) #for sensor in #sensors_lastReceivedTime[str(addr)] # store to InfluxDB on set interval storeNow = False if (int(time.time()) - lastStoreTime) > int(config['sensors'].get('store_interval')): if lastStoreTime == 0: lastStoreTime = int(time.time()) else: storeNow = True lastStoreTime = int(time.time()) if publishNow or storeNow: #print("available sensor data: ", sensors_lastUpdate) for id in sensors_lastUpdate: if (time.time() - sensors_lastUpdate[id]) < sensordata_maxage: s_name = sensors_id_to_name.get(id, None) if verbosemode: print("current data available for:", id, s_name) sensorDataComplete = True sum_temp=0 for val in sensors_lastValues_temp[id]: if val is None: sensorDataComplete = False else: sum_temp = sum_temp + val sum_hum=0 for val in sensors_lastValues_hum[id]: if val is None: sensorDataComplete = False else: sum_hum = sum_hum + val if sensorDataComplete: s_currAvgTemp = round(sum_temp / len(sensors_lastValues_temp[id]), 1) s_currAvgHum = int(sum_hum / len(sensors_lastValues_hum[id])) sensors_lastAvgValue_temp[id] = s_currAvgTemp sensors_lastAvgValue_hum[id] = s_currAvgHum if verbosemode: print("s_currAvgTemp =", s_currAvgTemp, "s_currAvgHum =", s_currAvgHum) else: if verbosemode: print("s_currAvgTemp/s_currAvgHum: not yet enough readings available") if sensorDataComplete: if sensors_batteryState.get(id,None) == 2: s_battNew = True s_battState = "NEW" elif sensors_batteryState.get(id, None) == 1: s_battNew = False s_battState = "LOW" elif sensors_batteryState.get(id, None) == 0: s_battNew = False s_battState = "OK" if s_name is not None: s_domIdx = sensors_yaml[s_name].get('DomoticzIdx', None) s_topic_temp = sensors_yaml[s_name].get('Topic_Temp', None) s_topic_hum = sensors_yaml[s_name].get('Topic_Hum', None) s_influxInstance = sensors_yaml[s_name].get('InfluxDB_Instance', None) s_isOutsideTempSensor = sensors_yaml[s_name].get('isOutsideTempSensor', None) if s_domIdx is not None and publishNow: domoticz_json = "{\"idx\":" + str(s_domIdx) + ",\"nvalue\":0,\"svalue\":\"" + str(s_currAvgTemp) + ";" + str(s_currAvgHum) + ";1\"}" if verbosemode: print("Domoticz JSON:", domoticz_json) mqttc.publish(mqtt_topic_domoticz_in, domoticz_json, qos=0, retain=False) if s_topic_temp is not None and len(s_topic_temp)>5 and publishNow: if verbosemode: print("publishing temp on ", s_topic_temp) mqttc.publish(s_topic_temp, str(s_currAvgTemp), qos=0, retain=False) if s_topic_hum is not None and len(s_topic_hum)>5 and publishNow: if verbosemode: print("publishing hum on ", s_topic_temp) mqttc.publish(s_topic_hum, str(s_currAvgHum), qos=0, retain=False) if publishNow: mqttc.publish(mqtt_topic_prefix+"/"+ s_name +"/temperature", str(s_currAvgTemp), qos=0, retain=False) mqttc.publish(mqtt_topic_prefix+"/"+ s_name +"/humidity", str(s_currAvgHum), qos=0, retain=False) mqttc.publish(mqtt_topic_prefix+"/"+ s_name +"/battery", s_battState, qos=0, retain=False) mqttc.publish(mqtt_topic_prefix+"/"+ s_name +"/availability", "available", qos=0, retain=False) mqttc.publish(mqtt_topic_prefix+"/"+ s_name +"/lastUpdate", strftime("%Y-%m-%d %H:%M:%S", localtime()), qos=0, retain=False) lacrosse_json = "{\"temperature\":" + str(s_currAvgTemp) + ", \"humidity\":" + str(s_currAvgHum) + ", \"battery\":\"" + str(s_battState) + "\"}" mqttc.publish(mqtt_topic_prefix+"/"+ s_name +"/json", lacrosse_json, qos=0, retain=False) tmptext = str(s_currAvgTemp) + "° " + str(s_currAvgHum) + "%" mqttc.publish(mqtt_topic_prefix+"/"+ s_name +"/TempHumText", tmptext, qos=0, retain=False) if s_influxInstance is not None and storeNow: ### write to InfluxDB here if s_influxInstance in influxdb_yaml: influx_measurement = influxdb_yaml[s_influxInstance].get('measurement', None) t_utc = datetime.utcnow() t_str = t_utc.isoformat() + 'Z' if influx_measurement is not None: influx_fieldnames = influxdb_yaml[s_influxInstance].get('fieldnames', None) if influx_fieldnames == None: influx_fieldname_temperature = influx_default_fieldname_temperature influx_fieldname_humidity = influx_default_fieldname_humidity else: if influxdb_yaml[s_influxInstance]['fieldnames'].get('temperature', None) != None: influx_fieldname_temperature = influxdb_yaml[s_influxInstance]['fieldnames'].get('temperature') else: influx_fieldname_temperature = influx_default_fieldname_temperature if influxdb_yaml[s_influxInstance]['fieldnames'].get('humidity', None) != None: influx_fieldname_humidity = influxdb_yaml[s_influxInstance]['fieldnames'].get('humidity') else: influx_fieldname_humidity = influx_default_fieldname_humidity influx_datatypes = influxdb_yaml[s_influxInstance].get('datatypes', None) if influx_datatypes == None: influx_datatype_temperature = influx_default_datatype_temperature influx_datatype_humidity = influx_default_datatype_humidity else: if influxdb_yaml[s_influxInstance]['datatypes'].get('temperature', None) != None: tmpdt = influxdb_yaml[s_influxInstance]['datatypes'].get('temperature') if tmpdt == 'float' or tmpdt == 'int': influx_datatype_temperature = tmpdt else: influx_datatype_temperature = influx_default_datatype_temperature else: influx_datatype_temperature = influx_default_datatype_temperature if influxdb_yaml[s_influxInstance]['datatypes'].get('humidity', None) != None: tmpdt = influxdb_yaml[s_influxInstance]['datatypes'].get('humidity') if tmpdt == 'float' or tmpdt == 'int': influx_datatype_humidity = tmpdt else: influx_datatype_humidity = influx_default_datatype_humidity else: influx_datatype_humidity = influx_default_datatype_humidity if influx_datatype_temperature == 'int': influx_value_temp = int(s_currAvgTemp) else: influx_value_temp = float(s_currAvgTemp) if influx_datatype_humidity == 'int': influx_value_hum = int(s_currAvgHum) else: influx_value_hum = float(s_currAvgHum) influx_json = [ { 'measurement': influx_measurement, 'tags': { 'sensor': s_name }, 'time': t_str, 'fields': { influx_fieldname_temperature: influx_value_temp, influx_fieldname_humidity: influx_value_hum } } ] try: if verbosemode: print("write to InfluxDB...") influxclient[s_influxInstance].write_points(influx_json) if verbosemode: print("DONE!") except Exception as e: print("Error writing to InfluxDB") print(e) else: if verbosemode: print("Error: invalid InfluxDB instance '" + s_influxInstance + "' configured for sensor '" + s_name + "'") else: # this is an unknown sensor if publishNow: if s_battNew: mqttc.publish(mqtt_topic_prefix+"/NewUnknownSensor/"+str(id)+"/temperature", str(s_currAvgTemp), qos=0, retain=False) mqttc.publish(mqtt_topic_prefix+"/NewUnknownSensor/"+str(id)+"/humidity", str(s_currAvgHum), qos=0, retain=False) else: mqttc.publish(mqtt_topic_prefix+"/UnknownSensor/"+str(id)+"/temperature", str(s_currAvgTemp), qos=0, retain=False) mqttc.publish(mqtt_topic_prefix+"/UnknownSensor/"+str(id)+"/humidity", str(s_currAvgHum), qos=0, retain=False) mqttc.publish(mqtt_topic_prefix+"/UnknownSensor/"+str(id)+"/battery", s_battState, qos=0, retain=False) if verbosemode: print() # outside sensors if (int(time.time()) - outSens_lastRun) > outSens_interval: outSens_lastRun = int(time.time()) sum_out_sensors_temp = 0 sum_out_sensors_temp_min = 100 sum_out_sensors_temp_max = -50 sum_out_sensors_hum = 0 sum_out_sensors_hum_min = 100 sum_out_sensors_hum_max = -50 count_used_out_sensors = 0 for id in sensors_outside_sensors: lupd = sensors_lastUpdate.get(id, None) tdiff = 0 if lupd is not None: tdiff = int(time.time()) - lupd if lupd is not None and (tdiff < sensordata_maxage): tmpval_t = sensors_lastAvgValue_temp.get(id, None) tmpval_h = sensors_lastAvgValue_hum.get(id, None) if tmpval_t is not None and tmpval_h is not None: sum_out_sensors_temp = sum_out_sensors_temp + tmpval_t sum_out_sensors_hum = sum_out_sensors_hum + tmpval_h if tmpval_t < sum_out_sensors_temp_min: sum_out_sensors_temp_min = tmpval_t if tmpval_t < sum_out_sensors_hum_min: sum_out_sensors_hum_min = tmpval_h if tmpval_t > sum_out_sensors_temp_max: sum_out_sensors_temp_max = tmpval_t if tmpval_t > sum_out_sensors_hum_max: sum_out_sensors_hum_max = tmpval_h count_used_out_sensors += 1 lacrosse_json = None if count_used_out_sensors > 0: out_temp_avg = round(sum_out_sensors_temp / count_used_out_sensors, 1) out_hum_avg = int(round(sum_out_sensors_hum / count_used_out_sensors)) mqttc.publish(mqtt_topic_atemp, str(out_temp_avg), qos=0, retain=True) mqttc.publish(mqtt_topic_ahum, str(out_hum_avg), qos=0, retain=True) mqttc.publish(topic_prefix_outside_temphum + '/temperature', str(out_temp_avg), qos=0, retain=True) mqttc.publish(topic_prefix_outside_temphum + '/humidity', str(out_hum_avg), qos=0, retain=True) mqttc.publish(topic_prefix_outside_temphum + '/lastUpdate', strftime("%Y-%m-%d %H:%M:%S", localtime()), qos=0, retain=True) tmptext = str(out_temp_avg) + "° " + str(out_hum_avg) + "%" mqttc.publish(topic_prefix_outside_temphum + "/TempHumText", tmptext, qos=0, retain=False) lacrosse_json = "{\"temperature\":" + str(out_temp_avg) + ", \"humidity\":" + str(out_hum_avg) + "\", \"usedSensors\":" + str(count_used_out_sensors) + "}" min = 100 max = 100 if count_used_out_sensors > 1: mqttc.publish(topic_prefix_outside_temphum + '/usedSensors', str(count_used_out_sensors), qos=0, retain=True) lacrosse_json = "{\"temperature\":" + str(out_temp_avg) + ", \"humidity\":" + str(out_hum_avg) + ", \"usedSensors\":" + str(count_used_out_sensors) if sum_out_sensors_temp_min < 100: mqttc.publish(topic_prefix_outside_temphum + '/temp_min', str(sum_out_sensors_temp_min), qos=0, retain=False) lacrosse_json = lacrosse_json + ", \"temp_min\":" + str(sum_out_sensors_temp_min) if sum_out_sensors_temp_max > -50: mqttc.publish(topic_prefix_outside_temphum + '/temp_max', str(sum_out_sensors_temp_max), qos=0, retain=False) lacrosse_json = lacrosse_json + ", \"temp_max\":" + str(sum_out_sensors_temp_max) if sum_out_sensors_hum_min < 100: mqttc.publish(topic_prefix_outside_temphum + '/hum_min', str(sum_out_sensors_hum_min), qos=0, retain=False) lacrosse_json = lacrosse_json + ", \"hum_min\":" + str(sum_out_sensors_hum_min) if sum_out_sensors_hum_max > -50: mqttc.publish(topic_prefix_outside_temphum + '/hum_max', str(sum_out_sensors_hum_max), qos=0, retain=False) lacrosse_json = lacrosse_json + ", \"hum_max\":" + str(sum_out_sensors_hum_max) lacrosse_json = lacrosse_json + "}" if lacrosse_json is not None: mqttc.publish(topic_prefix_outside_temphum + "/json", lacrosse_json, qos=0, retain=False) # handle outdated sensor values once a minute if (int(time.time()) - checkLastUpdateInterval_lastRun) > checkLastUpdateInterval: checkLastUpdateInterval_lastRun = int(time.time()) #print("check lastUpdate") for key in sensors_yaml: #print(key, '->', sensors_yaml[key]) #print("Sensor name:", key) sensorId = sensors_yaml[key].get('LaCrosseID', None) if sensorId is not None: lupd = sensors_lastUpdate.get(sensorId, None) tdiff = 0 if lupd is not None: tdiff = int(time.time()) - lupd if lupd is None or (tdiff > sensordata_maxage): mqttc.publish(mqtt_topic_prefix+"/"+ key +"/availability", "unavailable", qos=0, retain=False) notifystr = "received no data from sensor '" + key + "' with ID " + str(sensorId) + " for " + str(tdiff) + "s" mqttc.publish(mqtt_topic_prefix+"/" + mqtt_subtopic_notify, notifystr, qos=0, retain=False) except KeyboardInterrupt: print('\n') exit()