Wet­ter­da­ten von Open­wea­ther auf einem TFT anzeigen

Lese­zeit: 8 Minu­ten

Lösung
Seite als PDF

Mit der API (Appli­ca­ti­on Pro­gramming Inter­face = Pro­gram­mier­schnitt­stel­le) von Open​wea​ther​map​.org und den damit erho­be­nen Daten sol­len die Wet­ter­da­ten auf einem TFT-Dis­play und in etwas aus­führ­li­che­rer Form im Seri­el­len Moni­tor ange­zeigt werden.

Dar­stel­lung der Daten

TFT-Dis­play

Pin­be­le­gung ver­schie­de­ner TFT-Displays

Seri­el­ler Monitor

Vor­be­rei­tung

Zunächst benö­tigst du einen API-Schlüs­sel von Open​wea​ther​map​.org:

🔗https://​home​.open​wea​ther​map​.org/​u​s​e​r​s​/​s​i​g​n​_up

In der Bestä­ti­gungs­mail fin­dest du dei­nen API-Key. Der freie Zugang erlaubt 60 Zugrif­fe in der Minute.

Quel­le: 🔗https://​open​wea​ther​map​.org/​p​r​i​c​e​#​w​e​a​t​her

Benö­tig­te Bauteile

  • ESP32-Wroom, Wemos D1 Mini oder Ardui­no ESP32
  • TFT
  • Lei­tungs­dräh­te

Lei­der wer­den vie­le Namen für den ➨SPI-Bus verwendet.

Pin­be­le­gung ESP32-Wroom

Pin­be­le­gung Ardui­no Nano ESP32

Pin­be­le­gung Wemos D1

Board instal­lie­ren:

Benö­tig­te Bibliotheken

1,77 Zoll/1,8 Zoll TFT
2,4 Zoll TFT

Erläu­te­rung zu JSON

Die Daten lie­gen im JSON-For­mat (Java­Script Object Nota­ti­on) vor. JSON dient dem Aus­tausch von Daten zwi­schen einem Ser­ver und einer Web­an­wen­dung. JSON-Daten sind eine Samm­lung von Schlüs­sel-Wert-Paa­ren. Die Biblio­thek fil­tert aus den Daten die­se Schlüs­sel-Wert-Paa­re heraus. 

Bei­spiel JSON-Wer­te beim Auf­ruf für Ber­gisch Glad­bach, Schlüs­sel und Wert wer­den in ecki­ge Klam­mern eingeschlossen.

Abruf der Daten von open​wea​ther​map​.org

http://api.openweathermap.org/data/2.5/weather?q=Bergisch%20Gladbach,de&APPID=6d320ceb0961bbfc928aa313xxxxxxxx&units=metric&lang=de

  • q= → Name der Stadt, Länderkürzel
  • APPID → dei­ne APPID (ich habe mei­ne eige­ne unkennt­lich gemacht)
  • units=metric → metri­sche Maß­an­ga­ben, die Tem­pe­ra­tur wird als Stan­dard in Kel­vin angezeigt
  • lang=de → Aus­ga­be der Daten in deut­scher Sprache

Das Pro­gramm

Ein­bin­den der Biblio­the­ken und Defi­ni­ti­on der Variablen

Der ein­zi­ge Unter­schied zwi­schen den Micro­con­trol­lern ist die Zuord­nung der SPI-Pins.

#include "WiFi.h"
#include "HTTPClient.h"
#include "Arduino_JSON.h"
#include "time.h"
#include "TimeLib.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ST7735.h"

/*
  SPI-Pins ESP32-Wroom
  DIN 23
  CLK 18
  CS   3
  RST 22
  DC   2

  #define TFT_CS        5
  #define TFT_RST      22
  #define TFT_DC        2
*/

/*
  SPI-Pins Arduino Nano ESP32
  DIN 11
  CLK 13
  CS  10
  RST  8
  DC   9

  #define TFT_CS 10
  #define TFT_RST 8
  #define TFT_DC  9
*/

/*
  SPI-Pins Wemos D1 Mini
  SPI-Pins
  DIN D7
  CLK D5
  CS  D0
  RST D1
  DC  D8
  #define TFT_CS  D0
  #define TFT_RST D1
  #define TFT_DC  D8
*/
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;

// Daten für die API von Openweather
String APIKey = "6d320ceb0961bbfc928aa313xxxxxxxx";
String Stadt = "Bergisch Gladbach";
String Land = "DE";

// Aktualisierungs-Intervall
unsigned long Intervall = 60000;

// String für die vom Server gelieferten Daten
String JSONDaten;

set­up-Teil

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

  Serial.begin(9600);

  // WiFi starten und Verbindung aufbauen
  WiFi.begin(Router, Passwort);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }

  // SSID des Routers anzeigen
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(WiFi.SSID());

  // IP anzeigen
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());

  // TFT starten schwarzer Hintergrund
  tft.initR(INITR_BLACKTAB);
  // Rotation anpassen Querformat
  tft.setRotation(1);

  // Schriftgröße
  tft.setTextSize(1);
}

Funk­ti­on ServerAntwortHolen()

Im loop-Teil wird die Funk­ti­on Ser­ver­Ant­wort­ho­len() auf­ge­ru­fen. Sie holt die Wet­ter­da­ten als String, der im loop-Teil in Schlüs­sel-Wert-Paa­re umge­wan­delt wird.

String ServerAntwortHolen(const char* OpenweatherServer) 
{
  WiFiClient Client;
  HTTPClient httpClient;

  httpClient.begin(Client, OpenweatherServer);

  // Anfrage senden
  int AntwortCode = httpClient.GET();

  String ServerAntwort = "";

  if (AntwortCode > 0) 
  {
    // Serial.print("Antwort-Code: ");
    // Serial.println(AntwortCode);

    // Wetter als String holen, wird später in ein JSON-Objekt umgewandelt
    ServerAntwort = httpClient.getString();
  } 
  
  else {
    Serial.print("Fehler: ");
    Serial.println(ServerAntwort);
  }

  httpClient.end();

  return ServerAntwort;
}

loop-Teil

void loop() 
{
  tft.fillScreen(ST7735_BLACK);
  tft.setTextColor(ST7735_GREEN);

  tft.setCursor(1, 5);

  // aktuelle Zeit holen
  time(&aktuelleZeit);

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

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

  Serial.print(Zeit.tm_mday);
  Serial.print(".");
  tft.print(Zeit.tm_mday);
  tft.print(".");

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

  // Zählung des Monats beginnt mit 0 -> 1 hinzufügen
  Serial.print(Zeit.tm_mon + 1);
  Serial.print(".");
  tft.print(Zeit.tm_mon + 1);
  tft.print(".");

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

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

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

  // Sekunden
  if (Zeit.tm_sec < 10) 
  {
    Serial.print("0");
    tft.print("0");
  }
  Serial.print(Zeit.tm_sec);
  Serial.println();
  tft.print(Zeit.tm_sec);

  // Wetterdaten holen, wenn WiFi verbunden ist
  if (WiFi.status() == WL_CONNECTED) 
  {
    // Name des Servers und Daten übergeben
    String OpenweatherServer = "http://api.openweathermap.org/data/2.5/weather?q=" + Stadt + ",";
    OpenweatherServer = OpenweatherServer + Land + "&APPID=" + APIKey + "&units=metric";

    // Daten vom Server abrufen
    // c_str() liefert einen mit \0 beendeten String
    JSONDaten = ServerAntwortHolen(OpenweatherServer.c_str());

    // wenn die Stadt nicht gefunden wurde
    if (JSONDaten.indexOf("city not found") > 0) 
    {
      Serial.println("Stadt nicht gefunden!");
      tft.setCursor(1, 40);
      tft.println("Stadt nicht gefunden!");
      while (1)
        ;
    }

    /*
        parse: Zeichenkette im JSON-Format in ein JavaScript-Objekt umzuwandeln
        damit die Daten (Schlüssel-Wert-Paare)ausgewertet werden können 
        z.B. ["main"] ["temp"]
      */
    JSONVar Objekt = JSON.parse(JSONDaten);

    // Stadt
    Serial.println(Stadt);
    tft.setCursor(1, 15);
    tft.println(Stadt);
    tft.drawFastHLine(1, 25, tft.width(), ST7735_GREEN);
    tft.setTextColor(ST7735_WHITE);

    // Temperatur
    Serial.print("Temperatur: ");
    double Temperatur = Objekt["main"]["temp"];
    String AnzeigeTemperatur = String(Temperatur);
    AnzeigeTemperatur.replace(".", ",");
    Serial.print(AnzeigeTemperatur);
    Serial.println("°C");
    tft.setCursor(1, 33);
    tft.print("Temperatur: " + AnzeigeTemperatur + char(247) + "C");

    // Luftdruck
    Serial.print("Luftdruck: ");
    Serial.print(Objekt["main"]["pressure"]);
    Serial.println(" hPa");
    tft.setCursor(1, 46);
    tft.print("Luftdruck: ");
    tft.print(Objekt["main"]["pressure"]);
    tft.println(" hPa");

    // Luftfeuchtigkeit
    Serial.print("Luftfeuchtigkeit: ");
    Serial.print(Objekt["main"]["humidity"]);
    Serial.println("%");
    tft.setCursor(1, 59);
    tft.print("Luftfeuchtigkeit: ");
    tft.print(Objekt["main"]["humidity"]);
    tft.println("%");

    // Windgeschwindigkeit
    Serial.print("Windgeschwindigkeit: ");
    double Windgeschwindigkeit = Objekt["wind"]["speed"];
    String AnzeigeWindgeschwindigkeit = String(Windgeschwindigkeit);
    AnzeigeWindgeschwindigkeit.replace(".", ",");
    Serial.print(AnzeigeWindgeschwindigkeit);
    Serial.println(" m/s");
    tft.setCursor(1, 72);

    tft.print("Wind: " + AnzeigeWindgeschwindigkeit);
    tft.println(" m/s");

    // Windrichtung
    Serial.print("Windrichtung: ");
    Serial.print(Objekt["wind"]["deg"]);
    Serial.println("°");

    // Wetterlage
    Serial.print("Wetterlage: ");
    String Wetterlage = Objekt["weather"][0]["main"];
    tft.setCursor(1, 85);

    if (Wetterlage == "Clear") 
    {
      Serial.println("klarer Himmel");
      tft.print("klarer Himmel");
    }

    if (Wetterlage == "Mist") 
    {
      Serial.println("Nebel");
      tft.print("Nebel");
    }

    if (Wetterlage == "Clouds") 
    {
      Serial.println("wolkig");
      tft.println("wolkig");
    }

    if (Wetterlage == "Rain") 
    {
      Serial.println("Regen");
      tft.println("Regen");
    }

    if (Wetterlage == "Snow") 
    {
      Serial.println("Schneefall");
      tft.println("Schneefall");
    }

    if (Wetterlage == "Drizzle") 
    {
      Serial.println("Nieselregen");
      tft.println("Nieselregen");
    }

    if (Wetterlage == "Thunderstorm") 
    {
      Serial.println("Gewitter");
      tft.println("Gewitter");
    }

    // Sonnenaufgang als UNIX-Time holen
    long Sonnenaufgang = Objekt["sys"]["sunrise"];
    Serial.print("Sonnenaufgang: ");

    // Zeit des Sonnenaufgangs setzen
    setTime(Sonnenaufgang);
    String ZeitSonnenaufgang;

    // Uhrzeit bestimmen
    if (hour(Sonnenaufgang) + 2 < 10) ZeitSonnenaufgang = "0";
    ZeitSonnenaufgang = ZeitSonnenaufgang + String(hour(Sonnenaufgang) + 2) + ":";
    if (minute(Sonnenaufgang) < 10) ZeitSonnenaufgang = ZeitSonnenaufgang + "0";
    ZeitSonnenaufgang = ZeitSonnenaufgang + String(minute(Sonnenaufgang));
    Serial.println(ZeitSonnenaufgang);

    // Sonnenuntergang 
    long Sonnenuntergang = Objekt["sys"]["sunset"];
    Serial.print("Sonnenuntergang: ");
    setTime(Sonnenuntergang);  
    String ZeitSonnenuntergang;
    if (hour(Sonnenuntergang) + 2 < 10) ZeitSonnenuntergang = "0";
    ZeitSonnenuntergang = ZeitSonnenuntergang + String(hour(Sonnenuntergang) + 2) + ":";
    if (minute(Sonnenuntergang) < 10) ZeitSonnenuntergang = ZeitSonnenuntergang + "0";
    ZeitSonnenuntergang = ZeitSonnenuntergang + String(minute(Sonnenuntergang));
    Serial.println(ZeitSonnenuntergang);
    tft.setCursor(1, 98);
    tft.print("Sonnenuntergang: " + ZeitSonnenuntergang);

    // letzte Messung 
    long letzteMessung = Objekt["dt"];
    Serial.print("letzte Messung: ");
    setTime(letzteMessung);  
    String ZeitLetzteMessung;
    if (hour(letzteMessung) + 2 < 10) ZeitLetzteMessung = "0";
    ZeitLetzteMessung = ZeitLetzteMessung + String(hour(letzteMessung) + 2) + ":";
    if (minute(letzteMessung) < 10) ZeitLetzteMessung = ZeitLetzteMessung + "0";
    ZeitLetzteMessung = ZeitLetzteMessung + String(minute(letzteMessung));
    Serial.println(ZeitLetzteMessung);
    tft.setCursor(1, 111);
    tft.print("letzte Messung: " + ZeitLetzteMessung);
  }
  delay(Intervall);
}

Startseite
Aufgaben A-Z
Suchen
Downloads
Fehlermeldungen
Seite als PDF

Ver­wand­te Aufgaben:


Letzte Aktualisierung: 27. Feb 2024 @ 11:44