4,2″ Smarthome- und Wetterdisplay
Ich möchte ein kleines Display im Bad haben bei dem ich morgens und abends einen kleinen Überblick übers Wetter bekomme.
Aufgaben
- Hauptsächliche Datenquelle sollten meine Sensoren sein
- Als Alternative dann Wetteranbieter (Openweathermap)
- Anzeige von
- Temperatur und Luftfeuchte Außen
- Sonnenaufgang/-untergang
- Prognose Heute und Morgen
- Min/Max Temperatur
- Regenwahrscheinlichkeit und Menge
- UV-Index (eigentlich wollte ich Sonnenscheindauer, gab es aber leider nicht)
- Raumtemperaturen
- (aus aktuellem Anlass: Strom und Gaskosten des gestrigen und heutigen Tages)
Ich hole alle Daten aus der openHAB-API, auch wenn diese aus einer weiteren Quelle kommen. Dann habe ich aber eine einheitliche Schnittstelle und kann (ohne das Display noch mal auseinander zu nehmen und ein neues Programm zu flashen).
Das ist dabei heraus gekommen:
Material
4.2inch E-Paper Display Module * Affiliatelink
EEMB 3.7V 2000mAh Lipo Batterie * Affiliatelink
ANKKY Pin Header 2.54mm * Affiliatelink
PremiumCord USB-C zu Micro-USB-Adapter * Affiliatelink
LOLIN32 Lite Board * Affiliatelink
Jumper Wire Kabel * Affiliatelink
Anschlüsse
Ich habe an den Lötanschluss des E-Paper-Display sowie des LOLIN32-Boards Winkelstecker (Pin Header) angelötet um flacher zu werden und gleichzeitig noch ein bisschen Flexibilität zu haben falls ich das Board mal austauschen möchte. Man kann aber natürlich auch direkt auf die Platine löten.
Ich beziehe mich hier auf die Beschriftungen auf dem Board selber. Nutzt ihr ein anderes müsst ihr das vermutlich anpassen.
LOLIN32 Board | E-Paper-Display |
---|---|
4/R10 | BUSY |
16 | RST |
17 | DC |
5 | CS |
18 | CLK |
23 | DIN |
GND | GND |
3,3V | VCC |
Wichtig!
Der Akku ist (mit ziemlicher Sicherheit) „falsch“ gepolt wenn man den Stecker einstecken würde!
Das muss vor dem Einstecken geprüft und ggf. (durch umpinnen am Stecker) geändert werden!
Programmierung
Arduino
Das Programm basiert grundsätzlich auf Version 12.5 des unten verlinkten Projekts. Allerdings hole ich mir die Daten aus der openHAB-API mit folgendem Befehl:
Temp_Aussen = fetchopenHAB("http://IP:8080/rest/items/Display_Terrasse_Temperatur/state");
// usw ...
String fetchopenHAB(String url) {
String serverPath = url;
String payload = "";
// Your Domain name with URL path or IP address with path
http.begin(serverPath.c_str());
// Send HTTP GET request
int httpResponseCode = http.GET();
if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
Serial.println(payload);
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
return payload;
}
Die Daten zeige ich dann im „DisplayWeather“ wie folgt an:
// Header
u8g2Fonts.setFont(u8g2_font_helvB08_tf);
drawString(SCREEN_WIDTH / 2, 0, City, CENTER);
drawString(SCREEN_WIDTH, 0, date_str, RIGHT);
drawString(4, 0, time_str, LEFT);
display.drawLine(0, 12, SCREEN_WIDTH, 12, GxEPD_BLACK);
DrawBattery(65, 12);
// Außentemperatur
int x = 1;
int y = 15;
display.drawRect(x, y, 195, 100, GxEPD_BLACK);
u8g2Fonts.setFont(u8g2_font_helvB12_tf);
drawString(x + 8, y + 7, "Aussen", LEFT);
u8g2Fonts.setFont(u8g2_font_helvB18_tf);
drawString(x + 14, y + 37, Temp_Aussen + "°C", LEFT);
drawString(x + 114, y + 37, Feuchte_Aussen + "%", LEFT);
// Strom/Gasverbrauch
x = 1;
y = 60;
u8g2Fonts.setFont(u8g2_font_helvB12_tf);
drawString(x + 14, y + 12, Verbrauch_Oben, LEFT);
drawString(x + 14, y + 35, Verbrauch_Unten, LEFT);
// Sonnenauf-/untergang Mondphase
x = 198;
y = 15;
display.drawRect(x, y, 195, 100, GxEPD_BLACK);
u8g2Fonts.setFont(u8g2_font_helvB10_tf);
drawString(x + 9, y + 15, Sonnenaufgang + " " + TXT_SUNRISE, LEFT);
drawString(x + 9, y + 35, Sonnenuntergang + " " + TXT_SUNSET, LEFT);
time_t now = time(NULL);
struct tm * now_utc = gmtime(&now);
const int day_utc = now_utc->tm_mday;
const int month_utc = now_utc->tm_mon + 1;
const int year_utc = now_utc->tm_year + 1900;
drawString(x + 9, y + 55, MoonPhase(day_utc, month_utc, year_utc), LEFT);
DrawMoon(x + 125, y + 30, day_utc, month_utc, year_utc, Hemisphere);
// Min/Max + Icon Heute
x = 1;
y = 120;
display.drawRect(x, y, 95, 170, GxEPD_BLACK);
u8g2Fonts.setFont(u8g2_font_helvB12_tf);
drawString(x + 24, y + 10, "Heute", LEFT);
u8g2Fonts.setFont(u8g2_font_helvB10_tf);
drawString(x + 24, y + 55, "Max", LEFT);
drawString(x + 24, y + 100, "Min", LEFT);
u8g2Fonts.setFont(u8g2_font_helvB14_tf);
drawString(x + 14, y + 40, Temp_Heute_Max + "°C", LEFT);
drawString(x + 14, y + 86, Temp_Heute_Min + "°C", LEFT);
u8g2Fonts.setFont(u8g2_font_helvB08_tf);
drawString(x + 14, y + 120, Regenwahrscheinlichkeit_Heute + " (" + Regen_Heute + ")", LEFT);
drawString(x + 14, y + 140, "UV: " + UV_Index_Heute, LEFT);
u8g2Fonts.setFont(u8g2_font_helvB08_tf);
if (UV_Index_Heute.toInt() < 3) {
drawString(x + 14, y + 150, "niedrig", LEFT);
} else if (UV_Index_Heute.toInt() < 6) {
drawString(x + 14, y + 150, "mäßig", LEFT);
} else if (UV_Index_Heute.toInt() < 8) {
drawString(x + 14, y + 150, "hoch", LEFT);
} else if (UV_Index_Heute.toInt() < 11) {
drawString(x + 14, y + 150, "sehr hoch", LEFT);
} else {
drawString(x + 14, y + 150, "extrem", LEFT);
}
// Min/Max + Icon Morgen
x = 100;
y = 120;
display.drawRect(x, y, 95, 170, GxEPD_BLACK);
u8g2Fonts.setFont(u8g2_font_helvB12_tf);
drawString(x + 20, y + 10, "Morgen", LEFT);
u8g2Fonts.setFont(u8g2_font_helvB10_tf);
drawString(x + 24, y + 55, "Max", LEFT);
drawString(x + 24, y + 100, "Min", LEFT);
u8g2Fonts.setFont(u8g2_font_helvB14_tf);
drawString(x + 14, y + 40, Temp_Morgen_Max + "°C", LEFT);
drawString(x + 14, y + 86, Temp_Morgen_Min + "°C", LEFT);
u8g2Fonts.setFont(u8g2_font_helvB08_tf);
drawString(x + 14, y + 120, Regenwahrscheinlichkeit_Morgen + " (" + Regen_Morgen + ")", LEFT);
drawString(x + 14, y + 140, "UV: " + UV_Index_Morgen, LEFT);
u8g2Fonts.setFont(u8g2_font_helvB08_tf);
if (UV_Index_Morgen.toInt() < 3) {
drawString(x + 14, y + 150, "niedrig", LEFT);
} else if (UV_Index_Morgen.toInt() < 6) {
drawString(x + 14, y + 150, "mäßig", LEFT);
} else if (UV_Index_Morgen.toInt() < 8) {
drawString(x + 14, y + 150, "hoch", LEFT);
} else if (UV_Index_Morgen.toInt() < 11) {
drawString(x + 14, y + 150, "sehr hoch", LEFT);
} else {
drawString(x + 14, y + 150, "extrem", LEFT);
}
// Temperatur Räume
x = 198;
y = 120;
display.drawRect(x, y, 195, 170, GxEPD_BLACK);
u8g2Fonts.setFont(u8g2_font_helvB12_tf);
drawString(x + 10, y + 15, "Bad", LEFT);
drawString(x + 10, y + 40, "Kinderzimmer", LEFT);
drawString(x + 10, y + 65, "Wohnzimmer", LEFT);
drawString(x + 10, y + 90, "Bad Dach", LEFT);
drawString(x + 10, y + 115, "Keller", LEFT);
drawString(x + 130, y + 15, Temp_Badezimmer + "°C", LEFT);
drawString(x + 130, y + 40, Temp_Kinderzimmer + "°C", LEFT);
drawString(x + 130, y + 65, Temp_Wohnzimmer + "°C", LEFT);
drawString(x + 130, y + 90, Temp_BadJoshua + "°C", LEFT);
drawString(x + 130, y + 115, Temp_Keller + "°C", LEFT);
// display.drawLine(0, 12, SCREEN_WIDTH, 12, GxEPD_BLACK);
Wie man sieht hab ich x und y immer an jedem Block neu definiert und bin von dort aus relativ dazu weitergegangen.
Gehäuse
Ich habe mir ein Gehäuse gezeichnet und auf meinem 3D-Drucker gedruckt. Da sich das Projekt über lange Zeit hingezogen hat ist das ein bisschen gebastelt. Eigentlich sollte das ein Gehäuse werden, bei dem Vorder- und Rückseite ineinander einrasten oder verschraubt werden oder so. Durch ein paar kleine Fehler muss es halt auf dem Fuß stehen und einen Hut haben damit es hält und vernünftig aussieht. Ich find’s aber gar nicht so schlecht 🙂
Das Innenmaß vom Gehäuseboden ist 79,5mm, es passen also vermutlich auch größere (bzw. längere) Akkus in das Gehäuse wenn man etwas mehr Kapazität benötigt.
Um den Akku zu laden ohne alles auseinander zu bauen habe ich den Micro-USB auf USB-C-Adapter verwendet der dann rechts bündig mit dem Gehäuse abschließt (im Bild links zu sehen). Außerdem ist ein kleiner Steg hinter dem ESP damit man diesen beim einstecken nicht durchschiebt und die Buchse verschwindet.
https://www.printables.com/de/model/281765-42inch-weatherdisplay-for-smarthome
Daten
Die Daten für das Display hole ich per Rest-API aus openHAB wo ich diese Daten vorab bearbeite um das aussehen (Dezimalstellen, etc.) einfacher ändern zu können. Ich generiere die Daten einfach jede Minute und frage diese alle 30 Minuten ab.
Ausblick/Updates
Ich würde gerne noch einen Knopf zum manuellen Aktualisieren der Daten hinzufügen.
Quellen
Ich habe mir dazu nicht alles selber ausgedacht sondern auf einige Quellen zurückgegriffen denen ich hier explizit danken will:
Schreibe einen Kommentar