Blog der Heimetli Software AG

Temperatur und Luftfeuchtigkeit darstellen

Kürzlich habe ich mir einen Unitec W186-F zugelegt um neben der Temperatur auch die Luftfeuchtigkeit zu erfassen:

Unitec W186-F Temperatur- und Luftfeuchtigkeits-Sensor

Die Decodierung habe ich rtl_433 überlassen, was schon beim Pearl-Sensor gut geklappt hat. Die Installation der Software nach der Anleitung im Post zum Pearl-Sensor klappt immer noch problemlos.

Die Datenerfassung

Weil ich die Daten mit matplotlib darstellen wollte, habe ich mich für das CSV-Format entschieden. Mit folgender Kommandozeile werden die Messwerte als CSV abgelegt:

rtl_433 -R 16 -F csv:sensor.csv

Die Option -R sorgt dafür dass nur das AlectoV1 Protokoll aktiviert ist. Mit allen Protokollen kam mir immer der Prologue-Sensor in die Quere.

sensor.csv hat folgenden Aufbau:

time,msg,codes,model,id,channel,battery,temperature_C,humidity,rain_total,wind_speed,wind_gust,wind_direction,mic
2019-02-23 15:12:21,,,AlectoV1 Temperature Sensor,44,1,OK,15.900,36,,,,,CHECKSUM
2019-02-23 15:12:53,,,AlectoV1 Temperature Sensor,44,1,OK,15.800,36,,,,,CHECKSUM
2019-02-23 15:13:23,,,AlectoV1 Temperature Sensor,44,1,OK,15.800,36,,,,,CHECKSUM

Nach einer Weile entdeckte ich aber seltsame Messwerte:

2019-02-23 15:32:30,,,AlectoV1 Temperature Sensor,44,1,OK,13.900,36,,,,,CHECKSUM
2019-02-23 15:32:42,,,AlectoV1 Temperature Sensor,154,2,OK,-179.100,88,,,,,CHECKSUM
2019-02-23 15:33:01,,,AlectoV1 Temperature Sensor,44,1,OK,13.800,37,,,,,CHECKSUM

Um diese Zeit war es so um die 13 Grad, also sehr weit von -179.1 Grad entfernt.

Zum Glück haben diese Messwerte eine andere Id als die von meinem Sensor, sie können also einfach eliminiert werden.

Später stellte sich heraus, dass die Signale der beiden Sensoren kollidieren. Sie sind hinreichend ähnlich um dem anderen Empfänger eine Messung mit seltsamen Werten zu vorzutäuschen.

Das AlectoV1-Protokoll hat zwar eine simple Checksumme, aber bei gewissen Temperaturen passt beim Signal vom Prologue der Wert der entsprechenden Bits genau mit der Checksumme überein.

Prologue- und AlectoV1-Sensoren können also nicht parallel betrieben werden!

Darstellung der Messwerte mit matplotlib

nachdem es mit simulierten Daten so gut geklappt hat, lag es nahe die Visualisierung wieder mit matplotlib zu realisieren:

Unitec W186-F Temperatur- und Luftfeuchtigkeits-Sensor

Nach den Stufen im Diagramm zu urteilen ist die Auflösung des Feuchtigkeitssensors nicht gerade hoch...

Bei den Achsen habe ich einiges probiert um klar zu machen was die Linie bedeutet. Die Lösung mit den eingefärbten Achsenbeschriftungen hat mich am meisten überzeugt.

Der Code für das Diagramm

# Import the required modules
from datetime import datetime
from matplotlib.animation import FuncAnimation
from matplotlib import style
import matplotlib.pyplot as plt
import matplotlib.dates  as dates
import csv
import sys

# Set the style of the plot
style.use( 'ggplot' )

# Create figure and axes
fig, axt = plt.subplots()
axh      = axt.twinx()
tcolor   = "#D7191C"
hcolor   = "#2C7BD6"

# Update the plot
def update( frame ):
    try:
        previous    = datetime.min
        x           = []
        temperature = []
        humidity    = []

        # Read and parse the CSV file
        with open("sensor.csv") as file:
            for line in file:
                fields = line.split( "," )
                if (len(fields) > 7) and (fields[4] == "44"):
                    timestamp = datetime.strptime( fields[0], "%Y-%m-%d %H:%M:%S" )

                    if (timestamp.minute % 5 == 0) and (timestamp.minute != previous.minute):
                        previous = timestamp
                        x.append( timestamp )
                        temperature.append( float(fields[7]) )
                        humidity.append( float(fields[8]) )

        if len(x) > 0:
            # Renew the plot
            axt.clear()
            axh.clear()

            axt.xaxis.set_major_formatter( dates.DateFormatter("%H:%M") )
            axt.set_ylabel( "Temperatur", color = tcolor )
            axt.tick_params( axis = 'y', colors = tcolor )

            axh.set_ylabel( "Luftfeuchtigkeit", color = hcolor )
            axh.tick_params( axis = 'y', colors = hcolor )
            axh.grid( False )

            axt.plot( x, temperature, tcolor )
            axh.plot( x, humidity, hcolor )
    except:
        print( "Error: can't read file, ", sys.exc_info()[0] )

# Draw the initial graph
update( None )

# Update the graph every minute
ref = FuncAnimation( fig, update, interval=60000 )

# Show the plot
plt.show()

Die Bedingung für fields[4] sorgt dafür dass nur gültige Werte betrachtet werden. "44" ist die Id von meinem Sensor. Als positiver Nebeneffekt wird auch gleich die Headerzeile eliminiert.

Der Sensor sendet alle 30 Sekunden einen Update, und das ist definitiv zu viel wenn die Messung länger als ein paar Minuten dauert. Aus diesem Grunde wird pro 5 Minuten ein Messwert ausgewählt und angezeigt. Dieser Messwert ist klarerweise etwas zufällig. Vielleicht wäre es besser, den Mittelwert der Messungen im Intervall zu nehmen. Das würde auf jeden Fall die Kurve vom Feuchtigkeitssensor glatter machen.