diff --git a/README.md b/README.md index 0e2b110..8163288 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,61 @@ # Wordclock 2.0 ![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=main) -Wordclock 2.0 with ESP8266 and NTP time. +A modern Wi-Fi Word Clock powered by the ESP8266 and synchronized via NTP (Network Time Protocol). +Displays time in words with support for multiple languages and colorful NeoPixel LED effects. +Additional gaming modes, such as PONG, SNAKE, and TETRIS, can be played via an interactive Web UI. -More details on my website: https://techniccontroller.com/word-clock-with-wifi-and-neopixel/ +**Project Details and Guide:** -**Languages** +Full tutorial and build instructions on https://techniccontroller.com/word-clock-with-wifi-and-neopixel/ -The Wordclock is available in **German**, **English**, **Italian**, **French** and **Javanese** language. By default the language is German. -To use other languages like English or Italian please replace the file *wordclockfunctions.ino* with *wordclockfunctions.ino_english* or *wordclockfunctions.ino_italian*. -The code compiles only with one file named *wordclockfunctions.ino*. So please rename the file you want to use to *wordclockfunctions.ino* and replace the existing file. +## Features +- 6 modes + - Word Clock + - Digital Clock + - SPIRAL animation + - TETRIS (playable via web interface) + - SNAKE (playable via web interface) + - PONG (playable via web interface) +- Interactive Web-Based Games: Control PONG, TETRIS, and SNAKE directly through the built-in web UI +- Real-time clock synchronized over Wi-Fi using NTP +- Automatic daylight saving time (summer/winter) switching +- Automatic timezone detection +- Easy Wi-Fi setup with WiFiManager +- Configurable color themes +- Customizable night mode (start/end time) +- Adjustable brightness settings +- Automatic mode rotation +- Web interface for configuration and control +- Physical button for quick mode change or night mode toggle +- Intelligent current limiting of LEDs +- Dynamic color shifting mode + +## Supported Languages + +The WordClock currently supports the following languages: +- **German (default)** +- **English** +- **Italian** +- **French** +- **Swiss German** +- **Javanese** + +**How to Change the Language** + +To switch to another language: +1. Go to the `wordclockfunctions.ino_` file (e.g., `wordclockfunctions.ino_english`) +2. Rename it to `wordclockfunctions.ino` +3. Replace the existing `wordclockfunctions.ino` file +4. Compile and upload the code to your ESP8266 + +Only one language file should be named wordclockfunctions.ino at any time for successful compilation. Thank you to everyone who provided feedback on adding new languages and testing their accuracy — your efforts have been invaluable in making this project truly inclusive and reliable! -**Special Branches** - -We've got some interesting branches in this repo inspired by user feedback. These branches explore unique features and experimental ideas. Some will stay updated with the main branch's features. - -- [**hour_animation**](https://github.com/techniccontroller/wordclock_esp8266/tree/hour_animation): This branch replaces the spiral animation with some custom pattern animation defined as x/y coordinate pattern including custom color for each letter. Also, this animation is show ones per hour. -![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=hour_animation) -- [**mode_seconds**](https://github.com/techniccontroller/wordclock_esp8266/tree/mode_seconds): This branch adds one additional mode to show the seconds as numbers on the clock. Thanks to [@Bram](https://github.com/BramWerbrouck) -![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=mode_seconds) -- [**rgbw_leds**](https://github.com/techniccontroller/wordclock_esp8266/tree/rgbw_leds): This branch uses RGBW LEDs instead of RGB LEDs. -![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=rgbw_leds) -- [**static_background_pattern**](https://github.com/techniccontroller/wordclock_esp8266/tree/static_background_pattern): This branch allows to light up specific letters always during clock mode. E.G., to display some special words in another color. -![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=static_background_pattern) - -## Features -- 6 modes (Clock, Digital Clock, SPIRAL animation, TETRIS, SNAKE, PONG) -- time update via NTP server -- automatic summer/wintertime change -- automatic timezone selection -- easy WIFI setup with WifiManager -- configurable color -- configurable night mode (start and end time) -- configurable brightness -- automatic mode change -- webserver interface for configuration and control -- physical button to change mode or enable night mode without webserver -- automatic current limiting of LEDs -- dynamic color shift mode - ## Pictures of clock ![modes_images2](https://user-images.githubusercontent.com/36072504/156947689-dd90874d-a887-4254-bede-4947152d85c1.png) @@ -68,6 +80,19 @@ We've got some interesting branches in this repo inspired by user feedback. Thes +## Special Branches + +We've got some interesting branches in this repo inspired by user feedback. These branches explore unique features and experimental ideas. Some will stay updated with the main branch's features. + +- [**hour_animation**](https://github.com/techniccontroller/wordclock_esp8266/tree/hour_animation): This branch replaces the spiral animation with some custom pattern animation defined as x/y coordinate pattern including custom color for each letter. Also, this animation is show ones per hour. +![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=hour_animation) +- [**mode_seconds**](https://github.com/techniccontroller/wordclock_esp8266/tree/mode_seconds): This branch adds one additional mode to show the seconds as numbers on the clock. Thanks to [@Bram](https://github.com/BramWerbrouck) +![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=mode_seconds) +- [**rgbw_leds**](https://github.com/techniccontroller/wordclock_esp8266/tree/rgbw_leds): This branch uses RGBW LEDs instead of RGB LEDs. +![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=rgbw_leds) +- [**static_background_pattern**](https://github.com/techniccontroller/wordclock_esp8266/tree/static_background_pattern): This branch allows to light up specific letters always during clock mode. E.G., to display some special words in another color. +![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=static_background_pattern) + ## Install needed Libraries Please download all these libraries as ZIP from GitHub, and extract them in the *libraries* folder of your Sketchbook location (see **File -> Preferences**): diff --git a/wordclock_esp8266.ino b/wordclock_esp8266.ino index f0e6e44..e28371d 100644 --- a/wordclock_esp8266.ino +++ b/wordclock_esp8266.ino @@ -252,6 +252,10 @@ void setup() { // set a custom hostname wifiManager.setHostname(hostname); + + // set timeout of config portal to 10min, continue even if not connected, + // clock will show wrong time, but eventually restart after watchdog counter is 0 (after ~5min) + wifiManager.setConfigPortalTimeout(600); // fetches ssid and pass from eeprom and tries to connect // if it does not connect it starts an access point with the specified name diff --git a/wordclockfunctions.ino_italian b/wordclockfunctions.ino_italian index a1f0f47..a960a82 100644 --- a/wordclockfunctions.ino_italian +++ b/wordclockfunctions.ino_italian @@ -114,11 +114,7 @@ String timeToString(uint8_t hours,uint8_t minutes){ } //SONO LE - if(hours == 1 && minutes < 35) - { - message += "= # "; //E' L' -> = is for E' and # is for L' - } - else if (hours == 0 && minutes >= 35) + if(hours == 1) { message += "= # "; //E' L' -> = is for E' and # is for L' } diff --git a/wordclockfunctions.ino_swiss b/wordclockfunctions.ino_swiss new file mode 100644 index 0000000..7ec5f2c --- /dev/null +++ b/wordclockfunctions.ino_swiss @@ -0,0 +1,225 @@ +// Thanks to Sandro for providing this swiss german version +const String clockStringSwiss = "ESPESCHAFUFVIERTUBFZAAZWANZGSIVORABOHWORTUHRHAUBIANESSIEISZWOISDRUVIERIYFUFIOSACHSISEBNIACHTINUNIELZANIERBEUFIZWOUFINAGSI"; + +/** + * @brief control the four minute indicator LEDs + * + * @param minutes minutes to be displayed [0 ... 59] + * @param color 24bit color value + */ +void drawMinuteIndicator(uint8_t minutes, uint32_t color){ + //separate LEDs for minutes in an additional row + { + switch (minutes%5) + { + case 0: + break; + + case 1: + ledmatrix.setMinIndicator(0b1000, color); + break; + + case 2: + ledmatrix.setMinIndicator(0b1100, color); + break; + + case 3: + ledmatrix.setMinIndicator(0b1110, color); + break; + + case 4: + ledmatrix.setMinIndicator(0b1111, color); + break; + } + } +} + +/** + * @brief Draw the given sentence to the word clock + * + * @param message sentence to be displayed + * @param color 24bit color value + * @return int: 0 if successful, -1 if sentence not possible to display + */ +int showStringOnClock(String message, uint32_t color){ + String word = ""; + int lastLetterClock = 0; + int positionOfWord = 0; + int index = 0; + + // add space on the end of message for splitting + message = message + " "; + + // empty the targetgrid + ledmatrix.gridFlush(); + + while(true){ + // extract next word from message + word = split(message, ' ', index); + index++; + + if(word.length() > 0){ + // find word in clock string + positionOfWord = clockStringSwiss.indexOf(word, lastLetterClock); + + if(positionOfWord >= 0){ + // word found on clock -> enable leds in targetgrid + for(unsigned int i = 0; i < word.length(); i++){ + int x = (positionOfWord + i)%WIDTH; + int y = (positionOfWord + i)/WIDTH; + ledmatrix.gridAddPixel(x, y, color); + } + // remember end of the word on clock + lastLetterClock = positionOfWord + word.length(); + } + else{ + // word is not possible to show on clock + logger.logString("word is not possible to show on clock: " + String(word)); + return -1; + } + }else{ + // end - no more word in message + break; + } + } + // return success + return 0; +} + +/** + * @brief Converts the given time as sentence (String) + * + * @param hours hours of the time value + * @param minutes minutes of the time value + * @return String time as sentence + */ +String timeToString(uint8_t hours, uint8_t minutes, bool puristModeActive){ + + //ES IST + String message = ""; + + if(puristModeActive){ + message = ""; + if(minutes < 5 || (minutes >=30 && minutes < 35)){ + message = "ES ESCH "; + } + } + else{ + message = "ES ESCH "; + } + + //show minutes + if(minutes >= 5 && minutes < 10) + { + message += "FUF AB "; + } + else if(minutes >= 10 && minutes < 15) + { + message += "ZAA AB "; + } + else if(minutes >= 15 && minutes < 20) + { + message += "VIERTU AB "; + } + else if(minutes >= 20 && minutes < 25) + { + message += "ZWANZG AB "; //Sandro + } + else if(minutes >= 25 && minutes < 30) + { + message += "FUF VOR HAUBI "; + } + else if(minutes >= 30 && minutes < 35) + { + message += "HAUBI "; + } + else if(minutes >= 35 && minutes < 40) + { + message += "FUF AB HAUBI "; + } + else if(minutes >= 40 && minutes < 45) + { + message += "ZWANZG VOR "; //Sandro + } + else if(minutes >= 45 && minutes < 50) + { + message += "VIERTU VOR "; + } + else if(minutes >= 50 && minutes < 55) + { + message += "ZAA VOR "; + } + else if(minutes >= 55 && minutes < 60) + { + message += "FUF VOR "; + } + + //convert hours to 12h format + if(hours >= 12) + { + hours -= 12; + } + if(minutes >= 25) //Sandro 20 + { + hours++; + } + if(hours == 12) + { + hours = 0; + } + + // show hours + switch(hours) + { + case 0: + message += "ZWOUFI "; + break; + case 1: + message += "EIS "; + // //EIN(S) + // if(minutes > 4){ // Sandro + // message += "S"; + // } + // message += " "; + break; + case 2: + message += "ZWOI "; + break; + case 3: + message += "DRU "; + break; + case 4: + message += "VIERI "; + break; + case 5: + message += "FUFI "; + break; + case 6: + message += "SACHSI "; + break; + case 7: + message += "SEBNI "; + break; + case 8: + message += "ACHTI "; + break; + case 9: + message += "NUNI "; + break; + case 10: + message += "ZANI "; + break; + case 11: + message += "EUFI "; + break; + } + if(minutes < 5) + { + message += "GSI "; + } + + logger.logString("time as String: " + String(message)); + + return message; +} +