For the benefit of other users:
// Store the alarm over power down.
#include <EEPROM.h>
#include <DS3231.h>
// Initiate the DS3231 using the hardware interface
DS3231 rtc(SDA, SCL);
// Initiate a time-data structure
Time t;
// Various settings.
#define BLINK_FREQUENCY 750 // in milliseconds, how fast the LEDs blink when setting hour/minute.
#define LONG_PRESS_TIME 500 // How long before a long press is deteceted, in milliseconds.
#define DEBOUNCE_DELAY 50 // How long to wait for debounce/rebound.
#define SNOOZE_TIME 300000 // How long to snooze - and start playing alarm again, unless switched off by long press on the alarm button.
#define BUTTON_REPEAT_TIME 200
//ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΠΌ Π²ΡΠ²ΠΎΠ΄Ρ ΡΠ²Π΅ΡΠΎΠ΄ΠΈΠΎΠ΄ΠΎΠ² ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΠΌΡΡ
ΠΊ arduino
const byte leds[4][4] = {
{ -1, 11, -1, 3},
{ -1, 10, 6, 2},
{13, 8, 5, 1},
{12, 7, 4, 0}
};
//Π²ΡΠ²ΠΎΠ΄Ρ ΠΊΠ½ΠΎΠΏΠΎΠΊ
const byte buttonHourPin = A0;
const byte buttonMinutePin = A1;
const byte buttonAlarmPin = A2;
const byte buttonOnOffPin = A3;
byte buttons[3];
#define BUTTON_HOUR 0
#define BUTTON_MINUTE 1
#define BUTTON_ALARM 2
//Π²ΡΠ²ΠΎΠ΄ Π΄ΠΈΠ½Π°ΠΌΠΈΠΊΠ°
const byte speakerPin = 9;
// Default values for the alarm.
byte minuteAlarm = 0;
byte hourAlarm = 0;
// The various modes we can be in.
#define MODE_CLOCK 0
#define MODE_SET_ALARM 1
#define MODE_SET_CLOCK 2
#define MODE_ALARM 3
byte clockMode = MODE_CLOCK;
// The various status flags we have.
bool lightsOn = true;
bool alarmOn = false;
bool alarmSnoozed = false;
bool selectingMinute = false;
bool selectingHour = false;
bool blinkStatus = false;
// Button handling.
unsigned long buttonPressedTime[3];
byte buttonState[3];
#define BUTTON_UNPRESSED 0
#define BUTTON_DEBOUNCING 1
#define BUTTON_PRESSED 2
#define BUTTON_SHORTPRESSED 3
#define BUTTON_LONGPRESSED 4
#define BUTTON_HANDLED 5
#define BUTTON_LONGPRESS_REPEAT 6
// Various variables.
unsigned long blinkTime;
unsigned long alarmStartedTime;
unsigned long snoozedTime;
byte selectedHour;
byte selectedMinute;
// The special effects playing state.
byte effectsStage;
bool effectsPlaying = false;
bool playButtonPressEffects = false;
bool buttonPressEffectsPlaying = false;
bool playAlarmSwitchedOffEffects = false;
bool alarmSwitchedOffEffectsPlaying = false;
bool playAlarmSwitchedOnEffects = false;
bool alarmSwitchedOnEffectsPlaying = false;
bool playModeSetClockEffects = false;
bool modeSetClockEffectsPlaying = false;
bool playModeSetAlarmEffects = false;
bool modeSetAlarmEffectsPlaying = false;
bool playSnoozeOffEffects = false;
bool snoozeOffEffectsPlaying = false;
bool playFinishTimeSettingEffects = false;
bool finishTimeSettingEffectsPlaying = false;
bool playAlarm = false;
bool alarmPlaying = false;
unsigned int alarmRepeats = 0;
bool effectDisplayClock = false;
bool alarmJustSet = false;
uint32_t nextEffectMillis;
void setup()
{
rtc.begin();
//set outputs
for (byte i = 0; i < 4; i++) {
for (byte j = 0; j < 4; j++) {
pinMode(leds[i][j], OUTPUT);
}
}
pinMode(speakerPin, OUTPUT);
allOn();
delay(400);
allOff();
// Set buttons.
buttons[BUTTON_HOUR] = buttonHourPin;
buttons[BUTTON_MINUTE] = buttonMinutePin;
buttons[BUTTON_ALARM] = buttonAlarmPin;
for (byte i = 0; i < 3; i++) {
pinMode(buttons[i], INPUT_PULLUP);
}
pinMode(buttonOnOffPin, INPUT_PULLUP);
// Read the alarm from EEPROM.
minuteAlarm = EEPROM.read(0);
hourAlarm = EEPROM.read(1);
if (minuteAlarm > 59) minuteAlarm = 0;
if (hourAlarm > 23) hourAlarm = 0;
}
void displayClock()
{
// Clock is displayed when:
// - lightsOn and no special effects playing, or:
// - while alarm is snoozed, or:
// - when the special effects explicitly ask for it.
//
// Otherwise, the LEDs are switched off when:
// - no special effects playing.
t = rtc.getTime();
byte hourClock = t.hour;
byte minuteClock = t.min;
byte secondClock = t.sec;
// When it's time and alarms are switched on, start playing the alarm.
if (alarmJustSet == false &&
clockMode == MODE_CLOCK &&
((alarmPlaying == false && secondClock == 0 && minuteClock == minuteAlarm && hourClock == hourAlarm && alarmOn) ||
(alarmSnoozed && millis() - snoozedTime > SNOOZE_TIME))) {
playAlarm = true; // Will be handled after all other effects have been switched off.
alarmSnoozed = false;
effectsPlaying = false; // Make sure no other effects are playing.
clockMode = MODE_ALARM;
}
if (secondClock > 0 && alarmJustSet) {
alarmJustSet = false;
}
if ((lightsOn && effectsPlaying == false) ||
alarmSnoozed ||
effectDisplayClock) {
int hourUnit, minuteUnit, hourTens, minuteTens;
switch (clockMode) {
case MODE_CLOCK:
case MODE_ALARM:
hourUnit = hourClock % 10;
minuteUnit = minuteClock % 10;
hourTens = int(hourClock / 10);
minuteTens = int(minuteClock / 10);
break;
case MODE_SET_ALARM:
hourUnit = hourAlarm % 10;
minuteUnit = minuteAlarm % 10;
hourTens = int(hourAlarm / 10);
minuteTens = int(minuteAlarm / 10);
break;
case MODE_SET_CLOCK:
hourUnit = selectedHour % 10;
minuteUnit = selectedMinute % 10;
hourTens = int(selectedHour / 10);
minuteTens = int(selectedMinute / 10);
break;
}
for (byte i = 0; i < 4; i++) {
if (selectingMinute && (blinkStatus == false)) { // If we're selecting the minute, and blinkStatus is false, don't display the minutes.
digitalWrite(leds[3 - i][3], 0);
digitalWrite(leds[3 - i][2], 0);
}
else {
digitalWrite(leds[3 - i][3], minuteUnit & (1 << i));
digitalWrite(leds[3 - i][2], minuteTens & (1 << i));
}
if (selectingHour && (blinkStatus == false)) { // If we're selecting the hour, and blinkStatus is false, don't display the hours.
digitalWrite(leds[3 - i][1], 0);
digitalWrite(leds[3 - i][0], 0);
}
else {
digitalWrite(leds[3 - i][1], hourUnit & (1 << i));
digitalWrite(leds[3 - i][0], hourTens & (1 << i));
}
}
}
else if (effectsPlaying == false) {
ledsOff();
}
}
void readButtons()
{
for (uint8_t i = 0; i < 3; i++) { // Handle the buttons.
if (digitalRead(buttons[i]) == LOW) {
switch (buttonState[i]) {
case BUTTON_UNPRESSED: // Not debouncing or recorded press: start debounce delay.
buttonState[i] = BUTTON_DEBOUNCING;
buttonPressedTime[i] = millis();
if (lightsOn) {
playButtonPressEffects = true;
}
break;
case BUTTON_DEBOUNCING: // We're debouncing the button.
if (millis() - buttonPressedTime[i] > DEBOUNCE_DELAY) {
buttonState[i] = BUTTON_PRESSED; // Debounce done: record actual press.
}
break;
case BUTTON_PRESSED: // Button is pressed.
// Check for a long press of this button.
if (millis() - buttonPressedTime[i] > LONG_PRESS_TIME) {
buttonState[i] = BUTTON_LONGPRESSED;
buttonPressedTime[i] += LONG_PRESS_TIME;
}
break;
case BUTTON_LONGPRESS_REPEAT:
if (millis() - buttonPressedTime[i] > BUTTON_REPEAT_TIME) {
buttonState[i] = BUTTON_LONGPRESSED;
buttonPressedTime[i] += BUTTON_REPEAT_TIME;
}
break;
}
}
else { // Button not pressed.
switch (buttonState[i]) {
case BUTTON_PRESSED:
buttonState[i] = BUTTON_SHORTPRESSED;
break;
default:
buttonState[i] = BUTTON_UNPRESSED;
break;
}
}
// Do something useful with these button presses.
switch (buttonState[i]) {
case BUTTON_SHORTPRESSED:
buttonState[i] = BUTTON_HANDLED; // Make sure the button press is handled once and once only.
switch (clockMode) {
case MODE_CLOCK:
switch (i) {
case BUTTON_MINUTE:
break;
case BUTTON_HOUR:
break;
case BUTTON_ALARM:
break;
}
break;
case MODE_SET_ALARM:
switch (i) {
case BUTTON_MINUTE:
if (selectingMinute) {
minuteAlarm++;
if (minuteAlarm > 59) minuteAlarm = 0;
}
else {
selectingMinute = true;
selectingHour = false;
}
break;
case BUTTON_HOUR:
if (selectingHour) {
hourAlarm++;
if (hourAlarm > 23) hourAlarm = 0;
}
else {
selectingMinute = false;
selectingHour = true;
}
break;
case BUTTON_ALARM:
EEPROM.write(0, minuteAlarm);
EEPROM.write(1, hourAlarm);
clockMode = MODE_SET_CLOCK;
playModeSetClockEffects = true;
t = rtc.getTime();
selectedHour = t.hour;
selectedMinute = t.min;
selectingHour = false;
selectingMinute = true;
break;
}
break;
case MODE_SET_CLOCK:
switch (i) {
case BUTTON_MINUTE:
if (selectingMinute) {
selectedMinute++;
if (selectedMinute > 59) selectedMinute = 0;
}
else {
selectingMinute = true;
selectingHour = false;
}
break;
case BUTTON_HOUR:
if (selectingHour) {
selectedHour++;
if (selectedHour > 23) selectedHour = 0;
}
else {
selectingMinute = false;
selectingHour = true;
}
break;
case BUTTON_ALARM:
rtc.setTime(selectedHour, selectedMinute, 0);
clockMode = MODE_SET_ALARM;
selectingHour = false;
selectingMinute = true;
playModeSetAlarmEffects = true;
break;
}
break;
case MODE_ALARM:
switch (i) {
case BUTTON_MINUTE:
break;
case BUTTON_HOUR:
break;
case BUTTON_ALARM:
break;
}
break;
}
break;
case BUTTON_LONGPRESSED:
switch (clockMode) {
case MODE_CLOCK:
blinkTime = millis();
blinkStatus = true;
switch (i) {
case BUTTON_MINUTE: // Minute button long pressed in clock mode: if hour button also pressed, switch to alarm mode.
case BUTTON_HOUR: // Hour button long pressed in clock mode: if hour button also pressed, switch to alarm mode.
if (lightsOn && // Ignore these buttons if lights are off.
(buttonState[BUTTON_HOUR] == BUTTON_DEBOUNCING ||
buttonState[BUTTON_HOUR] == BUTTON_PRESSED ||
buttonState[BUTTON_HOUR] == BUTTON_LONGPRESSED) &&
(buttonState[BUTTON_MINUTE] == BUTTON_DEBOUNCING ||
buttonState[BUTTON_MINUTE] == BUTTON_PRESSED ||
buttonState[BUTTON_MINUTE] == BUTTON_LONGPRESSED)) {
clockMode = MODE_SET_ALARM;
buttonState[BUTTON_MINUTE] = BUTTON_HANDLED;
buttonState[BUTTON_HOUR] = BUTTON_HANDLED;
playModeSetAlarmEffects = true;
selectingMinute = true;
selectingHour = false;
t = rtc.getTime();
selectedHour = t.hour;
selectedMinute = t.min;
}
break;
case BUTTON_ALARM: // Alarm button long pressed in clock mode: if snoozed, cancel snooze; otherwise toggle alarm on/off.
if (alarmSnoozed) {
alarmSnoozed = false;
playSnoozeOffEffects = true;
}
else {
if (alarmOn) {
alarmOn = false;
playAlarmSwitchedOffEffects = true;
}
else {
alarmOn = true;
playAlarmSwitchedOnEffects = true;
}
}
buttonState[BUTTON_ALARM] = BUTTON_HANDLED;
break;
}
break;
case MODE_SET_ALARM: // Long press of buttons in alarm mode.
blinkTime = millis();
blinkStatus = true;
{
bool finish = false;
switch (i) {
case BUTTON_MINUTE: // Minute button long pressed in setting alarm mode: advance alarm minute; rate repeat.
if (buttonState[BUTTON_HOUR] == BUTTON_DEBOUNCING ||
buttonState[BUTTON_HOUR] == BUTTON_PRESSED ||
buttonState[BUTTON_HOUR] == BUTTON_LONGPRESSED) {
finish = true;
}
else if (selectingMinute) {
minuteAlarm++;
if (minuteAlarm > 59) minuteAlarm = 0;
buttonState[BUTTON_MINUTE] = BUTTON_LONGPRESS_REPEAT;
}
else {
selectingMinute = true;
selectingHour = false;
buttonState[BUTTON_MINUTE] = BUTTON_HANDLED;
}
break;
case BUTTON_HOUR: // Hour button long pressed in setting alarm mode: advance alarm hour; rate repeat.
if (buttonState[BUTTON_MINUTE] == BUTTON_DEBOUNCING ||
buttonState[BUTTON_MINUTE] == BUTTON_PRESSED ||
buttonState[BUTTON_MINUTE] == BUTTON_LONGPRESSED) {
finish = true;
}
else if (selectingHour) {
hourAlarm++;
if (hourAlarm > 23) hourAlarm = 0;
buttonState[BUTTON_HOUR] = BUTTON_LONGPRESS_REPEAT;
}
else {
selectingMinute = false;
selectingHour = true;
buttonState[BUTTON_HOUR] = BUTTON_HANDLED;
}
break;
}
if (finish) {
doFinish();
}
}
break;
case MODE_SET_CLOCK:
{
bool finish = false;
switch (i) {
case BUTTON_MINUTE: // Minute button long pressed in setting alarm mode: advance alarm minute; rate repeat.
if (buttonState[BUTTON_HOUR] == BUTTON_DEBOUNCING ||
buttonState[BUTTON_HOUR] == BUTTON_PRESSED ||
buttonState[BUTTON_HOUR] == BUTTON_LONGPRESSED) {
finish = true;
}
else if (selectingMinute) {
selectedMinute++;
if (selectedMinute > 59) selectedMinute = 0;
buttonState[BUTTON_MINUTE] = BUTTON_LONGPRESS_REPEAT;
}
else {
selectingMinute = true;
selectingHour = false;
buttonState[BUTTON_MINUTE] = BUTTON_HANDLED;
}
break;
case BUTTON_HOUR: // Hour button long pressed in setting alarm mode: advance alarm hour; rate repeat.
if (buttonState[BUTTON_MINUTE] == BUTTON_DEBOUNCING ||
buttonState[BUTTON_MINUTE] == BUTTON_PRESSED ||
buttonState[BUTTON_MINUTE] == BUTTON_LONGPRESSED) {
finish = true;
}
else if (selectingHour) {
selectedHour++;
if (selectedHour > 23) selectedHour = 0;
buttonState[BUTTON_HOUR] = BUTTON_LONGPRESS_REPEAT;
}
else {
selectingMinute = false;
selectingHour = true;
buttonState[BUTTON_HOUR] = BUTTON_HANDLED;
}
break;
}
if (finish) {
doFinish();
}
}
break;
}
case BUTTON_PRESSED:
switch (clockMode) {
case MODE_SET_ALARM:
case MODE_SET_CLOCK:
blinkTime = millis();
blinkStatus = true;
break;
case MODE_ALARM:
effectsPlaying = false;
alarmSnoozed = true;
snoozedTime = millis();
clockMode = MODE_CLOCK;
break;
}
break;
}
}
// Special case: this is a toggle button, not a push button. So it's simply on or off.
if (digitalRead(buttonOnOffPin) == LOW) {
lightsOn = true;
}
else {
lightsOn = false;
}
}
void doFinish() {
rtc.setTime(selectedHour, selectedMinute, 0);
EEPROM.write(0, minuteAlarm);
EEPROM.write(1, hourAlarm);
alarmJustSet = true;
selectingMinute = false;
selectingHour = false;
clockMode = MODE_CLOCK;
buttonState[BUTTON_MINUTE] = BUTTON_HANDLED;
buttonState[BUTTON_HOUR] = BUTTON_HANDLED;
playFinishTimeSettingEffects = true;
}
void setPattern(byte pattern[4]) {
for (byte i = 0; i < 4; i++) {
byte p = pattern[i];
for (byte j = 0; j < 4; j++) {
digitalWrite(leds[i][3 - j], p & (1 << j));
}
}
}
void ledsOff() {
for (byte i = 0; i < 4; i++) {
for (byte j = 0; j < 4; j++) {
digitalWrite(leds[i][j], LOW);
}
}
}
void allOff() {
ledsOff();
noTone(speakerPin);
}
void ledsOn() {
for (byte i = 0; i < 4; i++) {
for (byte j = 0; j < 4; j++) {
digitalWrite(leds[i][j], HIGH);
}
}
}
void allOn() {
ledsOn();
tone(speakerPin, 1865);
}
//Π³Π»Π°Π²Π½ΡΠΉ ΡΠΈΠΊΠ», Π²ΡΠ·ΠΎΠ² Π²ΡΠ΅Ρ
ΠΏΡΠΎΡΠ΅Π΄ΡΡ
void loop() {
displayClock();
readButtons();
specialEffects();
if (millis() - blinkTime > BLINK_FREQUENCY) {
blinkStatus = !blinkStatus;
blinkTime = millis();
}
if (lightsOn == false &&
(clockMode == MODE_SET_CLOCK || clockMode == MODE_SET_ALARM)) {
clockMode = MODE_CLOCK;
selectingMinute = false;
selectingHour = false;
}
}
void specialEffects() {
// If we're not supposed to play any effects now - switch them all off.
if (effectsPlaying == false) {
alarmSwitchedOnEffectsPlaying = false;
alarmSwitchedOffEffectsPlaying = false;
modeSetClockEffectsPlaying = false;
modeSetAlarmEffectsPlaying = false;
snoozeOffEffectsPlaying = false;
buttonPressEffectsPlaying = false;
finishTimeSettingEffectsPlaying = false;
effectDisplayClock = false;
alarmPlaying = false;
noTone(speakerPin);
}
if (playAlarmSwitchedOnEffects && effectsPlaying == false) {
alarmSwitchedOnEffectsPlaying = true;
effectsPlaying = true;
effectsStage = 0;
nextEffectMillis = millis();
playAlarmSwitchedOnEffects = false;
}
if (alarmSwitchedOnEffectsPlaying && effectsPlaying) {
if (millis() > nextEffectMillis) {
effectsStage++;
switch (effectsStage) {
case 1:
setPattern((const byte[4]) {
0b0000,
0b0000,
0b0000,
0b1111
});
tone(speakerPin, 1568);
nextEffectMillis += 200;
break;
case 2:
setPattern((const byte[4]) {
0b0000,
0b0000,
0b1111,
0b1111
});
tone(speakerPin, 1661);
nextEffectMillis += 200;
break;
case 3:
setPattern((const byte[4]) {
0b0000,
0b1111,
0b1111,
0b1111
});
tone(speakerPin, 1760);
nextEffectMillis += 200;
break;
case 4:
ledsOn();
tone(speakerPin, 1865);
nextEffectMillis += 500;
break;
case 5:
allOff();
nextEffectMillis += 100;
break;
default:
alarmSwitchedOnEffectsPlaying = false;
effectsPlaying = false;
}
}
}
if (playAlarmSwitchedOffEffects && effectsPlaying == false) {
alarmSwitchedOffEffectsPlaying = true;
effectsPlaying = true;
effectsStage = 0;
nextEffectMillis = millis();
playAlarmSwitchedOffEffects = false;
}
if (alarmSwitchedOffEffectsPlaying && effectsPlaying) {
if (millis() > nextEffectMillis) {
effectsStage++;
switch (effectsStage) {
case 1:
ledsOn();
tone(speakerPin, 1865);
nextEffectMillis += 200;
break;
case 2:
setPattern((const byte[4]) {
0b0000,
0b1111,
0b1111,
0b1111
});
tone(speakerPin, 1760);
nextEffectMillis += 200;
break;
case 3:
setPattern((const byte[4]) {
0b0000,
0b0000,
0b1111,
0b1111
});
tone(speakerPin, 1661);
nextEffectMillis += 200;
break;
case 4:
setPattern((const byte[4]) {
0b0000,
0b0000,
0b0000,
0b1111
});
tone(speakerPin, 1568);
nextEffectMillis += 200;
break;
case 5:
allOff();
nextEffectMillis += 100;
break;
default:
alarmSwitchedOffEffectsPlaying = false;
effectsPlaying = false;
}
}
}
if (playModeSetClockEffects && effectsPlaying == false) {
modeSetClockEffectsPlaying = true;
effectsPlaying = true;
effectsStage = 0;
nextEffectMillis = millis();
playModeSetClockEffects = false;
}
if (modeSetClockEffectsPlaying && effectsPlaying) {
if (millis() > nextEffectMillis) {
effectsStage++;
switch (effectsStage) {
case 1:
ledsOff();
nextEffectMillis += 100;
break;
default:
modeSetClockEffectsPlaying = false;
effectsPlaying = false;
}
}
}
if (playModeSetAlarmEffects && effectsPlaying == false) {
modeSetAlarmEffectsPlaying = true;
effectsPlaying = true;
effectsStage = 0;
nextEffectMillis = millis();
playModeSetAlarmEffects = false;
}
if (modeSetAlarmEffectsPlaying && effectsPlaying) {
if (millis() > nextEffectMillis) {
effectsStage++;
switch (effectsStage) {
case 1:
ledsOff();
nextEffectMillis += 100;
tone(speakerPin, 1865);
break;
case 2:
effectDisplayClock = true;
nextEffectMillis += 100;
tone(speakerPin, 1865);
break;
default:
noTone(speakerPin);
effectDisplayClock = false;
modeSetAlarmEffectsPlaying = false;
effectsPlaying = false;
}
}
}
if (playAlarm) {
alarmPlaying = true;
effectsPlaying = true;
effectsStage = 0;
nextEffectMillis = millis();
playAlarm = false;
}
if (alarmPlaying && effectsPlaying) {
if (millis() > nextEffectMillis) {
effectsStage++;
switch (effectsStage) {
case 1:
effectDisplayClock = false;
ledsOn();
tone(speakerPin, 1865);
nextEffectMillis += 500;
break;
case 2:
effectDisplayClock = true;
noTone(speakerPin);
nextEffectMillis += 500;
break;
case 3:
effectDisplayClock = false;
ledsOn();
tone(speakerPin, 1865);
nextEffectMillis += 1000;
break;
case 4:
noTone(speakerPin);
effectDisplayClock = true;
nextEffectMillis += 1000;
alarmRepeats++;
if (alarmRepeats < 200) { // 3 seconds per sequence; 200x2 = 600 seconds = 10 minutes.
effectsStage = 0;
}
break;
default:
alarmPlaying = false;
alarmRepeats = 0;
effectDisplayClock = false;
effectsPlaying = false;
clockMode = MODE_CLOCK;
}
}
}
//
// if (playButtonPressEffects && effectsPlaying == false) {
// buttonPressEffectsPlaying = true;
// effectsPlaying = true;
// effectsStage = 0;
// nextEffectMillis = millis();
// playButtonPressEffects = false;
// }
//
// if (buttonPressEffectsPlaying && effectsPlaying) {
// if (millis() > nextEffectMillis) {
// effectsStage++;
// switch (effectsStage) {
// case 1:
// break;
//
// default:
// buttonPressEffectsPlaying = false;
// effectsPlaying = false;
// }
// }
// }
if (playSnoozeOffEffects && effectsPlaying == false) {
snoozeOffEffectsPlaying = true;
effectsPlaying = true;
effectsStage = 0;
nextEffectMillis = millis();
playSnoozeOffEffects = false;
}
if (snoozeOffEffectsPlaying && effectsPlaying) {
if (millis() > nextEffectMillis) {
effectsStage++;
switch (effectsStage) {
case 1:
ledsOff();
nextEffectMillis += 50;
break;
case 2:
ledsOn();
nextEffectMillis += 200;
break;
case 3:
ledsOff();
nextEffectMillis += 50;
break;
default:
snoozeOffEffectsPlaying = false;
effectsPlaying = false;
}
}
}
if (playFinishTimeSettingEffects && effectsPlaying == false) {
finishTimeSettingEffectsPlaying = true;
effectsPlaying = true;
effectsStage = 0;
nextEffectMillis = millis();
playFinishTimeSettingEffects = false;
}
if (finishTimeSettingEffectsPlaying && effectsPlaying) {
if (millis() > nextEffectMillis) {
effectsStage++;
byte pattern[4];
switch (effectsStage) {
case 1:
ledsOn();
nextEffectMillis += 500;
break;
case 2:
pattern[0] = displayRow(3);
pattern[1] = 0b1111;
pattern[2] = 0b1111;
pattern[3] = 0b1111;
setPattern(pattern);
nextEffectMillis += 200;
break;
case 3:
pattern[0] = displayRow(3);
pattern[1] = displayRow(2);
pattern[2] = 0b1111;
pattern[3] = 0b1111;
setPattern(pattern);
nextEffectMillis += 200;
break;
case 4:
pattern[0] = displayRow(3);
pattern[1] = displayRow(2);
pattern[2] = displayRow(1);
pattern[3] = 0b1111;
setPattern(pattern);
nextEffectMillis += 200;
break;
default:
finishTimeSettingEffectsPlaying = false;
effectsPlaying = false;
}
}
}
}
byte displayRow(byte n) {
byte hourUnit = selectedHour % 10;
byte minuteUnit = selectedMinute % 10;
byte hourTens = int(selectedHour / 10);
byte minuteTens = int(selectedMinute / 10);
byte row = 0;
row |= (minuteUnit >> n) & 1;
row |= ((minuteTens >> n) & 1) << 1;
row |= ((hourUnit >> n) & 1) << 2;
row |= ((hourTens >> n) & 1) << 3;
return row;
}