Compare commits
11 Commits
refactorin
...
cleanUp
Author | SHA1 | Date | |
---|---|---|---|
|
913b4fbfaa | ||
|
8a50acdff4 | ||
|
db6cd39b01 | ||
|
32f559aeba | ||
|
4ae62c3cda | ||
|
986da87bb7 | ||
|
aaa191a66d | ||
|
825ee5ff50 | ||
|
fe2aa05b94 | ||
|
2468643acf | ||
|
96641edfe4 |
@ -1,39 +1,32 @@
|
||||
#include "time.h"
|
||||
#include <TaskScheduler.h>
|
||||
#define _TASK_SLEEP_ON_IDLE_RUN //ToDo check benefit
|
||||
|
||||
|
||||
//#include <MacroLogger.h>
|
||||
#include <NeoPixelBrightnessBus.h>
|
||||
#include <IotWebConf.h>
|
||||
#include <IotWebConfUsing.h>
|
||||
#include <IotWebConfTParameter.h>
|
||||
// UpdateServer includes
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <ESP8266WiFi.h>
|
||||
# include <ESP8266HTTPUpdateServer.h>
|
||||
#include <TZ.h>
|
||||
#define MYTZ TZ_Europe_Berlin
|
||||
#include <coredecls.h> // settimeofday_cb()
|
||||
//#include <Schedule.h>
|
||||
//#include <PolledTimeout.h>
|
||||
#include <sys/time.h> // struct timeval
|
||||
#include <sntp.h> // sntp_servermode_dhcp()
|
||||
|
||||
#elif defined(ESP32)
|
||||
#include <WiFi.h>
|
||||
// For ESP32 IotWebConf provides a drop-in replacement for UpdateServer.
|
||||
# include <IotWebConfESP32HTTPUpdateServer.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define MOD(a,b) ((((a)%(b))+(b))%(b))
|
||||
/* 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)
|
||||
-----------------
|
||||
ESP8266 24LED
|
||||
5V--10k-+-LDR--GND -ADC
|
||||
- 150k--220k-+-100k--GND
|
||||
*/
|
||||
|
||||
#ifdef ESP8266
|
||||
#define LDR_PIN A0
|
||||
#define IOTWEBCONF_DEBUG_DISABLED
|
||||
@ -57,8 +50,6 @@ volatile bool allDotsOn = true; //lighten up all leds
|
||||
#if NUM_LEDS == 60
|
||||
volatile bool followingHour = true; //move hour like an analog one
|
||||
#else
|
||||
//#endif
|
||||
//#if NUM_LEDS == 24
|
||||
volatile bool followingHour = false; //disabled due limited resolution
|
||||
#endif
|
||||
volatile int hourOffset = 0;
|
||||
@ -67,10 +58,43 @@ void bootAnimCallback();
|
||||
void clockTickCallback();
|
||||
void ledRefreshCallback();
|
||||
void brightnessAdjustmentCallback();
|
||||
void brightnessFadingCallback();
|
||||
void iotWebConfLoopCallback();
|
||||
|
||||
//https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
|
||||
#define MYTZ TZ_Europe_Berlin
|
||||
String currentNTP;
|
||||
struct tm timeinfo;
|
||||
time_t now;
|
||||
//https://github.com/arduino/esp8266/blob/master/cores/esp8266/sntp-lwip2.c
|
||||
|
||||
|
||||
//mapping for analog time representation
|
||||
volatile int currentSec = 30;
|
||||
volatile int currentMin = 50;
|
||||
volatile int currentHour = 50;
|
||||
volatile bool NTPreachable = false;
|
||||
volatile int MAX_BRIGHTNESS = 200;
|
||||
#ifdef LDR_PIN
|
||||
// variable for storing the potentiometer value
|
||||
volatile unsigned int ldrValue = 0;
|
||||
volatile unsigned int targetBrightness = MAX_BRIGHTNESS;
|
||||
#endif
|
||||
|
||||
// WebPortal
|
||||
const char thingName[] = "NTP-Clock-RGBLED";
|
||||
const char wifiInitialApPassword[] = "12345678";
|
||||
#define STRING_LEN 63
|
||||
#define NUMBER_LEN 4
|
||||
// -- Maximal length the input-range attributes can have.
|
||||
//#define COLOR_ATTR_LENGTH 60
|
||||
// -- Configuration specific key. The value should be modified if config structure was changed.
|
||||
#define CONFIG_VERSION "V1.1.10"
|
||||
|
||||
|
||||
#ifdef RGBW
|
||||
#define MINIMAL_BRIGHTNESS 5
|
||||
#define LDR_SCALE 16
|
||||
#define LDR_SCALE 4
|
||||
#define colorSaturation 255
|
||||
#ifdef ESP8266
|
||||
//NeoPixelBrightnessBus<NeoGrbwFeature, Neo800KbpsMethod> strip(NUM_LEDS);//RDX0 GPIO3
|
||||
@ -127,9 +151,9 @@ void transformHtmltoStrip(RgbwColor* outputColor, char* sInput) {
|
||||
//Serial.printf("StripColor: R:%i G:%i B:%i W:%i\n", stripColor.R, stripColor.G, stripColor.B, stripColor.W);
|
||||
memcpy(outputColor, &stripColor, sizeof(stripColor));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
#ifndef RGBW
|
||||
#define MINIMAL_BRIGHTNESS 20
|
||||
#define LDR_SCALE 16
|
||||
#define colorSaturation 192
|
||||
@ -177,33 +201,95 @@ void transformHtmltoStrip(RgbColor* outputColor, char* sInput) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//const char* ntpServer = "pool.ntp.org";
|
||||
const long gmtOffset_sec = 3600; //ToDo changable from user
|
||||
const int daylightOffset_sec = 3600;
|
||||
struct tm timeinfo;
|
||||
|
||||
volatile int currentSec = 59;
|
||||
volatile int currentMin = 1;
|
||||
volatile int currentHour = 2;
|
||||
volatile bool NTPreachable = false;
|
||||
|
||||
#ifdef LDR_PIN
|
||||
// variable for storing the potentiometer value
|
||||
volatile unsigned int ldrValue = 0;
|
||||
DNSServer dnsServer;
|
||||
WebServer server(80);
|
||||
#ifdef ESP8266
|
||||
ESP8266HTTPUpdateServer httpUpdater;
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdateServer httpUpdater;
|
||||
#endif
|
||||
volatile int MAX_BRIGHTNESS = 200;
|
||||
|
||||
// WebPortal
|
||||
const char thingName[] = "NTP-Clock-RGBLED";
|
||||
const char wifiInitialApPassword[] = "12345678";
|
||||
#define STRING_LEN 63
|
||||
#define NUMBER_LEN 4
|
||||
// -- Maximal length the input-range attributes can have.
|
||||
#define COLOR_ATTR_LENGTH 60
|
||||
// -- Configuration specific key. The value should be modified if config structure was changed.
|
||||
#define CONFIG_VERSION "V1.1.5"
|
||||
|
||||
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
|
||||
iotwebconf::ParameterGroup timeGroup = iotwebconf::ParameterGroup("Time", "Time settings");
|
||||
iotwebconf::TextTParameter<STRING_LEN> timezoneParam =
|
||||
iotwebconf::Builder<iotwebconf::TextTParameter<STRING_LEN>>("timezone").
|
||||
label("TimeZone").
|
||||
defaultValue("TZ_Europe_Berlin").
|
||||
build();
|
||||
/*
|
||||
iotwebconf::TextTParameter<STRING_LEN> ntpServerParam =
|
||||
iotwebconf::Builder<iotwebconf::TextTParameter<STRING_LEN>>("ntpServer").
|
||||
label("NTP Server").
|
||||
defaultValue("pool.ntp.org").
|
||||
build();*/
|
||||
iotwebconf::ParameterGroup ledGroup = iotwebconf::ParameterGroup("LED", "LED settings");
|
||||
iotwebconf::IntTParameter<int16_t> maxBrightnessParam =
|
||||
iotwebconf::Builder<iotwebconf::IntTParameter<int16_t>>("Max Brightness").
|
||||
label("Max brightness").
|
||||
defaultValue(200).
|
||||
min(MINIMAL_BRIGHTNESS).
|
||||
max(MAX_BRIGHTNESS).
|
||||
step(1).
|
||||
build();
|
||||
|
||||
iotwebconf::CheckboxTParameter singleSecondParam =
|
||||
iotwebconf::Builder<iotwebconf::CheckboxTParameter>("singleSecond").
|
||||
label("single Second visible").
|
||||
#if NUM_LEDS == 60
|
||||
defaultValue(true).
|
||||
build();
|
||||
#else
|
||||
defaultValue(false).
|
||||
build();
|
||||
#endif
|
||||
|
||||
iotwebconf::CheckboxTParameter allDotsOnParam =
|
||||
iotwebconf::Builder<iotwebconf::CheckboxTParameter>("allDotsOn").
|
||||
label("all Dots lighten on").
|
||||
defaultValue(true).
|
||||
build();
|
||||
|
||||
iotwebconf::CheckboxTParameter followingHourParam =
|
||||
iotwebconf::Builder<iotwebconf::CheckboxTParameter>("followingHour").
|
||||
label("following Hour").
|
||||
#if NUM_LEDS == 60
|
||||
defaultValue(true).
|
||||
build();
|
||||
#else
|
||||
defaultValue(false).
|
||||
build();
|
||||
#endif
|
||||
iotwebconf::ColorTParameter hourColorParam =
|
||||
iotwebconf::Builder<iotwebconf::ColorTParameter>("Stundenfarbe").
|
||||
label("Stundenfarbe").
|
||||
defaultValue("#FFD700").
|
||||
build();
|
||||
iotwebconf::ColorTParameter minuteColorParam =
|
||||
iotwebconf::Builder<iotwebconf::ColorTParameter>("Minutenfarbe").
|
||||
label("Minutenfarbe").
|
||||
defaultValue("#800000").
|
||||
build();
|
||||
iotwebconf::ColorTParameter secondsColorParam =
|
||||
iotwebconf::Builder<iotwebconf::ColorTParameter>("Sekundenfarbe").
|
||||
label("Sekundenfarbe").
|
||||
defaultValue("#000000").
|
||||
build();
|
||||
iotwebconf::ColorTParameter highnoonColorParam =
|
||||
iotwebconf::Builder<iotwebconf::ColorTParameter>("12 Uhr Farbe").
|
||||
label("12 Uhr Farbe").
|
||||
defaultValue("#C0C0C0").
|
||||
build();
|
||||
iotwebconf::ColorTParameter backlightColorParam =
|
||||
iotwebconf::Builder<iotwebconf::ColorTParameter>("Hintergrundfarbe").
|
||||
label("Hintergrundfarbe").
|
||||
defaultValue("#1E2823").
|
||||
build();
|
||||
iotwebconf::ColorTParameter hourMarkingColorParam =
|
||||
iotwebconf::Builder<iotwebconf::ColorTParameter>("Stundenmarkierung").
|
||||
label("Stundenmarkierung").
|
||||
defaultValue("#787878").
|
||||
build();
|
||||
const char CUSTOMHTML_SCRIPT_INNER[] PROGMEM = "\n\
|
||||
function colorCh(id)\n\
|
||||
{\n\
|
||||
@ -218,43 +304,6 @@ const char CUSTOMHTML_SCRIPT_INNER[] PROGMEM = "\n\
|
||||
btn.onclick = function() { if (p.type === 'password') { p.type = 'text'; btn.value = '🔒'; } else { p.type = 'password'; btn.value = '🔓'; } }\n\
|
||||
};\n\
|
||||
});\n";
|
||||
const char IOTWEBCONF_HTML_FORM_COLOR_PARAM[] PROGMEM =
|
||||
"<div class='{s}' '><label for='{i}'>{b}</label> (<span id='{i}Val'>{v}</span>)"
|
||||
"<input type='{t}' id='{i}' "
|
||||
"name='{i}' style=\"padding: unset\" maxlength={l} placeholder='{p}' value='{v}' {c}/>"
|
||||
"<div class='em'>{e}</div></div>\n";
|
||||
|
||||
// -- Our custom class declaration. You should move it to a .h fine in your project.
|
||||
class ColorWithValueParameter : public iotwebconf::NumberParameter
|
||||
{
|
||||
public:
|
||||
ColorWithValueParameter(
|
||||
const char* label, const char* id, char* valueBuffer, int length,
|
||||
const char* defaultValue
|
||||
) : iotwebconf::NumberParameter(
|
||||
label, id, valueBuffer, length, defaultValue)
|
||||
{
|
||||
snprintf(
|
||||
this->_colorAttr, COLOR_ATTR_LENGTH,
|
||||
"oninput='colorCh(this.id)'");
|
||||
|
||||
this->customHtml = this->_colorAttr;
|
||||
};
|
||||
protected:
|
||||
// Overrides
|
||||
virtual String renderHtml(
|
||||
bool dataArrived, bool hasValueFromPost, String valueFromPost) override
|
||||
{
|
||||
return TextParameter::renderHtml("color", hasValueFromPost, valueFromPost);
|
||||
};
|
||||
virtual String getHtmlTemplate()
|
||||
{
|
||||
return FPSTR(IOTWEBCONF_HTML_FORM_COLOR_PARAM);
|
||||
};
|
||||
|
||||
private:
|
||||
char _colorAttr[COLOR_ATTR_LENGTH];
|
||||
};
|
||||
|
||||
// -- We need to create our custom HtmlFormatProvider to add some javasripts.
|
||||
class CustomHtmlFormatProvider : public iotwebconf::HtmlFormatProvider
|
||||
@ -266,484 +315,22 @@ class CustomHtmlFormatProvider : public iotwebconf::HtmlFormatProvider
|
||||
HtmlFormatProvider::getScriptInner() +
|
||||
String(FPSTR(CUSTOMHTML_SCRIPT_INNER));
|
||||
}
|
||||
/*
|
||||
String getBodyInner() override
|
||||
{
|
||||
return
|
||||
String(FPSTR(CUSTOMHTML_BODY_INNER)) +
|
||||
HtmlFormatProvider::getBodyInner();
|
||||
}
|
||||
*/
|
||||
|
||||
};
|
||||
// -- Javascript block will be added to the header.
|
||||
/*
|
||||
const char CUSTOMHTML_SCRIPT_INNER[] PROGMEM = "\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 = '83%'; 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";
|
||||
*/
|
||||
//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;
|
||||
WebServer server(80);
|
||||
#ifdef ESP8266
|
||||
ESP8266HTTPUpdateServer httpUpdater;
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdateServer httpUpdater;
|
||||
#endif
|
||||
|
||||
char ntpServerParamValue[STRING_LEN];
|
||||
char maxBrightnessParamValue[NUMBER_LEN];
|
||||
char singleSecondParamValue[STRING_LEN];
|
||||
char allDotsOnParamValue[STRING_LEN];
|
||||
char followingHourParamValue[STRING_LEN];
|
||||
char hourColorParamValue[COLOR_ATTR_LENGTH];
|
||||
char minuteColorParamValue[COLOR_ATTR_LENGTH];
|
||||
char secondsColorParamValue[COLOR_ATTR_LENGTH];
|
||||
char highnoonColorParamValue[COLOR_ATTR_LENGTH];
|
||||
char backlightColorParamValue[COLOR_ATTR_LENGTH];
|
||||
char hourMarkingColorParamValue[COLOR_ATTR_LENGTH];
|
||||
|
||||
IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword, CONFIG_VERSION);
|
||||
IotWebConfParameterGroup timeGroup = IotWebConfParameterGroup("Time", "Time settings");
|
||||
IotWebConfTextParameter ntpServerParam = IotWebConfTextParameter("NTP Server", "ntpServer", ntpServerParamValue, STRING_LEN, "pool.ntp.org");
|
||||
IotWebConfParameterGroup ledGroup = IotWebConfParameterGroup("LED", "LED settings");
|
||||
IotWebConfNumberParameter maxBrightnessParam = IotWebConfNumberParameter("Max BRIGHTNESS", "max brightness", maxBrightnessParamValue, NUMBER_LEN, "200", "20..254", "min='20' max='254' step='1'");
|
||||
#if NUM_LEDS == 60
|
||||
IotWebConfCheckboxParameter singleSecondParam = IotWebConfCheckboxParameter("Show Seconds", "singleSecond", singleSecondParamValue, STRING_LEN, true);
|
||||
#else
|
||||
IotWebConfCheckboxParameter singleSecondParam = IotWebConfCheckboxParameter("Show Seconds", "singleSecond", singleSecondParamValue, STRING_LEN, false);
|
||||
#endif
|
||||
IotWebConfCheckboxParameter allDotsOnParam = IotWebConfCheckboxParameter("all Dots lighten on", "allDotsOn", allDotsOnParamValue, STRING_LEN, true);
|
||||
#if NUM_LEDS == 60
|
||||
IotWebConfCheckboxParameter followingHourParam = IotWebConfCheckboxParameter("following Hour", "followingHour", followingHourParamValue, STRING_LEN, true);
|
||||
#else
|
||||
IotWebConfCheckboxParameter followingHourParam = IotWebConfCheckboxParameter("following Hour", "followingHour", followingHourParamValue, STRING_LEN, false);
|
||||
#endif
|
||||
ColorWithValueParameter hourColorParam = ColorWithValueParameter("Stundenfarbe", "hourColorParam", hourColorParamValue, COLOR_ATTR_LENGTH, "#FFD700");
|
||||
ColorWithValueParameter minuteColorParam = ColorWithValueParameter("Minutenfarbe", "minuteColorParam", minuteColorParamValue, COLOR_ATTR_LENGTH, "#800000");
|
||||
ColorWithValueParameter secondsColorParam = ColorWithValueParameter("Sekundenfarbe", "secondsColorParam", secondsColorParamValue, COLOR_ATTR_LENGTH, "#000000");
|
||||
ColorWithValueParameter highnoonColorParam = ColorWithValueParameter("12Uhr Farbe", "highnoonColorParam", highnoonColorParamValue, COLOR_ATTR_LENGTH, "#C0C0C0");
|
||||
ColorWithValueParameter backlightColorParam = ColorWithValueParameter("Hintergrundfarbe", "backlightColorParam", backlightColorParamValue, COLOR_ATTR_LENGTH, "#1E2823");
|
||||
ColorWithValueParameter hourMarkingColorParam = ColorWithValueParameter("Stundenmarkierung", "hourMarkingColorParam", hourMarkingColorParamValue, COLOR_ATTR_LENGTH, "#787878");
|
||||
|
||||
|
||||
// -- An instance must be created from the class defined above.
|
||||
CustomHtmlFormatProvider customHtmlFormatProvider;
|
||||
|
||||
Task bootAnim(200, TASK_FOREVER, &bootAnimCallback);
|
||||
Task clockTick(1000, TASK_FOREVER, &clockTickCallback);
|
||||
Task ntpReachableCheck(1800000, TASK_FOREVER, &ntpReachableCheckCallback);
|
||||
Task ledRefresh(200, TASK_FOREVER, &ledRefreshCallback);
|
||||
#ifdef LDR_PIN
|
||||
Task brightness(10000, TASK_FOREVER, &brightnessAdjustmentCallback);
|
||||
Task brightnessAdjustment(10000, TASK_FOREVER, &brightnessAdjustmentCallback);
|
||||
Task brightnessFading(333, TASK_FOREVER, &brightnessFadingCallback);
|
||||
#endif
|
||||
//Task iotwebconfLoop(200, TASK_FOREVER, &iotWebConf.doLoop);
|
||||
Task iotwebconfLoop(1000, TASK_FOREVER, &iotWebConfLoopCallback);
|
||||
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 "";
|
||||
}
|
||||
//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 += ntpServerParamValue;
|
||||
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><tr><td>";
|
||||
s += "<tr><td>High noon: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||
transformtoHtmlColor ((char*)&sTemp, &highnoonColor);
|
||||
s += sTemp;
|
||||
s += ";\"><td></tr>";
|
||||
s += "<tr><td>Hour color: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||
transformtoHtmlColor ((char*)&sTemp, &hourColor);
|
||||
s += sTemp;
|
||||
s += ";\"><td></tr>";
|
||||
s += "<tr><td>Minute color: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||
transformtoHtmlColor ((char*)&sTemp, &minuteColor);
|
||||
s += sTemp;
|
||||
s += ";\"><td></tr>";
|
||||
if (singleSecond) {
|
||||
s += "<tr><td>Seconds color: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||
transformtoHtmlColor ((char*)&sTemp, &secondsColor);
|
||||
s += sTemp;
|
||||
s += ";\"><td></tr>";
|
||||
}
|
||||
if (allDotsOn) {
|
||||
s += "<tr><td>Backlight: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||
transformtoHtmlColor ((char*)&sTemp, &backlightColor);
|
||||
s += sTemp;
|
||||
s += ";\"><td></tr>";
|
||||
}
|
||||
s += "<tr><td>Hour Marking: </td><td style=\"border: 1px solid #000000; background-color:";
|
||||
transformtoHtmlColor ((char*)&sTemp, &hourMarkingColor);
|
||||
s += sTemp;
|
||||
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 = atoi(maxBrightnessParamValue);
|
||||
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;
|
||||
#endif
|
||||
//Serial.println(followingHourParam.isChecked() ? "true" : "false");
|
||||
|
||||
transformHtmltoStrip(&highnoonColor, (char*)&highnoonColorParamValue);
|
||||
transformHtmltoStrip(&hourColor, (char*)&hourColorParamValue);
|
||||
transformHtmltoStrip(&minuteColor, (char*)&minuteColorParamValue);
|
||||
transformHtmltoStrip(&secondsColor, (char*)&secondsColorParamValue);
|
||||
transformHtmltoStrip(&backlightColor, (char*)&backlightColorParamValue);
|
||||
transformHtmltoStrip(&hourMarkingColor, (char*)&hourMarkingColorParamValue);
|
||||
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.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_STATE_ONLINE) {
|
||||
//init and get the time
|
||||
#ifdef ESP8266
|
||||
//sntp_servermode_dhcp(0);
|
||||
configTime(MYTZ, ntpServerParamValue);
|
||||
#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();
|
||||
ledRefresh.enable();
|
||||
clockTick.enable();
|
||||
#ifdef LDR_PIN
|
||||
brightness.enable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
#ifdef LDR_PIN
|
||||
pinMode(LDR_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
pinMode(DATA_PIN, OUTPUT);
|
||||
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
Serial.flush();
|
||||
Serial.print("\n\n\nCPU Frequency is: ");
|
||||
#ifdef ESP8266
|
||||
Serial.print(ESP.getCpuFreqMHz());
|
||||
#elif defined(ESP32)
|
||||
Serial.print(getCpuFrequencyMhz()); //Get CPU clock
|
||||
#endif
|
||||
Serial.println(" Mhz");
|
||||
Serial.print("MAC address: ");
|
||||
Serial.println(WiFi.macAddress()); //Get CPU clock
|
||||
|
||||
strip.Begin();
|
||||
strip.ClearTo(white);
|
||||
strip.SetBrightness( MINIMAL_BRIGHTNESS );
|
||||
strip.Show();
|
||||
|
||||
runner.init();
|
||||
runner.addTask(ledRefresh);
|
||||
runner.addTask(clockTick);
|
||||
#ifdef LDR_PIN
|
||||
runner.addTask(brightness);
|
||||
#endif
|
||||
runner.addTask(bootAnim);
|
||||
bootAnim.enable();
|
||||
|
||||
iotWebConf_Setup();
|
||||
//Serial.end();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
runner.execute();
|
||||
iotWebConf.doLoop();
|
||||
/*
|
||||
while (Serial.available())
|
||||
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 (singleSecond) {
|
||||
strip.SetPixelColor(MOD(int(currentSec * NUM_LEDS / 60 + 0), NUM_LEDS), secondsColor);
|
||||
}
|
||||
#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);
|
||||
#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); //negative value
|
||||
//Serial.println("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("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_STATE_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_STATE_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_STATE_AP_MODE) {
|
||||
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_STATE_BOOT || iotWebConf.getState() == IOTWEBCONF_STATE_NOT_CONFIGURED) {
|
||||
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;
|
||||
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();
|
||||
}
|
||||
#endif
|
||||
|
@ -65,3 +65,7 @@ Unten auf der Statusseite gibt es einen Link zur Konfigurationsseite, eine Mögl
|
||||
## ausstehende Verbesserungen
|
||||
- [ ] flüssige Helligkeitsadaptierung
|
||||
- [ ] härtes non-blocking Verhalten
|
||||
- offensichtliche delay/yield aufgelöst
|
||||
- [ ] finde WDT reset beim WiFi connect
|
||||
- Wechsel des lwip bringt eine Verbesserung
|
||||
- [ ] schnelleres Berechnen des followingHour Offset
|
||||
|
144
iotwebconf.ino
Normal file
144
iotwebconf.ino
Normal file
@ -0,0 +1,144 @@
|
||||
|
||||
/**
|
||||
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 += "</tr><td><tr><td>Current Timezone:</td><td>";
|
||||
s += (getenv("TZ") ? : "(none)");
|
||||
s += "</td></tr>";
|
||||
s += "</table><table>";
|
||||
s += "<tr></tr><tr><td>NTP Server:</td><td>";
|
||||
s += currentNTP;
|
||||
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()
|
||||
{
|
||||
setTimeZone();
|
||||
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(&timezoneParam);
|
||||
//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(&ntpReachableCheckCallback);
|
||||
//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();
|
||||
}
|
121
ledcontrol.ino
Normal file
121
ledcontrol.ino
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Callback to set the led
|
||||
* like the analog time
|
||||
* struct
|
||||
*
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback to animate
|
||||
* black running for online but not NTP
|
||||
* white running for connecting
|
||||
* green running for AP mode
|
||||
* red running for boot and unconfigured
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//ToDo change to no valid time
|
||||
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();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback fo the brigthness
|
||||
* takes 10 values, get the median
|
||||
* and set the new value
|
||||
*/
|
||||
#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) + ")");
|
||||
}
|
||||
|
||||
/*
|
||||
* callback for fading the brigthness smootly
|
||||
*/
|
||||
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
|
82
main.ino
Normal file
82
main.ino
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
void setup() {
|
||||
#ifdef LDR_PIN
|
||||
pinMode(LDR_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
pinMode(DATA_PIN, OUTPUT);
|
||||
|
||||
Serial.begin(SERIAL_BAUD);
|
||||
Serial.flush();
|
||||
delay(100);
|
||||
Serial.println();
|
||||
Serial.print("\n\n\nCPU Frequency is: ");
|
||||
#ifdef ESP8266
|
||||
Serial.print(ESP.getCpuFreqMHz());
|
||||
Serial.println(" Mhz");
|
||||
Serial.print("Chip ID: ");
|
||||
Serial.println(ESP.getFlashChipId());
|
||||
#elif defined(ESP32)
|
||||
setCpuFrequencyMhz(160);
|
||||
Serial.print(getCpuFrequencyMhz()); //Get CPU clock
|
||||
Serial.println(" Mhz");
|
||||
uint32_t Freq = getXtalFrequencyMhz();
|
||||
Serial.print("XTAL Freq = ");
|
||||
Serial.print(Freq);
|
||||
uint32_t chipId = 0;
|
||||
for (int i = 0; i < 17; i = i + 8) {
|
||||
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
|
||||
}
|
||||
|
||||
Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
|
||||
Serial.printf("This chip has %d cores\n", ESP.getChipCores());
|
||||
Serial.print("Chip ID: "); Serial.println(chipId);
|
||||
#endif
|
||||
Serial.print("MAC address: ");
|
||||
Serial.println(WiFi.macAddress()); //Get CPU clock
|
||||
|
||||
#ifdef RGBW
|
||||
Serial.println("RGBW");
|
||||
#else
|
||||
Serial.println("RGB");
|
||||
#endif
|
||||
|
||||
strip.Begin();
|
||||
strip.ClearTo(white);
|
||||
strip.SetBrightness( MINIMAL_BRIGHTNESS );
|
||||
strip.Show();
|
||||
|
||||
runner.init();
|
||||
runner.addTask(ledRefresh);
|
||||
runner.addTask(clockTick);
|
||||
#ifdef LDR_PIN
|
||||
runner.addTask(brightnessAdjustment);
|
||||
runner.addTask(brightnessFading);
|
||||
#endif
|
||||
runner.addTask(bootAnim);
|
||||
runner.addTask(iotwebconfLoop);
|
||||
bootAnim.enable();
|
||||
iotwebconfLoop.enable();
|
||||
|
||||
iotWebConf_Setup();
|
||||
//Serial.end();
|
||||
#ifdef ESP8266
|
||||
ESP.wdtDisable();
|
||||
ESP.wdtEnable(1000);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#endif
|
||||
setTimeZone();
|
||||
//setNTP();
|
||||
settimeofday_cb(timeRefreshCallback); //internal callback for timesetting
|
||||
ntpReachableCheck.enable();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
runner.execute();
|
||||
yield();
|
||||
#ifdef ESP8266
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
|
||||
}
|
26
productionlist.md
Normal file
26
productionlist.md
Normal file
@ -0,0 +1,26 @@
|
||||
## production list
|
||||
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)
|
||||
-----------------
|
||||
ESP8266 24LED
|
||||
5V--10k-+-LDR--GND -ADC
|
||||
- 150k--220k-+-100k--GND
|
||||
-----------------
|
||||
ESP8266 60LED
|
||||
5V--??k-+-LDR--??k-GND
|
||||
- 39k--220k-+-100k--GND
|
||||
-ADC
|
||||
|
||||
--------------------
|
||||
ESP32 60 LED
|
||||
Chip is ESP32-D0WDQ6 (revision 1)
|
||||
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
|
||||
Crystal is 40MHz
|
||||
MAC: 08:3a:f2:50:f0:58
|
||||
MH Live ESP32 Mini Kit aka Mini D1 ESP32
|
||||
Data IO17
|
||||
LDR IO34
|
||||
RGBW
|
180
realtime.ino
Normal file
180
realtime.ino
Normal file
@ -0,0 +1,180 @@
|
||||
|
||||
// https://github.com/esp8266/Arduino/commit/a05a71fa9d2e6b143cb34f01b47e22c4b66b80a1
|
||||
|
||||
void debugSNTP() {
|
||||
// lwIP v2 is able to list more details about the currently configured SNTP servers
|
||||
for (int i = 0; i < SNTP_MAX_SERVERS; i++) {
|
||||
IPAddress sntp = *sntp_getserver(i);
|
||||
const char* name = sntp_getservername(i);
|
||||
if (sntp.isSet()) {
|
||||
Serial.printf("sntp%d: ", i);
|
||||
if (name) {
|
||||
Serial.printf("%s (%s) ", name, sntp.toString().c_str());
|
||||
} else {
|
||||
Serial.printf("%s ", sntp.toString().c_str());
|
||||
}
|
||||
Serial.printf("- IPv6: %s - Reachability: %o\n", sntp.isV6() ? "Yes" : "No", sntp_getreachability(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String printLocalTime() {
|
||||
if (!getLocalTime(&timeinfo, 200)) {
|
||||
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);
|
||||
return timeStringBuff;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for DHCP supplied NTP
|
||||
*/
|
||||
void ntpReachableCheckCallback() {
|
||||
// lwIP v2 is able to list more details about the currently configured SNTP servers
|
||||
int usuableServer = 0;
|
||||
int serverCount = 0;
|
||||
for (int i = 0; i < SNTP_MAX_SERVERS; i++) {
|
||||
IPAddress sntp = *sntp_getserver(i);
|
||||
const char* name = sntp_getservername(i);
|
||||
if (sntp.isSet()) {
|
||||
serverCount++;
|
||||
if (sntp_getreachability(i) > 0) {
|
||||
NTPreachable = true;
|
||||
usuableServer++;
|
||||
getLocalTime(&timeinfo, 200);
|
||||
Serial.println("NTP reachable");
|
||||
currentNTP=sntp.toString();
|
||||
}
|
||||
else {
|
||||
NTPreachable = false;
|
||||
Serial.println("ntp NOT reachable");
|
||||
}
|
||||
}
|
||||
if (serverCount == 0) {
|
||||
setFallbackNTP();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
refresh the internal time struct
|
||||
*/
|
||||
void timeRefreshCallback( bool from_sntp ) {
|
||||
getLocalTime(&timeinfo, 200);
|
||||
Serial.print(asctime(&timeinfo));
|
||||
Serial.printf("timezone: %s\n", getenv("TZ") ? : "(none)");
|
||||
|
||||
//set new time only when from sntp
|
||||
//no manual way to set time
|
||||
if (!from_sntp) {
|
||||
Serial.println("Not SNTP time");
|
||||
}
|
||||
else {
|
||||
debugSNTP();
|
||||
Serial.println("SNTP time used");
|
||||
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("timestruct mapped: " + String(int(currentHour * NUM_LEDS / 12)) + ":" + String(int(currentMin * NUM_LEDS / 60)) + ":" + String(int(currentSec * NUM_LEDS / 60)));
|
||||
bootAnim.disable();
|
||||
//iotWebConfConfigSaved(); //ToDo why?
|
||||
ledRefresh.enableIfNot();
|
||||
#ifdef LDR_PIN
|
||||
brightnessFading.enableIfNot();
|
||||
#endif
|
||||
clockTick.enableIfNot();
|
||||
brightnessAdjustment.enableIfNot();
|
||||
}
|
||||
}
|
||||
|
||||
void setTimeZone() {
|
||||
//init and get the time
|
||||
#ifdef ESP8266
|
||||
//sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default)
|
||||
configTime(MYTZ,currentNTP);
|
||||
yield();
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
setenv("TZ", "AEST-10", 1);
|
||||
tzset(); // save the TZ variable
|
||||
#endif
|
||||
yield();
|
||||
}
|
||||
/*
|
||||
function to set NTP server
|
||||
maybe not needed
|
||||
*/
|
||||
void setFallbackNTP() {
|
||||
//init and get the time
|
||||
#ifdef ESP8266
|
||||
//sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default)
|
||||
//configTime(int timezone, int daylightOffset_sec, const char* server1, const char* server2, const char* server3 )
|
||||
configTime(MYTZ, "pool.ntp.org"); //ToDo skip TZ
|
||||
//setTZ(MYTZ);
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
configTime(0, 0, "pool.ntp.org");
|
||||
#endif
|
||||
yield();
|
||||
}
|
||||
|
||||
/*
|
||||
Callback to handle the separate
|
||||
loose time structure for the mapping
|
||||
to the analog representation of a clock
|
||||
|
||||
*/
|
||||
void clockTickCallback() {
|
||||
#ifdef LDR_PIN
|
||||
ldrValue = (ldrValue + analogRead(LDR_PIN));
|
||||
#endif
|
||||
if (clockwiseRing) {
|
||||
if (currentSec >= 60) {
|
||||
currentSec = 0;
|
||||
currentMin++;
|
||||
if (currentMin >= 60) {
|
||||
currentMin = 0;
|
||||
currentHour++;
|
||||
if (currentHour >= 12) {
|
||||
currentHour = 0;
|
||||
}
|
||||
}
|
||||
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 (currentMin < 0) {
|
||||
currentMin = 59;
|
||||
currentHour--;
|
||||
if (currentHour < 0) {
|
||||
currentHour = 11;
|
||||
}
|
||||
}
|
||||
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