D1 Mini Datenlogger – Teil 4: Daten per Wifi an Server schicken

Features: RTC, WLAN, SD-Karte, Temperatur-, Luftdruck- und Luftfeuchtigkeitssensor und OLED-Display, Solarzelle

In diesem Beitrag wollen wir mit unserem D1 Mini Wifi Daten als UDP Pakete an einen Server in Form eines Raspberry Pi’s schicken. Dort können Sie weiter verarbeitet, in eine Datenbank geschrieben und grafisch dargestellt werden.

In dieser Beitragsserie wollen wir einen Datenlogger bauen der Temperatur, Luftfeuchtigkeit und Luftdruck in eine .csv-Datei auf eine SD-Karte schreibt und nebenbei auch noch mobil von einer Solarzelle versorgt wird. In Teil 1 wird der Sensor und das LCD Display eingebunden. Anschließend folgt in Teil 2 die Erweiterung um eine Real-Time-Clock für präzise Zeitstempel und die SD-Karte für langfristiges Speichern der Messwerte. In Teil 3 machen wir die Anwendung mittels Solarzelle mobil und optimieren den Stromverbrauch. Dann folgt in Teil 4 noch das zusätzliche Senden der Daten an einen Datenserver und abschließend stellen wir diese Daten in Teil 5 noch grafisch dar.

Bauteile für D1 Mini Wifi

Folgende Bauteile wurden für diesen Beitrag verwendet / genauer betrachtet:

Raspberry Pi*

Micro SD Karte 16 GB*

Raspberry Pi

Bei dem Modell 4 B des Raspberry Pi handelt es sich schon um einen recht performanten kleinen Einplatinenrechner:

  • 4 GB RAM
  • ARM Cortex A72 Quadcore 64-bit mit 1,5 GHz
  • 2,4/5,0 GHz Onboard WLAN
  • 40-poliger GPIO Header
wifi

Inzwischen ist das Modul aber auch schon nicht mehr so günstig wie die ersten Versionen die noch für ca. 30 EUR zu haben waren. Es gibt zwar deutlich günstigere Alternativen wie den Banana Pi, aber durch die Verbreitung ist es einfach unschlagbar was Support durch die Community und verfügbare Software-Pakete angeht. Bei dem Banana Pi ist es mir schon untergekommen, dass die identischen Befehle plötzlich zu Fehlermeldungen führen weil irgendwelche Linux-Pakete fehlen 🙁

Server einrichten

Wir brauchen einen Server der die Anfragen des Clients (= D1 mini) entgegen nimmt. Dies soll für uns ein kleiner Einplatinencomputer á la Raspberry Pi, Banana Pi o.ä. übernehmen. Als Software setzen wir das Javascript-basierte node.js ein. Dabei handelt es sich um ein leistungsstarkes (non-blocking IO) und flexibles (Paketmanager npm) Framework mit dem man ohne sich mit Threads usw. auseinandersetzen zu müssen sehr mächtige und skalierbare Applikationen schreiben kann.

Installation node.js

Wir loggen uns zunächst mit ssh auf den Raspi ein (Achtung: IP-Adresse anpassen oder DNS nutzen!) mit

ssh pi@192.168.2.89

Die verfügbaren node.js-Versionen stehen in einer Liste auf github. Wir wählen die V18.x

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - &&\ sudo apt-get install -y nodejs

Die erfolgte Installation und Version kann getestet werden mit

node -v

Code

D1 Mini

Inzwischen ist das Programm doch schon umfangreich geworden. Deshalb hier kurz die Ausschnitte die für die WLAN Kommunikation per UDP relevant sind. Das vollständige Programm gibt es auf github.

Wir legen uns zunächst ein paar globale Variablen an und definieren, dass wir die Daten an die Adresse 192.168.2.81:8266 schicken möchten. Das ist die Adresse des Raspberry Pi’s dem wir später „befehlen“ auf den Port 8266 zu lauschen.

// wifi include
#include <ESP8266WiFiMulti.h>
#include <WiFiUdp.h>
WiFiUDP Udp;
IPAddress unicastIP(192, 168, 2, 81);                  // Adresse des Empfänger der Nachricht dient, eintragen.
constexpr uint16_t PORT = 8266;                          // UDP Port an welchen gesendet wird.

// WiFi connect timeout per AP. Increase when connecting takes longer.
const uint32_t connectTimeoutMs = 5000;

Das zyklische Senden der Nachrichten lagern wir in eine kleine Unterfunktion aus die wir später im loop-Aufrufen und zwar im Sendeinterval

void datenPerWifiSchicken() 
{
  char buffer[120];

  sprintf(buffer, "%s - Temperatur=%4.1f Feuchte=%.0f Druck=%.0f", 
      Stationsname.c_str(),
      temp1, hum1, press1);
      
  Udp.beginPacket(unicastIP, PORT);
  Udp.printf(buffer);
  Udp.endPacket();
}

Schließlich rufen wir die Funktion zyklisch im loop auf:

void loop()
{
    static unsigned long millisLastRead = 0; // letztes sensor auslesen
    unsigned long curMillis = millis();

    // anzeigezeit abgelaufen ?
    if (curMillis > MS_ANZEIGEDAUER) {
        // dann display ausschalten
        //digitalWrite(PIN_SCREEN_POWER, LOW);
        Serial.println("stoppe anzeige. lege mich schlafen...");
        ESP.deepSleep(US_SCHLAFINTERVAL); // [us]
    } else { // anzeigezeit laeuft ? 
        // dann alle 2s werte anzeigen/schreiben
        if (curMillis - millisLastRead > 2000) {
            readRTC();
            if (!RTCError) {
                printDateTime(now); // RTC Zeit
                Serial.print(" | ");
            }
            if (!bme1SensorError) {
                readAndPrintBME280Data();
            }
            if (!RTCError && !bme1SensorError && !SDKarteError) {
                writeDataToSD();
            }
            if (!wifiError) {
              datenPerWifiSchicken();
            }
            millisLastRead = curMillis;
        }
    }
}

Raspberry Pi

Wir implementieren einen kleinen UDP Server. Dazu erstellen wir uns eine Textdatei udp.js im Home-Verzeichnis und schreiben etwas Javascript/node.js Code mit dem wir einfach die empfangenen Daten erstmal auf der Kommandozeile ausgeben:

var udp = require('dgram');
var buffer = require('buffer');

var server = udp.createSocket('udp4');

// dieser event wird ausgelöst wenn eine 'message' eintrifft
server.on('message',function(msg,info){
  console.log(`RX from ${info.address}:${info.port} ${msg.toString()}`);
});

//emits when socket is ready and listening for datagram msgs
server.on('listening',function(){
  var address = server.address();
  var port = address.port;
  var family = address.family;
  var ipaddr = address.address;
  console.log('Server is listening at port' + port);
  console.log('Server ip :' + ipaddr);
  console.log('Server is IP4/IP6 : ' + family);
});

server.bind(8266);

Angelehnt an das simple client and server example.

Das Programm liegt auch auf github (mit dem Stand um den es in Teil 5 erweitert wurde).

Praxis / Testergebnisse

Wir loggen uns per ssh auf dem Raspberry Pi ein. Das geht z.B. mit dem Terminalprogramm putty. Die Datei udp.js starten wir zum Test manuell mit

node udp.js

Daraufhin wartet unser Programm auf eingehende Nachrichten. Wenn wir nun noch den D1 Mini mit Strom versorgen nachdem dort auch das Programm eingespielt wurde trudeln hoffentlich Nachrichten mit den Messwerten ein 🙂 und es sieht in etwa so aus:

Damit wären wir für diesen Teil fertig.


Beitrag veröffentlicht

in

von

Schlagwörter:

Kommentare

Schreibe einen Kommentar

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