Skip to content
Merged
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ The code compiles only with one file named *wordclockfunctions.ino*. So please r

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.
- [**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)
- [**rgbw_leds**](https://github.com/techniccontroller/wordclock_esp8266/tree/rgbw_leds): This branch uses RGBW LEDs instead of RGB 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.

## Features
- 6 modes (Clock, Digital Clock, SPIRAL animation, TETRIS, SNAKE, PONG)
Expand Down
57 changes: 43 additions & 14 deletions data/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
}

.show{
height: 230px;
height: 280px;
transition: height 1s;
}

Expand Down Expand Up @@ -288,6 +288,12 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
<label for="nm_end" style="align-self: flex-start">Nightmode end time: </label>
<input type="time" id="nm_end" name="nm_end" min="00:00" max="23:59">
</div>
<div class="checkbox-container">
<label for="NightMode" style="align-self: flex-start">Nightmode</label>
<div>
<input name= "NightMode" id="NightMode" type="checkbox" class="toggle">
</div>
</div>
<div class="checkbox-container">
<label for="ResetWifi" style="align-self: flex-start">Reset Wifi</label>
<div>
Expand All @@ -311,9 +317,9 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
<div class="grid-item mode-item"><span class="dot-mode" onclick="modechange(this, 5)"><a onclick="sendCommand('./cmd?mode=pingpong')" class="buttonClass" style="width: 100%;"><img src = "./icons/pingpong.svg" style="height:50px"/></a></span></div>
</div>
<div class="checkbox-container">
<label for="Nightmode" style="align-self: flex-start">Nightmode</label>
<label for="LED_Off" style="align-self: flex-start">LEDs OFF</label>
<div>
<input name= "Nightmode" id="Nightmode" type="checkbox" class="toggle">
<input name= "LED_Off" id="LED_Off" type="checkbox" class="toggle">
</div>
</div>
<div class="checkbox-container">
Expand Down Expand Up @@ -456,20 +462,38 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
modebuttons[state].classList.add("active");

// set checkbox states
var ckb_nightmode = document.querySelector('input[id="Nightmode"]');
if(myVar.nightMode == "1") {
console.log("nightMode == 1");
ckb_nightmode.checked = true;
var ckb_nightmodeactivated = document.querySelector('input[id="NightMode"]');
if(myVar.nightModeActivated == "1") {
console.log("nightmodeactivated == 1");
ckb_nightmodeactivated.checked = true;
}
else {
console.log("nightmodeactivated == 0");
ckb_nightmodeactivated.checked = false;
}
ckb_nightmodeactivated.addEventListener('change', () => {
if(ckb_nightmodeactivated.checked) {
sendCommand("./cmd?nightmodeactivated=1");
} else {
sendCommand("./cmd?nightmodeactivated=0");
}
});

// set checkbox states
var ckb_ledoff = document.querySelector('input[id="LED_Off"]');
if(myVar.ledoff == "1") {
console.log("ledoff == 1");
ckb_ledoff.checked = true;
}
else {
console.log("nightMode == 0");
ckb_nightmode.checked = false;
console.log("ledoff == 0");
ckb_ledoff.checked = false;
}
ckb_nightmode.addEventListener('change', () => {
if(ckb_nightmode.checked) {
sendCommand("./cmd?nightmode=1");
ckb_ledoff.addEventListener('change', () => {
if(ckb_ledoff.checked) {
sendCommand("./cmd?ledoff=1");
} else {
sendCommand("./cmd?nightmode=0");
sendCommand("./cmd?ledoff=0");
}
});

Expand Down Expand Up @@ -501,8 +525,10 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
}
ckb_colorshift.addEventListener('change', () => {
if(ckb_colorshift.checked) {
document.getElementById("colorcontainer").classList.add("hidden");
sendCommand("./cmd?colorshift=1");
} else {
document.getElementById("colorcontainer").classList.remove("hidden");
sendCommand("./cmd?colorshift=0");
}
});
Expand Down Expand Up @@ -539,7 +565,10 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
if(myVar != null && myVar.stateAutoChange == "0"){
switch(modeid){
case 0: // clock
document.getElementById("colorcontainer").classList.remove("hidden");
var ckb_colorshift = document.querySelector('input[id="ColorShift"]');
if(!ckb_colorshift.checked) {
document.getElementById("colorcontainer").classList.remove("hidden");
}
document.getElementById("colorshiftcontainer").classList.remove("hidden");
break;
case 1: // diclock
Expand Down
71 changes: 39 additions & 32 deletions wordclock_esp8266.ino
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@
#define ADR_MC_GREEN 22
#define ADR_MC_BLUE 24
#define ADR_STATE 26
#define ADR_NM_ACTIVATED 27
#define ADR_COLSHIFTSPEED 28
#define ADR_COLSHIFTACTIVE 29


#define NEOPIXELPIN 5 // pin to which the NeoPixels are attached
#define NUMPIXELS 125 // number of pixels attached to Attiny85
#define BUTTONPIN 14 // pin to which the button is attached
#define LEFT 1
#define RIGHT 2
Expand Down Expand Up @@ -184,10 +184,12 @@ float filterFactor = DEFAULT_SMOOTHING_FACTOR;// stores smoothing factor for led
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 = true; // stores if dynamic color shift 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

Expand Down Expand Up @@ -414,11 +416,17 @@ void loop() {
}

// handle state behaviours (trigger loopCycles of different states depending on current state)
if(!nightMode && (millis() - lastStep > behaviorUpdatePeriod) && (millis() - lastLEDdirect > TIMEOUT_LEDDIRECT)){
if(!nightMode && !ledOff && (millis() - lastStep > behaviorUpdatePeriod) && (millis() - lastLEDdirect > TIMEOUT_LEDDIRECT)){
updateStateBehavior(currentState);
lastStep = millis();
}

// Turn off LEDs if ledOff is true or nightmode is active
if((ledOff || nightMode) && !waitForTimeAfterReboot){
ledmatrix.gridFlush();
ledmatrix.drawOnMatrixInstant();
}

// periodically write colors to matrix
if(millis() - lastAnimationStep > PERIOD_MATRIXUPDATE && !waitForTimeAfterReboot){
ledmatrix.drawOnMatrixSmooth(filterFactor);
Expand All @@ -429,7 +437,7 @@ void loop() {
handleButton();

// handle state changes
if(stateAutoChange && (millis() - lastStateChange > PERIOD_STATECHANGE) && !nightMode){
if(stateAutoChange && (millis() - lastStateChange > PERIOD_STATECHANGE) && !nightMode && !ledOff){
// increment state variable and trigger state change
stateChange((currentState + 1) % NUM_STATES, false);

Expand Down Expand Up @@ -610,18 +618,17 @@ void checkNightmode(){
int startInMinutes = nightModeStartHour * 60 + nightModeStartMin;
int endInMinutes = nightModeEndHour * 60 + nightModeEndMin;

if (startInMinutes < endInMinutes) { // Same day scenario
if (startInMinutes < endInMinutes && nightModeActivated) { // Same day scenario
if (startInMinutes < currentTimeInMinutes && currentTimeInMinutes < endInMinutes) {
nightMode = true;
logger.logString("Nightmode activated");
logger.logString("Nightmode active");
}
} else if (startInMinutes > endInMinutes) { // Overnight scenario
} else if (startInMinutes > endInMinutes && nightModeActivated) { // Overnight scenario
if (currentTimeInMinutes >= startInMinutes || currentTimeInMinutes < endInMinutes) {
nightMode = true;
logger.logString("Nightmode activated");
logger.logString("Nightmode active");
}
}
setNightmode(nightMode);
}

/**
Expand Down Expand Up @@ -691,9 +698,8 @@ void entryAction(uint8_t state){
* @param persistant if true, the state will be saved to EEPROM
*/
void stateChange(uint8_t newState, bool persistant){
if(nightMode){
// deactivate Nightmode
setNightmode(false);
if(ledOff){
ledOff = false;
}
// first clear matrix
ledmatrix.gridFlush();
Expand Down Expand Up @@ -782,14 +788,14 @@ void handleButton(){
// longpress -> nightmode
logger.logString("Button press ended - longpress");

setNightmode(true);
ledOff = true;
}
else if((millis() - buttonPressStart) > SHORTPRESS){
// shortpress -> state change
logger.logString("Button press ended - shortpress");

if(nightMode){
setNightmode(false);
if(ledOff){
ledOff = false;
}else{
stateChange((currentState + 1) % NUM_STATES, true);
}
Expand Down Expand Up @@ -848,10 +854,12 @@ void loadNightmodeSettingsFromEEPROM()
nightModeStartMin = EEPROM.read(ADR_NM_START_M);
nightModeEndHour = EEPROM.read(ADR_NM_END_H);
nightModeEndMin = EEPROM.read(ADR_NM_END_M);
nightModeActivated = EEPROM.read(ADR_NM_ACTIVATED);
if(nightModeStartHour < 0 || nightModeStartHour > 23) nightModeStartHour = 22;
if(nightModeStartMin < 0 || nightModeStartMin > 59) nightModeStartMin = 0;
if(nightModeEndHour < 0 || nightModeEndHour > 23) nightModeEndHour = 7;
if(nightModeEndMin < 0 || nightModeEndMin > 59) nightModeEndMin = 0;
logger.logString("Nightmode activated: " + String(nightModeActivated));
logger.logString("Nightmode starts at: " + String(nightModeStartHour) + ":" + String(nightModeStartMin));
logger.logString("Nightmode ends at: " + String(nightModeEndHour) + ":" + String(nightModeEndMin));
}
Expand Down Expand Up @@ -930,11 +938,20 @@ void handleCommand() {
stateChange(st_pingpong, true);
}
}
else if(server.argName(0) == "nightmode"){
else if(server.argName(0) == "ledoff"){
String modestr = server.arg(0);
logger.logString("Nightmode change via Webserver to: " + modestr);
if(modestr == "1") setNightmode(true);
else setNightmode(false);
logger.logString("LED off change via Webserver to: " + modestr);
if(modestr == "1") ledOff = true;
else ledOff = false;
}
else if(server.argName(0) == "nightmodeactivated"){
String modestr = server.arg(0);
logger.logString("nightModeActivated change via Webserver to: " + modestr);
if(modestr == "1") nightModeActivated = true;
else nightModeActivated = false;
EEPROM.write(ADR_NM_ACTIVATED, nightModeActivated);
EEPROM.commit();
checkNightmode();
}
else if(server.argName(0) == "setting"){
String timestr = server.arg(0) + "-";
Expand Down Expand Up @@ -1105,7 +1122,9 @@ void handleDataRequest() {
message += ",";
message += "\"stateAutoChange\":\"" + String(stateAutoChange) + "\"";
message += ",";
message += "\"nightMode\":\"" + String(nightMode) + "\"";
message += "\"ledoff\":\"" + String(ledOff) + "\"";
message += ",";
message += "\"nightModeActivated\":\"" + String(nightModeActivated) + "\"";
message += ",";
message += "\"nightModeStart\":\"" + leadingZero2Digit(nightModeStartHour) + "-" + leadingZero2Digit(nightModeStartMin) + "\"";
message += ",";
Expand All @@ -1122,18 +1141,6 @@ void handleDataRequest() {
}
}

/**
* @brief Set the nightmode state
*
* @param on true -> nightmode on
*/
void setNightmode(bool on){
if(on){
ledmatrix.gridFlush();
}
nightMode = on;
}

/**
* @brief Convert Integer to String with leading zero
*
Expand Down