Added Sunrise nightlight mode and more UI features

-   Added Sunrise nightlight mode
-   Added Chunchun effect
-   Added `LO` (live override) command to HTTP API
-   Added `mode` to `nl` object of JSON state API, deprecating `fade`
-   Added light color scheme support to web UI (click sun next to brightness slider)
-   Added option to hide labels in web UI (click flame icon next to intensity slider)
-   Added hex color input (click palette icon next to palette select) (resolves #506)
-   Added support for RGB sliders (need to set in localstorage)
-   Added support for custom background color or image (need to set in localstorage)
-   Added option to hide bottom tab bar in PC mode (need to set in localstorage)
-   Fixed transition lag with multiple segments (fixes #985)
-   Changed Nightlight wording (resolves #940)
This commit is contained in:
cschwinne 2020-06-22 12:30:31 +02:00
parent 60c7ec5aca
commit 4f7dc5be34
21 changed files with 3467 additions and 2884 deletions

View File

@ -2,6 +2,21 @@
### Development versions after 0.10.0 release
#### Build 2006220
- Added Sunrise nightlight mode
- Added Chunchun effect
- Added `LO` (live override) command to HTTP API
- Added `mode` to `nl` object of JSON state API, deprecating `fade`
- Added light color scheme support to web UI (click sun next to brightness slider)
- Added option to hide labels in web UI (click flame icon next to intensity slider)
- Added hex color input (click palette icon next to palette select) (resolves #506)
- Added support for RGB sliders (need to set in localstorage)
- Added support for custom background color or image (need to set in localstorage)
- Added option to hide bottom tab bar in PC mode (need to set in localstorage)
- Fixed transition lag with multiple segments (fixes #985)
- Changed Nightlight wording (resolves #940)
#### Build 2006060
- Added five effects by Andrew Tuline (Phased, Phased Noise, Sine, Noise Pal and Twinkleup)

View File

@ -1,6 +1,6 @@
{
"name": "wled",
"version": "0.10.0",
"version": "0.10.1",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {

View File

@ -15,7 +15,7 @@ extra_configs =
# Please uncomment one of the lines below to select your board(s)
# ------------------------------------------------------------------------------
# Travis CI binaries (comment this out when building for single board)
# Travis CI binaries
default_envs = travis_esp8266, esp01, esp01_1m_ota, travis_esp32
# Release binaries

View File

@ -7,7 +7,7 @@
<a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a>
</p>
# 👋 Welcome to my project WLED!
# Welcome to my project WLED!
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs or also SPI based chipsets like the WS2801!

View File

@ -1,6 +1,6 @@
# Temperature usermod
Based on the excellent `QuinLED_Dig_Uno_Temp_MQTT` by srg74!
Based on the excellent `QuinLED_Dig_Uno_Temp_MQTT` by srg74 and 400killer!
This usermod will read from an attached DS18B20 temperature sensor (as available on the QuinLED Dig-Uno)
The temperature is displayed both in the Info section of the web UI as well as published to the `/temperature` MQTT topic if enabled.
This usermod will be expanded with support for different sensor types in the future.

View File

@ -3342,8 +3342,8 @@ uint16_t WS2812FX::mode_solid_glitter()
*/
uint16_t WS2812FX::mode_sunrise() {
//speed 0 - static sun
//speed 1 - 120: sunrise time in minutes
//speed 121 - 240 : sunset time in minutes - 120;
//speed 1 - 60: sunrise time in minutes
//speed 60 - 120 : sunset time in minutes - 60;
//speed above: "breathing" rise and set
if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) {
SEGENV.step = millis(); //save starting time, millis() because now can change from sync
@ -3540,3 +3540,26 @@ uint16_t WS2812FX::mode_flow(void)
return FRAMETIME;
}
/*
* Dots waving around in a sine/pendulum motion.
* Little pixel birds flying in a circle. By Aircoookie
*/
uint16_t WS2812FX::mode_chunchun(void)
{
fill(SEGCOLOR(1));
uint16_t counter = now*(6 + (SEGMENT.speed >> 4));
uint16_t numBirds = SEGLEN >> 2;
uint16_t span = SEGMENT.intensity << 8;
for (uint16_t i = 0; i < numBirds; i++)
{
counter -= span/numBirds;
int megumin = sin16(counter) + 0x8000;
uint32_t bird = (megumin * SEGLEN) >> 16;
uint32_t c = color_from_palette((i * 255)/ numBirds, false, true, 0);
setPixelColor(bird, c);
}
return FRAMETIME;
}

View File

@ -98,7 +98,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
#define MODE_COUNT 111
#define MODE_COUNT 112
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@ -211,6 +211,7 @@
#define FX_MODE_SINEWAVE 108
#define FX_MODE_PHASEDNOISE 109
#define FX_MODE_FLOW 110
#define FX_MODE_CHUNCHUN 111
class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void);
@ -410,6 +411,7 @@ class WS2812FX {
_mode[FX_MODE_SINEWAVE] = &WS2812FX::mode_sinewave;
_mode[FX_MODE_PHASEDNOISE] = &WS2812FX::mode_phased_noise;
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
_mode[FX_MODE_CHUNCHUN] = &WS2812FX::mode_chunchun;
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
@ -604,7 +606,8 @@ class WS2812FX {
mode_noisepal(void),
mode_sinewave(void),
mode_phased_noise(void),
mode_flow(void);
mode_flow(void),
mode_chunchun(void);
private:
NeoPixelWrapper *bus;
@ -691,7 +694,8 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise","Flow"
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
"Flow","Chunchun"
])=====";

View File

@ -136,6 +136,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
}
}
//reorder channels to selected order
RgbwColor col;
switch (colorOrder)
{
@ -401,7 +402,12 @@ uint8_t WS2812FX::getMaxSegments(void) {
uint8_t WS2812FX::getMainSegmentId(void) {
if (mainSegment >= MAX_NUM_SEGMENTS) return 0;
return mainSegment;
if (_segments[mainSegment].isActive()) return mainSegment;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //get first active
{
if (_segments[i].isActive()) return i;
}
return 0;
}
uint32_t WS2812FX::getColor(void) {
@ -529,11 +535,14 @@ void WS2812FX::setShowCallback(show_callback cb)
void WS2812FX::setTransitionMode(bool t)
{
_segment_index = getMainSegmentId();
SEGMENT.setOption(SEG_OPTION_TRANSITIONAL, t);
if (!t) return;
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
if (SEGMENT.mode == FX_MODE_STATIC && SEGENV.next_time > waitMax) SEGENV.next_time = waitMax;
for (uint16_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
_segment_index = i;
SEGMENT.setOption(SEG_OPTION_TRANSITIONAL, t);
if (t && SEGMENT.mode == FX_MODE_STATIC && SEGENV.next_time > waitMax) SEGENV.next_time = waitMax;
}
}
/*

View File

@ -100,6 +100,12 @@
#define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor
#define SEG_OPTION_TRANSITIONAL 7
//Timer mode types
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
#define NL_MODE_FADE 1 //Fade to target brightness gradually
#define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color gradually
#define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min.
//EEPROM size
#define EEPSIZE 2560 //Maximum is 4096

File diff suppressed because it is too large Load Diff

View File

@ -156,7 +156,13 @@
<h3>Timed light</h3>
Default Duration: <input name="TL" type="number" min="1" max="255" required> min<br>
Default Target brightness: <input name="TB" type="number" min="0" max="255" required><br>
Fade down: <input type="checkbox" name="TW"><br>
Mode:
<select name="TW">
<option value="0">Wait and set</option>
<option value="1">Fade</option>
<option value="2">Fade Color</option>
<option value="3">Sunrise</option>
</select>
<h3>Advanced</h3>
Palette blending:
<select name="PB">

View File

@ -32,7 +32,7 @@
</head>
<body>
<h2>WLED Software Update</h2>Installed version: 0.10.0<br>Download the latest binary: <a
<h2>WLED Software Update</h2>Installed version: ##VERSION##<br>Download the latest binary: <a
href="https://github.com/Aircoookie/WLED/releases"><img
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br>
<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' class="bt" name='update'

View File

@ -39,7 +39,7 @@ const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta cont
<title>WLED Update</title><script>function B(){window.history.back()}</script>
<style>
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}
</style></head><body><h2>WLED Software Update</h2>Installed version: 0.10.0<br>
</style></head><body><h2>WLED Software Update</h2>Installed version: 0.10.1<br>
Download the latest binary: <a
href="https://github.com/Aircoookie/WLED/releases"><img
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">

View File

@ -118,12 +118,14 @@ name="TD" maxlength="5" size="2"> ms<br>Enable Palette transitions: <input
type="checkbox" name="PF"><h3>Timed light</h3>Default Duration: <input
name="TL" type="number" min="1" max="255" required> min<br>
Default Target brightness: <input name="TB" type="number" min="0" max="255"
required><br>Fade down: <input type="checkbox" name="TW"><br><h3>Advanced</h3>
Palette blending: <select name="PB"><option value="0">Linear (wrap if moving)
</option><option value="1">Linear (always wrap)</option><option value="2">
Linear (never wrap)</option><option value="3">None (not recommended)</option>
</select><br>Reverse LED order (rotate 180): <input type="checkbox" name="RV">
<br>Skip first LED: <input type="checkbox" name="SL"><hr><button type="button"
required><br>Mode: <select name="TW"><option value="0">Wait and set</option>
<option value="1">Fade</option><option value="2">Fade Color</option><option
value="3">Sunrise</option></select><h3>Advanced</h3>Palette blending: <select
name="PB"><option value="0">Linear (wrap if moving)</option><option value="1">
Linear (always wrap)</option><option value="2">Linear (never wrap)</option>
<option value="3">None (not recommended)</option></select><br>
Reverse LED order (rotate 180): <input type="checkbox" name="RV"><br>
Skip first LED: <input type="checkbox" name="SL"><hr><button type="button"
onclick="B()">Back</button><button type="submit">Save</button></form></body>
</html>)=====";
@ -335,7 +337,7 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
<h3>Software Update</h3><button type="button" onclick="U()">Manual OTA Update
</button><br>Enable ArduinoOTA: <input type="checkbox" name="AO"><br><h3>About
</h3><a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a>
version 0.10.0<br><br><a
version 0.10.1<br><br><a
href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About"
target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br>

File diff suppressed because it is too large Load Diff

View File

@ -115,7 +115,8 @@ bool deserializeState(JsonObject root)
JsonObject nl = root["nl"];
nightlightActive = nl["on"] | nightlightActive;
nightlightDelayMins = nl["dur"] | nightlightDelayMins;
nightlightFade = nl["fade"] | nightlightFade;
nightlightMode = nl["fade"] | nightlightMode; //deprecated
nightlightMode = nl["mode"] | nightlightMode;
nightlightTargetBri = nl["tbri"] | nightlightTargetBri;
JsonObject udpn = root["udpn"];
@ -246,7 +247,8 @@ void serializeState(JsonObject root)
JsonObject nl = root.createNestedObject("nl");
nl["on"] = nightlightActive;
nl["dur"] = nightlightDelayMins;
nl["fade"] = nightlightFade;
nl["fade"] = (nightlightMode > NL_MODE_SET); //deprecated
nl["mode"] = nightlightMode;
nl["tbri"] = nightlightTargetBri;
JsonObject udpn = root.createNestedObject("udpn");

View File

@ -114,7 +114,7 @@ void colorUpdated(int callMode)
if (!colChanged) return; //following code is for e.g. initiating transitions
if (callMode != NOTIFIER_CALL_MODE_NO_NOTIFY && nightlightActive && nightlightFade)
if (callMode != NOTIFIER_CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE))
{
briNlT = bri;
nightlightDelayMs -= (millis() - nightlightStartTime);
@ -134,6 +134,9 @@ void colorUpdated(int callMode)
briIT = bri;
if (bri > 0) briLast = bri;
//deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri && callMode != NOTIFIER_CALL_MODE_NO_NOTIFY) nightlightActive = false;
if (fadeTransition)
{
//set correct delay if not using notification delay
@ -223,30 +226,65 @@ void handleNightlight()
nightlightActiveOld = true;
briNlT = bri;
for (byte i=0; i<4; i++) colNlT[i] = col[i]; // remember starting color
if (nightlightMode == NL_MODE_SUN)
{
//save current
colNlT[0] = effectCurrent;
colNlT[1] = effectSpeed;
colNlT[2] = effectPalette;
effectCurrent = FX_MODE_SUNRISE;
effectSpeed = nightlightDelayMins;
effectPalette = 0;
if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes
if (bri) effectSpeed += 60; //sunset if currently on
briNlT = !bri; //true == sunrise, false == sunset
if (!bri) bri = briLast;
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
}
}
float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs);
if (nightlightFade)
if (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE)
{
bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
if (nightlightColorFade) // color fading only is enabled with "NF=2"
if (nightlightMode == NL_MODE_COLORFADE) // color fading only is enabled with "NF=2"
{
for (byte i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color
}
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
}
if (nper >= 1)
if (nper >= 1) //nightlight duration over
{
nightlightActive = false;
if (!nightlightFade)
if (nightlightMode == NL_MODE_SET)
{
bri = nightlightTargetBri;
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
}
updateBlynk();
if (bri == 0) briLast = briNlT;
if (nightlightMode == NL_MODE_SUN)
{
if (!briNlT) { //turn off if sunset
effectCurrent = colNlT[0];
effectSpeed = colNlT[1];
effectPalette = colNlT[2];
toggleOnOff();
setLedsStandard();
}
}
updateBlynk();
if (macroNl > 0)
applyMacro(macroNl);
nightlightActiveOld = false;
}
} else if (nightlightActiveOld) //early de-init
{
if (nightlightMode == NL_MODE_SUN) { //restore previous effect
effectCurrent = colNlT[0];
effectSpeed = colNlT[1];
effectPalette = colNlT[2];
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
}
nightlightActiveOld = false;
}

View File

@ -103,7 +103,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
t = request->arg("TL").toInt();
if (t > 0) nightlightDelayMinsDefault = t;
nightlightDelayMins = nightlightDelayMinsDefault;
nightlightFade = request->hasArg("TW");
nightlightMode = request->arg("TW").toInt();
t = request->arg("PB").toInt();
if (t >= 0 && t < 4) strip.paletteBlend = t;
@ -603,10 +603,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
pos = req.indexOf("NF=");
if (pos > 0)
{
nightlightFade = (req.charAt(pos+3) != '0');
nightlightColorFade = (req.charAt(pos+3) == '2'); //NighLightColorFade can only be enabled via API or Macro with "NF=2"
nightlightMode = getNumVal(&req, pos);
nightlightActiveOld = false; //re-init
}
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
#if AUXPIN >= 0
//toggle general purpose output
@ -647,8 +648,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
}
}
//deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri) nightlightActive = false;
//set time (unix timestamp)
pos = req.indexOf("ST=");
if (pos > 0) {
@ -662,6 +661,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (countdownTime - now() > 0) countdownOverTriggered = false;
}
pos = req.indexOf("LO=");
if (pos > 0) {
realtimeOverride = getNumVal(&req, pos);
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
}
pos = req.indexOf("RB");
if (pos > 0) doReboot = true;

View File

@ -3,12 +3,12 @@
/*
Main sketch, global variable declarations
@title WLED project sketch
@version 0.10.0
@version 0.10.1
@author Christian Schwinne
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2006060
#define VERSION 2006220
// ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).
@ -154,7 +154,7 @@
#endif
// Global Variable definitions
WLED_GLOBAL char versionString[] _INIT("0.10.0");
WLED_GLOBAL char versionString[] _INIT("0.10.1");
#define WLED_CODENAME "Namigai"
// AP and OTA default passwords (for maximum security change them!)
@ -193,8 +193,7 @@ WLED_GLOBAL byte briS _INIT(128); // default brightness
WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over
WLED_GLOBAL byte nightlightDelayMins _INIT(60);
WLED_GLOBAL bool nightlightFade _INIT(true); // if enabled, light will gradually dim towards the target bri. Otherwise, it will instantly set after delay over
WLED_GLOBAL bool nightlightColorFade _INIT(false); // if enabled, light will gradually fade color from primary to secondary color.
WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade
WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading color transition
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // default crossfade duration in ms

View File

@ -87,7 +87,7 @@ void saveSettingsToEEPROM()
writeStringToEEPROM(160, apPass, 64);
EEPROM.write(224, nightlightDelayMinsDefault);
EEPROM.write(225, nightlightFade);
EEPROM.write(225, nightlightMode);
EEPROM.write(226, notifyDirectDefault);
EEPROM.write(227, apChannel);
EEPROM.write(228, apHide);
@ -311,7 +311,7 @@ void loadSettingsFromEEPROM(bool first)
nightlightDelayMinsDefault = EEPROM.read(224);
nightlightDelayMins = nightlightDelayMinsDefault;
nightlightFade = EEPROM.read(225);
nightlightMode = EEPROM.read(225);
notifyDirectDefault = EEPROM.read(226);
notifyDirect = notifyDirectDefault;

View File

@ -12,7 +12,7 @@ void XML_response(AsyncWebServerRequest *request, char* dest)
olen = 0;
oappend((const char*)F("<?xml version=\"1.0\" ?><vs><ac>"));
oappendi((nightlightActive && nightlightFade) ? briT : bri);
oappendi((nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri);
oappend("</ac>");
for (int i = 0; i < 3; i++)
@ -34,7 +34,7 @@ void XML_response(AsyncWebServerRequest *request, char* dest)
oappend("</nr><nl>");
oappendi(nightlightActive);
oappend("</nl><nf>");
oappendi(nightlightFade);
oappendi(nightlightMode > NL_MODE_SET);
oappend("</nf><nd>");
oappendi(nightlightDelayMins);
oappend("</nd><nt>");
@ -301,7 +301,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',"BF",briMultiplier);
sappend('v',"TB",nightlightTargetBri);
sappend('v',"TL",nightlightDelayMinsDefault);
sappend('c',"TW",nightlightFade);
sappend('v',"TW",nightlightMode);
sappend('i',"PB",strip.paletteBlend);
sappend('c',"RV",strip.reverseMode);
sappend('c',"SL",skipFirstLed);