123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818 |
- #!/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 statistics
- #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 = False
- 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(' ')
-
- #print("Len: " + str(len(serLineParts)))
-
- if(len(serLineParts) == 7): # check correct size of incoming data
-
- #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")
-
- else:
- if verbosemode: print("ignored invalid sized data")
- pass
-
-
- # 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:
-
- # as Home Assistant MQTT binary sensor can only work with 2 states (unless using value templates):
- # -> removed "NEW" state string from /battery topic and added /batteryNew topic
- if sensors_batteryState.get(id,None) == 2:
- s_battNew = True
- s_battState = "OK"
- 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_battNew:
- s_battNew_str = "YES"
- else:
- s_battNew_str = "NO"
-
- 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 +"/batteryNew", s_battNew_str, 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)
- mqttc.publish(mqtt_topic_prefix+"/UnknownSensor/"+str(id)+"/batteryNew", s_battNew_str, 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
-
- # median
- out_sensors_temp_median_values = []
- out_sensors_hum_median_values = []
-
- 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
-
- # median
- out_sensors_temp_median_values.append(tmpval_t)
- out_sensors_hum_median_values.append(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))
-
- # median
- out_temp_median = statistics.median(out_sensors_temp_median_values)
- out_hum_median = statistics.median(out_sensors_hum_median_values)
-
- out_temp_publishvalue = out_temp_avg
- out_hum_publishvalue = out_hum_avg
- if(config['sensors'].get('outside_sensors_use_median')):
- out_temp_publishvalue = out_temp_median
- out_hum_publishvalue = out_hum_median
-
- mqttc.publish(mqtt_topic_atemp, str(out_temp_publishvalue), qos=0, retain=True)
- mqttc.publish(mqtt_topic_ahum, str(out_hum_publishvalue), qos=0, retain=True)
- mqttc.publish(topic_prefix_outside_temphum + '/temperature', str(out_temp_publishvalue), qos=0, retain=True)
- mqttc.publish(topic_prefix_outside_temphum + '/humidity', str(out_hum_publishvalue), qos=0, retain=True)
-
- mqttc.publish(topic_prefix_outside_temphum + '/temp_average', str(out_temp_avg), qos=0, retain=True)
- mqttc.publish(topic_prefix_outside_temphum + '/hum_average', str(out_hum_avg), qos=0, retain=True)
- mqttc.publish(topic_prefix_outside_temphum + '/temp_median', str(out_temp_median), qos=0, retain=True)
- mqttc.publish(topic_prefix_outside_temphum + '/hum_median', str(out_hum_median), 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_publishvalue) + "° " + str(out_hum_publishvalue) + "%"
- mqttc.publish(topic_prefix_outside_temphum + "/TempHumText", tmptext, qos=0, retain=False)
-
- lacrosse_json = "{\"temperature\":" + str(out_temp_publishvalue) + \
- ", \"humidity\":" + str(out_hum_publishvalue) + \
- "\", \"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_hum_publishvalue) + \
- ", \"humidity\":" + str(out_hum_publishvalue) + \
- ", \"usedSensors\":" + str(count_used_out_sensors) + \
- ", \"temp_average\":" + str(out_temp_avg) + \
- ", \"hum_average\":" + str(out_hum_avg) + \
- ", \"temp_median\":" + str(out_temp_median) + \
- ", \"hum_median\":" + str(out_temp_median)
-
- 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()
|