#! /usr/bin/python3 import time import sys from paho.mqtt import client as mqtt_client import os import serial MAXIMUM_COMMUNICATION_FAILURE=100 TEMPERATUR_MIN_DIFFERENCE = 2 TARGET_MIN_DIFFERENCE = 1 RPM_MIN_DIFFERENCE = 50 # MQTT Settings mqtt_server=os.environ['MQTT_SERVER'] mqtt_topic=os.environ['MQTT_TOPIC'] # SERIAL Port serial_device=os.environ['SERIAL_DEVICE'] # Start mqtt client_id = f'python-fan-ctrl' client = mqtt_client.Client(mqtt_client.CallbackAPIVersion.VERSION2) # Start Serial communication ser = serial.Serial(serial_device, 115200, timeout=1) # open serial port # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): print(msg.topic+" "+str(msg.payload)) # Handle MQTT Commands def on_connect(mqttc, obj, flags, reason_code, properties): client.subscribe(mqtt_topic + "cmd/led") client.subscribe(mqtt_topic + "cmd/rpm") print("Connected: " + str(reason_code)) client.on_message = on_message client.on_connect = on_connect if (not (mqtt_server)): print("MQTT_SERVER is not set") if (not (mqtt_topic)): print("MQTT_TOPIC is not set") # Start MQTT Client client.connect(mqtt_server, 1883) client.loop_start() client.publish(mqtt_topic + "device", ser.name) # check which port was really used SerialCommunicationFailureCounter=0 # store last published value lastTemperatur = -1 lastRPM = -1 lastTarget = -1 # Endless Loop try: while True: try: if (not (ser.is_open)): ser.open() continue except (serial.SerialException): client.publish(mqtt_topic + "exception", "serial reopen") # check which port was really used time.sleep(1.0) try: line = ser.readline() # read a '\n' terminated line except (serial.SerialException): SerialCommunicationFailureCounter = SerialCommunicationFailureCounter + 1 client.publish(mqtt_topic + "serialcom/failure", str(SerialCommunicationFailureCounter)) line=None if (SerialCommunicationFailureCounter > MAXIMUM_COMMUNICATION_FAILURE): raise serial.SerialException("device reports readiness / device disconnected " + str(MAXIMUM_COMMUNICATION_FAILURE) + " times") if (line): client.publish(mqtt_topic + "exception", "") # clear exception # convert byte array to string l = line.decode("utf-8") try: # Parse the controller information # e.g. : 22.00;0%;0RPM temperatur, percent, rpm = l.split(";") except (ValueError): # activate debug code temperatur = None percent = None rpm = None if ((temperatur) and (percent) and (rpm)): parseError=False currentTemperatur = float(temperatur.strip()) if (abs(currentTemperatur - lastTemperatur) > TEMPERATUR_MIN_DIFFERENCE): client.publish(mqtt_topic + "temperatur", str(currentTemperatur)) lastTemperatur = currentTemperatur if (percent.endswith('/100')): currentTarget = int(percent[:-4]) if (abs(lastTarget - currentTarget) > TARGET_MIN_DIFFERENCE): client.publish(mqtt_topic + "target", str(currentTarget)) lastTarget = currentTarget else: client.publish(mqtt_topic + "debug", "target%% invalid:" + str(percent)) parseError=True # remove new line for last element rpm = rpm.replace('\r','').replace('\n','') if (rpm.endswith('RPM')): currentRPM = int(rpm[:-3]) if (abs(currentRPM-lastRPM) > RPM_MIN_DIFFERENCE): client.publish(mqtt_topic + "rpm", str(currentRPM)) lastRPM = currentRPM else: client.publish(mqtt_topic + "debug", "RPM invalid:" + str(rpm)) parseError=True # cleanup debugging if (parseError == False): client.publish(mqtt_topic + "debug", None) else: client.publish(mqtt_topic + "debug", line) # line was invalid and could not be parsed else: time.sleep(0.2) except (KeyboardInterrupt, SystemExit): print("User aborted service ...") client.publish(mqtt_topic + "debug", "User aborted service") time.sleep(0.5) print("service Dead") client.loop_stop()