Nextion Display und ESP8266

Vorgeschichte

Nachdem ich die DIY-Wetterstation* und die dazugehörige Anzeige aufgezeichneter Wetterdaten* mittels Web-Script fertiggestellt hatte, fehlte eigentlich nur noch, wie bei käuflichen Wetterstationen, ein Anzeigedisplay, welches man sich ins Wohnzimmer stellen kann. So ist es damit möglich auch einmal einen Blick auf die aktuellen Temperaturen werfen zu können, ohne das Handy oder den PC anschalten zu müssen. Aus diesem Grund entstand fast zeitgleich mit der Wetterstation das Wetterdisplay, welches ich hier gern vorstellen möchte. 

In diesem Beitrag werde ich versuchen die Vorteile der Displays der Firma Nextion und den Aspekt der Kommunikation zwischen Micro-Controller und Display ein wenig hervorzuheben, da man diesen Teil auch für andere Projekte gut verwenden könnte. 

KOMMENTAR DES AUTORS

 

Hardwareauswahl

Die Auswahl der zu verwendenden Hardware stand bei  diesem Projekt eigentlich schon vorab fest. Da die DIY-Wetterstation* die anzuzeigenden Wetterdaten in meinem lokalen Netzwerk ablegt, brauche ich natürlich eine Möglichkeit diese von da aus auch zum Display zu bekommen. Der einfachste Weg hierfür erschien mir die Verwendung des bereits bei der Wetterstation selbst eingesetzten ESP8266* Micro-Controllers, da dieser nicht nur Daten an ein Webscript senden, sondern auch eine Webseite auslesen kann.

Um mich nicht um die Spannungsversorgung und den Anschluss kümmern zu müssen, wählte ich im Gegensatz zur DIY-Wetterstation* nicht den „blanken“ Chip, sondern kaufte ein kleines Development Board, auf welchem neben dem Micro-Controller, einem Spannungsregler und weitere Hardware auch gleich ein Micro-USB Anschluss, welchen ich für die Spannungsversorgung von Chip und Display nutze, verbaut ist. Dafür ist der Preis von < 20€ für 5 dieser Boards während der Chip-Krise dann meiner Meinung nach auch vollkommen in Ordnung.

Bei der Auswahl des Display stand ebenso schnell fest, dass ich hierfür auf eines aus der „Nextion-Familie“ zurückgreifen werde. Ich habe bereits vorher in einigen Projekten Nextion Displays eingesetzt und war mit dem Ergebnis immer sehr zufrieden. Sie sind in verschiedenen Größen erhältlich, womit man eigentlich für jedes Projekt ein passendes Display finden sollte. Beim aktuellen Projekt entschied ich mich für ein 4,3″ Display mit einer Auflösung von 480 x 272 Pixel. Dies reicht für die aktuelle Anwendung völlig aus.

 

Nextion Display und ESP8266 Quelle: Amazon.de



 

Meine Bezugsquelle für Nextion Displays

Zu der Zeit als ich mit den Nextion Displays angefangen habe, gab es in Deutschland nur eine Hand voll Web-Shops, wo man diese bestellen konnte. Am Anfang habe ich die Displays mangels Alternativen sogar direkt in Fern-Ost bestellt und die Lieferzeiten von teilweise 4-6 Wochen in Kauf genommen. Als mir in der Arbeit jedoch eines der Displays kaputt gegangen ist, brauchte ich schnellen Ersatz. Bei meiner Suche bin ich irgendwann auf den Webshop von Komputer.de* gestoßen, über welchen ich seit dem an auch immer meine Displays bestellt habe. Die Preise sind hier wirklich mehr als fair ( das NX3224To24 kostet hier 26,50€, bei Amazon zahlt man dafür stolze 40.99€ ) und die Lieferung ging immer super schnell.   

 

Schaltplan und Verkabelung des Wetterdisplay

Die Verkabelung des Wetterdisplays ist recht einfach. Das Display selbst benötigt für die Spannungsversorgung 5V und Gnd, welche am ESP8266 Development Board beide vorhanden sind. Die beiden Leitungen für die serielle Kommunikationsschnittstelle werden an den Pins D1 (RX) und D6 (TX)  angeschlossen und um den ESP nach dem DeepSleep reseten zu können ist noch eine Kabelbrücke zwischen den Pins D0 und Reset des Development Boards nötig.

Die Spannungsversorgung erfolgt dann via Micro-USB Anschlusskabel und einem 5V Steckernetzteil, wie sie zu jedem Handy mitgeliefert werden. Dieses sollte auf Grund der beide Komponenten mindestens einen Ausgangsstrom von 500mA aufweisen. Damit ist die Verkabelung dann auch schon erledigt. 

 

Schaltplan des Wetterdisplay mit der Verbindung zwischen ESP8266 und Nextion Display

 

Breadboard und NodeMCU als Entwicklungsplattform

Für die Entwicklung des Programmcodes habe ich die Schaltung, wie bei fast jedem Projekt, erst einmal auf einem Breadboard mit Jumper-Wires zusammengesteckt. Als Entwicklungsplattform nutzte ich ein NodeMCU* Development Board. Dieses habe ich bereits vor Jahren gekauft und damals auch sofort auf das Breadboard gesteckt und für die Entwicklung der Anwesenheitssteuerung meiner DIY-Hausautomatisierung*, welche ich initial ebenfalls auf ESP8266 Basis umgesetzt hatte, verwendet. Einen anderen Einsatzzweck hat es seit dem, trotz einiger ESP-Projekte, nicht mehr bekommen.

 

„fliegende“ Verkabelung zwischen NodeMCU und Nextion Display

 

Vorgriff: Feste Verkabelung der finalen Version

Da nach dem Abschluss der Entwicklung nur wenige Verbindungen nötig waren, habe ich mich in der finalen Version dazu entschieden für die Verbindung keine extra Platine anzufertigen, sondern direkte Kabelverbindungen zwischen ESP8266 und Display zu verwenden. Um auch den JST-Stecker am Display nicht nutzen zu müssen und somit noch einige Millimeter am Displaygehäuse einsparen zu können, habe ich die Kabel direkt an die Anschlüsse des JST-Steckergehäuses auf der Displayrückseite gelötet. Die vorhandenen Löt-Pads am Steckergehäuse sind hierfür mehr als groß genug.

   

feste Verkabelung zwischen final genutztem Development Board und Nextion Display

 

GUI Erstellung mittels Nextion Editor 

Vorab: Natürlich gibt es eine große Menge weiterer Displays, welches per I2C oder SPI an den ESP und viele weitere Micro-Controller angebunden werden können und zudem noch um einiges günstiger sind als die Nextion Display, doch fand ich es immer schwierig hierfür grafisch ansprechende Oberflächen zu entwickeln. Dies ist bei den Nextion Displays um einiges einfacher, da für das Konfigurieren der Displays ein separater Editor existiert, welcher auf der ITEAD, respektive Nextion-tech Seite kostenlos heruntergeladen werden kann. (https://nextion.tech/nextion-editor/*)

Mit diesem Editor ist es zum einen möglich die GUI mit Objekten wie Bildern, Texten, Graphen, Buttons oder auch Schiebereglern zu bestücken, zum anderen kann aber auch hier schon Logik, mittels im Editor integrierter Programmiersprache, implementiert werden. Damit kann dann später zum Beispiel auf Klick-Events oder ähnliches reagieren werden, wodurch sich hier schon einiges an Möglichkeiten ergibt. Die Syntax der Programmiersprache ist am Anfang zwar ein wenig gewöhnungsbedürftig, doch mit Hilfe der „Instruction Set Documentation“ aus dem Itead-Wiki (https://wiki.iteadstudio.com/index.php?title=Nextion_Instruction_Set*) kommt man mit der Zeit schon dahinter.

Beim aktuellen Projekt für das Wetterdisplay habe ich zum Beispiel mehrere Waveforms „übereinander“ platziert, welche mit Hilfe von Timern nacheinander angezeigt, bzw. ausgeblendet werden. So konnte ich das automatische Durchwechseln der Verlaufskurven für Temperatur, Luftfeuchtigkeit, Luftdruck und Windgeschwindigkeit umsetzen, ohne das man auf dem Display etwas drücken muss.

      

Der Nextion Editor inkl. dem geladenen Projekt für das Wetterdisplay

 

Wie man vielleicht auf dem obigen Screenshot erkennen kann, sind die meisten Labels und auch die Waveforms (zu erkennen an den gelben Kästchen) in der Ausgangskonfiguration unbefüllt. Das Befüllen mit den entsprechenden Werten übernimmt im Betrieb der Micro-Controller über die serielle Schnittstelle. Die Bezeichnung der Labels dient hierbei als Identifier, auf welches Objekt man gerade zugreifen möchte. Auch hierfür gibt es natürlich eine Dokumentation, welche Befehle das Display empfangen und verarbeiten kann. (https://nextion.tech/instruction-set/*)

Debug-Fenster des Nextion Editors

Auf den Debugger des Nextion Editors möchte auch noch ein wenig tiefer eingehen, da dieser beim Erstellen und Testen des Programmcodes durchaus hilfreich ist. Im Debugger, welchen man durch Klicken auf den „Debug“-Button in der oberen Toolleiste des Editors öffnen kann, hat man die Möglichkeit die angelegten Labels mit Text zu beschicken, oder aber auch einen COM-Port auszuwählen, um die Verbindung über die serielle Schnittstelle und den darüber versendeten Text schonmal vorab testen zu können. Das spart beim Herumprobieren einiges an Zeit, da man nach kleineren Änderungen an der GUI diese nicht gleich jedes Mal zum Display uploaden muss, sondern schon im Debugger sieht, ob die Änderungen auch den gewünschten Effekt erzielt haben.

 

Funktionsweise des Nextion-Debugger im aktuellen Projekt

 

Ist man dann mit dem Ergebnis zufrieden und möchte sich die GUI auf dem Display anschauen, dann lädt man diese einfach per Upload-Button auf das Display hoch. Ich verwende dafür meist ein Arduino Board, auf welchem ich den gesockelten Micro-Controller entfernt und das Board über die RX und TX Pins mit dem Display verbunden habe. Ein USB to UART Stick funktioniert natürlich genauso, doch habe ich das Arduino Board meist in Griffweite. 

Daten vom Micro-Controller an das Nextion Display senden

Das Übertragen der Daten vom Micro-Controller zum Nextion Display erfolgt, wie bereits angesprochen, über die gleiche serielle Schnittstelle, über welche auch der Upload der GUI erfolgte. Am Micro-Controller habe ich mir angewöhnt hierfür nicht die physisch vorhandene Schnittstelle zu verwenden, sondern nutze zwei weitere IO-Pins, welche unter Zuhilfenahme der „SoftwareSerial“-Bibliothek* ebenfalls zur seriellen Datenübertragung verwendet werden können. Das hat den Vorteil, dass die serielle Schnittstelle des Micro-Controllers fürs Debuggen und den Upload des Programmcodes frei bleibt und man nicht jedes mal das Display abstecken muss, um den Programmcode auf den Micro-Controller hochladen zu können.   

Die „SoftwareSerial“-Bibliothek* funktioniert hierfür sowohl auf dem Arduino, als auch auf dem ESP8266 tadellos. Nach dem Inkludieren der Bibliothek definiert man eine neue Instanz von SoftwareSerial und übergibt die verwendeten RX und TX Pins als Parameter. Danach initialisiert man die Schnittstelle mit der Übergabe der verwendeten Übertragungsgeschwindigkeit (Baudrate). Diese habe ich bereits displayseitig über die Programmierschnittstelle des Nextion Editors auf 115200Bd gesetzt, weshalb ich im Programmcode des Micro-Controllers diesen Wert ebenfalls als Geschwindigkeit der SoftwareSerial Schnittstelle auswählen muss.

Anschließend kann man über die so konfigurierte Schnittstelle, genau wie über die bekannte „Serial“ Schnittstelle, mit „print“ oder „println“ Daten an das Display senden. Zur besseren Veranschaulichung habe ich die nötigen Zeilen für die Kommunikation via SoftwareSerial einmal zusammengefasst.

 

#include <SoftwareSerial.h>

SoftwareSerial nextion(14, 5);  // bind nextion serial communication to pin D5 and pin D1 of the ESP8266


void setup() 
{  
    nextion.begin(115200); // start software serial with Nextion Display
}


void loop() 
{  
    nextion.print("Hallo Welt!");  // print nextion command to serial connection
}

 

Jetzt muss man natürlich noch wissen, wie genau die Daten an das Displays gesendet werden müssen, damit diese auch in den entsprechenden Elementen angezeigt werden. Hierfür findet man wieder alle nötigen Informationen innerhalb der Nextion Dokumentation (https://nextion.tech/instruction-set/*). Eine der wichtigsten Informationen haben die Entwickler dabei gleich am Anfang in Nummer 1 unter „– General Rules and Practices“ des Instruction Sets platziert.

 

All instructions over serial: are terminated with three bytes of 0xFF 0xFF 0xFF
ie: decimal: 255 or hex: 0xFF or ansichar: ÿ or binary: 11111111
ie byte ndt[3] = {255,255,255}; write(ndt,3); or print(“\xFF\xFF\xFF”); or print(“ÿÿÿ”)

 

Dies bedeutet, dass jedes gesendete Kommando durch das Senden von 3 High-Bytes bestätigt werden muss. Schaut man weiter runter, so findet man unter „– Assignment Statements“ schließlich auch die Kommandos um den Text eines Labels zu ändern, einem Waveform einen Wert hinzuzufügen oder auch auf verschiedene Aktionen reagieren zu können.

Mit diesen Informationen war es ein leichtes die Kommunikation mit dem Display herzustellen und die gewünschten Werte anzeigen zu können. Um nicht jedes Mal auf ein gesendetes Kommando die Zeile nextion.print("\xFF\xFF\xFF"); im Programmcode stehen zu haben, nutze ich für das Senden der Kommandos eine Funktion, welche das Kommando als String entgegennimmt, diesen an das Display schickt und anschließend das Terminate-Kommando hinterher sendet.

 

// sending a single command to the display and terminate sending with FF FF FF 
void sendNextionCommand(String command)
{
  nextion.print(command);  // print nextion command to serial connection
  nextion.print("\xFF\xFF\xFF");  // terminate actual command
}

 

Diese Funktion wird dann im Programmcode einfach nur noch an benötigter Stelle aufgerufen und der gewünschte Wert an das Display gesendet. Dabei werden die in der GUI platzierten Elemente mit ihrem im Nextion Editor angegebenen Objektname (objname) angesprochen und die Werte wie im Instruction Set beschrieben übergeben. Für die Einzelwerte der Temperatur und Luftfeuchtigkeit schaut das im Wetterdisplay dann zum Beispiel wie folgt aus.

 

...

sendNextionCommand("temp.txt=\"" + devTemp + "\"");    
sendNextionCommand("feuchte.txt=\"" + devHum + "\"");

...

 

Das Empfangen von Daten könnte man natürlich auf ähnliche Weise umsetzen. Da ich das Nextion Display in diesem Projekt allerdings nur als reine Anzeige verwende, gehe ich hier nicht näher darauf ein.

 

Micro-Controller Programmcode des Wetterdisplays

Der restliche Programmcode für den ESP8266 beinhaltet neben dem bereits bei der DIY-Wetterstation* vorgestellten Verbinden mit dem Netzwerk, eine Funktion zum Auslesen der auf dem Webserver vorhandenen Daten und eine split-Funktion für die als String gelieferten Datenreihen. Die einzelnen Daten sind dabei wieder durch ein Trennzeichen (Delimiter) voneinander getrennt.

Das Einlesen geschieht dabei per HTTP-GET Befehl, welcher direkt auf die URL, unter welcher sich die Daten-Dateien befinden, ausgeführt wird. Diese Dateien haben kein klassisches HTML-Grundgerüst, sondern beinhalten lediglich die Rohdaten, welche für die Anzeige auf dem Display benötigt werden. Da die Antwort des Aufrufs dennoch ein wenig Status-Overhead enthält, trenne ich diesen gleich innerhalb der Funktion ab und liefere nur die reinen Daten als Return-Value der Funktion zurück.  

  

// Read file content and split html header information
String Read_URL(String Filename)
{

    dataCollection = "";

    //Wertestring für Chartanzeige auslesen
    // We now create a URI for the request
    String url_1 = Filename;
    int Status = 0;

    Serial.print("Requesting URL: ");
    Serial.println(url_1);
    delay(10);

    // This will send the request to the server
    client.print(String("GET ") + url_1 + " HTTP/1.1\r\n" +
                "Host: " + host + "\r\n" +
                "Connection: Keep-Alive\r\n\r\n");


    // start waiting for the response
    unsigned long lasttime_1 = millis();
    
    while (!client.available() && millis() - lasttime_1 < 5000) 
    {
        delay(1); // wait max 1s for data
    }

    // Read all the lines of the reply from server and print them to Serial
    while (client.available())
    {
        char readchar_1 = client.read();
        dataCollection.concat(readchar_1);
        delay(1);
    }

    // split header information from data
    dataCollection = dataCollection.substring(dataCollection.indexOf("Accept-Ranges: bytes") + 20);
    dataCollection.trim();

    return dataCollection;
}

 

Nach dem erfolgreichen Einlesen der Datei wird innerhalb der bereits erwähnten split-Funktion per for-Schleife die Anzahl an vorhandenen Trennzeichen ermittelt. Danach wird erneut über die Zeichenkette iteriert und der String zwischen zwei Trennzeichen (also genau ein spezifischer Messwert) an der als index-Parameter übergebenen Stelle ermittelt und als Ergebnis zurück geliefert.

Durch das mehrfache Aufrufen der Funktion innerhalb einer for-Schleife im Loop-Programmteil werden so die Kurvenanzeigen (Waveforms) auf dem Nextion Display mit den anzuzeigenden Werten befüllt. Diese Funktion könnte man durch den Einsatz mehrerer String-Arrays, welche die gespeicherten Werte während der Laufzeit halten, sicherlich noch etwas performanter gestalten. Da beim Wetterdisplay das Befüllen der Kurven jedoch in ca. 3s abgeschlossen ist und ich am Anfang einiges an Problemen mit inkonsistenten Einzeldaten hatte, habe ich mich hier für die besser debugbare Einzelvariante entschieden.

 

// string split method
String split(String inputString, char delimiter, int index)
{
    int amountOfDelimiter = 0;

    //check amount of delimiter
    for (int i = 0; i < inputString.length(); i++)
    {
        if (inputString[i] == delimiter)
            amountOfDelimiter++;
    }

    if (index <= amountOfDelimiter)
    {
        String returnString = "";
        int delimiterCnt = 0;
        int rFromIndex = 0, rToIndex = -1;
        while (index >= delimiterCnt)
        {
            rFromIndex = rToIndex + 1;
            rToIndex = inputString.indexOf(delimiter, rFromIndex);
            if (index == delimiterCnt) 
            {
                if (rToIndex == 0 || rToIndex == -1) return "0";
                    return inputString.substring(rFromIndex, rToIndex);
            } 
            else 
                delimiterCnt++;
        }
        return returnString;
    }
    else
        return "0";
}

 

Damit sind die Hauptfunktionen des Programmcodes eigentlich hinreichend erläutert.  Der Vollständigkeit halber hier anbei nun noch der komplette Programmcode, um auch die Sleep-Funktionalität und das komplette Setup nochmal nachvollziehen zu können. Falls jemand vorhaben sollte den Code auf ein anderes Projekt zu portieren und dabei auf Probleme stoßen sollte, kann er sich gern in den Kommentaren oder per Mail an info@langer-sebastian.de melden.

 

#include <ESP8266WiFi.h>
#include <Time.h>
#include "String.h"
#include <SoftwareSerial.h>


SoftwareSerial nextion(14, 5);  // bind nextion serial communication to pin D5 and pin D1 of the ESP8266
WiFiClient client;  // use WiFiClient class to create TCP connections

const char* ssid = "WLAN-......";
const char* password = ".........";  // wifi password
const char* host = "192.168.2.198";  // IP-address of http host
const int httpPort = 8000;  // port of http host


String dataCollection = "";  // variable for measurement data collection (string-array) saved on the host computer  
String tempChartString;  // variable for temperature chart data
String presTempChartString;  // variable for temperature chart data from pressure sensor
String presChartString;  // variable for chart data from pressure sensor
String humChartString;  // variable for humidity chart data
String windChartString;  // variable for wind speed chart data
int intValueAktPos = 0;  // value for actual chart value as int

void setup() 
{
    Serial.begin(115200);  // start serial communication with ESP8266
    nextion.begin(115200); // start software serial with Nextion Display
    delay(10);  // wait short time

    // start connecting to  wifi network
    Serial.println("-- START WIFI CONNECT --");
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    // wait while wifi connection isn't established
    while (WiFi.status() != WL_CONNECTED) 
    {
        delay(500);
    }

    // output connection data to serial (for development purpose only)
    Serial.println("");
    Serial.println("-- WIFI CONNECTED --");
    Serial.print("  IP address: ");
    Serial.println(WiFi.localIP());
    Serial.print("Connecting to: ");
    Serial.println(host);

    // check if connection to http host was successful  
    if (!client.connect(host, httpPort))
    {
        Serial.println("connection failed");
        return;
    }

    delay(10);

    // call read url to get data for temperature chart
    tempChartString = Read_URL("/SHAS/Zusatz/ESP-Wetterstation_Tempchart.shas");
    //Serial.println("Tempstring: " + tempChartString + "END");

    // call read url to get data for temperature chart of pressure sensor
    presTempChartString = Read_URL("/SHAS/Zusatz/ESP-Wetterstation_pTempchart.shas");
    //Serial.println("Humstring: " + presTempChartString);

    // call read url to get data for humidity chart
    humChartString = Read_URL("/SHAS/Zusatz/ESP-Wetterstation_Feuchtechart.shas");
    //Serial.println("Feuchtestring: " + humChartString);

    // call read url to get data for air pressure chart
    presChartString = Read_URL("/SHAS/Zusatz/ESP-Wetterstation_Preschart.shas");
    //Serial.println("Druckstring: " + presChartString);

    windChartString = Read_URL("/SHAS/Zusatz/ESP-Wetterstation_Windchart.shas");
    //Serial.println("Windstring: " + windChartString);

    // call read url to get data for actual single measurement values
    dataCollection = Read_URL("/SHAS/Zusatz/ESP-Wetterstation.shas");

    //some delay for collecting data
    delay(100);
}

void loop() 
{
  
    /*

    1. get single value data of data collection

    */

    
    String Array[25];  // create array for actual value data
    int Array_pos = 0;  // flag for array position

    // iterate over dataCollection string
    for (int i = 0; i < dataCollection.length(); i++)
    {
        // check if next two signs are **, so the end of the actual entry was found 
        if (dataCollection.substring(i, i + 2) == "**")
        {
            Array[Array_pos] = dataCollection.substring(0, i);  // add substring before ** to actual array position
            dataCollection = dataCollection.substring(i + 2);  // split actual substring and ** from dataCollection 
            i = 0;  // reset iterator to start from the begining of new dataCollection
            Array_pos++;  // increase array position
        }
    }

    // store array positions in named variables (not necessary but helpful for better overview)
    String devName = Array[0];
    String devIP = Array[1];
    String devVCC = Array[2];
    String devTemp = Array[3];
    String devHum = Array[4];
    String devBrightness = Array[5];
    String devDew = Array[6];
    String devUV = Array[7];
    String devTemp2 = Array[8];
    String devPres = Array[9];
    String devPres_NN = Array[10];
    String devAltitude = Array[11];
    String devRainAmount = Array[12];
    String devWind = Array[13];
    String devDate = Array[14];
    String devDayRain = Array[15];
    String devMonthRain = Array[16];
    String devTempMaxString = Array[17];
    String devHumMaxString = Array[18];
    String devPresMaxString = Array[19];
    String devUVMaxString = Array[20];
    String devWindspeedNowMax = Array[21];
    String devWindDir = Array[22];

    float devFloatDayRain = devDayRain.toInt() * 0.3;
    float devFloatMonthRain = devMonthRain.toInt() * 0.3;

    sendNextionCommand(" ");
    sendNextionCommand("temp.txt=\"" + devTemp + "\"");
    sendNextionCommand("t4.txt=\"" + devTempMaxString + "\"");
    sendNextionCommand("t5.txt=\"" + devHumMaxString + "\"");
    sendNextionCommand("feuchte.txt=\"" + devHum + "\"");
    sendNextionCommand("t3.txt=\"le. Akt.:"  + devDate + "\"");
    sendNextionCommand("t8.txt=\"" +  devPresMaxString + "\"");
    sendNextionCommand("t11.txt=\"" +  devUVMaxString + "\"");
    sendNextionCommand("t7.txt=\"" +  devPres + "\"");
    sendNextionCommand("t10.txt=\"" +  devUV + "\"");
    sendNextionCommand("t14.txt=\"" +  String(devFloatDayRain) + "\"");
    sendNextionCommand("t17.txt=\"" +  String(devFloatMonthRain) + "\"");
    sendNextionCommand("t23.txt=\"" +  devWind + "\"");
    sendNextionCommand("t24.txt=\"Tag-max " + devWindspeedNowMax + "\"");
    sendNextionCommand("t26.txt=\"" +  devWindDir + "\"");
    sendNextionCommand("t27.txt=\"" +  devIP + " - " + devVCC + "V" + "\"");
    
    /*

    2. Reset and refill charts with actual data

    */

    //clear graphs from all displayed waveforms
    sendNextionCommand("cle 1,0");
    sendNextionCommand("cle 1,1");
    sendNextionCommand("cle 20,0");
    sendNextionCommand("cle 22,0");
    sendNextionCommand("cle 23,0");

    // for loop to iterate over readed value string arrays
    for (int test = 0; test < 238; test++)
    {        
        // set temperature 1 chart
        String actValueOnPos = split(tempChartString, '_', test);
        
        // check if a value was found
        if(actValueOnPos != "")
            intValueAktPos = (actValueOnPos.toInt() + 30) * 2;  // 30°C offset because -30°C = 0 mark on nextion

        sendNextionCommand("add 1,0," + String(intValueAktPos));  // insert value in nextion waveform


        // set temperature 2 chart (temperature from humidity sensor)
        actValueOnPos = split(presTempChartString, '_', test);

        if(actValueOnPos != "")
            intValueAktPos = (actValueOnPos.toInt() + 30) * 2;  // 30°C offset because -30°C = 0 mark on nextion

        sendNextionCommand("add 1,1," + String(intValueAktPos));  // insert value in nextion waveform


        // set humidity chart
        actValueOnPos = split(humChartString, '_', test);

        if(actValueOnPos != "")
            intValueAktPos = (actValueOnPos.toInt() * 1.6) - 23; // humidity + 1,6 because display height is 0 to 160
        
        sendNextionCommand("add 20,0," + String(intValueAktPos));  // insert value in nextion waveform


        // air pressure
        actValueOnPos = split(presChartString, '_', test);

        if(actValueOnPos != "")
            intValueAktPos = (actValueOnPos.toInt() - 970) * 2; // pressure - 970 because display height is 0 to 160

        sendNextionCommand("add 22,0," + String(intValueAktPos));  // insert value in nextion waveform


        // wind speed
        actValueOnPos = split(windChartString, '_', test);

        if(actValueOnPos != "")
            intValueAktPos = actValueOnPos.toInt() * 7; // wind speed display calibration

        sendNextionCommand("add 23,0," + String(intValueAktPos));  // insert value in nextion waveform
    } 

    delay(100);  // some delay to end operation
    ESP.deepSleep(10000000);  // go to sleep mode

}

//
// Helper-functions until here
//

// sending a single command to the display and terminate sending with FF FF FF 
void sendNextionCommand(String command)
{
    nextion.print(command);  // print nextion command to serial connection
    nextion.print("\xFF\xFF\xFF");  // terminate actual command
}


// Read file content and split html header information
String Read_URL(String Filename)
{

    dataCollection = "";

    //Wertestring für Chartanzeige auslesen
    // We now create a URI for the request
    String url_1 = Filename;
    int Status = 0;

    Serial.print("Requesting URL: ");
    Serial.println(url_1);
    delay(10);

    // This will send the request to the server
    client.print(String("GET ") + url_1 + " HTTP/1.1\r\n" +
                "Host: " + host + "\r\n" +
                "Connection: Keep-Alive\r\n\r\n");


    // start waiting for the response
    unsigned long lasttime_1 = millis();
    
    while (!client.available() && millis() - lasttime_1 < 5000) 
    {
        delay(1); // wait max 1s for data
    }

    // Read all the lines of the reply from server and print them to Serial
    while (client.available())
    {
        char readchar_1 = client.read();
        dataCollection.concat(readchar_1);
        delay(1);
    }

    // split header information from data
    dataCollection = dataCollection.substring(dataCollection.indexOf("Accept-Ranges: bytes") + 20);
    dataCollection.trim();

    return dataCollection;
}


// string split method
String split(String inputString, char delimiter, int index)
{
    int amountOfDelimiter = 0;

    //check amount of delimiter
    for (int i = 0; i < inputString.length(); i++)
    {
        if (inputString[i] == delimiter)
            amountOfDelimiter++;
    }

    if (index <= amountOfDelimiter)
    {
        String returnString = "";
        int delimiterCnt = 0;
        int rFromIndex = 0, rToIndex = -1;
        
        while (index >= delimiterCnt)
        {
            rFromIndex = rToIndex + 1;
            rToIndex = inputString.indexOf(delimiter, rFromIndex);
            if (index == delimiterCnt) 
            {
                if (rToIndex == 0 || rToIndex == -1) return "0";
                return inputString.substring(rFromIndex, rToIndex);
            } 
            else 
                delimiterCnt++;
        }
        return returnString;
    }
    else
    return "0";
}

 

Gehäuse aus dem 3D-Drucker

Da das Projekt damit nach ca. 3 Jahren Pause somit endlich vor dem Abschluss stand, designte ich noch schnell ein Gehäuse, in welchem das Display und das ESP-Prototyping-Board ihren Platz fanden. Den ESP8266 platzierte ich im Standfuss und sparte am hinteren Ende des Gehäuses eine Öffnung aus, durch welche ich den Micro-USB Port zur Spannungsversorgung des Wetterdisplays erreichen kann. So „verpackt“ taugt die Bastelei jetzt auch für die Wohnzimmerschrankwand und leistet seit ca. 3 Wochen tolle Dienste.

 

Abbildung des designten Gehäuses für das Wetterdisplay

 

Fazit

Ich bin wieder einmal von den Nextion Displays überzeugt und hoffe das ich die Vorteile mit diesem Beitrag ein wenig erläutern konnte. Da meine Frau bereits beanstandet hat, dass auf dem Display nicht die Raumtemperaturen meiner 433MHz Funktemperatursensoren* und auch keine Uhrzeit ersichtlich ist, habe ich bereits ein weiteres Display bestellt, auf welchem ich diese Anzeigen noch mit umsetzen werde. Wenn das getan ist, reicht das dabei Erlernte vielleicht sogar für einen weiteren Beitrag. 

 

 

 

Ein Gedanke zu „Nextion Display und ESP8266

  • Januar 8, 2024 um 12:24 pm Uhr
    Permalink

    Danke für den interessanten Beitrag und auch für die individuellen Programmcodes. Ich möchte für meine Firma spezifische Geräte bauen und brauche dafür maßgefertigte Gehäuse für die Displays. Dafür muss ich mich die nächsten Tage noch an einen Experten für die Herstellung von Industrie-Displaygehäusen wenden.

    Antwort

Schreibe einen Kommentar

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