Decoder für das Prologue-Protokoll auf Raspberry Pico
Der Raspberry Pico ist kein Raspberry im üblichen Sinne, sondern nur ein Mikrokontroller. Das Board hat einige GPIOs, AD-Wandler, und einen USB-Anschluss.
Um ihn zu testen habe ich einen Decoder für einen Temperatursensor geschrieben. Der Sensor hängt schon fast fünf Jahre draussen und liefert zuverlässig die aktuelle Temperatur. Obwohl der Aufbau HF-mässig jeder Regel widerspricht, gelingt der Empfang des Signals ohne Probleme.
Python auf dem Raspberry Pico
Normalerweise werden Embedded-Projekte mit C oder C++ realisiert. Weil ich zum Test MicroPython auf den Pico geflasht hatte, wollte ich ausprobieren ob der Interpreter schnell genug ist um dieses Signal zu decodieren. Ergebnis: funktioniert tadellos.
Den Interpreter zu installieren könnte nicht einfacher sein: das Image auf den PC laden, einen Taster auf dem Pico drücken, und das Image auf den Pico kopieren.
Nach einem Reboot meldet sich der Pico beim PC als serielle Schnittstelle an. Mit einem Terminalemulator kommt man direkt auf den Prompt des Python-Interpreters.
Sobald die ersten kleinen Testprogramme gelaufen sind braucht es aber doch einen vernünftigen Editor. Mit CTRL-E wird der Interpreter in einen Download-Mode geschaltet, so dass der Code unverändert im Pico landet. Mit CTRL-D kommt man zurück in den REPL-Modus wo das Programm läuft.
Der 433 Mhz Empfänger
Das Vellemann-Modul vom Arduino Projekt habe ich nirgends mehr gefunden. Anscheinend wird er nicht mehr produziert. Als Ersatz habe ich einen AM-RX12E-433P von rfsolutions genommen der gute Resultate liefert.
Das Python-Programm
""" Decodes the prologue 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(): """ Verifies that the pin is high for 450 to 650us """ ts = time.ticks_us() while p.value() == 1: pass te = time.ticks_us() return 450 < te - ts < 650 def measure(): """ Determines how long the pin is low """ ts = time.ticks_us() while p.value() == 0: pass te = time.ticks_us() return te - ts def prologue(): """ Decodes the signal and writes the value to the USB port """ while True: # Look for the start of a transmission duration = measure() if duration < 8500 or duration > 9500: continue # Check the pulse length if not check_pulse(): continue signal = 0 counter = 0 while counter < 32: # Read next bit of signal duration = measure() if 1500 < duration < 2500: signal = signal << 1 elif 3500 < duration < 4500: signal = (signal << 1) | 1 else: break if not check_pulse(): break counter += 1 # Print if we have all the bits if counter == 32: print( hex(signal) ) # Start the decoder prologue()
Auf 433Mhz gibt es sehr viele Störsignale, und deshalb wird jedes Bit genau geprüft um sicherzustellen dass der empfangene Wert auch tatsächlich vom Sensor stammt.
Das Signal beginnt mit einem Low-Pegel von ca. 900ms, gefolgt von einem High-Pegel von ca. 500ms. Dahinter kommen 36 Bit, codiert mit langen und kurzen Low-Pegeln. Der obige Code ignoriert die letzten 4 Bits weil die keine nützlichen Informationen enthalten.
Wenn eine Sequenz von 32 gültigen Bits empfangen wurde, schickt der Code sie als Hex-Zahl über die Schnittstelle zum PC. Eine Checksumme oder etwas ähnliches gibt es nicht, die Uebertragung kann also nicht verifiziert werden. Bei mir war das kein Problem, aber wenn nötig kann man weitere Check für den Wert des ersten Nibbles und die ID des Sensors einbauen.
Auspacken des Messwerts auf dem PC
Das Programm auf dem Pico schickt die empfangene Sequenz als Hex-Zahl an den PC. Um den Messwert auszulesen läuft dort ebenfalls ein Python-Script:
from datetime import datetime, timedelta seconds = datetime.now() ds = timedelta( seconds=20 ) with open( "/dev/ttyACM0" ) as input: for line in input: now = datetime.now() # Suppress repeated signals if now > seconds + ds: seconds = now value = int( line, 16 ) temp = (value >> 4) & 0xFFF if temp > 2047: temp = temp - 4096 temperature = temp / 10 with open("temperature.csv","a") as logfile: logfile.write( "{},{:.1f}\n".format(now.strftime("%d.%m.%Y %H:%M:%S"),temperature) )
Das Script liest die Hex-Zahl von der Schnittstelle, extrahiert den Messwert, und schreibt ihn zusammen mit einem Timestamp in ein CSV-File.
Weil der Sensor die Meldung gleich mehrfach schickt, wird alle 20 Sekunden eine neue Messung akzeptiert.
Autostart auf dem Pico
Für den Autostart wird das Script als main.py auf dem Pico abgelegt. Das habe ich mit rshell für Python erledigt.
Auf meinem Linux wollte rshell zuerst nicht starteni, weil eine Library fehlt. Erst als ich die rshell mit USE_AUTOCONNECT = False gepatcht hatte lief sie ohne zu meckern.
Mit genau der gleichen Hardware kann auch der Auriol AFT 77 B2 decodiert werden.