Master/Slave Netzwerk mit nRF24L01 und Arduino/ESP8266

In diesem Beitrag möchte ich euch meine Netzwerkbibliothek (SBNetwork) vorstellen, mit der es super einfach ist, Arduinos, ESP8266 (WeMos, nodeMCU, …) oder andere kleine Mikrocontroller über den nRF24L01 Transmitetr miteinander zu verbinden. Wer mein Tutorial “Arduino und nRF24L01” gelesen hat, hat vielleicht bemerkt, dass die Verdrahtung zwar recht einfach ist, man sich programmiertechnisch allerdings um so ziemlich alles selbst kümmern muss. Wer dann zusätzlich noch etwas unerfahren im Programmieren ist oder schlicht keine Lust hat, sich damit herumzuschlagen, dem wird dieser Beitrag hier vielleicht gefallen.

Was soll SBNetwork können?

Nun ja, diese Frage sollten wir zuerst beantworten, bevor hier noch falsche Hoffnungen aufkommen. Ich habe mich jetzt schon mehre Jahre mit dem nRF24L01 beschäftigt und bin immer wieder auf die typischen Bibliotheken gestoßen, die beispielsweise TCP/IP Fähigkeit , Mesh-Netzwerke, Sensoren-Netzwerke oder Audiostreaming mit dem nRF24L01 implementieren. Ohne Frage, diese Bibliotheken sind super und ihre Erfinder/Programmierer mindestens genau so. Nur haben sie allesamt für mich ein paar entschiedene Nachteile. Mal sind sie schwierig/aufwendig zu konfigurieren und mal verbrauchen die Bibliothen schon so viel Speicher sodass nur noch wenig übrig bleibt, um die eigentlichen Funktionen wie Sensoren auslesen oder Aktoren Steuern, zu implementieren.

Nicht zuletzt wollte ich mich aber auch einfach mal selber mit der Materie intensiver beschäftigen. Sein eigenes kleines Kommunikationsprotokoll zu schreiben macht schon irgendiwe Spaß ;-). Aber gut, meine Ziele waren zunächst folgende:

  • Einfaches Master/Slave Netzwerk ohne Mesh und Routing Funktionen. Alle Slave-Geräte müssen in Reichweite des Master-Gerätes sein. Das sorgt vor allem für den geringen Konfigurationsaufwand. Außerdem habe ich den nRF jetzt schon länger getestet und er funktioniert tadellos vom 3 Stock bis in den Keller, ohne Probleme.
  • Keine x-te Implementierung eines TCP/IP Protokolls oder Mesh-Netzwerkes. Ich möchte einfach nicht, dass jeder Sensor oder Aktor ein Teil meines LAN/WLAN ist und eine IP Adresse erhält. Ok, zugegeben das entspricht nicht unbedingt dem IoT Gedanken, aber gut, jedem seines.
  • Automatische Suche nach und Verbinden mit einem Master-Gerät. Das sorgt erneut für einen geringen Konfigurationsaufwand. Es sollen außerdem nich einfach irgendwelche neuen Geräte ins Netzwerk reinfunken oder beitreten können.
  • Die Slave-Geräte sollen so stromsparend wie möglich betrieben werden können. Dazu zählt natürlich der bekannte Sleep-Modus. Wenn ein Slave also mal ein paar Minuten nichts von sich gibt, ist das auch OK.
  • Grundlage für eine weitere Bibliothek, die eine SmartHome ähnliche Umgebung implementieren kann. Dazu aber später mehr, in einem anderen Beitrag.

Was kann SBNetwork?

Im Grunde alles das, was ich oben als Ziele beschrieben habe.

Einfache Konfiguration

Um ein Gerät für das Netzwerk vorzubereiten, muss man ihm nur eine eindeutige Adresse (MAC Adresse) geben und ihm sagen, ob es ein Master oder Slave Gerät sein soll. Das war es eigentlich auch schon.

Automarisches Suchen und Verbinden

Schaltet man ein Slave-Gerät das erste mal ein, sucht es automatisch nach einem in der Nähe befindlichen Master. Hat es einen gefunden, paart es sich  automatisch mit dem Master, sofern er das zulässt. Von diesem Zeitpunkt an, ist das Slave-Gerät dann mit dem Master gepaart und verbindet sich immer automatisch zu ihm, auch wenn es aus und wieder eingeschaltet wird.

Einfaches Übertragen von Daten und Nachrichten

Das Senden von Daten und Nachrichten ist auch recht einfach (siehe Beispiele). Vor allem muss man sich keine Gedanken über die Länge einer Nachricht machen. Bekantermaßen kann der nRF24L01 nur 40 Byte pro Übertragung senden. Das kann schon mal knapp werden, vor allem bei Texten. Man muss sich mit der Bibliothek nicht darum kümmern, es können bis zu 200Byte pro Datenpaket übertragen werden. Das Auseinanderpflücken, Stückweise Übertragen und Wiederzusammensetzten übernimmt meine Bibliothek.

Was muss man selber noch tun?

Wie man die Bibliothek nutzt und welche Daten man übertragen möchte, muss natürlich jeder für sich entscheiden. Und somit muss man sich auch selber darum kümmern, wie man die Informationen ( z.B. Sensorwerte) verpackt und wieder ausliest. Die Bibliothek stellt zunächst erstmal nur eine Vereinfachung der Kommunikation zwischen zwei Geräten dar.

Tutorial SBNetwork – Ein kleines Beispiel

Also legen wir direkt los und bauen unser erstes kleines Beispiel.

Bibliothek installieren

Zunächst benötigt man die Quelldateien. Diese habe ich auf github veröffentlicht unter: https://github.com/Schullebernd/SBNetwork. Am besten man lädt sich das ganze ZIP Archiv herunter und entpackt es in den libraries Ordner der Arduino Umgebung ab (Bei Windows ist das in der Regel C:\Users\Benutzername\Documents\Arduino\libraries\).

Wir benötigen aber noch eine weitere Bibliothek, nämlich dieselbe, die auch in meinem ersten Tutorial zum Einsatz kam. Diese kann man allerdings auch über die Bibliotheksverwaltung einbinden “Sketch > Bibliothek einbinden > Bibliotheken verwalten“. Dort einfach den Suchbegriff nrf24 eingeben und die Bibliothek RF24 von TMRh20 herunterladen. Derselbe Entwickler hat im übrigen auch viele andere Bibliotheken für den nRF24L01 geschrieben, wie die besagte TCP/IP Library oder die Mesh Library, die echt sehenswert sind. Auch habe ich mich durch seinen Code sehr inspirieren lassen – Somit geht ein kleiner Dank  an TRMh20.

Geräte Vorbereiten

Für unser Beispiel benötigen wir zwei nRF24L01, einen WeMos D1 mini und einen Arduino  (Uno / Pro Mini / Nano …). Anstelle des WeMos D1 Mini ginge natürlich auch eine NodeMCU oder ein reiner ESP8266 oder aber auch eine zweiter Arduino. D.h. ESP8266 ist nicht pflicht, nützt einem später aber eher weniger, es seie denn, man möchte nur ein Display oder ähnliches betreiben.

Jetzt die nRF mit dem Wemos bzw. dem Arduino verdrahten. Eine Anleitung, wie das geht, ist hier auch noch einmal zu finden. In den Beisoiel-Sketches sind ebenfalls emtsprechende Übersichten enthalten, wie der Wemos bzw. der Arduino mit dem nRF24L01 verdrahtet werden muss. Hier noch einmal die Übersicht:

Anschlussbild nRF24L01 an ArduinoNano mit Elko

 

Anschlussbild nRF24L01 an Wemos D1 mini mit Elko
Anschlussbild nRF24L01 an Wemos D1 mini mit Elko

Am besten man verbindet gleich beide Microcontroller mit dem USB.

Beispiel-Sketches öffnen und ausführen

Als nächstes starten wir die Ardino IDE und schauen im Menü unter Datei > Beispiele > SBNetwork nach. Dort müssten zwei Beispiele zu sehen sein. GettingStartedMaster und GettingStartetClient.

Das Master-Gerät

Öffnen wir zunächst den Sketch GettingStartetMaster. Das ist der Sketch unseres Master Gerätes. Man könnte auch Basisstation sagen. Das Beispiel ist so vorbereitet, dass ein WeMos D1 Mini bzw. ein ESP8266-Board verwendet wird. Im Kommentar oben steht aber auch die Info, was zu ändern ist, wenn man einen Arduino einsetzen möchte.

Hier ein paar Erläuterungen zum Code.

In Zeile 33 legen wir eine MAC-Adresse an. Sie besteht aus 5 Bytes und ist somit 40bit lang. Für jedes neue Geräte, dass ihr eurem Netzwerk hinzufügt, muss eine neue MAC vergeben werden. Wenn zwei Geräte dieselbe MAC haben sollten, passiert es, dass beide Geräte dieselbe Nachicht empfangen und sich gegenseitig mitunter stören oder gar nicht mehr funktionieren.

In Zeile 38 wird ein Netzwerkgerät angelegt. Als Parameter werden die beiden CE und CS Pins übergeben, die den Microcontroller mit dem nRF24L01 Transmitter verbinden und ein false, was den Netzwerkgeräte mitteilt, dass es ein Master-Gerät sein soll.

In Zeile 46 wird das Netzwerkgerät und der RF24 Transmitter initialisiert. Diese Funktion sollte immer in der setup() Funktion aufgerufen werden. Bei einem Slave-Device finden hier auch die erste Initialisierung, die Suche nach einem Master und das Pairing statt.

In Zeile 62 wird das Netzwerkgeräte komplett zurückgesetzt und alle Einstellungen wie das Pairing werden gelöscht. Danach ist das Gerät in dem Zustand, als würde man es zum ersten Mal einschalten. Es ist allersdings ein Neustart nötig, damit der Reset wirkt.

In Zeile 84 wird das Netzwerkgeräte aktualisiert. Diese Funktion muss zwingend innerhalb der loop() Funktion augerufen werden. In der Funktion werden alle empfangenen Nachrichten verarbeitet und ggf. für den Anwender aufbereitet.

Zeile 84 prüft, ob eine empfangene Nachricht vorliegt. Die Funktion available() liefert dann die Anzahl der Bytes zurück, die empfangen wurden.

In 87 wird die empfangene Nachricht abgerufen. Je nachdem, was sich in dem Empfangspaket befindet, können die Daten ausgelesen und verarbeitet werden. Hier im GettingStarted Sketch übertragen wir nur Strings, daher wird der Inhalt der Nachricht gleich auf die serielle Ausgabe geleitet.

Zu guter letzt, senden wir in Zeile 93 eine Antwort zum Slave, nachdem er uns eine Nachricht gesendet hat.

Ok, damit hätten wir das Beispiel für ein Mastergerät fertig. Jetzt einfach den Sketch ausführen und (am besten vorher noch) den seriellen Monitor öffnen und schauen, welche Ausgaben erscheinen. Diese sollten in der Regel so ausschauen:

Voila, damit läuft der Master schon mal.

Das erste Slave-Gerät

Kommen wir zum Slave. Dafür öffnen wir nun, am besten in einem zweiten Arduino Fenster den Sketch GettingStartedClient.

Vom Code her wird hier vieles gemacht, wie beim Master. Es wird eine eindeutige MAC Adresse vergeben (Zeile 33), ein Netzwerk-Gerät angelegt (Zeile 38 – diesmal mit einem true als Parameter, das dem Gerät sagt, es ist ein Slave-Gerät). In setup() wird das Gerät initialisiert und in der loop() wird alle 4 Sekunden eine Nachricht an den Master verschickt.

Zu beachten ist hier, dass das Warten auf die 4 Sekunden nicht über ein klassisches delay(4000); gelöst wird, sondern bei jeden loop() Durchlauf die interne Uhr befragt wird. Würden wir den Arduino nämlich mit delay(4000); warten lassen, würde er keinen weiteren Code abarbeiten und somit auch nicht die update() funktion aufrufen. Aber in der update() funktion wird ja geprüft, ob es neue Nachrichten gibt. Also muss diese ständig aufgerufen werden.

Ok, soviel zur Theorie, kommen wir zur Praxis uns starten den Sketch. Der erste Start sollte im seriellen Monitor die folgende Ausgabe erzeugen.

Wenn das erscheint, dann ist alle richtig gelaufen und es funktioniert. Damit haben wir das erste Master/Slave Paar, das miteinander kommuniziert.

Geschafft – nRF24L01 was will man mehr?

Und es war vollbracht. Super. Jetzt kann man seinen Ideen freien Lauf lassen und was auch immer programmieren. Chatprogramm, Sensoren-Werte lesen oder andere Dinge. Ich für meinen Teil habe sogleich damit begonnen, eine SmartHome Bibliothek zu entwickeln, die ich euch in einem weiteren Beitrag vorstellen werde. Die Bibliothek wird es noch mehr vereinfachen, Sensoren-Daten zu übertragen oder Aktoren zu steuern.

Wie gesagt, muss man sich jetzt zunächst selber darum kümmern, wie man Daten in eine Nachricht verpackt und wieder ausließt. Ich habe dazu mal ein kleines Beispiel erstellt, siehe UniversalSensorMaster und BME_280Client. Mit beiden Beispielen kann man die Werte eines BME280 (Temperatur, Luftfeuchte und Luftdruck) messen und an einen Master übertragen. Schaut sie euch einfach mal an.

Und wie immer gilt, Kritik, Lob, Verbesserungen und Fragen einfach per Kommentar oder Mail an mich.

Viel Spass beim Kommunizieren…

Bernd

 

7 Gedanken zu „Master/Slave Netzwerk mit nRF24L01 und Arduino/ESP8266“

  1. Hallo Bernd,

    ist es mir irgendwie möglich die empfangene Nachricht in einer if-Abfrage zu verwenden?
    Hab schon das ein oder andere versucht aber komme zu keinem Ergebnis. z.B. die Message vom Master an den Slave war 1.
    aber der Slave geht nicht in das untenstehende netzwerk rein.
    if((char*)networkDevice.getMessage() == “1”) {
    char* message = “ich habe eine 1 bekommen”;
    networkDevice.sendToDevice(networkDevice.NetworkDevice.MasterMAC, message, strlen(message) + 1);
    }
    wäre nett wenn du mir helfen könntest.

    Gruß Julian

  2. Hallo Bernd,
    erstmal vielen Dank für die Mühe, genau sowas hab ich schon lange gesucht,… einfach und auch für nichtprogrammierer zu verstehen!
    In deinem Beispiel sketch zum BME client hast du wait auf 20 Sekunden. Hat das einen bestimmten Grund?

    Ein kleiner Tip oder eher eine Bitte:
    bitte mach die Lib über die Bibliotheksverwaltung zugänglich. Oder hat das auch einen Grund, zwecks Server oder Kosten usw.? Würde mich interessieren.

    Grüße, Thomas

    1. Hallo Thomas,
      die 20 Sekunden habe ich nur gewählt, damit nicht permanent Daten gesendet werde, aber beim Testen nicht so lange warten muss.
      Den Wert kann man beliebig ändern. Ich empfehle im Live-Betrieb so alle 120 Sekunden einen Wert zu übermitteln.
      Gruß Bernd

  3. Moin,

    das sind zwei ganz großartige Projekte mit dem nRF … was ich im Moment versuch zu finden, ist eine Übersicht der Funktionen des nRF`s . Bspw. kann mein Sim-Modul nebenher den Batteriestatus auslesen. Gibt es weiterführende Links ?

    Ich möchte ein kleines batteriebetriebenes nRF-Netzwerk aufbauen und würde mir wünschen, wenn täglich einmal jeder Slave seinen Status abgibt.

    Danke schn jetzt für eine Antwort

  4. Hallo. Ich würde gern einen wemos als Master nutzen. An diesem ist auf dem i2c bus bereits ein Helligkeitssensor angebunden. Der SDA des Bus läuft auf PIN D2. Kann man in deiner lib den von dir genutzten PIN 2 auch auf die 3 oder 4 legen?

  5. Hallo Torsten,
    danke für deinen Kommentar und dein Lob. Freut mich, wenn ich der Community auch was nützliches zurückgeben kann.

    Der nrf24l01 hat zwar 6 Pipes, diese benötigt man aber (meines Erachtens) so gut wie nicht. Eine Pipe reicht völlig aus. Die Adresse, die du der Pipe vergibst ist eine Art MAC Adresse, also eine physische Adresse. Alle Datenpakete, die an die physische Adresse gesendet werden, werden erstmal grundsätzlich empfangen und dem Microcontroller zur Weiterverarbeitung gereicht.
    Wenn du jetzt 12+ Sensoren hast, dann brauchst du nur eine Möglichkeit, zu unterscheiden, von wem ein Datenpaket empfangen wurde. Um das zu erreichen, wird einfach immer die Absenderadresse mit übermittelt.
    Der Master empfängt und sendet nur auf einer Pipe, weiß aber immer, von wem er ein Datenpaket empfangen hat und kann auch entsprechend an die korrekte Adresse antworten.
    Gruß Bernd – Mein Spitzname 😉

  6. Hallo Bernd?
    Ich bin etwas verwirrt da Du Dich Anfangs als Marcel Schulz vorstellst oder ich habe mich verlesen.
    Wie auch immer, Dein Werdegang und Dein offenes Dokumentieren und Programmieren von dem dann auch andere Interessierte parizipieren können ehrt Dich sehr !!! Meine Hochachtung und vielen Dank dafür!
    Das hilft wirklich, wenn Wissen so prima vermittelt wird.

    Und nun zu meiner Fragestellung:
    Ich habe die HW zusammen und möchte mein SmartHome mit Arduinos & Raspi als HyperMaster, verbunden via RS485 weiter ausbauen. Das Einbinden der Funkverbindungen ist notwendig, da ich beim Häusle-Bau die Sensor-Verkabelung zu den Fenstern teils verschwitzt habe…
    D.h. fensterseitig Arduino Mini Pro´s, die offen/zu und Ubatt senden sollen, batterieversorgt. Also mit Sleepmodus.
    Als Funk-Master soll ein weiterer Arduino z.B. ein Nano oder Mega 2560 dienen, der dann routet.
    Ich muss allerdings ca. 12 Fenster-Sensoren verwalten.
    Die max. 6 Pipes pro Channel stellen für mich daher ein Verständnisproblem dar. Ich benötige ja keine parallel Sendeverarbeitung, da meist nur ein einziger Sender was zu melden hat. Also alle Sender im gleichen Pipe oder je 2 ein Pipe teilen lassen ??? Wie mache ich das am Besten???

    Ich danke Die für Deine Zeit !!!!
    Gruß
    Torsten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload CAPTCHA.