Merge branch 'master' into travis_all_features

This commit is contained in:
Aircoookie 2020-05-11 10:57:32 +02:00 committed by GitHub
commit 3b96eef2ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2531 additions and 2243 deletions

View File

@ -1,6 +1,49 @@
## WLED changelog
### Development versions after 0.9.1 release
### Development versions after 0.10.0 release
#### Build 2005100
- Update to Espalexa v2.4.6 (+1.6kB free heap memory)
- Added `m5atom` PlatformIO environment
#### Build 2005090
- Default to ESP8266 Arduino core v2.7.1 in PlatformIO
- Fixed Preset Slot 16 always indicating as empty (#891)
- Disabled Alexa emulation by default (causes bootloop for some users)
- Added BWLT11 and SHOJO_PCB defines to NpbWrapper
- Merged pull request #898 adding Solid Glitter effect
### WLED version 0.10.0
#### Build 2005030
- DMX Single RGW and Single DRGB modes now support an additional white channel
- Improved palettes derived from set colors and changed their names
### Development versions between 0.9.1 and 0.10.0 release
#### Build 2005020
- Added ACST and ACST/ACDT timezones
#### Build 2005010
- Added module info page to web UI
- Added realtime override functionality to web UI
- Added individial segment power and brightness to web UI
- Added feature to one-click select single segment only by tapping segment name
- Removed palette jumping to default if color is changed
#### Build 2004300
- Added realtime override option and `lor` JSON property
- Added `lm` (live mode) and `lip` (live IP) properties to info in JSON API
- Added reset commands to APIs
- Added `json/si`, returning state and info, but no FX or Palette lists
- Added rollover detection to millis(). Can track uptimes longer than 49 days
- Attempted to fix Wifi issues with Unifi brand APs
#### Build 2004230

View File

@ -16,7 +16,7 @@ extra_configs =
# ------------------------------------------------------------------------------
# Release binaries follow
default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom32_LEDPIN_16
; default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom32_LEDPIN_16
# Single binaries (uncomment your board)
; default_envs = nodemcuv2
@ -34,6 +34,8 @@ default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_W
; default_envs = esp8285_4CH_H801
; default_envs = esp8285_5CH_H801
; default_envs = d1_mini_5CH_Shojo_PCB
; default_envs = wemos_shield_esp32
; default_envs = m5atom
[common]
# ------------------------------------------------------------------------------
@ -50,6 +52,7 @@ default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_W
# arduino core 2.6.1 = platformIO 2.3.0
# arduino core 2.6.2 = platformIO 2.3.1
# arduino core 2.6.3 = platformIO 2.3.2
# arduino core 2.7.0 = platformIO 2.5.0
# ------------------------------------------------------------------------------
arduino_core_2_3_0 = espressif8266@1.5.0
arduino_core_2_4_0 = espressif8266@1.6.0
@ -61,13 +64,14 @@ arduino_core_2_5_2 = espressif8266@2.2.3
arduino_core_2_6_1 = espressif8266@2.3.0
arduino_core_2_6_2 = espressif8266@2.3.1
arduino_core_2_6_3 = espressif8266@2.3.3
arduino_core_2_7_1 = espressif8266@2.5.1
# Development platforms
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
platform = ${common.arduino_core_2_4_2}
platform_latest = ${common.arduino_core_2_6_3}
# Platform to use for ESP8266
platform_latest = ${common.arduino_core_2_7_1}
# ------------------------------------------------------------------------------
# FLAGS: DEBUG
@ -161,8 +165,7 @@ lib_deps =
#For use SSD1306 OLED display uncomment following
#U8g2@~2.27.2
#For Dallas sensor uncomment following 2 lines
DallasTemperature@~3.8.0
OneWire@~2.3.5
#OneWire@~2.3.5
#For BME280 sensor uncomment following
#BME280@~3.0.0
lib_ignore =
@ -183,13 +186,13 @@ board = esp01
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_512k}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
-D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
[env:esp01_1m_ota]
board = esp01_1m
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
[env:esp01_1m_full]
board = esp01_1m
@ -206,6 +209,7 @@ build_flags = ${common.build_flags_esp8266}
[env:d1_mini]
board = d1_mini
platform = ${common.platform_latest}
upload_speed = 921500
board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266}
@ -251,7 +255,7 @@ build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_
board = d1_mini
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
# ------------------------------------------------------------------------------
# DEVELOPMENT BOARDS
@ -309,6 +313,25 @@ lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:wemos_shield_esp32]
board = esp32dev
platform = espressif32@1.11.2
upload_port = /dev/cu.SLAB_USBtoUART
monitor_port = /dev/cu.SLAB_USBtoUART
upload_speed = 460800
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:m5atom]
board = esp32dev
build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
platform = espressif32@1.11.2
# ------------------------------------------------------------------------------
# travis test board configurations
# ------------------------------------------------------------------------------

View File

@ -1,24 +1,49 @@
#include "wled.h"
#include <Arduino.h>
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
#include <DallasTemperature.h> //Dallastemperature sensor
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
#include <OneWire.h> // Dallas temperature sensor
//Dallas sensor quick reading. Credit to - Author: Peter Scargill, August 17th, 2013
int16_t Dallas(int x, byte start)
{
OneWire DallasSensor(x);
byte i;
byte data[2];
int16_t result;
do
{
DallasSensor.reset();
DallasSensor.write(0xCC);
DallasSensor.write(0xBE);
for ( i = 0; i < 2; i++) data[i] = DallasSensor.read();
result=(data[1]<<8)|data[0];
result>>=4; if (data[1]&128) result|=61440;
if (data[0]&8) ++result;
DallasSensor.reset();
DallasSensor.write(0xCC);
DallasSensor.write(0x44,1);
if (start) delay(1000);
} while (start--);
return result;
}
#ifdef ARDUINO_ARCH_ESP32
uint8_t SCL_PIN = 22;
uint8_t SDA_PIN = 21;
OneWire oneWire(23);
#else //ESP8266 boards
uint8_t SDA_PIN = 21;
uint8_t DALLAS_PIN =23;
#else
uint8_t SCL_PIN = 5;
uint8_t SDA_PIN = 4;
uint8_t DALLAS_PIN =13;
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
OneWire oneWire(13);
#endif
//The SCL and SDA pins are defined here.
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
#define U8X8_PIN_SCL SCL_PIN
#define U8X8_PIN_SDA SDA_PIN
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
// Dallas sensor
DallasTemperature sensor(&oneWire);
// Dallas sensor reading timer
long temptimer = millis();
long lastMeasure = 0;
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
@ -36,7 +61,9 @@ U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
// gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup() {
sensor.begin(); //Start Dallas temperature sensor
//Serial.begin(115200);
Dallas (DALLAS_PIN,1);
u8x8.begin();
u8x8.setPowerSave(0);
u8x8.setFlipMode(1);
@ -77,18 +104,17 @@ void userLoop() {
//Check if MQTT Connected, otherwise it will crash the 8266
if (mqtt != nullptr)
{
sensor.requestTemperatures();
// Serial.println(Dallas(DALLAS_PIN,0));
//Gets prefered temperature scale based on selection in definitions section
#ifdef Celsius
float board_temperature = sensor.getTempCByIndex(0);
#else
float board_temperature = sensor.getTempFByIndex(0);
#endif
#ifdef Celsius
int16_t board_temperature = Dallas(DALLAS_PIN,0);
#else
int16_t board_temperature = (Dallas(DALLAS_PIN,0)* 1.8 + 32);
#endif
//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server.
char subuf[38];
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, "/temperature");
mqtt->publish(subuf, 0, true, String(board_temperature).c_str());
String t = String(mqttDeviceTopic);
t += "/temperature";
mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str());
}
}
@ -130,10 +156,10 @@ void userLoop() {
lastRedraw = millis();
// Update last known values.
#if defined(ESP8266)
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
#else
#ifdef ARDUINO_ARCH_ESP32
knownSsid = WiFi.SSID();
#else
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
#endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri;

View File

@ -3322,3 +3322,15 @@ CRGB WS2812FX::pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart
uint8_t sindex8 = scale16(sindex16, 240);
return ColorFromPalette(p, sindex8, bri, LINEARBLEND);
}
//Solid colour background with glitter
uint16_t WS2812FX::mode_solid_glitter()
{
fill(SEGCOLOR(0));
if (SEGMENT.intensity > random8())
{
setPixelColor(random16(SEGLEN), ULTRAWHITE);
}
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 103
#define MODE_COUNT 104
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@ -203,6 +203,7 @@
#define FX_MODE_HEARTBEAT 100
#define FX_MODE_PACIFICA 101
#define FX_MODE_CANDLE_MULTI 102
#define FX_MODE_SOLID_GLITTER 103
class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void);
@ -219,7 +220,7 @@ class WS2812FX {
uint8_t intensity;
uint8_t palette;
uint8_t mode;
uint8_t options; //bit pattern: msb first: transitional tbd tbd tbd tbd paused reverse selected
uint8_t options; //bit pattern: msb first: transitional needspixelstate tbd tbd (paused) on reverse selected
uint8_t grouping, spacing;
uint8_t opacity;
uint32_t colors[NUM_COLORS];
@ -394,6 +395,7 @@ class WS2812FX {
_mode[FX_MODE_HEARTBEAT] = &WS2812FX::mode_heartbeat;
_mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica;
_mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi;
_mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter;
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
@ -562,7 +564,7 @@ class WS2812FX {
mode_twinklecat(void),
mode_halloween_eyes(void),
mode_static_pattern(void),
mode_tri_static_pattern(void),
mode_tri_static_pattern(void),
mode_spots(void),
mode_spots_fade(void),
mode_glitter(void),
@ -580,8 +582,8 @@ class WS2812FX {
mode_ripple_rainbow(void),
mode_heartbeat(void),
mode_pacifica(void),
mode_candle_multi(void);
mode_candle_multi(void),
mode_solid_glitter(void);
private:
NeoPixelWrapper *bus;
@ -667,12 +669,12 @@ 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"
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter"
])=====";
const char JSON_palette_names[] PROGMEM = R"=====([
"Default","Random Cycle","Primary Color","Based on Primary","Set Colors","Based on Set","Party","Cloud","Lava","Ocean",
"Default","* Random Cycle","* Color 1","* Colors 1&2","* Color Gradient","* Colors Only","Party","Cloud","Lava","Ocean",
"Forest","Rainbow","Rainbow Bands","Sunset","Rivendell","Breeze","Red & Blue","Yellowout","Analogous","Splash",
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",

View File

@ -72,6 +72,7 @@ void WS2812FX::service() {
now = nowUp + timebase;
if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
bool doShow = false;
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
{
_segment_index = i;
@ -743,25 +744,25 @@ void WS2812FX::handle_palette(void)
case 2: {//primary color only
CRGB prim = col_to_crgb(SEGCOLOR(0));
targetPalette = CRGBPalette16(prim); break;}
case 3: {//based on primary
//considering performance implications
CRGB prim = col_to_crgb(SEGCOLOR(0));
CHSV prim_hsv = rgb2hsv_approximate(prim);
targetPalette = CRGBPalette16(
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v), //color itself
CHSV(prim_hsv.h, MAX(prim_hsv.s - 50,0), prim_hsv.v), //less saturated
CHSV(prim_hsv.h, prim_hsv.s, MAX(prim_hsv.v - 50,0)), //darker
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v)); //color itself
break;}
case 4: {//primary + secondary
case 3: {//primary + secondary
CRGB prim = col_to_crgb(SEGCOLOR(0));
CRGB sec = col_to_crgb(SEGCOLOR(1));
targetPalette = CRGBPalette16(sec,prim); break;}
case 5: {//based on primary + secondary
targetPalette = CRGBPalette16(prim,prim,sec,sec); break;}
case 4: {//primary + secondary + tertiary
CRGB prim = col_to_crgb(SEGCOLOR(0));
CRGB sec = col_to_crgb(SEGCOLOR(1));
CRGB ter = col_to_crgb(SEGCOLOR(2));
targetPalette = CRGBPalette16(ter,sec,prim); break;}
case 5: {//primary + secondary (+tert if not off), more distinct
CRGB prim = col_to_crgb(SEGCOLOR(0));
CRGB sec = col_to_crgb(SEGCOLOR(1));
if (SEGCOLOR(2)) {
CRGB ter = col_to_crgb(SEGCOLOR(2));
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,ter,ter,ter,ter,ter,prim);
} else {
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec);
}
break;}
case 6: //Party colors
targetPalette = PartyColors_p; break;
case 7: //Cloud colors

View File

@ -14,6 +14,8 @@
//#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13)
//#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well
//#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white
//#define WLED_USE_BWLT11
//#define WLED_USE_SHOJO_PCB
#ifndef BTNPIN
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
@ -62,7 +64,7 @@
#define GPIN 4 //G pin for analog LED strip
#define BPIN 14 //B pin for analog LED strip
#define WPIN 5 //W pin for analog LED strip
#elif defined(SHOJO_PCB)
#elif defined(WLED_USE_SHOJO_PCB)
//PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/)
#define RPIN 14 //R pin for analog LED strip
#define GPIN 4 //G pin for analog LED strip

View File

@ -45,6 +45,11 @@
#define REALTIME_MODE_ADALIGHT 5
#define REALTIME_MODE_ARTNET 6
//realtime override modes
#define REALTIME_OVERRIDE_NONE 0
#define REALTIME_OVERRIDE_ONCE 1
#define REALTIME_OVERRIDE_ALWAYS 2
//E1.31 DMX modes
#define DMX_MODE_DISABLED 0 //not used
#define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels)
@ -81,6 +86,8 @@
#define SEG_OPTION_SELECTED 0
#define SEG_OPTION_REVERSED 1
#define SEG_OPTION_ON 2
#define SEG_OPTION_PAUSED 3 //unused
#define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor
#define SEG_OPTION_TRANSITIONAL 7
//EEPROM size

File diff suppressed because one or more lines are too long

View File

@ -88,12 +88,12 @@
<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.9.0<br><br>
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.10.0<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>
(c) 2016-2019 Christian Schwinne <br>
<i>Licensed under the MIT license</i><br><br>
Server message: <span class="msg"> Response error! </span><hr>
Server message: <span class="sip"> Response error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
</form>
</body>

View File

@ -46,6 +46,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
// update status info
realtimeIP = clientIP;
byte wChannel = 0;
switch (DMXMode) {
case DMX_MODE_DISABLED:
@ -56,21 +57,25 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
if (uni != e131Universe) return;
if (dmxChannels-DMXAddress+1 < 3) return;
realtimeLock(realtimeTimeoutMs, mde);
if (realtimeOverride) return;
wChannel = (dmxChannels-DMXAddress+1 > 3) ? e131_data[DMXAddress+3] : 0;
for (uint16_t i = 0; i < ledCount; i++)
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], 0);
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], wChannel);
break;
case DMX_MODE_SINGLE_DRGB:
if (uni != e131Universe) return;
if (dmxChannels-DMXAddress+1 < 4) return;
realtimeLock(realtimeTimeoutMs, mde);
if (realtimeOverride) return;
wChannel = (dmxChannels-DMXAddress+1 > 4) ? e131_data[DMXAddress+4] : 0;
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
DMXOldDimmer = e131_data[DMXAddress+0];
bri = e131_data[DMXAddress+0];
strip.setBrightness(bri);
}
for (uint16_t i = 0; i < ledCount; i++)
setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], 0);
setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], wChannel);
break;
case DMX_MODE_EFFECT:
@ -103,6 +108,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
case DMX_MODE_MULTIPLE_RGB:
realtimeLock(realtimeTimeoutMs, mde);
if (realtimeOverride) return;
if (previousUniverses == 0) {
// first universe of this fixture
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress + 1) / 3;
@ -125,6 +131,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
case DMX_MODE_MULTIPLE_DRGB:
realtimeLock(realtimeTimeoutMs, mde);
if (realtimeOverride) return;
if (previousUniverses == 0) {
// first universe of this fixture
if (DMXOldDimmer != e131_data[DMXAddress+0]) {

View File

@ -50,7 +50,7 @@ const char PAGE_dmxmap[] PROGMEM = R"=====(<!DOCTYPE html>
const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta content='width=device-width' name='viewport'><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.9.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"></a><br><form method='POST' action='/update' enctype='multipart/form-data'><input type='file' class="bt" name='update' required><br><input type='submit' class="bt" value='Update!'></form><button type="button" class="bt" onclick="B()">Back</button></body></html>)=====";
<body><h2>WLED Software Update</h2>Installed version: 0.10.0<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' required><br><input type='submit' class="bt" value='Update!'></form><button type="button" class="bt" onclick="B()">Back</button></body></html>)=====";
//new user welcome page

View File

@ -344,7 +344,7 @@ Hue Bridge IP:<br>
<input name=H3 type=number min=0 max=255><br>
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br>
Hue status: <span class=hms> Disabled in this build </span><hr>
Hue status: <span class=sip> Disabled in this build </span><hr>
<button type=button onclick=B()>Back</button><button type=submit>Save</button>
</form>
</body></html>)=====";
@ -384,6 +384,8 @@ Time zone:
<option value="13">North Korea</option>
<option value="14">IST (India)</option>
<option value="15">CA-Saskatchewan</option>
<option value="16">ACST</option>
<option value="17">ACST/ACDT</option>
</select><br>
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
Current local time is <span class="times">unknown</span>.
@ -470,12 +472,12 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
<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.9.1<br><br>
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.10.0<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>
(c) 2016-2020 Christian Schwinne <br>
<i>Licensed under the MIT license</i><br><br>
Server message: <span class="msg"> Response error! </span><hr>
Server message: <span class="sip"> Response error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
</form>
</body>

File diff suppressed because it is too large Load Diff

View File

@ -129,6 +129,10 @@ bool deserializeState(JsonObject root)
int timein = root["time"] | -1;
if (timein != -1) setTime(timein);
doReboot = root["rb"] | doReboot;
realtimeOverride = root["lor"] | realtimeOverride;
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
byte prevMain = strip.getMainSegmentId();
strip.mainSegment = root["mainseg"] | prevMain;
@ -249,6 +253,8 @@ void serializeState(JsonObject root)
udpn["send"] = notifyDirect;
udpn["recv"] = receiveNotifications;
root["lor"] = realtimeOverride;
root["mainseg"] = strip.getMainSegmentId();
JsonArray seg = root.createNestedArray("seg");
@ -287,6 +293,7 @@ void serializeInfo(JsonObject root)
{
root["ver"] = versionString;
root["vid"] = VERSION;
//root["cn"] = WLED_CODENAME;
JsonObject leds = root.createNestedObject("leds");
leds["count"] = ledCount;
@ -305,6 +312,24 @@ void serializeInfo(JsonObject root)
root["name"] = serverDescription;
root["udpport"] = udpPort;
root["live"] = (bool)realtimeMode;
switch (realtimeMode) {
case REALTIME_MODE_INACTIVE: root["lm"] = ""; break;
case REALTIME_MODE_GENERIC: root["lm"] = ""; break;
case REALTIME_MODE_UDP: root["lm"] = "UDP"; break;
case REALTIME_MODE_HYPERION: root["lm"] = "Hyperion"; break;
case REALTIME_MODE_E131: root["lm"] = "E1.31"; break;
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight");
case REALTIME_MODE_ARTNET: root["lm"] = "Art-Net"; break;
}
if (realtimeIP[0] == 0)
{
root["lip"] = "";
} else {
root["lip"] = realtimeIP.toString();
}
root["fxcount"] = strip.getModeCount();
root["palcount"] = strip.getPaletteCount();
@ -339,7 +364,7 @@ void serializeInfo(JsonObject root)
#endif
root["freeheap"] = ESP.getFreeHeap();
root["uptime"] = millis()/1000;
root["uptime"] = millis()/1000 + rolloverMillis*4294967;
byte os = 0;
#ifdef WLED_DEBUG
@ -369,7 +394,7 @@ void serializeInfo(JsonObject root)
root["opt"] = os;
root["brand"] = "WLED";
root["product"] = "DIY light";
root["product"] = "FOSS";
root["mac"] = escapedMac;
}
@ -379,6 +404,7 @@ void serveJson(AsyncWebServerRequest* request)
const String& url = request->url();
if (url.indexOf("state") > 0) subJson = 1;
else if (url.indexOf("info") > 0) subJson = 2;
else if (url.indexOf("si") > 0) subJson = 3;
else if (url.indexOf("live") > 0) {
serveLiveLeds(request);
return;
@ -410,8 +436,11 @@ void serveJson(AsyncWebServerRequest* request)
serializeState(state);
JsonObject info = doc.createNestedObject("info");
serializeInfo(info);
doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names);
doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names);
if (subJson != 3)
{
doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names);
doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names);
}
}
response->setLength();

View File

@ -60,8 +60,13 @@ Timezone tzNK(NKST, NKST);
TimeChangeRule IST = {Last, Sun, Mar, 1, 330}; // India Standard Time = UTC + 5.5 hours
Timezone tzIndia(IST, IST);
TimeChangeRule ACST = {First, Sun, Apr, 3, 570}; //Australian Central Standard = UTC + 9.5 hours
TimeChangeRule ACDT = {First, Sun, Oct, 2, 630}; //Australian Central Daylight = UTC + 10.5 hours
Timezone tzAUNorthern(ACST, ACST);
Timezone tzAUSouthern(ACDT, ACST);
// Pick your timezone from here.
Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK, &tzIndia, &tzCASaskatchewan};
Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK, &tzIndia, &tzCASaskatchewan, &tzAUNorthern, &tzAUSouthern};
void handleNetworkTime()
{

View File

@ -659,6 +659,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (countdownTime - now() > 0) countdownOverTriggered = false;
}
pos = req.indexOf("RB");
if (pos > 0) doReboot = true;
//cronixie
#ifndef WLED_DISABLE_CRONIXIE
//mode, 1 countdown

View File

@ -1,318 +0,0 @@
/*
esp8266_waveform - General purpose waveform generation and control,
supporting outputs on all pins in parallel.
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
The core idea is to have a programmable waveform generator with a unique
high and low period (defined in microseconds). TIMER1 is set to 1-shot
mode and is always loaded with the time until the next edge of any live
waveforms.
Up to one waveform generator per pin supported.
Each waveform generator is synchronized to the ESP cycle counter, not the
timer. This allows for removing interrupt jitter and delay as the counter
always increments once per 80MHz clock. Changes to a waveform are
contiguous and only take effect on the next waveform transition,
allowing for smooth transitions.
This replaces older tone(), analogWrite(), and the Servo classes.
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef ESP8266
#include <Arduino.h>
#include "ets_sys.h"
#include "core_esp8266_waveform.h"
extern "C" {
// Maximum delay between IRQs
#define MAXIRQUS (10000)
// Set/clear GPIO 0-15 by bitmask
#define SetGPIO(a) do { GPOS = a; } while (0)
#define ClearGPIO(a) do { GPOC = a; } while (0)
// Waveform generator can create tones, PWM, and servos
typedef struct {
uint32_t nextServiceCycle; // ESP cycle timer when a transition required
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
} Waveform;
static Waveform waveform[17]; // State of all possible pins
static volatile uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
static volatile uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine
static volatile uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin
static volatile uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation
static uint32_t (*timer1CB)() = NULL;
// Non-speed critical bits
#pragma GCC optimize ("Os")
static inline ICACHE_RAM_ATTR uint32_t GetCycleCount() {
uint32_t ccount;
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
return ccount;
}
// Interrupt on/off control
static ICACHE_RAM_ATTR void timer1Interrupt();
static bool timerRunning = false;
static void initTimer() {
timer1_disable();
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
timerRunning = true;
}
static void ICACHE_RAM_ATTR deinitTimer() {
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
timer1_disable();
timer1_isr_init();
timerRunning = false;
}
// Set a callback. Pass in NULL to stop it
void setTimer1Callback(uint32_t (*fn)()) {
timer1CB = fn;
if (!timerRunning && fn) {
initTimer();
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
} else if (timerRunning && !fn && !waveformEnabled) {
deinitTimer();
}
}
// Start up a waveform on a pin, or change the current one. Will change to the new
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
// first, then it will immediately begin.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
if ((pin > 16) || isFlashInterfacePin(pin)) {
return false;
}
Waveform *wave = &waveform[pin];
// Adjust to shave off some of the IRQ time, approximately
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
if (runTimeUS && !wave->expiryCycle) {
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
}
uint32_t mask = 1<<pin;
if (!(waveformEnabled & mask)) {
// Actually set the pin high or low in the IRQ service to guarantee times
wave->nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1);
waveformToEnable |= mask;
if (!timerRunning) {
initTimer();
timer1_write(microsecondsToClockCycles(10));
} else {
// Ensure timely service....
if (T1L > microsecondsToClockCycles(10)) {
timer1_write(microsecondsToClockCycles(10));
}
}
while (waveformToEnable) {
delay(0); // Wait for waveform to update
}
}
return true;
}
// Speed critical bits
#pragma GCC optimize ("O2")
// Normally would not want two copies like this, but due to different
// optimization levels the inline attribute gets lost if we try the
// other version.
static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ() {
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
return ccount;
}
static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) {
if (a < b) {
return a;
}
return b;
}
// Stops a waveform on a pin
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
// Can't possibly need to stop anything if there is no timer active
if (!timerRunning) {
return false;
}
// If user sends in a pin >16 but <32, this will always point to a 0 bit
// If they send >=32, then the shift will result in 0 and it will also return false
uint32_t mask = 1<<pin;
if (!(waveformEnabled & mask)) {
return false; // It's not running, nothing to do here
}
waveformToDisable |= mask;
// Ensure timely service....
if (T1L > microsecondsToClockCycles(10)) {
timer1_write(microsecondsToClockCycles(10));
}
while (waveformToDisable) {
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
}
if (!waveformEnabled && !timer1CB) {
deinitTimer();
}
return true;
}
// The SDK and hardware take some time to actually get to our NMI code, so
// decrement the next IRQ's timer value by a bit so we can actually catch the
// real CPU cycle counter we want for the waveforms.
#if F_CPU == 80000000
#define DELTAIRQ (microsecondsToClockCycles(3))
#else
#define DELTAIRQ (microsecondsToClockCycles(2))
#endif
static ICACHE_RAM_ATTR void timer1Interrupt() {
// Optimize the NMI inner loop by keeping track of the min and max GPIO that we
// are generating. In the common case (1 PWM) these may be the same pin and
// we can avoid looking at the other pins.
static int startPin = 0;
static int endPin = 0;
uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14);
if (waveformToEnable || waveformToDisable) {
// Handle enable/disable requests from main app.
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
waveformState &= ~waveformToEnable; // And clear the state of any just started
waveformToEnable = 0;
waveformToDisable = 0;
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
startPin = __builtin_ffs(waveformEnabled) - 1;
// Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one)
endPin = 32 - __builtin_clz(waveformEnabled);
}
bool done = false;
if (waveformEnabled) {
do {
nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
for (int i = startPin; i <= endPin; i++) {
uint32_t mask = 1<<i;
// If it's not on, ignore!
if (!(waveformEnabled & mask)) {
continue;
}
Waveform *wave = &waveform[i];
uint32_t now = GetCycleCountIRQ();
// Disable any waveforms that are done
if (wave->expiryCycle) {
int32_t expiryToGo = wave->expiryCycle - now;
if (expiryToGo < 0) {
// Done, remove!
waveformEnabled &= ~mask;
if (i == 16) {
GP16O &= ~1;
} else {
ClearGPIO(mask);
}
continue;
}
}
// Check for toggles
int32_t cyclesToGo = wave->nextServiceCycle - now;
if (cyclesToGo < 0) {
// See #7057
// The following is a no-op unless we have overshot by an entire waveform cycle.
// As modulus is an expensive operation, this code is removed for now:
// cyclesToGo = -((-cyclesToGo) % (wave->nextTimeHighCycles + wave->nextTimeLowCycles));
//
// Alternative version with lower CPU impact:
// while (-cyclesToGo > wave->nextTimeHighCycles + wave->nextTimeLowCycles) { cyclesToGo += wave->nextTimeHighCycles + wave->nextTimeLowCycles)};
waveformState ^= mask;
if (waveformState & mask) {
if (i == 16) {
GP16O |= 1; // GPIO16 write slow as it's RMW
} else {
SetGPIO(mask);
}
wave->nextServiceCycle = now + wave->nextTimeHighCycles + cyclesToGo;
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeHighCycles + cyclesToGo, 1));
} else {
if (i == 16) {
GP16O &= ~1; // GPIO16 write slow as it's RMW
} else {
ClearGPIO(mask);
}
wave->nextServiceCycle = now + wave->nextTimeLowCycles + cyclesToGo;
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeLowCycles + cyclesToGo, 1));
}
} else {
uint32_t deltaCycles = wave->nextServiceCycle - now;
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
}
}
// Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur
uint32_t now = GetCycleCountIRQ();
int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles);
int32_t cyclesLeftTimeout = timeoutCycle - now;
done = (cycleDeltaNextEvent < 0) || (cyclesLeftTimeout < 0);
} while (!done);
} // if (waveformEnabled)
if (timer1CB) {
nextEventCycles = min_u32(nextEventCycles, timer1CB());
}
if (nextEventCycles < microsecondsToClockCycles(10)) {
nextEventCycles = microsecondsToClockCycles(10);
}
nextEventCycles -= DELTAIRQ;
// Do it here instead of global function to save time and because we know it's edge-IRQ
#if F_CPU == 160000000
T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS
#else
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
#endif
TEIE |= TEIE1; // Edge int enable
}
};
#endif

View File

@ -1,71 +0,0 @@
/*
esp8266_waveform - General purpose waveform generation and control,
supporting outputs on all pins in parallel.
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
The core idea is to have a programmable waveform generator with a unique
high and low period (defined in microseconds). TIMER1 is set to 1-shot
mode and is always loaded with the time until the next edge of any live
waveforms.
Up to one waveform generator per pin supported.
Each waveform generator is synchronized to the ESP cycle counter, not the
timer. This allows for removing interrupt jitter and delay as the counter
always increments once per 80MHz clock. Changes to a waveform are
contiguous and only take effect on the next waveform transition,
allowing for smooth transitions.
This replaces older tone(), analogWrite(), and the Servo classes.
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#ifndef __ESP8266_WAVEFORM_H
#define __ESP8266_WAVEFORM_H
#ifdef __cplusplus
extern "C" {
#endif
// Start or change a waveform of the specified high and low times on specific pin.
// If runtimeUS > 0 then automatically stop it after that many usecs.
// Returns true or false on success or failure.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS);
// Stop a waveform, if any, on the specified pin.
// Returns true or false on success or failure.
int stopWaveform(uint8_t pin);
// Add a callback function to be called on *EVERY* timer1 trigger. The
// callback returns the number of microseconds until the next desired call.
// However, since it is called every timer1 interrupt, it may be called
// again before this period. It should therefore use the ESP Cycle Counter
// to determine whether or not to perform an operation.
// Pass in NULL to disable the callback and, if no other waveforms being
// generated, stop the timer as well.
// Make sure the CB function has the ICACHE_RAM_ATTR decorator.
void setTimer1Callback(uint32_t (*fn)());
#ifdef __cplusplus
}
#endif
#endif

View File

@ -10,7 +10,7 @@
*/
/*
* @title Espalexa library
* @version 2.4.5
* @version 2.4.6
* @author Christian Schwinne
* @license MIT
* @contributors d-999
@ -49,7 +49,7 @@
#include <WiFiUdp.h>
#ifdef ESPALEXA_DEBUG
#pragma message "Espalexa 2.4.5 debug mode"
#pragma message "Espalexa 2.4.6 debug mode"
#define EA_DEBUG(x) Serial.print (x)
#define EA_DEBUGLN(x) Serial.println (x)
#else
@ -81,35 +81,29 @@ private:
WiFiUDP espalexaUdp;
IPAddress ipMulti;
bool udpConnected = false;
char packetBuffer[255]; //buffer to hold incoming udp packet
String escapedMac=""; //lowercase mac address
//private member functions
String boolString(bool st)
{
return(st)?"true":"false";
}
String modeString(EspalexaColorMode m)
const char* modeString(EspalexaColorMode m)
{
if (m == EspalexaColorMode::xy) return "xy";
if (m == EspalexaColorMode::hs) return "hs";
return "ct";
}
String typeString(EspalexaDeviceType t)
const char* typeString(EspalexaDeviceType t)
{
switch (t)
{
case EspalexaDeviceType::dimmable: return "Dimmable light";
case EspalexaDeviceType::whitespectrum: return "Color temperature light";
case EspalexaDeviceType::color: return "Color light";
case EspalexaDeviceType::extendedcolor: return "Extended color light";
case EspalexaDeviceType::dimmable: return PSTR("Dimmable light");
case EspalexaDeviceType::whitespectrum: return PSTR("Color temperature light");
case EspalexaDeviceType::color: return PSTR("Color light");
case EspalexaDeviceType::extendedcolor: return PSTR("Extended color light");
}
return "Light";
return "";
}
String modelidString(EspalexaDeviceType t)
const char* modelidString(EspalexaDeviceType t)
{
switch (t)
{
@ -118,7 +112,7 @@ private:
case EspalexaDeviceType::color: return "LST001";
case EspalexaDeviceType::extendedcolor: return "LCT015";
}
return "Plug";
return "";
}
//Workaround functions courtesy of Sonoff-Tasmota
@ -135,38 +129,38 @@ private:
}
//device JSON string: color+temperature device emulates LCT015, dimmable device LWB010, (TODO: on/off Plug 01, color temperature device LWT010, color device LST001)
String deviceJsonString(uint8_t deviceId)
void deviceJsonString(uint8_t deviceId, char* buf)
{
deviceId--;
if (deviceId >= currentDeviceCount) return "{}"; //error
if (deviceId >= currentDeviceCount) {strcpy(buf,"{}"); return;} //error
EspalexaDevice* dev = devices[deviceId];
String json = "{\"state\":{\"on\":";
json += boolString(dev->getValue());
if (dev->getType() != EspalexaDeviceType::onoff) //bri support
{
json += ",\"bri\":" + String(dev->getLastValue()-1);
if (static_cast<uint8_t>(dev->getType()) > 2) //color support
{
json += ",\"hue\":" + String(dev->getHue()) + ",\"sat\":" + String(dev->getSat());
json += ",\"effect\":\"none\",\"xy\":[" + String(dev->getX()) + "," + String(dev->getY()) + "]";
}
if (static_cast<uint8_t>(dev->getType()) > 1 && dev->getType() != EspalexaDeviceType::color) //white spectrum support
{
json += ",\"ct\":" + String(dev->getCt());
}
}
json += ",\"alert\":\"none";
if (static_cast<uint8_t>(dev->getType()) > 1) json += "\",\"colormode\":\"" + modeString(dev->getColorMode());
json += "\",\"mode\":\"homeautomation\",\"reachable\":true},";
json += "\"type\":\"" + typeString(dev->getType());
json += "\",\"name\":\"" + dev->getName();
json += "\",\"modelid\":\"" + modelidString(dev->getType());
json += "\",\"manufacturername\":\"Philips\",\"productname\":\"E" + String(static_cast<uint8_t>(dev->getType()));
json += "\",\"uniqueid\":\"" + String(encodeLightId(deviceId+1));
json += "\",\"swversion\":\"espalexa-2.4.5\"}";
return json;
//char buf_bri[12] = "";
//brightness support, add "bri" to JSON
//if (dev->getType() != EspalexaDeviceType::onoff)
// sprintf(buf_bri,",\"bri\":%u", dev->getLastValue()-1);
char buf_col[80] = "";
//color support
if (static_cast<uint8_t>(dev->getType()) > 2)
sprintf_P(buf_col,PSTR(",\"hue\":%u,\"sat\":%u,\"effect\":\"none\",\"xy\":[%f,%f]")
,dev->getHue(), dev->getSat(), dev->getX(), dev->getY());
char buf_ct[16] = "";
//white spectrum support
if (static_cast<uint8_t>(dev->getType()) > 1 && dev->getType() != EspalexaDeviceType::color)
sprintf(buf_ct, ",\"ct\":%u", dev->getCt());
char buf_cm[20] = "";
if (static_cast<uint8_t>(dev->getType()) > 1)
sprintf(buf_cm,PSTR("\",\"colormode\":\"%s"), modeString(dev->getColorMode()));
sprintf_P(buf, PSTR("{\"state\":{\"on\":%s,\"bri\":%u%s%s,\"alert\":\"none%s\",\"mode\":\"homeautomation\",\"reachable\":true},"
"\"type\":\"%s\",\"name\":\"%s\",\"modelid\":\"%s\",\"manufacturername\":\"Philips\",\"productname\":\"E%u"
"\",\"uniqueid\":\"%u\",\"swversion\":\"espalexa-2.4.6\"}")
, (dev->getValue())?"true":"false", dev->getLastValue()-1, buf_col, buf_ct, buf_cm, typeString(dev->getType()),
dev->getName().c_str(), modelidString(dev->getType()), static_cast<uint8_t>(dev->getType()), encodeLightId(deviceId+1));
}
//Espalexa status page /espalexa
@ -181,14 +175,14 @@ private:
res += "Value of device " + String(i+1) + " (" + dev->getName() + "): " + String(dev->getValue()) + " (" + typeString(dev->getType());
if (static_cast<uint8_t>(dev->getType()) > 1) //color support
{
res += ", colormode=" + modeString(dev->getColorMode()) + ", r=" + String(dev->getR()) + ", g=" + String(dev->getG()) + ", b=" + String(dev->getB());
res += ", colormode=" + String(modeString(dev->getColorMode())) + ", r=" + String(dev->getR()) + ", g=" + String(dev->getG()) + ", b=" + String(dev->getB());
res +=", ct=" + String(dev->getCt()) + ", hue=" + String(dev->getHue()) + ", sat=" + String(dev->getSat()) + ", x=" + String(dev->getX()) + ", y=" + String(dev->getY());
}
res += ")\r\n";
}
res += "\r\nFree Heap: " + (String)ESP.getFreeHeap();
res += "\r\nUptime: " + (String)millis();
res += "\r\n\r\nEspalexa library v2.4.5 by Christian Schwinne 2020";
res += "\r\n\r\nEspalexa library v2.4.6 by Christian Schwinne 2020";
server->send(200, "text/plain", res);
}
#endif
@ -206,7 +200,7 @@ private:
EA_DEBUGLN("Body: " + body);
if(!handleAlexaApiCall(server))
#endif
server->send(404, "text/plain", "Not Found (espalexa-internal)");
server->send(404, "text/plain", "Not Found (espalexa)");
}
//send description.xml device property page
@ -216,30 +210,31 @@ private:
IPAddress localIP = WiFi.localIP();
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
String setup_xml = "<?xml version=\"1.0\" ?>"
char buf[1024];
sprintf_P(buf,PSTR("<?xml version=\"1.0\" ?>"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
"<specVersion><major>1</major><minor>0</minor></specVersion>"
"<URLBase>http://"+ String(s) +":80/</URLBase>"
"<URLBase>http://%s:80/</URLBase>"
"<device>"
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
"<friendlyName>Espalexa ("+ String(s) +")</friendlyName>"
"<friendlyName>Espalexa (%s)</friendlyName>"
"<manufacturer>Royal Philips Electronics</manufacturer>"
"<manufacturerURL>http://www.philips.com</manufacturerURL>"
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
"<modelName>Philips hue bridge 2012</modelName>"
"<modelNumber>929000226503</modelNumber>"
"<modelURL>http://www.meethue.com</modelURL>"
"<serialNumber>"+ escapedMac +"</serialNumber>"
"<UDN>uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"</UDN>"
"<serialNumber>%s</serialNumber>"
"<UDN>uuid:2f402f80-da50-11e1-9b23-%s</UDN>"
"<presentationURL>index.html</presentationURL>"
"</device>"
"</root>";
"</root>"),s,s,escapedMac.c_str(),escapedMac.c_str());
server->send(200, "text/xml", setup_xml.c_str());
server->send(200, "text/xml", buf);
EA_DEBUG("Sending :");
EA_DEBUGLN(setup_xml);
EA_DEBUG("Send setup.xml");
//EA_DEBUGLN(setup_xml);
}
//init the server
@ -290,22 +285,23 @@ private:
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
String response =
"HTTP/1.1 200 OK\r\n"
char buf[1024];
sprintf_P(buf,PSTR("HTTP/1.1 200 OK\r\n"
"EXT:\r\n"
"CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL
"LOCATION: http://"+ String(s) +":80/description.xml\r\n"
"LOCATION: http://%s:80/description.xml\r\n"
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
"hue-bridgeid: "+ escapedMac +"\r\n"
"hue-bridgeid: %s\r\n"
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
"USN: uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"::ssdp:all\r\n" // _uuid::_deviceType
"\r\n";
"USN: uuid:2f402f80-da50-11e1-9b23-%s::ssdp:all\r\n" // _uuid::_deviceType
"\r\n"),s,escapedMac.c_str(),escapedMac.c_str());
espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort());
#ifdef ARDUINO_ARCH_ESP32
espalexaUdp.write((uint8_t*)response.c_str(), response.length());
espalexaUdp.write((uint8_t*)buf, strlen(buf));
#else
espalexaUdp.write(response.c_str());
espalexaUdp.write(buf);
#endif
espalexaUdp.endPacket();
}
@ -362,7 +358,8 @@ public:
if (!packetSize) return; //no new udp packet
EA_DEBUGLN("Got UDP!");
int len = espalexaUdp.read(packetBuffer, 254);
char packetBuffer[255]; //buffer to hold incoming udp packet
uint16_t len = espalexaUdp.read(packetBuffer, 254);
if (len > 0) {
packetBuffer[len] = 0;
}
@ -370,10 +367,9 @@ public:
if (!discoverable) return; //do not reply to M-SEARCH if not discoverable
String request = packetBuffer;
if(request.indexOf("M-SEA") >= 0) { //M-SEARCH
if(request.indexOf("M-SEARCH") >= 0) {
EA_DEBUGLN(request);
//match upnp:rootdevice, device:basic:1, ssdp:all and ssdp:discover
if(request.indexOf("np:rootd") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("dp:all") > 0 || request.indexOf("dp:dis") > 0) {
if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("ssdp:all") > 0) {
EA_DEBUGLN("Responding search req...");
respondToSearch();
}
@ -448,13 +444,13 @@ public:
{
EA_DEBUGLN("devType");
body = "";
server->send(200, "application/json", "[{\"success\":{\"username\":\"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]");
server->send(200, "application/json", F("[{\"success\":{\"username\":\"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]"));
return true;
}
if (req.indexOf("state") > 0) //client wants to control light
{
server->send(200, "application/json", "[{\"success\":{\"/lights/1/state/\": true}}]");
server->send(200, "application/json", F("[{\"success\":{\"/lights/1/state/\": true}}]"));
uint32_t devId = req.substring(req.indexOf("lights")+7).toInt();
EA_DEBUG("ls"); EA_DEBUGLN(devId);
@ -531,7 +527,9 @@ public:
for (int i = 0; i<currentDeviceCount; i++)
{
jsonTemp += "\"" + String(encodeLightId(i+1)) + "\":";
jsonTemp += deviceJsonString(i+1);
char buf[512];
deviceJsonString(i+1, buf);
jsonTemp += buf;
if (i < currentDeviceCount-1) jsonTemp += ",";
}
jsonTemp += "}";
@ -544,7 +542,9 @@ public:
{
server->send(200, "application/json", "{}");
} else {
server->send(200, "application/json", deviceJsonString(devId));
char buf[512];
deviceJsonString(devId, buf);
server->send(200, "application/json", buf);
}
}

View File

@ -28,6 +28,7 @@ EspalexaDevice::EspalexaDevice(String deviceName, DeviceCallbackFunction gnCallb
_callbackDev = gnCallback;
_type = t;
if (t == EspalexaDeviceType::onoff) _type = EspalexaDeviceType::dimmable; //on/off is broken, so make dimmable device instead
if (t == EspalexaDeviceType::whitespectrum) _mode = EspalexaColorMode::ct;
_val = initialValue;
_val_last = _val;
}

View File

@ -1,6 +1,6 @@
#ifndef EspalexaDevice_h
#define EspalexaDevice_h
#include <functional>
#include "Arduino.h"
#include <functional>

View File

@ -74,16 +74,18 @@ void notify(byte callMode, bool followUp)
void realtimeLock(uint32_t timeoutMs, byte md)
{
if (!realtimeMode){
if (!realtimeMode && !realtimeOverride){
for (uint16_t i = 0; i < ledCount; i++)
{
strip.setPixelColor(i,0,0,0,0);
}
realtimeMode = md;
}
realtimeTimeout = millis() + timeoutMs;
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
if (arlsForceMaxBri) strip.setBrightness(255);
realtimeMode = md;
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(255);
}
@ -103,8 +105,10 @@ void handleNotifications()
//unlock strip when realtime UDP times out
if (realtimeMode && millis() > realtimeTimeout)
{
if (realtimeOverride == REALTIME_OVERRIDE_ONCE) realtimeOverride = REALTIME_OVERRIDE_NONE;
strip.setBrightness(bri);
realtimeMode = REALTIME_MODE_INACTIVE;
realtimeIP[0] = 0;
}
//receive UDP notifications
@ -122,6 +126,7 @@ void handleNotifications()
uint8_t lbuf[packetSize];
rgbUdp.read(lbuf, packetSize);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
if (realtimeOverride) return;
uint16_t id = 0;
for (uint16_t i = 0; i < packetSize -2; i += 3)
{
@ -202,50 +207,52 @@ void handleNotifications()
{
realtimeIP = notifierUdp.remoteIP();
DEBUG_PRINTLN(notifierUdp.remoteIP());
if (packetSize > 1) {
if (udpIn[1] == 0)
{
realtimeTimeout = 0;
return;
} else {
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
}
if (udpIn[0] == 1) //warls
{
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2) //drgb
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
if (packetSize < 2) return;
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 3) //drgbw
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 4) //dnrgb
{
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (uint16_t i = 4; i < packetSize -2; i += 3)
{
if (id >= ledCount) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++;
}
}
strip.show();
if (udpIn[1] == 0)
{
realtimeTimeout = 0;
return;
} else {
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
}
if (realtimeOverride) return;
if (udpIn[0] == 1) //warls
{
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2) //drgb
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 3) //drgbw
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 4) //dnrgb
{
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (uint16_t i = 4; i < packetSize -2; i += 3)
{
if (id >= ledCount) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++;
}
}
strip.show();
}
}
}

View File

@ -67,7 +67,7 @@ void WLED::loop()
if (doReboot)
reset();
if (!realtimeMode) // block stuff if WARLS/Adalight is enabled
if (!realtimeMode || realtimeOverride) // block stuff if WARLS/Adalight is enabled
{
if (apActive)
dnsServer.processNextRequest();
@ -89,8 +89,10 @@ void WLED::loop()
#ifdef ESP8266
MDNS.update();
#endif
if (millis() - lastMqttReconnectAttempt > 30000)
if (millis() - lastMqttReconnectAttempt > 30000) {
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
initMqtt();
}
// DEBUG serial logging
#ifdef WLED_DEBUG
@ -284,7 +286,7 @@ void WLED::initAP(bool resetAP)
void WLED::initConnection()
{
WiFi.disconnect(); // close old connections
WiFi.disconnect(true); // close old connections
#ifdef ESP8266
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
#endif
@ -308,6 +310,7 @@ void WLED::initConnection()
} else {
DEBUG_PRINTLN("Access point disabled.");
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_STA);
}
}
showWelcomePage = false;

View File

@ -3,12 +3,12 @@
/*
Main sketch, global variable declarations
@title WLED project sketch
@version 0.9.1n
@version 0.10.0
@author Christian Schwinne
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2004230
#define VERSION 2005100
// 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).
@ -109,10 +109,10 @@
#include <IRutils.h>
#endif
// remove flicker because PWM signal of RGB channels can become out of phase
#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266)
#include "src/dependencies/arduino/core_esp8266_waveform.h"
#endif
// remove flicker because PWM signal of RGB channels can become out of phase (part of core as of Arduino core v2.7.0)
//#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266)
// #include "src/dependencies/arduino/core_esp8266_waveform.h"
//#endif
// enable additional debug output
#ifdef WLED_DEBUG
@ -148,7 +148,8 @@
#endif
// Global Variable definitions
WLED_GLOBAL char versionString[] _INIT("0.9.1n");
WLED_GLOBAL char versionString[] _INIT("0.10.0");
#define WLED_CODENAME "Namigai"
// AP and OTA default passwords (for maximum security change them!)
WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS);
@ -215,7 +216,7 @@ WLED_GLOBAL bool notifyMacro _INIT(false); // send notifi
WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes
WLED_GLOBAL bool notifyTwice _INIT(false); // notifications use UDP: enable if devices don't sync reliably
WLED_GLOBAL bool alexaEnabled _INIT(true); // enable device discovery by Amazon Echo
WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo
WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand
WLED_GLOBAL char blynkApiKey[36] _INIT(""); // Auth token for Blynk server. If empty, no connection will be made
@ -414,6 +415,7 @@ WLED_GLOBAL bool saveCurrPresetCycConf _INIT(false);
// realtime
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);
WLED_GLOBAL IPAddress realtimeIP _INIT((0, 0, 0, 0));
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
@ -447,6 +449,7 @@ WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L);
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
WLED_GLOBAL IPAddress ntpServerIP;
WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390);
WLED_GLOBAL uint16_t rolloverMillis _INIT(0);
// Temp buffer
WLED_GLOBAL char* obuf;

View File

@ -594,7 +594,7 @@ void savedToPresets()
savedPresets &= ~(0x01 << (index-1));
}
}
if (EEPROM.read(700) == 2) {
if (EEPROM.read(700) == 2 || EEPROM.read(700) == 3) {
savedPresets |= 0x01 << 15;
} else
{

View File

@ -67,13 +67,13 @@ void handleSerial()
break;
case AdaState::Data_Blue:
byte blue = next;
setRealtimePixel(pixel++, red, green, blue, 0);
if (!realtimeOverride) setRealtimePixel(pixel++, red, green, blue, 0);
if (--count > 0) state = AdaState::Data_Red;
else {
if (!realtimeMode && bri == 0) strip.setBrightness(briLast);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
strip.show();
if (!realtimeOverride) strip.show();
state = AdaState::Header_A;
}
break;

View File

@ -382,7 +382,7 @@ void getSettingsJS(byte subPage, char* dest)
default: sprintf(hueErrorString,"Bridge Error %i",hueError);
}
sappends('m',"(\"hms\")[0]",hueErrorString);
sappends('m',"(\"sip\")[0]",hueErrorString);
#endif
}
@ -445,12 +445,12 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',"NO",otaLock);
sappend('c',"OW",wifiLock);
sappend('c',"AO",aOtaEnabled);
sappends('m',"(\"msg\")[0]","WLED ");
sappends('m',"(\"sip\")[0]","WLED ");
olen -= 2; //delete ";
oappend(versionString);
oappend(" (build ");
oappendi(VERSION);
oappend(") OK\";");
oappend(")\";");
}
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled