Zisterne 4.0 + Nextion Display ohne Internet / WLAN Router (UPD)

Zisterne 4.0 + Nextion Display ohne Internet / WLAN Router (UPD)

Was wird für das Projekt benötigt.

1. Installation ESP8266 in der Arduino IDE

Um den EPS8266 in der Arduino IDE verwenden zu können, muss dieser erst installiert werden. Wie das geht habe ich in diesem Blogbeitrag schon einmal erklärt.

Welche Bauteile werden benötigt.

Funktionsweise

Der Sender sendet 3 Datenpacket. 1. die Batteriespannung, 2. die Nummer der letzten Messung und 3. die Messdaten vom Ultraschallsensor.

Der Empfänger empfängt die Daten und teilt sie auf zur Weitergabe an das Nextion Display.

Wenn die Externe Antenne verwendet werden soll muss der Widerstand umgelötet werden oder einfach einen Lötklecks über die Pads ziehen.
Sender Sketch
Um die Batteriefunktion  (Messung) nutzen zu können müsst Ihr am D1 mini pro v2.0 oder dem D1 Lipo Battery Shield. Je nachdem was Ihr verwendet das Lotpad auf der Rückseite verbinden.
Für die Deep Sleep Funktion müsst Ihr auf der Rückseite des D1 mini pro v2.0 das Lötpad Sleep verbinden.
				
					#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <EEPROM.h>

#ifndef STASSID
#define STASSID "WIFI_UPD_R"
#define STAPSK  "123456789+"
#endif

IPAddress ip(192, 168, 10, 10);
IPAddress gateway(192, 168, 10, 1);
IPAddress subnet(255, 255, 255, 0);

unsigned int sendPort = 9500;

int trigger = 2;
int echo = 4;
long dauer = 0;
int counter = 0;

unsigned int raw = 0;
float batt = 0.0;
long wasser = 0;
const int sleepSeconds = 2000;

WiFiUDP Udp;

void setup() {
  pinMode(A0, INPUT);
  Serial.begin(115200);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);

  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(STASSID, STAPSK);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());
  Serial.printf("UDP server on port %d\n", sendPort);
  Udp.begin(sendPort);
}

void batt_status()
{
  raw = analogRead(A0);
  batt = raw / 1023.0;
  batt = batt * 4.2;
}

void zeit()
{
  counter++;
  EEPROM.write(1, counter);
  Serial.println(counter);
  if (counter >= 21)
  {
    counter = 0;
    EEPROM.write(1, counter);
    EEPROM.commit();
    EEPROM.end();
    ESP.reset();
  }
}

void loop() {
  EEPROM.begin(512);
  counter = EEPROM.read(1);
  batt_status();
  zeit();
  digitalWrite(trigger, LOW);
  delay(5);
  digitalWrite(trigger, HIGH);
  delay(10);
  digitalWrite(trigger, LOW);
  dauer = pulseIn(echo, HIGH);
  wasser = (dauer / 2) / 29.1;

for (int i=0; i <= 3; i++){
  Udp.beginPacket(gateway, sendPort);
  Udp.write("Batterie:");
  Udp.print(batt);
  Udp.write(";count:");
  Udp.print(counter);
  Udp.write(";wasser:");
  Udp.print(wasser);
  Udp.endPacket();
  delay(1000);
}
  EEPROM.commit();
  EEPROM.end();
  delay(3000);
  ESP.deepSleep(sleepSeconds * 1000000);
}
				
			
Funktionsweise
Als erstes werden die Librarys (Bibliotheken) inkludiert.
				
					#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <EEPROM.h>
				
			
WLAN Daten um auf den Empfänger zugriff zu bekommen. IP Adressen und festlegen auf welchen UDP Port gesendet wird.
				
					#ifndef STASSID
#define STASSID "WIFI_UPD_R"
#define STAPSK  "123456789+"
#endif

IPAddress ip(192, 168, 10, 10);
IPAddress gateway(192, 168, 10, 1);
IPAddress subnet(255, 255, 255, 0);

unsigned int sendPort = 9500;
				
			
Definieren der Signale und Variablen.
				
					// Ultraschallsensor
int trigger = 2;
int echo = 4;
long dauer = 0;

// Zähler für die Messreihe
int counter = 0;

// Variablen für die Batterie und dem Wasserstand
unsigned int raw = 0;
float batt = 0.0;
long wasser = 0;

// Zeit für den DeepSleep in Sekunden
const int sleepSeconds = 2000;

WiFiUDP Udp;
				
			
Im Setupteil brauch ich glaub ich nicht viel zu sagen. Hier werden die Ausgangspin, Eingangspins und das WLAN gestartet.
				
					void setup() {
  pinMode(A0, INPUT);
  Serial.begin(115200);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);

  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(STASSID, STAPSK);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());
  Serial.printf("UDP server on port %d\n", sendPort);
  Udp.begin(sendPort);
}
				
			
Routine für das Batterie messen, der Wert wird in “batt” gespeichert.
				
					void batt_status()
{
  raw = analogRead(A0);
  batt = raw / 1023.0;
  batt = batt * 4.2;
}
				
			
Routine für den Zähler. Dieser dient nur dazu um zu pürfen ob die Messung funktioniert hat. Hier kann man sicher auch eine andere Möglichekeit wählen. Der Zähler zählt bis 20 und fängt dann wieder von vorne an. Der Zähler wird im EEPROM gespeichert, damit er nach dem DeepSleep / Ausschalten wieder zur verfügung steht. Der ESP wird nach den 20 Messwerten 1x Resetet.
				
					void zeit()
{
  counter++;
  EEPROM.write(1, counter);
  if (counter >= 21)
  {
    counter = 0;
    EEPROM.write(1, counter);
    EEPROM.commit();
    EEPROM.end();
    ESP.reset();
  }
}
				
			
Routine für den Zähler. Dieser dient nur dazu um zu pürfen ob die Messung funktioniert hat. Hier kann man sicher auch eine andere Möglichekeit wählen. Der Zähler zählt bis 20 und fängt dann wieder von vorne an.
				
					void loop() {
  // EEPROM Starten
  EEPROM.begin(512);
  // Zähler aus dem EEPROM lesen
  counter = EEPROM.read(1);
  batt_status();
  zeit();
  // Ultraschallmessung 
  digitalWrite(trigger, LOW);
  delay(5);
  digitalWrite(trigger, HIGH);
  delay(10);
  digitalWrite(trigger, LOW);
  dauer = pulseIn(echo, HIGH);
  wasser = (dauer / 2) / 29.1;
  
  // Daten werden gesendet, zur sicherheit 3x im ein Sekundenabstand
for (int i=0; i <= 3; i++){
  Udp.beginPacket(gateway, sendPort);
  Udp.write("Batterie:");
  Udp.print(batt);
  Udp.write(";count:");
  Udp.print(counter);
  Udp.write(";wasser:");
  Udp.print(wasser);
  Udp.endPacket();
  delay(1000);
}
  // EEPROM schließen
  EEPROM.commit();
  EEPROM.end();
  delay(3000);
  // deepSleep ausführen
  ESP.deepSleep(sleepSeconds * 1000000);
}
				
			
Empfänger Sketch
				
					#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <SoftwareSerial.h>

#ifndef APSSID
#define APSSID "WIFI_UPD_R"
#define APPSK  "123456789+"
#endif
SoftwareSerial nextion(12, 13); // RX, TX

IPAddress ip(192, 168, 10, 1);
IPAddress gateway(192, 168, 10, 10);
IPAddress subnet(255, 255, 255, 0);

unsigned int recivePort = 9500;

// buffers für Empfangene Daten
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; //buffer to hold incoming packet,
char * values[3];
char * buf[3];
float batt;
unsigned int w_stand_txt;
unsigned int w_stand;

WiFiUDP Udp;

void setup() {
  nextion.begin(9600);
  Serial.begin(115200);
  Serial.println();
  Serial.print("Configuring access point...");
  WiFi.softAPConfig(ip, gateway, subnet);
  WiFi.softAP(APSSID, APPSK);
  delay(500);
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
  Serial.printf("UDP server on port %d\n", recivePort);
  Udp.begin(recivePort);

  nextion.print("p0.pic=");
  nextion.print(0);
  sendTOdisplay();
}

void sendTOdisplay()
{
  nextion.write(0xFF);
  nextion.write(0xFF);
  nextion.write(0xFF);
}

void loop() {
  String cmd;
  cmd += "\"";
  // sind Daten vorhanden, lese ein packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {

    // lese das packet in packetBufffer
    int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    packetBuffer[n] = 0;
    //Empfangene Daten zerlegen
    char* ptr = strtok(packetBuffer, ";");
    for (byte i = 0; i < sizeof(values) / sizeof(values[0]); i++)
    {
      values[i] = ptr;
      ptr = strtok(NULL, ";");
    }

    buf[0] = strtok(values[0], ":");
    batt = atof(strtok(NULL, ":"));     //Batterie Wert
    buf[1] = strtok(values[1], ":");
    buf[2] = strtok(NULL, ":");     // Counter
    buf[3] = strtok(values[2], ":");
    w_stand_txt = atof(strtok(NULL, ":"));     // Messwert Ultraschallsensor

    //Daten an das Display senden
    nextion.print("batterie.txt=" + cmd + batt);
    nextion.print(" V" + cmd);
    sendTOdisplay();
    nextion.print("zeit.txt=" + cmd + buf[2] + cmd);
    sendTOdisplay();
    nextion.print("w_stand.txt=" + cmd + w_stand_txt + cmd);
    sendTOdisplay();
    w_stand = w_stand_txt * 0.1666667; // Berechnung für die Seule
    w_stand = 100 - w_stand;           // Berechnung für die Seule
    nextion.print("wstand.val=");
    nextion.print(w_stand);
    sendTOdisplay();
    if (batt >= 3.8 && batt <= 4.1)
    {
      nextion.print("p0.pic=");
      nextion.print(4);
      sendTOdisplay();
    }
    if (batt >= 3.5 && batt <= 3.8)
    {
      nextion.print("p0.pic=");
      nextion.print(3);
      sendTOdisplay();
    }
    if (batt >= 3.3 && batt <= 3.5)
    {
      nextion.print("p0.pic=");
      nextion.print(2);
      sendTOdisplay();
    }
    if (batt >= 0 && batt <= 3.3)
    {
      nextion.print("p0.pic=");
      nextion.print(1);
      sendTOdisplay();
    }
    delay(100);
  }
}
				
			
Funktionsweise
Als erstes werden die Librarys (Bibliotheken) inkludiert.
				
					#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <SoftwareSerial.h>
				
			
WLAN Daten für den eigenen Access Point. IP Adressen und festlegen auf welchen UDP Port empfangen wird. Der SoftwareSerial legt fest wo die RX/TX Leitungen für das Display liegen.
				
					#ifndef APSSID
#define APSSID "WIFI_UPD_R"
#define APPSK  "123456789+"
#endif
SoftwareSerial nextion(12, 13); // RX, TX

IPAddress ip(192, 168, 10, 1);
IPAddress gateway(192, 168, 10, 10);
IPAddress subnet(255, 255, 255, 0);

unsigned int recivePort = 9500;
				
			
Definieren der Variablen.
				
					// buffers für Empfangene Daten
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; //buffer to hold incoming packet,
char * values[3];
char * buf[3];
float batt;
unsigned int w_stand_txt;
unsigned int w_stand;

WiFiUDP Udp;
				
			
Serielle Schnittstellen, WLAN und das UDP werden gestartet.
				
					void setup() {
  nextion.begin(9600);
  Serial.begin(115200);
  Serial.println();
  Serial.print("Configuring access point...");
  WiFi.softAPConfig(ip, gateway, subnet);
  WiFi.softAP(APSSID, APPSK);
  delay(500);
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
  Serial.printf("UDP server on port %d\n", recivePort);
  Udp.begin(recivePort);

  // Nextion Display Batterie Bild auf leer setzen.
  nextion.print("p0.pic=");
  nextion.print(0);
  sendTOdisplay();
}
				
			
Im LOOP Teil werden hier die Datenpakete empfangen und in 3 Werte zerlegt.
				
					  // sind Daten vorhanden, lese ein packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {

    // lese das packet in packetBufffer
    int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    packetBuffer[n] = 0;
    //Empfangene Daten zerlegen
    char* ptr = strtok(packetBuffer, ";");
    for (byte i = 0; i < sizeof(values) / sizeof(values[0]); i++)
    {
      values[i] = ptr;
      ptr = strtok(NULL, ";");
    }

    buf[0] = strtok(values[0], ":");
    batt = atof(strtok(NULL, ":"));     //Batterie Wert
    buf[1] = strtok(values[1], ":");
    buf[2] = strtok(NULL, ":");     // Counter
    buf[3] = strtok(values[2], ":");
    w_stand_txt = atof(strtok(NULL, ":"));     // Messwert Ultraschallsensor
				
			
Im Anschluss werden die Werte an das Display übertragen.
				
					    //Daten an das Display senden
    nextion.print("batterie.txt=" + cmd + batt);
    nextion.print(" V" + cmd);
    sendTOdisplay();
    nextion.print("zeit.txt=" + cmd + buf[2] + cmd);
    sendTOdisplay();
    nextion.print("w_stand.txt=" + cmd + w_stand_txt + cmd);
    sendTOdisplay();
    w_stand = w_stand_txt * 0.1666667; // Berechnung für die Seule
    w_stand = 100 - w_stand;           // Berechnung für die Seule
    nextion.print("wstand.val=");
    nextion.print(w_stand);
    sendTOdisplay();
    if (batt >= 3.8 && batt <= 4.1)
    {
      nextion.print("p0.pic=");
      nextion.print(4);
      sendTOdisplay();
    }
    if (batt >= 3.5 && batt <= 3.8)
    {
      nextion.print("p0.pic=");
      nextion.print(3);
      sendTOdisplay();
    }
    if (batt >= 3.3 && batt <= 3.5)
    {
      nextion.print("p0.pic=");
      nextion.print(2);
      sendTOdisplay();
    }
    if (batt >= 0 && batt <= 3.3)
    {
      nextion.print("p0.pic=");
      nextion.print(1);
      sendTOdisplay();
    }
    delay(100);
  }

				
			

Wie wird das Programm auf das Nextion Display geladen?

Ihr packt die brunnen.tft Datei auf eine Micro SD Karte und steckt diese in das Display. Dann das Display mit Spannung versorgen und der Upload wird gestartet. Nach dem Upload das Display wieder von der Spannung trennen und nach dem nächsten Verbinden ist das Programm aktiv.

Hier könnt Ihr euch den Sketch runterladen.

Wenn Ihr hier mit einem Akku arbeitet dann nach dem ausfstecken noch einmal den Reset Knopft drücken.

Sicherlich kann die ein oder andere Stelle noch verbessert werden. Ich hoffe es ist alles soweit verständich. Wenn Ihr fragen habe schickt mir einfach ein Mail. Ich versuche Sie zeitnah zu beantworden.

Weitere Beträge zum Thema Füllstand:

Zisterne 3.0 Web Server + SPIFFS

In meinem ersten Beitrag für die Zisterne (Wasserstandsmessung), verwende ich Batterie Bilder für den Füllstand der Zisterne. Hier werde ich immer wieder gefragt wie die Bilder angezeigt werden können.

Weiterlesen »
Zisterne mit Wemos messen

Zisterne Füllstandsanzeige

Wasserstand einer Zisterne mit einem Wemos D1 mini überwachen. Hier zeige ich euch wir Ihr mit einem Wemos den Wasserstand einer Zisterne überwachen könnt.Ich habe

Weiterlesen »
Folgende Bauteile wurden verwendet: