/** * The MIT License (MIT) * * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn * Copyright (c) 2018 by Fabrice Weinberg * * OLED-Library: * https://github.com/ThingPulse/esp8266-oled-ssd1306 * https://thingpulse.com * * See http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html * on how to create xbm files * Online XBM-Konverter: * https://www.online-utility.org/image/convert/to/XBM */ #include #include #include #include #include #include #include // fuer Flashen ueber WLAN ( OTA = Over The Air) #include // Only needed for Arduino 1.6.5 and earlier #include "SSD1306Wire.h" // for OLED-Display #include "images.h" // Optionally include custom images/icons SSD1306Wire display(0x3c, D6, D5); //########################################################################################### // Netzwerk-Parameter festlegen //_________________________________________________________________________________________ // Set your own !!!! network variables in this section !!! const char* OTA_host = "OLED"; //### Name for OTA-Flashing (OTA = Over the Air) const char* ssid = "xxxxxxxxxxx"; //### your WLAN SSID //### the name of your WiFi-network / <= 31 Signs const char* pwd = "xxxxxxxx"; //### your WLAN Password //### the password of your WiFi-network / >= 8 or <= 63 signs or NULL IPAddress ip(xxx, xxx, xxx, xx); //### local ip-address of Wemos D1 mini IPAddress gateway(xxx xxx, xxx, xx); //### router IPAddress subnet(255, 255, 255, 0); //### subnet-mask IPAddress dns(xxx, xxx, xxx, xxx); //### dns-server = mostly the same adress as router //_________________________________________________________________________________________ //############################################################################################ char url[255] = "http://:8087/getPlainValue/javascript.0.OLED-Display"; // Datenpunkt in ioBroker, der abgefragt werden soll //############################################################################################ char curMessage[75]; //Speicher fuer Meldungen char zeit[30]; //Speicher fuer Zeit String monat; //Speicher fuer Monatsnamen String wotag; //Speicher fuer Wochentag-Namen String payload = "Noch keine Daten vorhanden"; //Speicher fuer Meldungen String uhrzeit, wochentag, datum; int udpStatus = 0; int loopCount = 0; String valueArray[20]; int valueCount = 0; byte timeSetTryCount = 0; // NTP Parameter const int timeZone = 1; // Central European Time const int NTP_PACKET_SIZE = 48; byte packetBuffer[ NTP_PACKET_SIZE]; unsigned int localNTPport = 2390; //############################################################################# // NTP-Server fuer Internet-Zeit festlegen // verschiedene Auswahlmöglichkeiten const char* ntpServerName = "194.25.134.196"; // = ntp1.t-online.de //const char* ntpServerName = "192.53.103.108"; // = ptbtime1.ptb.de //const char* ntpServerName = "ptbtime1.ptb.de"; // = 192.53.103.108 //const char* ntpServerName = "ptbtime2.ptb.de"; //const char* ntpServerName = "ntp1.t-online.de"; // = 194.25.134.196 //############################################################################# int anzeigedauer_zeit = 4000; // Zeitanzeige auf OLED fuer 4 Sekunden int anzeigedauer_daten = 3500; // Datensatzanzeige auf OLED fuer 3,5 Sekunden int display_dimmen = 22; // Display ab 22:00 Uhr dimmen int display_aufhellen = 8; // Display ab 08:00 Uhr wieder aufhellen //############################################################################ // UDP-Parameter (nicht verändern) WiFiUDP NTPudp; int localCNTRLport = 6711; char incomingPacket[255]; WiFiUDP CNTRLudp; //_____________________________________________________________________________ String loadDataFromURL() { if (WiFi.status() == WL_CONNECTED) { HTTPClient http; http.setTimeout(3000); Serial.println("getState url: " + String(url)); http.begin(url); int httpCode = http.GET(); String payload = "error"; if (httpCode > 0) { payload = http.getString(); } if (httpCode != 200) { Serial.println("HTTP " + String(url) + " fail"); payload = " HTTP Error "; display.clear(); display.setFont(ArialMT_Plain_16); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64, 17, "HTTP Error"); display.display(); delay(2000); } http.end(); if (payload.indexOf("") > 0) { payload = payload.substring(payload.indexOf("")); payload = payload.substring(5, payload.indexOf("")); } else { payload = payload.substring(1, payload.length() - 1); } Serial.println("getState payload = " + payload); Serial.println(); return payload; } else ESP.restart(); } //_____________________________________________________________________________ bool connectWIFI(){ WiFi.config(ip, gateway, subnet, dns); delay(200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pwd); Serial.print("Connecting to "); Serial.println(ssid); display.clear(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64, 0, "Verbinde mit"); display.drawString(64, 12, "WiFi"); display.setFont(ArialMT_Plain_16); display.drawString(64, 25, ssid); display.display(); int i=0; while (WiFi.status() != WL_CONNECTED) { //while (WiFi.waitForConnectResult() != WL_CONNECTED) { int progress = (i) % 100; // draw the progress bar display.drawProgressBar(0, 54, 120, 6, progress); display.display(); delay(70); i++; Serial.print("."); } Serial.println(); Serial.println(); Serial.print("WiFi connected ---> "); Serial.print("IP: "); Serial.println(WiFi.localIP()); // see http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html // on how to create xbm files display.clear(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64, 0, "Verbunden mit"); display.drawXbm(34, 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits); display.drawString(64, 54, ssid); display.display(); delay(3000); return true; } // end of connectWIFI //_____________________________________________________________________________ time_t getNtpTime() { IPAddress ntpServerIP; while (NTPudp.parsePacket() > 0) ; WiFi.hostByName(ntpServerName, ntpServerIP); sendNTPpacket(ntpServerIP); uint32_t beginWait = millis(); while (millis() - beginWait < 1600) { int size = NTPudp.parsePacket(); if (size >= NTP_PACKET_SIZE) { NTPudp.read(packetBuffer, NTP_PACKET_SIZE); unsigned long secsSince1900; secsSince1900 = (unsigned long)packetBuffer[40] << 24; secsSince1900 |= (unsigned long)packetBuffer[41] << 16; secsSince1900 |= (unsigned long)packetBuffer[42] << 8; secsSince1900 |= (unsigned long)packetBuffer[43]; Serial.print("NTP-time was set from "); Serial.println(ntpServerName); //return secsSince1900 - 2208988800UL; return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; } } return 0; } //_____________________________________________________________________________ unsigned long sendNTPpacket(IPAddress& address) { memset(packetBuffer, 0, NTP_PACKET_SIZE); packetBuffer[0] = 0b11100011; packetBuffer[1] = 0; packetBuffer[2] = 6; packetBuffer[3] = 0xEC; packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; NTPudp.beginPacket(address, 123); NTPudp.write(packetBuffer, NTP_PACKET_SIZE); NTPudp.endPacket(); } //_____________________________________________________________________________ String calcTime(time_t t) { long weekd = t / 86400L; int day_of_the_week = (weekd+4) % 7 ; //Serial.print( "day_of_the_week: "); //Serial.println( day_of_the_week ); // Wochentag als Text if( day_of_the_week == 0 ){ wotag = "Sonntag"; } else if( day_of_the_week == 1 ){ wotag = "Montag"; } else if( day_of_the_week == 2 ){ wotag = "Dienstag"; } else if( day_of_the_week == 3 ){ wotag = "Mittwoch"; } else if( day_of_the_week == 4 ){ wotag = "Donnerstag"; } else if( day_of_the_week == 5 ){ wotag = "Freitag"; } else if( day_of_the_week == 6 ){ wotag = "Samstag"; } // Monat als Text if( month(t) == 1 ){ monat = "Jan"; } else if( month(t) == 2 ){ monat = "Feb"; } else if( month(t) == 3 ){ monat = "Mrz"; } else if( month(t) == 3 ){ monat = "Mrz"; } else if( month(t) == 4 ){ monat = "Apr"; } else if( month(t) == 5 ){ monat = "Mai"; } else if( month(t) == 6 ){ monat = "Jun"; } else if( month(t) == 7 ){ monat = "Jul"; } else if( month(t) == 8 ){ monat = "Aug"; } else if( month(t) == 9 ){ monat = "Sep"; } else if( month(t) == 10 ){ monat = "Okt"; } else if( month(t) == 11 ){ monat = "Nov"; } else if( month(t) == 12 ){ monat = "Dez"; } byte Stunde = hour(t); Stunde = (summertime(t, 0)) ? Stunde + 1 : Stunde; if (Stunde > 23) Stunde = Stunde - 24; // Zwischen 8 - 20 Uhr OLED-Diplay abdunkeln if (Stunde >= display_aufhellen && Stunde < display_dimmen){ display.setBrightness(244); } else { display.setBrightness(5); } // Serial.println( String((Stunde < 10) ? "0" : "" ) + String(Stunde) + ":" + String((minute(t) < 10) ? "0" : "" ) + String(minute(t)) + " Test " + wotag + " " + String((day(t) < 10) ? "0" : "" ) + String(day(t)) + ". " + monat + " " + String(year(t)) ); // return String((Stunde < 10) ? "0" : "" ) + String(Stunde) + ":" + String((minute(t) < 10) ? "0" : "" ) + String(minute(t)) + " " + wotag + " " + String(day(t)) + ". " + monat + " " + String(year(t)) ; uhrzeit = String((Stunde < 10) ? "0" : "" ) + String(Stunde) + ":" + String((minute(t) < 10) ? "0" : "" ) + String(minute(t)) + " Uhr"; wochentag = wotag; datum = String(day(t)) + ". " + monat + " " + String(year(t)) ; return (uhrzeit, wochentag, datum); } //_____________________________________________________________________________ boolean summertime(time_t t, byte tzHours) { if (month(t) < 3 || month(t) > 10) { Serial.println( "1 Keine Sommerzeit"); return false; // keine Sommerzeit in Jan, Feb, Nov, Dez } if (month(t) > 3 && month(t) < 10){ //Serial.println( "2 Es ist Sommerzeit"); return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep } if (month(t) == 3 && (hour(t) + 24 * day(t)) >= (1 + tzHours + 24 * (31 - (5 * year(t) / 4 + 4) % 7)) || month(t) == 10 && (hour(t) + 24 * day(t)) < (1 + tzHours + 24 * (31 - (5 * year(t) / 4 + 1) % 7))){ //Serial.println( "3 Es ist Sommerzeit"); return true; } else{ //Serial.println( "4 Keine Sommerzeit"); return false; } } //_____________________________________________________________________________ String handleUDP() { int packetSize = CNTRLudp.parsePacket(); if (packetSize) { Serial.println("Received " + String(packetSize) + " bytes from " + CNTRLudp.remoteIP().toString() + ", port " + String(CNTRLudp.remotePort())); int len = CNTRLudp.read(incomingPacket, 255); if (len > 0) incomingPacket[len] = 0; Serial.println("UDP packet contents: " + String(incomingPacket)); CNTRLudp.beginPacket(CNTRLudp.remoteIP(), CNTRLudp.remotePort()); CNTRLudp.write("OK"); CNTRLudp.endPacket(); String message = String(incomingPacket); message.trim(); return message; } else return ""; } //_____________________________________________________________________________ void startOTAhandling() { ArduinoOTA.onStart([]() { Serial.println("Start updating"); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); String Hostname = OTA_host; // OTA Name ArduinoOTA.setHostname(Hostname.c_str()); ArduinoOTA.begin(); } //_____________________________________________________________________________ void setup() { Serial.begin(115200); Serial.println(); Serial.println(); display.init(); display.flipScreenVertically(); //display.setBrightness(230); connectWIFI(); if (connectWIFI() == true) { NTPudp.begin(localNTPport); CNTRLudp.begin(localCNTRLport); setSyncProvider(getNtpTime); setSyncInterval(3600); while (timeStatus() == timeNotSet) { Serial.print("Waiting for time-set from "); Serial.println(ntpServerName); display.clear(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64, 0, "Warte auf Zeit-"); display.drawString(64, 11, "synchronistation mit:"); display.setFont(ArialMT_Plain_16); display.drawString(64, 28, "ntp1.t-online.de"); display.drawString(64, 46, ntpServerName); display.display(); delay(2000); timeSetTryCount++; Serial.println("warte auf NTP ..."); delay(2000); if (timeSetTryCount > 2) { Serial.print("NTP Fehler -> "); delay(1500); Serial.println(" ---> Reboot ..."); delay(3000); ESP.restart(); } } startOTAhandling(); } else ESP.restart(); ArduinoOTA.setHostname(OTA_host); // fuer Flashen ueber WLAN ArduinoOTA.begin(); // fuer Flashen ueber WLAN } // End of setup //_____________________________________________________________________________ void loop() { ArduinoOTA.handle(); //for OTA-Flashing // Reboot if WiFi connection was lost if (WiFi.status() != WL_CONNECTED) { ESP.restart(); } String udpMessage = handleUDP(); if (udpMessage == "update" && String(url) != "") { udpStatus = 1; Serial.println(); Serial.println("Hole Daten von URL ..."); String valueString = loadDataFromURL(); char buf[valueString.length() + 1]; valueString.toCharArray(buf, sizeof(buf)); char *p = buf; char *str; valueCount = 0; while ((str = strtok_r(p, ";", &p)) != NULL) { valueArray[valueCount] = str; valueCount++; } } if (loopCount < valueCount) { String currentValue = valueArray[loopCount] ; Serial.println(currentValue); //#### optional Anzeige des gerade laufenden Strings im seiellen Monitor ### currentValue.toCharArray(curMessage, currentValue.length() + 1); display.clear(); display.setFont(ArialMT_Plain_16); display.setTextAlignment(TEXT_ALIGN_LEFT); if(currentValue.indexOf("Post ist da") >= 0 ){ //Animiertes Brief-Icon for(int z=64; z>=22; z--){ delay(3); display.clear(); display.drawXbm(40, z, letter_width, letter_height, letter_bits); // letter-picture display.display(); } } else if(currentValue.indexOf("Service") >= 0 ){ //Animiertes Service-Meldung-Icon for(int z=64; z>=15; z--){ delay(3); display.clear(); display.drawXbm(37, z, tool_width, tool_height, tool_bits); // tool-picture display.display(); } display.drawVerticalLine(15, 25, 30); display.drawVerticalLine(112, 25, 30); display.drawHorizontalLine(15, 25, 20); display.drawHorizontalLine(92, 25, 20); display.drawHorizontalLine(15, 55, 20); display.drawHorizontalLine(92, 55, 20); display.display(); } else if(currentValue.indexOf("besetzt") >= 0 ){ //Animiertes Toiletten-Icon for(int x=-40; x<=75; x++){ delay(1); display.clear(); display.drawXbm(x, 20, toilet_width, toilet_height, toilet_bits); // toilet-picture display.display(); } } else if(currentValue.indexOf("Geburtstag") >= 0 ){ //Animiertes Kuchen-Icon for(int z=64; z>=20; z--){ delay(5); display.clear(); display.drawXbm(89, z, birthday_width, birthday_height, birthday_bits); display.display(); } } else if(currentValue.indexOf("Temperatur") >= 0 || currentValue.indexOf("temperatur") >= 0 ){ // Temperatur-Icon nur anzeigen, wenn im String "Temperatur" enthalten ist. //Serial.println("Substring Temperatur ist enthalten"); //Animiertes Temperatur-Icon for(int z=64; z>=0; z--){ delay(3); display.clear(); display.drawXbm(111, z, temperatur_width, temperatur_height, temperatur_bits); display.display(); } } else if(currentValue.indexOf("ioBroker") >= 0 ){ display.drawHorizontalLine(1, 37, 116); } else if(currentValue.indexOf("Regen") >= 0 ){ display.drawHorizontalLine(1, 18, 121); //Animiertes Rain-Icon for(int z=-33; z<=33; z++){ delay(3); display.clear(); display.drawXbm(72, z, rain_width, rain_height, rain_bits); display.display(); } } else if(currentValue.indexOf("Waschmaschine") >= 0 ){ //Animiertes Waschmaschinen-Icon for(int z=64; z>=24; z--){ delay(4); display.clear(); display.drawXbm(91, z, washer_width, washer_height, washer_bits); display.display(); } } else if(currentValue.indexOf("Fenster") >= 0 ){ //Animiertes Window-Icon for(int z=64; z>=26; z--){ delay(5); display.clear(); display.drawXbm(99, z, window_width, window_height, window_bits); display.display(); } if(currentValue.indexOf("UG EG OG") >= 0 ){ display.drawHorizontalLine(1, 18, 115); display.drawVerticalLine(33, 18, 40); display.drawVerticalLine(61, 18, 40); display.drawRect(1, 18, 92, 40); } } else if(currentValue.indexOf("Wasserverbrauch ") >= 0 ){ display.drawHorizontalLine(1, 19, 122); //Animiertes Drop-Icon for(int z=-35; z<=25; z++){ delay(3); display.clear(); display.drawXbm(96, z, drop_width, drop_height, drop_bits); display.display(); } } //Alle vorhandenen Datensaetze nacheinander anzeigen display.setFont(ArialMT_Plain_16); if(currentValue.indexOf("Gelber") >= 0 || currentValue.indexOf("Bio") >= 0 || currentValue.indexOf("Papier") >= 0 || currentValue.indexOf("Rest") >= 0 ){ //Animiertes Trash-Icon for(int x=-38; x<=90; x++){ delay(1); display.clear(); display.drawXbm(x, 10, trash_width, trash_height, trash_bits); display.display(); } display.drawStringMaxWidth(0, 0, 115, curMessage ); } // maximale Laenge begrenzen else { display.drawStringMaxWidth(0, 0, 128, curMessage ); } display.display(); delay(anzeigedauer_daten); loopCount++; } if (loopCount >= valueCount) { String Zeit = calcTime(now()); Zeit.toCharArray(zeit, 30); Serial.print(uhrzeit); Serial.print(" "); Serial.print(wochentag); Serial.print(" "); Serial.println(datum); display.clear(); display.setFont(ArialMT_Plain_24); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64, 0, uhrzeit); display.setFont(ArialMT_Plain_16); display.drawString(64, 24, wochentag); display.drawString(64, 44, datum); display.display(); delay(anzeigedauer_zeit); int i=0; if (udpStatus == 0) { char warte[40] = { "Warte auf ioBroker-Daten ..."}; Serial.println("Warte auf ioBroker-Daten ..."); display.clear(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_LEFT); display.drawXbm(32, 17, sleep_width, sleep_height, sleep_bits); // sleep-picture display.drawStringMaxWidth(10, 0, 128, "Warte auf ioBroker-Daten" ); for (i=0; i<= 100; i++){ int progress = (i) % 100; // draw the progress bar display.drawProgressBar(0, 54, 120, 6, progress); display.display(); delay(70); i++; Serial.print("."); } Serial.println(); } loopCount = 0; } } // ######## End of loop