Compare commits

..

4 Commits

Author SHA1 Message Date
Ollo
10bbb68dc0 Handle RGB color values, seperated by semicolon 2024-12-22 21:45:04 +01:00
Ollo
0fd58d07a2 Describe logging environment variable 2024-12-22 20:34:37 +01:00
Ollo
83e3131ccb Integrated Logging to /var/log/app.log 2024-12-22 20:31:59 +01:00
Ollo
3ca17eb4cf Describe docker compose example 2024-12-17 20:58:17 +01:00
3 changed files with 94 additions and 20 deletions

View File

@ -38,3 +38,29 @@ Set the following parameter:
```docker run -t -i --device=/dev/ttyUSB0 -e SERIAL_DEVICE="/dev/ttyUSB0" -e MQTT_SERVER="192.168.x.y" -e MQTT_TOPIC="testtopic/" sha256:``` ```docker run -t -i --device=/dev/ttyUSB0 -e SERIAL_DEVICE="/dev/ttyUSB0" -e MQTT_SERVER="192.168.x.y" -e MQTT_TOPIC="testtopic/" sha256:```
Additional logging can be activated with the variable **PY_LOGGING** possible values are:
* DEBUG
* INFO
* WARNING
* ERROR
* CRITICAL
#### Execution via Docker Compose
```
# template docker-compose.yml
services:
python_app:
attach: false
build:
context: .
dockerfile: Dockerfile
environment:
- SERIAL_DEVICE=/dev/ttyUSB0
- MQTT_SERVER=192.168.x.y
- MQTT_TOPIC=testtopic/
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"
```
build image: **docker-compose up --build**
start with **docker-compose up --detach**

1
mqttclient/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
docker-compose.yml

View File

@ -4,6 +4,7 @@ import sys
from paho.mqtt import client as mqtt_client from paho.mqtt import client as mqtt_client
import os import os
import serial import serial
import logging
MAXIMUM_COMMUNICATION_FAILURE=1000 MAXIMUM_COMMUNICATION_FAILURE=1000
@ -11,35 +12,73 @@ TEMPERATUR_MIN_DIFFERENCE = 2
TARGET_MIN_DIFFERENCE = 1 TARGET_MIN_DIFFERENCE = 1
RPM_MIN_DIFFERENCE = 50 RPM_MIN_DIFFERENCE = 50
COMMAND_PREFIX = "ollpe"
# MQTT Settings # MQTT Settings
mqtt_server=os.environ['MQTT_SERVER'] mqtt_server=os.environ['MQTT_SERVER']
mqtt_topic=os.environ['MQTT_TOPIC'] mqtt_topic=os.environ['MQTT_TOPIC']
# SERIAL Port # SERIAL Port
serial_device=os.environ['SERIAL_DEVICE'] serial_device=os.environ['SERIAL_DEVICE']
# Logging
try:
if (os.environ['PY_LOGGING']):
customLevel = os.environ['PY_LOGGING'].upper()
except (KeyError):
customLevel = 'WARNING'
logging.basicConfig(
level=customLevel,
filename="/var/log/app.log",
filemode="w",
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.debug("Start Serial connect")
# Start Serial communication # Start Serial communication
ser = serial.Serial(serial_device, 115200, timeout=1) # open serial port ser = serial.Serial(serial_device, 115200, timeout=1) # open serial port
if (ser is None):
logging.error("Cannot open device" + str(serial_device))
sys.exit()
# The callback for when a PUBLISH message is received from the server. # The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg): def on_message(client, userdata, msg):
payload = msg.payload.decode("utf-8") payload = msg.payload.decode("utf-8")
if ((mqtt_topic + "cmd/rpm") == msg.topic): if ((mqtt_topic + "cmd/rpm") == msg.topic):
if (ser.is_open): if (ser.is_open):
command = "ollpef{:02x}".format(int(payload)) command = COMMAND_PREFIX+"f{:02x}".format(int(payload))
ser.write(command.encode('utf-8')) ser.write(command.encode('utf-8'))
else: else:
client.publish(mqtt_topic + "cmd/exception", "Serial Connection closed") # clear exception client.publish(mqtt_topic + "cmd/exception", "Serial Connection closed") # clear exception
elif ((mqtt_topic + "cmd/led") == msg.topic): elif ((mqtt_topic + "cmd/led") == msg.topic):
command = "ollpel" + payload # OpenHAB r,g,b payload: 20,0,250
ser.write(command.encode('utf-8')) try:
if (',' in payload):
red, green, blue = str(payload).split(',')
logging.debug("Red=" + str(red) + " Green=" + str(green) + " Blue=" + str(blue))
redB= int((int(red)*255)/250)
logging.debug("Byte Red=" + str(redB))
greenB= int((int(green)*255)/250)
logging.debug("Byte Green =" + str(greenB))
blueB= int((int(blue)*255)/250)
logging.debug("Byte Blue =" + str(blueB))
command = COMMAND_PREFIX+"l{:02x}{:02x}{:02x}".format(redB, greenB, blueB)
else:
command = COMMAND_PREFIX+"l" + payload
ser.write(command.encode('utf-8'))
except (ValueError):
logging.error("Wrong MQTT Command: '" + str(payload) + "'")
else: else:
print(msg.topic+" "+str(msg.payload)) logging.warning(msg.topic+" "+str(msg.payload))
# Handle MQTT Commands # Handle MQTT Commands
def on_connect(client, obj, flags, reason_code, properties): def on_connect(client, obj, flags, reason_code, properties):
client.subscribe(mqtt_topic + "cmd/led") client.subscribe(mqtt_topic + "cmd/led")
client.subscribe(mqtt_topic + "cmd/rpm") client.subscribe(mqtt_topic + "cmd/rpm")
print("Connected: " + str(reason_code)) client.publish(mqtt_topic + "online", payload="true", qos=1, retain=True)
logging.debug("Connected: " + str(reason_code))
# Start mqtt # Start mqtt
client_id = f'python-fan-ctrl' client_id = f'python-fan-ctrl'
@ -48,12 +87,13 @@ client.on_message = on_message
client.on_connect = on_connect client.on_connect = on_connect
if (not (mqtt_server)): if (not (mqtt_server)):
print("MQTT_SERVER is not set") logging.error("MQTT_SERVER is not set")
if (not (mqtt_topic)): if (not (mqtt_topic)):
print("MQTT_TOPIC is not set") logging.error("MQTT_TOPIC is not set")
# Start MQTT Client # Start MQTT Client
client.will_set(mqtt_topic + "online", payload="false", qos=1, retain=True)
client.connect(mqtt_server, 1883) client.connect(mqtt_server, 1883)
client.loop_start() client.loop_start()
@ -70,14 +110,15 @@ lastTarget = -1
# Endless Loop # Endless Loop
try: try:
while True: while ((mqtt_topic is not None) and (mqtt_server is not None)):
try: try:
if (not (ser.is_open)): if (not (ser.is_open)):
ser.open() ser.open()
continue continue
except (serial.SerialException): except (serial.SerialException):
logging.error("Could not open serial connection")
client.publish(mqtt_topic + "exception", "serial reopen") # check which port was really used client.publish(mqtt_topic + "exception", "serial reopen") # check which port was really used
time.sleep(1.0) time.sleep(3.0)
try: try:
line = ser.readline() # read a '\n' terminated line line = ser.readline() # read a '\n' terminated line
@ -88,26 +129,32 @@ try:
if (SerialCommunicationFailureCounter > MAXIMUM_COMMUNICATION_FAILURE): if (SerialCommunicationFailureCounter > MAXIMUM_COMMUNICATION_FAILURE):
raise serial.SerialException("device reports readiness / device disconnected " + str(MAXIMUM_COMMUNICATION_FAILURE) + " times") raise serial.SerialException("device reports readiness / device disconnected " + str(MAXIMUM_COMMUNICATION_FAILURE) + " times")
if (line): if (line) :
client.publish(mqtt_topic + "exception", "") # clear exception client.publish(mqtt_topic + "exception", "") # clear exception
# activate debug code, by default
temperatur = None
percent = None
rpm = None
# convert byte array to string # convert byte array to string
l = line.decode("utf-8") l = line.decode("utf-8")
if (COMMAND_PREFIX in l):
logging.debug("Skip '" + str(l) + "', found " + str(COMMAND_PREFIX))
continue
try: try:
# Parse the controller information # Parse the controller information
# e.g. : 22.00;0%;0RPM # e.g. : 22.00;0%;0RPM
temperatur, percent, rpm = l.split(";") temperatur, percent, rpm = l.split(";")
except (ValueError): except (ValueError):
# activate debug code logging.debug("Unparsable '" + str(l) + "'")
temperatur = None
percent = None
rpm = None
if ((temperatur) and (percent) and (rpm)): if ((temperatur) and (percent) and (rpm)):
parseError=False parseError=False
try: try:
currentTemperatur = float(temperatur) currentTemperatur = float(temperatur)
except (ValueError): except (ValueError):
print("Temperatur Error: could not convert string to float:" + temperatur) logging.error("Temperatur Error: could not convert string to float:" + temperatur)
currentTemperatur = lastTemperatur currentTemperatur = lastTemperatur
if (abs(currentTemperatur - lastTemperatur) > TEMPERATUR_MIN_DIFFERENCE): if (abs(currentTemperatur - lastTemperatur) > TEMPERATUR_MIN_DIFFERENCE):
client.publish(mqtt_topic + "temperatur", str(currentTemperatur)) client.publish(mqtt_topic + "temperatur", str(currentTemperatur))
@ -117,7 +164,7 @@ try:
try: try:
currentTarget = int(percent[:-4]) currentTarget = int(percent[:-4])
except (ValueError): except (ValueError):
print("Percent Error: could not convert string to int:" + (percent[:-4])) logging.error("Percent Error: could not convert string to int:" + (percent[:-4]))
currentTarget = lastTarget currentTarget = lastTarget
if (abs(lastTarget - currentTarget) > TARGET_MIN_DIFFERENCE): if (abs(lastTarget - currentTarget) > TARGET_MIN_DIFFERENCE):
@ -133,7 +180,7 @@ try:
try: try:
currentRPM = int(rpm[:-3]) currentRPM = int(rpm[:-3])
except (ValueError): except (ValueError):
print("RPM Error: could not convert string to int:" + (rpm[:-3])) logging.error("RPM Error: could not convert string to int:" + (rpm[:-3]))
currentRPM = lastRPM currentRPM = lastRPM
if (abs(currentRPM-lastRPM) > RPM_MIN_DIFFERENCE): if (abs(currentRPM-lastRPM) > RPM_MIN_DIFFERENCE):
@ -149,12 +196,12 @@ try:
else: else:
client.publish(mqtt_topic + "debug", line) # line was invalid and could not be parsed client.publish(mqtt_topic + "debug", line) # line was invalid and could not be parsed
else: else:
time.sleep(0.2) time.sleep(0.5)
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
print("User aborted service ...") logging.error("User aborted service ...")
client.publish(mqtt_topic + "debug", "User aborted service") client.publish(mqtt_topic + "debug", "User aborted service")
time.sleep(0.5) time.sleep(0.5)
print("service Dead") logging.debug("service Dead")
client.loop_stop() client.loop_stop()