/* Vertical Word Clock with WS2812-B LED-Stripe and NodeMCU ESP8266 WIFI, NTP Time + Timezone Shows the time every 5 miutes in words (German) and every 1 Minute additionally on 4 single LEDs Every full hour animation of all LEDs ("Cylon"-Animation from FastLed-library examples-folder) Made by joergeli 11.01.2022 http://arduino.joergeli.de Compiled with Arduino-IDE 1.8.10 */ #include // we need wifi to get internet access #include // time() ctime() #include // for flashing over WLAN ( OTA = Over The Air) #define FASTLED_ALLOW_INTERRUPTS 0 // reduces flickering #include #define LED_PIN 6 // = D6 #define LED_TYPE WS2812 #define NUM_LEDS 42 // Nr. 0-41 #define COLOR_ORDER GRB CRGB leds[NUM_LEDS]; // for WiFi Intro #define TEMPERATURE_1 Tungsten100W #define TEMPERATURE_2 OvercastSky #define DISPLAYTIME 1 #define BLACKTIME 0 // PINs single Minute-LEDs #define LED4 D8 // D8 to 4-Minute-LED #define LED3 D7 // D7 to 3-Minute-LED #define LED2 D2 // D2 to 2-Minute-LED #define LED1 D1 // D1 to 1-Minute-LED CRGB zColor[] = { CRGB::Yellow, CRGB::Red, CRGB::Blue, CRGB::Cyan, CRGB::Gold, CRGB::Magenta, CRGB::Orange, CRGB::Pink, CRGB::Purple, CRGB::Green, CRGB::SpringGreen, CRGB::Violet, CRGB::White }; CRGB farbe; int flag = 0; // changes to 1 at full hour int cylonFlag = 0; // for cancelling 5 Minutes fading //_________________________________________________________________________________________ // Set your own variables in this section !!! //######################################################################################## // set your own network parameters here !!! IPAddress ip(xxx, xxx, xxx, xxx); //### static ip-address IPAddress gateway(xxx, xxx, xxx, xxx); //### router IPAddress subnet(255, 255, 255, 0); //### subnet-mask IPAddress dns(xxx, xxx, xxx, xxx); //### dns-server = router const char* ssid = "xxxxxxxxxxx"; //### WLAN SSID const char* pwd = "xxxxxxxxxxx"; //### WLAN Password const char* OTA_host = "Vertical-Plexi-Clock"; // name of the virtual port in the Arduino-IDE // NTP-Parameter #define MY_NTP_SERVER "194.25.134.196" // = ntp1.t-online.de #define MY_TZ "CET-1CEST,M3.5.0/02,M10.5.0/03" //timezone = Europe/Berlin //Die Sommerzeitumstellung erfolgt im dritten Monat (M3), der fuenften Woche (5), am Sonntag (0) um zwei Uhr (/02). //Die Winterzeitumstellung erfolgt im 10 Monat (M10) wieder in der fuenften Woche (5) am Sonntag(0) um drei Uhr (/03). // siehe https://werner.rothschopf.net/201802_arduino_esp8266_ntp.htm //darken LEDS at night from 19:00 to 08:00 o'clock int darkenLEDs_from = 19; // 0-23 darken from 7 pm int darkenLEDs_til = 8; // 0-23 brighten from 8 am int brightness_day = 15; // 0-255 int brightness_night= 3; // 0-255 //######################################################################################## time_t now; // this is the epoch tm tm; // the structure tm holds time information in a more convient way String wochentag; int lastAktual = 0; int halb = 0; //_________________________________________________________________________________________ // subroutine for Wifi-connection void setup_wifi(){ WiFi.config(ip, gateway, subnet, dns); delay(100); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pwd); Serial.println(""); Serial.println(""); Serial.println("___________________________________________________"); Serial.print("Connecting to "); Serial.println(ssid); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(300); } // end of while Serial.println(""); Serial.print(" OK ---> "); Serial.print("IP: "); Serial.println(WiFi.localIP()); Serial.println(""); } // end of void connectWIFI //_________________________________________________________________________________________ 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(); Serial.println(); Serial.println("OTAhandling started ..."); Serial.println(); } //_____________________________________________________________________________ // Fade all LEDs down void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(220); } } //__________________________________________________________________________________________ // "Cylon"-Animation void cylon(){ //FastLED.setBrightness(100); for (int c=0; c<3; c++) { static uint8_t hue = 0; Serial.print("x"); // First slide the LEDs in one direction for(int i = 0; i < NUM_LEDS; i++) { leds[i] = CHSV(hue++, 255, 255); FastLED.show(); fadeall(); delay(9); // Wait a little bit before we loop around and do it again } Serial.print("x"); // Now go in the other direction. for(int i = (NUM_LEDS)-1; i >= 0; i--) { delay(16); leds[i] = CHSV(hue++, 255, 255); FastLED.show(); fadeall(); delay(9); // Wait a little bit before we loop around and do it again } } //end of for c FastLED.clear(); // all LEDs off FastLED.show(); } // end of cylon //__________________________________________________________________________________________ void minute_animation(){ // animation of the single minute-LEDs at every minute digitalWrite(LED1,LOW); digitalWrite(LED2,LOW); digitalWrite(LED3,LOW); digitalWrite(LED4,LOW); for ( int i =0; i < 3; i++) { delay(35); digitalWrite(LED1,HIGH); delay(35); digitalWrite(LED4,HIGH); delay(35); digitalWrite(LED1,LOW); delay(35); digitalWrite(LED4,LOW); delay(35); digitalWrite(LED2,HIGH); delay(35); digitalWrite(LED3,HIGH); delay(35); digitalWrite(LED2,LOW); delay(35); digitalWrite(LED3,LOW); } } //__________________________________________________________________________________________ void showTime() { time(&now); // read the current time localtime_r(&now, &tm); // update the structure tm with the current time /* // Only for debugging Serial.print("year:"); Serial.print(tm.tm_year + 1900); // years since 1900 Serial.print(" tmonth:"); Serial.print(tm.tm_mon + 1); // January = 0 (!) Serial.print(" tday:"); Serial.print(tm.tm_mday); // day of month Serial.print(" thour:"); Serial.print(tm.tm_hour); // hours since midnight 0-23 Serial.print(" tmin:"); Serial.print(tm.tm_min); // minutes after the hour 0-59 Serial.print(" tsec:"); Serial.print(tm.tm_sec); // seconds after the minute 0-61* Serial.print(" twday:"); Serial.print(tm.tm_wday); // days since Sunday 0-6 int tag = tm.tm_wday; if(tag == 0){wochentag = "Sontag";} else if(tag == 1){wochentag = "Montag";} else if(tag == 2){wochentag = "Dienstag";} else if(tag == 3){wochentag = "Mittwoch";} else if(tag == 4){wochentag = "Donnerstag";} else if(tag == 5){wochentag = "Freitag";} else if(tag == 6){wochentag = "Samstag";} Serial.print(" Wochentag: "); Serial.print(wochentag); if (tm.tm_isdst == 1){ // Daylight Saving Time flag Serial.print(" Sommerzeit");} else { Serial.print(" Keine Sommerzeit"); Serial.println(""); } */ } // end of showTime() //__________________________________________________________________________________________ void LED_Anzeige(){ // ############################################## // tm.tm_hour = 11; // 0-23 only for debugging // tm.tm_min = 59; // 0-59 only for debugging // tm.tm_sec = 30; // 0-59 only for debugging // tm.tm_isdst = 1; // 0/1 only for debugging // ############################################## // FastLED.clear(); // all LEDs off // FastLED.show(); int halb = 0; int stund = 0; int Stunde = tm.tm_hour; int Minute = tm.tm_min; int Sekunde = tm.tm_sec; if (Stunde > 12){ Stunde = Stunde -12; } // convert 24h to 12h if (Stunde == 0 && (Minute >= 0 && Minute <= 14) ){ Stunde = 12; } // from 0-14 minutes after midnight --> hour = 12 if (Stunde == 12 && Minute >= 15 && Minute <= 59){ Stunde = 1; } //only if Stunde == 12 and! minutes between 15-59 minutes --> hour = 1 else if (Minute >= 15 && Minute <= 59){ Stunde = Stunde + 1; } //only between 15-59 minutes --> hour = hour +1 if (Minute <= 4){ halb = 0; stund = 1; } //only between 0-4 minutes --> light up "UHR" (=o'clock) = full hour /* Serial.print("Stunde:"); Serial.print(Stunde); Serial.print("\tMinute:"); Serial.println(Minute); */ /* First initialization of LED-colors after boot, reboot and reset, because otherwise no color is defined, until next full hour is reached */ if( flag == 0) { if( Stunde == 0) {farbe = CRGB(CRGB::White);} // White if( Stunde == 1) {farbe = CRGB(CRGB::Yellow);} // Yellow if( Stunde == 2) {farbe = CRGB(CRGB::Red);} // Red if( Stunde == 3) {farbe = CRGB(CRGB::Blue);} // Blue if( Stunde == 4) {farbe = CRGB(CRGB::Cyan);} // Cyan if( Stunde == 5) {farbe = CRGB(CRGB::Magenta);} // Magenta if( Stunde == 6) {farbe = CRGB(CRGB::Green);} // Green if( Stunde == 7) {farbe = CRGB(CRGB::Purple);} // Purple if( Stunde == 8) {farbe = CRGB(CRGB::Gold);} // Gold if( Stunde == 9) {farbe = CRGB(CRGB::Blue);} // Blue if( Stunde == 10) {farbe = CRGB(CRGB::Red);} // Red if( Stunde == 11) {farbe = CRGB(CRGB::Green);} // Green if( Stunde == 12) {farbe = CRGB(CRGB::White);} // White } // end of if flag=0 // Change color of all LEDs at every full hour if( Stunde == 0 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::White);} // White if( Stunde == 1 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Yellow);} // Yellow if( Stunde == 2 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Red);} // Red if( Stunde == 3 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Blue);} // Blue if( Stunde == 4 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Cyan);} // Cyan if( Stunde == 5 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Magenta);} // Magenta if( Stunde == 6 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Green);} // Green if( Stunde == 7 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Purple);} // Purple if( Stunde == 8 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Gold);} // Gold if( Stunde == 9 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Blue);} // Blue if( Stunde == 10 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Red);} // Red if( Stunde == 11 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::Green);} // Green if( Stunde == 12 && Minute == 0 && Sekunde == 0) {flag=1; farbe = CRGB(CRGB::White);} // White // LED-Positions 0-41 //LED: 41,40 ES IST | 39,38 FUNF | 37,36 ZEHN | 35,34 DREI | 33,32 VIERTEL | 31,30 VOR | 29,28 NACH //LED: 27,26 HALB | 25,24 FUNF | 23,22 EINS | 21,20 ELF | 19,18 ZWEI | 17,16 DREI | 15,14 VIER //LED: 13,12 SECHS | 11,10 ACHT | 9,8 SIEBEN | 7,6 ZWOLF | 5,4 ZEHN | 3,2 NEUN | 1,0 UHR //minute-LEDs at LED-stripe ############################################ //ES IST / it is --> always on leds[41] = farbe; leds[40] = farbe; //FUNF NACH if (Minute >= 5 && Minute <= 9){ halb = 0; leds[39] = farbe; leds[38] = farbe; leds[29] = farbe; leds[28] = farbe; } //ZEHN NACH if (Minute >= 10 && Minute <= 14){ halb = 0; leds[37] = farbe; leds[36] = farbe; leds[29] = farbe; leds[28] = farbe; } //VIERTEL // NACH if (Minute >= 15 && Minute <= 19){ halb = 0; leds[33] = farbe; leds[32] = farbe; //leds[29] = farbe; //leds[28] = farbe; } //ZEHN VOR HALB if (Minute >= 20 && Minute <= 24){ halb = 1; leds[37] = farbe; leds[36] = farbe; leds[31] = farbe; leds[30] = farbe; } //FUNF VOR HALB if (Minute >= 25 && Minute <= 29){ halb = 1; leds[39] = farbe; leds[38] = farbe; leds[31] = farbe; leds[30] = farbe; } //HALB if (Minute >= 30 && Minute <= 34){ leds[27] = farbe; leds[26] = farbe; halb = 1; } //FUNF NACH HALB if (Minute >= 35 && Minute <= 39){ halb = 1; leds[39] = farbe; leds[38] = farbe; leds[29] = farbe; leds[28] = farbe; } //ZEHN NACH HALB if (Minute >= 40 && Minute <= 44){ halb = 1; leds[37] = farbe; leds[36] = farbe; leds[29] = farbe; leds[28] = farbe; } //DREI Viertel if (Minute >= 45 && Minute <= 49){ halb = 0; leds[35] = farbe; leds[34] = farbe; leds[33] = farbe; leds[32] = farbe; } //ZEHN VOR if (Minute >= 50 && Minute <= 54){ halb = 0; leds[37] = farbe; leds[36] = farbe; leds[31] = farbe; leds[30] = farbe; } //FUNF VOR if (Minute >= 55 && Minute <= 59){ halb = 0; leds[39] = farbe; leds[38] = farbe; leds[31] = farbe; leds[30] = farbe; } //hour-LEDs at LED-stripe ############################################ //EINS if ( Stunde == 1 ) { leds[23] = farbe; leds[22] = farbe; } //ZWEI if ( Stunde == 2 ) { leds[19] = farbe; leds[18] = farbe; } //DREI if ( Stunde == 3 ) { leds[17] = farbe; leds[16] = farbe; } //VIER if ( Stunde == 4 ) { leds[15] = farbe; leds[14] = farbe; } //FUNF if ( Stunde == 5 ) { leds[25] = farbe; leds[24] = farbe; } //SECHS if ( Stunde == 6 ) { leds[13] = farbe; leds[12] = farbe; } //SIEBEN if ( Stunde == 7 ) { leds[9] = farbe; leds[8] = farbe; } //ACHT if ( Stunde == 8 ) { leds[11] = farbe; leds[10] = farbe; } //NEUN if ( Stunde == 9 ) { leds[3] = farbe; leds[2] = farbe; } //ZEHN if ( Stunde == 10 ) { leds[5] = farbe; leds[4] = farbe; } //ELF if ( Stunde == 11 ) { leds[21] = farbe; leds[20] = farbe; } //ZWOLF if ( Stunde == 12 ) { leds[7] = farbe; leds[6] = farbe; } //################################################### // illuminate "HALB"-lettering if(halb == 1){ leds[27] = farbe; leds[26] = farbe; } else { leds[27] = CRGB( 0, 0, 0); leds[26] = CRGB( 0, 0, 0); } // illuminate "UHR"-lettering (o'clock) if(stund == 1){ leds[1] = farbe; leds[0] = farbe; } else { leds[0] = CRGB( 0, 0, 0); leds[1] = CRGB( 0, 0, 0); } FastLED.show(); // final: let the LEDs light up in the appropriate color depending on the time //################################################### // animation of the single minute-LEDs every minute if(Sekunde == 0 ){ minute_animation(); } // drive the 4 single minute-LEDS in the bottom stand if((Minute-(Minute/5)*5)==1) {digitalWrite(LED1,HIGH); digitalWrite(LED2,LOW); digitalWrite(LED3,LOW); digitalWrite(LED4,LOW); } else if((Minute-(Minute/5)*5)==2) {digitalWrite(LED1,HIGH); digitalWrite(LED2,HIGH); digitalWrite(LED3,LOW); digitalWrite(LED4,LOW); } else if((Minute-(Minute/5)*5)==3) {digitalWrite(LED1,HIGH); digitalWrite(LED2,HIGH); digitalWrite(LED3,HIGH); digitalWrite(LED4,LOW); } else if((Minute-(Minute/5)*5)==4) {digitalWrite(LED1,HIGH); digitalWrite(LED2,HIGH); digitalWrite(LED3,HIGH); digitalWrite(LED4,HIGH); } else { digitalWrite(LED1,LOW); digitalWrite(LED2,LOW); digitalWrite(LED3,LOW); digitalWrite(LED4,LOW); } /* // For debugging only int L1 = digitalRead(LED1); int L2 = digitalRead(LED2); int L3 = digitalRead(LED3); int L4 = digitalRead(LED4); Serial.print("L1: "); Serial.print(L1); Serial.print("\tL2: "); Serial.print(L2); Serial.print("\tL3: "); Serial.print(L3); Serial.print("\tL4: "); Serial.println(L4); */ } // End of void LEDS() //__________________________________________________________________________________________ void setup() //################## { configTime(MY_TZ, MY_NTP_SERVER); // --> Here is the IMPORTANT ONE LINER needed in your sketch! Serial.begin(115200); LEDS.addLeds(leds,NUM_LEDS); FastLED.setBrightness(25); // minute-LEDs pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(LED3, OUTPUT); pinMode(LED4, OUTPUT); // while not connected with WiFI all LEDs shining in red color for(int i=0; i<=NUM_LEDS-1; i++){ delay(25); leds[i] = CRGB(CRGB::Red); // brighten sequenz FastLED.show(); } setup_wifi(); // when WiFi is connected fade LEDs down and show "Cylon-anination" for(int i=NUM_LEDS-1; i>=0; i--){ // fade off fadeall(); delay(40); FastLED.show(); } cylon(); // "Cylon"-Animation startOTAhandling(); delay (100); showTime(); // Set brightness to day-/night-values if( tm.tm_hour >= darkenLEDs_til && tm.tm_hour < darkenLEDs_from){ FastLED.setBrightness(brightness_day); } else {FastLED.setBrightness(brightness_night);} LED_Anzeige(); } // end of setup //__________________________________________________________________________________________ void loop() { //################## ArduinoOTA.handle(); //for OTA-flashing showTime(); int Aktual = tm.tm_min ; int sek = tm.tm_sec; // Show "Cylon"-Animation at full hour if(tm.tm_min == 0 && tm.tm_sec == 0 ){ //if(tm.tm_min == 5 && tm.tm_sec == 0 ){ // only for testing cylonFlag = 1; // Set other brightness-values only while "Cylon-Animation" is running if( tm.tm_hour >= darkenLEDs_til && tm.tm_hour < darkenLEDs_from){ FastLED.setBrightness(45); } else {FastLED.setBrightness(10);} cylon(); FastLED.clear(); // all LEDs off FastLED.show(); // Reset brightness to day-/night-values if( tm.tm_hour >= darkenLEDs_til && tm.tm_hour < darkenLEDs_from){ FastLED.setBrightness(brightness_day); } else {FastLED.setBrightness(brightness_night);} LED_Anzeige(); } //----------------------------------------------------------------- // update the LED-Stripe only when the minute changes - reduces flickering if (Aktual != lastAktual ) { lastAktual= Aktual; if( tm.tm_hour >= darkenLEDs_til && tm.tm_hour < darkenLEDs_from ){ FastLED.setBrightness(brightness_day); } else {FastLED.setBrightness(brightness_night);} if (Aktual % 5 != 0){ LED_Anzeige(); Serial.println("LEDs refreshed"); } } //-------------------------------- // Fading only every 5th minute, but not! when "Cylon"-Animation has run before if (Aktual % 5 == 0 && sek == 0 && cylonFlag == 0 ){ lastAktual= Aktual; // fade down for(int i = 0; i < NUM_LEDS; i++) { fadeall(); FastLED.show(); delay(40); } // only set brightness to 0 at day if( tm.tm_hour >= darkenLEDs_til && tm.tm_hour < darkenLEDs_from){ FastLED.setBrightness(0);} // day else {FastLED.setBrightness(brightness_night);} // night FastLED.show(); // brighten LEDs at day if( tm.tm_hour >= darkenLEDs_til && tm.tm_hour < darkenLEDs_from){ LED_Anzeige(); //FastLED.setBrightness(brightness_day); for(int i=0; i<= brightness_day; i++){ FastLED.setBrightness(i); FastLED.show(); delay(120); } } // darken LEDs at night else { FastLED.setBrightness(brightness_night); LED_Anzeige(); /* for(int i=0; i<= brightness_night; i++){ FastLED.setBrightness(i); FastLED.show(); delay(40); } */ } Serial.println("LEDs refreshed with fading"); } //end of Aktual % 5 //----------------------------------------------------------------- if (cylonFlag == 1 ){ cylonFlag = 0; } } // end of loop //__________________________________________________________________________________________