Funkklingel

Posted on So 03 April 2022 in Computer & Electronics

Hin und wieder wollen andere Menschen uns darauf aufmerksam machen, dass Sie sich gerade vor unserem Haus befinden. Manche davon kennen wir, andere nicht. Manche möchten gerne hereingelassen werden, andere würden nur gerne ein Paket loswerden, das an uns adressiert ist. Allen gemein ist, dass es sie nervt, dass unsere Klingel nicht funktioniert.

Eigentlich gibt es einen Klingelknopf am Gartenzaun, aber der ist uralt und wir wollen die Klingel nach der Sanierung des Hauses eh erneuern, aber aus verschiedenen Gründen ist das bisher nicht passiert. Wenn ich ganz ehrlich bin fand ich den klingellosen Zustand eigentlich auch ganz angenehm, denn man hat so wirklich seine Ruhe. Dennoch wurde die Behebung dieses Misstands im Familienrat auf die Tagesordnung gebracht. Und so hatte ich irgendwann halbherzig so eine Funkklingel angeschafft und den Sender neben dem Briefkasten montiert. Die funktioniert auch ganz OK. Aber es hat sich herausgestellt dass die meisten Leute, mangels Hoftor, einfach ungefragt bis zur Haustür vorrücken und dort vergeblich nach einer Klingelmöglichkeit suchen. Zudem halten die blöden Knopfzellen im Sender nicht ewig und was noch blöder ist – man bekommt nicht wirklich mit wenn sie leer sind – bis einem irgendwann auffällt, dass es in letzter Zeit so friedlich ist und niemand klingelt.

Also muss eine bessere Lösung her.

Wunschliste und Planung

Meine Vorstellung besteht nun darin, je einen Klingelknopf am nicht vorhanden Tor und einen zweiten direkt am Haus anzubringen. Beide sollen dann per Funk je einen Empfänger (je einen im EG und OG) zu verheißungsvollem "Gongen" ermuntern.

Außerdem will ich nicht diese blöden Plastik-Klingelsender einfach an Wand bzw. Zaun pappen, sondern altmodische Messing-Klingelknöpfe haben. Zuguterletzt fände ich es auch ganz nett, wenn auch mein Homeassistant mitbekäme, wenn es klingelt. Also ist ein wenig Basteln angesagt.

Die Einkaufsliste umfasst also

  • 2x Funkklingel mit je einem Sender und Empfänger. Letzter bitte mit Stromversorgung aus der Steckdose
  • 2x Messingklingelknopf
  • ein bisschen Holz für das Gehäuse
  • Kleines Netzteil für einen der beiden Sender (beim zweiten gibt's keinen Stromanschluss)

Nach etwas Recherche habe ich mich für das Modell AVANTEK D-3B entschieden. Zwar habe ich nur ein Set mit einem Sender und zwei Empfängern gefunden, aber dafür konnte ich den Sender einzeln kaufen und bin so zu meiner Wunschkonfiguration gekommen. Angeblich reicht das Funksignal bis zu 300m weit und die Empfänger können als Relais-Stationen fungieren, um die Reichweite zu einem Zweitempfänger nochmal zu erhöhen. Die Beschreibung prahlt mit 52 verschiedenen Melodien bei 115dB (niemals...). Laut ist das Teil wirklich (kann man zum Glück runterregeln) aber die 52 "Melodien" haben mir spontan ein DejaVue an die Zeiten des Jamba-Spar-Abos verschafft. Bis auf 2 halbwegs dezente Ding-Dong Töne ist der Rest wohl eher auf die Zielgruppe (prä-)pubertärer Nutzer optimiert. Aber die muss ich ja nicht verwenden.

Und so schaut eine Sender-Empfänger-Kombi aus:

Funkklingel Avantc D-3B Sender und Empfänger

Technik

Zuerst machen wir mal so einen Sender auf. Als erstes fällt auf, dass der Sender keine Dichtung hat. D.h. es empfiehlt sich nicht, ihn einfach so zu montieren. Von wegen IP55... Im Inneren befindet sich eine recht simple Platine, die auf der einen Seite nur den Taster und zwei LEDs trägt und auf der Rückseite finden wir neben einer Knopfzelle diverse Bauteile:

Vordereite der Platinemit Taster und LEDS

Rückseite der Platine mit diversen Bauteilen.

Bei genauerer Betrachtung haben wir da

  1. Knopfzellenhalter (CR2032)
  2. Quarz (26.2982 MHz)
  3. Eine Antenne
  4. Einen IC
  5. Einen Datenport (VCC, GND, CLK, DATA)
  6. Diverse passive SMD Bauteile sowie ein Transistor

Alles in allem recht unspektakulär. Spannend aber ist der IC. Ich musste die Augen ordentlich zusammenkneifen und eine gute Lupe zuhilfe nehmen, um dann bei optimaler Beleuchtung was lesen zu können: CMT2157B steht drauf. Eine Googlesuche später habe ich tatsächlich ein Datenblatt. Die Beschreibung sagt "240 MHz-960 MHz Single Chip OOK Transmitter with Encoder". Das Ding funkt bei der vorliegenden Konfiguration auf der Frequenz 433.92 MHz. Das klingt erfolgversprechend in Sachen HA-Anbindung. Laut Datenblatt ist der Chip programmierbar wenn man einen Jumper brückt. Dazu ist der Datenport da. Allerdings habe ich keine Angaben zum Protokoll. Nur den Verweis auf ein Programmiergerät das ich nicht habe.

Anschließen

Die beiden Empfänger kommen in je eine Steckdose im Erdgeschoss und 1. Stock. Bei Bedarf kann man dann einen davon rausziehen und in eine Außensteckdose auf der Terrasse verpflanzen. Das finde ich einen echten Vorteil gegenüber fest installierten Gongs/Türklingeln.

Ein Klingelknopf soll an den Gartenzaun – netterweise habe ich noch das ursprüngliche Klingelkabel und so habe ich beschlossen, das zu benutzen und den Sender dann im Haus an selbiges anzuschließen. So kann ich mir mittels Netzteil auch die Knopfzelle sparen und der Sender muss weder Wind noch Wetter ertragen.

Den zweiten Sender baue ich in ein kleines Holzkästchen ein, auf das der andere Messing-Klingelknopf kommt. Und anstelle der Knopfzelle nehme ich eine größere Batterie, damit das möglichst lange hält. D.h. ich stelle mir das in etwa so vor:

Schaltung Klingelknöpfe und Sender

Funkprotokoll

Bleibt noch die Frage, ob und wie man das Klingelsignal auch am Heimserver auffangen kann. Wäre doch cool, wenn ich das irgendwie in Homeassistant einspeisen könnte und dann z.B. eine Email oder andere Nachricht versenden würde, wenn es an der Tür klingelt.

Wir hatten ja schon gelernt, dass wir hier einen 433MHz Sender vor uns haben und dass der On/Off-keying (OOK) verwendet. D.h. das sollte sich ganz gut reverse-engineeren lassen.

Also erstmal den RTL-SDR Stick rauskramen. Als erstes habe ich einfach mal rtl_433 gestartet, den Klingelknopf gedrückt und gehofft, dass da vielleicht schon was kommt. Leider nicht.

Aber das wäre ja auch zu langweilig gewesen. Also dickere Geschütze auffahren. In diesem Fall den Universal Radio Hacker (urh).

Das wollen wir mal in ein virtual environment installieren:

pipx install urh

Nun können wir es verwenden:

urh

Als erstes mal den Spectrum-Analyzer starten, ein paarmal auf den Klinkelknopf drücken und schauen, ob wir das Signal finden:

Spectrum

Das schaut doch schon ganz gut aus. Als nächstes wollten wir mal das Signal aufzeichnen. Also in den recording mode, dreimal den Knopf drücken. Und schon haben wir dies:

Recorded signal

Hübsch. Das speichern wir ab und wechseln in das Interpretation interface.

Zunächst zoomen wir mal ordentlich in das Signal hinein:

Recorded signal

Das Signal ist sehr gleichförmig und wird über bestimmte Perioden ein bzw. aus geschaltet. On-Off-Keying (OOK) eben. OOK ist letztlich ein Spezialfall von ASK (amplitude shift keying = Amplitudenmodulation).

Als nächstes gilt es, das zu decodieren. Also setzen wir die Demodulation auf ASK und schauen, was wir bekommen:

Demodulated signal

Wunderbar. Das sieht schon richtig digital aus. Und nun müssen wir über etwas reden, das mich anfänglich total verwirrt hat: Auf den ersten Blick hätte ich gesagt, dass ich hier ein Folge von Bits sehe, die man als 0101010110010 interpretieren würde. Aber das ist so nicht ganz richtig, denn auf dieser Ebene (Roh-Signal) spricht man noch nicht von Bits, sondern von Symbols. Bits bekommen wir erst nach der Decodierung. Diese kann die Symbols eins zu eins in Bits verwandeln, aber das muss nicht so sein. Z.B. gibt es Signale, die auf Symbol-Ebene nicht binär sind, sondern z.B. vier verschiedene Signal-Level kennen und so 2 Bits pro Symbol übertragen können. Und auf der anderen Seite gibt es Methoden, die binär sind, aber mehr als ein Symbol pro Bit verwenden. Und schließlich gibt es Codierungs-Verfahren die den Input Bit-Stream so verändern, dass es möglichst viele Übergänge von 0 auf 1 im Rohsignal gibt, damit sich der Empfänger leichter tut, den Takt (CLK) sauber synchron zu halten. Die Bits sind quasi die Nutzlast, die Symbols der Träger – so wie wir unser analog Signal durch Demodulation aus dem Radiosignal extrahiert hatten bekommen wir das digitale Signal in Bits durch Decodierung aus dem Symbol-Stream.

Ich habe ein sehr schöne Übersicht der kompletten Kette in einer wissenschaftlichen Publikation (Abb. 5 in Tianqi Wang at al. Deep Learning for Wireless Physical Layer: Opportunities and Challenges, China Communications, 14:11, Nov. 2017) gefunden (Copyright bei den Autoren):

Overview
diagram of tpical digital wireless communication: source - encoding -
modulation - transmission and back.

Bevor wir nun anfangen das demodulierte Signal zu decodieren werfen wir mal einen Blick auf das, was wir schon auf Symbol-Ebene sehen:

Demodulated symbol stream

Die Message startet mit 16 Symbols, die abwechselnd 1 und 0 sind (gelb hinterlegt). Das nennt man die Preamble. Die braucht der Empfänger, um aufzuwachen und zu lernen wie hoch die Symbol Rate ist – also wie lang so ein Symbol dauert.

Als nächstes folgt eine Sequenz, die man Sync oder Sync Word nennt. Das ist eine vordefinierte Folge von Symbols. Der Empfänger prüft nun, ob das Sync Word so aussieht wie erwartet. Wenn ja kann es losgehen.

Lektüre

Jetzt ist ein guter Zeitpunkt, um mit dem reinen Rumraten aufzuhören und sich durch die Lektüre von Datenblättern zu bilden.

Ich habe ein bisschen im großen weiten Netz recherchiert und auf den Seiten www.cmostek.com und hoperf.com weitere Datenblätter und application notes gefunden. Teils bezogen diese sich nicht genau auf diesen exakten Chip, aber ich habe den Eindruck, dass das meiste übertragbar ist. V.a. die Dokumente AN112_CMT2150A_Configuration_Guideline und AN1004-CMT2157A_CMT2219A_communication_example(1920 coding) erscheinen sehr hilfreich.

Und darin findet man, dass es mehrere verschiedene Formate gibt und diese konfigurierbar sind. Das erste im Handbuch ist das 1920 packet format und man kann da im Konfigurations-Tool verschiedenes einstellen:

1920 packet format overview

Zwar ist die Länge bzw. das Vorhandensein der Preamble konfigurierbar, aber das folgende Beispiel legt 16 Symbols nahe und passt somit perfekt zu unserem Signal (0xaaaa, wenn man die Symbols als Bits interpretiert):

Preamble description

Und als nächstes wird dort definiert, dass das sync word (dort head_n pattern genannt) so aussehen muss (0xcaca5353, wenn man die Symbols als Bits interpretiert):

Sync signal description

Und auch das finden wir genau so in unseren Signalen (grün hinterlegt). Damit ist das Vorgeplänkel abgeschlossen und es folgen die eigentlichen Daten. Und die können nun laut Data Sheet unterschiedlich codiert sein. Hier die Abbildung aus dem Datenblatt:

Bit encoding options.

Schauen wir also mal auf die Datenpakete, die wir nach Preamble und Sync haben:

1: 11011011011011011011011011011011010011010010011011010011011011010010010011011...
2: 11011011011011011011011011011011010011010011010010010011011010010010010011010...
3: 11011011011011011011011011011011010011010010011011010011011011010010010011011...
4: 11011011011011011011011011011011010011010011010010010011011010010010010011010...

Für mich schaut das doch sehr nach 3 Symbols pro Bit aus:

1: 110 110 110 110 110 110 110 110 110 110 110 100 110 100 100 110 110 100 110 ...
2: 110 110 110 110 110 110 110 110 110 110 110 100 110 100 110 100 100 100 110 ...
3: 110 110 110 110 110 110 110 110 110 110 110 100 110 100 100 110 110 100 110 ...
4: 110 110 110 110 110 110 110 110 110 110 110 100 110 100 110 100 100 100 110 ...

Ich denke, das dürfte stimmen. Ich sehe nur die beiden Triplets 110 (0) und 100 (1). Und wenn man nun einfach im Texteditor die beiden Symbol-Triplets durch das entsprechende Bit ersetzt, bekommt man das hier:

1: 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 1 0 ...
2: 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1 0 ...
3: 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 1 0 ...
4: 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1 0 ...

Passt!

Gegenprobe – 4 Symbols pro Bit:

1:  1101 1011 0110 1101 1011 0110 1101 1011 0100 1101 0010 0110 1101 0011 ... 
2:  1101 1011 0110 1101 1011 0110 1101 1011 0100 1101 0011 0100 1001 0011 ... 
3:  1101 1011 0110 1101 1011 0110 1101 1011 0100 1101 0010 0110 1101 0011 ... 
4:  1101 1011 0110 1101 1011 0110 1101 1011 0100 1101 0011 0100 1001 0011 ...

Nee – das ist es ganz klar nicht, denn es sollten nur 1110 und 1000 vorkommen.

Analog für 5 und 6 Symbols pro Bit...

Big picture

Bevor wir uns dem genauen Inhalt der Daten widmen, treten wir aber einen Schritt zurück und betrachten nochmal unsere demodulierten Daten:

Für mich schaut das so aus, als hätten wir bei einem Klingel-Event tatsächlich drei separate Datenpakete, die durch eine kurze Pause getrennt sind und so rein optisch ziemlich gleich aussehen.

Also spielen wir mal mit der Einstellung rum, damit er das als separate Messages erkennt. Und schon ...

... sind die Teile als separate Messages erkannt so dass aus den ursprünglich 4 Messages nun 3∙3=9 Messages geworden sind.

Daten Analyse

Nun stellt sich noch die Frage, was die ganzen Daten bedeuten. Vor allem ist zu erwarten, dass jeder Klingelknopf eine andere ID sendet, weil es sonst auch bei allen Nachbarn klingelt. Und in der Tat musste ich den separat erworbenen Sender auch erstmal an den Empfängern anmelden, damit er erkannt wurde. Bei einem so simplen Gerät wie einer Haustürklingel würde ich erwarten, dass hier einfach jedes mal der Gleiche Code gesendet wird und keine Tricks wie Rolling codes verwendet werden, denn die Sicherheitsimplikationen eines Klingel Hacks bestehen im Wesentlichen in der Möglichkeit von Klingelstreichen und dazu braucht man einfach nur den Knopf drücken und wegrennen, also lohnt sich der Aufwand nicht. Oben hatten wir schon gesehen, dass es da so D0, D1 etc. Bits gibt – die sind für den Fall, dass mehr als ein Taster angeschlossen ist.

Um der Sache mit der Sender-ID auf den Grund zu gehen zeichnen wir ein neues Signal auf. Diesmal drücken wir die beiden unterschiedlichen Sender abwechselnd, um zu erkennen, ob es Unterschiede gibt. Hier zunächst das analoge Signal:

Wie man leicht sehen kann ist die Amplitude der beiden Sender sehr verschieden – einen habe ich direkt neben die Antenne meines Empfängers gehalten, den anderen weiter weg. Auf diese weise sehe ich leicht wer der Sender ist und auch urh kann so die Participants automatisch zuordnen. Und so schaut das dann in der Analyse aus:

Wie versprochen, hat urh erkannt, dass hier zwei verschiedene Sender (A: hellgrün und B: dunkelgrün) beteiligt waren und das in der Zeilenbeschriftung kenntlich gemacht). Je drei Messages in jeder Gruppe. Die Preamble hat das Programm korrekt erkannt. Bei der Länge des Sync words habe ich nachgeholfen, weil urh nicht wissen kann wo es endet.

Bisher haben wir also folgendes Bild vom Message Format (Koordinaten und Länge in Symbols):

Start End Length Bedeutung
1 16 16 Preamble
17 48 32 Sync
49 134 86 Address/ID
135 146 12 Buttons
147 154 8 CRC

Das Ganze hat nur ein klitzekleines Problem: Es kann nicht stimmen, denn wie wir uns erinnern, brauchen wir 3 Symbols/Bit und 86 ist nicht durch 3 teilbar. Und auch der Start des Button Feldes kann nicht stimmen, denn dort sind wir bezüglich der Bit-Codierung aus dem Raster:

1:  011 010 011 011 
2:  011 010 011 011 
3:  011 010 011 011 
4:  010 010 010 011 
5:  010 010 010 011 
6:  010 010 010 011 
7:  011 010 011 011 
8:  011 010 011 011 
9:  011 010 011 011 
10: 010 010 010 011 
11: 010 010 010 011 
12: 010 010 010 011

Das sind keine gültigen Codes für Bits. Was ist da los? Also nochmal das Datenblatt studieren. Und dort erfahren wir, dass es mehrere verschiedene Button-Modes gibt: Normal, Matrix, Toggle und PWM. Bei den letzten drei stimmt die Angabe, dass es 4 Bits sind. Im Normal-mode hingegen können 1-4 Button Bits eingestellt werden. Da der Sender eh nur einen Button hat kann es natürlich sein, dass nur ein Bit konfiguriert ist. Wenn wir das mal so annehmen könnte das also so aussehen:

Start End Length (Sym/Bits) Bedeutung
1 16 16 Preamble
17 48 32 Sync
49 144 96/32 Address/ID
145 147 3/1 Buttons
148 154 7 ? CRC

32 Bit für Address würde auch insofern Sinn machen, als die Seriennummern auf den beiden Sender "1K26" bzw. "1L21" lauten – also 4 Byte = 32 Bit.

Prüfen wir doch mal diese Hypothese, indem wir versuchen, das Address-Wort zu decodieren. Eigentlich kann urh das und man kann eigene Decoder definieren, aber irgendwie habe ich es nicht hinbekommen, meine simple Symbol -> Bit Übersetztung in urh anzuwenden, ohne dass es über decoding errors gemeckert hat Ich glaube da muss ich mal das Handbuch gründlicher lesen.

Also machen wir das von Hand. Dazu habe ich die 96 Symbols aus dem Signal ausgeschnitten und ein eine Textdatei kopiert und mir schnell ein kleines Python-Skript geschrieben, um die Daten in Bits zu übersetzen und in Binär, Hex und ASCII auszugeben.

Bits                                Hex         ASCII
00000000000101100100011100111010    0016473a    ..G:
00000000000101100100011100111010    0016473a    ..G:
00000000000101100100011100111010    0016473a    ..G:
00000000000101011100111101101111    0015cf6f    ..Ïo
00000000000101011100111101101111    0015cf6f    ..Ïo
00000000000101011100111101101111    0015cf6f    ..Ïo
00000000000101100100011100111010    0016473a    ..G:
00000000000101100100011100111010    0016473a    ..G:
00000000000101100100011100111010    0016473a    ..G:
00000000000101011100111101101111    0015cf6f    ..Ïo
00000000000101011100111101101111    0015cf6f    ..Ïo
00000000000101011100111101101111    0015cf6f    ..Ïo

Hm – nicht erhellend. Aber wir haben auch noch was übersehen: Aus dem Datenblatt (dort wird von Sync ID gesprochen, was wir Address nannten):

The Sync ID is sent and received starting from the LSB. For example, if the “Sync ID Length” is set to 16 and the “Sync ID Value” is set to 1, the binary value of the Sync ID is “0000 0000 0000 0001”. In this case, bit<0> = 1 is received first and bit<15> = 0 is received at the end of the Sync ID field.

Also versuchen wir das mal reversed, also LSB zuerst:

Bits                                Hex         ASCII
01011100111000100110100000000000    5ce26800    \âh.
01011100111000100110100000000000    5ce26800    \âh.
01011100111000100110100000000000    5ce26800    \âh.
11110110111100111010100000000000    f6f3a800    öó¨.
11110110111100111010100000000000    f6f3a800    öó¨.
11110110111100111010100000000000    f6f3a800    öó¨.
01011100111000100110100000000000    5ce26800    \âh.
01011100111000100110100000000000    5ce26800    \âh.
01011100111000100110100000000000    5ce26800    \âh.
11110110111100111010100000000000    f6f3a800    öó¨.
11110110111100111010100000000000    f6f3a800    öó¨.
11110110111100111010100000000000    f6f3a800    öó¨.

Nun dürfte es korrekt decodiert sein. Dennoch sehe ich nichts, was der Seriennummer ähnelt. Grumpf!

An diesem Punkt fällt mir wirklich nicht mehr viel ein, das ich noch tun könnte, um der genauen Codierung auf den Grund zu gehen. Vielleicht, wenn ich noch einen Stapel weitere Sender hätte? Wie auch immer. Ich weiß nun, wie die Datenpakete meiner beiden Sender aussehen und kann sie somit erkennen und auf sie reagieren. Ich könnte sie auch klonen und Sender mit anderer ID bauen – nur nicht anhand der Seriennummer, weil mir dieses Puzzle-Teil fehlt. Das fuchst mich zwar gewaltig, aber das Leben ist halt hart.

Und dann ist da noch eine große Ungereimtheit. Schaut Euch mal das Ende der Messages an:

  SYNC-ID    B    CRC?
___________ ___ _______
... 100 110 110 1101101
... 100 110 110 1101101
... 100 110 110 1101101
... 100 100 110 1101101
... 100 100 110 1101101
... 100 100 110 1101101
... 100 110 110 1101101
... 100 110 110 1101101
... 100 110 110 1101101
... 100 100 110 1101101
... 100 100 110 1101101
... 100 100 110 1101101

Alles in Symbols. Die ersten beiden Triplets gehören noch zur Sync-ID. Dann kommt unser Button Bit (B) und schließlich 7 Symbols die CRC sein sollen. Mal davon abgesehen, dass wir laut Datenblatt eigentlich 8 Symbols CRC erwarten und nicht nur 7 fällt nochwas auf: Die vermeintlichen CRC Symbols sind in allen 12 Messages identisch! Das kann nicht sein, denn wir haben ja zwei unterschiedliche Messages von zwei Sendern und es müsste mit dem Teufel zugehen, wenn beide den selben CRC Wert hätten!

Irgendwas ist da noch oberfaul...

Fazit

  1. Das hat Spaß gemacht, obwohl es mir erstmal nicht gelungen ist das Message-Format komplett zu verstehen. Und das trotz Datenblatt... Dafür habe ich unterwegs viel über digitale Funk-Kommunikation gelernt.
  2. urh ist ein wirklich praktisches Werkzeug – das werde ich in Zukunft öfter verwenden.
  3. Wenn ich irgendwann Lust habe bastle ich vielleicht mal eine Lösung, um das an den homeassistant anzubinden (wahrscheinlich würde es reichen, die Events einfach an den MQTT Server weiter zu geben), oder vielleicht auch eine Standalone Lösung um z.B. eine Email zu versenden, wenn es klingelt. Aber für heute soll es gut sein.
  4. Wenn mir noch eine geniale Eingebung kommt, wie genau die Codierung der Seriennummer funktioniert werde ich den Post ergänzen. Sollte der geneigte Leser eine gute Idee haben, wo genau ich auf dem Schlauch stehe – immer her damit.