Zeit auf TFT anzeigen

Ide­aS­park ESP32 mit TFT 320×170 Pixel

#include "WiFi.h"
#include "time.h"
#include "Adafruit_ST7789.h"
#include "U8g2_for_Adafruit_GFX.h"

#define TFT_CS        15
#define TFT_RST        4
#define TFT_DC         2

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

int Vordergrundfarbe = WEISS;
int Hintergrundfarbe = SCHWARZ;

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// WiFi-Daten
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

// Variablen für die Zeit
int Stunden, Minuten, Sekunden;

// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = true;

unsigned long Zeitmessung = 0;

void setup() 
{
  // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft);

  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  WiFi.mode(WIFI_STA);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900);
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");

  Serial.println("-------------------------");
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");

  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900);

    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    delay(1000);
    Zaehler++;

    if (Zaehler >= 90) {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while (1);
    }

    Serial.print(".");
  }

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");

    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

    // Monat: führende 0 ergänzen
    if (Zeit.tm_mon < 9) Serial.print("0");

    // Zählung beginnt mit 0 -> +1
    Serial.print(Zeit.tm_mon + 1);
    Serial.print(".");

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");

    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.println(Zeit.tm_min);
    Serial.print(":");

    if (Zeit.tm_sec < 10) Serial.print("0");
    Serial.println(Zeit.tm_sec);
    Serial.println("-------------------------");
  }

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;

  // TFT starten
  tft.init(170, 320);

  // Rotation anpassen Querformat
  tft.setRotation(1);
  tft.fillScreen(Hintergrundfarbe);
  u8g2Schriften.setForegroundColor(Vordergrundfarbe);
  u8g2Schriften.setBackgroundColor(Hintergrundfarbe);
  u8g2Schriften.setFont(u8g2_font_fub42_tf);

  ZeigeDatum();

  Zeitmessung = millis() + 1000;
}

void loop() 
{
  // Start = true
  // -> Zeit einmalig synchronisieren
  if (Start)
  {
    Start = false;
  
   // Zeit jede Minute mit Zeitserver synchronisieren
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);

    ZeitAnzeigen();
  }

  // Sekunden weiter zählen
  if (Zeitmessung < millis()) 
  {
    Zeitmessung += 1000;
    Sekunden++;

    if (Sekunden == 60) 
    {
      // Zeit jede Minute mit Zeitserver synchronisieren
      // aktuelle Zeit holen
      time(&aktuelleZeit);

      // localtime_r -> Zeit in die lokale Zeitzone setzen
      localtime_r(&aktuelleZeit, &Zeit);

      // Zeit in Stunden, Minuten und Sekunden
      Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);

      // Mitternacht
      // -> Wechsel des Datums anzeigen
      if (Stunden == 0 && Minuten == 0) 
      {
        Serial.println("neues Datum");
        ZeigeDatum();
      }

      ZeitAnzeigen();
    }
  }
}

void ZeitAnzeigen()
{
    // nur den Beriech der Zeit löschen
    tft.fillRect(1, 75, tft.width(), tft.height(), Hintergrundfarbe);

    u8g2Schriften.setFont(u8g2_font_logisoso78_tn);

    // Cursor setzen
    u8g2Schriften.setCursor(2, 160);

    // Stunde: wenn Stunde < 10 -> 0 davor setzen
    if (Zeit.tm_hour < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_hour);
    u8g2Schriften.print(":");

    // Minuten
    // wenn Minute < 10 -> 0 davor setzen
    if (Zeit.tm_min < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_min);
}

void ZeigeDatum()
{
  tft.fillScreen(Hintergrundfarbe);
  
  u8g2Schriften.setFont(u8g2_font_fub42_tf);

  // Cursor setzen
  u8g2Schriften.setCursor(10, 50);

 // Tag: führende 0 ergänzen
  if (Zeit.tm_mday < 10) 
  {
    Serial.print("0");
    u8g2Schriften.print("0");
  }
  Serial.print(Zeit.tm_mday);
  Serial.print(".");
  u8g2Schriften.print(Zeit.tm_mday);
  u8g2Schriften.print(".");

  // Monat: führende 0 ergänzen
  if (Zeit.tm_mon < 9) 
  {
    Serial.print("0");
    u8g2Schriften.print("0");
  }
  Serial.print(Zeit.tm_mon + 1);
  Serial.print(".");
  u8g2Schriften.print(Zeit.tm_mon + 1);
  u8g2Schriften.print(".");

  // Anzahl Jahre seit 1900
  Serial.print(Zeit.tm_year + 1900);
  Serial.print(" ");
  u8g2Schriften.print(Zeit.tm_year + 1900);

  tft.drawFastHLine(1, 65, tft.width(), Vordergrundfarbe);
  tft.drawFastHLine(1, 66, tft.width(), Vordergrundfarbe);
}

TFT 320×240 Pixel

Du musst die SPI-Pins des ver­wen­de­ten Mikro­con­trol­lers und die WiFi-Daten anpassen.

DHT11/DHT22 - Mess­da­ten und Zeit auf TFT anzeigen

TFT 160×128

#ifdef ESP8266
  #include "ESP8266WiFi.h"

#else 
  #include "WiFi.h"
#endif

#include "time.h"
#include "Adafruit_ST7735.h"
#include "U8g2_for_Adafruit_GFX.h"
#include "DHT.h"

// freier digitaler Pin für DHT
int SENSOR_DHT = 11;

// Sensortyp festlegen
// DHT22
#define SensorTyp DHT22

// DHT11
// #define SensorTyp DHT11

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

// Wemos D1 Mini
// #define TFT_CS       D8
// #define TFT_RST      D1
// #define TFT_DC       D2

// XIAO
// #define TFT_CS       D7
// #define TFT_RST      D1
// #define TFT_DC       D2

// Arduino Nano ESP 32
// #define TFT_CS       10
// #define TFT_RST       9
// #define TFT_DC        8

// ESP32-C6
// #define TFT_CS       18
// #define TFT_RST       3                                          
// #define TFT_DC        2

// ESP32-WROOM
// #define TFT_CS        5
// #define TFT_RST       4 
// #define TFT_DC        2
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;
WiFiServer Server(80);
WiFiClient Client;

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// Bitmaps
const unsigned char Kalender [] PROGMEM = {
	// 'Kalender_30x35, 30x35px
	0x7f, 0xff, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 
	0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 
	0xff, 0xff, 0xff, 0xfc, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x8e, 0x00, 0x01, 0xc4, 
	0x8e, 0x00, 0x01, 0xc4, 0x8e, 0x00, 0x01, 0xc4, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 
	0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 
	0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 
	0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 
	0x8e, 0x00, 0x01, 0xc4, 0x8e, 0x00, 0x01, 0xc4, 0x8e, 0x00, 0x01, 0xc4, 0x80, 0x00, 0x00, 0x04, 
	0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xfc
};

const unsigned char Uhr [] PROGMEM = {
	// 'Uhr_30x30, 30x30px
	0x00, 0x1f, 0xe0, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x01, 0xf0, 0x3e, 0x00, 0x07, 0x80, 0x07, 0x80, 
	0x0f, 0x03, 0x03, 0xc0, 0x1c, 0x60, 0x18, 0xe0, 0x18, 0x00, 0x00, 0x60, 0x38, 0x01, 0x00, 0x70, 
	0x30, 0x01, 0x00, 0x30, 0x63, 0x01, 0x01, 0x98, 0x60, 0x01, 0x00, 0x18, 0xe0, 0x01, 0x00, 0x1c, 
	0xc0, 0x01, 0x00, 0x0c, 0xc0, 0x01, 0x00, 0x0c, 0xcc, 0x01, 0x00, 0xcc, 0xc0, 0x02, 0x00, 0x0c, 
	0xc0, 0x0c, 0x00, 0x0c, 0xc0, 0x30, 0x00, 0x0c, 0xe0, 0xc0, 0x00, 0x1c, 0x66, 0x00, 0x01, 0x98, 
	0x60, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x70, 0x18, 0x60, 0x10, 0x60, 
	0x1c, 0x00, 0x00, 0xe0, 0x0f, 0x03, 0x03, 0xc0, 0x07, 0x80, 0x07, 0x80, 0x01, 0xf0, 0x3e, 0x00, 
	0x00, 0x7f, 0xfc, 0x00, 0x00, 0x1f, 0xe0, 0x00
};

const unsigned char Thermometer [] PROGMEM = {
	// 'Thermometer_19x40, 19x40px
	0x01, 0xe0, 0x00, 0x03, 0xf8, 0x00, 0x06, 0x0c, 0x00, 0x04, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 
	0x04, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x18, 0x04, 
	0x00, 0x08, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 
	0x00, 0xe4, 0x00, 0x00, 0xe4, 0x00, 0x38, 0xe4, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe4, 0x00, 0x00, 
	0xe4, 0x00, 0x00, 0xe4, 0x00, 0x18, 0xe7, 0x00, 0x30, 0xe3, 0x80, 0x21, 0xe1, 0x80, 0x63, 0xf8, 
	0xc0, 0x47, 0xf8, 0xc0, 0x47, 0xfc, 0x40, 0xc7, 0xfc, 0x60, 0xc7, 0xfc, 0x60, 0xc7, 0xfc, 0x60, 
	0x47, 0xfc, 0x40, 0x63, 0xf8, 0xc0, 0x61, 0xf0, 0xc0, 0x30, 0x01, 0x80, 0x10, 0x03, 0x00, 0x0e, 
	0x0e, 0x00, 0x07, 0xfc, 0x00, 0x00, 0xe0, 0x00
};

const unsigned char Regen [] PROGMEM = {
	// 'Regen_43x35, 43x35px
	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x22, 0x22, 0x21, 0x00, 0x00, 0x00, 0x66, 0x22, 0x23, 0x20, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 
	0x03, 0x11, 0x11, 0x19, 0x10, 0x00, 0x02, 0x00, 0x01, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x08, 0x08, 0x88, 0x80, 0x31, 0x11, 
	0x19, 0x18, 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x88, 0x8c, 0x88, 0xc4, 0xcc, 0xc0, 0x08, 0x88, 0x88, 0x04, 
	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 
	0x00, 0x00, 0x80, 0x00, 0x23, 0x33, 0x11, 0x11, 0x99, 0x00, 0x20, 0x20, 0x11, 0x10, 0x11, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x88, 0x88, 0x88, 
	0x88, 0x00, 0x01, 0x08, 0x98, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x46, 0x00, 0x00, 
	0x00, 0x04, 0x44, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00
};

void setup()
{
    // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // WiFi starten
  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft); 

  // Zufallsgenerator starten
  randomSeed(analogRead(A0));
  Serial.begin(9600);
  delay(500);
  Serial.println("Bildschirm: " + String(tft.height()) + " x " + String(tft.width()));

  // TFT starten
  tft.initR(INITR_BLACKTAB);

  // Rotation anpassen
  tft.setRotation(2);

  // Bitmaps anzeigen
  tft.fillScreen(ST77XX_BLACK);
  tft.drawBitmap(1, 1, Kalender, 30, 35, ST77XX_WHITE);  
  tft.drawBitmap(1, 40, Uhr, 30, 30, ST77XX_WHITE);
  tft.drawBitmap(10, 75, Thermometer, 19, 40, ST77XX_WHITE);
  tft.drawBitmap(1, 121, Regen, 43, 35, ST77XX_WHITE);

  // Sensor starten
  dht.begin();
}

void loop()
{
  // aktuelle Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // Temperatur lesen
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  // nur den Bereich der Daten schwärzen 
  tft.fillRect(45, 1, tft.width(), tft.height(), ST77XX_BLACK);

  u8g2Schriften.setForegroundColor(ST77XX_WHITE);   
  u8g2Schriften.setBackgroundColor(ST77XX_BLACK);
  u8g2Schriften.setFont(u8g2_font_helvB12_te); 
  u8g2Schriften.setCursor(48, 20); 
    
    // Tag: führende 0 ergänzen
  if (Zeit.tm_mday < 10) 
  {
    u8g2Schriften.print("0");
  }

  u8g2Schriften.print(Zeit.tm_mday);
  u8g2Schriften.print(".");

  // Monat: führende 0 ergänzen
  if (Zeit.tm_mon < 9) 
  {
    u8g2Schriften.print("0");
  }
  u8g2Schriften.print(Zeit.tm_mon + 1);
  u8g2Schriften.print(".");

  // Anzahl Jahre seit 1900
  u8g2Schriften.print(Zeit.tm_year + 1900);
  u8g2Schriften.print(" ");

  u8g2Schriften.setCursor(48, 60);

  // Stunde: wenn Stunde < 10 -> 0 davor setzen
  if (Zeit.tm_hour < 10) u8g2Schriften.print("0");
  u8g2Schriften.print(Zeit.tm_hour);
  u8g2Schriften.print(":");

  // Minuten
  if (Zeit.tm_min < 10) u8g2Schriften.print("0");
  u8g2Schriften.print(Zeit.tm_min);

  // Messdaten anzeigen
  u8g2Schriften.setCursor(48, 100);
  u8g2Schriften.print(Temperatur + " °C");
  u8g2Schriften.setCursor(48, 140);
  u8g2Schriften.print(Luftfeuchtigkeit + " %");

  delay(10000);
}

TFT 320×240

#ifdef ESP8266
  #include "ESP8266WiFi.h"

#else 
  #include "WiFi.h"
#endif

#include "Adafruit_ILI9341.h"
#include "time.h"
#include "U8g2_for_Adafruit_GFX.h"
#include "DHT.h"

// freier digitaler Pin für DHT
int SENSOR_DHT = D3;

// Sensortyp festlegen
// DHT22
#define SensorTyp DHT22

// DHT11
// #define SensorTyp DHT11

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

// Wemos D1 Mini
// #define TFT_CS       D8
// #define TFT_RST      D1
// #define TFT_DC       D2

// XIAO
// #define TFT_CS       D7
// #define TFT_RST      D1
// #define TFT_DC       D2

// Arduino Nano ESP 32
// #define TFT_CS       10
// #define TFT_RST       9
// #define TFT_DC        8

// ESP32-C6
// #define TFT_CS       18
// #define TFT_RST       3                                          
// #define TFT_DC        2

// ESP32-WROOM
// #define TFT_CS        5
// #define TFT_RST       4 
// #define TFT_DC        2

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;
WiFiServer Server(80);
WiFiClient Client;

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// Bitmaps
const unsigned char Uhr [] PROGMEM = {
	// 'Uhr, 50x50px
	0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 
	0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x01, 
	0xfe, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x1f, 0xc0, 
	0x00, 0x01, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x03, 0xf0, 0x00, 0xc0, 0x03, 0xf0, 0x00, 0x07, 
	0xc0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x07, 0x80, 0xc0, 0x00, 0x40, 0x78, 0x00, 0x0f, 0x80, 0x00, 
	0x00, 0x00, 0x7c, 0x00, 0x1f, 0x00, 0x00, 0x80, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x00, 0xc0, 0x00, 
	0x1e, 0x00, 0x3e, 0x00, 0x00, 0xc0, 0x00, 0x1f, 0x00, 0x3c, 0x00, 0x00, 0xc0, 0x00, 0x0f, 0x00, 
	0x38, 0x30, 0x00, 0xc0, 0x01, 0x07, 0x00, 0x78, 0x00, 0x00, 0xc0, 0x00, 0x07, 0x80, 0x78, 0x00, 
	0x00, 0xc0, 0x00, 0x07, 0x80, 0x70, 0x00, 0x00, 0xc0, 0x00, 0x03, 0x80, 0xf0, 0x00, 0x00, 0xc0, 
	0x00, 0x03, 0xc0, 0xf0, 0x00, 0x00, 0xc0, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0x00, 0xc0, 0x00, 0x03, 
	0xc0, 0xf0, 0x00, 0x00, 0xc0, 0x00, 0x03, 0xc0, 0xf1, 0x80, 0x00, 0xc0, 0x00, 0x63, 0xc0, 0xf1, 
	0x80, 0x01, 0x80, 0x00, 0x63, 0xc0, 0xf0, 0x00, 0x07, 0x00, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0x1c, 
	0x00, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0x78, 0x00, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0xe0, 0x00, 0x00, 
	0x03, 0xc0, 0x70, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x78, 0x07, 0x00, 0x00, 0x00, 0x07, 0x80, 
	0x78, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x78, 0x20, 0x00, 0x00, 0x01, 0x07, 0x80, 0x3c, 0x00, 
	0x00, 0x00, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x00, 
	0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x7c, 
	0x00, 0x07, 0x80, 0x80, 0x00, 0xc0, 0x78, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x03, 
	0xf0, 0x00, 0xc0, 0x03, 0xf0, 0x00, 0x01, 0xf8, 0x00, 0xc0, 0x07, 0xe0, 0x00, 0x00, 0xfe, 0x00, 
	0x00, 0x1f, 0xc0, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x1f, 0xe0, 0x01, 0xfe, 
	0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf0, 0x00, 0x00, 
	0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00
};

const unsigned char Thermometer [] PROGMEM = {
	// 'Thermometer, 34x70px
	0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x00, 
	0x7c, 0x0f, 0x00, 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x00, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0xe0, 
	0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 
	0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 
	0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 
	0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 
	0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 
	0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 
	0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc3, 0xe1, 0xc0, 
	0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x0f, 0xc3, 0xf1, 0xc0, 0x00, 
	0x0f, 0xc3, 0xf1, 0xc0, 0x00, 0x0f, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 
	0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 
	0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x03, 0xc3, 0xf1, 0xf0, 0x00, 0x07, 0xc3, 0xf0, 
	0xf8, 0x00, 0x0f, 0x03, 0xf0, 0x7c, 0x00, 0x0e, 0x03, 0xe0, 0x3c, 0x00, 0x1c, 0x07, 0xf0, 0x1e, 
	0x00, 0x3c, 0x1f, 0xfc, 0x0f, 0x00, 0x38, 0x3f, 0xfe, 0x0f, 0x00, 0x78, 0x7f, 0xff, 0x07, 0x80, 
	0x70, 0x7f, 0xff, 0x87, 0x80, 0x70, 0x7f, 0xff, 0x83, 0x80, 0xf0, 0xff, 0xff, 0x83, 0xc0, 0xf0, 
	0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 
	0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0x83, 0xc0, 0x70, 0x7f, 0xff, 0x83, 0x80, 0x70, 0x7f, 0xff, 
	0x87, 0x80, 0x78, 0x3f, 0xff, 0x07, 0x80, 0x38, 0x3f, 0xfe, 0x0f, 0x00, 0x3c, 0x0f, 0xfc, 0x0f, 
	0x00, 0x1e, 0x03, 0xe0, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x3e, 0x00, 0x0f, 0x00, 0x00, 0x7c, 0x00, 
	0x07, 0xe0, 0x01, 0xf8, 0x00, 0x03, 0xf8, 0x07, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 
	0x7f, 0xff, 0x80, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00
};

const unsigned char Regen [] PROGMEM = {
	// 'Regen, 60x49px
	0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x02, 0x08, 0x21, 0x04, 0x10, 0x00, 0x00, 0x00, 0x06, 0x18, 0x63, 0x0c, 0x30, 0x80, 0x00, 
	0x00, 0x06, 0x10, 0x63, 0x0c, 0x31, 0x80, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x20, 0x84, 0x10, 0x41, 0x08, 0x20, 0x00, 0x00, 0x61, 0x8c, 0x30, 0xc3, 0x18, 0x60, 0x00, 
	0x08, 0xc1, 0x8c, 0x30, 0xc3, 0x18, 0x61, 0x00, 0x00, 0x41, 0x04, 0x20, 0x82, 0x08, 0x40, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x86, 0x18, 0x43, 0x04, 0x30, 0x80, 
	0x18, 0x71, 0x86, 0x18, 0xc3, 0x0c, 0x31, 0x80, 0x18, 0x21, 0x84, 0x10, 0xc3, 0x0c, 0x21, 0x80, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x18, 0x21, 0x04, 0x10, 0x42, 0x18, 0x40, 
	0x86, 0x18, 0x63, 0x0c, 0x30, 0xc6, 0x18, 0xc0, 0x86, 0x10, 0x63, 0x0c, 0x30, 0xc6, 0x18, 0xc0, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x18, 0x21, 0x04, 0x10, 0xc2, 0x0c, 0x21, 0x00, 0x30, 0x63, 0x0c, 0x31, 0xc6, 0x0c, 0x63, 0x00, 
	0x30, 0x63, 0x0c, 0x31, 0x86, 0x18, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x06, 0x10, 0x43, 0x08, 0x20, 0x86, 0x10, 0x00, 0x06, 0x30, 0xc3, 0x18, 0x61, 0x86, 0x30, 0x00, 
	0x04, 0x30, 0xc2, 0x18, 0x61, 0x8c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x0c, 0x30, 0xc6, 0x18, 0x61, 0x00, 0x00, 
	0x00, 0x00, 0x61, 0xc6, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x86, 0x10, 0x60, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const unsigned char Kalender [] PROGMEM = {
	// 'Kalender, 51x60px
	0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xe0, 0xff, 0xff, 
	0xff, 0x1f, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 
	0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0xf0, 
	0x00, 0x00, 0x01, 0xe0, 0x60, 0x81, 0xf8, 0x00, 0x00, 0x03, 0xf0, 0x60, 0x81, 0xf8, 0x00, 0x00, 
	0x03, 0xf0, 0x60, 0x81, 0xf8, 0x00, 0x00, 0x03, 0xf0, 0x60, 0x81, 0xf8, 0x00, 0x00, 0x03, 0xf0, 
	0x60, 0x80, 0xf0, 0x00, 0x00, 0x01, 0xe0, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
	0x80, 0xf0, 0x00, 0x00, 0x01, 0xe0, 0x60, 0x81, 0xf8, 0x00, 0x00, 0x03, 0xf0, 0x60, 0x81, 0xf8, 
	0x00, 0x00, 0x03, 0xf0, 0x60, 0xc1, 0xf8, 0x00, 0x00, 0x03, 0xf0, 0x60, 0xc1, 0xf8, 0x00, 0x00, 
	0x03, 0xf0, 0x60, 0xc0, 0xf0, 0x00, 0x00, 0x01, 0xe0, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0
};

void setup()
{
    // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // WiFi starten
  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft); 

  // Zufallsgenerator starten
  randomSeed(analogRead(A0));
  Serial.begin(9600);
  delay(500);
  Serial.println("Bildschirm: " + String(tft.height()) + " x " + String(tft.width()));

  // TFT starten
  tft.begin();

  // Rotation anpassen
  tft.setRotation(2);

  // Bitmaps anzeigen
  tft.fillScreen(ILI9341_BLACK);
  tft.drawBitmap(1, 1, Kalender, 51, 60, ILI9341_WHITE);  
  tft.drawBitmap(1, 90, Uhr, 50, 50, ILI9341_WHITE);
  tft.drawBitmap(10, 170, Thermometer, 34, 70, ILI9341_WHITE);
  tft.drawBitmap(1, 270, Regen, 60, 49, ILI9341_WHITE);

  // Sensor starten
  dht.begin();
}

void loop()
{
  // aktuelle Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // Temperatur lesen
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  // nur den Bereich der Daten schwärzen 
  tft.fillRect(60, 1, tft.width(), tft.height(), ILI9341_BLACK);

  u8g2Schriften.setForegroundColor(ILI9341_WHITE);   
  u8g2Schriften.setBackgroundColor(ILI9341_BLACK);
  u8g2Schriften.setFont(u8g2_font_helvB24_tf); 
  u8g2Schriften.setCursor(70, 45); 
    
    // Tag: führende 0 ergänzen
  if (Zeit.tm_mday < 10) 
  {
    u8g2Schriften.print("0");
  }

  u8g2Schriften.print(Zeit.tm_mday);
  u8g2Schriften.print(".");

  // Monat: führende 0 ergänzen
  if (Zeit.tm_mon < 9) 
  {
    u8g2Schriften.print("0");
  }
  u8g2Schriften.print(Zeit.tm_mon + 1);
  u8g2Schriften.print(".");

  // Anzahl Jahre seit 1900
  u8g2Schriften.print(Zeit.tm_year + 1900);
  u8g2Schriften.print(" ");

  u8g2Schriften.setCursor(70, 120);

    // Stunde: wenn Stunde < 10 -> 0 davor setzen
    if (Zeit.tm_hour < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_hour);
    u8g2Schriften.print(":");

    // Minuten
    if (Zeit.tm_min < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_min);

     // Messdaten anzeigen
    u8g2Schriften.setCursor(70, 210);
    u8g2Schriften.print(Temperatur + " °C");
    u8g2Schriften.setCursor(70, 300);
    u8g2Schriften.print(Luftfeuchtigkeit + " %");

    delay(10000);
}

Letzte Aktualisierung:

DHT11/DHT22 Mess­da­ten auf Wavesha­re 1,54 E-Ink anzeigen

Anzei­ge nur Text

#include "GxEPD2_3C.h"
#include "DHT.h"
#include "U8g2_for_Adafruit_GFX.h"

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// freien Pin auf dem Board wählen
int SENSOR_DHT = 9;

// Sensortyp festlegen
// DHT22
#define SensorTyp DHT22

// DHT11
// #define SensorTyp DHT11

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

// Display-Parameter
// GxEPD2_154_Z90c: Chip SSD1681 Bildschirm: 200x200
#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
#define GxEPD2_DRIVER_CLASS GxEPD2_154_Z90c  

// Board wählen:
// ESP32-Wroom
// Anschlüsse: CLK -> 18, DIN -> 23, CS -> 5, DC -> 2, RST -> 22, BUSY -> 4
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/ 5, /*DC=*/ 2, /*RST=*/ 22, /*BUSY=*/ 4));

// NodeMCU
// CLK - D5, DIN -> D7, CS -> D8, DC -> D6, RST -> D2, BUSY -> D1
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/D4, /*DC=*/ D6, /*RST=*/ D2, /*BUSY=*/ D1));

// ESP32-C6
// Anschlüsse: CLK -> 21, DIN -> 19, CS -> 18, DC -> 3, RST -> 10, BUSY -> 11
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/ 18, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 11));

// Nano ESP32
// Anschlüsse: CLK -> D13, DIN -> D11, CS -> D10, DC-> D6, RST -> D8, BUSY -> D9
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/ D10, /*DC=*/ D6, /*RST=*/ D7, /*BUSY=*/ D9));

void setup() 
{
  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // Sensor starten
  dht.begin();

  // Bildschirm starten
  display.init(115200, true, 2, false); 

  // Bildschirm um 90° drehen
  display.setRotation(1);

  // vollständigen Bildschirm nutzen
  display.setFullWindow();

  // weißer Hintergrund
  display.fillScreen(GxEPD_WHITE);

  // Schriften von u8g2 display zuordnen
  u8g2Schriften.begin(display); 
}

void loop() 
{
  // Temperatur lesen
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  // Anzeige aufbauen
  display.firstPage();
  do 
  {
    display.fillScreen(GxEPD_WHITE);

    u8g2Schriften.setForegroundColor(GxEPD_BLACK);   
    u8g2Schriften.setBackgroundColor(GxEPD_WHITE);
    u8g2Schriften.setFont(u8g2_font_fub35_tf);  

    u8g2Schriften.setCursor(1, 80);
    u8g2Schriften.print(Temperatur + " °C");
    u8g2Schriften.setCursor(1, 180);
    u8g2Schriften.print(Luftfeuchtigkeit + " %");
  } 
  while (display.nextPage());

  // alle 5 Minuten aktualisieren
  delay(300000);
}

Anzei­ge nur Text mit Uhrzeit

#ifdef ESP8266
  #include "ESP8266WiFi.h"
#else 
  #include "WiFi.h"
#endif

#include "time.h"
#include "GxEPD2_3C.h"
#include "U8g2_for_Adafruit_GFX.h"
#include "DHT.h"

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// freien Pin auf dem Board wählen
int SENSOR_DHT = 9;

// Sensortyp festlegen
// DHT22
#define SensorTyp DHT22

// DHT11
// #define SensorTyp DHT11

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

// Schriftart
#include "Fonts/FreeMonoBold24pt7b.h"

char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;
WiFiServer Server(80);
WiFiClient Client;

// Display-Parameter
// GxEPD2_154_Z90c: Chip SSD1681 Bildschirm: 200x200
#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
#define GxEPD2_DRIVER_CLASS GxEPD2_154_Z90c  

// Board wählen:
// ESP32-Wroom
// Anschlüsse: CLK -> 18, DIN -> 23, CS -> 5, DC -> 2, RST -> 22, BUSY -> 4
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/ 5, /*DC=*/ 2, /*RST=*/ 22, /*BUSY=*/ 4));

// NodeMCU
// CLK - D5, DIN -> D7, CS -> D8, DC -> D6, RST -> D2, BUSY -> D1
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/D4, /*DC=*/ D6, /*RST=*/ D2, /*BUSY=*/ D1));

// ESP32-C6
// Anschlüsse: CLK -> 21, DIN -> 19, CS -> 18, DC -> 3, RST -> 10, BUSY -> 11
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/ 18, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 11));

// Nano ESP32
// Anschlüsse: CLK -> D13, DIN -> D11, CS -> D10, DC-> D6, RST -> D8, BUSY -> D9
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/ D10, /*DC=*/ D6, /*RST=*/ D7, /*BUSY=*/ D9));

void setup() 
{
  // Schriften von u8g2 display zuordnen
  u8g2Schriften.begin(display); 
  
  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Sensor starten
  dht.begin();

  // Bildschirm starten
  display.init(115200, true, 2, false); 

  // Bildschirm um 90° drehen
  display.setRotation(1);

  // vollständigen Bildschirm nutzen
  display.setFullWindow();

  // weißer Hintergrund
  display.fillScreen(GxEPD_WHITE);
}

void loop() 
{
  // aktuelle Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // Temperatur lesen
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  // Anzeige aufbauen
  display.firstPage();
  do 
  {
    display.fillScreen(GxEPD_WHITE);
    
    u8g2Schriften.setForegroundColor(GxEPD_BLACK);   
    u8g2Schriften.setBackgroundColor(GxEPD_WHITE);
    u8g2Schriften.setFont(u8g2_font_fub35_tf); 
    
    u8g2Schriften.setCursor(1, 50);

    // Stunde: wenn Stunde < 10 -> 0 davor setzen
    if (Zeit.tm_hour < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_hour);
    u8g2Schriften.print(":");

    // Minuten
    if (Zeit.tm_min < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_min);

    // horizontale Linie
    display.fillRect(1, 62, display.width(), 4, GxEPD_BLACK);

    u8g2Schriften.setCursor(1, 110);

    u8g2Schriften.print(Temperatur + " °C");
    u8g2Schriften.setCursor(1, 170);
    u8g2Schriften.print(Luftfeuchtigkeit + " %");
  } 
  while (display.nextPage());

  // alle 5 Minuten aktualisieren
  delay(300000);
}

Anzei­ge mit Sym­bo­len und Text

#ifdef ESP8266
  #include "ESP8266WiFi.h"
#else 
  #include "WiFi.h"
#endif

#include "time.h"
#include "GxEPD2_3C.h"
#include "U8g2_for_Adafruit_GFX.h"
#include "DHT.h"

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// Pin DHT
int SENSOR_DHT = 9;

// Sensortyp festlegen
// DHT22
#define SensorTyp DHT22

// DHT11
// #define SensorTyp DHT11

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;
WiFiServer Server(80);
WiFiClient Client;

// Display-Parameter
// GxEPD2_154_Z90c: Chip SSD1681 Bildschirm: 200x200
#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
#define GxEPD2_DRIVER_CLASS GxEPD2_154_Z90c

// ESP32-Wroom
// Anschlüsse: CLK -> 18, DIN -> 23, CS -> 5, DC-> 2, RST -> 22, BUSY -> 4
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/5, /*DC=*/2, /*RST=*/22, /*BUSY=*/4));

// NodeMCU
// CLK - D5, DIN -> D7, CS -> D8, DC -> D6, RST -> D2, BUSY -> D1
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/D4, /*DC=*/D6, /*RST=*/D2, /*BUSY=*/D1));

// ESP32-C6
// Anschlüsse: CLK -> 21, DIN -> 19, CS -> 18, DC-> 3, RST -> 10, BUSY -> 11
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
//  display(GxEPD2_DRIVER_CLASS(/*CS=*/ 18, /*DC=*/ 3, /*RST=*/2, /*BUSY=*/11));

// Nano ESP32
// Anschlüsse: CLK -> D13, DIN -> D11, CS -> D10, DC-> D6, RST -> D8, BUSY -> D9
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, 200>
// display(GxEPD2_DRIVER_CLASS(/*CS=*/ D10, /*DC=*/ D6, /*RST=*/ D7, /*BUSY=*/ D9));


const unsigned char Thermometer [] PROGMEM = {
	// 'Thermometer, 34x70px
	0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x00, 
	0x7c, 0x0f, 0x00, 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x00, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0xe0, 
	0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 
	0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 
	0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 
	0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 
	0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 
	0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 
	0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc3, 0xe1, 0xc0, 
	0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x0f, 0xc3, 0xf1, 0xc0, 0x00, 
	0x0f, 0xc3, 0xf1, 0xc0, 0x00, 0x0f, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 
	0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 
	0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x03, 0xc3, 0xf1, 0xf0, 0x00, 0x07, 0xc3, 0xf0, 
	0xf8, 0x00, 0x0f, 0x03, 0xf0, 0x7c, 0x00, 0x0e, 0x03, 0xe0, 0x3c, 0x00, 0x1c, 0x07, 0xf0, 0x1e, 
	0x00, 0x3c, 0x1f, 0xfc, 0x0f, 0x00, 0x38, 0x3f, 0xfe, 0x0f, 0x00, 0x78, 0x7f, 0xff, 0x07, 0x80, 
	0x70, 0x7f, 0xff, 0x87, 0x80, 0x70, 0x7f, 0xff, 0x83, 0x80, 0xf0, 0xff, 0xff, 0x83, 0xc0, 0xf0, 
	0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 
	0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0x83, 0xc0, 0x70, 0x7f, 0xff, 0x83, 0x80, 0x70, 0x7f, 0xff, 
	0x87, 0x80, 0x78, 0x3f, 0xff, 0x07, 0x80, 0x38, 0x3f, 0xfe, 0x0f, 0x00, 0x3c, 0x0f, 0xfc, 0x0f, 
	0x00, 0x1e, 0x03, 0xe0, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x3e, 0x00, 0x0f, 0x00, 0x00, 0x7c, 0x00, 
	0x07, 0xe0, 0x01, 0xf8, 0x00, 0x03, 0xf8, 0x07, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 
	0x7f, 0xff, 0x80, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00
};

const unsigned char Regen [] PROGMEM = {
	// 'Regen, 60x49px
	0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x02, 0x08, 0x21, 0x04, 0x10, 0x00, 0x00, 0x00, 0x06, 0x18, 0x63, 0x0c, 0x30, 0x80, 0x00, 
	0x00, 0x06, 0x10, 0x63, 0x0c, 0x31, 0x80, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x20, 0x84, 0x10, 0x41, 0x08, 0x20, 0x00, 0x00, 0x61, 0x8c, 0x30, 0xc3, 0x18, 0x60, 0x00, 
	0x08, 0xc1, 0x8c, 0x30, 0xc3, 0x18, 0x61, 0x00, 0x00, 0x41, 0x04, 0x20, 0x82, 0x08, 0x40, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x86, 0x18, 0x43, 0x04, 0x30, 0x80, 
	0x18, 0x71, 0x86, 0x18, 0xc3, 0x0c, 0x31, 0x80, 0x18, 0x21, 0x84, 0x10, 0xc3, 0x0c, 0x21, 0x80, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x18, 0x21, 0x04, 0x10, 0x42, 0x18, 0x40, 
	0x86, 0x18, 0x63, 0x0c, 0x30, 0xc6, 0x18, 0xc0, 0x86, 0x10, 0x63, 0x0c, 0x30, 0xc6, 0x18, 0xc0, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x18, 0x21, 0x04, 0x10, 0xc2, 0x0c, 0x21, 0x00, 0x30, 0x63, 0x0c, 0x31, 0xc6, 0x0c, 0x63, 0x00, 
	0x30, 0x63, 0x0c, 0x31, 0x86, 0x18, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x06, 0x10, 0x43, 0x08, 0x20, 0x86, 0x10, 0x00, 0x06, 0x30, 0xc3, 0x18, 0x61, 0x86, 0x30, 0x00, 
	0x04, 0x30, 0xc2, 0x18, 0x61, 0x8c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x0c, 0x30, 0xc6, 0x18, 0x61, 0x00, 0x00, 
	0x00, 0x00, 0x61, 0xc6, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x86, 0x10, 0x60, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const unsigned char Uhr [] PROGMEM = {
	// Uhr, 50x50px
	0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 
	0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x01, 
	0xfe, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x1f, 0xc0, 
	0x00, 0x01, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x03, 0xf0, 0x00, 0xc0, 0x03, 0xf0, 0x00, 0x07, 
	0xc0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x07, 0x80, 0xc0, 0x00, 0x40, 0x78, 0x00, 0x0f, 0x80, 0x00, 
	0x00, 0x00, 0x7c, 0x00, 0x1f, 0x00, 0x00, 0x80, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x00, 0xc0, 0x00, 
	0x1e, 0x00, 0x3e, 0x00, 0x00, 0xc0, 0x00, 0x1f, 0x00, 0x3c, 0x00, 0x00, 0xc0, 0x00, 0x0f, 0x00, 
	0x38, 0x30, 0x00, 0xc0, 0x01, 0x07, 0x00, 0x78, 0x00, 0x00, 0xc0, 0x00, 0x07, 0x80, 0x78, 0x00, 
	0x00, 0xc0, 0x00, 0x07, 0x80, 0x70, 0x00, 0x00, 0xc0, 0x00, 0x03, 0x80, 0xf0, 0x00, 0x00, 0xc0, 
	0x00, 0x03, 0xc0, 0xf0, 0x00, 0x00, 0xc0, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0x00, 0xc0, 0x00, 0x03, 
	0xc0, 0xf0, 0x00, 0x00, 0xc0, 0x00, 0x03, 0xc0, 0xf1, 0x80, 0x00, 0xc0, 0x00, 0x63, 0xc0, 0xf1, 
	0x80, 0x01, 0x80, 0x00, 0x63, 0xc0, 0xf0, 0x00, 0x07, 0x00, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0x1c, 
	0x00, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0x78, 0x00, 0x00, 0x03, 0xc0, 0xf0, 0x00, 0xe0, 0x00, 0x00, 
	0x03, 0xc0, 0x70, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x78, 0x07, 0x00, 0x00, 0x00, 0x07, 0x80, 
	0x78, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x78, 0x20, 0x00, 0x00, 0x01, 0x07, 0x80, 0x3c, 0x00, 
	0x00, 0x00, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x00, 
	0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x7c, 
	0x00, 0x07, 0x80, 0x80, 0x00, 0xc0, 0x78, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x03, 
	0xf0, 0x00, 0xc0, 0x03, 0xf0, 0x00, 0x01, 0xf8, 0x00, 0xc0, 0x07, 0xe0, 0x00, 0x00, 0xfe, 0x00, 
	0x00, 0x1f, 0xc0, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x1f, 0xe0, 0x01, 0xfe, 
	0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf0, 0x00, 0x00, 
	0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00
};

void setup() 
{
  // Schriften von u8g2 display zuordnen
  u8g2Schriften.begin(display); 

  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Bildschirm starten
  display.init(115200, true, 2, false);

  // Bildschirm um 90° drehen
  display.setRotation(1);

  // vollständigen Bildschirm nutzen
  display.setFullWindow();
  display.fillScreen(GxEPD_WHITE);

  // Sensor starten
  dht.begin();
}

void loop()
{
  // aktuelle Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // Temperatur lesen
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  // Anzeige aufbauen
  display.firstPage();
  do 
  {
    u8g2Schriften.setForegroundColor(GxEPD_BLACK);   
    u8g2Schriften.setBackgroundColor(GxEPD_WHITE);
    u8g2Schriften.setFont(u8g2_font_helvB24_tf);   

    u8g2Schriften.setCursor(70, 40);

    // Stunde: wenn Stunde < 10 -> 0 davor setzen
    if (Zeit.tm_hour < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_hour);
    u8g2Schriften.print(":");

    // Minuten
    if (Zeit.tm_min < 10) u8g2Schriften.print("0");
    u8g2Schriften.print(Zeit.tm_min);

    // x, y, Bild-Array, Breite, Höhe, Farbe
    display.drawBitmap(5, 5, Uhr, 50, 50, GxEPD_BLACK);
    display.drawBitmap(15, 70, Thermometer, 34, 70, GxEPD_BLACK);
    display.drawBitmap(5, 150, Regen, 60, 49, GxEPD_BLACK);  

    // Messdaten anzeigen
    u8g2Schriften.setCursor(70, 110);
    u8g2Schriften.print(Temperatur + " °C");
    u8g2Schriften.setCursor(70, 180);
    u8g2Schriften.print(Luftfeuchtigkeit + " %");
  } 
  while (display.nextPage());

  // alle 5 Minuten aktualisieren
  delay(300000);
}

Letzte Aktualisierung:

Zeit mit time.h auf einem 4-stel­li­gen 7-Segment-Anzeige

ESP32-Wroom

#include "WiFi.h"
#include "time.h"
#include "TM1637.h"

TM1637 Anzeige(5, 17);

// WiFi-Daten
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_wday -> Wochentag (0 = Sonntag, 6 = Samstag)
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

// Variablen für die Zeit
int Stunden, Minuten, Sekunden;

// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = true;

unsigned long Zeitmessung = 0;

unsigned long Intervall = 1000;

// String für die Anzeige der Zeit
String ZeitAnzeige;

void setup() 
{
  Serial.begin(9600);
  
  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  WiFi.mode(WIFI_STA);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900);
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");

  Serial.println("-------------------------");
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");

  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900);

    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    delay(1000);
    Zaehler++;

    if (Zaehler >= 90) 
    {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while (1);
    }

    Serial.print(".");
  }

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");

    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

    // Monat: führende 0 ergänzen
    if (Zeit.tm_mon < 9) Serial.print("0");

    // Zählung beginnt mit 0 -> +1
    Serial.print(Zeit.tm_mon + 1);
    Serial.print(".");

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");

    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.print(Zeit.tm_min);
    Serial.print(":");
    
    if (Zeit.tm_sec < 10) Serial.print("0");
    Serial.println(Zeit.tm_sec);
    Serial.println("-------------------------");
  }

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
  
  // Anzeige starten
  Anzeige.begin();  

  // Helligkeit
  Anzeige.setBrightness(10);

  Anzeige.clearScreen();

  Zeitmessung = millis() + 1000;
}

void loop() 
{
  // Start = true
  // -> Zeit einmalig synchronisieren
  if (Start)
  {
    Start = false;
    
    // Zeit jede Minute mit Zeitserver synchronisieren
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }

  // Sekunden weiter zählen
  if (Zeitmessung < millis()) 
  {
    Zeitmessung += 1000;
    Sekunden++;

    if (Sekunden == 60) 
    {
      // Zeit jede Minute mit Zeitserver synchronisieren
      // aktuelle Zeit holen
      time(&aktuelleZeit);

      // localtime_r -> Zeit in die lokale Zeitzone setzen
      localtime_r(&aktuelleZeit, &Zeit);

      // Zeit in Stunden, Minuten und Sekunden
      Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    }
  }

  if (Sekunden == 0) 
  {
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }
 }

ESP32-C6

#include "WiFi.h"
#include "time.h"
#include "TM1637.h"

TM1637 Anzeige(15, 23);

// WiFi-Daten
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_wday -> Wochentag (0 = Sonntag, 6 = Samstag)
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

// Variablen für die Zeit
int Stunden, Minuten, Sekunden;

// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = true;

unsigned long Zeitmessung = 0;

unsigned long Intervall = 1000;

// String für die Anzeige der Zeit
String ZeitAnzeige;

void setup() 
{
  Serial.begin(9600);
  
  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  WiFi.mode(WIFI_STA);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900);
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");

  Serial.println("-------------------------");
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");

  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900);

    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    delay(1000);
    Zaehler++;

    if (Zaehler >= 90) 
    {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while (1);
    }

    Serial.print(".");
  }

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");

    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

    // Monat: führende 0 ergänzen
    if (Zeit.tm_mon < 9) Serial.print("0");

    // Zählung beginnt mit 0 -> +1
    Serial.print(Zeit.tm_mon + 1);
    Serial.print(".");

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");

    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.print(Zeit.tm_min);
    Serial.print(":");

    if (Zeit.tm_sec < 10) Serial.print("0");
    Serial.println(Zeit.tm_sec);
    Serial.println("-------------------------");
  }

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
  
  // Anzeige starten
  Anzeige.begin();  

  // Helligkeit
  Anzeige.setBrightness(10);

  Anzeige.clearScreen();

  Zeitmessung = millis() + 1000;
}

void loop() 
{
  // Start = true
  // -> Zeit einmalig synchronisieren
  if (Start)
  {
    Start = false;
    
    // Zeit jede Minute mit Zeitserver synchronisieren
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }

  // Sekunden weiter zählen
  if (Zeitmessung < millis()) 
  {
    Zeitmessung += 1000;
    Sekunden++;

    if (Sekunden == 60) 
    {
      // Zeit jede Minute mit Zeitserver synchronisieren
      // aktuelle Zeit holen
      time(&aktuelleZeit);

      // localtime_r -> Zeit in die lokale Zeitzone setzen
      localtime_r(&aktuelleZeit, &Zeit);

      // Zeit in Stunden, Minuten und Sekunden
      Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    }
  }

  if (Sekunden == 0) 
  {
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }
 }

XIAO-ESP32-C3

#include "WiFi.h"
#include "time.h"
#include "TM1637.h"

TM1637 Anzeige(D3, D4);

// WiFi-Daten
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_wday -> Wochentag (0 = Sonntag, 6 = Samstag)
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

// Variablen für die Zeit
int Stunden, Minuten, Sekunden;

// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = true;

unsigned long Zeitmessung = 0;

unsigned long Intervall = 1000;

// String für die Anzeige der Zeit
String ZeitAnzeige;

void setup() 
{
  Serial.begin(9600);
  
  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  WiFi.mode(WIFI_STA);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900);
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");

  Serial.println("-------------------------");
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");

  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900);

    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    delay(1000);
    Zaehler++;

    if (Zaehler >= 90) 
    {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while (1);
    }

    Serial.print(".");
  }

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");

    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

    // Monat: führende 0 ergänzen
    if (Zeit.tm_mon < 9) Serial.print("0");

    // Zählung beginnt mit 0 -> +1
    Serial.print(Zeit.tm_mon + 1);
    Serial.print(".");

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");

    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.print(Zeit.tm_min);
    Serial.print(":");

    if (Zeit.tm_sec < 10) Serial.print("0");
    Serial.println(Zeit.tm_sec);
    Serial.println("-------------------------");
  }

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
  
  // Anzeige starten
  Anzeige.begin();  

  // Helligkeit
  Anzeige.setBrightness(10);

  Anzeige.clearScreen();

  Zeitmessung = millis() + 1000;
}

void loop() 
{
  // Start = true
  // -> Zeit einmalig synchronisieren
  if (Start)
  {
    Start = false;
    
    // Zeit jede Minute mit Zeitserver synchronisieren
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }

  // Sekunden weiter zählen
  if (Zeitmessung < millis()) 
  {
    Zeitmessung += 1000;
    Sekunden++;

    if (Sekunden == 60) 
    {
      // Zeit jede Minute mit Zeitserver synchronisieren
      // aktuelle Zeit holen
      time(&aktuelleZeit);

      // localtime_r -> Zeit in die lokale Zeitzone setzen
      localtime_r(&aktuelleZeit, &Zeit);

      // Zeit in Stunden, Minuten und Sekunden
      Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    }
  }

  if (Sekunden == 0) 
  {
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }
 }

Wemos D1 Mini

#include "WiFi.h"
#include "time.h"
#include "TM1637.h"

TM1637 Anzeige(D3, D4);
// TM1637 Anzeige(5, 17);

// WiFi-Daten
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_wday -> Wochentag (0 = Sonntag, 6 = Samstag)
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

// Variablen für die Zeit
int Stunden, Minuten, Sekunden;

// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = true;

unsigned long Zeitmessung = 0;

unsigned long Intervall = 1000;

// String für die Anzeige der Zeit
String ZeitAnzeige;

void setup() 
{
  Serial.begin(9600);
  
  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  WiFi.mode(WIFI_STA);

  // WiFi starten
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900);
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");

  Serial.println("-------------------------");
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");

  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900);

    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    delay(1000);
    Zaehler++;

    if (Zaehler >= 90) 
    {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while (1);
    }

    Serial.print(".");
  }

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");

    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

    // Monat: führende 0 ergänzen
    if (Zeit.tm_mon < 9) Serial.print("0");

    // Zählung beginnt mit 0 -> +1
    Serial.print(Zeit.tm_mon + 1);
    Serial.print(".");

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");

    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.print(Zeit.tm_min);
    Serial.print(":");

    if (Zeit.tm_sec < 10) Serial.print("0");
    Serial.println(Zeit.tm_sec);
    Serial.println("-------------------------");
  }

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
  
  // Anzeige starten
  Anzeige.begin();  

  // Helligkeit
  Anzeige.setBrightness(10);

  Anzeige.clearScreen();

  Zeitmessung = millis() + 1000;
}

void loop() 
{
  // Start = true
  // -> Zeit einmalig synchronisieren
  if (Start)
  {
    Start = false;
    
    // Zeit jede Minute mit Zeitserver synchronisieren
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);

    // Zeit in Stunden, Minuten und Sekunden
    Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }

  // Sekunden weiter zählen
  if (Zeitmessung < millis()) 
  {
    Zeitmessung += 1000;
    Sekunden++;

    if (Sekunden == 60) 
    {
      // Zeit jede Minute mit Zeitserver synchronisieren
      // aktuelle Zeit holen
      time(&aktuelleZeit);

      // localtime_r -> Zeit in die lokale Zeitzone setzen
      localtime_r(&aktuelleZeit, &Zeit);

      // Zeit in Stunden, Minuten und Sekunden
      Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);
    }
  }

  if (Sekunden == 0) 
  {
    // : einschalten
    Anzeige.colonOn();
    
    if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
    else ZeitAnzeige = String(Zeit.tm_hour);

    if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
    else ZeitAnzeige += String(Zeit.tm_min);

    Anzeige.display(ZeitAnzeige);
  }
 }

#include "time.h"
#include "TM1637.h"

TM1637 Anzeige(D3, D4);

// Router/Passwort
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European Summer Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_wday -> Wochentag (0 = Sonntag, 6 = Samstag)
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;
WiFiServer Server(80);

// String für die Anzeige der Zeit
String ZeitAnzeige;

void setup() 
{
  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // WiFi starten
  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());
  
  // Anzeige starten
  Anzeige.begin();  

  // Helligkeit
  Anzeige.setBrightness(10);

  Anzeige.clearScreen();
}

void loop() 
{
  // aktuelle Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // : einschalten
  Anzeige.colonOn();

  /*
    es kann bis zu 30 Sekunden dauern
    bis die Zeit ermittelt wird  
    String ZeitAnzeige zusammenbauen
    wenn Stunden/Minuten < 10 → führende 0 ergänzen
  */
  if (Zeit.tm_hour < 10) ZeitAnzeige = "0" + String(Zeit.tm_hour);
  else ZeitAnzeige = String(Zeit.tm_hour);

  if (Zeit.tm_min < 10) ZeitAnzeige += "0" + String(Zeit.tm_min);
  else ZeitAnzeige += String(Zeit.tm_min);

  Anzeige.display(ZeitAnzeige);
  delay(5000);
}

Letzte Aktualisierung:

Mikro­con­trol­ler im AP-Modus vernetzen

Ser­ver

#ifdef ESP8266
  #include "ESP8266WebServer.h"
  ESP8266WebServer Server(80);
#else 
  #include "WiFi.h"
  #include "WebServer.h"
  WebServer Server(80);
#endif

#include "DHT.h"

// Pin des DHT-Sensors
int SENSOR_DHT = 19;

// Sensortyp festlegen
// DHT22 oder DHT11
#define SensorTyp DHT22

DHT dht(SENSOR_DHT, SensorTyp);

// Netzwerkname und Passwort des ESP
char Router[] = "ESPServer";
char Passwort[] = "espserver";

// farbige Box mit CSS
String Seitenkopf =
  "<head><style>"
  ".farbigeBox {"
  "background-color: ivory;"
  "color: black;"
  "width: 450px;"
  "padding: 20px;"
  "text-align: left;"
  "font-size: 40px;"
  "font-family: arial;"
  "}"
  "</style>"

  // refresh -> Seite automatisch aktualisieren
  "<meta http-equiv=\"refresh\" content=\"30\"></head>";

// Wartezeit für die sichere Übermittlung der Daten
unsigned long Wartezeit = 5000;

// enthält die Daten des 2. ESPs
String Messung;

// IP-Adresse des 2. ESP
const char* host = "192.168.4.2";

// Konfiguration als Server
IPAddress ip(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);

void setup() 
{
  Serial.begin(9600);
  
  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // ESP als Access-Point (AP) konfigurieren
  WiFi.softAPConfig(ip, gateway, subnet);

  // Access-Point starten
  WiFi.softAP(Router, Passwort);
   
  // SSID des Routers anzeigen
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(WiFi.softAPSSID());

  Serial.print("IP-Adresse: ");
  Serial.println(WiFi.softAPIP());

  // Webserver starten
  // / -> Aufruf der URL, SeiteBauen -> Aufruf der Funktion
  Server.begin();
  Server.on("/", SeiteBauen);

  dht.begin();
}

void loop() 
{
  static unsigned long Startzeit = millis();

  // auf Anfragen warten
  Server.handleClient();

  // Messdaten einsammeln
  if ((millis() - Startzeit) > Wartezeit)
  {
    // Daten des 2. ESPs einsammeln
    DatenHolen();
    
    Startzeit = millis();
  }
}

void SeiteBauen()
{
  // Seite "zusammenbauen"
  String Seite = "";
  Seite += Seitenkopf;
  Seite += "<h1>Messdaten</h1>";
  Seite += "<hr>";
  
  /*
    Messung enthält die mit / gtrennten Daten
    String Messung mit substring am / trennen
    Temperatur: von Position 0 bis zum / (indexOf))
    Luftfeuchtigkeit von /+1 bis zur Länge des Strings
  */
  String TemperaturKlient = Messung.substring(0, Messung.indexOf("/"));
  String LuftfeuchtigkeitKlient = Messung.substring(Messung.indexOf("/") + 1, Messung.length());
  
  Seite += "<h2>Daten vom Klienten ...</h2>";
  Seite += "<div class=\"farbigeBox\">";
  Seite += "Temperatur: ";
  Seite += TemperaturKlient;
  Seite += "<br>";
  Seite += "Luftfeuchtigkeit: ";
  Seite += LuftfeuchtigkeitKlient;
  Seite += "<br>";
  Seite += "</div>";

  // Messwerte ermitteln
  // . durch , ersetzen
  String TemperaturServer = String(dht.readTemperature());
  TemperaturServer.replace(".", ",");
  
  String LuftfeuchtigkeitServer = String(dht.readHumidity());
  LuftfeuchtigkeitServer.replace(".", ",");
  
  Seite += "<h2>Daten vom Server ...</h2>";
  Seite += "<div class=\"farbigeBox\">";
  Seite += "Temperatur: ";
  Seite += TemperaturServer + "°C";
  Seite += "<br>";
  Seite += "Luftfeuchtigkeit: ";
  Seite += LuftfeuchtigkeitServer + "%";
  Seite += "</div>";

  // Button aktualisieren
  Seite += "<hr><input style=\"font-size:16pt; font-weight:bold;";
  Seite += "background-color:#55A96B;";
  Seite += "display:block; cursor:pointer;\"type=\"button\"";

  // IP für den Button aktualisieren (location.href)
  // muss mit dem Wert für IPAdress übereinstimmen (. statt ,)
  Seite += " onClick  =\"location.href='http://192.168.4.1'\" value=\"aktualisieren\">";
  Seite += "<hr>";

  // Seite anzeigen
  Server.send(200, "text/html", Seite);
}

void DatenHolen()
{
  WiFiClient client;

  // wenn Klient erfolgreich verbunden wurde
  // wenn nicht return -> neuer Versuch
  if (!client.connect(host, 80)) return;
  
  /*
    GET-Anfrage senden
    /Messung -> Adresse (URL) für die zu übermittelnden Werte
    wird von den Klienten festgelegt
    host -> IP-Adresse des 2. ESPs
    HTTP/1.1 -> Abfrageprotokoll
    \r\n -> return mit anschließender neuer Zeile
  */
  client.print(String("GET ") + "/Messung" + " HTTP/1.1\r\n" + host + "\r\n");
  unsigned long LetzteZeit = millis();

  // Wartezeit 
  while (!client.available() && ((millis() - LetzteZeit) < 3000))
  {
    delay(1);
  }  

  // der Klient ist verfügbar
  while (client.available()) 
  {
    // den mit GET erhaltenen String bis zum return (\r) lesen
    String Daten = client.readStringUntil('\r');

    // wenn Daten vorhanden sind
    // Messung enthält die vom 2. ESP übermittelten Daten
    if(Daten != "")
    {
      Messung = Daten;
      Serial.println(Daten);
    }
  }
}

Kli­ent

Für die Dar­stel­lung im Brow­ser ist in Zei­le 65 eine Ände­rung nötig:

LEDs Tran­sis­tor schalten

#define TRANSISTOR 6 

void setup()
{
  pinMode(TRANSISTOR, OUTPUT);
}

void loop()
{
  digitalWrite(TRANSISTOR, HIGH);  
  delay(1000);                             
  digitalWrite(TRANSISTOR, LOW);  
  delay(1000);                              
}

Letzte Aktualisierung:

MQTT ESP32

Sen­der

#include "ArduinoMqttClient.h"

#ifdef ESP8266
  #include "ESP8266WiFi.h"
#else 
  #include "WiFi.h"
#endif

#include "DHT.h"

// Pin des DHT-Sensors
int SENSOR_DHT = 4;

// DHT11
// #define SensorTyp DHT11

// DHT22
#define SensorTyp DHT22

// dht-Sensor einen Namen und Typ zuweisen
DHT dht(SENSOR_DHT, SensorTyp);

char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxx";

WiFiClient wifiClient;

// wifiClient MqttClient zuordnen
MqttClient mqttClient(wifiClient);

// RaspberryPi als Broker
// const char broker[] = "192.168.1.222";
int port = 1883;

const char broker[] = "test.mosquitto.org";

/* öffentliche Broker
const char broker[] = "public.mqtthq.com";
int port = 1883;

const char broker[] = "test.mosquitto.org";
int port = 1883;

const char broker[] = "broker.emqx.io";
const char *mqtt_username = "emqx";
const char *mqtt_password = "public";
int port = 1883;
*/

// Thema für Senden/Empfangen
const char Messdaten[] = "Messdaten";

// Thema für die "will"-Nachricht für den Versuch die Verbindung 
// neu aufzubauen
const char getrennteVerbindung[] = "getrennteVerbindung";

// Intervall zwischen den Messungen
const long Interval = 5000;
unsigned long vorherigeZeit = 0;

void setup() 
{
  Serial.begin(9600);
  while (!Serial);
  delay(1000);

  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  /*
    will-Nachricht:
    wird an den Broker gesendet und versucht eine getrennte Verbindung neu aufzubauen
    Parameter:
    Thema, Länge des gesendeten Strings, Behalten der Anforderung, Qualität der Verbindung
    muss vor dem Aufbau der Verbindung zum Broker festgelegt werden
  */
  String willDaten = "getrennt";
  bool Behalten = true;
  int willQualitaetService= 2;

  // will-Nachricht senden
  mqttClient.beginWill(getrennteVerbindung, willDaten.length(), Behalten, willQualitaetService);
  mqttClient.print(getrennteVerbindung);
  mqttClient.endWill();

  Serial.println("Versuche mit dem Broker " + String(broker) + " zu verbinden ... ");

  delay(1000);

  // Verbindungsversuch
  if (!mqttClient.connect(broker, port)) 
  {
    Serial.print("Verbindung zum Broker gescheitert");

    // Programm anhalten
    while (1);
  }
  Serial.println();

  Serial.println("Mit dem Broker " + String(broker) + " verbunden!");
  Serial.println();

  // dht-Sensor starten
  dht.begin();
}

void loop() 
{
  // Broker abfragen
  mqttClient.poll();

  unsigned long aktuelleZeit = millis();

  // Intervall zwischen den Sendezeiten
  if (aktuelleZeit - vorherigeZeit >= Interval) 
  {
    // letzte Sendezeit sichern
    vorherigeZeit = aktuelleZeit;

    // gemessene Temperatur dht in String umwandeln
    String Temperatur = String(dht.readTemperature(), 1);

    // . durch , ersetzen
    Temperatur.replace(".", ",");

    // gemessene Luftfeuchtigkeit in String umwandeln
    String Luftfeuchtigkeit = String(dht.readHumidity(), 1);

    // . durch , ersetzen
    Luftfeuchtigkeit.replace(".", ",");

    // String Senden zusammenbauen / als Trennzeichen
    String Senden = Temperatur + "/" + Luftfeuchtigkeit;
    Serial.println("Nachricht gesendet:");

    // Anzeige im Seriellen Monitor: String Senden am / trennen
    int Suche = Senden.indexOf("/");

    // String bis zum /
    Temperatur = Senden.substring(0, Suche);

    // String vom ersten Zeichen hinter / bis zum Ende
    Luftfeuchtigkeit = Senden.substring(Suche + 1, Senden.length());

    // Daten im Seriellen Monitor anzeigen
    Serial.println(Temperatur + "°C");
    Serial.println(Luftfeuchtigkeit + "%");
    Serial.println("---------------------");

    // Messdaten senden
    bool Behalten = false;
    int ServiceQualitaet = 2;
    bool Duplikat = false;
    mqttClient.beginMessage(Messdaten, Senden.length(), Behalten, ServiceQualitaet, Duplikat);
    mqttClient.print(Senden);
    mqttClient.endMessage();
  }
}

Emp­fän­ger

#include "ArduinoMqttClient.h"

#ifdef ESP8266
  #include "ESP8266WiFi.h"
#else 
  #include "WiFi.h"
#endif

#include "U8g2lib.h"

/*
  Typbezeichnung mit Bildschirmgröße in Pixeln
  1 = page buffer mode, F = full screen buffer mode 
  Hardware I2C/Hardware SPI
  Name des OLEDs
  Rotation R0 (keine)
*/
U8G2_SSD1306_128X64_NONAME_1_HW_I2C oled(U8G2_R0, U8X8_PIN_NONE);

// Router SSID/Passwort
char Router[] = "FRITZ!Box 7590 LB";
char Passwort[] = "anea1246";

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

// RaspberryPi als Broker
// const char broker[] = "192.168.1.222";

const char broker[] = "test.mosquitto.org";
int port = 1883;

/* öffentliche Broker
const char broker[] = "public.mqtthq.com";
int port = 1883;

const char broker[] = "test.mosquitto.org";
int port = 1883;

const char broker[] = "broker.emqx.io";
const char *mqtt_username = "emqx";
const char *mqtt_password = "public";
int port = 1883;
*/

// Thema  für Senden/Empfangen
const char Messdaten[] = "Messdaten";

/*
  Qualität der Verbindung (0 .. 2)
  0 = Nachricht wird einmal versendet
      eine Überprüfung des Empfangs durch den Broker findet nicht statt
  1 = die Nachricht wird solange versendet, bis der Broker den Empfang bestätigt hat
  2 = die Nachricht wird einmal gesendet, es wird sicher gestellt, dass sie
      beim Broker angekommen ist
*/
int subscribeQoS = 2;

void setup() 
{
  Serial.begin(9600);
  while (!Serial);
  delay(1000);

  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  Serial.print("Versuche mit dem Broker " + String(broker) + " zu verbinden ... ");

  // Verbindung zum Broker aufbauen
  if (!mqttClient.connect(broker, port)) 
  {
    Serial.print("Verbindung zum Broker gescheitert");

    // Programm anhalten
    while (1);
  }
  Serial.println();

  Serial.println("Mit dem Broker " + String(broker) + " verbunden!");
  Serial.println();

  // den Rückruf für den Nachrichtenempfang festlegen
  mqttClient.onMessage(empfangeneNachricht);

  // in das Thema Messdaten "einschreiben"
  mqttClient.subscribe(Messdaten, subscribeQoS);

  // OLED starten
  oled.begin();

  // Kontrast maximal 255
  oled.setContrast(200);
  oled.setFont(u8g2_font_helvR24_tf);

  // Zeichenfarbe weiß
  oled.setDrawColor(1);

  // horizontale Schrift
  oled.setFontDirection(0);
}

void loop() 
{
  // Broker abfragen
  mqttClient.poll();
}

void empfangeneNachricht(int NachrichtGroesse) 
{
  Serial.println("Nachricht empfangen: ");

  // Thema der Nachricht empfangen und anzeigen
  String Nachricht = mqttClient.messageTopic();
  Serial.println(Nachricht + " ");

  // Nachricht als String lesen
  String EmpfangeneNachricht = mqttClient.readString();

  // String Anzeige am / trennen
  int Suche = EmpfangeneNachricht.indexOf("/");
  String Temperatur = EmpfangeneNachricht.substring(0, Suche);
  String Luftfeuchtigkeit = EmpfangeneNachricht.substring(Suche + 1, EmpfangeneNachricht.length());

  // Anzeige im Seriellen Monitor
  Serial.println(Temperatur + "°C");
  Serial.println(Luftfeuchtigkeit + "%");
  Serial.println("---------------------");
  Serial.println();

  // Anzeige OLED
  oled.clearDisplay();
  oled.firstPage();

  do 
  {
    oled.setCursor(2, 30);
    oled.print(Temperatur);

    // Grad-Zeichen
    oled.print((char)176);
    oled.print("C");
    oled.setCursor(2, 60);
    oled.print(Luftfeuchtigkeit + "%");

  } 
  while (oled.nextPage());
}

letz­te Aktualisierung: 

BME680 Dar­stel­lung LCD und Web

Dar­stel­lung auf LCD

#include "bsec.h"
#include "LCDIC2.h"

// 4-zeiliges LCD
LCDIC2 lcd(0x27, 20, 4);

// Objekt (iaqSensor) der Klasse Bsec definieren
Bsec iaqSensor;

void setup() 
{
  Serial.begin(9600);

  // auf Serielle Verbindung warten
  while (!Serial);
  delay(1000);
  
  // LCD starten
  lcd.begin();

  // Cursor "verstecken"
  lcd.setCursor(false);

  // Hex-Adresse des BME680
  // BME68X_I2C_ADDR_HIGH = 0x77 (Standard)
  // BME68X_I2C_ADDR_LOW = 0x76 
  iaqSensor.begin(BME68X_I2C_ADDR_HIGH, Wire);

  // Array der verfügbaren Sensoren
  bsec_virtual_sensor_t sensorList[13] = 
  {
    BSEC_OUTPUT_IAQ,
    BSEC_OUTPUT_STATIC_IAQ,
    BSEC_OUTPUT_CO2_EQUIVALENT,
    BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
    BSEC_OUTPUT_RAW_TEMPERATURE,
    BSEC_OUTPUT_RAW_PRESSURE,
    BSEC_OUTPUT_RAW_HUMIDITY,
    BSEC_OUTPUT_RAW_GAS,
    BSEC_OUTPUT_STABILIZATION_STATUS,
    BSEC_OUTPUT_RUN_IN_STATUS,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
    BSEC_OUTPUT_GAS_PERCENTAGE
  };

  // BSEC_SAMPLE_RATE_ULP: Ultra Low Powermode -> Messung alle 5 Minuten
  // BSEC_SAMPLE_RATE_LP: Low Powermode -> Messung alle 3 Sekunden
  iaqSensor.updateSubscription(sensorList, 13, BSEC_SAMPLE_RATE_LP);
}

void loop() 
{
  // wenn der Sensor arbeitet ...
  if (iaqSensor.run()) 
  {
    // Messwerte ermitteln, in Strings umwandeln, . durch , ersetzen
    String Temperatur = String(iaqSensor.temperature);
    Temperatur.replace(".", ",");

    String Luftfeuchtigkeit = String(iaqSensor.humidity);
    Luftfeuchtigkeit.replace(".", ",");

    String Luftdruck = String(iaqSensor.pressure / 100);
    Luftdruck.replace(".", ",");

    String IAQ = String(iaqSensor.iaq);
    IAQ.replace(".", ",");

    String StatischerIAQ = String(iaqSensor.staticIaq);
    StatischerIAQ.replace(".", ",");
    
    String CO2 = String(iaqSensor.co2Equivalent);
    CO2.replace(".", ",");

    String VOC = String(iaqSensor.breathVocEquivalent);
    VOC.replace(".", ",");

    String GasInProzent = String(iaqSensor.gasPercentage);
    GasInProzent.replace(".", ",");

    String WiderstandMOXSensor = String(iaqSensor.gasResistance / 1000);
    WiderstandMOXSensor.replace(".", ",");

    // Ausgabe Serieller Monitor
    Serial.println("Statusmeldungen:");
    Serial.println("-----------------------------");
    Serial.println("Sensor bereit (0-1): " + String(int(iaqSensor.runInStatus)));
    Serial.println("Genauigkeit IAQ (0-3): " + String(int(iaqSensor.iaqAccuracy)));
    Serial.println("-----------------------------");
    Serial.println("Messwerte:");
    Serial.println("-----------------------------");
    Serial.println("Temperatur: " + Temperatur + " °C");
    Serial.println("Feuchtigkeit: " + Luftfeuchtigkeit + " %");
    Serial.println("Luftdruck: " + Luftdruck + " hPa");
    Serial.println("IAQ: " + IAQ);
    Serial.println("Statischer IAQ: " + StatischerIAQ);
    Serial.println("Schätzung CO2: " + CO2 + " ppm");
    Serial.println("Gas (0-100): " + GasInProzent + " %");
    Serial.println("Widerstandswert MOX-Sensor: " + WiderstandMOXSensor + " kOhm");
    Serial.println("VOC: " + VOC);
    Serial.println("-----------------------------");

    // Ausgabe LCD
    lcd.setCursor(0, 0);
    lcd.print("Temperatur: " + Temperatur + "\337C");
    lcd.setCursor(0, 1);
    lcd.print("Feuchtigkeit: " + Luftfeuchtigkeit + "%");
    lcd.setCursor(0, 2);
    lcd.print("IAQ: " + IAQ);
    lcd.setCursor(0, 3);
    lcd.print("CO2: " + CO2 + " ppm");
  }
}

Dar­stel­lung im Browser

Für die kor­rek­te Dar­stel­lung im Brow­ser ist in Zei­le 417 eine Ände­rung nötig: