2019-12-11 08:03:32 +00:00
|
|
|
#include <WiFi.h>
|
|
|
|
#include "time.h"
|
2020-09-27 06:29:14 +00:00
|
|
|
#include <NeoPixelBrightnessBus.h>
|
2020-05-03 12:53:41 +00:00
|
|
|
#include <IotWebConf.h>
|
2019-12-11 08:03:32 +00:00
|
|
|
|
2019-12-12 18:06:56 +00:00
|
|
|
#define MOD(a,b) ((((a)%(b))+(b))%(b))
|
2020-05-03 12:53:41 +00:00
|
|
|
// LDR (GL5516 ) is connected to GPIO 34 (Analog ADC1_CH6, 12bit resolution default
|
2020-09-27 06:29:14 +00:00
|
|
|
// Light Resistance (at 10 Lux): 5-10 Kohm
|
|
|
|
// Dark Resistance: 0.5 Mohm
|
2019-12-11 08:03:32 +00:00
|
|
|
// over a 56k voltage divider . Dark (0.5MOhm) , 10Lux (5-10kOhm)
|
2020-09-27 06:29:14 +00:00
|
|
|
#define LDR_PIN A6
|
2019-12-11 08:03:32 +00:00
|
|
|
// How many leds in your strip?
|
2020-09-27 06:29:14 +00:00
|
|
|
#define colorSaturation 128
|
|
|
|
#define MINIMAL_BRIGHTNESS 2
|
2019-12-11 08:03:32 +00:00
|
|
|
#define NUM_LEDS 60
|
|
|
|
#define COLOR_ORDER GRB
|
2020-09-27 06:29:14 +00:00
|
|
|
#define DATA_PIN 17
|
2020-05-03 12:53:41 +00:00
|
|
|
#define SERIAL_BAUD 9600
|
2019-12-11 08:03:32 +00:00
|
|
|
// Define the array of leds
|
2020-09-27 06:29:14 +00:00
|
|
|
|
|
|
|
NeoPixelBrightnessBus<NeoGrbwFeature, Neo800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
|
|
|
|
//NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
|
|
|
|
//NeoPixelBus<NeoRgbFeature, Neo400KbpsMethod> 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 ) );
|
|
|
|
|
2019-12-11 08:03:32 +00:00
|
|
|
|
|
|
|
|
2019-12-12 18:06:56 +00:00
|
|
|
volatile signed int interruptCounter;
|
2019-12-11 08:03:32 +00:00
|
|
|
hw_timer_t * timer = NULL;
|
|
|
|
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
|
|
|
|
|
|
|
|
void IRAM_ATTR onTimer() {
|
|
|
|
portENTER_CRITICAL_ISR(&timerMux);
|
|
|
|
interruptCounter++;
|
|
|
|
portEXIT_CRITICAL_ISR(&timerMux);
|
|
|
|
}
|
|
|
|
|
2020-05-03 12:53:41 +00:00
|
|
|
//NTP handler
|
|
|
|
//const char* ntpServer = "pool.ntp.org";
|
|
|
|
const long gmtOffset_sec = 3600;
|
|
|
|
const int daylightOffset_sec = 3600;
|
|
|
|
struct tm timeinfo;
|
2019-12-11 08:03:32 +00:00
|
|
|
volatile int currentSec = 59;
|
|
|
|
volatile int currentMin = 1;
|
|
|
|
volatile int currentHour = 1;
|
|
|
|
|
|
|
|
// variable for storing the potentiometer value
|
|
|
|
volatile int ldrValue = 0;
|
|
|
|
|
2020-05-03 12:53:41 +00:00
|
|
|
// 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'");
|
2019-12-11 08:03:32 +00:00
|
|
|
|
|
|
|
|
2020-09-27 06:29:14 +00:00
|
|
|
void printLocalTime() {
|
2019-12-11 08:03:32 +00:00
|
|
|
if (!getLocalTime(&timeinfo)) {
|
|
|
|
Serial.println("Failed to obtain time");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
|
|
|
|
}
|
|
|
|
|
2020-05-03 12:53:41 +00:00
|
|
|
/**
|
|
|
|
Handle web requests to "/" path.
|
|
|
|
*/
|
2020-09-27 06:29:14 +00:00
|
|
|
void handleRoot() {
|
2020-05-03 12:53:41 +00:00
|
|
|
// -- Let IotWebConf test and handle captive portal requests.
|
|
|
|
if (iotWebConf.handleCaptivePortal())
|
|
|
|
{
|
|
|
|
// -- Captive portal request were already served.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
|
|
|
|
s += "<title>RGB LED Clock</title></head><body>RGB LED Clock Config";
|
|
|
|
s += "<ul>";
|
|
|
|
s += "<li>NTP Server: \t";
|
|
|
|
s += ntpServerParamValue;
|
|
|
|
s += "<li>Brightness value: \t";
|
|
|
|
s += atoi(brightnessParamValue);
|
|
|
|
//s += "<li>Float param value: ";
|
|
|
|
//s += atof(floatParamValue);
|
|
|
|
s += "</ul>";
|
|
|
|
s += "Go to <a href='config'>configure page</a> to change values.";
|
|
|
|
s += "</body></html>\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.");
|
|
|
|
}
|
|
|
|
|
2019-12-11 08:03:32 +00:00
|
|
|
void syncNTP() {
|
2020-05-03 12:53:41 +00:00
|
|
|
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));
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-03 12:53:41 +00:00
|
|
|
|
2020-09-27 06:29:14 +00:00
|
|
|
void setup() {
|
2019-12-11 08:03:32 +00:00
|
|
|
//interrupt for one second@80Mhz!
|
|
|
|
timer = timerBegin(0, 80, true);
|
|
|
|
timerAttachInterrupt(timer, &onTimer, true);
|
|
|
|
timerAlarmWrite(timer, 1000000, true);
|
|
|
|
timerAlarmEnable(timer);
|
2019-12-12 18:06:56 +00:00
|
|
|
|
2020-09-27 06:29:14 +00:00
|
|
|
pinMode(LDR_PIN, INPUT);
|
|
|
|
pinMode(DATA_PIN, OUTPUT);
|
2019-12-11 08:03:32 +00:00
|
|
|
|
2020-09-27 06:29:14 +00:00
|
|
|
Serial.begin(SERIAL_BAUD);
|
2019-12-11 08:03:32 +00:00
|
|
|
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.Begin();
|
|
|
|
strip.Show();
|
2019-12-11 08:03:32 +00:00
|
|
|
|
2019-12-12 18:06:56 +00:00
|
|
|
//currentSec = 40; currentMin = 1; currentHour = 2;
|
2020-05-03 12:53:41 +00:00
|
|
|
iotWebConf_Setup();
|
|
|
|
//syncNTP();
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
2020-05-03 12:53:41 +00:00
|
|
|
void brightnessSet() {
|
2020-09-27 06:29:14 +00:00
|
|
|
|
2020-05-03 12:53:41 +00:00
|
|
|
int BRIGHTNESS = atoi(brightnessParamValue);
|
|
|
|
int x;
|
2019-12-11 08:03:32 +00:00
|
|
|
if (ldrValue == 0) {
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.SetBrightness( BRIGHTNESS );
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-09-27 06:29:14 +00:00
|
|
|
x = int(MINIMAL_BRIGHTNESS + ( (BRIGHTNESS - MINIMAL_BRIGHTNESS) / (ldrValue / 64) + 1) );
|
|
|
|
if (strip.GetBrightness() != x) {
|
|
|
|
strip.SetBrightness( x );
|
|
|
|
}
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
2020-05-03 12:53:41 +00:00
|
|
|
Serial.println("Brightness: " + String( x ) + "(" + String(ldrValue) + ")");
|
|
|
|
ldrValue = 0;
|
2020-09-27 06:29:14 +00:00
|
|
|
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
2020-05-03 12:53:41 +00:00
|
|
|
|
2019-12-11 08:03:32 +00:00
|
|
|
void loop()
|
|
|
|
{
|
2020-05-03 12:53:41 +00:00
|
|
|
// -- doLoop should be called as frequently as possible.
|
|
|
|
iotWebConf.doLoop();
|
|
|
|
|
2019-12-11 08:03:32 +00:00
|
|
|
if (interruptCounter > 0) {
|
|
|
|
|
|
|
|
portENTER_CRITICAL(&timerMux);
|
|
|
|
interruptCounter--;
|
|
|
|
currentSec--;
|
2019-12-12 18:06:56 +00:00
|
|
|
portEXIT_CRITICAL(&timerMux);
|
2020-09-27 06:29:14 +00:00
|
|
|
|
2020-05-03 12:53:41 +00:00
|
|
|
//brigthness measurement
|
2020-09-27 06:29:14 +00:00
|
|
|
ldrValue = (ldrValue + analogRead(LDR_PIN)) / 2;
|
|
|
|
//Serial.println(ldrValue);
|
2019-12-12 18:06:56 +00:00
|
|
|
if (currentSec < 0) {
|
|
|
|
currentSec = 59;
|
|
|
|
currentMin--;
|
2020-05-03 12:53:41 +00:00
|
|
|
brightnessSet();
|
2019-12-12 18:06:56 +00:00
|
|
|
if (currentMin < 0) {
|
|
|
|
currentMin = 59;
|
|
|
|
currentHour--;
|
|
|
|
if (currentHour < 0) {
|
|
|
|
currentHour = 11;
|
|
|
|
//timerAlarmDisable(timer);
|
|
|
|
//ESP.restart();
|
|
|
|
syncNTP();
|
|
|
|
//timerAlarmEnable(timer);
|
|
|
|
}
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
2019-12-12 18:06:56 +00:00
|
|
|
//Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour * 5) + ":" + String(currentMin) + ":" + String(currentSec));
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
|
|
|
|
2019-12-12 18:06:56 +00:00
|
|
|
//reset color
|
2020-09-27 06:29:14 +00:00
|
|
|
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);
|
2019-12-12 18:06:56 +00:00
|
|
|
|
|
|
|
//1 dot hour marking
|
|
|
|
for (int dot = 0; dot < NUM_LEDS; dot++) {
|
|
|
|
if (dot % 5 == 0) {
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.SetPixelColor(dot, orangered);
|
2019-12-12 18:06:56 +00:00
|
|
|
}
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|
2019-12-12 18:06:56 +00:00
|
|
|
//3 dots hour
|
|
|
|
if (currentHour == 0) {
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.SetPixelColor(59 % NUM_LEDS, gold);
|
2019-12-12 18:06:56 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.SetPixelColor((currentHour * 5 - 1) % NUM_LEDS, gold);
|
2019-12-12 18:06:56 +00:00
|
|
|
}
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.SetPixelColor((currentHour * 5) % NUM_LEDS, gold);
|
|
|
|
strip.SetPixelColor((currentHour * 5 + 1) % NUM_LEDS, gold);
|
2019-12-12 18:06:56 +00:00
|
|
|
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.SetPixelColor(0, blue); //define high noon
|
|
|
|
//strip.SetPixelColor(NUM_LEDS / 2, CRGB::Green; //define half noon
|
2019-12-11 08:03:32 +00:00
|
|
|
|
2020-09-27 06:29:14 +00:00
|
|
|
strip.SetPixelColor((currentSec + 0) % NUM_LEDS, black);
|
|
|
|
strip.SetPixelColor((currentMin + 0) % NUM_LEDS, orange);
|
|
|
|
strip.Show();
|
2019-12-12 18:06:56 +00:00
|
|
|
}
|
2019-12-11 08:03:32 +00:00
|
|
|
}
|