Compare commits

...

79 Commits

Author SHA1 Message Date
cschwinne
a371239172 Fixed mobile UI effect list not loading 2019-02-12 14:50:19 +01:00
cschwinne
4fd904fbcc Merge branch 'master' of https://github.com/Aircoookie/WLED.git 2019-02-12 11:05:00 +01:00
cschwinne
b73a257389 Fixed broadcast IP compilation issue 2019-02-12 11:03:54 +01:00
Aircoookie
9e70d6b3e1 Merge pull request #105 from Aircoookie/development
Release of v0.8.3
2019-02-11 23:53:53 +01:00
cschwinne
9caca37ab1 Release of v0.8.3
Removed initLedsLast
Improved Fireworks
2019-02-11 23:49:04 +01:00
cschwinne
6e76fc0aa7 Added JSON FX + palette lists 2019-02-10 23:05:06 +01:00
cschwinne
6171883758 Split up WS2812FX.cpp in FX and helper files 2019-02-09 16:37:20 +01:00
cschwinne
942b68c948 Added shields.io to readme 2019-02-09 15:41:55 +01:00
cschwinne
9ca7ffa5a3 Refactored white to col[3]
Added Saw effect
2019-02-05 21:53:39 +01:00
cschwinne
d1ce23c5ac Unique mDNS name
Various optimizations
2019-02-05 19:40:24 +01:00
cschwinne
b7b6d0a6bc Improved ripple effect 2019-02-02 23:59:48 +01:00
cschwinne
10c51eea2c Added Ripple and revamped twinkle effects 2019-01-31 23:42:48 +01:00
cschwinne
48d20c02a1 Added timed macro weekday support 2019-01-31 00:09:44 +01:00
cschwinne
c5cc0b3f2b Updated Mobile UI
Fixed Smooth Meteor stuck pixels
Added CORS response
Added secondary color to http API response
2019-01-18 01:20:36 +01:00
cschwinne
6ebef8846c Merge branch 'development' of https://github.com/Aircoookie/WLED.git into development 2019-01-09 23:03:34 +01:00
cschwinne
5d1993935e Added Alexa Color support 2019-01-09 22:55:18 +01:00
Aircoookie
caab8943cb Merge pull request #90 from cboltz/cboltz-timezone-deps
Use time/time.h from local dependencies
2018-12-20 21:17:42 +01:00
Christian Boltz
f5c05b24fb Use time/time.h from local dependencies
This fixes a compile issue, which can be
a) file not found or
b) (after installing the Time library) redefinition of a variable
2018-12-17 22:07:43 +01:00
Aircoookie
940a0d006d Merge pull request #89 from definitio/master
Fix compiling on a case sensitive filesystems
2018-12-17 15:41:24 +01:00
definitio
8fe67a04d8 Fix compiling on a case sensitive file systems 2018-12-17 18:08:59 +04:00
cschwinne
bec745d095 Improved colortwinkles on longer strips
Added offMode
2018-12-16 20:38:00 +01:00
Aircoookie
223fd35138 Merge pull request #84 from Aircoookie/development
Updated platformio.ini for v0.8.2
2018-12-06 16:32:52 +01:00
cschwinne
d3fc0309c0 Updated platformio.ini for v0.8.2 2018-12-06 16:31:52 +01:00
Aircoookie
830223f6e2 Merge pull request #83 from Aircoookie/development
Fixed incorrect #defines for 0.8.2
2018-12-06 00:43:32 +01:00
cschwinne
eb53c52499 Fixed incorrect #defines for 0.8.2 2018-12-06 00:40:59 +01:00
Aircoookie
96c9e2b4d6 Merge pull request #82 from Aircoookie/development
Updated readme
2018-12-06 00:31:39 +01:00
cschwinne
c34b948bad Updated readme 2018-12-06 00:30:38 +01:00
Aircoookie
9ac609f846 Release of v0.8.2 (merge)
Release of v0.8.2 (PR)
2018-12-06 00:30:05 +01:00
cschwinne
6aa47bfd1b Release of v0.8.2
Improved settings page scaling on mobile devices
Added 2 new effects to web UIs
2018-12-06 00:27:36 +01:00
cschwinne
ff46e6ea86 Added Auto Brightness Limiter and power calculation 2018-12-04 00:58:06 +01:00
cschwinne
5489c74986 Added Smooth meteor and Railway effects 2018-12-02 02:49:05 +01:00
cschwinne
f6f8151150 Added meteor FX to web UI 2018-11-29 21:46:05 +01:00
cschwinne
a20d577f6c WS2812b Color Order changeable in settings
Meteor effect can now use palettes
2018-11-28 12:24:32 +01:00
cschwinne
c4c2494dd1 Improved binary size 2018-11-25 00:00:02 +01:00
cschwinne
c9c294a1d5 Merge branch 'development' of https://github.com/Aircoookie/WLED.git into development 2018-11-24 11:52:44 +01:00
cschwinne
6359a8a8a2 Improved effect updating internals 2018-11-24 11:52:23 +01:00
Aircoookie
f9b44381bd Merge pull request #77 from viknet365/master
add meteor effect
2018-11-23 00:21:07 +01:00
Aircoookie
eb1ccb600b Delete htmls00.h
0.8.2 will use the new gzip system with different files. HTML changes will be manually added
2018-11-23 00:20:26 +01:00
cschwinne
b2db61aa03 Merge branch 'development' of https://github.com/Aircoookie/WLED.git into development 2018-11-23 00:16:25 +01:00
cschwinne
ee55a574de Moved About section to Github wiki
Updated readme
2018-11-23 00:11:47 +01:00
cschwinne
0998fd32cd Moved About section to Github wiki 2018-11-23 00:03:44 +01:00
cschwinne
686f2c4aa6 IR codes will now also be printed without debug enabled 2018-11-22 22:43:44 +01:00
cschwinne
cd234673ea Fixed nightlight issues
Added custom infrared method
2018-11-22 00:09:30 +01:00
cschwinne
54d7a81f16 Incomplete commit for Nightlight Fixes
Interim state (Reason: Local Working Copy Data Corruption)
Affected files: (local changes will be re-implemented in next commit)
settings_sync.html (already recovered)
html_settings.h (already recovered)
wled03_set.ino
wled08_led.ino
wled09_button.ino
wled19_ir.ino
2018-11-21 23:28:20 +01:00
viknet365
9d8d2c0aa1 add meteor effect
This reverts commit f1371d6737.
2018-11-20 21:31:07 +01:00
viknet365
17ce6b9507 Revert "Add files via upload"
This reverts commit f1371d6737.
2018-11-20 21:09:06 +01:00
viknet365
296065a976 Revert "add meteor effect"
This reverts commit 0b0f600f97.
2018-11-20 20:59:13 +01:00
viknet365
0b0f600f97 add meteor effect 2018-11-20 20:42:47 +01:00
viknet365
f1371d6737 Add files via upload
add meteor effect
2018-11-20 20:35:04 +01:00
viknet365
03a33790e1 Update WS2812FX.cpp 2018-11-20 20:32:21 +01:00
cschwinne
c0816c80ae Infrared support added 2018-11-18 00:31:45 +01:00
cschwinne
071ebe6ef2 Gzipped UIs, improving speed and flash usage 2018-11-16 19:59:00 +01:00
Aircoookie
2126e42743 Merge pull request #74 from wiesendaniel/feature/pio-port
Added Plattform IO Support
2018-11-16 19:50:19 +01:00
Daniel Wiesendorf
8a2b34adb4 moved ws2812fx sources back 2018-11-16 15:02:09 +01:00
Daniel Wiesendorf
93eb4d21bf Added PIO recommendation when opening in vscode 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
868cedeed2 pio support for esp01 512k 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
5c794f428a added verbose flag to travisci.yml for debugging 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
612d6f85bd Pio support of esp32 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
e5cef6b877 fixed DEBUG constant for travis build 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
f2a63c04a8 fixed travisci build again... 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
5a5064e070 fixed travisci build 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
478fa3132c Minor fixes for PIO support 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
a84859c211 Changed platformio.ini. A few boards are building now 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
67013bd58f Changed platformio.ini. A few boards are building now 2018-11-14 22:07:04 +01:00
Daniel Wiesendorf
b51be31d8a added initial PlatformIO config. still needs work 2018-11-14 22:07:04 +01:00
Aircoookie
a3bef49124 Refactored code to improve readability (merge dev PR)
Refactored code to improve readability
Fixed non-2-char indentations
2018-11-09 17:02:58 +01:00
cschwinne
a5cf553f17 Refactored code to improve readability
Fixed non-2-char indentations
2018-11-09 17:00:36 +01:00
Aircoookie
640188f4e2 Merge pull request #68 from Aircoookie/development
Release of v0.8.0
2018-11-07 20:23:01 +01:00
cschwinne
48265bbe02 Release of WLED 0.8.1
Added Lake effect
2018-11-07 20:22:05 +01:00
cschwinne
6aaf544079 Auto-select pixel driving method based on LEDPIN 2018-11-05 02:24:13 +01:00
cschwinne
9904c10984 Added Colortwinkle effect 74 2018-11-04 20:14:23 +01:00
cschwinne
81c810eba4 Increased max. UDP leds from 341 to 490
MQTT now publishes state on connect
2018-11-01 16:16:38 +01:00
cschwinne
5e6b1e8175 Added defines for more granular feature disable control 2018-11-01 15:36:13 +01:00
cschwinne
48c165b0b4 Added support for E1.31 with more than 170 LEDs 2018-11-01 01:05:35 +01:00
cschwinne
042605701e Added DNRGB UDP protocol 2018-10-27 11:39:00 +02:00
cschwinne
32cf1495d3 Fixed tricolor chase modes
Added a new palette
2018-10-25 20:55:29 +02:00
cschwinne
9577e49231 Added Palette support for most effects
Fixed Analog Clock bugs
Added Tiamat palette
2018-10-24 02:06:07 +02:00
cschwinne
de19839145 Fixed overlay not unlocking on disable 2018-10-18 18:31:25 +02:00
cschwinne
f970780d6c Fixed Clock overlay not working in reverse mode
Removed need for Macros to start with capital letter
2018-10-18 18:06:46 +02:00
53 changed files with 6636 additions and 3250 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.pio
.pioenvs
.piolibdeps
.vscode
!.vscode/extensions.json

35
.travis.yml Normal file
View File

@@ -0,0 +1,35 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
language: python
python:
- "2.7"
sudo: false
cache:
directories:
- "~/.platformio"
env:
- PLATFORMIO_CI_SRC=wled00
install:
- pip install -U platformio
- platformio update
script:
- platformio ci --project-conf=./platformio.ini -v

7
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

39
include/README Normal file
View File

@@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

126
platformio.ini Normal file
View File

@@ -0,0 +1,126 @@
; PlatformIO Project Configuration File
; Please visit documentation: https://docs.platformio.org/page/projectconf.html
[platformio]
src_dir = ./wled00
data_dir = ./wled00/data
lib_extra_dirs = ./wled00/src
env_default = nodemcuv2
; env_default = esp01
; env_default = esp01_1m
; env_default = d1_mini
; env_default = esp32dev
[common]
framework = arduino
monitor_speed = 115200
board_build.flash_mode = dout
upload_speed = 921600
build_flags =
; -D VERSION=0.8.2
; -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
#E131@1.0.0
#webserver
FastLED@3.2.1
NeoPixelBus@2.4.1
#PubSubClient@2.7
#Time@1.5
#Timezone@1.2.1
#WS2812FX@1.1.2
[common:esp8266]
platform = espressif8266@1.8.0
build_flags =
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
[common:esp8266_512k]
platform = espressif8266@1.7.0
build_flags =
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
; -D WLED_DISABLE_MOBILE_UI
-D WLED_DISABLE_OTA
-D WLED_DISABLE_ALEXA
; -D WLED_DISABLE_BLYNK
; -D WLED_DISABLE_CRONIXIE
-D WLED_DISABLE_HUESYNC
-D WLED_DISABLE_INFRARED
[common:esp32]
platform = espressif32@1.5.0
build_flags =
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
-D ARDUINO_ARCH_ESP32
-D WORKAROUND_ESP32_BITBANG
# see: http://docs.platformio.org/en/latest/platforms/espressif8266.html
[env:nodemcuv2]
board = nodemcuv2
platform = ${common:esp8266.platform}
monitor_speed = ${common.monitor_speed}
upload_speed = ${common.upload_speed}
framework = ${common.framework}
build_flags =
${common.build_flags}
${common:esp8266.build_flags}
lib_deps =
${common.lib_deps_external}
IRremoteESP8266@2.5.3
[env:d1_mini]
board = d1_mini
platform = ${common:esp8266.platform}
monitor_speed = ${common.monitor_speed}
upload_speed = ${common.upload_speed}
framework = ${common.framework}
build_flags =
${common.build_flags}
${common:esp8266.build_flags}
lib_deps =
${common.lib_deps_external}
IRremoteESP8266@2.5.3
[env:esp01_1m]
board = esp01_1m
platform = ${common:esp8266.platform}
monitor_speed = ${common.monitor_speed}
upload_speed = ${common.upload_speed}
framework = ${common.framework}
build_flags =
${common.build_flags}
${common:esp8266.build_flags}
# disable IR because there is no pin for it
-D WLED_DISABLE_INFRARED
lib_deps =
${common.lib_deps_external}
[env:esp01]
board = esp01
platform = ${common:esp8266_512k.platform}
monitor_speed = ${common.monitor_speed}
upload_speed = ${common.upload_speed}
framework = ${common.framework}
build_flags =
${common.build_flags}
${common:esp8266_512k.build_flags}
lib_deps =
${common.lib_deps_external}
# see: http://docs.platformio.org/en/latest/platforms/espressif32.html
[env:esp32dev]
board = esp32dev
platform = ${common:esp32.platform}
monitor_speed = ${common.monitor_speed}
upload_speed = ${common.upload_speed}
framework = ${common.framework}
build_flags =
${common.build_flags}
${common:esp32.build_flags}
lib_deps =
${common.lib_deps_external}

View File

@@ -1,11 +1,16 @@
![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/development/wled_logo.png)
![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/master/wled_logo.png)
## Welcome to my project WLED! (v0.8.0)
[![](https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square)](https://github.com/Aircoookie/WLED/releases)
[![](https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square)](https://discord.gg/KuqP7NE)
[![](https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square)](https://github.com/Aircoookie/WLED/wiki)
[![](https://img.shields.io/badge/app-wled-blue.svg?style=flat-square)](https://github.com/Aircoookie/WLED-App)
## Welcome to my project WLED!
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs!
### Features:
- WS2812FX library integrated for over 70 special effects
- 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
@@ -16,18 +21,21 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
- 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 request API
- Blynk IoT
- MQTT
- E1.31
- Hyperion
- UDP realtime
- Alexa smart device (including dimming)
- 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:
@@ -37,16 +45,10 @@ See the [wiki](https://github.com/Aircoookie/WLED/wiki)!
### Other
Licensed under the MIT license
Credits in About page!
Credits [here](https://github.com/Aircoookie/WLED/wiki/Contributors-&-About)!
Uses Linearicons by Perxis!
Join the Discord [server](https://discord.gg/KuqP7NE) to discuss everything about WLED!
You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com).
If you insist that you just love WLED too much, you can [send me a gift](https://paypal.me/aircoookie)!
If WLED really brightens up your every day, you can [![](https://img.shields.io/badge/send%20me%20a%20small%20gift-paypal-blue.svg?style=flat-square)](https://paypal.me/aircoookie)

11
test/README Normal file
View File

@@ -0,0 +1,11 @@
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html

View File

@@ -5,32 +5,39 @@
//#define WORKAROUND_ESP32_BITBANG
//see https://github.com/Aircoookie/WLED/issues/2 for flicker free ESP32 support
#define LEDPIN 2 //strip pin. Only effective for ESP32, ESP8266 must use gpio2
//PIN CONFIGURATION
#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 is recommended for ESP8266
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
#define IR_PIN 4 //infrared pin.
#define AUXPIN 15 //unused auxiliary output pin
//uncomment this if red and green are swapped
//#define SWAPRG
//automatically uses the right driver method for each platform
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
#define PIXELMETHOD NeoEsp32BitBangWs2813Method
#else
#define PIXELMETHOD NeoEsp32RmtWS2813_V3Method
#endif
#ifdef WORKAROUND_ESP32_BITBANG
#define PIXELMETHOD NeoEsp32BitBangWs2813Method
#pragma message "Software BitBang is used because of your NeoPixelBus version. Look in NpbWrapper.h for instructions on how to mitigate flickering."
#else
#define PIXELMETHOD NeoWs2813Method
#endif
#else //esp8266
//you may change to DMA method on pin GPIO3 here
#define PIXELMETHOD NeoEsp8266Uart800KbpsMethod
//#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod
//autoselect the right method depending on strip pin
#if LEDPIN == 2
#define PIXELMETHOD NeoEsp8266UartWs2813Method //if you get an error here, try to change to NeoEsp8266Uart1Ws2813Method or use Neopixelbus v2.3.5
#elif LEDPIN == 3
#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod
#else
#define PIXELMETHOD NeoEsp8266BitBang800KbpsMethod
#pragma message "Software BitBang will be used because of your selected LED pin. This may cause flicker. Use GPIO 2 or 3 for best results."
#endif
#endif
//handle swapping Red and Green automatically
#ifdef SWAPRG
#define PIXELFEATURE3 NeoRgbFeature
#define PIXELFEATURE4 NeoRgbwFeature
#else
//you can now change the color order in the web settings
#define PIXELFEATURE3 NeoGrbFeature
#define PIXELFEATURE4 NeoGrbwFeature
#endif
#include <NeoPixelBrightnessBus.h>
@@ -46,10 +53,10 @@ class NeoPixelWrapper
{
public:
NeoPixelWrapper() :
// initialize each member to null
_pGrb(NULL),
_pGrbw(NULL),
_type(NeoPixelType_None)
// initialize each member to null
_pGrb(NULL),
_pGrbw(NULL),
_type(NeoPixelType_None)
{
}
@@ -64,8 +71,8 @@ public:
cleanup();
_type = type;
switch (_type) {
switch (_type)
{
case NeoPixelType_Grb:
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, LEDPIN);
_pGrb->Begin();
@@ -81,23 +88,25 @@ public:
void Show()
{
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
delay(1);
portDISABLE_INTERRUPTS(); //this is a workaround to prevent flickering (see https://github.com/adafruit/Adafruit_NeoPixel/issues/139)
#endif
#ifdef WORKAROUND_ESP32_BITBANG
delay(1);
portDISABLE_INTERRUPTS(); //this is a workaround to prevent flickering (see https://github.com/adafruit/Adafruit_NeoPixel/issues/139)
#endif
#endif
switch (_type) {
switch (_type)
{
case NeoPixelType_Grb: _pGrb->Show(); break;
case NeoPixelType_Grbw: _pGrbw->Show(); break;
}
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
portENABLE_INTERRUPTS();
#endif
#ifdef WORKAROUND_ESP32_BITBANG
portENABLE_INTERRUPTS();
#endif
#endif
}
bool CanShow() const
{
switch (_type) {
@@ -106,65 +115,65 @@ public:
}
}
void SetPixelColor(uint16_t indexPixel, RgbColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, color); break;
case NeoPixelType_Grbw:_pGrbw->SetPixelColor(indexPixel, color); break;
}
void SetPixelColor(uint16_t indexPixel, RgbColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, color); break;
case NeoPixelType_Grbw:_pGrbw->SetPixelColor(indexPixel, color); break;
}
}
void SetPixelColor(uint16_t indexPixel, RgbwColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B)); break;
case NeoPixelType_Grbw: _pGrbw->SetPixelColor(indexPixel, color); break;
}
void SetPixelColor(uint16_t indexPixel, RgbwColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B)); break;
case NeoPixelType_Grbw: _pGrbw->SetPixelColor(indexPixel, color); break;
}
}
void SetBrightness(byte b)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetBrightness(b); break;
case NeoPixelType_Grbw:_pGrbw->SetBrightness(b); break;
}
void SetBrightness(byte b)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetBrightness(b); break;
case NeoPixelType_Grbw:_pGrbw->SetBrightness(b); break;
}
}
RgbColor GetPixelColor(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: /*doesn't support it so we don't return it*/ break;
}
return 0;
RgbColor GetPixelColor(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: /*doesn't support it so we don't return it*/ break;
}
return 0;
}
// NOTE: Due to feature differences, some support RGBW but the method name
// here needs to be unique, thus GetPixeColorRgbw
RgbwColor GetPixelColorRgbw(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: return _pGrbw->GetPixelColor(indexPixel); break;
}
return 0;
// NOTE: Due to feature differences, some support RGBW but the method name
// here needs to be unique, thus GetPixeColorRgbw
RgbwColor GetPixelColorRgbw(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: return _pGrbw->GetPixelColor(indexPixel); break;
}
return 0;
}
void ClearTo(RgbColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->ClearTo(color); break;
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
}
void ClearTo(RgbColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->ClearTo(color); break;
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
}
}
void ClearTo(RgbwColor color)
{
switch (_type) {
case NeoPixelType_Grb: break;
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
}
void ClearTo(RgbwColor color)
{
switch (_type) {
case NeoPixelType_Grb: break;
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
}
}
private:
NeoPixelType _type;

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,7 @@
//pixelmethod now in NpbWrapper.h
/*
WS2812FX.h - Library for WS2812 LED effects.
Harm Aldick - 2016
www.aldick.org
FEATURES
* A lot of blinken modes and counting
* WS2812FX can be used as drop-in replacement for Adafruit NeoPixel Library
NOTES
* Uses the Adafruit NeoPixel library. Get it here:
https://github.com/adafruit/Adafruit_NeoPixel
LICENSE
The MIT License (MIT)
Copyright (c) 2016 Harm Aldick
@@ -28,11 +20,7 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
CHANGELOG
2016-05-28 Initial beta release
2016-06-03 Code cleanup, minor improvements, new modes
2016-06-04 2 new fx, fixed setColor (now also resets _mode_color)
2017-02-02 added external trigger functionality (e.g. for sound-to-light)
Modified for WLED
*/
@@ -41,9 +29,12 @@
#include "NpbWrapper.h"
#define DEFAULT_BRIGHTNESS (uint8_t)50
#define FASTLED_INTERNAL //remove annoying pragma messages
#include "FastLED.h"
#define DEFAULT_BRIGHTNESS (uint8_t)127
#define DEFAULT_MODE (uint8_t)0
#define DEFAULT_SPEED (uint16_t)1000
#define DEFAULT_SPEED (uint8_t)128
#define DEFAULT_COLOR (uint32_t)0xFF0000
#define min(a,b) ((a)<(b)?(a):(b))
@@ -82,7 +73,7 @@
#define REVERSE (uint8_t)0x80
#define IS_REVERSE ((SEGMENT.options & REVERSE) == REVERSE)
#define MODE_COUNT 74
#define MODE_COUNT 80
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@@ -100,10 +91,10 @@
#define FX_MODE_THEATER_CHASE 13
#define FX_MODE_THEATER_CHASE_RAINBOW 14
#define FX_MODE_RUNNING_LIGHTS 15
#define FX_MODE_TWINKLE 16
#define FX_MODE_TWINKLE_RANDOM 17
#define FX_MODE_TWINKLE_FADE 18
#define FX_MODE_TWINKLE_FADE_RANDOM 19
#define FX_MODE_SAW 16
#define FX_MODE_TWINKLE 17
#define FX_MODE_DISSOLVE 18
#define FX_MODE_DISSOLVE_RANDOM 19
#define FX_MODE_SPARKLE 20
#define FX_MODE_FLASH_SPARKLE 21
#define FX_MODE_HYPER_SPARKLE 22
@@ -127,7 +118,7 @@
#define FX_MODE_LARSON_SCANNER 40
#define FX_MODE_COMET 41
#define FX_MODE_FIREWORKS 42
#define FX_MODE_FIREWORKS_RANDOM 43
#define FX_MODE_RAIN 43
#define FX_MODE_MERRY_CHRISTMAS 44
#define FX_MODE_FIRE_FLICKER 45
#define FX_MODE_GRADIENT 46
@@ -159,6 +150,13 @@
#define FX_MODE_NOISE16_2 71
#define FX_MODE_NOISE16_3 72
#define FX_MODE_NOISE16_4 73
#define FX_MODE_COLORTWINKLE 74
#define FX_MODE_LAKE 75
#define FX_MODE_METEOR 76
#define FX_MODE_METEOR_SMOOTH 77
#define FX_MODE_RAILWAY 78
#define FX_MODE_RIPPLE 79
class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void);
@@ -201,10 +199,10 @@ class WS2812FX {
_mode[FX_MODE_FADE] = &WS2812FX::mode_fade;
_mode[FX_MODE_THEATER_CHASE] = &WS2812FX::mode_theater_chase;
_mode[FX_MODE_THEATER_CHASE_RAINBOW] = &WS2812FX::mode_theater_chase_rainbow;
_mode[FX_MODE_SAW] = &WS2812FX::mode_saw;
_mode[FX_MODE_TWINKLE] = &WS2812FX::mode_twinkle;
_mode[FX_MODE_TWINKLE_RANDOM] = &WS2812FX::mode_twinkle_random;
_mode[FX_MODE_TWINKLE_FADE] = &WS2812FX::mode_twinkle_fade;
_mode[FX_MODE_TWINKLE_FADE_RANDOM] = &WS2812FX::mode_twinkle_fade_random;
_mode[FX_MODE_DISSOLVE] = &WS2812FX::mode_dissolve;
_mode[FX_MODE_DISSOLVE_RANDOM] = &WS2812FX::mode_dissolve_random;
_mode[FX_MODE_SPARKLE] = &WS2812FX::mode_sparkle;
_mode[FX_MODE_FLASH_SPARKLE] = &WS2812FX::mode_flash_sparkle;
_mode[FX_MODE_HYPER_SPARKLE] = &WS2812FX::mode_hyper_sparkle;
@@ -228,7 +226,7 @@ class WS2812FX {
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
_mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks;
_mode[FX_MODE_FIREWORKS_RANDOM] = &WS2812FX::mode_fireworks_random;
_mode[FX_MODE_RAIN] = &WS2812FX::mode_rain;
_mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas;
_mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker;
_mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient;
@@ -261,19 +259,30 @@ class WS2812FX {
_mode[FX_MODE_NOISE16_2] = &WS2812FX::mode_noise16_2;
_mode[FX_MODE_NOISE16_3] = &WS2812FX::mode_noise16_3;
_mode[FX_MODE_NOISE16_4] = &WS2812FX::mode_noise16_4;
_mode[FX_MODE_COLORTWINKLE] = &WS2812FX::mode_colortwinkle;
_mode[FX_MODE_LAKE] = &WS2812FX::mode_lake;
_mode[FX_MODE_METEOR] = &WS2812FX::mode_meteor;
_mode[FX_MODE_METEOR_SMOOTH] = &WS2812FX::mode_meteor_smooth;
_mode[FX_MODE_RAILWAY] = &WS2812FX::mode_railway;
_mode[FX_MODE_RIPPLE] = &WS2812FX::mode_ripple;
_brightness = DEFAULT_BRIGHTNESS;
_running = false;
_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 = 750;
currentMilliamps = 0;
_locked = NULL;
_modeUsesLock = false;
_cronixieDigits = new byte[6];
bus = new NeoPixelWrapper();
RESET_RUNTIME;
@@ -282,8 +291,7 @@ class WS2812FX {
void
init(bool supportWhite, uint16_t countPixels, bool skipFirst),
service(void),
clear(void),
strip_off(void),
blur(uint8_t),
fade_out(uint8_t r),
setMode(uint8_t m),
setSpeed(uint8_t s),
@@ -316,9 +324,13 @@ class WS2812FX {
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
show(void);
bool
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p);
uint8_t
paletteFade,
paletteBlend,
colorOrder,
getBrightness(void),
getMode(void),
getSpeed(void),
@@ -327,14 +339,11 @@ class WS2812FX {
uint32_t
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),
getPixelColor(uint16_t),
getColor(void);
double
getPowerEstimate(uint16_t leds, uint32_t c, byte b),
getSafePowerMultiplier(double safeMilliAmps, uint16_t leds, uint32_t c, byte b);
WS2812FX::Segment
getSegment(void);
@@ -346,15 +355,18 @@ class WS2812FX {
// mode helper functions
uint16_t
blink(uint32_t, uint32_t, bool strobe),
color_wipe(uint32_t, uint32_t, bool),
theater_chase(uint32_t, uint32_t),
twinkle(uint32_t),
twinkle_fade(uint32_t),
chase(uint32_t, uint32_t, uint32_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),
fireworks(uint32_t),
tricolor_chase(uint32_t, uint32_t, uint32_t);
tricolor_chase(uint32_t, uint32_t);
// builtin modes
uint16_t
@@ -378,10 +390,10 @@ class WS2812FX {
mode_rainbow(void),
mode_rainbow_cycle(void),
mode_running_lights(void),
mode_saw(void),
mode_twinkle(void),
mode_twinkle_random(void),
mode_twinkle_fade(void),
mode_twinkle_fade_random(void),
mode_dissolve(void),
mode_dissolve_random(void),
mode_sparkle(void),
mode_flash_sparkle(void),
mode_hyper_sparkle(void),
@@ -401,7 +413,7 @@ class WS2812FX {
mode_larson_scanner(void),
mode_comet(void),
mode_fireworks(void),
mode_fireworks_random(void),
mode_rain(void),
mode_merry_christmas(void),
mode_halloween(void),
mode_fire_flicker(void),
@@ -416,6 +428,7 @@ class WS2812FX {
mode_tricolor_chase(void),
mode_tricolor_wipe(void),
mode_tricolor_fade(void),
mode_lightning(void),
mode_icu(void),
mode_multi_comet(void),
mode_dual_larson_scanner(void),
@@ -432,22 +445,30 @@ class WS2812FX {
mode_noise16_2(void),
mode_noise16_3(void),
mode_noise16_4(void),
mode_lightning(void);
mode_colortwinkle(void),
mode_lake(void),
mode_meteor(void),
mode_meteor_smooth(void),
mode_railway(void),
mode_ripple(void);
private:
NeoPixelWrapper *bus;
CRGB fastled_from_col(uint32_t);
CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette;
uint16_t _length;
uint16_t _rand16seed;
uint8_t _brightness;
void handle_palette(void);
void fill(uint32_t);
bool modeUsesLock(uint8_t);
double
_cronixieSecMultiplier;
boolean
_running,
bool
_modeUsesLock,
_rgbwMode,
_reverseMode,
_cronixieMode,
@@ -466,11 +487,146 @@ class WS2812FX {
uint8_t _segment_index = 0;
uint8_t _segment_index_palette_last = 99;
uint8_t _num_segments = 1;
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 20 bytes per element
// start, stop, speed, intensity, mode, options, color[]
{ 0, 7, DEFAULT_SPEED, 128, FX_MODE_STATIC, NO_OPTIONS, {DEFAULT_COLOR}}
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, FX_MODE_STATIC, NO_OPTIONS, {DEFAULT_COLOR}}
};
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 17 bytes per element
};
const char JSON_mode_names[] PROGMEM = R"=====({"effects":[
"Solid",
"Blink",
"Breathe",
"Wipe",
"Wipe Random",
"Random Colors",
"Sweep",
"Dynamic",
"Colorloop",
"Rainbow",
"Scan",
"Dual Scan",
"Fade",
"Chase",
"Chase Rainbow",
"Running",
"Saw",
"Twinkle",
"Dissolve",
"Dissolve Rnd",
"Sparkle",
"Dark Sparkle",
"Sparkle+",
"Strobe",
"Strobe Rainbow",
"Mega Strobe",
"Blink Rainbow",
"Android",
"Chase",
"Chase Random",
"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"
]})=====";
const char JSON_palette_names[] PROGMEM = R"=====({"palettes":[
"Default",
"Random Cycle",
"Primary Color",
"Based on Primary",
"Set Colors",
"Based on Set",
"Party",
"Cloud",
"Lava",
"Ocean",
"Forest",
"Rainbow",
"Rainbow Bands",
"Sunset",
"Rivendell",
"Breeze",
"Red & Blue",
"Yellowout",
"Analogous",
"Splash",
"Pastel",
"Sunset 2",
"Beech",
"Vintage",
"Departure",
"Landscape",
"Beach",
"Sherbet",
"Hult",
"Hult 64",
"Drywet",
"Jul",
"Grintage",
"Rewhi",
"Tertiary",
"Fire",
"Icefire",
"Cyane",
"Light Pink",
"Autumn",
"Magenta",
"Magred",
"Yelmag",
"Yelblu",
"Orange & Teal",
"Tiamat",
"April Night"
]})=====";
#endif

717
wled00/WS2812FX_fcn.cpp Normal file
View File

@@ -0,0 +1,717 @@
/*
WS2812FX_fcn.cpp contains all utility functions
Harm Aldick - 2016
www.aldick.org
LICENSE
The MIT License (MIT)
Copyright (c) 2016 Harm Aldick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Modified heavily for WLED
*/
#include "WS2812FX.h"
#include "palettes.h"
#define LED_SKIP_AMOUNT 1
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
{
if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL) return;
RESET_RUNTIME;
_rgbwMode = supportWhite;
_skipFirstMode = skipFirst;
_length = countPixels;
uint8_t ty = 1;
if (supportWhite) ty =2;
uint16_t lengthRaw = _length;
if (_skipFirstMode) lengthRaw += LED_SKIP_AMOUNT;
bus->Begin((NeoPixelType)ty, lengthRaw);
if (_locked != NULL) delete _locked;
_locked = new byte[_length];
_segments[0].start = 0;
_segments[0].stop = _length -1;
unlockAll();
setBrightness(_brightness);
}
void WS2812FX::service() {
unsigned long now = millis(); // Be aware, millis() rolls over every 49 days
bool doShow = false;
for(uint8_t i=0; i < _num_segments; i++)
{
_segment_index = i;
if(now > SEGMENT_RUNTIME.next_time || _triggered)
{
doShow = true;
handle_palette();
uint16_t delay = (this->*_mode[SEGMENT.mode])();
SEGMENT_RUNTIME.next_time = now + max(delay, 5);
SEGMENT_RUNTIME.counter_mode_call++;
}
}
if(doShow) {
show();
}
_triggered = false;
}
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;
return false;
}
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
uint8_t w = (c >> 24) & 0xFF;
uint8_t r = (c >> 16) & 0xFF;
uint8_t g = (c >> 8) & 0xFF;
uint8_t b = c & 0xFF;
setPixelColor(n, r, g, b, w);
}
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 - (i - SEGMENT.start); //reverse just individual segment
byte tmpg = g;
switch (colorOrder) //0 = Grb, default
{
case 0: break; //0 = Grb, default
case 1: g = r; r = tmpg; break; //1 = Rgb, common for WS2811
case 2: g = b; b = tmpg; break; //2 = Brg
case 3: g = b; b = r; r = tmpg; //3 = Rbg
}
if (!_cronixieMode)
{
if (_skipFirstMode)
{
if (i < LED_SKIP_AMOUNT) bus->SetPixelColor(i, RgbwColor(0,0,0,0));
i += LED_SKIP_AMOUNT;
}
bus->SetPixelColor(i, RgbwColor(r,g,b,w));
} else {
if(i>6)return;
byte o = 10*i;
if (_cronixieBacklightEnabled && _cronixieDigits[i] <11)
{
byte r2 = (_segments[0].colors[1] >>16) & 0xFF;
byte g2 = (_segments[0].colors[1] >> 8) & 0xFF;
byte b2 = (_segments[0].colors[1] ) & 0xFF;
byte w2 = (_segments[0].colors[1] >>24) & 0xFF;
for (int j=o; j< o+19; j++)
{
bus->SetPixelColor(j, RgbwColor(r2,g2,b2,w2));
}
} else
{
for (int j=o; j< o+19; j++)
{
bus->SetPixelColor(j, RgbwColor(0,0,0,0));
}
}
if (_skipFirstMode) o += LED_SKIP_AMOUNT;
switch(_cronixieDigits[i])
{
case 0: bus->SetPixelColor(o+5, RgbwColor(r,g,b,w)); break;
case 1: bus->SetPixelColor(o+0, RgbwColor(r,g,b,w)); break;
case 2: bus->SetPixelColor(o+6, RgbwColor(r,g,b,w)); break;
case 3: bus->SetPixelColor(o+1, RgbwColor(r,g,b,w)); break;
case 4: bus->SetPixelColor(o+7, RgbwColor(r,g,b,w)); break;
case 5: bus->SetPixelColor(o+2, RgbwColor(r,g,b,w)); break;
case 6: bus->SetPixelColor(o+8, RgbwColor(r,g,b,w)); break;
case 7: bus->SetPixelColor(o+3, RgbwColor(r,g,b,w)); break;
case 8: bus->SetPixelColor(o+9, RgbwColor(r,g,b,w)); break;
case 9: bus->SetPixelColor(o+4, RgbwColor(r,g,b,w)); break;
}
}
}
void WS2812FX::setReverseMode(bool b)
{
_reverseMode = b;
}
void WS2812FX::driverModeCronixie(bool b)
{
_cronixieMode = b;
_segments[0].stop = (b) ? 5 : _length-1;
}
void WS2812FX::setCronixieBacklight(bool b)
{
_cronixieBacklightEnabled = b;
}
void WS2812FX::setCronixieDigits(byte d[])
{
for (int i = 0; i<6; i++)
{
_cronixieDigits[i] = d[i];
}
}
//DISCLAIMER
//The following function attemps to calculate the current LED power usage,
//and will limit the brightness to stay below a set amperage threshold.
//It is NOT a measurement and NOT guaranteed to stay within the ablMilliampsMax margin.
//Stay safe with high amperage and have a reasonable safety margin!
//I am NOT to be held liable for burned down garages!
//fine tune power estimation constants for your setup
#define PU_PER_MA 3600 //power units per milliamperere for accurate power estimation
//formula: 195075 divided by mA per fully lit LED, here ~54mA)
//lowering the value increases the estimated usage and therefore makes the ABL more aggressive
#define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
void WS2812FX::show(void) {
//power limit calculation
//each LED can draw up 195075 "power units" (approx. 53mA)
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step
//so A=2,R=255,G=0,B=0 would use 510 PU per LED (1mA is about 3700 PU)
if (ablMilliampsMax > 149 && ablMilliampsMax < 65000) //lower numbers and 65000 turn off calculation
{
uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * PU_PER_MA; //100mA for ESP power
if (powerBudget > PU_PER_MA * _length) //each LED uses about 1mA in standby, exclude that from power budget
{
powerBudget -= PU_PER_MA * _length;
} else
{
powerBudget = 0;
}
uint32_t powerSum = 0;
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
{
RgbwColor c = bus->GetPixelColorRgbw(i);
powerSum += (c.R + c.G + c.B + c.W);
}
if (_rgbwMode) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
{
powerSum *= 3;
powerSum >> 2; //same as /= 4
}
uint32_t powerSum0 = powerSum;
powerSum *= _brightness;
if (powerSum > powerBudget) //scale brightness down to stay in current limit
{
float scale = (float)powerBudget / (float)powerSum;
uint16_t scaleI = scale * 255;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
uint8_t newBri = scale8(_brightness, scaleB);
bus->SetBrightness(newBri);
currentMilliamps = (powerSum0 * newBri) / PU_PER_MA;
} else
{
currentMilliamps = powerSum / PU_PER_MA;
bus->SetBrightness(_brightness);
}
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
currentMilliamps += _length; //add standby power back to estimate
} else {
currentMilliamps = 0;
}
bus->Show();
}
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);
}
//TODO transitions
void WS2812FX::setSpeed(uint8_t s) {
_segments[0].speed = s;
}
void WS2812FX::setIntensity(uint8_t in) {
_segments[0].intensity = in;
}
void WS2812FX::setPalette(uint8_t p) {
_segments[0].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;
}
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::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::setBrightness(uint8_t b) {
if (_brightness == b) return;
_brightness = b;
bus->SetBrightness(_brightness);
show();
}
uint8_t WS2812FX::getMode(void) {
return _segments[0].mode;
}
uint8_t WS2812FX::getSpeed(void) {
return _segments[0].speed;
}
uint8_t WS2812FX::getBrightness(void) {
return _brightness;
}
uint8_t WS2812FX::getNumSegments(void) {
return _num_segments;
}
void WS2812FX::setNumSegments(uint8_t n) {
_num_segments = n;
}
uint32_t WS2812FX::getColor(void) {
return _segments[0].colors[0];
}
uint32_t WS2812FX::getPixelColor(uint16_t i)
{
if (_reverseMode) i = _length- 1 -i;
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
if (_cronixieMode)
{
if(i>6)return 0;
byte o = 10*i;
switch(_cronixieDigits[i])
{
case 0: i=o+5; break;
case 1: i=o+0; break;
case 2: i=o+6; break;
case 3: i=o+1; break;
case 4: i=o+7; break;
case 5: i=o+2; break;
case 6: i=o+8; break;
case 7: i=o+3; break;
case 8: i=o+9; break;
case 9: i=o+4; break;
default: return 0;
}
}
RgbwColor lColor = bus->GetPixelColorRgbw(i);
byte r = lColor.R, g = lColor.G, b = lColor.B;
switch (colorOrder)
{
case 0: break; //0 = Grb
case 1: r = lColor.G; g = lColor.R; break; //1 = Rgb, common for WS2811
case 2: g = lColor.B; b = lColor.G; break; //2 = Brg
case 3: r = lColor.B; g = lColor.R; b = lColor.G; //3 = Rbg
}
return ( (lColor.W << 24) | (r << 16) | (g << 8) | (b) );
}
WS2812FX::Segment WS2812FX::getSegment(void) {
return SEGMENT;
}
WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) {
return SEGMENT_RUNTIME;
}
WS2812FX::Segment* WS2812FX::getSegments(void) {
return _segments;
}
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint8_t speed, uint8_t intensity, bool reverse) {
uint32_t colors[] = {color, 0, 0};
setSegment(n, start, stop, mode, colors, speed, intensity, reverse);
}
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, bool reverse) {
setSegment(n, start, stop, mode, colors, speed, intensity, (uint8_t)(reverse ? REVERSE : NO_OPTIONS));
}
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, uint8_t options) {
if(n < (sizeof(_segments) / sizeof(_segments[0]))) {
if(n + 1 > _num_segments) _num_segments = n + 1;
_segments[n].start = start;
_segments[n].stop = stop;
_segments[n].mode = mode;
_segments[n].speed = speed;
_segments[n].intensity = intensity;
_segments[n].options = options;
for(uint8_t i=0; i<NUM_COLORS; i++) {
_segments[n].colors[i] = colors[i];
}
}
}
void WS2812FX::resetSegments() {
memset(_segments, 0, sizeof(_segments));
memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
_segment_index = 0;
_num_segments = 1;
setSegment(0, 0, 7, FX_MODE_STATIC, (const uint32_t[]){DEFAULT_COLOR, 0, 0}, DEFAULT_SPEED, 128, NO_OPTIONS);
}
void WS2812FX::setIndividual(uint16_t i, uint32_t col)
{
if (modeUsesLock(SEGMENT.mode)) return;
if (i >= 0 && i < _length)
{
_locked[i] = false;
setPixelColor(i, col);
_locked[i] = true;
}
}
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
{
if (i2 >= i)
{
for (uint16_t x = i; x <= i2; x++) setIndividual(x,col);
} else
{
for (uint16_t x = i2; x <= i; x++) setIndividual(x,col);
}
}
void WS2812FX::lock(uint16_t i)
{
if (modeUsesLock(SEGMENT.mode)) return;
if (i >= 0 && 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 (i >= 0 && i < _length) _locked[i] = true;
}
}
void WS2812FX::unlock(uint16_t i)
{
if (modeUsesLock(SEGMENT.mode)) return;
if (i >= 0 && i < _length) _locked[i] = false;
}
void WS2812FX::unlockRange(uint16_t i, uint16_t i2)
{
if (modeUsesLock(SEGMENT.mode)) return;
for (uint16_t x = i; x < i2; x++)
{
if (x >= 0 && x < _length) _locked[x] = false;
}
}
void WS2812FX::unlockAll()
{
for (int i=0; i < _length; i++) _locked[i] = false;
}
void WS2812FX::setTransitionMode(bool t)
{
SEGMENT_RUNTIME.trans_act = (t) ? 1:2;
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;
}
/*
* color blend function
*/
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;
int w2 = (color2 >> 24) & 0xff;
int r2 = (color2 >> 16) & 0xff;
int g2 = (color2 >> 8) & 0xff;
int b2 = color2 & 0xff;
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8;
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8;
uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8;
uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8;
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
}
/*
* Fills segment with color
*/
void WS2812FX::fill(uint32_t c) {
for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
setPixelColor(i, c);
}
}
/*
* fade out function, higher rate = quicker fade
*/
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
int w2 = (color >> 24) & 0xff;
int r2 = (color >> 16) & 0xff;
int g2 = (color >> 8) & 0xff;
int b2 = color & 0xff;
for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
color = getPixelColor(i);
int w1 = (color >> 24) & 0xff;
int r1 = (color >> 16) & 0xff;
int g1 = (color >> 8) & 0xff;
int b1 = color & 0xff;
int wdelta = (w2 - w1) / mappedRate;
int rdelta = (r2 - r1) / mappedRate;
int gdelta = (g2 - g1) / mappedRate;
int bdelta = (b2 - b1) / mappedRate;
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
setPixelColor(i, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
}
}
/*
* blurs segment content, source: FastLED colorutils.cpp
*/
void WS2812FX::blur(uint8_t blur_amount)
{
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for(uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++)
{
CRGB cur = fastled_from_col(getPixelColor(i));
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if(i > SEGMENT.start) {
uint32_t c = getPixelColor(i-1);
uint8_t r = (c >> 16 & 0xFF);
uint8_t g = (c >> 8 & 0xFF);
uint8_t b = (c & 0xFF);
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
}
setPixelColor(i,cur.red, cur.green, cur.blue);
carryover = part;
}
}
/*
* Put a value 0 to 255 in to get a color value.
* The colours are a transition r -> g -> b -> back to r
* Inspired by the Adafruit examples.
*/
uint32_t WS2812FX::color_wheel(uint8_t pos) {
if (SEGMENT.palette) return color_from_palette(pos, false, true, 0);
pos = 255 - pos;
if(pos < 85) {
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
} else if(pos < 170) {
pos -= 85;
return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
} else {
pos -= 170;
return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
}
}
/*
* Returns a new, random wheel index with a minimum distance of 42 from pos.
*/
uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) {
uint8_t r = 0, x = 0, y = 0, d = 0;
while(d < 42) {
r = random8();
x = abs(pos - r);
y = 255 - x;
d = min(x, y);
}
return r;
}
CRGB WS2812FX::fastled_from_col(uint32_t color)
{
CRGB fastled_col;
fastled_col.red = (color >> 16 & 0xFF);
fastled_col.green = (color >> 8 & 0xFF);
fastled_col.blue = (color & 0xFF);
return fastled_col;
}
/*
* FastLED palette modes helper function. Limitation: Due to memory reasons, multiple active segments with FastLED will disable the Palette transitions
*/
void WS2812FX::handle_palette(void)
{
bool singleSegmentMode = (_segment_index == _segment_index_palette_last);
_segment_index_palette_last = _segment_index;
byte paletteIndex = SEGMENT.palette;
if ((SEGMENT.mode >= FX_MODE_METEOR) && SEGMENT.palette == 0) paletteIndex = 4;
switch (paletteIndex)
{
case 0: {//default palette. Differs depending on effect
switch (SEGMENT.mode)
{
case FX_MODE_FIRE_2012 : targetPalette = gGradientPalettes[22]; break;//heat palette
case FX_MODE_COLORWAVES : targetPalette = gGradientPalettes[13]; break;//landscape 33
case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p; break;
case FX_MODE_NOISE16_1 : targetPalette = gGradientPalettes[17]; break;//Drywet
case FX_MODE_NOISE16_2 : targetPalette = gGradientPalettes[30]; break;//Blue cyan yellow
case FX_MODE_NOISE16_3 : targetPalette = gGradientPalettes[22]; break;//heat palette
case FX_MODE_NOISE16_4 : targetPalette = gGradientPalettes[13]; break;//landscape 33
default: targetPalette = PartyColors_p; break;//palette, bpm
}
break;}
case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments
if (!singleSegmentMode)
{
targetPalette = PartyColors_p; break; //fallback
}
if (millis() - _lastPaletteChange > 1000 + ((uint32_t)(255-SEGMENT.intensity))*100)
{
targetPalette = CRGBPalette16(
CHSV(random8(), 255, random8(128, 255)),
CHSV(random8(), 255, random8(128, 255)),
CHSV(random8(), 192, random8(128, 255)),
CHSV(random8(), 255, random8(128, 255)));
_lastPaletteChange = millis();
} break;}
case 2: {//primary color only
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
targetPalette = CRGBPalette16(prim); break;}
case 3: {//based on primary
//considering performance implications
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
CHSV prim_hsv = rgb2hsv_approximate(prim);
targetPalette = CRGBPalette16(
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v), //color itself
CHSV(prim_hsv.h, max(prim_hsv.s - 50,0), prim_hsv.v), //less saturated
CHSV(prim_hsv.h, prim_hsv.s, max(prim_hsv.v - 50,0)), //darker
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v)); //color itself
break;}
case 4: {//primary + secondary
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
CRGB sec = fastled_from_col(SEGMENT.colors[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]);
targetPalette = CRGBPalette16(sec,prim,CRGB::White); break;}
case 6: //Party colors
targetPalette = PartyColors_p; break;
case 7: //Cloud colors
targetPalette = CloudColors_p; break;
case 8: //Lava colors
targetPalette = LavaColors_p; break;
case 9: //Ocean colors
targetPalette = OceanColors_p; break;
case 10: //Forest colors
targetPalette = ForestColors_p; break;
case 11: //Rainbow colors
targetPalette = RainbowColors_p; break;
case 12: //Rainbow stripe colors
targetPalette = RainbowStripeColors_p; break;
default: //progmem palettes
targetPalette = gGradientPalettes[constrain(SEGMENT.palette -13, 0, gGradientPaletteCount -1)];
}
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode
{
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
} else
{
currentPalette = targetPalette;
}
}
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
uint8_t paletteIndex = i;
if (mapping) paletteIndex = map(i,SEGMENT.start,SEGMENT.stop,0,255);
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
CRGB fastled_col;
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b;
}

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.0</title>
<title>WLED 0.8.3</title>
<script>
var d=document;
var w=window.getComputedStyle(d.querySelector("html"));
@@ -18,6 +18,9 @@
var nState = 0;
var cv=0;
var lm=0;
var fxi=0;
var fpi=0;
var fxn=1;
aC="";
bC="";
dC="";
@@ -26,17 +29,22 @@
{
return d.getElementById(s);
}
function Startup()
function UCol()
{
var w=window.getComputedStyle(d.querySelector("html"));
aC = w.getPropertyValue("--aCol");
bC = w.getPropertyValue("--bCol");
dC = w.getPropertyValue("--dCol");
d.querySelector("meta[name=theme-color]").setAttribute("content",bC);
}
function Startup()
{
var w=window.getComputedStyle(d.querySelector("html"));
UCol();
CV(0);
setInterval('GIO()', 5000);
setInterval(GIO, 5000);
GIO();
setTimeout(function(){fillfx(0);}, 500);
setTimeout(function(){fillfx(1);}, 750);
}
function GIO()
{
@@ -57,17 +65,29 @@
} else {
uwv = false;
}
Cf.TX.selectedIndex = this.responseXML.getElementsByTagName('fx')[0].childNodes[0].nodeValue;
Cf.FP.selectedIndex = this.responseXML.getElementsByTagName('fp')[0].childNodes[0].nodeValue;
fxi = this.responseXML.getElementsByTagName('fx')[0].childNodes[0].nodeValue;
fpi = this.responseXML.getElementsByTagName('fp')[0].childNodes[0].nodeValue;
d.Cf.SX.value = this.responseXML.getElementsByTagName('sx')[0].childNodes[0].nodeValue;
d.Cf.IX.value = this.responseXML.getElementsByTagName('ix')[0].childNodes[0].nodeValue;
nla = (this.responseXML.getElementsByTagName('nl')[0].innerHTML)!=0?true:false;
if(firstload){
d.Cf.NC.checked = (this.responseXML.getElementsByTagName('nf')[0].innerHTML)!=0?true:false;
d.Cf.SN.value = this.responseXML.getElementsByTagName('nd')[0].childNodes[0].nodeValue;
d.Cf.ST.value = this.responseXML.getElementsByTagName('nt')[0].childNodes[0].nodeValue;
CV(parseInt(this.responseXML.getElementsByTagName('md')[0].childNodes[0].nodeValue));
}firstload=false;
d.Cf.NC.checked = (this.responseXML.getElementsByTagName('nf')[0].innerHTML)!=0?true:false;
d.Cf.SN.value = this.responseXML.getElementsByTagName('nd')[0].childNodes[0].nodeValue;
d.Cf.ST.value = this.responseXML.getElementsByTagName('nt')[0].childNodes[0].nodeValue;
d.documentElement.style.setProperty("--aCol",this.responseXML.getElementsByTagName('ca')[0].childNodes[0].nodeValue);
d.documentElement.style.setProperty("--bCol",this.responseXML.getElementsByTagName('cb')[0].childNodes[0].nodeValue);
d.documentElement.style.setProperty("--cCol",this.responseXML.getElementsByTagName('cc')[0].childNodes[0].nodeValue);
d.documentElement.style.setProperty("--dCol",this.responseXML.getElementsByTagName('cd')[0].childNodes[0].nodeValue);
d.documentElement.style.setProperty("--sCol",this.responseXML.getElementsByTagName('cu')[0].childNodes[0].nodeValue);
d.documentElement.style.setProperty("--tCol",this.responseXML.getElementsByTagName('ct')[0].childNodes[0].nodeValue);
d.documentElement.style.setProperty("--cFn",this.responseXML.getElementsByTagName('cf')[0].childNodes[0].nodeValue);
UCol();
CV(parseInt(this.responseXML.getElementsByTagName('md')[0].childNodes[0].nodeValue));
}else{
Cf.TX.selectedIndex = fxi;
Cf.IX.selectedIndex = fpi;
}
firstload=false;
nState = 0;
nState = (this.responseXML.getElementsByTagName('nr')[0].innerHTML)!=0?1:0;
nState += (this.responseXML.getElementsByTagName('ns')[0].innerHTML)!=0?2:0;
@@ -77,6 +97,7 @@
}
}
}
if (firstload) resp+="&IT"
request.open("GET", "win" +resp +nocache, true);
request.send(null);
resp="";
@@ -172,7 +193,7 @@
case 3: gId("path1").style.fill = aC; gId("path2").style.fill = aC;
}
tgb.style.fill=(Cf.SA.value>0)?aC:dC;
fpX.style.display=(Cf.TX.selectedIndex>64)?"block":"none";
fpX.style.display=(Cf.TX.selectedIndex>0)?"block":"none";
fof.style.fill=(Cf.TX.selectedIndex>64)?aC:dC;
fmr.style.fill=(Cf.TX.selectedIndex<1)?aC:dC;
}
@@ -192,10 +213,10 @@
function SwFX(s)
{
var n=Cf.TX.selectedIndex+s;
if (n==-1||n==74) return;
if (n==-1||n==fxn) return;
Cf.TX.selectedIndex =n;
if (n < 0) Cf.TX.selectedIndex = 0;
if (n > 73) Cf.TX.selectedIndex = 65;
if (n > fxn) Cf.TX.selectedIndex = Math.min(65,fxn-1);
GX();
}
function TgHSB()
@@ -302,7 +323,6 @@
rr=diffc(r);
gg=diffc(g);
bb=diffc(b);
if(r===v) {
h=bb-gg;
}else if (g===v){
@@ -345,6 +365,32 @@
{
resp+="&PL=0";GIO();
}
function fillfx(fp)
{
e="<option>Error loading list!</option>";
el = fp?Cf.FP:Cf.TX;
fetch(fp?'/json/palettes':'/json/effects')
.then(res => {
if (!res.ok) {
el.innerHTML=e;
}
return res.json();
})
.then(json => {
var x="";
var l=fp?json.palettes:json.effects;
for (i in l) {
x += "<option value=\""+i+"\">"+l[i]+" ("+i+")</option>";
}
el.innerHTML=x;
el.selectedIndex=fp?fpi:fxi;
if(!fp)fxn=l.length;
UV();
})
.catch(function () {
el.innerHTML=e;
})
}
</script>
<style>
:root {
@@ -586,80 +632,7 @@
<svg id="fmf" onclick="SwFX(1)"><use xlink:href="#lnr-arrow-right-circle"></use></svg>
<svg id="fof" onclick="SwFX(99)"><use xlink:href="#lnr-rocket"></use></svg><br><br>
<select name="TX" onchange="GX()">
<option value="0" selected>Solid (0)</option>
<option value="1">Blink (1)</option>
<option value="2">Breath (2)</option>
<option value="3">Wipe (3)</option>
<option value="4">Wipe Random (4)</option>
<option value="5">Color R (5)</option>
<option value="6">Sweep (6)</option>
<option value="7">Dynamic (7)</option>
<option value="8">Colorloop (8)</option>
<option value="9">Rainbow (9)</option>
<option value="10">Scan (10)</option>
<option value="11">Scan x2 (11)</option>
<option value="12">Fade (12)</option>
<option value="13">Chase (13)</option>
<option value="14">Chase Cl (14)</option>
<option value="15">Running (15)</option>
<option value="16">Twinkle (16)</option>
<option value="17">Twinkle R (17)</option>
<option value="18">Twinkle Fade (18)</option>
<option value="19">Twinkle RF (19)</option>
<option value="20">Sparkle (20)</option>
<option value="21">Sparkle Inv (21)</option>
<option value="22">Sparkle Inv+ (22)</option>
<option value="23">Strobe (23)</option>
<option value="24">Strobe Cl (24)</option>
<option value="25">Strobe + (25)</option>
<option value="26">Blink Cl (26)</option>
<option value="27">Android (27)</option>
<option value="28">Chase (28)</option>
<option value="29">Chase R (29)</option>
<option value="30">Chase Rainbow (30)</option>
<option value="31">Chase Flash (31)</option>
<option value="32">Chase RF (32)</option>
<option value="33">Chase Cl Inv (33)</option>
<option value="34">Colorful (34)</option>
<option value="35">Traffic Light (35)</option>
<option value="36">Sweep R(36)</option>
<option value="37">Running 2 (37)</option>
<option value="38">Red/Blue (38)</option>
<option value="39">Running R (39)</option>
<option value="40">Scanner (40)</option>
<option value="41">Lighthouse (41)</option>
<option value="42">Fireworks (42)</option>
<option value="43">Fireworks R (43)</option>
<option value="44">Christmas (44)</option>
<option value="45">Fire Flicker (45)</option>
<option value="46">Gradient (46)</option>
<option value="47">Loading (47)</option>
<option value="48">Wipe IO (48)</option>
<option value="49">Wipe II (49)</option>
<option value="50">Wipe OO (50)</option>
<option value="51">Wipe OI (51)</option>
<option value="52">Circus (52)</option>
<option value="53">Halloween (53)</option>
<option value="54">Tricolor Chase (54)</option>
<option value="55">Tricolor Wipe (55)</option>
<option value="56">Tricolor Fade (56)</option>
<option value="57">Lighting (57)</option>
<option value="58">ICU (58)</option>
<option value="59">Multi Comet (59)</option>
<option value="60">Scanner x2 (60)</option>
<option value="61">Random Chase (61)</option>
<option value="62">Oscillate (62)</option>
<option value="63">Pride 2015 (63)</option>
<option value="64">Juggle (64)</option>
<option value="65">Palette (65)</option>
<option value="66">Fire 2012 (66)</option>
<option value="67">Colorwaves (67)</option>
<option value="68">BPM (68)</option>
<option value="69">Fill Noise 8 (69)</option>
<option value="70">Noise 16 1 (70)</option>
<option value="71">Noise 16 2 (71)</option>
<option value="72">Noise 16 3 (72)</option>
<option value="73">Noise 16 4 (73)</option>
<option>Loading...</option>
</select><br><br>
Set secondary color to
<button type="button" onclick="CS(0)">White</button>
@@ -671,51 +644,7 @@
<div id="fpX">
<br>FastLED Palette<br><br>
<select name="FP" onchange="GP()">
<option value="0" selected>Default</option>
<option value="1">Random Cycle</option>
<option value="2">Primary Color Only</option>
<option value="3">Based on Primary</option>
<option value="4">Set Colors Only</option>
<option value="5">Based on Set Colors</option>
<option value="6">Party</option>
<option value="7">Cloud</option>
<option value="8">Lava</option>
<option value="9">Ocean</option>
<option value="10">Forest</option>
<option value="11">Rainbow</option>
<option value="12">Rainbow Stripe</option>
<option value="13">Sunset</option>
<option value="14">Rivendell</option>
<option value="15">Breeze</option>
<option value="16">Red & Blue</option>
<option value="17">Yellowout</option>
<option value="18">Analogous</option>
<option value="19">Splash</option>
<option value="20">Pastel</option>
<option value="21">Sunset2</option>
<option value="22">Beech</option>
<option value="23">Vintage</option>
<option value="24">Departure</option>
<option value="25">Landscape</option>
<option value="26">Beach</option>
<option value="27">Sherbet</option>
<option value="28">Hult</option>
<option value="29">Hult64</option>
<option value="30">Drywet</option>
<option value="31">Jul</option>
<option value="32">Grintage</option>
<option value="33">Rewhi</option>
<option value="34">Tertiary</option>
<option value="35">Fire</option>
<option value="36">Icefire</option>
<option value="37">Cyane</option>
<option value="38">Light Pink</option>
<option value="39">Autumn</option>
<option value="40">Magenta</option>
<option value="41">Magred</option>
<option value="42">Yelmag</option>
<option value="43">Yelblu</option>
<option value="44">Orange & Teal</option>
<option>Loading...</option>
</select>
</div>
<div id="slX" class="sl">
@@ -730,14 +659,14 @@
<svg id="psn" onclick="SwitchPS(1)"><use xlink:href="#lnr-arrow-right-circle"></use></svg>
<svg id="pss" onclick="PSIO(true)"><use xlink:href="#lnr-arrow-down-circle"></use></svg>
<br><input id="psI" name = "FF" type="number" value="1" min="1" max="25" step="1"><br><br>
Click checkmark to apply <input type="checkbox" checked="true" name="BC"> brightness, <input type="checkbox" checked="true" name="CC"> color and <input type="checkbox" checked="true" name="FC"> effects.<br><br>
Click checkmark to apply <input type="checkbox" checked name="CC"> color, <input type="checkbox" checked name="FC"> effects and <input type="checkbox" name="BC"> brightness.<br><br>
Cycle through presets <input id="cy1" name="P1" type="number" value="1" min="1" max="25" step="1"> to <input id="cy2" name="P2" type="number" value="5" min="1" max="25" step="1">, keep each for <input id="cyT" name="PT" type="number" value="1250" min="50" max="65501" step="1">ms: <input type="checkbox" name="CY" onclick="uCY()"><br><br>
<button type="button" onclick="R()">Apply boot config</button><br>
</div>
<div id="tlN" class="tools">
Timed Light<br><br>
<svg id="ntb" onclick="TgNl()"><use xlink:href="#lnr-power-switch"></use></svg><br><br>
Gradually dim down <input type="checkbox" checked="true" name="NC"><br>
Gradually dim down <input type="checkbox" checked name="NC"><br>
1st slider sets duration (1-255min), 2nd sets target brightness.
<div id="slN" class="sl">
<input type="range" title="Duration" class="sds" name="SN" value="60" min="1" max="255" step="1"></div>

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html><head>
<meta content='width=device-width' name='viewport'>
<title>WLED Message</title>
<script>
function B() {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta content='width=device-width' name='viewport'>
<title>WLED Setup</title>
<style>
:root {
@@ -14,9 +15,7 @@
font-family: Verdana, Helvetica, sans-serif;
text-align: center;
background: linear-gradient(var(--bCol),black);
height: 100%;
margin: 0;
background-repeat: no-repeat;
background-attachment: fixed;
color: var(--dCol);
}

658
wled00/html_classic.h Normal file
View File

@@ -0,0 +1,658 @@
/*
* Binary arrays for the classic desktop UI index page.
* gzip is used for smaller size and improved speeds.
*
* Workflow for creating them from HTML source:
* 1. Minify HTML (https://htmlcompressor.com/compressor/) (optional)
* 2. Compress with gzip (https://online-converting.com/archives/convert-to-gzip/)
* 3. Convert gzip binary to c array (https://sourceforge.net/projects/bin2header/)
* alternative: https://littlevgl.com/image-to-c-array (raw)
* 4. update length value
*/
const uint16_t PAGE_index0_L = 10264;
const char PAGE_index0[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x08, 0x67, 0x5e, 0x61, 0x5c, 0x00, 0x03, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65,
0x73, 0x73, 0x65, 0x64, 0x20, 0x28, 0x37, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0xcc, 0x5a,
0xe9, 0x72, 0xdb, 0x46, 0xb6, 0xfe, 0xaf, 0xa7, 0x80, 0xe9, 0x4a, 0x4c, 0x46, 0x04, 0x88, 0x9d,
0x00, 0x29, 0x28, 0x65, 0x2b, 0xde, 0xaa, 0x1c, 0x45, 0x65, 0x69, 0x62, 0xa5, 0x32, 0x29, 0x17,
0x88, 0x85, 0xc4, 0x18, 0x04, 0x68, 0x00, 0xa4, 0xa4, 0x30, 0x7a, 0xf7, 0xf9, 0x4e, 0x77, 0x93,
0x04, 0xa8, 0x8d, 0xf4, 0x64, 0xe6, 0x5e, 0x57, 0x19, 0x40, 0xf7, 0x39, 0xdd, 0x67, 0x5f, 0xba,
0xa9, 0xa3, 0x67, 0x3f, 0xfd, 0x72, 0x72, 0xf1, 0xdb, 0xd9, 0x6b, 0x69, 0x52, 0x4d, 0xd3, 0xe3,
0x23, 0xf1, 0x8c, 0xfc, 0xf0, 0xf8, 0x68, 0x1a, 0x55, 0xbe, 0x14, 0x4c, 0xfc, 0xa2, 0x8c, 0x2a,
0x6f, 0x5e, 0xc5, 0xb2, 0x23, 0xe6, 0x32, 0x7f, 0x1a, 0x79, 0xd5, 0x24, 0x9a, 0x46, 0x72, 0x90,
0xa7, 0x79, 0x21, 0x05, 0x79, 0x56, 0x45, 0x59, 0xe5, 0x3d, 0x8f, 0xe3, 0xf8, 0xf8, 0x28, 0x4d,
0xb2, 0x2f, 0x52, 0x11, 0xa5, 0xde, 0x8b, 0x72, 0x92, 0x17, 0x55, 0x30, 0xaf, 0xa4, 0x04, 0x18,
0x2f, 0xa4, 0xea, 0x66, 0x16, 0x79, 0xc9, 0xd4, 0x1f, 0x47, 0xbd, 0x6b, 0x99, 0xa6, 0xa4, 0x49,
0x11, 0xc5, 0xde, 0x8b, 0x5e, 0xec, 0x2f, 0x68, 0xa8, 0xe0, 0xf1, 0xa2, 0x77, 0x7c, 0x54, 0x25,
0x55, 0x1a, 0x1d, 0x7f, 0xfa, 0xf0, 0xfa, 0x27, 0x49, 0x55, 0x1c, 0xc5, 0x38, 0xea, 0xf1, 0x19,
0xe9, 0xa8, 0x0c, 0x8a, 0x64, 0x56, 0x1d, 0x2f, 0xfc, 0x42, 0x0a, 0xbd, 0x30, 0x0f, 0xe6, 0x53,
0x90, 0x1d, 0xd2, 0xf0, 0xca, 0xbb, 0x4a, 0xb2, 0x30, 0xbf, 0x52, 0xc6, 0x51, 0x75, 0x92, 0x4f,
0x67, 0xf3, 0x2a, 0x0a, 0xcf, 0xab, 0x9b, 0x34, 0x6a, 0x87, 0xca, 0xd7, 0x79, 0x54, 0xdc, 0x9c,
0x47, 0x69, 0x14, 0x54, 0x79, 0xd1, 0x6e, 0x91, 0x8c, 0xad, 0x4e, 0x67, 0x58, 0x44, 0xe5, 0xcc,
0x6b, 0xb5, 0xd8, 0xf2, 0x2c, 0xf5, 0xbd, 0xd8, 0x4f, 0xcb, 0x88, 0x8f, 0x8a, 0xc6, 0xa8, 0xac,
0x8f, 0xca, 0x2a, 0xaf, 0x8d, 0xe6, 0x57, 0x8b, 0x3a, 0x6c, 0x14, 0x7b, 0x55, 0x31, 0xe7, 0x83,
0x38, 0x29, 0xca, 0x2a, 0xcd, 0xfd, 0x70, 0x33, 0x95, 0xfa, 0x65, 0x55, 0x5e, 0x7b, 0x2a, 0xdf,
0xf6, 0xbc, 0xf2, 0xab, 0x48, 0x0c, 0x82, 0x85, 0xf8, 0x48, 0xa7, 0xe2, 0x23, 0xbe, 0x4e, 0x56,
0x5f, 0xb3, 0xf5, 0xd7, 0x75, 0xe6, 0x69, 0x43, 0xff, 0x84, 0xb8, 0x1e, 0xb1, 0x67, 0xc8, 0x9e,
0xf1, 0x3c, 0x0b, 0xaa, 0x04, 0xfa, 0x1c, 0xbf, 0x0f, 0xdb, 0x65, 0xe7, 0x60, 0x59, 0x44, 0xd5,
0xbc, 0xc8, 0xa4, 0x90, 0xb4, 0xf1, 0x3a, 0x8d, 0x48, 0x4b, 0xaf, 0x6e, 0x18, 0x6c, 0x78, 0x7b,
0xb0, 0xc6, 0xfe, 0xc7, 0x49, 0x9e, 0xb6, 0x81, 0x8d, 0x0d, 0x99, 0xde, 0xce, 0x8a, 0x7c, 0x16,
0x15, 0xd5, 0xcd, 0xaf, 0x7e, 0x3a, 0x8f, 0xda, 0x2d, 0x59, 0xf6, 0x81, 0xd0, 0xea, 0x10, 0xa9,
0xfb, 0xe1, 0x23, 0x0e, 0x0f, 0x1f, 0x82, 0x87, 0x02, 0xbe, 0x6d, 0x01, 0xf2, 0xa2, 0xdf, 0xb7,
0xbd, 0xe8, 0x8f, 0x56, 0x47, 0x81, 0xa7, 0xbd, 0xac, 0xaa, 0x22, 0x19, 0xc1, 0x7c, 0xed, 0x96,
0x70, 0xab, 0x56, 0x77, 0x74, 0xd2, 0xe0, 0x1b, 0x8a, 0x2b, 0xaa, 0xf9, 0x8c, 0x58, 0xff, 0x46,
0xd3, 0x73, 0xc9, 0x87, 0x27, 0xbf, 0xb6, 0xd5, 0xce, 0x10, 0x44, 0xdf, 0x83, 0x50, 0xb1, 0xf0,
0xd3, 0xf6, 0xdb, 0xf7, 0xbf, 0x74, 0x2d, 0x55, 0xc5, 0x2c, 0xbe, 0xda, 0x0c, 0x76, 0x91, 0x4c,
0xa3, 0x7c, 0x5e, 0xb5, 0x57, 0xe4, 0xdb, 0x9d, 0x65, 0x9c, 0xa4, 0x69, 0x7c, 0x4d, 0x6b, 0x6f,
0x09, 0xfb, 0x09, 0x34, 0x8d, 0xd0, 0xfa, 0x96, 0xda, 0x90, 0x81, 0x6d, 0x7f, 0xb0, 0xcc, 0xf2,
0xc0, 0x0f, 0x26, 0x91, 0xd7, 0xfa, 0x7e, 0xfd, 0x75, 0xf8, 0xb3, 0x5f, 0x4d, 0x94, 0xc2, 0x87,
0x48, 0xd3, 0x76, 0xe7, 0x07, 0x4d, 0x65, 0xff, 0x98, 0xfd, 0x8b, 0x08, 0xf2, 0x94, 0x95, 0x97,
0x45, 0x57, 0xd2, 0xe5, 0xcf, 0x1f, 0xde, 0x55, 0xd5, 0xec, 0x23, 0x9f, 0x6a, 0x93, 0x3b, 0xb3,
0x2f, 0x25, 0xcf, 0x0a, 0x84, 0xef, 0x4d, 0x49, 0xde, 0x85, 0xe8, 0xcd, 0xc6, 0x91, 0xb7, 0xe1,
0xe9, 0x60, 0x99, 0xc4, 0xed, 0x6a, 0x92, 0x94, 0x0a, 0x43, 0xe2, 0x2e, 0xe8, 0x99, 0x9d, 0xf5,
0x34, 0x2d, 0x9b, 0x97, 0x9e, 0xa7, 0x43, 0xac, 0x1a, 0x6e, 0x39, 0xcb, 0xb3, 0x32, 0x02, 0xcd,
0x67, 0x5e, 0x36, 0x4f, 0xd3, 0xce, 0x32, 0x54, 0x4e, 0x62, 0xe5, 0xfc, 0xa5, 0xb2, 0x20, 0x5b,
0x7b, 0xdb, 0x58, 0x35, 0xbf, 0x2b, 0x5f, 0xdd, 0x5c, 0xf8, 0xe3, 0x53, 0x18, 0xbb, 0xfd, 0xc2,
0x0f, 0x5e, 0x74, 0x7e, 0x57, 0xff, 0x50, 0x82, 0x49, 0x92, 0x86, 0xa7, 0x79, 0x18, 0x95, 0x34,
0xca, 0xf0, 0xc1, 0x5c, 0x66, 0xc8, 0x37, 0xfd, 0xb8, 0xdf, 0xa6, 0x41, 0xba, 0xcb, 0xa6, 0x6f,
0xbf, 0x61, 0x53, 0xed, 0xa9, 0x4d, 0x5f, 0x7d, 0xc3, 0xa6, 0xfa, 0xc3, 0x9b, 0xde, 0xa3, 0xee,
0x07, 0x76, 0xba, 0x5a, 0x3c, 0x2a, 0xf3, 0xb1, 0xa7, 0xae, 0x2c, 0xf4, 0x69, 0x3f, 0x16, 0x9f,
0xd8, 0x78, 0x48, 0xf9, 0x8e, 0xa5, 0xb3, 0xdb, 0x08, 0x49, 0x6f, 0xb9, 0x49, 0x7f, 0x70, 0x6d,
0x24, 0xac, 0x1d, 0xa9, 0xc4, 0xd7, 0x8f, 0x53, 0xa1, 0x8c, 0xb7, 0xeb, 0x56, 0xb3, 0x5d, 0xac,
0x7f, 0xb9, 0x9f, 0x16, 0xca, 0x27, 0xf8, 0x63, 0x9b, 0xbe, 0xdf, 0x73, 0xd3, 0xe4, 0x89, 0x4d,
0xa9, 0x04, 0xed, 0x6a, 0xff, 0x4c, 0xf8, 0x7c, 0x92, 0x65, 0x51, 0xf1, 0xee, 0xe2, 0xe7, 0x0f,
0x9d, 0x67, 0x9e, 0xfa, 0x23, 0x19, 0x66, 0xc0, 0xcd, 0x01, 0x57, 0x5a, 0xd7, 0x1f, 0xe1, 0x0a,
0xa7, 0x27, 0x20, 0x1d, 0x05, 0x5f, 0xa2, 0x70, 0x77, 0x32, 0xf1, 0x13, 0x64, 0xb8, 0x76, 0x4f,
0xf7, 0x53, 0x44, 0x16, 0xee, 0x62, 0xb2, 0x8b, 0x3d, 0x37, 0xad, 0x9e, 0xda, 0x74, 0xd5, 0x2e,
0x88, 0xc5, 0xc8, 0x74, 0x28, 0x11, 0x54, 0x71, 0x56, 0x65, 0x6b, 0x5d, 0xf1, 0xba, 0xbb, 0xc6,
0xb3, 0xff, 0x28, 0xcd, 0xce, 0xae, 0x44, 0x47, 0x7b, 0x11, 0x1d, 0xfd, 0x3d, 0x44, 0x83, 0xbd,
0x88, 0x3e, 0x9e, 0xb8, 0x77, 0x26, 0x1a, 0xee, 0x45, 0xf4, 0x71, 0x3f, 0xd9, 0x99, 0x68, 0xb9,
0x17, 0xd1, 0xf9, 0xdf, 0x43, 0xb4, 0xda, 0x8b, 0xe8, 0xe3, 0xce, 0xbb, 0xbb, 0x4d, 0xdf, 0x64,
0xbb, 0xd3, 0x8c, 0x9f, 0xa0, 0xb9, 0xe9, 0x91, 0x66, 0x74, 0x04, 0x40, 0x8b, 0xb4, 0x6b, 0xda,
0x98, 0x3e, 0x61, 0xb8, 0x8e, 0xa8, 0x1e, 0x08, 0xf3, 0x8b, 0x4b, 0xc8, 0x40, 0xdd, 0x59, 0x14,
0xbe, 0xcf, 0xc2, 0xe8, 0xda, 0x43, 0x15, 0x19, 0xf2, 0xe4, 0xba, 0x35, 0x3f, 0x4b, 0xa8, 0xc6,
0xac, 0x7b, 0x6a, 0x9e, 0x7f, 0xd6, 0x3d, 0xb4, 0xf8, 0xd8, 0x39, 0xb1, 0x15, 0xf7, 0x25, 0x36,
0x6d, 0xb0, 0xda, 0xe8, 0x70, 0xf7, 0x9d, 0xca, 0xfb, 0x76, 0xd2, 0xb1, 0x53, 0xd8, 0x5c, 0x71,
0x82, 0xe6, 0xbf, 0x64, 0x6b, 0x5a, 0x50, 0x48, 0xd0, 0x6a, 0xae, 0xda, 0x35, 0xcd, 0x85, 0xdb,
0xe4, 0x86, 0xff, 0xf8, 0x15, 0x46, 0xba, 0xc5, 0xbf, 0x83, 0x46, 0xce, 0xa7, 0xad, 0x0e, 0xd1,
0x56, 0xbe, 0xbf, 0x68, 0x1d, 0xac, 0x3b, 0xc3, 0x59, 0x94, 0xb5, 0x5b, 0x6f, 0x5f, 0x5f, 0xb4,
0xba, 0x2d, 0xb4, 0xcc, 0xad, 0x43, 0x86, 0x24, 0x1a, 0xcf, 0x2e, 0xa5, 0xf5, 0x4d, 0x17, 0x59,
0x46, 0x59, 0xd8, 0x66, 0xad, 0xde, 0xfa, 0x9c, 0x54, 0xef, 0x5e, 0x4f, 0xda, 0xec, 0x94, 0xc1,
0x69, 0xbc, 0x44, 0xd3, 0x5a, 0xeb, 0x06, 0x87, 0xab, 0xf9, 0x8f, 0x62, 0xfe, 0xe3, 0xd6, 0xfc,
0x5b, 0x31, 0xff, 0x76, 0x6b, 0xfe, 0x95, 0x98, 0x17, 0x6d, 0x15, 0x15, 0x31, 0x34, 0x18, 0x6b,
0x51, 0x3e, 0x09, 0xb0, 0x68, 0x69, 0xb8, 0xe4, 0xbc, 0x4d, 0xaf, 0xb3, 0x76, 0x59, 0x67, 0xed,
0xcd, 0x25, 0x5f, 0xb4, 0xed, 0x67, 0x6b, 0x9a, 0xe7, 0x02, 0x61, 0xd5, 0x22, 0xac, 0x01, 0xef,
0x05, 0x60, 0x55, 0xe6, 0x1f, 0x22, 0x17, 0x55, 0x1f, 0xdf, 0xbe, 0x5a, 0x1d, 0x45, 0x8a, 0xee,
0xb8, 0x3b, 0xea, 0x26, 0xdd, 0xb8, 0x3b, 0xeb, 0x7e, 0xed, 0xf2, 0x93, 0xe9, 0xc4, 0xe3, 0x05,
0xed, 0x1d, 0xdf, 0xa7, 0x5b, 0x8a, 0xf1, 0xb9, 0x18, 0x2f, 0x3c, 0xdd, 0xb2, 0x86, 0x89, 0xc7,
0xda, 0xfe, 0x38, 0xcd, 0x71, 0x4e, 0x99, 0xfc, 0x60, 0x77, 0x86, 0xb1, 0x87, 0x97, 0x9c, 0x0c,
0x67, 0xde, 0xe2, 0x87, 0xb6, 0x26, 0xe3, 0xe8, 0xf6, 0x95, 0x7f, 0xc5, 0x3f, 0xe0, 0xbb, 0xe2,
0xdf, 0x34, 0xec, 0xd0, 0xb8, 0xbc, 0x4a, 0xaa, 0x60, 0xd2, 0x4e, 0xbe, 0xb3, 0x3b, 0xcb, 0xc0,
0x2f, 0x23, 0x49, 0x1d, 0x14, 0xde, 0xa2, 0x3b, 0xf6, 0xaa, 0xee, 0xc8, 0x9b, 0x0d, 0x47, 0x68,
0xf7, 0xbf, 0x0c, 0x19, 0x40, 0x03, 0xe0, 0x2b, 0x00, 0x8b, 0x6d, 0x80, 0x0e, 0xc0, 0x4c, 0x00,
0xaa, 0x3a, 0xc0, 0x10, 0x80, 0xaf, 0x00, 0x2c, 0xea, 0x00, 0x13, 0x80, 0x0a, 0x80, 0xd9, 0x36,
0xc0, 0x12, 0xc4, 0x09, 0xf0, 0x15, 0xea, 0x6a, 0x36, 0xf6, 0xc5, 0x56, 0x4f, 0x3e, 0xde, 0x6a,
0xa7, 0x47, 0x43, 0xf2, 0xaf, 0x86, 0x96, 0xcf, 0x1a, 0x46, 0x3d, 0xe3, 0xa6, 0x79, 0x73, 0xb6,
0x65, 0xd4, 0x3b, 0xd6, 0x41, 0xf2, 0x5a, 0xf0, 0x33, 0x0f, 0x8e, 0xed, 0x9d, 0x93, 0x34, 0x2f,
0xa3, 0xf3, 0xa8, 0xaa, 0x92, 0x6c, 0x5c, 0x02, 0x91, 0x4e, 0xcb, 0xad, 0x32, 0x7d, 0x49, 0x07,
0x4f, 0x96, 0x4e, 0xc3, 0xa4, 0x9c, 0xa5, 0xfe, 0x8d, 0xd7, 0xca, 0xf2, 0x2c, 0x6a, 0x09, 0x78,
0x31, 0x1e, 0x3d, 0x8e, 0x30, 0x29, 0x1f, 0x87, 0xa7, 0x9f, 0x1e, 0x85, 0x57, 0xe9, 0xe5, 0x13,
0xf0, 0xb3, 0x27, 0xe0, 0xa7, 0x0f, 0xc1, 0x21, 0xf7, 0xe2, 0x48, 0x67, 0xe7, 0x38, 0x0a, 0xa4,
0x87, 0xd9, 0x19, 0xa5, 0x79, 0xf0, 0xa5, 0xf5, 0x88, 0x42, 0x04, 0xc2, 0xed, 0x81, 0xf0, 0xb3,
0xc5, 0xda, 0xcb, 0x1e, 0x51, 0x92, 0x58, 0xc4, 0xae, 0x34, 0x1a, 0x0e, 0xf8, 0xb0, 0xde, 0x36,
0x4b, 0xb4, 0xa6, 0x6b, 0x3e, 0xac, 0x0a, 0xb1, 0xa4, 0xe1, 0xaf, 0x0f, 0x2b, 0xf6, 0x2e, 0xb6,
0x39, 0x78, 0x58, 0x8d, 0x6b, 0xb1, 0x83, 0x05, 0x1c, 0x7c, 0x1a, 0x8e, 0x04, 0x02, 0x9d, 0xec,
0xbd, 0x76, 0x3a, 0x3d, 0x56, 0x3b, 0x3f, 0xfa, 0x27, 0x83, 0xf0, 0xa4, 0xee, 0x74, 0xd0, 0x85,
0x3e, 0x89, 0xae, 0xdb, 0x45, 0x14, 0x76, 0xc7, 0x45, 0x14, 0x65, 0xdd, 0x11, 0x55, 0x3d, 0x9e,
0x20, 0xc6, 0x23, 0x8f, 0x46, 0x7f, 0xb5, 0x19, 0xe4, 0xe8, 0xc8, 0xe9, 0xfc, 0x45, 0x88, 0x47,
0x47, 0x9a, 0x4d, 0x99, 0x96, 0xae, 0x6d, 0x5e, 0x3c, 0x7f, 0x71, 0xd8, 0x56, 0xaf, 0xc5, 0xc1,
0xff, 0x10, 0x4b, 0x3a, 0x4a, 0x95, 0x9f, 0x57, 0x05, 0xdc, 0xb6, 0x0d, 0x34, 0xa5, 0x4c, 0x93,
0x20, 0x6a, 0x6b, 0x9d, 0x1a, 0xcd, 0x14, 0xb0, 0xc2, 0x0f, 0xdb, 0x2c, 0x01, 0x75, 0xc4, 0xfd,
0x4f, 0x0b, 0xb3, 0x91, 0x5f, 0xc8, 0x04, 0x49, 0x50, 0x48, 0xda, 0xad, 0xc3, 0xd1, 0xc9, 0x21,
0x92, 0xff, 0xe1, 0x9a, 0x45, 0x86, 0x7e, 0xd8, 0xea, 0x34, 0xb2, 0x3b, 0x65, 0xba, 0x03, 0x1c,
0x1a, 0x46, 0x79, 0x78, 0x23, 0x04, 0x1e, 0xf9, 0xc1, 0x97, 0x71, 0x91, 0xcf, 0xb3, 0xd0, 0x5b,
0x91, 0xaa, 0x45, 0x74, 0xb7, 0x16, 0xcd, 0xdd, 0x5a, 0x24, 0xb3, 0x8b, 0x91, 0x77, 0xe7, 0xbb,
0xa1, 0xc6, 0xd7, 0x4d, 0xed, 0xb2, 0x9c, 0xb0, 0x9d, 0xb7, 0x37, 0x0a, 0xcf, 0xd2, 0x26, 0x3a,
0x8e, 0x4f, 0x6b, 0x50, 0xf5, 0x20, 0x48, 0xb8, 0x2f, 0xaf, 0xf2, 0x10, 0xb2, 0xee, 0xc4, 0x33,
0x24, 0x60, 0x6d, 0xed, 0x03, 0x6c, 0x29, 0x56, 0xac, 0x41, 0xfa, 0x1d, 0xd0, 0x5d, 0x9f, 0xbe,
0x67, 0x0b, 0x7f, 0xd7, 0x2d, 0xf4, 0x6f, 0xe1, 0xc2, 0x3f, 0xb9, 0xc7, 0xf1, 0xf7, 0xe3, 0xc2,
0x27, 0xe7, 0xad, 0xc6, 0x4d, 0x95, 0xd5, 0xca, 0xf9, 0x46, 0xe5, 0xf1, 0xec, 0x72, 0x2b, 0x40,
0xda, 0x0f, 0x98, 0x48, 0x04, 0xce, 0x40, 0xe4, 0xa1, 0x38, 0x8f, 0xb7, 0x77, 0xbf, 0xb3, 0xca,
0x36, 0xd7, 0x64, 0xa6, 0xc5, 0x53, 0xd8, 0x47, 0xda, 0x3d, 0x71, 0x77, 0x31, 0xbe, 0x10, 0x17,
0x5c, 0x4d, 0xee, 0x37, 0x85, 0xe3, 0xc2, 0x53, 0x5b, 0xc3, 0xfa, 0xbd, 0x95, 0xca, 0x3b, 0xd1,
0x3a, 0x86, 0x4e, 0xa1, 0x70, 0x7f, 0xad, 0x3f, 0xbf, 0x7a, 0x73, 0xc9, 0xae, 0x57, 0xd9, 0xf5,
0xad, 0x77, 0x0f, 0x5f, 0x87, 0x25, 0xe5, 0xdc, 0xcc, 0xf3, 0x64, 0xed, 0xaf, 0xbf, 0xf0, 0x8a,
0xaf, 0xb3, 0x0e, 0x8f, 0xc5, 0xe1, 0x7d, 0xcd, 0x6e, 0xc6, 0xb0, 0x8f, 0xd4, 0xce, 0x7d, 0x40,
0x95, 0x01, 0x8f, 0x69, 0x8b, 0xfb, 0xc0, 0xac, 0x5d, 0x98, 0x26, 0x59, 0xdb, 0xb6, 0xba, 0xc0,
0x91, 0x35, 0x30, 0x7c, 0xd9, 0xe4, 0xf7, 0x62, 0xfc, 0xee, 0xfc, 0x95, 0x50, 0x49, 0x40, 0x85,
0xe0, 0x60, 0x89, 0x77, 0xe7, 0x47, 0x76, 0xed, 0x39, 0xc0, 0x53, 0x5b, 0x77, 0xe2, 0xbf, 0x22,
0x99, 0x51, 0x1b, 0x59, 0x17, 0x96, 0x22, 0xe5, 0xec, 0xbc, 0x7d, 0xcd, 0x72, 0x01, 0x95, 0xdb,
0x37, 0x42, 0x6b, 0xeb, 0xf3, 0x40, 0x63, 0xba, 0x73, 0x78, 0x4d, 0x1c, 0x37, 0xe6, 0x60, 0xa7,
0xe6, 0x52, 0xed, 0x0e, 0xca, 0xb1, 0x6e, 0x6d, 0xe1, 0xe8, 0x56, 0x5d, 0x88, 0xb3, 0x97, 0xd5,
0xa6, 0xf6, 0xf3, 0xa5, 0xaf, 0xd6, 0x37, 0x19, 0xf0, 0xb4, 0xef, 0xcf, 0x5e, 0x7a, 0x1a, 0x3c,
0x8d, 0xde, 0xb0, 0x6e, 0x1d, 0xef, 0xa4, 0x89, 0x77, 0x22, 0xf0, 0x4e, 0xb6, 0xf1, 0xde, 0x34,
0xf1, 0x2e, 0x05, 0xde, 0x25, 0xe1, 0xd5, 0x39, 0x39, 0x87, 0x43, 0x94, 0xd4, 0x4f, 0x30, 0x9e,
0x48, 0x12, 0x36, 0x5a, 0xf9, 0xce, 0xd9, 0xb9, 0xb7, 0xda, 0xb7, 0x21, 0xd0, 0xb6, 0x8f, 0x9d,
0x7d, 0x78, 0x08, 0xef, 0xe0, 0x8e, 0xcb, 0xfd, 0x82, 0x96, 0x7d, 0xd3, 0xb1, 0x1c, 0x2c, 0xe9,
0xd7, 0x07, 0x76, 0xff, 0x56, 0x36, 0x73, 0x1c, 0x82, 0x38, 0x08, 0x5f, 0xdd, 0xdf, 0x05, 0x94,
0x55, 0xbc, 0x0d, 0x48, 0x32, 0x2a, 0x0d, 0xac, 0x41, 0x28, 0x47, 0x71, 0x87, 0x61, 0x14, 0x81,
0xd7, 0xea, 0x95, 0x82, 0x16, 0x56, 0x8d, 0xe2, 0xcd, 0xd5, 0xde, 0xba, 0x9f, 0x6a, 0x76, 0x50,
0x9c, 0x1f, 0x8e, 0xb5, 0xc5, 0x50, 0x78, 0x2f, 0x43, 0x2b, 0xba, 0xf7, 0xb0, 0xc4, 0x79, 0x6d,
0x78, 0xef, 0x79, 0x7b, 0xd3, 0xbb, 0x1d, 0x2c, 0xb7, 0xbb, 0x37, 0xee, 0xb9, 0x4d, 0x05, 0x35,
0x3c, 0xf8, 0x62, 0x7c, 0xca, 0x7e, 0xde, 0xa0, 0x8b, 0xb5, 0x67, 0x78, 0xb0, 0x78, 0x42, 0x29,
0x58, 0x1b, 0xe2, 0x14, 0x86, 0x38, 0x6c, 0x5c, 0x61, 0xad, 0xbb, 0xff, 0xd3, 0x8b, 0x35, 0xe8,
0xa2, 0x01, 0x6a, 0x6f, 0xdd, 0xa5, 0x91, 0xc7, 0x9c, 0xbe, 0xe1, 0x1e, 0x83, 0x37, 0x79, 0x0c,
0xe3, 0xab, 0x46, 0x43, 0x7d, 0x38, 0xa3, 0x80, 0x45, 0xc6, 0x21, 0x3f, 0x74, 0x1e, 0x32, 0x0e,
0xd9, 0xf7, 0xb1, 0xd1, 0x59, 0x9f, 0x6d, 0x1f, 0xa8, 0x59, 0xeb, 0x13, 0xcc, 0xa9, 0xa7, 0x7e,
0xff, 0xf1, 0x94, 0xc8, 0x34, 0xbb, 0xfc, 0x2d, 0xb8, 0xd6, 0xda, 0x6a, 0xf6, 0x37, 0x70, 0xed,
0xee, 0x7a, 0xe3, 0x0e, 0x5c, 0x7b, 0x58, 0x0c, 0x5e, 0xe5, 0x45, 0x87, 0x83, 0x9e, 0x02, 0x4d,
0xc5, 0xa8, 0x5b, 0x78, 0x7e, 0x31, 0x66, 0x77, 0x16, 0x74, 0xfc, 0xef, 0xe1, 0x90, 0x83, 0x03,
0xc1, 0x66, 0x4a, 0xe3, 0x53, 0xa3, 0xda, 0x94, 0xce, 0xa7, 0x26, 0xdd, 0x12, 0x87, 0x22, 0x9e,
0xdf, 0xfc, 0x55, 0x8f, 0xd2, 0x0d, 0x93, 0x38, 0xf6, 0x16, 0xf2, 0x3a, 0xed, 0xd5, 0xa6, 0x83,
0xcd, 0x0f, 0x1c, 0xc1, 0xaa, 0xf7, 0x69, 0x2f, 0xe4, 0xa0, 0xd3, 0xb3, 0x7b, 0x04, 0x3f, 0xd4,
0x7a, 0xfa, 0xf0, 0x96, 0x65, 0x1e, 0xda, 0x84, 0x2e, 0xc7, 0x27, 0x5e, 0xb9, 0x4a, 0xfe, 0x4b,
0x1c, 0xc8, 0x30, 0xdd, 0x5b, 0x0c, 0x8b, 0x82, 0x7d, 0x05, 0xed, 0x02, 0x67, 0x83, 0xb1, 0xf8,
0x1e, 0x77, 0x86, 0xa3, 0x91, 0xf8, 0x1e, 0xb1, 0xa0, 0x2f, 0x3c, 0xcf, 0x5b, 0xd0, 0x16, 0xa3,
0x91, 0x3c, 0x1e, 0xf3, 0x4d, 0x24, 0xcc, 0x8f, 0x57, 0xf3, 0x6d, 0xad, 0x67, 0x74, 0x0e, 0x8b,
0x42, 0x1e, 0x8d, 0x36, 0xd0, 0xd1, 0x1a, 0xaa, 0x13, 0x74, 0x3c, 0x96, 0x8b, 0x62, 0xc8, 0x0e,
0xed, 0x93, 0x23, 0x62, 0xe8, 0x10, 0xb9, 0x71, 0x8d, 0x3c, 0x39, 0xd6, 0x30, 0x25, 0xd3, 0x14,
0x43, 0x29, 0x51, 0xc6, 0x1a, 0xa7, 0x48, 0x6f, 0x32, 0x6c, 0x9c, 0x22, 0xbd, 0xb2, 0x11, 0xa6,
0xe7, 0xed, 0x84, 0x82, 0x53, 0x9c, 0x09, 0xef, 0xf1, 0x99, 0x4f, 0x0f, 0x39, 0xcb, 0xab, 0x87,
0xbc, 0xe4, 0xe3, 0x96, 0x03, 0xd5, 0x1c, 0xe4, 0x6c, 0xab, 0x9f, 0x5e, 0x03, 0x4e, 0x5a, 0x5b,
0x87, 0xc2, 0xcd, 0x66, 0x2c, 0x28, 0xee, 0x38, 0xd2, 0xfc, 0xe4, 0xb7, 0xf6, 0x3a, 0xbf, 0x36,
0x52, 0xf9, 0x6f, 0xf5, 0x80, 0x3b, 0xf9, 0x8d, 0x07, 0x1c, 0xde, 0xeb, 0x54, 0x8e, 0xbc, 0xaa,
0xf1, 0x63, 0xe1, 0x99, 0xb6, 0x15, 0xcc, 0x67, 0xba, 0x00, 0xe8, 0xdb, 0x80, 0x0b, 0x01, 0x58,
0xc5, 0xf8, 0x1d, 0x86, 0x3e, 0xd6, 0xcf, 0x9d, 0x67, 0x2c, 0x96, 0xef, 0xe0, 0x88, 0x9f, 0xf9,
0xe2, 0x19, 0x50, 0x23, 0xaf, 0x75, 0x94, 0xcf, 0x68, 0xfa, 0xf8, 0x75, 0x51, 0xe4, 0x85, 0x44,
0x97, 0x31, 0xc8, 0x4d, 0x68, 0xd0, 0xcb, 0xea, 0xd9, 0x51, 0x4f, 0xc0, 0x5a, 0xc3, 0x28, 0xf5,
0xe2, 0xd9, 0x8f, 0xec, 0x10, 0x3b, 0x60, 0xe5, 0x7d, 0x18, 0x47, 0x64, 0x2c, 0x4c, 0xbe, 0xe8,
0xfd, 0xab, 0xcc, 0xb3, 0xde, 0xcc, 0x4f, 0x91, 0xd7, 0xa2, 0xf2, 0xc5, 0x40, 0x4c, 0x44, 0x71,
0x8c, 0xfa, 0x5f, 0xbe, 0xc0, 0x69, 0x60, 0x12, 0x21, 0x00, 0xa2, 0xd2, 0x3b, 0xa6, 0xf4, 0xf8,
0x0c, 0x5f, 0x4a, 0xfe, 0xa5, 0xb3, 0x8c, 0xd2, 0xda, 0x85, 0x12, 0xe5, 0x6d, 0xf1, 0x33, 0x30,
0xc1, 0x69, 0x07, 0x62, 0x5b, 0x2c, 0xa6, 0x21, 0x56, 0x53, 0xc0, 0x5e, 0xaf, 0x7e, 0x03, 0x67,
0x1c, 0x11, 0x40, 0x59, 0x91, 0x1e, 0xb0, 0x91, 0xa0, 0x8b, 0x2e, 0xae, 0x68, 0x27, 0x52, 0x82,
0xc3, 0x46, 0x67, 0x79, 0x7d, 0xb8, 0x16, 0x54, 0xe2, 0x0e, 0xf8, 0xcf, 0x56, 0xeb, 0x30, 0x39,
0x6c, 0xfd, 0xb3, 0x75, 0xdc, 0x3a, 0x4c, 0x7f, 0x4f, 0xfe, 0x38, 0x6c, 0x49, 0x6d, 0x36, 0xd3,
0xa9, 0x49, 0x7d, 0x7b, 0xd0, 0xe0, 0xf1, 0x1a, 0x6a, 0xb8, 0x73, 0xcf, 0xf7, 0x63, 0x3c, 0x4b,
0x06, 0x74, 0x0d, 0x48, 0xa2, 0x41, 0xa9, 0xf4, 0xa3, 0x77, 0xaa, 0xa4, 0x51, 0x36, 0xae, 0x26,
0xe2, 0xb6, 0xab, 0xa3, 0x04, 0x3e, 0x53, 0xd6, 0xe6, 0xb7, 0xd6, 0x6d, 0xd9, 0x3b, 0xb7, 0x47,
0x3d, 0xf1, 0xd7, 0x02, 0xd2, 0x11, 0x2b, 0x35, 0xc7, 0x83, 0x22, 0xcf, 0xab, 0x25, 0xbf, 0xe3,
0x1f, 0x3c, 0x0f, 0xdd, 0x91, 0xa1, 0xa9, 0x43, 0x7e, 0xfb, 0x3e, 0x78, 0xae, 0x8e, 0x8c, 0xc0,
0x0a, 0x87, 0xfc, 0x5e, 0x7c, 0xf0, 0x5c, 0x0b, 0xf5, 0xbe, 0xa1, 0x0d, 0xf9, 0x8d, 0xf5, 0xe0,
0xb9, 0xa1, 0x3b, 0x41, 0x40, 0xc3, 0x92, 0x23, 0xab, 0xb4, 0xb0, 0x6a, 0x82, 0x82, 0x37, 0xd9,
0xe0, 0xd7, 0xa8, 0x08, 0xfd, 0xcc, 0xbf, 0x55, 0x82, 0xaa, 0x48, 0x3f, 0x8f, 0xf2, 0xeb, 0xe5,
0x14, 0xe9, 0x2d, 0xc9, 0x06, 0xfe, 0xbc, 0xca, 0x87, 0x57, 0x49, 0x58, 0x4d, 0x06, 0x8e, 0xba,
0xb8, 0x1a, 0x6e, 0xce, 0x53, 0xfc, 0xc7, 0xef, 0x01, 0x0c, 0xd0, 0xe6, 0xc4, 0x3b, 0xc3, 0x59,
0x5e, 0x26, 0x24, 0xd6, 0xc0, 0x1f, 0x95, 0x79, 0x3a, 0xaf, 0xa2, 0x61, 0x95, 0xcf, 0x06, 0x96,
0xf5, 0xdd, 0x30, 0x8d, 0xe2, 0x6a, 0x60, 0xa9, 0xdf, 0x0d, 0xab, 0xc2, 0xcf, 0x4a, 0x18, 0x64,
0x3a, 0x60, 0x5f, 0x29, 0x2a, 0x43, 0x5b, 0x06, 0xa0, 0x4b, 0x0f, 0x9c, 0xa5, 0x92, 0xb4, 0x8a,
0x8a, 0x41, 0x58, 0xe4, 0x33, 0xb9, 0x9c, 0xf8, 0x61, 0x7e, 0x05, 0xe8, 0xec, 0x5a, 0x62, 0x0f,
0xfa, 0xcf, 0xc9, 0x91, 0x34, 0x9d, 0xce, 0xad, 0x52, 0x86, 0xe5, 0x92, 0x33, 0x87, 0x43, 0xe7,
0x77, 0xc3, 0x49, 0x94, 0x8c, 0x27, 0xd5, 0x40, 0xd3, 0x17, 0x93, 0x21, 0xe7, 0x5f, 0x26, 0x06,
0x30, 0x04, 0x6a, 0x2a, 0x44, 0x92, 0x19, 0x2f, 0x4c, 0x2e, 0x31, 0x51, 0xb0, 0x55, 0xf5, 0x19,
0xb1, 0x4a, 0x08, 0xde, 0xef, 0x2f, 0xae, 0x6e, 0x9f, 0x97, 0xe9, 0xcb, 0x65, 0x0d, 0xac, 0x02,
0xbc, 0x51, 0xc6, 0x60, 0xfb, 0xc4, 0x5a, 0xe5, 0x12, 0xdb, 0x16, 0x47, 0x68, 0x20, 0x75, 0x6f,
0xa2, 0x34, 0xcd, 0xaf, 0x3a, 0xb4, 0xcb, 0xc7, 0xe5, 0xee, 0xcb, 0x70, 0xc0, 0x66, 0x6b, 0xde,
0xee, 0xb1, 0x86, 0x9d, 0xcf, 0xd9, 0xaa, 0x57, 0x7b, 0xac, 0x62, 0x27, 0x7d, 0x5a, 0xf4, 0x69,
0x8f, 0x45, 0x57, 0x93, 0xa4, 0xe2, 0xab, 0xde, 0xed, 0xb4, 0x8a, 0x2e, 0x16, 0xf2, 0x82, 0x7e,
0xd9, 0x17, 0x0a, 0x11, 0xd7, 0x0c, 0xc1, 0x8d, 0xcf, 0xef, 0x1a, 0xba, 0x8b, 0x24, 0x47, 0x04,
0xaf, 0xe5, 0x3e, 0xdf, 0x69, 0x5b, 0x6c, 0x72, 0x53, 0x13, 0xfb, 0x74, 0x0f, 0x09, 0x90, 0x66,
0xbe, 0xce, 0xf3, 0xa4, 0xe4, 0x52, 0x5c, 0xec, 0xb1, 0x72, 0x65, 0x51, 0xa5, 0xca, 0xf3, 0xb4,
0xfc, 0x8f, 0x7d, 0xeb, 0xf2, 0x9b, 0xd4, 0xfe, 0x7e, 0x5f, 0x5f, 0xa2, 0x9b, 0x91, 0x65, 0x9c,
0x67, 0x95, 0x1c, 0xfb, 0xd3, 0x24, 0xbd, 0x59, 0x85, 0xef, 0x9b, 0xac, 0xd3, 0x7d, 0x17, 0xa5,
0x8b, 0xa8, 0x4a, 0x02, 0xbf, 0x5b, 0x22, 0x32, 0xe5, 0x32, 0x2a, 0x92, 0x78, 0x58, 0x45, 0xd7,
0x95, 0xec, 0xa7, 0xc9, 0x38, 0x1b, 0x04, 0x11, 0xfd, 0xb1, 0xc9, 0x63, 0x4e, 0xcf, 0x37, 0xa3,
0xbc, 0xd4, 0xe1, 0x44, 0x3b, 0xeb, 0x90, 0xa4, 0xf0, 0x14, 0x29, 0x45, 0xad, 0x27, 0x91, 0x22,
0x9a, 0x45, 0x7e, 0x35, 0xc8, 0x72, 0xf1, 0x55, 0x87, 0xf9, 0x55, 0xe5, 0x07, 0x13, 0x6a, 0xb1,
0x06, 0x71, 0x72, 0x1d, 0x85, 0xc3, 0x7a, 0xc6, 0xa1, 0x24, 0xd6, 0xb9, 0xa5, 0xbf, 0x8b, 0x59,
0xd6, 0x68, 0xdc, 0x26, 0x71, 0xe1, 0x4f, 0xa3, 0xa5, 0xe8, 0xce, 0x07, 0xd4, 0x9c, 0x0f, 0x47,
0x79, 0x11, 0x22, 0xa9, 0xa8, 0xfb, 0x65, 0x97, 0xe1, 0x03, 0x19, 0x50, 0x50, 0xb3, 0x29, 0x01,
0xfc, 0xc7, 0x09, 0xef, 0xb6, 0x5c, 0x8c, 0xd9, 0x9f, 0xdb, 0x08, 0xa9, 0x42, 0x96, 0x47, 0x45,
0x4a, 0xd3, 0x37, 0xd4, 0x34, 0x75, 0x81, 0xde, 0x71, 0xcf, 0xf4, 0x98, 0x64, 0xb3, 0x79, 0xb5,
0xdc, 0x4f, 0xe8, 0x07, 0x7c, 0x63, 0xe3, 0x11, 0xb7, 0xa3, 0x79, 0x55, 0xe5, 0x59, 0xdd, 0xf1,
0x6a, 0x66, 0x6f, 0x98, 0x88, 0x0b, 0x23, 0xb4, 0xaf, 0x58, 0xc1, 0x44, 0x82, 0x92, 0x92, 0x50,
0xaa, 0xe3, 0x8b, 0xa0, 0x18, 0xe5, 0xd8, 0x74, 0x3a, 0xd0, 0xa0, 0xd3, 0xbf, 0x9b, 0x5f, 0x5e,
0xa6, 0x77, 0xe1, 0xb7, 0xda, 0x81, 0xdf, 0xbf, 0x9b, 0x3b, 0x66, 0xa3, 0xdf, 0xd9, 0x1f, 0x18,
0x66, 0xf3, 0xe9, 0x28, 0x2a, 0xfe, 0xf8, 0xbb, 0x38, 0xe5, 0x4e, 0x64, 0x44, 0xd3, 0x3a, 0x0d,
0x96, 0x7c, 0xff, 0x58, 0xca, 0x57, 0xd1, 0xe8, 0x4b, 0x82, 0xc0, 0x9e, 0x21, 0xe6, 0x30, 0x17,
0x44, 0x3c, 0x52, 0x84, 0xcb, 0xcb, 0x26, 0x04, 0x51, 0xef, 0xae, 0x1b, 0xc4, 0x79, 0x30, 0x2f,
0x97, 0xf9, 0xbc, 0xa2, 0xc8, 0x1f, 0xdc, 0x87, 0x31, 0x58, 0x6d, 0x5d, 0x82, 0x9f, 0xa8, 0x90,
0x8b, 0x79, 0x96, 0xf9, 0xa3, 0x34, 0x92, 0xe1, 0xfd, 0xc1, 0x97, 0x87, 0x8a, 0x75, 0x30, 0x2f,
0x4a, 0x08, 0x37, 0xcb, 0x93, 0xed, 0x14, 0x53, 0x93, 0x68, 0x07, 0x6a, 0xd5, 0x04, 0x3a, 0xdc,
0xd3, 0xe3, 0x37, 0x11, 0xb6, 0xca, 0xc9, 0xda, 0x56, 0x6d, 0xe7, 0xe8, 0x3e, 0xb7, 0x42, 0x93,
0xd3, 0xc7, 0x15, 0xc9, 0x72, 0x3d, 0x7c, 0xfa, 0x5e, 0xce, 0xa7, 0xf9, 0x9f, 0x32, 0x1b, 0xfc,
0xb7, 0x54, 0x53, 0x23, 0xf0, 0xbf, 0x56, 0xcb, 0x2e, 0xe2, 0x97, 0xdf, 0x2a, 0x37, 0xcb, 0xa3,
0x33, 0xbf, 0xa0, 0xbf, 0xa0, 0xe5, 0x21, 0x20, 0x5a, 0xd1, 0x3a, 0xe0, 0xce, 0xcc, 0x43, 0x4c,
0x50, 0xf2, 0x95, 0x51, 0xc9, 0xa3, 0xa2, 0x1e, 0x78, 0xcf, 0x9f, 0x54, 0xae, 0x58, 0x39, 0x87,
0xe1, 0xf7, 0x5e, 0xc9, 0xed, 0xb1, 0xb7, 0x56, 0x6b, 0x26, 0xa1, 0x43, 0x02, 0x3b, 0x1b, 0x88,
0x33, 0x82, 0x94, 0x84, 0xde, 0x24, 0x4f, 0xa1, 0x8b, 0x7f, 0x21, 0xb3, 0xb0, 0x19, 0x46, 0x95,
0xca, 0x77, 0x2f, 0x28, 0xcb, 0xe3, 0x15, 0xfe, 0x51, 0x8f, 0xff, 0x8d, 0x34, 0x35, 0x02, 0x52,
0x9e, 0xb1, 0x3f, 0x49, 0x58, 0xff, 0x59, 0xaa, 0x14, 0xd0, 0x6f, 0xfd, 0xde, 0xe7, 0xcf, 0xa8,
0x9d, 0x49, 0xf6, 0x99, 0x16, 0x7f, 0xfe, 0xf8, 0xfa, 0xe5, 0x4f, 0xbf, 0x7d, 0xfe, 0x4c, 0x84,
0x66, 0x7e, 0x26, 0x30, 0xe8, 0x0f, 0x01, 0x8e, 0x3f, 0xf0, 0x13, 0xa2, 0xa2, 0x28, 0xd8, 0x1c,
0x30, 0x42, 0x59, 0x8c, 0x25, 0x46, 0xc7, 0xbb, 0x5b, 0x19, 0xb9, 0xb8, 0xea, 0x4a, 0x0a, 0x75,
0x98, 0x2f, 0xa2, 0x22, 0x86, 0xe6, 0x07, 0x93, 0x24, 0x0c, 0x23, 0x1c, 0xc7, 0xa2, 0xa2, 0xc4,
0x0a, 0x4f, 0x53, 0x34, 0xe9, 0x7a, 0x9a, 0x66, 0xa5, 0x37, 0xa9, 0xaa, 0xd9, 0xa0, 0xd7, 0xbb,
0xba, 0xba, 0x52, 0xae, 0x0c, 0x25, 0x2f, 0xc6, 0x3d, 0x1d, 0x27, 0x98, 0x1e, 0xa8, 0x80, 0x56,
0x18, 0xc5, 0xe5, 0xb1, 0xd4, 0xeb, 0x7d, 0x60, 0x4d, 0x08, 0xfd, 0x19, 0x76, 0xa9, 0x04, 0xf9,
0xb4, 0x17, 0xa3, 0x11, 0x04, 0x27, 0x37, 0xd3, 0x51, 0x9e, 0x92, 0x5a, 0xd2, 0xac, 0x90, 0x67,
0x64, 0x5f, 0x99, 0x5f, 0x2b, 0x48, 0x8b, 0x24, 0xba, 0x7a, 0x95, 0xe3, 0xf4, 0xa8, 0x4a, 0xaa,
0xa4, 0xa9, 0xba, 0xc9, 0x1e, 0xad, 0xe3, 0x23, 0xfa, 0x8d, 0x41, 0x0a, 0xbd, 0xd6, 0xcf, 0xa6,
0x63, 0x2b, 0xa6, 0x64, 0x6b, 0xa6, 0x62, 0x06, 0x32, 0x9e, 0x9a, 0xe1, 0x48, 0xaa, 0xac, 0x5b,
0x8a, 0x2d, 0x6b, 0x9a, 0x62, 0xda, 0x1a, 0xff, 0xa6, 0xc7, 0x42, 0x36, 0x6d, 0x55, 0x71, 0x02,
0x75, 0x85, 0xc7, 0x10, 0x74, 0x06, 0x93, 0xd6, 0x58, 0x25, 0x1b, 0x72, 0x90, 0xb4, 0x06, 0x2d,
0xc4, 0x52, 0x89, 0x2d, 0x75, 0xe5, 0x1a, 0x7c, 0xb3, 0xfe, 0x4f, 0x30, 0xd6, 0x23, 0xce, 0xee,
0xf0, 0xe7, 0xf6, 0x75, 0xac, 0x96, 0xc1, 0xbc, 0x62, 0xf5, 0xc1, 0x9f, 0xe6, 0xba, 0xb2, 0xe1,
0x2a, 0xae, 0x69, 0xca, 0x7a, 0x5f, 0x53, 0x2c, 0x03, 0x1b, 0xea, 0x8a, 0xd9, 0x97, 0x81, 0x67,
0xe9, 0xce, 0xea, 0x25, 0x26, 0x35, 0xdb, 0x51, 0x5c, 0x7b, 0x35, 0xe2, 0x0b, 0xb0, 0x89, 0x63,
0x2a, 0x86, 0x6b, 0x49, 0xba, 0xad, 0x38, 0x16, 0x38, 0xb2, 0xa1, 0x82, 0xbe, 0x23, 0xf5, 0xfb,
0x8a, 0xdd, 0xc7, 0xb6, 0x06, 0xb0, 0x5c, 0x53, 0x32, 0x5d, 0x45, 0xb3, 0x64, 0xc0, 0x5c, 0xcd,
0x82, 0x54, 0xd8, 0xa8, 0x4f, 0xdc, 0x1b, 0x58, 0x0a, 0x65, 0xba, 0xb6, 0x62, 0xeb, 0xa6, 0xac,
0x19, 0xb6, 0x62, 0xa9, 0x9a, 0x84, 0x69, 0xcb, 0x92, 0x4d, 0x45, 0x35, 0x4c, 0x49, 0xef, 0x2b,
0x8e, 0x6a, 0x49, 0x86, 0x62, 0x3b, 0x86, 0x84, 0xcd, 0x1c, 0x52, 0x58, 0x5f, 0xd1, 0x0d, 0xb3,
0x94, 0xf9, 0x24, 0xc7, 0x90, 0xf9, 0xa4, 0x40, 0x81, 0x8c, 0x24, 0x97, 0x65, 0x49, 0xa6, 0xa6,
0xd8, 0x16, 0xf1, 0xd1, 0x57, 0xfa, 0xaa, 0x8e, 0xa5, 0xd0, 0xc0, 0x66, 0x68, 0x68, 0xae, 0xa2,
0xea, 0x3a, 0x59, 0xd5, 0x01, 0x51, 0x15, 0x1a, 0x07, 0xa7, 0x3a, 0x78, 0x32, 0x0c, 0x20, 0xd6,
0x9f, 0x25, 0x7b, 0xca, 0x0d, 0xb8, 0xcc, 0x9e, 0xcc, 0x92, 0xb6, 0xa2, 0x39, 0x7d, 0xd9, 0xc5,
0xb6, 0x16, 0x54, 0xd3, 0x57, 0x8c, 0xbe, 0xa0, 0xa2, 0xc9, 0x9c, 0x08, 0x89, 0x07, 0xb1, 0x74,
0x2e, 0x97, 0xac, 0x6b, 0x8a, 0x6e, 0x43, 0xa7, 0x8e, 0xa2, 0x3b, 0x8e, 0x60, 0x5e, 0x16, 0xf2,
0x11, 0x86, 0x2e, 0xd0, 0x25, 0xc2, 0x70, 0x05, 0x3a, 0x97, 0xae, 0xcf, 0xd1, 0x2d, 0xa6, 0x63,
0x13, 0x36, 0x37, 0x14, 0x8d, 0x71, 0xde, 0x57, 0x4c, 0x28, 0x1e, 0x0a, 0x77, 0x74, 0xae, 0x53,
0x03, 0x6f, 0xe8, 0xd4, 0x74, 0x5d, 0xc9, 0x82, 0xdf, 0x68, 0xb6, 0x64, 0xf7, 0x15, 0x4d, 0xe3,
0x2b, 0xfb, 0x16, 0x5b, 0xa2, 0x43, 0x0d, 0x62, 0xc8, 0x8d, 0xe5, 0x70, 0x1f, 0x87, 0x87, 0x70,
0xdf, 0xa0, 0xbd, 0x20, 0x80, 0xaa, 0x0b, 0xcb, 0x4b, 0xc2, 0x55, 0xb8, 0x73, 0x48, 0xec, 0x65,
0x0b, 0xe7, 0x90, 0x9a, 0xce, 0xc1, 0x47, 0x35, 0x7f, 0xec, 0xf1, 0x20, 0x3b, 0xde, 0x8e, 0x36,
0xba, 0x32, 0xda, 0x21, 0xca, 0x5c, 0xd7, 0x81, 0x17, 0x3b, 0xd0, 0xa7, 0x3e, 0x91, 0xfb, 0xb6,
0xf3, 0x54, 0xa8, 0x95, 0xf7, 0x86, 0xd6, 0x84, 0x56, 0xf2, 0x00, 0x02, 0xa1, 0x4d, 0x9c, 0x69,
0x9b, 0x38, 0x2b, 0xe5, 0xda, 0xcc, 0xe3, 0x91, 0xc5, 0x79, 0xb2, 0x6c, 0xe3, 0xff, 0x1d, 0x4f,
0x86, 0xda, 0x7f, 0x8c, 0x27, 0xfd, 0x5b, 0x79, 0xd2, 0xbf, 0x89, 0xa7, 0xbe, 0x4d, 0x91, 0x64,
0x39, 0x94, 0x20, 0x4d, 0x5d, 0x31, 0x4c, 0x4a, 0x40, 0x34, 0x29, 0x1b, 0xc8, 0x18, 0xe4, 0x4f,
0xf4, 0x4d, 0x8f, 0xb2, 0x36, 0x21, 0xad, 0x67, 0x25, 0xbe, 0x01, 0x03, 0x49, 0x1b, 0x50, 0x6d,
0x62, 0x83, 0xf6, 0x27, 0xa7, 0xa6, 0x5b, 0x36, 0x97, 0x1c, 0x1e, 0xcf, 0x25, 0x67, 0x02, 0x38,
0xd6, 0x86, 0xd3, 0x92, 0x4f, 0x6c, 0x24, 0xda, 0x3c, 0xe4, 0x1a, 0x48, 0xae, 0x4d, 0x6c, 0xd4,
0x26, 0x3f, 0x2a, 0xab, 0x28, 0x06, 0xf7, 0xc8, 0xaa, 0x6d, 0x64, 0xc5, 0xbc, 0x40, 0xb8, 0x57,
0xe8, 0xf2, 0x5e, 0xa1, 0x91, 0xff, 0xd9, 0x22, 0xf7, 0x51, 0xe9, 0x2d, 0x4d, 0xff, 0x3f, 0x94,
0xde, 0xe9, 0xab, 0x4f, 0x4b, 0xff, 0xa4, 0xa5, 0xb5, 0x1d, 0x2d, 0xbd, 0xf6, 0xf1, 0xff, 0x91,
0xac, 0x0f, 0xe5, 0xb1, 0x69, 0x4e, 0x97, 0xc4, 0x4f, 0xe6, 0x31, 0x4b, 0x37, 0xc1, 0x34, 0xcd,
0x12, 0xd7, 0xaa, 0xa2, 0xf5, 0x5d, 0x62, 0x1b, 0x49, 0xd3, 0xb5, 0x1d, 0xd9, 0x32, 0x91, 0xc1,
0x61, 0x5b, 0x0c, 0x55, 0x17, 0xb5, 0xc5, 0x32, 0x50, 0x45, 0x4a, 0xf1, 0x46, 0x51, 0x51, 0x51,
0x44, 0x57, 0x23, 0x81, 0x44, 0x25, 0x48, 0xb3, 0x14, 0x1d, 0xc9, 0x1a, 0xe5, 0x41, 0xc7, 0xf6,
0xaa, 0x46, 0xb4, 0x6d, 0xc5, 0x75, 0x91, 0xc6, 0xa1, 0x19, 0x0b, 0x85, 0xc2, 0x30, 0x58, 0x39,
0x37, 0x51, 0x75, 0x6d, 0xd4, 0x00, 0x83, 0x55, 0x68, 0x07, 0xcd, 0x93, 0x45, 0x35, 0xd9, 0x55,
0x0c, 0xdd, 0x62, 0x39, 0xde, 0xd0, 0x0d, 0x09, 0x05, 0x4d, 0xb5, 0x54, 0xaa, 0x48, 0x26, 0xfa,
0x06, 0xd4, 0x12, 0xdb, 0x94, 0x2d, 0x4b, 0x31, 0x49, 0x1a, 0xd4, 0x12, 0x13, 0x64, 0x40, 0x5a,
0x87, 0xd6, 0x5c, 0x14, 0x16, 0x14, 0x28, 0xc5, 0x45, 0xe5, 0xd6, 0x55, 0x86, 0xa1, 0x2a, 0x86,
0x61, 0x53, 0x47, 0xe0, 0xa2, 0xcd, 0x40, 0xfd, 0xd2, 0xf5, 0x12, 0x95, 0x90, 0x2a, 0x37, 0x8a,
0x04, 0x4a, 0x95, 0xa1, 0xa8, 0x36, 0x4a, 0xbb, 0x03, 0x2e, 0x11, 0xa1, 0x60, 0x4b, 0xc5, 0x24,
0x9a, 0x03, 0x03, 0x2d, 0x8d, 0xe9, 0xa0, 0x76, 0xba, 0x92, 0x06, 0x8d, 0xa3, 0x42, 0xaf, 0x87,
0xae, 0xc1, 0x8d, 0x8b, 0x22, 0x85, 0xa2, 0xd4, 0xc7, 0x04, 0xc4, 0x05, 0x9b, 0x06, 0x5e, 0x8d,
0x27, 0x2a, 0x9c, 0xa9, 0x99, 0xa4, 0x79, 0xec, 0xdf, 0xef, 0xc3, 0x96, 0x16, 0x76, 0xd0, 0x56,
0x3b, 0xf0, 0x0d, 0x1d, 0x70, 0xad, 0xa9, 0x7d, 0xd4, 0x62, 0xa8, 0x80, 0xb8, 0xd6, 0x0c, 0x74,
0x13, 0xa6, 0xed, 0x0a, 0xa6, 0x38, 0x87, 0xe4, 0x32, 0x1a, 0xf5, 0x0c, 0x00, 0x9b, 0x4c, 0x0e,
0x53, 0x08, 0x15, 0xd0, 0xae, 0x0e, 0xf2, 0x1e, 0x59, 0xa1, 0x6f, 0x50, 0xa1, 0x74, 0x4c, 0x28,
0x51, 0x85, 0x0c, 0x8e, 0xd0, 0x8c, 0x2d, 0x14, 0x65, 0x91, 0x12, 0x35, 0xdb, 0x96, 0x4c, 0xf8,
0x10, 0x7a, 0x20, 0xa8, 0xc0, 0x42, 0x7c, 0x40, 0x3c, 0x98, 0x66, 0xa5, 0xee, 0x95, 0xfa, 0x5d,
0x15, 0x75, 0x13, 0xba, 0x80, 0x8c, 0xae, 0x43, 0xfd, 0x99, 0x62, 0x50, 0x69, 0xdf, 0x32, 0xa4,
0x18, 0xff, 0xf9, 0x33, 0xd4, 0x8c, 0x0e, 0xaa, 0x4f, 0xf8, 0x8e, 0x4b, 0xc9, 0x0e, 0xd5, 0xb8,
0x6f, 0x6a, 0x64, 0x5b, 0xd7, 0x41, 0x3e, 0x07, 0x15, 0x0d, 0x60, 0x1d, 0x3e, 0xa6, 0xa2, 0x39,
0x5b, 0x8d, 0x4d, 0x9d, 0xf6, 0x25, 0x25, 0xe9, 0x36, 0x78, 0x83, 0x85, 0x75, 0xaa, 0xd4, 0x16,
0x78, 0x24, 0xaf, 0x68, 0x3c, 0x35, 0xc7, 0x65, 0x8d, 0x95, 0x8a, 0xe4, 0x0d, 0x4d, 0x6a, 0xa6,
0x68, 0x03, 0xac, 0xd5, 0x2e, 0xab, 0x5d, 0x65, 0x0b, 0xd3, 0xc4, 0xac, 0x4b, 0x4d, 0x04, 0x9a,
0x4c, 0xd2, 0x3b, 0xda, 0x33, 0x97, 0x01, 0x35, 0x34, 0xae, 0x16, 0x48, 0xae, 0x86, 0x78, 0xbb,
0xd4, 0x78, 0x21, 0xb2, 0x74, 0xe8, 0x1a, 0xab, 0x55, 0x6a, 0x14, 0x11, 0xe5, 0x60, 0xdd, 0x80,
0xd5, 0x90, 0x39, 0xa8, 0x24, 0xb9, 0xe8, 0x78, 0x6c, 0x97, 0xbd, 0xfa, 0x62, 0x92, 0x9a, 0x27,
0x72, 0x70, 0x7b, 0x3d, 0xe6, 0x8b, 0x28, 0x99, 0x82, 0x45, 0xcd, 0xd0, 0x60, 0x5d, 0x00, 0x55,
0x98, 0x12, 0xdd, 0x4c, 0x93, 0x81, 0x1d, 0x82, 0x38, 0xc8, 0xc7, 0x3b, 0xc4, 0xb0, 0x01, 0x53,
0x91, 0x5b, 0xa9, 0x20, 0xd3, 0xb7, 0xac, 0x00, 0x11, 0xa0, 0xa9, 0x14, 0xc6, 0x26, 0xc2, 0xd0,
0x91, 0x55, 0xf4, 0x6b, 0xba, 0x6c, 0x93, 0xaf, 0xc9, 0xd4, 0x7a, 0xc9, 0xb0, 0xbe, 0xdb, 0x67,
0x99, 0xc5, 0x51, 0x0d, 0xb2, 0xb3, 0x46, 0xf9, 0x1b, 0x76, 0x31, 0xa9, 0xd5, 0x83, 0xc3, 0x20,
0xa8, 0x11, 0xf9, 0xba, 0x46, 0x28, 0xae, 0x8e, 0xa4, 0x88, 0xa8, 0x40, 0x43, 0x6e, 0x93, 0x6f,
0xea, 0x3a, 0x01, 0x5c, 0xea, 0x8e, 0x29, 0x0f, 0x1a, 0x26, 0xb9, 0x23, 0x9c, 0x19, 0x7a, 0x70,
0x75, 0xf8, 0x1d, 0x19, 0xcf, 0x65, 0xed, 0x23, 0xfc, 0x4c, 0x8c, 0xe0, 0xe8, 0xae, 0x4b, 0x1a,
0xb6, 0x6c, 0xa6, 0x24, 0x62, 0x80, 0x14, 0x8b, 0xd6, 0xce, 0x6c, 0x3e, 0xe1, 0xdf, 0x3a, 0xe5,
0x4d, 0xec, 0xac, 0x92, 0x9f, 0xc2, 0xaa, 0xeb, 0xe5, 0x62, 0x33, 0xbc, 0x34, 0xc3, 0x90, 0xa8,
0x4f, 0xa7, 0xee, 0x8e, 0x22, 0x55, 0x02, 0x44, 0x17, 0xec, 0xe8, 0x82, 0x37, 0x24, 0x1e, 0x0d,
0x51, 0x45, 0x3e, 0xa5, 0x53, 0xee, 0x37, 0x55, 0x47, 0x76, 0xc8, 0x6b, 0x2c, 0x2e, 0x9b, 0x26,
0x44, 0xa5, 0x68, 0x33, 0x0c, 0x83, 0xb6, 0x75, 0x1d, 0x17, 0xd1, 0xe6, 0xc2, 0x59, 0x6d, 0x2a,
0x69, 0x92, 0x46, 0x34, 0x98, 0x66, 0xf0, 0x62, 0xed, 0x3b, 0x0e, 0x29, 0x64, 0x6f, 0x83, 0xb9,
0x79, 0x1f, 0xfb, 0x23, 0xe8, 0xe8, 0x68, 0x20, 0x46, 0xe8, 0xb9, 0x01, 0x2b, 0x65, 0x16, 0xb9,
0x20, 0x67, 0xc8, 0x0c, 0xe0, 0x30, 0x80, 0xa9, 0x06, 0x44, 0xa4, 0xcf, 0x62, 0x5d, 0xef, 0x53,
0x48, 0x21, 0xc7, 0xea, 0x24, 0xb3, 0x6d, 0x38, 0xb2, 0xc6, 0x05, 0x62, 0xc4, 0xfa, 0x92, 0xb0,
0x0d, 0xb7, 0x94, 0x24, 0x6c, 0xc3, 0x2d, 0x25, 0x35, 0xd8, 0x47, 0x80, 0x71, 0xe3, 0x30, 0x4b,
0x49, 0xdc, 0x3a, 0xcc, 0x52, 0x12, 0xb7, 0x0e, 0x57, 0x87, 0xc4, 0xcc, 0x63, 0x30, 0x53, 0xb1,
0xd6, 0x1d, 0x49, 0x8f, 0xeb, 0x53, 0x62, 0xda, 0x5d, 0x0d, 0xb8, 0x81, 0x44, 0xdb, 0xbd, 0x32,
0x94, 0x54, 0x33, 0x11, 0x1d, 0xd5, 0xc8, 0x48, 0xb6, 0xcc, 0x6d, 0xc3, 0x0c, 0x45, 0x41, 0xb4,
0x31, 0xb4, 0xcc, 0xd5, 0xc6, 0xec, 0x84, 0x00, 0x81, 0x69, 0x74, 0x66, 0x27, 0x93, 0x82, 0xa1,
0xe6, 0x36, 0xcc, 0x36, 0xdc, 0x50, 0x36, 0xcb, 0x42, 0x14, 0xd1, 0xdc, 0x52, 0x52, 0xc3, 0x0d,
0x35, 0xe2, 0xce, 0xa5, 0x88, 0x84, 0xa5, 0x58, 0xde, 0x23, 0xeb, 0x90, 0xa5, 0xa4, 0x95, 0xba,
0x6c, 0xfe, 0x32, 0x49, 0xcd, 0xb4, 0x71, 0x5f, 0x65, 0x09, 0x71, 0x6d, 0x29, 0x64, 0x59, 0x66,
0x02, 0x31, 0x2a, 0x61, 0x1a, 0x6e, 0x24, 0x36, 0x0f, 0xf5, 0x73, 0x0b, 0x06, 0x20, 0xe7, 0x30,
0x2b, 0x69, 0x94, 0x6b, 0x6d, 0xd3, 0xe2, 0x56, 0xb2, 0x38, 0x21, 0x97, 0x5b, 0xc9, 0x95, 0x84,
0x5d, 0x98, 0x95, 0x74, 0x89, 0xec, 0x62, 0x09, 0x23, 0x09, 0xce, 0x0d, 0x69, 0xc5, 0xb9, 0xc6,
0x92, 0x0b, 0x33, 0x12, 0xb1, 0x89, 0x52, 0xc0, 0x8c, 0xa4, 0x3a, 0x5c, 0x19, 0x92, 0x70, 0x5a,
0x32, 0x8c, 0xce, 0xad, 0x64, 0x33, 0x6d, 0x22, 0xa3, 0x33, 0x3b, 0xf5, 0x57, 0xa3, 0x55, 0x10,
0xad, 0x6c, 0x54, 0xb7, 0x4d, 0xf3, 0xc9, 0xec, 0x43, 0x59, 0x92, 0xdb, 0x86, 0x19, 0x4a, 0x2c,
0x17, 0x86, 0x92, 0x98, 0x71, 0x1c, 0x6e, 0x29, 0x89, 0x1b, 0x87, 0x59, 0x4a, 0xf0, 0x63, 0x0a,
0xe6, 0x98, 0x6d, 0x6c, 0x61, 0x29, 0xc9, 0xe4, 0x59, 0x95, 0x5b, 0x8a, 0x0b, 0xb8, 0x32, 0x94,
0xc4, 0x4d, 0xc3, 0x83, 0x08, 0x76, 0x72, 0xa1, 0x59, 0x6e, 0x27, 0xe1, 0xd8, 0xc2, 0x52, 0xb2,
0xb0, 0x0d, 0xb7, 0x94, 0x08, 0x0f, 0x61, 0x29, 0xb9, 0x61, 0xa9, 0x52, 0xd8, 0x07, 0xc7, 0xea,
0xda, 0x3c, 0xce, 0xd3, 0x3c, 0x86, 0x24, 0xb2, 0x94, 0xc4, 0x43, 0x48, 0xe2, 0x21, 0x24, 0xd5,
0x29, 0xb9, 0x22, 0xbd, 0x09, 0x53, 0x89, 0xf4, 0xc6, 0x4d, 0x25, 0x37, 0x58, 0x67, 0xd9, 0xcd,
0xe2, 0x86, 0xb2, 0x64, 0x61, 0x1b, 0x6e, 0x29, 0xb9, 0xa6, 0x0c, 0x5d, 0x16, 0xc6, 0x61, 0x96,
0x92, 0x1b, 0xb6, 0x91, 0xff, 0x5d, 0xda, 0x15, 0xf5, 0xc6, 0x6d, 0x23, 0xe1, 0xbf, 0x42, 0xdc,
0xbd, 0xf4, 0x80, 0xca, 0x15, 0x29, 0x91, 0xa2, 0x8a, 0x34, 0x40, 0x93, 0xbb, 0xb4, 0x05, 0x2e,
0x81, 0x11, 0x07, 0xd7, 0xdc, 0xd3, 0x61, 0x23, 0x3b, 0x89, 0x91, 0x8d, 0x6d, 0x58, 0x4e, 0xda,
0xe4, 0xd7, 0xdf, 0x7c, 0xdf, 0x8c, 0x76, 0x25, 0xed, 0xca, 0x51, 0x93, 0x07, 0xef, 0x2e, 0x2d,
0x69, 0x48, 0x0e, 0x67, 0x86, 0x33, 0xdf, 0x8c, 0xa4, 0x11, 0x73, 0xa5, 0x35, 0x28, 0x91, 0x69,
0xcc, 0xd8, 0xda, 0xd9, 0x12, 0x95, 0xce, 0x2c, 0x9d, 0xae, 0x8d, 0x59, 0xbb, 0xe9, 0x42, 0x9b,
0x48, 0x63, 0xa1, 0x92, 0x1a, 0xb8, 0x61, 0xa1, 0x38, 0x9c, 0x41, 0xbd, 0x6d, 0x6d, 0x74, 0xa5,
0x0a, 0x5b, 0x1b, 0x5d, 0xa9, 0x9d, 0x89, 0x30, 0x63, 0x1e, 0x48, 0x17, 0x2b, 0x95, 0xcc, 0xc4,
0xe9, 0x4a, 0x15, 0x63, 0xe1, 0x6e, 0xd4, 0xc2, 0x65, 0x5b, 0x29, 0xb5, 0x70, 0x71, 0x6c, 0xc8,
0x06, 0x6d, 0xc9, 0x7d, 0x01, 0xcc, 0x43, 0x6d, 0xdd, 0x44, 0xbd, 0xc4, 0x91, 0x92, 0x98, 0x1d,
0x6e, 0xa5, 0x81, 0x29, 0x1c, 0xb0, 0x4c, 0x19, 0xbe, 0x9a, 0x8c, 0x14, 0xfb, 0x04, 0x1b, 0x9f,
0x9f, 0x4a, 0x68, 0x60, 0x0e, 0x7a, 0x04, 0x42, 0x11, 0x69, 0x7a, 0x64, 0xcf, 0x14, 0x0d, 0xaa,
0x82, 0x62, 0x52, 0xe2, 0x4b, 0xb5, 0x5e, 0x9c, 0x37, 0xd9, 0x9c, 0x21, 0xac, 0x00, 0x13, 0x1a,
0x59, 0x85, 0x00, 0xc1, 0x91, 0x88, 0xbf, 0x24, 0x74, 0x91, 0x1b, 0x42, 0x09, 0xa1, 0xd5, 0xbd,
0xa7, 0x4e, 0x45, 0x14, 0xff, 0x84, 0xa6, 0xb0, 0x6c, 0x70, 0x7a, 0x2d, 0x9b, 0x34, 0xdc, 0xbb,
0x26, 0x5a, 0x43, 0x76, 0x79, 0x9f, 0x83, 0xa2, 0x46, 0xa9, 0x15, 0x47, 0x07, 0x0e, 0x61, 0x4d,
0x6f, 0x16, 0xfe, 0x52, 0x85, 0x7d, 0x5b, 0x7f, 0x37, 0x70, 0xd0, 0x54, 0x9f, 0x80, 0x6e, 0x04,
0x76, 0xc6, 0xcb, 0xbd, 0x03, 0xad, 0x4c, 0xb9, 0x6f, 0x68, 0xca, 0x1a, 0xe1, 0x70, 0x90, 0xab,
0x2a, 0xd0, 0x4f, 0x29, 0x38, 0x1b, 0x8d, 0x8d, 0xad, 0x86, 0x77, 0x04, 0xe6, 0x07, 0x48, 0x12,
0x66, 0x24, 0x2e, 0x9a, 0xcc, 0x45, 0x2c, 0xb8, 0xb5, 0x74, 0xba, 0x12, 0x8f, 0xa8, 0x86, 0x2a,
0x33, 0xbc, 0xcd, 0x7e, 0x38, 0xda, 0xe9, 0xfc, 0x0b, 0x63, 0x86, 0xce, 0xbf, 0x20, 0x37, 0x52,
0x31, 0xed, 0x51, 0x19, 0xe0, 0xc0, 0x8d, 0xa0, 0x0c, 0xa8, 0x75, 0xd0, 0x03, 0x03, 0xb4, 0x61,
0x4c, 0x50, 0x1f, 0x3f, 0x15, 0x63, 0x66, 0x18, 0x1b, 0xd4, 0xf0, 0x0b, 0x23, 0x38, 0xff, 0xc2,
0x98, 0x31, 0x22, 0x35, 0xcc, 0xbf, 0x30, 0x6e, 0x28, 0x03, 0x0a, 0xe5, 0xc6, 0x74, 0x6d, 0x94,
0x01, 0x4e, 0xb9, 0xa1, 0xf3, 0x77, 0xd3, 0xf9, 0x5b, 0xb3, 0x1f, 0x18, 0x50, 0x0c, 0xfc, 0x50,
0x69, 0x30, 0x6e, 0x75, 0xc6, 0x01, 0x78, 0xc4, 0x58, 0x52, 0x8a, 0x83, 0x23, 0x3b, 0x6a, 0xeb,
0xd2, 0x16, 0x40, 0x19, 0xe0, 0xc8, 0x8d, 0xc8, 0x51, 0x33, 0x08, 0x29, 0x9b, 0x60, 0x0d, 0x5b,
0xcf, 0xd2, 0x29, 0x27, 0x8c, 0x03, 0x53, 0x41, 0xd0, 0xdf, 0x8d, 0x79, 0x57, 0xca, 0x81, 0x22,
0xb0, 0x33, 0xe3, 0x80, 0xb2, 0x83, 0x0c, 0xa8, 0x1c, 0xd9, 0x51, 0x2b, 0x03, 0x9c, 0x71, 0xc3,
0x46, 0x63, 0x63, 0x23, 0x03, 0x1c, 0xb9, 0x61, 0x02, 0xde, 0xb8, 0x09, 0x3b, 0xdc, 0x20, 0x0e,
0xc5, 0xa0, 0x0d, 0xaa, 0x1c, 0xc5, 0xe4, 0x70, 0xd3, 0x71, 0xfe, 0xa6, 0x1b, 0xce, 0xd4, 0xc1,
0xb8, 0x31, 0xed, 0x51, 0x19, 0xa0, 0xca, 0xa1, 0x0c, 0xa8, 0x8b, 0x31, 0x03, 0xac, 0x31, 0x88,
0x83, 0xce, 0xd9, 0x8d, 0x99, 0x61, 0x9f, 0x6a, 0xc2, 0xca, 0xb6, 0x50, 0x75, 0x30, 0x66, 0xa8,
0x3a, 0x18, 0x2f, 0x75, 0xfe, 0xa6, 0x1c, 0xc6, 0x00, 0x55, 0x0e, 0x37, 0x5d, 0x1b, 0x65, 0x80,
0x2a, 0x87, 0x9b, 0xa8, 0xc3, 0x30, 0x7f, 0x6b, 0x1e, 0x8b, 0xf1, 0x61, 0x41, 0x52, 0x92, 0x80,
0xa6, 0xfb, 0xb2, 0x10, 0xf7, 0xcb, 0x4a, 0xbe, 0x30, 0xcf, 0x45, 0x39, 0x50, 0xd3, 0x55, 0x63,
0x39, 0xba, 0x2f, 0x5b, 0xfc, 0x7e, 0x69, 0xb7, 0xee, 0xbe, 0xe8, 0x71, 0xf5, 0x8b, 0xee, 0xf2,
0x8a, 0x00, 0xe2, 0xed, 0xc5, 0xe6, 0x76, 0x0d, 0x9c, 0x39, 0x01, 0xe5, 0xb1, 0xb5, 0x12, 0x4e,
0x3f, 0x89, 0xb2, 0xa5, 0x78, 0xca, 0x08, 0xf6, 0x26, 0xc0, 0xc2, 0x88, 0xa0, 0xe5, 0x84, 0x2c,
0xde, 0x74, 0x38, 0xc1, 0x06, 0x08, 0x44, 0x39, 0xcb, 0x8e, 0xa0, 0xb8, 0x79, 0x90, 0xe5, 0xf2,
0x01, 0x4e, 0xad, 0x97, 0x78, 0x83, 0xdc, 0x4b, 0xb5, 0xb8, 0xc1, 0xb2, 0xb9, 0x62, 0xb3, 0x44,
0x60, 0x8b, 0x6f, 0xd9, 0xa5, 0x12, 0x02, 0x8a, 0x40, 0xc0, 0xdf, 0xe7, 0x9d, 0x15, 0xa9, 0x24,
0x2c, 0xcd, 0xb2, 0x1b, 0xc8, 0x35, 0x4d, 0x44, 0x1c, 0xcf, 0x60, 0x49, 0xf6, 0x85, 0xa1, 0x19,
0x2a, 0x19, 0x55, 0x26, 0xab, 0x6b, 0xdd, 0x03, 0xbc, 0xc4, 0xcc, 0x11, 0x11, 0xa6, 0xf4, 0x05,
0xa7, 0x43, 0x3e, 0xed, 0x37, 0xc4, 0x50, 0xd4, 0x10, 0x53, 0xae, 0x08, 0x16, 0x42, 0x31, 0xb0,
0xd5, 0x47, 0xc4, 0xa0, 0x1e, 0x0a, 0xd2, 0x8a, 0xd3, 0x25, 0xbb, 0x6a, 0x88, 0x9e, 0xbe, 0x44,
0x43, 0x3d, 0xad, 0xc5, 0x50, 0xd4, 0x70, 0x50, 0x2a, 0x84, 0xf0, 0x51, 0x7c, 0x4d, 0xd9, 0xd6,
0x52, 0x39, 0xec, 0x04, 0x40, 0x60, 0xa2, 0xb8, 0x84, 0x12, 0xc9, 0x9a, 0x49, 0x4f, 0x08, 0x01,
0x1a, 0x64, 0x0a, 0xec, 0xc4, 0x3a, 0x29, 0x6e, 0x22, 0x4a, 0x51, 0x37, 0x4e, 0x42, 0xe7, 0x2c,
0xfe, 0xbe, 0x75, 0xa7, 0xbd, 0x97, 0xbb, 0xa6, 0x4d, 0xa3, 0xd4, 0xa1, 0x0f, 0xd3, 0x71, 0xa3,
0xe9, 0xc8, 0x31, 0xd1, 0x17, 0xc4, 0x9e, 0xe8, 0x19, 0x46, 0x20, 0x66, 0xba, 0xce, 0xca, 0x13,
0x67, 0x3c, 0x41, 0xe8, 0x8f, 0x7c, 0x47, 0x12, 0xad, 0x8e, 0xe2, 0xf7, 0xc3, 0xb7, 0x80, 0xeb,
0x2c, 0x2b, 0x5b, 0xa7, 0x81, 0xd9, 0x6e, 0x60, 0xb6, 0x87, 0x25, 0x80, 0xcb, 0x56, 0x8a, 0x96,
0x32, 0x2d, 0x51, 0xd2, 0x75, 0x00, 0x7a, 0xde, 0xc0, 0xac, 0xe9, 0x4a, 0xba, 0x61, 0x25, 0x2b,
0xf8, 0x3b, 0x62, 0xfb, 0x11, 0x2b, 0x6a, 0x14, 0x41, 0x51, 0x50, 0xb9, 0xd0, 0xc6, 0xe7, 0xa7,
0x36, 0x05, 0xe8, 0x47, 0x47, 0xd1, 0x68, 0x33, 0xd4, 0x31, 0xc0, 0x41, 0x83, 0xff, 0x96, 0x7c,
0x6d, 0x0d, 0xfd, 0x84, 0x7d, 0x89, 0x10, 0x1c, 0x4e, 0xbb, 0x12, 0x27, 0x21, 0xc0, 0x91, 0x90,
0xfd, 0x2a, 0x20, 0xcd, 0x20, 0xff, 0xaf, 0x64, 0xb8, 0x95, 0x4c, 0x19, 0x8e, 0x9b, 0x44, 0xd3,
0xd9, 0x33, 0x74, 0x17, 0xeb, 0x02, 0x30, 0x48, 0x0c, 0xe2, 0x49, 0x8a, 0xc2, 0x25, 0xf1, 0x30,
0xe8, 0x8f, 0x0b, 0x5f, 0xe0, 0xe5, 0x89, 0xad, 0x8c, 0x50, 0x98, 0xf6, 0xa4, 0xca, 0x20, 0x5d,
0x01, 0x12, 0x01, 0x52, 0x07, 0xe6, 0xd9, 0xc9, 0xc5, 0x70, 0xb2, 0x84, 0xcd, 0x70, 0xd1, 0x11,
0xd7, 0x07, 0xc0, 0xc7, 0xda, 0xb1, 0xcc, 0x1f, 0x51, 0x40, 0xbd, 0x6b, 0x0f, 0x03, 0x29, 0x87,
0x79, 0x15, 0x9c, 0x4f, 0xd2, 0xf9, 0x4c, 0x3e, 0x73, 0x83, 0x0c, 0x0c, 0x37, 0x4c, 0xb1, 0x6f,
0x31, 0x21, 0x11, 0xd2, 0x00, 0xd0, 0x6a, 0x2b, 0x65, 0x71, 0x25, 0xac, 0x6f, 0xc1, 0x52, 0x40,
0x7d, 0xe2, 0x24, 0x01, 0x78, 0x94, 0x51, 0x21, 0xad, 0x22, 0x04, 0x22, 0x80, 0x8c, 0x5a, 0x61,
0x1b, 0xb6, 0x24, 0xa0, 0x2c, 0x11, 0x68, 0xc0, 0x53, 0x8d, 0xde, 0x8e, 0x15, 0x7a, 0xac, 0x43,
0x3e, 0xa6, 0x8e, 0x09, 0x09, 0xad, 0x4a, 0x36, 0x5d, 0xe0, 0x31, 0x1e, 0x7d, 0x59, 0x1f, 0xd6,
0xe7, 0xd0, 0x5e, 0x61, 0x32, 0xfa, 0xbb, 0xcd, 0xed, 0x0a, 0x8b, 0xd1, 0x08, 0x61, 0x64, 0x68,
0xf6, 0x36, 0xa3, 0x8c, 0xb4, 0x19, 0x08, 0xf7, 0x3c, 0x13, 0x4b, 0x22, 0x1b, 0x21, 0x8a, 0x77,
0x89, 0x70, 0x64, 0x2b, 0x3a, 0xd9, 0xd2, 0x7b, 0x45, 0x82, 0xaa, 0xf5, 0x61, 0x68, 0x3b, 0x6b,
0xc3, 0xa5, 0x01, 0xbd, 0x9a, 0xbb, 0xbd, 0xb0, 0xd8, 0x7b, 0xa6, 0x9f, 0x90, 0xb0, 0x68, 0x80,
0x9e, 0x08, 0xd1, 0xe4, 0x81, 0x45, 0xb4, 0xb2, 0x4b, 0x89, 0xd0, 0x34, 0xf4, 0xbe, 0x4b, 0xf4,
0x16, 0x4f, 0x40, 0x57, 0xf8, 0x08, 0x7c, 0x22, 0xca, 0x35, 0xed, 0x56, 0xb4, 0x92, 0xb9, 0xad,
0x16, 0x03, 0x03, 0x1b, 0xe4, 0x1c, 0x09, 0xfa, 0xf4, 0x3b, 0x76, 0x12, 0xf9, 0x34, 0x42, 0x46,
0x3f, 0x5b, 0x6e, 0x38, 0x1e, 0x0d, 0xe0, 0x24, 0xa1, 0xa1, 0x8a, 0xb7, 0xbe, 0xee, 0x3d, 0x6c,
0x4f, 0x50, 0x84, 0x2d, 0x10, 0x9c, 0x63, 0xc6, 0xab, 0xae, 0xf2, 0x16, 0x94, 0x31, 0x1d, 0x74,
0x14, 0xa1, 0xb6, 0x01, 0x07, 0x43, 0x4d, 0xe8, 0xb0, 0xab, 0xe9, 0x64, 0x67, 0x62, 0x7a, 0x58,
0x59, 0x22, 0xc2, 0xb0, 0x35, 0xc2, 0x2c, 0x4c, 0x85, 0xad, 0xde, 0xc3, 0xc2, 0x06, 0x71, 0x4d,
0xa0, 0xb6, 0x7a, 0xc8, 0xe9, 0xa1, 0xad, 0xd2, 0x73, 0x46, 0xcf, 0x59, 0x6f, 0x4e, 0x7b, 0xeb,
0x5a, 0x0d, 0xe2, 0xc4, 0xc9, 0xa6, 0x8c, 0x84, 0x1a, 0x91, 0x7d, 0x05, 0xdf, 0x0c, 0x43, 0x54,
0xe7, 0x3a, 0xf7, 0x0a, 0x73, 0x81, 0x95, 0x55, 0xa5, 0xf3, 0x72, 0x3a, 0xaf, 0xed, 0xc0, 0x0f,
0x67, 0xfc, 0x70, 0xca, 0x2e, 0x67, 0xec, 0xea, 0xc0, 0x6a, 0x20, 0x57, 0x00, 0xea, 0xa8, 0xdf,
0x50, 0x25, 0x78, 0x76, 0xe4, 0xb1, 0x53, 0x1e, 0xcb, 0x9a, 0xd7, 0x1e, 0x71, 0xb8, 0x27, 0xca,
0x90, 0x24, 0x40, 0x11, 0x53, 0x52, 0x11, 0x22, 0x11, 0xb5, 0xe3, 0x6f, 0xdd, 0x25, 0x81, 0x89,
0x23, 0x04, 0x41, 0xf2, 0x26, 0xc3, 0xef, 0x97, 0xa1, 0x53, 0xf5, 0x20, 0x20, 0xa4, 0x20, 0x02,
0x02, 0x83, 0x53, 0x03, 0xb9, 0x0c, 0x90, 0xa1, 0x04, 0x24, 0x20, 0x46, 0xac, 0x44, 0x44, 0x9c,
0x23, 0xe6, 0xe4, 0xa4, 0xd2, 0xe0, 0x4b, 0x4e, 0x81, 0xa9, 0xc0, 0x82, 0x61, 0xe7, 0x6c, 0x10,
0xd1, 0x09, 0xb7, 0x24, 0x90, 0xda, 0x7a, 0xd8, 0x5f, 0xa6, 0x00, 0xf5, 0x3b, 0xc0, 0x50, 0x56,
0x1e, 0x38, 0xb3, 0x08, 0x0a, 0x44, 0xac, 0xcc, 0x25, 0x28, 0xd5, 0x04, 0x63, 0xe1, 0x6f, 0x0a,
0x91, 0x86, 0x1e, 0x74, 0x82, 0x77, 0x8d, 0x90, 0x71, 0x4b, 0xc0, 0x50, 0xe4, 0x5d, 0x54, 0xab,
0x84, 0x58, 0x0f, 0x6d, 0x67, 0x6d, 0x84, 0x37, 0x89, 0x3d, 0x57, 0xe8, 0xab, 0x04, 0xb3, 0x18,
0x57, 0x67, 0xa5, 0xe3, 0x06, 0x3a, 0xd6, 0xbd, 0xd3, 0xee, 0x9d, 0x8e, 0xaa, 0xb6, 0xef, 0xd4,
0x45, 0x73, 0x4c, 0x81, 0xd7, 0x8a, 0x24, 0x88, 0x53, 0xc9, 0xc5, 0x8f, 0x9c, 0x92, 0xb3, 0x29,
0x19, 0x1f, 0x9c, 0xf1, 0xc1, 0x29, 0x9b, 0x80, 0x11, 0x90, 0x4d, 0x9d, 0x74, 0x15, 0x10, 0xbb,
0x97, 0x19, 0x44, 0x10, 0x54, 0x93, 0x9d, 0xc6, 0x5b, 0x6d, 0xac, 0x41, 0x1a, 0x6f, 0xaf, 0xfb,
0x7e, 0x4d, 0xbe, 0xa0, 0x56, 0xf7, 0x34, 0x56, 0x62, 0xe9, 0xb6, 0x21, 0x8b, 0xdc, 0xb4, 0x40,
0x73, 0xf1, 0x0d, 0xb9, 0x04, 0x56, 0xcc, 0x4f, 0xa7, 0xbf, 0xe1, 0xda, 0x95, 0xd8, 0x03, 0xaa,
0x44, 0x56, 0xb6, 0x44, 0x8f, 0xf5, 0x53, 0x8f, 0x59, 0x83, 0xc7, 0x65, 0xb3, 0xde, 0x1a, 0x31,
0xe0, 0xdf, 0x13, 0xe2, 0xc3, 0xff, 0xbb, 0x62, 0xdf, 0xcb, 0x31, 0x1a, 0xb0, 0x42, 0x6c, 0xba,
0xd1, 0x79, 0x6e, 0x18, 0x87, 0xd3, 0x73, 0xb6, 0xd3, 0x4e, 0xf2, 0xbc, 0xd3, 0x6e, 0x44, 0xa2,
0x39, 0x4a, 0x42, 0x58, 0x20, 0x22, 0x8e, 0x89, 0x7a, 0xd1, 0x43, 0xac, 0x59, 0xdd, 0x32, 0xab,
0x00, 0x41, 0x61, 0xa3, 0xf7, 0x95, 0x4a, 0x11, 0xb3, 0xde, 0x7a, 0xa4, 0xc0, 0x91, 0x76, 0x3b,
0xed, 0x35, 0xbb, 0x79, 0xef, 0x4a, 0x78, 0x4f, 0x5e, 0x5c, 0x90, 0x11, 0x7d, 0xbf, 0x48, 0xdf,
0x2b, 0xfd, 0x6e, 0x3c, 0xf3, 0x63, 0xeb, 0x50, 0x6d, 0x67, 0x5c, 0xcd, 0x2b, 0x44, 0x64, 0x73,
0x7b, 0x7b, 0xfd, 0x07, 0x8b, 0x84, 0x8b, 0xee, 0xf2, 0xb6, 0xdb, 0x5e, 0xac, 0x10, 0x17, 0xc3,
0xce, 0x99, 0xf2, 0x10, 0x95, 0xe9, 0x46, 0x18, 0x3a, 0x32, 0x1c, 0x53, 0xf0, 0xdc, 0x19, 0x78,
0x3e, 0xb4, 0x7b, 0x03, 0xe4, 0x1d, 0x01, 0xf9, 0x68, 0x87, 0x51, 0x5e, 0xa0, 0xa7, 0x0f, 0xdf,
0x4a, 0x66, 0xdf, 0x1e, 0x80, 0x7b, 0xbb, 0x4c, 0xa9, 0xb4, 0x07, 0xbd, 0x4c, 0x2f, 0x0b, 0xc5,
0x94, 0x7c, 0x28, 0x86, 0xeb, 0x26, 0xe9, 0x80, 0xbc, 0x4b, 0x07, 0xec, 0x4e, 0x9b, 0x4c, 0x22,
0xec, 0x32, 0x00, 0x76, 0xd9, 0x30, 0x87, 0x59, 0x2f, 0x9f, 0x27, 0x2e, 0xb7, 0x65, 0x92, 0x4a,
0x4d, 0x1c, 0x15, 0xe3, 0x8c, 0x52, 0xc1, 0xcf, 0xde, 0xfe, 0x57, 0x8c, 0xfe, 0xa7, 0x9f, 0xe2,
0x00, 0xd8, 0xc5, 0xda, 0x76, 0xe3, 0x13, 0x95, 0x44, 0xbf, 0x94, 0xa1, 0x3a, 0x16, 0x4e, 0x79,
0x19, 0x16, 0xd1, 0x53, 0x4f, 0x08, 0x70, 0x1b, 0xc4, 0x3f, 0x14, 0x5e, 0xe1, 0x93, 0x62, 0x15,
0x4d, 0xbd, 0x47, 0x8a, 0x97, 0x07, 0x8d, 0x28, 0xdd, 0x5e, 0xf5, 0x4d, 0xf0, 0xe6, 0x5a, 0x23,
0xc6, 0x15, 0x79, 0x1e, 0x38, 0xa6, 0x09, 0xf9, 0xc2, 0xf4, 0x36, 0x06, 0x66, 0x90, 0xba, 0xa1,
0x2e, 0xe0, 0xde, 0x92, 0x83, 0x79, 0x81, 0xd1, 0xdb, 0xc2, 0x2e, 0xdf, 0x1a, 0x39, 0x67, 0xe4,
0xbb, 0xfd, 0x48, 0xe2, 0xf1, 0x91, 0x14, 0x35, 0x47, 0xc9, 0xcf, 0x82, 0x4a, 0xd6, 0x50, 0xaf,
0x12, 0x8c, 0x38, 0x94, 0x91, 0x8d, 0xbe, 0x18, 0x6b, 0x99, 0x1d, 0x2a, 0x1a, 0xb2, 0xa6, 0x18,
0xf3, 0x46, 0xf6, 0x01, 0xb3, 0x42, 0xf2, 0x83, 0x5d, 0x05, 0xd5, 0x36, 0xff, 0x17, 0x94, 0x8b,
0x25, 0xef, 0xeb, 0xb5, 0x2b, 0xc3, 0x67, 0x47, 0x3c, 0x60, 0xda, 0x55, 0x4c, 0xd4, 0x6b, 0x29,
0x37, 0xb5, 0x53, 0xaf, 0x62, 0xaa, 0x5f, 0x33, 0x05, 0xa8, 0x8b, 0x99, 0x7e, 0xcd, 0x14, 0x28,
0xb9, 0xa9, 0x7e, 0xcd, 0xd4, 0x2f, 0xcf, 0xd4, 0x32, 0xcc, 0xd4, 0x37, 0xb8, 0xa9, 0x7e, 0xcd,
0x94, 0x3f, 0xb8, 0x99, 0x7e, 0xcd, 0x14, 0x28, 0x17, 0x53, 0xfd, 0x2a, 0xee, 0xd5, 0xaf, 0x99,
0x8e, 0x1c, 0x51, 0xa6, 0xfe, 0x50, 0x6d, 0x4c, 0xbf, 0xa6, 0xba, 0x79, 0x24, 0xdb, 0xdb, 0x1f,
0xd1, 0xd7, 0x65, 0xfd, 0x6a, 0x72, 0xa2, 0x74, 0x0d, 0xfa, 0x35, 0x15, 0xa2, 0x91, 0x86, 0x8d,
0xb7, 0xb6, 0xbc, 0xdb, 0x1e, 0x47, 0x9b, 0x6b, 0x53, 0x1c, 0xd7, 0xb0, 0xb9, 0x82, 0x0d, 0x2a,
0x32, 0x2b, 0xbd, 0x71, 0xa3, 0x72, 0xa0, 0x7d, 0x59, 0xc2, 0xb8, 0xa4, 0x46, 0x35, 0x6c, 0x50,
0xb0, 0x62, 0xae, 0x61, 0xa3, 0xa1, 0xc4, 0xe3, 0x43, 0x71, 0x23, 0x15, 0x73, 0x63, 0x15, 0x73,
0x13, 0x15, 0x9b, 0xef, 0x63, 0x7b, 0x0d, 0x1b, 0xf3, 0x66, 0xd0, 0x2f, 0xf7, 0x55, 0xfa, 0x75,
0x7b, 0xdd, 0xbd, 0xbb, 0x58, 0x83, 0x84, 0x24, 0xc4, 0x81, 0x4e, 0x8b, 0x1b, 0x8b, 0x46, 0x64,
0x8c, 0x05, 0x11, 0x48, 0x06, 0xc4, 0x86, 0x59, 0x46, 0xcf, 0x0c, 0x51, 0xee, 0xf7, 0x4d, 0x67,
0xff, 0xc2, 0xb7, 0xd3, 0x7f, 0xbb, 0xe1, 0xdf, 0xfb, 0xe6, 0x70, 0xc6, 0x67, 0xeb, 0x82, 0x25,
0x41, 0x93, 0xa2, 0x94, 0x83, 0xc2, 0x9b, 0x7e, 0x5e, 0x6e, 0x73, 0x4f, 0x0d, 0xca, 0x41, 0xed,
0x12, 0x3f, 0x8e, 0x49, 0x20, 0x56, 0x15, 0xc9, 0x28, 0xd6, 0x7c, 0x24, 0x96, 0xdb, 0x95, 0x0c,
0x3f, 0x59, 0x3b, 0x81, 0x18, 0x8b, 0xbe, 0x44, 0x52, 0x5f, 0x02, 0x41, 0xa7, 0x04, 0x52, 0xfa,
0x29, 0x51, 0x40, 0x8c, 0x1a, 0x79, 0x06, 0x89, 0xc1, 0xda, 0x48, 0x07, 0x4c, 0x3c, 0xcf, 0x26,
0x33, 0x92, 0x0a, 0x48, 0x21, 0xd4, 0x99, 0x22, 0x02, 0x42, 0x55, 0xd0, 0x92, 0xbf, 0x80, 0xa2,
0x44, 0x58, 0x98, 0xa1, 0xdd, 0x9c, 0x64, 0x40, 0x4c, 0xc8, 0xfc, 0xb4, 0xa8, 0xa9, 0x40, 0xb9,
0x09, 0x40, 0x8e, 0x98, 0x92, 0xab, 0xa2, 0x96, 0x88, 0x34, 0x84, 0xa1, 0x86, 0x2f, 0x71, 0xac,
0xbd, 0x38, 0x3e, 0x35, 0xcb, 0x34, 0x2b, 0x91, 0x18, 0x91, 0xd4, 0x56, 0xab, 0x40, 0x35, 0x95,
0xd2, 0x30, 0xea, 0x2e, 0x80, 0x77, 0x78, 0xa4, 0xef, 0xc4, 0x2e, 0x64, 0x09, 0x0e, 0xab, 0xa0,
0xb5, 0x38, 0xa8, 0x44, 0xc9, 0x94, 0xb2, 0x8c, 0x72, 0x40, 0xa6, 0x31, 0xc4, 0xf5, 0xf6, 0xf8,
0x8d, 0x44, 0x81, 0x4c, 0x00, 0xe5, 0x0c, 0xf8, 0xfd, 0xf9, 0x69, 0xa8, 0x51, 0x24, 0x82, 0xc0,
0x5d, 0xfa, 0x8b, 0x08, 0xb2, 0x23, 0xbe, 0x2d, 0xab, 0xdf, 0x6a, 0x9a, 0xb5, 0x2e, 0x44, 0x95,
0x43, 0x0e, 0x28, 0x17, 0x09, 0x15, 0x53, 0xb7, 0x48, 0x7a, 0xd4, 0x12, 0x5e, 0x10, 0xf1, 0x0a,
0x88, 0xfd, 0x4a, 0x8d, 0x20, 0x64, 0xc5, 0x23, 0xb3, 0x1e, 0x88, 0xf5, 0x1a, 0xe0, 0x8c, 0x55,
0x64, 0x56, 0x14, 0x91, 0x1f, 0x00, 0x0a, 0x04, 0x34, 0xf0, 0xf0, 0xc1, 0x8c, 0x84, 0xf0, 0x41,
0x62, 0x9d, 0x8a, 0xde, 0x6c, 0xac, 0xc1, 0xd2, 0xa2, 0x6a, 0x08, 0x60, 0x37, 0x25, 0xb1, 0xb7,
0x94, 0x18, 0x39, 0x0a, 0x3b, 0x1a, 0x24, 0x0f, 0x6b, 0x2d, 0x04, 0x55, 0x34, 0x4d, 0x86, 0xde,
0x60, 0x25, 0x2b, 0x9a, 0xf4, 0x93, 0x94, 0x83, 0x22, 0x21, 0xd2, 0x81, 0xac, 0x0a, 0x4c, 0x25,
0x62, 0x86, 0x34, 0x7c, 0x21, 0xa9, 0x04, 0xfc, 0xa7, 0x84, 0x7a, 0x22, 0xeb, 0x83, 0xec, 0x10,
0x1b, 0xcb, 0xf5, 0x7c, 0x48, 0x65, 0xa3, 0xde, 0xb4, 0x56, 0x63, 0x22, 0x73, 0x8d, 0x09, 0x4c,
0x89, 0x80, 0x08, 0xa5, 0xd9, 0x4a, 0xc8, 0x2a, 0x43, 0x44, 0xa4, 0x9e, 0x03, 0x95, 0xb6, 0x4a,
0x9a, 0xe5, 0x96, 0xd9, 0x10, 0x80, 0xcf, 0x84, 0xa1, 0x83, 0xc7, 0xa5, 0x59, 0x17, 0x2b, 0x33,
0xbe, 0x64, 0xc4, 0x1c, 0xd4, 0x35, 0x2d, 0x59, 0x76, 0x1a, 0x10, 0x02, 0x23, 0x94, 0x67, 0x22,
0x04, 0x85, 0xb9, 0x59, 0xa2, 0x43, 0x40, 0x6b, 0x72, 0x0c, 0x55, 0xa1, 0x05, 0xea, 0x42, 0x50,
0x34, 0x5a, 0xb2, 0x36, 0x18, 0x89, 0x31, 0x44, 0xd5, 0xb2, 0x46, 0x28, 0x0a, 0x40, 0x08, 0xa6,
0x25, 0xc1, 0x2c, 0xf7, 0x42, 0xe0, 0x9c, 0x6c, 0x3f, 0x03, 0x12, 0xc4, 0x8a, 0x97, 0x92, 0xc1,
0x1b, 0x10, 0xb2, 0x44, 0x59, 0x06, 0x7e, 0x26, 0x26, 0x0e, 0x40, 0x98, 0xc3, 0x90, 0x5b, 0x08,
0x56, 0x59, 0xa1, 0x2e, 0x86, 0x20, 0x13, 0xb2, 0x37, 0xd0, 0x22, 0xa6, 0x0d, 0x91, 0x8c, 0x47,
0xb0, 0x85, 0x81, 0x66, 0x8f, 0xb0, 0x10, 0x80, 0x31, 0xf0, 0x7a, 0x56, 0x30, 0x30, 0xc9, 0xcb,
0x59, 0xb6, 0x27, 0x4d, 0x84, 0x57, 0x0f, 0x48, 0x08, 0xc9, 0xc4, 0x36, 0x58, 0x43, 0xa6, 0xa4,
0x38, 0x65, 0x65, 0x88, 0xba, 0x16, 0xdb, 0x96, 0x09, 0x7a, 0x87, 0xf0, 0xbb, 0x44, 0x88, 0x8f,
0x42, 0x8e, 0x9a, 0xa0, 0xba, 0x57, 0x80, 0xa8, 0x25, 0x93, 0x6b, 0x44, 0xe2, 0x0d, 0x52, 0x93,
0xb4, 0x1f, 0xc4, 0x4e, 0x6a, 0x24, 0x79, 0x1a, 0x4d, 0x4d, 0x06, 0x56, 0x40, 0xf9, 0xa8, 0x1a,
0x29, 0x8a, 0x48, 0x4c, 0x2c, 0x31, 0x1c, 0xaf, 0x29, 0xef, 0x4e, 0x26, 0x0e, 0x68, 0x5e, 0x84,
0x94, 0x29, 0x2d, 0x19, 0x9a, 0xc8, 0x3a, 0xb8, 0x83, 0x12, 0xdb, 0xc0, 0x14, 0xa2, 0x7d, 0xa1,
0x2e, 0x4c, 0x02, 0x5a, 0x60, 0x84, 0xd5, 0x70, 0x4a, 0xd0, 0x2b, 0x58, 0x26, 0x5d, 0xb3, 0x78,
0x0a, 0x09, 0x52, 0xec, 0x1a, 0x48, 0x7f, 0xb3, 0xac, 0x57, 0xbb, 0x0d, 0x36, 0x0a, 0xcf, 0x94,
0x88, 0x96, 0x54, 0x34, 0x62, 0x42, 0x64, 0xf4, 0x29, 0x27, 0xcc, 0x85, 0x59, 0x80, 0x06, 0x59,
0x00, 0x4c, 0xac, 0x42, 0x5a, 0x3c, 0x8b, 0x82, 0xf0, 0x13, 0xc2, 0x81, 0xe2, 0x2c, 0xe0, 0x24,
0x28, 0x88, 0x93, 0x21, 0x5b, 0x0a, 0xa7, 0xc4, 0x0e, 0x13, 0x91, 0x31, 0xcd, 0x4c, 0x98, 0x36,
0x0d, 0x33, 0x8f, 0x15, 0xcb, 0xa9, 0x1a, 0x74, 0xab, 0x2d, 0x85, 0x30, 0x4b, 0xa7, 0x0a, 0x22,
0x8a, 0xd4, 0x70, 0x57, 0xaa, 0x59, 0xa5, 0xd0, 0x94, 0x44, 0x31, 0x91, 0x4d, 0x93, 0x21, 0xb6,
0x2e, 0x13, 0xec, 0xa9, 0x01, 0x49, 0xef, 0x96, 0x7c, 0x10, 0x81, 0x3a, 0x11, 0xa1, 0xae, 0x1a,
0xfa, 0x3b, 0xa2, 0xa7, 0x09, 0xd6, 0x32, 0x6a, 0xb6, 0xc3, 0x84, 0x49, 0x85, 0x8b, 0xf9, 0x3f,
0x11, 0xf4, 0x3a, 0x02, 0x25, 0x07, 0xcc, 0x82, 0xca, 0x8f, 0xb6, 0x84, 0x68, 0x0e, 0x12, 0xaa,
0x02, 0x5b, 0x69, 0xc4, 0x0e, 0x34, 0x0a, 0x55, 0xae, 0xb2, 0xbe, 0xc8, 0x9d, 0x4b, 0x6c, 0x06,
0x88, 0x45, 0x65, 0x3e, 0x68, 0x5e, 0x34, 0xd5, 0x34, 0x0f, 0xb1, 0xe1, 0x6a, 0x01, 0xc7, 0x85,
0x70, 0x00, 0x0f, 0x00, 0x98, 0xa2, 0xaa, 0x54, 0xed, 0x54, 0x4b, 0x14, 0x05, 0x63, 0x85, 0x21,
0x4a, 0xb0, 0x55, 0x89, 0xf5, 0xee, 0x01, 0x94, 0x65, 0x7d, 0xac, 0x69, 0x3a, 0xfb, 0x51, 0x8b,
0x6d, 0xb5, 0xc4, 0xf0, 0xa9, 0x8f, 0x2d, 0x83, 0x59, 0xb1, 0xf5, 0xb0, 0xac, 0x9d, 0x44, 0xfe,
0xa8, 0x13, 0x83, 0x05, 0x52, 0x93, 0x95, 0x6b, 0x82, 0xa8, 0xf4, 0x01, 0xcb, 0x46, 0x51, 0x09,
0x98, 0xc4, 0x8a, 0x89, 0xc6, 0x20, 0x93, 0x8f, 0x9a, 0xcb, 0x01, 0xa6, 0x0e, 0xfc, 0xc3, 0x7b,
0x82, 0x7b, 0x31, 0xd1, 0x96, 0x7b, 0x61, 0x4a, 0x14, 0xb1, 0x89, 0x2d, 0xeb, 0xce, 0x2a, 0x45,
0x6e, 0xc0, 0xbe, 0x44, 0x20, 0x2b, 0xcb, 0xfc, 0x51, 0x2b, 0x5e, 0x11, 0x6a, 0x4f, 0x0d, 0xb2,
0xc5, 0x01, 0xc5, 0x57, 0x2e, 0x0b, 0x0b, 0x64, 0xbb, 0xe9, 0x64, 0x12, 0x8d, 0xb8, 0x7c, 0x58,
0xa4, 0x08, 0x26, 0xd1, 0x11, 0xf1, 0xdc, 0x17, 0x71, 0x85, 0x57, 0x02, 0xa8, 0x1d, 0x90, 0xf1,
0xe0, 0x96, 0x00, 0x96, 0xc6, 0x43, 0x33, 0x98, 0x02, 0xaf, 0x54, 0x15, 0x30, 0x0c, 0xec, 0xd4,
0xc2, 0xe4, 0x96, 0x15, 0x45, 0x80, 0x94, 0x33, 0x0b, 0x81, 0x50, 0xc9, 0x58, 0x81, 0xc9, 0x28,
0x16, 0x6e, 0x39, 0x3b, 0x00, 0xfa, 0x98, 0x6d, 0xe5, 0xe3, 0xe7, 0xa7, 0x4d, 0xc3, 0xe2, 0x2a,
0x17, 0x31, 0x43, 0x00, 0x43, 0x80, 0x5f, 0xc5, 0x28, 0x8a, 0x3f, 0xde, 0x42, 0x07, 0x80, 0x29,
0x52, 0x26, 0x22, 0xb7, 0x3f, 0x60, 0xca, 0x50, 0xb4, 0xa1, 0x5d, 0x92, 0xbf, 0xc8, 0x1a, 0xc9,
0xfa, 0x7a, 0xe8, 0x77, 0x05, 0x7b, 0x85, 0xc2, 0x02, 0x16, 0x02, 0x12, 0xc2, 0x6e, 0xe0, 0x3a,
0x54, 0x5c, 0x53, 0xd1, 0x65, 0x58, 0x73, 0x99, 0x4c, 0xf2, 0x19, 0x88, 0x2f, 0xd2, 0xcc, 0x91,
0x59, 0x1a, 0x61, 0x0c, 0x3a, 0xe0, 0x27, 0x2a, 0x95, 0x70, 0xb6, 0x68, 0x85, 0xee, 0x2a, 0x38,
0x81, 0x67, 0x73, 0x27, 0x68, 0x81, 0xee, 0xa3, 0xd8, 0x3f, 0x0e, 0xbd, 0x48, 0x9f, 0x8d, 0x90,
0xda, 0xb7, 0x50, 0xbb, 0x55, 0x2a, 0xec, 0x89, 0x28, 0xdd, 0x04, 0x2c, 0x31, 0x5f, 0xac, 0x83,
0x6f, 0x46, 0x93, 0x09, 0xcc, 0xa7, 0x7b, 0xec, 0x66, 0xd0, 0x4f, 0xb1, 0x06, 0x11, 0x05, 0x55,
0x40, 0xf2, 0x51, 0x5f, 0x24, 0x3b, 0x46, 0x86, 0xa3, 0x5e, 0x06, 0xea, 0x77, 0x24, 0xae, 0xc9,
0x8d, 0x55, 0x7c, 0x94, 0x1a, 0x9b, 0xb4, 0xec, 0xee, 0x0a, 0xc3, 0xe9, 0x39, 0xbb, 0x6b, 0xd6,
0xa0, 0xd5, 0x9f, 0xae, 0xba, 0x2f, 0x78, 0x75, 0x72, 0x26, 0x9f, 0xcd, 0xa5, 0xe1, 0xad, 0x84,
0x12, 0x34, 0xc9, 0x35, 0x98, 0xd9, 0x9a, 0xcb, 0xfd, 0x05, 0x44, 0x4a, 0x56, 0x3f, 0x57, 0x94,
0x66, 0xf9, 0x42, 0x79, 0x1d, 0x92, 0x57, 0x25, 0x90, 0x53, 0x6e, 0x44, 0x2d, 0x6e, 0x33, 0x28,
0x51, 0xd4, 0xc5, 0xdc, 0x80, 0x08, 0xac, 0x48, 0x91, 0xe8, 0x0e, 0x73, 0xf0, 0xb2, 0x15, 0xe9,
0x97, 0xf8, 0x4d, 0xb9, 0xd4, 0x9c, 0x09, 0x53, 0x4d, 0x44, 0x5e, 0x40, 0x48, 0x5b, 0xd0, 0xdb,
0xc0, 0xed, 0x14, 0x66, 0x58, 0x78, 0x02, 0xb3, 0x82, 0x8c, 0x79, 0x82, 0x8b, 0x08, 0xec, 0x31,
0xb3, 0x82, 0x33, 0x69, 0x26, 0xca, 0xc2, 0xd1, 0x13, 0xbd, 0xeb, 0x04, 0x95, 0x6b, 0x30, 0x72,
0x89, 0xb5, 0x24, 0xb1, 0x6d, 0xf4, 0x84, 0xec, 0xf4, 0xec, 0xe1, 0x0c, 0x9c, 0xad, 0xc7, 0x0b,
0x3b, 0x1b, 0xc4, 0x31, 0x84, 0x06, 0xb0, 0x30, 0xef, 0x3c, 0xa1, 0x67, 0x80, 0x21, 0x24, 0xdc,
0xe4, 0xc2, 0x64, 0xcc, 0xae, 0xed, 0x5b, 0x8d, 0xe8, 0x50, 0x80, 0x19, 0xb4, 0xac, 0x0c, 0x9b,
0x23, 0x7d, 0x36, 0xad, 0x49, 0xad, 0x60, 0xcb, 0x7d, 0x4b, 0x96, 0x45, 0x99, 0xaa, 0x7e, 0xad,
0x60, 0xf2, 0x04, 0x34, 0x3c, 0x16, 0x4c, 0xc4, 0xed, 0x38, 0x6b, 0xfa, 0x8d, 0x00, 0xd9, 0x76,
0x94, 0x45, 0x5d, 0x02, 0xcb, 0xe2, 0x0e, 0x2c, 0x9b, 0xfb, 0x41, 0x26, 0x50, 0x41, 0x63, 0xf0,
0xc4, 0xe2, 0x65, 0xb1, 0xa4, 0x4c, 0x97, 0xb2, 0xc6, 0x0f, 0xde, 0x31, 0x38, 0x5f, 0xc1, 0x9a,
0xd8, 0x32, 0x21, 0x32, 0xd5, 0x95, 0x21, 0xe7, 0xe1, 0x6c, 0x54, 0x08, 0x08, 0xc8, 0x7a, 0xc8,
0x06, 0x59, 0xef, 0x94, 0xd5, 0x28, 0xd4, 0xd5, 0x3c, 0xd8, 0xd0, 0x56, 0xd6, 0x13, 0xc0, 0x8b,
0xda, 0x81, 0xb1, 0xbe, 0x30, 0xd6, 0x17, 0x64, 0x7d, 0xf0, 0x5b, 0x65, 0xb9, 0x33, 0xce, 0x8b,
0xff, 0x38, 0x02, 0x28, 0xdb, 0x31, 0x40, 0xd9, 0x2e, 0x03, 0x94, 0xdd, 0x18, 0xf7, 0x1c, 0xaf,
0xda, 0x08, 0x40, 0x1c, 0xb3, 0xf0, 0xcb, 0x90, 0xec, 0x76, 0x9c, 0x0d, 0x5f, 0x81, 0xae, 0xf6,
0xd6, 0x6e, 0x07, 0xef, 0x51, 0xa9, 0x50, 0x05, 0x4d, 0x1f, 0x3b, 0xe8, 0xa1, 0x53, 0x3d, 0xe4,
0x3e, 0xd7, 0xa2, 0x94, 0x80, 0x7a, 0x18, 0x9c, 0x29, 0xa2, 0x53, 0x45, 0xe4, 0x7d, 0x45, 0xac,
0x34, 0x6f, 0x74, 0xab, 0xa5, 0x26, 0xd6, 0x4e, 0x75, 0xcf, 0xa9, 0x26, 0x86, 0xa1, 0x39, 0xa8,
0xa2, 0x53, 0x55, 0x2c, 0x54, 0x13, 0x9d, 0x69, 0x62, 0x61, 0x9a, 0x48, 0xdd, 0xca, 0xba, 0xdc,
0x1e, 0xba, 0x85, 0x7b, 0xa3, 0x74, 0xb9, 0x75, 0x85, 0xb9, 0xde, 0x6b, 0x62, 0x53, 0x3e, 0x63,
0xe7, 0xfd, 0xe6, 0xf6, 0xdd, 0x7a, 0xe4, 0x47, 0xc1, 0x0d, 0x2b, 0xdb, 0x5f, 0x57, 0xc0, 0x5c,
0xf7, 0xb3, 0xa2, 0xe5, 0x7a, 0x06, 0x0c, 0x25, 0x94, 0xee, 0x93, 0x56, 0x35, 0x20, 0x42, 0x53,
0xf0, 0x72, 0x77, 0x62, 0xaf, 0x04, 0xaa, 0x39, 0x22, 0x34, 0xb4, 0xbb, 0xdd, 0x90, 0xdc, 0xfd,
0x10, 0x6e, 0xbf, 0x0a, 0xc2, 0xad, 0xdd, 0x14, 0xe4, 0xd9, 0x1d, 0x1e, 0x00, 0x2f, 0xa7, 0x35,
0xd9, 0x33, 0x22, 0x73, 0x3c, 0xeb, 0xf3, 0x9e, 0x6b, 0x10, 0xc1, 0xaf, 0x87, 0x4d, 0x17, 0x51,
0xda, 0x45, 0x90, 0xf6, 0x58, 0x24, 0x05, 0xdf, 0xa3, 0xa9, 0x39, 0x94, 0xc4, 0x38, 0xa7, 0x3c,
0x80, 0x1a, 0xf7, 0x09, 0x83, 0x71, 0x11, 0xcb, 0xd4, 0x9a, 0x1e, 0xd5, 0xce, 0x23, 0xa9, 0x8f,
0x62, 0xa6, 0x49, 0x28, 0xac, 0xa1, 0xc1, 0xb4, 0xef, 0xca, 0xca, 0x19, 0xf4, 0x3b, 0x77, 0x87,
0xba, 0x39, 0xa6, 0x30, 0xc5, 0x7a, 0xf3, 0x51, 0x84, 0x35, 0x6e, 0x69, 0x9b, 0xea, 0xe1, 0x56,
0x2b, 0xcb, 0x97, 0x14, 0xa3, 0x7c, 0x49, 0x31, 0xce, 0x97, 0xac, 0x46, 0x49, 0xcf, 0xaf, 0xff,
0xb8, 0xfa, 0xab, 0x20, 0x69, 0x92, 0x90, 0x13, 0x37, 0x02, 0xe6, 0x59, 0x0a, 0x62, 0x56, 0xc7,
0x3f, 0x93, 0x9d, 0xdc, 0x17, 0x53, 0x4d, 0x98, 0xab, 0xcc, 0x92, 0x2a, 0xed, 0x55, 0xcd, 0xc0,
0xd1, 0x09, 0xc4, 0x9a, 0x67, 0x10, 0x6b, 0x98, 0x41, 0xac, 0x61, 0x0a, 0xb1, 0xd6, 0x33, 0x88,
0x35, 0xcc, 0x20, 0xd6, 0x74, 0xf0, 0xff, 0x29, 0xc4, 0xda, 0x4c, 0x21, 0xd6, 0x5d, 0xaa, 0x02,
0xc9, 0x59, 0x91, 0x66, 0xa6, 0xf2, 0x44, 0xf7, 0x27, 0xb7, 0xb3, 0x1c, 0x02, 0xa1, 0xfd, 0x12,
0xfe, 0xd9, 0x0d, 0x77, 0xc2, 0x2c, 0xe2, 0xa0, 0xfd, 0xa2, 0x7a, 0x1c, 0x2d, 0xe8, 0x2a, 0x6b,
0x6e, 0x48, 0xb9, 0x62, 0x91, 0xd8, 0x41, 0x06, 0x42, 0xe5, 0x3a, 0x1e, 0x4f, 0x6c, 0x8d, 0xb4,
0x62, 0x01, 0x41, 0x3d, 0x00, 0x32, 0x3f, 0xee, 0x00, 0xd2, 0xe1, 0x3e, 0xe8, 0x83, 0x3b, 0x25,
0xf5, 0xd6, 0xc4, 0x11, 0x6c, 0x3a, 0xba, 0x41, 0xf1, 0xe3, 0x04, 0x20, 0xf5, 0x2c, 0x59, 0x22,
0xfd, 0x35, 0x68, 0xee, 0x38, 0x07, 0x61, 0xc8, 0x28, 0x61, 0xd2, 0x62, 0x0c, 0x93, 0xf6, 0xb6,
0x41, 0x57, 0xa6, 0x2b, 0xdc, 0x6f, 0x78, 0x44, 0x79, 0xe3, 0xf6, 0xbc, 0x81, 0x7b, 0xe1, 0x0c,
0x1d, 0xf5, 0xd4, 0x43, 0x8f, 0xbb, 0x68, 0x8f, 0xaa, 0xd6, 0x0f, 0x7a, 0x13, 0xfa, 0x03, 0xde,
0x92, 0xfe, 0xe0, 0xfc, 0xf2, 0x23, 0xb4, 0xec, 0xee, 0xd5, 0x23, 0xbb, 0x4d, 0x1e, 0x8f, 0x06,
0xc2, 0xc3, 0xb4, 0xec, 0xce, 0x78, 0x1c, 0x7b, 0xf3, 0xca, 0x5d, 0x5f, 0x75, 0xdb, 0xcb, 0xee,
0xdd, 0x4f, 0x7c, 0xec, 0xeb, 0xc3, 0x07, 0x1f, 0xfa, 0x0b, 0xf7, 0x27, 0x5e, 0x3d, 0xf6, 0x23,
0x5f, 0x2a, 0xf6, 0xf7, 0xf9, 0xfd, 0xea, 0xd2, 0x9f, 0x9c, 0xf2, 0xf0, 0x81, 0xdd, 0xf6, 0x6e,
0x84, 0xde, 0x9f, 0x8f, 0x09, 0xf1, 0x71, 0xa9, 0xc7, 0x49, 0xe1, 0x66, 0xdc, 0xe3, 0x24, 0x6e,
0xfa, 0x3d, 0x89, 0xc7, 0xff, 0xf9, 0x2e, 0x2c, 0x10, 0x60, 0xfd, 0xdb, 0x71, 0x0a, 0xaf, 0xff,
0x9c, 0x50, 0xa8, 0x16, 0x28, 0xa0, 0x1c, 0xe6, 0x38, 0x81, 0xab, 0xed, 0x84, 0x40, 0xbd, 0x40,
0x00, 0x37, 0xe2, 0x2d, 0x10, 0xe8, 0xc7, 0x6c, 0x78, 0xb6, 0xc4, 0x04, 0x84, 0x38, 0xc7, 0x09,
0xf4, 0x77, 0x63, 0x02, 0x67, 0x4b, 0x04, 0xba, 0xeb, 0x37, 0x93, 0xeb, 0x65, 0xe5, 0x2f, 0x3f,
0xee, 0x56, 0xbc, 0x3b, 0x1f, 0x56, 0x7c, 0x78, 0x7c, 0xda, 0xc3, 0x07, 0x78, 0xe4, 0x0f, 0x79,
0x24, 0xdf, 0xff, 0xeb, 0xf4, 0xd5, 0x73, 0x8f, 0x5f, 0x4b, 0xc7, 0xaf, 0x6e, 0x77, 0xd7, 0xf5,
0xdb, 0x9f, 0xed, 0xba, 0x1e, 0xd2, 0xc4, 0xa7, 0x45, 0xb8, 0xfd, 0xd3, 0x22, 0x1c, 0xdf, 0x1e,
0xf7, 0xd3, 0x23, 0xa6, 0xb4, 0xae, 0x2e, 0xfa, 0x7e, 0x38, 0xf9, 0xbc, 0x57, 0x7a, 0x67, 0x3f,
0xdb, 0x33, 0xec, 0x4a, 0xf7, 0xfe, 0xf2, 0x0a, 0x9f, 0x9b, 0x3f, 0xf1, 0x50, 0x7e, 0xd7, 0xdf,
0x5d, 0xdc, 0xfc, 0xe4, 0x31, 0x31, 0x7d, 0x8f, 0x16, 0x1e, 0x4b, 0x3f, 0x1b, 0x33, 0x9e, 0x7c,
0x3e, 0x1a, 0xc8, 0xf3, 0x15, 0x03, 0xf9, 0xdb, 0xf3, 0x8b, 0x73, 0xc7, 0x37, 0x61, 0xfc, 0xed,
0x60, 0x24, 0xcf, 0xbf, 0x61, 0x24, 0xdb, 0x5f, 0xd6, 0x74, 0xfe, 0x0b, 0x1e, 0xf0, 0xb5, 0xd4,
0xfd, 0x2f, 0xdf, 0xd2, 0xfd, 0xa3, 0x35, 0xdd, 0x3f, 0x12, 0xf2, 0x4b, 0xbd, 0x3f, 0xfa, 0x8a,
0xde, 0xa7, 0x63, 0x78, 0xdb, 0x8f, 0xc6, 0xf3, 0xeb, 0x8a, 0xf1, 0xfc, 0x2a, 0xa3, 0x99, 0x0f,
0xe3, 0xd7, 0x23, 0xc3, 0xf0, 0x3a, 0x88, 0xf2, 0xa4, 0x0c, 0x71, 0x34, 0x10, 0x7b, 0xf9, 0xc3,
0x01, 0x2b, 0xce, 0x56, 0x74, 0x7d, 0xb6, 0xb9, 0xfb, 0x70, 0xbb, 0xe1, 0x13, 0x14, 0xe7, 0x23,
0x38, 0xfb, 0xea, 0x11, 0xcc, 0xc6, 0xf1, 0xfb, 0x9a, 0x25, 0xf9, 0x1d, 0xcf, 0x41, 0x5b, 0x5a,
0x93, 0xdf, 0xbf, 0x5e, 0x22, 0xee, 0xb6, 0x2f, 0x47, 0x06, 0x5c, 0xec, 0xfb, 0xbf, 0xf8, 0x20,
0x49, 0x77, 0xba, 0xb9, 0xba, 0xd8, 0x52, 0x7f, 0xe5, 0x6f, 0x6f, 0x04, 0xdf, 0xdf, 0xee, 0x2c,
0x08, 0x1f, 0xb4, 0x5d, 0xb4, 0xed, 0x92, 0x15, 0x41, 0x85, 0xd0, 0x82, 0x29, 0xbd, 0x9e, 0x53,
0xf1, 0x0b, 0x44, 0x0e, 0x6a, 0x48, 0x16, 0x08, 0xbe, 0x7f, 0x3d, 0x25, 0x78, 0x3f, 0xbd, 0x71,
0xda, 0x7c, 0x69, 0x84, 0x33, 0x82, 0x8b, 0xd3, 0xd4, 0x44, 0xe1, 0xd4, 0x5e, 0xee, 0xb9, 0xc6,
0xc7, 0x71, 0xe9, 0x22, 0xbd, 0x78, 0x39, 0x5a, 0x87, 0x97, 0x58, 0x07, 0x7b, 0xe0, 0xe6, 0xf8,
0xd1, 0x32, 0xf6, 0x2f, 0x6c, 0xb2, 0xbc, 0x74, 0x4f, 0xeb, 0xec, 0xe2, 0xce, 0xf5, 0x17, 0xdd,
0xf5, 0xd5, 0xf9, 0xe6, 0xf6, 0x93, 0xd3, 0x37, 0x7a, 0xde, 0x5d, 0x8b, 0x85, 0xe5, 0x13, 0xca,
0x54, 0x60, 0xec, 0xf7, 0x6e, 0x93, 0x39, 0xfb, 0xae, 0xfc, 0xc7, 0x43, 0x0a, 0xce, 0x83, 0x1f,
0xf4, 0xd8, 0xc3, 0x2f, 0x5d, 0x20, 0x8c, 0x7b, 0x84, 0x87, 0xd9, 0xad, 0xbe, 0x40, 0x76, 0xd2,
0xe7, 0x7c, 0x0b, 0xe2, 0xea, 0x2b, 0x64, 0xe7, 0x3c, 0xbd, 0xbd, 0x94, 0xf8, 0xf5, 0xd3, 0xea,
0x4b, 0x64, 0xaf, 0x3c, 0xfb, 0x63, 0x73, 0xe3, 0x4e, 0x7f, 0x38, 0xdb, 0x5f, 0x23, 0x0c, 0xf8,
0xc2, 0x65, 0x51, 0x2e, 0x13, 0xb6, 0x59, 0x6f, 0x60, 0xd7, 0x6c, 0xa8, 0x83, 0x12, 0xbc, 0xbe,
0x79, 0xa9, 0x9b, 0xd5, 0x93, 0x4d, 0x7f, 0x87, 0x37, 0x9a, 0x9e, 0xea, 0xb3, 0x55, 0x8f, 0xaf,
0xe4, 0x93, 0xd3, 0xd1, 0x4a, 0x9e, 0xae, 0x5e, 0xc9, 0x99, 0xd6, 0xbf, 0x5c, 0xa3, 0xf5, 0xa6,
0x8c, 0x67, 0x37, 0x17, 0x17, 0xe7, 0x87, 0x6a, 0xff, 0x72, 0xad, 0xda, 0xbf, 0x3c, 0x62, 0xfd,
0x7e, 0xfb, 0x0b, 0xfd, 0xe3, 0xcd, 0x9b, 0x57, 0xfd, 0xe5, 0xdd, 0xa7, 0x83, 0x31, 0xfc, 0xf6,
0x35, 0x63, 0x98, 0x19, 0xa0, 0xd3, 0xa9, 0x01, 0x7a, 0xb2, 0xf9, 0x78, 0x7d, 0x0b, 0x63, 0x77,
0x7a, 0x7b, 0xd1, 0x5f, 0xdc, 0xf5, 0x07, 0x46, 0xe8, 0xa6, 0xdf, 0xee, 0x56, 0x99, 0x8f, 0x7b,
0xe7, 0xb3, 0xcd, 0x97, 0xcc, 0xd0, 0x0c, 0x2c, 0x59, 0x72, 0x0f, 0x6f, 0x46, 0xfa, 0x6e, 0xcf,
0xd4, 0xff, 0x56, 0xab, 0x74, 0xd3, 0x5f, 0x1d, 0x12, 0xfd, 0x56, 0xcb, 0x74, 0x23, 0x9e, 0xd1,
0x64, 0xf2, 0x7c, 0x23, 0xd4, 0x7d, 0x34, 0x47, 0xe1, 0xef, 0x8c, 0x24, 0x18, 0xab, 0x2b, 0x4f,
0xc2, 0xbf, 0x99, 0x78, 0x3f, 0x71, 0xa3, 0x47, 0xf4, 0xd9, 0xf2, 0x7a, 0x2e, 0xaf, 0xb7, 0xe5,
0xb5, 0xd5, 0xdd, 0x5b, 0xa7, 0xc7, 0x18, 0x8f, 0xdb, 0xf1, 0x1a, 0xaa, 0xb6, 0xb9, 0xb9, 0xd9,
0x7e, 0x9a, 0x48, 0x16, 0x0f, 0x8b, 0xbf, 0xe8, 0xec, 0x21, 0xd1, 0xe6, 0x27, 0x3e, 0x7e, 0xa8,
0xe6, 0xec, 0xfb, 0x15, 0x27, 0x3f, 0x91, 0x93, 0xed, 0x49, 0xc7, 0x4e, 0x54, 0xf9, 0xf8, 0x15,
0x3c, 0xf3, 0x91, 0x9c, 0xf9, 0x6a, 0xe7, 0x4c, 0x9e, 0xec, 0x47, 0xfa, 0x09, 0x30, 0xc0, 0xdd,
0xdb, 0xdb, 0xeb, 0x0f, 0x6f, 0xde, 0xba, 0x1b, 0x15, 0x31, 0xb7, 0x67, 0x43, 0xf7, 0xc9, 0x2b,
0x81, 0x53, 0xbf, 0x9a, 0x0d, 0x34, 0xc4, 0x23, 0x0a, 0xc1, 0x28, 0x84, 0x23, 0x14, 0xe2, 0x51,
0x0a, 0xdf, 0xbb, 0x77, 0x17, 0x17, 0x37, 0xee, 0x62, 0xd3, 0xbd, 0x75, 0xd8, 0x1d, 0xc7, 0xd4,
0x5e, 0x18, 0xb5, 0x17, 0xc7, 0xc6, 0x13, 0xa2, 0x2a, 0x5e, 0x54, 0xcd, 0x4b, 0x11, 0xc1, 0x9e,
0x11, 0x7d, 0xdf, 0xff, 0x78, 0x0f, 0x83, 0x1e, 0xff, 0x77, 0x27, 0x47, 0x7c, 0xa0, 0xf7, 0x68,
0xdb, 0xba, 0xc7, 0xaa, 0x3e, 0x97, 0x13, 0x7f, 0xe6, 0xca, 0xbe, 0xba, 0xbe, 0xbe, 0xc3, 0x3b,
0xa5, 0x5f, 0x5f, 0xbe, 0xd9, 0xdb, 0x53, 0x90, 0x98, 0x69, 0xf7, 0xb3, 0xa9, 0x76, 0xe3, 0x0d,
0xbc, 0xe7, 0xee, 0xdf, 0x58, 0x98, 0x03, 0xc5, 0xbe, 0x9a, 0xc4, 0x27, 0x78, 0x2f, 0xc0, 0x5f,
0x8c, 0x18, 0x77, 0x14, 0x7f, 0xb9, 0xdd, 0x9c, 0x7f, 0xd8, 0x6c, 0x65, 0x98, 0xe7, 0x97, 0xef,
0x1d, 0x34, 0x60, 0x85, 0x70, 0x3d, 0x7b, 0xac, 0x17, 0xfb, 0x5e, 0xb6, 0x5a, 0x3e, 0x63, 0xd1,
0x51, 0x38, 0xce, 0x07, 0x0f, 0xf0, 0x3b, 0x84, 0xf8, 0x51, 0xd8, 0xfd, 0x8f, 0xef, 0x5d, 0x10,
0xe9, 0xe3, 0x51, 0x89, 0xf7, 0xde, 0xc8, 0x26, 0x33, 0x96, 0xb5, 0x9d, 0x8d, 0x7d, 0xb6, 0xc2,
0xc6, 0xfe, 0x73, 0xc9, 0xbf, 0x7c, 0x66, 0x6b, 0x9c, 0xca, 0x89, 0xc8, 0xec, 0x95, 0x6f, 0x66,
0xd0, 0x5f, 0xac, 0x31, 0xe8, 0x2f, 0x74, 0xb4, 0xfb, 0x30, 0xeb, 0x70, 0x57, 0x79, 0x71, 0xaf,
0x45, 0x9f, 0xd8, 0x70, 0x35, 0x21, 0x3f, 0x20, 0xec, 0xdb, 0xfd, 0x47, 0x1f, 0x4a, 0xab, 0xe1,
0xe6, 0x6b, 0x87, 0x17, 0x56, 0x6c, 0x5e, 0x5d, 0x7f, 0xb8, 0xfb, 0xf1, 0xd5, 0x76, 0x73, 0xf5,
0x4e, 0xce, 0xd2, 0xe3, 0xf2, 0x03, 0x4f, 0xe5, 0xc3, 0x23, 0xfa, 0xf0, 0x32, 0xf3, 0xff, 0x03,
0x5d, 0x2f, 0xbc, 0xe7, 0xe2, 0x7c, 0x00, 0x00,
};

1230
wled00/html_mobile.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -3,19 +3,14 @@
*/
//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:3em}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) );}</style>
)=====";
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>)=====";
//settings menu
const char PAGE_settings0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head><title>WLED Settings</title>
)=====";
const char PAGE_settings0[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><title>WLED Settings</title>)=====";
const char PAGE_settings1[] PROGMEM = R"=====(
body{text-align:center;background:var(--cCol);height:100%;margin:0;background-attachment:fixed}html{--h:11.55vh}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),Helvetica,sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:8vmin;height:var(--h);width:95%;margin-top:2.4vh}</style>
const char PAGE_settings1[] PROGMEM = R"=====(body{text-align:center;background:var(--cCol);height:100%;margin:0;background-attachment:fixed}html{--h:11.55vh}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),Helvetica,sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:8vmin;height:var(--h);width:95%;margin-top:2.4vh}</style>
<script>function BB(){if(window.frameElement){document.getElementById("b").style.display="none";document.documentElement.style.setProperty("--h","13.86vh")}};</script>
</head>
<body onload=BB()>
@@ -27,19 +22,15 @@ body{text-align:center;background:var(--cCol);height:100%;margin:0;background-at
<form action=/settings/time><button type=submit>Time & Macros</button></form>
<form action=/settings/sec><button type=submit>Security & Updates</button></form>
</body>
</html>
)=====";
</html>)=====";
//wifi settings
const char PAGE_settings_wifi0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
<title>WiFi Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#wifi-settings");}function B(){window.history.back();}function GetV(){var d = document;
)=====";
const char PAGE_settings_wifi0[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500">
<title>WiFi Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#wifi-settings");}function B(){window.history.back();}function GetV(){var d = document;)=====";
const char PAGE_settings_wifi1[] PROGMEM = R"=====(
</head>
const char PAGE_settings_wifi1[] PROGMEM = R"=====(</head>
<body onload="GetV()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
@@ -76,51 +67,66 @@ AP IP: <span class="sip"> Not active </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
</form>
</body>
</html>
)=====";
</html>)=====";
//LED settings
const char PAGE_settings_leds0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
<title>LED Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");}function B(){window.history.back();}function GetV(){var d = document;
)=====";
const char PAGE_settings_leds0[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500">
<title>LED Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");}function B(){window.history.back();}function S(){GetV();UI();}function UI(){
var myC=document.querySelectorAll('.wc'),l=myC.length;
for (i = 0; i < l; i++){myC[i].style.display=(document.getElementById('rgbw').checked)?'inline':'none';}
var val=Math.ceil((100+document.Sf.LC.value*55)/500)/2;
val=(val>5)?Math.ceil(val):val;var s="";
if (val<1.1){s="ESP 5V pin with 1A USB supply";}else{s="External 5V ";s+=val;s+="A supply connected to LEDs";}
document.getElementById('psu').innerHTML=s;document.getElementById('ps2').innerHTML=val+"A = "+val*1000;
}function GetV(){var d = document;)=====";
const char PAGE_settings_leds1[] PROGMEM = R"=====(
</head>
<body onload="GetV()">
const char PAGE_settings_leds1[] PROGMEM = R"=====(</head>
<body onload="S()">
<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</button><hr>
<h2>LED setup</h2>
LED count: <input name="LC" type="number" min="1" max="1200" required><br>
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW"><br>
<br>
Apply preset <input name="BP" type="number" min="0" max="25" required> at boot (0 uses defaults)<br>
Turn on after power up/reset: <input type="checkbox" name="BO"><br>
<br>
LED count: <input name="LC" type="number" min="1" max="1200" 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>
<i>Automatically limits brightness to stay close to the limit.<br>
Keep at &lt;1A if powering LEDs directly from the ESP 5V pin!<br>
If you are using an external 5V supply, enter its rating.<br>
"65000" completely diasbles the power calculation.<br>
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW" onchange=UI() id="rgbw"><br>
Color order:
<select name="CO">
<option value="0">GRB</option>
<option value="1">RGB</option>
<option value="2">BRG</option>
<option value="3">RBG</option></select>
<h3>Defaults</h3>
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br><br>
Default RGB color:
<input name="CR" type="number" min="0" max="255" required>
<input name="CG" type="number" min="0" max="255" required>
<input name="CB" type="number" min="0" max="255" required><br>
Default white value (only RGBW): <input name="CW" type="number" min="0" max="255" required><br>
Auto-calculate white from RGB instead: <input type="checkbox" name="AW"><br>
<span class="wc">Default white value: <input name="CW" type="number" min="0" max="255" required><br>
Auto-calculate white from RGB instead: <input type="checkbox" name="AW"><br></span>
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br>
Default effect ID: <input name="FX" type="number" min="0" max="57" required><br>
Default effect speed: <input name="SX" type="number" min="0" max="255" required><br>
Default effect intensity: <input name="IX" type="number" min="0" max="255" required><br>
Default effect palette: <input name="FP" type="number" min="0" max="255" required><br>
Default secondary RGB(W):<br>
Default secondary RGB<span class="wc">W</span>:<br>
<input name="SR" type="number" min="0" max="255" required>
<input name="SG" type="number" min="0" max="255" required>
<input name="SB" type="number" min="0" max="255" required>
<input name="SW" type="number" min="0" max="255" required><br>
Ignore and use current color, brightness and effects: <input type="checkbox" name="IS"><br>
Save current preset cycle configuration as boot default: <input type="checkbox" name="PC"><br>
<br>
<span class="wc"><input name="SW" type="number" min="0" max="255" required></span><br>
Ignore and use current color, brightness and effects: <input type="checkbox" name="IS"><br><br>
Apply preset <input name="BP" type="number" min="0" max="25" required> at boot (0 uses defaults)<br>
Save current preset cycle configuration as boot default: <input type="checkbox" name="PC"><br><br>
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br>
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
Brightness factor: <input name="BF" type="number" min="0" max="255" required> %
<h3>Transitions</h3>
Crossfade: <input type="checkbox" name="TF"><br>
@@ -140,25 +146,20 @@ Palette blending:
<option value="3">None (not recommended)</option>
</select><br>
Reverse LED order (rotate 180): <input type="checkbox" name="RV"><br>
Init LEDs after WiFi: <input type="checkbox" name="EI"><br>
Skip first LED: <input type="checkbox" name="SL"><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>
)=====";
</html>)=====";
//User Interface settings
const char PAGE_settings_ui0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
const char PAGE_settings_ui0[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500">
<title>UI Settings</title><script>
function gId(s){return document.getElementById(s);}function S(){GetV();Ct();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#user-interface-settings");}function B(){window.history.back();}function Ct(){if (gId("co").selected){gId("cth").style.display="block";}else{gId("cth").style.display="none";}}function GetV(){var d = document;
)=====";
function gId(s){return document.getElementById(s);}function S(){GetV();Ct();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#user-interface-settings");}function B(){window.history.back();}function Ct(){if (gId("co").selected){gId("cth").style.display="block";}else{gId("cth").style.display="none";}}function GetV(){var d = document;)=====";
const char PAGE_settings_ui1[] PROGMEM = R"=====(
</head>
const char PAGE_settings_ui1[] PROGMEM = R"=====(</head>
<body onload="S()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
@@ -182,13 +183,13 @@ Color Theme:
<option value="4">Electric</option>
<option value="5">Mint</option>
<option value="6">Amber</option>
<option value="7">Club</option>
<option value="7">Dark</option>
<option value="8">Air</option>
<option value="9">Nixie</option>
<option value="10">Terminal</option>
<option value="11">C64</option>
<option value="12">Easter</option>
<option value="13">Placeholder</option>
<option value="13">Christmas</option>
<option value="14">The End</option>
<option value="15" id="co">Custom</option>
</select><br>
@@ -205,26 +206,24 @@ Make sure the font you use is installed on your system!<br>
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>
)=====";
</html>)=====";
//sync settings
const char PAGE_settings_sync0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head><title>Sync Settings</title>
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}function GetV(){var d = document;
)=====";
const char PAGE_settings_sync0[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><title>Sync Settings</title>
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}function GetV(){var d = document;)=====";
const char PAGE_settings_sync1[] PROGMEM = R"=====(
</head>
const char PAGE_settings_sync1[] PROGMEM = R"=====(</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</button><hr>
<h2>Sync setup</h2>
<h3>Button setup</h3>
On/Off button enabled: <input type="checkbox" name="BT">
On/Off button enabled: <input type="checkbox" name="BT"><br>
Infrared receiver enabled: <input type="checkbox" name="IR"><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
<h3>WLED Broadcast</h3>
UDP Port: <input name="UP" maxlength="5" size="4"><br>
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
@@ -237,7 +236,7 @@ Send notifications twice: <input type="checkbox" name="S2"><br>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
<i>E1.31 (sACN)</i><br>
Use E1.31 multicast: <input type="checkbox" name="EM"><br>
E1.31 universe: <input name="EU" type="number" min="1" max="63999" required><br>
E1.31 start universe: <input name="EU" type="number" min="1" max="63999" required><br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br><br>
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
Force max brightness: <input type="checkbox" name="FB"><br>
@@ -248,6 +247,10 @@ Enable UI access during realtime: <input type="checkbox" name="RU"> (can cause i
Emulate Alexa device: <input type="checkbox" name="AL"><br>
Alexa invocation name: <input name="AI" maxlength="32">
<h3>Blynk</h3>
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
This impacts the responsiveness of the ESP8266.</b><br>
For best results, only use one of these services at a time.<br>
(alternatively, connect a second ESP to them and use the UDP sync)<br><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>
@@ -270,21 +273,20 @@ Hue status: <span class="hms"> Internal ESP Error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>
)=====";
</html>)=====";
//time and macro settings
const char PAGE_settings_time0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head><title>Time Settings</title>
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");}function B(){window.open("/settings","_self");}function S(){GetV();Cs();}function gId(s){return document.getElementById(s);}function Cs(){gId("cac").style.display="none";gId("coc").style.display="block";gId("ccc").style.display="none";if (gId("ca").selected){gId("cac").style.display="block";}if (gId("cc").selected){gId("coc").style.display="none";gId("ccc").style.display="block";}if (gId("cn").selected){gId("coc").style.display="none";}}function GetV(){var d = document;
)=====";
const char PAGE_settings_time0[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><title>Time Settings</title>
<script>var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");}function B(){window.open("/settings","_self");}function S(){BTa();GetV();Cs();FC();}function gId(s){return d.getElementById(s);}function Cs(){gId("cac").style.display="none";gId("coc").style.display="block";gId("ccc").style.display="none";if (gId("ca").selected){gId("cac").style.display="block";}if (gId("cc").selected){gId("coc").style.display="none";gId("ccc").style.display="block";}if (gId("cn").selected){gId("coc").style.display="none";}}
function BTa(){var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Macro</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for (i=0;i<8;i++){ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"16\"></td>";for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";}gId("TMT").innerHTML=ih;}
function FC(){for(j=0;j<8;j++){for(i=0;i<8;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1;}}
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]+=gId("W"+i+j).checked*m;m*=2;}gId("W"+i).value=a[i];}}function GetV(){)=====";
const char PAGE_settings_time1[] PROGMEM = R"=====(
</head>
const char PAGE_settings_time1[] PROGMEM = R"=====(</head>
<body onload="S()">
<form id="form_s" name="Sf" method="post">
<form id="form_s" name="Sf" method="post" onsubmit="Wd()">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>Time setup</h2>
@@ -329,7 +331,8 @@ Cronixie Display: <input name="CX" maxlength="6"><br>
Cronixie Backlight: <input type="checkbox" name="CB"><br>
</div>
Countdown Mode: <input type="checkbox" name="CE"><br>
Countdown Goal: Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
Countdown Goal:<br>
Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
Hour: <input name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" type="number" min="0" max="59" required> Second: <input name="CS" type="number" min="0" max="59" required><br>
<h3>Advanced Macros</h3>
Define API macros here:<br>
@@ -355,40 +358,23 @@ Alexa On/Off Macros: <input name="A0" type="number" min="0" max="16" required> <
Button Macro: <input name="MP" type="number" min="0" max="16" required> Long Press: <input name="ML" type="number" min="0" max="16" required><br>
Countdown-Over Macro: <input name="MC" type="number" min="0" max="16" required><br>
Timed-Light-Over Macro: <input name="MN" type="number" min="0" max="16" required><br>
Time-Controlled Macros (Hours/Minutes &gt; Macro):<br>
<input name="H0" type="number" min="0" max="24"> <input name="N0" type="number" min="0" max="59">
&gt; <input name="T0" type="number" min="0" max="16"><br>
<input name="H1" type="number" min="0" max="24"> <input name="N1" type="number" min="0" max="59">
&gt; <input name="T1" type="number" min="0" max="16"><br>
<input name="H2" type="number" min="0" max="24"> <input name="N2" type="number" min="0" max="59">
&gt; <input name="T2" type="number" min="0" max="16"><br>
<input name="H3" type="number" min="0" max="24"> <input name="N3" type="number" min="0" max="59">
&gt; <input name="T3" type="number" min="0" max="16"><br>
<input name="H4" type="number" min="0" max="24"> <input name="N4" type="number" min="0" max="59">
&gt; <input name="T4" type="number" min="0" max="16"><br>
<input name="H5" type="number" min="0" max="24"> <input name="N5" type="number" min="0" max="59">
&gt; <input name="T5" type="number" min="0" max="16"><br>
<input name="H6" type="number" min="0" max="24"> <input name="N6" type="number" min="0" max="59">
&gt; <input name="T6" type="number" min="0" max="16"><br>
<input name="H7" type="number" min="0" max="24"> <input name="N7" type="number" min="0" max="59">
&gt; <input name="T7" type="number" min="0" max="16"><hr>
Time-Controlled Macros:<br>
<div style="display: inline-block">
<table id="TMT">
</table></div><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>
)=====";
</html>)=====";
//security settings and about
const char PAGE_settings_sec0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
const char PAGE_settings_sec0[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500">
<title>Misc Settings</title>
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#security-settings");}function B(){window.open("/settings","_self");}function U(){window.open("/update","_self");}function GetV(){var d = document;
)=====";
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#security-settings");}function B(){window.open("/settings","_self");}function U(){window.open("/update","_self");}function GetV(){var d = document;)=====";
const char PAGE_settings_sec1[] PROGMEM = R"=====(
</head>
const char PAGE_settings_sec1[] PROGMEM = R"=====(</head>
<body onload="GetV()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
@@ -411,27 +397,13 @@ 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.0<br><br>
<b>Contributors:</b><br>
StormPie <i>(Mobile HTML UI)</i><br><br>
Thank you so much!<br><br>
(c) 2016-2018 Christian Schwinne <br>
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.8.3<br><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br>
(c) 2016-2019 Christian Schwinne <br>
<i>Licensed under the MIT license</i><br><br>
<b>Uses libraries:</b><br>
<i>ESP8266/ESP32 Arduino Core</i><br>
<i><a href="https://github.com/svenihoney/NeoPixelBus" target="_blank">NeoPixelBus</a> by Makuna (svenihoney fork)</i><br>
<i><a href="https://github.com/FastLED/FastLED/" target="_blank">FastLED</a> library</i><br>
<i>(ESP32) <a href="https://github.com/bbx10/WebServer_tng" target="_blank">WebServer_tng</a> by bbx10</i><br>
<i><a href="https://github.com/kitesurfer1404/WS2812FX" target="_blank">WS2812FX</a> by kitesurfer1404 (modified)</i><br>
<i><a href="https://github.com/JChristensen/Timezone" target="_blank">Timezone</a> library by JChristensen</i><br>
<i><a href="https://github.com/blynkkk/blynk-library" target="_blank">Blynk</a> library (compacted)</i><br>
<i><a href="https://github.com/forkineye/E131" target="_blank">E1.31</a> library by forkineye (modified)</i><br>
<i><a href="https://github.com/knolleary/pubsubclient" target="_blank">PubSubClient</a> by knolleary (modified)</i><br>
<i><a href="https://github.com/Aircoookie/Espalexa" target="_blank">Espalexa</a> by Aircoookie (modified)</i><br><br>
<i>UI icons by <a href="https://linearicons.com" target="_blank">Linearicons</a> created by <a href="https://perxis.com" target="_blank">Perxis</a>! (CC-BY-SA 4.0)</i> <br><br>
Server message: <span class="msg"> Response error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
</form>
</body>
</html>
)=====";
</html>)=====";

File diff suppressed because one or more lines are too long

95
wled00/ir_codes.h Normal file
View File

@@ -0,0 +1,95 @@
//Infrared codes
//Add your custom codes here
#define IRCUSTOM_ONOFF 0xA55AEA15 //Pioneer RC-975R "+FAV" button (example)
#define IRCUSTOM_MACRO1 0xFFFFFFFF //placeholder, will never be checked for
//Infrared codes for 24-key remote from http://woodsgood.ca/projects/2015/02/13/rgb-led-strip-controllers-ir-codes/
#define IR24_BRIGHTER 0xF700FF
#define IR24_DARKER 0xF7807F
#define IR24_OFF 0xF740BF
#define IR24_ON 0xF7C03F
#define IR24_RED 0xF720DF
#define IR24_REDDISH 0xF710EF
#define IR24_ORANGE 0xF730CF
#define IR24_YELLOWISH 0xF708F7
#define IR24_YELLOW 0xF728D7
#define IR24_GREEN 0xF7A05F
#define IR24_GREENISH 0xF7906F
#define IR24_TURQUOISE 0xF7B04F
#define IR24_CYAN 0xF78877
#define IR24_AQUA 0xF7A857
#define IR24_BLUE 0xF7609F
#define IR24_DEEPBLUE 0xF750AF
#define IR24_PURPLE 0xF7708F
#define IR24_MAGENTA 0xF748B7
#define IR24_PINK 0xF76897
#define IR24_WHITE 0xF7E01F
#define IR24_FLASH 0xF7D02F
#define IR24_STROBE 0xF7F00F
#define IR24_FADE 0xF7C837
#define IR24_SMOOTH 0xF7E817
/* 44-key defs, to be done later
#define IR44_BPlus 0xFF3AC5 //
#define IR44_BMinus 0xFFBA45 //
#define IR44_ON 0xFF827D //
#define IR44_OFF 0xFF02FD //
#define IR44_R 0xFF1AE5 //
#define IR44_G 0xFF9A65 //
#define IR44_B 0xFFA25D //
#define IR44_W 0xFF22DD //
#define IR44_B1 0xFF2AD5 //
#define IR44_B2 0xFFAA55 //
#define IR44_B3 0xFF926D //
#define IR44_B4 0xFF12ED //
#define IR44_B5 0xFF0AF5 //
#define IR44_B6 0xFF8A75 //
#define IR44_B7 0xFFB24D //
#define IR44_B8 0xFF32CD //
#define IR44_B9 0xFF38C7 //
#define IR44_B10 0xFFB847 //
#define IR44_B11 0xFF7887 //
#define IR44_B12 0xFFF807 //
#define IR44_B13 0xFF18E7 //
#define IR44_B14 0xFF9867 //
#define IR44_B15 0xFF58A7 //
#define IR44_B16 0xFFD827 //
#define IR44_UPR 0xFF28D7 //
#define IR44_UPG 0xFFA857 //
#define IR44_UPB 0xFF6897 //
#define IR44_QUICK 0xFFE817 //
#define IR44_DOWNR 0xFF08F7 //
#define IR44_DOWNG 0xFF8877 //
#define IR44_DOWNB 0xFF48B7 //
#define IR44_SLOW 0xFFC837 //
#define IR44_DIY1 0xFF30CF //
#define IR44_DIY2 0xFFB04F //
#define IR44_DIY3 0xFF708F //
#define IR44_AUTO 0xFFF00F //
#define IR44_DIY4 0xFF10EF //
#define IR44_DIY5 0xFF906F //
#define IR44_DIY6 0xFF50AF //
#define IR44_FLASH 0xFFD02F //
#define IR44_JUMP3 0xFF20DF //
#define IR44_JUMP7 0xFFA05F //
#define IR44_FADE3 0xFF609F //
#define IR44_FADE7 0xFFE01F //
*/
#define COLOR_RED 0xFF0000
#define COLOR_REDDISH 0xFF7800
#define COLOR_ORANGE 0xFFA000
#define COLOR_YELLOWISH 0xFFC800
#define COLOR_YELLOW 0xFFFF00
#define COLOR_GREEN 0x00FF00
#define COLOR_GREENISH 0x00FF78
#define COLOR_TURQUOISE 0x00FFA0
#define COLOR_CYAN 0x00FFDC
#define COLOR_AQUA 0x00C8FF
#define COLOR_BLUE 0x00A0FF
#define COLOR_DEEPBLUE 0x0000FF
#define COLOR_PURPLE 0xAA00FF
#define COLOR_MAGENTA 0xFF00DC
#define COLOR_PINK 0xFF00A0
#define COLOR_WHITE 0xFFFFDC

View File

@@ -500,6 +500,42 @@ DEFINE_GRADIENT_PALETTE( Orange_Teal_gp ) {
200, 255, 72, 0,
255, 255, 72, 0};
//Custom palette by Aircoookie
DEFINE_GRADIENT_PALETTE( Tiamat_gp ) {
0, 1, 2, 14, //gc
33, 2, 5, 35, //gc from 47, 61,126
100, 13,135, 92, //gc from 88,242,247
120, 43,255,193, //gc from 135,255,253
140, 247, 7,249, //gc from 252, 69,253
160, 193, 17,208, //gc from 231, 96,237
180, 39,255,154, //gc from 130, 77,213
200, 4,213,236, //gc from 57,122,248
220, 39,252,135, //gc from 177,254,255
240, 193,213,253, //gc from 203,239,253
255, 255,249,255};
//Custom palette by Aircoookie
DEFINE_GRADIENT_PALETTE( April_Night_gp ) {
0, 1, 5, 45, //deep blue
10, 1, 5, 45,
25, 5,169,175, //light blue
40, 1, 5, 45,
61, 1, 5, 45,
76, 45,175, 31, //green
91, 1, 5, 45,
112, 1, 5, 45,
127, 249,150, 5, //yellow
143, 1, 5, 45,
162, 1, 5, 45,
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};
// Single array of defined cpt-city color palettes.
// This will let us programmatically choose one based on
@@ -543,8 +579,10 @@ const TProgmemRGBGradientPalettePtr gGradientPalettes[] = {
BlacK_Magenta_Red_gp, //41-28 Magred
BlacK_Red_Magenta_Yellow_gp, //42-29 Yelmag
Blue_Cyan_Yellow_gp, //43-30 Yelblu
Orange_Teal_gp //44-31 Orange & Teal
};
Orange_Teal_gp, //44-31 Orange & Teal
Tiamat_gp, //45-32 Tiamat
April_Night_gp //46-33 April Night
};
// Count of how many cpt-city gradients are defined:
@@ -552,4 +590,3 @@ const uint8_t gGradientPaletteCount =
sizeof( gGradientPalettes) / sizeof( TProgmemRGBGradientPalettePtr );
#endif

View File

@@ -0,0 +1,487 @@
#ifndef Espalexa_h
#define Espalexa_h
/*
* Alexa Voice On/Off/Brightness/Color Control. Emulates a Philips Hue bridge to Alexa.
*
* This was put together from these two excellent projects:
* https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch
* https://github.com/probonopd/ESP8266HueEmulator
*/
/*
* @title Espalexa library
* @version 2.3.3
* @author Christian Schwinne
* @license MIT
* @contributors d-999
*/
#include "Arduino.h"
//you can use these defines for library config in your sketch. Just use them before #include <Espalexa.h>
//#define ESPALEXA_ASYNC
#ifndef ESPALEXA_MAXDEVICES
#define ESPALEXA_MAXDEVICES 10 //this limit only has memory reasons, set it higher should you need to
#endif
//#define ESPALEXA_DEBUG
#ifdef ESPALEXA_ASYNC
#ifdef ARDUINO_ARCH_ESP32
#include <AsyncTCP.h>
#else
#include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>
#else
#ifdef ARDUINO_ARCH_ESP32
#include <WiFi.h>
#include "../webserver/WebServer.h" //if you get an error here please update to ESP32 arduino core 1.0.0
#else
#include <ESP8266WebServer.h>
#include <ESP8266WiFi.h>
#endif
#endif
#include <WiFiUdp.h>
#ifdef ESPALEXA_DEBUG
#pragma message "Espalexa 2.3.3 debug mode"
#define EA_DEBUG(x) Serial.print (x)
#define EA_DEBUGLN(x) Serial.println (x)
#else
#define EA_DEBUG(x)
#define EA_DEBUGLN(x)
#endif
#include "EspalexaDevice.h"
class Espalexa {
private:
//private member vars
#ifdef ESPALEXA_ASYNC
AsyncWebServer* serverAsync;
AsyncWebServerRequest* server; //this saves many #defines
String body = "";
#elif defined ARDUINO_ARCH_ESP32
WebServer* server;
#else
ESP8266WebServer* server;
#endif
uint8_t currentDeviceCount = 0;
EspalexaDevice* devices[ESPALEXA_MAXDEVICES] = {};
//Keep in mind that Device IDs go from 1 to DEVICES, cpp arrays from 0 to DEVICES-1!!
WiFiUDP espalexaUdp;
IPAddress ipMulti;
bool udpConnected = false;
char packetBuffer[255]; //buffer to hold incoming udp packet
String escapedMac=""; //lowercase mac address
//private member functions
String deviceJsonString(uint8_t deviceId)
{
if (deviceId < 1 || deviceId > currentDeviceCount) return "{}"; //error
EspalexaDevice* dev = devices[deviceId-1];
String json = "{\"type\":\"";
json += dev->isColorDevice() ? "Extended color light" : "Dimmable light";
json += "\",\"manufacturername\":\"OpenSource\",\"swversion\":\"0.1\",\"name\":\"";
json += dev->getName();
json += "\",\"uniqueid\":\""+ WiFi.macAddress() +"-"+ (deviceId+1) ;
json += "\",\"modelid\":\"LST001\",\"state\":{\"on\":";
json += boolString(dev->getValue()) +",\"bri\":"+ (String)(dev->getLastValue()-1) ;
if (dev->isColorDevice())
{
json += ",\"xy\":[0.00000,0.00000],\"colormode\":\"";
json += (dev->isColorTemperatureMode()) ? "ct":"hs";
json += "\",\"effect\":\"none\",\"ct\":" + (String)(dev->getCt()) + ",\"hue\":" + (String)(dev->getHue()) + ",\"sat\":" + (String)(dev->getSat());
}
json +=",\"alert\":\"none\",\"reachable\":true}}";
return json;
}
//Espalexa status page /espalexa
void servePage()
{
EA_DEBUGLN("HTTP Req espalexa ...\n");
String res = "Hello from Espalexa!\r\n\r\n";
for (int i=0; i<currentDeviceCount; i++)
{
res += "Value of device " + String(i+1) + " (" + devices[i]->getName() + "): " + String(devices[i]->getValue()) + "\r\n";
}
res += "\r\nFree Heap: " + (String)ESP.getFreeHeap();
res += "\r\nUptime: " + (String)millis();
res += "\r\n\r\nEspalexa library v2.3.3 by Christian Schwinne 2019";
server->send(200, "text/plain", res);
}
//not found URI (only if internal webserver is used)
void serveNotFound()
{
EA_DEBUGLN("Not-Found HTTP call:");
#ifndef ESPALEXA_ASYNC
EA_DEBUGLN("URI: " + server->uri());
EA_DEBUGLN("Body: " + server->arg(0));
if(!handleAlexaApiCall(server->uri(), server->arg(0)))
#else
EA_DEBUGLN("URI: " + server->url());
EA_DEBUGLN("Body: " + body);
if(!handleAlexaApiCall(server))
#endif
server->send(404, "text/plain", "Not Found (espalexa-internal)");
}
//send description.xml device property page
void serveDescription()
{
EA_DEBUGLN("# Responding to description.xml ... #\n");
IPAddress localIP = WiFi.localIP();
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
String setup_xml = "<?xml version=\"1.0\" ?>"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
"<specVersion><major>1</major><minor>0</minor></specVersion>"
"<URLBase>http://"+ String(s) +":80/</URLBase>"
"<device>"
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
"<friendlyName>Philips hue ("+ String(s) +")</friendlyName>"
"<manufacturer>Royal Philips Electronics</manufacturer>"
"<manufacturerURL>http://www.philips.com</manufacturerURL>"
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
"<modelName>Philips hue bridge 2012</modelName>"
"<modelNumber>929000226503</modelNumber>"
"<modelURL>http://www.meethue.com</modelURL>"
"<serialNumber>"+ escapedMac +"</serialNumber>"
"<UDN>uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"</UDN>"
"<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>"
" <icon>"
" <mimetype>image/png</mimetype>"
" <height>120</height>"
" <width>120</width>"
" <depth>24</depth>"
" <url>hue_logo_3.png</url>"
" </icon>"
"</iconList>"
"</device>"
"</root>";
server->send(200, "text/xml", setup_xml.c_str());
EA_DEBUG("Sending :");
EA_DEBUGLN(setup_xml);
}
//init the server
void startHttpServer()
{
#ifdef ESPALEXA_ASYNC
if (serverAsync == nullptr) {
serverAsync = new AsyncWebServer(80);
serverAsync->onNotFound([=](AsyncWebServerRequest *request){server = request; serveNotFound();});
}
serverAsync->onRequestBody([=](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
char b[len +1];
b[len] = 0;
memcpy(b, data, len);
body = b; //save the body so we can use it for the API call
EA_DEBUG("Received body: ");
EA_DEBUGLN(body);
});
serverAsync->on("/espalexa", HTTP_GET, [=](AsyncWebServerRequest *request){server = request; servePage();});
serverAsync->on("/description.xml", HTTP_GET, [=](AsyncWebServerRequest *request){server = request; serveDescription();});
serverAsync->begin();
#else
if (server == nullptr) {
#ifdef ARDUINO_ARCH_ESP32
server = new WebServer(80);
#else
server = new ESP8266WebServer(80);
#endif
server->onNotFound([=](){serveNotFound();});
}
server->on("/espalexa", HTTP_GET, [=](){servePage();});
server->on("/description.xml", HTTP_GET, [=](){serveDescription();});
server->begin();
#endif
}
//called when Alexa sends ON command
void alexaOn(uint8_t deviceId)
{
devices[deviceId-1]->setValue(devices[deviceId-1]->getLastValue());
devices[deviceId-1]->setPropertyChanged(1);
devices[deviceId-1]->doCallback();
}
//called when Alexa sends OFF command
void alexaOff(uint8_t deviceId)
{
devices[deviceId-1]->setValue(0);
devices[deviceId-1]->setPropertyChanged(2);
devices[deviceId-1]->doCallback();
}
//called when Alexa sends BRI command
void alexaDim(uint8_t deviceId, uint8_t briL)
{
if (briL == 255)
{
devices[deviceId-1]->setValue(255);
} else {
devices[deviceId-1]->setValue(briL+1);
}
devices[deviceId-1]->setPropertyChanged(3);
devices[deviceId-1]->doCallback();
}
//called when Alexa sends HUE command
void alexaCol(uint8_t deviceId, uint16_t hue, uint8_t sat)
{
devices[deviceId-1]->setColor(hue, sat);
devices[deviceId-1]->setPropertyChanged(4);
devices[deviceId-1]->doCallback();
}
//called when Alexa sends CT command (color temperature)
void alexaCt(uint8_t deviceId, uint16_t ct)
{
devices[deviceId-1]->setColor(ct);
devices[deviceId-1]->setPropertyChanged(5);
devices[deviceId-1]->doCallback();
}
//respond to UDP SSDP M-SEARCH
void respondToSearch()
{
IPAddress localIP = WiFi.localIP();
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
String response =
"HTTP/1.1 200 OK\r\n"
"EXT:\r\n"
"CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL
"LOCATION: http://"+ String(s) +":80/description.xml\r\n"
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
"hue-bridgeid: "+ escapedMac +"\r\n"
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
"USN: uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"::upnp:rootdevice\r\n" // _uuid::_deviceType
"\r\n";
espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort());
#ifdef ARDUINO_ARCH_ESP32
espalexaUdp.write((uint8_t*)response.c_str(), response.length());
#else
espalexaUdp.write(response.c_str());
#endif
espalexaUdp.endPacket();
}
String boolString(bool st)
{
return(st)?"true":"false";
}
public:
Espalexa(){}
//initialize interfaces
#ifdef ESPALEXA_ASYNC
bool begin(AsyncWebServer* externalServer = nullptr)
#elif defined ARDUINO_ARCH_ESP32
bool begin(WebServer* externalServer = nullptr)
#else
bool begin(ESP8266WebServer* externalServer = nullptr)
#endif
{
EA_DEBUGLN("Espalexa Begin...");
EA_DEBUG("MAXDEVICES ");
EA_DEBUGLN(ESPALEXA_MAXDEVICES);
escapedMac = WiFi.macAddress();
escapedMac.replace(":", "");
escapedMac.toLowerCase();
#ifdef ESPALEXA_ASYNC
serverAsync = externalServer;
#else
server = externalServer;
#endif
#ifdef ARDUINO_ARCH_ESP32
udpConnected = espalexaUdp.beginMulticast(IPAddress(239, 255, 255, 250), 1900);
#else
udpConnected = espalexaUdp.beginMulticast(WiFi.localIP(), IPAddress(239, 255, 255, 250), 1900);
#endif
if (udpConnected){
startHttpServer();
EA_DEBUGLN("Done");
return true;
}
EA_DEBUGLN("Failed");
return false;
}
//service loop
void loop() {
#ifndef ESPALEXA_ASYNC
if (server == nullptr) return; //only if begin() was not called
server->handleClient();
#endif
if (!udpConnected) return;
int packetSize = espalexaUdp.parsePacket();
if (!packetSize) return; //no new udp packet
EA_DEBUGLN("Got UDP!");
int len = espalexaUdp.read(packetBuffer, 254);
if (len > 0) {
packetBuffer[len] = 0;
}
espalexaUdp.flush();
String request = packetBuffer;
EA_DEBUGLN(request);
if(request.indexOf("M-SEARCH") >= 0) {
if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("asic:1") > 0) {
EA_DEBUGLN("Responding search req...");
respondToSearch();
}
}
}
bool addDevice(EspalexaDevice* d)
{
EA_DEBUG("Adding device ");
EA_DEBUGLN((currentDeviceCount+1));
if (currentDeviceCount >= ESPALEXA_MAXDEVICES) return false;
devices[currentDeviceCount] = d;
currentDeviceCount++;
return true;
}
bool addDevice(String deviceName, CallbackBriFunction 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, CallbackColFunction 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);
}
//basic implementation of Philips hue api functions needed for basic Alexa control
#ifdef ESPALEXA_ASYNC
bool handleAlexaApiCall(AsyncWebServerRequest* request)
{
server = request; //copy request reference
String req = request->url(); //body from global variable
EA_DEBUGLN(request->contentType());
if (request->hasParam("body", true)) // This is necessary, otherwise ESP crashes if there is no body
{
EA_DEBUG("BodyMethod2");
body = request->getParam("body", true)->value();
}
EA_DEBUG("FinalBody: ");
EA_DEBUGLN(body);
#else
bool handleAlexaApiCall(String req, String body)
{
#endif
EA_DEBUGLN("AlexaApiCall");
if (req.indexOf("api") <0) return false; //return if not an API call
EA_DEBUGLN("ok");
if (body.indexOf("devicetype") > 0) //client wants a hue api username, we dont care and give static
{
EA_DEBUGLN("devType");
body = "";
server->send(200, "application/json", "[{\"success\":{\"username\": \"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]");
return true;
}
if (req.indexOf("state") > 0) //client wants to control light
{
server->send(200, "application/json", "[{\"success\":true}]"); //short valid response
int tempDeviceId = req.substring(req.indexOf("lights")+7).toInt();
EA_DEBUG("ls"); EA_DEBUGLN(tempDeviceId);
if (body.indexOf("false")>0) {alexaOff(tempDeviceId); return true;}
if (body.indexOf("bri")>0 ) {alexaDim(tempDeviceId, body.substring(body.indexOf("bri") +5).toInt()); return true;}
if (body.indexOf("hue")>0 ) {alexaCol(tempDeviceId, body.substring(body.indexOf("hue") +5).toInt(), body.substring(body.indexOf("sat") +5).toInt()); return true;}
if (body.indexOf("ct") >0 ) {alexaCt (tempDeviceId, body.substring(body.indexOf("ct") +4).toInt()); return true;}
alexaOn(tempDeviceId);
return true;
}
int pos = req.indexOf("lights");
if (pos > 0) //client wants light info
{
int tempDeviceId = req.substring(pos+7).toInt();
EA_DEBUG("l"); EA_DEBUGLN(tempDeviceId);
if (tempDeviceId == 0) //client wants all lights
{
EA_DEBUGLN("lAll");
String jsonTemp = "{";
for (int i = 0; i<currentDeviceCount; i++)
{
jsonTemp += "\"" + String(i+1) + "\":";
jsonTemp += deviceJsonString(i+1);
if (i < currentDeviceCount-1) jsonTemp += ",";
}
jsonTemp += "}";
server->send(200, "application/json", jsonTemp);
} else //client wants one light (tempDeviceId)
{
server->send(200, "application/json", deviceJsonString(tempDeviceId));
}
return true;
}
//we dont care about other api commands at this time and send empty JSON
server->send(200, "application/json", "{}");
return true;
}
//is an unique device ID
String getEscapedMac()
{
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
};
#endif

View File

@@ -0,0 +1,176 @@
//EspalexaDevice Class
#include "EspalexaDevice.h"
EspalexaDevice::EspalexaDevice(){}
EspalexaDevice::EspalexaDevice(String deviceName, CallbackBriFunction gnCallback, uint8_t initialValue) { //constructor
_deviceName = deviceName;
_callback = gnCallback;
_val = initialValue;
_val_last = _val;
}
EspalexaDevice::EspalexaDevice(String deviceName, CallbackColFunction gnCallback, uint8_t initialValue) { //constructor for color device
_deviceName = deviceName;
_callbackCol = gnCallback;
_callback = nullptr;
_val = initialValue;
_val_last = _val;
}
EspalexaDevice::~EspalexaDevice(){/*nothing to destruct*/}
bool EspalexaDevice::isColorDevice()
{
//if brightness-only callback is null, we have color device
return (_callback == nullptr);
}
bool EspalexaDevice::isColorTemperatureMode()
{
return _ct;
}
String EspalexaDevice::getName()
{
return _deviceName;
}
uint8_t EspalexaDevice::getLastChangedProperty()
{
return _changed;
}
uint8_t EspalexaDevice::getValue()
{
return _val;
}
uint16_t EspalexaDevice::getHue()
{
return _hue;
}
uint8_t EspalexaDevice::getSat()
{
return _sat;
}
uint16_t EspalexaDevice::getCt()
{
if (_ct == 0) return 500;
return _ct;
}
uint32_t EspalexaDevice::getColorRGB()
{
uint8_t rgb[3];
if (isColorTemperatureMode())
{
//TODO tweak a bit to match hue lamp characteristics
//based on https://gist.github.com/paulkaplan/5184275
float temp = 10000/ _ct; //kelvins = 1,000,000/mired (and that /100)
float r, g, b;
if( temp <= 66 ){
r = 255;
g = temp;
g = 99.470802 * log(g) - 161.119568;
if( temp <= 19){
b = 0;
} else {
b = temp-10;
b = 138.517731 * log(b) - 305.044793;
}
} else {
r = temp - 60;
r = 329.698727 * pow(r, -0.13320476);
g = temp - 60;
g = 288.12217 * pow(g, -0.07551485 );
b = 255;
}
rgb[0] = (byte)constrain(r,0.1,255.1);
rgb[1] = (byte)constrain(g,0.1,255.1);
rgb[2] = (byte)constrain(b,0.1,255.1);
}
else
{ //hue + sat mode
float h = ((float)_hue)/65535.0;
float s = ((float)_sat)/255.0;
byte i = floor(h*6);
float f = h * 6-i;
float p = 255 * (1-s);
float q = 255 * (1-f*s);
float t = 255 * (1-(1-f)*s);
switch (i%6) {
case 0: rgb[0]=255,rgb[1]=t,rgb[2]=p;break;
case 1: rgb[0]=q,rgb[1]=255,rgb[2]=p;break;
case 2: rgb[0]=p,rgb[1]=255,rgb[2]=t;break;
case 3: rgb[0]=p,rgb[1]=q,rgb[2]=255;break;
case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break;
case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q;
}
}
return ((rgb[0] << 16) | (rgb[1] << 8) | (rgb[2]));
}
uint8_t EspalexaDevice::getLastValue()
{
if (_val_last == 0) return 255;
return _val_last;
}
void EspalexaDevice::setPropertyChanged(uint8_t p)
{
//0: initial 1: on 2: off 3: bri 4: col 5: ct
_changed = p;
}
//you need to re-discover the device for the Alexa name to change
void EspalexaDevice::setName(String name)
{
_deviceName = name;
}
void EspalexaDevice::setValue(uint8_t val)
{
if (_val != 0)
{
_val_last = _val;
}
if (val != 0)
{
_val_last = val;
}
_val = val;
}
void EspalexaDevice::setPercent(uint8_t perc)
{
uint16_t val = perc * 255;
val /= 100;
if (val > 255) val = 255;
setValue(val);
}
void EspalexaDevice::setColor(uint16_t hue, uint8_t sat)
{
_hue = hue;
_sat = sat;
_ct = 0;
}
void EspalexaDevice::setColor(uint16_t ct)
{
_ct = ct;
}
void EspalexaDevice::doCallback()
{
(_callback != nullptr) ? _callback(_val) : _callbackCol(_val, getColorRGB());
}

View File

@@ -0,0 +1,46 @@
#ifndef EspalexaDevice_h
#define EspalexaDevice_h
#include "Arduino.h"
typedef void (*CallbackBriFunction) (uint8_t br);
typedef void (*CallbackColFunction) (uint8_t br, uint32_t col);
class EspalexaDevice {
private:
String _deviceName;
CallbackBriFunction _callback;
CallbackColFunction _callbackCol;
uint8_t _val, _val_last, _sat = 0;
uint16_t _hue = 0, _ct = 0;
uint8_t _changed = 0;
public:
EspalexaDevice();
~EspalexaDevice();
EspalexaDevice(String deviceName, CallbackBriFunction gnCallback, uint8_t initialValue =0);
EspalexaDevice(String deviceName, CallbackColFunction gnCallback, uint8_t initialValue =0);
bool isColorDevice();
bool isColorTemperatureMode();
String getName();
uint8_t getLastChangedProperty();
uint8_t getValue();
uint16_t getHue();
uint8_t getSat();
uint16_t getCt();
uint32_t getColorRGB();
void setPropertyChanged(uint8_t p);
void setValue(uint8_t bri);
void setPercent(uint8_t perc);
void setName(String name);
void setColor(uint16_t hue, uint8_t sat);
void setColor(uint16_t ct);
void doCallback();
uint8_t getLastValue(); //last value that was not off (1-255)
};
#endif

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Christian Schwinne
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -16,7 +16,8 @@
#else
#include <WProgram.h>
#endif
#include <Time.h> //http://www.arduino.cc/playground/Code/Time
#include "../time/Time.h" //http://www.arduino.cc/playground/Code/Time
//convenient constants for dstRules
enum week_t {Last, First, Second, Third, Fourth};

View File

@@ -3,50 +3,83 @@
*/
/*
* @title WLED project sketch
* @version 0.8.0
* @version 0.8.3
* @author Christian Schwinne
*/
//ESP8266-01 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).
//Uncomment the following line to disable some features (currently Mobile UI, welcome page and single digit + cronixie overlays) to compile for ESP8266-01
//#define WLED_FLASH_512K_MODE
//CURRENTLY NOT WORKING
//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 (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):
//You are required to disable over-the-air updates:
//#define WLED_DISABLE_OTA
//You need to choose 1-2 of these features to disable:
//#define WLED_DISABLE_ALEXA
//#define WLED_DISABLE_BLYNK
//#define WLED_DISABLE_CRONIXIE
//#define WLED_DISABLE_HUESYNC
//#define WLED_DISABLE_INFRARED //there is no pin left for this on ESP8266-01
//#define WLED_DISABLE_MOBILE_UI
//to toggle usb serial debug (un)comment following line(s)
//#define WLED_DEBUG
//library inclusions
#include <Arduino.h>
#ifdef ARDUINO_ARCH_ESP32
#include <WiFi.h>
#include <ESPmDNS.h>
#include "src/dependencies/webserver/WebServer.h"
#include <HTTPClient.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include "src/dependencies/webserver/WebServer.h"
#include <HTTPClient.h>
/*#ifndef WLED_DISABLE_INFRARED
#include <IRremote.h>
#endif*/ //there are issues with ESP32 infrared, so it is disabled for now
#else
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#ifndef WLED_DISABLE_INFRARED
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRutils.h>
#endif
#endif
#include <EEPROM.h>
#include <ArduinoOTA.h>
#include <WiFiUDP.h>
#include <WiFiUdp.h>
#include <DNSServer.h>
#include "src/dependencies/webserver/ESP8266HTTPUpdateServer.h"
#ifndef WLED_DISABLE_OTA
#include <ArduinoOTA.h>
#include "src/dependencies/webserver/ESP8266HTTPUpdateServer.h"
#endif
#include "src/dependencies/time/Time.h"
#include "src/dependencies/time/TimeLib.h"
#include "src/dependencies/timezone/Timezone.h"
#include "src/dependencies/blynk/BlynkSimpleEsp.h"
#ifndef WLED_DISABLE_ALEXA
#define ESPALEXA_MAXDEVICES 1
#include "src/dependencies/espalexa/Espalexa.h"
#endif
#ifndef WLED_DISABLE_BLYNK
#include "src/dependencies/blynk/BlynkSimpleEsp.h"
#endif
#include "src/dependencies/e131/E131.h"
#include "src/dependencies/pubsubclient/PubSubClient.h"
#include "htmls00.h"
#include "htmls01.h"
#include "htmls02.h"
#include "html_classic.h"
#include "html_mobile.h"
#include "html_settings.h"
#include "html_other.h"
#include "WS2812FX.h"
#include "ir_codes.h"
//version code in format yymmddb (b = daily build)
#define VERSION 1810151
char versionString[] = "0.8.0";
#define VERSION 1902122
char versionString[] = "0.8.3";
//AP and OTA default passwords (for maximum change them!)
@@ -54,18 +87,13 @@ char apPass[65] = "wled1234";
char otaPass[33] = "wledota";
//to toggle usb serial debug (un)comment following line(s)
//#define DEBUG
//spiffs FS only useful for debug (only ESP8266)
//#define USEFS
//Hardware CONFIG (only changeble HERE, not at runtime)
//LED strip pin changeable in NpbWrapper.h. Only change for ESP32
byte buttonPin = 0; //needs pull-up
byte auxPin = 15; //debug feature, use e.g. for external relay with API call AX=
//LED strip pin, button pin and IR pin changeable in NpbWrapper.h!
byte auxDefaultState = 0; //0: input 1: high 2: low
byte auxTriggeredState = 0; //0: input 1: high 2: low
char ntpServerName[] = "0.wled.pool.ntp.org"; //NTP server to use
@@ -74,7 +102,7 @@ char ntpServerName[] = "0.wled.pool.ntp.org"; //NTP server to use
//WiFi CONFIG (all these can be changed via web UI, no need to set them here)
char clientSSID[33] = "Your_Network";
char clientPass[65] = "";
char cmDNS[33] = "led"; //mDNS address (x.local), only for Apple and Windows, if Bonjour installed
char cmDNS[33] = "x"; //mDNS address (placeholder, will be replaced by wledXXXXXXXXXXXX.local)
char apSSID[65] = ""; //AP off by default (unless setup)
byte apChannel = 1; //2.4GHz WiFi AP channel (1-13)
byte apHide = 0; //hidden AP SSID
@@ -87,16 +115,15 @@ IPAddress staticDNS(8, 8, 8, 8); //only for NTP, google DNS server
//LED CONFIG
uint16_t ledCount = 10; //lowered to prevent accidental overcurrent
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
bool turnOnAtBoot = true; //turn on LEDs at power-up
byte bootPreset = 0; //save preset to load after power-up
byte colS[]{255, 159, 0}; //default RGB color
byte colSecS[]{0, 0, 0}; //default RGB secondary color
byte whiteS = 0; //default White channel
byte whiteSecS = 0; //default secondary White channel
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 effectSpeedDefault = 75;
@@ -114,7 +141,6 @@ bool enableSecTransition = true; //also enable transition for secon
uint16_t transitionDelay = 900; //default crossfade duration in ms
bool reverseMode = false; //flip entire LED strip (reverses all effect directions)
bool initLedsLast = false; //turn on LEDs only after WiFi connected/AP open
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)
@@ -130,7 +156,8 @@ bool useHSBDefault = useHSB;
//Sync CONFIG
bool buttonEnabled = true;
bool buttonEnabled = true;
bool irEnabled = false; //Infrared receiver
uint16_t udpPort = 21324; //WLED notifier default port
uint16_t udpRgbPort = 19446; //Hyperion port
@@ -139,7 +166,7 @@ bool receiveNotificationBrightness = true; //apply brightness from incoming n
bool receiveNotificationColor = true; //apply color
bool receiveNotificationEffects = true; //apply effects setup
bool notifyDirect = true; //send notification if change via UI or HTTP API
bool notifyButton = true;
bool notifyButton = true; //send if updated by button or infrared remote
bool notifyAlexa = false; //send notification if updated via Alexa
bool notifyMacro = false; //send notification for macro
bool notifyHue = true; //send notification if Hue light changes
@@ -216,16 +243,14 @@ uint16_t userVar0 = 0, userVar1 = 0;
//internal global variable declarations
//color
byte col[]{255, 159, 0}; //target RGB color
byte colOld[]{0, 0, 0}; //color before transition
byte colT[]{0, 0, 0}; //current color
byte colIT[]{0, 0, 0}; //color that was last sent to LEDs
byte colSec[]{0, 0, 0};
byte colSecT[]{0, 0, 0};
byte colSecOld[]{0, 0, 0};
byte colSecIT[]{0, 0, 0};
byte white = whiteS, whiteOld, whiteT, whiteIT;
byte whiteSec = whiteSecS, whiteSecOld, whiteSecT, whiteSecIT;
byte col[]{255, 159, 0, 0}; //target RGB(W) color
byte colOld[]{0, 0, 0, 0}; //color before transition
byte colT[]{0, 0, 0, 0}; //current color
byte colIT[]{0, 0, 0, 0}; //color that was last sent to LEDs
byte colSec[]{0, 0, 0, 0};
byte colSecT[]{0, 0, 0, 0};
byte colSecOld[]{0, 0, 0, 0};
byte colSecIT[]{0, 0, 0, 0};
byte lastRandomIndex = 0; //used to save last random color so the new one is not the same
@@ -240,10 +265,13 @@ float tperLast = 0; //crossfade transition progress, 0
bool nightlightActive = false;
bool nightlightActiveOld = false;
uint32_t nightlightDelayMs = 10;
uint8_t nightlightDelayMinsDefault = nightlightDelayMins;
unsigned long nightlightStartTime;
byte briNlT = 0; //current nightlight brightness
//brightness
bool offMode = false;
unsigned long lastOnTime = 0;
byte bri = briS;
byte briOld = 0;
byte briT = 0;
@@ -273,7 +301,6 @@ bool udpConnected = false, udpRgbConnected = false;
//ui style
char cssCol[6][9]={"","","","","",""};
String cssColorString="";
bool showWelcomePage = false;
//hue
@@ -311,7 +338,7 @@ byte timerHours[] = {0,0,0,0,0,0,0,0};
byte timerMinutes[] = {0,0,0,0,0,0,0,0};
byte timerMacro[] = {0,0,0,0,0,0,0,0};
byte timerWeekday[] = {255,255,255,255,255,255,255,255}; //weekdays to activate on
//bit pattern of arr elem: 0b11111111: sat,fri,thu,wed,tue,mon,sun,validity
//bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity
//blynk
bool blynkEnabled = false;
@@ -321,7 +348,7 @@ bool presetCyclingEnabled = false;
byte presetCycleMin = 1, presetCycleMax = 5;
uint16_t presetCycleTime = 1250;
unsigned long presetCycledTime = 0; byte presetCycCurr = presetCycleMin;
bool presetApplyBri = true, presetApplyCol = true, presetApplyFx = true;
bool presetApplyBri = false, presetApplyCol = true, presetApplyFx = true;
bool saveCurrPresetCycConf = false;
//realtime
@@ -342,10 +369,11 @@ unsigned long auxStartTime = 0;
bool auxActive = false, auxActiveBefore = false;
//alexa udp
WiFiUDP alexaUDP;
IPAddress ipMulti(239, 255, 255, 250);
unsigned int portMulti = 1900;
String escapedMac;
#ifndef WLED_DISABLE_ALEXA
Espalexa espalexa;
EspalexaDevice* espalexaDevice;
#endif
//dns server
DNSServer dnsServer;
@@ -361,21 +389,23 @@ unsigned int ntpLocalPort = 2390;
#define NTP_PACKET_SIZE 48
//string temp buffer
#define OMAX 1750
#define OMAX 2000
char obuf[OMAX];
uint16_t olen = 0;
//server library objects
#ifdef ARDUINO_ARCH_ESP32
WebServer server(80);
WebServer server(80);
#else
ESP8266WebServer server(80);
ESP8266WebServer server(80);
#endif
HTTPClient* hueClient = NULL;
WiFiClient* mqttTCPClient = NULL;
PubSubClient* mqtt = NULL;
ESP8266HTTPUpdateServer httpUpdater;
#ifndef WLED_DISABLE_OTA
ESP8266HTTPUpdateServer httpUpdater;
#endif
//udp interface objects
WiFiUDP notifierUdp, rgbUdp;
@@ -386,7 +416,7 @@ E131* e131;
WS2812FX strip = WS2812FX();
//debug macros
#ifdef DEBUG
#ifdef WLED_DEBUG
#define DEBUG_PRINT(x) Serial.print (x)
#define DEBUG_PRINTLN(x) Serial.println (x)
#define DEBUG_PRINTF(x) Serial.printf (x)
@@ -401,8 +431,8 @@ WS2812FX strip = WS2812FX();
//filesystem
#ifdef USEFS
#include <FS.h>;
File fsUploadFile;
#include <FS.h>;
File fsUploadFile;
#endif
//gamma 2.4 lookup table used for color correction
@@ -434,6 +464,7 @@ void serveMessage(int,String,String,int=255);
void reset()
{
briT = 0;
delay(250); //enough time to send response to client
setAllLeds();
DEBUG_PRINTLN("MODULE RESET");
ESP.restart();
@@ -462,64 +493,76 @@ bool oappendi(int i)
//boot starts here
void setup() {
wledInit();
wledInit();
}
//main program loop
void loop() {
server.handleClient();
handleSerial();
handleNotifications();
handleTransitions();
userLoop();
yield();
handleButton();
handleNetworkTime();
if (!onlyAP)
{
handleAlexa();
handleMQTT();
}
handleOverlays();
server.handleClient();
handleSerial();
handleNotifications();
handleTransitions();
userLoop();
yield();
handleButton();
handleIR();
handleNetworkTime();
if (!onlyAP)
{
handleAlexa();
handleMQTT();
}
handleOverlays();
yield();
if (!realtimeActive) //block stuff if WARLS/Adalight is enabled
{
if (dnsActive) dnsServer.processNextRequest();
if (aOtaEnabled) ArduinoOTA.handle();
handleNightlight();
if (!onlyAP) {
handleHue();
handleBlynk();
}
if (briT) strip.service(); //do not update strip if off, prevents flicker on ESP32
}
//DEBUG serial logging
#ifdef DEBUG
if (millis() - debugTime > 5000)
{
DEBUG_PRINTLN("---MODULE DEBUG INFO---");
DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis());
DEBUG_PRINT("Unix time: "); DEBUG_PRINTLN(now());
DEBUG_PRINT("Free heap: "); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status());
if (WiFi.status() != lastWifiState)
{
wifiStateChangedTime = millis();
}
lastWifiState = WiFi.status();
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();
}
yield();
if (!realtimeActive) //block stuff if WARLS/Adalight is enabled
{
if (dnsActive) dnsServer.processNextRequest();
#ifndef WLED_DISABLE_OTA
if (aOtaEnabled) ArduinoOTA.handle();
#endif
handleNightlight();
if (!onlyAP) {
handleHue();
handleBlynk();
}
if (briT) lastOnTime = millis();
if (millis() - lastOnTime < 600)
{
offMode = false;
strip.service();
} else if (!offMode)
{
/*#if LEDPIN == 2 //turn off onboard LED
pinMode(2, OUTPUT);
digitalWrite(2, HIGH);
#endif*/
offMode = true;
}
}
//DEBUG serial logging
#ifdef WLED_DEBUG
if (millis() - debugTime > 5000)
{
DEBUG_PRINTLN("---MODULE DEBUG INFO---");
DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis());
DEBUG_PRINT("Unix time: "); DEBUG_PRINTLN(now());
DEBUG_PRINT("Free heap: "); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status());
if (WiFi.status() != lastWifiState)
{
wifiStateChangedTime = millis();
}
lastWifiState = WiFi.status();
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();
}
#endif
}

View File

@@ -6,7 +6,7 @@
#define EEPSIZE 3072
//eeprom Version code, enables default settings instead of 0 init on update
#define EEPVER 9
#define EEPVER 10
//0 -> old version, default
//1 -> 0.4p 1711272 and up
//2 -> 0.4p 1711302 and up
@@ -17,6 +17,8 @@
//7 -> 0.7.1 and up
//8 -> 0.8.0-a and up
//9 -> 0.8.0
//10-> 0.8.2
/*
* Erase all configuration data
@@ -30,6 +32,7 @@ void clearEEPROM()
EEPROM.commit();
}
void writeStringToEEPROM(uint16_t pos, char* str, uint16_t len)
{
for (int i = 0; i < len; ++i)
@@ -39,6 +42,7 @@ void writeStringToEEPROM(uint16_t pos, char* str, uint16_t len)
}
}
void readStringFromEEPROM(uint16_t pos, char* str, uint16_t len)
{
for (int i = 0; i < len; ++i)
@@ -49,6 +53,7 @@ void readStringFromEEPROM(uint16_t pos, char* str, uint16_t len)
str[len] = 0; //make sure every string is properly terminated. str must be at least len +1 big.
}
/*
* Write configuration to flash
*/
@@ -66,12 +71,12 @@ void saveSettingsToEEPROM()
writeStringToEEPROM(128, apSSID, 32);
writeStringToEEPROM(160, apPass, 64);
EEPROM.write(224, nightlightDelayMins);
EEPROM.write(224, nightlightDelayMinsDefault);
EEPROM.write(225, nightlightFade);
EEPROM.write(226, notifyDirectDefault);
EEPROM.write(227, apChannel);
EEPROM.write(228, apHide);
EEPROM.write(229, (ledCount >> 0) & 0xFF);
EEPROM.write(229, ledCount & 0xFF);
EEPROM.write(230, notifyButton);
EEPROM.write(231, notifyTwice);
EEPROM.write(232, buttonEnabled);
@@ -92,7 +97,7 @@ void saveSettingsToEEPROM()
EEPROM.write(250, receiveNotificationBrightness);
EEPROM.write(251, fadeTransition);
EEPROM.write(252, reverseMode);
EEPROM.write(253, (transitionDelayDefault >> 0) & 0xFF);
EEPROM.write(253, transitionDelayDefault & 0xFF);
EEPROM.write(254, (transitionDelayDefault >> 8) & 0xFF);
EEPROM.write(255, briMultiplier);
@@ -101,7 +106,7 @@ void saveSettingsToEEPROM()
EEPROM.write(288, nightlightTargetBri);
EEPROM.write(289, otaLock);
EEPROM.write(290, (udpPort >> 0) & 0xFF);
EEPROM.write(290, udpPort & 0xFF);
EEPROM.write(291, (udpPort >> 8) & 0xFF);
writeStringToEEPROM(292, serverDescription, 32);
@@ -124,7 +129,7 @@ void saveSettingsToEEPROM()
EEPROM.write(368, abs(arlsOffset));
EEPROM.write(369, turnOnAtBoot);
EEPROM.write(370, useHSBDefault);
EEPROM.write(371, whiteS);
EEPROM.write(371, colS[3]); //white default
EEPROM.write(372, useRGBW);
EEPROM.write(373, effectPaletteDefault);
EEPROM.write(374, strip.paletteFade);
@@ -136,19 +141,24 @@ void saveSettingsToEEPROM()
EEPROM.write(378, colSecS[0]);
EEPROM.write(379, colSecS[1]);
EEPROM.write(380, colSecS[2]);
EEPROM.write(381, whiteSecS);
EEPROM.write(381, colSecS[3]);
EEPROM.write(382, strip.paletteBlend);
EEPROM.write(383, strip.colorOrder);
EEPROM.write(385, irEnabled);
EEPROM.write(387, strip.ablMilliampsMax & 0xFF);
EEPROM.write(388, (strip.ablMilliampsMax >> 8) & 0xFF);
EEPROM.write(389, bootPreset);
EEPROM.write(390, aOtaEnabled);
EEPROM.write(391, receiveNotificationColor);
EEPROM.write(392, receiveNotificationEffects);
EEPROM.write(393, wifiLock);
EEPROM.write(394, (abs(utcOffsetSecs) >> 0) & 0xFF);
EEPROM.write(394, abs(utcOffsetSecs) & 0xFF);
EEPROM.write(395, (abs(utcOffsetSecs) >> 8) & 0xFF);
EEPROM.write(396, (utcOffsetSecs<0)); //is negative
EEPROM.write(397, initLedsLast);
//397 was initLedsLast
EEPROM.write(398, (ledCount >> 8) & 0xFF);
EEPROM.write(399, !enableSecTransition);
@@ -170,7 +180,7 @@ void saveSettingsToEEPROM()
EEPROM.write(i, hueIP[i-2050]);
}
writeStringToEEPROM(2054, hueApiKey, 46);
EEPROM.write(2100, (huePollIntervalMs >> 0) & 0xFF);
EEPROM.write(2100, huePollIntervalMs & 0xFF);
EEPROM.write(2101, (huePollIntervalMs >> 8) & 0xFF);
EEPROM.write(2102, notifyHue);
EEPROM.write(2103, hueApplyOnOff);
@@ -205,10 +215,10 @@ void saveSettingsToEEPROM()
EEPROM.write(2180, macroCountdown);
EEPROM.write(2181, macroNl);
EEPROM.write(2190, (e131Universe >> 0) & 0xFF);
EEPROM.write(2190, e131Universe & 0xFF);
EEPROM.write(2191, (e131Universe >> 8) & 0xFF);
EEPROM.write(2192, e131Multicast);
EEPROM.write(2193, (realtimeTimeoutMs >> 0) & 0xFF);
EEPROM.write(2193, realtimeTimeoutMs & 0xFF);
EEPROM.write(2194, (realtimeTimeoutMs >> 8) & 0xFF);
EEPROM.write(2195, arlsForceMaxBri);
EEPROM.write(2196, arlsDisableGammaCorrection);
@@ -222,7 +232,7 @@ void saveSettingsToEEPROM()
if (saveCurrPresetCycConf)
{
EEPROM.write(2205, presetCyclingEnabled);
EEPROM.write(2206, (presetCycleTime >> 0) & 0xFF);
EEPROM.write(2206, presetCycleTime & 0xFF);
EEPROM.write(2207, (presetCycleTime >> 8) & 0xFF);
EEPROM.write(2208, presetCycleMin);
EEPROM.write(2209, presetCycleMax);
@@ -246,9 +256,10 @@ void saveSettingsToEEPROM()
writeStringToEEPROM(2333, mqttDeviceTopic, 32);
writeStringToEEPROM(2366, mqttGroupTopic, 32);
EEPROM.commit();
commit();
}
/*
* Read all configuration from flash
*/
@@ -256,7 +267,9 @@ void loadSettingsFromEEPROM(bool first)
{
if (EEPROM.read(233) != 233) //first boot/reset to default
{
DEBUG_PRINT("Settings invalid, restoring defaults...");
saveSettingsToEEPROM();
DEBUG_PRINTLN("done");
return;
}
int lastEEPROMversion = EEPROM.read(377); //last EEPROM version before update
@@ -268,7 +281,8 @@ void loadSettingsFromEEPROM(bool first)
readStringFromEEPROM(128, apSSID, 32);
readStringFromEEPROM(160, apPass, 64);
nightlightDelayMins = EEPROM.read(224);
nightlightDelayMinsDefault = EEPROM.read(224);
nightlightDelayMins = nightlightDelayMinsDefault;
nightlightFade = EEPROM.read(225);
notifyDirectDefault = EEPROM.read(226);
notifyDirect = notifyDirectDefault;
@@ -277,7 +291,7 @@ void loadSettingsFromEEPROM(bool first)
if (apChannel > 13 || apChannel < 1) apChannel = 1;
apHide = EEPROM.read(228);
if (apHide > 1) apHide = 1;
ledCount = ((EEPROM.read(229) << 0) & 0xFF) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 10;
ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 30;
notifyButton = EEPROM.read(230);
notifyTwice = EEPROM.read(231);
@@ -307,7 +321,7 @@ void loadSettingsFromEEPROM(bool first)
receiveNotificationBrightness = EEPROM.read(250);
fadeTransition = EEPROM.read(251);
reverseMode = EEPROM.read(252);
transitionDelayDefault = ((EEPROM.read(253) << 0) & 0xFF) + ((EEPROM.read(254) << 8) & 0xFF00);
transitionDelayDefault = EEPROM.read(253) + ((EEPROM.read(254) << 8) & 0xFF00);
transitionDelay = transitionDelayDefault;
briMultiplier = EEPROM.read(255);
@@ -315,7 +329,7 @@ void loadSettingsFromEEPROM(bool first)
nightlightTargetBri = EEPROM.read(288);
otaLock = EEPROM.read(289);
udpPort = ((EEPROM.read(290) << 0) & 0xFF) + ((EEPROM.read(291) << 8) & 0xFF00);
udpPort = EEPROM.read(290) + ((EEPROM.read(291) << 8) & 0xFF00);
readStringFromEEPROM(292, serverDescription, 32);
@@ -338,7 +352,7 @@ void loadSettingsFromEEPROM(bool first)
if (!EEPROM.read(367)) arlsOffset = -arlsOffset;
turnOnAtBoot = EEPROM.read(369);
useHSBDefault = EEPROM.read(370);
whiteS = EEPROM.read(371); white = whiteS;
colS[3] = EEPROM.read(371); col[3] = colS[3];
useRGBW = EEPROM.read(372);
effectPaletteDefault = EEPROM.read(373); effectPalette = effectPaletteDefault;
//374 - strip.paletteFade
@@ -349,10 +363,10 @@ void loadSettingsFromEEPROM(bool first)
}
//377 = lastEEPROMversion
if (lastEEPROMversion > 1) {
colSecS[0] = EEPROM.read(378); colSec[0] = colSecS[0];
colSecS[1] = EEPROM.read(379); colSec[1] = colSecS[1];
colSecS[2] = EEPROM.read(380); colSec[2] = colSecS[2];
whiteSecS = EEPROM.read(381); whiteSec = whiteSecS;
for (byte i=0; i<4; i++)
{
colSecS[i] = EEPROM.read(378+i); colSec[i] = colSecS[i];
}
}
if (lastEEPROMversion > 3) {
effectIntensityDefault = EEPROM.read(326); effectIntensity = effectIntensityDefault;
@@ -377,7 +391,7 @@ void loadSettingsFromEEPROM(bool first)
readStringFromEEPROM(2054, hueApiKey, 46);
huePollIntervalMs = ((EEPROM.read(2100) << 0) & 0xFF) + ((EEPROM.read(2101) << 8) & 0xFF00);
huePollIntervalMs = EEPROM.read(2100) + ((EEPROM.read(2101) << 8) & 0xFF00);
notifyHue = EEPROM.read(2102);
hueApplyOnOff = EEPROM.read(2103);
hueApplyBri = EEPROM.read(2104);
@@ -413,9 +427,9 @@ void loadSettingsFromEEPROM(bool first)
if (lastEEPROMversion > 6)
{
e131Universe = ((EEPROM.read(2190) << 0) & 0xFF) + ((EEPROM.read(2191) << 8) & 0xFF00);
e131Universe = EEPROM.read(2190) + ((EEPROM.read(2191) << 8) & 0xFF00);
e131Multicast = EEPROM.read(2192);
realtimeTimeoutMs = ((EEPROM.read(2193) << 0) & 0xFF) + ((EEPROM.read(2194) << 8) & 0xFF00);
realtimeTimeoutMs = EEPROM.read(2193) + ((EEPROM.read(2194) << 8) & 0xFF00);
arlsForceMaxBri = EEPROM.read(2195);
arlsDisableGammaCorrection = EEPROM.read(2196);
}
@@ -430,8 +444,8 @@ void loadSettingsFromEEPROM(bool first)
timerHours[i] = EEPROM.read(2260 + i);
timerMinutes[i] = EEPROM.read(2270 + i);
timerWeekday[i] = EEPROM.read(2280 + i);
timerMacro[i] = EEPROM.read(2290 + i);
if (timerWeekday[i] == 0) timerWeekday[i] = 255;
timerMacro[i] = EEPROM.read(2290 + i);
}
}
@@ -441,12 +455,24 @@ void loadSettingsFromEEPROM(bool first)
readStringFromEEPROM(2333, mqttDeviceTopic, 32);
readStringFromEEPROM(2366, mqttGroupTopic, 32);
}
if (lastEEPROMversion > 9)
{
strip.colorOrder = EEPROM.read(383);
irEnabled = EEPROM.read(385);
strip.ablMilliampsMax = EEPROM.read(387) + ((EEPROM.read(388) << 8) & 0xFF00);
} else if (lastEEPROMversion > 1) //ABL is off by default when updating from version older than 0.8.2
{
strip.ablMilliampsMax = 65000;
} else {
strip.ablMilliampsMax = ABL_MILLIAMPS_DEFAULT;
}
receiveDirect = !EEPROM.read(2200);
enableRealtimeUI = EEPROM.read(2201);
uiConfiguration = EEPROM.read(2202);
#ifdef WLED_FLASH_512K_MODE
#ifdef WLED_DISABLE_MOBILE_UI
uiConfiguration = 1;
//force default UI since mobile is unavailable
#endif
@@ -457,7 +483,7 @@ void loadSettingsFromEEPROM(bool first)
if (EEPROM.read(2210) || EEPROM.read(2211) || EEPROM.read(2212))
{
presetCyclingEnabled = EEPROM.read(2205);
presetCycleTime = ((EEPROM.read(2206) << 0) & 0xFF) + ((EEPROM.read(2207) << 8) & 0xFF00);
presetCycleTime = EEPROM.read(2206) + ((EEPROM.read(2207) << 8) & 0xFF00);
presetCycleMin = EEPROM.read(2208);
presetCycleMax = EEPROM.read(2209);
presetApplyBri = EEPROM.read(2210);
@@ -467,9 +493,8 @@ void loadSettingsFromEEPROM(bool first)
bootPreset = EEPROM.read(389);
wifiLock = EEPROM.read(393);
utcOffsetSecs = ((EEPROM.read(394) << 0) & 0xFF) + ((EEPROM.read(395) << 8) & 0xFF00);
utcOffsetSecs = EEPROM.read(394) + ((EEPROM.read(395) << 8) & 0xFF00);
if (EEPROM.read(396)) utcOffsetSecs = -utcOffsetSecs; //negative
initLedsLast = EEPROM.read(397);
enableSecTransition = !EEPROM.read(399);
//favorite setting (preset) memory (25 slots/ each 20byte)
@@ -491,47 +516,41 @@ void loadSettingsFromEEPROM(bool first)
useHSB = useHSBDefault;
strip.setMode(effectCurrent);
strip.setSpeed(effectSpeed);
strip.setIntensity(effectIntensity);
strip.setPalette(effectPalette);
overlayCurrent = overlayDefault;
}
//PRESET PROTOCOL 20 bytes
//0: preset purpose byte 0:invalid 1:valid preset 1.0
//1:a 2:r 3:g 4:b 5:w 6:er 7:eg 8:eb 9:ew 10:fx 11:sx | custom chase 12:numP 13:numS 14:(0:fs 1:both 2:fe) 15:step 16:ix 17: fp 18-19:Zeros
void applyPreset(byte index, bool loadBri, bool loadCol, bool loadFX)
bool applyPreset(byte index, bool loadBri = true, bool loadCol = true, bool loadFX = true)
{
if (index == 255 || index == 0) loadSettingsFromEEPROM(false);//load boot defaults
if (index > 25 || index < 1) return;
if (index == 255 || index == 0)
{
loadSettingsFromEEPROM(false);//load boot defaults
return true;
}
if (index > 25 || index < 1) return false;
uint16_t i = 380 + index*20;
if (EEPROM.read(i) == 0) return;
if (EEPROM.read(i) == 0) return false;
if (loadBri) bri = EEPROM.read(i+1);
if (loadCol)
{
col[0] = EEPROM.read(i+2);
col[1] = EEPROM.read(i+3);
col[2] = EEPROM.read(i+4);
white = EEPROM.read(i+5);
colSec[0] = EEPROM.read(i+6);
colSec[1] = EEPROM.read(i+7);
colSec[2] = EEPROM.read(i+8);
whiteSec = EEPROM.read(i+9);
for (byte j=0; j<4; j++)
{
col[j] = EEPROM.read(i+j+2);
colSec[j] = EEPROM.read(i+j+6);
}
}
if (loadFX)
{
byte lastfx = effectCurrent;
effectCurrent = EEPROM.read(i+10);
effectSpeed = EEPROM.read(i+11);
effectIntensity = EEPROM.read(i+16);
effectPalette = EEPROM.read(i+17);
if (lastfx != effectCurrent) strip.setMode(effectCurrent);
strip.setSpeed(effectSpeed);
strip.setIntensity(effectIntensity);
strip.setPalette(effectPalette);
}
return true;
}
void savePreset(byte index)
@@ -541,22 +560,20 @@ void savePreset(byte index)
uint16_t i = 380 + index*20;//min400
EEPROM.write(i, 1);
EEPROM.write(i+1, bri);
EEPROM.write(i+2, col[0]);
EEPROM.write(i+3, col[1]);
EEPROM.write(i+4, col[2]);
EEPROM.write(i+5, white);
EEPROM.write(i+6, colSec[0]);
EEPROM.write(i+7, colSec[1]);
EEPROM.write(i+8, colSec[2]);
EEPROM.write(i+9, whiteSec);
for (uint16_t j=0; j<4; j++)
{
EEPROM.write(i+j+2, col[j]);
EEPROM.write(i+j+6, colSec[j]);
}
EEPROM.write(i+10, effectCurrent);
EEPROM.write(i+11, effectSpeed);
EEPROM.write(i+16, effectIntensity);
EEPROM.write(i+17, effectPalette);
EEPROM.commit();
commit();
}
String loadMacro(byte index)
{
index-=1;
@@ -567,10 +584,10 @@ String loadMacro(byte index)
if (EEPROM.read(i) == 0) break;
m += char(EEPROM.read(i));
}
if (m.charAt(0) < 65 || m.charAt(0) > 90) return ""; //do simple check if macro is valid (capital first letter)
return m;
}
void applyMacro(byte index)
{
index-=1;
@@ -589,6 +606,7 @@ void applyMacro(byte index)
handleSet(mc);
}
void saveMacro(byte index, String mc, bool sing=true) //only commit on single save, not in settings
{
index-=1;
@@ -598,6 +616,23 @@ void saveMacro(byte index, String mc, bool sing=true) //only commit on single sa
{
EEPROM.write(i, mc.charAt(i-s));
}
if (sing) EEPROM.commit();
if (sing) commit();
}
void commit()
{
DEBUG_PRINT("s");
//this is to support IR on ESP32, needs work
/*#ifdef ARDUINO_ARCH_ESP32
portMUX_TYPE mMux = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&mMux);
#endif*/
EEPROM.commit();
/*#ifdef ARDUINO_ARCH_ESP32
portEXIT_CRITICAL(&mMux);
#endif*/
DEBUG_PRINT(".");
}

View File

@@ -2,60 +2,88 @@
* Sending XML status files to client
*/
void XML_response(bool isHTTP)
//build XML response to HTTP /win API request
void XML_response(bool isHTTP, bool includeTheme)
{
olen = 0;
oappend("<?xml version = \"1.0\" ?><vs><ac>");
if (nightlightActive && nightlightFade)
{
oappendi(briT);
} else
{
oappendi(bri);
}
oappend("</ac>");
for (int i = 0; i < 3; i++)
{
oappend("<cl>");
oappendi(col[i]);
oappend("</cl>");
}
oappend("<ns>");
oappendi(notifyDirect);
oappend("</ns><nr>");
oappendi(receiveNotifications);
oappend("</nr><nl>");
oappendi(nightlightActive);
oappend("</nl><nf>");
oappendi(nightlightFade);
oappend("</nf><nd>");
oappendi(nightlightDelayMins);
oappend("</nd><nt>");
oappendi(nightlightTargetBri);
oappend("</nt><fx>");
oappendi(effectCurrent);
oappend("</fx><sx>");
oappendi(effectSpeed);
oappend("</sx><ix>");
oappendi(effectIntensity);
oappend("</ix><fp>");
oappendi(effectPalette);
oappend("</fp><wv>");
if (useRGBW && !autoRGBtoRGBW) {
oappendi(white);
} else {
oappend("-1");
}
oappend("</wv><md>");
oappendi(useHSB);
oappend("</md><ds>");
oappend(serverDescription);
oappend("</ds></vs>");
if (isHTTP) server.send(200, "text/xml", obuf);
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>");
oappendi(col[i]);
oappend("</cl>");
}
for (int i = 0; i < 3; i++)
{
oappend("<cs>");
oappendi(colSec[i]);
oappend("</cs>");
}
oappend("<ns>");
oappendi(notifyDirect);
oappend("</ns><nr>");
oappendi(receiveNotifications);
oappend("</nr><nl>");
oappendi(nightlightActive);
oappend("</nl><nf>");
oappendi(nightlightFade);
oappend("</nf><nd>");
oappendi(nightlightDelayMins);
oappend("</nd><nt>");
oappendi(nightlightTargetBri);
oappend("</nt><fx>");
oappendi(effectCurrent);
oappend("</fx><sx>");
oappendi(effectSpeed);
oappend("</sx><ix>");
oappendi(effectIntensity);
oappend("</ix><fp>");
oappendi(effectPalette);
oappend("</fp><wv>");
if (useRGBW && !autoRGBtoRGBW) {
oappendi(col[3]);
} else {
oappend("-1");
}
oappend("</wv><ws>");
oappendi(colSec[3]);
oappend("</ws><md>");
oappendi(useHSB);
oappend("</md><cy>");
oappendi(presetCyclingEnabled);
oappend("</cy><ds>");
oappend(serverDescription);
oappend("</ds>");
if (includeTheme)
{
char cs[6][9];
getThemeColors(cs);
oappend("<th><ca>#");
oappend(cs[0]);
oappend("</ca><cb>#");
oappend(cs[1]);
oappend("</cb><cc>#");
oappend(cs[2]);
oappend("</cc><cd>#");
oappend(cs[3]);
oappend("</cd><cu>#");
oappend(cs[4]);
oappend("</cu><ct>#");
oappend(cs[5]);
oappend("</ct><cf>");
oappend(cssFont);
oappend("</cf></th>");
}
oappend("</vs>");
if (isHTTP) server.send(200, "text/xml", obuf);
}
void sappend(char stype, char* key, int val) //append a setting to string buffer
//append a numeric setting to string buffer
void sappend(char stype, char* key, int val)
{
char ds[] = "d.Sf.";
@@ -85,28 +113,30 @@ void sappend(char stype, char* key, int val) //append a setting to string buffer
}
}
void sappends(char stype, char* key, char* val) //append a string setting
//append a string setting to buffer
void sappends(char stype, char* key, char* val)
{
switch(stype)
{
case 's': //string (we can interpret val as char*)
oappend("d.Sf.");
oappend(key);
oappend(".value=\"");
oappend(val);
oappend("\";");
break;
oappend("d.Sf.");
oappend(key);
oappend(".value=\"");
oappend(val);
oappend("\";");
break;
case 'm': //message
oappend("d.getElementsByClassName");
oappend(key);
oappend(".innerHTML=\"");
oappend(val);
oappend("\";");
break;
oappend("d.getElementsByClassName");
oappend(key);
oappend(".innerHTML=\"");
oappend(val);
oappend("\";");
break;
}
}
void getSettingsJS(byte subPage) //get values for settings form in javascript
//get values for settings form in javascript
void getSettingsJS(byte subPage)
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec
DEBUG_PRINT("settings resp");
@@ -171,17 +201,26 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript
if (subPage == 2) {
sappend('v',"LC",ledCount);
sappend('v',"MA",strip.ablMilliampsMax);
if (strip.currentMilliamps)
{
sappends('m',"(\"pow\")[0]","");
olen -= 2; //delete ";
oappendi(strip.currentMilliamps);
oappend("mA\";");
}
sappend('v',"CR",colS[0]);
sappend('v',"CG",colS[1]);
sappend('v',"CB",colS[2]);
sappend('v',"CA",briS);
sappend('c',"EW",useRGBW);
sappend('i',"CO",strip.colorOrder);
sappend('c',"AW",autoRGBtoRGBW);
sappend('v',"CW",whiteS);
sappend('v',"CW",colS[3]);
sappend('v',"SR",colSecS[0]);
sappend('v',"SG",colSecS[1]);
sappend('v',"SB",colSecS[2]);
sappend('v',"SW",whiteSecS);
sappend('v',"SW",colSecS[3]);
sappend('c',"BO",turnOnAtBoot);
sappend('v',"BP",bootPreset);
sappend('v',"FX",effectDefault);
@@ -196,11 +235,10 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript
sappend('c',"T2",enableSecTransition);
sappend('v',"BF",briMultiplier);
sappend('v',"TB",nightlightTargetBri);
sappend('v',"TL",nightlightDelayMins);
sappend('v',"TL",nightlightDelayMinsDefault);
sappend('c',"TW",nightlightFade);
sappend('i',"PB",strip.paletteBlend);
sappend('c',"RV",reverseMode);
sappend('c',"EI",initLedsLast);
sappend('c',"SL",skipFirstLed);
}
@@ -222,6 +260,7 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript
if (subPage == 4)
{
sappend('c',"BT",buttonEnabled);
sappend('c',"IR",irEnabled);
sappend('v',"UP",udpPort);
sappend('c',"RB",receiveNotificationBrightness);
sappend('c',"RC",receiveNotificationColor);
@@ -303,6 +342,7 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript
k[0] = 'H'; sappend('v',k,timerHours[i]);
k[0] = 'N'; sappend('v',k,timerMinutes[i]);
k[0] = 'T'; sappend('v',k,timerMacro[i]);
k[0] = 'W'; sappend('v',k,timerWeekday[i]);
}
}
@@ -321,3 +361,29 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript
}
oappend("}</script>");
}
//get colors from current theme as c strings
void getThemeColors(char o[][9])
{
switch (currentTheme)
{
// 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
case 3: strcpy(o[0], "c09f80"); strcpy(o[1], "d7cec7"); strcpy(o[2], "76323f"); strcpy(o[3], "888"); strcpy(o[4], "3334"); strcpy(o[5], "888"); break; //wine
case 4: strcpy(o[0], "3cc47c"); strcpy(o[1], "828081"); strcpy(o[2], "d9a803"); strcpy(o[3], "1e392a"); strcpy(o[4], "000a"); strcpy(o[5], "1e392a"); break; //electric
case 5: strcpy(o[0], "57bc90"); strcpy(o[1], "a5a5af"); strcpy(o[2], "015249"); strcpy(o[3], "88c9d4"); strcpy(o[4], "0004"); strcpy(o[5], "88c9d4"); break; //mint
case 6: strcpy(o[0], "f7c331"); strcpy(o[1], "dca"); strcpy(o[2], "6b7a8f"); strcpy(o[3], "f7882f"); strcpy(o[4], "0007"); strcpy(o[5], "f7882f"); break; //amber
case 7: strcpy(o[0], "fff"); strcpy(o[1], "333"); strcpy(o[2], "222"); strcpy(o[3], "666"); strcpy(o[4], ""); strcpy(o[5], "fff"); break; //dark
case 8: strcpy(o[0], "0ac"); strcpy(o[1], "124"); strcpy(o[2], "224"); strcpy(o[3], "003eff"); strcpy(o[4], "003eff"); strcpy(o[5], "003eff"); break; //air
case 9: strcpy(o[0], "f70"); strcpy(o[1], "421"); strcpy(o[2], "221"); strcpy(o[3], "a50"); strcpy(o[4], "f70"); strcpy(o[5], "f70"); break; //nixie
case 10: strcpy(o[0], "2d2"); strcpy(o[1], "010"); strcpy(o[2], "121"); strcpy(o[3], "060"); strcpy(o[4], "040"); strcpy(o[5], "3f3"); break; //terminal
case 11: strcpy(o[0], "867ADE"); strcpy(o[1], "4033A3"); strcpy(o[2], "483AAA"); strcpy(o[3], "483AAA"); strcpy(o[4], ""); strcpy(o[5], "867ADE"); break; //c64
case 12: strcpy(o[0], "fbe8a6"); strcpy(o[1], "d2fdff"); strcpy(o[2], "b4dfe5"); strcpy(o[3], "f4976c"); strcpy(o[4], ""); strcpy(o[5], "303c6c"); break; //easter
case 13: strcpy(o[0], "d4af37"); strcpy(o[1], "173305"); strcpy(o[2], "308505"); strcpy(o[3], "f21313"); strcpy(o[4], "f002"); strcpy(o[5], "d4af37"); break; //christmas
case 14: strcpy(o[0], "fc7"); strcpy(o[1], "49274a"); strcpy(o[2], "94618e"); strcpy(o[3], "f4decb"); strcpy(o[4], "0008"); strcpy(o[5], "f4decb"); break; //end
case 15: for (int i=0;i<6;i++) strcpy(o[i], cssCol[i]); //custom
}
}

View File

@@ -59,18 +59,19 @@ void handleSettingsSet(byte subPage)
#ifdef ARDUINO_ARCH_ESP32
if (ledCount > 600) ledCount = 600;
#endif
strip.ablMilliampsMax = server.arg("MA").toInt();
useRGBW = server.hasArg("EW");
strip.colorOrder = server.arg("CO").toInt();
autoRGBtoRGBW = server.hasArg("AW");
if (server.hasArg("IS")) //ignore settings and save current brightness, colors and fx as default
//ignore settings and save current brightness, colors and fx as default
if (server.hasArg("IS"))
{
colS[0] = col[0];
colS[1] = col[1];
colS[2] = col[2];
colSecS[0] = colSec[0];
colSecS[1] = colSec[1];
colSecS[2] = colSec[2];
whiteS = white;
whiteSecS = whiteSec;
for (byte i=0; i<4; i++)
{
colS[i] = col[i];
colSecS[i] = colSec[i];
}
briS = bri;
effectDefault = effectCurrent;
effectSpeedDefault = effectSpeed;
@@ -83,8 +84,8 @@ void handleSettingsSet(byte subPage)
colSecS[0] = server.arg("SR").toInt();
colSecS[1] = server.arg("SG").toInt();
colSecS[2] = server.arg("SB").toInt();
whiteS = server.arg("CW").toInt();
whiteSecS = server.arg("SW").toInt();
colS[3] = server.arg("CW").toInt();
colSecS[3] = server.arg("SW").toInt();
briS = server.arg("CA").toInt();
effectDefault = server.arg("FX").toInt();
effectSpeedDefault = server.arg("SX").toInt();
@@ -107,12 +108,11 @@ void handleSettingsSet(byte subPage)
nightlightTargetBri = server.arg("TB").toInt();
t = server.arg("TL").toInt();
if (t > 0) nightlightDelayMins = t;
if (t > 0) nightlightDelayMinsDefault = t;
nightlightFade = server.hasArg("TW");
t = server.arg("PB").toInt();
if (t >= 0 && t < 4) strip.paletteBlend = t;
initLedsLast = server.hasArg("EI");
reverseMode = server.hasArg("RV");
strip.setReverseMode(reverseMode);
skipFirstLed = server.hasArg("SL");
@@ -136,13 +136,13 @@ void handleSettingsSet(byte subPage)
strcpy(cssCol[i],server.arg(k).c_str());
}
strcpy(cssFont,server.arg("CF").c_str());
buildCssColorString();
}
//SYNC
if (subPage == 4)
{
buttonEnabled = server.hasArg("BT");
irEnabled = server.hasArg("IR");
int t = server.arg("UP").toInt();
if (t > 0) udpPort = t;
receiveNotificationBrightness = server.hasArg("RB");
@@ -170,7 +170,9 @@ void handleSettingsSet(byte subPage)
strcpy(alexaInvocationName, server.arg("AI").c_str());
notifyAlexa = server.hasArg("SA");
if (server.hasArg("BK") && !server.arg("BK").equals("Hidden")) {strcpy(blynkApiKey,server.arg("BK").c_str()); initBlynk(blynkApiKey);}
if (server.hasArg("BK") && !server.arg("BK").equals("Hidden")) {
strcpy(blynkApiKey,server.arg("BK").c_str()); initBlynk(blynkApiKey);
}
strcpy(mqttServer, server.arg("MS").c_str());
strcpy(mqttDeviceTopic, server.arg("MD").c_str());
@@ -209,10 +211,13 @@ void handleSettingsSet(byte subPage)
useAMPM = !server.hasArg("CF");
currentTimezone = server.arg("TZ").toInt();
utcOffsetSecs = server.arg("UO").toInt();
if (ntpEnabled && WiFi.status() == WL_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort); //start if not already connected
//start ntp if not already connected
if (ntpEnabled && WiFi.status() == WL_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
if (server.hasArg("OL")){
overlayDefault = server.arg("OL").toInt();
if (overlayCurrent != overlayDefault) strip.unlockAll();
overlayCurrent = overlayDefault;
}
@@ -264,6 +269,9 @@ void handleSettingsSet(byte subPage)
k[0] = 'T'; //macros
timerMacro[i] = server.arg(k).toInt();
k[0] = 'W'; //weekdays
timerWeekday[i] = server.arg(k).toInt();
}
}
@@ -273,7 +281,7 @@ void handleSettingsSet(byte subPage)
if (server.hasArg("RS")) //complete factory reset
{
clearEEPROM();
serveMessage(200, "All Settings erased.", "Connect to WLED-AP to setup again...",255);
serveMessage(200, "All Settings erased.", "Connect to WLED-AP to setup again",255);
reset();
}
@@ -300,455 +308,426 @@ void handleSettingsSet(byte subPage)
}
saveSettingsToEEPROM();
if (subPage == 2) strip.init(useRGBW,ledCount,skipFirstLed);
if (subPage == 4) alexaInit();
}
//helper to get int value at a position in string
int getNumVal(String* req, uint16_t pos)
{
return req->substring(pos + 3).toInt();
}
//HTTP API request parser
bool handleSet(String req)
{
bool effectUpdated = false;
if (!(req.indexOf("win") >= 0)) return false;
if (!(req.indexOf("win") >= 0)) return false;
int pos = 0;
DEBUG_PRINT("API req: ");
DEBUG_PRINTLN(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) {
int en = req.indexOf(')');
String mc = req.substring(pos);
if (en > 0) mc = req.substring(pos, en);
saveMacro(i, mc);
}
pos = req.indexOf("IN");
if (pos < 1) XML_response(true, false);
return true;
//if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise
}
//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) {
int en = req.indexOf(')');
String mc = req.substring(pos);
if (en > 0) mc = req.substring(pos, en);
saveMacro(i, mc);
}
pos = req.indexOf("IN");
if (pos < 1) XML_response(true);
return true;
//if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise
}
//set brigthness
pos = req.indexOf("&A=");
if (pos > 0) {
bri = req.substring(pos + 3).toInt();
}
//set brigthness
pos = req.indexOf("&A=");
if (pos > 0) {
bri = getNumVal(&req, pos);
}
//set hue
pos = req.indexOf("HU=");
if (pos > 0) {
uint16_t temphue = req.substring(pos + 3).toInt();
byte tempsat = 255;
pos = req.indexOf("SA=");
if (pos > 0) {
tempsat = req.substring(pos + 3).toInt();
}
colorHStoRGB(temphue,tempsat,(req.indexOf("H2")>0)? colSec:col);
}
//set hue
pos = req.indexOf("HU=");
if (pos > 0) {
uint16_t temphue = getNumVal(&req, pos);
byte tempsat = 255;
pos = req.indexOf("SA=");
if (pos > 0) {
tempsat = getNumVal(&req, pos);
}
colorHStoRGB(temphue,tempsat,(req.indexOf("H2")>0)? colSec:col);
}
//set red value
pos = req.indexOf("&R=");
if (pos > 0) {
col[0] = req.substring(pos + 3).toInt();
}
//set green value
pos = req.indexOf("&G=");
if (pos > 0) {
col[1] = req.substring(pos + 3).toInt();
}
//set blue value
pos = req.indexOf("&B=");
if (pos > 0) {
col[2] = req.substring(pos + 3).toInt();
}
//set white value
pos = req.indexOf("&W=");
if (pos > 0) {
white = req.substring(pos + 3).toInt();
}
//set red value
pos = req.indexOf("&R=");
if (pos > 0) {
col[0] = getNumVal(&req, pos);
}
//set green value
pos = req.indexOf("&G=");
if (pos > 0) {
col[1] = getNumVal(&req, pos);
}
//set blue value
pos = req.indexOf("&B=");
if (pos > 0) {
col[2] = getNumVal(&req, pos);
}
//set white value
pos = req.indexOf("&W=");
if (pos > 0) {
col[3] = getNumVal(&req, pos);
}
//set 2nd red value
pos = req.indexOf("R2=");
if (pos > 0) {
colSec[0] = req.substring(pos + 3).toInt();
}
//set 2nd green value
pos = req.indexOf("G2=");
if (pos > 0) {
colSec[1] = req.substring(pos + 3).toInt();
}
//set 2nd blue value
pos = req.indexOf("B2=");
if (pos > 0) {
colSec[2] = req.substring(pos + 3).toInt();
}
//set 2nd white value
pos = req.indexOf("W2=");
if (pos > 0) {
whiteSec = req.substring(pos + 3).toInt();
}
//set 2nd red value
pos = req.indexOf("R2=");
if (pos > 0) {
colSec[0] = getNumVal(&req, pos);
}
//set 2nd green value
pos = req.indexOf("G2=");
if (pos > 0) {
colSec[1] = getNumVal(&req, pos);
}
//set 2nd blue value
pos = req.indexOf("B2=");
if (pos > 0) {
colSec[2] = getNumVal(&req, pos);
}
//set 2nd white value
pos = req.indexOf("W2=");
if (pos > 0) {
colSec[3] = getNumVal(&req, pos);
}
//set color from HEX or 32bit DEC
pos = req.indexOf("CL=");
if (pos > 0) {
colorFromDecOrHexString(col, &white, (char*)req.substring(pos + 3).c_str());
}
pos = req.indexOf("C2=");
if (pos > 0) {
colorFromDecOrHexString(colSec, &whiteSec, (char*)req.substring(pos + 3).c_str());
}
//set color from HEX or 32bit DEC
pos = req.indexOf("CL=");
if (pos > 0) {
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str());
}
pos = req.indexOf("C2=");
if (pos > 0) {
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
}
//set 2nd to white
pos = req.indexOf("SW");
if (pos > 0) {
if(useRGBW) {
whiteSec = 255;
colSec[0] = 0;
colSec[1] = 0;
colSec[2] = 0;
} else {
colSec[0] = 255;
colSec[1] = 255;
colSec[2] = 255;
}
}
//set 2nd to black
pos = req.indexOf("SB");
if (pos > 0) {
whiteSec = 0;
//set 2nd to white
pos = req.indexOf("SW");
if (pos > 0) {
if(useRGBW) {
colSec[3] = 255;
colSec[0] = 0;
colSec[1] = 0;
colSec[2] = 0;
}
} else {
colSec[0] = 255;
colSec[1] = 255;
colSec[2] = 255;
}
}
//set to random hue SR=0->1st SR=1->2nd
pos = req.indexOf("SR");
if (pos > 0) {
_setRandomColor(req.substring(pos + 3).toInt());
}
//set 2nd to 1st
pos = req.indexOf("SP");
if (pos > 0) {
colSec[0] = col[0];
colSec[1] = col[1];
colSec[2] = col[2];
whiteSec = white;
}
//swap 2nd & 1st
pos = req.indexOf("SC");
if (pos > 0) {
byte _temp[4];
for (int i = 0; i<3; i++)
{
_temp[i] = col[i];
col[i] = colSec[i];
colSec[i] = _temp[i];
}
_temp[3] = white;
white = whiteSec;
whiteSec = _temp[3];
}
//set 2nd to black
pos = req.indexOf("SB");
if (pos > 0) {
colSec[3] = 0;
colSec[0] = 0;
colSec[1] = 0;
colSec[2] = 0;
}
//set current effect index
pos = req.indexOf("FX=");
if (pos > 0) {
if (effectCurrent != req.substring(pos + 3).toInt())
{
effectCurrent = req.substring(pos + 3).toInt();
strip.setMode(effectCurrent);
effectUpdated = true;
}
}
//set effect speed
pos = req.indexOf("SX=");
if (pos > 0) {
if (effectSpeed != req.substring(pos + 3).toInt())
{
effectSpeed = req.substring(pos + 3).toInt();
strip.setSpeed(effectSpeed);
effectUpdated = true;
}
}
//set effect intensity
pos = req.indexOf("IX=");
if (pos > 0) {
if (effectIntensity != req.substring(pos + 3).toInt())
{
effectIntensity = req.substring(pos + 3).toInt();
strip.setIntensity(effectIntensity);
effectUpdated = true;
}
}
//set effect palette (only for FastLED effects)
pos = req.indexOf("FP=");
if (pos > 0) {
if (effectPalette != req.substring(pos + 3).toInt())
{
effectPalette = req.substring(pos + 3).toInt();
strip.setPalette(effectPalette);
effectUpdated = true;
}
}
//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) {
colSec[0] = col[0];
colSec[1] = col[1];
colSec[2] = col[2];
colSec[3] = col[3];
}
//swap 2nd & 1st
pos = req.indexOf("SC");
if (pos > 0) {
byte temp;
for (uint8_t i=0; i<4; i++)
{
temp = col[i];
col[i] = colSec[i];
colSec[i] = temp;
}
}
//set current effect index
pos = req.indexOf("FX=");
if (pos > 0) {
effectCurrent = getNumVal(&req, pos);
presetCyclingEnabled = false;
}
//set effect speed
pos = req.indexOf("SX=");
if (pos > 0) {
effectSpeed = getNumVal(&req, pos);
}
//set effect intensity
pos = req.indexOf("IX=");
if (pos > 0) {
effectIntensity = req.substring(pos + 3).toInt();
}
//set effect palette (only for FastLED effects)
pos = req.indexOf("FP=");
if (pos > 0) {
effectPalette = req.substring(pos + 3).toInt();
}
//set hue polling light: 0 -off
pos = req.indexOf("HP=");
if (pos > 0) {
int id = req.substring(pos + 3).toInt();
if (id > 0)
{
if (id < 100) huePollLightId = id;
setupHue();
} else {
huePollingEnabled = false;
}
}
//set hue polling light: 0 -off
pos = req.indexOf("HP=");
if (pos > 0) {
int id = getNumVal(&req, pos);
if (id > 0)
{
if (id < 100) huePollLightId = id;
setupHue();
} else {
huePollingEnabled = false;
}
}
//set default control mode (0 - RGB, 1 - HSB)
pos = req.indexOf("MD=");
if (pos > 0) {
useHSB = req.substring(pos + 3).toInt();
}
//set advanced overlay
pos = req.indexOf("OL=");
if (pos > 0) {
overlayCurrent = req.substring(pos + 3).toInt();
strip.unlockAll();
}
//(un)lock pixel (ranges)
pos = req.indexOf("&L=");
if (pos > 0){
int index = req.substring(pos + 3).toInt();
pos = req.indexOf("L2=");
if (pos > 0){
int index2 = req.substring(pos + 3).toInt();
if (req.indexOf("UL") > 0)
{
strip.unlockRange(index, index2);
} else
{
strip.lockRange(index, index2);
}
//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){
int index = getNumVal(&req, pos);
pos = req.indexOf("L2=");
if (pos > 0){
int index2 = getNumVal(&req, pos);
if (req.indexOf("UL") > 0)
{
strip.unlockRange(index, index2);
} else
{
if (req.indexOf("UL") > 0)
{
strip.unlock(index);
} else
{
strip.lock(index);
}
strip.lockRange(index, index2);
}
}
} else
{
if (req.indexOf("UL") > 0)
{
strip.unlock(index);
} else
{
strip.lock(index);
}
}
}
//apply macro
pos = req.indexOf("&M=");
if (pos > 0) {
applyMacro(req.substring(pos + 3).toInt());
}
//toggle send UDP direct notifications
if (req.indexOf("SN=") > 0)
{
notifyDirect = true;
if (req.indexOf("SN=0") > 0)
{
notifyDirect = false;
}
}
//apply macro
pos = req.indexOf("&M=");
if (pos > 0) {
applyMacro(getNumVal(&req, pos));
}
//toggle send UDP direct notifications
if (req.indexOf("SN=") > 0)
{
notifyDirect = true;
if (req.indexOf("SN=0") > 0)
{
notifyDirect = false;
}
}
//toggle receive UDP direct notifications
if (req.indexOf("RN=") > 0)
{
receiveNotifications = true;
if (req.indexOf("RN=0") > 0)
{
receiveNotifications = false;
}
}
//toggle receive UDP direct notifications
if (req.indexOf("RN=") > 0)
{
receiveNotifications = true;
if (req.indexOf("RN=0") > 0)
{
receiveNotifications = false;
}
}
//toggle nightlight mode
bool aNlDef = false;
if (req.indexOf("&ND") > 0) aNlDef = true;
pos = req.indexOf("NL=");
if (pos > 0)
{
if (req.indexOf("NL=0") > 0)
{
nightlightActive = false;
bri = briT;
} else {
nightlightActive = true;
if (!aNlDef) nightlightDelayMins = req.substring(pos + 3).toInt();
nightlightStartTime = millis();
}
} else if (aNlDef)
{
//toggle nightlight mode
bool aNlDef = false;
if (req.indexOf("&ND") > 0) aNlDef = true;
pos = req.indexOf("NL=");
if (pos > 0)
{
if (req.indexOf("NL=0") > 0)
{
nightlightActive = false;
bri = briT;
} else {
nightlightActive = true;
if (!aNlDef) nightlightDelayMins = getNumVal(&req, pos);
nightlightStartTime = millis();
}
}
} else if (aNlDef)
{
nightlightActive = true;
nightlightStartTime = millis();
}
//set nightlight target brightness
pos = req.indexOf("NT=");
if (pos > 0) {
nightlightTargetBri = req.substring(pos + 3).toInt();
nightlightActiveOld = false; //re-init
}
//set nightlight target brightness
pos = req.indexOf("NT=");
if (pos > 0) {
nightlightTargetBri = getNumVal(&req, pos);
nightlightActiveOld = false; //re-init
}
//toggle nightlight fade
if (req.indexOf("NF=") > 0)
{
if (req.indexOf("NF=0") > 0)
{
nightlightFade = false;
} else {
nightlightFade = true;
}
nightlightActiveOld = false; //re-init
}
//toggle nightlight fade
if (req.indexOf("NF=") > 0)
{
if (req.indexOf("NF=0") > 0)
{
nightlightFade = false;
} else {
nightlightFade = true;
}
nightlightActiveOld = false; //re-init
}
//toggle general purpose output
pos = req.indexOf("AX=");
if (pos > 0) {
auxTime = req.substring(pos + 3).toInt();
auxActive = true;
if (auxTime == 0) auxActive = false;
}
pos = req.indexOf("TT=");
if (pos > 0) {
transitionDelay = req.substring(pos + 3).toInt();
}
//toggle general purpose output
pos = req.indexOf("AX=");
if (pos > 0) {
auxTime = getNumVal(&req, pos);
auxActive = true;
if (auxTime == 0) auxActive = false;
}
pos = req.indexOf("TT=");
if (pos > 0) {
transitionDelay = getNumVal(&req, pos);
}
//main toggle on/off
pos = req.indexOf("&T=");
if (pos > 0) {
nightlightActive = false; //always disable nightlight when toggling
switch (req.substring(pos + 3).toInt())
{
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off
case 1: bri = briLast; break; //on
default: if (bri == 0) //toggle
{
bri = briLast;
} else
{
briLast = bri;
bri = 0;
}
}
}
//main toggle on/off
pos = req.indexOf("&T=");
if (pos > 0) {
nightlightActive = false; //always disable nightlight when toggling
switch (getNumVal(&req, pos))
{
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off
case 1: bri = briLast; break; //on
default: toggleOnOff(); //toggle
}
}
//deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri) nightlightActive = false;
//set time (unix timestamp)
pos = req.indexOf("ST=");
if (pos > 0) {
setTime(req.substring(pos+3).toInt());
}
//deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri) nightlightActive = false;
//set time (unix timestamp)
pos = req.indexOf("ST=");
if (pos > 0) {
setTime(getNumVal(&req, pos));
}
//set countdown goal (unix timestamp)
pos = req.indexOf("CT=");
if (pos > 0) {
countdownTime = req.substring(pos+3).toInt();
if (countdownTime - now() > 0) countdownOverTriggered = false;
}
//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 = req.substring(pos + 3).toInt();
pos = req.indexOf("P2="); //sets last preset for cycle
if (pos > 0) presetCycleMax = req.substring(pos + 3).toInt();
//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);
if (req.indexOf("CY=") > 0) //preset cycle
{
presetCyclingEnabled = true;
if (req.indexOf("CY=0") > 0)
{
presetCyclingEnabled = false;
}
presetCycCurr = presetCycleMin;
}
pos = req.indexOf("PT="); //sets cycle time in ms
if (pos > 0) {
int v = req.substring(pos + 3).toInt();
if (v > 49) presetCycleTime = v;
}
if (req.indexOf("PA=") > 0) //apply brightness from preset
{
presetApplyBri = true;
if (req.indexOf("PA=0") > 0) presetApplyBri = false;
}
if (req.indexOf("PC=") > 0) //apply color from preset
{
presetApplyCol = true;
if (req.indexOf("PC=0") > 0) presetApplyCol = false;
}
if (req.indexOf("PX=") > 0) //apply effects from preset
{
presetApplyFx = true;
if (req.indexOf("PX=0") > 0) presetApplyFx = false;
}
pos = req.indexOf("PS="); //saves current in preset
if (pos > 0) {
savePreset(req.substring(pos + 3).toInt());
}
pos = req.indexOf("PL="); //applies entire preset
if (pos > 0) {
applyPreset(req.substring(pos + 3).toInt(), presetApplyBri, presetApplyCol, presetApplyFx);
if (presetApplyFx) effectUpdated = true;
}
//cronixie
pos = req.indexOf("NX="); //sets digits to code
if (pos > 0) {
strcpy(cronixieDisplay,req.substring(pos + 3, pos + 9).c_str());
setCronixie();
}
pos = req.indexOf("NM="); //mode, 1 countdown
if (pos > 0) {
countdownMode = true;
if (req.indexOf("NM=0") > 0)
{
countdownMode = false;
}
}
if (req.indexOf("NB=") > 0) //sets backlight
{
cronixieBacklight = true;
if (req.indexOf("NB=0") > 0)
{
cronixieBacklight = false;
}
if (overlayCurrent == 3) strip.setCronixieBacklight(cronixieBacklight);
overlayRefreshedTime = 0;
}
pos = req.indexOf("U0="); //user var 0
if (pos > 0) {
userVar0 = req.substring(pos + 3).toInt();
}
pos = req.indexOf("U1="); //user var 1
if (pos > 0) {
userVar1 = req.substring(pos + 3).toInt();
}
//you can add more if you need
if (req.indexOf("CY=") > 0) //preset cycle
{
presetCyclingEnabled = true;
if (req.indexOf("CY=0") > 0)
{
presetCyclingEnabled = false;
}
presetCycCurr = presetCycleMin;
}
pos = req.indexOf("PT="); //sets cycle time in ms
if (pos > 0) {
int v = getNumVal(&req, pos);
if (v > 49) presetCycleTime = v;
}
if (req.indexOf("PA=") > 0) //apply brightness from preset
{
presetApplyBri = true;
if (req.indexOf("PA=0") > 0) presetApplyBri = false;
}
if (req.indexOf("PC=") > 0) //apply color from preset
{
presetApplyCol = true;
if (req.indexOf("PC=0") > 0) presetApplyCol = false;
}
if (req.indexOf("PX=") > 0) //apply effects from preset
{
presetApplyFx = true;
if (req.indexOf("PX=0") > 0) presetApplyFx = false;
}
pos = req.indexOf("PS="); //saves current in preset
if (pos > 0) {
savePreset(getNumVal(&req, pos));
}
pos = req.indexOf("PL="); //applies entire preset
if (pos > 0) {
applyPreset(getNumVal(&req, pos), presetApplyBri, presetApplyCol, presetApplyFx);
}
//cronixie
pos = req.indexOf("NX="); //sets digits to code
if (pos > 0) {
strcpy(cronixieDisplay,req.substring(pos + 3, pos + 9).c_str());
setCronixie();
}
pos = req.indexOf("NM="); //mode, 1 countdown
if (pos > 0) {
countdownMode = true;
if (req.indexOf("NM=0") > 0)
{
countdownMode = false;
}
}
if (req.indexOf("NB=") > 0) //sets backlight
{
cronixieBacklight = true;
if (req.indexOf("NB=0") > 0)
{
cronixieBacklight = false;
}
if (overlayCurrent == 3) strip.setCronixieBacklight(cronixieBacklight);
overlayRefreshedTime = 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(true);
//do not send UDP notifications this time
pos = req.indexOf("NN");
if (pos > 0)
{
colorUpdated(5);
return true;
}
if (effectUpdated)
{
colorUpdated(6);
} else
{
colorUpdated(1);
}
return true;
//internal call, does not send XML response
pos = req.indexOf("IN");
if (pos < 1) XML_response(true, (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,36 +3,37 @@
*/
void handleSerial()
{
if (Serial.available() > 0) //support for Adalight protocol to high-speed control LEDs over serial (gamma correction done by PC)
if (Serial.available() > 0) //support for Adalight protocol to high-speed control LEDs over serial
{
if (Serial.find("Ada"))
if (!Serial.find("Ada")) return;
if (!realtimeActive && bri == 0) strip.setBrightness(briLast);
arlsLock(realtimeTimeoutMs);
delay(1);
byte hi = Serial.read();
byte ledc = Serial.read();
byte chk = Serial.read();
if(chk != (hi ^ ledc ^ 0x55)) return;
if (ledCount < ledc) ledc = ledCount;
byte sc[3]; int t =-1; int to = 0;
for (int i=0; i < ledc; i++)
{
if (!realtimeActive && bri == 0) strip.setBrightness(briLast);
arlsLock(realtimeTimeoutMs);
delay(1);
byte hi = Serial.read();
byte ledc = Serial.read();
byte chk = Serial.read();
if(chk != (hi ^ ledc ^ 0x55)) return;
if (ledCount < ledc) ledc = ledCount;
byte sc[3]; int t =-1; int to = 0;
for (int i=0; i < ledc; i++)
for (byte j=0; j<3; j++)
{
for (byte j=0; j<3; j++)
while (Serial.peek()<0) //no data yet available
{
while (Serial.peek()<0) //no data yet available
{
delay(1);
to++;
if (to>5) {strip.show(); return;} //unexpected end of transmission
}
to = 0;
sc[j] = Serial.read();
delay(1);
to++;
if (to>5) {strip.show(); return;} //unexpected end of transmission
}
setRealtimePixel(i,sc[0],sc[1],sc[2],0);
to = 0;
sc[j] = Serial.read();
}
strip.show();
setRealtimePixel(i,sc[0],sc[1],sc[2],0);
}
strip.show();
}
}

View File

@@ -5,29 +5,29 @@
void wledInit()
{
EEPROM.begin(EEPSIZE);
ledCount = ((EEPROM.read(229) << 0) & 0xFF) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 10;
ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00);
if (ledCount > 1200 || ledCount == 0) ledCount = 30;
//RMT eats up too much RAM
#ifdef ARDUINO_ARCH_ESP32
if (ledCount > 600) ledCount = 600;
if (ledCount > 600) ledCount = 600;
#endif
if (!EEPROM.read(397)) strip.init(EEPROM.read(372),ledCount,EEPROM.read(2204)); //quick init
Serial.begin(115200);
Serial.setTimeout(50);
strip.init(EEPROM.read(372),ledCount,EEPROM.read(2204)); //init LEDs quickly
#ifdef USEFS
SPIFFS.begin();
SPIFFS.begin();
#endif
DEBUG_PRINTLN("Load EEPROM");
loadSettingsFromEEPROM(true);
if (!initLedsLast) initStrip();
beginStrip();
DEBUG_PRINT("CSSID: ");
DEBUG_PRINT(clientSSID);
buildCssColorString();
userBeginPreConnection();
if (strcmp(clientSSID,"Your_Network") == 0) showWelcomePage = true;
WiFi.persistent(false);
initCon();
DEBUG_PRINTLN("");
@@ -58,6 +58,11 @@ void wledInit()
}
prepareIds(); //UUID from MAC (for Alexa and MQTT)
if (strcmp(cmDNS,"x") == 0) //fill in unique mdns default
{
strcpy(cmDNS, "wled-");
strcat(cmDNS, escapedMac.c_str());
}
if (mqttDeviceTopic[0] == 0)
{
strcpy(mqttDeviceTopic, "wled/");
@@ -72,12 +77,12 @@ void wledInit()
mqttInit = initMQTT();
}
if (!initLedsLast) strip.service();
strip.service();
//HTTP server page init
initServer();
if (!initLedsLast) strip.service();
strip.service();
//init Alexa hue emulation
if (alexaEnabled && !onlyAP) alexaInit();
@@ -86,6 +91,7 @@ void wledInit()
//init ArduinoOTA
if (!onlyAP) {
#ifndef WLED_DISABLE_OTA
if (aOtaEnabled)
{
ArduinoOTA.onStart([]() {
@@ -97,8 +103,9 @@ void wledInit()
if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS);
ArduinoOTA.begin();
}
#endif
if (!initLedsLast) strip.service();
strip.service();
// Set up mDNS responder:
if (strlen(cmDNS) > 0 && !onlyAP)
{
@@ -106,8 +113,9 @@ void wledInit()
DEBUG_PRINTLN("mDNS responder started");
// Add service to MDNS
MDNS.addService("http", "tcp", 80);
MDNS.addService("wled", "tcp", 80);
}
if (!initLedsLast) strip.service();
strip.service();
initBlynk(blynkApiKey);
initE131();
@@ -117,29 +125,30 @@ void wledInit()
e131Enabled = false;
}
if (initLedsLast) initStrip();
userBegin();
if (macroBoot>0) applyMacro(macroBoot);
Serial.println("Ada");
}
void initStrip()
void beginStrip()
{
// Initialize NeoPixel Strip and button
if (initLedsLast) strip.init(useRGBW,ledCount,skipFirstLed);
strip.setReverseMode(reverseMode);
strip.setColor(0);
strip.setBrightness(255);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(4,OUTPUT); //this is only needed in special cases
digitalWrite(4,LOW);
pinMode(BTNPIN, INPUT_PULLUP);
if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true);
colorUpdated(0);
if(digitalRead(buttonPin) == LOW) buttonEnabled = false; //disable button if it is "pressed" unintentionally
//disable button if it is "pressed" unintentionally
if(digitalRead(BTNPIN) == LOW) buttonEnabled = false;
}
void initAP(){
bool set = apSSID[0];
if (!set) strcpy(apSSID,"WLED-AP");
@@ -147,6 +156,7 @@ void initAP(){
if (!set) apSSID[0] = 0;
}
void initCon()
{
WiFi.disconnect(); //close old connections
@@ -170,26 +180,24 @@ void initCon()
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
if (strlen(clientSSID) <1 || strcmp(clientSSID,"Your_Network") == 0)
fail_count = apWaitTimeSecs*2; //instantly go to ap mode
#ifndef ARDUINO_ARCH_ESP32
WiFi.hostname(serverDescription);
WiFi.hostname(serverDescription);
#endif
WiFi.begin(clientSSID, clientPass);
WiFi.begin(clientSSID, clientPass);
#ifdef ARDUINO_ARCH_ESP32
WiFi.setHostname(serverDescription);
WiFi.setHostname(serverDescription);
#endif
unsigned long lastTry = 0;
bool con = false;
while(!con)
{
yield();
if (!initLedsLast)
{
handleTransitions();
handleButton();
handleOverlays();
if (briT) strip.service();
}
handleTransitions();
handleButton();
handleOverlays();
if (briT) strip.service();
if (millis()-lastTry > 499) {
con = (WiFi.status() == WL_CONNECTED);
lastTry = millis();
@@ -208,9 +216,9 @@ void initCon()
}
//fill string buffer with build info
void getBuildInfo()
{
//fill string buffer with build info
olen = 0;
oappend("hard-coded build info:\r\n\n");
#ifdef ARDUINO_ARCH_ESP32
@@ -224,25 +232,46 @@ void getBuildInfo()
oappendi(VERSION);
oappend("\r\neepver: ");
oappendi(EEPVER);
oappend("\r\nesp-core: ");
#ifdef ARDUINO_ARCH_ESP32
oappend((char*)ESP.getSdkVersion());
#else
oappend((char*)ESP.getCoreVersion().c_str());
#endif
oappend("\r\nopt: ");
#ifndef WLED_DISABLE_ALEXA
oappend("alexa ");
#endif
#ifndef WLED_DISABLE_BLYNK
oappend("blynk ");
#endif
#ifndef WLED_DISABLE_CRONIXIE
oappend("cronixie ");
#endif
#ifndef WLED_DISABLE_HUESYNC
oappend("huesync ");
#endif
#ifndef WLED_DISABLE_MOBILE_UI
oappend("mobile-ui ");
#endif
#ifndef WLED_DISABLE_OTA
oappend("ota");
#endif
#ifdef USEFS
oappend("\r\nspiffs: true\r\n");
#else
oappend("\r\nspiffs: false\r\n");
#endif
#ifdef DEBUG
#ifdef WLED_DEBUG
oappend("debug: true\r\n");
#else
oappend("debug: false\r\n");
#endif
oappend("button-pin: gpio");
oappendi(buttonPin);
oappend("\r\n");
#ifdef ARDUINO_ARCH_ESP32
oappend("strip-pin: gpio");
oappendi(BTNPIN);
oappend("\r\nstrip-pin: gpio");
oappendi(LEDPIN);
#else
oappend("strip-pin: gpio2");
#endif
oappend("\r\nbrand: wled");
oappend("\r\nbuild-type: src\r\n");
}
@@ -255,6 +284,3 @@ bool checkClientIsMobile(String useragent)
if (useragent.indexOf("iPod") >= 0) return true;
return false;
}

View File

@@ -3,6 +3,8 @@
*/
#define WLEDPACKETSIZE 24
#define UDP_IN_MAXSIZE 1472
void notify(byte callMode, bool followUp=false)
{
@@ -14,9 +16,10 @@ void notify(byte callMode, bool followUp=false)
case 2: if (!notifyButton) return; break;
case 4: if (!notifyDirect) return; break;
case 6: if (!notifyDirect) return; break; //fx change
case 7: if (!notifyHue) return; break;
case 7: if (!notifyHue) return; break;
case 8: if (!notifyDirect) return; break;
case 9: if (!notifyDirect) return; break;
case 10: if (!notifyAlexa) return; break;
default: return;
}
byte udpOut[WLEDPACKETSIZE];
@@ -30,19 +33,19 @@ void notify(byte callMode, bool followUp=false)
udpOut[7] = nightlightDelayMins;
udpOut[8] = effectCurrent;
udpOut[9] = effectSpeed;
udpOut[10] = white;
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
udpOut[12] = colSec[0];
udpOut[13] = colSec[1];
udpOut[14] = colSec[2];
udpOut[15] = whiteSec;
udpOut[15] = colSec[3];
udpOut[16] = effectIntensity;
udpOut[17] = (transitionDelay >> 0) & 0xFF;
udpOut[18] = (transitionDelay >> 8) & 0xFF;
udpOut[19] = effectPalette;
IPAddress broadcastIp;
broadcastIp = ~WiFi.subnetMask() | WiFi.gatewayIP();
broadcastIp = ~uint32_t(WiFi.subnetMask()) | uint32_t(WiFi.gatewayIP());
notifierUdp.beginPacket(broadcastIp, udpPort);
notifierUdp.write(udpOut, WLEDPACKETSIZE);
@@ -52,6 +55,7 @@ void notify(byte callMode, bool followUp=false)
notificationTwoRequired = (followUp)? false:notifyTwice;
}
void arlsLock(uint32_t timeoutMs)
{
if (!realtimeActive){
@@ -59,13 +63,14 @@ void arlsLock(uint32_t timeoutMs)
{
strip.setPixelColor(i,0,0,0,0);
}
strip.setMode(0);
strip.unlockAll();
}
realtimeActive = true;
realtimeTimeout = millis() + timeoutMs;
if (arlsForceMaxBri) strip.setBrightness(255);
}
void initE131(){
if (WiFi.status() == WL_CONNECTED && e131Enabled)
{
@@ -76,6 +81,29 @@ void initE131(){
}
}
void handleE131(){
//E1.31 protocol support
if(e131Enabled) {
uint16_t len = e131->parsePacket();
if (!len || e131->universe < e131Universe || e131->universe > e131Universe +4) return;
len /= 3; //one LED is 3 DMX channels
uint16_t multipacketOffset = (e131->universe - e131Universe)*170; //if more than 170 LEDs (510 channels), client will send in next higher universe
if (ledCount <= multipacketOffset) return;
arlsLock(realtimeTimeoutMs);
if (len + multipacketOffset > ledCount) len = ledCount - multipacketOffset;
for (uint16_t i = 0; i < len; i++) {
int j = i * 3;
setRealtimePixel(i + multipacketOffset, e131->data[j], e131->data[j+1], e131->data[j+2], 0);
}
strip.show();
}
}
void handleNotifications()
{
//send second notification if enabled
@@ -83,153 +111,147 @@ void handleNotifications()
notify(notificationSentCallMode,true);
}
//E1.31 protocol support
if(e131Enabled) {
uint16_t len = e131->parsePacket();
if (len && e131->universe == e131Universe) {
arlsLock(realtimeTimeoutMs);
if (len > ledCount) len = ledCount;
for (uint16_t i = 0; i < len; i++) {
int j = i * 3;
setRealtimePixel(i, e131->data[j], e131->data[j+1], e131->data[j+2], 0);
}
strip.show();
}
}
handleE131();
//unlock strip when realtime UDP times out
if (realtimeActive && millis() > realtimeTimeout)
{
strip.unlockAll();
//strip.unlockAll();
strip.setBrightness(bri);
realtimeActive = false;
strip.setMode(effectCurrent);
//strip.setMode(effectCurrent);
realtimeIP[0] = 0;
}
//receive UDP notifications
if(udpConnected && (receiveNotifications || receiveDirect)){
uint16_t packetSize = notifierUdp.parsePacket();
//hyperion / raw RGB
if (!packetSize && udpRgbConnected) {
packetSize = rgbUdp.parsePacket();
if (!receiveDirect) return;
if (packetSize > 1026 || packetSize < 3) return;
realtimeIP = rgbUdp.remoteIP();
DEBUG_PRINTLN(rgbUdp.remoteIP());
byte udpIn[packetSize];
rgbUdp.read(udpIn, packetSize);
arlsLock(realtimeTimeoutMs);
uint16_t id = 0;
for (uint16_t i = 0; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= ledCount) break;
}
strip.show();
return;
}
if (!udpConnected || !(receiveNotifications || receiveDirect)) return;
if (packetSize > 1026) return;
if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) //don't process broadcasts we send ourselves
uint16_t packetSize = notifierUdp.parsePacket();
//hyperion / raw RGB
if (!packetSize && udpRgbConnected) {
packetSize = rgbUdp.parsePacket();
if (!receiveDirect) return;
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return;
realtimeIP = rgbUdp.remoteIP();
DEBUG_PRINTLN(rgbUdp.remoteIP());
olen = 0;
rgbUdp.read(obuf, packetSize);
arlsLock(realtimeTimeoutMs);
uint16_t id = 0;
for (uint16_t i = 0; i < packetSize -2; i += 3)
{
byte udpIn[packetSize];
notifierUdp.read(udpIn, packetSize);
if (udpIn[0] == 0 && !realtimeActive && receiveNotifications) //wled notifier, block if realtime packets active
setRealtimePixel(id, obuf[i], obuf[i+1], obuf[i+2], 0);
id++; if (id >= ledCount) break;
}
strip.show();
return;
}
//notifier and UDP realtime
if (packetSize > UDP_IN_MAXSIZE) return;
if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) //don't process broadcasts we send ourselves
{
olen = 0;
notifierUdp.read(obuf, packetSize);
char* udpIn = obuf;
//wled notifier, block if realtime packets active
if (udpIn[0] == 0 && !realtimeActive && receiveNotifications)
{
//apply colors from notification
if (receiveNotificationColor)
{
if (receiveNotificationColor)
{
col[0] = udpIn[3];
col[1] = udpIn[4];
col[2] = udpIn[5];
}
if (udpIn[11] > 0 && receiveNotificationColor) //check if sending modules white val is inteded
if (udpIn[11] > 0) //check if sending modules white val is inteded
{
white = udpIn[10];
if (udpIn[11] > 1 )
col[3] = udpIn[10];
if (udpIn[11] > 1)
{
colSec[0] = udpIn[12];
colSec[1] = udpIn[13];
colSec[2] = udpIn[14];
whiteSec = udpIn[15];
colSec[3] = udpIn[15];
}
}
if (udpIn[8] != effectCurrent && receiveNotificationEffects)
{
effectCurrent = udpIn[8];
strip.setMode(effectCurrent);
}
if (udpIn[9] != effectSpeed && receiveNotificationEffects)
{
effectSpeed = udpIn[9];
strip.setSpeed(effectSpeed);
}
if (udpIn[11] > 2 && udpIn[16] != effectIntensity && receiveNotificationEffects)
{
effectIntensity = udpIn[16];
strip.setIntensity(effectIntensity);
}
if (udpIn[11] > 3)
{
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
}
if (udpIn[11] > 4 && udpIn[19] != effectPalette && receiveNotificationEffects)
{
effectPalette = udpIn[19];
strip.setPalette(effectPalette);
}
nightlightActive = udpIn[6];
if (!nightlightActive)
{
if (receiveNotificationBrightness) bri = udpIn[2];
colorUpdated(3);
}
} else if (udpIn[0] > 0 && udpIn[0] < 4 && receiveDirect) //1 warls //2 drgb //3 drgbw
{
realtimeIP = notifierUdp.remoteIP();
DEBUG_PRINTLN(notifierUdp.remoteIP());
if (packetSize > 1) {
if (udpIn[1] == 0)
{
realtimeActive = false;
} else {
arlsLock(udpIn[1]*1000);
}
if (udpIn[0] == 1) //warls
{
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2) //drgb
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
}
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 3) //drgbw
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++; if (id >= ledCount) break;
}
}
strip.show();
//apply effects from notification
if (receiveNotificationEffects)
{
effectCurrent = udpIn[8];
effectSpeed = udpIn[9];
if (udpIn[11] > 2) effectIntensity = udpIn[16];
if (udpIn[11] > 4) effectPalette = udpIn[19];
}
if (udpIn[11] > 3)
{
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
}
nightlightActive = udpIn[6];
if (nightlightActive) nightlightDelayMins = udpIn[7];
if (receiveNotificationBrightness) bri = udpIn[2];
colorUpdated(3);
} else if (udpIn[0] > 0 && udpIn[0] < 4 && receiveDirect) //1 warls //2 drgb //3 drgbw
{
realtimeIP = notifierUdp.remoteIP();
DEBUG_PRINTLN(notifierUdp.remoteIP());
if (packetSize > 1) {
if (udpIn[1] == 0)
{
realtimeActive = false;
return;
} else {
arlsLock(udpIn[1]*1000);
}
if (udpIn[0] == 1) //warls
{
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2) //drgb
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 3) //drgbw
{
uint16_t id = 0;
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++; if (id >= ledCount) break;
}
} else if (udpIn[0] == 4) //dnrgb
{
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (uint16_t i = 4; i < packetSize -2; i += 3)
{
if (id >= ledCount) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++;
}
}
strip.show();
}
}
}
}
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
{
uint16_t pix = i + arlsOffset;
@@ -243,5 +265,3 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
}
}
}

View File

@@ -2,6 +2,19 @@
* LED methods
*/
void toggleOnOff()
{
if (bri == 0)
{
bri = briLast;
} else
{
briLast = bri;
bri = 0;
}
}
void setAllLeds() {
if (!realtimeActive || !arlsForceMaxBri)
{
@@ -21,59 +34,63 @@ void setAllLeds() {
{
colSecT[i] = colSec[i];
}
whiteSecT = whiteSec;
colSecT[3] = colSec[3];
}
if (autoRGBtoRGBW)
if (useRGBW && autoRGBtoRGBW)
{
colorRGBtoRGBW(colT,&whiteT);
colorRGBtoRGBW(colSecT,&whiteSecT);
colorRGBtoRGBW(colT);
colorRGBtoRGBW(colSecT);
}
if (useGammaCorrectionRGB)
{
strip.setColor(gamma8[colT[0]], gamma8[colT[1]], gamma8[colT[2]], gamma8[whiteT]);
strip.setSecondaryColor(gamma8[colSecT[0]], gamma8[colSecT[1]], gamma8[colSecT[2]], gamma8[whiteSecT]);
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], whiteT);
strip.setSecondaryColor(colSecT[0], colSecT[1], colSecT[2], whiteSecT);
strip.setColor(colT[0], colT[1], colT[2], colT[3]);
strip.setSecondaryColor(colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
}
}
void setLedsStandard()
{
for (byte i = 0; i<3; i++)
for (byte i=0; i<4; i++)
{
colOld[i] = col[i];
colT[i] = col[i];
colSecOld[i] = colSec[i];
colSecT[i] = colSec[i];
}
whiteOld = white;
briOld = bri;
whiteSecOld = whiteSec;
whiteT = white;
briT = bri;
whiteSecT = whiteSec;
setAllLeds();
}
bool colorChanged()
{
for (int i = 0; i < 3; i++)
for (byte i=0; i<4; i++)
{
if (col[i] != colIT[i]) return true;
if (colSec[i] != colSecIT[i]) return true;
}
if (white != whiteIT || whiteSec != whiteSecIT) return true;
if (bri != briIT) return true;
return false;
}
void colorUpdated(int callMode)
{
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (NN)6: fx changed 7: hue 8: preset cycle 9: blynk
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette);
if (!colorChanged())
{
if (callMode == 6) notify(6);
if (nightlightActive && !nightlightActiveOld && callMode != 3 && callMode != 5)
{
notify(4); return;
}
else if (fxChanged) notify(6);
return; //no change
}
if (callMode != 5 && nightlightActive && nightlightFade)
@@ -82,14 +99,11 @@ void colorUpdated(int callMode)
nightlightDelayMs -= (millis() - nightlightStartTime);
nightlightStartTime = millis();
}
colIT[0] = col[0];
colIT[1] = col[1];
colIT[2] = col[2];
colSecIT[0] = colSec[0];
colSecIT[1] = colSec[1];
colSecIT[2] = colSec[2];
whiteIT = white;
whiteSecIT = whiteSec;
for (byte i=0; i<4; i++)
{
colIT[i] = col[i];
colSecIT[i] = colSec[i];
}
briIT = bri;
if (bri > 0) briLast = bri;
@@ -103,14 +117,11 @@ void colorUpdated(int callMode)
if (transitionActive)
{
colOld[0] = colT[0];
colOld[1] = colT[1];
colOld[2] = colT[2];
whiteOld = whiteT;
colSecOld[0] = colSecT[0];
colSecOld[1] = colSecT[1];
colSecOld[2] = colSecT[2];
whiteSecOld = whiteSecT;
for (byte i=0; i<4; i++)
{
colOld[i] = colT[i];
colSecOld[i] = colSecT[i];
}
briOld = briT;
tperLast = 0;
}
@@ -124,6 +135,9 @@ void colorUpdated(int callMode)
}
if (callMode == 8) return;
#ifndef WLED_DISABLE_ALEXA
if (espalexaDevice != nullptr) espalexaDevice->setValue(bri);
#endif
//only update Blynk and mqtt every 2 seconds to reduce lag
if (millis() - lastInterfaceUpdate <= 2000)
{
@@ -133,6 +147,7 @@ void colorUpdated(int callMode)
updateInterfaces(callMode);
}
void updateInterfaces(uint8_t callMode)
{
if (callMode != 9 && callMode != 5) updateBlynk();
@@ -140,6 +155,7 @@ void updateInterfaces(uint8_t callMode)
lastInterfaceUpdate = millis();
}
void handleTransitions()
{
//handle still pending interface update
@@ -160,26 +176,20 @@ void handleTransitions()
setLedsStandard();
return;
}
if (tper - tperLast < 0.004)
{
return;
}
if (tper - tperLast < 0.004) return;
tperLast = tper;
if (fadeTransition)
for (byte i=0; i<4; i++)
{
for (byte i = 0; i<3; i++)
{
colT[i] = colOld[i]+((col[i] - colOld[i])*tper);
colSecT[i] = colSecOld[i]+((colSec[i] - colSecOld[i])*tper);
}
whiteT = whiteOld +((white - whiteOld )*tper);
whiteSecT = whiteSecOld +((whiteSec - whiteSecOld )*tper);
briT = briOld +((bri - briOld )*tper);
colT[i] = colOld[i]+((col[i] - colOld[i])*tper);
colSecT[i] = colSecOld[i]+((colSec[i] - colSecOld[i])*tper);
}
if (fadeTransition) setAllLeds();
briT = briOld +((bri - briOld )*tper);
setAllLeds();
}
}
void handleNightlight()
{
if (nightlightActive)
@@ -187,7 +197,6 @@ void handleNightlight()
if (!nightlightActiveOld) //init
{
nightlightStartTime = millis();
notify(4);
nightlightDelayMs = (int)(nightlightDelayMins*60000);
nightlightActiveOld = true;
briNlT = bri;
@@ -195,7 +204,7 @@ void handleNightlight()
float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs);
if (nightlightFade)
{
bri = briNlT+((nightlightTargetBri - briNlT)*nper);
bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
colorUpdated(5);
}
if (nper >= 1)

View File

@@ -6,15 +6,15 @@ void handleButton()
{
if (buttonEnabled)
{
if (digitalRead(buttonPin) == LOW && !buttonPressedBefore)
if (digitalRead(BTNPIN) == LOW && !buttonPressedBefore)
{
buttonPressedTime = millis();
buttonPressedBefore = true;
}
else if (digitalRead(buttonPin) == HIGH && buttonPressedBefore)
else if (digitalRead(BTNPIN) == HIGH && buttonPressedBefore)
{
delay(15); //debounce
if (digitalRead(buttonPin) == HIGH)
if (digitalRead(BTNPIN) == HIGH)
{
if (millis() - buttonPressedTime > 7000) {initAP();}
else if (millis() - buttonPressedTime > 700)
@@ -25,14 +25,7 @@ void handleButton()
else {
if (macroButton == 0)
{
if (bri == 0)
{
bri = briLast;
} else
{
briLast = bri;
bri = 0;
}
toggleOnOff();
colorUpdated(2);
} else {
applyMacro(macroButton);
@@ -51,9 +44,9 @@ void handleButton()
auxActiveBefore = true;
switch (auxTriggeredState)
{
case 0: pinMode(auxPin, INPUT); break;
case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
case 0: pinMode(AUXPIN, INPUT); break;
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
}
auxStartTime = millis();
}
@@ -63,9 +56,9 @@ void handleButton()
auxActiveBefore = false;
switch (auxDefaultState)
{
case 0: pinMode(auxPin, INPUT); break;
case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
case 0: pinMode(AUXPIN, INPUT); break;
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
}
}
}

View File

@@ -166,6 +166,13 @@ bool checkCountdown()
return false;
}
byte weekdayMondayFirst()
{
byte wd = weekday(local) -1;
if (wd == 0) wd = 7;
return wd;
}
void checkTimers()
{
if (lastTimerMinute != minute(local)) //only check once a new minute begins
@@ -176,11 +183,11 @@ void checkTimers()
if (timerMacro[i] != 0
&& (timerHours[i] == hour(local) || timerHours[i] == 24) //if hour is set to 24, activate every hour
&& timerMinutes[i] == minute(local)
&& timerWeekday[i] >> weekday(local) & 0x01) //timer should activate at current day of week
&& (timerWeekday[i] & 0x01) //timer is enabled
&& timerWeekday[i] >> weekdayMondayFirst() & 0x01) //timer should activate at current day of week
{
applyMacro(timerMacro[i]);
}
}
}
}

View File

@@ -22,7 +22,7 @@ void _nixieDisplay(int num[], uint16_t dur[], uint16_t pausedur[], byte cnt)
strip.setRange(overlayMin, overlayMax, 0);
if (num[nixieClockI] >= 0 && !nixiePause)
{
strip.setIndividual(num[nixieClockI],((uint32_t)white << 24)| ((uint32_t)colT[0] << 16) | ((uint32_t)colT[1] << 8) | colT[2]);
strip.setIndividual(num[nixieClockI],((uint32_t)colT[3] << 24)| ((uint32_t)colT[0] << 16) | ((uint32_t)colT[1] << 8) | colT[2]);
strip.unlock(num[nixieClockI]);
}
if (!nixiePause)
@@ -171,9 +171,9 @@ void _overlayAnalogClock()
int pix;
for (int i = 0; i <= 12; i++)
{
pix = overlayMin + analogClock12pixel + (overlaySize/12)*i;
if (pix > overlayMax) pix = pix - overlayMax;
strip.setIndividual(pix,0x00FFAA);
pix = analogClock12pixel + round((overlaySize / 12.0) *i);
if (pix > overlayMax) pix -= overlaySize;
strip.setIndividual(pix, 0x00FFAA);
}
}
if (!analogClockSecondsTrail) strip.setIndividual(secondPixel, 0xFF0000);
@@ -184,7 +184,7 @@ void _overlayAnalogClock()
void _overlayNixieClock()
{
#ifdef WLED_FLASH_512K_MODE
#ifdef WLED_DISABLE_CRONIXIE
if (countdownMode) checkCountdown();
#else
@@ -310,11 +310,11 @@ void _overlayAnalogCountdown()
byte pixelCnt = perc*overlaySize;
if (analogClock12pixel + pixelCnt > overlayMax)
{
strip.setRange(analogClock12pixel, overlayMax, ((uint32_t)whiteSec << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
strip.setRange(overlayMin, overlayMin +pixelCnt -(1+ overlayMax -analogClock12pixel), ((uint32_t)whiteSec << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
strip.setRange(analogClock12pixel, overlayMax, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
strip.setRange(overlayMin, overlayMin +pixelCnt -(1+ overlayMax -analogClock12pixel), ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
} else
{
strip.setRange(analogClock12pixel, analogClock12pixel + pixelCnt, ((uint32_t)whiteSec << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
strip.setRange(analogClock12pixel, analogClock12pixel + pixelCnt, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
}
}
overlayRefreshMs = 998;

View File

@@ -5,286 +5,76 @@
* https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch
* https://github.com/probonopd/ESP8266HueEmulator
*/
void alexaInit()
{
if (alexaEnabled && WiFi.status() == WL_CONNECTED)
{
udpConnected = connectUDP();
if (udpConnected) alexaInitPages();
}
}
void handleAlexa()
{
if (alexaEnabled && WiFi.status() == WL_CONNECTED)
{
if(udpConnected){
// if theres data available, read a packet
int packetSize = alexaUDP.parsePacket();
if(packetSize>0) {
IPAddress remote = alexaUDP.remoteIP();
int len = alexaUDP.read(obuf, 254);
if (len > 0) {
obuf[len] = 0;
}
if(strstr(obuf,"M-SEARCH") > 0) {
if(strstr(obuf,"upnp:rootdevice") > 0 || strstr(obuf,"device:basic:1") > 0) {
DEBUG_PRINTLN("Responding search req...");
respondToSearch();
}
}
}
}
}
}
void alexaOn()
{
if (macroAlexaOn == 0)
{
handleSet((notifyAlexa)?"win&T=1&IN":"win&T=1&NN&IN");
} else
{
applyMacro(macroAlexaOn);
}
server.send(200, "application/json", "[{\"success\":{\"/lights/1/state/on\":true}}]");
}
void alexaOff()
{
if (macroAlexaOff == 0)
{
handleSet((notifyAlexa)?"win&T=0&IN":"win&T=0&NN&IN");
} else
{
applyMacro(macroAlexaOff);
}
server.send(200, "application/json", "[{\"success\":{\"/lights/1/state/on\":false}}]");
}
void alexaDim(byte briL)
{
olen = 0;
oappend("[{\"success\":{\"/lights/1/state/bri\":");
oappendi(briL);
oappend("}}]");
server.send(200, "application/json", obuf);
String ct = (notifyAlexa)?"win&IN&A=":"win&NN&IN&A=";
if (briL < 255)
{
ct = ct + (briL+1);
} else
{
ct = ct + (255);
}
handleSet(ct);
}
void prepareIds() {
escapedMac = WiFi.macAddress();
escapedMac.replace(":", "");
escapedMac.toLowerCase();
}
void respondToSearch() {
DEBUG_PRINTLN("");
DEBUG_PRINT("Send resp to ");
DEBUG_PRINTLN(alexaUDP.remoteIP());
DEBUG_PRINT("Port : ");
DEBUG_PRINTLN(alexaUDP.remotePort());
#ifndef WLED_DISABLE_ALEXA
void onAlexaChange(byte b, uint32_t color);
IPAddress localIP = WiFi.localIP();
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
olen = 0;
oappend(
"HTTP/1.1 200 OK\r\n"
"EXT:\r\n"
"CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL
"LOCATION: http://");
oappend(s);
oappend(":80/description.xml\r\n"
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
"hue-bridgeid: ");
oappend((char*)escapedMac.c_str());
oappend("\r\n"
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
"USN: uuid:2f402f80-da50-11e1-9b23-");
oappend((char*)escapedMac.c_str());
oappend("::upnp:rootdevice\r\n" // _uuid::_deviceType
"\r\n");
alexaUDP.beginPacket(alexaUDP.remoteIP(), alexaUDP.remotePort());
#ifdef ARDUINO_ARCH_ESP32
alexaUDP.write((byte*)obuf, olen);
#else
alexaUDP.write(obuf);
#endif
alexaUDP.endPacket();
DEBUG_PRINTLN("Response sent!");
}
void alexaInitPages() {
server.on("/description.xml", HTTP_GET, [](){
DEBUG_PRINTLN(" # Responding to description.xml ... #\n");
IPAddress localIP = WiFi.localIP();
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
olen = 0;
oappend("<?xml version=\"1.0\" ?>"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
"<specVersion><major>1</major><minor>0</minor></specVersion>"
"<URLBase>http://");
oappend(s);
oappend(":80/</URLBase>"
"<device>"
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
"<friendlyName>Philips hue (");
oappend(s);
oappend(")</friendlyName>"
"<manufacturer>Royal Philips Electronics</manufacturer>"
"<manufacturerURL>http://www.philips.com</manufacturerURL>"
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
"<modelName>Philips hue bridge 2012</modelName>"
"<modelNumber>929000226503</modelNumber>"
"<modelURL>http://www.meethue.com</modelURL>"
"<serialNumber>");
oappend((char*)escapedMac.c_str());
oappend("</serialNumber>"
"<UDN>uuid:2f402f80-da50-11e1-9b23-");
oappend((char*)escapedMac.c_str());
oappend("</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>"
" <icon>"
" <mimetype>image/png</mimetype>"
" <height>120</height>"
" <width>120</width>"
" <depth>24</depth>"
" <url>hue_logo_3.png</url>"
" </icon>"
"</iconList>"
"</device>"
"</root>");
server.send(200, "text/xml", obuf);
DEBUG_PRINTLN("Sending setup_xml");
});
// openHAB support
server.on("/on.html", HTTP_GET, [](){
DEBUG_PRINTLN("on req");
server.send(200, "text/plain", "turned on");
alexaOn();
});
server.on("/off.html", HTTP_GET, [](){
DEBUG_PRINTLN("off req");
server.send(200, "text/plain", "turned off");
alexaOff();
});
server.on("/status.html", HTTP_GET, [](){
DEBUG_PRINTLN("Got status request");
char statrespone[] = "0";
if (bri > 0) {
statrespone[0] = '1';
}
server.send(200, "text/plain", statrespone);
});
}
String boolString(bool st)
void alexaInit()
{
return (st)?"true":"false";
if (alexaEnabled && WiFi.status() == WL_CONNECTED)
{
if (espalexaDevice == nullptr) //only init once
{
espalexaDevice = new EspalexaDevice(alexaInvocationName, onAlexaChange);
espalexa.addDevice(espalexaDevice);
espalexa.begin(&server);
} else {
espalexaDevice->setName(alexaInvocationName);
}
}
}
String briForHue(int realBri)
void handleAlexa()
{
realBri--;
if (realBri < 0) realBri = 0;
return String(realBri);
if (!alexaEnabled || WiFi.status() != WL_CONNECTED) return;
espalexa.loop();
}
bool handleAlexaApiCall(String req, String body) //basic implementation of Philips hue api functions needed for basic Alexa control
void onAlexaChange(byte b, uint32_t color)
{
DEBUG_PRINTLN("AlexaApiCall");
if (req.indexOf("api") <0) return false;
DEBUG_PRINTLN("ok");
if (body.indexOf("devicetype") > 0) //client wants a hue api username, we dont care and give static
{
DEBUG_PRINTLN("devType");
server.send(200, "application/json", "[{\"success\":{\"username\": \"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]");
return true;
}
if (req.indexOf("state") > 0) //client wants to control light
{
DEBUG_PRINTLN("ls");
if (body.indexOf("bri")>0) {alexaDim(body.substring(body.indexOf("bri") +5).toInt()); return true;}
if (body.indexOf("false")>0) {alexaOff(); return true;}
alexaOn();
return true;
}
if (req.indexOf("lights/1") > 0) //client wants light info
{
DEBUG_PRINTLN("l1");
server.send(200, "application/json", "{\"manufacturername\":\"OpenSource\",\"modelid\":\"LST001\",\"name\":\""+ String(alexaInvocationName) +"\",\"state\":{\"on\":"+ boolString(bri) +",\"hue\":0,\"bri\":"+ briForHue(bri) +",\"sat\":0,\"xy\":[0.00000,0.00000],\"ct\":500,\"alert\":\"none\",\"effect\":\"none\",\"colormode\":\"hs\",\"reachable\":true},\"swversion\":\"0.1\",\"type\":\"Extended color light\",\"uniqueid\":\"2\"}");
return true;
}
if (req.indexOf("lights") > 0) //client wants all lights
{
DEBUG_PRINTLN("lAll");
server.send(200, "application/json", "{\"1\":{\"type\":\"Extended color light\",\"manufacturername\":\"OpenSource\",\"swversion\":\"0.1\",\"name\":\""+ String(alexaInvocationName) +"\",\"uniqueid\":\""+ WiFi.macAddress() +"-2\",\"modelid\":\"LST001\",\"state\":{\"on\":"+ boolString(bri) +",\"bri\":"+ briForHue(bri) +",\"xy\":[0.00000,0.00000],\"colormode\":\"hs\",\"effect\":\"none\",\"ct\":500,\"hue\":0,\"sat\":0,\"alert\":\"none\",\"reachable\":true}}}");
return true;
}
//we dont care about other api commands at this time and send empty JSON
server.send(200, "application/json", "{}");
return true;
}
bool connectUDP(){
bool state = false;
byte m = espalexaDevice->getLastChangedProperty();
DEBUG_PRINTLN("");
DEBUG_PRINTLN("Con UDP");
#ifdef ARDUINO_ARCH_ESP32
if(alexaUDP.beginMulticast(ipMulti, portMulti))
#else
if(alexaUDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti))
#endif
if (m == 1){ //ON
if (!macroAlexaOn)
{
if (bri == 0)
{
bri = briLast;
colorUpdated(10);
}
} else applyMacro(macroAlexaOn);
} else if (m == 2) //OFF
{
DEBUG_PRINTLN("Con success");
state = true;
if (!macroAlexaOff)
{
if (bri > 0)
{
briLast = bri;
bri = 0;
colorUpdated(10);
}
} else applyMacro(macroAlexaOff);
} else if (m == 3) //brightness
{
bri = b;
colorUpdated(10);
} else //color
{
col[0] = ((color >> 16) & 0xFF);
col[1] = ((color >> 8) & 0xFF);
col[2] = (color & 0xFF);
if (useRGBW) colorRGBtoRGBW(col);
colorUpdated(10);
}
else{
DEBUG_PRINTLN("Con failed");
}
return state;
}
#else
void alexaInit(){}
void handleAlexa(){}
#endif

View File

@@ -19,7 +19,7 @@ byte getSameCodeLength(char code, int index, char const cronixieDisplay[])
void setCronixie()
{
#ifndef WLED_FLASH_512K_MODE
#ifndef WLED_DISABLE_CRONIXIE
/*
* digit purpose index
* 0-9 | 0-9 (incl. random)
@@ -145,73 +145,72 @@ void setCronixie()
void _overlayCronixie()
{
if (countdownMode) checkCountdown();
#ifndef WLED_FLASH_512K_MODE
byte h = hour(local);
byte h0 = h;
byte m = minute(local);
byte s = second(local);
byte d = day(local);
byte mi = month(local);
int y = year(local);
//this has to be changed in time for 22nd century
y -= 2000; if (y<0) y += 30; //makes countdown work
if (countdownMode) checkCountdown();
#ifndef WLED_DISABLE_CRONIXIE
byte h = hour(local);
byte h0 = h;
byte m = minute(local);
byte s = second(local);
byte d = day(local);
byte mi = month(local);
int y = year(local);
//this has to be changed in time for 22nd century
y -= 2000; if (y<0) y += 30; //makes countdown work
if (useAMPM && !countdownMode)
{
if (h>12) h-=12;
else if (h==0) h+=12;
}
byte _digitOut[]{10,10,10,10,10,10};
for (int i = 0; i < 6; i++)
{
if (dP[i] < 12) _digitOut[i] = dP[i];
else {
if (dP[i] < 65)
if (useAMPM && !countdownMode)
{
if (h>12) h-=12;
else if (h==0) h+=12;
}
byte _digitOut[]{10,10,10,10,10,10};
for (int i = 0; i < 6; i++)
{
if (dP[i] < 12) _digitOut[i] = dP[i];
else {
if (dP[i] < 65)
{
switch(dP[i])
{
switch(dP[i])
{
case 21: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; i++; break; //HH
case 25: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; i++; break; //MM
case 31: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; i++; break; //SS
case 21: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; i++; break; //HH
case 25: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; i++; break; //MM
case 31: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; i++; break; //SS
case 20: _digitOut[i] = h- (h/10)*10; break; //H
case 24: _digitOut[i] = m/10; break; //M
case 30: _digitOut[i] = s/10; break; //S
case 43: _digitOut[i] = weekday(local); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //D
case 44: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; i++; break; //DD
case 40: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; i++; break; //II
case 37: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //YY
case 39: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //YYYY
case 16: _digitOut[i+2] = ((h0/3)&1)?1:0; i++; //BBB (BBBB NI)
case 15: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:0; i++; //BB
case 14: _digitOut[i] = (h0>11)?1:0; break; //B
}
} else
case 20: _digitOut[i] = h- (h/10)*10; break; //H
case 24: _digitOut[i] = m/10; break; //M
case 30: _digitOut[i] = s/10; break; //S
case 43: _digitOut[i] = weekday(local); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //D
case 44: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; i++; break; //DD
case 40: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; i++; break; //II
case 37: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //YY
case 39: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //YYYY
case 16: _digitOut[i+2] = ((h0/3)&1)?1:0; i++; //BBB (BBBB NI)
case 15: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:0; i++; //BB
case 14: _digitOut[i] = (h0>11)?1:0; break; //B
}
} else
{
switch(dP[i])
{
switch(dP[i])
{
case 71: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //hh
case 75: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //mm
case 81: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ss
case 66: _digitOut[i+2] = ((h0/3)&1)?1:10; i++; //bbb (bbbb NI)
case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb
case 64: _digitOut[i] = (h0>11)?1:10; break; //b
case 71: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //hh
case 75: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //mm
case 81: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ss
case 66: _digitOut[i+2] = ((h0/3)&1)?1:10; i++; //bbb (bbbb NI)
case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb
case 64: _digitOut[i] = (h0>11)?1:10; break; //b
case 93: _digitOut[i] = weekday(local); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d
case 94: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //dd
case 90: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ii
case 87: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //yy
case 89: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //yyyy
}
case 93: _digitOut[i] = weekday(local); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d
case 94: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //dd
case 90: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ii
case 87: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //yy
case 89: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //yyyy
}
}
}
strip.setCronixieDigits(_digitOut);
//strip.trigger(); //this has a drawback, no effects slower than RefreshMs. advantage: Quick update, not dependant on effect time
#endif
}
strip.setCronixieDigits(_digitOut);
//strip.trigger(); //this has a drawback, no effects slower than RefreshMs. advantage: Quick update, not dependant on effect time
#endif
}

View File

@@ -1,34 +1,13 @@
/*
* Color conversion methods
*/
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
void colorFromUint32(uint32_t in)
{
//this is only an approximation using WS2812B with gamma correction enabled
if (mired > 475)
{
rgb[0]=255;rgb[1]=199;rgb[2]=92;//500
} else if (mired > 425)
{
rgb[0]=255;rgb[1]=213;rgb[2]=118;//450
} else if (mired > 375)
{
rgb[0]=255;rgb[1]=216;rgb[2]=118;//400
} else if (mired > 325)
{
rgb[0]=255;rgb[1]=234;rgb[2]=140;//350
} else if (mired > 275)
{
rgb[0]=255;rgb[1]=243;rgb[2]=160;//300
} else if (mired > 225)
{
rgb[0]=250;rgb[1]=255;rgb[2]=188;//250
} else if (mired > 175)
{
rgb[0]=247;rgb[1]=255;rgb[2]=215;//200
} else
{
rgb[0]=237;rgb[1]=255;rgb[2]=239;//150
}
col[3] = in >> 24 & 0xFF;
col[0] = in >> 16 & 0xFF;
col[1] = in >> 8 & 0xFF;
col[2] = in & 0xFF;
}
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
@@ -50,6 +29,29 @@ void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
}
}
#ifndef WLED_DISABLE_HUESYNC
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
{
//this is only an approximation using WS2812B with gamma correction enabled
if (mired > 475) {
rgb[0]=255;rgb[1]=199;rgb[2]=92;//500
} else if (mired > 425) {
rgb[0]=255;rgb[1]=213;rgb[2]=118;//450
} else if (mired > 375) {
rgb[0]=255;rgb[1]=216;rgb[2]=118;//400
} else if (mired > 325) {
rgb[0]=255;rgb[1]=234;rgb[2]=140;//350
} else if (mired > 275) {
rgb[0]=255;rgb[1]=243;rgb[2]=160;//300
} else if (mired > 225) {
rgb[0]=250;rgb[1]=255;rgb[2]=188;//250
} else if (mired > 175) {
rgb[0]=247;rgb[1]=255;rgb[2]=215;//200
} else {
rgb[0]=237;rgb[1]=255;rgb[2]=239;//150
}
}
void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
{
float z = 1.0f - x - y;
@@ -59,20 +61,20 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
float g = (int)255*(-X * 0.707196f + 1.655397f + Z * 0.036152f);
float b = (int)255*(X * 0.051713f - 0.121364f + Z * 1.011530f);
if (r > b && r > g && r > 1.0f) {
// red is too big
g = g / r;
b = b / r;
r = 1.0f;
// red is too big
g = g / r;
b = b / r;
r = 1.0f;
} else if (g > b && g > r && g > 1.0f) {
// green is too big
r = r / g;
b = b / g;
g = 1.0f;
// green is too big
r = r / g;
b = b / g;
g = 1.0f;
} else if (b > r && b > g && b > 1.0f) {
// blue is too big
r = r / b;
g = g / b;
b = 1.0f;
// blue is too big
r = r / b;
g = g / b;
b = 1.0f;
}
// Apply gamma correction
r = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * pow(r, (1.0f / 2.4f)) - 0.055f;
@@ -80,33 +82,43 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
b = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * pow(b, (1.0f / 2.4f)) - 0.055f;
if (r > b && r > g) {
// red is biggest
if (r > 1.0f) {
g = g / r;
b = b / r;
r = 1.0f;
}
// red is biggest
if (r > 1.0f) {
g = g / r;
b = b / r;
r = 1.0f;
}
} else if (g > b && g > r) {
// green is biggest
if (g > 1.0f) {
r = r / g;
b = b / g;
g = 1.0f;
}
// green is biggest
if (g > 1.0f) {
r = r / g;
b = b / g;
g = 1.0f;
}
} else if (b > r && b > g) {
// blue is biggest
if (b > 1.0f) {
r = r / b;
g = g / b;
b = 1.0f;
}
// blue is biggest
if (b > 1.0f) {
r = r / b;
g = g / b;
b = 1.0f;
}
}
rgb[0] = 255.0*r;
rgb[1] = 255.0*g;
rgb[2] = 255.0*b;
}
void colorFromDecOrHexString(byte* rgb, byte* wht, char* in)
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
{
float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f;
float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f;
float Z = rgb[0] * 0.000088f + rgb[1] * 0.072310f + rgb[2] * 0.986039f;
xy[0] = X / (X + Y + Z);
xy[1] = Y / (X + Y + Z);
}
#endif
void colorFromDecOrHexString(byte* rgb, char* in)
{
if (in[0] == 0) return;
char first = in[0];
@@ -120,21 +132,12 @@ void colorFromDecOrHexString(byte* rgb, byte* wht, char* in)
c = strtoul(in, NULL, 10);
}
*wht = (c >> 24) & 0xFF;
rgb[3] = (c >> 24) & 0xFF;
rgb[0] = (c >> 16) & 0xFF;
rgb[1] = (c >> 8) & 0xFF;
rgb[2] = c & 0xFF;
}
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
{
float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f;
float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f;
float Z = rgb[0] * 0.000088f + rgb[1] * 0.072310f + rgb[2] * 0.986039f;
xy[0] = X / (X + Y + Z);
xy[1] = Y / (X + Y + Z);
}
float minf (float v, float w)
{
if (w > v) return v;
@@ -147,12 +150,11 @@ float maxf (float v, float w)
return v;
}
void colorRGBtoRGBW(byte* rgb, byte* wht) //rgb to rgbw (http://codewelt.com/rgbw)
void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw)
{
float low = minf(rgb[0],minf(rgb[1],rgb[2]));
float high = maxf(rgb[0],maxf(rgb[1],rgb[2]));
if (high < 0.1f) return;
float sat = 255.0f * ((high - low) / high);
*wht = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3);
rgb[3] = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3);
}

View File

@@ -1,7 +1,7 @@
/*
* Sync to Philips hue lights
*/
#ifndef WLED_DISABLE_HUESYNC
void handleHue()
{
if (huePollingEnabled && WiFi.status() == WL_CONNECTED && hueClient != NULL)
@@ -206,4 +206,7 @@ String getJsonValue(String* req, String key)
}
return "";
}
#else
void handleHue(){}
bool setupHue(){return false;}
#endif

View File

@@ -7,19 +7,24 @@ byte blSat = 255;
void initBlynk(const char* auth)
{
#ifndef WLED_DISABLE_BLYNK
if (WiFi.status() != WL_CONNECTED) return;
blynkEnabled = (auth[0] != 0);
if (blynkEnabled) Blynk.config(auth);
#endif
}
void handleBlynk()
{
#ifndef WLED_DISABLE_BLYNK
if (WiFi.status() == WL_CONNECTED && blynkEnabled)
Blynk.run();
#endif
}
void updateBlynk()
{
#ifndef WLED_DISABLE_BLYNK
if (onlyAP) return;
Blynk.virtualWrite(V0, bri);
//we need a RGB -> HSB convert here
@@ -29,26 +34,28 @@ void updateBlynk()
Blynk.virtualWrite(V6, effectIntensity);
Blynk.virtualWrite(V7, nightlightActive);
Blynk.virtualWrite(V8, notifyDirect);
#endif
}
#ifndef WLED_DISABLE_BLYNK
BLYNK_WRITE(V0)
{
bri = param.asInt();//bri
colorUpdated(9);
bri = param.asInt();//bri
colorUpdated(9);
}
BLYNK_WRITE(V1)
{
blHue = param.asInt();//hue
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(9);
blHue = param.asInt();//hue
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(9);
}
BLYNK_WRITE(V2)
{
blSat = param.asInt();//sat
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(9);
blSat = param.asInt();//sat
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(9);
}
BLYNK_WRITE(V3)
@@ -58,23 +65,20 @@ BLYNK_WRITE(V3)
BLYNK_WRITE(V4)
{
effectCurrent = param.asInt()-1;//fx
strip.setMode(effectCurrent);
colorUpdated(6);
effectCurrent = param.asInt()-1;//fx
colorUpdated(9);
}
BLYNK_WRITE(V5)
{
effectSpeed = param.asInt();//sx
strip.setSpeed(effectSpeed);
colorUpdated(6);
effectSpeed = param.asInt();//sx
colorUpdated(9);
}
BLYNK_WRITE(V6)
{
effectIntensity = param.asInt();//ix
strip.setIntensity(effectIntensity);
colorUpdated(6);
effectIntensity = param.asInt();//ix
colorUpdated(9);
}
BLYNK_WRITE(V7)
@@ -86,4 +90,4 @@ BLYNK_WRITE(V8)
{
notifyDirect = (param.asInt()>0); //send notifications
}
#endif

View File

@@ -2,10 +2,12 @@
* MQTT communication protocol for home automation
*/
#define WLED_MQTT_PORT 1883
void parseMQTTBriPayload(char* payload)
{
if (strcmp(payload, "ON") == 0) {bri = briLast; colorUpdated(1);}
else if (strcmp(payload, "T" ) == 0) {handleSet("win&T=2");}
else if (strcmp(payload, "T" ) == 0) {toggleOnOff(); colorUpdated(1);}
else {
uint8_t in = strtoul(payload, NULL, 10);
if (in == 0 && bri > 0) briLast = bri;
@@ -14,6 +16,7 @@ void parseMQTTBriPayload(char* payload)
}
}
void callbackMQTT(char* topic, byte* payload, unsigned int length) {
DEBUG_PRINT("MQTT callb rec: ");
@@ -24,7 +27,7 @@ void callbackMQTT(char* topic, byte* payload, unsigned int length) {
if (strstr(topic, "/col"))
{
colorFromDecOrHexString(col, &white, (char*)payload);
colorFromDecOrHexString(col, (char*)payload);
colorUpdated(1);
} else if (strstr(topic, "/api"))
{
@@ -37,6 +40,7 @@ void callbackMQTT(char* topic, byte* payload, unsigned int length) {
}
}
void publishMQTT()
{
if (mqtt == NULL) return;
@@ -51,19 +55,20 @@ void publishMQTT()
strcat(subuf, "/g");
mqtt->publish(subuf, s);
sprintf(s, "#%X", white*16777216 + col[0]*65536 + col[1]*256 + col[2]);
sprintf(s, "#%X", col[3]*16777216 + col[0]*65536 + col[1]*256 + col[2]);
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, "/c");
mqtt->publish(subuf, s);
//if you want to use this, increase the MQTT buffer in PubSubClient.h to 350+
//it will publish the API response to MQTT
/*XML_response(false);
/*XML_response(false, false);
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, "/v");
mqtt->publish(subuf, obuf);*/
}
bool reconnectMQTT()
{
if (mqtt->connect(escapedMac.c_str()))
@@ -93,10 +98,13 @@ bool reconnectMQTT()
strcat(subuf, "/api");
mqtt->subscribe(subuf);
}
publishMQTT();
}
return mqtt->connected();
}
bool initMQTT()
{
if (WiFi.status() != WL_CONNECTED) return false;
@@ -105,15 +113,16 @@ bool initMQTT()
IPAddress mqttIP;
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
{
mqtt->setServer(mqttIP,1883);
mqtt->setServer(mqttIP, WLED_MQTT_PORT);
} else {
mqtt->setServer(mqttServer,1883);
mqtt->setServer(mqttServer, WLED_MQTT_PORT);
}
mqtt->setCallback(callbackMQTT);
DEBUG_PRINTLN("MQTT ready.");
return true;
}
void handleMQTT()
{
if (WiFi.status() != WL_CONNECTED || !mqttInit) return;

View File

@@ -87,6 +87,22 @@ void initServer()
serveMessage(200,"Security settings saved.","Rebooting now... (takes ~20 seconds, wait for auto-redirect)",139);
reset();
});
server.on("/json", HTTP_ANY, [](){
server.send(500, "application/json", "{\"error\":\"Not implemented\"}");
});
server.on("/json/effects", HTTP_GET, [](){
server.setContentLength(strlen_P(JSON_mode_names));
server.send(200, "application/json", "");
server.sendContent_P(JSON_mode_names);
});
server.on("/json/palettes", HTTP_GET, [](){
server.setContentLength(strlen_P(JSON_palette_names));
server.send(200, "application/json", "");
server.sendContent_P(JSON_palette_names);
});
server.on("/version", HTTP_GET, [](){
server.send(200, "text/plain", (String)VERSION);
@@ -101,9 +117,16 @@ void initServer()
});
server.on("/power", HTTP_GET, [](){
String val = (String)(int)strip.getPowerEstimate(ledCount,strip.getColor(),strip.getBrightness());
val += "mA currently";
serveMessage(200,val,"This is just an estimate (does not take into account several factors like effects and wire resistance). It is NOT an accurate measurement!",254);
String val = "";
if (strip.currentMilliamps == 0)
{
val = "Power calculation disabled";
} else
{
val += (String)strip.currentMilliamps;
val += "mA currently";
}
serveMessage(200, val, "This is just an estimate (does not account for factors like wire resistance). It is NOT a measurement!", 254);
});
server.on("/u", HTTP_GET, [](){
@@ -113,7 +136,7 @@ void initServer()
});
server.on("/teapot", HTTP_GET, [](){
serveMessage(418, "418. I'm a teapot.","(Tangible Embedded Advanced Project Of Twinkling)",254);
serveMessage(418, "418. I'm a teapot.", "(Tangible Embedded Advanced Project Of Twinkling)", 254);
});
server.on("/build", HTTP_GET, [](){
@@ -132,7 +155,13 @@ void initServer()
server.on("/list", HTTP_GET, handleFileList);
#endif
//init ota page
#ifndef WLED_DISABLE_OTA
httpUpdater.setup(&server);
#else
server.on("/update", HTTP_GET, [](){
serveMessage(500, "Not implemented", "OTA updates are unsupported in this build.", 254);
});
#endif
} else
{
server.on("/edit", HTTP_GET, [](){
@@ -157,6 +186,17 @@ void initServer()
DEBUG_PRINTLN("URI: " + server.uri());
DEBUG_PRINTLN("Body: " + server.arg(0));
//make API CORS compatible
if (server.method() == HTTP_OPTIONS)
{
server.sendHeader("Access-Control-Allow-Origin", "*");
server.sendHeader("Access-Control-Max-Age", "10000");
server.sendHeader("Access-Control-Allow-Methods", "PUT,POST,GET,OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "*");
server.send(200);
return;
}
//workaround for subpage issue
if (server.uri().length() == 1)
{
@@ -165,7 +205,9 @@ void initServer()
}
if(!handleSet(server.uri())){
if(!handleAlexaApiCall(server.uri(),server.arg(0)))
#ifndef WLED_DISABLE_ALEXA
if(!espalexa.handleAlexaApiCall(server.uri(),server.arg(0)))
#endif
server.send(404, "text/plain", "Not Found");
}
});
@@ -179,43 +221,6 @@ void initServer()
#endif
}
void buildCssColorString()
{
String cs[]={"","","","","",""};
switch (currentTheme)
{
default: cs[0]="D9B310"; cs[1]="0B3C5D"; cs[2]="1D2731"; cs[3]="328CC1"; cs[4]="000"; cs[5]="328CC1"; break; //night
case 1: cs[0]="eee"; cs[1]="ddd"; cs[2]="b9b9b9"; cs[3]="049"; cs[4]="777"; cs[5]="049"; break; //modern
case 2: cs[0]="abc"; cs[1]="fff"; cs[2]="ddd"; cs[3]="000"; cs[4]="0004"; cs[5]="000"; break; //bright
case 3: cs[0]="c09f80"; cs[1]="d7cec7"; cs[2]="76323f"; cs[3]="888"; cs[4]="3334"; cs[5]="888"; break; //wine
case 4: cs[0]="3cc47c"; cs[1]="828081"; cs[2]="d9a803"; cs[3]="1e392a"; cs[4]="000a"; cs[5]="1e392a"; break; //electric
case 5: cs[0]="57bc90"; cs[1]="a5a5af"; cs[2]="015249"; cs[3]="88c9d4"; cs[4]="0004"; cs[5]="88c9d4"; break; //mint
case 6: cs[0]="f7c331"; cs[1]="dcc7aa"; cs[2]="6b7a8f"; cs[3]="f7882f"; cs[4]="0007"; cs[5]="f7882f"; break; //amber
case 7: cs[0]="fc3"; cs[1]="124"; cs[2]="334"; cs[3]="f1d"; cs[4]="f00"; cs[5]="f1d"; break;//club
case 8: cs[0]="0ac"; cs[1]="124"; cs[2]="224"; cs[3]="003eff"; cs[4]="003eff"; cs[5]="003eff"; break;//air
case 9: cs[0]="f70"; cs[1]="421"; cs[2]="221"; cs[3]="a50"; cs[4]="f70"; cs[5]="f70"; break;//nixie
case 10: cs[0]="2d2"; cs[1]="010"; cs[2]="121"; cs[3]="060"; cs[4]="040"; cs[5]="3f3"; break; //terminal
case 11: cs[0]="867ADE"; cs[1]="4033A3"; cs[2]="483AAA"; cs[3]="483AAA"; cs[4]=""; cs[5]="867ADE"; break; //c64
case 12: cs[0]="fbe8a6"; cs[1]="d2fdff"; cs[2]="b4dfe5"; cs[3]="f4976c"; cs[4]=""; cs[5]="303c6c"; break; //c64
case 14: cs[0]="fc7"; cs[1]="49274a"; cs[2]="94618e"; cs[3]="f4decb"; cs[4]="0008"; cs[5]="f4decb"; break; //end
case 15: for (int i=0;i<6;i++)cs[i]=cssCol[i];//custom
}
cssColorString="<style>:root{--aCol:#";
cssColorString+=cs[0];
cssColorString+=";--bCol:#";
cssColorString+=cs[1];
cssColorString+=";--cCol:#";
cssColorString+=cs[2];
cssColorString+=";--dCol:#";
cssColorString+=cs[3];
cssColorString+=";--sCol:#";
cssColorString+=cs[4];
cssColorString+=";--tCol:#";
cssColorString+=cs[5];
cssColorString+=";--cFn:";
cssColorString+=cssFont;
cssColorString+=";}";
}
void serveIndexOrWelcome()
{
@@ -247,36 +252,52 @@ void serveRealtimeError(bool settings)
server.send(200, "text/plain", mesg);
}
void getCSSColors()
{
char cs[6][9];
getThemeColors(cs);
oappend("<style>:root{--aCol:#"); oappend(cs[0]);
oappend(";--bCol:#"); oappend(cs[1]);
oappend(";--cCol:#"); oappend(cs[2]);
oappend(";--dCol:#"); oappend(cs[3]);
oappend(";--sCol:#"); oappend(cs[4]);
oappend(";--tCol:#"); oappend(cs[5]);
oappend(";--cFn:"); oappend(cssFont);
oappend(";}");
}
void serveIndex()
{
bool serveMobile = false;
if (uiConfiguration == 0) serveMobile = checkClientIsMobile(server.header("User-Agent"));
else if (uiConfiguration == 2) serveMobile = true;
if (!realtimeActive || enableRealtimeUI) //do not serve while receiving realtime
if (realtimeActive && !enableRealtimeUI) //do not serve while receiving realtime
{
if (serveMobile)
{
server.setContentLength(strlen_P(PAGE_indexM));
server.send(200, "text/html", "");
server.sendContent_P(PAGE_indexM);
} else
{
server.setContentLength(strlen_P(PAGE_index0) + cssColorString.length() + strlen_P(PAGE_index1) + strlen_P(PAGE_index2) + strlen_P(PAGE_index3));
server.send(200, "text/html", "");
server.sendContent_P(PAGE_index0);
server.sendContent(cssColorString);
server.sendContent_P(PAGE_index1);
server.sendContent_P(PAGE_index2);
server.sendContent_P(PAGE_index3);
}
} else {
serveRealtimeError(false);
return;
}
//error message is not gzipped
#ifdef WLED_DISABLE_MOBILE_UI
if (!serveMobile) server.sendHeader("Content-Encoding","gzip");
#else
server.sendHeader("Content-Encoding","gzip");
#endif
server.send_P(200, "text/html",
(serveMobile) ? PAGE_indexM : PAGE_index0,
(serveMobile) ? PAGE_indexM_L : PAGE_index0_L);
}
void serveMessage(int code, String headl, String subl="", int optionType)
{
olen = 0;
getCSSColors();
String messageBody = "<h2>";
messageBody += headl;
messageBody += "</h2>";
@@ -298,69 +319,72 @@ void serveMessage(int code, String headl, String subl="", int optionType)
messageBody += "<script>setTimeout(RP," + String((optionType-120)*1000) + ")</script>";
}
messageBody += "</body></html>";
server.setContentLength(strlen_P(PAGE_msg0) + cssColorString.length() + strlen_P(PAGE_msg1) + messageBody.length());
server.setContentLength(strlen_P(PAGE_msg0) + olen + strlen_P(PAGE_msg1) + messageBody.length());
server.send(code, "text/html", "");
server.sendContent_P(PAGE_msg0);
server.sendContent(cssColorString);
server.sendContent(obuf);
server.sendContent_P(PAGE_msg1);
server.sendContent(messageBody);
}
void serveSettings(byte subPage)
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 255: welcomepage
if (!realtimeActive || enableRealtimeUI) //do not serve while receiving realtime
{
#ifdef WLED_FLASH_512K_MODE //disable welcome page if not enough storage
if (subPage == 255) {serveIndex(); return;}
#endif
int pl0, pl1;
switch (subPage)
{
case 1: pl0 = strlen_P(PAGE_settings_wifi0); pl1 = strlen_P(PAGE_settings_wifi1); break;
case 2: pl0 = strlen_P(PAGE_settings_leds0); pl1 = strlen_P(PAGE_settings_leds1); break;
case 3: pl0 = strlen_P(PAGE_settings_ui0); pl1 = strlen_P(PAGE_settings_ui1); break;
case 4: pl0 = strlen_P(PAGE_settings_sync0); pl1 = strlen_P(PAGE_settings_sync1); break;
case 5: pl0 = strlen_P(PAGE_settings_time0); pl1 = strlen_P(PAGE_settings_time1); break;
case 6: pl0 = strlen_P(PAGE_settings_sec0); pl1 = strlen_P(PAGE_settings_sec1); break;
case 255: pl0 = strlen_P(PAGE_welcome0); pl1 = strlen_P(PAGE_welcome1); break;
default: pl0 = strlen_P(PAGE_settings0); pl1 = strlen_P(PAGE_settings1);
}
getSettingsJS(subPage);
int sCssLength = (subPage >0 && subPage <7)?strlen_P(PAGE_settingsCss):0;
server.setContentLength(pl0 + cssColorString.length() + olen + sCssLength + pl1);
server.send(200, "text/html", "");
switch (subPage)
{
case 1: server.sendContent_P(PAGE_settings_wifi0); break;
case 2: server.sendContent_P(PAGE_settings_leds0); break;
case 3: server.sendContent_P(PAGE_settings_ui0); break;
case 4: server.sendContent_P(PAGE_settings_sync0); break;
case 5: server.sendContent_P(PAGE_settings_time0); break;
case 6: server.sendContent_P(PAGE_settings_sec0); break;
case 255: server.sendContent_P(PAGE_welcome0); break;
default: server.sendContent_P(PAGE_settings0);
}
server.sendContent(obuf);
server.sendContent(cssColorString);
if (subPage >0 && subPage <7) server.sendContent_P(PAGE_settingsCss);
switch (subPage)
{
case 1: server.sendContent_P(PAGE_settings_wifi1); break;
case 2: server.sendContent_P(PAGE_settings_leds1); break;
case 3: server.sendContent_P(PAGE_settings_ui1); break;
case 4: server.sendContent_P(PAGE_settings_sync1); break;
case 5: server.sendContent_P(PAGE_settings_time1); break;
case 6: server.sendContent_P(PAGE_settings_sec1); break;
case 255: server.sendContent_P(PAGE_welcome1); break;
default: server.sendContent_P(PAGE_settings1);
}
} else {
serveRealtimeError(true);
}
}
if (realtimeActive && !enableRealtimeUI) //do not serve while receiving realtime
{
serveRealtimeError(true);
return;
}
#ifdef WLED_DISABLE_MOBILE_UI //disable welcome page if not enough storage
if (subPage == 255) {serveIndex(); return;}
#endif
int pl0, pl1;
switch (subPage) //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 255: welcomepage
{
case 1: pl0 = strlen_P(PAGE_settings_wifi0); pl1 = strlen_P(PAGE_settings_wifi1); break;
case 2: pl0 = strlen_P(PAGE_settings_leds0); pl1 = strlen_P(PAGE_settings_leds1); break;
case 3: pl0 = strlen_P(PAGE_settings_ui0); pl1 = strlen_P(PAGE_settings_ui1); break;
case 4: pl0 = strlen_P(PAGE_settings_sync0); pl1 = strlen_P(PAGE_settings_sync1); break;
case 5: pl0 = strlen_P(PAGE_settings_time0); pl1 = strlen_P(PAGE_settings_time1); break;
case 6: pl0 = strlen_P(PAGE_settings_sec0); pl1 = strlen_P(PAGE_settings_sec1); break;
case 255: pl0 = strlen_P(PAGE_welcome0); pl1 = strlen_P(PAGE_welcome1); break;
default: pl0 = strlen_P(PAGE_settings0); pl1 = strlen_P(PAGE_settings1);
}
uint16_t sCssLength = (subPage >0 && subPage <7)?strlen_P(PAGE_settingsCss):0;
getSettingsJS(subPage);
getCSSColors();
server.setContentLength(pl0 + olen + sCssLength + pl1);
server.send(200, "text/html", "");
switch (subPage)
{
case 1: server.sendContent_P(PAGE_settings_wifi0); break;
case 2: server.sendContent_P(PAGE_settings_leds0); break;
case 3: server.sendContent_P(PAGE_settings_ui0 ); break;
case 4: server.sendContent_P(PAGE_settings_sync0); break;
case 5: server.sendContent_P(PAGE_settings_time0); break;
case 6: server.sendContent_P(PAGE_settings_sec0 ); break;
case 255: server.sendContent_P(PAGE_welcome0 ); break;
default: server.sendContent_P(PAGE_settings0 );
}
server.sendContent(obuf);
if (subPage >0 && subPage <7) server.sendContent_P(PAGE_settingsCss);
switch (subPage)
{
case 1: server.sendContent_P(PAGE_settings_wifi1); break;
case 2: server.sendContent_P(PAGE_settings_leds1); break;
case 3: server.sendContent_P(PAGE_settings_ui1 ); break;
case 4: server.sendContent_P(PAGE_settings_sync1); break;
case 5: server.sendContent_P(PAGE_settings_time1); break;
case 6: server.sendContent_P(PAGE_settings_sec1 ); break;
case 255: server.sendContent_P(PAGE_welcome1 ); break;
default: server.sendContent_P(PAGE_settings1 );
}
}

155
wled00/wled19_ir.ino Normal file
View File

@@ -0,0 +1,155 @@
/*
* Infrared sensor support for generic 24 key RGB remote
*/
#if defined(WLED_DISABLE_INFRARED) || defined(ARDUINO_ARCH_ESP32)
void handleIR(){}
#else
IRrecv* irrecv;
//change pin in NpbWrapper.h
decode_results results;
unsigned long irCheckedTime = 0;
uint32_t lastValidCode = 0;
uint16_t irTimesRepeated = 0;
//Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control
//IR codes themselves can be defined directly after "case" or in "ir_codes.h"
bool decodeIRCustom(uint32_t code)
{
switch (code)
{
//just examples, feel free to modify or remove
case IRCUSTOM_ONOFF : toggleOnOff(); break;
case IRCUSTOM_MACRO1 : applyMacro(1); break;
default: return false;
}
if (code != IRCUSTOM_MACRO1) colorUpdated(2); //don't update color again if we apply macro, it already does it
return true;
}
//relatively change brightness, minumum A=5
void relativeChange(byte* property, int8_t amount, byte lowerBoundary =0)
{
int16_t new_val = (int16_t) *property + amount;
if (new_val > 0xFF) new_val = 0xFF;
else if (new_val < lowerBoundary) new_val = lowerBoundary;
*property = new_val;
}
void decodeIR(uint32_t code)
{
if (code == 0xFFFFFFFF) //repeated code, continue brightness up/down
{
irTimesRepeated++;
if (lastValidCode == IR24_BRIGHTER)
{
relativeChange(&bri, 10); colorUpdated(2);
}
else if (lastValidCode == IR24_DARKER)
{
relativeChange(&bri, -10, 5); colorUpdated(2);
}
else if (lastValidCode == IR24_ON && irTimesRepeated > 7)
{
nightlightActive = true;
nightlightStartTime = millis();
colorUpdated(2);
}
return;
}
lastValidCode = 0; irTimesRepeated = 0;
if (decodeIRCustom(code)) return;
if (code > 0xFFFFFF) return; //invalid code
else if (code > 0xFF0000) decodeIR44(code); //is in 44-key remote range
else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range
//code <= 0xF70000 also invalid
}
void decodeIR24(uint32_t code)
{
switch (code) {
case IR24_BRIGHTER : relativeChange(&bri, 10); break;
case IR24_DARKER : relativeChange(&bri, -10, 5); break;
case IR24_OFF : briLast = bri; bri = 0; break;
case IR24_ON : bri = briLast; break;
case IR24_RED : colorFromUint32(COLOR_RED); break;
case IR24_REDDISH : colorFromUint32(COLOR_REDDISH); break;
case IR24_ORANGE : colorFromUint32(COLOR_ORANGE); break;
case IR24_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break;
case IR24_YELLOW : colorFromUint32(COLOR_YELLOW); break;
case IR24_GREEN : colorFromUint32(COLOR_GREEN); break;
case IR24_GREENISH : colorFromUint32(COLOR_GREENISH); break;
case IR24_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break;
case IR24_CYAN : colorFromUint32(COLOR_CYAN); break;
case IR24_AQUA : colorFromUint32(COLOR_AQUA); break;
case IR24_BLUE : colorFromUint32(COLOR_BLUE); break;
case IR24_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break;
case IR24_PURPLE : colorFromUint32(COLOR_PURPLE); break;
case IR24_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
case IR24_PINK : colorFromUint32(COLOR_PINK); break;
case IR24_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
case IR24_FLASH : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break;
case IR24_STROBE : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break;
case IR24_FADE : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break;
case IR24_SMOOTH : if (!applyPreset(4)) effectCurrent = FX_MODE_RAINBOW; break;
default: return;
}
lastValidCode = code;
colorUpdated(2); //for notifier, IR is considered a button input
}
void decodeIR44(uint32_t code)
{
//not implemented for now
}
void initIR()
{
if (irEnabled)
{
irrecv = new IRrecv(IR_PIN);
irrecv->enableIRIn();
}
}
void handleIR()
{
if (irEnabled && millis() - irCheckedTime > 120)
{
irCheckedTime = millis();
if (irEnabled)
{
if (irrecv == NULL)
{
initIR(); return;
}
if (irrecv->decode(&results))
{
Serial.print("IR recv\r\n0x");
Serial.println((uint32_t)results.value, HEX);
Serial.println();
decodeIR(results.value);
irrecv->resume();
}
} else if (irrecv != NULL)
{
irrecv->disableIRIn();
delete irrecv; irrecv = NULL;
}
}
}
#endif