jeelink2mqtt.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #!/usr/bin/python -u
  2. # -*- coding: utf-8 -*-
  3. #
  4. import serial
  5. import time
  6. import os
  7. import paho.mqtt.client as mqtt
  8. #import json
  9. #import math
  10. #import numpy as np
  11. #import httplib
  12. verbosemode = False
  13. def touch(fname, times=None):
  14. with open(fname, 'a'):
  15. os.utime(fname, times)
  16. def on_connect(client, userdata, flags, rc):
  17. print("MQTT connected with result code " + str(rc))
  18. #client.subscribe("wetter/atemp")
  19. def on_disconnect(client, userdata, rc):
  20. if rc != 0:
  21. print "Unexpected MQTT disconnection. Will auto-reconnect"
  22. #def on_message(client, userdata, msg):
  23. # #print(msg.topic + " " + str(msg.payload))
  24. # global atemp
  25. # atemp = msg.payload
  26. minUpdateInterval = 60
  27. mqtt_topic_prefix = "LaCrosse"
  28. override_updateinterval_on_change = False
  29. atemp_sensor_idx = 94
  30. sensors = {}
  31. sensors_idx = {}
  32. with open("/home/pi/jeelink_sensors.csv", "r") as sensorscsv:
  33. for line in sensorscsv:
  34. if line.find('ID,DomoticzIdx,Name') == -1:
  35. # nur Zeilen die nicht der header sind sind interessant
  36. line = line.strip('\r')
  37. line = line.strip('\n')
  38. parts = line.split(',')
  39. sensorId = parts[0]
  40. domoticzIdx = parts[1]
  41. sensorName = parts[2]
  42. sensors[str(sensorId)] = str(sensorName)
  43. sensors_idx[str(sensorId)] = str(domoticzIdx)
  44. mqttc = mqtt.Client()
  45. mqttc.on_connect = on_connect
  46. mqttc.on_disconnect = on_disconnect
  47. ##mqttc.on_message = on_message
  48. mqttc.connect("10.1.1.11", 1883, 60)
  49. mqttc.loop_start()
  50. #mqttc.loop_forever()
  51. ser = serial.Serial(port='/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AL01MYTF-if00-port0',
  52. baudrate = 57600,
  53. parity=serial.PARITY_NONE,
  54. stopbits=serial.STOPBITS_ONE,
  55. bytesize=serial.EIGHTBITS,
  56. timeout=1)
  57. #sensors = {'4':'Arbeitszimmer','16':'AussenGarten','60':'AussenParkplatz','50':'Bad','39':'Balkon','55':'Kueche','40':'Schlafzimmer'}
  58. #sensors_idx = {'4':'1','16':'94','60':'113','50':'4','39':'88','55':'6','40':'3'}
  59. if verbosemode:
  60. print sensors
  61. print sensors_idx
  62. sensors_lastTemp = {}
  63. sensors_lastHum = {}
  64. sensors_lastUpdate = {}
  65. try:
  66. while True:
  67. msg_was_sent = 0
  68. #clear serial buffer to remove junk and noise
  69. ser.flushInput()
  70. #read buffer until cr/lf
  71. serLine = ser.readline()
  72. if(serLine):
  73. #print (repr(serLine)) #Echo the serial buffer bytes up to the CRLF back to screen
  74. serLine = serLine.strip('\r')
  75. serLine = serLine.strip('\n')
  76. if verbosemode:
  77. print serLine
  78. if serLine.find('OK 9') != -1:
  79. # uns interessieren nur reinkommende Zeilen die mit "OK 9 " beginnen
  80. # 0 1 2 3 4 5 6
  81. # OK 9 ID XXX XXX XXX XXX
  82. # | | | | | | |
  83. # | | | | | | --- Humidity incl. WeakBatteryFlag
  84. # | | | | | |------ Temp * 10 + 1000 LSB
  85. # | | | | |---------- Temp * 10 + 1000 MSB
  86. # | | | |-------------- Sensor type (1 or 2) +128 if NewBatteryFlag
  87. # | | |----------------- Sensor ID
  88. # | |------------------- fix "9"
  89. # |---------------------- fix "OK"
  90. bytes = serLine.split(' ')
  91. #addr = bytes[2]
  92. #addr = "{0:x}".format(int(bytes[2]))
  93. #addr = hex((int(bytes[2])))
  94. addr = int(bytes[2])
  95. addrhex = "{0:x}".format(int(bytes[2]))
  96. currentsensor_name = sensors.get(str(addr), None)
  97. #if currentsensor_name == 0:
  98. if currentsensor_name is None:
  99. fname = '/home/pi/logs/jeelink_unknown_sensor_' + str(addr)
  100. try:
  101. touch(fname)
  102. except:
  103. # guat dann hoit ned...
  104. pass
  105. if verbosemode:
  106. print "unknown sensor ID " + str(addr)
  107. temp = (int(bytes[4])*256 + int(bytes[5]) - 1000)/10.0
  108. print "Temp: " + str(temp)
  109. lastUpdate = sensors_lastUpdate.get(str(addr), None)
  110. lastTemp = sensors_lastTemp.get(str(addr), None)
  111. lastHum = sensors_lastHum.get(str(addr), None)
  112. currentsensor_idx = sensors_idx.get(str(addr),None)
  113. senddata = False
  114. if currentsensor_idx is not None:
  115. if override_updateinterval_on_change:
  116. if lastTemp != str(temp) or lastHum != str(hum):
  117. senddata = True
  118. #print "hier! " + str(temp) + " != " + str(lastTemp) + " " + str(hum) + " != " + str(lastHum)
  119. if lastUpdate is not None:
  120. timediff = int(time.time()) - lastUpdate
  121. if timediff >= minUpdateInterval:
  122. senddata = True
  123. #print "do!"
  124. else:
  125. senddata = True
  126. if senddata:
  127. if int(bytes[3]) >= 128:
  128. batt_new = 1
  129. type = int(bytes[3]) - 128
  130. else:
  131. batt_new = 0
  132. type = int(bytes[3])
  133. temp = (int(bytes[4])*256 + int(bytes[5]) - 1000)/10.0
  134. if int(bytes[6]) >= 128:
  135. batt_low = 1
  136. hum = int(bytes[6]) - 128
  137. else:
  138. batt_low = 0
  139. hum = int(bytes[6])
  140. if hum > 100:
  141. hum = 100
  142. if batt_low == 0:
  143. batterystate = "ok"
  144. else:
  145. batterystate = "low"
  146. sensors_lastUpdate[str(addr)] = int(time.time())
  147. sensors_lastTemp[str(addr)] = str(temp)
  148. sensors_lastHum[str(addr)] = str(hum)
  149. if int(currentsensor_idx) == atemp_sensor_idx:
  150. mqttc.publish("wetter/atemp", str(temp), qos=2, retain=True)
  151. mqttc.publish("wetter/ahum", str(hum), qos=2, retain=True)
  152. domoticz_json = "{\"idx\":" + str(currentsensor_idx) + ",\"nvalue\":0,\"svalue\":\"" + str(temp) + ";" + str(hum) + ";1\"}"
  153. if verbosemode:
  154. print domoticz_json
  155. mqttc.publish("domoticz/in", domoticz_json, qos=2, retain=False)
  156. mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/temperature", str(temp), qos=2, retain=True)
  157. mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/humidity", str(hum), qos=2, retain=True)
  158. mqttc.publish(mqtt_topic_prefix+"/"+str(currentsensor_name)+"/battery", str(batterystate), qos=2, retain=True)
  159. if verbosemode:
  160. 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)
  161. try:
  162. touch("/tmp/jeelink2mqtt_running")
  163. except:
  164. # guat dann ned...
  165. pass
  166. except KeyboardInterrupt, e:
  167. print('\n')