ioext.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/python3 -u
  2. #
  3. import serial
  4. from time import sleep
  5. import os
  6. import sys
  7. import paho.mqtt.client as mqtt
  8. import json
  9. from datetime import datetime
  10. # --- CONFIGURATION ---
  11. import config
  12. # --- END CONFIGURATION ---
  13. # --- GLOBAL VARS ---
  14. noReceiveCount = 0 # increase everytime the serial readline times out (1s timeout)
  15. #getStatusCount = 0 # used as heartbeat, get status every 30s
  16. verbose = False
  17. debug = False
  18. quiet = True
  19. lastState_P2 = None
  20. lastState_P3 = None
  21. lastState_P4 = None
  22. lastState_P5 = None
  23. # --- END GLOBAL VARS ---
  24. if len(sys.argv) >= 2:
  25. if sys.argv[1] == "-q":
  26. verbose = False
  27. debug = False
  28. quiet = True
  29. #print("VERBOSE=ON")
  30. elif sys.argv[1] == "-v":
  31. verbose = True
  32. debug = False
  33. quiet = False
  34. #print("VERBOSE=ON")
  35. elif sys.argv[1] == "-d":
  36. verbose = True
  37. quiet = False
  38. debug = True
  39. #print("DEBUG=ON")
  40. def on_connect(client, userdata, flags, rc):
  41. if not quiet:
  42. print("MQTT connected with result code " + str(rc))
  43. #client.subscribe(mqtt_topic_cmd)
  44. #def on_message(client, userdata, msg):
  45. # if msg.topic == mqtt_topic_cmd:
  46. # payload = msg.payload.decode('ascii')
  47. # if payload == "status" or payload == "get conf" or payload == "clear" or payload == "open door" or payload.startswith("set prof ") or payload.startswith("set conf "):
  48. # if verbose:
  49. # print("serCmd: " + payload)
  50. # serCmd = payload + '\n'
  51. # ser.write(serCmd.encode('ascii'))
  52. # elif verbose:
  53. # print("unknown command:", payload)
  54. def touch(fname, times=None):
  55. with open(fname, 'a'):
  56. os.utime(fname, times)
  57. mqttc = mqtt.Client()
  58. mqttc.on_connect = on_connect
  59. #mqttc.on_disconnect = on_disconnect
  60. #mqttc.on_message = on_message
  61. mqttc.username_pw_set(config.mqtt_user, config.mqtt_password)
  62. mqttc.connect(config.mqtt_server, config.mqtt_port, 60)
  63. mqttc.loop_start()
  64. ser = serial.Serial(port=config.serialPort,
  65. baudrate = config.serialBaud,
  66. parity=serial.PARITY_NONE,
  67. stopbits=serial.STOPBITS_ONE,
  68. bytesize=serial.EIGHTBITS,
  69. timeout=config.serialTimeout)
  70. try:
  71. while True:
  72. ##ser.flushInput() ## attention truncates incoming strings if there is little time between them
  73. #read buffer until cr/lf
  74. serLine = ser.readline().strip()
  75. # catch exception on invalid char coming in: UnicodeDecodeError: 'ascii' codec can't decode byte 0xf4 in position 6: ordinal not in range(128)
  76. try:
  77. serLine = serLine.decode('ascii')
  78. except:
  79. serLine = ""
  80. # if there came something in...
  81. if(serLine):
  82. noReceiveCount = 0
  83. # touch status file if configured
  84. try:
  85. config.statusFile
  86. except:
  87. if debug:
  88. print("statusFile not defined")
  89. else:
  90. if config.statusFile is not None and config.statusFile != "":
  91. try:
  92. touch(config.statusFile)
  93. except:
  94. if debug:
  95. print("ERROR - could not touch statusFile '" + str(config.statusFile) + "'")
  96. else:
  97. if debug:
  98. print("statusFile not configured")
  99. if verbose:
  100. print ('RX: ' + repr(serLine)) #Echo the serial buffer bytes up to the CRLF back to screen
  101. mqttc.publish(config.mqtt_base_topic + "/RX", str(serLine), qos=0, retain=False)
  102. # digital input P2
  103. if serLine.startswith('P2='):
  104. newState = None
  105. if serLine == "P2=L":
  106. newState = "OFF"
  107. elif serLine == "P2=H":
  108. newState = "ON"
  109. if newState is not None and (lastState_P2 != newState or not config.P2_MQTT_SendOnlyIfValueChanged):
  110. lastState_P2 = newState
  111. mqttc.publish(config.P2_MQTT_Topic, newState, qos=0, retain=config.P2_MQTT_SendRetained)
  112. if config.P2_MQTT_SendLastUpdate:
  113. mqttc.publish(config.P2_MQTT_Topic + "_lastUpdate", datetime.now().isoformat(), qos=0, retain=config.P2_MQTT_SendRetained)
  114. # digital input P3
  115. if serLine.startswith('P3='):
  116. newState = None
  117. if serLine == "P3=L":
  118. newState = "OFF"
  119. elif serLine == "P3=H":
  120. newState = "ON"
  121. if newState is not None and (lastState_P3 != newState or not config.P3_MQTT_SendOnlyIfValueChanged):
  122. lastState_P3 = newState
  123. mqttc.publish(config.P3_MQTT_Topic, newState, qos=0, retain=config.P3_MQTT_SendRetained)
  124. if config.P3_MQTT_SendLastUpdate:
  125. mqttc.publish(config.P3_MQTT_Topic + "_lastUpdate", datetime.now().isoformat(), qos=0, retain=config.P3_MQTT_SendRetained)
  126. # digital input P4
  127. if serLine.startswith('P4='):
  128. newState = None
  129. if serLine == "P4=L":
  130. newState = "OFF"
  131. elif serLine == "P4=H":
  132. newState = "ON"
  133. if newState is not None and (lastState_P4 != newState or not config.P4_MQTT_SendOnlyIfValueChanged):
  134. lastState_P4 = newState
  135. mqttc.publish(config.P4_MQTT_Topic, newState, qos=0, retain=config.P4_MQTT_SendRetained)
  136. if config.P4_MQTT_SendLastUpdate:
  137. mqttc.publish(config.P4_MQTT_Topic + "_lastUpdate", datetime.now().isoformat(), qos=0, retain=config.P4_MQTT_SendRetained)
  138. # digital input P5
  139. if serLine.startswith('P5='):
  140. newState = None
  141. if serLine == "P5=L":
  142. newState = "OFF"
  143. elif serLine == "P5=H":
  144. newState = "ON"
  145. if newState is not None and (lastState_P5 != newState or not config.P5_MQTT_SendOnlyIfValueChanged):
  146. lastState_P5 = newState
  147. mqttc.publish(config.P5_MQTT_Topic, newState, qos=0, retain=config.P5_MQTT_SendRetained)
  148. if config.P5_MQTT_SendLastUpdate:
  149. mqttc.publish(config.P5_MQTT_Topic + "_lastUpdate", datetime.now().isoformat(), qos=0, retain=config.P5_MQTT_SendRetained)
  150. # DHT TH sensor
  151. # {"T":26.60,"H":36}
  152. if serLine.startswith('{"T":'):
  153. th = json.loads(serLine)
  154. t = round(float(th["T"]), 1)
  155. h = int(th["H"])
  156. if t >= -20 and t <= 50:
  157. mqttc.publish(config.DHT22_MQTT_Topic_Temp, str(t), qos=0, retain=config.DHT22_MQTT_SendRetained)
  158. if h >= 0 and h <= 100:
  159. mqttc.publish(config.DHT22_MQTT_Topic_Hum, str(h), qos=0, retain=config.DHT22_MQTT_SendRetained)
  160. if config.DHT22_MQTT_SendLastUpdate:
  161. mqttc.publish(config.DHT22_MQTT_Topic_Temp + "_lastUpdate", datetime.now().isoformat(), qos=0, retain=config.DHT22_MQTT_SendRetained)
  162. # nothing came in this time...
  163. else:
  164. noReceiveCount += 1
  165. if debug:
  166. print("noReceiveCount=" + str(noReceiveCount))
  167. # quit script if nothing has been received for some time - will be restarted by systemd
  168. if noReceiveCount >= config.quitOnNoReceiveTimeout:
  169. quit()
  170. except KeyboardInterrupt:
  171. print('\n')