Merge pull request 'colorPicker' (#7) from colorPicker into master

Reviewed-on: #7
This commit is contained in:
coelner 2021-05-06 21:20:19 +02:00
commit 00eb84389b
4 changed files with 361 additions and 122 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.bin

View File

@ -1,6 +1,4 @@
#include <WiFi.h>
#include "time.h"
#include <TaskScheduler.h>
@ -9,8 +7,17 @@
#include <IotWebConfUsing.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>
#endif
@ -22,14 +29,23 @@
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
#define DATA_PIN D7 //DMA RDX0/GPIO3 | Uart1 TXD1/GPIO2 | UART0 GPIO1
#elif defined(ESP32)
#define LDR_PIN A6
#define NUM_LEDS 60
#define COLOR_ORDER GRB
#define DATA_PIN 17
#endif
#define NUM_LEDS 60
#define SERIAL_BAUD 115200
//#define RGBW
#define RGBW
volatile bool singleSecond = true; //show seconds
volatile bool allDotsOn = true; //lighten up all leds
volatile bool followingHour = true; //move hour like an analog one
@ -44,8 +60,14 @@ void brightnessAdjustmentCallback();
#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);
#ifdef ESP8266
//NeoPixelBrightnessBus<NeoGrbwFeature, Neo800KbpsMethod> strip(NUM_LEDS);//RDX0 GPIO3
//NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266AsyncUart0Sk6812Method> strip(NUM_LEDS);
//NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266Uart0Sk6812Method> strip(NUM_LEDS);
NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266BitBang800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
#elif defined(ESP32)
NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s1800KbpsMethod> strip(NUM_LEDS, DATA_PIN); //ESP32
#endif
RgbwColor red(colorSaturation, 0, 0, 0);
RgbwColor green(0, colorSaturation, 0, 0);
RgbwColor blue(0, 0, colorSaturation, 0);
@ -57,16 +79,55 @@ RgbwColor black(0);
RgbwColor gold(HtmlColor( 0xFFD700 ) );
RgbwColor orangered(HtmlColor( 0xFF4500 ) );
RgbwColor orange(HtmlColor( 0xFFA500 ) );
RgbwColor darkred(HtmlColor(0x800000));
RgbwColor darkgreen(HtmlColor(0x006400));
RgbwColor lightgreen(HtmlColor(0x90ee90));
RgbwColor darkred(HtmlColor( 0x800000) );
RgbwColor darkgreen(HtmlColor( 0x006400) );
RgbwColor lightgreen(HtmlColor( 0x30ee30) );
RgbwColor temp;
RgbwColor secondsColor = black;
RgbwColor minuteColor = darkred;
RgbwColor hourColor = gold;
RgbwColor highnoonColor = white12;
RgbwColor backlightColor = white;
RgbwColor hourMarkingColor = whiter;
void transformtoHtmlColor (char* sOutput, RgbwColor* inputColor) {
//Serial.printf("InputColor: R:%i G:%i B:%i W:%i\n", inputColor.R, inputColor.G, inputColor.B, inputColor.W);
if (inputColor->IsMonotone())
{
//Serial.print("White: "); Serial.println(inputColor->W);
HtmlColor(RgbColor(inputColor->W, inputColor->W, inputColor->W)).ToNumericalString(sOutput, 12);
//Serial.println((char*)sOutput);
}
else {
//Serial.print("Color: "); Serial.print(inputColor->R); Serial.print(inputColor->G); Serial.println(inputColor->B);
HtmlColor(RgbColor(inputColor->R, inputColor->G, inputColor->B)).ToNumericalString(sOutput, 12);
//Serial.println((char*)sOutput);
}
}
void transformHtmltoStrip(RgbwColor* outputColor, char* sInput) {
HtmlColor htmlTemp;
//Serial.print("HtmltoStrip ");
//Serial.println((char*)sInput);
htmlTemp.Parse<HtmlColorNames>( sInput );
RgbwColor stripColor( htmlTemp );
//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));
}
#else
#define MINIMAL_BRIGHTNESS 20
#define LDR_SCALE 16
#define colorSaturation 192
//NeoPixelBrightnessBus<NeoGrbFeature, Neo800KbpsMethod> strip(NUM_LEDS, DATA_PIN); //ws2812B
NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
#ifdef ESP8266
//NeoPixelBrightnessBus<NeoGrbFeature, Neo800KbpsMethod> strip(NUM_LEDS);//RDX0 GPIO3 Broken due IoTWebConf
NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart1800KbpsMethod> strip(NUM_LEDS);
//NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod> strip(NUM_LEDS, DATA_PIN);
#elif defined(ESP32)
NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1800KbpsMethod> strip(NUM_LEDS, DATA_PIN); //ESP32
#endif
RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
@ -75,70 +136,115 @@ 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 darkgreen(HtmlColor(0x006400));
RgbColor lightgreen(HtmlColor(0x90ee90));
RgbColor gold(HtmlColor( 0xFFD700 ));
RgbColor orangered(HtmlColor( 0xFF4500 ));
RgbColor orange(HtmlColor( 0xFFA500 ));
RgbColor darkred(HtmlColor( 0x800000 ));
RgbColor darkgreen(HtmlColor( 0x006400 ));
RgbColor lightgreen(HtmlColor( 0x90ee90 ));
RgbColor temp;
RgbColor secondsColor = black;
RgbColor minuteColor = darkred;
RgbColor hourColor = gold;
RgbColor highnoonColor = white12;
RgbColor backlightColor = white;
RgbColor hourMarkingColor = whiter;
void transformtoHtmlColor (char* sOutput, RgbColor* inputColor) {
HtmlColor(RgbColor(inputColor->R, inputColor->G, inputColor->B)).ToNumericalString(sOutput, 12);
}
void transformHtmltoStrip(RgbColor* outputColor, char* sInput) {
HtmlColor htmlTemp;
//Serial.print("HtmltoStrip ");
//Serial.println((char*)sInput);
htmlTemp.Parse<HtmlColorNames>( sInput );
RgbColor stripColor( htmlTemp );
//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
//NTP handler
//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;
#endif
volatile int MAX_BRIGHTNESS = 200;
// WebPortal
const char thingName[] = "NTP-Clock-RGBLED";
const char wifiInitialApPassword[] = "12345678";
//ToDo add internal LED and check visibility
#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.0.0"
#define CONFIG_VERSION "V1.1.4"
// -- 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' src='data:image/png;base64,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'/>";
DNSServer dnsServer;
WebServer server(80);
#ifdef ESP8266
ESP8266HTTPUpdateServer httpUpdater;
#elif defined(ESP32)
HTTPUpdateServer httpUpdater;
#endif
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";
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";
char ntpServerParamValue[STRING_LEN];
char maxBrightnessParamValue[NUMBER_LEN];
char singleSecondParamValue[STRING_LEN];
char allDotsOnParamValue[STRING_LEN];
char followingHourParamValue[STRING_LEN];
// -- 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)'");
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'");
IotWebConfCheckboxParameter singleSecondParam = IotWebConfCheckboxParameter("Show Seconds", "singleSecond", singleSecondParamValue, STRING_LEN, true);
IotWebConfCheckboxParameter allDotsOnParam = IotWebConfCheckboxParameter("all Dots lighten on", "allDotsOn", allDotsOnParamValue, STRING_LEN, true);
IotWebConfCheckboxParameter followingHourParam = IotWebConfCheckboxParameter("following Hour", "followingHour", followingHourParamValue, STRING_LEN, true);
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
{
protected:
@ -157,22 +263,87 @@ class CustomHtmlFormatProvider : public iotwebconf::HtmlFormatProvider
}
*/
};
// -- 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' 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'");
IotWebConfCheckboxParameter singleSecondParam = IotWebConfCheckboxParameter("Show Seconds", "singleSecond", singleSecondParamValue, STRING_LEN, true);
IotWebConfCheckboxParameter allDotsOnParam = IotWebConfCheckboxParameter("all Dots lighten on", "allDotsOn", allDotsOnParamValue, STRING_LEN, true);
IotWebConfCheckboxParameter followingHourParam = IotWebConfCheckboxParameter("following Hour", "followingHour", followingHourParamValue, STRING_LEN, true);
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;
//ToDo color Picker Second, 12Clock, Minute, Hour
Task bootAnim(200, TASK_FOREVER, &bootAnimCallback);
Task clockTick(1000, TASK_FOREVER, &clockTickCallback);
Task ledRefresh(200, TASK_FOREVER, &ledRefreshCallback);
#ifdef LDR_PIN
Task brightness(10000, TASK_FOREVER, &brightnessAdjustmentCallback);
#endif
//Task iotwebconfLoop(200, TASK_FOREVER, &iotWebConf.doLoop);
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)) {
if (!getLocalTime(&timeinfo, 200)) {
Serial.println("Failed to obtain time");
NTPreachable = false;
return "";
}
//Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
@ -180,6 +351,7 @@ String printLocalTime() {
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;
}
@ -194,7 +366,7 @@ void iotWebConfHandleRoot() {
// -- 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;
@ -204,7 +376,8 @@ void iotWebConfHandleRoot() {
s += "<table>";
s += "<tr><td>Current Time:</td><td>";
s += printLocalTime();
s += "</td></tr><tr></tr><tr><td>NTP Server:</td><td>";
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());
@ -216,7 +389,35 @@ void iotWebConfHandleRoot() {
s += (allDotsOn ? "Yes" : "No");
s += "</td></tr><tr><td>Following Hour: </td><td>";
s += (followingHour ? "Yes" : "No");
s += "<td></tr></table>";
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";
@ -234,30 +435,15 @@ void iotWebConfConfigSaved()
//Serial.println(allDotsOnParam.isChecked() ? "true" : "false");
followingHour = followingHourParam.isChecked() ? true : false;
//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.");
}
/*
bool iotWebConfFormValidator(iotwebconf::WebRequestWrapper* webRequestWrapper)
{
Serial.println("Validating form.");
boolean valid = true;
int l = server.arg(ntpServerParam.getId()).length();
if (l < 3)
{
ntpServerParam.errorMessage = "Please provide at least 3 characters for this test!";
valid = false;
}
int b = atoi(maxBrightnessParamValue);
if (b < MINIMAL_BRIGHTNESS || b > 254)
{
valid = false;
}
return valid;
}
*/
void iotWebConf_Setup() {
@ -267,6 +453,12 @@ void iotWebConf_Setup() {
ledGroup.addItem(&singleSecondParam);
ledGroup.addItem(&allDotsOnParam);
ledGroup.addItem(&followingHourParam);
ledGroup.addItem(&hourColorParam);
ledGroup.addItem(&minuteColorParam);
ledGroup.addItem(&secondsColorParam);
ledGroup.addItem(&highnoonColorParam);
ledGroup.addItem(&backlightColorParam);
ledGroup.addItem(&hourMarkingColorParam);
iotWebConf.addParameterGroup(&timeGroup);
iotWebConf.addParameterGroup(&ledGroup);
@ -301,46 +493,64 @@ void iotWebConf_Setup() {
void syncNTP() {
if (iotWebConf.getState() == IOTWEBCONF_STATE_ONLINE) {
//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServerParamValue);
#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());
//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(currentHour) + ":" + String(currentMin) + ":" + String(currentSec));
bootAnim.disable();
ledRefresh.enable();
clockTick.enable();
brightness.enable();
if (NTPreachable) {
//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(currentHour) + ":" + String(currentMin) + ":" + String(currentSec));
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
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");
strip.Begin();
strip.SetBrightness( MINIMAL_BRIGHTNESS );
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();
@ -359,34 +569,40 @@ void loop()
}
void ledRefreshCallback() {
temp = allDotsOn ? white : black;
temp = allDotsOn ? backlightColor : 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);
strip.SetPixelColor(dot, hourMarkingColor);
}
}
//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(MOD((currentHour * 5 - 1 + hourOffset), NUM_LEDS), hourColor);
strip.SetPixelColor(MOD((currentHour * 5 + 0 + hourOffset), NUM_LEDS), hourColor);
strip.SetPixelColor(MOD((currentHour * 5 + 1 + hourOffset), NUM_LEDS), hourColor);
strip.SetPixelColor(0, white12); //define high noon
strip.SetPixelColor(0, highnoonColor); //define high noon
if (singleSecond) {
strip.SetPixelColor(MOD((currentSec + 0), NUM_LEDS), (allDotsOn ? black : white));
strip.SetPixelColor(MOD((currentSec + 0), NUM_LEDS), (secondsColor));
//strip.SetPixelColor(MOD((currentSec + 0), NUM_LEDS), (allDotsOn ? black : secondsColor));
}
strip.SetPixelColor(MOD((currentMin + 0), NUM_LEDS), darkred);
strip.SetPixelColor(MOD((currentMin + 0), NUM_LEDS), minuteColor);
strip.Show();
}
// Scheduler
void clockTickCallback() {
#ifdef LDR_PIN
ldrValue = (ldrValue + analogRead(LDR_PIN));
#endif
if (currentSec < 0) {
currentSec = 59;
currentMin--;
if (!NTPreachable) {
syncNTP();
}
if (currentMin < 0) {
currentMin = 59;
currentHour--;
@ -406,29 +622,39 @@ void clockTickCallback() {
void bootAnimCallback() {
strip.ClearTo(black);
currentSec--;
if (currentSec < 0) {
currentSec = 59;
int tail = -1;
currentSec--;
if (currentSec < 0) {
currentSec = NUM_LEDS-1;
tail = 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), NUM_LEDS), whiter);
strip.SetPixelColor(MOD((currentSec - 2), NUM_LEDS), white12);
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), NUM_LEDS), green);
strip.SetPixelColor(MOD((currentSec - 2), NUM_LEDS), darkgreen);
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), NUM_LEDS), red);
strip.SetPixelColor(MOD((currentSec - 2), NUM_LEDS), darkred);
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
@ -441,7 +667,8 @@ void brightnessAdjustmentCallback() {
x = int(MINIMAL_BRIGHTNESS + (MAX_BRIGHTNESS - MINIMAL_BRIGHTNESS) / ((ldrValue / LDR_SCALE) + 1) );
strip.SetBrightness(x);
}
Serial.println("Brightness: " + String(strip.GetBrightness()) + "(" + String(ldrValue) + ")");
//Serial.println("Brightness: " + String(strip.GetBrightness()) + "(" + String(ldrValue) + ")");
ldrValue = 0;
strip.Show();
}
#endif

View File

@ -1,13 +1,15 @@
# Anleitung RGB LED Uhr
Dies ist eine Beschreibung der RGB LED Uhr
Nach jeden Neustart wird der eigene WiFi Accesspoint für 30 Sekunden aktiviert. Verbindet man sich mit diesem, so kann man etwaige Fehler korrigieren.
# Schnellstart
Sobald die Uhr mit Strom versorgt wird ( 5V, 500mAh) bietet das Board (Lolin32lite) einen WiFi Accesspoint "NTP-Clock-RGBLED" an und drei LEDs in roten Farben kreisen schnell herum. Zu diesem kann man sich verbinden (Passwort: 12345678) bzw das Smartphone meldet, dass eine Anmeldung erforderlich ist. Man kommt zunächst auf der Übersichtsseite an. Diese ist prinzipiell uninteressant, stattdessen muss die Internetverbindung konfiguriert werden. Hierzu klickt man auf "Config" und trägt die folgenden drei Dinge ein:
- Ein Passwort für die Uhr
Sobald die Uhr mit Strom versorgt wird ( 5V, 500mAh) bietet das Board (Lolin32lite) einen WiFi Accesspoint "NTP-Clock-RGBLED" an und drei LEDs in roten Farben kreisen schnell herum. Zu diesem kann man sich verbinden (Passwort: 12345678) bzw. das Smartphone meldet, dass eine Anmeldung erforderlich ist. Man kommt zunächst auf der Übersichtsseite an. Diese ist später erst interessant, stattdessen muss die Internetverbindung konfiguriert werden. Hierzu klickt man auf "Config" und trägt die folgenden drei Dinge ein:
- Ein Passwort für die Uhr bzw den temporären Accesspoint
- Den Namen des Wlans
- Das Passwort des Wlans
Der Rest ist nicht notwendig. Sobald man die Werte gespeichert hat, trennt man das Smartphone vom WLAN. Die drei kreisenden LEDs können dann weiß kurz aufleuchten, üblicherweise sieht man dies nicht, da sobald die Uhrzeit verfügbar ist, diese angezeigt wird. Damit ist die Uhr konfiguriert.
Ab sofort ist die Uhr unter einer neuen IP erreichbar, sodass dort weitere Einstellungen vorgenommen werden können. Die Uhr merkt sich auch die Einstellungen.
Der Rest ist nicht notwendig. Sobald man die Werte gespeichert hat, trennt man das Smartphone vom WLAN der Uhr. Die drei kreisenden LEDs können dann weiß kurz aufleuchten. Üblicherweise sieht man dies nicht, da sobald die Uhrzeit verfügbar ist, diese angezeigt wird. In seltenen Fällen wird der Ring weiß beleuchtet und drei schwarze LEDs kreisen. Dies bedeutet, dass keine Uhrzeit zur Verfügung steht. Ansonsten ist damit die Uhr konfiguriert.
Ab sofort ist die Uhr unter einer neuen IP erreichbar (nachzusehen im Router), sodass dort weitere Einstellungen vorgenommen werden können. Die Uhr merkt sich auch die getätigten Einstellungen.
# erweiterte Einstellungen
Es wird unter der IP 192.168.4.1 ein Webserver angeboten (sofern über den Accesspoint direkt verbunden), der zwei Webseiten anzeigen kann. Primär wird die Statusseite angezeigt, die alle wesentlichen Parameter auflistet:
- Aktuelle NTP Zeit
@ -17,6 +19,12 @@ Ab sofort ist die Uhr unter einer neuen IP erreichbar, sodass dort weitere Einst
- Anzeige der einzelnen Sekunden
- Aufleuchten aller LEDs
- Folgende Stunde (wie auf einer analogen Uhr)
- Farbwahl der 12Uhr Markierung
- Farbwahl der aktuelle Stunde (3LED)
- Farbwahl der aktuellen Minute (1LED)
- Farbwahl der aktuellen Sekunde (1LED)
- Farbwahl der übrigen LEDs
- Farbwahl der restlichen Stunden (10 LEDs)
Unten auf der Statusseite gibt es einen Link zur Konfigurationsseite, eine Möglichkeit für den Upload einer neuen Firmware sowie die aktuelle Firmwareversion wird angezeigt.
@ -44,13 +52,16 @@ Unten auf der Statusseite gibt es einen Link zur Konfigurationsseite, eine Mögl
- Show Seconds
- all Dots lighten up
- following Hour
- hourColor
- minuteColor
- secondsColor
- highnoonColor
- backlightColor
- hourMarkingColor
- firmware update link
- Firmware config version 'xxxx'
## ausstehende Verbesserungen
- [ ] RGB Auswahl Sekunden
- [ ] RGB Auswahl Minuten
- [ ] RGB Auswahl Stunden
- [ ] RGB Auswahl 12 Uhr
- [ ] flüssige Helligkeitsadaptierung
- [ ] härtes non-blocking Verhalten