Moin!
Aktuell hab ich da ein kleines Projekt um einen Kaco Powador 3600xi Wechselrichter per RS232 auszulesen.
Die Ausgabe der RS232-Schnittstelle sieht wiefolgt aus:
Code:
00.00.0000 05:05:50 4 489.7 5.35 2619 232.9 10.57 2441 41
Man sieht, das Gerät übermittelt schon in CSV. Dies tut es alle 10 Sekunden.
Jetzt wollte ich den sechsten Wert "rausgrepen" (da dies die Leistung in Watt ist) und in meine Influx Datenbank einpflegen.
Mein Code ist auch in der Übermittlung zu Influx lauffähig, als auch das rauslesen und in eine Variable stopfen lauffähig, allerdings nicht die Kombination daraus. Jetzt fangen allerdings die Probleme an:
- Influxdb möchte in seinen json_body-fields ein integer haben, meine Variable die den Energie-Wert enthält ist aber ein string.
Kein Problem, überschreiben wir die Variable einfach in eine neue integer Variable und gut.
Code:
ValueError: invalid literal for int() with base 10: ''
Und genau hier hapert es, anscheind enthält meine Daten die ich über die Serielle Schnittstelle bekomme soviel "Müll" wie Nullbytes oder newline sowie anderen Kram, das er natürlich keine Zahlenfolge erkennt, für uns sichtbar ja, für den Interpreter nicht.
Jetzt war ich ja nicht doof und hab erstmal alles rausgeschnitten, was wir nicht brauchen:
serData = ser.readline().decode("utf-8").strip('\n').strip('\r').replace('\x00', '').strip()
Natürlich.. reicht das nicht.
Entferne ich das decode "utf-8" sieht der Code übrigens ganz Wild aus, mit 'b am Anfang und Ende.
Falls ihr euch fragt, warum Influx-json-body nicht einfach mit String gefüttert werden kann, dann:
{"energy": 1223} <- so muss das aussehen.
sobald ich aber da die Variable reindrücke ({"energy": rd2}) passiert folgendes:
{"energy": '1493'} <- das geht nicht, und der Influxclient sagt nope.
Ich hab mir jetzt überlegt das vielleicht erstmal alles von Dezimal in .. keine Ahnung hex umgewandelt werden sollte um wirklich nur noch die Zahl ansich rauszugrepen?
Ich bin mir noch nicht mal sicher ob das dann sowieso so funktioniert, da ich ja einen Zeichenbereich von 37-41 ablese, aber natürlich in den Morgen und Abendstunden ja auch nur 3 bzw 2 stellige Zahlen existieren die dann nur noch 39-41 einnehmen.
Weiterhin bin ich mir nicht mal sicher, ob das überhaupt der richtige Weg ist..
Ein weiteres Problem existiert nebenher noch: das Auslesen der Seriellen Daten dauert mit Python e-w-i-g und auf einmal kommt ein Berg mit alten Datenmüll, als gäbe es irgendwo ein Buffer der fröhlich mitschneidet, kommt aber nur halbwegs Datenmüll raus.. daher hab ich jetzt eine Schleife eingebaut die 0 und 'garnix' ausblendet, da sonst der Interpreter abstürzt weil er halt die Variable int(rd2) mit nix füllen würde, was natürlich nicht geht. Sobald ich meinen Zeichenbereich von 37-41 ein Wert vorhanden ist, macht er quasi weiter. Funktioniert.. aber auch anscheind nicht wirklich.
Ich geb jetzt hier erstmal mein Textschnippsel hin, die Vorlage hab ich irgendwo her, hab es soweit umgebaut wie ich es brauchte. Jetzt ist da ein bisschen getüddel drin um irgendwie aus dem Problem rauszukommen.
Code:
#!/usr/bin/python3
# Python Modules
import serial, sys, time, json
from influxdb import InfluxDBClient
# Configuration
serialPort='/dev/ttyUSB0'
db = InfluxDBClient(host='pinkiserver.mine.nu', port=8086, username='********', password='*******', database='inverter3')
# Open serial port
try:
ser = serial.Serial(serialPort,baudrate=9600)
except:
sys.exit(1)
# Main loop
while True:
# Wait for data and try error recovery on disconnect
try:
serData = ser.readline().decode("utf-8").strip('\n').strip('\r').replace('\x00', '').strip()
# Parse meter readings into dictionary (abbr. to rd for typing laziness of yours truely)
rd = serData[37:41]
#rd.replace('\x00', '').strip()
while rd != '':
global count
print("zero detected")
contiune
rd2 = int(rd)
print(" ", serData)
print(" ", rd)
print(type(serData))
# Write Dictionary to InfluxDB
json_body = [
{
"measurement": "Powerkaco3600",
"fields": {"energy": rd2}
}
]
try:
print("Write points: {0}".format(json_body))
db.write_points(json_body)
print("done.")
except:
pass
print("error.")
except serial.SerialException as e:
try:
ser.close()
time.sleep(10)
ser = serial.Serial(serialPort,baudrate=9600,timeout=None)
except:
pass