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