Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 61 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,60 @@
# 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:**

Full tutorial and build instructions on https://techniccontroller.com/word-clock-with-wifi-and-neopixel/

**Languages**

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_<language>` 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)

Expand All @@ -68,6 +79,21 @@ We've got some interesting branches in this repo inspired by user feedback. Thes

<img src="https://techniccontroller.com/wp-content/uploads/filemanager1-1.png" height="300px" /> <img src="https://techniccontroller.com/wp-content/uploads/filemanager2-1.png" height="300px" /> <img src="https://techniccontroller.com/wp-content/uploads/filemanager3-1.png" height="300px" />

## 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)
- [**frame_light**](https://github.com/techniccontroller/wordclock_esp8266/tree/frame_light): This branch allows to add an additional LEDs around the clock, as background/frame light it has the same color as the clock. Thanks to Sandro for the idea.
![compile esp8266 workflow](https://github.com/techniccontroller/wordclock_esp8266/actions/workflows/compile_esp8266.yml/badge.svg?branch=frame_light)

## 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**):
Expand Down
121 changes: 82 additions & 39 deletions wordclock_esp8266.ino
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,46 @@
// CONSTANTS
// ----------------------------------------------------------------------------------

#define EEPROM_SIZE 30 // size of EEPROM to save persistent variables
#define ADR_NM_START_H 0
#define ADR_NM_END_H 1
#define ADR_NM_START_M 2
#define ADR_NM_END_M 3
#define ADR_BRIGHTNESS 4
#define ADR_MC_RED 5
#define ADR_MC_GREEN 6
#define ADR_MC_BLUE 7
#define ADR_PURIST_MODE_ACTIVE 8
#define ADR_STATICBACKGROUND 9
#define ADR_BRIGHTNESS_FRAME 10
#define ADR_FRAMELIGHTACTIVE 11
#define ADR_FRAMELIGHTSECONDSACTIVE 12
#define ADR_FRAMELIGHTSECONDSSINGLE 13
#define ADR_FRAMELIGHTSECONDSINCDECCYCLE 14
#define ADR_STATICBACKGROUND2 15
#define ADR_STATE 26
#define ADR_NM_ACTIVATED 27
#define ADR_COLSHIFTSPEED 28
#define ADR_COLSHIFTACTIVE 29

#define EEPROM_VERSION_CODE 2 // Change this value when defaults settings change

// EEPROM address map (all uint8_t, 1 byte each)
#define EEPROM_SIZE 25 // size of EEPROM to save persistent variables
#define ADR_EEPROM_VERSION 0 // uint8_t
#define ADR_NM_START_H 1 // uint8_t
#define ADR_NM_END_H 2 // uint8_t
#define ADR_NM_START_M 3 // uint8_t
#define ADR_NM_END_M 4 // uint8_t
#define ADR_BRIGHTNESS 5 // uint8_t
#define ADR_MC_RED 6 // uint8_t
#define ADR_MC_GREEN 7 // uint8_t
#define ADR_MC_BLUE 8 // uint8_t
#define ADR_STATE 9 // uint8_t
#define ADR_NM_ACTIVATED 10 // uint8_t
#define ADR_COLSHIFTSPEED 11 // uint8_t
#define ADR_COLSHIFTACTIVE 12 // uint8_t
#define ADR_PURIST_MODE_ACTIVE 13 // uint8_t
#define ADR_STATICBACKGROUND 14 // uint8_t
#define ADR_BRIGHTNESS_FRAME 15 // uint8_t
#define ADR_FRAMELIGHTACTIVE 16 // uint8_t
#define ADR_FRAMELIGHTSECONDSACTIVE 17 // uint8_t
#define ADR_FRAMELIGHTSECONDSSINGLE 18 // uint8_t
#define ADR_FRAMELIGHTSECONDSINCDECCYCLE 19 // uint8_t
#define ADR_STATICBACKGROUND2 20 // uint8_t

// DEFAULT SETTINGS (if one changes this, also increment the EEPROM_VERSION_CODE, to ensure that the EEPROM is updated with the new defaults)
#define DEFAULT_NM_START_HOUR 22 // default start hour of nightmode (0-23)
#define DEFAULT_NM_START_MIN 5 // default start minute of nightmode (0-59)
#define DEFAULT_NM_END_HOUR 7 // default end hour of nightmode (0-23)
#define DEFAULT_NM_END_MIN 0 // default end minute of nightmode (0-59)
#define DEFAULT_BRIGHTNESS 40 // default brightness of LEDs (0-255)
#define DEFAULT_MC_RED 200 // default main color red value
#define DEFAULT_MC_GREEN 200 // default main color green value
#define DEFAULT_MC_BLUE 0 // default main color blue value
#define DEFAULT_NM_ACTIVATED 1 // if function nightmode is activated (0 = deactivated, 1 = activated)
#define DEFAULT_COLSHIFT_SPEED 1 // needs to be between larger than 0 (1 = slowest, 255 = fastest)
#define DEFAULT_COLSHIFT_ACTIVE 0 // if dynamic color shift is active (0 = deactivated, 1 = activated)
#define DEFAULT_BRIGHTNESSFRAME 40 // default brightness of Frame LEDs (0-255)


#define NEOPIXELPIN 5 // pin to which the NeoPixels are attached
Expand Down Expand Up @@ -170,8 +189,10 @@ const uint32_t colors24bit[NUM_COLORS] = {
LEDMatrix::Color24bit(0, 128, 0),
LEDMatrix::Color24bit(0, 0, 255) };

uint8_t brightness = 40; // current brightness of leds
uint8_t brightnessFrame = 40; // brightness of leds for frame light

uint8_t brightness = DEFAULT_BRIGHTNESS; // current brightness of leds
uint8_t brightnessFrame = DEFAULT_BRIGHTNESSFRAME; // current brightness of frame leds

bool sprialDir = false;

// timestamp variables
Expand All @@ -195,18 +216,18 @@ Tetris mytetris = Tetris(&ledmatrix, &logger);
Snake mysnake = Snake(&ledmatrix, &logger);
Pong mypong = Pong(&ledmatrix, &logger);

float filterFactor = DEFAULT_SMOOTHING_FACTOR;// stores smoothing factor for led transition
uint8_t currentState = st_clock; // stores current state
bool stateAutoChange = false; // stores state of automatic state change
bool nightMode = false; // stores state of nightmode
bool nightModeActivated = true; // stores if the function nightmode is activated (its not the state of nightmode)
bool ledOff = false; // stores state of led off
uint32_t maincolor_clock = colors24bit[2]; // color of the clock and digital clock
uint32_t maincolor_snake = colors24bit[1]; // color of the random snake animation
bool apmode = false; // stores if WiFi AP mode is active
bool dynColorShiftActive = false; // stores if dynamic color shift is active
uint8_t dynColorShiftPhase = 0; // stores the phase of the dynamic color shift
uint8_t dynColorShiftSpeed = 1; // stores the speed of the dynamic color shift -> used to calc update period
float filterFactor = DEFAULT_SMOOTHING_FACTOR; // stores smoothing factor for led transition
uint8_t currentState = st_clock; // stores current state
bool stateAutoChange = false; // stores state of automatic state change
bool nightMode = false; // stores state of nightmode
bool nightModeActivated = DEFAULT_NM_ACTIVATED; // stores if the function nightmode is activated (its not the state of nightmode)
bool ledOff = false; // stores state of led off
uint32_t maincolor_clock = colors24bit[2]; // color of the clock and digital clock
uint32_t maincolor_snake = colors24bit[1]; // color of the random snake animation
bool apmode = false; // stores if WiFi AP mode is active
bool dynColorShiftActive = DEFAULT_COLSHIFT_ACTIVE; // stores if dynamic color shift is active
uint8_t dynColorShiftPhase = 0; // stores the phase of the dynamic color shift
uint8_t dynColorShiftSpeed = DEFAULT_COLSHIFT_SPEED; // stores the speed of the dynamic color shift -> used to calc update period
bool puristModeActive = false; // stores if purist mode is active
bool staticBackgroundActive = false; // stores if static background is active
bool staticBackground2Active = false; // stores if static background is active
Expand All @@ -217,10 +238,10 @@ bool frameSecondsIncDecCycle = false; // stores if frame light should be


// nightmode settings
uint8_t nightModeStartHour = 22;
uint8_t nightModeStartMin = 0;
uint8_t nightModeEndHour = 7;
uint8_t nightModeEndMin = 0;
uint8_t nightModeStartHour = DEFAULT_NM_START_HOUR;
uint8_t nightModeStartMin = DEFAULT_NM_START_MIN;
uint8_t nightModeEndHour = DEFAULT_NM_END_HOUR;
uint8_t nightModeEndMin = DEFAULT_NM_END_MIN;

// Watchdog counter to trigger restart if NTP update was not possible 30 times in a row (5min)
int watchdogCounter = 30;
Expand All @@ -242,6 +263,24 @@ void setup() {
//Init EEPROM
EEPROM.begin(EEPROM_SIZE);

// Check EEPROM version code
uint8_t storedVersion = EEPROM.read(ADR_EEPROM_VERSION);
if (storedVersion != EEPROM_VERSION_CODE) {
// Set new defaults
EEPROM.write(ADR_EEPROM_VERSION, EEPROM_VERSION_CODE);
EEPROM.write(ADR_NM_START_H, DEFAULT_NM_START_HOUR);
EEPROM.write(ADR_NM_START_M, DEFAULT_NM_START_MIN);
EEPROM.write(ADR_NM_END_H, DEFAULT_NM_END_HOUR);
EEPROM.write(ADR_NM_END_M, DEFAULT_NM_END_MIN);
EEPROM.write(ADR_BRIGHTNESS, DEFAULT_BRIGHTNESS);
setMainColor(DEFAULT_MC_RED, DEFAULT_MC_GREEN, DEFAULT_MC_BLUE);
EEPROM.write(ADR_STATE, st_clock);
EEPROM.write(ADR_NM_ACTIVATED, DEFAULT_NM_ACTIVATED);
EEPROM.write(ADR_COLSHIFTSPEED, DEFAULT_COLSHIFT_SPEED);
EEPROM.write(ADR_COLSHIFTACTIVE, DEFAULT_COLSHIFT_ACTIVE);
EEPROM.commit();
}

// configure button pin as input
pinMode(BUTTONPIN, INPUT_PULLUP);

Expand Down Expand Up @@ -273,6 +312,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
Expand Down
6 changes: 1 addition & 5 deletions wordclockfunctions.ino_italian
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}
Expand Down
2 changes: 1 addition & 1 deletion wordclockfunctions.ino_swiss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

// Thanks to Sandro for providing this swiss german version
const String clockStringSwiss = "ESPESCHAFUFVIERTUBFZAAZWANZGSIVORABOHWORTUHRHAUBIANESSIEISZWOISDRUVIERIYFUFIOSACHSISEBNIACHTINUNIELZANIERBEUFIZWOUFINAGSI";

/**
Expand Down