In der Bastler- und Maker-Szene werden oft nur einfache Display- und Touch-Lösungen benötigt. Doch dieses günstigste Entwicklungsboard ESP32-2432S028 mit 2,8 Zoll Display das in der Maker-Szene auch als Cheap Yellow Display (CYD) bekannt ist und es gibt weitere mit unterschiedlichen ESP32 Varianten und Displaygrößen. Weiter unten Lösung für 3,5Zoll Display

Es basiert auf einem ESP32-WROOM-Modul mit 4 MB Flash, das auf einer auffällig gelben Platine sitzt. Verbaut ist ein 2,8-Zoll Touchdisplay mit 320 × 240 Pixeln, das sich ideal für einfache grafische Benutzeroberflächen eignet.
Das Cheap Yellow Display Board ist wie folgt ausgestattet:
- Resistiver Touchscreen mit ILI9341-TFT & XPT2046-Touch
- microSD-Kartenslot
- LDR (Helligkeitssensor)
- RGB-LED (GPIO-Pins: 4, 16, 17)
- Lautsprecheranschluss
- Boot-Taster
- JST-Anschlüsse (1,25 mm, für Sensoren/Peripherie)
- USB (Micro-USB und/oder USB-C) zur Stromversorgung & Programmierung
- WLAN/Bluetooth
Detaillierte Hersteller Informationen habe ich nicht gefunden, dennoch gibt es eine Vielzahl von deckungsgleichen Dokumenten die bei der Umsetzung hilfreich sind.


Weitere Details: https://randomnerdtutorials.com/
Projektübersicht: LED Steuerung & Temperaturanzeige
Für den einfachen Einstieg wird in diesem Projekt ein DHT22-Temperatursensor angeschlossen, dessen Messwerte direkt auf dem Display angezeigt werden.
Zusätzlich soll die integrierte RGB-LED über das Touchdisplay ein- und ausgeschaltet werden können.
Hardware:
ESP32-2432S028R oder ESP32 2,8 Zoll Smart Display V3
DHT11 oder DHT11 Sensor (Für Temperatur-/Feuchtigkeits-Messung)
ACHTUNG: Ich habe hier die Resistive Version des Boards vor mir liegen.
Zu erkennen an dem letzten R in der Typenbezeichnung: ESP32-2432S028R
Diese Version hat ein Touchscreen das den XPT2046-Chip nutzt, über SPI-Kommunikation (Serial Peripheral Interface).
Es gibt noch eine C-Version (Kapazitiv) die den GT911-Chip für die Touch nutzt über I2C-Bus (TAMC_GT911-Bibliothek)
Also nicht verwechseln
Entwicklungsumgebung: Für dieses Beispiel nutzen wir die klassische Arduino‑IDE.
Vorgehensweise: Direkte Programmierung mit TFT_eSPI & TouchScreen.h
Die ersten Schritte sind bewusst minimal gehalten, um das Board sicher zu testen:
- Display-Test
Prüfen, ob das TFT korrekt initialisiert und Text ausgeben kann. - Sensor-Test (DHT11)
Den DHT11 anschließen und sicherstellen, dass Temperaturwerte auf dem Display erscheinen. - Touch-Button + RGB‑LED
Eine einfache Schaltfläche zeichnen und testen, ob die RGB‑LED per Touch ein‑ und ausgeschaltet werden kann.
Vorbereitung: Benötigte Bibliothek installieren und anpassen.
Eine Bibliothek zur Ansteuerung von TFT-Displays (Thin-Film-Transistor).
Kann über den Bibliotheksmanager installiert werden (Suche nach „TFT_eSPI“)

Nun muss die Datei User_Setup.h der gerade installierten Bibliothek TFT_eSPI für das CYD angepasst werden:
1. Richtige Pin-Zuweisungen für SPI und Touchscreen:
TFT_MISO 12
TFT_MOSI 13
TFT_SCLK 14
TFT_CS 15
TFT_DC 2
TFT_RST -1
TOUCH_CS 33
2. Aktiviere den passenden Display-Treiber: #define ILI9341_2_DRIVER und deaktiviere andere Display-Treiber
3. Richtige Displaygröße: TFT_WIDTH 240, TFT_HEIGHT 320
Also das sollte dann in der User_Setup.h drin stehen, die im Ordner C:\ordner deiner sketche\libraries\TFT_eSPI\ zufinden ist:
klicken zum Aufklappen
// Konfiguration für das ESP32-2432S028R (Cheap Yellow Display - CYD)
#define USER_SETUP_INFO "User_Setup_CYD"
// 1. Treiber und Display-Auflösung
#define ILI9341_2_DRIVER
#define TFT_WIDTH 240
#define TFT_HEIGHT 320
// 2. Pin-Belegung
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS 15 // Chip Select
#define TFT_DC 2 // Data Command
#define TFT_RST -1 // Reset (wird direkt vom ESP32 gesteuert)
#define TFT_BL 21 // Backlight (Hintergrundbeleuchtung)
#define TFT_BACKLIGHT_ON HIGH
#define TOUCH_CS 33 // Chip Select für den Touchscreen
// 3. Schriftarten (Fonts) laden
#define LOAD_GLCD
#define LOAD_FONT2
#define LOAD_FONT4
#define LOAD_FONT6
#define LOAD_FONT7
#define LOAD_FONT8
#define LOAD_GFXFF
#define SMOOTH_FONT
// 4. Geschwindigkeiten für die serielle Peripherieschnittstelle (SPI - Serial Peripheral Interface)
#define SPI_FREQUENCY 55000000
#define SPI_READ_FREQUENCY 20000000
#define SPI_TOUCH_FREQUENCY 2500000
// 5. Weitere Optionen
#define USE_HSPI_PORT
Einfache Display Text Ausgabe
Sketch (Zum aufklappen anklicken)
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI(); // Initialisiert das TFT-Display-Objekt
void setup() {
// WICHTIG für das CYD: Hintergrundbeleuchtung aktivieren
pinMode(21, OUTPUT);
digitalWrite(21, HIGH);
// Startet das TFT-Display
tft.init();
tft.setRotation(1); // Setzt das Display ins Querformat (320 x 240 Bildpunkte)
// Löscht den Bildschirm (setzt alles auf Schwarz)
tft.fillScreen(TFT_BLACK);
// 1. Einen zweifarbigen Rahmen um den gesamten Bildschirm zeichnen
// drawRect(x, y, breite, höhe, farbe)
tft.drawRect(0, 0, 320, 240, TFT_CYAN);
tft.drawRect(2, 2, 316, 236, TFT_BLUE);
// 2. Begrüßung in mittlerer Schrift (Font 4) und Gelb
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
// drawCentreString platziert den Text exakt in der Mitte der X-Achse (bei 320 Pixeln Breite ist das 160)
tft.drawCentreString("Hallo Bastler & Tueftler!", 160, 20, 4);
// 3. Eine dekorative rote Trennlinie zeichnen
// drawLine(start_x, start_y, ende_x, ende_y, farbe)
tft.drawLine(20, 60, 300, 60, TFT_RED);
// 4. Normaler Text (Font 2) in Weiß
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawCentreString("Willkommen auf", 160, 80, 2);
// 5. Der Blog-Name hervorgehoben in leuchtendem Grün
tft.setTextColor(TFT_GREEN, TFT_BLACK);
// Mit Sonderzeichen wie Klammern oder Pfeilen kann man den Text optisch einrahmen
tft.drawCentreString(">>> prilchen.de <<<", 160, 110, 4);
// 6. Ein kleiner Status-Text (Font 2) in Orange
tft.setTextColor(TFT_ORANGE, TFT_BLACK);
tft.drawCentreString("Hardware-Test bestanden! [OK]", 160, 160, 2);
// 7. Ein paar grafische Spielereien: Gefüllte Kreise
// fillCircle(x, y, radius, farbe)
tft.fillCircle(60, 210, 10, TFT_MAGENTA);
tft.fillCircle(160, 210, 10, TFT_CYAN);
tft.fillCircle(260, 210, 10, TFT_YELLOW);
}
void loop() {
// Der Hauptcode, der wiederholt ausgeführt wird.
// Hier bleibt es erstmal leer, da sich unser Bildausschnitt nicht verändert.
}
Als Board wählst du ESP32 Dev Module und beim Upload ggf. die Boot Taste drücken.
Der Text ist zu sehen, aber erst mal nicht spannend.

Nun mal was auslesen und steuern:
DHT11 anschießen, Temperaturwert auf dem Display erscheint und die LED schalten
Benötigte Bibliothek:
TFT_eSPI
XPT2046_Touchscreen
DHT11

Verdrahtung:
Beiliegendes 4 adriges Adapterkabel nehmen und an Anschluss IO2:4P1.25mm anklemmen.
Ein DHT11 an Plus an Rot, Minus an Schwarz und Daten an Gelb anschließen. Blaues Kabel bleibt frei.
Arduino Sketch:
Sketch (Zum aufklappen anklicken)
#include <TFT_eSPI.h> // Bibliothek für das TFT-Display (Thin-Film-Transistor)
#include <XPT2046_Touchscreen.h> // Bibliothek für den Touchscreen
#include <DHT.h> // Bibliothek für den DHT11-Sensor (Digital Humidity and Temperature)
// DHT11 Sensor Setup
#define DHTPIN 27
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// Touchscreen Setup
#define TOUCH_CS 33
#define TOUCH_IRQ 36
#define TOUCH_CLK 25
#define TOUCH_MISO 39
#define TOUCH_MOSI 32
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen ts(TOUCH_CS, TOUCH_IRQ);
// TFT-Display Setup
TFT_eSPI tft = TFT_eSPI();
// GPIO-Pins (General Purpose Input/Output) der verbauten RGB-LED (Red, Green, Blue)
// Hinweis: Diese LEDs leuchten, wenn der Pin auf LOW (0 Volt) geschaltet wird (aktiv-low)
#define LED_R 4
#define LED_G 16
#define LED_B 17
bool ledState = false; // Speichert, ob die LED gerade an oder aus ist
unsigned long lastSensorUpdate = 0; // Merker für die Zeitsteuerung
void setup() {
Serial.begin(115200);
dht.begin();
// WICHTIG: Hintergrundbeleuchtung des CYD einschalten
pinMode(21, OUTPUT);
digitalWrite(21, HIGH);
// Touchscreen initialisieren
touchscreenSPI.begin(TOUCH_CLK, TOUCH_MISO, TOUCH_MOSI, TOUCH_CS);
ts.begin(touchscreenSPI);
ts.setRotation(1); // Querformat
// LED-Pins (Light Emitting Diode) als Ausgang setzen
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
updateLED(); // Schaltet die LED beim Start sicher aus
// Display initialisieren
tft.init();
tft.setRotation(1); // Querformat (320 x 240 Bildpunkte)
tft.fillScreen(TFT_BLACK);
// --- Grafisches Grundgerüst zeichnen (wird nur 1x im Setup gemacht) ---
// 1. Kopfzeile mit abgerundeten Ecken
// fillRoundRect(x, y, breite, höhe, radius, farbe)
tft.fillRoundRect(10, 10, 300, 40, 8, TFT_DARKCYAN);
tft.setTextColor(TFT_WHITE, TFT_DARKCYAN);
tft.drawCentreString("Prilchen.de - Sensor-Station", 160, 20, 2); // Zentriert mit Font 2
// 2. Optische Rahmen für die Messwerte
tft.drawRoundRect(10, 60, 300, 100, 8, TFT_DARKGREY);
// 3. Feste Beschriftungen (werden nicht mehr überschrieben)
tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
tft.drawString("Temperatur:", 25, 75, 2);
tft.drawString("Luftfeuchte:", 25, 115, 2);
// 4. Den Button (Schaltfläche) zum ersten Mal zeichnen
drawButton();
}
void loop() {
unsigned long currentMillis = millis();
// Temperaturanzeige alle 2000 ms (2 Sekunden) aktualisieren
// Der DHT11 ist recht langsam, 2 Sekunden Pause sind ideal
if (currentMillis - lastSensorUpdate >= 2000) {
lastSensorUpdate = currentMillis;
float temp = dht.readTemperature();
float hum = dht.readHumidity();
// Wir setzen TextPadding (Hintergrund-Füllung), um flimmerfrei zu überschreiben.
// Die Bibliothek füllt automatisch 80 Bildpunkte Breite in der Hintergrundfarbe.
tft.setTextPadding(80);
// Temperatur in Gelb anzeigen
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
String tempStr = String(temp, 1) + " C"; // Kommazahl auf 1 Stelle runden
tft.drawString(tempStr, 180, 70, 4);
// Feuchtigkeit in Hellblau anzeigen
tft.setTextColor(TFT_CYAN, TFT_BLACK);
String humStr = String(hum, 1) + " %";
tft.drawString(humStr, 180, 110, 4);
tft.setTextPadding(0); // Padding wieder ausschalten, damit andere Texte nicht gestört werden
}
// Touchscreen auswerten
if (ts.tirqTouched() && ts.touched()) {
TS_Point p = ts.getPoint();
// Koordinaten an das Display-Raster (320x240) anpassen
int x = map(p.x, 200, 3700, 0, 320);
int y = map(p.y, 240, 3800, 0, 240);
// Entprellung: Nur alle 300 Millisekunden einen Touch-Druck zulassen
static unsigned long lastTouch = 0;
// Prüfen, ob der Touch innerhalb unseres gezeichneten Buttons lag
if (x >= 80 && x <= 240 && y >= 170 && y <= 230 && millis() - lastTouch > 300) {
lastTouch = millis();
ledState = !ledState; // Zustand umkehren (aus AN wird AUS und umgekehrt)
updateLED(); // LED hardwareseitig schalten
drawButton(); // Button auf dem Display neu zeichnen
}
}
}
// Funktion, um die Schaltfläche optisch ansprechend zu zeichnen
void drawButton() {
// Wenn LED an ist -> Roter Button ("Ausschalten"). Wenn LED aus ist -> Grüner Button ("Einschalten").
uint16_t buttonColor = ledState ? TFT_RED : TFT_DARKGREEN;
// Einen großen, abgerundeten Button zeichnen
tft.fillRoundRect(80, 175, 160, 50, 10, buttonColor);
// Einen weißen Rand als "Highlight" hinzufügen
tft.drawRoundRect(80, 175, 160, 50, 10, TFT_WHITE);
// Text zentriert auf dem Button platzieren
tft.setTextColor(TFT_WHITE, buttonColor);
if (ledState) {
tft.drawCentreString("LED AUS", 160, 190, 4);
} else {
tft.drawCentreString("LED AN", 160, 190, 4);
}
}
// Funktion, um die Hardware-LED zu steuern
void updateLED() {
if (ledState) {
// LED einschalten (Wir nutzen hier als Beispiel nur die rote LED)
digitalWrite(LED_R, LOW); // LOW bedeutet bei dieser LED: AN
digitalWrite(LED_G, HIGH); // HIGH bedeutet: AUS
digitalWrite(LED_B, HIGH);
} else {
// Alle Farbkanäle ausschalten
digitalWrite(LED_R, HIGH);
digitalWrite(LED_G, HIGH);
digitalWrite(LED_B, HIGH);
}
}
Ergebnis:

Temperaturwerte werden aktuell angezeigt und LED auf der Rückseite lässt sich per Touch auf dem Display schalten.
3.5 Zoll CYD Varianten mit optionalen Akku Anschluss:
Wer einen der größeren Varianten der CYD vorliegen hat, wie zum Beispiel diesen 3,5 Zoll ESP32-3248S035R, muss einige Dinge ändern:
Unterschiede zur 2,8 Zoll Version:
| CYD 2,8 Zoll | CYD 3,5 Zoll | |
| Backlight | Pin 21 | Pin 27 |
| TFT_WIDTH | 240 | 320 |
| TFT_HEIGHT | 320 | 480 |
| Display Treiber | ILI9341 | ST7796 |
| Touch Treiber | XPT2046 über SPI | GT911 über I²C |
| RGB‑LED | GPIO 4, 16, 17 | GPIO 22, 16, 17 |
| SPI_FREQUENCY | 40000000 | 65000000 |
| DHT Anschluss | 27 | 32 |
Anpassung 1: Somit hier die angepasste User_Setup.h in der TFT_eSPI Library
User_Setup.h für CYD 3,5 Zoll: (Zum aufklappen anklicken)
// Konfiguration für das ESP32-3248S035R (Cheap Yellow Display - CYD)
#define USER_SETUP_INFO "User_Setup_CYD"
// 1. Treiber und Display-Auflösung
#define ST7796_DRIVER
#define TFT_WIDTH 320
#define TFT_HEIGHT 480
// 2. Pin-Belegung
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS 15 // Chip Select
#define TFT_DC 2 // Data Command
#define TFT_RST -1 // Reset (wird direkt vom ESP32 gesteuert)
#define TFT_BL 27 // Backlight (Hintergrundbeleuchtung)
#define TFT_BACKLIGHT_ON HIGH
#define TOUCH_CS 33 // Chip Select für den Touchscreen
// 3. Schriftarten (Fonts) laden
#define LOAD_GLCD
#define LOAD_FONT2
#define LOAD_FONT4
#define LOAD_FONT6
#define LOAD_FONT7
#define LOAD_FONT8
#define LOAD_GFXFF
#define SMOOTH_FONT
// 4. Geschwindigkeiten für die serielle Peripherieschnittstelle (SPI - Serial Peripheral Interface)
#define SPI_FREQUENCY 65000000
#define SPI_READ_FREQUENCY 20000000
#define SPI_TOUCH_FREQUENCY 2500000
// 5. Weitere Optionen
#define USE_HSPI_PORT
Anpassung 2: Anpassung im Arduino Sketch für CYD 3,5 Zoll. TFT_eSPI hat eine eingebaute GT911‑Touch‑Integration und somit wird keine weitere Library benötigt:
Sketch (Zum aufklappen anklicken)
#include <TFT_eSPI.h> // Bibliothek für das TFT-Display (Thin-Film-Transistor)
#include <DHT.h> // Bibliothek für den DHT11-Sensor
// DHT11 Sensor Setup
#define DHTPIN 32
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// TFT-Display Setup (steuert jetzt auch den Touchscreen!)
TFT_eSPI tft = TFT_eSPI();
// GPIO-Pins der verbauten RGB-LED
#define LED_R 22
#define LED_G 16
#define LED_B 17
bool ledState = false;
unsigned long lastSensorUpdate = 0;
void setup() {
Serial.begin(115200);
dht.begin();
// Hintergrundbeleuchtung (Pin 27)
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
// LED-Pins als Ausgang setzen
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
updateLED();
// Display und Touch initialisieren (alles in einem Abwasch!)
tft.init();
tft.setRotation(1); // Querformat (480 x 320)
tft.fillScreen(TFT_BLACK);
// Kalibrierung des Touchscreens (WICHTIG!)
// Diese Werte passen die rohen Touch-Daten an das 480x320 Display an
uint16_t calData[5] = { 250, 3600, 250, 3600, 1 };
tft.setTouch(calData);
// --- Grafisches Grundgerüst zeichnen ---
tft.fillRoundRect(10, 10, 460, 40, 8, TFT_DARKCYAN);
tft.setTextColor(TFT_WHITE, TFT_DARKCYAN);
tft.drawCentreString("Prilchen.de - Sensor-Station", 240, 20, 2);
tft.drawRoundRect(10, 60, 460, 120, 8, TFT_DARKGREY);
tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
tft.drawString("Temperatur:", 50, 85, 4);
tft.drawString("Luftfeuchte:", 50, 135, 4);
drawButton();
}
void loop() {
unsigned long currentMillis = millis();
// Temperaturanzeige alle 2000 ms
if (currentMillis - lastSensorUpdate >= 2000) {
lastSensorUpdate = currentMillis;
float temp = dht.readTemperature();
float hum = dht.readHumidity();
tft.setTextPadding(120);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
String tempStr = String(temp, 1) + " C";
tft.drawString(tempStr, 280, 85, 4);
tft.setTextColor(TFT_CYAN, TFT_BLACK);
String humStr = String(hum, 1) + " %";
tft.drawString(humStr, 280, 135, 4);
tft.setTextPadding(0);
}
// --- Touchscreen auswerten mit TFT_eSPI ---
uint16_t x, y;
if (tft.getTouch(&x, &y)) {
y = 320 - y;
Serial.print("Touch X: "); Serial.print(x);
Serial.print(" | Y (korrigiert): "); Serial.println(y);
static unsigned long lastTouch = 0;
if (x >= 140 && x <= 340 && y >= 220 && y <= 290 && millis() - lastTouch > 300) {
lastTouch = millis();
ledState = !ledState;
updateLED();
drawButton();
}
}
}
void drawButton() {
uint16_t buttonColor = ledState ? TFT_RED : TFT_DARKGREEN;
tft.fillRoundRect(140, 220, 200, 70, 10, buttonColor);
tft.drawRoundRect(140, 220, 200, 70, 10, TFT_WHITE);
tft.setTextColor(TFT_WHITE, buttonColor);
if (ledState) {
tft.drawCentreString("LED AUS", 240, 240, 4);
} else {
tft.drawCentreString("LED AN", 240, 240, 4);
}
}
void updateLED() {
if (ledState) {
digitalWrite(LED_R, LOW);
digitalWrite(LED_G, HIGH);
digitalWrite(LED_B, HIGH);
} else {
digitalWrite(LED_R, HIGH);
digitalWrite(LED_G, HIGH);
digitalWrite(LED_B, HIGH);
}
}
Verkabelung: Anschluss des DHT11:

Pinbelegung und weitere Details: 3.5inch ESP32-32E Display – LCD wiki
Installation: Adafruit-ST7735-Library

Ergebnis:

Beim Antippen des Button geht auf der Rückseite tatsächlich die LED in Rot an und auf dem Display ist dann der Button mit „LED aus“ mit roten Hintergrund anklickbar, um beim weiteren anklicken die LED auch wieder auszuschalten.
CYD mit 3,5 Zoll mit externen Wetterdaten als Wetterstation
Als abschließendes Beispiel für die direkte Programmierung mit der Library TFT_eSPI zeige ich, wie ich die Netzwerkfunktionen des CYD nutze: Wie im Projekt smart-weather-e-paper-display gezeigt, werden über Open‑Meteo lokale Wetterdaten abgerufen und grafisch auf dem Display dargestellt.
Um die Funktion der einzelnen Abschnitte vorab besser zu verstehen, hier nur erstmal der Code nur einem Wert, mit Temperatur:
Quellcode hier aufklappen
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TFT_eSPI.h>
// WLAN-Zugangsdaten (SSID = Service Set Identifier)
const char* ssid = "DEIN_WLAN_NAME";
const char* password = "DEIN_WLAN_PASSWORT";
// Open-Meteo API URL (Koordinaten: 50.91, 6.81)
String apiUrl = "http://api.open-meteo.com/v1/forecast?latitude=50.91&longitude=6.81¤t_weather=true";
// TFT-Display Setup
TFT_eSPI tft = TFT_eSPI();
// Timer-Variablen: Wir wollen die API nicht blockieren oder überlasten
unsigned long lastTime = 0;
// Intervall auf 15 Minuten setzen (15 Minuten * 60 Sekunden * 1000 Millisekunden)
unsigned long timerDelay = 900000;
void setup() {
Serial.begin(115200);
// Hintergrundbeleuchtung des Displays einschalten (Pin 27)
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
// Display initialisieren
tft.init();
tft.setRotation(1); // Querformat (480 x 320)
tft.fillScreen(TFT_BLACK);
// 1. WLAN-Verbindung aufbauen
WiFi.begin(ssid, password);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawCentreString("Verbinde mit WLAN...", 240, 150, 4);
Serial.print("Verbinde mit WLAN");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Erfolgsmeldung auf dem Display
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.drawCentreString("WLAN verbunden!", 240, 150, 4);
delay(2000);
tft.fillScreen(TFT_BLACK);
// 2. Ersten API-Aufruf direkt beim Start ausführen
fetchAndDisplayWeather();
}
void loop() {
// API nur alle 15 Minuten abfragen
if ((millis() - lastTime) > timerDelay) {
if (WiFi.status() == WL_CONNECTED) {
fetchAndDisplayWeather();
}
lastTime = millis();
}
}
// Funktion für den HTTP-Request (Hypertext Transfer Protocol) und die Anzeige
void fetchAndDisplayWeather() {
HTTPClient http;
http.begin(apiUrl);
int httpResponseCode = http.GET(); // GET-Anfrage an den Server senden
if (httpResponseCode > 0) {
String payload = http.getString();
// Neues JSON-Dokument vorbereiten (ArduinoJson Version 7)
JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
// Temperatur aus dem JSON extrahieren
float temp = doc["current_weather"]["temperature"];
// Anzeige auf dem TFT aktualisieren
// TextPadding füllt den Hintergrund automatisch schwarz, um altes Flackern zu verhindern
tft.setTextPadding(240);
tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
tft.drawCentreString("Aktuelle Temperatur in Koeln:", 230, 80, 4);
// Temperatur groß in Gelb darstellen
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
String tempNumber = String(temp, 1);
tft.setTextPadding(150);
tft.drawRightString(tempNumber, 280, 150, 7);
tft.setTextPadding(0);
tft.drawString("C", 290, 180, 4);
tft.setTextPadding(0);
} else {
Serial.print("JSON parsen fehlgeschlagen: ");
Serial.println(error.c_str());
}
} else {
Serial.print("Fehler beim HTTP-Request. Code: ");
Serial.println(httpResponseCode);
}
http.end(); // Verbindung sauber schließen, um Speicher freizugeben
}
Ergebnis:

In einem zweiten Teil werde ich, mit dieser einfachen Version – um die Entwicklung nachvollziehbar zu halten – zeigen, wie sich mit LVGL und dem EEZ‑Studio Tool auch animierte Darstellungen sowie eigene Logos realisieren lassen, selbst trotz des begrenzten Speichers der Microcontroller.
Vorab aber noch diese TFT_eSPI Version mit deutlich mehr Information die uns ja Open-Meteo anbietet:
Sketch mit informativeren Display ohne LVGL:
Quellcode hier aufklappen
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TFT_eSPI.h>
// WLAN-Zugangsdaten (SSID = Service Set Identifier)
const char* ssid = "DEIN_WLAN_NAME";
const char* password = "DEIN_WLAN_PASSWORT";
String apiUrl = "http://api.open-meteo.com/v1/forecast?latitude=50.91&longitude=6.81¤t=temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m,wind_direction_10m&daily=precipitation_probability_max&timezone=Europe/Berlin";
// TFT-Display Setup (Thin-Film Transistor)
TFT_eSPI tft = TFT_eSPI();
// Timer-Variablen
unsigned long lastTime = 0;
// Intervall auf 15 Minuten setzen (15 * 60 * 1000)
unsigned long timerDelay = 900000;
// Hilfsfunktion: WMO-Code (World Meteorological Organization) in Text übersetzen
String getWeatherDescription(int code) {
switch (code) {
case 0: return "Klarer Himmel";
case 1: case 2: case 3: return "Heiter bis wolkig";
case 45: case 48: return "Nebel";
case 51: case 53: case 55: return "Nieselregen";
case 61: case 63: case 65: return "Regen";
case 71: case 73: case 75: return "Schnee";
case 77: return "Schneegriesel";
case 80: case 81: case 82: return "Regenschauer";
case 85: case 86: return "Schneeschauer";
case 95: case 96: case 99: return "Gewitter";
default: return "Unbekanntes Wetter";
}
}
void setup() {
Serial.begin(115200);
// Hintergrundbeleuchtung des Displays einschalten (Pin 27)
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
// Display initialisieren
tft.init();
tft.setRotation(1); // Querformat (480 x 320)
tft.fillScreen(TFT_BLACK);
// 1. WLAN-Verbindung aufbauen
WiFi.begin(ssid, password);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawCentreString("Verbinde mit WLAN...", 240, 150, 4);
Serial.print("Verbinde mit WLAN");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Erfolgsmeldung
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.drawCentreString("WLAN verbunden!", 240, 150, 4);
delay(2000);
tft.fillScreen(TFT_BLACK);
// 2. Ersten API-Aufruf direkt beim Start ausführen
fetchAndDisplayWeather();
}
void loop() {
// API nur alle 15 Minuten abfragen
if ((millis() - lastTime) > timerDelay) {
if (WiFi.status() == WL_CONNECTED) {
fetchAndDisplayWeather();
}
lastTime = millis();
}
}
// Funktion für den HTTP-Request (Hypertext Transfer Protocol)
void fetchAndDisplayWeather() {
HTTPClient http;
http.begin(apiUrl);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
String payload = http.getString();
// JSON (JavaScript Object Notation) Dokument vorbereiten (ArduinoJson Version 7)
JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
// Daten aus dem JSON extrahieren
float temp = doc["current"]["temperature_2m"];
float feelsLike = doc["current"]["apparent_temperature"];
int humidity = doc["current"]["relative_humidity_2m"];
float windSpeed = doc["current"]["wind_speed_10m"];
int windDir = doc["current"]["wind_direction_10m"];
int weatherCode = doc["current"]["weather_code"];
// Regenwahrscheinlichkeit für den heutigen Tag (Index 0)
int rainProb = doc["daily"]["precipitation_probability_max"][0];
String weatherDesc = getWeatherDescription(weatherCode);
// Bildschirm leeren
tft.fillScreen(TFT_BLACK);
// --- ÜBERSCHRIFT ---
tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
tft.drawCentreString("Wetter in Koeln", 240, 10, 4);
tft.drawLine(20, 40, 460, 40, TFT_DARKGREY);
// --- LINKE SEITE (Hauptinformationen) ---
// 1. Nur die Temperatur-Zahl mit der großen Schriftart (7) schreiben
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
String tempString = String(temp, 1);
tft.drawString(tempString, 30, 80, 7);
// 2. Die Breite der Zahl berechnen, damit wir wissen, wo das 'C' hin muss
int numWidth = tft.textWidth(tempString, 7);
// 3. Grad-Zeichen als zwei ineinanderliegende Kreise selbst zeichnen (sieht oft besser aus)
int degreeX = 30 + numWidth + 5;
tft.drawCircle(degreeX, 85, 3, TFT_YELLOW);
tft.drawCircle(degreeX, 85, 4, TFT_YELLOW); // Etwas dicker machen
// 4. Das 'C' mit der normalen Schriftart (4) schreiben
tft.drawString("C", degreeX + 10, 80 + 15, 4);
// Wetterbeschreibung (z.B. "Heiter bis wolkig")
tft.setTextColor(TFT_CYAN, TFT_BLACK);
tft.drawString(weatherDesc, 30, 150, 4);
// --- RECHTE SEITE (Details) ---
int rightColX = 250; // Startpunkt für die rechte Spalte
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawString("Details:", rightColX, 70, 4);
tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
String feelsString = "Gefuehlt: " + String(feelsLike, 1) + " C";
tft.drawString(feelsString, rightColX, 105, 2);
String humString = "Feuchte: " + String(humidity) + " %";
tft.drawString(humString, rightColX, 130, 2);
String windString = "Wind: " + String(windSpeed, 1) + " km/h";
tft.drawString(windString, rightColX, 155, 2);
String dirString = "Richtung: " + String(windDir) + " Grad";
tft.drawString(dirString, rightColX, 180, 2);
String rainString = "Regenrisiko: " + String(rainProb) + " %";
tft.drawString(rainString, rightColX, 205, 2);
// --- FUSSZEILE ---
tft.drawLine(20, 280, 460, 280, TFT_DARKGREY);
tft.setTextColor(TFT_DARKGREY, TFT_BLACK);
tft.drawCentreString("Daten bereitgestellt von Open-Meteo", 240, 290, 2);
} else {
Serial.print("JSON parsen fehlgeschlagen: ");
Serial.println(error.c_str());
}
} else {
Serial.print("Fehler beim HTTP-Request. Code: ");
Serial.println(httpResponseCode);
}
http.end(); // Verbindung sauber schließen
}

Wie ihr eure perfekte Open-Meteo Koordinate für deinen Ort findet, hatte ich hier beschrieben:
https://prilchen.de/esp32-projekt-smart-weather-e-paper-display/
Übersicht weiterer Möglichkeiten grafischer User Interfaces (GUI) zu erstellen
| Methode | Beschreibung | Für wen geeignet |
|---|---|---|
| Arduino IDE (manuell) | Direkte Programmierung mit TFT_eSPI & TouchScreen.h | Fortgeschrittene Bastler |
| EEZ Studio | Visuelle GUI-Erstellung mit automatischer Code-Generierung | Einsteiger & GUI-Fans |
| LVGL mit Arduino IDE | Professionelle GUI mit Widgets, Animationen, Themes | Fortgeschrittene Entwickler |
| Adafruit GFX | Alternative Display-Library, einfacher aber weniger performant | Minimalisten & Lernende |
| VS Code mit PlatformIO | Moderne Entwicklungsumgebung mit besserem Projektmanagement | Profis & Power-User |
| Web-basierte Tools | z. B. ESP Web Tools für OTA-Upload & GUI-Editor | Schnelle Tests & Updates |
Youtube Video:
Vorschau:
In Teil 2 zeige ich, wie ich mit LVGL eine modernere und mobile Version dieser Wetterstation erstelle, mit passendem 3D Druck Gehäuse.
Der letzte Teil 3 wird im Oktober veröffentlicht. Da zeige ich wie das ganze mit dem kostenlose GUI Erstellungstool EEZ Studio zum laufen gebracht werden kann.
