diff --git a/60LED_WS2812B_NTP_Clock.ino b/60LED_WS2812B_NTP_Clock.ino index b2467fe..24e863d 100644 --- a/60LED_WS2812B_NTP_Clock.ino +++ b/60LED_WS2812B_NTP_Clock.ino @@ -1,5 +1,9 @@ #include #include "time.h" + +#include + + #include #include @@ -21,20 +25,27 @@ bool singleSecond = true; //show seconds bool allDotsOn = true; //lighten up all leds bool followingHour = true; //move hour like an analog one -bool setupDone = false; int volatile hourOffset = 0; +void bootAnimCallback(); +void clockTickCallback(); +void ledRefreshCallback(); +void brightnessAdjustmentCallback(); + #ifdef RGBW #define MINIMAL_BRIGHTNESS 5 #define LDR_SCALE 16 #define colorSaturation 255 -NeoPixelBrightnessBus strip(NUM_LEDS, DATA_PIN); //SK6812 +//NeoPixelBrightnessBus strip(NUM_LEDS, DATA_PIN); //SK6812 +NeoPixelBrightnessBus strip(NUM_LEDS, DATA_PIN); RgbwColor red(colorSaturation, 0, 0, 0); RgbwColor green(0, colorSaturation, 0, 0); RgbwColor blue(0, 0, colorSaturation, 0); -RgbwColor white(colorSaturation); +RgbwColor realWhite(colorSaturation); +RgbColor white(0, 0, 0, 40); //darkish dirt +RgbwColor whiter(0, 0, 0, 120); //darkish dirt +RgbwColor white12(0,0,0,192); //darkish dirt RgbwColor black(0); -RgbwColor unknown(30, 48, 40, 0); //darkish dirt RgbwColor gold(HtmlColor( 0xFFD700 ) ); RgbwColor orangered(HtmlColor( 0xFF4500 ) ); RgbwColor orange(HtmlColor( 0xFFA500 ) ); @@ -61,16 +72,6 @@ RgbColor darkred(HtmlColor(0x800000)); RgbColor temp; #endif -volatile signed int interruptCounter; -hw_timer_t * timer = NULL; -portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; - -void IRAM_ATTR onTimer() { - portENTER_CRITICAL_ISR(&timerMux); - interruptCounter++; - portEXIT_CRITICAL_ISR(&timerMux); -} - //NTP handler //const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 3600; //ToDo changable from user @@ -111,6 +112,14 @@ IotWebConfParameter maxBrightnessParam = IotWebConfParameter("Max BRIGHTNESS", " //ToDo color Picker Second, 12Clock, Minute, Hour + +Task bootAnim(200, TASK_FOREVER, &bootAnimCallback); +Task clockTick(1000, TASK_FOREVER, &clockTickCallback); +Task ledRefresh(200, TASK_FOREVER, &ledRefreshCallback); +Task brightness(10000, TASK_FOREVER, &brightnessAdjustmentCallback); +//Task iotwebconfLoop(200, TASK_FOREVER, &iotWebConf.doLoop); +Scheduler runner; + String printLocalTime() { if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); @@ -233,139 +242,128 @@ void syncNTP() { //inverted logic - remaining time currentSec = 60 - timeinfo.tm_sec; currentMin = 60 - timeinfo.tm_min; - currentHour = 12 - (timeinfo.tm_hour % 12); + currentHour = 12 - MOD(timeinfo.tm_hour, 12); Serial.println("NTP mapped: " + String(currentHour) + ":" + String(currentMin) + ":" + String(currentSec)); - setupDone = true; + bootAnim.disable(); + ledRefresh.enable(); + clockTick.enable(); + brightness.enable(); } } void setup() { - //interrupt for one second - timer = timerBegin(0, 80, true); - timerAttachInterrupt(timer, &onTimer, true); - timerAlarmWrite(timer, 1000000, true); - timerAlarmEnable(timer); pinMode(LDR_PIN, INPUT_PULLUP); pinMode(DATA_PIN, OUTPUT); Serial.begin(SERIAL_BAUD); Serial.flush(); - Serial.print("\nCPU Frequency is: "); + Serial.print("\n\n\nCPU Frequency is: "); Serial.print(getCpuFrequencyMhz()); //Get CPU clock Serial.println(" Mhz"); + Serial.println("-----------------------\nSettings\n-----------------------"); + Serial.printf("Show single second: \t%s\n", singleSecond ? "yes" : "no"); + Serial.printf("Lighten up all LEDs: \t%s\n", allDotsOn ? "yes" : "no"); + Serial.printf("Following Hour: \t%s\n\n", followingHour? "yes" : "no"); + strip.Begin(); strip.SetBrightness( MINIMAL_BRIGHTNESS ); strip.ClearTo(white); - /* - for (int dot = 0; dot < NUM_LEDS; dot++) { - strip.SetPixelColor(dot, white); - } - */ strip.Show(); - iotWebConf.delay(250); + + runner.init(); + runner.addTask(ledRefresh); + runner.addTask(clockTick); + runner.addTask(brightness); + runner.addTask(bootAnim); + bootAnim.enable(); iotWebConf_Setup(); //Serial.end(); - if (followingHour) { - hourOffset = 0 - ((60 - currentMin) / 12); //negative value - } } void loop() { - // -- doLoop should be called as frequently as possible. + runner.execute(); iotWebConf.doLoop(); /* while (Serial.available()) Serial.read(); */ - if (!setupDone && interruptCounter > 0) { - if (currentSec < 0) { - currentSec = 59; - currentMin--; - } - strip.ClearTo(black); - strip.SetPixelColor((currentSec + 0) % NUM_LEDS, white); - strip.SetPixelColor((currentSec - 1) % NUM_LEDS, whiter); - strip.SetPixelColor((currentSec - 2) % NUM_LEDS, white12); - strip.Show(); - portENTER_CRITICAL(&timerMux); - interruptCounter--; - currentSec--; - portEXIT_CRITICAL(&timerMux); - } - if (setupDone && interruptCounter > 0) { - //brigthness measurement - ldrValue = (ldrValue + analogRead(LDR_PIN)); - //Serial.println(ldrValue); - if (currentSec % 10 == 0) { - //brigthness begin - ldrValue = ldrValue / 10; - int x; - if (ldrValue == 0) { - strip.SetBrightness( MAX_BRIGHTNESS ); - } - else { - x = int(MINIMAL_BRIGHTNESS + (MAX_BRIGHTNESS - MINIMAL_BRIGHTNESS) / ((ldrValue / LDR_SCALE) + 1) ); - strip.SetBrightness(x); - } - //Serial.println("Brightness: " + String(strip.GetBrightness()) + "(" + String(ldrValue) + ")"); - ldrValue = 0; - //brightness end - } - if (currentSec < 0) { - currentSec = 59; - currentMin--; - - if (currentMin < 0) { - currentMin = 59; - currentHour--; - if (currentHour < 0) { - currentHour = 11; - //timerAlarmDisable(timer); - syncNTP(); - //timerAlarmEnable(timer); - } - } - if (followingHour) { - hourOffset = 0 - ((60 - currentMin) / 12); //negative value - //Serial.println("hourOffset: " + String(hourOffset)); - } - //Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour * 5) + ":" + String(currentMin) + ":" + String(currentSec)); - } - - temp = allDotsOn ? white : black; - strip.ClearTo(temp); - //1 dot hour marking - for (int dot = 0; dot < NUM_LEDS; dot++) { - if (dot % 5 == 0) { - strip.SetPixelColor(dot, whiter); - } - } - //3 dots hour - if (currentHour == 0) { - strip.SetPixelColor((59 + hourOffset) % NUM_LEDS, gold); - } - else { - strip.SetPixelColor((currentHour * 5 - 1 + hourOffset) % NUM_LEDS, gold); - } - strip.SetPixelColor((currentHour * 5 + hourOffset) % NUM_LEDS, gold); - strip.SetPixelColor((currentHour * 5 + 1 + hourOffset) % NUM_LEDS, gold); - - strip.SetPixelColor(0, white12); //define high noon - //strip.SetPixelColor(NUM_LEDS / 2, green; //define half noon - - if (singleSecond) { - strip.SetPixelColor((currentSec + 0) % NUM_LEDS, (allDotsOn ? black : white)); - } - strip.SetPixelColor((currentMin + 0) % NUM_LEDS, darkred); - strip.Show(); - - portENTER_CRITICAL(&timerMux); - interruptCounter--; - currentSec--; - portEXIT_CRITICAL(&timerMux); - } +} + +void ledRefreshCallback() { + temp = allDotsOn ? white : black; + strip.ClearTo(temp); + //1 dot hour marking + for (int dot = 0; dot < NUM_LEDS; dot++) { + if (MOD(dot, 5) == 0) { + strip.SetPixelColor(dot, whiter); + } + } + //3 dots hour + strip.SetPixelColor(MOD((currentHour * 5 - 1 + hourOffset), NUM_LEDS), gold); + strip.SetPixelColor(MOD((currentHour * 5 + 0 + hourOffset), NUM_LEDS), gold); + strip.SetPixelColor(MOD((currentHour * 5 + 1 + hourOffset), NUM_LEDS), gold); + + strip.SetPixelColor(0, white12); //define high noon + + if (singleSecond) { + strip.SetPixelColor(MOD((currentSec + 0), NUM_LEDS), (allDotsOn ? black : white)); + } + strip.SetPixelColor(MOD((currentMin + 0), NUM_LEDS), darkred); + strip.Show(); +} + +// Scheduler +void clockTickCallback() { + ldrValue = (ldrValue + analogRead(LDR_PIN)); + if (currentSec < 0) { + currentSec = 59; + currentMin--; + if (currentMin < 0) { + currentMin = 59; + currentHour--; + if (currentHour < 0) { + currentHour = 11; + syncNTP(); + } + } + if (followingHour) { + hourOffset = 0 - ((60 - currentMin) / 12); //negative value + //Serial.println("hourOffset: " + String(hourOffset)); + } + //Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour * 5) + ":" + String(currentMin) + ":" + String(currentSec)); + } + currentSec--; +} + +void bootAnimCallback() { + strip.ClearTo(black); + currentSec--; + if (currentSec < 0) { + currentSec = 59; + } + strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), white); + strip.SetPixelColor(MOD((currentSec - 1), NUM_LEDS), whiter); + strip.SetPixelColor(MOD((currentSec - 2), NUM_LEDS), white12); + strip.Show(); +} + +void brightnessAdjustmentCallback() { + //Serial.println(ldrValue); + //brigthness begin + ldrValue = ldrValue / 10; + int x; + if (ldrValue == 0) { + strip.SetBrightness( MAX_BRIGHTNESS ); + } + else { + x = int(MINIMAL_BRIGHTNESS + (MAX_BRIGHTNESS - MINIMAL_BRIGHTNESS) / ((ldrValue / LDR_SCALE) + 1) ); + strip.SetBrightness(x); + } + //Serial.println("Brightness: " + String(strip.GetBrightness()) + "(" + String(ldrValue) + ")"); + ldrValue = 0; + strip.Show(); }