Decoder für das Nexus-Protokoll auf Raspberry Pico
Gleiche Firma, gleiche Marke, anderes Protokoll des Funksenders...
Bei Lidl gab es wieder eine Wetterstation mit Funksender. Diesmal eine die die Luftfeuchtigkeit misst. Als Marke stand wiederum Auriol auf der Packung, und der Sensor sieht fast genau gleich aus.
Ein Versuch mit dem Auriol-Decoder war erfolglos, er konnte das Signal nicht empfangen. rtl_433 erkannte ein Nexus-Protokoll. Das ist im Sourcefile im Repository recht genau beschrieben, was es einfach machte einen Decoder in MicroPython zu schreiben.
Der Decoder läuft auf einem Raspberry Pico mit einem Empfängermodul für 433MHz. Der Aufbau ist hier beschrieben.
Das Script
""" Decodes the nexus protocol used by wireless sensors
Setup:
GPIO 16 is connected to tho output pin of an AM-RX12E-433P
The output is sent to the serial port on USB.
"""
import time
from machine import Pin
p = Pin( 16, Pin.IN )
def check_pulse( ts ):
""" Verifies that the pin is high for 450 to 650us """
while p.value() == 1:
pass
te = time.ticks_us()
return 450 < te - ts < 650, te
def measure( ts ):
""" Determines how long the pin is low """
while p.value() == 0:
pass
te = time.ticks_us()
return te - ts, te
def nexus():
""" Decodes the signal and writes the value to the USB port """
while True:
# Look for the start of a transmission
duration, te = measure( time.ticks_us() )
if duration < 3500 or duration > 4500:
continue
# Check the pulse length
valid, te = check_pulse( te )
if not valid:
continue
signal = 0
counter = 0
while counter < 36:
# Read next bit of signal
duration, te = measure( te )
if 700 < duration < 1300:
signal = signal << 1
elif 1700 < duration < 2300:
signal = (signal << 1) | 1
else:
break
valid, te = check_pulse( te )
if not valid:
break
counter += 1
# Print if we have all the bits
if counter == 36:
print( hex(signal) )
# Start the decoder
nexus()
Auch hier war es nötig die Zeit der letzten Flanke durch das ganze Script zu ziehen weil das Timing sonst aus dem Ruder lief.
Die Erkennung des Signals ist erstaunlich zuverlässig, auch wenn es keinerlei Verifikation des gesendeten Codes enthält. Ein Nibble enthält immer 0x0F, das könnte einen Anhaltspunkt geben ob das Signal tatsächlich von diesem Sensor stammt.
Die Messwerte auspacken und Loggen
Das obige Script schreibt eine Hex-Zahl auf die Konsole. Die Konsole ist in diesem Fall eine serielle Verbindung über USB.
Auf der PC-Seite läuft ein zweites Python-Script das die Werte auspackt und loggt.
Weil der Sensor die Messwerte mehrfach hintereinander sendet, werden nur Signale mit mindestens 20 Sekunden Abstand geloggt.
from datetime import datetime, timedelta
def log_weather( line ):
value = int( line, 16 )
humidity = value & 0xFF
raw = (value >> 12) & 0xFFF
if raw > 2047:
raw = -raw
temperature = float(raw) / 10
with open("weather.csv","a") as logfile:
logfile.write( "{},{:.1f},{}\n".format(now.strftime("%d.%m.%Y %H:%M:%S"),temperature,humidity) )
last = datetime.now()
delta = timedelta( seconds=20 )
previous = ""
with open( "/dev/ttyACM0" ) as input:
for line in input:
now = datetime.now()
if (line != previous) or (now > last + delta):
log_weather( line )
previous = line
last = now