#include #include "time.h" #include #include #define MOD(a,b) ((((a)%(b))+(b))%(b)) // LDR (GL5516 ) is connected to GPIO 34 (Analog ADC1_CH6, 12bit resolution default // Light Resistance (at 10 Lux): 5-10 Kohm // Dark Resistance: 0.5 Mohm // over a 56k voltage divider . Dark (0.5MOhm) , 10Lux (5-10kOhm) #define LDR_PIN A6 // How many leds in your strip? #define colorSaturation 128 #define MINIMAL_BRIGHTNESS 2 #define NUM_LEDS 60 #define COLOR_ORDER GRB #define DATA_PIN 17 #define SERIAL_BAUD 9600 // Define the array of leds NeoPixelBrightnessBus strip(NUM_LEDS, DATA_PIN); //NeoPixelBus strip(NUM_LEDS, DATA_PIN); //NeoPixelBus 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 black(0); RgbwColor unknown(30, 48, 40, 0); //darkish dirt RgbwColor gold(HtmlColor( 0xFFD700 ) ); RgbwColor orangered(HtmlColor( 0xFF4500 ) ); RgbwColor orange(HtmlColor( 0xFFA500 ) ); 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; const int daylightOffset_sec = 3600; struct tm timeinfo; volatile int currentSec = 59; volatile int currentMin = 1; volatile int currentHour = 1; // variable for storing the potentiometer value volatile int ldrValue = 0; // WebPortal const char thingName[] = "NTP-Clock-RGBLED"; const char wifiInitialApPassword[] = "abcdefgh"; #define STRING_LEN 63 #define NUMBER_LEN 4 // -- Configuration specific key. The value should be modified if config structure was changed. #define CONFIG_VERSION "dem2" DNSServer dnsServer; WebServer server(80); char ntpServerParamValue[STRING_LEN] = "pool.ntp.org"; char brightnessParamValue[NUMBER_LEN] = "100"; IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION); IotWebConfParameter ntpServerParam = IotWebConfParameter("NTP Server", "ntpServer", ntpServerParamValue, STRING_LEN, "text", "pool.ntp.org", "pool.ntp.org"); IotWebConfSeparator separator1 = IotWebConfSeparator("LED settings"); IotWebConfParameter brightnessParam = IotWebConfParameter("BRIGHTNESS", "brightness", brightnessParamValue, NUMBER_LEN, "number", "10..254", "100", "min='10' max='254' step='1'"); void printLocalTime() { if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); return; } Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); } /** Handle web requests to "/" path. */ void handleRoot() { // -- Let IotWebConf test and handle captive portal requests. if (iotWebConf.handleCaptivePortal()) { // -- Captive portal request were already served. return; } String s = ""; s += "RGB LED ClockRGB LED Clock Config"; s += "
    "; s += "
  • NTP Server: \t"; s += ntpServerParamValue; s += "
  • Brightness value: \t"; s += atoi(brightnessParamValue); //s += "
  • Float param value: "; //s += atof(floatParamValue); s += "
"; s += "Go to configure page to change values."; s += "\n"; server.send(200, "text/html", s); } void configSaved() { Serial.println("Configuration was updated."); } boolean formValidator() { Serial.println("Validating form."); boolean valid = true; int l = server.arg(ntpServerParam.getId()).length(); if (l < 3) { ntpServerParam.errorMessage = "Please provide at least 3 characters for this test!"; valid = false; } int b = atoi(brightnessParamValue); if (b < MINIMAL_BRIGHTNESS || b > 254) { valid = false; } //TODO check brightness return valid; } void iotWebConf_Setup() { iotWebConf.addParameter(&ntpServerParam); iotWebConf.addParameter(&separator1); iotWebConf.addParameter(&brightnessParam); //iotWebConf.addParameter(&separator2); //iotWebConf.addParameter(&floatParam); iotWebConf.setConfigSavedCallback(&configSaved); iotWebConf.setWifiConnectionCallback(&syncNTP); iotWebConf.setFormValidator(&formValidator); iotWebConf.getApTimeoutParameter()->visible = true; // -- Initializing the configuration. iotWebConf.init(); // -- Set up required URL handlers on the web server. server.on("/", handleRoot); server.on("/config", [] { iotWebConf.handleConfig(); }); server.onNotFound([]() { iotWebConf.handleNotFound(); }); Serial.println("Ready."); } void syncNTP() { if (iotWebConf.getState() == 4) { //init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServerParamValue); printLocalTime(); //inverted logic - remaining time currentSec = 60 - timeinfo.tm_sec; currentMin = 60 - timeinfo.tm_min; currentHour = 12 - (timeinfo.tm_hour % 12); Serial.println("NTP mapped: " + String(currentHour) + ":" + String(currentMin) + ":" + String(currentSec)); } } void setup() { //interrupt for one second@80Mhz! timer = timerBegin(0, 80, true); timerAttachInterrupt(timer, &onTimer, true); timerAlarmWrite(timer, 1000000, true); timerAlarmEnable(timer); pinMode(LDR_PIN, INPUT); pinMode(DATA_PIN, OUTPUT); Serial.begin(SERIAL_BAUD); strip.Begin(); strip.Show(); //currentSec = 40; currentMin = 1; currentHour = 2; iotWebConf_Setup(); //syncNTP(); } void brightnessSet() { int BRIGHTNESS = atoi(brightnessParamValue); int x; if (ldrValue == 0) { strip.SetBrightness( BRIGHTNESS ); } else { x = int(MINIMAL_BRIGHTNESS + ( (BRIGHTNESS - MINIMAL_BRIGHTNESS) / (ldrValue / 64) + 1) ); if (strip.GetBrightness() != x) { strip.SetBrightness( x ); } } Serial.println("Brightness: " + String( x ) + "(" + String(ldrValue) + ")"); ldrValue = 0; } void loop() { // -- doLoop should be called as frequently as possible. iotWebConf.doLoop(); if (interruptCounter > 0) { portENTER_CRITICAL(&timerMux); interruptCounter--; currentSec--; portEXIT_CRITICAL(&timerMux); //brigthness measurement ldrValue = (ldrValue + analogRead(LDR_PIN)) / 2; //Serial.println(ldrValue); if (currentSec < 0) { currentSec = 59; currentMin--; brightnessSet(); if (currentMin < 0) { currentMin = 59; currentHour--; if (currentHour < 0) { currentHour = 11; //timerAlarmDisable(timer); //ESP.restart(); syncNTP(); //timerAlarmEnable(timer); } } //Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour * 5) + ":" + String(currentMin) + ":" + String(currentSec)); } //reset color strip.SetPixelColor((currentSec + 1) % NUM_LEDS, white); strip.SetPixelColor((currentMin + 1) % NUM_LEDS, white); strip.SetPixelColor(((currentHour + 1) * 5 - 1) % NUM_LEDS, white); strip.SetPixelColor(((currentHour + 1) * 5 + 1) % NUM_LEDS, white); //1 dot hour marking for (int dot = 0; dot < NUM_LEDS; dot++) { if (dot % 5 == 0) { strip.SetPixelColor(dot, orangered); } } //3 dots hour if (currentHour == 0) { strip.SetPixelColor(59 % NUM_LEDS, gold); } else { strip.SetPixelColor((currentHour * 5 - 1) % NUM_LEDS, gold); } strip.SetPixelColor((currentHour * 5) % NUM_LEDS, gold); strip.SetPixelColor((currentHour * 5 + 1) % NUM_LEDS, gold); strip.SetPixelColor(0, blue); //define high noon //strip.SetPixelColor(NUM_LEDS / 2, CRGB::Green; //define half noon strip.SetPixelColor((currentSec + 0) % NUM_LEDS, black); strip.SetPixelColor((currentMin + 0) % NUM_LEDS, orange); strip.Show(); } }