diff --git a/TODO.txt b/TODO.txt
index c2419f68e..6103b95d6 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,6 +1,3 @@
-color cycle
-other vfx (fire...)
-sequence
simple slide transition
additional color picker field
implement HSB slider option
@@ -14,6 +11,8 @@ use iframe for all adv. features?
/dumpeeprom and /pusheeprom (ota lock!)
aux trigger pin
randomizer
+ir, touch, pin input
+Automations
clock functions:
analog clock on range (dots)
diff --git a/readme.md b/readme.md
index 85994691a..2186d9538 100644
--- a/readme.md
+++ b/readme.md
@@ -1,8 +1,18 @@
WLED is a basic, fast and (relatively) (ok, VERY relatively) secure implementation of a ESP8266 webserver to control Neopixel (WS2812B) leds
-Features:
+Uses ESP8266 Arduino libraries from 15th August 2016! Untested with newer version!
+Contents in the /data directory need to be uploaded to SPIFFS.
+
+Features: (V0.2)
- RGB and brightness sliders
- Settings page - configuration over network
- Access Point and station mode - automatic failsafe AP
-- Edit page. Change html and other files via OTA. Support for ArduinoOTA.
+- Edit page. Change html and other files via OTA.
+Additions for V0.3 (nearly complete!)
+- WS2812FX library integrated for nearly 50 special effects!
+- Nightlight function (gradually dims down)
+- Notifier function (multiple ESPs sync color via UDP broadcast)
+- Support for power pushbutton
+- Full OTA software update capability
+- Password protected OTA page for added security (OTA lock)
diff --git a/wled00/WS2812FX.cpp b/wled00/WS2812FX.cpp
index dbb8cd1f6..583c70297 100644
--- a/wled00/WS2812FX.cpp
+++ b/wled00/WS2812FX.cpp
@@ -1171,7 +1171,7 @@ void WS2812FX::mode_fire_flicker_soft(void) {
void WS2812FX::mode_fire_flicker_int(int rev_intensity)
{
- byte p_r = (_color & 0x00FF0000) >> 16;
+ byte p_r = (_color & 0x00FF0000) >> 16;
byte p_g = (_color & 0x0000FF00) >> 8;
byte p_b = (_color & 0x000000FF) >> 0;
byte flicker_val = max(p_r,max(p_g, p_b))/rev_intensity;
diff --git a/wled00/data/settings.htm b/wled00/data/settings.htm
index 29a219f47..6e1208632 100644
--- a/wled00/data/settings.htm
+++ b/wled00/data/settings.htm
@@ -32,6 +32,12 @@
document.S_form.APPASS.value = this.responseXML.getElementsByTagName('appass')[0].innerHTML; //fake pass like ******
document.S_form.APCHAN.value = this.responseXML.getElementsByTagName('apchan')[0].innerHTML;
document.S_form.DESC.value = this.responseXML.getElementsByTagName('desc')[0].innerHTML;
+ document.S_form.CLDFR.value = this.responseXML.getElementsByTagName('cldef')[0].innerHTML;
+ document.S_form.CLDFG.value = this.responseXML.getElementsByTagName('cldef')[1].innerHTML;
+ document.S_form.CLDFB.value = this.responseXML.getElementsByTagName('cldef')[2].innerHTML;
+ document.S_form.CLDFA.value = this.responseXML.getElementsByTagName('cldfa')[0].innerHTML;
+ document.S_form.FXDEF.value = this.responseXML.getElementsByTagName('fxdef')[0].innerHTML;
+ document.S_form.SXDEF.value = this.responseXML.getElementsByTagName('sxdef')[0].innerHTML;
document.S_form.BTNON.checked = (this.responseXML.getElementsByTagName('btnon')[0].innerHTML)!=0?true:false;
document.S_form.TFADE.checked = (this.responseXML.getElementsByTagName('tfade')[0].innerHTML)!=0?true:false;
document.S_form.TDLAY.value = this.responseXML.getElementsByTagName('tdlay')[0].innerHTML;
@@ -44,6 +50,8 @@
document.S_form.NSDIR.checked = (this.responseXML.getElementsByTagName('nsdir')[0].innerHTML)!=0?true:false;
document.S_form.NSBTN.checked = (this.responseXML.getElementsByTagName('nsbtn')[0].innerHTML)!=0?true:false;
document.S_form.NSFWD.checked = (this.responseXML.getElementsByTagName('nsfwd')[0].innerHTML)!=0?true:false;
+ document.S_form.NTPON.checked = (this.responseXML.getElementsByTagName('ntpon')[0].innerHTML)!=0?true:false;
+ document.getElementsByClassName("times")[0].innerHTML = this.responseXML.getElementsByTagName('times')[0].innerHTML;
document.S_form.NOOTA.checked = (this.responseXML.getElementsByTagName('noota')[0].innerHTML)!=0?true:false;
document.S_form.NORAP.checked = (this.responseXML.getElementsByTagName('norap')[0].innerHTML)!=0?true:false;
document.getElementsByClassName("sip")[0].innerHTML = this.responseXML.getElementsByTagName('sip')[0].innerHTML;
@@ -75,54 +83,64 @@
WiFi setup
Connect to existing network
- Network SSID (leave empty to not connect):
+ Network SSID (leave empty to not connect):
Network password:
Static IP (leave at 0.0.0.0 for DHCP):
- .
- .
- .
-
+ .
+ .
+ .
+
Static gateway:
- .
- .
- .
-
+ .
+ .
+ .
+
Static subnet mask:
- .
- .
- .
-
+ .
+ .
+ .
+
mDNS address (leave empty for no mDNS):
- http:// .local
+ http:// .local
Client IP: Not connected
Configure Access Point
- AP SSID (leave empty for no AP):
+ AP SSID (leave empty for no AP):
Hide AP SSID:
AP password (leave empty for open):
- AP channel:
+ AP channel:
AP IP: Not active
Application setup
Web setup
- Server description:
+ Server description:
LED setup
- The default boot LED color is the current color when settings are saved.
- Brightness factor: %
+ Default RGB color:
+
+
+
+ Default brightness: (0-255)
+ Default effect ID:
+ Default effect speed:
+ Ignore and use current color, brightness and effects:
+ Brightness factor: %
Button setup
On/Off button enabled:
Transitions
Fade:
- Transition Delay: ms
+ Transition Delay: ms
Timed light
- Target brightness: (0-255)
- Change after: min
+ Target brightness: (0-255)
+ Change after: min
Fade:
Daisy chain
- UDP Port:
+ UDP Port:
Receive notifications:
Send notifications on direct change:
Send notifications on button press:
Send nightlight notifications:
+ Time
+ Get time from NTP server:
+ Current local time is unknown
Security
OTA locked:
Passphrase:
diff --git a/wled00/wled00.ino b/wled00/wled00.ino
index b845a076e..35701b5f0 100644
--- a/wled00/wled00.ino
+++ b/wled00/wled00.ino
@@ -8,6 +8,9 @@
#include "WS2812FX.h"
#include
#include
+#include
+#include
+#include
/*
* @title WLED project sketch
@@ -15,8 +18,15 @@
* @author Christian Schwinne
*/
//Hardware-settings (only changeble via code)
-uint8_t led_amount = 84;
+uint8_t led_amount = 9;
uint8_t buttonPin = 0; //needs pull-up
+
+TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time
+TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; //Central European Standard Time
+Timezone CE(CEST, CET);
+TimeChangeRule *tcr; //pointer to the time change rule, use to get the TZ abbrev
+time_t local;
+
//Default CONFIG
String serverDescription = "WLED 0.3pd";
String clientssid = "Your_Network_Here";
@@ -30,7 +40,8 @@ boolean useap = true;
IPAddress staticip(0, 0, 0, 0);
IPAddress staticgateway(0, 0, 0, 0);
IPAddress staticsubnet(255, 255, 255, 0);
-byte col[]{255, 127, 0};
+byte col_s[]{255, 127, 0};
+byte bri_s = 127;
uint8_t bri_nl = 0;
boolean fadeTransition = true;
boolean seqTransition = false;
@@ -45,19 +56,24 @@ uint8_t bri_n = 100;
uint8_t nightlightDelayMins = 60;
boolean nightlightFade = true;
uint16_t udpPort = 21324;
-uint8_t effectCurrent = 0;
-uint8_t effectSpeed = 75;
+uint8_t effectDefault = 0;
+uint8_t effectSpeedDefault = 75;
+boolean ntpEnabled = true;
+const char* ntpServerName = "time.nist.gov";
+long ntpRetryMs = 20000;
+long ntpResyncMs = 72000000;
double transitionResolution = 0.011;
//Internal vars
+byte col[]{0, 0, 0};
byte col_old[]{0, 0, 0};
byte col_t[]{0, 0, 0};
byte col_it[]{0, 0, 0};
long transitionStartTime;
long nightlightStartTime;
float tper_last = 0;
-byte bri = 127;
+byte bri = 0;
byte bri_old = 0;
byte bri_t = 0;
byte bri_it = 0;
@@ -68,12 +84,21 @@ boolean nightlightActive = false;
boolean nightlightActive_old = false;
int transitionDelay_old;
int nightlightDelayMs;
+uint8_t effectCurrent = 0;
+uint8_t effectSpeed = 75;
boolean udpConnected = false;
byte udpIn[16];
+IPAddress ntpIp;
+byte ntpBuffer[48];
+boolean ntpConnected = false;
+boolean ntpSyncNeeded = true;
+boolean ntpPacketSent = false;
+long ntpPacketSentTime, ntpSyncTime;
ESP8266WebServer server(80);
ESP8266HTTPUpdateServer httpUpdater;
WiFiUDP notifierUdp;
+WiFiUDP ntpUdp;
WS2812FX strip = WS2812FX(led_amount, 2, NEO_GRB + NEO_KHZ800);
@@ -111,6 +136,7 @@ void loop() {
handleTransitions();
handleNightlight();
handleButton();
+ handleNetworkTime();
strip.service();
}
diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino
index fbbf3a27b..b0764f165 100644
--- a/wled00/wled01_eeprom.ino
+++ b/wled00/wled01_eeprom.ino
@@ -56,10 +56,10 @@ void saveSettingsToEEPROM()
EEPROM.write(243, staticsubnet[1]);
EEPROM.write(244, staticsubnet[2]);
EEPROM.write(245, staticsubnet[3]);
- EEPROM.write(246, col[0]);
- EEPROM.write(247, col[1]);
- EEPROM.write(248, col[2]);
- EEPROM.write(249, bri);
+ EEPROM.write(246, col_s[0]);
+ EEPROM.write(247, col_s[1]);
+ EEPROM.write(248, col_s[2]);
+ EEPROM.write(249, bri_s);
EEPROM.write(250, receiveNotificationsDefault);
EEPROM.write(251, fadeTransition);
EEPROM.write(253, (transitionDelay >> 0) & 0xFF);
@@ -78,6 +78,12 @@ void saveSettingsToEEPROM()
{
EEPROM.write(i, serverDescription.charAt(i-292));
}
+ EEPROM.write(324, effectDefault);
+ EEPROM.write(325, effectSpeedDefault);
+ //326 reserved for effectIntensity
+ EEPROM.write(327, ntpEnabled);
+ //328 reserved for timezone setting
+ //329 reserved for dst setting
EEPROM.commit();
}
@@ -141,10 +147,10 @@ void loadSettingsFromEEPROM()
staticsubnet[1] = EEPROM.read(243);
staticsubnet[2] = EEPROM.read(244);
staticsubnet[3] = EEPROM.read(245);
- col[0] = EEPROM.read(246);
- col[1] = EEPROM.read(247);
- col[2] = EEPROM.read(248);
- bri = EEPROM.read(249);
+ col_s[0] = EEPROM.read(246); col[0] = col_s[0];
+ col_s[1] = EEPROM.read(247); col[1] = col_s[1];
+ col_s[2] = EEPROM.read(248); col[2] = col_s[2];
+ bri_s = EEPROM.read(249); bri = bri_s;
receiveNotifications = EEPROM.read(250);
receiveNotificationsDefault = receiveNotifications;
fadeTransition = EEPROM.read(251);
@@ -166,4 +172,7 @@ void loadSettingsFromEEPROM()
if (EEPROM.read(i) == 0) break;
serverDescription += char(EEPROM.read(i));
}
+ effectDefault = EEPROM.read(324); effectCurrent = effectDefault;
+ effectSpeedDefault = EEPROM.read(325); effectSpeed = effectSpeedDefault;
+ ntpEnabled = EEPROM.read(327);
}
diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino
index d829cdb64..640503d5e 100644
--- a/wled00/wled02_xml.ino
+++ b/wled00/wled02_xml.ino
@@ -31,9 +31,9 @@ void XML_response()
resp = resp + "";
resp = resp + effectCurrent;
resp = resp + " ";
- resp = resp + "";
+ resp = resp + "";
resp = resp + effectSpeed;
- resp = resp + " ";
+ resp = resp + "";
resp = resp + "";
resp = resp + serverDescription;
resp = resp + " ";
@@ -94,8 +94,23 @@ void XML_response_settings()
resp = resp + apchannel;
resp = resp + "";
resp = resp + "";
- resp = resp + serverDescription;
- resp = resp + " ";
+ resp = resp + serverDescription;
+ resp = resp + "";
+ for (int i = 0; i < 3; i++)
+ {
+ resp = resp + "";
+ resp = resp + col_s[i];
+ resp = resp + " ";
+ }
+ resp = resp + "";
+ resp = resp + bri_s;
+ resp = resp + " ";
+ resp = resp + "";
+ resp = resp + effectDefault;
+ resp = resp + " ";
+ resp = resp + "";
+ resp = resp + effectSpeedDefault;
+ resp = resp + " ";
resp = resp + "";
resp = resp + bool2int(buttonEnabled);
resp = resp + " ";
@@ -126,6 +141,14 @@ void XML_response_settings()
resp = resp + "";
resp = resp + bool2int(notifyNightlight);
resp = resp + " ";
+ resp = resp + "";
+ resp = resp + bool2int(ntpEnabled);
+ resp = resp + " ";
+ Serial.println("pretime");
+ resp = resp + "";
+ resp = resp + getTimeString();
+ resp = resp + " ";
+ Serial.println("posttime");
resp = resp + "";
resp = resp + bool2int(ota_lock);
resp = resp +" ";
diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino
index f118ccb14..6638faedf 100644
--- a/wled00/wled03_set.ino
+++ b/wled00/wled03_set.ino
@@ -94,6 +94,46 @@ void handleSettingsSet()
if (i >= 0 && i <= 255) staticsubnet[3] = i;
}
if (server.hasArg("DESC")) serverDescription = server.arg("DESC");
+ if (server.hasArg("CBEOR"))
+ {
+ col_s[0] = col[0];
+ col_s[1] = col[1];
+ col_s[2] = col[2];
+ bri_s = bri;
+ effectDefault = effectCurrent;
+ effectSpeedDefault = effectSpeed;
+ } else {
+ if (server.hasArg("CLDFR"))
+ {
+ int i = server.arg("CLDFR").toInt();
+ if (i >= 0 && i <= 255) col_s[0] = i;
+ }
+ if (server.hasArg("CLDFG"))
+ {
+ int i = server.arg("CLDFG").toInt();
+ if (i >= 0 && i <= 255) col_s[1] = i;
+ }
+ if (server.hasArg("CLDFB"))
+ {
+ int i = server.arg("CLDFB").toInt();
+ if (i >= 0 && i <= 255) col_s[2] = i;
+ }
+ if (server.hasArg("CLDFA"))
+ {
+ int i = server.arg("CLDFA").toInt();
+ if (i >= 0 && i <= 255) bri_s = i;
+ }
+ if (server.hasArg("FXDEF"))
+ {
+ int i = server.arg("FXDEF").toInt();
+ if (i >= 0 && i <= 255) effectDefault = i;
+ }
+ if (server.hasArg("SXDEF"))
+ {
+ int i = server.arg("SXDEF").toInt();
+ if (i >= 0 && i <= 255) effectSpeedDefault = i;
+ }
+ }
buttonEnabled = server.hasArg("BTNON");
fadeTransition = server.hasArg("TFADE");
if (server.hasArg("TDLAY"))
@@ -128,6 +168,7 @@ void handleSettingsSet()
notifyDirect = server.hasArg("NSDIR");
notifyButton = server.hasArg("NSBTN");
notifyNightlight = server.hasArg("NSFWD");
+ ntpEnabled = server.hasArg("NTPON");
if (server.hasArg("OPASS"))
{
if (!ota_lock)
diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino
index 08fa123ba..aac65a937 100644
--- a/wled00/wled05_init.ino
+++ b/wled00/wled05_init.ino
@@ -1,13 +1,6 @@
void wledInit()
{
Serial.begin(115200);
- Serial.println();
-
- for(uint8_t t = 4; t > 0; t--) {
- Serial.printf("[SETUP] BOOT WAIT %d...\n", t);
- Serial.flush();
- delay(1000);
- }
SPIFFS.begin();
{
@@ -59,10 +52,14 @@ void wledInit()
}
Serial.println("mDNS responder started");
- if (udpPort > 0)
+ if (udpPort > 0 && udpPort != 123)
{
udpConnected = notifierUdp.begin(udpPort);
}
+ if (ntpEnabled && !only_ap)
+ {
+ ntpConnected = ntpUdp.begin(123);
+ }
//SERVER INIT
//settings page
@@ -132,7 +129,7 @@ void wledInit()
MDNS.addService("http", "tcp", 80);
// Initialize NeoPixel Strip
strip.init();
- strip.setMode(0);
+ strip.setMode(effectCurrent);
strip.setColor(0);
strip.setSpeed(effectSpeed);
strip.setBrightness(255);
diff --git a/wled00/wled10_ntp.ino b/wled00/wled10_ntp.ino
new file mode 100644
index 000000000..a7de08c7f
--- /dev/null
+++ b/wled00/wled10_ntp.ino
@@ -0,0 +1,89 @@
+void handleNetworkTime()
+{
+ if (ntpEnabled && ntpConnected)
+ {
+ if (ntpSyncNeeded)
+ {
+ if (ntpPacketSent)
+ {
+ if (getNtpTime())
+ {
+ ntpSyncNeeded = false;
+ ntpPacketSent = false;
+ ntpSyncTime = millis();
+ Serial.print("Time: ");
+ Serial.println(now());
+ } else
+ {
+ if (millis() - ntpPacketSentTime > ntpRetryMs)
+ {
+ ntpPacketSent = false; //try new packet
+ }
+ }
+ } else
+ {
+ WiFi.hostByName(ntpServerName, ntpIp);
+ sendNTPpacket();
+ ntpPacketSent = true;
+ ntpPacketSentTime = millis();
+ }
+ } else if (millis() - ntpSyncTime > ntpResyncMs)
+ {
+ ntpSyncNeeded = true;
+ }
+ }
+}
+
+bool getNtpTime()
+{
+ int size = ntpUdp.parsePacket();
+ if (size >= 48) {
+ ntpUdp.read(ntpBuffer, 48); // read packet into the buffer
+ unsigned long secsSince1900;
+ // convert four bytes starting at location 40 to a long integer
+ secsSince1900 = (unsigned long)ntpBuffer[40] << 24;
+ secsSince1900 |= (unsigned long)ntpBuffer[41] << 16;
+ secsSince1900 |= (unsigned long)ntpBuffer[42] << 8;
+ secsSince1900 |= (unsigned long)ntpBuffer[43];
+ setTime(secsSince1900 - 2208988800UL + (millis() - ntpPacketSentTime)/2000); //naive approach to improve accuracy, utc
+ return true;
+ }
+ return false; //unable to get the time
+}
+
+void sendNTPpacket()
+{
+ Serial.println("Sending NTP packet");
+ memset(ntpBuffer, 0, 48);
+ ntpBuffer[0] = 0b11100011; // LI, Version, Mode
+ ntpBuffer[1] = 0; // Stratum, or type of clock
+ ntpBuffer[2] = 6; // Polling Interval
+ ntpBuffer[3] = 0xEC; // Peer Clock Precision
+ ntpBuffer[12] = 49;
+ ntpBuffer[13] = 0x4E;
+ ntpBuffer[14] = 49;
+ ntpBuffer[15] = 52;
+ ntpUdp.beginPacket(ntpIp, 123); //NTP requests are to port 123
+ ntpUdp.write(ntpBuffer, 48);
+ ntpUdp.endPacket();
+}
+
+String getTimeString()
+{
+ local = CE.toLocal(now(), &tcr);
+ String ret = monthStr(month(local));
+ ret = ret + " ";
+ ret = ret + day(local);
+ ret = ret + " ";
+ ret = ret + year(local);
+ ret = ret + ", ";
+ ret = ret + hour(local);
+ ret = ret + ":";
+ if (minute(local) < 10) ret = ret + "0";
+ ret = ret + minute(local);
+ ret = ret + ":";
+ if (second(local) < 10) ret = ret + "0";
+ ret = ret + second(local);
+ return ret;
+}
+