Skip to content

Commit 1c7494f

Browse files
Merge branch 'hour_animation' into dev_main
2 parents 75e6bd1 + 3b726af commit 1c7494f

File tree

4 files changed

+145
-16
lines changed

4 files changed

+145
-16
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ A modern Wi-Fi Word Clock powered by the ESP8266 and synchronized via NTP (Netwo
55
Displays time in words with support for multiple languages and colorful NeoPixel LED effects.
66
Additional gaming modes, such as PONG, SNAKE, and TETRIS, can be played via an interactive Web UI.
77

8+
89
**Project Details and Guide:**
910

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

animationfunctions.ino

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,60 @@ int spiral(bool init, bool empty, uint8_t size){
6969
return 0;
7070
}
7171

72+
/**
73+
* @brief Function to perform animation of an/multiple words on the matrix
74+
*
75+
* @param init marks if call is the initial step of the animation
76+
* @param empty marks if the animation should 'draw' empty leds
77+
* @return int 1 if end is reached, else 0
78+
*/
79+
int word_animation(bool init, bool empty){
80+
81+
// colors for the different words, mapping via colorPerCoordinate array
82+
uint32_t colors[] = { LEDMatrix::Color24bit(0, 255, 0), // -> 0
83+
LEDMatrix::Color24bit(255, 0, 0), // -> 1
84+
LEDMatrix::Color24bit(200, 200, 0), // -> 2
85+
LEDMatrix::Color24bit(255, 0, 200), // -> 3
86+
LEDMatrix::Color24bit(0, 0, 255), // -> 4
87+
};
88+
// coordinate of the letters to light up after each other top left LED = (0, 0)
89+
uint8_t coordinatesX[] = {8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 5, 5, 5, 0, 1, 2, 3, 4, 6, 6, 6, 6, 6};
90+
uint8_t coordinatesY[] = {5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 6, 7, 8, 5, 5, 5, 5, 5, 4, 5, 6, 7, 8};
91+
uint8_t colorPerCoordinate[] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4};
92+
uint8_t numLEDs = sizeof(coordinatesX)/sizeof(uint8_t);
93+
94+
static int x;
95+
static int y;
96+
static int counter1;
97+
static int randNum;
98+
if(init){
99+
logger.logString("Init Word Animation with empty=" + String(empty));
100+
x = coordinatesX[0];
101+
y = coordinatesY[0];
102+
if(!empty)ledmatrix.gridFlush();
103+
counter1 = 0;
104+
randNum = random(255);
105+
}
106+
else if (counter1 >= numLEDs){
107+
// End reached return 1
108+
return 1;
109+
}
110+
else{
111+
uint32_t color = colors[colorPerCoordinate[counter1]];
112+
// if draw mode is empty, set color to zero
113+
if(empty){
114+
color = 0;
115+
}
116+
117+
x = coordinatesX[counter1];
118+
y = coordinatesY[counter1];
119+
ledmatrix.gridAddPixel(x, y, color);
120+
counter1++;
121+
}
122+
return 0;
123+
124+
}
125+
72126
/**
73127
* @brief Run random snake animation
74128
*

data/index.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,12 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
334334
<input name= "ColorShift" id="ColorShift" type="checkbox" class="toggle">
335335
</div>
336336
</div>
337+
<div class="checkbox-container" id = "hour_animation">
338+
<label for="HourAnimation" style="align-self: flex-start">Hourly animation</label>
339+
<div>
340+
<input name= "HourAnimation" id="HourAnimation" type="checkbox" class="toggle">
341+
</div>
342+
</div>
337343

338344
<div class="main-container hidden" id="colorcontainer">
339345
<div class="verticalline">
@@ -532,6 +538,23 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
532538
sendCommand("./cmd?colorshift=0");
533539
}
534540
});
541+
542+
var ckb_houranimation = document.querySelector('input[id="HourAnimation"]');
543+
if(myVar.houranimation == "1") {
544+
console.log("houranimation == 1");
545+
ckb_houranimation.checked = true;
546+
}
547+
else {
548+
console.log("houranimation == 0");
549+
ckb_houranimation.checked = false;
550+
}
551+
ckb_houranimation.addEventListener('change', () => {
552+
if(ckb_houranimation.checked) {
553+
sendCommand("./cmd?houranimation=1");
554+
} else {
555+
sendCommand("./cmd?houranimation=0");
556+
}
557+
});
535558

536559
document.getElementById("nm_start").value = myVar.nightModeStart.replace("-", ":");
537560
document.getElementById("nm_end").value = myVar.nightModeEnd.replace("-", ":");
@@ -570,25 +593,31 @@ <h1 id="headline">WORDCLOCK 2.0</h1>
570593
document.getElementById("colorcontainer").classList.remove("hidden");
571594
}
572595
document.getElementById("colorshiftcontainer").classList.remove("hidden");
596+
document.getElementById("hour_animation").classList.remove("hidden");
573597
break;
574598
case 1: // diclock
575599
document.getElementById("colorcontainer").classList.remove("hidden");
576600
document.getElementById("colorshiftcontainer").classList.add("hidden");
601+
document.getElementById("hour_animation").classList.add("hidden");
577602
break;
578603
case 2: // spiral
579604
document.getElementById("colorshiftcontainer").classList.add("hidden");
605+
document.getElementById("hour_animation").classList.add("hidden");
580606
break;
581607
case 3: // tetris
582608
document.getElementById("tetriscontainer").classList.remove("hidden");
583609
document.getElementById("colorshiftcontainer").classList.add("hidden");
610+
document.getElementById("hour_animation").classList.add("hidden");
584611
break;
585612
case 4: // snake
586613
document.getElementById("snakecontainer").classList.remove("hidden");
587614
document.getElementById("colorshiftcontainer").classList.add("hidden");
615+
document.getElementById("hour_animation").classList.add("hidden");
588616
break;
589617
case 5: // pingping
590618
document.getElementById("pongcontainer").classList.remove("hidden");
591619
document.getElementById("colorshiftcontainer").classList.add("hidden");
620+
document.getElementById("hour_animation").classList.add("hidden");
592621
break;
593622

594623
}

wordclock_esp8266.ino

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
// CONSTANTS
4949
// ----------------------------------------------------------------------------------
5050

51-
#define EEPROM_SIZE 30 // size of EEPROM to save persistent variables
51+
#define EEPROM_SIZE 32 // size of EEPROM to save persistent variables
5252
#define ADR_NM_START_H 0
5353
#define ADR_NM_END_H 4
5454
#define ADR_NM_START_M 8
@@ -61,6 +61,7 @@
6161
#define ADR_NM_ACTIVATED 27
6262
#define ADR_COLSHIFTSPEED 28
6363
#define ADR_COLSHIFTACTIVE 29
64+
#define ADR_HOURANIMATION 30
6465

6566

6667
#define NEOPIXELPIN 5 // pin to which the NeoPixels are attached
@@ -160,7 +161,7 @@ const uint32_t colors24bit[NUM_COLORS] = {
160161
LEDMatrix::Color24bit(0, 0, 255) };
161162

162163
uint8_t brightness = 40; // current brightness of leds
163-
bool sprialDir = false;
164+
bool animationDir = false;
164165

165166
// timestamp variables
166167
long lastheartbeat = millis(); // time of last heartbeat sending
@@ -170,7 +171,8 @@ long lastStateChange = millis(); // time of last state change
170171
long lastNTPUpdate = millis() - (PERIOD_NTPUPDATE-3000); // time of last NTP update
171172
long lastAnimationStep = millis(); // time of last Matrix update
172173
long lastNightmodeCheck = millis() - (PERIOD_NIGHTMODECHECK-3000); // time of last nightmode check
173-
long buttonPressStart = 0; // time of push button press start
174+
long buttonPressStart = 0; // time of push button press start
175+
long hourAnimationStart = 0; // time of hour animation start
174176
uint16_t behaviorUpdatePeriod = PERIOD_TIMEVISUUPDATE; // holdes the period in which the behavior should be updated
175177

176178
// Create necessary global objects
@@ -194,6 +196,8 @@ bool apmode = false; // stores if WiFi AP mode is activ
194196
bool dynColorShiftActive = false; // stores if dynamic color shift is active
195197
uint8_t dynColorShiftPhase = 0; // stores the phase of the dynamic color shift
196198
uint8_t dynColorShiftSpeed = 1; // stores the speed of the dynamic color shift -> used to calc update period
199+
bool hourAnimation = false; // stores if the hour animation is active
200+
uint32_t hourAnimationDuration = 18000; // stores the duration of the hour animation in seconds
197201

198202
// nightmode settings
199203
uint8_t nightModeStartHour = 22;
@@ -360,6 +364,7 @@ void setup() {
360364
loadNightmodeSettingsFromEEPROM();
361365
loadBrightnessSettingsFromEEPROM();
362366
loadColorShiftStateFromEEPROM();
367+
loadHourAnimationSettingsFromEEPROM();
363368

364369
if(ESP.getResetReason().equals("Power On") || ESP.getResetReason().equals("External System")){
365370
// test quickly each LED
@@ -424,6 +429,25 @@ void loop() {
424429
delay(1000);
425430
}
426431
}
432+
if(hourAnimation){
433+
// Show word animation allows from XX:00:00 till XX:00:12 (for 12 seconds every hour)
434+
// start
435+
static uint8_t lastMinutes = 0;
436+
uint8_t minutes = ntp.getMinutes();
437+
if(lastMinutes == 59 && minutes == 0 && currentState == st_clock){
438+
logger.logString("Start hour animation");
439+
logger.logString("Time: " + ntp.getFormattedTime());
440+
stateChange(st_spiral, false);
441+
hourAnimationStart = millis();
442+
}
443+
lastMinutes = minutes;
444+
445+
// end
446+
if((millis() - hourAnimationStart) >= hourAnimationDuration && currentState == st_spiral && hourAnimationStart != 0){
447+
stateChange(st_clock, false);
448+
hourAnimationStart = 0;
449+
}
450+
}
427451

428452
// handle state behaviours (trigger loopCycles of different states depending on current state)
429453
if(!nightMode && !ledOff && (millis() - lastStep > behaviorUpdatePeriod) && (millis() - lastLEDdirect > TIMEOUT_LEDDIRECT)){
@@ -558,18 +582,18 @@ void updateStateBehavior(uint8_t state){
558582
// state spiral
559583
case st_spiral:
560584
{
561-
int res = spiral(false, sprialDir, WIDTH-6);
562-
if(res && sprialDir == 0){
563-
// change spiral direction to closing (draw empty leds)
564-
sprialDir = 1;
565-
// init spiral with new spiral direction
566-
spiral(true, sprialDir, WIDTH-6);
585+
int res = word_animation(false, animationDir);
586+
if(res && animationDir == 0){
587+
// change animation direction to closing (draw empty leds)
588+
animationDir = 1;
589+
// init animation with new animation direction
590+
word_animation(true, animationDir);
567591

568-
}else if(res && sprialDir == 1){
569-
// reset spiral direction to normal drawing leds
570-
sprialDir = 0;
571-
// init spiral with new spiral direction
572-
spiral(true, sprialDir, WIDTH-6);
592+
}else if(res && animationDir == 1){
593+
// reset animation direction to normal drawing leds
594+
animationDir = 0;
595+
// init animation with new animation direction
596+
word_animation(true, animationDir);
573597
}
574598
}
575599
break;
@@ -657,8 +681,8 @@ void entryAction(uint8_t state){
657681
behaviorUpdatePeriod = PERIOD_ANIMATION;
658682
ledmatrix.setDynamicColorShiftPhase(-1); // disable dyn. color shift
659683
// Init spiral with normal drawing mode
660-
sprialDir = 0;
661-
spiral(true, sprialDir, WIDTH-6);
684+
animationDir = 0;
685+
word_animation(true, animationDir);
662686
break;
663687
case st_tetris:
664688
ledmatrix.setDynamicColorShiftPhase(-1); // disable dyn. color shift
@@ -897,6 +921,17 @@ void loadColorShiftStateFromEEPROM()
897921
logger.logString("ColorShiftActive: " + String(dynColorShiftActive));
898922
}
899923

924+
/**
925+
* @brief load the hour animation setting from EEPROM
926+
*
927+
*/
928+
void loadHourAnimationSettingsFromEEPROM()
929+
{
930+
hourAnimation = EEPROM.read(ADR_HOURANIMATION);
931+
logger.logString("HourAnimation: " + String(hourAnimation));
932+
}
933+
934+
900935
/**
901936
* @brief Handler for handling commands sent to "/cmd" url
902937
*
@@ -1080,6 +1115,14 @@ void handleCommand() {
10801115
EEPROM.write(ADR_COLSHIFTACTIVE, dynColorShiftActive);
10811116
EEPROM.commit();
10821117
}
1118+
else if(server.argName(0) == "houranimation"){
1119+
Serial.println("HourAnimation change via Webserver");
1120+
String str = server.arg(0);
1121+
if(str == "1") hourAnimation = true;
1122+
else hourAnimation = false;
1123+
EEPROM.write(ADR_HOURANIMATION, hourAnimation);
1124+
EEPROM.commit();
1125+
}
10831126
server.send(204, "text/plain", "No Content"); // this page doesn't send back content --> 204
10841127
}
10851128

@@ -1142,6 +1185,8 @@ void handleDataRequest() {
11421185
message += "\"colorshift\":\"" + String(dynColorShiftActive) + "\"";
11431186
message += ",";
11441187
message += "\"colorshiftspeed\":\"" + String(dynColorShiftSpeed) + "\"";
1188+
message += ",";
1189+
message += "\"houranimation\":\"" + String(hourAnimation) + "\"";
11451190
}
11461191
message += "}";
11471192
server.send(200, "application/json", message);

0 commit comments

Comments
 (0)