first file split
This commit is contained in:
parent
4ae62c3cda
commit
32f559aeba
@ -197,36 +197,6 @@ const char wifiInitialApPassword[] = "12345678";
|
|||||||
// -- Configuration specific key. The value should be modified if config structure was changed.
|
// -- Configuration specific key. The value should be modified if config structure was changed.
|
||||||
#define CONFIG_VERSION "V1.1.8"
|
#define CONFIG_VERSION "V1.1.8"
|
||||||
|
|
||||||
const char CUSTOMHTML_SCRIPT_INNER[] PROGMEM = "\n\
|
|
||||||
function colorCh(id)\n\
|
|
||||||
{\n\
|
|
||||||
var x=document.getElementById(id);\n\
|
|
||||||
var s=document.getElementById(id + 'Val');\n\
|
|
||||||
s.innerHTML = x.value;\n\
|
|
||||||
}\n\n\
|
|
||||||
document.addEventListener('DOMContentLoaded', function(event) {\n\
|
|
||||||
let elements = document.querySelectorAll('input[type=\"password\"]');\n\
|
|
||||||
for (let p of elements) {\n\
|
|
||||||
let btn = document.createElement('INPUT'); btn.type = 'button'; btn.value = '🔓'; btn.style.width = 'auto'; p.style.width = '80%'; p.parentNode.insertBefore(btn,p.nextSibling);\n\
|
|
||||||
btn.onclick = function() { if (p.type === 'password') { p.type = 'text'; btn.value = '🔒'; } else { p.type = 'password'; btn.value = '🔓'; } }\n\
|
|
||||||
};\n\
|
|
||||||
});\n";
|
|
||||||
|
|
||||||
// -- We need to create our custom HtmlFormatProvider to add some javasripts.
|
|
||||||
class CustomHtmlFormatProvider : public iotwebconf::HtmlFormatProvider
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
String getScriptInner() override
|
|
||||||
{
|
|
||||||
return
|
|
||||||
HtmlFormatProvider::getScriptInner() +
|
|
||||||
String(FPSTR(CUSTOMHTML_SCRIPT_INNER));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
// -- Javascript block will be added to the header.
|
|
||||||
//const char CUSTOMHTML_BODY_INNER[] PROGMEM = " <link rel='icon' href='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎯</text></svg>'>";
|
|
||||||
//const char CUSTOMHTML_BODY_INNER[] PROGMEM = " <link rel='icon' src='data:image/png;base64,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'/>";
|
|
||||||
DNSServer dnsServer;
|
DNSServer dnsServer;
|
||||||
WebServer server(80);
|
WebServer server(80);
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -323,216 +293,6 @@ Task brightnessFading(333, TASK_FOREVER, &brightnessFadingCallback);
|
|||||||
Task iotwebconfLoop(1000, TASK_FOREVER, &iotWebConfLoopCallback);
|
Task iotwebconfLoop(1000, TASK_FOREVER, &iotWebConfLoopCallback);
|
||||||
Scheduler runner;
|
Scheduler runner;
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
bool getLocalTime(struct tm * info, uint32_t ms)
|
|
||||||
{
|
|
||||||
uint32_t start = millis();
|
|
||||||
time_t now;
|
|
||||||
while ((millis() - start) <= ms) {
|
|
||||||
time(&now);
|
|
||||||
localtime_r(&now, info);
|
|
||||||
if (info->tm_year > (2016 - 1900)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String printLocalTime() {
|
|
||||||
if (!getLocalTime(&timeinfo, 200)) {
|
|
||||||
Serial.println("Failed to obtain time");
|
|
||||||
NTPreachable = false;
|
|
||||||
return "N/A";
|
|
||||||
}
|
|
||||||
//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);
|
|
||||||
NTPreachable = true;
|
|
||||||
return timeStringBuff;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Handle web requests to "/" path.
|
|
||||||
*/
|
|
||||||
void iotWebConfHandleRoot() {
|
|
||||||
// -- Let IotWebConf test and handle captive portal requests.
|
|
||||||
if (iotWebConf.handleCaptivePortal())
|
|
||||||
{
|
|
||||||
// -- Captive portal request were already served.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//char sTemp[12];
|
|
||||||
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
|
|
||||||
s += "<meta http-equiv=\"refresh\" content=\"30\">";
|
|
||||||
//s += CUSTOMHTML_BODY_INNER;
|
|
||||||
s += "<title>RGB LED Clock</title></head><body>";
|
|
||||||
s += "RGB LED Clock";
|
|
||||||
s += "<p>";
|
|
||||||
s += "<table>";
|
|
||||||
s += "<tr><td>Current Time:</td><td>";
|
|
||||||
s += printLocalTime();
|
|
||||||
s += "</td></tr></table><table>";
|
|
||||||
s += "<tr></tr><tr><td>NTP Server:</td><td>";
|
|
||||||
s += ntpServerParam.value();
|
|
||||||
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 += maxBrightnessParam.value();
|
|
||||||
s += "</td></tr><tr><td>Show Seconds: </td><td>";
|
|
||||||
s += (singleSecondParam.isChecked() ? "Yes" : "No");
|
|
||||||
s += "</td></tr><tr><td>All Dots On: </td><td>";
|
|
||||||
s += (allDotsOnParam.isChecked() ? "Yes" : "No");
|
|
||||||
s += "</td></tr><tr><td>Following Hour: </td><td>";
|
|
||||||
s += (followingHourParam.isChecked() ? "Yes" : "No");
|
|
||||||
s += "</td></tr><tr><td>";
|
|
||||||
s += "<tr><td>High noon: </td><td style=\"border: 1px solid #000000; background-color:";
|
|
||||||
s += highnoonColorParam.value();
|
|
||||||
s += ";\"><td></tr>";
|
|
||||||
s += "<tr><td>Hour color: </td><td style=\"border: 1px solid #000000; background-color:";
|
|
||||||
s += hourColorParam.value();
|
|
||||||
s += ";\"><td></tr>";
|
|
||||||
s += "<tr><td>Minute color: </td><td style=\"border: 1px solid #000000; background-color:";
|
|
||||||
s += minuteColorParam.value();
|
|
||||||
s += ";\"><td></tr>";
|
|
||||||
if (singleSecond) {
|
|
||||||
s += "<tr><td>Seconds color: </td><td style=\"border: 1px solid #000000; background-color:";
|
|
||||||
s += secondsColorParam.value();
|
|
||||||
s += ";\"><td></tr>";
|
|
||||||
}
|
|
||||||
if (allDotsOn) {
|
|
||||||
s += "<tr><td>Backlight: </td><td style=\"border: 1px solid #000000; background-color:";
|
|
||||||
s += backlightColorParam.value();
|
|
||||||
s += ";\"><td></tr>";
|
|
||||||
}
|
|
||||||
s += "<tr><td>Hour Marking: </td><td style=\"border: 1px solid #000000; background-color:";
|
|
||||||
s += hourMarkingColorParam.value();
|
|
||||||
s += ";\"><td></tr></table>";
|
|
||||||
s += "<p>";
|
|
||||||
s += "Go to <a href='config'>configure page</a> to change values.";
|
|
||||||
s += "</body></html>\n";
|
|
||||||
|
|
||||||
server.send(200, "text/html; charset=UTF-8", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void iotWebConfConfigSaved()
|
|
||||||
{
|
|
||||||
//ToDo ntpServerParamValue;
|
|
||||||
MAX_BRIGHTNESS = maxBrightnessParam.value();
|
|
||||||
singleSecond = singleSecondParam.isChecked() ? true : false;
|
|
||||||
//Serial.println(singleSecondParam.isChecked() ? "true" : "false");
|
|
||||||
allDotsOn = allDotsOnParam.isChecked() ? true : false;
|
|
||||||
//Serial.println(allDotsOnParam.isChecked() ? "true" : "false");
|
|
||||||
#if NUM_LEDS == 60
|
|
||||||
followingHour = followingHourParam.isChecked() ? true : false;
|
|
||||||
if (!followingHour) {
|
|
||||||
hourOffset = 0 ;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
//Serial.println(followingHourParam.isChecked() ? "true" : "false");
|
|
||||||
|
|
||||||
transformHtmltoStrip(&highnoonColor, (char*)&highnoonColorParam.value());
|
|
||||||
transformHtmltoStrip(&hourColor, (char*)&hourColorParam.value());
|
|
||||||
transformHtmltoStrip(&minuteColor, (char*)&minuteColorParam.value());
|
|
||||||
transformHtmltoStrip(&secondsColor, (char*)&secondsColorParam.value());
|
|
||||||
transformHtmltoStrip(&backlightColor, (char*)&backlightColorParam.value());
|
|
||||||
transformHtmltoStrip(&hourMarkingColor, (char*)&hourMarkingColorParam.value());
|
|
||||||
Serial.println("Configuration was updated.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void iotWebConf_Setup() {
|
|
||||||
|
|
||||||
timeGroup.addItem(&ntpServerParam);
|
|
||||||
|
|
||||||
ledGroup.addItem(&maxBrightnessParam);
|
|
||||||
ledGroup.addItem(&singleSecondParam);
|
|
||||||
ledGroup.addItem(&allDotsOnParam);
|
|
||||||
#if NUM_LEDS == 60
|
|
||||||
ledGroup.addItem(&followingHourParam);
|
|
||||||
#endif
|
|
||||||
ledGroup.addItem(&hourColorParam);
|
|
||||||
ledGroup.addItem(&minuteColorParam);
|
|
||||||
ledGroup.addItem(&secondsColorParam);
|
|
||||||
ledGroup.addItem(&highnoonColorParam);
|
|
||||||
ledGroup.addItem(&backlightColorParam);
|
|
||||||
ledGroup.addItem(&hourMarkingColorParam);
|
|
||||||
|
|
||||||
iotWebConf.addParameterGroup(&timeGroup);
|
|
||||||
iotWebConf.addParameterGroup(&ledGroup);
|
|
||||||
|
|
||||||
iotWebConf.setConfigSavedCallback(&iotWebConfConfigSaved);
|
|
||||||
//iotWebConf.setWifiConnectionTimeoutMs(60000);
|
|
||||||
iotWebConf.setWifiConnectionCallback(&syncNTP); //NTP call after connection established
|
|
||||||
//iotWebConf.setFormValidator(&iotWebConfFormValidator);
|
|
||||||
iotWebConf.getApTimeoutParameter()->visible = true;
|
|
||||||
iotWebConf.setupUpdateServer(
|
|
||||||
[](const char* updatePath) {
|
|
||||||
httpUpdater.setup(&server, updatePath);
|
|
||||||
},
|
|
||||||
[](const char* userName, char* password) {
|
|
||||||
httpUpdater.updateCredentials(userName, password);
|
|
||||||
});
|
|
||||||
|
|
||||||
iotWebConf.setHtmlFormatProvider(&customHtmlFormatProvider);
|
|
||||||
// -- Initializing the configuration.
|
|
||||||
iotWebConf.init();
|
|
||||||
|
|
||||||
// -- Set up required URL handlers on the web server.
|
|
||||||
server.on("/", iotWebConfHandleRoot);
|
|
||||||
server.on("/config", [] { iotWebConf.handleConfig(); });
|
|
||||||
server.onNotFound([]() {
|
|
||||||
iotWebConf.handleNotFound();
|
|
||||||
});
|
|
||||||
|
|
||||||
Serial.println("Ready.");
|
|
||||||
Serial.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void syncNTP() {
|
|
||||||
if (iotWebConf.getState() == iotwebconf::OnLine) {
|
|
||||||
//init and get the time
|
|
||||||
#ifdef ESP8266
|
|
||||||
//sntp_servermode_dhcp(0);
|
|
||||||
configTime(MYTZ, ntpServerParam.value());
|
|
||||||
#endif
|
|
||||||
#ifdef ESP32
|
|
||||||
configTime(0, 0, ntpServer);
|
|
||||||
// TZ string information: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
|
||||||
setenv("TZ", "AEST-10", 1);
|
|
||||||
tzset(); // save the TZ variable
|
|
||||||
//setTimeZone(long offset, int daylight);
|
|
||||||
//configTime(gmtOffset_sec, daylightOffset_sec, ntpServerParamValue);
|
|
||||||
#endif
|
|
||||||
Serial.println(printLocalTime());
|
|
||||||
if (NTPreachable) {
|
|
||||||
if (clockwiseRing) {
|
|
||||||
currentSec = timeinfo.tm_sec;
|
|
||||||
currentMin = timeinfo.tm_min;
|
|
||||||
currentHour = MOD(timeinfo.tm_hour, 12);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//inverted logic - remaining time
|
|
||||||
currentSec = 60 - timeinfo.tm_sec;
|
|
||||||
currentMin = 60 - timeinfo.tm_min;
|
|
||||||
currentHour = 12 - MOD(timeinfo.tm_hour, 12);
|
|
||||||
}
|
|
||||||
Serial.println("NTP mapped: " + String(int(currentHour * NUM_LEDS / 12)) + ":" + String(int(currentMin * NUM_LEDS / 60)) + ":" + String(int(currentSec * NUM_LEDS / 60)));
|
|
||||||
bootAnim.disable();
|
|
||||||
iotWebConfConfigSaved();
|
|
||||||
ledRefresh.enable();
|
|
||||||
#ifdef LDR_PIN
|
|
||||||
brightnessFading.enable();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
clockTick.enable(); //enable to check for ntp every 60 seconds
|
|
||||||
brightnessAdjustment.enable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
#ifdef LDR_PIN
|
#ifdef LDR_PIN
|
||||||
pinMode(LDR_PIN, INPUT_PULLUP);
|
pinMode(LDR_PIN, INPUT_PULLUP);
|
||||||
@ -613,161 +373,3 @@ void loop()
|
|||||||
Serial.read();
|
Serial.read();
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void ledRefreshCallback() {
|
|
||||||
temp = allDotsOn ? backlightColor : black;
|
|
||||||
strip.ClearTo(temp);
|
|
||||||
for (int dot = 0; dot < NUM_LEDS; dot++) {
|
|
||||||
#if NUM_LEDS == 60
|
|
||||||
//1 dot hour marking
|
|
||||||
if (MOD(dot, 5) == 0) {
|
|
||||||
strip.SetPixelColor(dot, hourMarkingColor);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if NUM_LEDS == 24
|
|
||||||
//1 dot quarter marking
|
|
||||||
if (MOD(dot, 6) == 0) {
|
|
||||||
strip.SetPixelColor(dot, hourMarkingColor);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
strip.SetPixelColor(0, highnoonColor); //define high noon
|
|
||||||
|
|
||||||
#if NUM_LEDS == 60
|
|
||||||
//3 dots hour
|
|
||||||
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 - 1 + hourOffset), NUM_LEDS), hourColor);
|
|
||||||
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 + 0 + hourOffset), NUM_LEDS), hourColor);
|
|
||||||
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 + 1 + hourOffset), NUM_LEDS), hourColor);
|
|
||||||
if (singleSecond) {
|
|
||||||
strip.SetPixelColor(MOD(int(currentSec * NUM_LEDS / 60 + 0), NUM_LEDS), allDotsOn ? secondsColor : backlightColor);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 + 0 + hourOffset), NUM_LEDS) , hourColor);
|
|
||||||
#endif
|
|
||||||
strip.SetPixelColor(MOD(int(currentMin * NUM_LEDS / 60 + 0), NUM_LEDS), minuteColor);
|
|
||||||
strip.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scheduler
|
|
||||||
void clockTickCallback() {
|
|
||||||
#ifdef LDR_PIN
|
|
||||||
ldrValue = (ldrValue + analogRead(LDR_PIN));
|
|
||||||
#endif
|
|
||||||
if (clockwiseRing) {
|
|
||||||
if (currentSec >= 60) {
|
|
||||||
currentSec = 0;
|
|
||||||
currentMin++;
|
|
||||||
if (!NTPreachable) {
|
|
||||||
syncNTP();
|
|
||||||
}
|
|
||||||
if (currentMin >= 60) {
|
|
||||||
currentMin = 0;
|
|
||||||
currentHour++;
|
|
||||||
if (currentHour >= 12) {
|
|
||||||
currentHour = 0;
|
|
||||||
syncNTP();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (followingHour) {
|
|
||||||
hourOffset = int(currentMin * NUM_LEDS / 60 / 12);
|
|
||||||
//Serial.println("clockwise hourOffset: " + String(hourOffset));
|
|
||||||
}
|
|
||||||
//Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour / (12 / NUM_LEDS)) + ":" + String(currentMin / (60 / NUM_LEDS)) + ":" + String(currentSec / (60 / NUM_LEDS)));
|
|
||||||
}
|
|
||||||
currentSec++;
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (currentSec < 0) {
|
|
||||||
currentSec = 59;
|
|
||||||
currentMin--;
|
|
||||||
if (!NTPreachable) {
|
|
||||||
syncNTP();
|
|
||||||
}
|
|
||||||
if (currentMin < 0) {
|
|
||||||
currentMin = 59;
|
|
||||||
currentHour--;
|
|
||||||
if (currentHour < 0) {
|
|
||||||
currentHour = 11;
|
|
||||||
syncNTP();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (followingHour) {
|
|
||||||
hourOffset = 0 - int((60 - currentMin * NUM_LEDS / 60) / 12); //negative value
|
|
||||||
//Serial.println("Anticlockwise hourOffset: " + String(hourOffset));
|
|
||||||
}
|
|
||||||
//Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour / (12 / NUM_LEDS)) + ":" + String(currentMin / (60 / NUM_LEDS)) + ":" + String(currentSec / (60 / NUM_LEDS)));
|
|
||||||
}
|
|
||||||
currentSec--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootAnimCallback() {
|
|
||||||
strip.ClearTo(black);
|
|
||||||
int tail = -1;
|
|
||||||
if (clockwiseRing) {
|
|
||||||
currentSec++;
|
|
||||||
if (currentSec >= NUM_LEDS) {
|
|
||||||
currentSec = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentSec--;
|
|
||||||
tail = 1;
|
|
||||||
if (currentSec < 0) {
|
|
||||||
currentSec = NUM_LEDS - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iotWebConf.getState() == iotwebconf::OnLine && !NTPreachable) {
|
|
||||||
strip.ClearTo(white);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), black);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), black);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), black);
|
|
||||||
}
|
|
||||||
if (iotWebConf.getState() == iotwebconf::Connecting ) {
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), white);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), whiter);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), white12);
|
|
||||||
}
|
|
||||||
if (iotWebConf.getState() == iotwebconf::ApMode ) {
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), lightgreen);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), green);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), darkgreen);
|
|
||||||
}
|
|
||||||
if (iotWebConf.getState() == iotwebconf::Boot || iotWebConf.getState() == iotwebconf::NotConfigured) {
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), orangered);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), red);
|
|
||||||
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), darkred);
|
|
||||||
}
|
|
||||||
|
|
||||||
strip.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LDR_PIN
|
|
||||||
void brightnessAdjustmentCallback() {
|
|
||||||
//Serial.println(ldrValue);
|
|
||||||
//brigthness begin
|
|
||||||
ldrValue = ldrValue / 10;
|
|
||||||
if (ldrValue == 0) {
|
|
||||||
targetBrightness = MAX_BRIGHTNESS;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
targetBrightness = int(MINIMAL_BRIGHTNESS + (MAX_BRIGHTNESS - MINIMAL_BRIGHTNESS) / ((ldrValue / LDR_SCALE) + 1) );
|
|
||||||
}
|
|
||||||
//Serial.println("Brightness: " + String(strip.GetBrightness()) + "(" + String(ldrValue) + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
void brightnessFadingCallback() {
|
|
||||||
int currentBrightness = strip.GetBrightness();
|
|
||||||
int diff = targetBrightness - currentBrightness;
|
|
||||||
int rate = rint(diff / 10);
|
|
||||||
strip.SetBrightness(currentBrightness + rate);
|
|
||||||
strip.Show();
|
|
||||||
//Serial.println("Brightness: " + String(currentBrightness) + " diff " + String(rate));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void iotWebConfLoopCallback() {
|
|
||||||
iotWebConf.doLoop();
|
|
||||||
}
|
|
||||||
|
170
iotwebconf.ino
Normal file
170
iotwebconf.ino
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
const char CUSTOMHTML_SCRIPT_INNER[] PROGMEM = "\n\
|
||||||
|
function colorCh(id)\n\
|
||||||
|
{\n\
|
||||||
|
var x=document.getElementById(id);\n\
|
||||||
|
var s=document.getElementById(id + 'Val');\n\
|
||||||
|
s.innerHTML = x.value;\n\
|
||||||
|
}\n\n\
|
||||||
|
document.addEventListener('DOMContentLoaded', function(event) {\n\
|
||||||
|
let elements = document.querySelectorAll('input[type=\"password\"]');\n\
|
||||||
|
for (let p of elements) {\n\
|
||||||
|
let btn = document.createElement('INPUT'); btn.type = 'button'; btn.value = '🔓'; btn.style.width = 'auto'; p.style.width = '80%'; p.parentNode.insertBefore(btn,p.nextSibling);\n\
|
||||||
|
btn.onclick = function() { if (p.type === 'password') { p.type = 'text'; btn.value = '🔒'; } else { p.type = 'password'; btn.value = '🔓'; } }\n\
|
||||||
|
};\n\
|
||||||
|
});\n";
|
||||||
|
|
||||||
|
// -- We need to create our custom HtmlFormatProvider to add some javasripts.
|
||||||
|
class CustomHtmlFormatProvider : public iotwebconf::HtmlFormatProvider
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
String getScriptInner() override
|
||||||
|
{
|
||||||
|
return
|
||||||
|
HtmlFormatProvider::getScriptInner() +
|
||||||
|
String(FPSTR(CUSTOMHTML_SCRIPT_INNER));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
// -- Javascript block will be added to the header.
|
||||||
|
//const char CUSTOMHTML_BODY_INNER[] PROGMEM = " <link rel='icon' href='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎯</text></svg>'>";
|
||||||
|
//const char CUSTOMHTML_BODY_INNER[] PROGMEM = " <link rel='icon' src='data:image/png;base64,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'/>";
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handle web requests to "/" path.
|
||||||
|
*/
|
||||||
|
void iotWebConfHandleRoot() {
|
||||||
|
// -- Let IotWebConf test and handle captive portal requests.
|
||||||
|
if (iotWebConf.handleCaptivePortal())
|
||||||
|
{
|
||||||
|
// -- Captive portal request were already served.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//char sTemp[12];
|
||||||
|
String s = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/>";
|
||||||
|
s += "<meta http-equiv=\"refresh\" content=\"30\">";
|
||||||
|
//s += CUSTOMHTML_BODY_INNER;
|
||||||
|
s += "<title>RGB LED Clock</title></head><body>";
|
||||||
|
s += "RGB LED Clock";
|
||||||
|
s += "<p>";
|
||||||
|
s += "<table>";
|
||||||
|
s += "<tr><td>Current Time:</td><td>";
|
||||||
|
s += printLocalTime();
|
||||||
|
s += "</td></tr></table><table>";
|
||||||
|
s += "<tr></tr><tr><td>NTP Server:</td><td>";
|
||||||
|
s += ntpServerParam.value();
|
||||||
|
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 += maxBrightnessParam.value();
|
||||||
|
s += "</td></tr><tr><td>Show Seconds: </td><td>";
|
||||||
|
s += (singleSecondParam.isChecked() ? "Yes" : "No");
|
||||||
|
s += "</td></tr><tr><td>All Dots On: </td><td>";
|
||||||
|
s += (allDotsOnParam.isChecked() ? "Yes" : "No");
|
||||||
|
s += "</td></tr><tr><td>Following Hour: </td><td>";
|
||||||
|
s += (followingHourParam.isChecked() ? "Yes" : "No");
|
||||||
|
s += "</td></tr><tr><td>";
|
||||||
|
s += "<tr><td>High noon: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||||
|
s += highnoonColorParam.value();
|
||||||
|
s += ";\"><td></tr>";
|
||||||
|
s += "<tr><td>Hour color: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||||
|
s += hourColorParam.value();
|
||||||
|
s += ";\"><td></tr>";
|
||||||
|
s += "<tr><td>Minute color: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||||
|
s += minuteColorParam.value();
|
||||||
|
s += ";\"><td></tr>";
|
||||||
|
if (singleSecond) {
|
||||||
|
s += "<tr><td>Seconds color: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||||
|
s += secondsColorParam.value();
|
||||||
|
s += ";\"><td></tr>";
|
||||||
|
}
|
||||||
|
if (allDotsOn) {
|
||||||
|
s += "<tr><td>Backlight: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||||
|
s += backlightColorParam.value();
|
||||||
|
s += ";\"><td></tr>";
|
||||||
|
}
|
||||||
|
s += "<tr><td>Hour Marking: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||||
|
s += hourMarkingColorParam.value();
|
||||||
|
s += ";\"><td></tr></table>";
|
||||||
|
s += "<p>";
|
||||||
|
s += "Go to <a href='config'>configure page</a> to change values.";
|
||||||
|
s += "</body></html>\n";
|
||||||
|
|
||||||
|
server.send(200, "text/html; charset=UTF-8", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iotWebConfConfigSaved()
|
||||||
|
{
|
||||||
|
//ToDo ntpServerParamValue;
|
||||||
|
MAX_BRIGHTNESS = maxBrightnessParam.value();
|
||||||
|
singleSecond = singleSecondParam.isChecked() ? true : false;
|
||||||
|
//Serial.println(singleSecondParam.isChecked() ? "true" : "false");
|
||||||
|
allDotsOn = allDotsOnParam.isChecked() ? true : false;
|
||||||
|
//Serial.println(allDotsOnParam.isChecked() ? "true" : "false");
|
||||||
|
#if NUM_LEDS == 60
|
||||||
|
followingHour = followingHourParam.isChecked() ? true : false;
|
||||||
|
if (!followingHour) {
|
||||||
|
hourOffset = 0 ;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//Serial.println(followingHourParam.isChecked() ? "true" : "false");
|
||||||
|
|
||||||
|
transformHtmltoStrip(&highnoonColor, (char*)&highnoonColorParam.value());
|
||||||
|
transformHtmltoStrip(&hourColor, (char*)&hourColorParam.value());
|
||||||
|
transformHtmltoStrip(&minuteColor, (char*)&minuteColorParam.value());
|
||||||
|
transformHtmltoStrip(&secondsColor, (char*)&secondsColorParam.value());
|
||||||
|
transformHtmltoStrip(&backlightColor, (char*)&backlightColorParam.value());
|
||||||
|
transformHtmltoStrip(&hourMarkingColor, (char*)&hourMarkingColorParam.value());
|
||||||
|
Serial.println("Configuration was updated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void iotWebConf_Setup() {
|
||||||
|
|
||||||
|
timeGroup.addItem(&ntpServerParam);
|
||||||
|
|
||||||
|
ledGroup.addItem(&maxBrightnessParam);
|
||||||
|
ledGroup.addItem(&singleSecondParam);
|
||||||
|
ledGroup.addItem(&allDotsOnParam);
|
||||||
|
#if NUM_LEDS == 60
|
||||||
|
ledGroup.addItem(&followingHourParam);
|
||||||
|
#endif
|
||||||
|
ledGroup.addItem(&hourColorParam);
|
||||||
|
ledGroup.addItem(&minuteColorParam);
|
||||||
|
ledGroup.addItem(&secondsColorParam);
|
||||||
|
ledGroup.addItem(&highnoonColorParam);
|
||||||
|
ledGroup.addItem(&backlightColorParam);
|
||||||
|
ledGroup.addItem(&hourMarkingColorParam);
|
||||||
|
|
||||||
|
iotWebConf.addParameterGroup(&timeGroup);
|
||||||
|
iotWebConf.addParameterGroup(&ledGroup);
|
||||||
|
|
||||||
|
iotWebConf.setConfigSavedCallback(&iotWebConfConfigSaved);
|
||||||
|
//iotWebConf.setWifiConnectionTimeoutMs(60000);
|
||||||
|
iotWebConf.setWifiConnectionCallback(&syncNTP); //NTP call after connection established
|
||||||
|
//iotWebConf.setFormValidator(&iotWebConfFormValidator);
|
||||||
|
iotWebConf.getApTimeoutParameter()->visible = true;
|
||||||
|
iotWebConf.setupUpdateServer(
|
||||||
|
[](const char* updatePath) {
|
||||||
|
httpUpdater.setup(&server, updatePath);
|
||||||
|
},
|
||||||
|
[](const char* userName, char* password) {
|
||||||
|
httpUpdater.updateCredentials(userName, password);
|
||||||
|
});
|
||||||
|
|
||||||
|
iotWebConf.setHtmlFormatProvider(&customHtmlFormatProvider);
|
||||||
|
// -- Initializing the configuration.
|
||||||
|
iotWebConf.init();
|
||||||
|
|
||||||
|
// -- Set up required URL handlers on the web server.
|
||||||
|
server.on("/", iotWebConfHandleRoot);
|
||||||
|
server.on("/config", [] { iotWebConf.handleConfig(); });
|
||||||
|
server.onNotFound([]() {
|
||||||
|
iotWebConf.handleNotFound();
|
||||||
|
});
|
||||||
|
|
||||||
|
Serial.println("Ready.");
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void iotWebConfLoopCallback() {
|
||||||
|
iotWebConf.doLoop();
|
||||||
|
}
|
100
ledcontrol.ino
Normal file
100
ledcontrol.ino
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
void ledRefreshCallback() {
|
||||||
|
temp = allDotsOn ? backlightColor : black;
|
||||||
|
strip.ClearTo(temp);
|
||||||
|
for (int dot = 0; dot < NUM_LEDS; dot++) {
|
||||||
|
#if NUM_LEDS == 60
|
||||||
|
//1 dot hour marking
|
||||||
|
if (MOD(dot, 5) == 0) {
|
||||||
|
strip.SetPixelColor(dot, hourMarkingColor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if NUM_LEDS == 24
|
||||||
|
//1 dot quarter marking
|
||||||
|
if (MOD(dot, 6) == 0) {
|
||||||
|
strip.SetPixelColor(dot, hourMarkingColor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
strip.SetPixelColor(0, highnoonColor); //define high noon
|
||||||
|
|
||||||
|
#if NUM_LEDS == 60
|
||||||
|
//3 dots hour
|
||||||
|
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 - 1 + hourOffset), NUM_LEDS), hourColor);
|
||||||
|
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 + 0 + hourOffset), NUM_LEDS), hourColor);
|
||||||
|
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 + 1 + hourOffset), NUM_LEDS), hourColor);
|
||||||
|
if (singleSecond) {
|
||||||
|
strip.SetPixelColor(MOD(int(currentSec * NUM_LEDS / 60 + 0), NUM_LEDS), allDotsOn ? secondsColor : backlightColor);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
strip.SetPixelColor(MOD(int(currentHour * NUM_LEDS / 12 + 0 + hourOffset), NUM_LEDS) , hourColor);
|
||||||
|
#endif
|
||||||
|
strip.SetPixelColor(MOD(int(currentMin * NUM_LEDS / 60 + 0), NUM_LEDS), minuteColor);
|
||||||
|
strip.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootAnimCallback() {
|
||||||
|
strip.ClearTo(black);
|
||||||
|
int tail = -1;
|
||||||
|
if (clockwiseRing) {
|
||||||
|
currentSec++;
|
||||||
|
if (currentSec >= NUM_LEDS) {
|
||||||
|
currentSec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentSec--;
|
||||||
|
tail = 1;
|
||||||
|
if (currentSec < 0) {
|
||||||
|
currentSec = NUM_LEDS - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iotWebConf.getState() == iotwebconf::OnLine && !NTPreachable) {
|
||||||
|
strip.ClearTo(white);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), black);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), black);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), black);
|
||||||
|
}
|
||||||
|
if (iotWebConf.getState() == iotwebconf::Connecting ) {
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), white);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), whiter);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), white12);
|
||||||
|
}
|
||||||
|
if (iotWebConf.getState() == iotwebconf::ApMode ) {
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), lightgreen);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), green);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), darkgreen);
|
||||||
|
}
|
||||||
|
if (iotWebConf.getState() == iotwebconf::Boot || iotWebConf.getState() == iotwebconf::NotConfigured) {
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 0), NUM_LEDS), orangered);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 1 * tail), NUM_LEDS), red);
|
||||||
|
strip.SetPixelColor(MOD((currentSec - 2 * tail), NUM_LEDS), darkred);
|
||||||
|
}
|
||||||
|
|
||||||
|
strip.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LDR_PIN
|
||||||
|
void brightnessAdjustmentCallback() {
|
||||||
|
//Serial.println(ldrValue);
|
||||||
|
//brigthness begin
|
||||||
|
ldrValue = ldrValue / 10;
|
||||||
|
if (ldrValue == 0) {
|
||||||
|
targetBrightness = MAX_BRIGHTNESS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
targetBrightness = int(MINIMAL_BRIGHTNESS + (MAX_BRIGHTNESS - MINIMAL_BRIGHTNESS) / ((ldrValue / LDR_SCALE) + 1) );
|
||||||
|
}
|
||||||
|
//Serial.println("Brightness: " + String(strip.GetBrightness()) + "(" + String(ldrValue) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
void brightnessFadingCallback() {
|
||||||
|
int currentBrightness = strip.GetBrightness();
|
||||||
|
int diff = targetBrightness - currentBrightness;
|
||||||
|
int rate = rint(diff / 10);
|
||||||
|
strip.SetBrightness(currentBrightness + rate);
|
||||||
|
strip.Show();
|
||||||
|
//Serial.println("Brightness: " + String(currentBrightness) + " diff " + String(rate));
|
||||||
|
}
|
||||||
|
#endif
|
129
realtime.ino
Normal file
129
realtime.ino
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
bool getLocalTime(struct tm * info, uint32_t ms)
|
||||||
|
{
|
||||||
|
uint32_t start = millis();
|
||||||
|
time_t now;
|
||||||
|
while ((millis() - start) <= ms) {
|
||||||
|
time(&now);
|
||||||
|
localtime_r(&now, info);
|
||||||
|
if (info->tm_year > (2016 - 1900)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String printLocalTime() {
|
||||||
|
if (!getLocalTime(&timeinfo, 200)) {
|
||||||
|
Serial.println("Failed to obtain time");
|
||||||
|
NTPreachable = false;
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
//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);
|
||||||
|
NTPreachable = true;
|
||||||
|
return timeStringBuff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void syncNTP() {
|
||||||
|
if (iotWebConf.getState() == iotwebconf::OnLine) {
|
||||||
|
//init and get the time
|
||||||
|
#ifdef ESP8266
|
||||||
|
//sntp_servermode_dhcp(0);
|
||||||
|
configTime(MYTZ, ntpServerParam.value());
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
configTime(0, 0, ntpServer);
|
||||||
|
// TZ string information: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
||||||
|
setenv("TZ", "AEST-10", 1);
|
||||||
|
tzset(); // save the TZ variable
|
||||||
|
//setTimeZone(long offset, int daylight);
|
||||||
|
//configTime(gmtOffset_sec, daylightOffset_sec, ntpServerParamValue);
|
||||||
|
#endif
|
||||||
|
Serial.println(printLocalTime());
|
||||||
|
if (NTPreachable) {
|
||||||
|
if (clockwiseRing) {
|
||||||
|
currentSec = timeinfo.tm_sec;
|
||||||
|
currentMin = timeinfo.tm_min;
|
||||||
|
currentHour = MOD(timeinfo.tm_hour, 12);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//inverted logic - remaining time
|
||||||
|
currentSec = 60 - timeinfo.tm_sec;
|
||||||
|
currentMin = 60 - timeinfo.tm_min;
|
||||||
|
currentHour = 12 - MOD(timeinfo.tm_hour, 12);
|
||||||
|
}
|
||||||
|
Serial.println("NTP mapped: " + String(int(currentHour * NUM_LEDS / 12)) + ":" + String(int(currentMin * NUM_LEDS / 60)) + ":" + String(int(currentSec * NUM_LEDS / 60)));
|
||||||
|
bootAnim.disable();
|
||||||
|
iotWebConfConfigSaved();
|
||||||
|
ledRefresh.enable();
|
||||||
|
#ifdef LDR_PIN
|
||||||
|
brightnessFading.enable();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
clockTick.enable(); //enable to check for ntp every 60 seconds
|
||||||
|
brightnessAdjustment.enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scheduler
|
||||||
|
void clockTickCallback() {
|
||||||
|
#ifdef LDR_PIN
|
||||||
|
ldrValue = (ldrValue + analogRead(LDR_PIN));
|
||||||
|
#endif
|
||||||
|
if (clockwiseRing) {
|
||||||
|
if (currentSec >= 60) {
|
||||||
|
currentSec = 0;
|
||||||
|
currentMin++;
|
||||||
|
if (!NTPreachable) {
|
||||||
|
syncNTP();
|
||||||
|
}
|
||||||
|
if (currentMin >= 60) {
|
||||||
|
currentMin = 0;
|
||||||
|
currentHour++;
|
||||||
|
if (currentHour >= 12) {
|
||||||
|
currentHour = 0;
|
||||||
|
syncNTP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (followingHour) {
|
||||||
|
hourOffset = int(currentMin * NUM_LEDS / 60 / 12);
|
||||||
|
//Serial.println("clockwise hourOffset: " + String(hourOffset));
|
||||||
|
}
|
||||||
|
//Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour / (12 / NUM_LEDS)) + ":" + String(currentMin / (60 / NUM_LEDS)) + ":" + String(currentSec / (60 / NUM_LEDS)));
|
||||||
|
}
|
||||||
|
currentSec++;
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (currentSec < 0) {
|
||||||
|
currentSec = 59;
|
||||||
|
currentMin--;
|
||||||
|
if (!NTPreachable) {
|
||||||
|
syncNTP();
|
||||||
|
}
|
||||||
|
if (currentMin < 0) {
|
||||||
|
currentMin = 59;
|
||||||
|
currentHour--;
|
||||||
|
if (currentHour < 0) {
|
||||||
|
currentHour = 11;
|
||||||
|
syncNTP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (followingHour) {
|
||||||
|
hourOffset = 0 - int((60 - currentMin * NUM_LEDS / 60) / 12); //negative value
|
||||||
|
//Serial.println("Anticlockwise hourOffset: " + String(hourOffset));
|
||||||
|
}
|
||||||
|
//Serial.println(String(interruptCounter) + " | Ring Index: " + String(currentHour / (12 / NUM_LEDS)) + ":" + String(currentMin / (60 / NUM_LEDS)) + ":" + String(currentSec / (60 / NUM_LEDS)));
|
||||||
|
}
|
||||||
|
currentSec--;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user