LED-Clock/60LED_WS2812B_NTP_Clock.ino

370 lines
12 KiB
Arduino
Raw Normal View History

2019-12-11 08:03:32 +00:00
#include <WiFi.h>
#include "time.h"
#include <TaskScheduler.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-12-26 15:00:29 +00:00
/* Model I
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)
*/
2020-09-27 06:29:14 +00:00
#define LDR_PIN A6
2020-12-26 15:00:29 +00:00
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-12-26 15:00:29 +00:00
#define SERIAL_BAUD 115200
//#define RGBW
bool singleSecond = true; //show seconds
bool allDotsOn = true; //lighten up all leds
bool followingHour = true; //move hour like an analog one
int volatile hourOffset = 0;
void bootAnimCallback();
void clockTickCallback();
void ledRefreshCallback();
void brightnessAdjustmentCallback();
2020-12-26 15:00:29 +00:00
#ifdef RGBW
#define MINIMAL_BRIGHTNESS 5
#define LDR_SCALE 16
#define colorSaturation 255
//NeoPixelBrightnessBus<NeoGrbwFeature, Neo800KbpsMethod> strip(NUM_LEDS, DATA_PIN); //SK6812
NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s1800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
2020-09-27 06:29:14 +00:00
RgbwColor red(colorSaturation, 0, 0, 0);
RgbwColor green(0, colorSaturation, 0, 0);
RgbwColor blue(0, 0, colorSaturation, 0);
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
2020-09-27 06:29:14 +00:00
RgbwColor black(0);
RgbwColor gold(HtmlColor( 0xFFD700 ) );
RgbwColor orangered(HtmlColor( 0xFF4500 ) );
RgbwColor orange(HtmlColor( 0xFFA500 ) );
2020-12-26 15:00:29 +00:00
RgbwColor darkred(HtmlColor(0x800000));
RgbwColor temp;
#else
#define MINIMAL_BRIGHTNESS 20
#define LDR_SCALE 16
#define colorSaturation 192
//NeoPixelBrightnessBus<NeoGrbFeature, Neo800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
2020-12-26 15:00:29 +00:00
RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
RgbColor realWhite(colorSaturation);
RgbColor black(0);
RgbColor white(30, 40, 35); //darkish dirt
RgbColor whiter(120, 120, 120); //darkish dirt
RgbColor white12(255, 255, 255); //darkish dirt
RgbColor gold(HtmlColor( 0xFFD700 ) );
RgbColor orangered(HtmlColor( 0xFF4500 ) );
RgbColor orange(HtmlColor( 0xFFA500 ) );
RgbColor darkred(HtmlColor(0x800000));
RgbColor temp;
#endif
2019-12-11 08:03:32 +00:00
2020-05-03 12:53:41 +00:00
//NTP handler
//const char* ntpServer = "pool.ntp.org";
2020-12-26 15:00:29 +00:00
const long gmtOffset_sec = 3600; //ToDo changable from user
2020-05-03 12:53:41 +00:00
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
2020-12-26 15:00:29 +00:00
volatile unsigned int ldrValue = 0;
int MAX_BRIGHTNESS = 200;
2019-12-11 08:03:32 +00:00
2020-05-03 12:53:41 +00:00
// WebPortal
const char thingName[] = "NTP-Clock-RGBLED";
2020-12-26 15:00:29 +00:00
const char wifiInitialApPassword[] = "12345678";
2020-05-03 12:53:41 +00:00
#define STRING_LEN 63
#define NUMBER_LEN 4
// -- Configuration specific key. The value should be modified if config structure was changed.
2020-12-26 15:00:29 +00:00
#define CONFIG_VERSION "dem3"
2020-05-03 12:53:41 +00:00
DNSServer dnsServer;
WebServer server(80);
char ntpServerParamValue[STRING_LEN] = "pool.ntp.org";
2020-12-26 15:00:29 +00:00
char maxBrightnessParamValue[NUMBER_LEN] = "100";
2020-05-03 12:53:41 +00:00
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");
2020-12-26 15:00:29 +00:00
IotWebConfParameter maxBrightnessParam = IotWebConfParameter("Max BRIGHTNESS", "max brightness", maxBrightnessParamValue, NUMBER_LEN, "number", "20..254", "200", "min='20' max='254' step='1'");
//IotWebConfParameter singleSecondParam = IotWebConfParameter("Show Seconds", "singleSecond", singleSecondParamValue, STRING_LEN, "text", "Yes", "Yes");
//IotWebConfParameter allDotsOnParam = IotWebConfParameter("all Dots lighten on", "allDotsOn", allDotsOnParamValue, STRING_LEN, "text", "Yes", "Yes");
//IotWebConfParameter followingHourParam = IotWebConfParameter("following Hour", "followingHour ", followingHourParamValue, STRING_LEN, "text", "Yes", "Yes");
//Version3.X.X IotWebConfCheckboxParameter checkboxParam = IotWebConfCheckboxParameter("Check param", "checkParam", checkboxParamValue, STRING_LEN, true);
2019-12-11 08:03:32 +00:00
2020-12-26 15:00:29 +00:00
//ToDo color Picker Second, 12Clock, Minute, Hour
2019-12-11 08:03:32 +00:00
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;
2020-12-26 15:00:29 +00:00
String printLocalTime() {
2019-12-11 08:03:32 +00:00
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
2020-12-26 15:00:29 +00:00
return "";
2019-12-11 08:03:32 +00:00
}
2020-12-26 15:00:29 +00:00
//Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
char timeStringBuff[50]; //50 chars should be enough
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
//Serial.println(timeStringBuff);
return timeStringBuff;
2019-12-11 08:03:32 +00:00
}
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;
}
2020-12-26 15:00:29 +00:00
//char timeStringBuff[50]; //50 chars should be enough
//strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
2020-05-03 12:53:41 +00:00
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
2020-12-26 15:00:29 +00:00
s += "<meta http-equiv=\"refresh\" content=\"30\">";
s += "<meta charset=\"UTF-8\">";
s += "<title>RGB LED Clock</title></head><body>RGB LED Clock";
s += "<p>";
s += "<table>";
s += "<tr><td>Current Time:</td><td>";
s += printLocalTime();
s += "</td></tr><tr></tr><tr><td>NTP Server:</td><td>";
2020-05-03 12:53:41 +00:00
s += ntpServerParamValue;
2020-12-26 15:00:29 +00:00
s += "</td><tr><tr><td>Current Brightness value: </td><td>";
s += String(strip.GetBrightness());
s += "</td><tr><tr><td>Max Brightness value: </td><td>";
s += atoi(maxBrightnessParamValue);
s += "</td></tr><tr><td>Show Seconds: </td><td>";
s += (singleSecond ? "Yes" : "No");
s += "</td></tr><tr><td>All Dots On: </td><td>";
s += (allDotsOn ? "Yes" : "No");
s += "</td></tr><tr><td>Following Hour: </td><td>";
s += (followingHour ? "Yes" : "No");
s += "<td></tr></table>";
s += "<p>";
2020-05-03 12:53:41 +00:00
s += "Go to <a href='config'>configure page</a> to change values.";
s += "</body></html>\n";
server.send(200, "text/html", s);
}
void configSaved()
{
2020-12-26 15:00:29 +00:00
//ToDo ntpServerParamValue;
MAX_BRIGHTNESS = atoi(maxBrightnessParamValue);
2020-05-03 12:53:41 +00:00
Serial.println("Configuration was updated.");
2020-12-26 15:00:29 +00:00
2020-05-03 12:53:41 +00:00
}
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;
}
2020-12-26 15:00:29 +00:00
int b = atoi(maxBrightnessParamValue);
2020-05-03 12:53:41 +00:00
if (b < MINIMAL_BRIGHTNESS || b > 254)
{
valid = false;
}
return valid;
}
void iotWebConf_Setup() {
iotWebConf.addParameter(&ntpServerParam);
iotWebConf.addParameter(&separator1);
2020-12-26 15:00:29 +00:00
iotWebConf.addParameter(&maxBrightnessParam);
/*
iotWebConf.addParameter(&separator1);
iotWebConf.addParameter(&singleSecondParam);
iotWebConf.addParameter(&separator1);
iotWebConf.addParameter(&allDotsOnParam);
iotWebConf.addParameter(&separator1);
iotWebConf.addParameter(&followingHourParam);
*/
2020-05-03 12:53:41 +00:00
iotWebConf.setConfigSavedCallback(&configSaved);
2020-12-26 15:00:29 +00:00
iotWebConf.setWifiConnectionCallback(&syncNTP); //NTP call after connection established
2020-05-03 12:53:41 +00:00
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.");
2020-12-26 15:00:29 +00:00
Serial.flush();
2020-05-03 12:53:41 +00:00
}
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);
2020-12-26 15:00:29 +00:00
Serial.println(printLocalTime());
2020-05-03 12:53:41 +00:00
//inverted logic - remaining time
currentSec = 60 - timeinfo.tm_sec;
currentMin = 60 - timeinfo.tm_min;
currentHour = 12 - MOD(timeinfo.tm_hour, 12);
2020-05-03 12:53:41 +00:00
Serial.println("NTP mapped: " + String(currentHour) + ":" + String(currentMin) + ":" + String(currentSec));
bootAnim.disable();
ledRefresh.enable();
clockTick.enable();
brightness.enable();
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-12 18:06:56 +00:00
2020-12-26 15:00:29 +00:00
pinMode(LDR_PIN, INPUT_PULLUP);
2020-09-27 06:29:14 +00:00
pinMode(DATA_PIN, OUTPUT);
2019-12-11 08:03:32 +00:00
2020-09-27 06:29:14 +00:00
Serial.begin(SERIAL_BAUD);
2020-12-26 15:00:29 +00:00
Serial.flush();
Serial.print("\n\n\nCPU Frequency is: ");
2020-12-26 15:00:29 +00:00
Serial.print(getCpuFrequencyMhz()); //Get CPU clock
Serial.println(" Mhz");
2019-12-11 08:03:32 +00:00
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");
2020-09-27 06:29:14 +00:00
strip.Begin();
2020-12-26 15:00:29 +00:00
strip.SetBrightness( MINIMAL_BRIGHTNESS );
strip.ClearTo(white);
2020-09-27 06:29:14 +00:00
strip.Show();
runner.init();
runner.addTask(ledRefresh);
runner.addTask(clockTick);
runner.addTask(brightness);
runner.addTask(bootAnim);
bootAnim.enable();
2019-12-11 08:03:32 +00:00
2020-05-03 12:53:41 +00:00
iotWebConf_Setup();
2020-12-26 15:00:29 +00:00
//Serial.end();
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()
{
runner.execute();
2020-05-03 12:53:41 +00:00
iotWebConf.doLoop();
/*
while (Serial.available())
2020-12-26 15:00:29 +00:00
Serial.read();
*/
}
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);
2020-12-26 15:00:29 +00:00
}
}
//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
2019-12-11 08:03:32 +00:00
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();
2019-12-12 18:06:56 +00:00
}
2019-12-11 08:03:32 +00:00
}
if (followingHour) {
hourOffset = 0 - ((60 - currentMin) / 12); //negative value
//Serial.println("hourOffset: " + String(hourOffset));
2019-12-12 18:06:56 +00:00
}
//Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour * 5) + ":" + String(currentMin) + ":" + String(currentSec));
}
currentSec--;
}
2019-12-11 08:03:32 +00:00
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();
}
2020-12-26 15:00:29 +00:00
void brightnessAdjustmentCallback() {
//Serial.println(ldrValue);
//brigthness begin
ldrValue = ldrValue / 10;
int x;
if (ldrValue == 0) {
strip.SetBrightness( MAX_BRIGHTNESS );
2019-12-12 18:06:56 +00:00
}
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();
2019-12-11 08:03:32 +00:00
}