Schon länger ärgert es mich, dass ich aktuelle Wetterdaten und weitere nützliche Informationen für den Tag mir immer mühsam von verschiedenen Seiten oder Geräten holen muss. Dazu zählen das Wetter, Sonnenaufgang und -untergang, Temperatur und die Mondphase. Natürlich dürfen auch das aktuelle Datum und die Uhrzeit nicht fehlen.
Die oben genannten Informationen generiere ich mir von aus drei verschiedenen Quellen, einem NTP-Server, einem Wetterdienst, der die Informationen im JSON-Format liefert und durch simple Mathematik. Letzteres dient für die Berechnung der Mondphase für den aktuellen Tag. Die Hardware soll dabei schlank aber gleichzeitig leistungsstark für weitere Modifikationen sein.
Damit das komplette Projekt funktioniert, bedarf es eines freien Accounts bei openweathermap.org und den API-Key für diesen Account. Wie Sie an die API-Key kommen, wird in der Hilfe von openweathermap.org ausführlich erklärt. Damit keiner mit dem IoT-Gerät Unsinn treibt, wird gleichzeitig auch das sichere https-Protokoll verwendet.
Was das JSON-Protokoll ist und wie die Mondphase berechnet wird, erkläre ich vor der benötigten Hard- und Software.
Was das JSON-Protokoll ist und wie die Mondphase berechnet wird, erkläre ich vor der benötigten Hard- und Software.
Die Berechnung der Mondphase
Wie in der Einleitung erwähnt, wird der ESP32 die Mondphase nicht über eine API abfragen, sondern diese selbst berechnen. Dazu braucht es simple Mathematik. Damit die Berechnung funktioniert, brauchen wir das genaue Datum einer vergangenen Vollmondnacht. Diese kann man sich unter www.mondverlauf.de für einen genauen Standort ausgeben lassen.
Danach errechnet man das Ergebnis zwischen der vergangenen Zeit bis heute und teilt dieses durch die Zeit, die zwischen zwei Neumondphasen vergeht. Diese Zeitspanne nennt sich auch synodische Periode.
Von diesem Ergebnis verwenden wir nur die Nachkommastellen, um die aktuelle Mondphase zu ermitteln. Dabei sagen die Nachkommastellen folgende Mondphasen aus:
- Vollmond bei 0,0
- Abnehmender Halbmond bei 0,25
- Neumond bei 0,5
- Zunehmender Halbmond bei 0,75
Ein kleines Beispiel dazu:
- Aktuell ist der 04.05.2020, 22:00 Uhr
- Der letzte Vollmond war am 08.04.2020 um 4:34 Uhr
- Dazwischen liegen knapp 26,72 Tage
- Diese Tage werden durch 29,53 geteilt (synodische Periode)
- Als Ergebnis erhalten wir 0,90 (zweite Stelle hinter dem Komma gerundet)
- Die Zahl vor dem Komma gibt an, wie oft schon eine Mondperiode durchlaufen wurde, in diesem Fall kein Mal
- Die Nachkommastelle gibt Aussage darüber, dass wir einen zunehmenden Mond haben und es bald Vollmond sein wird
Damit die Berechnung im Sketch funktioniert, definieren wir eine Variable vom Typ time und beschreiben diese in der Funktion setup() mit einer Funktion tmConvert, siehe Code 1.
time_t tmConvert(int iYear, byte byMonth, byte byDay, byte byHour, byte byMinute, byte bySecond) { tmElements_t tmSet; tmSet.Year = iYear - 1970; tmSet.Month = byMonth; tmSet.Day = byDay; tmSet.Hour = byHour; tmSet.Minute = byMinute; tmSet.Second = bySecond; return makeTime(tmSet); }
Code 1: Funktion, um UTC-Zeit letzte Mondphase zu errechnen
Die Berechnung und die Ausgabe erfolgen über zwei separate Funktionen. Die Funktion MoonUpdate übernimmt dabei die Berechnung der Mondphase wie oben beschrieben, siehe Code 2. Der Rückgabewert der Funktion ist eine Variable vom Typ double.
double MoonUpdate() { double dDaySinceLastFullmoon = (now() / 86400 - tmLastFullMoon / 86400) / 29.53; int iToHundret = (dDaySinceLastFullmoon - int(dDaySinceLastFullmoon)) * 100; return (double) iToHundret / 100; //Needed to get only 2 decimal places }
Die Funktion GetMoonPhase übernimmt die Interpretation des double-Werts von Moon-Update und wandelt diesen in einen für den Menschen verständlichen Wert, in diesem Fall als lesbaren Text. Zu Beginn ruft GetMoonPhase die Funktion MoonUpdate auf, um den aktuellen double-Wert zu erhalten, siehe Code 3.
String GetMoonPhase() { static double dMoonphase = MoonUpdate(); //Method to update moonphase Serial.println("Calculated moon result: " +String(dMoonphase,3)); if(dMoonphase == 0.0) dMoonphase = 1.00; if(dMoonphase < double(0.25)) { return "Abnehmende Mond"; } else if (dMoonphase == 0.25) { return "Abnehmender Halbmond"; } else if(0.25 < dMoonphase && dMoonphase < 0.50) { return "Abnehmende Sichel"; } else if(dMoonphase == 0.50) { return "Neumond"; } else if(0.50 < dMoonphase && dMoonphase < 0.75) { return "Zunehmende Sichel"; } else if(dMoonphase == 0.75) { return "Zunehmender Halbmond"; } else if(0.75 < dMoonphase && dMoonphase < 1.00) { return "Zunehmender Mond"; } else //Moonphase == 1 { return "Vollmond"; } }
Code 3:Berechnung der Mondphase
Was ist das JSON-Format
JSON ist die Abkürzung von JavaScript Object Notation und ist ein offenes Standard Dateiformat in einer einfachen lesbaren Textform, ähnlich wie XML. Es dient dem simplen Datenaustausch zwischen Anwendungen und findet unter anderem in der Industrie, bei systemübergreifender Kommunikation, Anwendung.
Beim JSON-Format handelt es sich zwar um ein gültiges JavaScript, aber es gibt Parser für alle verbreiteten Programmiersprachen, wie auch dem Arduino. In unserem Falle nutzen wir den Parser ArduinoJson, der uns die Antwort auf unserer Wetteranfrage in gültiges und leicht zu parsendes JSON umwandelt.
Eine Antwort kann wie folgt aussehen und ist dabei schnell und einfach zu lesen.
{ "Herausgeber": "Xema", "Nummer": "1234-5678-9012-3456", "Deckung": 2e+6, "Waehrung": "EURO", "Inhaber": { "Name": "Mustermann", "Vorname": "Max", "maennlich": true, "Hobbys": ["Reiten", "Golfen", "Lesen"], "Alter": 42, "Kinder": [], "Partner": null } }
Im Falle der Wetterdaten ist die Vorgehensweise wie folgt:
- Anfrage an den Wetterdienst openweathermap.org senden
- Antwort-String abwarten
- Nicht benötigte Daten, wie z.B. den Header, der Antwort eliminieren
- Den erhaltenen String ins DynamicJsonDocument-Format konvertieren
- Daten auslesen und ggf. schon in den richtigen Variablentyp umwandeln
Die oben beschriebene Arbeitsreihenfolge wird über die Funktion WeatherUpdate ausgeführt, siehe Code 4. Um mit ArduinoJson nun einen genauen Wert, wie z.B. das Alter von Herrn Mustermann aus unserem fiktiven Beispiel, zu bekommen, muss im Unterknoten „Inhaber“ die Variable „Alter“ ausgelesen werden. Diese Abfrage ist relativ simpel.
jsonDoc["Inhaber"]["Alter"]
Durch das Anfügen von „.as<int>()“ kann die Variable direkt noch in das gewünschte Variablenformat, hier Integer, konvertiert werden. Genau dieselbe Methode wird im Sketch genutzt, um die benötigten Werte direkt in die globalen Variablen zu schreiben, zu finden ab dem Kommentar „Save data to global var“.
void WeatherUpdate() { static bool bUpdateDone; if((firstrun || (minute() % 5) == 0) && !bUpdateDone) { jsonDoc.clear(); //Normally not needed, but sometimes new data will not stored String strRequestData = RequestWeather(); //Get JSON as RAW string Serial.println("Received data: " + strRequestData); //Only do an update, if we got valid data if(strRequestData != "") //Only do an update, if we got valid data { DeserializationError error = deserializeJson(jsonDoc, strRequestData); //Deserialize string to AJSON-doc if (error) { Serial.print(F("deserializeJson() failed: ")); Serial.println(error.c_str()); return; } //Save data to global var strMinTemp = RoundTemp(jsonDoc["main"]["temp_min"].as<double>()); strMaxTemp = RoundTemp(jsonDoc["main"]["temp_max"].as<double>()); strCurTemp = RoundTemp(jsonDoc["main"]["temp"].as<double>()); strFeelTemp = RoundTemp(jsonDoc["main"]["feels_like"].as<double>()); strSunrise = jsonDoc["sys"]["sunrise"].as<int>(); strSunset = jsonDoc["sys"]["sunset"].as<int>(); static long timeZone = jsonDoc["timezone"]; //Get latest timezone //Print to Serial Monitor Serial.println("Min Temp: " + strMinTemp); Serial.println("Max Temp: " + strMaxTemp); Serial.println("Cur Temp: " + strCurTemp); Serial.println("Feel Temp: " + strFeelTemp); //Check if timezone changed (sommer- / wintertime if(timeZone != utcOffsetInSeconds) { utcOffsetInSeconds = timeZone; timeClient.setTimeOffset(utcOffsetInSeconds); } } bUpdateDone = true; bUpdateDisplay = true; } if((minute() % 5) != 0) bUpdateDone = false; }
Code 4: Parsen der JSON-Wetterdaten
Interessant ist dabei die Ähnlichkeit zu XML und die Tatsache, dass Variablen durch „[]“ zu einem weiteren Unterknoten werden können, welcher wiederum Variablen oder Unterknoten enthalten kann. Somit kann man schnell und einfach Dateninhalte hinzufügen und auch auslesen, sofern man im Quellcode die genaue Knotenposition einprogrammiert.
Benötigte Hardware
Die Hardware für dieses Projekt kann komplett bei AZ-Delivery bezogen werden.
Anzahl | Bauteil | Anmerkung |
---|---|---|
1 | ESP32 DevelpomentBoard | |
1 | 0,96“ OLED Display mit I2C 128 | |
1 | Jumper Wire Female to Male |
Sollte ein anderes Display oder ESP-Modul von Ihnen genutzt werden, so muss das Pinout der Hardware beachtet werden.
Benötigte Software
-
Arduino IDE (https://www.arduino.cc/en/main/software)
-
Für das eingesetzte NodeMCU die korrekte Boardbibliothek einbinden, siehe hierzu im eBook zum entsprechend gekauften NodeMCU bzw. ESP nach.
-
Die folgenden Bibliotheken, siehe hierzu Arduino IDE - Programmieren für Einsteiger - Teil 1 (https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/arduino-ide-programmieren-fuer-einsteiger-teil-1) im Abschnitt Bibliothekenverwaltung
-
NTPClient
-
WiFi
-
WiFiClientSecure
-
Adafruit SSD1306 (Für die Displaykontrolle)
-
ArduinoJson (Zum Parsen vom JSON-Format)
-
Time
-
Einrichtung des ESP32 NodeMCU
Zwar habe ich unter dem Punkt „Software“ schon drauf hingewiesen, dass die richtige Boardbibliothek eingebunden werden soll, dennoch möchte ich Ihnen in kurzen Schritten erklären, was zu tun ist. Die detaillierte Anleitung finden Sie bei AZ-Delivery bei den kostenlosen eBooks.
Starten Sie die Arduino IDE und öffnen Sie die Voreinstellungen und tragen Sie die URL https://dl.espressif.com/dl/package_esp32_index.json unter zusätzliche Boardverwalter-URLs ein, siehe Abbildung 1 und Abbildung 2.
Nach einem Neustart der Arduino IDE öffnen Sie unter Werkzeuge -> Board die Boardverwaltung, siehe Abbildung 3, und geben Sie bei der Suche ESP32 ein, siehe Abbildung 4.
Wählen Sie die aktuellste Version der Boardbibliothek es32 von Espressif Systems aus, hier 1.0.4, und installieren Sie diese. Nach einem weiteren Neustart sollten die neuen Boards Im Menü Werkzeuge -> Board erscheinen. Hier suchen Sie nach dem Eintrag ESP32 Dev Module und wählen diesen aus, siehe Abbildung 5. Die Standardeinstellungen für dieses Board können Sie so übernehmen.
Der Aufbau
Der Aufbau der Schaltung ist mit vier Anschlüssen relativ einfach gehalten. Wir verbinden dabei das Display via I2C und stellen die Stromversorgung mit dem NodeMCU her, siehe Abbildung 6 und Tabelle 2. Gerade für den Testaufbau ist ein Breadboard für die schnelle Verbindung sinnvoll, aber kein Muss.
NodeMCU – Pin | OLED-Pin |
---|---|
3.3 V | VCC |
GND | GND |
SCL | G22 |
SDA | G21 |
Die Pinbelegung
Bei dem ESP32 DevelopmentBoard ist der GND-Pin neben dem 5V-Pin kein regulärer Ground-Pin, sondern der CMD-Pin. Dieser ist daher nicht zu benutzen!
Die Software
Ist alles aufgebaut, muss die SSID und das Passwort des WLAN-Netzwerkes, sowie der API-Key, die Location für openweathermap.org und die letzte Vollmondphase angepasst werden. In der oben verlinkten Website muss dafür eine aktuelle Position gesucht und dann das Datum für den eigenen Standort eingestellt werden. Man erhält dann einen vergangenen Vollmond. Diese Zeit muss man dann bei der Generierung von tmLastFullMoon übergeben.
Für mich wäre das aktuell:
tmLastFullMoon = tmConvert(2023,7,3,13,38,21);
An den entsprechenden Stellen ist dies mit dem Kommentar TODO markiert
Anschließend kann der Code auf den NodeMCU hochgeladen werden.
// Weatherstation with JSON and moonphase calculation // Autor: Joern Weise // License: GNU GPl 3.0 // Created: 14. April 2020 // Update: 14. April 2020 //----------------------------------------------------- #include <Adafruit_SSD1306.h> #include <Wire.h> #include <ArduinoJson.h> #include <NTPClient.h> #include <WiFiUdp.h> #include <TimeLib.h> #include <WiFiClientSecure.h> #include <WiFi.h> //Variables for display #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire); //Login data for WiFi const char *ssid = "WIFI_SSID"; //TODO const char *password = "WIFI-PASS"; //TODO //Needed variables for openweathermap.org const String apiKey = "ADD-YOUR_API"; //TODO const String location = "ADD-YOUR-LOCATION"; //TODO like "Wiesbaden,de" const char *clientAdress = "api.openweathermap.org"; int strMinTemp, strMaxTemp, strCurTemp, strFeelTemp, strSunrise, strSunset; DynamicJsonDocument jsonDoc(2000); //Variables to get and set time int utcOffsetInSeconds = 7200; String daysOfTheWeek[7] = {"So","Mo", "Di", "Mi", "Do", "Fr", "Sa"}; time_t tmLastFullMoon; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", utcOffsetInSeconds); bool firstrun = true; bool bUpdateDisplay = true; //Setup to init the NodeMCU void setup() { Serial.begin(115200); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) // Address 0x3C for OLED-Display { Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } WiFi.begin(ssid, password); while ( WiFi.status() != WL_CONNECTED ) { delay ( 500 ); Serial.print ( "." ); } tmLastFullMoon = tmConvert(YEAR,MONTH,DAY,HOUR,MINUTE,SECOND); //TODO https://www.mondverlauf.de Serial.println(""); Serial.println("Last moon: " + String(tmLastFullMoon)); Serial.println("Connected to Wifi with IP: " + WiFi.localIP().toString()); timeClient.begin(); } void loop() { WeatherUpdate(); //Method to update weather TimeUpdate(); //Method to update time DisplayUpdate(); //Method to update Display if(firstrun) firstrun = false; } //Method to update time and overwrite void TimeUpdate() { static bool bUpdateDone; if((firstrun || (minute() % 2) == 0) && !bUpdateDone) { bool bUpdate = timeClient.update(); setTime(timeClient.getEpochTime()); Serial.print("Update time: "); if(bUpdate){ Serial.println("Success"); } else{ Serial.println("Failed"); } bUpdateDone = true; } if((minute() % 2) != 0) bUpdateDone = false; } //Method to update weather forecast void WeatherUpdate() { static bool bUpdateDone; if((firstrun || (minute() % 5) == 0) && !bUpdateDone) { jsonDoc.clear(); //Normally not needed, but sometimes new data will not stored String strRequestData = RequestWeather(); //Get JSON as RAW string Serial.println("Received data: " + strRequestData); //Only do an update, if we got valid data if(strRequestData != "") //Only do an update, if we got valid data { DeserializationError error = deserializeJson(jsonDoc, strRequestData); //Deserialize string to AJSON-doc if (error) { Serial.print(F("deserializeJson() failed: ")); Serial.println(error.c_str()); return; } //Save data to global var strMinTemp = RoundTemp(jsonDoc["main"]["temp_min"].as<double>()); strMaxTemp = RoundTemp(jsonDoc["main"]["temp_max"].as<double>()); strCurTemp = RoundTemp(jsonDoc["main"]["temp"].as<double>()); strFeelTemp = RoundTemp(jsonDoc["main"]["feels_like"].as<double>()); strSunrise = jsonDoc["sys"]["sunrise"].as<int>(); strSunset = jsonDoc["sys"]["sunset"].as<int>(); static long timeZone = jsonDoc["timezone"]; //Get latest timezone //Print to Serial Monitor Serial.println("Min Temp: " + strMinTemp); Serial.println("Max Temp: " + strMaxTemp); Serial.println("Cur Temp: " + strCurTemp); Serial.println("Feel Temp: " + strFeelTemp); //Check if timezone changed (sommer- / wintertime if(timeZone != utcOffsetInSeconds) { utcOffsetInSeconds = timeZone; timeClient.setTimeOffset(utcOffsetInSeconds); } } bUpdateDone = true; bUpdateDisplay = true; } if((minute() % 5) != 0) bUpdateDone = false; } //Method for the API-Request to openweathermap.org String RequestWeather() { WiFiClientSecure client; if(!client.connect(clientAdress,443)){ //Changed to https -> Port 443 Serial.println("Failed to connect"); return ""; } /* * path as followed: * /data/2.5/weather? <- static url-path * q="location" <- given location to get weatherforecast * &lang=de <- german description for weather * &units=metric <- metric value in Celcius and hPa * appid="apiKey" <- API-Key from user-account */ String path = "/data/2.5/weather?q=" + location + "&lang=de&units=metric&appid=" + apiKey; //Send request to openweathermap.org client.print( "GET " + path + " HTTP/1.1\r\n" + "Host: " + clientAdress + "\r\n" + "Connection: close\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n" + "User-Agent: ESP32\r\n" + "Accept: text/html,application/json\r\n\r\n"); //Wait for the answer, max 2 sec. uint64_t startMillis = millis(); while (client.available() == 0) { if (millis() - startMillis > 2000) { Serial.println("Client timeout"); client.stop(); return ""; } } //If there is an answer, parse answer from openweathermap.org String resHeader = "", resBody = ""; bool receivingHeader = true; while(client.available()) { String line = client.readStringUntil('\r'); if (line.length() == 1 && resBody.length() == 0) { receivingHeader = false; continue; } if (receivingHeader) { resHeader += line; } else { resBody += line; } } client.stop(); //Need to stop, otherwise NodeMCU will crash after a while return resBody; } int RoundTemp(double dTemp) { return int(dTemp + 0.5); } //Method to update display content void DisplayUpdate() { static int iLastMinute; if(iLastMinute != minute() || firstrun || bUpdateDisplay){ display.clearDisplay(); display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(SSD1306_WHITE); // Draw white text display.setCursor(0,0); // Start at top-left corner display.println(String(daysOfTheWeek[weekday()-1]) + " " + GetDigits(day()) + String(".") + GetDigits(month()) + String(".") + year() + " " + GetDigits(hour()) + String(":") + GetDigits(minute())); display.println(String("Minimum ") + strMinTemp + String(" C")); display.println(String("Maximum ") + strMaxTemp + String(" C")); display.println(String("Aktuell ") + strCurTemp + String(" C")); //"Aktuell" german for current display.println(String("Gefuehlt ") + strFeelTemp + String(" C")); //"Gefuehlt" german for feels like display.cp437(true); // Use full 256 char 'Code Page 437' font display.write(int16_t(30)); display.println(" Sonne " + GetTimeAsString(strSunrise, utcOffsetInSeconds)); display.write(int16_t(31)); display.println(" Sonne " + GetTimeAsString(strSunset, utcOffsetInSeconds)); display.println(GetMoonPhase()); display.display(); //Print all in serial monitor Serial.println("---------------------"); Serial.println("EpochTime: " + String(timeClient.getEpochTime())); Serial.println(String(daysOfTheWeek[weekday()-1]) + String(". ") + GetDigits(day()) + String(".") + GetDigits(month()) + String(".") + year()); Serial.println(GetDigits(hour()) + String(":") + GetDigits(minute())); Serial.println(String("Min: ") + strMinTemp); Serial.println(String("Max: ") + strMaxTemp); Serial.println(String("Current: ") + strCurTemp); Serial.println(String("Feels like: ") + strFeelTemp); Serial.println(String("Sunrise: ") + GetTimeAsString(strSunrise, utcOffsetInSeconds)); Serial.println(String("Sunset: ") + GetTimeAsString(strSunset, utcOffsetInSeconds)); Serial.println(String("Moonphase: ") + GetMoonPhase()); iLastMinute = minute(); bUpdateDisplay = false; } } //Method to write given integer to String //If the value is less than 10, a "0" is placed in front String GetDigits(int iValue) { String rValue = ""; if(iValue < 10) rValue += "0"; rValue += iValue; return rValue; } time_t tmConvert(int iYear, byte byMonth, byte byDay, byte byHour, byte byMinute, byte bySecond) { tmElements_t tmSet; tmSet.Year = iYear - 1970; tmSet.Month = byMonth; tmSet.Day = byDay; tmSet.Hour = byHour; tmSet.Minute = byMinute; tmSet.Second = bySecond; return makeTime(tmSet); } String GetTimeAsString(int iValue, int iOffset) { if(iValue > 0){ iValue += iOffset; return GetDigits(hour(iValue))+":"+GetDigits(minute(iValue)); } return ""; } double MoonUpdate() { double dDaySinceLastFullmoon = (now() / 86400 - tmLastFullMoon / 86400) / 29.53; int iToHundret = (dDaySinceLastFullmoon - int(dDaySinceLastFullmoon)) * 100; return (double) iToHundret / 100; //Needed to get only 2 decimal places } String GetMoonPhase() { static double dMoonphase = MoonUpdate(); //Method to update moonphase Serial.println("Calculated moon result: " +String(dMoonphase,3)); if(dMoonphase == 0.0) dMoonphase = 1.00; if(dMoonphase < double(0.25)) { return "Abnehmender Mond"; } else if (dMoonphase == 0.25) { return "Abnehmender Halbmond"; } else if(0.25 < dMoonphase && dMoonphase < 0.50) { return "Abnehmende Sichel"; } else if(dMoonphase == 0.50) { return "Neumond"; } else if(0.50 < dMoonphase && dMoonphase < 0.75) { return "Zunehmende Sichel"; } else if(dMoonphase == 0.75) { return "Zunehmender Halbmond"; } else if(0.75 < dMoonphase && dMoonphase < 1.00) { return "Zunehmender Mond"; } else //Moonphase == 1 { return "Vollmond"; } }
Info zum Code
Die Funktion loop() führt lediglich die Methoden zum Updaten der Wetterdaten, Zeit und Displayanzeige aus. Beim Update der Displayanzeige wird gleichzeitig auch die aktuelle Mondphase berechnet.
Ist alles hochgeladen und sind die individuellen Änderungen im Code gemacht zeigt das Display die gewünschten Informationen an.
Ich wünsche Ihnen viel Spaß beim Nachbau.
Jörn Weise
Dieses und weitere Projekte finden sich auf GitHub unter: https://github.com/M3taKn1ght/Blog-Repo
44 Kommentare
Sascha Giese
Es werden nach dem Download leider keine aktuellen Temperaturen angezeigt. (nur 0 °C)
Uhrzeit und Datum funktionieren. Was kann ich am Code ändern ?
Der api String funktioniert. Habe ich mit einem anderen Sketch ausprobiert.
Harald Bohnenkamp
Hallo,
wenn du den folgenden OWM-api aufrufst (LATidude, LONgitude und appid anpassen!), gibt OWM dir unter anderem die Mond-Auf—, ~Untergangszeit und die Mondphase zurück!
https://api.openweathermap.org/data/2.5/onecall?lat=51&lon=7.2&exclude=hourly,minutely&appid=
Ich denke, dein Programm anzupassen ist nicht so schwierig…
Gruß Harald
Andreas Wolter
ich habe den Hinweis von Jörn Weise in den Beitrag eingefügt.
Grüße,
Andreas Wolter
AZ-Delivery Blog
Jörn Weise
Hallo Harald,
ich musste mich tatsächlich wieder in das Projekt ein bisschen einarbeiten, aber ich glaube so langsam kommt wieder die Erinnerung. Bei der Zeit tmLastFullMoon brauchte ich einen Zeitstempel für die Kalkulation in der Funktion MoonUpdate(). Im Blogtext steht vllt. nicht ganz klar dazu:
“Ist alles aufgebaut, muss die SSID und das Passwort vom WLAN sowie der API-Key, die Location für openweathermap.org und die letzte Vollmondphase angepasst werden. An den entsprechenden Stellen ist dies mit dem Kommentar TODO markiert.”
Damit ist gemeint, in der oben verlinkten Website bei ToDo sich seine aktuelle Position zu suchen und dann das Datum für den eigenen Standort so einzustellen, dass man einen vergangenen Vollmond bekommt. Diese Zeit muss man dann bei der Generierung von tmLastFullMoon übergeben.
Für mich wäre das aktuell:
tmLastFullMoon = tmConvert(2023,7,3,13,38,21);
Damit kann dann der ESP die weitere Berechnung vornehmen und greift nicht auf falsche Daten zurück.
Gruß
Jörn
Harald Bohnenkamp
Tolles Projekt!
Leider bekomme ich die Monddaten nicht; der ToDo-Link tmLastFullMoon = tmConvert(YEAR,MONTH,DAY,HOUR,MINUTE,SECOND); //TODO https://www.mondverlauf.de
funktioniert nicht. :-(
Wie muss ich den Aufruf machen? oder wie kommt das Programm an das Datum des letzten Vollmond?
“Ansonsten” klappt alles wunderbar; ich habe das (winzige) OLed-Display durch ein 3,5" TFT ersetzt und in ein Gehäuse eingebaut; als Wandbild DER Hingucker!
Vielen Dank, Harald
Peter Schildt
Nachtrag zu Kommentar vom März 03, 2021 at 08:07am
Geändert: – funktioniert…
String Weather::RequestWeather()
{
// WiFiClientSecure client; // Changed to https → Port 443?
WiFiClient client; // Changed to https → Port 80!
if(!client.connect(clientAdress,80))
{
Serial.println(“Failed to connect”);
return "";
}…
Vermute Library wurde geändert.
der Peter
Peter Schildt
Gutes Programm, Respekt.
Erste Installation auf ESP 32-WROOM – ohne Probleme,
spätere Versuche mit gleicher und verschiedenen anderen MCU s – kein Kontakt zu api.openweathermap.org client . 2. apiKey bringt auch keine Lösung.
Fehler: mit Method RequestWeather() => Failed to connect //Changed to https > Port 443
Port 443 Firewall Freigabe ist ok. Seltsam ist, das erste Installation immer problemlos läuft.
Arduino 1.8.13 kompilieren und hochladen – kein Fehler. WIFI auch ok.
Hilfe! der Peter ;(
Thomas Oehmke
Hallo, Herr Weise,
kann man das Programm auch auf ein Heltec-LoRa-Board
anpassen, und wie müsste ich da vorgehen ? Mit einem
ESP32-MCU und abgesetztem 0,96-Display hat es gut geklappt.
Viele Grüße aus Berlin
Th.Oehmke
Jörn Weise
Guten Abend Herr Engel,
Ich nutze bei meinen Projekten immer die neusten Bibliotheken und führe in regelmäßigen Abständen Updates als Bibliotheken über die Verwaltung durch.
Es liegt natürlich auch ein Stück weit an Ihnen, Ihre Bibliotheken auf dem aktuellsten Stand zu halten. In den meisten Beiträgen hier, ist keine spezielle Version einer libary genutzt worden, also können Sie auch davon ausgehen, dass sie Beispiele laufen. Meist werden den libraries nur neue Funktionen oder Hardwareanbindungen hinzugefügt, was sie eigentliche Funktion in unseren Beiträgen nicht beeinflusst.
Wie oben schon beschrieben, sind Sie auch als Endnutzer für die Aktualität ihrer libraries verantwortlich, da wir als Blogger nicht wissen, wie ihr Softwarestand aussieht.
Gruß
Weise
Ulrich Engel
Sehr geehrter Herr Weise,
nun funktioniert es.
Ich habe angefangen von der Boardverwaltung ESP32 Installation und Boardauswahl bis zu den librarys alles neu installiert und merkwürdigerweise hat er mir auch zu einigen Libs weitere Libs angeboten, die mit #include t wurden. Vielleicht habe ich damit eine aktuellere passende Version gefunden. Egal. Meistens liegt es an den Libs. Deshalb wäre eigentlich eine Angabe der Quellen und Versionen immer hilfreich. Es ist oft nicht die neueste Lib, sondern eine spezielle auch mal von einem anderen Programmierer.
Vielen Dank für Ihre Geduld und bleiben Sie gesund
Ulrich Engel aus Berlin
Ulrich Engel
Ich habe ja schon einige Projekte umgesetzt. Auch mit SSD1306 OLED. Dort habe ich meistens die SSD1306.h verwendet:
#include “SSD1306.h”
Adafruit_BME280 bme; // I2C
SSD1306 display(0×3c, 0, 2); // Initialize the OLED display using Wire library
Vielleicht werde ich das hier auch so machen.
Ich habe oft schon erlebt, dass es an der Version einer Lib liegt. Ich habe hier die Versionen:
Arduino IDE 1.8.7
Adafruit_SSD1306 2.4.0
Wire PaulStoffregen /Wire Github
Jörn Weise
Hallo Ulrich Engel,
das ist ein ziemlich hartnäckiger Fall, den Sie da beschreiben. Ggf. müssen sie tatsächlich in Ihrem Dokumenten-Ordner Arduino\libraries in libraries_org umbenennen und danach noch einmal alles komplett nach Tutorial installieren. Ich habe mal alles auf meinem Rechner neu gemacht und ihren Fehlerfall nicht nachvollziehen können.
Gruß
jörn Weise
Ulrich Engel
Hallo Jörn,
ich habe nun aus meinen librarys noch einmal die Adafruit_SSD1306 und die Wire Lib rausgeworfen und die neuesten Versionen installiert. Bei der Adafruit_SSD1306 habe ich aber keine (Zitat)
“Abfrage ob alle abhängigen Pakete für die Library “Adafruit SSD1306” (Zitatende) erhalten. Die Installation über die Bibliotheksverwaltung lief glatt durch und die Lib war in meinem library-Verzeichnis.
Trotzdem erhalte ich die Fehlermeldung wieder:
“Wetter_mit_Mondphasen:22:56: error: ‘Wire’ was not declared in this scope
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);
Was mich wundert, und ich habe schon andere Profekte mit OLED SSD1306 0,96" gemacht ist, wie hier diese Zuweisung erfolgt.
In den anderen Projekten z.B. Standard “Hello” mit ESP8266 sieht es so aus:
/* Hello World OLED Test */
#include
#include “SSD1306.h”
SSD1306 display(0×3c, 5, 4); // Initialise the OLED display using Wire library
……….
Hier gebe ich die Adresse des Oled (I2C-Scanner) und den SDA und SCL Pin an.
Muss ich vielleicht diese Lib einbinden und dann Pin 21 und 22 angeben? Die Adresse ist gleich.
Nun bin ich mit meinem Anfängerwissen am Ende. Will aber dieses Projekt unbedingt fixen.
Viele Grüße Ulli
Jörn Weise
Hallo Ulrich Engel,
so wie ich das sehe, haben Sie bei der Abfrage ob alle abhängigen Pakete für die Library “Adafruit SSD1306” nur die angegebene Library installieren lassen. Diese ist aber abhängig von anderen Librarys und müssen somit nachinstalliert werden. Besser ist der Weg, dass Sie in Ihrem Dokumenten-Ordner nach dem Ordner Arduino\libraries\Adafruit_SSD1306 suchen und diesen noch einmal löschen. Starten Sie danach die Arduino IDE neu und installieren Sie noch einmal die Library “Adafruit_SSD1306”. Bei der Frage, ob auch die weiteren benötigten Librarys installiert werden sollen, bitte dies bestätigen und mit downloaden lassen.
Danach sollte das Projekt so klappen.
Gruß
Jörn Weise
Ulrich Engel
Ich habe nun die Librarys aktualisiert. Es bleibt beim Kompilieren die Fehlermeldung zur Zeile:
Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi = &Wire,Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);
Fehlermeldung:
Arduino\libraries\Adafruit_SSD1306-master/Adafruit_SSD1306.h:129:42: error: ‘TwoWire’ has not been declared
Jörn Weise
Hallo Ulrich Engel,
ich habe mir das gerade mal schnell angesehen und es kann nur daran liegen, dass die Bibliothek ArduinoJson nicht vorhanden ist oder falsch inkludiert wurde. Bitte prüfen Sie noch einmal, ob die aktuelle Version über die Bibliotheksverwaltung installiert wurde.
Ggf. müssen Sie die Arduino IDE noch einmal neustarten, wenn Sie zu viele Bibliotheken auf einmal herunterladen. Da kommt es ab und zu zu einem internen Fehler der Arduino IDE.
Gruß
Jörn Weise
Ulrich Engel
Hallo,
ich starte gerade mit diesem Tutorial.
Leider bekomme ich beim Kompilieren folgenden Fehler:
‘DynamicJsonDocument’ does not name a type
Eigentlich habe ich alle Librarys gespeichert.
Woran könnte es liegen?
Viele Grüße Ulli
Dieter Möller
Hallo, so ich habe die Sache mit description hingekriegt: despcrition und icon sind Strings, die id ist ein int. Ich hatte einen dummen Anfängerfehler gemacht: in .as() string klein geschrieben. Es muss so heißen: wetter = jsonDoc[“weather”]0[“description”].as();
strid = jsonDoc[“weather”]0[“id”];
icon = jsonDoc[“weather”]0[“icon”].as();
Die Variabeln wetter, strid und icon müssen natürlich voher global defefeniert sein.
Gruss Dieter
Jörn Weise
An Dieter Möller:
Ich habe mir mal angesehen, was sie versuchen zu konvertieren und dazu schon ein bisschen was gefunden
strWeather = jsonDoc[“main”][“description”].as(); <- Diesen Pfad gibt es nicht und nur ein as() funktioniert auch nicht
strDescription = jsonDoc[“main”][“description”]; <- Diesen Pfad gibt es, theoretisch sollte der string so übernommen werden, ansonsten as()
strid = jsonDoc[“weather”][“id”].as(); <- Diesen Pfad gibt es, aber bei dem hier fehlt die korrekte Konvertierung as() oder das as() weglassen
strIcon = jsonDoc[“main”][“icon”]; <- siehe oben
Generell kann ich mit den wenigen Informationen nicht genau sagen, wo der Fehler liegt. Bitte fügen Sie doch dafür bei https://pastebin.com/ mal den Quellcode ein (vorher bitte alle Sicherheitsrelevaten Daten löschen), damit ich besser sehen kann, wo der Fehler liegt.
Dieter Möller
nochmal Hallo,
leider ist beim Kopieren was falsch gelaufen. Die Zeilen, die nicht funktionieren, sehen so aus:
strWeather = jsonDoc[“main”][“description”];
strid = jsonDoc[“weather”][“id”];
strIcon = jsonDoc[“weather”][“icon”];
Gruss Dieter
Dieter Möller
Hallo, nach einem anderen Project wende ich mich wieder diesem Wetter- Project zu. Viel weiter bin ich nicht gekommen. Die nachfolgenden Zeilen funktionieren nicht. ich habs mit "weather und “main” und .as() odwer .as versucht, aber der Monitor zeigt immer “0” an. Wär schön, wenn mir wieder geholfen wird.
Gruss
strWeather = jsonDoc[“main”][“description”].as();
strDescription = jsonDoc[“main”][“description”];
strid = jsonDoc[“weather”][“id”].as();
strIcon = jsonDoc[“main”][“icon”];
Joern Weise
An Dieter Möller:
Vom Prinzip müssen Sie nur die Funktion WeatherUpdate() modifizieren.
Hier sehen Sie ja schon, wie Sie einzelne Knoten vom JSON-Format auslesen können. Laut API-Dokumentation befindet sich die “description” im Elternknoten “main”, daher sähe der Datenaufruf wie folgt aus:
strDescription = jsonDoc[“main”][“description”];
Wichtig hierbei ist noch, dass Sie die Variable strDescription vorher global definieren, suchen Sie dazu z.B. nach strMinTemp und fügen Sie die neue Variable hinzu.
Danach können Sie diese auf dem seriellen Monitor oder mit Anpassung der Displayanzeige entsprechend lesbar machen.
Bedenke Sie aber bitte, dass die Description länger als die maximale Anzahl an Zeichen fürs Display sein kann.
Dieter Möller
Ein sehr schönes Projekt. Das habe ich sofort nachgebastelt. Funktioniert auch. Aber ich möchte gern noch die Openweatermap “description” zufügen, es gelingt mir aber nicht!? Kann mir jemand helfen?
Gruss
Jörn Weise
An Gerhard: So ganz kann ich die Änderungen nicht nachvollziehen, Sie können mir diese aber gerne an boardriderxp(at) gmx.net schicken. Im Grunde eliminieren Sie mit einer Codezeile die https-Verbindung (Port 443), da Sie wieder den Port 80 nutzen (http).
Ich kann mir aber gerne Ihre Modifikationen noch einmal genauer ansehen und dann mehr dazu sagen.
Gruß
Jörn Weise
Gerhard
Liebe Freunde, mit der Änderung auf ESP8266 vom 26. Juni 2020 und der Anweisung:
Wire.begin(2, 0); // I2C pins (SDA = GPIO2, SCL = GPIO0)
im setup vor dem öffenen der OLED’s läuft das Ganze auch einwandfrei auf eniem ESP-01
Viel Spass Gerhard
Gerhard
Sehr geehrter Herr Joern Weise!
} else { Serial.println(“Failed to connect”); return ""; } /einfügen Ja das sind alle Änderungendie ich gemacht habe. Noch ein Tipp an alle die ein grösseres Display einbauen, man kann durch z.b. mit strPressure = RoundTemp(jsonDoc[“main”][“pressure”].as()); strHumidity = RoundTemp(jsonDoc[“main”][“humidity”].as()); oder auch andere Parameter mittels dem JASON ganz leicht auch mehrere Parameter holen, muß aber vorher die entsprechenden Strings deffinieren. Enstspechende Information was es alles gibt, gibts auf openweathermap.org Viel Spass GerhardIch hab es nun selbst geschafft Ihr wirklich gutes Programm
auf ESP8266 zu portieren, es läuft jetzt und ich es auf verschiedenen
ESP8266 12E mit Modulen versehenen Board’s getestet.
Für alle die es auch erprobrn wollen hier die Änderungen:
Zeile 15 entfernen
16 auf #include //ändern
26 const char* host = “api.openweathermap.org”; //und
27 const char *clientAdress = “api.openweathermap.org”; //einfügen
148 – 152 entfernen, dafür vor
164 if (client.connect(host, 80))
{ // einfügen und nach "Accept….
Fred Krause
Vielen Dank Herr Weise.
Ihr Projekt funktionierte bei mir auf Anhieb wie erwartet. Gute Arbeit!
Das Wichtigste ist, man kann viel daraus lernen, wenn man versucht es für die eigenen Wünsche oder andere Displays anzupassen. Probleme macht mir gerade noch das 1.3 Zoll I2C OLED Display (auch von AZ-Del.), weil ich keine passende Bibliothek dafür finde (Controller DS1106). Die u8g2 Bibliothek, die im Quick-Start-Guide beschrieben ist, finde ich nicht. Hat jemand eine Lösung?
Gilbert
Hallo,
Funktioniert sehr gut!
Nur manchmal beim Hochladen den Message:
“A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header”
Dann einfach “neu starten”: einige Sekunden auf den Taster “BOOT” zu Beginn des Uploads.
(Die fünf “TODO” nicht vergessen !)
Mit größerem Display könnte man Luftdruck, Wind und andere Daten hinzuzufügen.
Hier unten wass man im Serial Display lesen kann.
EpochTime: 1592408160
Me. le 17/06/2020
Heure : 15:36
Min: 17°C
Max: 18°C
Actuel : 18°C
Ressenti : 18°C
Lever Soleil : 05:42
Coucher Soleil : 21:35
Calcul de la phase de la lune : 0.400
Phase de la Lune : Dernier croissant
Gerhard
Sehr geehrter Herr Joern Weise!
Ein Wirklich schönes Projekt, dass auch auf dem ESP32 einwandfrei läuft.
Ich versuche es nun auf ein ESP-12 (NodeMCU) zu portieren.
Leider gelingt mir das nicht, die Verbindung zum Timeserver geht einwandfrei, zur Wetter.org aber leider nicht. Geändert habe ich nur die WiFi.h auf WiFi8266.h.
Vielleicht haben Sie eine Tipp für mich wie ich das zum laufen bekomme.
Besten Dank für Ihre Antwort im Voraus.
Gerhard
Joern Weise
@Juergen Babenhauserheide: Damit belegen Sie aber nur unnötig Speicher für eine globale Variable und ist so auch nicht gedacht gewesen. In dem Artikel wird ja beschrieben, dass Sie die letzte Vollmondphase über die angegebene Website ermitteln sollen. Initial werden Sie dadurch immer eine falsche Prognose bekommen.
@Randy P: Die Fehlermeldung sieht danach aus, dass Sie vergessen haben AJSON runterzuladen, wie es am Anfang vom Artikel beschrieben ist. Dadurch versucht die IDE einen Kopierkonstruktor für ein Array von char zu nutzen, obwohl er einen anderen Datentyp dafür nutzen sollte. Bitte die fehlende Bibliothek nachladen.
Randy P
bekomme folgende Fehlermeldung
no match for ‘operator[]’ (operand types are ‘ArduinoJson670_0_0::DynamicJsonDocument’ and ‘const char 5’)
bitte um Hilfe
Joern Weise
@Jochen Pils
Das sind auch erst mal nur Platzhalter. Sie müssen, wie in der Anleitung beschrieben, an dieser Stelle ein Datum für die letzte Vollmondphase angeben. Steht aber genauso auch noch einmal als Kommentar im Quellcode. Andernfalls klappt es natürlich nicht, die aktuelle mondphase zu berechnen.
Juergen Babenhauserheide
Hallo,
mit dem Original-Code erhalte ich auch die Fehlermeldung: “‘YEAR’ was not declared in this scope”.
Mit dem folgenden Zusatz am Anfang von void setup():
int YEAR;
byte MONTH, DAY, HOUR, MINUTE, SECOND;
funktioniert der Programm-Code einwandfrei.
MfG
Juergen B.
Anonymous
Schöne Projektidee!
Zeil 56 macht mir Probleme, so dass der Sketch nicht läuft, da bekomme ich Fehlermeldungen:
Wetterstation_MOndphase:56:29: error: ‘YEAR’ was not declared in this scope
Wetterstation_MOndphase:56:34: error: ‘MONTH’ was not declared in this scope
Wetterstation_MOndphase:56:40: error: ‘DAY’ was not declared in this scope
Wetterstation_MOndphase:56:44: error: ‘HOUR’ was not declared in this scope
Wetterstation_MOndphase:56:49: error: ‘MINUTE’ was not declared in this scope
Wetterstation_MOndphase:56:56: error: ‘SECOND’ was not declared in this scope
Kann jemand helfen?
Danke, Jochen
Jürgen Reimann
Hallo, hab es gleich ausprobiert und läuft problemlos. Danke für die tolle Vorlage
Da ich als Zugang zum Internet auf meiner FritzBox das Gastnetz benutze hatte ich Probleme mit dem NTP Connect, das ist auf dem Gastnetz nämlich gesperrt. Das lässt sich aber leicht lösen, denn viele Internet Access Points haben einen eigenen NTP Server, so auch die FritzBox. Man trägt man einfach statt “europe.pool.ntp.org” die Adresse “fritz.box” ein, vorher unter Benutzereinstellungen noch NTP aktivieren.
Joern Weise
@Thomas Bierschwale
Das wundert mich dann aber sehr, weil ich in meiner Anleitung genau das gleiche Display verwenden. Gerade wenn nur “Schnee” angezeigt wird, deutet es darauf hin, dass die i2c-Verbindung nicht korrekt ist. Daher wäre nun die Frage, welchen MicroController Sie nutzen und ob das korrekte Pinout für den MicoController genutzt wird. “Schnee” ist immer ein Anzeichen dafür, dass das Display zar Strom bekommt, aber eben keine Daten.
Gilbert Lerch
Vielen dank für die Antwort. Ich werde den ESP 32 nehmen.
Thomas Bierschwale
Ich habe das Projekt nachgebaut. Es läuft soweit, im Monitore werden richtige Werte angezeigt. Leider zeigt das Display nur “Schnee” an. Das Display ist genau dieses hier: https://az-delivery.de/products/0-96zolldisplay. Normalerweise benutze ich immer die Lib , wie auch im Ebook dazu angegeben.
Irgendwo auf diesen Seiten hatte ich mal was zur Abhilfe gesehen, finde es aber nicht mehr. Was kann ich tun?
Joern Weise
@Anyone: Das freut mich. Die Bauteile sind recht übersichtlich gehalten, sollte daher schnell und unkompliziert aufgebaut sein.
@Ulrich Klaas: Für jedes Board gibt es in der Kategorie “Kostenlose eBooks” eine Anleitung, wie man das ESP zum Leben erweckt. Mittlerweile gibt es einen Haufen an ESP32-Module, mit den verschiedensten Unterschieden. Ich habe mich bewusst für dieses Model entschieden, da es einen 5V-Ausgang hat, der gerade bei den LCD-Displays gebraucht wird, da 3,3V einfach zu wenig ist. Ich bin kein Freund eine Spannungsquelle so zu splitten, dass ich diverse Geräte damit mit Strom versorgen kann, wobei es auch hier eine gute lösung von AZ-Delivery gibt https://az-delivery.de/collections/basis-produkte/products/mb102-breadboard. Meist ist es bei den ESP’s so, dass man mehr Pinouts hat oder mehr Schnittstellen oder sie sehr kompakt sind. Ähnlich wie beim Arduino ist der Grundaufbau “quelloffen” es kann sich theoretisch also jeder selbst etwas basteln. Zudem unterscheidet man noch darin, ob sie eine Programmierschnittstelle haben oder eben nicht. Ich glaube das Thema hier zur Gänze zu klären schaffe ich nicht, dafür gibt es diverse (englischsprachige) Foren, wo es Diskussionen dazu gibt.
@michael: Natürlich können sie auch andere Displays nutzen, wichtig dabei ist aber, dass Sie die richtige Schnittstelle und Libary für das jeweilige Display einsetzen. Da es auf dem Markt eine große Anzahl an Displays gibt, diese unterschiedlich angesteuert werden, kann es durchaus sein, dass Sie den Code stark modifizieren müssen, um ein ähnliches Ergebnis zu bekommen. Ggf. wird es auf meiner GitHub-Seite eine Update mit dem dem 1,8" Display von AZ-Delivery geben (https://az-delivery.de/collections/displays/products/1-8-zoll-spi-tft-display). Dazu muss ich aber dann die Zeit finden.
@Sven Hesse: Danke für dieses schnelle und positive Feedback. Das freut mich als Blogger und auch das Team von AZ-Delivery, wenn solche Projekte positiven anklang finden.
@Gilbert: Geht theoretisch auch mit einem ESP 12, Sie brauchen aber unbedingt die i2c-Schnittstelle, damit das Display auch geht. Zusätzlich ist die verwendete JSON-Libary sehr groß, das heißt auch der Platzbedarf vom Coder sollte nicht unterschätzt werde.
Gilbert
Sehr interessant!
Frage: Geht es auch mit einem ESP8266NodeMCU ESP 12E?
Danke.
Sven Hesse
Hi,
vielen Dank für das Tutorial.
Direkt getestet und läuft.
Kleiner Hinweis an @michael: Man kann natürlich auch größere Displays verwenden, dazu findet man auf Github auch reichlich Informationen.
michael
Hallo, tolles Teil. Frage kannn man cu einen anderen “Monitor” anschließen?
zB.: 1,77 Zoll SPI TFT-Display und 128×160 Pixeln für Arduino
Danke und schönes WE
Ulrich Klaas
Hallo, gibt es eigentlich irgendwo eine vernünftige Übersicht was man für welches Board im Boardverwalter einstellen muss ? Bisher wurde für alle ESP32-Nodemcu Projekte hier das Board ESP32_Firebeetle angegeben. Hier jetzt für das selbe Board ESP32-DEV. Wo sind die Unterschieden in den Einstellungen ? Bei den einfachen Arduinotypen einschließlich Tinies und auch Mighty-Core (also 644 und 1284) blicke ich ja durch, Aber bei den ganzen EPSs ist das ja inflationär.
Anyone
Ein sehr schönes Projekt. Das wird umgehend nachgebastelt.