Compare commits

...

58 Commits

Author SHA1 Message Date
cschwinne
f4a2ffc5d2 Update platformio.ini 2019-10-26 01:01:16 +02:00
cschwinne
ba1117e10e Release v0.8.6 2019-10-26 00:00:44 +02:00
cschwinne
0cd46f932a Fix 2.4.0 2019-10-25 15:32:09 +02:00
cschwinne
937f404583 Fix ESP32 2019-10-25 11:54:47 +02:00
cschwinne
d13d60d752 New WiFi logic 2019-10-25 00:14:58 +02:00
cschwinne
31e4e7c709 HA discovery wdt reset 2019-10-20 17:38:25 +02:00
cschwinne
0d3a8ce31b Update MQTT library 2019-10-20 12:48:29 +02:00
cschwinne
be185b46a7 Reworked WiFi logic
Remaining issues:
MQTT reconnects too often
WiFI AP doesn't work if searching for STA
2019-10-18 23:47:11 +02:00
cschwinne
90fa5b3b93 Removed onlyAP 2019-10-18 14:06:07 +02:00
cschwinne
733996772b WLED_CONNECTED macro 2019-10-18 13:26:39 +02:00
cschwinne
d4c921ea2e Timebase sync 2019-10-18 12:19:52 +02:00
cschwinne
2852061699 Refactor WS812FX file names 2019-10-07 23:38:21 +02:00
cschwinne
d8859b9f0a Improved running effects 2019-10-07 23:22:56 +02:00
cschwinne
ae1bc96006 More effects use FRAMETIME 2019-10-07 20:17:52 +02:00
cschwinne
f30ffb4413 Improved rainbow effects 2019-10-05 01:56:55 +02:00
cschwinne
273c6467c8 Fix travis (ESP01 too little flash) 2019-10-04 01:38:42 +02:00
cschwinne
846a1d007c Improved fade modes 2019-10-04 01:21:18 +02:00
cschwinne
1dccc8dc78 Improved Color Wipe 2019-10-03 20:57:22 +02:00
cschwinne
e0d67bd057 Improved effects 2019-10-03 16:33:37 +02:00
cschwinne
4b4b93ac04 Added Halloween Eyes effect
Added Twinklecat
2019-10-02 01:17:26 +02:00
Aircoookie
4390aee1e0 Merge pull request #234 from pille/master
fix verison number of current release
2019-09-29 11:20:30 +02:00
pille
4cddb16788 fix verison number of current release 2019-09-28 13:43:57 +02:00
cschwinne
e1179fd8c8 Delete accidentallly included bin 2019-09-26 14:06:50 +02:00
cschwinne
cb77285277 Support APA102 on ESP32 2019-09-26 14:02:58 +02:00
cschwinne
6c9d161950 Fixed transitions and gamma 2019-09-19 21:15:20 +02:00
Aircoookie
40aaac5868 Merge pull request #218 from Aircoookie/captiveportal
Release v0.8.5
2019-09-12 15:30:34 +02:00
cschwinne
e16b69594e Fix PIO 2019-09-12 13:08:07 +02:00
cschwinne
4837bf007a Update welcome page 2019-09-12 12:41:51 +02:00
cschwinne
705fd4dafd Release v0.8.5 2019-09-12 12:40:06 +02:00
cschwinne
a3e28d3c66 First version of captive portal 2019-09-05 22:45:59 +02:00
cschwinne
4a6755c28a Added C9 and Sakura palettes 2019-08-31 01:41:25 +02:00
cschwinne
188fe5dc52 Added TwinkleFOX effect
Added Orangery palette
2019-08-30 15:39:34 +02:00
cschwinne
44a8ae457d Fixed JSON API POST requests
Speed set COOLING for Fire2012 (#208)
2019-08-25 23:52:40 +02:00
cschwinne
92eafcfe1a Fixed crash on opening settings in core 2.5.2 (#168) 2019-08-21 01:18:25 +02:00
Aircoookie
b12b031fdd Merge pull request #202 from timothybrown/mqttauth
MQTT Authentication Support
2019-08-19 23:20:35 +02:00
cschwinne
492ec489a1 Small changes to MQTT auth
Changed mqttPort to uint16 type
Password no longer transmitted to settings page
Chnaged topics and identifiers to last 6 bytes of mac format
Added security warning
2019-08-18 18:14:17 +02:00
Timothy Brown
c57124e876 Added MQTT port field, bumped user, pass and CID to 40 characters 2019-08-17 21:34:47 -04:00
Timothy Brown
95b33c9c34 Tidied up code 2019-08-17 07:26:40 -04:00
Timothy Brown
c6d8b63e54 Added MQTT authentication support 2019-08-17 06:27:06 -04:00
Aircoookie
f0f02c4ea6 Merge pull request #193 from stockklauser/0.8.4_master_extend_VS
Fix Compile Issues with Visual Studio 2017 / Visual Assist Arduino  and Add Visual Studio Project Files
2019-07-24 23:22:01 +02:00
thomas.stockklauser
eb2cb6810a Modify Structure to fix path issues 2019-07-23 18:51:26 +02:00
thomas.stockklauser
b3c090e9ed Add Visual Studio Support and fix a Compile Issue with Visual Assist / Studio 2017 2019-07-23 18:04:26 +02:00
thomas.stockklauser
13366fc9f8 Add Visual Studio Project Structure 2019-07-23 17:59:55 +02:00
thomas.stockklauser
929af7830a Add Visual Studio Project Structure
Fix a compile Issue in wled19_json.ino with Visual Studio / Visual Assist
2019-07-23 17:35:40 +02:00
cschwinne
13062cf0e4 Merge branch 'master' of https://github.com/Aircoookie/WLED.git 2019-06-21 23:14:36 +02:00
cschwinne
b897a8a35f Updated to ArduinoJson v6
Fixed JSON crash on core v2.5.2
2019-06-21 23:12:58 +02:00
cschwinne
117dc5288d Added basic segment support
Updated Espalexa
2019-06-20 14:40:12 +02:00
Aircoookie
4b5a3bd3d5 Revert LEDPIN to 2 2019-05-23 00:33:15 +02:00
cschwinne
b224a67ea7 Refactored WS2812FX variable names 2019-05-22 00:23:09 +02:00
cschwinne
793f919d59 Added MQTT auto reconnect 2019-05-21 18:50:56 +02:00
Aircoookie
315987b2f6 Merge pull request #160 from T-Arens/master
Added support for APA102 LEDs.
2019-05-04 15:54:33 +02:00
Thomas Arens
9b7db548a2 Only disable the button pin if it conflicts with one of the APA102 pins. 2019-05-01 16:52:22 +02:00
Thomas Arens
126b70f781 Added support for APA102 LEDs. Uncomment "#define USE_APA102" in NbpWrapper.h. Connect clock to GPIO 0 and data to GPIO 2. 2019-05-01 03:09:08 +02:00
Aircoookie
0bbff627e2 Merge pull request #152 from YeonV/patch-1
Fixed MQTT color response
2019-04-15 22:37:41 +02:00
Yeon Vinzenz Varapragasam
961d23e2a1 Fixed MQTT color response
Leading zeros are not trimmed on /c topic anymore :)
Before blue: #FF
After blue: #0000FF
2019-04-15 20:43:32 +02:00
cschwinne
b03ff9a48a Updated Espalexa to 2.4.2
Added UDP realtime 255 as keep state until changed
Added "true" and "false" MQTT payloads
2019-04-14 19:31:25 +02:00
cschwinne
3ffb40fafa Fixed HA autodiscovery and MQTT ON 2019-03-27 21:31:59 +01:00
cschwinne
1a3b4ac2ac Fixed meteor FX crashing 2019-03-27 21:06:07 +01:00
51 changed files with 8568 additions and 4779 deletions

2
.gitignore vendored
View File

@@ -3,3 +3,5 @@
.piolibdeps
.vscode
!.vscode/extensions.json
/wled00/Release
/wled00/extLibs

BIN
.vs/wled00/v15/.suo Normal file

Binary file not shown.

View File

@@ -21,15 +21,15 @@ upload_speed = 115200
upload_speed_fast = 921600
build_flags =
-w ; supresses all C/C++ warnings
; -D VERSION=0.8.4
; -D VERSION=0.8.5
; -D DEBUG
# TODO replace libs in /lib with managed libs in here if possible.
# If they are not changed it's just a matter of setting the correct version and change the import statement
lib_deps_external =
#Blynk@0.5.4(changed)
#E131@1.0.0(changed)
FastLED@3.2.6
NeoPixelBus@2.4.3
FastLED@3.3.2
NeoPixelBus@2.5.1
ESPAsyncTCP@1.2.0
AsyncTCP@1.0.3
Esp Async WebServer@1.2.0
@@ -56,8 +56,9 @@ arduino_core_2_4_0 = espressif8266@1.6.0
arduino_core_2_4_1 = espressif8266@1.7.3
arduino_core_2_4_2 = espressif8266@1.8.0
arduino_core_2_5_0 = espressif8266@2.0.4
arduino_core_2_5_2 = espressif8266@2.2.3
arduino_core_stage = https://github.com/platformio/platform-espressif8266.git#feature/stage
platform = ${common:esp8266.arduino_core_2_4_2}
platform = ${common:esp8266.arduino_core_2_5_2}
build_flags =
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
-Wl,-Teagle.flash.4m1m.ld ;;;; Required for core > v2.5.0 or staging version 4MB Flash 3MB SPIFFs
@@ -70,8 +71,8 @@ build_flags =
; -D WLED_DISABLE_MOBILE_UI
; -D WLED_DISABLE_OTA
; -D WLED_DISABLE_ALEXA
; -D WLED_DISABLE_BLYNK
; -D WLED_DISABLE_CRONIXIE
-D WLED_DISABLE_BLYNK
-D WLED_DISABLE_CRONIXIE
; -D WLED_DISABLE_HUESYNC
-D WLED_DISABLE_INFRARED
@@ -83,8 +84,8 @@ build_flags =
; -D WLED_DISABLE_MOBILE_UI
-D WLED_DISABLE_OTA
; -D WLED_DISABLE_ALEXA
; -D WLED_DISABLE_BLYNK
; -D WLED_DISABLE_CRONIXIE
-D WLED_DISABLE_BLYNK
-D WLED_DISABLE_CRONIXIE
; -D WLED_DISABLE_HUESYNC
-D WLED_DISABLE_INFRARED
@@ -159,5 +160,4 @@ build_flags =
lib_deps =
${common.lib_deps_external}
lib_ignore =
IRremoteESP8266
IRremoteESP8266

View File

@@ -7,36 +7,36 @@
## Welcome to my project WLED!
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs!
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs!
### Features:
- WS2812FX library integrated for 80 special effects
- FastLED noise effects and palettes
- Customizable Mobile and desktop UI with color and effect controls
- Settings page - configuration over network
- Access Point and station mode - automatic failsafe AP
- Support for RGBW strips
- 25 user presets to save and load colors/effects easily, supports cycling through them.
- Macro functions to automatically execute API calls
- Nightlight function (gradually dims down)
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable
- Configurable analog clock + support for the Cronixie kit by Diamex
- Configurable Auto Brightness limit for safer operation
- WS2812FX library integrated for 80 special effects
- FastLED noise effects and palettes
- Customizable Mobile and desktop UI with color and effect controls
- Settings page - configuration over network
- Access Point and station mode - automatic failsafe AP
- Support for RGBW strips
- 25 user presets to save and load colors/effects easily, supports cycling through them.
- Macro functions to automatically execute API calls
- Nightlight function (gradually dims down)
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable
- Configurable analog clock + support for the Cronixie kit by Diamex
- Configurable Auto Brightness limit for safer operation
### Supported light control interfaces:
- WLED Android app
- HTTP and JSON request APIs
- Blynk IoT
- MQTT
- E1.31
- Hyperion
- UDP realtime
- Alexa voice control (including dimming and color)
- Sync to Philips hue lights
- Adalight (PC ambilight via serial)
- Sync color of multiple WLED devices (UDP notifier)
- Infrared remotes (24-key RGB, receiver required)
- Simple timers/schedules (time from NTP, timezones/DST supported)
- WLED app for Android and iOS
- JSON and HTTP request APIs
- MQTT
- Blynk IoT
- E1.31
- Hyperion
- UDP realtime
- Alexa voice control (including dimming and color)
- Sync to Philips hue lights
- Adalight (PC ambilight via serial)
- Sync color of multiple WLED devices (UDP notifier)
- Infrared remotes (24-key RGB, receiver required)
- Simple timers/schedules (time from NTP, timezones/DST supported)
### Quick start guide and documentation:

25
wled00.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2046
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wled00", "wled00\wled00.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9A679C2B-61D3-400B-B96F-06E604E9CED2}
EndGlobalSection
EndGlobal

BIN
wled00/.vs/wled00/v15/.suo Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -40,14 +40,21 @@
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
/* Not used in all effects yet */
#define WLED_FPS 42
#define FRAMETIME 1000/WLED_FPS
/* each segment uses 37 bytes of SRAM memory, so if you're application fails because of
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#define MAX_NUM_SEGMENTS 1
#define NUM_COLORS 3 /* number of colors per segment */
#define MAX_NUM_SEGMENTS 10
#define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT _segments[_segment_index]
#define SEGMENT_RUNTIME _segment_runtimes[_segment_index]
#define SEGMENT_LENGTH (SEGMENT.stop - SEGMENT.start)
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGMENT_LENGTH
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x])
#define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN SEGMENT.length()
#define SEGACT SEGMENT.stop
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGLEN
#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes))
// some common colors
@@ -77,7 +84,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED) == SELECTED )
#define MODE_COUNT 80
#define MODE_COUNT 83
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@@ -160,6 +167,9 @@
#define FX_MODE_METEOR_SMOOTH 77
#define FX_MODE_RAILWAY 78
#define FX_MODE_RIPPLE 79
#define FX_MODE_TWINKLEFOX 80
#define FX_MODE_TWINKLECAT 81
#define FX_MODE_HALLOWEEN_EYES 82
class WS2812FX {
@@ -176,11 +186,6 @@ class WS2812FX {
uint8_t mode;
uint8_t options; //bit pattern: msb first: transitional tbd tbd tbd tbd paused reverse selected
uint32_t colors[NUM_COLORS];
//member functions
uint32_t color(uint8_t n)
{
return colors[n];
}
void setOption(uint8_t n, bool val)
{
if (val) {
@@ -194,19 +199,32 @@ class WS2812FX {
{
return ((options >> n) & 0x01);
}
bool isSelected()
{
return getOption(0);
}
bool isActive()
{
return stop > start;
}
uint16_t length()
{
return stop - start;
}
} segment;
// segment runtime parameters
typedef struct Segment_runtime { // 16 bytes
unsigned long next_time;
uint32_t counter_mode_step;
uint32_t counter_mode_call;
uint16_t aux_param;
uint16_t aux_param2;
void reset(){next_time = 0; counter_mode_step = 0; counter_mode_call = 0; aux_param = 0; aux_param2 = 0;};
uint32_t step;
uint32_t call;
uint16_t aux0;
uint16_t aux1;
void reset(){next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;};
} segment_runtime;
WS2812FX() {
//assign each member of the _mode[] array to its respective function reference
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
_mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe;
@@ -287,43 +305,35 @@ class WS2812FX {
_mode[FX_MODE_METEOR_SMOOTH] = &WS2812FX::mode_meteor_smooth;
_mode[FX_MODE_RAILWAY] = &WS2812FX::mode_railway;
_mode[FX_MODE_RIPPLE] = &WS2812FX::mode_ripple;
_mode[FX_MODE_TWINKLEFOX] = &WS2812FX::mode_twinklefox;
_mode[FX_MODE_TWINKLECAT] = &WS2812FX::mode_twinklecat;
_mode[FX_MODE_HALLOWEEN_EYES] = &WS2812FX::mode_halloween_eyes;
_brightness = DEFAULT_BRIGHTNESS;
_num_segments = 1;
_segments[0].mode = DEFAULT_MODE;
_segments[0].colors[0] = DEFAULT_COLOR;
_segments[0].start = 0;
_segments[0].speed = DEFAULT_SPEED;
currentPalette = CRGBPalette16(CRGB::Black);
targetPalette = CloudColors_p;
_reverseMode = false;
_skipFirstMode = false;
colorOrder = 0;
paletteFade = 0;
paletteBlend = 0;
ablMilliampsMax = 850;
currentMilliamps = 0;
timebase = 0;
_locked = nullptr;
_modeUsesLock = false;
bus = new NeoPixelWrapper();
RESET_RUNTIME;
resetSegments();
}
void
init(bool supportWhite, uint16_t countPixels, bool skipFirst),
init(bool supportWhite, uint16_t countPixels, bool skipFirs),
service(void),
blur(uint8_t),
fade_out(uint8_t r),
setMode(uint8_t m),
setMode(uint8_t segid, uint8_t m),
setSpeed(uint8_t s),
setIntensity(uint8_t i),
setPalette(uint8_t p),
setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setSecondaryColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setColor(uint32_t c),
setSecondaryColor(uint32_t c),
setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setColor(uint8_t slot, uint32_t c),
setBrightness(uint8_t b),
setReverseMode(bool b),
driverModeCronixie(bool b),
setCronixieDigits(byte* d),
setCronixieBacklight(bool b),
@@ -343,25 +353,37 @@ class WS2812FX {
show(void);
bool
reverseMode = false,
gammaCorrectBri = false,
gammaCorrectCol = true,
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p);
uint8_t
paletteFade,
paletteBlend,
colorOrder,
returnedSegment = 0,
paletteFade = 0,
paletteBlend = 0,
colorOrder = 0,
getBrightness(void),
getMode(void),
getSpeed(void),
getNumSegments(void),
getModeCount(void),
getPaletteCount(void),
getMaxSegments(void),
getFirstSelectedSegment(void),
getReturnedSegmentId(void),
gamma8(uint8_t),
get_random_wheel_index(uint8_t);
uint16_t
ablMilliampsMax,
currentMilliamps;
uint32_t
timebase,
color_wheel(uint8_t),
color_from_palette(uint16_t, bool, bool, uint8_t, uint8_t pbri = 255),
color_blend(uint32_t,uint32_t,uint8_t),
gamma32(uint32_t),
getPixelColor(uint16_t),
getColor(void);
@@ -374,21 +396,6 @@ class WS2812FX {
WS2812FX::Segment*
getSegments(void);
// mode helper functions
uint16_t
ablMilliampsMax,
currentMilliamps,
blink(uint32_t, uint32_t, bool strobe, bool),
color_wipe(uint32_t, uint32_t, bool , bool),
scan(bool),
theater_chase(uint32_t, uint32_t, bool),
running_base(bool),
dissolve(uint32_t),
chase(uint32_t, uint32_t, uint32_t, bool),
gradient_base(bool),
running(uint32_t, uint32_t),
tricolor_chase(uint32_t, uint32_t);
// builtin modes
uint16_t
mode_static(void),
@@ -471,15 +478,20 @@ class WS2812FX {
mode_meteor(void),
mode_meteor_smooth(void),
mode_railway(void),
mode_ripple(void);
mode_ripple(void),
mode_twinklefox(void),
mode_twinklecat(void),
mode_halloween_eyes(void);
private:
NeoPixelWrapper *bus;
CRGB fastled_from_col(uint32_t);
uint32_t crgb_to_col(CRGB fastled);
CRGB col_to_crgb(uint32_t);
CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette;
uint32_t now;
uint16_t _length;
uint16_t _rand16seed;
uint8_t _brightness;
@@ -487,11 +499,11 @@ class WS2812FX {
void handle_palette(void);
void fill(uint32_t);
bool modeUsesLock(uint8_t);
void twinklefox_base(bool);
bool
_modeUsesLock,
_rgbwMode,
_reverseMode,
_cronixieMode,
_cronixieBacklightEnabled,
_skipFirstMode,
@@ -502,13 +514,26 @@ class WS2812FX {
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
// mode helper functions
uint16_t
blink(uint32_t, uint32_t, bool strobe, bool),
color_wipe(bool, bool),
scan(bool),
theater_chase(uint32_t, uint32_t, bool),
running_base(bool),
dissolve(uint32_t),
chase(uint32_t, uint32_t, uint32_t, bool),
gradient_base(bool),
running(uint32_t, uint32_t),
tricolor_chase(uint32_t, uint32_t);
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
uint32_t _lastPaletteChange = 0;
uint32_t _lastShow = 0;
uint8_t _segment_index = 0;
uint8_t _segment_index_palette_last = 99;
uint8_t _num_segments = 1;
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 21 bytes per element
// start, stop, speed, intensity, palette, mode, options, color[]
{ 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, {DEFAULT_COLOR}}
@@ -525,8 +550,9 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","In Out","In In",
"Out Out","Out In","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
"Dual Scanner","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","BPM","Fill Noise","Noise 1",
"Noise 2","Noise 3","Noise 4","Colortwinkle","Lake","Meteor","Smooth Meteor","Railway","Ripple"
"Dual Scanner","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","BPM","Fill Noise",
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Smooth Meteor","Railway","Ripple",
"Twinklefox","Twinklecat","Halloween Eyes"
])=====";
@@ -535,7 +561,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([
"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",
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night"
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura"
])=====";
#endif

View File

@@ -24,7 +24,7 @@
Modified heavily for WLED
*/
#include "WS2812FX.h"
#include "FX.h"
#include "palettes.h"
#define LED_SKIP_AMOUNT 1
@@ -55,19 +55,22 @@ void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
}
void WS2812FX::service() {
unsigned long now = millis(); // Be aware, millis() rolls over every 49 days
now = millis() + timebase; // Be aware, millis() rolls over every 49 days
if (now - _lastShow < MIN_SHOW_DELAY) return;
bool doShow = false;
for(uint8_t i=0; i < _num_segments; i++)
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
{
_segment_index = i;
if(now > SEGMENT_RUNTIME.next_time || _triggered)
if (SEGMENT.isActive())
{
doShow = true;
handle_palette();
uint16_t delay = (this->*_mode[SEGMENT.mode])();
SEGMENT_RUNTIME.next_time = now + max(delay, MIN_SHOW_DELAY);
SEGMENT_RUNTIME.counter_mode_call++;
if(now > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
{
doShow = true;
handle_palette();
uint16_t delay = (this->*_mode[SEGMENT.mode])();
SEGENV.next_time = now + delay;
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
}
}
}
if(doShow) {
@@ -82,7 +85,7 @@ bool WS2812FX::modeUsesLock(uint8_t m)
{
if (m == FX_MODE_FIRE_2012 || m == FX_MODE_COLORTWINKLE ||
m == FX_MODE_METEOR || m == FX_MODE_METEOR_SMOOTH ||
m == FX_MODE_RIPPLE) return true;
m == FX_MODE_RIPPLE || m == FX_MODE_DYNAMIC ) return true;
return false;
}
@@ -97,7 +100,6 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
{
if (_locked[i] && !_modeUsesLock) return;
if (_reverseMode) i = _length -1 -i;
if (IS_REVERSE) i = SEGMENT.stop -1 -i - SEGMENT.start; //reverse just individual segment
byte tmpg = g;
switch (colorOrder) //0 = Grb, default
@@ -109,6 +111,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
}
if (!_cronixieMode)
{
if (reverseMode) i = _length -1 -i;
if (_skipFirstMode)
{
if (i < LED_SKIP_AMOUNT) bus->SetPixelColor(i, RgbwColor(0,0,0,0));
@@ -153,11 +156,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
}
}
void WS2812FX::setReverseMode(bool b)
{
_reverseMode = b;
}
void WS2812FX::driverModeCronixie(bool b)
{
_cronixieMode = b;
@@ -254,14 +252,24 @@ void WS2812FX::trigger() {
_triggered = true;
}
void WS2812FX::setMode(uint8_t m) {
RESET_RUNTIME;
bool ua = modeUsesLock(_segments[0].mode) && !modeUsesLock(m);
if (m > MODE_COUNT - 1) m = MODE_COUNT - 1;
_segments[0].mode = m;
if (ua) unlockAll();
_modeUsesLock = modeUsesLock(_segments[0].mode);
setBrightness(_brightness);
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
if (segid >= MAX_NUM_SEGMENTS) return;
bool anyUsedLock = _modeUsesLock, anyUseLock = false;
if (m >= MODE_COUNT) m = MODE_COUNT - 1;
if (_segments[segid].mode != m)
{
_segment_runtimes[segid].reset();
_segments[segid].mode = m;
}
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (modeUsesLock(_segments[i].mode)) anyUseLock = true;
}
if (anyUsedLock && !anyUseLock) unlockAll();
_modeUsesLock = anyUseLock;
}
uint8_t WS2812FX::getModeCount()
@@ -276,77 +284,117 @@ uint8_t WS2812FX::getPaletteCount()
//TODO transitions
void WS2812FX::setMode(uint8_t m) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected()) setMode(i, m);
}
}
void WS2812FX::setSpeed(uint8_t s) {
_segments[0].speed = s;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected()) _segments[i].speed = s;
}
}
void WS2812FX::setIntensity(uint8_t in) {
_segments[0].intensity = in;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected()) _segments[i].intensity = in;
}
}
void WS2812FX::setPalette(uint8_t p) {
_segments[0].palette = p;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected()) _segments[i].palette = p;
}
}
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p) {
bool changed = false;
m = constrain(m, 0, MODE_COUNT - 1);
if (m != _segments[0].mode) { setMode(m); changed = true; }
if (s != _segments[0].speed) { setSpeed(s); changed = true; }
if (i != _segments[0].intensity) { setIntensity(i); changed = true; }
if (p != _segments[0].palette) { setPalette(p); changed = true; }
return changed;
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
uint8_t retSeg = getReturnedSegmentId();
Segment& seg = _segments[retSeg];
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected())
{
_segments[i].speed = s;
_segments[i].intensity = in;
_segments[i].palette = p;
setMode(i, m);
}
}
if (seg.mode != modePrev || seg.speed != speedPrev || seg.intensity != intensityPrev || seg.palette != palettePrev) return true;
return false;
}
void WS2812FX::setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
setColor(((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
void WS2812FX::setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
setColor(slot, ((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
}
void WS2812FX::setSecondaryColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
setSecondaryColor(((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
}
void WS2812FX::setColor(uint32_t c) {
_segments[0].colors[0] = c;
}
void WS2812FX::setSecondaryColor(uint32_t c) {
_segments[0].colors[1] = c;
void WS2812FX::setColor(uint8_t slot, uint32_t c) {
if (slot >= NUM_COLORS) return;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected()) _segments[i].colors[slot] = c;
}
}
void WS2812FX::setBrightness(uint8_t b) {
if (_brightness == b) return;
_brightness = b;
if (SEGMENT_RUNTIME.next_time > millis() + 20) show(); //apply brightness change immeadiately if no refresh soon
_brightness = (gammaCorrectBri) ? gamma8(b) : b;
_segment_index = 0;
if (SEGENV.next_time > millis() + 22) show();//apply brightness change immediately if no refresh soon
}
uint8_t WS2812FX::getMode(void) {
return _segments[0].mode;
return _segments[getReturnedSegmentId()].mode;
}
uint8_t WS2812FX::getSpeed(void) {
return _segments[0].speed;
return _segments[getReturnedSegmentId()].speed;
}
uint8_t WS2812FX::getBrightness(void) {
return _brightness;
}
uint8_t WS2812FX::getNumSegments(void) {
return _num_segments;
}
uint8_t WS2812FX::getMaxSegments(void) {
return MAX_NUM_SEGMENTS;
}
uint8_t WS2812FX::getFirstSelectedSegment(void)
{
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isActive() && _segments[i].isSelected()) return i;
}
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //if none selected, get first active
{
if (_segments[i].isActive()) return i;
}
return 0;
}
uint8_t WS2812FX::getReturnedSegmentId(void) {
if (returnedSegment >= MAX_NUM_SEGMENTS || !_segments[returnedSegment].isActive())
{
return getFirstSelectedSegment();
}
return returnedSegment;
}
uint32_t WS2812FX::getColor(void) {
return _segments[0].colors[0];
return _segments[getReturnedSegmentId()].colors[0];
}
uint32_t WS2812FX::getPixelColor(uint16_t i)
{
if (_reverseMode) i = _length- 1 -i;
if (reverseMode) i = _length- 1 -i;
if (IS_REVERSE) i = SEGMENT.stop -1 -i - SEGMENT.start; //reverse just individual segment
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
if (_cronixieMode)
@@ -386,7 +434,7 @@ WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
}
WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) {
return SEGMENT_RUNTIME;
return SEGENV;
}
WS2812FX::Segment* WS2812FX::getSegments(void) {
@@ -397,6 +445,16 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2) {
if (n >= MAX_NUM_SEGMENTS) return;
Segment& seg = _segments[n];
if (seg.start == i1 && seg.stop == i2) return;
if (seg.isActive() && modeUsesLock(seg.mode))
{
_modeUsesLock = false;
unlockRange(seg.start, seg.stop);
_modeUsesLock = true;
}
if (i2 <= i1) //disable segment
{
seg.stop = 0; return;
}
if (i1 < _length) seg.start = i1;
seg.stop = i2;
if (i2 > _length) seg.stop = _length;
@@ -407,12 +465,12 @@ void WS2812FX::resetSegments() {
memset(_segments, 0, sizeof(_segments));
memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
_segment_index = 0;
_num_segments = 1;
_segments[0].mode = DEFAULT_MODE;
_segments[0].colors[0] = DEFAULT_COLOR;
_segments[0].start = 0;
_segments[0].speed = DEFAULT_SPEED;
_segments[0].stop = _length;
_segments[0].setOption(0, 1); //select
}
void WS2812FX::setIndividual(uint16_t i, uint32_t col)
@@ -439,31 +497,31 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
void WS2812FX::lock(uint16_t i)
{
if (modeUsesLock(SEGMENT.mode)) return;
if (i >= 0 && i < _length) _locked[i] = true;
if (_modeUsesLock) return;
if (i < _length) _locked[i] = true;
}
void WS2812FX::lockRange(uint16_t i, uint16_t i2)
{
if (modeUsesLock(SEGMENT.mode)) return;
for (uint16_t x = i; x <= i2; x++)
if (_modeUsesLock) return;
for (uint16_t x = i; x < i2; x++)
{
if (i >= 0 && i < _length) _locked[i] = true;
if (x < _length) _locked[i] = true;
}
}
void WS2812FX::unlock(uint16_t i)
{
if (modeUsesLock(SEGMENT.mode)) return;
if (i >= 0 && i < _length) _locked[i] = false;
if (_modeUsesLock) return;
if (i < _length) _locked[i] = false;
}
void WS2812FX::unlockRange(uint16_t i, uint16_t i2)
{
if (modeUsesLock(SEGMENT.mode)) return;
if (_modeUsesLock) return;
for (uint16_t x = i; x < i2; x++)
{
if (x >= 0 && x < _length) _locked[x] = false;
if (x < _length) _locked[x] = false;
}
}
@@ -474,10 +532,11 @@ void WS2812FX::unlockAll()
void WS2812FX::setTransitionMode(bool t)
{
_segment_index = 0;
SEGMENT.setOption(7,t);
if (!t) return;
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
if (SEGMENT.mode == FX_MODE_STATIC && SEGMENT_RUNTIME.next_time > waitMax) SEGMENT_RUNTIME.next_time = waitMax;
if (SEGMENT.mode == FX_MODE_STATIC && SEGENV.next_time > waitMax) SEGENV.next_time = waitMax;
}
/*
@@ -487,15 +546,15 @@ uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend)
if(blend == 0) return color1;
if(blend == 255) return color2;
int w1 = (color1 >> 24) & 0xff;
int r1 = (color1 >> 16) & 0xff;
int g1 = (color1 >> 8) & 0xff;
int b1 = color1 & 0xff;
uint32_t w1 = (color1 >> 24) & 0xff;
uint32_t r1 = (color1 >> 16) & 0xff;
uint32_t g1 = (color1 >> 8) & 0xff;
uint32_t b1 = color1 & 0xff;
int w2 = (color2 >> 24) & 0xff;
int r2 = (color2 >> 16) & 0xff;
int g2 = (color2 >> 8) & 0xff;
int b2 = color2 & 0xff;
uint32_t w2 = (color2 >> 24) & 0xff;
uint32_t r2 = (color2 >> 16) & 0xff;
uint32_t g2 = (color2 >> 8) & 0xff;
uint32_t b2 = color2 & 0xff;
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8;
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8;
@@ -521,7 +580,7 @@ void WS2812FX::fade_out(uint8_t rate) {
rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1;
uint32_t color = SEGMENT.colors[1]; // target color
uint32_t color = SEGCOLOR(1); // target color
int w2 = (color >> 24) & 0xff;
int r2 = (color >> 16) & 0xff;
int g2 = (color >> 8) & 0xff;
@@ -559,7 +618,7 @@ void WS2812FX::blur(uint8_t blur_amount)
CRGB carryover = CRGB::Black;
for(uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++)
{
CRGB cur = fastled_from_col(getPixelColor(i));
CRGB cur = col_to_crgb(getPixelColor(i));
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
@@ -611,7 +670,13 @@ uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) {
}
CRGB WS2812FX::fastled_from_col(uint32_t color)
uint32_t WS2812FX::crgb_to_col(CRGB fastled)
{
return (((uint32_t)fastled.red << 16) | ((uint32_t)fastled.green << 8) | fastled.blue);
}
CRGB WS2812FX::col_to_crgb(uint32_t color)
{
CRGB fastled_col;
fastled_col.red = (color >> 16 & 0xFF);
@@ -663,11 +728,11 @@ void WS2812FX::handle_palette(void)
_lastPaletteChange = millis();
} break;}
case 2: {//primary color only
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
CRGB prim = col_to_crgb(SEGCOLOR(0));
targetPalette = CRGBPalette16(prim); break;}
case 3: {//based on primary
//considering performance implications
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
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
@@ -676,12 +741,12 @@ void WS2812FX::handle_palette(void)
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v)); //color itself
break;}
case 4: {//primary + secondary
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
CRGB sec = fastled_from_col(SEGMENT.colors[1]);
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
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
CRGB sec = fastled_from_col(SEGMENT.colors[1]);
CRGB prim = col_to_crgb(SEGCOLOR(0));
CRGB sec = col_to_crgb(SEGCOLOR(1));
targetPalette = CRGBPalette16(sec,prim,CRGB::White); break;}
case 6: //Party colors
targetPalette = PartyColors_p; break;
@@ -712,7 +777,7 @@ void WS2812FX::handle_palette(void)
uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
{
if (SEGMENT.palette == 0 && mcol < 3) return SEGMENT.colors[mcol]; //WS2812FX default
if (SEGMENT.palette == 0 && mcol < 3) return SEGCOLOR(mcol); //WS2812FX default
uint8_t paletteIndex = i;
if (mapping) paletteIndex = map(i,SEGMENT.start,SEGMENT.stop-1,0,255);
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
@@ -720,3 +785,41 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b;
}
//gamma 2.4 lookup table used for color correction
const byte gammaT[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
uint8_t WS2812FX::gamma8(uint8_t b)
{
return gammaT[b];
}
uint32_t WS2812FX::gamma32(uint32_t color)
{
if (!gammaCorrectCol) return color;
uint8_t w = (color >> 24) & 0xFF;
uint8_t r = (color >> 16) & 0xFF;
uint8_t g = (color >> 8) & 0xFF;
uint8_t b = color & 0xFF;
w = gammaT[w];
r = gammaT[r];
g = gammaT[g];
b = gammaT[b];
return ((w << 24) | (r << 16) | (g << 8) | (b));
}

View File

@@ -4,20 +4,35 @@
//PIN CONFIGURATION
#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 or 3 is recommended for ESP8266 (gpio2/3 are labeled D4/RX on NodeMCU and Wemos)
//#define USE_APA102 // Uncomment for using APA102 LEDs.
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
#define IR_PIN 4 //infrared pin (-1 to disable)
#define IR_PIN 4 //infrared pin (-1 to disable)
#define RLYPIN 12 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
#ifdef USE_APA102
#define CLKPIN 0
#define DATAPIN 2
#if BTNPIN == CLKPIN || BTNPIN == DATAPIN
#undef BTNPIN // Deactivate button pin if it conflicts with one of the APA102 pins.
#endif
#endif
//automatically uses the right driver method for each platform
#ifdef ARDUINO_ARCH_ESP32
#define PIXELMETHOD NeoWs2813Method
#ifdef USE_APA102
#define PIXELMETHOD DotStarMethod
#else
#define PIXELMETHOD NeoEsp32Rmt0Ws2812xMethod
#endif
#else //esp8266
//autoselect the right method depending on strip pin
#if LEDPIN == 2
#ifdef USE_APA102
#define PIXELMETHOD DotStarMethod
#elif LEDPIN == 2
#define PIXELMETHOD NeoEsp8266Uart1Ws2813Method //if you get an error here, try to change to NeoEsp8266UartWs2813Method or update Neopixelbus
#elif LEDPIN == 3
#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod
@@ -29,8 +44,13 @@
//you can now change the color order in the web settings
#define PIXELFEATURE3 NeoGrbFeature
#define PIXELFEATURE4 NeoGrbwFeature
#ifdef USE_APA102
#define PIXELFEATURE3 DotStarBgrFeature
#define PIXELFEATURE4 DotStarLbgrFeature
#else
#define PIXELFEATURE3 NeoGrbFeature
#define PIXELFEATURE4 NeoGrbwFeature
#endif
#include <NeoPixelBrightnessBus.h>
@@ -68,12 +88,20 @@ public:
switch (_type)
{
case NeoPixelType_Grb:
#ifdef USE_APA102
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
#else
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, LEDPIN);
#endif
_pGrb->Begin();
break;
case NeoPixelType_Grbw:
#ifdef USE_APA102
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
#else
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, LEDPIN);
#endif
_pGrbw->Begin();
break;
}

View File

@@ -0,0 +1,129 @@
/*
Editor: https://www.visualmicro.com/
This file is for intellisense purpose only.
Visual micro (and the arduino ide) ignore this code during compilation. This code is automatically maintained by visualmicro, manual changes to this file will be overwritten
The contents of the _vm sub folder can be deleted prior to publishing a project
All non-arduino files created by visual micro and all visual studio project or solution files can be freely deleted and are not required to compile a sketch (do not delete your own code!).
Note: debugger breakpoints are stored in '.sln' or '.asln' files, knowledge of last uploaded breakpoints is stored in the upload.vmps.xml file. Both files are required to continue a previous debug session without needing to compile and upload again
Hardware: ESP32 Dev Module, Platform=esp32, Package=esp32
*/
#if defined(_VMICRO_INTELLISENSE)
#ifndef _VSARDUINO_H_
#define _VSARDUINO_H_
#define __ESP32_esp32__
#define __ESP32_ESP32__
#define ESP_PLATFORM
#define HAVE_CONFIG_H
#define F_CPU 240000000L
#define ARDUINO 10807
#define ARDUINO_ESP32_DEV
#define ARDUINO_ARCH_ESP32
#define ESP32
#define CORE_DEBUG_LEVEL 0
#define __cplusplus 201103L
#define _Pragma(x)
#undef __cplusplus
#define __cplusplus 201103L
#define __STDC__
#define __ARM__
#define __arm__
#define __inline__
#define __asm__(...)
#define __extension__
#define __ATTR_PURE__
#define __ATTR_CONST__
#define __volatile__
#define __ASM
#define __INLINE
#define __attribute__(noinline)
//#define _STD_BEGIN
//#define EMIT
#define WARNING
#define _Lockit
#define __CLR_OR_THIS_CALL
#define C4005
#define _NEW
typedef bool _Bool;
typedef int _read;
typedef int _seek;
typedef int _write;
typedef int _close;
typedef int __cleanup;
//#define inline
#define __builtin_clz
#define __builtin_clzl
#define __builtin_clzll
#define __builtin_labs
#define __builtin_va_list
typedef int __gnuc_va_list;
#define __ATOMIC_ACQ_REL
#define __CHAR_BIT__
#define _EXFUN()
typedef unsigned char byte;
extern "C" void __cxa_pure_virtual() {;}
typedef long __INTPTR_TYPE__ ;
typedef long __UINTPTR_TYPE__ ;
typedef long __SIZE_TYPE__ ;
typedef long __PTRDIFF_TYPE__;
typedef long pthread_t;
typedef long pthread_key_t;
typedef long pthread_once_t;
typedef long pthread_mutex_t;
typedef long pthread_mutex_t;
typedef long pthread_cond_t;
#include "arduino.h"
#include <pins_arduino.h>
//#include "..\generic\Common.h"
//#include "..\generic\pins_arduino.h"
//#undef F
//#define F(string_literal) ((const PROGMEM char *)(string_literal))
//#undef PSTR
//#define PSTR(string_literal) ((const PROGMEM char *)(string_literal))
//current vc++ does not understand this syntax so use older arduino example for intellisense
//todo:move to the new clang/gcc project types.
#define interrupts() sei()
#define noInterrupts() cli()
#include "wled00.ino"
#include "wled01_eeprom.ino"
#include "wled02_xml.ino"
#include "wled03_set.ino"
#include "wled04_file.ino"
#include "wled05_init.ino"
#include "wled06_usermod.ino"
#include "wled07_notify.ino"
#include "wled08_led.ino"
#include "wled09_button.ino"
#include "wled10_ntp.ino"
#include "wled11_ol.ino"
#include "wled12_alexa.ino"
#include "wled13_cronixie.ino"
#include "wled14_colors.ino"
#include "wled15_hue.ino"
#include "wled16_blynk.ino"
#include "wled17_mqtt.ino"
#include "wled18_server.ino"
#include "wled19_json.ino"
#include "wled20_ir.ino"
#endif
#endif

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
<html>
<head><meta charset="utf-8"><meta name="theme-color" content="#fff">
<link rel='shortcut icon' type='image/x-icon' href='/favicon.ico'/>
<title>WLED 0.8.4</title>
<title>WLED 0.8.6</title>
<script>
var d=document;
var w=window.getComputedStyle(d.querySelector("html"));

View File

@@ -7,7 +7,7 @@
<meta name="theme-color" content="#333333">
<meta content="yes" name="apple-mobile-web-app-capable">
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAGACGAAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAE1JREFUOI1j/P//PwOxgNGeAUMxE9G6cQCKDWAhpADZ2f8PMjBS3QW08QK20KaZC2gfC9hCnqouoNgARgY7zMxAyNlUdQHlXiAlO2MDAD63EVqNHAe0AAAAAElFTkSuQmCC"/>
<title>WLED 0.8.4</title>
<title>WLED 0.8.6</title>
<script>function feedback(){}</script>
<style>
*{transition-duration: 0.5s;}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<html><head><meta content='width=device-width' name='viewport'><title>WLED Message</title><script>function B(){window.history.back()}</script>
<style>:root{--aCol:#D9B310;--bCol:#0B3C5D;--cCol:#1D2731;--dCol:#328CC1;--sCol:#000;--tCol:#328CC1;--cFn:Verdana;}.bt{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%}</style></head>
<body><h2>WLED Software Update</h2>Installed version: 0.8.4-dev<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.8.5-dev<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>

View File

@@ -1,27 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content='width=device-width' name='viewport'>
<meta name="theme-color" content="#333333">
<title>WLED Setup</title>
<style>
:root {
--aCol: #D9B310;
--bCol: #0B3C5D;
--cCol: #1D2731;
--dCol: #328CC1;
--sCol: #000;
}
body {
font-family: Verdana, Helvetica, sans-serif;
text-align: center;
background: linear-gradient(var(--bCol),black);
background-color: #333;
margin: 0;
background-attachment: fixed;
color: var(--dCol);
color: #fff;
}
button {
outline: none;
cursor: pointer;
padding: 8px;
margin: 10px;
width: 230px;
text-transform: uppercase;
font-family: helvetica;
font-size: 19px;
background-color: #222;
color: white;
border: 0px solid white;
border-radius: 5px;
}
svg {
fill: var(--dCol);
fill: #fff;
}
</style>
</head>
@@ -34,10 +43,12 @@
<svg><use xlink:href="#lnr-smile"></use></svg>
<h1>Welcome to WLED!</h1>
<h3>Thank you for installing my application!</h3>
Take a quick look at the <a href="https://github.com/Aircoookie/WLED/wiki" target="_blank">wiki</a>!<br>
If you encounter a bug or have a question/feature suggestion, feel free to open a GitHub issue!<br><br>
<b>Next steps:</b><br><br>
Connect the module to your local WiFi <a href="/settings/wifi">here</a>!<br><br>
<i>Just trying this out in AP mode?</i> <a href="/sliders">Here are the controls.</a><br>
Connect the module to your local WiFi here!<br>
<button onclick="window.location.href='/settings/wifi'">WiFi settings</button><br>
<i>Just trying this out in AP mode?</i><br>
<button onclick="window.location.href='/sliders'">To the controls!</button>
</body>
</html>

View File

@@ -20,30 +20,14 @@ const char PAGE_msg[] 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>
%CSS%.bt{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%%}</style></head>
<body><h2>WLED Software Update</h2>Installed version: 0.8.4<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.8.6<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
#ifndef WLED_DISABLE_MOBILE_UI
const char PAGE_welcome[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta content='width=device-width' name='viewport'><title>WLED Welcome!</title>
%CSS%body{font-family:var(--cFn),sans-serif;text-align:center;background:linear-gradient(var(--bCol),black);margin:0;background-attachment: fixed;color: var(--tCol);}svg {fill: var(--dCol);}
</style></head>
<body>
<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="lnr-smile" viewBox="0 0 1024 1024"><path d="M486.4 1024c-129.922 0-252.067-50.594-343.936-142.464s-142.464-214.014-142.464-343.936c0-129.923 50.595-252.067 142.464-343.936s214.013-142.464 343.936-142.464c129.922 0 252.067 50.595 343.936 142.464s142.464 214.014 142.464 343.936-50.594 252.067-142.464 343.936c-91.869 91.87-214.014 142.464-343.936 142.464zM486.4 102.4c-239.97 0-435.2 195.23-435.2 435.2s195.23 435.2 435.2 435.2 435.2-195.23 435.2-435.2-195.23-435.2-435.2-435.2z"></path><path d="M332.8 409.6c-42.347 0-76.8-34.453-76.8-76.8s34.453-76.8 76.8-76.8 76.8 34.453 76.8 76.8-34.453 76.8-76.8 76.8zM332.8 307.2c-14.115 0-25.6 11.485-25.6 25.6s11.485 25.6 25.6 25.6 25.6-11.485 25.6-25.6-11.485-25.6-25.6-25.6z"></path><path d="M640 409.6c-42.349 0-76.8-34.453-76.8-76.8s34.451-76.8 76.8-76.8 76.8 34.453 76.8 76.8-34.451 76.8-76.8 76.8zM640 307.2c-14.115 0-25.6 11.485-25.6 25.6s11.485 25.6 25.6 25.6 25.6-11.485 25.6-25.6-11.485-25.6-25.6-25.6z"></path><path d="M486.4 870.4c-183.506 0-332.8-149.294-332.8-332.8 0-14.139 11.462-25.6 25.6-25.6s25.6 11.461 25.6 25.6c0 155.275 126.325 281.6 281.6 281.6s281.6-126.325 281.6-281.6c0-14.139 11.461-25.6 25.6-25.6s25.6 11.461 25.6 25.6c0 183.506-149.294 332.8-332.8 332.8z"></path></symbol>
</defs></svg>
<br><br>
<svg><use xlink:href="#lnr-smile"></use></svg>
<h1>Welcome to WLED!</h1>
<h3>Thank you for installing my application!</h3>
Take a quick look at the <a href="https://github.com/Aircoookie/WLED/wiki" target="_blank">wiki</a>!<br>
If you encounter a bug or have a question/feature suggestion, feel free to open a GitHub issue!<br><br>
<b>Next steps:</b><br><br>
Connect the module to your local WiFi <a href="/settings/wifi">here</a>!<br><br>
<i>Just trying this out in AP mode?</i> <a href="/sliders">Here are the controls.</a><br>
</body></html>)=====";
const char PAGE_welcome[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta charset=utf-8><meta content='width=device-width' name=viewport><meta name=theme-color content=#333333><title>WLED Setup</title> <style>body{font-family:Verdana,Helvetica,sans-serif;text-align:center;background-color:#333;margin:0;color:#fff}button{outline:0;cursor:pointer}.btn{padding:8px;margin:10px;width:230px;text-transform:uppercase;font-family:helvetica;font-size:19px;background-color:#222;color:white;border:0 solid white;border-radius:5px}svg{fill:#fff}</style></head>
<body> <svg style=position:absolute;width:0;height:0;overflow:hidden version=1.1 xmlns=http://www.w3.org/2000/svg> <defs> <symbol id=lnr-smile viewBox="0 0 1024 1024"><path d="M486.4 1024c-129.922 0-252.067-50.594-343.936-142.464s-142.464-214.014-142.464-343.936c0-129.923 50.595-252.067 142.464-343.936s214.013-142.464 343.936-142.464c129.922 0 252.067 50.595 343.936 142.464s142.464 214.014 142.464 343.936-50.594 252.067-142.464 343.936c-91.869 91.87-214.014 142.464-343.936 142.464zM486.4 102.4c-239.97 0-435.2 195.23-435.2 435.2s195.23 435.2 435.2 435.2 435.2-195.23 435.2-435.2-195.23-435.2-435.2-435.2z"></path><path d="M332.8 409.6c-42.347 0-76.8-34.453-76.8-76.8s34.453-76.8 76.8-76.8 76.8 34.453 76.8 76.8-34.453 76.8-76.8 76.8zM332.8 307.2c-14.115 0-25.6 11.485-25.6 25.6s11.485 25.6 25.6 25.6 25.6-11.485 25.6-25.6-11.485-25.6-25.6-25.6z"></path><path d="M640 409.6c-42.349 0-76.8-34.453-76.8-76.8s34.451-76.8 76.8-76.8 76.8 34.453 76.8 76.8-34.451 76.8-76.8 76.8zM640 307.2c-14.115 0-25.6 11.485-25.6 25.6s11.485 25.6 25.6 25.6 25.6-11.485 25.6-25.6-11.485-25.6-25.6-25.6z"></path><path d="M486.4 870.4c-183.506 0-332.8-149.294-332.8-332.8 0-14.139 11.462-25.6 25.6-25.6s25.6 11.461 25.6 25.6c0 155.275 126.325 281.6 281.6 281.6s281.6-126.325 281.6-281.6c0-14.139 11.461-25.6 25.6-25.6s25.6 11.461 25.6 25.6c0 183.506-149.294 332.8-332.8 332.8z"></path></symbol> </defs></svg> <br><br>
<svg><use xlink:href=#lnr-smile></use></svg><h1>Welcome to WLED!</h1><h3>Thank you for installing my application!</h3> If you encounter a bug or have a question/feature suggestion, feel free to open a GitHub issue!<br><br> <b>Next steps:</b><br><br> Connect the module to your local WiFi here!<br> <button class=btn onclick="window.location.href='/settings/wifi'">WiFi settings</button><br> <i>Just trying this out in AP mode?</i><br> <button class=btn onclick="window.location.href='/sliders'">To the controls!</button></body></html>)=====";
#else
const char PAGE_welcome[] PROGMEM = "";
#endif

View File

@@ -1,7 +1,7 @@
/*
* Settings html
*/
//common CSS of settings pages
const char PAGE_settingsCss[] PROGMEM = R"=====(body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%%;margin:0;background-attachment:fixed}hr{border-color:var(--dCol);filter:drop-shadow(-5px -5px 5px var(--sCol))}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.5ch solid var(--bCol);filter:drop-shadow(-5px -5px 5px var(--sCol))}input[type=number]{width:4em}select{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:0.5ch solid var(--bCol);filter:drop-shadow( -5px -5px 5px var(--sCol) );}td{padding:2px;}</style>)=====";
@@ -28,7 +28,7 @@ const char PAGE_settings_wifi[] PROGMEM = R"=====(<!DOCTYPE html>
%CSS%%SCSS%</head><body onload="GetV()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
<h2>WiFi setup</h2>
<h3>Connect to existing network</h3>
Network name (SSID, empty to not connect): <br><input name="CS" maxlength="32"><br>
@@ -50,15 +50,20 @@ Static subnet mask:<br>
<input name="S3" type="number" min="0" max="255" required><br>
mDNS address (leave empty for no mDNS):<br/>
http:// <input name="CM" maxlength="32"> .local<br>
Try connecting before opening AP for: <input name="AT" type="number" min="0" max="255" required> s <br>
Client IP: <span class="sip"> Not connected </span><br>
<h3>Configure Access Point</h3>
AP SSID (leave empty for no AP):<br><input name="AS" maxlength="32"><br>
Hide AP name: <input type="checkbox" name="AH"><br>
AP password (leave empty for open):<br> <input type="password" name="AP" maxlength="63"><br>
Access Point WiFi channel: <input name="AC" type="number" min="1" max="13" required><br>
AP opens:
<select name="AB">
<option value="0">No connection after boot</option>
<option value="1">Disconnected</option>
<option value="2">Always</option>
<option value="3">Never (not recommended)</option></select><br>
AP IP: <span class="sip"> Not active </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
</form>
</body>
</html>)=====";
@@ -80,7 +85,7 @@ el.innerHTML=x;el.selectedIndex=pl?p:f;}).catch(function(){el.innerHTML=e;})}fun
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>LED setup</h2>
LED count: <input name="LC" type="number" min="1" max="1200" oninput=UI() required><br>
LED count: <input name="LC" type="number" min="1" max="1500" oninput=UI() required><br>
<i>Recommended power supply for brightest white:</i><br>
<b><span id="psu">?</span></b><br><br>
Maximum Current: <input name="MA" type="number" min="250" max="65000" required> mA<br>
@@ -252,7 +257,13 @@ For best results, only use one of these services at a time.<br>
Device Auth token: <input name="BK" maxlength="33"><br>
<i>Clear the token field to disable. </i><a href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info</a>
<h3>MQTT</h3>
Broker: <input name="MS" maxlength="32"><br>
Broker: <input name="MS" maxlength="32">
Port: <input name="MQPORT" type="number" min="1" max="65535" required><br>
<b>The MQTT credentials are sent over an unsecured connection.<br>
Never use the MQTT password for another service!</b><br>
Username: <input name="MQUSER" maxlength="40"><br>
Password: <input type="password" input name="MQPASS" maxlength="40"><br>
Client ID: <input name="MQCID" maxlength="40"><br>
Device Topic: <input name="MD" maxlength="32"><br>
Group Topic: <input name="MG" maxlength="32"><br>
<i>Reboot required to apply changes. </i><a href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info</a>
@@ -289,7 +300,7 @@ function Wd(){a=[0,0,0,0,0,0,0,0];for(i=0;i<8;i++){m=1;for(j=0;j<8;j++){a[i]+=gI
<h2>Time setup</h2>
Get time from NTP server: <input type="checkbox" name="NT"><br>
Use 24h format: <input type="checkbox" name="CF"><br>
Time zone:
Time zone:
<select name="TZ">
<option value="0" selected>GMT(UTC)</option>
<option value="1">GMT/BST</option>
@@ -384,9 +395,6 @@ The password should be changed when OTA is enabled.<br>
<b>Disable OTA when not in use, otherwise an attacker can reflash device software!</b><br>
<i>Settings on this page are only changable if OTA lock is disabled!</i><br>
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
Disable recovery AP: <input type="checkbox" name="NA"><br>
In case of an error there will be no wireless recovery possible!<br>
Completely disables all Access Point functions.<br><br>
Factory reset: <input type="checkbox" name="RS"><br>
All EEPROM content (settings) will be erased.<br><br>
HTTP traffic is unencrypted. An attacker in the same network can intercept form data!
@@ -394,7 +402,7 @@ 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.8.4<br><br>
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.8.6<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>

View File

@@ -529,12 +529,41 @@ DEFINE_GRADIENT_PALETTE( April_Night_gp ) {
127, 249,150, 5, //yellow
143, 1, 5, 45,
162, 1, 5, 45,
178, 255,92, 0, //pastel orange
178, 255, 92, 0, //pastel orange
193, 1, 5, 45,
214, 1, 5, 45,
229, 223, 45, 72, //pink
244, 1, 5, 45,
255, 1, 5, 45};
DEFINE_GRADIENT_PALETTE( Orangery_gp ) {
0, 255, 95, 23,
30, 255, 82, 0,
60, 223, 13, 8,
90, 144, 44, 2,
120, 255,110, 17,
150, 255, 69, 0,
180, 158, 13, 11,
210, 241, 82, 17,
255, 213, 37, 4};
//inspired by Mark Kriegsman https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
DEFINE_GRADIENT_PALETTE( C9_gp ) {
0, 184, 4, 0, //red
60, 184, 4, 0,
65, 144, 44, 2, //amber
125, 144, 44, 2,
130, 4, 96, 2, //green
190, 4, 96, 2,
195, 7, 7, 88, //blue
255, 7, 7, 88};
DEFINE_GRADIENT_PALETTE( Sakura_gp ) {
0, 196, 19, 10,
65, 255, 69, 45,
130, 223, 45, 72,
195, 255, 82,103,
255, 223, 13, 17};
// Single array of defined cpt-city color palettes.
@@ -581,7 +610,10 @@ const TProgmemRGBGradientPalettePtr gGradientPalettes[] = {
Blue_Cyan_Yellow_gp, //43-30 Yelblu
Orange_Teal_gp, //44-31 Orange & Teal
Tiamat_gp, //45-32 Tiamat
April_Night_gp //46-33 April Night
April_Night_gp, //46-33 April Night
Orangery_gp, //47-34 Orangery
C9_gp, //48-35 C9
Sakura_gp, //49-36 Sakura
};

View File

@@ -38,6 +38,7 @@ AsyncMqttClient::AsyncMqttClient()
#ifdef ESP32
sprintf(_generatedClientId, "esp32%06x", ESP.getEfuseMac());
_xSemaphore = xSemaphoreCreateMutex();
#elif defined(ESP8266)
sprintf(_generatedClientId, "esp8266%06x", ESP.getChipId());
#endif
@@ -49,6 +50,9 @@ AsyncMqttClient::AsyncMqttClient()
AsyncMqttClient::~AsyncMqttClient() {
delete _currentParsedPacket;
delete[] _parsingInformation.topicBuffer;
#ifdef ESP32
vSemaphoreDelete(_xSemaphore);
#endif
}
AsyncMqttClient& AsyncMqttClient::setKeepAlive(uint16_t keepAlive) {
@@ -298,9 +302,11 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) {
neededSpace += passwordLength;
}
SEMAPHORE_TAKE();
if (_client.space() < neededSpace) {
_connectPacketNotEnoughSpace = true;
_client.close(true);
SEMAPHORE_GIVE();
return;
}
@@ -329,26 +335,24 @@ void AsyncMqttClient::_onConnect(AsyncClient* client) {
}
_client.send();
_lastClientActivity = millis();
SEMAPHORE_GIVE();
}
void AsyncMqttClient::_onDisconnect(AsyncClient* client) {
(void)client;
AsyncMqttClientDisconnectReason reason;
if (!_disconnectFlagged) {
AsyncMqttClientDisconnectReason reason;
if (_connectPacketNotEnoughSpace) {
reason = AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE;
} else if (_tlsBadFingerprint) {
reason = AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT;
} else {
reason = AsyncMqttClientDisconnectReason::TCP_DISCONNECTED;
if (_connectPacketNotEnoughSpace) {
reason = AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE;
} else if (_tlsBadFingerprint) {
reason = AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT;
} else {
reason = AsyncMqttClientDisconnectReason::TCP_DISCONNECTED;
}
for (auto callback : _onDisconnectUserCallbacks) callback(reason);
}
_clear();
for (auto callback : _onDisconnectUserCallbacks) callback(reason);
_connectPacketNotEnoughSpace = false;
_tlsBadFingerprint = false;
}
void AsyncMqttClient::_onError(AsyncClient* client, int8_t error) {
@@ -481,8 +485,8 @@ void AsyncMqttClient::_onConnAck(bool sessionPresent, uint8_t connectReturnCode)
_connected = true;
for (auto callback : _onConnectUserCallbacks) callback(sessionPresent);
} else {
_clear();
for (auto callback : _onDisconnectUserCallbacks) callback(static_cast<AsyncMqttClientDisconnectReason>(connectReturnCode));
_disconnectFlagged = true;
}
}
@@ -606,19 +610,22 @@ bool AsyncMqttClient::_sendPing() {
size_t neededSpace = 2;
if (_client.space() < neededSpace) return false;
SEMAPHORE_TAKE(false);
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; }
_client.add(fixedHeader, 2);
_client.send();
_lastClientActivity = millis();
_lastPingRequestTime = millis();
SEMAPHORE_GIVE();
return true;
}
void AsyncMqttClient::_sendAcks() {
uint8_t neededAckSpace = 2 + 2;
SEMAPHORE_TAKE();
for (size_t i = 0; i < _toSendAcks.size(); i++) {
if (_client.space() < neededAckSpace) break;
@@ -643,12 +650,17 @@ void AsyncMqttClient::_sendAcks() {
_lastClientActivity = millis();
}
SEMAPHORE_GIVE();
}
bool AsyncMqttClient::_sendDisconnect() {
if (!_connected) return true;
const uint8_t neededSpace = 2;
if (_client.space() < neededSpace) return false;
SEMAPHORE_TAKE(false);
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; }
char fixedHeader[2];
fixedHeader[0] = AsyncMqttClientInternals::PacketType.DISCONNECT;
@@ -662,6 +674,7 @@ bool AsyncMqttClient::_sendDisconnect() {
_disconnectFlagged = false;
SEMAPHORE_GIVE();
return true;
}
@@ -704,7 +717,6 @@ void AsyncMqttClient::disconnect(bool force) {
} else {
_disconnectFlagged = true;
_sendDisconnect();
_client.send();
}
}
@@ -732,7 +744,9 @@ uint16_t AsyncMqttClient::subscribe(const char* topic, uint8_t qos) {
neededSpace += 2;
neededSpace += topicLength;
neededSpace += 1;
if (_client.space() < neededSpace) return 0;
SEMAPHORE_TAKE(0);
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; }
uint16_t packetId = _getNextPacketId();
char packetIdBytes[2];
@@ -747,6 +761,7 @@ uint16_t AsyncMqttClient::subscribe(const char* topic, uint8_t qos) {
_client.send();
_lastClientActivity = millis();
SEMAPHORE_GIVE();
return packetId;
}
@@ -770,7 +785,9 @@ uint16_t AsyncMqttClient::unsubscribe(const char* topic) {
neededSpace += 2;
neededSpace += 2;
neededSpace += topicLength;
if (_client.space() < neededSpace) return 0;
SEMAPHORE_TAKE(0);
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; }
uint16_t packetId = _getNextPacketId();
char packetIdBytes[2];
@@ -784,6 +801,7 @@ uint16_t AsyncMqttClient::unsubscribe(const char* topic) {
_client.send();
_lastClientActivity = millis();
SEMAPHORE_GIVE();
return packetId;
}
@@ -825,7 +843,9 @@ uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, c
neededSpace += topicLength;
if (qos != 0) neededSpace += 2;
if (payload != nullptr) neededSpace += payloadLength;
if (_client.space() < neededSpace) return 0;
SEMAPHORE_TAKE(0);
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; }
uint16_t packetId = 0;
char packetIdBytes[2];
@@ -848,6 +868,7 @@ uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, c
_client.send();
_lastClientActivity = millis();
SEMAPHORE_GIVE();
if (qos != 0) {
return packetId;
} else {

View File

@@ -7,6 +7,7 @@
#ifdef ESP32
#include <AsyncTCP.h>
#include <freertos/semphr.h>
#elif defined(ESP8266)
#include <ESPAsyncTCP.h>
#else
@@ -37,6 +38,14 @@
#include "AsyncMqttClient/Packets/PubRecPacket.hpp"
#include "AsyncMqttClient/Packets/PubCompPacket.hpp"
#if ESP32
#define SEMAPHORE_TAKE(X) if (xSemaphoreTake(_xSemaphore, 1000 / portTICK_PERIOD_MS) != pdTRUE) { return X; } // Waits max 1000ms
#define SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore);
#elif defined(ESP8266)
#define SEMAPHORE_TAKE(X) void()
#define SEMAPHORE_GIVE() void()
#endif
class AsyncMqttClient {
public:
AsyncMqttClient();
@@ -121,6 +130,10 @@ class AsyncMqttClient {
std::vector<AsyncMqttClientInternals::PendingAck> _toSendAcks;
#ifdef ESP32
SemaphoreHandle_t _xSemaphore = nullptr;
#endif
void _clear();
void _freeCurrentParsedPacket();

View File

@@ -10,7 +10,7 @@
*/
/*
* @title Espalexa library
* @version 2.4.0
* @version 2.4.3
* @author Christian Schwinne
* @license MIT
* @contributors d-999
@@ -49,7 +49,7 @@
#include <WiFiUdp.h>
#ifdef ESPALEXA_DEBUG
#pragma message "Espalexa 2.4.0 debug mode"
#pragma message "Espalexa 2.4.3 debug mode"
#define EA_DEBUG(x) Serial.print (x)
#define EA_DEBUGLN(x) Serial.println (x)
#else
@@ -118,14 +118,28 @@ private:
case EspalexaDeviceType::color: return "LST001";
case EspalexaDeviceType::extendedcolor: return "LCT015";
}
return "Plug 01";
return "Plug";
}
//Workaround functions courtesy of Sonoff-Tasmota
uint32_t encodeLightId(uint8_t idx)
{
uint8_t mac[6];
WiFi.macAddress(mac);
uint32_t id = (mac[3] << 20) | (mac[4] << 12) | (mac[5] << 4) | (idx & 0xF);
return id;
}
uint32_t decodeLightId(uint32_t id) {
return id & 0xF;
}
//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)
{
if (deviceId < 1 || deviceId > currentDeviceCount) return "{}"; //error
EspalexaDevice* dev = devices[deviceId-1];
deviceId--;
if (deviceId >= currentDeviceCount) return "{}"; //error
EspalexaDevice* dev = devices[deviceId];
String json = "{\"state\":{\"on\":";
json += boolString(dev->getValue());
@@ -148,9 +162,9 @@ private:
json += "\"type\":\"" + typeString(dev->getType());
json += "\",\"name\":\"" + dev->getName();
json += "\",\"modelid\":\"" + modelidString(dev->getType());
json += "\",\"manufacturername\":\"Espalexa\",\"productname\":\"E" + String(static_cast<uint8_t>(dev->getType()));
json += "\",\"uniqueid\":\""+ WiFi.macAddress() +"-"+ (deviceId+1);
json += "\",\"swversion\":\"2.4.0\"}";
json += "\",\"manufacturername\":\"Philips\",\"productname\":\"E" + String(static_cast<uint8_t>(dev->getType()));
json += "\",\"uniqueid\":\"" + String(encodeLightId(deviceId+1));
json += "\",\"swversion\":\"espalexa-2.4.3\"}";
return json;
}
@@ -174,7 +188,7 @@ private:
}
res += "\r\nFree Heap: " + (String)ESP.getFreeHeap();
res += "\r\nUptime: " + (String)millis();
res += "\r\n\r\nEspalexa library v2.4.0 by Christian Schwinne 2019";
res += "\r\n\r\nEspalexa library v2.4.3 by Christian Schwinne 2019";
server->send(200, "text/plain", res);
}
#endif
@@ -219,15 +233,6 @@ private:
"<serialNumber>"+ escapedMac +"</serialNumber>"
"<UDN>uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"</UDN>"
"<presentationURL>index.html</presentationURL>"
"<iconList>"
" <icon>"
" <mimetype>image/png</mimetype>"
" <height>48</height>"
" <width>48</width>"
" <depth>24</depth>"
" <url>hue_logo_0.png</url>"
" </icon>"
"</iconList>"
"</device>"
"</root>";
@@ -386,7 +391,7 @@ public:
return true;
}
//deprecated brightness-only callback
//brightness-only callback
bool addDevice(String deviceName, BrightnessCallbackFunction callback, uint8_t initialValue = 0)
{
EA_DEBUG("Constructing device ");
@@ -395,6 +400,17 @@ public:
EspalexaDevice* d = new EspalexaDevice(deviceName, callback, initialValue);
return addDevice(d);
}
//brightness-only callback
bool addDevice(String deviceName, ColorCallbackFunction callback, uint8_t initialValue = 0)
{
EA_DEBUG("Constructing device ");
EA_DEBUGLN((currentDeviceCount+1));
if (currentDeviceCount >= ESPALEXA_MAXDEVICES) return false;
EspalexaDevice* d = new EspalexaDevice(deviceName, callback, initialValue);
return addDevice(d);
}
bool addDevice(String deviceName, DeviceCallbackFunction callback, EspalexaDeviceType t = EspalexaDeviceType::dimmable, uint8_t initialValue = 0)
{
@@ -439,22 +455,27 @@ public:
{
server->send(200, "application/json", "[{\"success\":true}]"); //short valid response
int devId = req.substring(req.indexOf("lights")+7).toInt();
uint32_t devId = req.substring(req.indexOf("lights")+7).toInt();
EA_DEBUG("ls"); EA_DEBUGLN(devId);
devices[devId-1]->setPropertyChanged(EspalexaDeviceProperty::none);
devId = decodeLightId(devId);
EA_DEBUGLN(devId);
devId--; //zero-based for devices array
if (devId >= currentDeviceCount) return true; //return if invalid ID
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::none);
if (body.indexOf("false")>0) //OFF command
{
devices[devId-1]->setValue(0);
devices[devId-1]->setPropertyChanged(EspalexaDeviceProperty::off);
devices[devId-1]->doCallback();
devices[devId]->setValue(0);
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::off);
devices[devId]->doCallback();
return true;
}
if (body.indexOf("true") >0) //ON command
{
devices[devId-1]->setValue(devices[devId-1]->getLastValue());
devices[devId-1]->setPropertyChanged(EspalexaDeviceProperty::on);
devices[devId]->setValue(devices[devId]->getLastValue());
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::on);
}
if (body.indexOf("bri") >0) //BRIGHTNESS command
@@ -462,35 +483,35 @@ public:
uint8_t briL = body.substring(body.indexOf("bri") +5).toInt();
if (briL == 255)
{
devices[devId-1]->setValue(255);
devices[devId]->setValue(255);
} else {
devices[devId-1]->setValue(briL+1);
devices[devId]->setValue(briL+1);
}
devices[devId-1]->setPropertyChanged(EspalexaDeviceProperty::bri);
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::bri);
}
if (body.indexOf("xy") >0) //COLOR command (XY mode)
{
devices[devId-1]->setColorXY(body.substring(body.indexOf("[") +1).toFloat(), body.substring(body.indexOf(",0") +1).toFloat());
devices[devId-1]->setPropertyChanged(EspalexaDeviceProperty::xy);
devices[devId]->setColorXY(body.substring(body.indexOf("[") +1).toFloat(), body.substring(body.indexOf(",0") +1).toFloat());
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::xy);
}
if (body.indexOf("hue") >0) //COLOR command (HS mode)
{
devices[devId-1]->setColor(body.substring(body.indexOf("hue") +5).toInt(), body.substring(body.indexOf("sat") +5).toInt());
devices[devId-1]->setPropertyChanged(EspalexaDeviceProperty::hs);
devices[devId]->setColor(body.substring(body.indexOf("hue") +5).toInt(), body.substring(body.indexOf("sat") +5).toInt());
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::hs);
}
if (body.indexOf("ct") >0) //COLOR TEMP command (white spectrum)
{
devices[devId-1]->setColor(body.substring(body.indexOf("ct") +4).toInt());
devices[devId-1]->setPropertyChanged(EspalexaDeviceProperty::ct);
devices[devId]->setColor(body.substring(body.indexOf("ct") +4).toInt());
devices[devId]->setPropertyChanged(EspalexaDeviceProperty::ct);
}
devices[devId-1]->doCallback();
devices[devId]->doCallback();
#ifdef ESPALEXA_DEBUG
if (devices[devId-1]->getLastChangedProperty() == EspalexaDeviceProperty::none)
if (devices[devId]->getLastChangedProperty() == EspalexaDeviceProperty::none)
EA_DEBUGLN("STATE REQ WITHOUT BODY (likely Content-Type issue #6)");
#endif
return true;
@@ -508,7 +529,7 @@ public:
String jsonTemp = "{";
for (int i = 0; i<currentDeviceCount; i++)
{
jsonTemp += "\"" + String(i+1) + "\":";
jsonTemp += "\"" + String(encodeLightId(i+1)) + "\":";
jsonTemp += deviceJsonString(i+1);
if (i < currentDeviceCount-1) jsonTemp += ",";
}
@@ -516,7 +537,14 @@ public:
server->send(200, "application/json", jsonTemp);
} else //client wants one light (devId)
{
server->send(200, "application/json", deviceJsonString(devId));
devId = decodeLightId(devId);
EA_DEBUGLN(devId);
if (devId > currentDeviceCount)
{
server->send(200, "application/json", "{}");
} else {
server->send(200, "application/json", deviceJsonString(devId));
}
}
return true;
@@ -546,6 +574,13 @@ public:
return escapedMac;
}
//convert brightness (0-255) to percentage
uint8_t toPercent(uint8_t bri)
{
uint16_t perc = bri * 100;
return perc / 255;
}
~Espalexa(){delete devices;} //note: Espalexa is NOT meant to be destructed
};

View File

@@ -4,7 +4,7 @@
EspalexaDevice::EspalexaDevice(){}
EspalexaDevice::EspalexaDevice(String deviceName, BrightnessCallbackFunction gnCallback, uint8_t initialValue) { //constructor
EspalexaDevice::EspalexaDevice(String deviceName, BrightnessCallbackFunction gnCallback, uint8_t initialValue) { //constructor for dimmable device
_deviceName = deviceName;
_callback = gnCallback;
@@ -13,12 +13,21 @@ EspalexaDevice::EspalexaDevice(String deviceName, BrightnessCallbackFunction gnC
_type = EspalexaDeviceType::dimmable;
}
EspalexaDevice::EspalexaDevice(String deviceName, DeviceCallbackFunction gnCallback, EspalexaDeviceType t, uint8_t initialValue) { //constructor for color device
EspalexaDevice::EspalexaDevice(String deviceName, ColorCallbackFunction gnCallback, uint8_t initialValue) { //constructor for color device
_deviceName = deviceName;
_callbackCol = gnCallback;
_val = initialValue;
_val_last = _val;
_type = EspalexaDeviceType::extendedcolor;
}
EspalexaDevice::EspalexaDevice(String deviceName, DeviceCallbackFunction gnCallback, EspalexaDeviceType t, uint8_t initialValue) { //constructor for general device
_deviceName = deviceName;
_callbackDev = gnCallback;
_callback = nullptr;
_type = t;
if (t == EspalexaDeviceType::onoff) _type = EspalexaDeviceType::dimmable; //on/off is broken, so make dimmable device instead
_val = initialValue;
_val_last = _val;
}
@@ -305,5 +314,7 @@ void EspalexaDevice::setColor(uint8_t r, uint8_t g, uint8_t b)
void EspalexaDevice::doCallback()
{
(_callback != nullptr) ? _callback(_val) : _callbackDev(this);
if (_callback != nullptr) {_callback(_val); return;}
if (_callbackDev != nullptr) {_callbackDev(this); return;}
if (_callbackCol != nullptr) _callbackCol(_val, getRGB());
}

View File

@@ -7,6 +7,7 @@ typedef class EspalexaDevice;
typedef void (*BrightnessCallbackFunction) (uint8_t b);
typedef void (*DeviceCallbackFunction) (EspalexaDevice* d);
typedef void (*ColorCallbackFunction) (uint8_t br, uint32_t col);
enum class EspalexaColorMode : uint8_t { none = 0, ct = 1, hs = 2, xy = 3 };
enum class EspalexaDeviceType : uint8_t { onoff = 0, dimmable = 1, whitespectrum = 2, color = 3, extendedcolor = 4 };
@@ -15,22 +16,24 @@ enum class EspalexaDeviceProperty : uint8_t { none = 0, on = 1, off = 2, bri = 3
class EspalexaDevice {
private:
String _deviceName;
BrightnessCallbackFunction _callback;
DeviceCallbackFunction _callbackDev;
BrightnessCallbackFunction _callback = nullptr;
DeviceCallbackFunction _callbackDev = nullptr;
ColorCallbackFunction _callbackCol = nullptr;
uint8_t _val, _val_last, _sat = 0;
uint16_t _hue = 0, _ct = 0;
float _x = 0, _y = 0;
float _x = 0.5, _y = 0.5;
uint32_t _rgb = 0;
uint8_t _id = 0;
EspalexaDeviceType _type;
EspalexaDeviceProperty _changed = EspalexaDeviceProperty::none;
EspalexaColorMode _mode;
EspalexaColorMode _mode = EspalexaColorMode::xy;
public:
EspalexaDevice();
~EspalexaDevice();
EspalexaDevice(String deviceName, BrightnessCallbackFunction bcb, uint8_t initialValue =0);
EspalexaDevice(String deviceName, DeviceCallbackFunction dcb, EspalexaDeviceType t =EspalexaDeviceType::dimmable, uint8_t initialValue =0);
EspalexaDevice(String deviceName, ColorCallbackFunction ccb, uint8_t initialValue =0);
String getName();
uint8_t getId();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
// AsyncJson.h
// AsyncJson-v6.h
/*
Original file at: https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/src/AsyncJson.h
Original file at: https://github.com/baggior/ESPAsyncWebServer/blob/master/src/AsyncJson.h
Only changes are ArduinoJson lib path and removed content-type check
Async Response to use with ArduinoJson and AsyncWebServer
@@ -12,9 +12,12 @@
*/
#ifndef ASYNC_JSON_H_
#define ASYNC_JSON_H_
#include "ArduinoJson-v5.h"
#include "ArduinoJson-v6.h"
#include <Print.h>
constexpr char* JSON_MIMETYPE = "application/json";
#define DYNAMYC_JSON_DOCUMENT_SIZE 4096
constexpr const char* JSON_MIMETYPE = "application/json";
/*
* Json Response
@@ -41,27 +44,38 @@ class ChunkPrint : public Print {
}
return 0;
}
size_t write(const uint8_t *buffer, size_t size)
{
return this->Print::write(buffer, size);
}
};
class AsyncJsonResponse: public AsyncAbstractResponse {
private:
DynamicJsonBuffer _jsonBuffer;
DynamicJsonDocument _jsonBuffer;
JsonVariant _root;
bool _isValid;
public:
AsyncJsonResponse(bool isArray=false): _isValid{false} {
public:
AsyncJsonResponse(size_t maxJsonBufferSize = DYNAMYC_JSON_DOCUMENT_SIZE, bool isArray=false) : _jsonBuffer(maxJsonBufferSize), _isValid{false} {
_code = 200;
_contentType = JSON_MIMETYPE;
if(isArray)
_root = _jsonBuffer.createArray();
_root = _jsonBuffer.createNestedArray();
else
_root = _jsonBuffer.createObject();
_root = _jsonBuffer.createNestedObject();
}
~AsyncJsonResponse() {}
JsonVariant & getRoot() { return _root; }
bool _sourceValid() const { return _isValid; }
size_t setLength() {
_contentLength = _root.measureLength();
_contentLength = measureJson(_root);
if (_contentLength) { _isValid = true; }
return _contentLength;
}
@@ -70,12 +84,13 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
size_t _fillBuffer(uint8_t *data, size_t len){
ChunkPrint dest(data, _sentLength, len);
_root.printTo( dest ) ;
serializeJson(_root, dest);
return len;
}
};
typedef std::function<void(AsyncWebServerRequest *request, JsonVariant &json)> ArJsonRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest *request, JsonObject json)> ArJsonRequestHandlerFunction;
class AsyncCallbackJsonWebHandler: public AsyncWebHandler {
private:
@@ -84,9 +99,13 @@ protected:
WebRequestMethodComposite _method;
ArJsonRequestHandlerFunction _onRequest;
int _contentLength;
const size_t maxJsonBufferSize;
int _maxContentLength;
public:
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize=DYNAMYC_JSON_DOCUMENT_SIZE)
: _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {}
void setMethod(WebRequestMethodComposite method){ _method = method; }
void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; }
void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; }
@@ -108,14 +127,17 @@ public:
virtual void handleRequest(AsyncWebServerRequest *request) override final {
if(_onRequest) {
if (request->_tempObject != NULL) {
DynamicJsonBuffer jsonBuffer;
JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject));
if (json.success()) {
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject));
if(!error) {
JsonObject json = jsonBuffer.as<JsonObject>();
_onRequest(request, json);
return;
}
}
request->send(_contentLength > _maxContentLength ? 413 : 400, "{\"error\":\"Empty body\"}");
request->send(_contentLength > _maxContentLength ? 413 : 400);
} else {
request->send(500);
}

View File

@@ -3,12 +3,12 @@
*/
/*
* @title WLED project sketch
* @version 0.8.4
* @version 0.8.6
* @author Christian Schwinne
*/
//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.3.0 and the setting 512K(64K SPIFFS).
//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).
//ESP8266-01 (black) has 1MB flash and can thus fit the whole program. Use 1M(64K SPIFFS).
//Uncomment some of the following lines to disable features to compile for ESP8266-01 (max flash size 434kB):
@@ -35,15 +35,16 @@
//library inclusions
#include <Arduino.h>
#ifdef ARDUINO_ARCH_ESP32
#include <WiFi.h>
#include <ESPmDNS.h>
#include <AsyncTCP.h>
#include "SPIFFS.h"
#else
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESPAsyncTCP.h>
#else
#include <WiFi.h>
#include "esp_wifi.h"
#include <ESPmDNS.h>
#include <AsyncTCP.h>
#include "SPIFFS.h"
#endif
#include <ESPAsyncWebServer.h>
@@ -61,6 +62,7 @@
#define ESPALEXA_ASYNC
#define ESPALEXA_NO_SUBPAGE
#define ESPALEXA_MAXDEVICES 1
//#define ESPALEXA_DEBUG
#include "src/dependencies/espalexa/Espalexa.h"
#endif
#ifndef WLED_DISABLE_BLYNK
@@ -68,13 +70,13 @@
#endif
#include "src/dependencies/e131/E131.h"
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
#include "src/dependencies/json/AsyncJson.h"
#include "src/dependencies/json/ArduinoJson-v5.h"
#include "src/dependencies/json/AsyncJson-v6.h"
#include "src/dependencies/json/ArduinoJson-v6.h"
#include "html_classic.h"
#include "html_mobile.h"
#include "html_settings.h"
#include "html_other.h"
#include "WS2812FX.h"
#include "FX.h"
#include "ir_codes.h"
@@ -98,8 +100,8 @@
//version code in format yymmddb (b = daily build)
#define VERSION 1903252
char versionString[] = "0.8.4";
#define VERSION 1910255
char versionString[] = "0.8.6";
//AP and OTA default passwords (for maximum change them!)
@@ -122,47 +124,45 @@ char cmDNS[33] = "x"; //mDNS address (placeholder, will
char apSSID[33] = ""; //AP off by default (unless setup)
byte apChannel = 1; //2.4GHz WiFi AP channel (1-13)
byte apHide = 0; //hidden AP SSID
byte apWaitTimeSecs = 32; //time to wait for connection before opening AP
bool recoveryAPDisabled = false; //never open AP (not recommended)
//byte apWaitTimeSecs = 32; //time to wait for connection before opening AP
byte apBehavior = 0; //0: Open AP when no connection after boot 1: Open when no connection 2: Always open 3: Only when button pressed for 6 sec
//bool recoveryAPDisabled = false; //never open AP (not recommended)
IPAddress staticIP(0, 0, 0, 0); //static IP of ESP
IPAddress staticGateway(0, 0, 0, 0); //gateway (router) IP
IPAddress staticSubnet(255, 255, 255, 0); //most common subnet in home networks
//LED CONFIG
uint16_t ledCount = 30; //overcurrent prevented by ABL
uint16_t ledCount = 30; //overcurrent prevented by ABL
bool useRGBW = false; //SK6812 strips can contain an extra White channel
bool autoRGBtoRGBW = false; //if RGBW enabled, calculate White channel from RGB
#define ABL_MILLIAMPS_DEFAULT 850; //auto lower brightness to stay close to milliampere limit
#define ABL_MILLIAMPS_DEFAULT 850; //auto lower brightness to stay close to milliampere limit
bool turnOnAtBoot = true; //turn on LEDs at power-up
byte bootPreset = 0; //save preset to load after power-up
byte colS[]{255, 159, 0, 0}; //default RGB(W) color
byte colSecS[]{0, 0, 0, 0}; //default RGB(W) secondary color
byte briS = 127; //default brightness
byte effectDefault = 0;
byte effectDefault = 0;
byte effectSpeedDefault = 75;
byte effectIntensityDefault = 128; //intensity is supported on some effects as an additional parameter (e.g. for blink you can change the duty cycle)
byte effectPaletteDefault = 0; //palette is supported on the FastLED effects, otherwise it has no effect
bool useGammaCorrectionBri = false; //gamma correct brightness (not recommended)
bool useGammaCorrectionRGB = true; //gamma correct colors (strongly recommended)
byte nightlightTargetBri = 0; //brightness after nightlight is over
byte nightlightDelayMins = 60;
bool nightlightFade = true; //if enabled, light will gradually dim towards the target bri. Otherwise, it will instantly set after delay over
bool fadeTransition = true; //enable crossfading color transition
bool enableSecTransition = true; //also enable transition for secondary color
uint16_t transitionDelay = 750; //default crossfade duration in ms
uint16_t transitionDelay = 750; //default crossfade duration in ms
bool reverseMode = false; //flip entire LED strip (reverses all effect directions)
//bool strip.reverseMode = false; //flip entire LED strip (reverses all effect directions) --> edit in WS2812FX.h
bool skipFirstLed = false; //ignore first LED in strip (useful if you need the LED as signal repeater)
byte briMultiplier = 100; //% of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127)
//User Interface CONFIG
char serverDescription[33] = "WLED Light"; //Name of module
char serverDescription[33] = "WLED"; //Name of module
byte currentTheme = 7; //UI theme index for settings and classic UI
byte uiConfiguration = 0; //0: automatic (depends on user-agent) 1: classic UI 2: mobile UI
byte uiConfiguration = 2; //0: automatic (depends on user-agent) 1: classic UI 2: mobile UI
bool useHSB = true; //classic UI: use HSB sliders instead of RGB by default
char cssFont[33] = "Verdana"; //font to use in classic UI
@@ -204,6 +204,10 @@ bool e131Multicast = false;
char mqttDeviceTopic[33] = ""; //main MQTT topic (individual per device, default is wled/mac)
char mqttGroupTopic[33] = "wled/all"; //second MQTT topic (for example to group devices)
char mqttServer[33] = ""; //both domains and IPs should work (no SSL)
char mqttUser[41] = ""; //optional: username for MQTT auth
char mqttPass[41] = ""; //optional: password for MQTT auth
char mqttClientID[41] = ""; //override the client ID
uint16_t mqttPort = 1883;
bool huePollingEnabled = false; //poll hue bridge for light state
uint16_t huePollIntervalMs = 2500; //low values (< 1sec) may cause lag but offer quicker response
@@ -239,7 +243,7 @@ byte countdownMin = 0, countdownSec = 0;
byte macroBoot = 0; //macro loaded after startup
byte macroNl = 0; //after nightlight delay over
byte macroCountdown = 0;
byte macroCountdown = 0;
byte macroAlexaOn = 0, macroAlexaOff = 0;
byte macroButton = 0, macroLongPress = 0, macroDoublePress = 0;
@@ -254,6 +258,13 @@ uint16_t userVar0 = 0, userVar1 = 0;
//internal global variable declarations
//wifi
bool apActive = false;
bool forceReconnect = false;
uint32_t lastReconnectAttempt = 0;
bool interfacesInited = false;
bool wasConnected = false;
//color
byte col[]{255, 159, 0, 0}; //target RGB(W) color
byte colOld[]{0, 0, 0, 0}; //color before transition
@@ -292,6 +303,7 @@ byte briLast = 127; //brightness before turned off. Us
//button
bool buttonPressedBefore = false;
bool buttonLongPressed = false;
unsigned long buttonPressedTime = 0;
unsigned long buttonWaitTime = 0;
@@ -309,7 +321,6 @@ byte effectIntensity = effectIntensityDefault;
byte effectPalette = effectPaletteDefault;
//network
bool onlyAP = false; //only Access Point active, no connection to home network
bool udpConnected = false, udpRgbConnected = false;
//ui style
@@ -326,8 +337,6 @@ unsigned long hueLastRequestSent = 0;
bool hueAuthRequired = false;
bool hueReceived = false;
bool hueStoreAllowed = false, hueNewKey = false;
//unsigned long huePollIntervalMsTemp = huePollIntervalMs;
//bool hueAttempt = false;
//overlays
byte overlayCurrent = overlayDefault;
@@ -373,10 +382,9 @@ IPAddress realtimeIP = (0,0,0,0);
unsigned long realtimeTimeout = 0;
//mqtt
long lastMQTTReconnectAttempt = 0;
long lastMqttReconnectAttempt = 0;
long lastInterfaceUpdate = 0;
byte interfaceUpdateCallMode = 0;
uint32_t mqttFailedConAttempts = 0;
#if AUXPIN >= 0
//auxiliary debug pin
@@ -394,7 +402,6 @@ EspalexaDevice* espalexaDevice;
//dns server
DNSServer dnsServer;
bool dnsActive = false;
//network time
bool ntpConnected = false;
@@ -405,6 +412,9 @@ IPAddress ntpServerIP;
unsigned int ntpLocalPort = 2390;
#define NTP_PACKET_SIZE 48
#define MAX_LEDS 1500
#define MAX_LEDS_DMA 500
//string temp buffer (now stored in stack locally)
#define OMAX 2048
char* obuf;
@@ -414,6 +424,8 @@ String messageHead, messageSub;
byte optionType;
bool doReboot = false; //flag to initiate reboot from async handlers
bool doPublishMqtt = false;
bool doSendHADiscovery = true;
//server library objects
AsyncWebServer server(80);
@@ -428,6 +440,9 @@ E131* e131;
//led fx library object
WS2812FX strip = WS2812FX();
#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED)
#define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID,"Your_Network") != 0)
//debug macros
#ifdef WLED_DEBUG
#define DEBUG_PRINT(x) Serial.print (x)
@@ -436,6 +451,7 @@ WS2812FX strip = WS2812FX();
unsigned long debugTime = 0;
int lastWifiState = 3;
unsigned long wifiStateChangedTime = 0;
int loops = 0;
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
@@ -451,24 +467,6 @@ WS2812FX strip = WS2812FX();
#include "SPIFFSEditor.h"
#endif
//gamma 2.4 lookup table used for color correction
const byte gamma8[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
//function prototypes
void serveMessage(AsyncWebServerRequest*,uint16_t,String,String,byte);
@@ -503,7 +501,7 @@ bool oappend(char* txt)
//append new number to temp buffer efficiently
bool oappendi(int i)
{
char s[11];
char s[11];
sprintf(s,"%ld", i);
return oappend(s);
}
@@ -517,38 +515,41 @@ void setup() {
//main program loop
void loop() {
handleConnection();
handleSerial();
handleNotifications();
handleTransitions();
userLoop();
yield();
handleIO();
handleIR();
handleNetworkTime();
if (!onlyAP) handleAlexa();
handleOverlays();
handleAlexa();
handleOverlays();
if (doSendHADiscovery) sendHADiscoveryMQTT();
yield();
if (doReboot) reset();
if (!realtimeActive) //block stuff if WARLS/Adalight is enabled
{
if (dnsActive) dnsServer.processNextRequest();
if (apActive) dnsServer.processNextRequest();
#ifndef WLED_DISABLE_OTA
if (aOtaEnabled) ArduinoOTA.handle();
if (WLED_CONNECTED && aOtaEnabled) ArduinoOTA.handle();
#endif
handleNightlight();
yield();
if (!onlyAP) {
handleHue();
handleBlynk();
}
handleHue();
handleBlynk();
yield();
if (!offMode) strip.service();
}
yield();
if (millis() - lastMqttReconnectAttempt > 30000) initMqtt();
//DEBUG serial logging
#ifdef WLED_DEBUG
if (millis() - debugTime > 9999)
@@ -566,7 +567,10 @@ void loop() {
DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime);
DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime);
DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP());
debugTime = millis();
DEBUG_PRINT("Loops/sec: "); DEBUG_PRINTLN(loops/10);
loops = 0;
debugTime = millis();
}
loops++;
#endif
}

367
wled00/wled00.vcxproj Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,272 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="wled00.ino" />
<None Include="wled01_eeprom.ino" />
<None Include="wled02_xml.ino" />
<None Include="wled03_set.ino" />
<None Include="wled04_file.ino" />
<None Include="wled05_init.ino" />
<None Include="wled06_usermod.ino" />
<None Include="wled07_notify.ino" />
<None Include="wled08_led.ino" />
<None Include="wled09_button.ino" />
<None Include="wled10_ntp.ino" />
<None Include="wled11_ol.ino" />
<None Include="wled12_alexa.ino" />
<None Include="wled13_cronixie.ino" />
<None Include="wled14_colors.ino" />
<None Include="wled15_hue.ino" />
<None Include="wled16_blynk.ino" />
<None Include="wled17_mqtt.ino" />
<None Include="wled18_server.ino" />
<None Include="wled19_json.ino" />
<None Include="wled20_ir.ino" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="__vm\.wled00.vsarduino.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_classic.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_mobile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_other.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="html_settings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ir_codes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NpbWrapper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="palettes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WS2812FX.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Callbacks.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\DisconnectReasons.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Flags.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Helpers.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\MessageProperties.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\ParsingInformation.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Storage.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\Packet.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\BlynkSimpleEsp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApiArduino.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkArduinoClient.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkConfig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDateTime.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDebug.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDetectDevice.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkEveryN.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkFifo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkHandlers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkParam.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocol.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocolDefs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTemplates.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTimer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkUtility.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWidgetBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWiFiCommon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\e131\E131.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\espalexa\Espalexa.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\espalexa\EspalexaDevice.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\json\ArduinoJson-v6.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\json\AsyncJson-v6.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\time\Time.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\time\TimeLib.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\dependencies\timezone\Timezone.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="WS2812FX.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WS2812FX_fcn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkDebug.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkHandlers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkTimer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\blynk\Blynk\utility.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\e131\E131.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\espalexa\EspalexaDevice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\time\DateStrings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\time\Time.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\dependencies\timezone\Timezone.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@@ -6,7 +6,7 @@
#define EEPSIZE 2560
//eeprom Version code, enables default settings instead of 0 init on update
#define EEPVER 10
#define EEPVER 11
//0 -> old version, default
//1 -> 0.4p 1711272 and up
//2 -> 0.4p 1711302 and up
@@ -18,6 +18,7 @@
//8 -> 0.8.0-a and up
//9 -> 0.8.0
//10-> 0.8.2
//11-> 0.8.5-dev #mqttauth @TimothyBrown
/*
@@ -64,7 +65,7 @@ void saveSettingsToEEPROM()
clearEEPROM();
EEPROM.write(233, 233);
}
writeStringToEEPROM( 0, clientSSID, 32);
writeStringToEEPROM( 32, clientPass, 64);
writeStringToEEPROM( 96, cmDNS, 32);
@@ -81,50 +82,50 @@ void saveSettingsToEEPROM()
EEPROM.write(231, notifyTwice);
EEPROM.write(232, buttonEnabled);
//233 reserved for first boot flag
for (int i = 0; i<4; i++) //ip addresses
{
EEPROM.write(234+i, staticIP[i]);
EEPROM.write(238+i, staticGateway[i]);
EEPROM.write(242+i, staticSubnet[i]);
}
EEPROM.write(246, colS[0]);
EEPROM.write(247, colS[1]);
EEPROM.write(248, colS[2]);
EEPROM.write(249, briS);
EEPROM.write(250, receiveNotificationBrightness);
EEPROM.write(251, fadeTransition);
EEPROM.write(252, reverseMode);
EEPROM.write(252, strip.reverseMode);
EEPROM.write(253, transitionDelayDefault & 0xFF);
EEPROM.write(254, (transitionDelayDefault >> 8) & 0xFF);
EEPROM.write(255, briMultiplier);
//255,250,231,230,226 notifier bytes
writeStringToEEPROM(256, otaPass, 32);
EEPROM.write(288, nightlightTargetBri);
EEPROM.write(289, otaLock);
EEPROM.write(290, udpPort & 0xFF);
EEPROM.write(291, (udpPort >> 8) & 0xFF);
writeStringToEEPROM(292, serverDescription, 32);
EEPROM.write(324, effectDefault);
EEPROM.write(325, effectSpeedDefault);
EEPROM.write(326, effectIntensityDefault);
EEPROM.write(327, ntpEnabled);
EEPROM.write(328, currentTimezone);
EEPROM.write(329, useAMPM);
EEPROM.write(330, useGammaCorrectionBri);
EEPROM.write(331, useGammaCorrectionRGB);
EEPROM.write(330, strip.gammaCorrectBri);
EEPROM.write(331, strip.gammaCorrectCol);
EEPROM.write(332, overlayDefault);
EEPROM.write(333, alexaEnabled);
writeStringToEEPROM(334, alexaInvocationName, 32);
EEPROM.write(366, notifyAlexa);
EEPROM.write(367, (arlsOffset>=0));
EEPROM.write(368, abs(arlsOffset));
EEPROM.write(369, turnOnAtBoot);
@@ -133,11 +134,11 @@ void saveSettingsToEEPROM()
EEPROM.write(372, useRGBW);
EEPROM.write(373, effectPaletteDefault);
EEPROM.write(374, strip.paletteFade);
EEPROM.write(375, apWaitTimeSecs);
EEPROM.write(376, recoveryAPDisabled);
//EEPROM.write(375, apWaitTimeSecs);
EEPROM.write(376, apBehavior);
EEPROM.write(377, EEPVER); //eeprom was updated to latest
EEPROM.write(378, colSecS[0]);
EEPROM.write(379, colSecS[1]);
EEPROM.write(380, colSecS[2]);
@@ -154,7 +155,7 @@ void saveSettingsToEEPROM()
EEPROM.write(391, receiveNotificationColor);
EEPROM.write(392, receiveNotificationEffects);
EEPROM.write(393, wifiLock);
EEPROM.write(394, abs(utcOffsetSecs) & 0xFF);
EEPROM.write(395, (abs(utcOffsetSecs) >> 8) & 0xFF);
EEPROM.write(396, (utcOffsetSecs<0)); //is negative
@@ -193,7 +194,7 @@ void saveSettingsToEEPROM()
EEPROM.write(2152, analogClock12pixel);
EEPROM.write(2153, analogClock5MinuteMarks);
EEPROM.write(2154, analogClockSecondsTrail);
EEPROM.write(2155, countdownMode);
EEPROM.write(2156, countdownYear);
EEPROM.write(2157, countdownMonth);
@@ -206,7 +207,7 @@ void saveSettingsToEEPROM()
writeStringToEEPROM(2165, cronixieDisplay, 6);
EEPROM.write(2171, cronixieBacklight);
setCronixie();
EEPROM.write(2175, macroBoot);
EEPROM.write(2176, macroAlexaOn);
EEPROM.write(2177, macroAlexaOff);
@@ -253,10 +254,15 @@ void saveSettingsToEEPROM()
EEPROM.write(2290 + i, timerMacro[i] );
}
writeStringToEEPROM(2300, mqttServer, 32);
writeStringToEEPROM(2300, mqttServer, 32);
writeStringToEEPROM(2333, mqttDeviceTopic, 32);
writeStringToEEPROM(2366, mqttGroupTopic, 32);
writeStringToEEPROM(2366, mqttGroupTopic, 32);
writeStringToEEPROM(2399, mqttUser, 40);
writeStringToEEPROM(2440, mqttPass, 40);
writeStringToEEPROM(2481, mqttClientID, 40);
EEPROM.write(2522, mqttPort & 0xFF);
EEPROM.write(2523, (mqttPort >> 8) & 0xFF);
EEPROM.commit();
}
@@ -274,7 +280,7 @@ void loadSettingsFromEEPROM(bool first)
return;
}
int lastEEPROMversion = EEPROM.read(377); //last EEPROM version before update
readStringFromEEPROM( 0, clientSSID, 32);
readStringFromEEPROM( 32, clientPass, 64);
@@ -287,17 +293,17 @@ void loadSettingsFromEEPROM(bool first)
nightlightFade = EEPROM.read(225);
notifyDirectDefault = EEPROM.read(226);
notifyDirect = notifyDirectDefault;
apChannel = EEPROM.read(227);
if (apChannel > 13 || apChannel < 1) apChannel = 1;
apHide = EEPROM.read(228);
if (apHide > 1) apHide = 1;
ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 30;
ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > MAX_LEDS || ledCount == 0) ledCount = 30;
notifyButton = EEPROM.read(230);
notifyTwice = EEPROM.read(231);
buttonEnabled = EEPROM.read(232);
staticIP[0] = EEPROM.read(234);
staticIP[1] = EEPROM.read(235);
staticIP[2] = EEPROM.read(236);
@@ -310,7 +316,7 @@ void loadSettingsFromEEPROM(bool first)
staticSubnet[1] = EEPROM.read(243);
staticSubnet[2] = EEPROM.read(244);
staticSubnet[3] = EEPROM.read(245);
colS[0] = EEPROM.read(246); col[0] = colS[0];
colS[1] = EEPROM.read(247); col[1] = colS[1];
colS[2] = EEPROM.read(248); col[2] = colS[2];
@@ -321,33 +327,33 @@ void loadSettingsFromEEPROM(bool first)
}
receiveNotificationBrightness = EEPROM.read(250);
fadeTransition = EEPROM.read(251);
reverseMode = EEPROM.read(252);
strip.reverseMode = EEPROM.read(252);
transitionDelayDefault = EEPROM.read(253) + ((EEPROM.read(254) << 8) & 0xFF00);
transitionDelay = transitionDelayDefault;
briMultiplier = EEPROM.read(255);
readStringFromEEPROM(256, otaPass, 32);
nightlightTargetBri = EEPROM.read(288);
otaLock = EEPROM.read(289);
udpPort = EEPROM.read(290) + ((EEPROM.read(291) << 8) & 0xFF00);
readStringFromEEPROM(292, serverDescription, 32);
effectDefault = EEPROM.read(324); effectCurrent = effectDefault;
effectSpeedDefault = EEPROM.read(325); effectSpeed = effectSpeedDefault;
ntpEnabled = EEPROM.read(327);
currentTimezone = EEPROM.read(328);
useAMPM = EEPROM.read(329);
useGammaCorrectionBri = EEPROM.read(330);
useGammaCorrectionRGB = EEPROM.read(331);
strip.gammaCorrectBri = EEPROM.read(330);
strip.gammaCorrectCol = EEPROM.read(331);
overlayDefault = EEPROM.read(332);
if (lastEEPROMversion < 8 && overlayDefault > 0) overlayDefault--; //overlay mode 1 (solid) was removed
alexaEnabled = EEPROM.read(333);
readStringFromEEPROM(334, alexaInvocationName, 32);
notifyAlexa = EEPROM.read(366);
arlsOffset = EEPROM.read(368);
if (!EEPROM.read(367)) arlsOffset = -arlsOffset;
@@ -358,9 +364,9 @@ void loadSettingsFromEEPROM(bool first)
effectPaletteDefault = EEPROM.read(373); effectPalette = effectPaletteDefault;
//374 - strip.paletteFade
if (lastEEPROMversion > 0) {
apWaitTimeSecs = EEPROM.read(375);
recoveryAPDisabled = EEPROM.read(376);
if (lastEEPROMversion > 0) {
//apWaitTimeSecs = EEPROM.read(375);
apBehavior = EEPROM.read(376);
}
//377 = lastEEPROMversion
if (lastEEPROMversion > 1) {
@@ -370,7 +376,7 @@ void loadSettingsFromEEPROM(bool first)
}
}
if (lastEEPROMversion > 3) {
effectIntensityDefault = EEPROM.read(326); effectIntensity = effectIntensityDefault;
effectIntensityDefault = EEPROM.read(326); effectIntensity = effectIntensityDefault;
aOtaEnabled = EEPROM.read(390);
receiveNotificationColor = EEPROM.read(391);
receiveNotificationEffects = EEPROM.read(392);
@@ -391,7 +397,7 @@ void loadSettingsFromEEPROM(bool first)
}
readStringFromEEPROM(2054, hueApiKey, 46);
huePollIntervalMs = EEPROM.read(2100) + ((EEPROM.read(2101) << 8) & 0xFF00);
notifyHue = EEPROM.read(2102);
hueApplyOnOff = EEPROM.read(2103);
@@ -416,7 +422,7 @@ void loadSettingsFromEEPROM(bool first)
readStringFromEEPROM(2165, cronixieDisplay, 6);
cronixieBacklight = EEPROM.read(2171);
macroBoot = EEPROM.read(2175);
macroAlexaOn = EEPROM.read(2176);
macroAlexaOff = EEPROM.read(2177);
@@ -454,9 +460,9 @@ void loadSettingsFromEEPROM(bool first)
if (lastEEPROMversion > 8)
{
readStringFromEEPROM(2300, mqttServer, 32);
readStringFromEEPROM(2300, mqttServer, 32);
readStringFromEEPROM(2333, mqttDeviceTopic, 32);
readStringFromEEPROM(2366, mqttGroupTopic, 32);
readStringFromEEPROM(2366, mqttGroupTopic, 32);
}
if (lastEEPROMversion > 9)
@@ -470,16 +476,24 @@ void loadSettingsFromEEPROM(bool first)
} else {
strip.ablMilliampsMax = ABL_MILLIAMPS_DEFAULT;
}
if (lastEEPROMversion > 10)
{
readStringFromEEPROM(2399, mqttUser, 40);
readStringFromEEPROM(2440, mqttPass, 40);
readStringFromEEPROM(2481, mqttClientID, 40);
mqttPort = EEPROM.read(2522) + ((EEPROM.read(2523) << 8) & 0xFF00);
}
receiveDirect = !EEPROM.read(2200);
notifyMacro = EEPROM.read(2201);
uiConfiguration = EEPROM.read(2202);
#ifdef WLED_DISABLE_MOBILE_UI
uiConfiguration = 1;
//force default UI since mobile is unavailable
#endif
autoRGBtoRGBW = EEPROM.read(2203);
skipFirstLed = EEPROM.read(2204);
@@ -493,7 +507,7 @@ void loadSettingsFromEEPROM(bool first)
presetApplyCol = EEPROM.read(2211);
presetApplyFx = EEPROM.read(2212);
}
bootPreset = EEPROM.read(389);
wifiLock = EEPROM.read(393);
utcOffsetSecs = EEPROM.read(394) + ((EEPROM.read(395) << 8) & 0xFF00);
@@ -513,10 +527,10 @@ void loadSettingsFromEEPROM(bool first)
//1024-2047 reserved
readStringFromEEPROM(2220, blynkApiKey, 35);
//user MOD memory
//2944 - 3071 reserved
useHSB = useHSBDefault;
overlayCurrent = overlayDefault;
@@ -570,7 +584,7 @@ void savePreset(byte index)
}
EEPROM.write(i+10, effectCurrent);
EEPROM.write(i+11, effectSpeed);
EEPROM.write(i+16, effectIntensity);
EEPROM.write(i+17, effectPalette);
EEPROM.commit();
@@ -597,7 +611,7 @@ void applyMacro(byte index)
if (!notifyMacro) mc += "&NN";
String forbidden = "&M="; //dont apply if called by the macro itself to prevent loop
/*
* NOTE: loop is still possible if you call a different macro from a macro, which then calls the first macro again.
* NOTE: loop is still possible if you call a different macro from a macro, which then calls the first macro again.
* To prevent that, but also disable calling macros within macros, comment the next line out.
*/
forbidden = forbidden + index;

View File

@@ -7,12 +7,12 @@ char* XML_response(AsyncWebServerRequest *request, bool includeTheme, char* dest
{
char sbuf[(dest == nullptr)?1024:1]; //allocate local buffer if none passed
obuf = (dest == nullptr)? sbuf:dest;
olen = 0;
oappend("<?xml version=\"1.0\" ?><vs><ac>");
oappendi((nightlightActive && nightlightFade) ? briT : bri);
oappend("</ac>");
for (int i = 0; i < 3; i++)
{
oappend("<cl>");
@@ -77,7 +77,7 @@ char* XML_response(AsyncWebServerRequest *request, bool includeTheme, char* dest
} else {
oappend(serverDescription);
}
oappend("</ds>");
if (includeTheme)
{
@@ -107,7 +107,7 @@ char* XML_response(AsyncWebServerRequest *request, bool includeTheme, char* dest
void sappend(char stype, char* key, int val)
{
char ds[] = "d.Sf.";
switch(stype)
{
case 'c': //checkbox
@@ -165,7 +165,7 @@ void getSettingsJS(byte subPage, char* dest)
DEBUG_PRINTLN(subPage);
obuf = dest;
olen = 0;
if (subPage <1 || subPage >6) return;
if (subPage == 1) {
@@ -174,7 +174,7 @@ void getSettingsJS(byte subPage, char* dest)
byte l = strlen(clientPass);
char fpass[l+1]; //fill password field with ***
fpass[l] = 0;
memset(fpass,'*',l);
memset(fpass,'*',l);
sappends('s',"CP",fpass);
char k[3]; k[2] = 0; //IP addresses
@@ -187,16 +187,16 @@ void getSettingsJS(byte subPage, char* dest)
}
sappends('s',"CM",cmDNS);
sappend('v',"AT",apWaitTimeSecs);
sappend('i',"AB",apBehavior);
sappends('s',"AS",apSSID);
sappend('c',"AH",apHide);
l = strlen(apPass);
char fapass[l+1]; //fill password field with ***
fapass[l] = 0;
memset(fapass,'*',l);
memset(fapass,'*',l);
sappends('s',"AP",fapass);
sappend('v',"AC",apChannel);
if (WiFi.localIP()[0] != 0) //is connected
@@ -209,7 +209,7 @@ void getSettingsJS(byte subPage, char* dest)
{
sappends('m',"(\"sip\")[0]","Not connected");
}
if (WiFi.softAPIP()[0] != 0) //is active
{
char s[16];
@@ -221,7 +221,7 @@ void getSettingsJS(byte subPage, char* dest)
sappends('m',"(\"sip\")[1]","Not active");
}
}
if (subPage == 2) {
sappend('v',"LC",ledCount);
sappend('v',"MA",strip.ablMilliampsMax);
@@ -253,8 +253,8 @@ void getSettingsJS(byte subPage, char* dest)
oappend(";");
sappend('v',"SX",effectSpeedDefault);
sappend('v',"IX",effectIntensityDefault);
sappend('c',"GB",useGammaCorrectionBri);
sappend('c',"GC",useGammaCorrectionRGB);
sappend('c',"GB",strip.gammaCorrectBri);
sappend('c',"GC",strip.gammaCorrectCol);
sappend('c',"TF",fadeTransition);
sappend('v',"TD",transitionDelay);
sappend('c',"PF",strip.paletteFade);
@@ -264,12 +264,12 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',"TL",nightlightDelayMinsDefault);
sappend('c',"TW",nightlightFade);
sappend('i',"PB",strip.paletteBlend);
sappend('c',"RV",reverseMode);
sappend('c',"RV",strip.reverseMode);
sappend('c',"SL",skipFirstLed);
}
if (subPage == 3)
{
{
sappend('i',"UI",uiConfiguration);
sappends('s',"DS",serverDescription);
sappend('c',"MD",useHSBDefault);
@@ -308,6 +308,15 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',"SA",notifyAlexa);
sappends('s',"BK",(char*)((blynkEnabled)?"Hidden":""));
sappends('s',"MS",mqttServer);
sappend('v',"MQPORT",mqttPort);
sappends('s',"MQUSER",mqttUser);
sappends('s',"MQPASS",mqttPass);
byte l = strlen(mqttPass);
char fpass[l+1]; //fill password field with ***
fpass[l] = 0;
memset(fpass,'*',l);
sappends('s',"MQPASS",fpass);
sappends('s',"MQCID",mqttClientID);
sappends('s',"MD",mqttDeviceTopic);
sappends('s',"MG",mqttGroupTopic);
sappend('v',"H0",hueIP[0]);
@@ -330,7 +339,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('i',"TZ",currentTimezone);
sappend('v',"UO",utcOffsetSecs);
char tm[32];
getTimeString(tm);
getTimeString(tm);
sappends('m',"(\"times\")[0]",tm);
sappend('i',"OL",overlayCurrent);
sappend('v',"O1",overlayMin);
@@ -355,7 +364,7 @@ void getSettingsJS(byte subPage, char* dest)
sprintf(k+1,"%i",i);
sappends('s',k,m);
}
sappend('v',"MB",macroBoot);
sappend('v',"A0",macroAlexaOn);
sappend('v',"A1",macroAlexaOff);
@@ -381,7 +390,6 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',"NO",otaLock);
sappend('c',"OW",wifiLock);
sappend('c',"AO",aOtaEnabled);
sappend('c',"NA",recoveryAPDisabled);
sappends('m',"(\"msg\")[0]","WLED ");
olen -= 2; //delete ";
oappend(versionString);
@@ -398,7 +406,7 @@ void getThemeColors(char o[][9])
{
switch (currentTheme)
{
// accent color (aCol) background (bCol) panel (cCol) controls (dCol) shadows (sCol) text (tCol)
// accent color (aCol) background (bCol) panel (cCol) controls (dCol) shadows (sCol) text (tCol)
default: strcpy(o[0], "D9B310"); strcpy(o[1], "0B3C5D"); strcpy(o[2], "1D2731"); strcpy(o[3], "328CC1"); strcpy(o[4], "000"); strcpy(o[5], "328CC1"); break; //night
case 1: strcpy(o[0], "eee"); strcpy(o[1], "ddd"); strcpy(o[2], "b9b9b9"); strcpy(o[3], "049"); strcpy(o[4], "777"); strcpy(o[5], "049"); break; //modern
case 2: strcpy(o[0], "abb"); strcpy(o[1], "fff"); strcpy(o[2], "ddd"); strcpy(o[3], "000"); strcpy(o[4], "0004"); strcpy(o[5], "000"); break; //bright

View File

@@ -19,7 +19,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec
if (subPage <1 || subPage >6) return;
//WIFI SETTINGS
if (subPage == 1)
{
@@ -27,24 +27,25 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (request->arg("CP").charAt(0) != '*') strcpy(clientPass, request->arg("CP").c_str());
strcpy(cmDNS, request->arg("CM").c_str());
int t = request->arg("AT").toInt(); if (t > 9 && t <= 255) apWaitTimeSecs = t;
apBehavior = request->arg("AB").toInt();
strcpy(apSSID, request->arg("AS").c_str());
apHide = request->hasArg("AH");
if (request->arg("AP").charAt(0) != '*') strcpy(apPass, request->arg("AP").c_str());
t = request->arg("AC").toInt(); if (t > 0 && t < 14) apChannel = t;
int passlen = request->arg("AP").length();
if (passlen == 0 || (passlen > 7 && request->arg("AP").charAt(0) != '*')) strcpy(apPass, request->arg("AP").c_str());
int t = request->arg("AC").toInt(); if (t > 0 && t < 14) apChannel = t;
char k[3]; k[2] = 0;
for (int i = 0; i<4; i++)
{
k[1] = i+48;//ascii 0,1,2,3
k[0] = 'I'; //static IP
staticIP[i] = request->arg(k).toInt();
k[0] = 'G'; //gateway
staticGateway[i] = request->arg(k).toInt();
k[0] = 'S'; //subnet
staticSubnet[i] = request->arg(k).toInt();
}
@@ -54,15 +55,15 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (subPage == 2)
{
int t = request->arg("LC").toInt();
if (t > 0 && t <= 1200) ledCount = t;
if (t > 0 && t <= MAX_LEDS) ledCount = t;
#ifndef ARDUINO_ARCH_ESP32
#if LEDPIN == 3
if (ledCount > 300) ledCount = 300; //DMA method uses too much ram
if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram
#endif
#endif
strip.ablMilliampsMax = request->arg("MA").toInt();
useRGBW = request->hasArg("EW");
strip.colorOrder = request->arg("CO").toInt();
strip.colorOrder = request->arg("CO").toInt();
autoRGBtoRGBW = request->hasArg("AW");
//ignore settings and save current brightness, colors and fx as default
@@ -97,25 +98,25 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
turnOnAtBoot = request->hasArg("BO");
t = request->arg("BP").toInt();
if (t <= 25) bootPreset = t;
useGammaCorrectionBri = request->hasArg("GB");
useGammaCorrectionRGB = request->hasArg("GC");
strip.gammaCorrectBri = request->hasArg("GB");
strip.gammaCorrectCol = request->hasArg("GC");
fadeTransition = request->hasArg("TF");
t = request->arg("TD").toInt();
if (t > 0) transitionDelay = t;
transitionDelayDefault = t;
strip.paletteFade = request->hasArg("PF");
enableSecTransition = request->hasArg("T2");
nightlightTargetBri = request->arg("TB").toInt();
t = request->arg("TL").toInt();
if (t > 0) nightlightDelayMinsDefault = t;
nightlightDelayMins = nightlightDelayMinsDefault;
nightlightFade = request->hasArg("TW");
t = request->arg("PB").toInt();
if (t >= 0 && t < 4) strip.paletteBlend = t;
reverseMode = request->hasArg("RV");
strip.setReverseMode(reverseMode);
strip.reverseMode = request->hasArg("RV");
skipFirstLed = request->hasArg("SL");
t = request->arg("BF").toInt();
if (t > 0) briMultiplier = t;
@@ -157,7 +158,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
notifyHue = request->hasArg("SH");
notifyMacro = request->hasArg("SM");
notifyTwice = request->hasArg("S2");
receiveDirect = request->hasArg("RD");
e131Multicast = request->hasArg("EM");
t = request->arg("EU").toInt();
@@ -168,18 +169,23 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
arlsDisableGammaCorrection = request->hasArg("RG");
t = request->arg("WO").toInt();
if (t >= -255 && t <= 255) arlsOffset = t;
alexaEnabled = request->hasArg("AL");
strcpy(alexaInvocationName, request->arg("AI").c_str());
if (request->hasArg("BK") && !request->arg("BK").equals("Hidden")) {
strcpy(blynkApiKey,request->arg("BK").c_str()); initBlynk(blynkApiKey);
}
strcpy(mqttServer, request->arg("MS").c_str());
t = request->arg("MQPORT").toInt();
if (t > 0) mqttPort = t;
strcpy(mqttUser, request->arg("MQUSER").c_str());
if (request->arg("MQPASS").charAt(0) != '*') strcpy(mqttPass, request->arg("MQPASS").c_str());
strcpy(mqttClientID, request->arg("MQCID").c_str());
strcpy(mqttDeviceTopic, request->arg("MD").c_str());
strcpy(mqttGroupTopic, request->arg("MG").c_str());
for (int i=0;i<4;i++){
String a = "H"+String(i);
hueIP[i] = request->arg(a).toInt();
@@ -208,20 +214,20 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
utcOffsetSecs = request->arg("UO").toInt();
//start ntp if not already connected
if (ntpEnabled && WiFi.status() == WL_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
if (request->hasArg("OL")){
overlayDefault = request->arg("OL").toInt();
if (overlayCurrent != overlayDefault) strip.unlockAll();
overlayCurrent = overlayDefault;
}
overlayMin = request->arg("O1").toInt();
overlayMax = request->arg("O2").toInt();
analogClock12pixel = request->arg("OM").toInt();
analogClock5MinuteMarks = request->hasArg("O5");
analogClockSecondsTrail = request->hasArg("OS");
strcpy(cronixieDisplay,request->arg("CX").c_str());
bool cbOld = cronixieBacklight;
cronixieBacklight = request->hasArg("CB");
@@ -236,13 +242,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
countdownHour = request->arg("CH").toInt();
countdownMin = request->arg("CM").toInt();
countdownSec = request->arg("CS").toInt();
for (int i=1;i<17;i++)
{
String a = "M"+String(i);
if (request->hasArg(a.c_str())) saveMacro(i,request->arg(a),false);
}
macroBoot = request->arg("MB").toInt();
macroAlexaOn = request->arg("A0").toInt();
macroAlexaOff = request->arg("A1").toInt();
@@ -256,13 +262,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
for (int i = 0; i<8; i++)
{
k[1] = i+48;//ascii 0,1,2,3
k[0] = 'H'; //timer hours
timerHours[i] = request->arg(k).toInt();
k[0] = 'N'; //minutes
timerMinutes[i] = request->arg(k).toInt();
k[0] = 'T'; //macros
timerMacro[i] = request->arg(k).toInt();
@@ -293,12 +299,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
strcpy(otaPass,request->arg("OP").c_str());
}
}
if (pwdCorrect) //allow changes if correct pwd or no ota active
{
otaLock = request->hasArg("NO");
wifiLock = request->hasArg("OW");
recoveryAPDisabled = request->hasArg("NA");
aOtaEnabled = request->hasArg("AO");
}
}
@@ -321,7 +326,7 @@ bool updateVal(const String* req, const char* key, byte* val, byte minv=0, byte
{
int pos = req->indexOf(key);
if (pos < 1) return false;
if (req->charAt(pos+3) == '~') {
int out = getNumVal(req, pos+1);
if (out == 0)
@@ -354,25 +359,25 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
int pos = 0;
DEBUG_PRINT("API req: ");
DEBUG_PRINTLN(req);
//save macro, requires &MS=<slot>(<macro>) format
pos = req.indexOf("&MS=");
if (pos > 0) {
int i = req.substring(pos + 4).toInt();
pos = req.indexOf('(') +1;
if (pos > 0) {
if (pos > 0) {
int en = req.indexOf(')');
String mc = req.substring(pos);
if (en > 0) mc = req.substring(pos, en);
saveMacro(i, mc);
saveMacro(i, mc);
}
pos = req.indexOf("IN");
if (pos < 1) XML_response(request, false);
return true;
//if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise
}
//set brightness
updateVal(&req, "&A=", &bri);
@@ -397,7 +402,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
}
colorHStoRGB(temphue,tempsat,(req.indexOf("H2")>0)? colSec:col);
}
//set color from HEX or 32bit DEC
pos = req.indexOf("CL=");
if (pos > 0) {
@@ -407,7 +412,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (pos > 0) {
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
}
//set 2nd to white
pos = req.indexOf("SW");
if (pos > 0) {
@@ -422,7 +427,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
colSec[2] = 255;
}
}
//set 2nd to black
pos = req.indexOf("SB");
if (pos > 0) {
@@ -431,13 +436,13 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
colSec[1] = 0;
colSec[2] = 0;
}
//set to random hue SR=0->1st SR=1->2nd
pos = req.indexOf("SR");
if (pos > 0) {
_setRandomColor(getNumVal(&req, pos));
}
//set 2nd to 1st
pos = req.indexOf("SP");
if (pos > 0) {
@@ -446,7 +451,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
colSec[2] = col[2];
colSec[3] = col[3];
}
//swap 2nd & 1st
pos = req.indexOf("SC");
if (pos > 0) {
@@ -458,7 +463,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
colSec[i] = temp;
}
}
//set effect parameters
if (updateVal(&req, "FX=", &effectCurrent, 0, strip.getModeCount()-1)) presetCyclingEnabled = false;
updateVal(&req, "SX=", &effectSpeed);
@@ -479,27 +484,27 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
}
}
#endif
//set default control mode (0 - RGB, 1 - HSB)
pos = req.indexOf("MD=");
if (pos > 0) {
useHSB = getNumVal(&req, pos);
}
//set advanced overlay
pos = req.indexOf("OL=");
if (pos > 0) {
overlayCurrent = getNumVal(&req, pos);
strip.unlockAll();
}
//(un)lock pixel (ranges)
pos = req.indexOf("&L=");
if (pos > 0) {
uint16_t index = getNumVal(&req, pos);
pos = req.indexOf("L2=");
bool unlock = req.indexOf("UL") > 0;
if (pos > 0){
if (pos > 0) {
uint16_t index2 = getNumVal(&req, pos);
if (unlock) {
strip.unlockRange(index, index2);
@@ -520,11 +525,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (pos > 0) {
applyMacro(getNumVal(&req, pos));
}
//toggle send UDP direct notifications
pos = req.indexOf("SN=");
if (pos > 0) notifyDirect = (req.charAt(pos+3) != '0');
//toggle receive UDP direct notifications
pos = req.indexOf("RN=");
if (pos > 0) receiveNotifications = (req.charAt(pos+3) != '0');
@@ -532,7 +537,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
//receive live data via UDP/Hyperion
pos = req.indexOf("RD=");
if (pos > 0) receiveDirect = (req.charAt(pos+3) != '0');
//toggle nightlight mode
bool aNlDef = false;
if (req.indexOf("&ND") > 0) aNlDef = true;
@@ -553,14 +558,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
nightlightActive = true;
nightlightStartTime = millis();
}
//set nightlight target brightness
pos = req.indexOf("NT=");
if (pos > 0) {
nightlightTargetBri = getNumVal(&req, pos);
nightlightActiveOld = false; //re-init
}
//toggle nightlight fade
pos = req.indexOf("NF=");
if (pos > 0)
@@ -578,7 +583,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (auxTime == 0) auxActive = false;
}
#endif
pos = req.indexOf("TT=");
if (pos > 0) transitionDelay = getNumVal(&req, pos);
@@ -597,7 +602,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
//Segment reverse
pos = req.indexOf("RV=");
if (pos > 0) strip.getSegment(0).setOption(1, req.charAt(pos+3) != '0');
//deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri) nightlightActive = false;
//set time (unix timestamp)
@@ -605,18 +610,18 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (pos > 0) {
setTime(getNumVal(&req, pos));
}
//set countdown goal (unix timestamp)
pos = req.indexOf("CT=");
if (pos > 0) {
countdownTime = getNumVal(&req, pos);
if (countdownTime - now() > 0) countdownOverTriggered = false;
}
//set presets
pos = req.indexOf("P1="); //sets first preset for cycle
if (pos > 0) presetCycleMin = getNumVal(&req, pos);
pos = req.indexOf("P2="); //sets last preset for cycle
if (pos > 0) presetCycleMax = getNumVal(&req, pos);
@@ -627,7 +632,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
presetCyclingEnabled = (req.charAt(pos+3) != '0');
presetCycCurr = presetCycleMin;
}
pos = req.indexOf("PT="); //sets cycle time in ms
if (pos > 0) {
int v = getNumVal(&req, pos);
@@ -638,11 +643,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (pos > 0) presetApplyBri = (req.charAt(pos+3) != '0');
pos = req.indexOf("PC="); //apply color from preset
if (pos > 0) presetApplyCol = (req.charAt(pos+3) != '0');
if (pos > 0) presetApplyCol = (req.charAt(pos+3) != '0');
pos = req.indexOf("PX="); //apply effects from preset
if (pos > 0) presetApplyFx = (req.charAt(pos+3) != '0');
pos = req.indexOf("PS="); //saves current in preset
if (pos > 0) savePreset(getNumVal(&req, pos));
@@ -650,7 +655,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
if (updateVal(&req, "PL=", &presetCycCurr, presetCycleMin, presetCycleMax)) {
applyPreset(presetCycCurr, presetApplyBri, presetApplyCol, presetApplyFx);
}
//cronixie
#ifndef WLED_DISABLE_CRONIXIE
pos = req.indexOf("NX="); //sets digits to code
@@ -658,7 +663,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
strcpy(cronixieDisplay,req.substring(pos + 3, pos + 9).c_str());
setCronixie();
}
if (req.indexOf("NB=") > 0) //sets backlight
{
cronixieBacklight = true;
@@ -673,24 +678,24 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
//mode, 1 countdown
pos = req.indexOf("NM=");
if (pos > 0) countdownMode = (req.charAt(pos+3) != '0');
pos = req.indexOf("U0="); //user var 0
if (pos > 0) {
userVar0 = getNumVal(&req, pos);
}
pos = req.indexOf("U1="); //user var 1
if (pos > 0) {
userVar1 = getNumVal(&req, pos);
}
//you can add more if you need
//internal call, does not send XML response
pos = req.indexOf("IN");
if (pos < 1) XML_response(request, (req.indexOf("&IT") > 0)); //include theme if firstload
pos = req.indexOf("&NN"); //do not send UDP notifications this time
colorUpdated((pos > 0) ? 5:1);
return true;
}

View File

@@ -3,13 +3,13 @@
*/
void wledInit()
{
{
EEPROM.begin(EEPSIZE);
ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00);
if (ledCount > 1200 || ledCount == 0) ledCount = 30;
ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00);
if (ledCount > MAX_LEDS || ledCount == 0) ledCount = 30;
#ifndef ARDUINO_ARCH_ESP32
#if LEDPIN == 3
if (ledCount > 300) ledCount = 300; //DMA method uses too much ram
if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram
#endif
#endif
Serial.begin(115200);
@@ -24,7 +24,7 @@ void wledInit()
int heapPreAlloc = ESP.getFreeHeap();
DEBUG_PRINT("heap ");
DEBUG_PRINTLN(ESP.getFreeHeap());
strip.init(EEPROM.read(372),ledCount,EEPROM.read(2204)); //init LEDs quickly
DEBUG_PRINT("LEDs inited. heap usage ~");
@@ -36,125 +36,68 @@ void wledInit()
#endif
SPIFFS.begin();
#endif
DEBUG_PRINTLN("Load EEPROM");
loadSettingsFromEEPROM(true);
beginStrip();
DEBUG_PRINT("CSSID: ");
DEBUG_PRINT(clientSSID);
userBeginPreConnection();
userSetup();
if (strcmp(clientSSID,"Your_Network") == 0) showWelcomePage = true;
WiFi.persistent(false);
initCon();
DEBUG_PRINTLN("");
DEBUG_PRINT("Connected! IP address: ");
DEBUG_PRINTLN(WiFi.localIP());
if (macroBoot>0) applyMacro(macroBoot);
Serial.println("Ada");
if (hueIP[0] == 0)
{
hueIP[0] = WiFi.localIP()[0];
hueIP[1] = WiFi.localIP()[1];
hueIP[2] = WiFi.localIP()[2];
}
if (udpPort > 0 && udpPort != ntpLocalPort)
{
udpConnected = notifierUdp.begin(udpPort);
if (udpConnected && udpRgbPort != udpPort) udpRgbConnected = rgbUdp.begin(udpRgbPort);
}
if (ntpEnabled && WiFi.status() == WL_CONNECTED)
ntpConnected = ntpUdp.begin(ntpLocalPort);
//start captive portal if AP active
if (onlyAP || strlen(apSSID) > 0)
{
dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
dnsServer.start(53, "wled.me", WiFi.softAPIP());
dnsActive = true;
}
prepareIds(); //UUID from MAC (for Alexa and MQTT)
//generate module IDs
escapedMac = WiFi.macAddress();
escapedMac.replace(":", "");
escapedMac.toLowerCase();
if (strcmp(cmDNS,"x") == 0) //fill in unique mdns default
{
strcpy(cmDNS, "wled-");
strcat(cmDNS, escapedMac.c_str());
sprintf(cmDNS+5, "%*s", 6, escapedMac.c_str()+6);
}
if (mqttDeviceTopic[0] == 0)
{
strcpy(mqttDeviceTopic, "wled/");
strcat(mqttDeviceTopic, escapedMac.c_str());
sprintf(mqttDeviceTopic+5, "%*s", 6, escapedMac.c_str()+6);
}
//smartInit, we only init some resources when connected
if (!onlyAP && WiFi.status() == WL_CONNECTED)
if (mqttClientID[0] == 0)
{
mqtt = new AsyncMqttClient();
initMqtt();
strcpy(mqttClientID, "WLED-");
sprintf(mqttClientID+5, "%*s", 6, escapedMac.c_str()+6);
}
strip.service();
//HTTP server page init
initServer();
strip.service();
//init Alexa hue emulation
if (alexaEnabled && !onlyAP) alexaInit();
server.begin();
DEBUG_PRINTLN("HTTP server started");
//init ArduinoOTA
if (!onlyAP) {
#ifndef WLED_DISABLE_OTA
#ifndef WLED_DISABLE_OTA
if (aOtaEnabled)
{
ArduinoOTA.onStart([]() {
#ifndef ARDUINO_ARCH_ESP32
#ifdef ESP8266
wifi_set_sleep_type(NONE_SLEEP_T);
#endif
DEBUG_PRINTLN("Start ArduinoOTA");
});
if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS);
ArduinoOTA.begin();
}
#endif
#endif
strip.service();
// Set up mDNS responder:
if (strlen(cmDNS) > 0 && !onlyAP)
{
MDNS.begin(cmDNS);
DEBUG_PRINTLN("mDNS responder started");
// Add service to MDNS
MDNS.addService("http", "tcp", 80);
MDNS.addService("wled", "tcp", 80);
}
strip.service();
//HTTP server page init
initServer();
initBlynk(blynkApiKey);
initE131();
reconnectHue();
} else {
e131Enabled = false;
}
strip.service();
userBegin();
if (macroBoot>0) applyMacro(macroBoot);
Serial.println("Ada");
initConnection();
}
void beginStrip()
{
// Initialize NeoPixel Strip and button
strip.setReverseMode(reverseMode);
strip.setColor(0);
strip.setBrightness(255);
#ifdef BTNPIN
pinMode(BTNPIN, INPUT_PULLUP);
#endif
if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true);
colorUpdated(0);
@@ -170,19 +113,41 @@ void beginStrip()
#endif
//disable button if it is "pressed" unintentionally
#ifdef BTNPIN
if(digitalRead(BTNPIN) == LOW) buttonEnabled = false;
#else
buttonEnabled = false;
#endif
}
void initAP(){
bool set = apSSID[0];
if (!set) strcpy(apSSID,"WLED-AP");
void initAP(bool resetAP=false){
if (apBehavior == 3 && !resetAP) return;
if (!apSSID[0] || resetAP) strcpy(apSSID, "WLED-AP");
if (resetAP) strcpy(apPass,"wled1234");
DEBUG_PRINT("Opening access point ");
DEBUG_PRINTLN(apSSID);
WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255,255,255,0));
WiFi.softAP(apSSID, apPass, apChannel, apHide);
if (!set) apSSID[0] = 0;
if (!apActive) //start captive portal if AP active
{
DEBUG_PRINTLN("Init AP interfaces");
server.begin();
if (udpPort > 0 && udpPort != ntpLocalPort)
{
udpConnected = notifierUdp.begin(udpPort);
if (udpConnected && udpRgbPort != udpPort) udpRgbConnected = rgbUdp.begin(udpRgbPort);
}
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(53, "*", WiFi.softAPIP());
}
apActive = true;
}
void initCon()
void initConnection()
{
WiFi.disconnect(); //close old connections
@@ -194,48 +159,135 @@ void initCon()
WiFi.config(0U, 0U, 0U);
}
if (strlen(apSSID)>0)
lastReconnectAttempt = millis();
if (!WLED_WIFI_CONFIGURED)
{
DEBUG_PRINT(" USING AP");
DEBUG_PRINTLN(strlen(apSSID));
initAP();
} else
{
DEBUG_PRINTLN(" NO AP");
WiFi.softAPdisconnect(true);
DEBUG_PRINT("No connection configured. ");
if (!apActive) initAP(); //instantly go to ap mode
return;
} else if (!apActive) {
if (apBehavior == 2)
{
initAP();
} else
{
DEBUG_PRINTLN("Access point disabled.");
WiFi.softAPdisconnect(true);
}
}
int fail_count = 0;
if (strlen(clientSSID) <1 || strcmp(clientSSID,"Your_Network") == 0)
fail_count = apWaitTimeSecs*2; //instantly go to ap mode
#ifndef ARDUINO_ARCH_ESP32
showWelcomePage = false;
DEBUG_PRINT("Connecting to ");
DEBUG_PRINT(clientSSID);
DEBUG_PRINTLN("...");
#ifdef ESP8266
WiFi.hostname(serverDescription);
#endif
WiFi.begin(clientSSID, clientPass);
#ifdef ARDUINO_ARCH_ESP32
WiFi.setHostname(serverDescription);
#endif
unsigned long lastTry = 0;
bool con = false;
while(!con)
}
void initInterfaces() {
DEBUG_PRINTLN("Init STA interfaces");
if (hueIP[0] == 0)
{
yield();
handleTransitions();
handleButton();
handleOverlays();
if (briT) strip.service();
if (millis()-lastTry > 499) {
con = (WiFi.status() == WL_CONNECTED);
lastTry = millis();
DEBUG_PRINTLN("C_NC");
if (!recoveryAPDisabled && fail_count > apWaitTimeSecs*2)
{
WiFi.disconnect();
DEBUG_PRINTLN("Can't connect. Opening AP...");
onlyAP = true;
initAP();
return;
}
fail_count++;
hueIP[0] = WiFi.localIP()[0];
hueIP[1] = WiFi.localIP()[1];
hueIP[2] = WiFi.localIP()[2];
}
//init Alexa hue emulation
if (alexaEnabled) alexaInit();
#ifndef WLED_DISABLE_OTA
if (aOtaEnabled) ArduinoOTA.begin();
#endif
strip.service();
// Set up mDNS responder:
if (strlen(cmDNS) > 0)
{
if (!aOtaEnabled) MDNS.begin(cmDNS);
DEBUG_PRINTLN("mDNS started");
MDNS.addService("http", "tcp", 80);
MDNS.addService("wled", "tcp", 80);
}
server.begin();
if (udpPort > 0 && udpPort != ntpLocalPort)
{
udpConnected = notifierUdp.begin(udpPort);
if (udpConnected && udpRgbPort != udpPort) udpRgbConnected = rgbUdp.begin(udpRgbPort);
}
if (ntpEnabled && WLED_CONNECTED)
ntpConnected = ntpUdp.begin(ntpLocalPort);
initBlynk(blynkApiKey);
initE131();
reconnectHue();
initMqtt();
interfacesInited = true;
wasConnected = true;
}
byte stacO = 0;
void handleConnection() {
//TODO: reconnect if heap <8000
byte stac = 0;
#ifdef ESP8266
stac = wifi_softap_get_station_num();
#else
wifi_sta_list_t stationList;
esp_wifi_ap_get_sta_list(&stationList);
stac = stationList.num;
#endif
if (stac != stacO)
{
stacO = stac;
DEBUG_PRINT("Connected AP clients: ");
DEBUG_PRINTLN(stac);
if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) { //trying to connect, but not connected
if (stac) WiFi.disconnect(); //disable search so that AP can work
else initConnection(); //restart search
}
}
if (forceReconnect) {
DEBUG_PRINTLN("Forcing reconnect.");
initConnection();
interfacesInited = false;
forceReconnect = false;
wasConnected = false;
return;
}
if (!WLED_CONNECTED) {
if (interfacesInited) {
DEBUG_PRINTLN("Disconnected!");
interfacesInited = false;
initConnection();
}
if (millis() - lastReconnectAttempt > 300000 && WLED_WIFI_CONFIGURED) initConnection();
if (!apActive && millis() - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == 1)) initAP();
} else if (!interfacesInited) { //newly connected
DEBUG_PRINTLN("");
DEBUG_PRINT("Connected! IP address: ");
DEBUG_PRINTLN(WiFi.localIP());
initInterfaces();
userConnected();
//shut down AP
if (apBehavior != 2 && apActive)
{
dnsServer.stop();
WiFi.softAPdisconnect(true);
apActive = false;
DEBUG_PRINTLN("Access point disabled.");
}
}
}
@@ -247,5 +299,6 @@ bool checkClientIsMobile(String useragent)
if (useragent.indexOf("Android") >= 0) return true;
if (useragent.indexOf("iPhone") >= 0) return true;
if (useragent.indexOf("iPod") >= 0) return true;
if (useragent.indexOf("iPad") >= 0) return true;
return false;
}

View File

@@ -7,16 +7,19 @@
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
void userBeginPreConnection()
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup()
{
}
void userBegin()
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
void userConnected()
{
}
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
void userLoop()
{

View File

@@ -2,7 +2,7 @@
* UDP notifier
*/
#define WLEDPACKETSIZE 24
#define WLEDPACKETSIZE 29
#define UDP_IN_MAXSIZE 1472
@@ -34,7 +34,11 @@ void notify(byte callMode, bool followUp=false)
udpOut[8] = effectCurrent;
udpOut[9] = effectSpeed;
udpOut[10] = col[3];
udpOut[11] = 5; //compatibilityVersionByte: 0: old 1: supports white 2: supports secondary color 3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//compatibilityVersionByte:
//0: old 1: supports white 2: supports secondary color
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color
udpOut[11] = 6;
udpOut[12] = colSec[0];
udpOut[13] = colSec[1];
udpOut[14] = colSec[2];
@@ -43,6 +47,16 @@ void notify(byte callMode, bool followUp=false)
udpOut[17] = (transitionDelay >> 0) & 0xFF;
udpOut[18] = (transitionDelay >> 8) & 0xFF;
udpOut[19] = effectPalette;
/*udpOut[20] = colTer[0];
udpOut[21] = colTer[1];
udpOut[22] = colTer[2];
udpOut[23] = colTer[3];*/
udpOut[24] = followUp;
uint32_t t = millis() + strip.timebase;
udpOut[25] = (t >> 24) & 0xFF;
udpOut[26] = (t >> 16) & 0xFF;
udpOut[27] = (t >> 8) & 0xFF;
udpOut[28] = (t >> 0) & 0xFF;
IPAddress broadcastIp;
broadcastIp = ~uint32_t(WiFi.subnetMask()) | uint32_t(WiFi.gatewayIP());
@@ -64,17 +78,18 @@ void arlsLock(uint32_t timeoutMs)
strip.setPixelColor(i,0,0,0,0);
}
strip.unlockAll();
realtimeActive = true;
}
realtimeActive = true;
realtimeTimeout = millis() + timeoutMs;
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
if (arlsForceMaxBri) strip.setBrightness(255);
}
void initE131(){
if (WiFi.status() == WL_CONNECTED && e131Enabled)
if (WLED_CONNECTED && e131Enabled)
{
e131 = new E131();
if (e131 == nullptr) e131 = new E131();
e131->begin((e131Multicast) ? E131_MULTICAST : E131_UNICAST , e131Universe);
} else {
e131Enabled = false;
@@ -84,7 +99,7 @@ void initE131(){
void handleE131(){
//E1.31 protocol support
if(e131Enabled) {
if(WLED_CONNECTED && e131Enabled) {
uint16_t len = e131->parsePacket();
if (!len || e131->universe < e131Universe || e131->universe > e131Universe +4) return;
len /= 3; //one LED is 3 DMX channels
@@ -159,6 +174,9 @@ void handleNotifications()
//wled notifier, block if realtime packets active
if (udpIn[0] == 0 && !realtimeActive && receiveNotifications)
{
//ignore notification if received within a second after sending a notification ourselves
if (millis() - notificationSentTime < 1000) return;
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
//apply colors from notification
if (receiveNotificationColor || !someSel)
@@ -176,11 +194,25 @@ void handleNotifications()
colSec[2] = udpIn[14];
colSec[3] = udpIn[15];
}
if (udpIn[11] > 5)
{
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
t -= 2;
t -= millis();
strip.timebase = t;
}
/*if (udpIn[11] > 6)
{
colTer[0] = udpIn[20];
colTer[1] = udpIn[21];
colTer[2] = udpIn[22];
colSec[3] = udpIn[23];
}*/
}
}
//apply effects from notification
if (receiveNotificationEffects || !someSel)
if (udpIn[11] < 200 && (receiveNotificationEffects || !someSel))
{
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
effectSpeed = udpIn[9];
@@ -206,10 +238,10 @@ void handleNotifications()
if (packetSize > 1) {
if (udpIn[1] == 0)
{
realtimeActive = false;
realtimeTimeout = 0;
return;
} else {
arlsLock(udpIn[1]*1000);
arlsLock(udpIn[1]*1000 +1);
}
if (udpIn[0] == 1) //warls
{
@@ -257,9 +289,9 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
uint16_t pix = i + arlsOffset;
if (pix < ledCount)
{
if (!arlsDisableGammaCorrection && useGammaCorrectionRGB)
if (!arlsDisableGammaCorrection && strip.gammaCorrectCol)
{
strip.setPixelColor(pix, gamma8[r], gamma8[g], gamma8[b], gamma8[w]);
strip.setPixelColor(pix, strip.gamma8(r), strip.gamma8(g), strip.gamma8(b), strip.gamma8(w));
} else {
strip.setPixelColor(pix, r, g, b, w);
}

View File

@@ -21,12 +21,7 @@ void setAllLeds() {
double d = briT*briMultiplier;
int val = d/100;
if (val > 255) val = 255;
if (useGammaCorrectionBri)
{
strip.setBrightness(gamma8[val]);
} else {
strip.setBrightness(val);
}
strip.setBrightness(val);
}
if (!enableSecTransition)
{
@@ -40,14 +35,8 @@ void setAllLeds() {
colorRGBtoRGBW(colT);
colorRGBtoRGBW(colSecT);
}
if (useGammaCorrectionRGB)
{
strip.setColor(gamma8[colT[0]], gamma8[colT[1]], gamma8[colT[2]], gamma8[colT[3]]);
strip.setSecondaryColor(gamma8[colSecT[0]], gamma8[colSecT[1]], gamma8[colSecT[2]], gamma8[colSecT[3]]);
} else {
strip.setColor(colT[0], colT[1], colT[2], colT[3]);
strip.setSecondaryColor(colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
}
strip.setColor(0, colT[0], colT[1], colT[2], colT[3]);
strip.setColor(1, colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
}
@@ -87,11 +76,16 @@ void colorUpdated(int callMode)
{
if (nightlightActive && !nightlightActiveOld && callMode != 3 && callMode != 5)
{
notify(4); return;
notify(4); interfaceUpdateCallMode = 4; return;
}
else if (fxChanged) {
notify(6);
if (callMode != 8) interfaceUpdateCallMode = 6;
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
}
else if (fxChanged) notify(6);
return; //no change
}
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
if (callMode != 5 && nightlightActive && nightlightFade)
{
briNlT = bri;
@@ -134,13 +128,8 @@ void colorUpdated(int callMode)
}
if (callMode == 8) return;
//only update Blynk and mqtt every 2 seconds to reduce lag
if (millis() - lastInterfaceUpdate <= 2000)
{
interfaceUpdateCallMode = callMode;
return;
}
updateInterfaces(callMode);
//set flag to update blynk and mqtt
interfaceUpdateCallMode = callMode;
}
@@ -153,7 +142,7 @@ void updateInterfaces(uint8_t callMode)
}
#endif
if (callMode != 9 && callMode != 5) updateBlynk();
publishMqtt();
doPublishMqtt = true;
lastInterfaceUpdate = millis();
}
@@ -166,6 +155,7 @@ void handleTransitions()
updateInterfaces(interfaceUpdateCallMode);
interfaceUpdateCallMode = 0; //disable
}
if (doPublishMqtt) publishMqtt();
if (transitionActive && transitionDelayTemp > 0)
{

View File

@@ -16,12 +16,24 @@ void shortPressAction()
void handleButton()
{
#ifdef BTNPIN
if (!buttonEnabled) return;
if (digitalRead(BTNPIN) == LOW && !buttonPressedBefore) //pressed
if (digitalRead(BTNPIN) == LOW) //pressed
{
buttonPressedTime = millis();
if (!buttonPressedBefore) buttonPressedTime = millis();
buttonPressedBefore = true;
if (millis() - buttonPressedTime > 600) //long press
{
if (!buttonLongPressed)
{
if (macroLongPress) {applyMacro(macroLongPress);}
else _setRandomColor(false,true);
buttonLongPressed = true;
}
}
}
else if (digitalRead(BTNPIN) == HIGH && buttonPressedBefore) //released
{
@@ -30,13 +42,11 @@ void handleButton()
bool doublePress = buttonWaitTime;
buttonWaitTime = 0;
if (dur > 6000) {initAP();}
else if (dur > 600) //long press
if (dur > 6000) //long press
{
if (macroLongPress) {applyMacro(macroLongPress);}
else _setRandomColor(false,true);
initAP(true);
}
else { //short press
else if (!buttonLongPressed) { //short press
if (macroDoublePress)
{
if (doublePress) applyMacro(macroDoublePress);
@@ -44,6 +54,7 @@ void handleButton()
} else shortPressAction();
}
buttonPressedBefore = false;
buttonLongPressed = false;
}
if (buttonWaitTime && millis() - buttonWaitTime > 450 && !buttonPressedBefore)
@@ -51,6 +62,7 @@ void handleButton()
buttonWaitTime = 0;
shortPressAction();
}
#endif
}
void handleIO()

View File

@@ -56,7 +56,7 @@ Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern
void handleNetworkTime()
{
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WiFi.status() == WL_CONNECTED)
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WLED_CONNECTED)
{
if (millis() - ntpPacketSentTime > 10000)
{

View File

@@ -5,18 +5,13 @@
* https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch
* https://github.com/probonopd/ESP8266HueEmulator
*/
void prepareIds() {
escapedMac = WiFi.macAddress();
escapedMac.replace(":", "");
escapedMac.toLowerCase();
}
#ifndef WLED_DISABLE_ALEXA
void onAlexaChange(EspalexaDevice* dev);
void alexaInit()
{
if (alexaEnabled && WiFi.status() == WL_CONNECTED)
if (alexaEnabled && WLED_CONNECTED)
{
if (espalexaDevice == nullptr) //only init once
{
@@ -31,7 +26,7 @@ void alexaInit()
void handleAlexa()
{
if (!alexaEnabled || WiFi.status() != WL_CONNECTED) return;
if (!alexaEnabled || !WLED_CONNECTED) return;
espalexa.loop();
}

View File

@@ -4,17 +4,6 @@
#ifndef WLED_DISABLE_HUESYNC
void handleHue()
{
if (hueClient != nullptr && millis() - hueLastRequestSent > huePollIntervalMs && WiFi.status() == WL_CONNECTED)
{
hueLastRequestSent = millis();
if (huePollingEnabled)
{
reconnectHue();
} else {
hueClient->close();
if (hueError[0] == 'A') strcpy(hueError,"Inactive");
}
}
if (hueReceived)
{
colorUpdated(7); hueReceived = false;
@@ -25,11 +14,22 @@ void handleHue()
hueNewKey = false;
}
}
if (!WLED_CONNECTED || hueClient == nullptr || millis() - hueLastRequestSent < huePollIntervalMs) return;
hueLastRequestSent = millis();
if (huePollingEnabled)
{
reconnectHue();
} else {
hueClient->close();
if (hueError[0] == 'A') strcpy(hueError,"Inactive");
}
}
void reconnectHue()
{
if (WiFi.status() != WL_CONNECTED || !huePollingEnabled) return;
if (!WLED_CONNECTED || !huePollingEnabled) return;
DEBUG_PRINTLN("Hue reconnect");
if (hueClient == nullptr) {
hueClient = new AsyncClient();
@@ -87,16 +87,16 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
if (str == nullptr) return;
str += 4;
StaticJsonBuffer<512> jb;
StaticJsonDocument<512> root;
if (str[0] == '[') //is JSON array
{
JsonArray& root = jb.parseArray(str);
if (!root.success())
auto error = deserializeJson(root, str);
if (error)
{
strcpy(hueError,"JSON parsing error"); return;
}
int hueErrorCode = root[0]["error"]["type"];
if (hueErrorCode)//hue bridge returned error
{
switch (hueErrorCode)
@@ -130,8 +130,8 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
if (str == nullptr) return;
str = strstr(str,"{");
JsonObject& root = jb.parseObject(str);
if (!root.success())
auto error = deserializeJson(root, str);
if (error)
{
strcpy(hueError,"JSON parsing error"); return;
}

View File

@@ -8,7 +8,7 @@ byte blSat = 255;
void initBlynk(const char* auth)
{
#ifndef WLED_DISABLE_BLYNK
if (WiFi.status() != WL_CONNECTED) return;
if (!WLED_CONNECTED) return;
blynkEnabled = (auth[0] != 0);
if (blynkEnabled) Blynk.config(auth);
#endif
@@ -17,7 +17,7 @@ void initBlynk(const char* auth)
void handleBlynk()
{
#ifndef WLED_DISABLE_BLYNK
if (WiFi.status() == WL_CONNECTED && blynkEnabled)
if (WLED_CONNECTED && blynkEnabled)
Blynk.run();
#endif
}
@@ -25,7 +25,7 @@ void handleBlynk()
void updateBlynk()
{
#ifndef WLED_DISABLE_BLYNK
if (onlyAP) return;
if (!WLED_CONNECTED) return;
Blynk.virtualWrite(V0, bri);
//we need a RGB -> HSB convert here
Blynk.virtualWrite(V3, bri? 1:0);

View File

@@ -2,12 +2,10 @@
* MQTT communication protocol for home automation
*/
#define WLED_MQTT_PORT 1883
void parseMQTTBriPayload(char* payload)
{
if (strcmp(payload, "ON") == 0 || strcmp(payload, "on") == 0) {bri = briLast; colorUpdated(1);}
else if (strcmp(payload, "T" ) == 0 || strcmp(payload, "t" ) == 0) {toggleOnOff(); colorUpdated(1);}
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; colorUpdated(1);}
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); colorUpdated(1);}
else {
uint8_t in = strtoul(payload, NULL, 10);
if (in == 0 && bri > 0) briLast = bri;
@@ -22,7 +20,7 @@ void onMqttConnect(bool sessionPresent)
//(re)subscribe to required topics
char subuf[38];
strcpy(subuf, mqttDeviceTopic);
if (mqttDeviceTopic[0] != 0)
{
strcpy(subuf, mqttDeviceTopic);
@@ -45,16 +43,15 @@ void onMqttConnect(bool sessionPresent)
mqtt->subscribe(subuf, 0);
}
#ifdef WLED_ENABLE_HOMEASSISTANT_AUTODISCOVERY
sendHADiscoveryMQTT();
#endif
publishMqtt();
doSendHADiscovery = true;
doPublishMqtt = true;
DEBUG_PRINTLN("MQTT ready");
}
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
DEBUG_PRINT("MQTT callb rec: ");
DEBUG_PRINT("MQTT msg: ");
DEBUG_PRINTLN(topic);
DEBUG_PRINTLN(payload);
@@ -75,19 +72,19 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
void publishMqtt()
{
if (mqtt == NULL) return;
if (!mqtt->connected()) return;
doPublishMqtt = false;
if (mqtt == nullptr || !mqtt->connected()) return;
DEBUG_PRINTLN("Publish MQTT");
char s[10];
char subuf[38];
sprintf(s, "%ld", bri);
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, "/g");
mqtt->publish(subuf, 0, true, s);
sprintf(s, "#%X", col[3]*16777216 + col[0]*65536 + col[1]*256 + col[2]);
sprintf(s, "#%06X", col[3]*16777216 + col[0]*65536 + col[1]*256 + col[2]);
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, "/c");
mqtt->publish(subuf, 0, true, s);
@@ -101,10 +98,15 @@ void publishMqtt()
const char HA_static_JSON[] PROGMEM = R"=====(,"bri_val_tpl":"{{value}}","rgb_cmd_tpl":"{{'#%02x%02x%02x' | format(red, green, blue)}}","rgb_val_tpl":"{{value[1:3]|int(base=16)}},{{value[3:5]|int(base=16)}},{{value[5:7]|int(base=16)}}","qos":0,"opt":true,"pl_on":"ON","pl_off":"OFF","fx_val_tpl":"{{value}}","fx_list":[)=====";
void sendHADiscoveryMQTT(){
char* buffer;
void sendHADiscoveryMQTT()
{
#if ARDUINO_ARCH_ESP32 || LWIP_VERSION_MAJOR > 1
/*
YYYY is discovery tipic
YYYY is device topic
XXXX is device name
Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
@@ -128,14 +130,19 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
"fx_val_tpl":"{{value}}",
"fx_list":[
"[FX=00] Solid",
"[FX=01] Blink",
"[FX=01] Blink",
"[FX=02] ...",
"[FX=79] Ripple"
]
}
*/
char bufc[36], bufcol[38], bufg[36], bufapi[38], buffer[2500];
doSendHADiscovery = false;
if (mqtt == nullptr || !mqtt->connected()) return;
buffer = new char[2400];
if (!buffer) {delete[] buffer; return;}
char bufc[36], bufcol[38], bufg[36], bufapi[38];
strcpy(bufc, mqttDeviceTopic);
strcpy(bufcol, mqttDeviceTopic);
@@ -147,8 +154,7 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
strcat(bufg, "/g");
strcat(bufapi, "/api");
StaticJsonBuffer<JSON_OBJECT_SIZE(9) +512> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
StaticJsonDocument<JSON_OBJECT_SIZE(9) +512> root;
root["name"] = serverDescription;
root["stat_t"] = bufc;
root["cmd_t"] = mqttDeviceTopic;
@@ -159,10 +165,9 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
root["fx_cmd_t"] = bufapi;
root["fx_stat_t"] = bufapi;
size_t jlen = root.measureLength();
char pubt[21 + sizeof(serverDescription) + 8];
DEBUG_PRINTLN(jlen);
root.printTo(buffer, jlen);
size_t jlen = measureJson(root);
//DEBUG_PRINTLN(jlen);
serializeJson(root, buffer, jlen);
//add values which don't change
strcpy_P(buffer + jlen -1, HA_static_JSON);
@@ -180,11 +185,11 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
{
if (pgm_read_byte(JSON_mode_names + j) == '\"' || j == jmnlen -1)
{
if (isNameStart)
if (isNameStart)
{
nameStart = j +1;
}
else
else
{
nameEnd = j;
char mdnfx[64], mdn[56];
@@ -193,11 +198,11 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
mdn[namelen] = 0;
snprintf(mdnfx, 64, "\"[FX=%02d] %s\",", i, mdn);
oappend(mdnfx);
DEBUG_PRINTLN(mdnfx);
//DEBUG_PRINTLN(mdnfx);
i++;
}
isNameStart = !isNameStart;
}
}
}
olen--;
oappend("]}");
@@ -205,28 +210,39 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
DEBUG_PRINT("HA Discovery Sending >>");
DEBUG_PRINTLN(buffer);
strcpy(pubt, "homeassistant/light/WLED_");
strcat(pubt, escapedMac.c_str());
char pubt[25 + 12 + 8];
strcpy(pubt, "homeassistant/light/");
strcat(pubt, mqttClientID);
strcat(pubt, "/config");
mqtt->publish(pubt, 0, true, buffer);
bool success = mqtt->publish(pubt, 0, true, buffer);
DEBUG_PRINTLN(success);
yield();
delete[] buffer;
#endif
}
bool initMqtt()
{
if (WiFi.status() != WL_CONNECTED) return false;
if (mqttServer[0] == 0) return false;
lastMqttReconnectAttempt = millis();
if (mqttServer[0] == 0 || !WLED_CONNECTED) return false;
if (mqtt == nullptr) {
mqtt = new AsyncMqttClient();
mqtt->onMessage(onMqttMessage);
mqtt->onConnect(onMqttConnect);
}
if (mqtt->connected()) return true;
DEBUG_PRINTLN("Reconnecting MQTT");
IPAddress mqttIP;
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
{
mqtt->setServer(mqttIP, WLED_MQTT_PORT);
mqtt->setServer(mqttIP, mqttPort);
} else {
mqtt->setServer(mqttServer, WLED_MQTT_PORT);
mqtt->setServer(mqttServer, mqttPort);
}
mqtt->setClientId(escapedMac.c_str());
mqtt->onMessage(onMqttMessage);
mqtt->onConnect(onMqttConnect);
mqtt->setClientId(mqttClientID);
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
mqtt->connect();
DEBUG_PRINTLN("MQTT ready");
return true;
}

View File

@@ -2,6 +2,34 @@
* Server page definitions
*/
//Is this an IP?
bool isIp(String str) {
for (size_t i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) {
return false;
}
}
return true;
}
bool captivePortal(AsyncWebServerRequest *request)
{
if (ON_STA_FILTER(request)) return false; //only serve captive in AP mode
String hostH;
if (!request->hasHeader("Host")) return false;
hostH = request->getHeader("Host")->value();
if (!isIp(hostH) && hostH.indexOf("wled.me") < 0 && hostH.indexOf(cmDNS) < 0) {
DEBUG_PRINTLN("Captive portal");
AsyncWebServerResponse *response = request->beginResponse(302);
response->addHeader("Location", "http://4.3.2.1");
request->send(response);
return true;
}
return false;
}
void initServer()
{
//CORS compatiblity
@@ -36,8 +64,8 @@ void initServer()
server.on("/settings/wifi", HTTP_POST, [](AsyncWebServerRequest *request){
if (!(wifiLock && otaLock)) handleSettingsSet(request, 1);
serveMessage(request, 200,"WiFi settings saved.","Rebooting now...",255);
doReboot = true;
serveMessage(request, 200,"WiFi settings saved.","Reconnecting now...",255);
forceReconnect = true;
});
server.on("/settings/leds", HTTP_POST, [](AsyncWebServerRequest *request){
@@ -70,10 +98,9 @@ void initServer()
serveJson(request);
});
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/json", [](AsyncWebServerRequest *request, JsonVariant &json) {
JsonObject& root = json.as<JsonObject>();
if (!root.success()){request->send(500, "application/json", "{\"error\":\"Parsing failed\"}"); return;}
deserializeState(root);
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/json", [](AsyncWebServerRequest *request, JsonObject root) {
if (root.isNull()){request->send(500, "application/json", "{\"error\":\"Parsing failed\"}"); return;}
if (deserializeState(root)) { serveJson(request); return; } //if JSON contains "v" (verbose response)
request->send(200, "application/json", "{\"success\":true}");
});
server.addHandler(handler);
@@ -162,6 +189,7 @@ void initServer()
}
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
if (captivePortal(request)) return;
serveIndexOrWelcome(request);
});
@@ -169,6 +197,7 @@ void initServer()
server.onNotFound([](AsyncWebServerRequest *request){
DEBUG_PRINTLN("Not-Found HTTP call:");
DEBUG_PRINTLN("URI: " + request->url());
if (captivePortal(request)) return;
//make API CORS compatible
if (request->method() == HTTP_OPTIONS)
@@ -305,7 +334,7 @@ String settingsProcessor(const String& var)
getCSSColors();
return String(buf);
}
if (var == "SCSS") return String(PAGE_settingsCss);
if (var == "SCSS") return String(FPSTR(PAGE_settingsCss));
return String();
}
@@ -343,7 +372,7 @@ void serveSettings(AsyncWebServerRequest* request)
case 4: request->send_P(200, "text/html", PAGE_settings_sync, settingsProcessor); break;
case 5: request->send_P(200, "text/html", PAGE_settings_time, settingsProcessor); break;
case 6: request->send_P(200, "text/html", PAGE_settings_sec , settingsProcessor); break;
case 255: request->send_P(200, "text/html", PAGE_welcome , settingsProcessor); break;
case 255: request->send_P(200, "text/html", PAGE_welcome); break;
default: request->send_P(200, "text/html", PAGE_settings , settingsProcessor);
}
}

View File

@@ -2,8 +2,10 @@
* JSON API (De)serialization
*/
void deserializeState(JsonObject& root)
bool deserializeState(JsonObject root)
{
bool stateResponse = root["v"] | false;
bri = root["bri"] | bri;
bool on = root["on"] | (bri > 0);
@@ -21,76 +23,114 @@ void deserializeState(JsonObject& root)
int cy = root["pl"] | -1;
presetCyclingEnabled = (cy >= 0);
JsonObject& nl = root["nl"];
JsonObject nl = root["nl"];
nightlightActive = nl["on"] | nightlightActive;
nightlightDelayMins = nl["dur"] | nightlightDelayMins;
nightlightFade = nl["fade"] | nightlightFade;
nightlightTargetBri = nl["tbri"] | nightlightTargetBri;
JsonObject& udpn = root["udpn"];
JsonObject udpn = root["udpn"];
notifyDirect = udpn["send"] | notifyDirect;
receiveNotifications = udpn["recv"] | receiveNotifications;
bool noNotification = udpn["nn"]; //send no notification just for this request
int timein = root["time"] | -1;
if (timein != -1) setTime(timein);
int it = 0;
JsonArray& segs = root["seg"];
for (JsonObject& elem : segs)
JsonArray segs = root["seg"];
for (JsonObject elem : segs)
{
byte id = elem["id"] | it;
if (id < strip.getMaxSegments())
{
WS2812FX::Segment& seg = strip.getSegment(id);
/*uint16_t start = elem["start"] | seg.start;
uint16_t start = elem["start"] | seg.start;
int stop = elem["stop"] | -1;
if (stop < 0) {
uint16_t len = elem["len"];
stop = (len > 0) ? start + len : seg.stop;
}
strip.setSegment(id, start, stop);*/
strip.setSegment(id, start, stop);
JsonArray& colarr = elem["col"];
if (colarr.success())
JsonArray colarr = elem["col"];
if (!colarr.isNull())
{
for (uint8_t i = 0; i < 3; i++)
{
JsonArray& colX = colarr[i];
if (!colX.success()) break;
JsonArray colX = colarr[i];
if (colX.isNull()) break;
byte sz = colX.size();
if (sz > 0 && sz < 5)
{
int rgbw[] = {0,0,0,0};
byte cp = colX.copyTo(rgbw);
byte cp = copyArray(colX, rgbw);
seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0;
//temporary
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
if (id == 0) //temporary
{
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
}
}
}
}
byte fx = elem["fx"] | seg.mode;
if (fx != seg.mode && fx < strip.getModeCount()) strip.setMode(fx);
if (fx != seg.mode && fx < strip.getModeCount()) strip.setMode(id, fx);
seg.speed = elem["sx"] | seg.speed;
seg.intensity = elem["ix"] | seg.intensity;
byte pal = elem["pal"] | seg.palette;
if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
seg.setOption(0, elem["sel"] | seg.getOption(0));
seg.setOption(1, elem["rev"] | seg.getOption(1));
seg.palette = elem["pal"] | seg.palette;
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
seg.setOption(0, elem["sel"] | seg.getOption(0)); //selected
seg.setOption(1, elem["rev"] | seg.getOption(1)); //reverse
//int cln = seg_0["cln"];
//temporary
effectCurrent = seg.mode;
effectSpeed = seg.speed;
effectIntensity = seg.intensity;
effectPalette = seg.palette;
if (id == 0) {
effectCurrent = seg.mode;
effectSpeed = seg.speed;
effectIntensity = seg.intensity;
effectPalette = seg.palette;
}
}
it++;
}
colorUpdated(noNotification ? 5:1);
return stateResponse;
}
void serializeState(JsonObject& root)
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
{
root["id"] = id;
root["start"] = seg.start;
root["stop"] = seg.stop;
root["len"] = seg.stop - seg.start;
JsonArray colarr = root.createNestedArray("col");
for (uint8_t i = 0; i < 3; i++)
{
JsonArray colX = colarr.createNestedArray();
colX.add((seg.colors[i] >> 16) & 0xFF);
colX.add((seg.colors[i] >> 8) & 0xFF);
colX.add((seg.colors[i]) & 0xFF);
if (useRGBW)
colX.add((seg.colors[i] >> 24) & 0xFF);
}
root["fx"] = seg.mode;
root["sx"] = seg.speed;
root["ix"] = seg.intensity;
root["pal"] = seg.palette;
root["sel"] = seg.isSelected();
root["rev"] = seg.getOption(1);
root["cln"] = -1;
}
void serializeState(JsonObject root)
{
root["on"] = (bri > 0);
root["bri"] = briLast;
@@ -99,66 +139,37 @@ void serializeState(JsonObject& root)
root["ps"] = -1; //
root["pl"] = (presetCyclingEnabled) ? 0: -1;
JsonObject& nl = root.createNestedObject("nl");
JsonObject nl = root.createNestedObject("nl");
nl["on"] = nightlightActive;
nl["dur"] = nightlightDelayMins;
nl["fade"] = nightlightFade;
nl["tbri"] = nightlightTargetBri;
JsonObject& udpn = root.createNestedObject("udpn");
JsonObject udpn = root.createNestedObject("udpn");
udpn["send"] = notifyDirect;
udpn["recv"] = receiveNotifications;
JsonArray& seg = root.createNestedArray("seg");
JsonObject& seg0 = seg.createNestedObject();
serializeSegment(seg0);
}
void serializeSegment(JsonObject& root)
{
WS2812FX::Segment seg = strip.getSegment(0);
//root["id"] = i;
root["start"] = seg.start;
root["stop"] = seg.stop;
root["len"] = seg.stop - seg.start;
JsonArray& colarr = root.createNestedArray("col");
//temporary
JsonArray& c0 = colarr.createNestedArray();
c0.add(col[0]); c0.add(col[1]); c0.add(col[2]); if (useRGBW) c0.add(col[3]);
JsonArray& c1 = colarr.createNestedArray();
c1.add(colSec[0]); c1.add(colSec[1]); c1.add(colSec[2]); if (useRGBW) c1.add(colSec[3]);
//set i back to 0 once temporary is removed!
for (uint8_t i = 2; i < 3; i++)
JsonArray seg = root.createNestedArray("seg");
for (byte s = 0; s < strip.getMaxSegments(); s++)
{
JsonArray& colX = colarr.createNestedArray();
colX.add((seg.colors[i] >> 16) & 0xFF);
colX.add((seg.colors[i] >> 8) & 0xFF);
colX.add((seg.colors[i] ) & 0xFF);
if (useRGBW)
colX.add((seg.colors[i] >> 24) & 0xFF);
WS2812FX::Segment sg = strip.getSegment(s);
if (sg.isActive())
{
JsonObject seg0 = seg.createNestedObject();
serializeSegment(seg0, sg, s);
}
}
root["fx"] = seg.mode;
root["sx"] = seg.speed;
root["ix"] = seg.intensity;
root["pal"] = seg.palette;
root["sel"] = true; //seg.getOption(0);
root["rev"] = seg.getOption(1);
root["cln"] = -1;
}
void serializeInfo(JsonObject& root)
void serializeInfo(JsonObject root)
{
root["ver"] = versionString;
root["vid"] = VERSION;
JsonObject& leds = root.createNestedObject("leds");
JsonObject leds = root.createNestedObject("leds");
leds["count"] = ledCount;
leds["rgbw"] = useRGBW;
JsonArray& leds_pin = leds.createNestedArray("pin");
JsonArray leds_pin = leds.createNestedArray("pin");
leds_pin.add(LEDPIN);
leds["pwr"] = strip.currentMilliamps;
@@ -235,7 +246,7 @@ void serveJson(AsyncWebServerRequest* request)
}
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject& doc = response->getRoot();
JsonObject doc = response->getRoot();
switch (subJson)
{
@@ -244,12 +255,12 @@ void serveJson(AsyncWebServerRequest* request)
case 2: //info
serializeInfo(doc); break;
default: //all
JsonObject& state = doc.createNestedObject("state");
JsonObject state = doc.createNestedObject("state");
serializeState(state);
JsonObject& info = doc.createNestedObject("info");
JsonObject info = doc.createNestedObject("info");
serializeInfo(info);
doc["effects"] = RawJson(String(JSON_mode_names));
doc["palettes"] = RawJson(String(JSON_palette_names));
doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names);
doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names);
}
response->setLength();