#! /usr/bin/python3 import time import sys from paho.mqtt import client as mqtt_client import os import serial MAXIMUM_COMMUNICATION_FAILURE=1000 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 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): payload = msg.payload.decode("utf-8") if ((mqtt_topic + "cmd/rpm") == msg.topic): if (ser.is_open): command = "ollpef{:02x}".format(int(payload)) ser.write(command.encode('utf-8')) else: client.publish(mqtt_topic + "cmd/exception", "Serial Connection closed") # clear exception elif ((mqtt_topic + "cmd/led") == msg.topic): command = "ollpel" + payload ser.write(command.encode('utf-8')) else: print(msg.topic+" "+str(msg.payload)) # Handle MQTT Commands def on_connect(client, obj, flags, reason_code, properties): client.subscribe(mqtt_topic + "cmd/led") client.subscribe(mqtt_topic + "cmd/rpm") print("Connected: " + str(reason_code)) # Start mqtt client_id = f'python-fan-ctrl' client = mqtt_client.Client(mqtt_client.CallbackAPIVersion.VERSION2) 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 # Reset Serial Communication statistic SerialCommunicationFailureCounter=0 client.publish(mqtt_topic + "serialcom/failure", str(SerialCommunicationFailureCounter)) # 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(3.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 try: currentTemperatur = float(temperatur) except (ValueError): print("Temperatur Error: could not convert string to float:" + temperatur) currentTemperatur = lastTemperatur if (abs(currentTemperatur - lastTemperatur) > TEMPERATUR_MIN_DIFFERENCE): client.publish(mqtt_topic + "temperatur", str(currentTemperatur)) lastTemperatur = currentTemperatur if (percent.endswith('/100')): try: currentTarget = int(percent[:-4]) except (ValueError): print("Percent Error: could not convert string to int:" + (percent[:-4])) currentTarget = lastTarget 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')): try: currentRPM = int(rpm[:-3]) except (ValueError): print("RPM Error: could not convert string to int:" + (rpm[:-3])) currentRPM = lastRPM 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.5) 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()