Browse Source

add features:
- enable verbose mode via "-v" commandline switch
- use 2 sensors as "atemp" source - value is taken from the one with the lower reading (prevent wrong readings due to sunlight)
- fixed: send updated values if they changed even if interval is not yet expired
- fixed: catch exception on invalid char coming in (UnicodeDecodeError: 'ascii' codec can't decode byte 0xf4 in position 6: ordinal not in range(128))
- improved verbose output
- minor fixes

FloKra 4 years ago
parent
commit
0861bdbc43
1 changed files with 99 additions and 39 deletions
  1. 99 39
      src/jeelink2mqtt.py

+ 99 - 39
src/jeelink2mqtt.py

@@ -10,6 +10,7 @@ import time
 from time import localtime, strftime   
 
 import os
+import sys
 import paho.mqtt.client as mqtt
 #import json
 #import math
@@ -25,18 +26,22 @@ sensordata_maxage = 300
 
 verbosemode = False
 
+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))
+        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")
+        print("Unexpected MQTT disconnection. Will auto-reconnect\n")
         
 #def on_message(client, userdata, msg):
 #    #print(msg.topic + " " + str(msg.payload))
@@ -48,6 +53,16 @@ minUpdateInterval = 60
 mqtt_topic_prefix = "LaCrosse"
 override_updateinterval_on_change = False
 atemp_sensor_idx = 94
+atemp_sensor_idx_2 = 113
+
+atemp = 61 #starting values only..
+ahum = 101
+atemp1 = 61
+ahum1 = 101
+atemp2 = 61
+ahum2 = 101
+atemp_last = 61
+ahum_last = 101
 
 checkLastUpdateInterval = 60
 checkLastUpdateInterval_lastRun = 0
@@ -59,6 +74,11 @@ sensors_lastHum = {}
 sensors_lastUpdate = {}
 sensors_unavailable = {}
 
+if verbosemode:
+    print("JeeLink2MQTT by Flo Kra")
+    print("=======================================================================")
+    print("loading sensors assignment: ")
+
 with open("/home/pi/jeelink_sensors.csv", "r") as sensorscsv:
     for line in sensorscsv:
         if line.find('ID,DomoticzIdx,Name') == -1:
@@ -76,8 +96,11 @@ with open("/home/pi/jeelink_sensors.csv", "r") as sensorscsv:
             sensors_lastUpdate[str(sensorId)] = 0
             sensors_unavailable[str(sensorId)] = 1 #will be overwritten when first value is received
             if verbosemode:
-                print("Sensor " + sensorId + " = '" + sensorName + "'")
+                idhex = "{0:x}".format(int(sensorId))
+                print("Sensor " + sensorId + " = 0x" + str(idhex) + ", Idx = " + str(domoticzIdx) + ", Name = '" + sensorName + "'")
 
+if verbosemode:
+    print("\n")
             
 mqttc = mqtt.Client()
 mqttc.on_connect = on_connect
@@ -100,9 +123,9 @@ ser = serial.Serial(port='/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AL01MYTF-if
 #sensors = {'4':'Arbeitszimmer','16':'AussenGarten','60':'AussenParkplatz','50':'Bad','39':'Balkon','55':'Kueche','40':'Schlafzimmer'}
 #sensors_idx = {'4':'1','16':'94','60':'113','50':'4','39':'88','55':'6','40':'3'}
 
-if verbosemode:
-    print(sensors)
-    print(sensors_idx)
+#if verbosemode:
+#    print(sensors)
+#    print(sensors_idx)
     
 
 checkLastUpdateInterval_lastRun = time.time() # first check after 1 min
@@ -116,14 +139,16 @@ try:
         
         #read buffer until cr/lf
         serLine = ser.readline().strip()
-        serLine = serLine.decode('ascii')
+        # 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 verbosemode:
-                print(serLine)
             if serLine.find('OK 9') != -1:
                 if verbosemode:
-                    print("is LaCrosse sensor")
+                    print(serLine + " = LaCrosse sensor")
 
                 # uns interessieren nur reinkommende Zeilen die mit "OK 9 " beginnen
                 
@@ -153,25 +178,6 @@ try:
                 currentsensor_idx = sensors_idx.get(str(addr),None)
                 currentsensor_name = sensors.get(str(addr), None)
                 
-                senddata = False
-                if currentsensor_idx is not None:
-                    if override_updateinterval_on_change:
-                        if lastTemp != str(temp) or lastHum != str(hum):
-                            senddata = True
-                            #print "hier! " + str(temp) + " != " + str(lastTemp) + "    " + str(hum) + " != " + str(lastHum)
-                            
-                    if lastUpdate is not None:
-                        timediff = int(time.time()) - lastUpdate
-                        if timediff >= minUpdateInterval:
-                            senddata = True
-                        elif sensors_unavailable[str(addr)] == 1:
-                            senddata = True
-                    else:
-                        senddata = True
-                
-                    sensors_unavailable[str(addr)] = 0
-                    #print(sensors_unavailable)
-                
                 if int(serLineParts[3]) >= 128: 
                     batt_new = 1
                     type = int(serLineParts[3]) - 128
@@ -195,6 +201,25 @@ try:
                 else:
                     batterystate = "low"
                 
+                senddata = False
+                if currentsensor_idx is not None:
+                    if override_updateinterval_on_change:
+                        if lastTemp != temp or lastHum != hum:
+                            senddata = True
+                            if verbosemode:
+                                print("override interval (value changed): " + str(temp) + " != " + str(lastTemp) + "    " + str(hum) + " != " + str(lastHum))
+                            
+                    if lastUpdate is not None:
+                        timediff = int(time.time()) - lastUpdate
+                        if timediff >= minUpdateInterval:
+                            senddata = True
+                        elif sensors_unavailable[str(addr)] == 1:
+                            senddata = True
+                    else:
+                        senddata = True
+                
+                    sensors_unavailable[str(addr)] = 0
+                    #print(sensors_unavailable)
                 
                 if currentsensor_name is None: 
                     if batt_new == 1:
@@ -211,24 +236,47 @@ try:
                     temp = (int(serLineParts[4])*256 + int(serLineParts[5]) - 1000)/10.0
                     if verbosemode:
                         print("unknown sensor ID " + str(addr))
-                        print("Temp: " + str(temp))
                     mqttc.publish(mqtt_topic_prefix+"/UnknownSensor/"+str(addr)+"/temperature", str(temp), qos=2, retain=False)
                     mqttc.publish(mqtt_topic_prefix+"/UnknownSensor/"+str(addr)+"/humidity", str(hum), qos=2, retain=False)
                     mqttc.publish(mqtt_topic_prefix+"/UnknownSensor/"+str(addr)+"/battNew", str(batt_new), qos=2, retain=False)
+
                 
+                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))
                 
                 if senddata:
                     sensors_lastUpdate[str(addr)] = int(time.time())
-                    sensors_lastTemp[str(addr)] = str(temp)
-                    sensors_lastHum[str(addr)] = str(hum)
+                    sensors_lastTemp[str(addr)] = temp
+                    sensors_lastHum[str(addr)] = hum
                     
+                    isAtemp = False
                     if int(currentsensor_idx) == atemp_sensor_idx:
-                        mqttc.publish("wetter/atemp", str(temp), qos=2, retain=True)
-                        mqttc.publish("wetter/ahum", str(hum), qos=2, retain=True)
+                        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:
+                                atemp_last = atemp
+                                ahum_last = ahum
+                                mqttc.publish("wetter/atemp", str(atemp), qos=2, retain=True)
+                                mqttc.publish("wetter/ahum", str(ahum), qos=2, retain=True)
                     
                     domoticz_json = "{\"idx\":" + str(currentsensor_idx) + ",\"nvalue\":0,\"svalue\":\"" + str(temp) + ";" + str(hum) + ";1\"}"
-                    if verbosemode:
-                        print(domoticz_json)
+                    #if verbosemode:
+                    #    print(domoticz_json)
                     mqttc.publish("domoticz/in", domoticz_json, qos=2, retain=False)
                     
                     mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/temperature", str(temp), qos=2, retain=False)
@@ -241,14 +289,24 @@ try:
                     mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/json", lacrosse_json, qos=2, retain=False)
                     
                     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("\n")
+                        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")
                         
         # handle outdated sensor values once a minute
         if (time.time() - checkLastUpdateInterval_lastRun) > checkLastUpdateInterval:
@@ -257,9 +315,11 @@ try:
             for key in sensors_lastUpdate:
                 #print(key, '->', sensors_lastUpdate[key], '->', sensors[key])
                 if (time.time() - sensors_lastUpdate[key]) > sensordata_maxage:
-                    print(sensors[key], ' outd ->')
+                    if verbosemode:
+                        print(sensors[key], ' outd ->')
                     sensors_unavailable[key] = 1
                     mqttc.publish(mqtt_topic_prefix+"/"+str(sensors[key])+"/availability", "unavailable", qos=2, retain=False)
 
 except KeyboardInterrupt:
     print('\n')
+    exit()