Compare commits
202 Commits
settings
...
v0.14.0-b5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60c47cfca1 | ||
|
|
720abd4e04 | ||
|
|
b4fe694d1b | ||
|
|
c117785554 | ||
|
|
e9723de6c3 | ||
|
|
da0cf01eee | ||
|
|
e40f266042 | ||
|
|
69fb15d3cb | ||
|
|
188956a4af | ||
|
|
c7dd4a7f2b | ||
|
|
111f1729c9 | ||
|
|
164372b46a | ||
|
|
1af3794fed | ||
|
|
885f4ded0c | ||
|
|
9bb018d8d9 | ||
|
|
58187e00e6 | ||
|
|
5110a8c636 | ||
|
|
ddbe883d47 | ||
|
|
945ac82b6a | ||
|
|
84148ad07a | ||
|
|
25553a28a1 | ||
|
|
c2f5846a8e | ||
|
|
3f98e9451a | ||
|
|
6c72194346 | ||
|
|
822dd24756 | ||
|
|
262ed38429 | ||
|
|
5ff66ce4dd | ||
|
|
ca73b8e0b8 | ||
|
|
2d49ace0e3 | ||
|
|
d52f22044e | ||
|
|
2bf052aac9 | ||
|
|
a79c9d5f4f | ||
|
|
6f9bcf1858 | ||
|
|
d1b00ba95d | ||
|
|
bb45bee7f8 | ||
|
|
246f0b21fd | ||
|
|
394443b6d1 | ||
|
|
fc1dd2daac | ||
|
|
ba1b6f321e | ||
|
|
06402cf1c6 | ||
|
|
dfc33389d8 | ||
|
|
4e83752655 | ||
|
|
7e28718681 | ||
|
|
bf452e922a | ||
|
|
4911a74cac | ||
|
|
a2bda5a4db | ||
|
|
800abc605f | ||
|
|
ac83b67632 | ||
|
|
00bc7dccb9 | ||
|
|
04aa9f0e61 | ||
|
|
353e97a4c1 | ||
|
|
7b28387bb4 | ||
|
|
1889fe23c5 | ||
|
|
9832fbe042 | ||
|
|
084070475d | ||
|
|
cb42ca8765 | ||
|
|
45d7e66488 | ||
|
|
93a1616933 | ||
|
|
9a87a2ff0d | ||
|
|
bdff05feaf | ||
|
|
937e3d0b94 | ||
|
|
8503aba583 | ||
|
|
bb8223d4ff | ||
|
|
af3c8f66f7 | ||
|
|
3097a1b17e | ||
|
|
54b80f74b2 | ||
|
|
9a78d28cd7 | ||
|
|
5df197e814 | ||
|
|
5fe09e9787 | ||
|
|
1ed817932b | ||
|
|
0ccadb246f | ||
|
|
b67235a7e5 | ||
|
|
93853613bd | ||
|
|
1ecb4fedcc | ||
|
|
c8fdf3731a | ||
|
|
f8e766ffc0 | ||
|
|
050489dd80 | ||
|
|
2db966ba47 | ||
|
|
aa54d65f63 | ||
|
|
e3ee48b52e | ||
|
|
8ccf349458 | ||
|
|
2fce15db94 | ||
|
|
0cf50e8000 | ||
|
|
5b9630cf46 | ||
|
|
7dcbb409a9 | ||
|
|
286e057fae | ||
|
|
7d4fe341f1 | ||
|
|
76acb7bb58 | ||
|
|
5ef7cd7bdd | ||
|
|
ebb4628e66 | ||
|
|
0928060c75 | ||
|
|
d8f9a9a03c | ||
|
|
abfb8bbc34 | ||
|
|
82e01f7b17 | ||
|
|
a97609e920 | ||
|
|
f1e1bd41b9 | ||
|
|
57d35858d8 | ||
|
|
0b956c66c1 | ||
|
|
b1dfa1db61 | ||
|
|
cb579ecc62 | ||
|
|
ae235aa58c | ||
|
|
6302056182 | ||
|
|
5e20abd7f1 | ||
|
|
72a72dbc88 | ||
|
|
4766666913 | ||
|
|
fa6070c680 | ||
|
|
6267d11e51 | ||
|
|
822298ab66 | ||
|
|
2ad3ab7f0d | ||
|
|
f437fd6cd6 | ||
|
|
42b247756a | ||
|
|
fbbf2d5eb3 | ||
|
|
788a276616 | ||
|
|
196779ffb6 | ||
|
|
59a144baed | ||
|
|
ad825b80b0 | ||
|
|
45a0061660 | ||
|
|
8831c76fb4 | ||
|
|
66616e1cab | ||
|
|
fa281a0df0 | ||
|
|
d48a96599f | ||
|
|
7de7ef8e8c | ||
|
|
406a254523 | ||
|
|
eabd6f60ef | ||
|
|
e416d06aa9 | ||
|
|
65e073e6b8 | ||
|
|
45ac0d5dc6 | ||
|
|
c9ef034ab8 | ||
|
|
c89f38f4f8 | ||
|
|
858b57d77a | ||
|
|
9b87892036 | ||
|
|
272f96b405 | ||
|
|
3e519001a3 | ||
|
|
f442aad962 | ||
|
|
fa9b151c36 | ||
|
|
481bd6f57a | ||
|
|
f015227fc8 | ||
|
|
61ba16b779 | ||
|
|
f6e86bfcf8 | ||
|
|
498dd76730 | ||
|
|
ebd909dfe7 | ||
|
|
067ed1258b | ||
|
|
ef3c72a24f | ||
|
|
b257f476c9 | ||
|
|
d3af2be79a | ||
|
|
e4ee392c27 | ||
|
|
cf48ad06ed | ||
|
|
63df85f7f9 | ||
|
|
b29611509e | ||
|
|
dd1cf0ec56 | ||
|
|
c04c73bbd7 | ||
|
|
4ea5723b7f | ||
|
|
75244853c1 | ||
|
|
264b3a785b | ||
|
|
bb15e1d8ac | ||
|
|
7538649e81 | ||
|
|
31efbe915e | ||
|
|
9e69627626 | ||
|
|
dd9da2853a | ||
|
|
670461c66f | ||
|
|
f6092b9128 | ||
|
|
a690cb36ff | ||
|
|
5ca8f4a3aa | ||
|
|
ba6e2f0a54 | ||
|
|
149f4e38a0 | ||
|
|
b5ee170726 | ||
|
|
04961880fe | ||
|
|
e22e8ffa0e | ||
|
|
d18d800947 | ||
|
|
3ca58ee65f | ||
|
|
21387b9a83 | ||
|
|
ccb0d491ed | ||
|
|
daa3200713 | ||
|
|
fec2d1f7ee | ||
|
|
eb8e95723c | ||
|
|
999bec19f1 | ||
|
|
dfb8de2349 | ||
|
|
59f1cdcc82 | ||
|
|
3eb8be6239 | ||
|
|
7dfc4a651d | ||
|
|
189d145393 | ||
|
|
26bec11d76 | ||
|
|
1e7071bff3 | ||
|
|
92390d1d59 | ||
|
|
b9b072119b | ||
|
|
b6d9fd8030 | ||
|
|
24537c4fdc | ||
|
|
82e448de7c | ||
|
|
9831e7bc3b | ||
|
|
90e37439e5 | ||
|
|
65f2490e89 | ||
|
|
c14a921e5a | ||
|
|
2bc8ffefce | ||
|
|
b88d8c85cb | ||
|
|
693f52d984 | ||
|
|
56a74bc54c | ||
|
|
a20358b61b | ||
|
|
341d9d1697 | ||
|
|
9cee424383 | ||
|
|
37cb51cfd6 | ||
|
|
84b7bfb989 | ||
|
|
04d17e4839 |
73
CHANGELOG.md
73
CHANGELOG.md
@@ -1,7 +1,78 @@
|
||||
## WLED changelog
|
||||
|
||||
#### Build 2306020
|
||||
#### Build 2309100
|
||||
- Release of WLED beta version 0.14.0-b5 "Hoshi"
|
||||
- New standard esp32 build with audioreactive
|
||||
- Effect blending bugfixes, and minor optimizations
|
||||
|
||||
#### Build 2309050
|
||||
- Effect blending (#3311) (finally efect transitions!)
|
||||
*WARNING*: May not work well with ESP8266, with plenty of segments or usermods (low RAM condition)!!!
|
||||
- Added receive and send sync groups to JSON API (#3317) (you can change sync groups using preset)
|
||||
- Internal temperature usermod (#3246)
|
||||
- MQTT server and topic length overrides (#3354) (new build flags)
|
||||
- Animated Staircase usermod enhancement (#3348) (on/off toggle/relay control)
|
||||
- Added local time info to Info page (#3351)
|
||||
- New effect: Rolling Balls (a.k.a. linear bounce) (#1039)
|
||||
- Various bug fixes and enhancements.
|
||||
|
||||
#### Build 2308110
|
||||
- Release of WLED beta version 0.14.0-b4 "Hoshi"
|
||||
- Reset effect data immediately upon mode change
|
||||
|
||||
#### Build 2308030
|
||||
- Improved random palette handling and blending
|
||||
- Soap bugfix
|
||||
- Fix ESP-NOW crash with AP mode Always
|
||||
|
||||
#### Build 2307180
|
||||
- Bus-level global buffering (#3280)
|
||||
- Removed per-segment LED buffer (SEGMENT.leds)
|
||||
- various fixes and improvements (ESP variants platform 5.3.0, effect optimizations, /json/cfg pin allocation)
|
||||
|
||||
#### Build 2307130
|
||||
- larger `oappend()` stack buffer (3.5k) for ESP32
|
||||
- Preset cycle bugfix (#3262)
|
||||
- Rotary encoder ALT fix for large LED count (#3276)
|
||||
- effect updates (2D Plasmaball), `blur()` speedup
|
||||
- On/Off toggle from nodes view (may show unknow device type on older versions) (#3291)
|
||||
- various fixes and improvements (ABL, crashes when changing presets with different segments)
|
||||
|
||||
#### Build 2306270
|
||||
- ESP-NOW remote support (#3237)
|
||||
- Pixel Magic tool (display pixel art) (#3249)
|
||||
- Websocket (peek) fallback when connection cannot be established, WS retries (#3267)
|
||||
- Add WiFi network scan RPC command to Improv Serial (#3271)
|
||||
- Longer (custom option available) segment name for ESP32
|
||||
- various fixes and improvements
|
||||
|
||||
#### Build 2306210
|
||||
- 0.14.0-b3 release
|
||||
- respect global I2C in all usermods (no local initilaisation of I2C bus)
|
||||
- Multi relay usermod compile-time enabled option (-D MULTI_RELAY_ENABLED=true|false)
|
||||
|
||||
#### Build 2306180
|
||||
- Added client-side option for applying effect defaults from metadata
|
||||
- Improved ESP8266 stability by reducing WebSocket response resends
|
||||
- Updated ESP8266 core to 3.1.2
|
||||
|
||||
#### Build 2306141
|
||||
- Lissajous improvements
|
||||
- Scrolling Text improvements (leading 0)
|
||||
|
||||
#### Build 2306140
|
||||
- Add settings PIN (un)locking to JSON post API
|
||||
|
||||
#### Build 2306130
|
||||
- Bumped version to 0.14-b3 (beta 3)
|
||||
- added pin dropdowns in LED preferences (not for LED pins) and usermods
|
||||
- introduced (unused ATM) NeoGammaWLEDMethod class
|
||||
- Reverse proxy support
|
||||
- PCF8754 support for Rotary encoder (requires wiring INT pin to ESP GPIO)
|
||||
- Rely on global I2C pins for usermods (breaking change)
|
||||
- various fixes and enhancements
|
||||
|
||||
#### Build 2306020
|
||||
- Support for segment sets (PR #3171)
|
||||
- Reduce sound simulation modes to 2 to facilitiate segment sets
|
||||
- Trigger button immediately on press if all configured presets are the same (PR #3226)
|
||||
|
||||
8
package-lock.json
generated
8
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.14.0-b2",
|
||||
"version": "0.14.0-b5",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1409,9 +1409,9 @@
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="
|
||||
},
|
||||
"semver-diff": {
|
||||
"version": "2.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.14.0-b2",
|
||||
"version": "0.14.0-b5",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# CI binaries
|
||||
;; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
|
||||
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi
|
||||
|
||||
# Release binaries
|
||||
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
|
||||
@@ -40,6 +40,8 @@ default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_
|
||||
; default_envs = esp32dev_qio80
|
||||
; default_envs = esp32_eth_ota1mapp
|
||||
; default_envs = esp32s2_saola
|
||||
; default_envs = esp32c3dev
|
||||
; default_envs = lolin_s2_mini
|
||||
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
@@ -60,13 +62,14 @@ arduino_core_2_7_4 = espressif8266@2.6.2
|
||||
arduino_core_3_0_0 = espressif8266@3.0.0
|
||||
arduino_core_3_2_0 = espressif8266@3.2.0
|
||||
arduino_core_4_1_0 = espressif8266@4.1.0
|
||||
arduino_core_3_1_2 = espressif8266@4.2.0
|
||||
|
||||
# Development platforms
|
||||
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
|
||||
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
|
||||
|
||||
# Platform to use for ESP8266
|
||||
platform_wled_default = ${common.arduino_core_4_1_0}
|
||||
platform_wled_default = ${common.arduino_core_3_1_2}
|
||||
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
|
||||
#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||
platform_packages = platformio/framework-arduinoespressif8266
|
||||
@@ -84,11 +87,13 @@ platform_packages = platformio/framework-arduinoespressif8266
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: DEBUG
|
||||
#
|
||||
# esp8266 : see https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level
|
||||
# esp32 : see https://docs.platformio.org/en/latest/platforms/espressif32.html#debug-level
|
||||
# ------------------------------------------------------------------------------
|
||||
debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM
|
||||
#if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h"
|
||||
#-DDEBUG_ESP_CORE is not working right now
|
||||
debug_flags = -D DEBUG=1 -D WLED_DEBUG
|
||||
-DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM ;; for esp8266
|
||||
# if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h"
|
||||
# -DDEBUG_ESP_CORE is not working right now
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: ldscript (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld)
|
||||
@@ -172,7 +177,7 @@ upload_speed = 115200
|
||||
# ------------------------------------------------------------------------------
|
||||
lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.5.0
|
||||
fastled/FastLED @ 3.6.0
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.7.5
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7
|
||||
@@ -198,7 +203,7 @@ build_flags =
|
||||
-DESP8266
|
||||
-DFP_IN_IROM
|
||||
;-Wno-deprecated-declarations
|
||||
-Wno-register ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C
|
||||
;-Wno-register ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C
|
||||
;-Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library ;; warning: this can be dangerous
|
||||
-Wno-misleading-indentation
|
||||
; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
|
||||
@@ -211,6 +216,9 @@ build_flags =
|
||||
-DVTABLES_IN_FLASH
|
||||
; restrict to minimal mime-types
|
||||
-DMIMETYPE_MINIMAL
|
||||
; other special-purpose framework flags (see https://docs.platformio.org/en/latest/platforms/espressif8266.html)
|
||||
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
|
||||
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown
|
||||
|
||||
lib_deps =
|
||||
#https://github.com/lorol/LITTLEFS.git
|
||||
@@ -221,9 +229,7 @@ lib_deps =
|
||||
[esp32]
|
||||
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
|
||||
platform = espressif32@3.5.0
|
||||
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4
|
||||
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
#-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
@@ -231,14 +237,14 @@ build_flags = -g
|
||||
#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
|
||||
-D LOROL_LITTLEFS
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
||||
|
||||
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
|
||||
lib_deps =
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
${env.lib_deps}
|
||||
|
||||
# additional build flags for audioreactive
|
||||
AR_build_flags = -D USERMOD_AUDIOREACTIVE -D UM_AUDIOREACTIVE_USE_NEW_FFT
|
||||
AR_lib_deps = https://github.com/kosme/arduinoFFT#develop @ ^1.9.2
|
||||
|
||||
[esp32_idf_V4]
|
||||
;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5
|
||||
@@ -246,9 +252,8 @@ lib_deps =
|
||||
;;
|
||||
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
|
||||
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
|
||||
platform = espressif32@5.2.0
|
||||
platform = espressif32@5.3.0
|
||||
platform_packages =
|
||||
toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
|
||||
build_flags = -g
|
||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||
-DARDUINO_ARCH_ESP32 -DESP32
|
||||
@@ -262,9 +267,8 @@ lib_deps =
|
||||
|
||||
[esp32s2]
|
||||
;; generic definitions for all ESP32-S2 boards
|
||||
platform = espressif32@5.2.0
|
||||
platform = espressif32@5.3.0
|
||||
platform_packages =
|
||||
toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32S2
|
||||
@@ -282,9 +286,8 @@ lib_deps =
|
||||
|
||||
[esp32c3]
|
||||
;; generic definitions for all ESP32-C3 boards
|
||||
platform = espressif32@5.2.0
|
||||
platform = espressif32@5.3.0
|
||||
platform_packages =
|
||||
toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32C3
|
||||
@@ -301,9 +304,8 @@ lib_deps =
|
||||
|
||||
[esp32s3]
|
||||
;; generic definitions for all ESP32-S3 boards
|
||||
platform = espressif32@5.2.0
|
||||
platform = espressif32@5.3.0
|
||||
platform_packages =
|
||||
toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0
|
||||
build_flags = -g
|
||||
-DESP32
|
||||
-DARDUINO_ARCH_ESP32
|
||||
@@ -400,6 +402,20 @@ lib_deps = ${esp32.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32dev_audioreactive]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
; board_build.f_flash = 80000000L
|
||||
; board_build.flash_mode = dio
|
||||
|
||||
[env:esp32dev_qio80]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
@@ -434,6 +450,7 @@ platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
-D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
@@ -447,6 +464,7 @@ board_build.flash_mode = qio
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=S2_saola
|
||||
;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
lib_deps = ${esp32s2.lib_deps}
|
||||
|
||||
@@ -457,10 +475,11 @@ platform_packages = ${esp32c3.platform_packages}
|
||||
framework = arduino
|
||||
board = esp32-c3-devkitm-1
|
||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=ESP32-C3
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
|
||||
;-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
lib_deps = ${esp32c3.lib_deps}
|
||||
@@ -472,10 +491,10 @@ platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600 ; or 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=0 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
;-D WLED_DEBUG
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
board_build.partitions = tools/WLED_ESP32_8MB.csv
|
||||
@@ -484,19 +503,18 @@ board_build.flash_mode = qio
|
||||
; board_build.flash_mode = dio ;; try this if you have problems at startup
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32s3dev_8MB_PSRAM]
|
||||
;; ESP32-TinyS3 development board, with 8MB FLASH and 8MB PSRAM (memory_type: qio_opi, qio_qspi, or opi_opi)
|
||||
;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860
|
||||
;board = esp32s3box ; -> error: 'esp32_adc2gpio' was not declared in this scope
|
||||
board = esp32-s3-devkitc-1 ; -> compiles, but does not support PSRAM
|
||||
[env:esp32s3dev_8MB_PSRAM_opi]
|
||||
;; ESP32-S3 development board, with 8MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags}
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=0 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
; -D WLED_RELEASE_NAME=ESP32-S3_PSRAM
|
||||
-D WLED_USE_PSRAM -DBOARD_HAS_PSRAM ; tells WLED that PSRAM shall be used
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
@@ -505,6 +523,13 @@ board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32s3dev_8MB_PSRAM_qspi]
|
||||
;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi)
|
||||
extends = env:esp32s3dev_8MB_PSRAM_opi
|
||||
;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB
|
||||
|
||||
[env:esp8285_4CH_MagicHome]
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
@@ -572,10 +597,10 @@ platform = ${esp32s2.platform}
|
||||
platform_packages = ${esp32s2.platform_packages}
|
||||
board = lolin_s2_mini
|
||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
build_unflags = ${common.build_unflags} -DARDUINO_USB_CDC_ON_BOOT=1
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2
|
||||
build_unflags = ${common.build_unflags} #-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
|
||||
@@ -12,7 +12,7 @@ anyio==3.6.2
|
||||
# via starlette
|
||||
bottle==0.12.25
|
||||
# via platformio
|
||||
certifi==2022.12.7
|
||||
certifi==2023.7.22
|
||||
# via requests
|
||||
charset-normalizer==3.1.0
|
||||
# via requests
|
||||
|
||||
8
tools/WLED_ESP32_16MB_9MB_FS.csv
Normal file
8
tools/WLED_ESP32_16MB_9MB_FS.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x300000,
|
||||
app1, app, ota_1, 0x310000,0x300000,
|
||||
spiffs, data, spiffs, 0x610000,0x9E0000,
|
||||
coredump, data, coredump,,64K
|
||||
# to create/use ffat, see https://github.com/marcmerlin/esp32_fatfsimage
|
||||
|
@@ -3,4 +3,5 @@ nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x200000,
|
||||
app1, app, ota_1, 0x210000,0x200000,
|
||||
spiffs, data, spiffs, 0x410000,0x3F0000,
|
||||
spiffs, data, spiffs, 0x410000,0x3E0000,
|
||||
coredump, data, coredump,,64K
|
||||
|
||||
|
@@ -222,6 +222,7 @@ writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index');
|
||||
writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple');
|
||||
writeHtmlGzipped("wled00/data/pixart/pixart.htm", "wled00/html_pixart.h", 'pixart');
|
||||
writeHtmlGzipped("wled00/data/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal');
|
||||
writeHtmlGzipped("wled00/data/pxmagic/pxmagic.htm", "wled00/html_pxmagic.h", 'pxmagic');
|
||||
/*
|
||||
writeChunks(
|
||||
"wled00/data",
|
||||
@@ -389,12 +390,6 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "liveviewws.htm",
|
||||
name: "PAGE_liveviewws",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "liveviewws2D.htm",
|
||||
name: "PAGE_liveviewws2D",
|
||||
|
||||
@@ -25,6 +25,7 @@ class Animated_Staircase : public Usermod {
|
||||
bool useUSSensorBottom = false; // using PIR or UltraSound sensor?
|
||||
unsigned int topMaxDist = 50; // default maximum measured distance in cm, top
|
||||
unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom
|
||||
bool togglePower = false; // toggle power on/off with staircase on/off
|
||||
|
||||
/* runtime variables */
|
||||
bool initDone = false;
|
||||
@@ -90,7 +91,8 @@ class Animated_Staircase : public Usermod {
|
||||
static const char _bottomEcho_pin[];
|
||||
static const char _topEchoCm[];
|
||||
static const char _bottomEchoCm[];
|
||||
|
||||
static const char _togglePower[];
|
||||
|
||||
void publishMqtt(bool bottom, const char* state) {
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
@@ -196,6 +198,7 @@ class Animated_Staircase : public Usermod {
|
||||
if (on) {
|
||||
lastSensor = topSensorRead;
|
||||
} else {
|
||||
if (togglePower && onIndex == offIndex && offMode) toggleOnOff(); // toggle power on if off
|
||||
// If the bottom sensor triggered, we need to swipe up, ON
|
||||
swipe = bottomSensorRead;
|
||||
|
||||
@@ -249,7 +252,10 @@ class Animated_Staircase : public Usermod {
|
||||
offIndex = MAX(onIndex, offIndex - 1);
|
||||
}
|
||||
}
|
||||
if (oldOn != onIndex || oldOff != offIndex) updateSegments(); // reduce the number of updates to necessary ones
|
||||
if (oldOn != onIndex || oldOff != offIndex) {
|
||||
updateSegments(); // reduce the number of updates to necessary ones
|
||||
if (togglePower && onIndex == offIndex && !offMode && !on) toggleOnOff(); // toggle power off for all segments off
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +301,7 @@ class Animated_Staircase : public Usermod {
|
||||
strip.setTransition(segment_delay_ms/100);
|
||||
strip.trigger();
|
||||
} else {
|
||||
if (togglePower && !on && offMode) toggleOnOff(); // toggle power on if off
|
||||
// Restore segment options
|
||||
for (int i = 0; i <= strip.getLastActiveSegmentId(); i++) {
|
||||
Segment &seg = strip.getSegment(i);
|
||||
@@ -444,6 +451,7 @@ class Animated_Staircase : public Usermod {
|
||||
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
|
||||
staircase[FPSTR(_topEchoCm)] = topMaxDist;
|
||||
staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist;
|
||||
staircase[FPSTR(_togglePower)] = togglePower;
|
||||
DEBUG_PRINTLN(F("Staircase config saved."));
|
||||
}
|
||||
|
||||
@@ -488,6 +496,8 @@ class Animated_Staircase : public Usermod {
|
||||
bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist;
|
||||
bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)
|
||||
|
||||
togglePower = top[FPSTR(_togglePower)] | togglePower; // staircase toggles power on/off
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
@@ -511,7 +521,7 @@ class Animated_Staircase : public Usermod {
|
||||
if (changed) setup();
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return true;
|
||||
return !top[FPSTR(_togglePower)].isNull();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -551,3 +561,4 @@ const char Animated_Staircase::_bottomPIRorTrigger_pin[] PROGMEM = "bottomPIR
|
||||
const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin";
|
||||
const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm";
|
||||
const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm";
|
||||
const char Animated_Staircase::_togglePower[] PROGMEM = "toggle-on-off";
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <Wire.h>
|
||||
#include <BH1750.h>
|
||||
|
||||
// the max frequency to check photoresistor, 10 seconds
|
||||
@@ -56,15 +55,6 @@ private:
|
||||
static const char _offset[];
|
||||
static const char _HomeAssistantDiscovery[];
|
||||
|
||||
// set the default pins based on the architecture, these get overridden by Usermod menu settings
|
||||
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
||||
#define HW_PIN_SCL 22
|
||||
#define HW_PIN_SDA 21
|
||||
#else // ESP8266 boards
|
||||
#define HW_PIN_SCL 5
|
||||
#define HW_PIN_SDA 4
|
||||
#endif
|
||||
int8_t ioPin[2] = {HW_PIN_SCL, HW_PIN_SDA}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup()
|
||||
bool initDone = false;
|
||||
bool sensorFound = false;
|
||||
|
||||
@@ -123,14 +113,7 @@ private:
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
bool HW_Pins_Used = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); // note whether architecture-based hardware SCL/SDA pins used
|
||||
PinOwner po = PinOwner::UM_BH1750; // defaults to being pinowner for SCL/SDA pins
|
||||
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins
|
||||
if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) return;
|
||||
|
||||
Wire.begin(ioPin[1], ioPin[0]);
|
||||
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
sensorFound = lightMeter.begin();
|
||||
initDone = true;
|
||||
}
|
||||
@@ -190,7 +173,9 @@ public:
|
||||
user = root.createNestedObject(F("u"));
|
||||
|
||||
JsonArray lux_json = user.createNestedArray(F("Luminance"));
|
||||
if (!sensorFound) {
|
||||
if (!enabled) {
|
||||
lux_json.add(F("disabled"));
|
||||
} else if (!sensorFound) {
|
||||
// if no sensor
|
||||
lux_json.add(F("BH1750 "));
|
||||
lux_json.add(F("Not Found"));
|
||||
@@ -216,9 +201,6 @@ public:
|
||||
top[FPSTR(_minReadInterval)] = minReadingInterval;
|
||||
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
|
||||
top[FPSTR(_offset)] = offset;
|
||||
JsonArray io_pin = top.createNestedArray(F("pin"));
|
||||
for (byte i=0; i<2; i++) io_pin.add(ioPin[i]);
|
||||
top[F("help4Pins")] = F("SCL,SDA"); // help for Settings page
|
||||
|
||||
DEBUG_PRINTLN(F("BH1750 config saved."));
|
||||
}
|
||||
@@ -226,8 +208,6 @@ public:
|
||||
// called before setup() to populate properties from values stored in cfg.json
|
||||
bool readFromConfig(JsonObject &root)
|
||||
{
|
||||
int8_t newPin[2]; for (byte i=0; i<2; i++) newPin[i] = ioPin[i]; // prepare to note changed pins
|
||||
|
||||
// we look for JSON object.
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull())
|
||||
@@ -244,27 +224,12 @@ public:
|
||||
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
|
||||
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
|
||||
configComplete &= getJsonValue(top[FPSTR(_offset)], offset, 1);
|
||||
for (byte i=0; i<2; i++) configComplete &= getJsonValue(top[F("pin")][i], newPin[i], ioPin[i]);
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
// changing parameters from settings page
|
||||
bool pinsChanged = false;
|
||||
for (byte i=0; i<2; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } // check if any pins changed
|
||||
if (pinsChanged) { //if pins changed, deallocate old pins and allocate new ones
|
||||
PinOwner po = PinOwner::UM_BH1750;
|
||||
if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||
pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 2, po); // deallocate pins
|
||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||
setup();
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[F("pin")].isNull();
|
||||
}
|
||||
|
||||
return configComplete;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <BME280I2C.h> // BME280 sensor
|
||||
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
||||
|
||||
@@ -34,7 +33,6 @@ private:
|
||||
#ifdef ESP8266
|
||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
int8_t ioPin[2] = {i2c_scl, i2c_sda}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup()
|
||||
bool initDone = false;
|
||||
|
||||
// BME280 sensor settings
|
||||
@@ -186,14 +184,8 @@ private:
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
bool HW_Pins_Used = (ioPin[0]==i2c_scl && ioPin[1]==i2c_sda); // note whether architecture-based hardware SCL/SDA pins used
|
||||
PinOwner po = PinOwner::UM_BME280; // defaults to being pinowner for SCL/SDA pins
|
||||
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins
|
||||
if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) { sensorType=0; return; }
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; }
|
||||
|
||||
Wire.begin(ioPin[1], ioPin[0]);
|
||||
|
||||
if (!bme.begin())
|
||||
{
|
||||
sensorType = 0;
|
||||
@@ -415,9 +407,6 @@ public:
|
||||
top[F("PublishAlways")] = PublishAlways;
|
||||
top[F("UseCelsius")] = UseCelsius;
|
||||
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
||||
JsonArray io_pin = top.createNestedArray(F("pin"));
|
||||
for (byte i=0; i<2; i++) io_pin.add(ioPin[i]);
|
||||
top[F("help4Pins")] = F("SCL,SDA"); // help for Settings page
|
||||
DEBUG_PRINTLN(F("BME280 config saved."));
|
||||
}
|
||||
|
||||
@@ -427,8 +416,6 @@ public:
|
||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||
|
||||
int8_t newPin[2]; for (byte i=0; i<2; i++) newPin[i] = ioPin[i]; // prepare to note changed pins
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINT(F(_name));
|
||||
@@ -447,27 +434,14 @@ public:
|
||||
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
||||
for (byte i=0; i<2; i++) configComplete &= getJsonValue(top[F("pin")][i], newPin[i], ioPin[i]);
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
// changing parameters from settings page
|
||||
bool pinsChanged = false;
|
||||
for (byte i=0; i<2; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } // check if any pins changed
|
||||
if (pinsChanged) { //if pins changed, deallocate old pins and allocate new ones
|
||||
PinOwner po = PinOwner::UM_BME280;
|
||||
if (ioPin[0]==i2c_scl && ioPin[1]==i2c_sda) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||
pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 2, po); // deallocate pins
|
||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||
setup();
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[F("pin")].isNull();
|
||||
}
|
||||
|
||||
return configComplete;
|
||||
|
||||
17
usermods/Internal_Temperature_v2/readme.md
Normal file
17
usermods/Internal_Temperature_v2/readme.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Internal Temperature Usermod
|
||||
This usermod adds the temperature readout to the Info tab and also publishes that over the topic `mcutemp` topic.
|
||||
|
||||
## Important
|
||||
A shown temp of 53,33°C might indicate that the internal temp is not supported.
|
||||
|
||||
ESP8266 does not have a internal temp sensor
|
||||
|
||||
ESP32S2 seems to crash on reading the sensor -> disabled
|
||||
|
||||
## Installation
|
||||
Add a build flag `-D USERMOD_INTERNAL_TEMPERATURE` to your `platformio.ini` (or `platformio_override.ini`).
|
||||
|
||||
## Authors
|
||||
Soeren Willrodt [@lost-hope](https://github.com/lost-hope)
|
||||
|
||||
Dimitry Zhemkov [@dima-zhemkov](https://github.com/dima-zhemkov)
|
||||
117
usermods/Internal_Temperature_v2/usermod_internal_temperature.h
Normal file
117
usermods/Internal_Temperature_v2/usermod_internal_temperature.h
Normal file
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
class InternalTemperatureUsermod : public Usermod
|
||||
{
|
||||
|
||||
private:
|
||||
unsigned long loopInterval = 10000;
|
||||
unsigned long lastTime = 0;
|
||||
bool isEnabled = false;
|
||||
float temperature = 0;
|
||||
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
static const char _loopInterval[];
|
||||
|
||||
// any private methods should go here (non-inline methosd should be defined out of class)
|
||||
void publishMqtt(const char *state, bool retain = false); // example for publishing MQTT message
|
||||
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// if usermod is disabled or called during strip updating just exit
|
||||
// NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
|
||||
if (!isEnabled || strip.isUpdating() || millis() - lastTime <= loopInterval)
|
||||
return;
|
||||
|
||||
lastTime = millis();
|
||||
|
||||
#ifdef ESP8266 // ESP8266
|
||||
// does not seem possible
|
||||
temperature = -1;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32S2
|
||||
temperature = -1;
|
||||
#else // ESP32 ESP32S3 and ESP32C3
|
||||
temperature = roundf(temperatureRead() * 10) / 10;
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
if (WLED_MQTT_CONNECTED)
|
||||
{
|
||||
char array[10];
|
||||
snprintf(array, sizeof(array), "%f", temperature);
|
||||
publishMqtt(array);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
if (!isEnabled)
|
||||
return;
|
||||
|
||||
// if "u" object does not exist yet wee need to create it
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull())
|
||||
user = root.createNestedObject("u");
|
||||
|
||||
JsonArray userTempArr = user.createNestedArray(FPSTR(_name));
|
||||
userTempArr.add(temperature);
|
||||
userTempArr.add(F(" °C"));
|
||||
|
||||
// if "sensor" object does not exist yet wee need to create it
|
||||
JsonObject sensor = root[F("sensor")];
|
||||
if (sensor.isNull())
|
||||
sensor = root.createNestedObject(F("sensor"));
|
||||
|
||||
JsonArray sensorTempArr = sensor.createNestedArray(FPSTR(_name));
|
||||
sensorTempArr.add(temperature);
|
||||
sensorTempArr.add(F("°C"));
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
top[FPSTR(_enabled)] = isEnabled;
|
||||
top[FPSTR(_loopInterval)] = loopInterval;
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
bool configComplete = !top.isNull();
|
||||
configComplete &= getJsonValue(top[FPSTR(_enabled)], isEnabled);
|
||||
configComplete &= getJsonValue(top[FPSTR(_loopInterval)], loopInterval);
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_INTERNAL_TEMPERATURE;
|
||||
}
|
||||
};
|
||||
|
||||
const char InternalTemperatureUsermod::_name[] PROGMEM = "Internal Temperature";
|
||||
const char InternalTemperatureUsermod::_enabled[] PROGMEM = "Enabled";
|
||||
const char InternalTemperatureUsermod::_loopInterval[] PROGMEM = "Loop Interval";
|
||||
|
||||
void InternalTemperatureUsermod::publishMqtt(const char *state, bool retain)
|
||||
{
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
// Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED)
|
||||
{
|
||||
char subuf[64];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat_P(subuf, PSTR("/mcutemp"));
|
||||
mqtt->publish(subuf, 0, retain, state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
* This usermod handles PIR sensor states.
|
||||
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
||||
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
|
||||
*
|
||||
* Maintained by: @blazoncek
|
||||
*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
@@ -38,21 +38,21 @@ public:
|
||||
~PIRsensorSwitch() {}
|
||||
|
||||
//Enable/Disable the PIR sensor
|
||||
void EnablePIRsensor(bool en) { enabled = en; }
|
||||
inline void EnablePIRsensor(bool en) { enabled = en; }
|
||||
|
||||
// Get PIR sensor enabled/disabled state
|
||||
bool PIRsensorEnabled() { return enabled; }
|
||||
inline bool PIRsensorEnabled() { return enabled; }
|
||||
|
||||
private:
|
||||
|
||||
byte prevPreset = 0;
|
||||
byte prevPlaylist = 0;
|
||||
|
||||
uint32_t offTimerStart = 0; // off timer start time
|
||||
volatile unsigned long offTimerStart = 0; // off timer start time
|
||||
volatile bool PIRtriggered = false; // did PIR trigger?
|
||||
byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for stateUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE
|
||||
byte sensorPinState = LOW; // current PIR sensor pin state
|
||||
bool initDone = false; // status of initialization
|
||||
bool PIRtriggered = false;
|
||||
unsigned long lastLoop = 0;
|
||||
|
||||
// configurable parameters
|
||||
@@ -66,6 +66,7 @@ private:
|
||||
// flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR)
|
||||
bool m_offOnly = false;
|
||||
bool m_offMode = offMode;
|
||||
bool m_override = false;
|
||||
|
||||
// Home Assistant
|
||||
bool HomeAssistantDiscovery = false; // is HA discovery turned on
|
||||
@@ -81,173 +82,33 @@ private:
|
||||
static const char _offOnly[];
|
||||
static const char _haDiscovery[];
|
||||
static const char _notify[];
|
||||
static const char _override[];
|
||||
|
||||
/**
|
||||
* check if it is daytime
|
||||
* if sunrise/sunset is not defined (no NTP or lat/lon) default to nighttime
|
||||
*/
|
||||
bool isDayTime() {
|
||||
updateLocalTime();
|
||||
uint8_t hr = hour(localTime);
|
||||
uint8_t mi = minute(localTime);
|
||||
|
||||
if (sunrise && sunset) {
|
||||
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
||||
return true;
|
||||
} else {
|
||||
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
||||
return true;
|
||||
}
|
||||
if (hour(sunset)==hr && minute(sunset)>mi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static bool isDayTime();
|
||||
|
||||
/**
|
||||
* switch strip on/off
|
||||
*/
|
||||
void switchStrip(bool switchOn)
|
||||
{
|
||||
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return; //if lights on and off only, do nothing
|
||||
if (PIRtriggered && switchOn) return; //if already on and triggered before, do nothing
|
||||
PIRtriggered = switchOn;
|
||||
DEBUG_PRINT(F("PIR: strip=")); DEBUG_PRINTLN(switchOn?"on":"off");
|
||||
if (switchOn) {
|
||||
if (m_onPreset) {
|
||||
if (currentPlaylist>0 && !offMode) {
|
||||
prevPlaylist = currentPlaylist;
|
||||
unloadPlaylist();
|
||||
} else if (currentPreset>0 && !offMode) {
|
||||
prevPreset = currentPreset;
|
||||
} else {
|
||||
saveTemporaryPreset();
|
||||
prevPlaylist = 0;
|
||||
prevPreset = 255;
|
||||
}
|
||||
applyPreset(m_onPreset, NotifyUpdateMode);
|
||||
return;
|
||||
}
|
||||
// preset not assigned
|
||||
if (bri == 0) {
|
||||
bri = briLast;
|
||||
stateUpdated(NotifyUpdateMode);
|
||||
}
|
||||
} else {
|
||||
if (m_offPreset) {
|
||||
applyPreset(m_offPreset, NotifyUpdateMode);
|
||||
return;
|
||||
} else if (prevPlaylist) {
|
||||
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode);
|
||||
prevPlaylist = 0;
|
||||
return;
|
||||
} else if (prevPreset) {
|
||||
if (prevPreset<255) { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPreset, NotifyUpdateMode); }
|
||||
else { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyTemporaryPreset(); }
|
||||
prevPreset = 0;
|
||||
return;
|
||||
}
|
||||
// preset not assigned
|
||||
if (bri != 0) {
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
stateUpdated(NotifyUpdateMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void publishMqtt(const char* state)
|
||||
{
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat_P(subuf, PSTR("/motion"));
|
||||
mqtt->publish(subuf, 0, false, state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void switchStrip(bool switchOn);
|
||||
void publishMqtt(const char* state);
|
||||
|
||||
// Create an MQTT Binary Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||
void publishHomeAssistantAutodiscovery()
|
||||
{
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
StaticJsonDocument<600> doc;
|
||||
char uid[24], json_str[1024], buf[128];
|
||||
|
||||
sprintf_P(buf, PSTR("%s Motion"), serverDescription); //max length: 33 + 7 = 40
|
||||
doc[F("name")] = buf;
|
||||
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||
doc[F("stat_t")] = buf;
|
||||
doc[F("pl_on")] = "on";
|
||||
doc[F("pl_off")] = "off";
|
||||
sprintf_P(uid, PSTR("%s_motion"), escapedMac.c_str());
|
||||
doc[F("uniq_id")] = uid;
|
||||
doc[F("dev_cla")] = F("motion");
|
||||
doc[F("exp_aft")] = 1800;
|
||||
|
||||
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||
device[F("name")] = serverDescription;
|
||||
device[F("ids")] = String(F("wled-sensor-")) + mqttClientID;
|
||||
device[F("mf")] = "WLED";
|
||||
device[F("mdl")] = F("FOSS");
|
||||
device[F("sw")] = versionString;
|
||||
|
||||
sprintf_P(buf, PSTR("homeassistant/binary_sensor/%s/config"), uid);
|
||||
DEBUG_PRINTLN(buf);
|
||||
size_t payload_size = serializeJson(doc, json_str);
|
||||
DEBUG_PRINTLN(json_str);
|
||||
|
||||
mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain?
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void publishHomeAssistantAutodiscovery();
|
||||
|
||||
/**
|
||||
* Read and update PIR sensor state.
|
||||
* Initilize/reset switch off timer
|
||||
*/
|
||||
bool updatePIRsensorState()
|
||||
{
|
||||
bool pinState = digitalRead(PIRsensorPin);
|
||||
if (pinState != sensorPinState) {
|
||||
sensorPinState = pinState; // change previous state
|
||||
|
||||
if (sensorPinState == HIGH) {
|
||||
offTimerStart = 0;
|
||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
||||
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||
publishMqtt("on");
|
||||
} else {
|
||||
// start switch off timer
|
||||
offTimerStart = millis();
|
||||
if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool updatePIRsensorState();
|
||||
|
||||
/**
|
||||
* switch off the strip if the delay has elapsed
|
||||
*/
|
||||
bool handleOffTimer()
|
||||
{
|
||||
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
||||
offTimerStart = 0;
|
||||
if (enabled == true) {
|
||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()) || PIRtriggered)) switchStrip(false);
|
||||
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||
publishMqtt("off");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool handleOffTimer();
|
||||
|
||||
public:
|
||||
//Functions called by WLED
|
||||
@@ -256,186 +117,57 @@ public:
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
if (enabled) {
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
sensorPinState = digitalRead(PIRsensorPin);
|
||||
} else {
|
||||
if (PIRsensorPin >= 0) {
|
||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||
}
|
||||
PIRsensorPin = -1; // allocation failed
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
initDone = true;
|
||||
}
|
||||
void setup();
|
||||
|
||||
/**
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected()
|
||||
{
|
||||
}
|
||||
//void connected();
|
||||
|
||||
/**
|
||||
* onMqttConnect() is called when MQTT connection is established
|
||||
*/
|
||||
void onMqttConnect(bool sessionPresent) {
|
||||
if (HomeAssistantDiscovery) {
|
||||
publishHomeAssistantAutodiscovery();
|
||||
}
|
||||
}
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
|
||||
/**
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
// only check sensors 4x/s
|
||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||
lastLoop = millis();
|
||||
|
||||
if (!updatePIRsensorState()) {
|
||||
handleOffTimer();
|
||||
}
|
||||
}
|
||||
void loop();
|
||||
|
||||
/**
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
*
|
||||
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||
*/
|
||||
void addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
|
||||
|
||||
String uiDomString;
|
||||
if (enabled) {
|
||||
if (offTimerStart > 0)
|
||||
{
|
||||
uiDomString = "";
|
||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - offTimerStart)) / 1000;
|
||||
if (offSeconds >= 3600)
|
||||
{
|
||||
uiDomString += (offSeconds / 3600);
|
||||
uiDomString += F("h ");
|
||||
offSeconds %= 3600;
|
||||
}
|
||||
if (offSeconds >= 60)
|
||||
{
|
||||
uiDomString += (offSeconds / 60);
|
||||
offSeconds %= 60;
|
||||
}
|
||||
else if (uiDomString.length() > 0)
|
||||
{
|
||||
uiDomString += 0;
|
||||
}
|
||||
if (uiDomString.length() > 0)
|
||||
{
|
||||
uiDomString += F("min ");
|
||||
}
|
||||
uiDomString += (offSeconds);
|
||||
infoArr.add(uiDomString + F("s"));
|
||||
} else {
|
||||
infoArr.add(sensorPinState ? F("sensor on") : F("inactive"));
|
||||
}
|
||||
} else {
|
||||
infoArr.add(F("disabled"));
|
||||
}
|
||||
|
||||
uiDomString = F(" <button class=\"btn btn-xs\" onclick=\"requestJson({");
|
||||
uiDomString += FPSTR(_name);
|
||||
uiDomString += F(":{");
|
||||
uiDomString += FPSTR(_enabled);
|
||||
if (enabled) {
|
||||
uiDomString += F(":false}});\">");
|
||||
uiDomString += F("<i class=\"icons on\"></i>");
|
||||
} else {
|
||||
uiDomString += F(":true}});\">");
|
||||
uiDomString += F("<i class=\"icons off\"></i>");
|
||||
}
|
||||
uiDomString += F("</button>");
|
||||
infoArr.add(uiDomString);
|
||||
|
||||
JsonObject sensor = root[F("sensor")];
|
||||
if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
|
||||
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
||||
}
|
||||
void addToJsonInfo(JsonObject &root);
|
||||
|
||||
/**
|
||||
* onStateChanged() is used to detect WLED state change
|
||||
*/
|
||||
void onStateChange(uint8_t mode) {
|
||||
if (!initDone) return;
|
||||
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
||||
if (PIRtriggered && offTimerStart) {
|
||||
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
||||
DEBUG_PRINTLN(F("PIR: Canceled."));
|
||||
offTimerStart = 0;
|
||||
PIRtriggered = false;
|
||||
}
|
||||
}
|
||||
void onStateChange(uint8_t mode);
|
||||
|
||||
/**
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
/*
|
||||
void addToJsonState(JsonObject &root)
|
||||
{
|
||||
}
|
||||
*/
|
||||
//void addToJsonState(JsonObject &root);
|
||||
|
||||
/**
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
|
||||
void readFromJsonState(JsonObject &root)
|
||||
{
|
||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||
JsonObject usermod = root[FPSTR(_name)];
|
||||
if (!usermod.isNull()) {
|
||||
if (usermod[FPSTR(_enabled)].is<bool>()) {
|
||||
enabled = usermod[FPSTR(_enabled)].as<bool>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readFromJsonState(JsonObject &root);
|
||||
|
||||
/**
|
||||
* provide the changeable values
|
||||
*/
|
||||
void addToConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
top[FPSTR(_enabled)] = enabled;
|
||||
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
||||
top["pin"] = PIRsensorPin;
|
||||
top[FPSTR(_onPreset)] = m_onPreset;
|
||||
top[FPSTR(_offPreset)] = m_offPreset;
|
||||
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
||||
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
||||
top[FPSTR(_offOnly)] = m_offOnly;
|
||||
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
||||
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
||||
DEBUG_PRINTLN(F("PIR config saved."));
|
||||
}
|
||||
void addToConfig(JsonObject &root);
|
||||
|
||||
void appendConfigData()
|
||||
{
|
||||
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('PIRsensorSwitch:notifications',1,'Periodic WS updates');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
/**
|
||||
* provide UI information and allow extending UI options
|
||||
*/
|
||||
void appendConfigData();
|
||||
|
||||
/**
|
||||
* restore the changeable values
|
||||
@@ -443,72 +175,13 @@ public:
|
||||
*
|
||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||
*/
|
||||
bool readFromConfig(JsonObject &root)
|
||||
{
|
||||
bool oldEnabled = enabled;
|
||||
int8_t oldPin = PIRsensorPin;
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
PIRsensorPin = top["pin"] | PIRsensorPin;
|
||||
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
|
||||
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
||||
|
||||
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
||||
m_onPreset = max(0,min(250,(int)m_onPreset));
|
||||
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
||||
m_offPreset = max(0,min(250,(int)m_offPreset));
|
||||
|
||||
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
||||
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
||||
|
||||
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
||||
|
||||
if (!initDone) {
|
||||
// reading config prior to setup()
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
||||
// check if pin is OK
|
||||
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
||||
// if we are changing pin in settings page
|
||||
// deallocate old pin
|
||||
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
||||
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
} else {
|
||||
// allocation failed
|
||||
PIRsensorPin = -1;
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
if (enabled) {
|
||||
sensorPinState = digitalRead(PIRsensorPin);
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[FPSTR(_haDiscovery)].isNull();
|
||||
}
|
||||
bool readFromConfig(JsonObject &root);
|
||||
|
||||
/**
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_PIRSWITCH;
|
||||
}
|
||||
uint16_t getId() { return USERMOD_ID_PIRSWITCH; }
|
||||
};
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
@@ -522,3 +195,359 @@ const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
||||
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
||||
const char PIRsensorSwitch::_haDiscovery[] PROGMEM = "HA-discovery";
|
||||
const char PIRsensorSwitch::_notify[] PROGMEM = "notifications";
|
||||
const char PIRsensorSwitch::_override[] PROGMEM = "override";
|
||||
|
||||
bool PIRsensorSwitch::isDayTime() {
|
||||
updateLocalTime();
|
||||
uint8_t hr = hour(localTime);
|
||||
uint8_t mi = minute(localTime);
|
||||
|
||||
if (sunrise && sunset) {
|
||||
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
||||
return true;
|
||||
} else {
|
||||
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
||||
return true;
|
||||
}
|
||||
if (hour(sunset)==hr && minute(sunset)>mi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::switchStrip(bool switchOn)
|
||||
{
|
||||
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return; //if lights on and off only, do nothing
|
||||
if (PIRtriggered && switchOn) return; //if already on and triggered before, do nothing
|
||||
PIRtriggered = switchOn;
|
||||
DEBUG_PRINT(F("PIR: strip=")); DEBUG_PRINTLN(switchOn?"on":"off");
|
||||
if (switchOn) {
|
||||
if (m_onPreset) {
|
||||
if (currentPlaylist>0 && !offMode) {
|
||||
prevPlaylist = currentPlaylist;
|
||||
unloadPlaylist();
|
||||
} else if (currentPreset>0 && !offMode) {
|
||||
prevPreset = currentPreset;
|
||||
} else {
|
||||
saveTemporaryPreset();
|
||||
prevPlaylist = 0;
|
||||
prevPreset = 255;
|
||||
}
|
||||
applyPreset(m_onPreset, NotifyUpdateMode);
|
||||
return;
|
||||
}
|
||||
// preset not assigned
|
||||
if (bri == 0) {
|
||||
bri = briLast;
|
||||
stateUpdated(NotifyUpdateMode);
|
||||
}
|
||||
} else {
|
||||
if (m_offPreset) {
|
||||
applyPreset(m_offPreset, NotifyUpdateMode);
|
||||
return;
|
||||
} else if (prevPlaylist) {
|
||||
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode);
|
||||
prevPlaylist = 0;
|
||||
return;
|
||||
} else if (prevPreset) {
|
||||
if (prevPreset<255) { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPreset, NotifyUpdateMode); }
|
||||
else { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyTemporaryPreset(); }
|
||||
prevPreset = 0;
|
||||
return;
|
||||
}
|
||||
// preset not assigned
|
||||
if (bri != 0) {
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
stateUpdated(NotifyUpdateMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::publishMqtt(const char* state)
|
||||
{
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
char buf[64];
|
||||
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||
mqtt->publish(buf, 0, false, state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::publishHomeAssistantAutodiscovery()
|
||||
{
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
StaticJsonDocument<600> doc;
|
||||
char uid[24], json_str[1024], buf[128];
|
||||
|
||||
sprintf_P(buf, PSTR("%s Motion"), serverDescription); //max length: 33 + 7 = 40
|
||||
doc[F("name")] = buf;
|
||||
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||
doc[F("stat_t")] = buf;
|
||||
doc[F("pl_on")] = "on";
|
||||
doc[F("pl_off")] = "off";
|
||||
sprintf_P(uid, PSTR("%s_motion"), escapedMac.c_str());
|
||||
doc[F("uniq_id")] = uid;
|
||||
doc[F("dev_cla")] = F("motion");
|
||||
doc[F("exp_aft")] = 1800;
|
||||
|
||||
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||
device[F("name")] = serverDescription;
|
||||
device[F("ids")] = String(F("wled-sensor-")) + mqttClientID;
|
||||
device[F("mf")] = "WLED";
|
||||
device[F("mdl")] = F("FOSS");
|
||||
device[F("sw")] = versionString;
|
||||
|
||||
sprintf_P(buf, PSTR("homeassistant/binary_sensor/%s/config"), uid);
|
||||
DEBUG_PRINTLN(buf);
|
||||
size_t payload_size = serializeJson(doc, json_str);
|
||||
DEBUG_PRINTLN(json_str);
|
||||
|
||||
mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain?
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PIRsensorSwitch::updatePIRsensorState()
|
||||
{
|
||||
bool pinState = digitalRead(PIRsensorPin);
|
||||
if (pinState != sensorPinState) {
|
||||
sensorPinState = pinState; // change previous state
|
||||
|
||||
if (sensorPinState == HIGH) {
|
||||
offTimerStart = 0;
|
||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
||||
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||
publishMqtt("on");
|
||||
} else {
|
||||
// start switch off timer
|
||||
offTimerStart = millis();
|
||||
if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PIRsensorSwitch::handleOffTimer()
|
||||
{
|
||||
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
||||
offTimerStart = 0;
|
||||
if (enabled == true) {
|
||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()) || PIRtriggered)) switchStrip(false);
|
||||
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||
publishMqtt("off");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//Functions called by WLED
|
||||
|
||||
void PIRsensorSwitch::setup()
|
||||
{
|
||||
if (enabled) {
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
sensorPinState = digitalRead(PIRsensorPin);
|
||||
} else {
|
||||
if (PIRsensorPin >= 0) {
|
||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||
}
|
||||
PIRsensorPin = -1; // allocation failed
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
if (HomeAssistantDiscovery) {
|
||||
publishHomeAssistantAutodiscovery();
|
||||
}
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::loop()
|
||||
{
|
||||
// only check sensors 4x/s
|
||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||
lastLoop = millis();
|
||||
|
||||
if (!updatePIRsensorState()) {
|
||||
handleOffTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
|
||||
|
||||
String uiDomString;
|
||||
if (enabled) {
|
||||
if (offTimerStart > 0)
|
||||
{
|
||||
uiDomString = "";
|
||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - offTimerStart)) / 1000;
|
||||
if (offSeconds >= 3600)
|
||||
{
|
||||
uiDomString += (offSeconds / 3600);
|
||||
uiDomString += F("h ");
|
||||
offSeconds %= 3600;
|
||||
}
|
||||
if (offSeconds >= 60)
|
||||
{
|
||||
uiDomString += (offSeconds / 60);
|
||||
offSeconds %= 60;
|
||||
}
|
||||
else if (uiDomString.length() > 0)
|
||||
{
|
||||
uiDomString += 0;
|
||||
}
|
||||
if (uiDomString.length() > 0)
|
||||
{
|
||||
uiDomString += F("min ");
|
||||
}
|
||||
uiDomString += (offSeconds);
|
||||
infoArr.add(uiDomString + F("s"));
|
||||
} else {
|
||||
infoArr.add(sensorPinState ? F("sensor on") : F("inactive"));
|
||||
}
|
||||
} else {
|
||||
infoArr.add(F("disabled"));
|
||||
}
|
||||
|
||||
uiDomString = F(" <button class=\"btn btn-xs\" onclick=\"requestJson({");
|
||||
uiDomString += FPSTR(_name);
|
||||
uiDomString += F(":{");
|
||||
uiDomString += FPSTR(_enabled);
|
||||
if (enabled) {
|
||||
uiDomString += F(":false}});\">");
|
||||
uiDomString += F("<i class=\"icons on\"></i>");
|
||||
} else {
|
||||
uiDomString += F(":true}});\">");
|
||||
uiDomString += F("<i class=\"icons off\"></i>");
|
||||
}
|
||||
uiDomString += F("</button>");
|
||||
infoArr.add(uiDomString);
|
||||
|
||||
JsonObject sensor = root[F("sensor")];
|
||||
if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
|
||||
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::onStateChange(uint8_t mode) {
|
||||
if (!initDone) return;
|
||||
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
||||
if (m_override && PIRtriggered && offTimerStart) { // debounce
|
||||
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
||||
DEBUG_PRINTLN(F("PIR: Canceled."));
|
||||
offTimerStart = 0;
|
||||
PIRtriggered = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::readFromJsonState(JsonObject &root)
|
||||
{
|
||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||
JsonObject usermod = root[FPSTR(_name)];
|
||||
if (!usermod.isNull()) {
|
||||
if (usermod[FPSTR(_enabled)].is<bool>()) {
|
||||
enabled = usermod[FPSTR(_enabled)].as<bool>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::addToConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
top[FPSTR(_enabled)] = enabled;
|
||||
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
||||
top["pin"] = PIRsensorPin;
|
||||
top[FPSTR(_onPreset)] = m_onPreset;
|
||||
top[FPSTR(_offPreset)] = m_offPreset;
|
||||
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
||||
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
||||
top[FPSTR(_offOnly)] = m_offOnly;
|
||||
top[FPSTR(_override)] = m_override;
|
||||
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
||||
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
||||
DEBUG_PRINTLN(F("PIR config saved."));
|
||||
}
|
||||
|
||||
void PIRsensorSwitch::appendConfigData()
|
||||
{
|
||||
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('PIRsensorSwitch:notifications',1,'Periodic WS updates');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
|
||||
bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
||||
{
|
||||
bool oldEnabled = enabled;
|
||||
int8_t oldPin = PIRsensorPin;
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
PIRsensorPin = top["pin"] | PIRsensorPin;
|
||||
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
|
||||
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
||||
|
||||
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
||||
m_onPreset = max(0,min(250,(int)m_onPreset));
|
||||
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
||||
m_offPreset = max(0,min(250,(int)m_offPreset));
|
||||
|
||||
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
||||
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||
m_override = top[FPSTR(_override)] | m_override;
|
||||
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
||||
|
||||
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
||||
|
||||
if (!initDone) {
|
||||
// reading config prior to setup()
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
||||
// check if pin is OK
|
||||
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
||||
// if we are changing pin in settings page
|
||||
// deallocate old pin
|
||||
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
||||
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
} else {
|
||||
// allocation failed
|
||||
PIRsensorPin = -1;
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
if (enabled) {
|
||||
sensorPinState = digitalRead(PIRsensorPin);
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[FPSTR(_override)].isNull();
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ class RTCUsermod : public Usermod {
|
||||
public:
|
||||
|
||||
void setup() {
|
||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { disabled = true; return; }
|
||||
if (i2c_scl<0 || i2c_sda<0) { disabled = true; return; }
|
||||
RTC.begin();
|
||||
time_t rtcTime = RTC.get();
|
||||
if (rtcTime) {
|
||||
@@ -25,8 +24,8 @@ class RTCUsermod : public Usermod {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (strip.isUpdating()) return;
|
||||
if (!disabled && toki.isTick()) {
|
||||
if (disabled || strip.isUpdating()) return;
|
||||
if (toki.isTick()) {
|
||||
time_t t = toki.second();
|
||||
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
|
||||
}
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
#ifndef TFT_HEIGHT
|
||||
#error Please define TFT_HEIGHT
|
||||
#endif
|
||||
#ifndef TFT_MOSI
|
||||
#error Please define TFT_MOSI
|
||||
#endif
|
||||
#ifndef TFT_SCLK
|
||||
#error Please define TFT_SCLK
|
||||
#endif
|
||||
#ifndef TFT_DC
|
||||
#error Please define TFT_DC
|
||||
#endif
|
||||
@@ -140,8 +134,14 @@ class St7789DisplayUsermod : public Usermod {
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
PinManagerPinType pins[] = { { TFT_MOSI, true }, { TFT_MISO, false}, { TFT_SCLK, true }, { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
||||
if (!pinManager.allocateMultiplePins(pins, 7, PinOwner::UM_FourLineDisplay)) { enabled = false; return; }
|
||||
PinManagerPinType spiPins[] = { { spi_mosi, true }, { spi_miso, false}, { spi_sclk, true } };
|
||||
if (!pinManager.allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) { enabled = false; return; }
|
||||
PinManagerPinType displayPins[] = { { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
||||
if (!pinManager.allocateMultiplePins(displayPins, sizeof(displayPins)/sizeof(PinManagerPinType), PinOwner::UM_FourLineDisplay)) {
|
||||
pinManager.deallocateMultiplePins(spiPins, 3, PinOwner::HW_SPI);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
tft.init();
|
||||
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
|
||||
@@ -365,9 +365,6 @@ class St7789DisplayUsermod : public Usermod {
|
||||
{
|
||||
JsonObject top = root.createNestedObject("ST7789");
|
||||
JsonArray pins = top.createNestedArray("pin");
|
||||
pins.add(TFT_MOSI);
|
||||
pins.add(TFT_MISO);
|
||||
pins.add(TFT_SCLK);
|
||||
pins.add(TFT_CS);
|
||||
pins.add(TFT_DC);
|
||||
pins.add(TFT_RST);
|
||||
@@ -376,6 +373,13 @@ class St7789DisplayUsermod : public Usermod {
|
||||
}
|
||||
|
||||
|
||||
void appendConfigData() {
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI BL');"));
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
|
||||
Adafruit_Si7021 si7021;
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
#else //ESP8266 boards
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
#endif
|
||||
|
||||
class Si7021_MQTT_HA : public Usermod
|
||||
{
|
||||
private:
|
||||
@@ -184,7 +176,6 @@ class Si7021_MQTT_HA : public Usermod
|
||||
{
|
||||
if (enabled) {
|
||||
Serial.println("Si7021_MQTT_HA: Starting!");
|
||||
Wire.begin(SDA_PIN, SCL_PIN);
|
||||
Serial.println("Si7021_MQTT_HA: Initializing sensors.. ");
|
||||
_initializeSensor();
|
||||
}
|
||||
|
||||
@@ -50,9 +50,7 @@ class UsermodVL53L0XGestures : public Usermod {
|
||||
public:
|
||||
|
||||
void setup() {
|
||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
||||
Wire.begin();
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
|
||||
sensor.setTimeout(150);
|
||||
if (!sensor.init())
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
* ....
|
||||
*/
|
||||
|
||||
#if !defined(FFTTASK_PRIORITY)
|
||||
#define FFTTASK_PRIORITY 1 // standard: looptask prio
|
||||
//#define FFTTASK_PRIORITY 2 // above looptask, below asyc_tcp
|
||||
//#define FFTTASK_PRIORITY 4 // above asyc_tcp
|
||||
#endif
|
||||
|
||||
// Comment/Uncomment to toggle usb serial debugging
|
||||
// #define MIC_LOGGER // MIC sampling & sound input debugging (serial plotter)
|
||||
// #define FFT_SAMPLING_LOG // FFT result debugging
|
||||
@@ -104,7 +110,7 @@ static float sampleAgc = 0.0f; // Smoothed AGC sample
|
||||
|
||||
// peak detection
|
||||
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
|
||||
static uint8_t maxVol = 10; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
|
||||
static uint8_t maxVol = 31; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
|
||||
static uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated)
|
||||
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
|
||||
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
|
||||
@@ -173,13 +179,18 @@ static float windowWeighingFactors[samplesFFT] = {0.0f};
|
||||
|
||||
// Create FFT object
|
||||
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
|
||||
// lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2
|
||||
#define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc), and an a few other speedups
|
||||
#define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt
|
||||
#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 50% on ESP32 (as alternative to FFT_SQRT_APPROXIMATION)
|
||||
// lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2
|
||||
// these options actually cause slow-downs on all esp32 processors, don't use them.
|
||||
// #define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc) - not faster on ESP32
|
||||
// #define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt - slower on ESP32
|
||||
// Below options are forcing ArduinoFFT to use sqrtf() instead of sqrt()
|
||||
#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 10-50% on ESP32
|
||||
#define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83
|
||||
#else
|
||||
// lib_deps += https://github.com/blazoncek/arduinoFFT.git
|
||||
// around 40% slower on -S2
|
||||
// lib_deps += https://github.com/blazoncek/arduinoFFT.git
|
||||
#endif
|
||||
|
||||
#include <arduinoFFT.h>
|
||||
|
||||
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
|
||||
@@ -411,7 +422,7 @@ static void runMicFilter(uint16_t numSamples, float *sampleBuffer) // p
|
||||
//constexpr float beta1 = 0.8285f; // 18Khz
|
||||
constexpr float beta1 = 0.85f; // 20Khz
|
||||
|
||||
constexpr float beta2 = (1.0f - beta1) / 2.0;
|
||||
constexpr float beta2 = (1.0f - beta1) / 2.0f;
|
||||
static float last_vals[2] = { 0.0f }; // FIR high freq cutoff filter
|
||||
static float lowfilt = 0.0f; // IIR low frequency cutoff filter
|
||||
|
||||
@@ -464,17 +475,17 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels) // p
|
||||
switch (FFTScalingMode) {
|
||||
case 1:
|
||||
// Logarithmic scaling
|
||||
currentResult *= 0.42; // 42 is the answer ;-)
|
||||
currentResult -= 8.0; // this skips the lowest row, giving some room for peaks
|
||||
if (currentResult > 1.0) currentResult = logf(currentResult); // log to base "e", which is the fastest log() function
|
||||
else currentResult = 0.0; // special handling, because log(1) = 0; log(0) = undefined
|
||||
currentResult *= 0.42f; // 42 is the answer ;-)
|
||||
currentResult -= 8.0f; // this skips the lowest row, giving some room for peaks
|
||||
if (currentResult > 1.0f) currentResult = logf(currentResult); // log to base "e", which is the fastest log() function
|
||||
else currentResult = 0.0f; // special handling, because log(1) = 0; log(0) = undefined
|
||||
currentResult *= 0.85f + (float(i)/18.0f); // extra up-scaling for high frequencies
|
||||
currentResult = mapf(currentResult, 0, LOG_256, 0, 255); // map [log(1) ... log(255)] to [0 ... 255]
|
||||
break;
|
||||
case 2:
|
||||
// Linear scaling
|
||||
currentResult *= 0.30f; // needs a bit more damping, get stay below 255
|
||||
currentResult -= 4.0; // giving a bit more room for peaks
|
||||
currentResult -= 4.0f; // giving a bit more room for peaks
|
||||
if (currentResult < 1.0f) currentResult = 0.0f;
|
||||
currentResult *= 0.85f + (float(i)/1.8f); // extra up-scaling for high frequencies
|
||||
break;
|
||||
@@ -482,8 +493,8 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels) // p
|
||||
// square root scaling
|
||||
currentResult *= 0.38f;
|
||||
currentResult -= 6.0f;
|
||||
if (currentResult > 1.0) currentResult = sqrtf(currentResult);
|
||||
else currentResult = 0.0; // special handling, because sqrt(0) = undefined
|
||||
if (currentResult > 1.0f) currentResult = sqrtf(currentResult);
|
||||
else currentResult = 0.0f; // special handling, because sqrt(0) = undefined
|
||||
currentResult *= 0.85f + (float(i)/4.5f); // extra up-scaling for high frequencies
|
||||
currentResult = mapf(currentResult, 0.0, 16.0, 0.0, 255.0); // map [sqrt(1) ... sqrt(256)] to [0 ... 255]
|
||||
break;
|
||||
@@ -511,11 +522,11 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels) // p
|
||||
// peak detection is called from FFT task when vReal[] contains valid FFT results
|
||||
static void detectSamplePeak(void) {
|
||||
bool havePeak = false;
|
||||
|
||||
// softhack007: this code continuously triggers while amplitude in the selected bin is above a certain threshold. So it does not detect peaks - it detects high activity in a frequency bin.
|
||||
// Poor man's beat detection by seeing if sample > Average + some value.
|
||||
// This goes through ALL of the 255 bins - but ignores stupid settings
|
||||
// Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync.
|
||||
if ((sampleAvg > 1) && (maxVol > 0) && (binNum > 1) && (vReal[binNum] > maxVol) && ((millis() - timeOfPeak) > 100)) {
|
||||
if ((sampleAvg > 1) && (maxVol > 0) && (binNum > 4) && (vReal[binNum] > maxVol) && ((millis() - timeOfPeak) > 100)) {
|
||||
havePeak = true;
|
||||
}
|
||||
|
||||
@@ -569,16 +580,6 @@ class AudioReactive : public Usermod {
|
||||
#else
|
||||
int8_t i2sckPin = I2S_CKPIN;
|
||||
#endif
|
||||
#ifndef ES7243_SDAPIN
|
||||
int8_t sdaPin = -1;
|
||||
#else
|
||||
int8_t sdaPin = ES7243_SDAPIN;
|
||||
#endif
|
||||
#ifndef ES7243_SCLPIN
|
||||
int8_t sclPin = -1;
|
||||
#else
|
||||
int8_t sclPin = ES7243_SCLPIN;
|
||||
#endif
|
||||
#ifndef MCLK_PIN
|
||||
int8_t mclkPin = I2S_PIN_NO_CHANGE; /* ESP32: only -1, 0, 1, 3 allowed*/
|
||||
#else
|
||||
@@ -768,7 +769,7 @@ class AudioReactive : public Usermod {
|
||||
if (time_now - last_time > 2) {
|
||||
last_time = time_now;
|
||||
|
||||
if((fabsf(sampleReal) < 2.0f) || (sampleMax < 1.0f)) {
|
||||
if((fabsf(sampleReal) < 2.0f) || (sampleMax < 1.0)) {
|
||||
// MIC signal is "squelched" - deliver silence
|
||||
tmpAgc = 0;
|
||||
// we need to "spin down" the intgrated error buffer
|
||||
@@ -883,8 +884,8 @@ class AudioReactive : public Usermod {
|
||||
// keep "peak" sample, but decay value if current sample is below peak
|
||||
if ((sampleMax < sampleReal) && (sampleReal > 0.5f)) {
|
||||
sampleMax = sampleMax + 0.5f * (sampleReal - sampleMax); // new peak - with some filtering
|
||||
// another simple way to detect samplePeak
|
||||
if ((binNum < 10) && (millis() - timeOfPeak > 80) && (sampleAvg > 1)) {
|
||||
// another simple way to detect samplePeak - cannot detect beats, but reacts on peak volume
|
||||
if (((binNum < 12) || ((maxVol < 1))) && (millis() - timeOfPeak > 80) && (sampleAvg > 1)) {
|
||||
samplePeak = true;
|
||||
timeOfPeak = millis();
|
||||
udpSamplePeak = true;
|
||||
@@ -974,9 +975,10 @@ class AudioReactive : public Usermod {
|
||||
transmitData.FFT_Magnitude = my_magnitude;
|
||||
transmitData.FFT_MajorPeak = FFT_MajorPeak;
|
||||
|
||||
fftUdp.beginMulticastPacket();
|
||||
fftUdp.write(reinterpret_cast<uint8_t *>(&transmitData), sizeof(transmitData));
|
||||
fftUdp.endPacket();
|
||||
if (fftUdp.beginMulticastPacket() != 0) { // beginMulticastPacket returns 0 in case of error
|
||||
fftUdp.write(reinterpret_cast<uint8_t *>(&transmitData), sizeof(transmitData));
|
||||
fftUdp.endPacket();
|
||||
}
|
||||
return;
|
||||
} // transmitAudioData()
|
||||
|
||||
@@ -1136,7 +1138,7 @@ class AudioReactive : public Usermod {
|
||||
DEBUGSR_PRINTLN(F("AR: ES7243 Microphone (right channel only)."));
|
||||
audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE);
|
||||
delay(100);
|
||||
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
break;
|
||||
case 3:
|
||||
DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
|
||||
@@ -1159,6 +1161,13 @@ class AudioReactive : public Usermod {
|
||||
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin);
|
||||
break;
|
||||
#endif
|
||||
case 6:
|
||||
DEBUGSR_PRINTLN(F("AR: ES8388 Source"));
|
||||
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE);
|
||||
delay(100);
|
||||
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
break;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// ADC over I2S is only possible on "classic" ESP32
|
||||
case 0:
|
||||
@@ -1275,9 +1284,10 @@ class AudioReactive : public Usermod {
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
// complain when audio userloop has been delayed for long time. Currently we need userloop running between 500 and 1500 times per second.
|
||||
if ((userloopDelay > 23) && !disableSoundProcessing && (audioSyncEnabled == 0)) {
|
||||
DEBUG_PRINTF("[AR userLoop] hickup detected -> was inactive for last %d millis!\n", userloopDelay);
|
||||
}
|
||||
// softhack007 disabled temporarily - avoid serial console spam with MANY leds and low FPS
|
||||
//if ((userloopDelay > 65) && !disableSoundProcessing && (audioSyncEnabled == 0)) {
|
||||
//DEBUG_PRINTF("[AR userLoop] hickup detected -> was inactive for last %d millis!\n", userloopDelay);
|
||||
//}
|
||||
#endif
|
||||
|
||||
// run filters, and repeat in case of loop delays (hick-up compensation)
|
||||
@@ -1314,6 +1324,9 @@ class AudioReactive : public Usermod {
|
||||
if (millis() - lastTime > delayMs) {
|
||||
have_new_sample = receiveAudioData();
|
||||
if (have_new_sample) last_UDPTime = millis();
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
else fftUdp.flush(); // Flush udp input buffers if we haven't read it - avoids hickups in receive mode. Does not work on 8266.
|
||||
#endif
|
||||
lastTime = millis();
|
||||
}
|
||||
if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample
|
||||
@@ -1332,7 +1345,7 @@ class AudioReactive : public Usermod {
|
||||
// Info Page: keep max sample from last 5 seconds
|
||||
if ((millis() - sampleMaxTimer) > CYCLE_SAMPLEMAX) {
|
||||
sampleMaxTimer = millis();
|
||||
maxSample5sec = (0.15 * maxSample5sec) + 0.85 *((soundAgc) ? sampleAgc : sampleAvg); // reset, and start with some smoothing
|
||||
maxSample5sec = (0.15f * maxSample5sec) + 0.85f *((soundAgc) ? sampleAgc : sampleAvg); // reset, and start with some smoothing
|
||||
if (sampleAvg < 1) maxSample5sec = 0; // noise gate
|
||||
} else {
|
||||
if ((sampleAvg >= 1)) maxSample5sec = fmaxf(maxSample5sec, (soundAgc) ? rawSampleAgc : sampleRaw); // follow maximum volume
|
||||
@@ -1376,10 +1389,11 @@ class AudioReactive : public Usermod {
|
||||
memset(fftAvg, 0, sizeof(fftAvg));
|
||||
memset(fftResult, 0, sizeof(fftResult));
|
||||
for(int i=(init?0:1); i<NUM_GEQ_CHANNELS; i+=2) fftResult[i] = 16; // make a tiny pattern
|
||||
inputLevel = 128; // resset level slider to default
|
||||
inputLevel = 128; // reset level slider to default
|
||||
autoResetPeak();
|
||||
|
||||
if (init && FFT_Task) {
|
||||
delay(25); // give some time for I2S driver to finish sampling before we suspend it
|
||||
vTaskSuspend(FFT_Task); // update is about to begin, disable task to prevent crash
|
||||
if (udpSyncConnected) { // close UDP sync connection (if open)
|
||||
udpSyncConnected = false;
|
||||
@@ -1391,15 +1405,14 @@ class AudioReactive : public Usermod {
|
||||
vTaskResume(FFT_Task);
|
||||
connected(); // resume UDP
|
||||
} else
|
||||
// xTaskCreatePinnedToCore(
|
||||
xTaskCreate( // no need to "pin" this task to core #0
|
||||
xTaskCreateUniversal( // xTaskCreateUniversal also works on -S2 and -C3 with single core
|
||||
FFTcode, // Function to implement the task
|
||||
"FFT", // Name of the task
|
||||
5000, // Stack size in words
|
||||
NULL, // Task input parameter
|
||||
1, // Priority of the task
|
||||
FFTTASK_PRIORITY, // Priority of the task
|
||||
&FFT_Task // Task handle
|
||||
// , 0 // Core where the task should run
|
||||
, 0 // Core where the task should run
|
||||
);
|
||||
}
|
||||
micDataReal = 0.0f; // just to be sure
|
||||
@@ -1496,7 +1509,7 @@ class AudioReactive : public Usermod {
|
||||
infoArr.add(F("I2S digital"));
|
||||
}
|
||||
// input level or "silence"
|
||||
if (maxSample5sec > 1.0) {
|
||||
if (maxSample5sec > 1.0f) {
|
||||
float my_usage = 100.0f * (maxSample5sec / 255.0f);
|
||||
snprintf_P(myStringBuffer, 15, PSTR(" - peak %3d%%"), int(my_usage));
|
||||
infoArr.add(myStringBuffer);
|
||||
@@ -1506,7 +1519,7 @@ class AudioReactive : public Usermod {
|
||||
} else {
|
||||
// error during audio source setup
|
||||
infoArr.add(F("not initialized"));
|
||||
infoArr.add(F(" - check GPIO config"));
|
||||
infoArr.add(F(" - check pin settings"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1657,8 +1670,6 @@ class AudioReactive : public Usermod {
|
||||
pinArray.add(i2swsPin);
|
||||
pinArray.add(i2sckPin);
|
||||
pinArray.add(mclkPin);
|
||||
pinArray.add(sdaPin);
|
||||
pinArray.add(sclPin);
|
||||
|
||||
JsonObject cfg = top.createNestedObject("config");
|
||||
cfg[F("squelch")] = soundSquelch;
|
||||
@@ -1719,8 +1730,6 @@ class AudioReactive : public Usermod {
|
||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][1], i2swsPin);
|
||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][2], i2sckPin);
|
||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][3], mclkPin);
|
||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][4], sdaPin);
|
||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][5], sclPin);
|
||||
|
||||
configComplete &= getJsonValue(top["config"][F("squelch")], soundSquelch);
|
||||
configComplete &= getJsonValue(top["config"][F("gain")], sampleGain);
|
||||
@@ -1752,6 +1761,8 @@ class AudioReactive : public Usermod {
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
oappend(SET_F("addOption(dd,'Generic I2S PDM',5);"));
|
||||
#endif
|
||||
oappend(SET_F("addOption(dd,'ES8388',6);"));
|
||||
|
||||
oappend(SET_F("dd=addDropdown('AudioReactive','config:AGC');"));
|
||||
oappend(SET_F("addOption(dd,'Off',0);"));
|
||||
oappend(SET_F("addOption(dd,'Normal',1);"));
|
||||
@@ -1784,8 +1795,6 @@ class AudioReactive : public Usermod {
|
||||
#else
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>master clock</i>','I2S MCLK');"));
|
||||
#endif
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',4,'','I2C SDA');"));
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',5,'','I2C SCL');"));
|
||||
}
|
||||
|
||||
|
||||
@@ -1814,7 +1823,9 @@ class AudioReactive : public Usermod {
|
||||
const char AudioReactive::_name[] PROGMEM = "AudioReactive";
|
||||
const char AudioReactive::_enabled[] PROGMEM = "enabled";
|
||||
const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel";
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
const char AudioReactive::_analogmic[] PROGMEM = "analogmic";
|
||||
#endif
|
||||
const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic";
|
||||
const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00002"; // new sync header version, as format no longer compatible with previous structure
|
||||
const char AudioReactive::UDP_SYNC_HEADER_v1[] PROGMEM = "00001"; // old sync header version - need to add backwards-compatibility feature
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Wire.h>
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "wled.h"
|
||||
#include <driver/i2s.h>
|
||||
#include <driver/adc.h>
|
||||
@@ -23,14 +22,14 @@
|
||||
|
||||
// see https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/chip-series-comparison.html#related-documents
|
||||
// and https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#overview-of-all-modes
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(ESP8266) || defined(ESP8265)
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(ESP8266) || defined(ESP8265)
|
||||
// there are two things in these MCUs that could lead to problems with audio processing:
|
||||
// * no floating point hardware (FPU) support - FFT uses float calculations. If done in software, a strong slow-down can be expected (between 8x and 20x)
|
||||
// * single core, so FFT task might slow down other things like LED updates
|
||||
#if !defined(SOC_I2S_NUM) || (SOC_I2S_NUM < 1)
|
||||
#error This audio reactive usermod does not support ESP32-C2, ESP32-C3 or ESP32-S2.
|
||||
#error This audio reactive usermod does not support ESP32-C2 or ESP32-C3.
|
||||
#else
|
||||
#warning This audio reactive usermod does not support ESP32-C2, ESP32-C3 or ESP32-S2.
|
||||
#warning This audio reactive usermod does not support ESP32-C2 and ESP32-C3.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -72,7 +71,7 @@
|
||||
* if you want to receive two channels, one is the actual data from microphone and another channel is suppose to receive 0, it's different data in two channels, you need to choose I2S_CHANNEL_FMT_RIGHT_LEFT in this case.
|
||||
*/
|
||||
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 4, 3))
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 4, 4))
|
||||
// espressif bug: only_left has no sound, left and right are swapped
|
||||
// https://github.com/espressif/esp-idf/issues/9635 I2S mic not working since 4.4 (IDFGH-8138)
|
||||
// https://github.com/espressif/esp-idf/issues/8538 I2S channel selection issue? (IDFGH-6918)
|
||||
@@ -383,21 +382,12 @@ class I2SSource : public AudioSource {
|
||||
*/
|
||||
class ES7243 : public I2SSource {
|
||||
private:
|
||||
// I2C initialization functions for ES7243
|
||||
void _es7243I2cBegin() {
|
||||
bool i2c_initialized = Wire.begin(pin_ES7243_SDA, pin_ES7243_SCL, 100000U);
|
||||
if (i2c_initialized == false) {
|
||||
DEBUGSR_PRINTLN(F("AR: ES7243 failed to initialize I2C bus driver."));
|
||||
}
|
||||
}
|
||||
|
||||
void _es7243I2cWrite(uint8_t reg, uint8_t val) {
|
||||
#ifndef ES7243_ADDR
|
||||
Wire.beginTransmission(0x13);
|
||||
#define ES7243_ADDR 0x13 // default address
|
||||
#else
|
||||
#ifndef ES7243_ADDR
|
||||
#define ES7243_ADDR 0x13 // default address
|
||||
#endif
|
||||
Wire.beginTransmission(ES7243_ADDR);
|
||||
#endif
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)val);
|
||||
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
|
||||
@@ -407,7 +397,6 @@ class ES7243 : public I2SSource {
|
||||
}
|
||||
|
||||
void _es7243InitAdc() {
|
||||
_es7243I2cBegin();
|
||||
_es7243I2cWrite(0x00, 0x01);
|
||||
_es7243I2cWrite(0x06, 0x00);
|
||||
_es7243I2cWrite(0x05, 0x1B);
|
||||
@@ -422,47 +411,139 @@ public:
|
||||
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
||||
};
|
||||
|
||||
void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
|
||||
// check that pins are valid
|
||||
if ((sdaPin < 0) || (sclPin < 0)) {
|
||||
DEBUGSR_PRINTF("\nAR: invalid ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
|
||||
return;
|
||||
}
|
||||
|
||||
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
|
||||
if ((i2sckPin < 0) || (mclkPin < 0)) {
|
||||
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reserve SDA and SCL pins of the I2C interface
|
||||
PinManagerPinType es7243Pins[2] = { { sdaPin, true }, { sclPin, true } };
|
||||
if (!pinManager.allocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C)) {
|
||||
pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C);
|
||||
DEBUGSR_PRINTF("\nAR: Failed to allocate ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
|
||||
return;
|
||||
}
|
||||
|
||||
pin_ES7243_SDA = sdaPin;
|
||||
pin_ES7243_SCL = sclPin;
|
||||
|
||||
// First route mclk, then configure ADC over I2C, then configure I2S
|
||||
_es7243InitAdc();
|
||||
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
}
|
||||
|
||||
void deinitialize() {
|
||||
// Release SDA and SCL pins of the I2C interface
|
||||
PinManagerPinType es7243Pins[2] = { { pin_ES7243_SDA, true }, { pin_ES7243_SCL, true } };
|
||||
pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C);
|
||||
I2SSource::deinitialize();
|
||||
}
|
||||
};
|
||||
|
||||
/* ES8388 Sound Modude
|
||||
This is an I2S sound processing unit that requires ininitialization over
|
||||
I2C before I2S data can be received.
|
||||
*/
|
||||
class ES8388Source : public I2SSource {
|
||||
private:
|
||||
|
||||
void _es8388I2cWrite(uint8_t reg, uint8_t val) {
|
||||
#ifndef ES8388_ADDR
|
||||
Wire.beginTransmission(0x10);
|
||||
#define ES8388_ADDR 0x10 // default address
|
||||
#else
|
||||
Wire.beginTransmission(ES8388_ADDR);
|
||||
#endif
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)val);
|
||||
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
|
||||
if (i2cErr != 0) {
|
||||
DEBUGSR_PRINTF("AR: ES8388 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X).\n", i2cErr, ES8388_ADDR, reg, val);
|
||||
}
|
||||
}
|
||||
|
||||
void _es8388InitAdc() {
|
||||
// https://dl.radxa.com/rock2/docs/hw/ds/ES8388%20user%20Guide.pdf Section 10.1
|
||||
// http://www.everest-semi.com/pdf/ES8388%20DS.pdf Better spec sheet, more clear.
|
||||
// https://docs.google.com/spreadsheets/d/1CN3MvhkcPVESuxKyx1xRYqfUit5hOdsG45St9BCUm-g/edit#gid=0 generally
|
||||
// Sets ADC to around what AudioReactive expects, and loops line-in to line-out/headphone for monitoring.
|
||||
// Registries are decimal, settings are binary as that's how everything is listed in the docs
|
||||
// ...which makes it easier to reference the docs.
|
||||
//
|
||||
_es8388I2cWrite( 8,0b00000000); // I2S to slave
|
||||
_es8388I2cWrite( 2,0b11110011); // Power down DEM and STM
|
||||
_es8388I2cWrite(43,0b10000000); // Set same LRCK
|
||||
_es8388I2cWrite( 0,0b00000101); // Set chip to Play & Record Mode
|
||||
_es8388I2cWrite(13,0b00000010); // Set MCLK/LRCK ratio to 256
|
||||
_es8388I2cWrite( 1,0b01000000); // Power up analog and lbias
|
||||
_es8388I2cWrite( 3,0b00000000); // Power up ADC, Analog Input, and Mic Bias
|
||||
_es8388I2cWrite( 4,0b11111100); // Power down DAC, Turn on LOUT1 and ROUT1 and LOUT2 and ROUT2 power
|
||||
_es8388I2cWrite( 2,0b01000000); // Power up DEM and STM and undocumented bit for "turn on line-out amp"
|
||||
|
||||
// #define use_es8388_mic
|
||||
|
||||
#ifdef use_es8388_mic
|
||||
// The mics *and* line-in are BOTH connected to LIN2/RIN2 on the AudioKit
|
||||
// so there's no way to completely eliminate the mics. It's also hella noisy.
|
||||
// Line-in works OK on the AudioKit, generally speaking, as the mics really need
|
||||
// amplification to be noticable in a quiet room. If you're in a very loud room,
|
||||
// the mics on the AudioKit WILL pick up sound even in line-in mode.
|
||||
// TL;DR: Don't use the AudioKit for anything, use the LyraT.
|
||||
//
|
||||
// The LyraT does a reasonable job with mic input as configured below.
|
||||
|
||||
// Pick one of these. If you have to use the mics, use a LyraT over an AudioKit if you can:
|
||||
_es8388I2cWrite(10,0b00000000); // Use Lin1/Rin1 for ADC input (mic on LyraT)
|
||||
//_es8388I2cWrite(10,0b01010000); // Use Lin2/Rin2 for ADC input (mic *and* line-in on AudioKit)
|
||||
|
||||
_es8388I2cWrite( 9,0b10001000); // Select Analog Input PGA Gain for ADC to +24dB (L+R)
|
||||
_es8388I2cWrite(16,0b00000000); // Set ADC digital volume attenuation to 0dB (left)
|
||||
_es8388I2cWrite(17,0b00000000); // Set ADC digital volume attenuation to 0dB (right)
|
||||
_es8388I2cWrite(38,0b00011011); // Mixer - route LIN1/RIN1 to output after mic gain
|
||||
|
||||
_es8388I2cWrite(39,0b01000000); // Mixer - route LIN to mixL, +6dB gain
|
||||
_es8388I2cWrite(42,0b01000000); // Mixer - route RIN to mixR, +6dB gain
|
||||
_es8388I2cWrite(46,0b00100001); // LOUT1VOL - 0b00100001 = +4.5dB
|
||||
_es8388I2cWrite(47,0b00100001); // ROUT1VOL - 0b00100001 = +4.5dB
|
||||
_es8388I2cWrite(48,0b00100001); // LOUT2VOL - 0b00100001 = +4.5dB
|
||||
_es8388I2cWrite(49,0b00100001); // ROUT2VOL - 0b00100001 = +4.5dB
|
||||
|
||||
// Music ALC - the mics like Auto Level Control
|
||||
// You can also use this for line-in, but it's not really needed.
|
||||
//
|
||||
_es8388I2cWrite(18,0b11111000); // ALC: stereo, max gain +35.5dB, min gain -12dB
|
||||
_es8388I2cWrite(19,0b00110000); // ALC: target -1.5dB, 0ms hold time
|
||||
_es8388I2cWrite(20,0b10100110); // ALC: gain ramp up = 420ms/93ms, gain ramp down = check manual for calc
|
||||
_es8388I2cWrite(21,0b00000110); // ALC: use "ALC" mode, no zero-cross, window 96 samples
|
||||
_es8388I2cWrite(22,0b01011001); // ALC: noise gate threshold, PGA gain constant, noise gate enabled
|
||||
#else
|
||||
_es8388I2cWrite(10,0b01010000); // Use Lin2/Rin2 for ADC input ("line-in")
|
||||
_es8388I2cWrite( 9,0b00000000); // Select Analog Input PGA Gain for ADC to 0dB (L+R)
|
||||
_es8388I2cWrite(16,0b01000000); // Set ADC digital volume attenuation to -32dB (left)
|
||||
_es8388I2cWrite(17,0b01000000); // Set ADC digital volume attenuation to -32dB (right)
|
||||
_es8388I2cWrite(38,0b00001001); // Mixer - route LIN2/RIN2 to output
|
||||
|
||||
_es8388I2cWrite(39,0b01010000); // Mixer - route LIN to mixL, 0dB gain
|
||||
_es8388I2cWrite(42,0b01010000); // Mixer - route RIN to mixR, 0dB gain
|
||||
_es8388I2cWrite(46,0b00011011); // LOUT1VOL - 0b00011110 = +0dB, 0b00011011 = LyraT balance fix
|
||||
_es8388I2cWrite(47,0b00011110); // ROUT1VOL - 0b00011110 = +0dB
|
||||
_es8388I2cWrite(48,0b00011110); // LOUT2VOL - 0b00011110 = +0dB
|
||||
_es8388I2cWrite(49,0b00011110); // ROUT2VOL - 0b00011110 = +0dB
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
ES8388Source(SRate_t sampleRate, int blockSize, float sampleScale = 1.0f, bool i2sMaster=true) :
|
||||
I2SSource(sampleRate, blockSize, sampleScale) {
|
||||
_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
|
||||
};
|
||||
|
||||
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
|
||||
|
||||
if ((i2sckPin < 0) || (mclkPin < 0)) {
|
||||
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
|
||||
return;
|
||||
}
|
||||
|
||||
// First route mclk, then configure ADC over I2C, then configure I2S
|
||||
_es8388InitAdc();
|
||||
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
}
|
||||
|
||||
void deinitialize() {
|
||||
I2SSource::deinitialize();
|
||||
}
|
||||
|
||||
private:
|
||||
int8_t pin_ES7243_SDA;
|
||||
int8_t pin_ES7243_SCL;
|
||||
};
|
||||
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
|
||||
#if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC)
|
||||
#warning this MCU does not support analog sound input
|
||||
@@ -685,3 +766,4 @@ class SPH0654 : public I2SSource {
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -85,12 +85,9 @@ class MPU6050Driver : public Usermod {
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
*/
|
||||
void setup() {
|
||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
||||
// join I2C bus (I2Cdev library doesn't do this automatically)
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||
Wire.setClock(400000U); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
||||
Fastwire::setup(400, true);
|
||||
#endif
|
||||
|
||||
@@ -5,14 +5,18 @@
|
||||
#ifndef MULTI_RELAY_MAX_RELAYS
|
||||
#define MULTI_RELAY_MAX_RELAYS 4
|
||||
#else
|
||||
#if MULTI_RELAY_MAX_RELAYS>16
|
||||
#if MULTI_RELAY_MAX_RELAYS>8
|
||||
#undef MULTI_RELAY_MAX_RELAYS
|
||||
#define MULTI_RELAY_MAX_RELAYS 16
|
||||
#define MULTI_RELAY_MAX_RELAYS 8
|
||||
#warning Maximum relays set to 8
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MULTI_RELAY_PINS
|
||||
#define MULTI_RELAY_PINS -1
|
||||
#define MULTI_RELAY_ENABLED false
|
||||
#else
|
||||
#define MULTI_RELAY_ENABLED true
|
||||
#endif
|
||||
|
||||
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
|
||||
@@ -20,6 +24,14 @@
|
||||
#define ON true
|
||||
#define OFF false
|
||||
|
||||
#ifndef USERMOD_USE_PCF8574
|
||||
#undef USE_PCF8574
|
||||
#define USE_PCF8574 false
|
||||
#else
|
||||
#undef USE_PCF8574
|
||||
#define USE_PCF8574 true
|
||||
#endif
|
||||
|
||||
#ifndef PCF8574_ADDRESS
|
||||
#define PCF8574_ADDRESS 0x20 // some may start at 0x38
|
||||
#endif
|
||||
@@ -37,7 +49,7 @@ typedef struct relay_t {
|
||||
int8_t pin;
|
||||
struct { // reduces memory footprint
|
||||
bool active : 1; // is the relay waiting to be switched
|
||||
bool mode : 1; // does On mean 1 or 0 (inverted output)
|
||||
bool invert : 1; // does On mean 1 or 0
|
||||
bool state : 1; // 1 relay is On, 0 relay is Off
|
||||
bool external : 1; // is the relay externally controlled
|
||||
int8_t button : 4; // which button triggers relay
|
||||
@@ -50,23 +62,17 @@ class MultiRelay : public Usermod {
|
||||
|
||||
private:
|
||||
// array of relays
|
||||
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
||||
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
||||
|
||||
// switch timer start time
|
||||
uint32_t _switchTimerStart = 0;
|
||||
// old brightness
|
||||
bool _oldMode;
|
||||
|
||||
// usermod enabled
|
||||
bool enabled = false; // needs to be configured (no default config)
|
||||
// status of initialisation
|
||||
bool initDone = false;
|
||||
bool usePcf8574 = false;
|
||||
uint8_t addrPcf8574 = PCF8574_ADDRESS;
|
||||
bool HAautodiscovery = false;
|
||||
|
||||
uint16_t periodicBroadcastSec = 60;
|
||||
unsigned long lastBroadcast = 0;
|
||||
uint32_t _switchTimerStart; // switch timer start time
|
||||
bool _oldMode; // old brightness
|
||||
bool enabled; // usermod enabled
|
||||
bool initDone; // status of initialisation
|
||||
bool usePcf8574;
|
||||
uint8_t addrPcf8574;
|
||||
bool HAautodiscovery;
|
||||
uint16_t periodicBroadcastSec;
|
||||
unsigned long lastBroadcast;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
@@ -103,7 +109,7 @@ class MultiRelay : public Usermod {
|
||||
/**
|
||||
* desctructor
|
||||
*/
|
||||
~MultiRelay() {}
|
||||
//~MultiRelay() {}
|
||||
|
||||
/**
|
||||
* Enable/Disable the usermod
|
||||
@@ -313,7 +319,7 @@ int MultiRelay::getValue(String data, char separator, int index) {
|
||||
|
||||
//Write a byte to the IO expander
|
||||
byte MultiRelay::IOexpanderWrite(byte address, byte _data ) {
|
||||
Wire.beginTransmission(addrPcf8574 + address);
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(_data);
|
||||
return Wire.endTransmission();
|
||||
}
|
||||
@@ -321,7 +327,7 @@ byte MultiRelay::IOexpanderWrite(byte address, byte _data ) {
|
||||
//Read a byte from the IO expander
|
||||
byte MultiRelay::IOexpanderRead(int address) {
|
||||
byte _data = 0;
|
||||
Wire.requestFrom(addrPcf8574 + address, 1);
|
||||
Wire.requestFrom(address, 1);
|
||||
if (Wire.available()) {
|
||||
_data = Wire.read();
|
||||
}
|
||||
@@ -331,12 +337,21 @@ byte MultiRelay::IOexpanderRead(int address) {
|
||||
|
||||
// public methods
|
||||
|
||||
MultiRelay::MultiRelay() {
|
||||
MultiRelay::MultiRelay()
|
||||
: _switchTimerStart(0)
|
||||
, enabled(MULTI_RELAY_ENABLED)
|
||||
, initDone(false)
|
||||
, usePcf8574(USE_PCF8574)
|
||||
, addrPcf8574(PCF8574_ADDRESS)
|
||||
, HAautodiscovery(false)
|
||||
, periodicBroadcastSec(60)
|
||||
, lastBroadcast(0)
|
||||
{
|
||||
const int8_t defPins[] = {MULTI_RELAY_PINS};
|
||||
for (size_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
_relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1;
|
||||
_relay[i].delay = 0;
|
||||
_relay[i].mode = false;
|
||||
_relay[i].invert = false;
|
||||
_relay[i].active = false;
|
||||
_relay[i].state = false;
|
||||
_relay[i].external = false;
|
||||
@@ -348,25 +363,27 @@ MultiRelay::MultiRelay() {
|
||||
* switch relay on/off
|
||||
*/
|
||||
void MultiRelay::switchRelay(uint8_t relay, bool mode) {
|
||||
if (relay>=MULTI_RELAY_MAX_RELAYS || (_relay[relay].pin<0 && !usePcf8574)) return;
|
||||
if (relay>=MULTI_RELAY_MAX_RELAYS || _relay[relay].pin<0) return;
|
||||
_relay[relay].state = mode;
|
||||
if (usePcf8574) {
|
||||
byte expander = relay/8;
|
||||
uint16_t state = 0;
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) state |= (uint16_t)_relay[i].state << i; // fill relay states for all pins
|
||||
state = (mode ? !_relay[relay].mode : _relay[relay].mode) ? state | (1<<relay) : state & ~(1<<relay); // take into account invert mode
|
||||
IOexpanderWrite(expander, state>>(8*expander));
|
||||
DEBUG_PRINT(F("PCF8574 Writing to ")); DEBUG_PRINT(addrPcf8574 + expander); DEBUG_PRINT(F(" with data ")); DEBUG_PRINTLN(state>>(8*expander));
|
||||
} else {
|
||||
if (usePcf8574 && _relay[relay].pin >= 100) {
|
||||
// we need to send all ouputs at the same time
|
||||
uint8_t state = 0;
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin < 100) continue;
|
||||
uint8_t pin = _relay[i].pin - 100;
|
||||
state |= (_relay[i].invert ? !_relay[i].state : _relay[i].state) << pin; // fill relay states for all pins
|
||||
}
|
||||
IOexpanderWrite(addrPcf8574, state);
|
||||
DEBUG_PRINT(F("Writing to PCF8574: ")); DEBUG_PRINTLN(state);
|
||||
} else if (_relay[relay].pin < 100) {
|
||||
pinMode(_relay[relay].pin, OUTPUT);
|
||||
digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
|
||||
}
|
||||
digitalWrite(_relay[relay].pin, _relay[relay].invert ? !_relay[relay].state : _relay[relay].state);
|
||||
} else return;
|
||||
publishMqtt(relay);
|
||||
}
|
||||
|
||||
uint8_t MultiRelay::getActiveRelayCount() {
|
||||
uint8_t count = 0;
|
||||
if (usePcf8574) return MULTI_RELAY_MAX_RELAYS; // we don't know how many there are
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) if (_relay[i].pin>=0) count++;
|
||||
return count;
|
||||
}
|
||||
@@ -465,29 +482,28 @@ void MultiRelay::publishHomeAssistantAutodiscovery() {
|
||||
void MultiRelay::setup() {
|
||||
// pins retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
// if we want PCF8574 expander I2C pins need to be valid
|
||||
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
|
||||
if (i2c_sda<0 || i2c_scl<0) usePcf8574 = false;
|
||||
|
||||
if (usePcf8574) {
|
||||
uint16_t state = 0;
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) state |= (uint16_t)(_relay[i].external ? (_relay[i].mode ? !_relay[i].state : _relay[i].state) : (_relay[i].mode ? !offMode : offMode)) << i; // fill relay states for all pins
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i += 8) {
|
||||
byte expander = i/8;
|
||||
IOexpanderWrite(expander, state>>(8*expander)); // init expander (set all outputs)
|
||||
delay(1);
|
||||
}
|
||||
DEBUG_PRINTLN(F("PCF8574(s) inited."));
|
||||
} else {
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin<0) continue;
|
||||
if (!pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
|
||||
_relay[i].pin = -1; // allocation failed
|
||||
} else {
|
||||
uint8_t state = 0;
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (usePcf8574 && _relay[i].pin >= 100) {
|
||||
uint8_t pin = _relay[i].pin - 100;
|
||||
if (!_relay[i].external) _relay[i].state = !offMode;
|
||||
state |= (uint8_t)(_relay[i].invert ? !_relay[i].state : _relay[i].state) << pin;
|
||||
} else if (_relay[i].pin<100 && _relay[i].pin>=0) {
|
||||
if (pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
|
||||
if (!_relay[i].external) _relay[i].state = !offMode;
|
||||
switchRelay(i, _relay[i].state);
|
||||
_relay[i].active = false;
|
||||
} else {
|
||||
_relay[i].pin = -1; // allocation failed
|
||||
}
|
||||
}
|
||||
}
|
||||
if (usePcf8574) {
|
||||
IOexpanderWrite(addrPcf8574, state); // init expander (set all outputs)
|
||||
DEBUG_PRINTLN(F("PCF8574(s) inited."));
|
||||
}
|
||||
_oldMode = offMode;
|
||||
initDone = true;
|
||||
}
|
||||
@@ -508,7 +524,7 @@ void MultiRelay::loop() {
|
||||
_oldMode = offMode;
|
||||
_switchTimerStart = millis();
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if ((_relay[i].pin>=0 || usePcf8574) && !_relay[i].external) _relay[i].active = true;
|
||||
if ((_relay[i].pin>=0) && !_relay[i].external) _relay[i].active = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,7 +640,7 @@ void MultiRelay::addToJsonInfo(JsonObject &root) {
|
||||
|
||||
String uiDomString;
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if ((_relay[i].pin<0 && !usePcf8574) || !_relay[i].external) continue;
|
||||
if (_relay[i].pin<0 || !_relay[i].external) continue;
|
||||
uiDomString = F("Relay "); uiDomString += i;
|
||||
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
|
||||
|
||||
@@ -715,7 +731,7 @@ void MultiRelay::addToConfig(JsonObject &root) {
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
JsonObject relay = top.createNestedObject(parName);
|
||||
relay["pin"] = _relay[i].pin;
|
||||
relay[FPSTR(_activeHigh)] = _relay[i].mode;
|
||||
relay[FPSTR(_activeHigh)] = _relay[i].invert;
|
||||
relay[FPSTR(_delay_str)] = _relay[i].delay;
|
||||
relay[FPSTR(_external)] = _relay[i].external;
|
||||
relay[FPSTR(_button)] = _relay[i].button;
|
||||
@@ -724,9 +740,10 @@ void MultiRelay::addToConfig(JsonObject &root) {
|
||||
}
|
||||
|
||||
void MultiRelay::appendConfigData() {
|
||||
oappend(SET_F("addInfo('MultiRelay:first-PCF8574',1,'<i>(not hex!)</i>','address');"));
|
||||
oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||
oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
|
||||
oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
|
||||
//oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
|
||||
oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -751,7 +768,7 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
|
||||
usePcf8574 = top[FPSTR(_pcf8574)] | usePcf8574;
|
||||
addrPcf8574 = top[FPSTR(_pcfAddress)] | addrPcf8574;
|
||||
// if I2C is not globally initialised just ignore
|
||||
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
|
||||
if (i2c_sda<0 || i2c_scl<0) usePcf8574 = false;
|
||||
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
|
||||
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
|
||||
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
|
||||
@@ -760,14 +777,14 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
oldPin[i] = _relay[i].pin;
|
||||
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
|
||||
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
|
||||
_relay[i].invert = top[parName][FPSTR(_activeHigh)] | _relay[i].invert;
|
||||
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
||||
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
||||
_relay[i].button = top[parName][FPSTR(_button)] | _relay[i].button;
|
||||
// begin backwards compatibility (beta) remove when 0.13 is released
|
||||
parName += '-';
|
||||
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
||||
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
||||
_relay[i].invert = top[parName+FPSTR(_activeHigh)] | _relay[i].invert;
|
||||
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
||||
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
||||
// end compatibility
|
||||
@@ -781,22 +798,11 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
|
||||
} else {
|
||||
// deallocate all pins 1st
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++)
|
||||
if (oldPin[i]>=0) {
|
||||
if (oldPin[i]>=0 && oldPin[i]<100) {
|
||||
pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
|
||||
}
|
||||
// allocate new pins
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin>=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) {
|
||||
if (!_relay[i].external) {
|
||||
_relay[i].state = !offMode;
|
||||
switchRelay(i, _relay[i].state);
|
||||
_oldMode = offMode;
|
||||
}
|
||||
} else {
|
||||
_relay[i].pin = -1;
|
||||
}
|
||||
_relay[i].active = false;
|
||||
}
|
||||
setup();
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
@@ -814,4 +820,4 @@ const char MultiRelay::_button[] PROGMEM = "button";
|
||||
const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
|
||||
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
|
||||
const char MultiRelay::_pcf8574[] PROGMEM = "use-PCF8574";
|
||||
const char MultiRelay::_pcfAddress[] PROGMEM = "first-PCF8574";
|
||||
const char MultiRelay::_pcfAddress[] PROGMEM = "PCF8574-address";
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP280.h>
|
||||
#include <Adafruit_CCS811.h>
|
||||
@@ -16,14 +15,6 @@ Adafruit_BMP280 bmp;
|
||||
Adafruit_Si7021 si7021;
|
||||
Adafruit_CCS811 ccs811;
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
#else //ESP8266 boards
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
#endif
|
||||
|
||||
class UserMod_SensorsToMQTT : public Usermod
|
||||
{
|
||||
private:
|
||||
@@ -231,7 +222,6 @@ public:
|
||||
void setup()
|
||||
{
|
||||
Serial.println("Starting!");
|
||||
Wire.begin(SDA_PIN, SCL_PIN);
|
||||
Serial.println("Initializing sensors.. ");
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ class ShtUsermod : public Usermod
|
||||
private:
|
||||
bool enabled = false; // Is usermod enabled or not
|
||||
bool firstRunDone = false; // Remembers if the first config load run had been done
|
||||
bool pinAllocDone = true; // Remembers if we have allocated pins
|
||||
bool initDone = false; // Remembers if the mod has been completely initialised
|
||||
bool haMqttDiscovery = false; // Is MQTT discovery enabled or not
|
||||
bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics
|
||||
@@ -94,7 +93,7 @@ void ShtUsermod::initShtTempHumiditySensor()
|
||||
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
|
||||
}
|
||||
|
||||
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
|
||||
shtTempHumidSensor->begin(shtI2cAddress); // uses &Wire
|
||||
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
|
||||
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
|
||||
cleanup();
|
||||
@@ -132,13 +131,6 @@ void ShtUsermod::cleanupShtTempHumiditySensor()
|
||||
void ShtUsermod::cleanup()
|
||||
{
|
||||
cleanupShtTempHumiditySensor();
|
||||
|
||||
if (pinAllocDone) {
|
||||
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
||||
pinManager.deallocateMultiplePins(pins, 2, PinOwner::HW_I2C);
|
||||
pinAllocDone = false;
|
||||
}
|
||||
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
@@ -237,14 +229,12 @@ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
|
||||
void ShtUsermod::setup()
|
||||
{
|
||||
if (enabled) {
|
||||
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
||||
// GPIOs can be set to -1 and allocateMultiplePins() will return true, so check they're gt zero
|
||||
if (i2c_sda < 0 || i2c_scl < 0 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) {
|
||||
DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name);
|
||||
// GPIOs can be set to -1 , so check they're gt zero
|
||||
if (i2c_sda < 0 || i2c_scl < 0) {
|
||||
DEBUG_PRINTF("[%s] I2C bus not initialised!\n", _name);
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
pinAllocDone = true;
|
||||
|
||||
initShtTempHumiditySensor();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
22
usermods/wireguard/platformio_override.ini
Normal file
22
usermods/wireguard/platformio_override.ini
Normal file
@@ -0,0 +1,22 @@
|
||||
# Example PlatformIO Project Configuration Override for WireGuard
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copy to platformio_override.ini to activate.
|
||||
# ------------------------------------------------------------------------------
|
||||
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = WLED_ESP32-WireGuard
|
||||
|
||||
[env:WLED_ESP32-WireGuard]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
-D WLED_RELEASE_NAME=ESP32-WireGuard
|
||||
-D USERMOD_WIREGUARD
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
https://github.com/kienvu58/WireGuard-ESP32-Arduino.git
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
upload_speed = 921600
|
||||
19
usermods/wireguard/readme.md
Normal file
19
usermods/wireguard/readme.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# WireGuard VPN
|
||||
|
||||
This usermod will connect your WLED instance to a remote WireGuard subnet.
|
||||
|
||||
Configuration is performed via the Usermod menu. There are no parameters to set in code!
|
||||
|
||||
## Installation
|
||||
|
||||
Copy the `platformio_override.ini` file to the root project directory, review the build options, and select the `WLED_ESP32-WireGuard` environment.
|
||||
|
||||
|
||||
## Author
|
||||
|
||||
Aiden Vigue [vigue.me](https://vigue.me)
|
||||
[@acvigue](https://github.com/acvigue)
|
||||
aiden@vigue.me
|
||||
|
||||
|
||||
|
||||
127
usermods/wireguard/wireguard.h
Normal file
127
usermods/wireguard/wireguard.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include <WireGuard-ESP32.h>
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
class WireguardUsermod : public Usermod {
|
||||
public:
|
||||
void setup() { configTzTime(posix_tz, ntpServerName); }
|
||||
|
||||
void connected() {
|
||||
if (wg.is_initialized()) {
|
||||
wg.end();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (millis() - lastTime > 5000) {
|
||||
if (is_enabled && WLED_CONNECTED) {
|
||||
if (!wg.is_initialized()) {
|
||||
struct tm timeinfo;
|
||||
if (getLocalTime(&timeinfo, 0)) {
|
||||
if (strlen(preshared_key) < 1) {
|
||||
wg.begin(local_ip, private_key, endpoint_address, public_key, endpoint_port, NULL);
|
||||
} else {
|
||||
wg.begin(local_ip, private_key, endpoint_address, public_key, endpoint_port, preshared_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray infoArr = user.createNestedArray(F("WireGuard"));
|
||||
String uiDomString;
|
||||
|
||||
struct tm timeinfo;
|
||||
if (!getLocalTime(&timeinfo, 0)) {
|
||||
uiDomString = "Time out of sync!";
|
||||
} else {
|
||||
if (wg.is_initialized()) {
|
||||
uiDomString = "netif up!";
|
||||
} else {
|
||||
uiDomString = "netif down :(";
|
||||
}
|
||||
}
|
||||
if (is_enabled) infoArr.add(uiDomString);
|
||||
}
|
||||
|
||||
void appendConfigData() {
|
||||
oappend(SET_F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root) {
|
||||
JsonObject top = root.createNestedObject(F("WireGuard"));
|
||||
top[F("host")] = endpoint_address;
|
||||
top[F("port")] = endpoint_port;
|
||||
top[F("ip")] = local_ip.toString();
|
||||
top[F("psk")] = preshared_key;
|
||||
top[F("pem")] = private_key;
|
||||
top[F("pub")] = public_key;
|
||||
top[F("tz")] = posix_tz;
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject& root) {
|
||||
JsonObject top = root[F("WireGuard")];
|
||||
|
||||
if (top["host"].isNull() || top["port"].isNull() || top["ip"].isNull() || top["pem"].isNull() || top["pub"].isNull() || top["tz"].isNull()) {
|
||||
is_enabled = false;
|
||||
return false;
|
||||
} else {
|
||||
const char* host = top["host"];
|
||||
strncpy(endpoint_address, host, 100);
|
||||
|
||||
const char* ip_s = top["ip"];
|
||||
uint8_t ip[4];
|
||||
sscanf(ip_s, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);
|
||||
local_ip = IPAddress(ip[0], ip[1], ip[2], ip[3]);
|
||||
|
||||
const char* pem = top["pem"];
|
||||
strncpy(private_key, pem, 45);
|
||||
|
||||
const char* pub = top["pub"];
|
||||
strncpy(public_key, pub, 45);
|
||||
|
||||
const char* tz = top["tz"];
|
||||
strncpy(posix_tz, tz, 150);
|
||||
|
||||
endpoint_port = top["port"];
|
||||
|
||||
if (!top["psk"].isNull()) {
|
||||
const char* psk = top["psk"];
|
||||
strncpy(preshared_key, psk, 45);
|
||||
}
|
||||
|
||||
is_enabled = true;
|
||||
}
|
||||
|
||||
return is_enabled;
|
||||
}
|
||||
|
||||
uint16_t getId() { return USERMOD_ID_WIREGUARD; }
|
||||
|
||||
private:
|
||||
WireGuard wg;
|
||||
char preshared_key[45];
|
||||
char private_key[45];
|
||||
IPAddress local_ip;
|
||||
char public_key[45];
|
||||
char endpoint_address[100];
|
||||
char posix_tz[150];
|
||||
int endpoint_port = 0;
|
||||
bool is_enabled = false;
|
||||
unsigned long lastTime = 0;
|
||||
};
|
||||
25
wled00.sln
25
wled00.sln
@@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28010.2046
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wled00", "wled00\wled00.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9A679C2B-61D3-400B-B96F-06E604E9CED2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
493
wled00/FX.cpp
493
wled00/FX.cpp
File diff suppressed because it is too large
Load Diff
142
wled00/FX.h
142
wled00/FX.h
@@ -176,7 +176,7 @@
|
||||
#define FX_MODE_FIRE_FLICKER 45
|
||||
#define FX_MODE_GRADIENT 46
|
||||
#define FX_MODE_LOADING 47
|
||||
// #define FX_MODE_POLICE 48 // removed in 0.14!
|
||||
#define FX_MODE_ROLLINGBALLS 48 //was Police before 0.14
|
||||
#define FX_MODE_FAIRY 49 //was Police All prior to 0.13.0-b6 (use "Two Dots" with Red/Blue and full intensity)
|
||||
#define FX_MODE_TWO_DOTS 50
|
||||
#define FX_MODE_FAIRYTWINKLE 51 //was Two Areas prior to 0.13.0-b6 (use "Two Dots" with full intensity)
|
||||
@@ -329,7 +329,7 @@ typedef enum mapping1D2D {
|
||||
M12_pCorner = 3
|
||||
} mapping1D2D_t;
|
||||
|
||||
// segment, 72 bytes
|
||||
// segment, 80 bytes
|
||||
typedef struct Segment {
|
||||
public:
|
||||
uint16_t start; // start index / start X coordinate 2D (left)
|
||||
@@ -370,7 +370,7 @@ typedef struct Segment {
|
||||
};
|
||||
uint8_t startY; // start Y coodrinate 2D (top); there should be no more than 255 rows
|
||||
uint8_t stopY; // stop Y coordinate 2D (bottom); there should be no more than 255 rows
|
||||
char *name;
|
||||
char *name;
|
||||
|
||||
// runtime data
|
||||
unsigned long next_time; // millis() of next update
|
||||
@@ -378,11 +378,33 @@ typedef struct Segment {
|
||||
uint32_t call; // call counter
|
||||
uint16_t aux0; // custom var
|
||||
uint16_t aux1; // custom var
|
||||
byte* data; // effect data pointer
|
||||
CRGB* leds; // local leds[] array (may be a pointer to global)
|
||||
static CRGB *_globalLeds; // global leds[] array
|
||||
byte *data; // effect data pointer
|
||||
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
|
||||
|
||||
typedef struct TemporarySegmentData {
|
||||
uint16_t _optionsT;
|
||||
uint32_t _colorT[NUM_COLORS];
|
||||
uint8_t _speedT;
|
||||
uint8_t _intensityT;
|
||||
uint8_t _custom1T, _custom2T; // custom FX parameters/sliders
|
||||
struct {
|
||||
uint8_t _custom3T : 5; // reduced range slider (0-31)
|
||||
bool _check1T : 1; // checkmark 1
|
||||
bool _check2T : 1; // checkmark 2
|
||||
bool _check3T : 1; // checkmark 3
|
||||
};
|
||||
uint16_t _aux0T;
|
||||
uint16_t _aux1T;
|
||||
uint32_t _stepT;
|
||||
uint32_t _callT;
|
||||
uint8_t *_dataT;
|
||||
uint16_t _dataLenT;
|
||||
TemporarySegmentData()
|
||||
: _dataT(nullptr) // just in case...
|
||||
, _dataLenT(0)
|
||||
{}
|
||||
} tmpsegd_t;
|
||||
|
||||
private:
|
||||
union {
|
||||
uint8_t _capabilities;
|
||||
@@ -394,42 +416,37 @@ typedef struct Segment {
|
||||
uint8_t _reserved : 4;
|
||||
};
|
||||
};
|
||||
uint16_t _dataLen;
|
||||
uint16_t _dataLen;
|
||||
static uint16_t _usedSegmentData;
|
||||
|
||||
// transition data, valid only if transitional==true, holds values during transition
|
||||
// perhaps this should be per segment, not static
|
||||
static CRGBPalette16 _randomPalette; // actual random palette
|
||||
static CRGBPalette16 _newRandomPalette; // target random palette
|
||||
static unsigned long _lastPaletteChange; // last random palette change time in millis()
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
static bool _modeBlend; // mode/effect blending semaphore
|
||||
#endif
|
||||
|
||||
// transition data, valid only if transitional==true, holds values during transition (72 bytes)
|
||||
struct Transition {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
tmpsegd_t _segT; // previous segment environment
|
||||
uint8_t _modeT; // previous mode/effect
|
||||
#else
|
||||
uint32_t _colorT[NUM_COLORS];
|
||||
#endif
|
||||
uint8_t _briT; // temporary brightness
|
||||
uint8_t _cctT; // temporary CCT
|
||||
CRGBPalette16 _palT; // temporary palette
|
||||
uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 belnds possible)
|
||||
uint8_t _modeP; // previous mode/effect
|
||||
//uint16_t _aux0, _aux1; // previous mode/effect runtime data
|
||||
//uint32_t _step, _call; // previous mode/effect runtime data
|
||||
//byte *_data; // previous mode/effect runtime data
|
||||
uint32_t _start;
|
||||
unsigned long _start; // must accommodate millis()
|
||||
uint16_t _dur;
|
||||
Transition(uint16_t dur=750)
|
||||
: _briT(255)
|
||||
, _cctT(127)
|
||||
, _palT(CRGBPalette16(CRGB::Black))
|
||||
: _palT(CRGBPalette16(CRGB::Black))
|
||||
, _prevPaletteBlends(0)
|
||||
, _modeP(FX_MODE_STATIC)
|
||||
, _start(millis())
|
||||
, _dur(dur)
|
||||
{}
|
||||
Transition(uint16_t d, uint8_t b, uint8_t c, const uint32_t *o)
|
||||
: _briT(b)
|
||||
, _cctT(c)
|
||||
, _palT(CRGBPalette16(CRGB::Black))
|
||||
, _prevPaletteBlends(0)
|
||||
, _modeP(FX_MODE_STATIC)
|
||||
, _start(millis())
|
||||
, _dur(d)
|
||||
{
|
||||
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = o[i];
|
||||
}
|
||||
} *_t;
|
||||
|
||||
public:
|
||||
@@ -463,12 +480,14 @@ typedef struct Segment {
|
||||
aux0(0),
|
||||
aux1(0),
|
||||
data(nullptr),
|
||||
leds(nullptr),
|
||||
_capabilities(0),
|
||||
_dataLen(0),
|
||||
_t(nullptr)
|
||||
{
|
||||
//refreshLightCapabilities();
|
||||
#ifdef WLED_DEBUG
|
||||
//Serial.printf("-- Creating segment: %p\n", this);
|
||||
#endif
|
||||
}
|
||||
|
||||
Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) : Segment(sStartX, sStopX) {
|
||||
@@ -480,16 +499,14 @@ typedef struct Segment {
|
||||
Segment(Segment &&orig) noexcept; // move constructor
|
||||
|
||||
~Segment() {
|
||||
//#ifdef WLED_DEBUG
|
||||
//Serial.print(F("Destroying segment:"));
|
||||
#ifdef WLED_DEBUG
|
||||
//Serial.printf("-- Destroying segment: %p\n", this);
|
||||
//if (name) Serial.printf(" %s (%p)", name, name);
|
||||
//if (data) Serial.printf(" %d (%p)", (int)_dataLen, data);
|
||||
//if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB));
|
||||
//Serial.println();
|
||||
//#endif
|
||||
if (!Segment::_globalLeds && leds) free(leds);
|
||||
if (name) delete[] name;
|
||||
if (_t) delete _t;
|
||||
#endif
|
||||
if (name) { delete[] name; name = nullptr; }
|
||||
stopTransition();
|
||||
deallocateData();
|
||||
}
|
||||
|
||||
@@ -497,7 +514,7 @@ typedef struct Segment {
|
||||
Segment& operator= (Segment &&orig) noexcept; // move assignment
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
size_t getSize() const { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0) + (!Segment::_globalLeds && leds?sizeof(CRGB)*length():0); }
|
||||
size_t getSize() const { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0); }
|
||||
#endif
|
||||
|
||||
inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); }
|
||||
@@ -507,16 +524,20 @@ typedef struct Segment {
|
||||
inline bool hasRGB(void) const { return _isRGB; }
|
||||
inline bool hasWhite(void) const { return _hasW; }
|
||||
inline bool isCCT(void) const { return _isCCT; }
|
||||
inline uint16_t width(void) const { return stop - start; } // segment width in physical pixels (length if 1D)
|
||||
inline uint16_t height(void) const { return stopY - startY; } // segment height (if 2D) in physical pixels
|
||||
inline uint16_t length(void) const { return width() * height(); } // segment length (count) in physical pixels
|
||||
inline uint16_t width(void) const { return isActive() ? (stop - start) : 0; } // segment width in physical pixels (length if 1D)
|
||||
inline uint16_t height(void) const { return stopY - startY; } // segment height (if 2D) in physical pixels (it *is* always >=1)
|
||||
inline uint16_t length(void) const { return width() * height(); } // segment length (count) in physical pixels
|
||||
inline uint16_t groupLength(void) const { return grouping + spacing; }
|
||||
inline uint8_t getLightCapabilities(void) const { return _capabilities; }
|
||||
|
||||
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
|
||||
static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
static void modeBlend(bool blend) { _modeBlend = blend; }
|
||||
#endif
|
||||
static void handleRandomPalette();
|
||||
|
||||
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
|
||||
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t segId = 255);
|
||||
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
|
||||
void setCCT(uint16_t k);
|
||||
void setOpacity(uint8_t o);
|
||||
@@ -538,11 +559,15 @@ typedef struct Segment {
|
||||
* Safe to call from interrupts and network requests.
|
||||
*/
|
||||
inline void markForReset(void) { reset = true; } // setOption(SEG_OPTION_RESET, true)
|
||||
void setUpLeds(void); // set up leds[] array for loseless getPixelColor()
|
||||
|
||||
// transition functions
|
||||
void startTransition(uint16_t dur); // transition has to start before actual segment values change
|
||||
void stopTransition(void);
|
||||
void handleTransition(void);
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
void swapSegenv(tmpsegd_t &tmpSegD);
|
||||
void restoreSegenv(tmpsegd_t &tmpSegD);
|
||||
#endif
|
||||
uint16_t progress(void); //transition progression between 0-65535
|
||||
uint8_t currentBri(uint8_t briNew, bool useCct = false);
|
||||
uint8_t currentMode(uint8_t modeNew);
|
||||
@@ -579,7 +604,7 @@ typedef struct Segment {
|
||||
uint16_t virtualHeight(void) const;
|
||||
uint16_t nrOfVStrips(void) const;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment (for leds[])
|
||||
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment
|
||||
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
|
||||
void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
|
||||
void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
|
||||
@@ -604,9 +629,9 @@ typedef struct Segment {
|
||||
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
|
||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
|
||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0);
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, uint8_t rotate = 0);
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, uint8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline
|
||||
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
||||
void blur1d(fract8 blur_amount); // blur all rows in 1 dimension
|
||||
void blur2d(fract8 blur_amount) { blur(blur_amount); }
|
||||
@@ -692,7 +717,15 @@ class WS2812FX { // 96 bytes
|
||||
customMappingSize(0),
|
||||
_lastShow(0),
|
||||
_segment_index(0),
|
||||
_mainSegment(0)
|
||||
_mainSegment(0),
|
||||
_queuedChangesSegId(255),
|
||||
_qStart(0),
|
||||
_qStop(0),
|
||||
_qStartY(0),
|
||||
_qStopY(0),
|
||||
_qGrouping(0),
|
||||
_qSpacing(0),
|
||||
_qOffset(0)
|
||||
{
|
||||
WS2812FX::instance = this;
|
||||
_mode.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size())
|
||||
@@ -710,7 +743,6 @@ class WS2812FX { // 96 bytes
|
||||
panel.clear();
|
||||
#endif
|
||||
customPalettes.clear();
|
||||
if (useLedsArray && Segment::_globalLeds) free(Segment::_globalLeds);
|
||||
}
|
||||
|
||||
static WS2812FX* getInstance(void) { return instance; }
|
||||
@@ -749,7 +781,7 @@ class WS2812FX { // 96 bytes
|
||||
inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
|
||||
inline void setShowCallback(show_callback cb) { _callback = cb; }
|
||||
inline void setTransition(uint16_t t) { _transitionDur = t; }
|
||||
inline void appendSegment(const Segment &seg = Segment()) { _segments.push_back(seg); }
|
||||
inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
|
||||
|
||||
bool
|
||||
checkSegmentAlignment(void),
|
||||
@@ -757,8 +789,7 @@ class WS2812FX { // 96 bytes
|
||||
hasCCTBus(void),
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void),
|
||||
deserializeMap(uint8_t n=0),
|
||||
useLedsArray = false;
|
||||
deserializeMap(uint8_t n=0);
|
||||
|
||||
inline bool isServicing(void) { return _isServicing; }
|
||||
inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
|
||||
@@ -900,13 +931,20 @@ class WS2812FX { // 96 bytes
|
||||
uint16_t* customMappingTable;
|
||||
uint16_t customMappingSize;
|
||||
|
||||
uint32_t _lastShow;
|
||||
unsigned long _lastShow;
|
||||
|
||||
uint8_t _segment_index;
|
||||
uint8_t _mainSegment;
|
||||
uint8_t _queuedChangesSegId;
|
||||
uint16_t _qStart, _qStop, _qStartY, _qStopY;
|
||||
uint8_t _qGrouping, _qSpacing;
|
||||
uint16_t _qOffset;
|
||||
|
||||
uint8_t
|
||||
estimateCurrentAndLimitBri(void);
|
||||
|
||||
void
|
||||
estimateCurrentAndLimitBri(void);
|
||||
setUpSegmentFromQueuedChanges(void);
|
||||
};
|
||||
|
||||
extern const char JSON_mode_names[];
|
||||
|
||||
@@ -189,20 +189,17 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
|
||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||
uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) {
|
||||
uint16_t width = virtualWidth(); // segment width in logical pixels
|
||||
uint16_t height = virtualHeight(); // segment height in logical pixels
|
||||
return (x%width) + (y%height) * width;
|
||||
uint16_t width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
uint16_t height = virtualHeight(); // segment height in logical pixels (is always >= 1)
|
||||
return isActive() ? (x%width) + (y%height) * width : 0;
|
||||
}
|
||||
|
||||
void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
if (Segment::maxHeight==1) return; // not a matrix set-up
|
||||
if (!isActive()) return; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
|
||||
if (leds) leds[XY(x,y)] = col;
|
||||
|
||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||
if (!_bri_t && !transitional) return;
|
||||
if (_bri_t < 255) {
|
||||
byte r = scale8(R(col), _bri_t);
|
||||
byte g = scale8(G(col), _bri_t);
|
||||
@@ -219,23 +216,29 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
y *= groupLength(); // expand to physical pixels
|
||||
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
|
||||
|
||||
uint32_t tmpCol = col;
|
||||
for (int j = 0; j < grouping; j++) { // groupping vertically
|
||||
for (int g = 0; g < grouping; g++) { // groupping horizontally
|
||||
uint16_t xX = (x+g), yY = (y+j);
|
||||
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
|
||||
|
||||
strip.setPixelColorXY(start + xX, startY + yY, col);
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
// if blending modes, blend with underlying pixel
|
||||
if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true);
|
||||
#endif
|
||||
|
||||
strip.setPixelColorXY(start + xX, startY + yY, tmpCol);
|
||||
|
||||
if (mirror) { //set the corresponding horizontally mirrored pixel
|
||||
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
|
||||
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
|
||||
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
||||
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
||||
}
|
||||
if (mirror_y) { //set the corresponding vertically mirrored pixel
|
||||
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
|
||||
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
|
||||
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
||||
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
||||
}
|
||||
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
|
||||
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, col);
|
||||
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, tmpCol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,7 +247,7 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
// anti-aliased version of setPixelColorXY()
|
||||
void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
||||
{
|
||||
if (Segment::maxHeight==1) return; // not a matrix set-up
|
||||
if (!isActive()) return; // not active
|
||||
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||
|
||||
const uint16_t cols = virtualWidth();
|
||||
@@ -287,8 +290,8 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
||||
|
||||
// returns RGBW values of pixel
|
||||
uint32_t Segment::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
int i = XY(x,y);
|
||||
if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0);
|
||||
if (!isActive()) return 0; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
|
||||
if (reverse ) x = virtualWidth() - x - 1;
|
||||
if (reverse_y) y = virtualHeight() - y - 1;
|
||||
if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
|
||||
@@ -305,6 +308,8 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t
|
||||
|
||||
// Adds the specified color with the existing pixel color perserving color balance.
|
||||
void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
|
||||
if (!isActive()) return; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
uint32_t col = getPixelColorXY(x,y);
|
||||
uint8_t r = R(col);
|
||||
uint8_t g = G(col);
|
||||
@@ -323,62 +328,70 @@ void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
|
||||
}
|
||||
|
||||
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
|
||||
if (!isActive()) return; // not active
|
||||
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
|
||||
setPixelColorXY(x, y, pix);
|
||||
}
|
||||
|
||||
// blurRow: perform a blur on a row of a rectangular matrix
|
||||
void Segment::blurRow(uint16_t row, fract8 blur_amount) {
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (!isActive()) return; // not active
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
|
||||
if (row >= rows) return;
|
||||
// blur one row
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint16_t x = 0; x < cols; x++) {
|
||||
for (uint_fast16_t x = 0; x < cols; x++) {
|
||||
CRGB cur = getPixelColorXY(x, row);
|
||||
CRGB before = cur; // remember color before blur
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if (x) {
|
||||
if (x>0) {
|
||||
CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part;
|
||||
setPixelColorXY(x-1, row, prev);
|
||||
}
|
||||
setPixelColorXY(x, row, cur);
|
||||
if (before != cur) // optimization: only set pixel if color has changed
|
||||
setPixelColorXY(x, row, cur);
|
||||
carryover = part;
|
||||
}
|
||||
}
|
||||
|
||||
// blurCol: perform a blur on a column of a rectangular matrix
|
||||
void Segment::blurCol(uint16_t col, fract8 blur_amount) {
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (!isActive()) return; // not active
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
|
||||
if (col >= cols) return;
|
||||
// blur one column
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint16_t i = 0; i < rows; i++) {
|
||||
CRGB cur = getPixelColorXY(col, i);
|
||||
for (uint_fast16_t y = 0; y < rows; y++) {
|
||||
CRGB cur = getPixelColorXY(col, y);
|
||||
CRGB part = cur;
|
||||
CRGB before = cur; // remember color before blur
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if (i) {
|
||||
CRGB prev = CRGB(getPixelColorXY(col, i-1)) + part;
|
||||
setPixelColorXY(col, i-1, prev);
|
||||
if (y>0) {
|
||||
CRGB prev = CRGB(getPixelColorXY(col, y-1)) + part;
|
||||
setPixelColorXY(col, y-1, prev);
|
||||
}
|
||||
setPixelColorXY(col, i, cur);
|
||||
if (before != cur) // optimization: only set pixel if color has changed
|
||||
setPixelColorXY(col, y, cur);
|
||||
carryover = part;
|
||||
}
|
||||
}
|
||||
|
||||
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
|
||||
void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
const uint16_t dim1 = vertical ? rows : cols;
|
||||
@@ -391,8 +404,8 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
for (uint16_t j = 0; j < dim1; j++) {
|
||||
uint16_t x = vertical ? i : j;
|
||||
uint16_t y = vertical ? j : i;
|
||||
uint16_t xp = vertical ? x : x-1;
|
||||
uint16_t yp = vertical ? y-1 : y;
|
||||
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
|
||||
int16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow
|
||||
uint16_t xn = vertical ? x : x+1;
|
||||
uint16_t yn = vertical ? y+1 : y;
|
||||
CRGB curr = getPixelColorXY(x,y);
|
||||
@@ -431,6 +444,7 @@ void Segment::blur1d(fract8 blur_amount) {
|
||||
}
|
||||
|
||||
void Segment::moveX(int8_t delta, bool wrap) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (!delta || abs(delta) >= cols) return;
|
||||
@@ -448,6 +462,7 @@ void Segment::moveX(int8_t delta, bool wrap) {
|
||||
}
|
||||
|
||||
void Segment::moveY(int8_t delta, bool wrap) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (!delta || abs(delta) >= rows) return;
|
||||
@@ -483,6 +498,7 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) {
|
||||
}
|
||||
|
||||
void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
if (!isActive()) return; // not active
|
||||
// Bresenham’s Algorithm
|
||||
int d = 3 - (2*radius);
|
||||
int y = radius, x = 0;
|
||||
@@ -507,6 +523,7 @@ void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
|
||||
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
||||
void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (int16_t y = -radius; y <= radius; y++) {
|
||||
@@ -520,6 +537,7 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
}
|
||||
|
||||
void Segment::nscale8(uint8_t scale) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
@@ -529,6 +547,7 @@ void Segment::nscale8(uint8_t scale) {
|
||||
|
||||
//line function
|
||||
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return;
|
||||
@@ -552,7 +571,8 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
|
||||
// draws a raster font character on canvas
|
||||
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
|
||||
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2) {
|
||||
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, uint8_t rotate) {
|
||||
if (!isActive()) return; // not active
|
||||
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
|
||||
chr -= 32; // align with font table entries
|
||||
const uint16_t cols = virtualWidth();
|
||||
@@ -564,9 +584,6 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
|
||||
//if (w<5 || w>6 || h!=8) return;
|
||||
for (int i = 0; i<h; i++) { // character height
|
||||
int16_t y0 = y + i;
|
||||
if (y0 < 0) continue; // drawing off-screen
|
||||
if (y0 >= rows) break; // drawing off-screen
|
||||
uint8_t bits = 0;
|
||||
switch (font) {
|
||||
case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]); break; // 5x8 font
|
||||
@@ -578,8 +595,15 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
}
|
||||
col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
|
||||
for (int j = 0; j<w; j++) { // character width
|
||||
int16_t x0 = x + (w-1) - j;
|
||||
if ((x0 >= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen
|
||||
int x0, y0;
|
||||
switch (rotate) {
|
||||
case 3: x0 = x + (h-1) - i; y0 = y + (w-1) - j; break;
|
||||
case 2: x0 = x + j; y0 = y + (h-1) - i; break;
|
||||
case 1: x0 = x + i; y0 = y + j; break;
|
||||
default: x0 = x + (w-1) - j; y0 = y + i; break;
|
||||
}
|
||||
if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen
|
||||
if (((bits>>(j+(8-w))) & 0x01)) { // bit set
|
||||
setPixelColorXY(x0, y0, col);
|
||||
}
|
||||
}
|
||||
@@ -588,6 +612,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
|
||||
#define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8))
|
||||
void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel procedure by reddit u/sutaburosu
|
||||
if (!isActive()) return; // not active
|
||||
// extract the fractional parts and derive their inverses
|
||||
uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
|
||||
// calculate the intensities for each affected pixel
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,9 @@
|
||||
#include <IPAddress.h>
|
||||
|
||||
#define NODE_TYPE_ID_UNDEFINED 0
|
||||
#define NODE_TYPE_ID_ESP8266 82
|
||||
#define NODE_TYPE_ID_ESP32 32
|
||||
#define NODE_TYPE_ID_ESP32S2 33
|
||||
#define NODE_TYPE_ID_ESP8266 82 // should be 1
|
||||
#define NODE_TYPE_ID_ESP32 32 // should be 2
|
||||
#define NODE_TYPE_ID_ESP32S2 33 // etc
|
||||
#define NODE_TYPE_ID_ESP32S3 34
|
||||
#define NODE_TYPE_ID_ESP32C3 35
|
||||
|
||||
@@ -23,7 +23,13 @@ struct NodeStruct
|
||||
String nodeName;
|
||||
IPAddress ip;
|
||||
uint8_t age;
|
||||
uint8_t nodeType;
|
||||
union {
|
||||
uint8_t nodeType; // a waste of space as we only have 5 types
|
||||
struct {
|
||||
uint8_t type : 7; // still a waste of space (4 bits would be enough and future-proof)
|
||||
bool on : 1;
|
||||
};
|
||||
};
|
||||
uint32_t build;
|
||||
|
||||
NodeStruct() : age(0), nodeType(0), build(0)
|
||||
|
||||
@@ -91,96 +91,172 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) {
|
||||
return RGBW32(r, g, b, w);
|
||||
}
|
||||
|
||||
uint8_t *Bus::allocData(size_t size) {
|
||||
if (_data) free(_data); // should not happen, but for safety
|
||||
return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr);
|
||||
}
|
||||
|
||||
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite), _colorOrderMap(com) {
|
||||
|
||||
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
|
||||
, _skip(bc.skipAmount) //sacrificial pixels
|
||||
, _colorOrder(bc.colorOrder)
|
||||
, _colorOrderMap(com)
|
||||
{
|
||||
if (!IS_DIGITAL(bc.type) || !bc.count) return;
|
||||
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
|
||||
_frequencykHz = 0U;
|
||||
_pins[0] = bc.pins[0];
|
||||
if (IS_2PIN(bc.type)) {
|
||||
if (!pinManager.allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
|
||||
cleanup(); return;
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
_pins[1] = bc.pins[1];
|
||||
_frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined
|
||||
}
|
||||
reversed = bc.reversed;
|
||||
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
|
||||
_skip = bc.skipAmount; //sacrificial pixels
|
||||
_len = bc.count + _skip;
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
if (_iType == I_NONE) return;
|
||||
uint16_t lenToCreate = _len;
|
||||
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus
|
||||
_busPtr = PolyBus::create(_iType, _pins, lenToCreate, nr, _frequencykHz);
|
||||
if (bc.doubleBuffer && !allocData(bc.count * (Bus::hasWhite(_type) + 3*Bus::hasRGB(_type)))) return; //warning: hardcoded channel count
|
||||
_buffering = bc.doubleBuffer;
|
||||
uint16_t lenToCreate = bc.count;
|
||||
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
|
||||
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz);
|
||||
_valid = (_busPtr != nullptr);
|
||||
_colorOrder = bc.colorOrder;
|
||||
DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, _len, bc.type, _pins[0],_pins[1],_iType);
|
||||
DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], _pins[1], _iType);
|
||||
}
|
||||
|
||||
void BusDigital::show() {
|
||||
PolyBus::show(_busPtr, _iType);
|
||||
if (!_valid) return;
|
||||
if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop
|
||||
size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
|
||||
for (size_t i=0; i<_len; i++) {
|
||||
size_t offset = i*channels;
|
||||
uint8_t co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder);
|
||||
uint32_t c;
|
||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs (_len is always a multiple of 3)
|
||||
switch (i%3) {
|
||||
case 0: c = RGBW32(_data[offset] , _data[offset+1], _data[offset+2], 0); break;
|
||||
case 1: c = RGBW32(_data[offset-1], _data[offset] , _data[offset+1], 0); break;
|
||||
case 2: c = RGBW32(_data[offset-2], _data[offset-1], _data[offset] , 0); break;
|
||||
}
|
||||
} else {
|
||||
c = RGBW32(_data[offset],_data[offset+1],_data[offset+2],(Bus::hasWhite(_type)?_data[offset+3]:0));
|
||||
}
|
||||
uint16_t pix = i;
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
|
||||
}
|
||||
#if !defined(STATUSLED) || STATUSLED>=0
|
||||
if (_skip) PolyBus::setPixelColor(_busPtr, _iType, 0, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
|
||||
#endif
|
||||
for (int i=1; i<_skip; i++) PolyBus::setPixelColor(_busPtr, _iType, i, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
|
||||
}
|
||||
PolyBus::show(_busPtr, _iType, !_buffering); // faster if buffer consistency is not important
|
||||
}
|
||||
|
||||
bool BusDigital::canShow() {
|
||||
if (!_valid) return true;
|
||||
return PolyBus::canShow(_busPtr, _iType);
|
||||
}
|
||||
|
||||
void BusDigital::setBrightness(uint8_t b) {
|
||||
if (_bri == b) return;
|
||||
//Fix for turning off onboard LED breaking bus
|
||||
#ifdef LED_BUILTIN
|
||||
if (_bri == 0 && b > 0) {
|
||||
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
|
||||
if (_bri == 0) { // && b > 0, covered by guard if above
|
||||
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) reinit();
|
||||
}
|
||||
#endif
|
||||
uint8_t prevBri = _bri;
|
||||
Bus::setBrightness(b);
|
||||
PolyBus::setBrightness(_busPtr, _iType, b);
|
||||
|
||||
if (_buffering) return;
|
||||
|
||||
// must update/repaint every LED in the NeoPixelBus buffer to the new brightness
|
||||
// the only case where repainting is unnecessary is when all pixels are set after the brightness change but before the next show
|
||||
// (which we can't rely on)
|
||||
uint16_t hwLen = _len;
|
||||
if (_type == TYPE_WS2812_1CH_X3) hwLen = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus
|
||||
for (uint_fast16_t i = 0; i < hwLen; i++) {
|
||||
// use 0 as color order, actual order does not matter here as we just update the channel values as-is
|
||||
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, i, 0),prevBri);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, i, c, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//If LEDs are skipped, it is possible to use the first as a status LED.
|
||||
//TODO only show if no new show due in the next 50ms
|
||||
void BusDigital::setStatusPixel(uint32_t c) {
|
||||
if (_skip && canShow()) {
|
||||
if (_valid && _skip) {
|
||||
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
|
||||
PolyBus::show(_busPtr, _iType);
|
||||
if (canShow()) PolyBus::show(_busPtr, _iType);
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814 || _type == TYPE_WS2812_1CH_X3) c = autoWhiteCalc(c);
|
||||
if (!_valid) return;
|
||||
if (Bus::hasWhite(_type)) c = autoWhiteCalc(c);
|
||||
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
if (reversed) pix = _len - pix -1;
|
||||
else pix += _skip;
|
||||
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
|
||||
uint16_t pOld = pix;
|
||||
pix = IC_INDEX_WS2812_1CH_3X(pix);
|
||||
uint32_t cOld = PolyBus::getPixelColor(_busPtr, _iType, pix, co);
|
||||
switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set)
|
||||
case 0: c = RGBW32(R(cOld), W(c) , B(cOld), 0); break;
|
||||
case 1: c = RGBW32(W(c) , G(cOld), B(cOld), 0); break;
|
||||
case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break;
|
||||
if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop
|
||||
size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
|
||||
size_t offset = pix*channels;
|
||||
if (Bus::hasRGB(_type)) {
|
||||
_data[offset++] = R(c);
|
||||
_data[offset++] = G(c);
|
||||
_data[offset++] = B(c);
|
||||
}
|
||||
if (Bus::hasWhite(_type)) _data[offset] = W(c);
|
||||
} else {
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
|
||||
uint16_t pOld = pix;
|
||||
pix = IC_INDEX_WS2812_1CH_3X(pix);
|
||||
uint32_t cOld = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co),_bri);
|
||||
switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set)
|
||||
case 0: c = RGBW32(R(cOld), W(c) , B(cOld), 0); break;
|
||||
case 1: c = RGBW32(W(c) , G(cOld), B(cOld), 0); break;
|
||||
case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break;
|
||||
}
|
||||
}
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
|
||||
}
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
|
||||
}
|
||||
|
||||
// returns original color if global buffering is enabled, else returns lossly restored color from bus
|
||||
uint32_t BusDigital::getPixelColor(uint16_t pix) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
else pix += _skip;
|
||||
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
|
||||
uint16_t pOld = pix;
|
||||
pix = IC_INDEX_WS2812_1CH_3X(pix);
|
||||
uint32_t c = PolyBus::getPixelColor(_busPtr, _iType, pix, co);
|
||||
switch (pOld % 3) { // get only the single channel
|
||||
case 0: c = RGBW32(G(c), G(c), G(c), G(c)); break;
|
||||
case 1: c = RGBW32(R(c), R(c), R(c), R(c)); break;
|
||||
case 2: c = RGBW32(B(c), B(c), B(c), B(c)); break;
|
||||
if (!_valid) return 0;
|
||||
if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop
|
||||
size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
|
||||
size_t offset = pix*channels;
|
||||
uint32_t c;
|
||||
if (!Bus::hasRGB(_type)) {
|
||||
c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]);
|
||||
} else {
|
||||
c = RGBW32(_data[offset], _data[offset+1], _data[offset+2], Bus::hasWhite(_type) ? _data[offset+3] : 0);
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
|
||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = _reversed ? B(c) : G(c); // should G and B be switched if _reversed?
|
||||
uint8_t b = _reversed ? G(c) : B(c);
|
||||
switch (pix % 3) { // get only the single channel
|
||||
case 0: c = RGBW32(g, g, g, g); break;
|
||||
case 1: c = RGBW32(r, r, r, r); break;
|
||||
case 2: c = RGBW32(b, b, b, b); break;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, co);
|
||||
}
|
||||
|
||||
uint8_t BusDigital::getPins(uint8_t* pinArray) {
|
||||
@@ -196,6 +272,7 @@ void BusDigital::setColorOrder(uint8_t colorOrder) {
|
||||
}
|
||||
|
||||
void BusDigital::reinit() {
|
||||
if (!_valid) return;
|
||||
PolyBus::begin(_busPtr, _iType, _pins);
|
||||
}
|
||||
|
||||
@@ -205,13 +282,15 @@ void BusDigital::cleanup() {
|
||||
_iType = I_NONE;
|
||||
_valid = false;
|
||||
_busPtr = nullptr;
|
||||
if (_data != nullptr) freeData();
|
||||
pinManager.deallocatePin(_pins[1], PinOwner::BusDigital);
|
||||
pinManager.deallocatePin(_pins[0], PinOwner::BusDigital);
|
||||
}
|
||||
|
||||
|
||||
BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
_valid = false;
|
||||
BusPwm::BusPwm(BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
||||
{
|
||||
if (!IS_PWM(bc.type)) return;
|
||||
uint8_t numPins = NUM_PWM_PINS(bc.type);
|
||||
_frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ;
|
||||
@@ -229,7 +308,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
uint8_t currentPin = bc.pins[i];
|
||||
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) {
|
||||
deallocatePins(); return;
|
||||
deallocatePins(); return;
|
||||
}
|
||||
_pins[i] = currentPin; //store only after allocatePin() succeeds
|
||||
#ifdef ESP8266
|
||||
@@ -239,7 +318,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
ledcAttachPin(_pins[i], _ledcStart + i);
|
||||
#endif
|
||||
}
|
||||
reversed = bc.reversed;
|
||||
_data = _pwmdata; // avoid malloc() and use stack
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
@@ -307,7 +386,7 @@ void BusPwm::show() {
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
uint8_t scaled = (_data[i] * _bri) / 255;
|
||||
if (reversed) scaled = 255 - scaled;
|
||||
if (_reversed) scaled = 255 - scaled;
|
||||
#ifdef ESP8266
|
||||
analogWrite(_pins[i], scaled);
|
||||
#else
|
||||
@@ -342,8 +421,10 @@ void BusPwm::deallocatePins() {
|
||||
}
|
||||
|
||||
|
||||
BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
_valid = false;
|
||||
BusOnOff::BusOnOff(BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
||||
, _onoffdata(0)
|
||||
{
|
||||
if (bc.type != TYPE_ONOFF) return;
|
||||
|
||||
uint8_t currentPin = bc.pins[0];
|
||||
@@ -352,7 +433,7 @@ BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
}
|
||||
_pin = currentPin; //store only after allocatePin() succeeds
|
||||
pinMode(_pin, OUTPUT);
|
||||
reversed = bc.reversed;
|
||||
_data = &_onoffdata; // avoid malloc() and use stack
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
@@ -363,18 +444,17 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
uint8_t w = W(c);
|
||||
|
||||
_data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
_data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) {
|
||||
if (!_valid) return 0;
|
||||
return RGBW32(_data, _data, _data, _data);
|
||||
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
|
||||
}
|
||||
|
||||
void BusOnOff::show() {
|
||||
if (!_valid) return;
|
||||
digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data);
|
||||
digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]);
|
||||
}
|
||||
|
||||
uint8_t BusOnOff::getPins(uint8_t* pinArray) {
|
||||
@@ -384,8 +464,10 @@ uint8_t BusOnOff::getPins(uint8_t* pinArray) {
|
||||
}
|
||||
|
||||
|
||||
BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
_valid = false;
|
||||
BusNetwork::BusNetwork(BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count)
|
||||
, _broadcastLock(false)
|
||||
{
|
||||
switch (bc.type) {
|
||||
case TYPE_NET_ARTNET_RGB:
|
||||
_rgbw = false;
|
||||
@@ -401,18 +483,13 @@ BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
break;
|
||||
}
|
||||
_UDPchannels = _rgbw ? 4 : 3;
|
||||
_data = (byte *)malloc(bc.count * _UDPchannels);
|
||||
if (_data == nullptr) return;
|
||||
memset(_data, 0, bc.count * _UDPchannels);
|
||||
_len = bc.count;
|
||||
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
|
||||
_broadcastLock = false;
|
||||
_valid = true;
|
||||
_valid = (allocData(_len * _UDPchannels) != nullptr);
|
||||
}
|
||||
|
||||
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (!_valid || pix >= _len) return;
|
||||
if (hasWhite()) c = autoWhiteCalc(c);
|
||||
if (_rgbw) c = autoWhiteCalc(c);
|
||||
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
uint16_t offset = pix * _UDPchannels;
|
||||
_data[offset] = R(c);
|
||||
@@ -424,7 +501,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
uint32_t BusNetwork::getPixelColor(uint16_t pix) {
|
||||
if (!_valid || pix >= _len) return 0;
|
||||
uint16_t offset = pix * _UDPchannels;
|
||||
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], _rgbw ? (_data[offset+3] << 24) : 0);
|
||||
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (_rgbw ? _data[offset+3] : 0));
|
||||
}
|
||||
|
||||
void BusNetwork::show() {
|
||||
@@ -444,8 +521,7 @@ uint8_t BusNetwork::getPins(uint8_t* pinArray) {
|
||||
void BusNetwork::cleanup() {
|
||||
_type = I_NONE;
|
||||
_valid = false;
|
||||
if (_data != nullptr) free(_data);
|
||||
_data = nullptr;
|
||||
freeData();
|
||||
}
|
||||
|
||||
|
||||
@@ -506,7 +582,7 @@ void BusManager::setStatusPixel(uint32_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) {
|
||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
Bus* b = busses[i];
|
||||
uint16_t bstart = b->getStart();
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
#define IC_INDEX_WS2812_2CH_3X(i) ((i)*2/3)
|
||||
#define WS2812_2CH_3X_SPANS_2_ICS(i) ((i)&0x01) // every other LED zone is on two different ICs
|
||||
|
||||
// flag for using double buffering in BusDigital
|
||||
extern bool useGlobalLedBuffer;
|
||||
|
||||
|
||||
//temporary struct for passing bus configuration to bus
|
||||
struct BusConfig {
|
||||
uint8_t type;
|
||||
@@ -30,15 +34,25 @@ struct BusConfig {
|
||||
uint8_t autoWhite;
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||
uint16_t frequency;
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U) {
|
||||
bool doubleBuffer;
|
||||
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U, bool dblBfr=false)
|
||||
: count(len)
|
||||
, start(pstart)
|
||||
, colorOrder(pcolorOrder)
|
||||
, reversed(rev)
|
||||
, skipAmount(skip)
|
||||
, autoWhite(aw)
|
||||
, frequency(clock_kHz)
|
||||
, doubleBuffer(dblBfr)
|
||||
{
|
||||
refreshReq = (bool) GET_BIT(busType,7);
|
||||
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
|
||||
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; autoWhite = aw; frequency = clock_kHz;
|
||||
uint8_t nPins = 1;
|
||||
size_t nPins = 1;
|
||||
if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
|
||||
else if (type > 47) nPins = 2;
|
||||
else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||
for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
}
|
||||
|
||||
//validates start and length and extends total if needed
|
||||
@@ -54,6 +68,7 @@ struct BusConfig {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Defines an LED Strip and its color ordering.
|
||||
struct ColorOrderMapEntry {
|
||||
uint16_t start;
|
||||
@@ -64,9 +79,7 @@ struct ColorOrderMapEntry {
|
||||
struct ColorOrderMap {
|
||||
void add(uint16_t start, uint16_t len, uint8_t colorOrder);
|
||||
|
||||
uint8_t count() const {
|
||||
return _count;
|
||||
}
|
||||
uint8_t count() const { return _count; }
|
||||
|
||||
void reset() {
|
||||
_count = 0;
|
||||
@@ -87,56 +100,63 @@ struct ColorOrderMap {
|
||||
ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS];
|
||||
};
|
||||
|
||||
|
||||
//parent class of BusDigital, BusPwm, and BusNetwork
|
||||
class Bus {
|
||||
public:
|
||||
Bus(uint8_t type, uint16_t start, uint8_t aw)
|
||||
: _bri(255)
|
||||
, _len(1)
|
||||
Bus(uint8_t type, uint16_t start, uint8_t aw, uint16_t len = 1, bool reversed = false, bool refresh = false)
|
||||
: _type(type)
|
||||
, _bri(255)
|
||||
, _start(start)
|
||||
, _len(len)
|
||||
, _reversed(reversed)
|
||||
, _valid(false)
|
||||
, _needsRefresh(false)
|
||||
, _needsRefresh(refresh)
|
||||
, _data(nullptr) // keep data access consistent across all types of buses
|
||||
{
|
||||
_type = type;
|
||||
_start = start;
|
||||
_autoWhiteMode = Bus::hasWhite(_type) ? aw : RGBW_MODE_MANUAL_ONLY;
|
||||
};
|
||||
|
||||
virtual ~Bus() {} //throw the bus under the bus
|
||||
|
||||
virtual void show() = 0;
|
||||
virtual bool canShow() { return true; }
|
||||
virtual void setStatusPixel(uint32_t c) {}
|
||||
virtual bool canShow() { return true; }
|
||||
virtual void setStatusPixel(uint32_t c) {}
|
||||
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
|
||||
virtual uint32_t getPixelColor(uint16_t pix) { return 0; }
|
||||
virtual void setBrightness(uint8_t b) { _bri = b; };
|
||||
virtual void setBrightness(uint8_t b) { _bri = b; };
|
||||
virtual void cleanup() = 0;
|
||||
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
|
||||
virtual uint16_t getLength() { return _len; }
|
||||
virtual void setColorOrder() {}
|
||||
virtual uint8_t getColorOrder() { return COL_ORDER_RGB; }
|
||||
virtual uint8_t skippedLeds() { return 0; }
|
||||
virtual uint16_t getFrequency() { return 0U; }
|
||||
inline uint16_t getStart() { return _start; }
|
||||
inline void setStart(uint16_t start) { _start = start; }
|
||||
inline uint8_t getType() { return _type; }
|
||||
inline bool isOk() { return _valid; }
|
||||
inline bool isOffRefreshRequired() { return _needsRefresh; }
|
||||
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
|
||||
virtual uint16_t getLength() { return _len; }
|
||||
virtual void setColorOrder() {}
|
||||
virtual uint8_t getColorOrder() { return COL_ORDER_RGB; }
|
||||
virtual uint8_t skippedLeds() { return 0; }
|
||||
virtual uint16_t getFrequency() { return 0U; }
|
||||
inline void setReversed(bool reversed) { _reversed = reversed; }
|
||||
inline uint16_t getStart() { return _start; }
|
||||
inline void setStart(uint16_t start) { _start = start; }
|
||||
inline uint8_t getType() { return _type; }
|
||||
inline bool isOk() { return _valid; }
|
||||
inline bool isReversed() { return _reversed; }
|
||||
inline bool isOffRefreshRequired() { return _needsRefresh; }
|
||||
bool containsPixel(uint16_t pix) { return pix >= _start && pix < _start+_len; }
|
||||
|
||||
virtual bool hasRGB() {
|
||||
if ((_type >= TYPE_WS2812_1CH && _type <= TYPE_WS2812_WWA) || _type == TYPE_ANALOG_1CH || _type == TYPE_ANALOG_2CH || _type == TYPE_ONOFF) return false;
|
||||
virtual bool hasRGB(void) { return Bus::hasRGB(_type); }
|
||||
static bool hasRGB(uint8_t type) {
|
||||
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF) return false;
|
||||
return true;
|
||||
}
|
||||
virtual bool hasWhite() { return Bus::hasWhite(_type); }
|
||||
virtual bool hasWhite(void) { return Bus::hasWhite(_type); }
|
||||
static bool hasWhite(uint8_t type) {
|
||||
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; // digital types with white channel
|
||||
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel
|
||||
if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel
|
||||
return false;
|
||||
}
|
||||
virtual bool hasCCT() {
|
||||
if (_type == TYPE_WS2812_2CH_X3 || _type == TYPE_WS2812_WWA ||
|
||||
_type == TYPE_ANALOG_2CH || _type == TYPE_ANALOG_5CH) return true;
|
||||
virtual bool hasCCT(void) { return Bus::hasCCT(_type); }
|
||||
static bool hasCCT(uint8_t type) {
|
||||
if (type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA ||
|
||||
type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_5CH) return true;
|
||||
return false;
|
||||
}
|
||||
static void setCCT(uint16_t cct) {
|
||||
@@ -155,107 +175,87 @@ class Bus {
|
||||
inline static void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
|
||||
inline static uint8_t getGlobalAWMode() { return _gAWM; }
|
||||
|
||||
bool reversed = false;
|
||||
|
||||
protected:
|
||||
uint8_t _type;
|
||||
uint8_t _bri;
|
||||
uint16_t _start;
|
||||
uint16_t _len;
|
||||
bool _reversed;
|
||||
bool _valid;
|
||||
bool _needsRefresh;
|
||||
uint8_t _autoWhiteMode;
|
||||
uint8_t *_data;
|
||||
static uint8_t _gAWM;
|
||||
static int16_t _cct;
|
||||
static uint8_t _cctBlend;
|
||||
|
||||
uint32_t autoWhiteCalc(uint32_t c);
|
||||
uint8_t *allocData(size_t size = 1);
|
||||
void freeData() { if (_data != nullptr) free(_data); _data = nullptr; }
|
||||
};
|
||||
|
||||
|
||||
class BusDigital : public Bus {
|
||||
public:
|
||||
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
||||
~BusDigital() { cleanup(); }
|
||||
|
||||
inline void show();
|
||||
|
||||
void show();
|
||||
bool canShow();
|
||||
|
||||
void setBrightness(uint8_t b);
|
||||
|
||||
void setStatusPixel(uint32_t c);
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
uint8_t getColorOrder() {
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
uint16_t getLength() {
|
||||
return _len - _skip;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
|
||||
void setColorOrder(uint8_t colorOrder);
|
||||
|
||||
uint8_t skippedLeds() {
|
||||
return _skip;
|
||||
}
|
||||
|
||||
uint16_t getFrequency() { return _frequencykHz; }
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
uint8_t getColorOrder() { return _colorOrder; }
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
uint8_t skippedLeds() { return _skip; }
|
||||
uint16_t getFrequency() { return _frequencykHz; }
|
||||
void reinit();
|
||||
|
||||
void cleanup();
|
||||
|
||||
~BusDigital() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _colorOrder = COL_ORDER_GRB;
|
||||
uint8_t _pins[2] = {255, 255};
|
||||
uint8_t _iType = 0; //I_NONE;
|
||||
uint8_t _skip = 0;
|
||||
uint16_t _frequencykHz = 0U;
|
||||
void * _busPtr = nullptr;
|
||||
uint8_t _skip;
|
||||
uint8_t _colorOrder;
|
||||
uint8_t _pins[2];
|
||||
uint8_t _iType;
|
||||
uint16_t _frequencykHz;
|
||||
void * _busPtr;
|
||||
const ColorOrderMap &_colorOrderMap;
|
||||
bool _buffering; // temporary until we figure out why comparison "_data != nullptr" causes severe FPS drop
|
||||
|
||||
inline uint32_t restoreColorLossy(uint32_t c, uint8_t restoreBri) {
|
||||
if (restoreBri < 255) {
|
||||
uint8_t* chan = (uint8_t*) &c;
|
||||
for (uint_fast8_t i=0; i<4; i++) {
|
||||
uint_fast16_t val = chan[i];
|
||||
chan[i] = ((val << 8) + restoreBri) / (restoreBri + 1); //adding _bri slighly improves recovery / stops degradation on re-scale
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BusPwm : public Bus {
|
||||
public:
|
||||
BusPwm(BusConfig &bc);
|
||||
~BusPwm() { cleanup(); }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
//does no index check
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
void show();
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix); //does no index check
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
uint16_t getFrequency() { return _frequency; }
|
||||
|
||||
void cleanup() {
|
||||
deallocatePins();
|
||||
}
|
||||
|
||||
~BusPwm() {
|
||||
cleanup();
|
||||
}
|
||||
void show();
|
||||
void cleanup() { deallocatePins(); }
|
||||
|
||||
private:
|
||||
uint8_t _pins[5] = {255, 255, 255, 255, 255};
|
||||
uint8_t _data[5] = {0};
|
||||
uint8_t _pins[5];
|
||||
uint8_t _pwmdata[5];
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t _ledcStart = 255;
|
||||
uint8_t _ledcStart;
|
||||
#endif
|
||||
uint16_t _frequency = 0U;
|
||||
uint16_t _frequency;
|
||||
|
||||
void deallocatePins();
|
||||
};
|
||||
@@ -264,72 +264,46 @@ class BusPwm : public Bus {
|
||||
class BusOnOff : public Bus {
|
||||
public:
|
||||
BusOnOff(BusConfig &bc);
|
||||
~BusOnOff() { cleanup(); }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
void show();
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
|
||||
void cleanup() {
|
||||
pinManager.deallocatePin(_pin, PinOwner::BusOnOff);
|
||||
}
|
||||
|
||||
~BusOnOff() {
|
||||
cleanup();
|
||||
}
|
||||
void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); }
|
||||
|
||||
private:
|
||||
uint8_t _pin = 255;
|
||||
uint8_t _data = 0;
|
||||
uint8_t _pin;
|
||||
uint8_t _onoffdata;
|
||||
};
|
||||
|
||||
|
||||
class BusNetwork : public Bus {
|
||||
public:
|
||||
BusNetwork(BusConfig &bc);
|
||||
~BusNetwork() { cleanup(); }
|
||||
|
||||
bool hasRGB() { return true; }
|
||||
bool hasRGB() { return true; }
|
||||
bool hasWhite() { return _rgbw; }
|
||||
|
||||
bool canShow() { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
void show();
|
||||
|
||||
bool canShow() {
|
||||
// this should be a return value from UDP routine if it is still sending data out
|
||||
return !_broadcastLock;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
|
||||
uint16_t getLength() {
|
||||
return _len;
|
||||
}
|
||||
|
||||
void cleanup();
|
||||
|
||||
~BusNetwork() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
IPAddress _client;
|
||||
uint8_t _UDPtype;
|
||||
uint8_t _UDPchannels;
|
||||
bool _rgbw;
|
||||
bool _broadcastLock;
|
||||
byte *_data;
|
||||
};
|
||||
|
||||
|
||||
class BusManager {
|
||||
public:
|
||||
BusManager() {};
|
||||
BusManager() : numBusses(0) {};
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
static uint32_t memUsage(BusConfig &bc);
|
||||
@@ -340,38 +314,24 @@ class BusManager {
|
||||
void removeAll();
|
||||
|
||||
void show();
|
||||
|
||||
void setStatusPixel(uint32_t c);
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
|
||||
|
||||
void setBrightness(uint8_t b);
|
||||
|
||||
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
bool canAllShow();
|
||||
void setStatusPixel(uint32_t c);
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
void setBrightness(uint8_t b);
|
||||
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
Bus* getBus(uint8_t busNr);
|
||||
|
||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||
uint16_t getTotalLength();
|
||||
inline uint8_t getNumBusses() const { return numBusses; }
|
||||
|
||||
inline void updateColorOrderMap(const ColorOrderMap &com) {
|
||||
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
|
||||
}
|
||||
|
||||
inline const ColorOrderMap& getColorOrderMap() const {
|
||||
return colorOrderMap;
|
||||
}
|
||||
|
||||
inline uint8_t getNumBusses() {
|
||||
return numBusses;
|
||||
}
|
||||
inline void updateColorOrderMap(const ColorOrderMap &com) { memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); }
|
||||
inline const ColorOrderMap& getColorOrderMap() const { return colorOrderMap; }
|
||||
|
||||
private:
|
||||
uint8_t numBusses = 0;
|
||||
uint8_t numBusses;
|
||||
Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||
ColorOrderMap colorOrderMap;
|
||||
|
||||
@@ -381,4 +341,4 @@ class BusManager {
|
||||
return j;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -122,6 +122,9 @@
|
||||
#define I_SS_LPO_3 48
|
||||
|
||||
|
||||
// In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly
|
||||
// unfortunately that may apply Gamma correction to pre-calculated palettes which is undesired
|
||||
|
||||
/*** ESP8266 Neopixel methods ***/
|
||||
#ifdef ESP8266
|
||||
//RGB
|
||||
@@ -247,7 +250,11 @@
|
||||
#define B_SS_LPO_3 NeoPixelBusLg<Lpd6803GrbFeature, Lpd6803Method, NeoGammaNullMethod>
|
||||
|
||||
//WS2801
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
#define B_HS_WS1_3 NeoPixelBusLg<NeoRbgFeature, Ws2801MethodBase<TwoWireHspiImple<SpiSpeedHz>>, NeoGammaNullMethod>
|
||||
#else
|
||||
#define B_HS_WS1_3 NeoPixelBusLg<NeoRbgFeature, Ws2801SpiHzMethod, NeoGammaNullMethod>
|
||||
#endif
|
||||
#define B_SS_WS1_3 NeoPixelBusLg<NeoRbgFeature, Ws2801Method, NeoGammaNullMethod>
|
||||
|
||||
//P9813
|
||||
@@ -273,6 +280,7 @@ class PolyBus {
|
||||
#endif
|
||||
if (clock_kHz) dotStar_strip->SetMethodSettings(NeoSpiSettings((uint32_t)clock_kHz*1000));
|
||||
}
|
||||
|
||||
// Begin & initialize the PixelSettings for TM1814 strips.
|
||||
template <class T>
|
||||
static void beginTM1814(void* busPtr) {
|
||||
@@ -281,6 +289,7 @@ class PolyBus {
|
||||
// Max current for each LED (22.5 mA).
|
||||
tm1814_strip->SetPixelSettings(NeoTm1814Settings(/*R*/225, /*G*/225, /*B*/225, /*W*/225));
|
||||
}
|
||||
|
||||
static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) {
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
@@ -383,7 +392,8 @@ class PolyBus {
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) {
|
||||
void* busPtr = nullptr;
|
||||
switch (busType) {
|
||||
@@ -484,104 +494,106 @@ class PolyBus {
|
||||
}
|
||||
begin(busPtr, busType, pins, clock_kHz);
|
||||
return busPtr;
|
||||
};
|
||||
static void show(void* busPtr, uint8_t busType) {
|
||||
}
|
||||
|
||||
static void show(void* busPtr, uint8_t busType, bool consistent = true) {
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Show(); break;
|
||||
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Show(); break;
|
||||
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->Show(); break;
|
||||
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->Show(); break;
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->Show(); break;
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->Show(); break;
|
||||
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(); break;
|
||||
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(); break;
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->Show(); break;
|
||||
// case I_32_BB_UCS_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(); break;
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(); break;
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Show(); break;
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->Show(); break;
|
||||
case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->Show(); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Show(); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(); break;
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(consistent); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(consistent); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(consistent); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(consistent); break;
|
||||
case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(consistent); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Show(consistent); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(consistent); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(consistent); break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static bool canShow(void* busPtr, uint8_t busType) {
|
||||
switch (busType) {
|
||||
case I_NONE: return true;
|
||||
@@ -678,7 +690,8 @@ class PolyBus {
|
||||
case I_SS_P98_3: return (static_cast<B_SS_P98_3*>(busPtr))->CanShow(); break;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) {
|
||||
uint8_t r = c >> 16;
|
||||
uint8_t g = c >> 8;
|
||||
@@ -798,7 +811,8 @@ class PolyBus {
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) {
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
@@ -895,7 +909,8 @@ class PolyBus {
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
|
||||
RgbwColor col(0,0,0,0);
|
||||
switch (busType) {
|
||||
@@ -1202,4 +1217,4 @@ class PolyBus {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -21,6 +21,7 @@ void shortPressAction(uint8_t b)
|
||||
case 1: ++effectCurrent %= strip.getModeCount(); stateChanged = true; colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
|
||||
}
|
||||
|
||||
@@ -42,6 +43,7 @@ void longPressAction(uint8_t b)
|
||||
case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
|
||||
}
|
||||
} else {
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
|
||||
}
|
||||
|
||||
@@ -63,6 +65,7 @@ void doublePressAction(uint8_t b)
|
||||
case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET);
|
||||
}
|
||||
|
||||
@@ -153,6 +156,7 @@ void handleAnalog(uint8_t b)
|
||||
#ifdef ESP8266
|
||||
rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit
|
||||
#else
|
||||
if ((btnPin[b] < 0) || (digitalPinToAnalogChannel(btnPin[b]) < 0)) return; // pin must support analog ADC - newer esp32 frameworks throw lots of warnings otherwise
|
||||
rawReading = analogRead(btnPin[b]); // collect at full 12bit resolution
|
||||
#endif
|
||||
yield(); // keep WiFi task running - analog read may take several millis on ESP8266
|
||||
@@ -185,7 +189,7 @@ void handleAnalog(uint8_t b)
|
||||
if (aRead == 0) {
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
} else{
|
||||
} else {
|
||||
bri = aRead;
|
||||
}
|
||||
} else if (macroDoublePress[b] == 249) {
|
||||
@@ -262,7 +266,7 @@ void handleButton()
|
||||
shortPressAction(b);
|
||||
buttonPressedBefore[b] = true;
|
||||
buttonPressedTime[b] = now; // continually update (for debouncing to work in release handler)
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!buttonPressedBefore[b]) buttonPressedTime[b] = now;
|
||||
@@ -283,7 +287,7 @@ void handleButton()
|
||||
// released after rising-edge short press action
|
||||
if (macroButton[b] && macroButton[b] == macroLongPress[b] && macroButton[b] == macroDoublePress[b]) {
|
||||
if (dur > WLED_DEBOUNCE_THRESHOLD) buttonPressedBefore[b] = false; // debounce, blocks button for 50 ms once it has been released
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} // too short "press", debounce
|
||||
|
||||
@@ -90,7 +90,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||
CJSON(strip.useLedsArray, hw_led[F("ld")]);
|
||||
CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
@@ -134,7 +134,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (fromFS || !ins.isNull()) {
|
||||
uint8_t s = 0; // bus iterator
|
||||
if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback
|
||||
uint32_t mem = 0;
|
||||
uint32_t mem = 0, globalBufMem = 0;
|
||||
uint16_t maxlen = 0;
|
||||
bool busesChanged = false;
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
|
||||
@@ -160,12 +161,16 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
||||
uint8_t AWmode = elm[F("rgbwm")] | autoWhiteMode;
|
||||
if (fromFS) {
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz);
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer);
|
||||
mem += BusManager::memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
|
||||
if (useGlobalLedBuffer && start + length > maxlen) {
|
||||
maxlen = start + length;
|
||||
globalBufMem = maxlen * 4;
|
||||
}
|
||||
if (mem + globalBufMem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
|
||||
} else {
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
|
||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer);
|
||||
busesChanged = true;
|
||||
}
|
||||
s++;
|
||||
@@ -173,7 +178,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
doInitBusses = busesChanged;
|
||||
// finalization done in beginStrip()
|
||||
}
|
||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||
if (hw_led["rev"]) busses.getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
|
||||
|
||||
// read color order map configuration
|
||||
JsonArray hw_com = hw[F("com")];
|
||||
@@ -197,6 +202,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
disablePullUp = !pull;
|
||||
JsonArray hw_btn_ins = btn_obj[F("ins")];
|
||||
if (!hw_btn_ins.isNull()) {
|
||||
for (uint8_t b = 0; b < WLED_MAX_BUTTONS; b++) { // deallocate existing button pins
|
||||
pinManager.deallocatePin(btnPin[b], PinOwner::Button); // does nothing if trying to deallocate a pin with PinOwner != Button
|
||||
}
|
||||
uint8_t s = 0;
|
||||
for (JsonObject btn : hw_btn_ins) {
|
||||
CJSON(buttonType[s], btn["type"]);
|
||||
@@ -264,6 +272,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
|
||||
if (hw_ir_pin > -2) {
|
||||
pinManager.deallocatePin(irPin, PinOwner::IR);
|
||||
if (pinManager.allocatePin(hw_ir_pin, false, PinOwner::IR)) {
|
||||
irPin = hw_ir_pin;
|
||||
} else {
|
||||
@@ -276,6 +285,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
JsonObject relay = hw[F("relay")];
|
||||
int hw_relay_pin = relay["pin"] | -2;
|
||||
if (hw_relay_pin > -2) {
|
||||
pinManager.deallocatePin(rlyPin, PinOwner::Relay);
|
||||
if (pinManager.allocatePin(hw_relay_pin,true, PinOwner::Relay)) {
|
||||
rlyPin = hw_relay_pin;
|
||||
pinMode(rlyPin, OUTPUT);
|
||||
@@ -297,9 +307,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
||||
if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
||||
#ifdef ESP32
|
||||
Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called prior)
|
||||
if (!Wire.setPins(i2c_sda, i2c_scl)) { i2c_scl = i2c_sda = -1; } // this will fail if Wire is initilised (Wire.begin() called prior)
|
||||
else Wire.begin();
|
||||
#else
|
||||
Wire.begin(i2c_sda, i2c_scl);
|
||||
#endif
|
||||
Wire.begin();
|
||||
} else {
|
||||
i2c_sda = -1;
|
||||
i2c_scl = -1;
|
||||
@@ -336,7 +348,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
||||
else gammaCorrectCol = false;
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
||||
if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal);
|
||||
if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
} else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
@@ -430,17 +442,24 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
JsonObject if_mqtt = interfaces["mqtt"];
|
||||
CJSON(mqttEnabled, if_mqtt["en"]);
|
||||
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
|
||||
getStringFromJson(mqttServer, if_mqtt[F("broker")], MQTT_MAX_SERVER_LEN+1);
|
||||
CJSON(mqttPort, if_mqtt["port"]); // 1883
|
||||
getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
|
||||
getStringFromJson(mqttPass, if_mqtt["psk"], 65); //normally not present due to security
|
||||
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
|
||||
|
||||
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
|
||||
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
|
||||
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], MQTT_MAX_TOPIC_LEN+1); // "wled/test"
|
||||
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], MQTT_MAX_TOPIC_LEN+1); // ""
|
||||
CJSON(retainMqttMsg, if_mqtt[F("rtn")]);
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
JsonObject remote = doc["remote"];
|
||||
CJSON(enable_espnow_remote, remote[F("remote_enabled")]);
|
||||
getStringFromJson(linked_remote, remote[F("linked_remote")], 13);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
JsonObject if_hue = interfaces["hue"];
|
||||
CJSON(huePollingEnabled, if_hue["en"]);
|
||||
@@ -697,7 +716,7 @@ void serializeConfig() {
|
||||
hw_led[F("cb")] = strip.cctBlending;
|
||||
hw_led["fps"] = strip.getTargetFps();
|
||||
hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override
|
||||
hw_led[F("ld")] = strip.useLedsArray;
|
||||
hw_led[F("ld")] = useGlobalLedBuffer;
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
@@ -732,7 +751,7 @@ void serializeConfig() {
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
|
||||
ins[F("order")] = bus->getColorOrder();
|
||||
ins["rev"] = bus->reversed;
|
||||
ins["rev"] = bus->isReversed();
|
||||
ins[F("skip")] = bus->skippedLeds();
|
||||
ins["type"] = bus->getType() & 0x7F;
|
||||
ins["ref"] = bus->isOffRefreshRequired();
|
||||
@@ -893,6 +912,13 @@ void serializeConfig() {
|
||||
if_mqtt_topics[F("group")] = mqttGroupTopic;
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
JsonObject remote = doc.createNestedObject(F("remote"));
|
||||
remote[F("remote_enabled")] = enable_espnow_remote;
|
||||
remote[F("linked_remote")] = linked_remote;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
JsonObject if_hue = interfaces.createNestedObject("hue");
|
||||
if_hue["en"] = huePollingEnabled;
|
||||
|
||||
@@ -302,7 +302,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
||||
}
|
||||
|
||||
//gamma 2.8 lookup table used for color correction
|
||||
static byte gammaT[] = {
|
||||
uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
@@ -320,27 +320,22 @@ static byte gammaT[] = {
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
|
||||
uint8_t gamma8_cal(uint8_t b, float gamma)
|
||||
{
|
||||
return (int)(powf((float)b / 255.0f, gamma) * 255.0f + 0.5f);
|
||||
}
|
||||
|
||||
// re-calculates & fills gamma table
|
||||
void calcGammaTable(float gamma)
|
||||
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||
{
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
gammaT[i] = gamma8_cal(i, gamma);
|
||||
for (size_t i = 0; i < 256; i++) {
|
||||
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
// used for individual channel or brightness gamma correction
|
||||
uint8_t gamma8(uint8_t b)
|
||||
uint8_t NeoGammaWLEDMethod::Correct(uint8_t value)
|
||||
{
|
||||
return gammaT[b];
|
||||
if (!gammaCorrectCol) return value;
|
||||
return gammaT[value];
|
||||
}
|
||||
|
||||
// used for color gamma correction
|
||||
uint32_t gamma32(uint32_t color)
|
||||
uint32_t NeoGammaWLEDMethod::Correct32(uint32_t color)
|
||||
{
|
||||
if (!gammaCorrectCol) return color;
|
||||
uint8_t w = W(color);
|
||||
|
||||
@@ -91,6 +91,21 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WLED_MAX_SEGNAME_LEN
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_SEGNAME_LEN 32
|
||||
#else
|
||||
#define WLED_MAX_SEGNAME_LEN 64
|
||||
#endif
|
||||
#else
|
||||
#if WLED_MAX_SEGNAME_LEN<32
|
||||
#undef WLED_MAX_SEGNAME_LEN
|
||||
#define WLED_MAX_SEGNAME_LEN 32
|
||||
#else
|
||||
#warning WLED UI does not support modified maximum segment name length!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Usermod IDs
|
||||
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
||||
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
|
||||
@@ -132,7 +147,9 @@
|
||||
#define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h"
|
||||
#define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h
|
||||
#define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h
|
||||
#define USERMOD_ID_KLIPPER 40 // Usermod Klipper percentage
|
||||
#define USERMOD_ID_KLIPPER 40 //Usermod Klipper percentage
|
||||
#define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h"
|
||||
#define USERMOD_ID_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@@ -320,7 +337,8 @@
|
||||
|
||||
// WLED Error modes
|
||||
#define ERR_NONE 0 // All good :)
|
||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)
|
||||
#define ERR_DENIED 1 // Permission denied
|
||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) OBSOLETE
|
||||
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
|
||||
#define ERR_JSON 9 // JSON parsing failed (input too large?)
|
||||
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
||||
@@ -332,12 +350,29 @@
|
||||
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
|
||||
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
|
||||
|
||||
//Timer mode types
|
||||
// Timer mode types
|
||||
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
|
||||
#define NL_MODE_FADE 1 //Fade to target brightness gradually
|
||||
#define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color gradually
|
||||
#define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min.
|
||||
|
||||
// Settings sub page IDs
|
||||
#define SUBPAGE_MENU 0
|
||||
#define SUBPAGE_WIFI 1
|
||||
#define SUBPAGE_LEDS 2
|
||||
#define SUBPAGE_UI 3
|
||||
#define SUBPAGE_SYNC 4
|
||||
#define SUBPAGE_TIME 5
|
||||
#define SUBPAGE_SEC 6
|
||||
#define SUBPAGE_DMX 7
|
||||
#define SUBPAGE_UM 8
|
||||
#define SUBPAGE_UPDATE 9
|
||||
#define SUBPAGE_2D 10
|
||||
#define SUBPAGE_LOCK 251
|
||||
#define SUBPAGE_PINREQ 252
|
||||
#define SUBPAGE_CSS 253
|
||||
#define SUBPAGE_JS 254
|
||||
#define SUBPAGE_WELCOME 255
|
||||
|
||||
#define NTP_PACKET_SIZE 48
|
||||
|
||||
@@ -370,7 +405,7 @@
|
||||
#ifdef ESP8266
|
||||
#define SETTINGS_STACK_BUF_SIZE 2048
|
||||
#else
|
||||
#define SETTINGS_STACK_BUF_SIZE 3096
|
||||
#define SETTINGS_STACK_BUF_SIZE 3608 // warning: quite a large value for stack
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
@@ -442,7 +477,10 @@
|
||||
#define DEFAULT_LED_COUNT 30
|
||||
#endif
|
||||
|
||||
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
|
||||
#define INTERFACE_UPDATE_COOLDOWN 1000 // time in ms to wait between websockets, alexa, and MQTT updates
|
||||
|
||||
#define PIN_RETRY_COOLDOWN 3000 // time in ms after an incorrect attempt PIN and OTA pass will be rejected even if correct
|
||||
#define PIN_TIMEOUT 900000 // time in ms after which the PIN will be required again, 15 minutes
|
||||
|
||||
// HW_PIN_SCL & HW_PIN_SDA are used for information in usermods settings page and usermods themselves
|
||||
// which GPIO pins are actually used in a hardwarea layout (controller board)
|
||||
|
||||
@@ -42,6 +42,6 @@
|
||||
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAbUExURQAAAAB81gCU/zKq/////9bW1oCAgGhoaAAAAGPLX8AAAAAJdFJOU///////////AFNPeBIAAAAJcEhZcwAADsAAAA7AAWrWiQkAAACdSURBVDhPxc9bDoUgEANQebP/FUuHMjBGY/B+3EYR7RH0qC/ZBc6HwCljgHO+xZIVSI2sYgHaG7EBWh8jWoxTrCBFdDJ+BD4lbIHxAcz8APAVLTsrZE4eQD5qzt3cAFTYokC4YCN9Gybgu4yAQtBFLQXHuHABA7JMeOEC/E0W5uy9gv4vo5QHK2i7yq2C8UABM4HmL+CSTXCTF1DrCX6+Gp9zB5dsAAAAAElFTkSuQmCC">
|
||||
<h1>404 Not Found</h1>
|
||||
<b>Akemi does not know where you are headed...</b><br><br>
|
||||
<button onclick="window.location.href='/sliders'">Back to controls</button>
|
||||
<button onclick="window.location.href='../?sliders'">Back to controls</button>
|
||||
</body>
|
||||
</html>
|
||||
@@ -134,7 +134,7 @@ button {
|
||||
|
||||
.off {
|
||||
color: var(--c-6) !important;
|
||||
cursor: default !important;
|
||||
/* cursor: default !important; */
|
||||
}
|
||||
|
||||
.top .icons, .bot .icons {
|
||||
@@ -410,6 +410,7 @@ button {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
#sliders .labels {
|
||||
@@ -418,7 +419,7 @@ button {
|
||||
}
|
||||
|
||||
.slider {
|
||||
max-width: 300px;
|
||||
/*max-width: 300px;*/
|
||||
/* margin: 5px auto; add 5px; if you want some vertical space but looks ugly */
|
||||
border-radius: 24px;
|
||||
position: relative;
|
||||
@@ -434,12 +435,16 @@ button {
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#sliders .slider {
|
||||
padding-right: 64px; /* offset for bubble */
|
||||
}
|
||||
|
||||
#sliders .slider, #info .slider {
|
||||
background-color: var(--c-2);
|
||||
}
|
||||
|
||||
#sliders .sliderwrap, .sbs .sliderwrap {
|
||||
left: 16px; /* offset for icon */
|
||||
left: 32px; /* offset for icon */
|
||||
}
|
||||
|
||||
.filter, .option {
|
||||
@@ -685,18 +690,19 @@ img {
|
||||
|
||||
.sliderbubble {
|
||||
width: 24px;
|
||||
position: relative;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border-radius: 10px;
|
||||
border-radius: 16px;
|
||||
background: var(--c-3);
|
||||
color: var(--c-f);
|
||||
padding: 2px 4px;
|
||||
padding: 4px;
|
||||
font-size: 14px;
|
||||
right: 3px;
|
||||
transition: visibility 0.25s ease, opacity 0.25s ease;
|
||||
right: 6px;
|
||||
transition: visibility .25s ease,opacity .25s ease;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
left: 8px;
|
||||
/* left: 8px; */
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
output.sliderbubbleshow {
|
||||
@@ -1004,7 +1010,7 @@ textarea {
|
||||
width: 50px !important;
|
||||
}
|
||||
|
||||
.segname, .pname {
|
||||
.segname, .pname, .bname {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
@@ -1014,6 +1020,9 @@ textarea {
|
||||
max-width: 170px;
|
||||
position: relative;
|
||||
}
|
||||
.bname {
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.segname .flr, .pname .flr {
|
||||
transform: rotate(0deg);
|
||||
@@ -1022,8 +1031,9 @@ textarea {
|
||||
|
||||
/* segment power wrapper */
|
||||
.sbs {
|
||||
padding: 1px 0 1px 20px;
|
||||
/*padding: 1px 0 1px 20px;*/
|
||||
display: var(--sgp);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pname {
|
||||
@@ -1538,8 +1548,11 @@ TD .checkmark, TD .radiomark {
|
||||
#sliders .sliderbubble {
|
||||
display: none;
|
||||
}
|
||||
.sliderwrap {
|
||||
width: calc(100% - 28px);
|
||||
#sliders .sliderwrap, .sbs .sliderwrap {
|
||||
width: calc(100% - 42px);
|
||||
}
|
||||
#sliders .slider {
|
||||
padding-right: 0;
|
||||
}
|
||||
#sliders .sliderwrap {
|
||||
left: 12px;
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons"></i><p class="tab-label">Peek</p></button>
|
||||
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
||||
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button>
|
||||
<button onclick="window.location.href='/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button onclick="window.location.href=getURL('/settings');"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
||||
</div>
|
||||
<div id="briwrap">
|
||||
@@ -88,7 +88,7 @@
|
||||
<div class ="container">
|
||||
<div id="Colors" class="tabcontent">
|
||||
<div id="picker" class="noslide"></div>
|
||||
<div id="hwrap" class="slider">
|
||||
<div id="hwrap" class="slider" style="margin-top: 20px;">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderH" class="noslide" oninput="fromH()" onchange="setColor(0)" max="359" min="0" type="range" value="0" step="any">
|
||||
<div class="sliderdisplay" style="background: linear-gradient(90deg, #f00 2%, #ff0 19%, #0f0 35%, #0ff 52%, #00f 68%, #f0f 85%, #f00)"></div>
|
||||
@@ -199,7 +199,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="btn btn-xs" type="button" onclick="window.location.href=(loc?'http://'+locip:'')+'/cpal.htm'"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,7 +363,7 @@
|
||||
<div>
|
||||
<button class="btn infobtn" onclick="requestJson()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn infobtn" onclick="window.open('/update','_self');">Update WLED</button>
|
||||
<button class="btn infobtn" onclick="window.open(getURL('/update'),'_self');">Update WLED</button>
|
||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button>
|
||||
</div>
|
||||
<br>
|
||||
@@ -379,8 +379,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mliveview2D" class="modal">
|
||||
<div id="kliveview2D" style="width:100%; height:100%">Loading...</div><br>
|
||||
<div id="mlv2D" class="modal">
|
||||
<div id="klv2D" style="width:100%; height:100%">Loading...</div>
|
||||
</div>
|
||||
|
||||
<div id="rover" class="modal">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//page js
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
|
||||
var hasWhite = false, hasRGB = false, hasCCT = false;
|
||||
var nlDur = 60, nlTar = 0;
|
||||
@@ -22,11 +22,12 @@ var pN = "", pI = 0, pNum = 0;
|
||||
var pmt = 1, pmtLS = 0, pmtLast = 0;
|
||||
var lastinfo = {};
|
||||
var isM = false, mw = 0, mh=0;
|
||||
var ws, cpick, ranges;
|
||||
var ws, cpick, ranges, wsRpt=0;
|
||||
var cfg = {
|
||||
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
|
||||
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false, css:true, hdays:false}
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false,
|
||||
css:true, hdays:false, fxdef:true}
|
||||
};
|
||||
var hol = [
|
||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||
@@ -193,21 +194,39 @@ function loadSkinCSS(cId)
|
||||
l.id = cId;
|
||||
l.rel = 'stylesheet';
|
||||
l.type = 'text/css';
|
||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
||||
l.href = getURL('/skin.css');
|
||||
l.media = 'all';
|
||||
h.appendChild(l);
|
||||
}
|
||||
}
|
||||
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
function onLoad()
|
||||
{
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy and/or HTTPS
|
||||
let pathn = l.pathname;
|
||||
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||
//if (paths[0]==="sliders") paths.shift();
|
||||
//while (paths[0]==="") paths.shift();
|
||||
locproto = l.protocol;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "");
|
||||
if (paths.length > 0 && paths[0]!=="") {
|
||||
loc = true;
|
||||
locip += "/" + paths[0];
|
||||
} else if (locproto==="https:") {
|
||||
loc = true;
|
||||
}
|
||||
}
|
||||
var sett = localStorage.getItem('wledUiCfg');
|
||||
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
||||
@@ -217,7 +236,7 @@ function onLoad()
|
||||
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
|
||||
applyCfg();
|
||||
if (cfg.comp.hdays) { //load custom holiday list
|
||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", { // may be loaded from external source
|
||||
fetch(getURL("/holidays.json"), { // may be loaded from external source
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -433,9 +452,7 @@ function loadPresets(callback = null)
|
||||
// afterwards
|
||||
if (!callback && pmt == pmtLast) return;
|
||||
|
||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/presets.json'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -459,9 +476,7 @@ function loadPresets(callback = null)
|
||||
|
||||
function loadPalettes(callback = null)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/palettes'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -483,9 +498,7 @@ function loadPalettes(callback = null)
|
||||
|
||||
function loadFX(callback = null)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/effects'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -497,6 +510,7 @@ function loadFX(callback = null)
|
||||
populateEffects();
|
||||
})
|
||||
.catch((e)=>{
|
||||
//setTimeout(loadFX, 250); // retry
|
||||
showToast(e, true);
|
||||
})
|
||||
.finally(()=>{
|
||||
@@ -507,9 +521,7 @@ function loadFX(callback = null)
|
||||
|
||||
function loadFXData(callback = null)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/fxdata'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -524,6 +536,7 @@ function loadFXData(callback = null)
|
||||
})
|
||||
.catch((e)=>{
|
||||
fxdata = [];
|
||||
//setTimeout(loadFXData, 250); // retry
|
||||
showToast(e, true);
|
||||
})
|
||||
.finally(()=>{
|
||||
@@ -670,6 +683,7 @@ ${i.opt&0x100?inforow("Debug","<button class=\"btn btn-xs\" onclick=\"requestJso
|
||||
${inforow("Build",i.vid)}
|
||||
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
|
||||
${inforow("Uptime",getRuntimeStr(i.uptime))}
|
||||
${inforow("Time",i.time)}
|
||||
${inforow("Free heap",heap," kB")}
|
||||
${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""}
|
||||
${inforow("Estimated current",pwru)}
|
||||
@@ -760,7 +774,7 @@ function populateSegments(s)
|
||||
`<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})"></i>`+
|
||||
(cfg.comp.segpwr ? segp : '') +
|
||||
`<div class="segin" id="seg${i}in">`+
|
||||
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
|
||||
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=${li.arch=="esp8266"?32:64} value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
|
||||
`<table class="infot segt">`+
|
||||
`<tr>`+
|
||||
`<td>${isMSeg?'Start X':'Start LED'}</td>`+
|
||||
@@ -813,6 +827,7 @@ function populateSegments(s)
|
||||
resetUtil(noNewSegs);
|
||||
if (gId('selall')) gId('selall').checked = true;
|
||||
for (var i = 0; i <= lSeg; i++) {
|
||||
if (!gId(`seg${i}`)) continue;
|
||||
updateLen(i);
|
||||
updateTrail(gId(`seg${i}bri`));
|
||||
gId(`segr${i}`).classList.add("hide");
|
||||
@@ -991,10 +1006,15 @@ function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', e
|
||||
function btype(b)
|
||||
{
|
||||
switch (b) {
|
||||
case 2:
|
||||
case 32: return "ESP32";
|
||||
case 3:
|
||||
case 33: return "ESP32-S2";
|
||||
case 4:
|
||||
case 34: return "ESP32-S3";
|
||||
case 5:
|
||||
case 35: return "ESP32-C3";
|
||||
case 1:
|
||||
case 82: return "ESP8266";
|
||||
}
|
||||
return "?";
|
||||
@@ -1015,8 +1035,9 @@ function populateNodes(i,n)
|
||||
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
for (var o of n.nodes) {
|
||||
if (o.name) {
|
||||
var url = `<button class="btn" title="${o.ip}" onclick="location.assign('http://${o.ip}');">${bname(o)}</button>`;
|
||||
urows += inforow(url,`${btype(o.type)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
|
||||
let onoff = `<i class="icons e-icon flr ${o.type&0x80?'':'off'}" onclick="rmtTgl('${o.ip}',this);""></i>`;
|
||||
var url = `<button class="btn" title="${o.ip}" onclick="location.assign('http://${o.ip}');"><div class="bname">${bname(o)}</div>${o.vid<2307130?'':onoff}</button>`;
|
||||
urows += inforow(url,`${btype(o.type&0x7F)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
|
||||
nnodes++;
|
||||
}
|
||||
}
|
||||
@@ -1032,8 +1053,7 @@ function populateNodes(i,n)
|
||||
|
||||
function loadNodes()
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/nodes'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -1253,6 +1273,7 @@ function updateSelectedFx()
|
||||
// hide non-0D effects if segment only has 1 pixel (0D)
|
||||
var fxs = parent.querySelectorAll('.lstI');
|
||||
for (const fx of fxs) {
|
||||
if (!fx.dataset.opt) continue;
|
||||
let opts = fx.dataset.opt.split(";");
|
||||
if (fx.dataset.id>0) {
|
||||
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
|
||||
@@ -1293,7 +1314,8 @@ function cmpP(a, b)
|
||||
|
||||
function makeWS() {
|
||||
if (ws || lastinfo.ws < 0) return;
|
||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+'://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||
ws = new WebSocket(url);
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.onmessage = (e)=>{
|
||||
if (e.data instanceof ArrayBuffer) return; // liveview packet
|
||||
@@ -1317,11 +1339,12 @@ function makeWS() {
|
||||
};
|
||||
ws.onclose = (e)=>{
|
||||
gId('connind').style.backgroundColor = "var(--c-r)";
|
||||
setTimeout(makeWS,1500); // retry WS connection
|
||||
if (wsRpt++ < 5) setTimeout(makeWS,1500); // retry WS connection
|
||||
ws = null;
|
||||
}
|
||||
ws.onopen = (e)=>{
|
||||
//ws.send("{'v':true}"); // unnecessary (https://github.com/Aircoookie/WLED/blob/master/wled00/ws.cpp#L18)
|
||||
wsRpt = 0;
|
||||
reqsLegal = true;
|
||||
}
|
||||
}
|
||||
@@ -1572,7 +1595,6 @@ function requestJson(command=null)
|
||||
if (command && !reqsLegal) return; // stop post requests from chrome onchange event on page restore
|
||||
if (!jsonTimeout) jsonTimeout = setTimeout(()=>{if (ws) ws.close(); ws=null; showErrorToast()}, 3000);
|
||||
var req = null;
|
||||
var url = (loc?`http://${locip}`:'') + '/json/si';
|
||||
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
||||
var type = command ? 'post':'get';
|
||||
if (command) {
|
||||
@@ -1593,7 +1615,7 @@ function requestJson(command=null)
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/si'), {
|
||||
method: type,
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
@@ -1624,6 +1646,7 @@ function requestJson(command=null)
|
||||
//load presets and open websocket sequentially
|
||||
if (!pJson || isEmpty(pJson)) setTimeout(()=>{
|
||||
loadPresets(()=>{
|
||||
wsRpt = 0;
|
||||
if (!(ws && ws.readyState === WebSocket.OPEN)) makeWS();
|
||||
});
|
||||
},25);
|
||||
@@ -1671,27 +1694,22 @@ function toggleSync()
|
||||
|
||||
function toggleLiveview()
|
||||
{
|
||||
//WLEDSR adding liveview2D support
|
||||
if (isInfo && isM) toggleInfo();
|
||||
if (isNodes && isM) toggleNodes();
|
||||
isLv = !isLv;
|
||||
let wsOn = ws && ws.readyState === WebSocket.OPEN;
|
||||
|
||||
var lvID = "liveview";
|
||||
if (isM) {
|
||||
lvID = "liveview2D"
|
||||
if (isLv) {
|
||||
var cn = '<iframe id="liveview2D" src="about:blank"></iframe>';
|
||||
d.getElementById('kliveview2D').innerHTML = cn;
|
||||
}
|
||||
|
||||
gId('mliveview2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
|
||||
if (isM && wsOn) {
|
||||
lvID += "2D";
|
||||
if (isLv) gId('klv2D').innerHTML = `<iframe id="${lvID}" src="about:blank"></iframe>`;
|
||||
gId('mlv2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
|
||||
}
|
||||
|
||||
gId(lvID).style.display = (isLv) ? "block":"none";
|
||||
var url = (loc?`http://${locip}`:'') + "/" + lvID;
|
||||
gId(lvID).src = (isLv) ? url:"about:blank";
|
||||
gId('buttonSr').className = (isLv) ? "active":"";
|
||||
if (!isLv && ws && ws.readyState === WebSocket.OPEN) ws.send('{"lv":false}');
|
||||
gId(lvID).src = (isLv) ? getURL("/" + lvID + ((wsOn) ? "?ws":"")):"about:blank";
|
||||
gId('buttonSr').classList.toggle("active");
|
||||
if (!isLv && wsOn) ws.send('{"lv":false}');
|
||||
size();
|
||||
}
|
||||
|
||||
@@ -2035,14 +2053,14 @@ function tglSegn(s)
|
||||
function selSegAll(o)
|
||||
{
|
||||
var obj = {"seg":[]};
|
||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":o.checked});
|
||||
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":o.checked});
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function selSegEx(s)
|
||||
{
|
||||
var obj = {"seg":[]};
|
||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
|
||||
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":(i==s)});
|
||||
obj.mainseg = s;
|
||||
requestJson(obj);
|
||||
}
|
||||
@@ -2060,7 +2078,7 @@ function selGrp(g)
|
||||
event.stopPropagation();
|
||||
var sel = gId(`segcont`).querySelectorAll(`div[data-set="${g}"]`);
|
||||
var obj = {"seg":[]};
|
||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":false});
|
||||
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":false});
|
||||
if (sel) for (let s of sel||[]) {
|
||||
let i = parseInt(s.id.substring(3));
|
||||
obj.seg[i] = {"id":i,"sel":true};
|
||||
@@ -2227,8 +2245,7 @@ function setFX(ind = null)
|
||||
} else {
|
||||
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
||||
}
|
||||
|
||||
var obj = {"seg": {"fx": parseInt(ind),"fxdef":1}}; // fxdef sets effect parameters to default values, TODO add client setting
|
||||
var obj = {"seg": {"fx": parseInt(ind), "fxdef": cfg.comp.fxdef}}; // fxdef sets effect parameters to default values
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
@@ -2562,6 +2579,24 @@ function setBalance(b)
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function rmtTgl(ip,i) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
fetch(`http://${ip}/win&T=2`, {method: 'get'})
|
||||
.then((r)=>{
|
||||
return r.text();
|
||||
})
|
||||
.then((t)=>{
|
||||
let c = (new window.DOMParser()).parseFromString(t, "text/xml");
|
||||
// perhaps just i.classList.toggle("off"); would be enough
|
||||
if (c.getElementsByTagName('ac')[0].textContent === "0") {
|
||||
i.classList.add("off");
|
||||
} else {
|
||||
i.classList.remove("off");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var hc = 0;
|
||||
setInterval(()=>{
|
||||
if (!isInfo) return;
|
||||
@@ -2584,7 +2619,7 @@ function cnfReset()
|
||||
bt.innerHTML = "Confirm Reboot";
|
||||
cnfr = true; return;
|
||||
}
|
||||
window.location.href = "/reset";
|
||||
window.location.href = getURL("/reset");
|
||||
}
|
||||
|
||||
var cnfrS = false;
|
||||
@@ -2638,9 +2673,7 @@ function loadPalettesData(callback = null)
|
||||
|
||||
function getPalettesData(page, callback)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL(`/json/palx?page=${page}`), {
|
||||
method: 'get',
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
|
||||
@@ -17,21 +17,17 @@
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="canv" />
|
||||
<script>
|
||||
update();
|
||||
|
||||
var ws;
|
||||
var tmout = null;
|
||||
function update()
|
||||
function update() // via HTTP (/json/live)
|
||||
{
|
||||
if (document.hidden) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 250);
|
||||
return;
|
||||
}
|
||||
fetch('/json/live')
|
||||
fetch('./json/live')
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
clearTimeout(tmout);
|
||||
@@ -57,8 +53,57 @@
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 2500);
|
||||
})
|
||||
}
|
||||
function S() { // Startup function (onload)
|
||||
let wsOn = (window.location.href.indexOf("?ws") > 0);
|
||||
if (!wsOn) {update(); return;}
|
||||
|
||||
// Initialize WebSocket connection
|
||||
try {
|
||||
ws = top.window.ws;
|
||||
} catch (e) {}
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
//console.info("Peek uses top WS");
|
||||
ws.send("{'lv':true}");
|
||||
} else {
|
||||
//console.info("Peek WS opening");
|
||||
let l = window.location;
|
||||
let pathn = l.pathname;
|
||||
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||
let url = l.origin.replace("http","ws");
|
||||
if (paths.length > 1) {
|
||||
url += "/" + paths[0];
|
||||
}
|
||||
ws = new WebSocket(url+"/ws");
|
||||
ws.onopen = function () {
|
||||
//console.info("Peek WS open");
|
||||
ws.send("{'lv':true}");
|
||||
}
|
||||
}
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.addEventListener('message', (e) => {
|
||||
try {
|
||||
if (toString.call(e.data) === '[object ArrayBuffer]') {
|
||||
let leds = new Uint8Array(event.data);
|
||||
if (leds[0] != 76) return; //'L'
|
||||
let str = "linear-gradient(90deg,";
|
||||
let len = leds.length;
|
||||
let start = leds[1]==2 ? 4 : 2; // 1 = 1D, 2 = 1D/2D (leds[2]=w, leds[3]=h)
|
||||
for (i = start; i < len; i+=3) {
|
||||
str += `rgb(${leds[i]},${leds[i+1]},${leds[i+2]})`;
|
||||
if (i < len -3) str += ","
|
||||
}
|
||||
str += ")";
|
||||
document.getElementById("canv").style.background = str;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Peek WS error:",err);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<div id="canv"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,61 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#222222">
|
||||
<title>WLED Live Preview</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
#canv {
|
||||
background: black;
|
||||
filter: brightness(175%);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="canv"></div>
|
||||
<script>
|
||||
var ws;
|
||||
try {
|
||||
ws = top.window.ws;
|
||||
} catch (e) {}
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
//console.info("Peek uses top WS");
|
||||
ws.send("{'lv':true}");
|
||||
} else {
|
||||
console.info("Peek WS opening");
|
||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
||||
ws.onopen = function () {
|
||||
//console.info("Peek WS open");
|
||||
ws.send("{'lv':true}");
|
||||
}
|
||||
}
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.addEventListener('message', (e) => {
|
||||
try {
|
||||
if (toString.call(e.data) === '[object ArrayBuffer]') {
|
||||
let leds = new Uint8Array(event.data);
|
||||
if (leds[0] != 76) return; //'L'
|
||||
let str = "linear-gradient(90deg,";
|
||||
let len = leds.length;
|
||||
let start = leds[1]==2 ? 4 : 2; // 1 = 1D, 2 = 1D/2D (leds[2]=w, leds[3]=h)
|
||||
for (i = start; i < len; i+=3) {
|
||||
str += `rgb(${leds[i]},${leds[i+1]},${leds[i+2]})`;
|
||||
if (i < len -3) str += ","
|
||||
}
|
||||
str += ")";
|
||||
document.getElementById("canv").style.background = str;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Peek WS error:",err);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -33,7 +33,14 @@
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send("{'lv':true}");
|
||||
} else {
|
||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
||||
let l = window.location;
|
||||
let pathn = l.pathname;
|
||||
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||
let url = l.origin.replace("http","ws");
|
||||
if (paths.length > 1) {
|
||||
url += "/" + paths[0];
|
||||
}
|
||||
ws = new WebSocket(url+"/ws");
|
||||
ws.onopen = ()=>{
|
||||
ws.send("{'lv':true}");
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<title>WLED Message</title>
|
||||
<script>
|
||||
function B() { window.history.back() };
|
||||
function RS() { window.location = "/settings"; }
|
||||
function RP() { top.location.href = "/"; }
|
||||
function RS() { window.location = "../settings"; }
|
||||
function RP() { top.location.href = "../"; }
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
|
||||
2026
wled00/data/pxmagic/pxmagic.htm
Normal file
2026
wled00/data/pxmagic/pxmagic.htm
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
<title>WLED Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
function gId(n){return d.getElementById(n);}
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
@@ -26,17 +26,29 @@
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 1) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=0';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=0'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@@ -65,15 +77,15 @@
|
||||
</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<button type=submit id="b" onclick="window.location='/'">Back</button>
|
||||
<button type="submit" onclick="window.location='./settings/wifi'">WiFi Setup</button>
|
||||
<button type="submit" onclick="window.location='./settings/leds'">LED Preferences</button>
|
||||
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location='./settings/2D'">2D Configuration</button>
|
||||
<button type="submit" onclick="window.location='./settings/ui'">User Interface</button>
|
||||
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location='./settings/dmx'">DMX Output</button>
|
||||
<button type="submit" onclick="window.location='./settings/sync'">Sync Interfaces</button>
|
||||
<button type="submit" onclick="window.location='./settings/time'">Time & Macros</button>
|
||||
<button type="submit" onclick="window.location='./settings/um'">Usermods</button>
|
||||
<button type="submit" onclick="window.location='./settings/sec'">Security & Updates</button>
|
||||
<button type=submit id="b" onclick="window.location=getURL('/')">Back</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/wifi')">WiFi Setup</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/leds')">LED Preferences</button>
|
||||
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/ui')">User Interface</button>
|
||||
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/dmx')">DMX Output</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/sync')">Sync Interfaces</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/time')">Time & Macros</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/um')">Usermods</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/sec')">Security & Updates</button>
|
||||
</body>
|
||||
</html>
|
||||
@@ -7,11 +7,11 @@
|
||||
<title>2D Set-up</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var maxPanels=64;
|
||||
var ctx = null; // WLEDMM
|
||||
function H(){window.open("https://kno.wled.ge/features/2D");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function gId(n){return d.getElementById(n);}
|
||||
function fS(){d.Sf.submit();} // <button type=submit> sometimes didn't work
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
@@ -35,16 +35,29 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=10'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/2D');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
|
||||
function UI() {
|
||||
@@ -322,7 +335,7 @@ Y:<input name="P${i}Y" type="number" min="0" max="255" value="0" oninput="UI()">
|
||||
<option value="1">Vertical</option>
|
||||
</select><br>
|
||||
Serpentine: <input type="checkbox" name="PS"><br>
|
||||
<i style="color:#fa0;">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<br>
|
||||
<i class="warn">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<br>
|
||||
WARNING: You may need to update each panel parameters after they are generated.</i><br>
|
||||
<button type="button" onclick="gen();expand(gId('expGen'),gId('mxGen'));">Populate</button>
|
||||
</div>
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<title>DMX Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
|
||||
function B(){window.history.back();}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function GCH(num) {
|
||||
d.getElementById('dmxchannels').innerHTML += "";
|
||||
for (i=0;i<num;i++) {
|
||||
@@ -54,16 +54,29 @@
|
||||
});
|
||||
}
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=7';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=7'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/dmx');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
d.um_p = [];
|
||||
d.rsvd = [];
|
||||
d.ro_gpio = [];
|
||||
d.max_gpio = 39;
|
||||
d.max_gpio = 50;
|
||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function gId(n){return d.getElementById(n);}
|
||||
function off(n){d.getElementsByName(n)[0].value = -1;}
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
@@ -26,8 +26,12 @@
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
GetV();checkSi();setABL();
|
||||
GetV();
|
||||
checkSi();
|
||||
setABL();
|
||||
d.Sf.addEventListener("submit", trySubmit);
|
||||
if (d.um_p[0]==-1) d.um_p.shift();
|
||||
pinDropdowns();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
@@ -49,7 +53,7 @@
|
||||
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
||||
}
|
||||
function pinsOK() {
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
// ignore IP address
|
||||
@@ -59,23 +63,36 @@
|
||||
if (t>=80) continue;
|
||||
}
|
||||
//check for pin conflicts
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4"/* || nm=="RL" || nm=="BT" || nm=="IR"*/)
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
var p = []; // used pin array
|
||||
for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations
|
||||
for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with usermod pins
|
||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;}
|
||||
else if (!(nm == "IR" || nm=="BT") && d.ro_gpio.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);LCs[i].value="";LCs[i].focus();return false;}
|
||||
for (j=i+1; j<LCs.length; j++)
|
||||
{
|
||||
var p = d.rsvd.concat(d.um_p); // used pin array
|
||||
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||
if (p.some((e)=>e==parseInt(LCs[i].value))) {
|
||||
alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);
|
||||
LCs[i].value="";
|
||||
LCs[i].focus();
|
||||
return false;
|
||||
}
|
||||
else if (/*!(nm == "IR" || nm=="BT") &&*/ d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))) {
|
||||
alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);
|
||||
LCs[i].value="";
|
||||
LCs[i].focus();
|
||||
return false;
|
||||
}
|
||||
for (j=i+1; j<LCs.length; j++) {
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR") {
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4"/* || n2=="RL" || n2=="BT" || n2=="IR"*/) {
|
||||
if (n2.substring(0,1)==="L") {
|
||||
var m = LCs[j].name.substring(2);
|
||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||
if (t2>=80) continue;
|
||||
}
|
||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);LCs[j].value="";LCs[j].focus();return false;}
|
||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {
|
||||
alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);
|
||||
LCs[j].value="";
|
||||
LCs[j].focus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,6 +113,7 @@
|
||||
gId('abl').style.display = (en) ? 'inline':'none';
|
||||
gId('psu2').style.display = (en) ? 'inline':'none';
|
||||
if (d.Sf.LA.value > 0) setABL();
|
||||
UI();
|
||||
}
|
||||
function enLA()
|
||||
{
|
||||
@@ -117,28 +135,28 @@
|
||||
default: gId('LAdis').style.display = 'inline';
|
||||
}
|
||||
gId('m1').innerHTML = maxM;
|
||||
d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
|
||||
UI();
|
||||
}
|
||||
//returns mem usage
|
||||
function getMem(t, n) {
|
||||
let len = parseInt(d.getElementsByName("LC"+n)[0].value);
|
||||
len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too
|
||||
let dbl = 0;
|
||||
if (d.Sf.LD.checked) dbl = len * 4; // double buffering
|
||||
if (t < 32) {
|
||||
if (t==26 || t==29) len *= 2; // 16 bit LEDs
|
||||
if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem
|
||||
if (t > 28) return len*20; //RGBW
|
||||
return len*15;
|
||||
if (t > 28) return len*20 + dbl; //RGBW
|
||||
return len*15 + dbl;
|
||||
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
||||
{
|
||||
if (t > 28) return len*8; //RGBW
|
||||
return len*6;
|
||||
if (t > 28) return len*8 + dbl; //RGBW
|
||||
return len*6 + dbl;
|
||||
}
|
||||
if (t > 28) return len*4; //RGBW
|
||||
return len*3;
|
||||
if (t > 28) return len*4 + dbl; //RGBW
|
||||
return len*3 + dbl;
|
||||
}
|
||||
if (t > 31 && t < 48) return 5;
|
||||
return len*3;
|
||||
if (t > 31 && t < 48) return 5; // analog
|
||||
return len*3 + dbl;
|
||||
}
|
||||
|
||||
function UI(change=false)
|
||||
@@ -151,53 +169,50 @@
|
||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||
|
||||
// enable/disable LED fields
|
||||
var s = d.getElementsByTagName("select");
|
||||
for (i=0; i<s.length; i++) {
|
||||
d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((s)=>{
|
||||
// is the field a LED type?
|
||||
if (s[i].name.substring(0,2)=="LT") {
|
||||
var n = s[i].name.substring(2);
|
||||
var t = parseInt(s[i].value,10);
|
||||
gId("p0d"+n).innerHTML = (t>=80 && t<96) ? "IP address:" : (t > 49) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:";
|
||||
gId("p1d"+n).innerHTML = (t> 49 && t<64) ? "Clk GPIO:" : "";
|
||||
var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
||||
var n = s.name.substring(2);
|
||||
var t = parseInt(s.value);
|
||||
gId("p0d"+n).innerHTML = (t>=80 && t<96) ? "IP address:" : (t > 49) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:";
|
||||
gId("p1d"+n).innerHTML = (t> 49 && t<64) ? "Clk GPIO:" : "";
|
||||
//var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
||||
|
||||
memu += getMem(t, n); // calc memory
|
||||
memu += getMem(t, n); // calc memory
|
||||
|
||||
// enumerate pins
|
||||
for (p=1; p<5; p++) {
|
||||
var LK = d.getElementsByName("L"+p+n)[0]; // secondary pins
|
||||
if (!LK) continue;
|
||||
if (((t>=80 && t<96) && p<4) || (t>49 && p==1) || (t>41 && t < 50 && (p+40 < t))) // TYPE_xxxx values from const.h
|
||||
{
|
||||
// display pin field
|
||||
LK.style.display = "inline";
|
||||
LK.required = true;
|
||||
} else {
|
||||
// hide pin field
|
||||
LK.style.display = "none";
|
||||
LK.required = false;
|
||||
LK.value="";
|
||||
}
|
||||
// enumerate pins
|
||||
for (p=1; p<5; p++) {
|
||||
var LK = d.getElementsByName("L"+p+n)[0]; // secondary pins
|
||||
if (!LK) continue;
|
||||
if (((t>=80 && t<96) && p<4) || (t>49 && p==1) || (t>41 && t < 50 && (p+40 < t))) // TYPE_xxxx values from const.h
|
||||
{
|
||||
// display pin field
|
||||
LK.style.display = "inline";
|
||||
LK.required = true;
|
||||
} else {
|
||||
// hide pin field
|
||||
LK.style.display = "none";
|
||||
LK.required = false;
|
||||
LK.value="";
|
||||
}
|
||||
if (change) {
|
||||
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state
|
||||
if (t > 31 && t < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED
|
||||
}
|
||||
gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814
|
||||
gRGBW |= isRGBW = ((t > 17 && t < 22) || (t > 28 && t < 32) || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide color order for PWM
|
||||
gId("dig"+n+"w").style.display = (t > 28 && t < 32) ? "inline":"none"; // show swap channels dropdown
|
||||
if (!(t > 28 && t < 32)) d.getElementsByName("WO"+n)[0].value = 0; // reset swapping
|
||||
gId("dig"+n+"c").style.display = (t >= 40 && t < 48) ? "none":"inline"; // hide count for analog
|
||||
gId("dig"+n+"r").style.display = (t >= 80 && t < 96) ? "none":"inline"; // hide reversed for virtual
|
||||
gId("dig"+n+"s").style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||
gId("dig"+n+"f").style.display = ((t >= 16 && t < 32) || (t >= 50 && t < 64)) ? "inline":"none"; // hide refresh
|
||||
gId("dig"+n+"a").style.display = (isRGBW && t != 40) ? "inline":"none"; // auto calculate white
|
||||
gId("dig"+n+"l").style.display = (t > 48 && t < 64) ? "inline":"none"; // bus clock speed
|
||||
gId("rev"+n).innerHTML = (t >= 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
|
||||
gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description
|
||||
}
|
||||
}
|
||||
if (change) {
|
||||
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state
|
||||
if (t > 31 && t < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED
|
||||
}
|
||||
gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814
|
||||
gRGBW |= isRGBW = ((t > 17 && t < 22) || (t > 28 && t < 32) || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide color order for PWM
|
||||
gId("dig"+n+"w").style.display = (t > 28 && t < 32) ? "inline":"none"; // show swap channels dropdown
|
||||
if (!(t > 28 && t < 32)) d.getElementsByName("WO"+n)[0].value = 0; // reset swapping
|
||||
gId("dig"+n+"c").style.display = (t >= 40 && t < 48) ? "none":"inline"; // hide count for analog
|
||||
gId("dig"+n+"r").style.display = (t >= 80 && t < 96) ? "none":"inline"; // hide reversed for virtual
|
||||
gId("dig"+n+"s").style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||
gId("dig"+n+"f").style.display = ((t >= 16 && t < 32) || (t >= 50 && t < 64)) ? "inline":"none"; // hide refresh
|
||||
gId("dig"+n+"a").style.display = (isRGBW && t != 40) ? "inline":"none"; // auto calculate white
|
||||
gId("dig"+n+"l").style.display = (t > 48 && t < 64) ? "inline":"none"; // bus clock speed
|
||||
gId("rev"+n).innerHTML = (t >= 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
|
||||
gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description
|
||||
});
|
||||
// display global white channel overrides
|
||||
gId("wc").style.display = (gRGBW) ? 'inline':'none';
|
||||
if (!gRGBW) {
|
||||
@@ -205,7 +220,7 @@
|
||||
d.Sf.CR.checked = false;
|
||||
}
|
||||
// check for pin conflicts
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||
var sLC = 0, sPC = 0, maxLC = 0;
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2); // field name
|
||||
@@ -243,15 +258,14 @@
|
||||
}
|
||||
}
|
||||
// check for pin conflicts
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4"/* || nm=="RL" || nm=="BT" || nm=="IR"*/)
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
var p = []; // used pin array
|
||||
for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations
|
||||
for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with usermod pins
|
||||
var p = d.rsvd.concat(d.um_p); // used pin array
|
||||
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||
for (j=0; j<LCs.length; j++) {
|
||||
if (i==j) continue;
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR") {
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4"/* || n2=="RL" || n2=="BT" || n2=="IR"*/) {
|
||||
if (n2.substring(0,1)==="L") {
|
||||
var m = LCs[j].name.substring(2);
|
||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||
@@ -261,13 +275,13 @@
|
||||
}
|
||||
}
|
||||
// now check for conflicts
|
||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color=d.ro_gpio.some((e)=>e==parseInt(LCs[i].value,10))?"orange":"#fff";
|
||||
if (p.some((e)=>e==parseInt(LCs[i].value))) LCs[i].style.color="red"; else LCs[i].style.color=d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))?"orange":"#fff";
|
||||
}
|
||||
// check buttons, IR & relay
|
||||
if (nm=="IR" || nm=="BT" || nm=="RL") {
|
||||
LCs[i].max = d.max_gpio;
|
||||
LCs[i].min = -1;
|
||||
}
|
||||
//if (nm=="IR" || nm=="BT" || nm=="RL") {
|
||||
// LCs[i].max = d.max_gpio;
|
||||
// LCs[i].min = -1;
|
||||
//}
|
||||
}
|
||||
// update total led count
|
||||
gId("lc").textContent = sLC;
|
||||
@@ -366,11 +380,11 @@ ${i+1}:
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />
|
||||
<div id="dig${i}c" style="display:inline">Length: <input type="number" name="LC${i}" class="l" min="1" max="${maxPB}" value="1" required oninput="UI()" /></div><br>
|
||||
</div>
|
||||
<span id="p0d${i}">GPIO:</span> <input type="number" name="L0${i}" required class="s" onchange="UI()"/>
|
||||
<span id="p1d${i}"></span><input type="number" name="L1${i}" class="s" onchange="UI()"/>
|
||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" class="s" onchange="UI()"/>
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" class="s" onchange="UI()"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" class="s" onchange="UI()"/>
|
||||
<span id="p0d${i}">GPIO:</span><input type="number" name="L0${i}" required class="s" onchange="UI();pinUpd(this);"/>
|
||||
<span id="p1d${i}"></span><input type="number" name="L1${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||
<div id="dig${i}r" style="display:inline"><br><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div>
|
||||
<div id="dig${i}s" style="display:inline"><br>Skip first LEDs: <input type="number" name="SL${i}" min="0" max="255" value="0" oninput="UI()"></div>
|
||||
<div id="dig${i}f" style="display:inline"><br>Off Refresh: <input id="rf${i}" type="checkbox" name="RF${i}"></div>
|
||||
@@ -546,17 +560,126 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
}
|
||||
}
|
||||
}
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
function pinDropdowns() {
|
||||
let fields = ["IR","RL"]; // IR & relay
|
||||
gId("btns").querySelectorAll('input[type="number"]').forEach((e)=>{fields.push(e.name);}) // buttons
|
||||
for (let i of d.Sf.elements) {
|
||||
if (i.type === "number" && fields.includes(i.name)) { //select all pin select elements
|
||||
let v = parseInt(i.value);
|
||||
let sel = addDropdown(i.name,0);
|
||||
for (var j = -1; j <= d.max_gpio; j++) {
|
||||
if (d.rsvd.includes(j)) continue;
|
||||
let foundPin = d.um_p.indexOf(j);
|
||||
let txt = (j === -1) ? "unused" : `${j}`;
|
||||
if (foundPin >= 0 && j !== v) txt += ` used`; // already reserved pin
|
||||
if (d.ro_gpio.includes(j)) txt += " (R/O)";
|
||||
let opt = addOption(sel, txt, j);
|
||||
if (j === v) opt.selected = true; // this is "our" pin
|
||||
else if (d.um_p.includes(j)) opt.disabled = true; // someone else's pin
|
||||
}
|
||||
}
|
||||
}
|
||||
// update select options
|
||||
d.Sf.querySelectorAll("select.pin").forEach((e)=>{pinUpd(e);});
|
||||
// add dataset values for LED GPIO pins
|
||||
d.Sf.querySelectorAll(".iST input.s[name^=L]").forEach((i)=>{
|
||||
if (i.value!=="" && i.value>=0)
|
||||
i.dataset.val = i.value;
|
||||
});
|
||||
}
|
||||
function pinUpd(e) {
|
||||
// update changed select options across all usermods
|
||||
let oldV = parseInt(e.dataset.val);
|
||||
e.dataset.val = e.value;
|
||||
let txt = e.name;
|
||||
let pins = [];
|
||||
d.Sf.querySelectorAll(".iST input.s[name^=L]").forEach((i)=>{
|
||||
if (i.value!=="" && i.value>=0 && i.max<255)
|
||||
pins.push(i.value);
|
||||
});
|
||||
let selects = d.Sf.querySelectorAll("select.pin");
|
||||
for (let sel of selects) {
|
||||
if (sel == e) continue
|
||||
Array.from(sel.options).forEach((i)=>{
|
||||
let led = pins.includes(i.value);
|
||||
if (!(i.value==oldV || i.value==e.value || led)) return;
|
||||
if (i.value == -1) {
|
||||
i.text = "unused";
|
||||
return
|
||||
}
|
||||
i.text = i.value;
|
||||
if (i.value==oldV) {
|
||||
i.disabled = false;
|
||||
}
|
||||
if (i.value==e.value || led) {
|
||||
i.disabled = true;
|
||||
i.text += ` ${led?'LED':txt}`;
|
||||
}
|
||||
if (d.ro_gpio.includes(parseInt(i.value))) i.text += " (R/O)";
|
||||
});
|
||||
}
|
||||
}
|
||||
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
||||
function addDropdown(field) {
|
||||
let sel = d.createElement('select');
|
||||
sel.classList.add("pin");
|
||||
let inp = d.getElementsByName(field)[0];
|
||||
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||
let v = inp.value;
|
||||
let n = inp.name;
|
||||
// copy the existing input element's attributes to the new select element
|
||||
for (var i = 0; i < inp.attributes.length; ++ i) {
|
||||
var att = inp.attributes[i];
|
||||
// type and value don't apply, so skip them
|
||||
// ** you might also want to skip style, or others -- modify as needed **
|
||||
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style') {
|
||||
sel.setAttribute(att.name, att.value);
|
||||
}
|
||||
}
|
||||
sel.setAttribute("data-val", v);
|
||||
sel.setAttribute("onchange", "pinUpd(this)");
|
||||
// finally, replace the old input element with the new select element
|
||||
inp.parentElement.replaceChild(sel, inp);
|
||||
return sel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function addOption(sel,txt,val) {
|
||||
if (sel===null) return; // select object missing
|
||||
let opt = d.createElement("option");
|
||||
opt.value = val;
|
||||
opt.text = txt;
|
||||
sel.appendChild(opt);
|
||||
for (let i=0; i<sel.childNodes.length; i++) {
|
||||
let c = sel.childNodes[i];
|
||||
if (c.value == sel.dataset.val) sel.selectedIndex = i;
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=2';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=2'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/leds');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
@@ -576,7 +699,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||
<div id="abl">
|
||||
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
<div id="ampwarning" style="color: orange; display: none;">
|
||||
<div id="ampwarning" class="warn" style="display: none;">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
@@ -604,14 +727,14 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
<button type="button" id="-" onclick="addLEDs(-1,false)">-</button><br>
|
||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||
<div id="ledwarning" style="color: orange; display: none;">
|
||||
<div id="ledwarning" class="warn" style="display: none;">
|
||||
⚠ You might run into stability or lag issues.<br>
|
||||
Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br>
|
||||
</div>
|
||||
<hr class="sml">
|
||||
Make a segment for each output: <input type="checkbox" name="MS"><br>
|
||||
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br>
|
||||
Use global LED buffer: <input type="checkbox" name="LD"><br>
|
||||
Use global LED buffer: <input type="checkbox" name="LD" onchange="UI()"><br>
|
||||
<hr class="sml">
|
||||
<div id="color_order_mapping">
|
||||
Color Order Override:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<title>PIN required</title>
|
||||
<script>
|
||||
var d = document;
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function B() { window.open("../settings","_self"); }
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<title>Misc Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function U() { window.open("/update","_self"); }
|
||||
function B() { window.open(getURL("/settings"),"_self"); }
|
||||
function U() { window.open(getURL("/update"),"_self"); }
|
||||
function gId(s) { return d.getElementById(s); }
|
||||
function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
@@ -47,7 +47,7 @@
|
||||
var req = new XMLHttpRequest();
|
||||
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
|
||||
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
||||
req.open("POST", "/upload");
|
||||
req.open("POST", getURL("/upload"));
|
||||
var formData = new FormData();
|
||||
formData.append("data", fO.files[0], name);
|
||||
req.send(formData);
|
||||
@@ -65,16 +65,33 @@
|
||||
x.setAttribute("download","wled_" + x.getAttribute("download") + (sd=="WLED"?"":("_" +sd)));
|
||||
}
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=6';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) {
|
||||
gId("bckcfg").setAttribute('href',getURL(gId("bckcfg").pathname));
|
||||
gId("bckpresets").setAttribute('href',getURL(gId("bckpresets").pathname));
|
||||
}
|
||||
loadJS(getURL('/settings/s.js?p=6'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/sec');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@@ -89,7 +106,7 @@
|
||||
</div>
|
||||
<h2>Security & Update setup</h2>
|
||||
Settings PIN: <input type="password" id="PIN" name="PIN" size="4" maxlength="4" minlength="4" onkeydown="checkNum(this)" pattern="[0-9]*" inputmode="numeric" title="Please enter a 4 digit number"><br>
|
||||
<div style="color: #fa0;">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
||||
<div class="warn">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
||||
To enable OTA, for security reasons you need to also enter the correct password!<br>
|
||||
@@ -99,7 +116,7 @@
|
||||
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
|
||||
Factory reset: <input type="checkbox" name="RS"><br>
|
||||
All settings and presets will be erased.<br><br>
|
||||
<div style="color: #fa0;">⚠ Unencrypted transmission. An attacker on the same network can intercept form data!</div>
|
||||
<div class="warn">⚠ Unencrypted transmission. An attacker on the same network can intercept form data!</div>
|
||||
<hr>
|
||||
<h3>Software Update</h3>
|
||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||
@@ -110,7 +127,7 @@
|
||||
<div>Restore presets<br><input type="file" name="data" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data,'/presets.json');">Upload</button><br></div><br>
|
||||
<a class="btn lnk" id="bckpresets" href="/cfg.json" download="cfg">Backup configuration</a><br>
|
||||
<div>Restore configuration<br><input type="file" name="data2" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data2,'/cfg.json');">Upload</button><br></div>
|
||||
<div style="color: #fa0;">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||
<div class="warn">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||
Incorrect configuration may require a factory reset or re-flashing of your ESP.</div>
|
||||
For security reasons, passwords are not backed up.
|
||||
<hr>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<meta charset="utf-8">
|
||||
<title>Sync Settings</title>
|
||||
<script>var d=document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
function gId(s){return d.getElementById(s);}
|
||||
function toggle(el){gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide");}
|
||||
function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
|
||||
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
@@ -56,16 +56,28 @@
|
||||
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
||||
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();}
|
||||
function S(){
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let paths = l.pathname.slice(1,l.pathname.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=4';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=4'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/sync');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
@@ -172,7 +184,7 @@ Realtime LED offset: <input name="WO" type="number" min="-255" max="255" require
|
||||
<hr class="sml">
|
||||
<h3>Alexa Voice Assistant</h3>
|
||||
<div id="NoAlexa" class="hide">
|
||||
<em style="color:#fa0;">This firmware build does not include Alexa support.<br></em><br>
|
||||
<i class="warn">This firmware build does not include Alexa support.<br></i><br>
|
||||
</div>
|
||||
<div id="Alexa">
|
||||
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||
@@ -180,7 +192,7 @@ Alexa invocation name: <input type="text" name="AI" maxlength="32"><br>
|
||||
Also emulate devices to call the first <input name="AP" type="number" class="s" min="0" max="9" required> presets<br><br>
|
||||
</div>
|
||||
<hr class="sml">
|
||||
<div style="color: #fa0;">⚠ <b>MQTT and Hue sync all connect to external hosts!<br>
|
||||
<div class="warn">⚠ <b>MQTT and Hue sync all connect to external hosts!<br>
|
||||
This may impact the responsiveness of WLED.</b><br>
|
||||
</div>
|
||||
For best results, only use one of these services at a time.<br>
|
||||
@@ -188,7 +200,7 @@ For best results, only use one of these services at a time.<br>
|
||||
<hr class="sml">
|
||||
<h3>MQTT</h3>
|
||||
<div id="NoMQTT" class="hide">
|
||||
<em style="color:#fa0;">This firmware build does not include MQTT support.<br></em>
|
||||
<i class="warn">This firmware build does not include MQTT support.<br></i>
|
||||
</div>
|
||||
<div id="MQTT">
|
||||
Enable MQTT: <input type="checkbox" name="MQ"><br>
|
||||
@@ -207,7 +219,7 @@ Retain brightness & color messages: <input type="checkbox" name="RT"><br>
|
||||
</div>
|
||||
<h3>Philips Hue</h3>
|
||||
<div id="NoHue" class="hide">
|
||||
<em style="color:#fa0;">This firmware build does not include Philips Hue support.<br></em>
|
||||
<em class="warn">This firmware build does not include Philips Hue support.<br></em>
|
||||
</div>
|
||||
<div id="Hue">
|
||||
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
<title>Time Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var el=false;
|
||||
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#time-settings"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function B() { window.open(getURL("/settings"),"_self"); }
|
||||
function gId(s) { return d.getElementById(s); }
|
||||
function gN(s) { return d.getElementsByName(s)[0]; }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
@@ -33,16 +33,29 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=5';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=5'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/time');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
function expand(o,i)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<title>UI Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var initial_ds, initial_st, initial_su;
|
||||
var sett = null;
|
||||
var l = {
|
||||
@@ -26,7 +26,8 @@
|
||||
"segpwr": "Hide segment power & brightness",
|
||||
"segexp" : "Always expand first segment",
|
||||
"css": "Enable custom CSS",
|
||||
"hdays": "Enable custom Holidays list"
|
||||
"hdays": "Enable custom Holidays list",
|
||||
"fxdef": "Use effect default parameters"
|
||||
},
|
||||
"theme":{
|
||||
"alpha": {
|
||||
@@ -185,21 +186,33 @@
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S()
|
||||
{
|
||||
if (window.location.protocol == "file:") {
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=3';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=3'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/ui');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function B() { window.open(getURL("/settings"),"_self"); }
|
||||
function UI()
|
||||
{
|
||||
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
|
||||
@@ -249,7 +262,7 @@
|
||||
Server description: <input type="text" name="DS" maxlength="32"><br>
|
||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
||||
<div id="NoSimple" class="hide">
|
||||
<em style="color:#fa0;">This firmware build does not include simplified UI support.<br></em>
|
||||
<i class="warn">This firmware build does not include simplified UI support.<br></i>
|
||||
</div>
|
||||
<div id="Simple">Enable simplified UI: <input type="checkbox" name="SU"><br></div>
|
||||
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
|
||||
|
||||
@@ -7,19 +7,20 @@
|
||||
<title>Usermod Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
d.max_gpio = 39;
|
||||
d.max_gpio = 50;
|
||||
d.um_p = [];
|
||||
d.rsvd = [];
|
||||
d.ro_gpio = [];
|
||||
d.extra = [];
|
||||
var umCfg = {};
|
||||
var pins = [], pinO = [], owner;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var urows;
|
||||
var numM = 0;
|
||||
function gId(s) { return d.getElementById(s); }
|
||||
function isO(i) { return (i && typeof i === 'object' && !Array.isArray(i)); }
|
||||
function H() { window.open("https://github.com/Aircoookie/WLED/wiki/Settings#usermod-settings"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function B() { window.open(getURL("/settings"),"_self"); }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
@@ -30,15 +31,11 @@
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
GetV();
|
||||
for (let k=0; k<d.rsvd.length; k++) { pins.push(d.rsvd[k]); pinO.push("rsvd"); }
|
||||
if (d.um_p[0]==-1) d.um_p.shift();
|
||||
d.Sf.SDA.max = d.max_gpio;
|
||||
d.Sf.SCL.max = d.max_gpio;
|
||||
d.Sf.MOSI.max = d.max_gpio;
|
||||
d.Sf.SCLK.max = d.max_gpio;
|
||||
d.Sf.MISO.max = d.max_gpio;
|
||||
let inp = d.getElementsByTagName("input");
|
||||
for (let i of inp) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
|
||||
for (let r of d.rsvd) { pins.push(r); pinO.push("rsvd"); } // reserved pins
|
||||
if (d.um_p[0]==-1) d.um_p.shift(); // remove filler
|
||||
d.Sf.SDA.max = d.Sf.SCL.max = d.Sf.MOSI.max = d.Sf.SCLK.max = d.Sf.MISO.max = d.max_gpio;
|
||||
//for (let i of d.getElementsByTagName("input")) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
|
||||
pinDropdowns(); // convert INPUT to SELECT for pins
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
@@ -47,21 +44,36 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
ldS();
|
||||
if (!numM) gId("um").innerHTML = "No Usermods installed.";
|
||||
if (loc) d.Sf.action = getURL('/settings/um');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
// https://stackoverflow.com/questions/3885817/how-do-i-check-that-a-number-is-float-or-integer
|
||||
function isF(n) { return n === +n && n !== (n|0); }
|
||||
function isI(n) { return n === +n && n === (n|0); }
|
||||
function check(o,k) { // input object, pin owner key
|
||||
/* no longer necessary with pin dropdown fields
|
||||
var n = o.name.replace("[]","").substr(-3);
|
||||
if (o.type=="number" && n.substr(0,3)=="pin") {
|
||||
for (var i=0; i<pins.length; i++) {
|
||||
@@ -84,13 +96,16 @@
|
||||
if (o.value==pins[i] || o.value<-1 || o.value>d.max_gpio) { o.style.color="red"; break; } else o.style.color=d.ro_gpio.some((e)=>e==parseInt(o.value,10))?"orange":"#fff";
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
function getPins(o) {
|
||||
if (isO(o)) {
|
||||
for (const [k,v] of Object.entries(o)) {
|
||||
if (isO(v)) {
|
||||
let oldO = owner; // keep parent name
|
||||
owner = k;
|
||||
getPins(v);
|
||||
owner = oldO;
|
||||
continue;
|
||||
}
|
||||
if (k.replace("[]","").substr(-3)=="pin") {
|
||||
@@ -149,11 +164,76 @@
|
||||
urows += `<input type="${t==="int"?"number":t}" name="${k}:${f}${a?"[]":""}" ${c} oninput="check(this,'${k.substr(k.indexOf(":")+1)}')"><br>`;
|
||||
}
|
||||
}
|
||||
function pinDropdowns() {
|
||||
for (let i of d.Sf.elements) {
|
||||
if (i.type === "number" && (i.name.includes("pin") || ["SDA","SCL","MOSI","MISO","SCLK"].includes(i.name))) { //select all pin select elements
|
||||
let v = parseInt(i.value);
|
||||
let sel = addDropdown(i.name,0);
|
||||
for (var j = -1; j <= d.max_gpio; j++) {
|
||||
if (d.rsvd.includes(j)) continue;
|
||||
let foundPin = pins.indexOf(j);
|
||||
let txt = (j === -1) ? "unused" : `${j}`;
|
||||
if (foundPin >= 0 && j !== v) txt += ` ${pinO[foundPin]=="if"?"global":pinO[foundPin]}`; // already reserved pin
|
||||
if (d.ro_gpio.includes(j)) txt += " (R/O)";
|
||||
let opt = addOption(sel, txt, j);
|
||||
if (j === v) opt.selected = true; // this is "our" pin
|
||||
else if (pins.includes(j)) opt.disabled = true; // someone else's pin
|
||||
}
|
||||
let um = i.name.split(":")[0];
|
||||
d.extra.forEach((o)=>{
|
||||
if (o[um] && o[um].pin) o[um].pin.forEach((e)=>{
|
||||
let opt = addOption(sel,e[0],e[1]);
|
||||
if (e[1]==v) opt.selected = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
function UI(e) {
|
||||
// update changed select options across all usermods
|
||||
let oldV = parseInt(e.dataset.val);
|
||||
e.dataset.val = e.value;
|
||||
let txt = e.name.split(":")[e.name.split(":").length-2];
|
||||
let selects = d.Sf.querySelectorAll("select[class='pin']");
|
||||
for (let sel of selects) {
|
||||
if (sel == e) continue
|
||||
Array.from(sel.options).forEach((i)=>{
|
||||
if (!(i.value==oldV || i.value==e.value)) return;
|
||||
if (i.value == -1) {
|
||||
i.text = "unused";
|
||||
return
|
||||
}
|
||||
if (i.value<100) { // TODO remove this hack and use d.extra
|
||||
i.text = i.value;
|
||||
if (i.value==oldV) {
|
||||
i.disabled = false;
|
||||
}
|
||||
if (i.value==e.value) {
|
||||
i.disabled = true;
|
||||
i.text += ` ${txt}`;
|
||||
}
|
||||
if (d.ro_gpio.includes(parseInt(i.value))) i.text += " (R/O)";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
||||
function addDropdown(um,fld) {
|
||||
let sel = d.createElement('select');
|
||||
let arr = d.getElementsByName(um+":"+fld);
|
||||
let inp = arr[1]; // assume 1st field to be hidden (type)
|
||||
if (typeof(fld) === "string") { // parameter from usermod (field name)
|
||||
if (fld.includes("pin")) sel.classList.add("pin");
|
||||
um += ":"+fld;
|
||||
} else if (typeof(fld) === "number") sel.classList.add("pin"); // a hack to add a class
|
||||
let arr = d.getElementsByName(um);
|
||||
let idx = arr[0].type==="hidden"?1:0; // ignore hidden field
|
||||
if (arr.length > 2) {
|
||||
// we have array of values (usually pins)
|
||||
for (let i of arr) {
|
||||
if (i.type === "number") break;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
let inp = arr[idx];
|
||||
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||
let v = inp.value;
|
||||
let n = inp.name;
|
||||
@@ -162,11 +242,12 @@
|
||||
var att = inp.attributes[i];
|
||||
// type and value don't apply, so skip them
|
||||
// ** you might also want to skip style, or others -- modify as needed **
|
||||
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style') {
|
||||
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style' && att.name != 'oninput' && att.name != 'max' && att.name != 'min') {
|
||||
sel.setAttribute(att.name, att.value);
|
||||
}
|
||||
}
|
||||
sel.setAttribute("data-val", v);
|
||||
sel.setAttribute("onchange", "UI(this)");
|
||||
// finally, replace the old input element with the new select element
|
||||
inp.parentElement.replaceChild(sel, inp);
|
||||
return sel;
|
||||
@@ -183,6 +264,7 @@
|
||||
let c = sel.childNodes[i];
|
||||
if (c.value == sel.dataset.val) sel.selectedIndex = i;
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
// https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript
|
||||
function addInfo(name,el,txt, txt2="") {
|
||||
@@ -194,10 +276,13 @@
|
||||
if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + ' '); //add pre texts
|
||||
}
|
||||
}
|
||||
// add Help Button
|
||||
function addHB(um) {
|
||||
addInfo(um + ':help',0,`<button onclick="location.href='https://kno.wled.ge/usermods/${um}'" type="button">?</button>`);
|
||||
}
|
||||
// load settings and insert values into DOM
|
||||
function ldS() {
|
||||
var url = (loc?`http://${locip}`:'') + '/cfg.json';
|
||||
fetch(url, {
|
||||
fetch(getURL('/cfg.json'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -216,8 +301,7 @@
|
||||
}
|
||||
if (urows==="") urows = "Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults.";
|
||||
gId("um").innerHTML = urows;
|
||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=8';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=8'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
})
|
||||
.catch((error)=>{
|
||||
gId('lserr').style.display = "inline";
|
||||
@@ -242,15 +326,17 @@
|
||||
</div>
|
||||
<h2>Usermod Setup</h2>
|
||||
Global I<sup>2</sup>C GPIOs (HW)<br>
|
||||
<i style="color: orange;">(only changable on ESP32, change requires reboot!)</i><br>
|
||||
<i class="warn">(change requires reboot!)</i><br>
|
||||
SDA:<input type="number" min="-1" max="48" name="SDA" onchange="check(this,'if')" class="s" placeholder="SDA">
|
||||
SCL:<input type="number" min="-1" max="48" name="SCL" onchange="check(this,'if')" class="s" placeholder="SCL">
|
||||
<hr class="sml">
|
||||
Global SPI GPIOs (HW)<br>
|
||||
<i style="color: orange;">(only changable on ESP32, change requires reboot!)</i><br>
|
||||
<i class="warn">(only changable on ESP32, change requires reboot!)</i><br>
|
||||
MOSI:<input type="number" min="-1" max="48" name="MOSI" onchange="check(this,'if')" class="s" placeholder="MOSI">
|
||||
MISO:<input type="number" min="-1" max="48" name="MISO" onchange="check(this,'if')" class="s" placeholder="MISO">
|
||||
SCLK:<input type="number" min="-1" max="48" name="SCLK" onchange="check(this,'if')" class="s" placeholder="SCLK">
|
||||
<hr class="sml">
|
||||
Reboot after save? <input type="checkbox" name="RBT"><br>
|
||||
<div id="um">Loading settings...</div>
|
||||
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
|
||||
@@ -7,21 +7,19 @@
|
||||
<title>WiFi Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var scanLoops = 0, preScanSSID = "";
|
||||
|
||||
function gId(e) { return d.getElementById(e); }
|
||||
function cE(e) { return d.createElement(e); }
|
||||
function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function N() {
|
||||
const url = (loc?`http://${locip}`:"") + "/json/net";
|
||||
|
||||
const button = gId("scan");
|
||||
button.disabled = true;
|
||||
button.innerHTML = "Scanning...";
|
||||
button.textContent = "Scanning...";
|
||||
|
||||
fetch(url).then((response) => {
|
||||
fetch(getURL("/json/net")).then((response) => {
|
||||
return response.json();
|
||||
}).then((json) => {
|
||||
// Get the list of networks only, defaulting to an empty array.
|
||||
@@ -70,7 +68,7 @@
|
||||
const option = cE("option");
|
||||
|
||||
option.setAttribute("value", networks[i].ssid);
|
||||
option.innerHTML = `${networks[i].ssid} (${networks[i].rssi} dBm)`;
|
||||
option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`;
|
||||
|
||||
if (networks[i].ssid === cs.value) {
|
||||
option.setAttribute("selected", "selected");
|
||||
@@ -81,14 +79,14 @@
|
||||
const option = cE("option");
|
||||
|
||||
option.setAttribute("value", "!Cs");
|
||||
option.innerHTML = `Other network...`;
|
||||
option.textContent = `Other network...`;
|
||||
select.appendChild(option);
|
||||
|
||||
cs.replaceWith(select);
|
||||
}
|
||||
|
||||
button.disabled = false;
|
||||
button.innerHTML = "Scan";
|
||||
button.textContent = "Scan";
|
||||
});
|
||||
}
|
||||
// replace WiFi select with custom SSID input field again
|
||||
@@ -122,16 +120,29 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem("locIp");
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem("locIp", locip);
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy
|
||||
let path = l.pathname;
|
||||
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths.length > 2) {
|
||||
locproto = l.protocol;
|
||||
loc = true;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||
}
|
||||
}
|
||||
let url = (loc?`http://${locip}`:'') + '/settings/s.js?p=1';
|
||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
loadJS(getURL('/settings/s.js?p=1'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
if (loc) d.Sf.action = getURL('/settings/wifi');
|
||||
}
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
@@ -182,6 +193,17 @@
|
||||
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
||||
<i>Can help with connectivity issues.<br>
|
||||
Do not enable if WiFi is working correctly, increases power consumption.</i>
|
||||
|
||||
<div id="remd">
|
||||
<h3>Wireless Remote</h3>
|
||||
<i>Listen for events over ESP-NOW<br>
|
||||
Keep disabled if not using a remote, increases power consumption.<br></i>
|
||||
|
||||
Enable Remote: <input type="checkbox" name="RE"><br>
|
||||
Hardware MAC: <input type="text" name="RMAC"><br>
|
||||
Last Seen: <span class="rlid">None</span> <br>
|
||||
</div>
|
||||
|
||||
<div id="ethd">
|
||||
<h3>Ethernet Type</h3>
|
||||
<select name="ETH">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//page js
|
||||
var loc = false, locip;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var noNewSegs = false;
|
||||
var isOn = false, isInfo = false, isNodes = false, isRgbw = false, cct = false;
|
||||
var whites = [0,0,0];
|
||||
@@ -148,22 +148,39 @@ function loadSkinCSS(cId)
|
||||
l.id = cId;
|
||||
l.rel = 'stylesheet';
|
||||
l.type = 'text/css';
|
||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
||||
l.href = getURL('/skin.css');
|
||||
l.media = 'all';
|
||||
h.appendChild(l);
|
||||
}
|
||||
}
|
||||
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
async function onLoad()
|
||||
{
|
||||
if (window.location.protocol == "file:") {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip)
|
||||
{
|
||||
if (!locip) {
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
} else {
|
||||
// detect reverse proxy and/or HTTPS
|
||||
let pathn = l.pathname;
|
||||
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||
if (paths[0]==="sliders") paths.shift();
|
||||
//while (paths[0]==="") paths.shift();
|
||||
locproto = l.protocol;
|
||||
locip = l.hostname + (l.port ? ":" + l.port : "");
|
||||
if (paths.length > 0 && paths[0]!=="") {
|
||||
loc = true;
|
||||
locip += "/" + paths[0];
|
||||
} else if (locproto==="https:") {
|
||||
loc = true;
|
||||
}
|
||||
}
|
||||
var sett = localStorage.getItem('wledUiCfg');
|
||||
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
||||
@@ -173,7 +190,7 @@ async function onLoad()
|
||||
applyCfg();
|
||||
if (cfg.theme.bg.url=="" || cfg.theme.bg.url === "https://picsum.photos/1920/1080") {
|
||||
var iUrl = cfg.theme.bg.url;
|
||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", {
|
||||
fetch(getURL("/holidays.json"), {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -330,9 +347,7 @@ function loadPresets(callback = null)
|
||||
|
||||
pmtLast = pmt;
|
||||
|
||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/presets.json'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -355,9 +370,7 @@ function loadPresets(callback = null)
|
||||
|
||||
function loadPalettes(callback = null)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/palettes'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -379,9 +392,7 @@ function loadPalettes(callback = null)
|
||||
|
||||
function loadFX(callback = null)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/effects'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -403,9 +414,7 @@ function loadFX(callback = null)
|
||||
|
||||
function loadFXData(callback = null)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/fxdata'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -514,6 +523,7 @@ ${urows}
|
||||
${inforow("Build",i.vid)}
|
||||
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
|
||||
${inforow("Uptime",getRuntimeStr(i.uptime))}
|
||||
${inforow("Time",i.time)}
|
||||
${inforow("Free heap",heap," kB")}
|
||||
${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""}
|
||||
${inforow("Estimated current",pwru)}
|
||||
@@ -611,8 +621,7 @@ function populateNodes(i,n)
|
||||
|
||||
function loadNodes()
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/nodes'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -855,7 +864,8 @@ function cmpP(a, b)
|
||||
|
||||
function makeWS() {
|
||||
if (ws) return;
|
||||
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||
ws = new WebSocket(url);
|
||||
ws.onmessage = (e)=>{
|
||||
var json = JSON.parse(e.data);
|
||||
if (json.leds) return; //liveview packet
|
||||
@@ -974,7 +984,6 @@ function requestJson(command=null)
|
||||
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
|
||||
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
|
||||
var req = null;
|
||||
var url = (loc?`http://${locip}`:'') + '/json/si';
|
||||
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
||||
var type = command ? 'post':'get';
|
||||
if (command) {
|
||||
@@ -991,7 +1000,7 @@ function requestJson(command=null)
|
||||
setTimeout(requestJson,200);
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL('/json/si'), {
|
||||
method: type,
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
@@ -1314,9 +1323,7 @@ function loadPalettesData(callback = null)
|
||||
|
||||
function getPalettesData(page, callback)
|
||||
{
|
||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
||||
|
||||
fetch(url, {
|
||||
fetch(getURL(`/json/palx?page=${page}`), {
|
||||
method: 'get',
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
|
||||
@@ -61,6 +61,12 @@ button.sml {
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.err {
|
||||
color: #f00;
|
||||
}
|
||||
.warn {
|
||||
color: #fa0;
|
||||
}
|
||||
input {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
@@ -114,6 +120,10 @@ select {
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
select.pin {
|
||||
max-width: 120px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
tr {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<body onload="GetV()">
|
||||
<h2>WLED Software Update</h2>
|
||||
<form method='POST' action='/update' id='uf' enctype='multipart/form-data' onsubmit="U()">
|
||||
<form method='POST' action='./update' id='uf' enctype='multipart/form-data' onsubmit="U()">
|
||||
Installed version: <span class="sip">##VERSION##</span><br>
|
||||
Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases" target="_blank">
|
||||
<img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br>
|
||||
|
||||
@@ -55,9 +55,9 @@
|
||||
<h3>Thank you for installing my application!</h3>
|
||||
<b>Next steps:</b><br><br>
|
||||
Connect the module to your local WiFi here!<br>
|
||||
<button onclick="window.location.href='/settings/wifi'">WiFi settings</button><br>
|
||||
<button onclick="window.location.href='./settings/wifi'">WiFi settings</button><br>
|
||||
<i>Just trying this out in AP mode?</i><br>
|
||||
<button onclick="window.location.href='/sliders'">To the controls!</button><br>
|
||||
<button onclick="window.location.href='./?sliders'">To the controls!</button><br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,7 +25,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ddpChannelsPerLed = (p->dataType & 0b00111000 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
|
||||
uint8_t ddpChannelsPerLed = ((p->dataType & 0b00111000)>>3 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
|
||||
|
||||
uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed;
|
||||
start += DMXAddress / ddpChannelsPerLed;
|
||||
|
||||
@@ -50,6 +50,18 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
|
||||
|
||||
//colors.cpp
|
||||
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
|
||||
class NeoGammaWLEDMethod {
|
||||
public:
|
||||
static uint8_t Correct(uint8_t value); // apply Gamma to single channel
|
||||
static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
|
||||
static void calcGammaTable(float gamma); // re-calculates & fills gamma table
|
||||
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
|
||||
private:
|
||||
static uint8_t gammaT[];
|
||||
};
|
||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||
uint32_t color_add(uint32_t,uint32_t);
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
@@ -63,10 +75,6 @@ bool colorFromHexString(byte* rgb, const char* in);
|
||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||
void setRandomColor(byte* rgb);
|
||||
uint8_t gamma8_cal(uint8_t b, float gamma);
|
||||
void calcGammaTable(float gamma);
|
||||
uint8_t gamma8(uint8_t b);
|
||||
uint32_t gamma32(uint32_t);
|
||||
|
||||
//dmx.cpp
|
||||
void initDMX();
|
||||
@@ -96,10 +104,20 @@ void sendHuePoll();
|
||||
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
||||
|
||||
//improv.cpp
|
||||
enum ImprovRPCType {
|
||||
Command_Wifi = 0x01,
|
||||
Request_State = 0x02,
|
||||
Request_Info = 0x03,
|
||||
Request_Scan = 0x04
|
||||
};
|
||||
|
||||
void handleImprovPacket();
|
||||
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings = 0, const char **strings = nullptr);
|
||||
void sendImprovStateResponse(uint8_t state, bool error = false);
|
||||
void sendImprovInfoResponse();
|
||||
void sendImprovRPCResponse(uint8_t commandId);
|
||||
void startImprovWifiScan();
|
||||
void handleImprovWifiScan();
|
||||
void sendImprovIPRPCResult(ImprovRPCType type);
|
||||
|
||||
//ir.cpp
|
||||
void applyRepeatActions();
|
||||
@@ -129,8 +147,8 @@ bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE,
|
||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
||||
void serializeInfo(JsonObject root);
|
||||
void serializeModeNames(JsonArray arr, const char *qstring);
|
||||
void serializeModeData(JsonObject root);
|
||||
void serializeModeNames(JsonArray root);
|
||||
void serializeModeData(JsonArray root);
|
||||
void serveJson(AsyncWebServerRequest* request);
|
||||
#ifdef WLED_ENABLE_JSONLIVE
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||
@@ -152,9 +170,11 @@ void handleTransitions();
|
||||
void handleNightlight();
|
||||
byte scaledBri(byte in);
|
||||
|
||||
#ifdef WLED_ENABLE_LOXONE
|
||||
//lx_parser.cpp
|
||||
bool parseLx(int lxValue, byte* rgbw);
|
||||
void parseLxJson(int lxValue, byte segId, bool secondary);
|
||||
#endif
|
||||
|
||||
//mqtt.cpp
|
||||
bool initMqtt();
|
||||
@@ -190,12 +210,16 @@ void serializePlaylist(JsonObject obj);
|
||||
void initPresetsFile();
|
||||
void handlePresets();
|
||||
bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE);
|
||||
void applyPresetWithFallback(uint8_t presetID, uint8_t callMode, uint8_t effectID = 0, uint8_t paletteID = 0);
|
||||
inline bool applyTemporaryPreset() {return applyPreset(255);};
|
||||
void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject());
|
||||
inline void saveTemporaryPreset() {savePreset(255);};
|
||||
void deletePreset(byte index);
|
||||
bool getPresetName(byte index, String& name);
|
||||
|
||||
//remote.cpp
|
||||
void handleRemote();
|
||||
|
||||
//set.cpp
|
||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage);
|
||||
@@ -203,7 +227,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=tru
|
||||
|
||||
//udp.cpp
|
||||
void notify(byte callMode, bool followUp=false);
|
||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false);
|
||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false);
|
||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||
void exitRealtime();
|
||||
void handleNotifications();
|
||||
@@ -325,6 +349,7 @@ void releaseJSONBufferLock();
|
||||
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr);
|
||||
int16_t extractModeDefaults(uint8_t mode, const char *segVar);
|
||||
void checkSettingsPIN(const char *pin);
|
||||
uint16_t crc16(const unsigned char* data_p, size_t length);
|
||||
um_data_t* simulateSound(uint8_t simulationId);
|
||||
void enumerateLedmaps();
|
||||
@@ -372,7 +397,6 @@ void serveIndexOrWelcome(AsyncWebServerRequest *request);
|
||||
void serveIndex(AsyncWebServerRequest* request);
|
||||
String msgProcessor(const String& var);
|
||||
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255);
|
||||
String settingsProcessor(const String& var);
|
||||
String dmxProcessor(const String& var);
|
||||
void serveSettings(AsyncWebServerRequest* request, bool post = false);
|
||||
void serveSettingsJS(AsyncWebServerRequest* request);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// Autogenerated from wled00/data/cpal/cpal.htm, do not edit!!
|
||||
const uint16_t PAGE_cpal_L = 4721;
|
||||
const uint8_t PAGE_cpal[] PROGMEM = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0xbd, 0x3b, 0x7f, 0x73, 0xdb, 0xb6,
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0xbd, 0x3b, 0x7f, 0x73, 0xdb, 0xb6,
|
||||
0x92, 0xff, 0xe7, 0x53, 0x20, 0x4c, 0x5f, 0x42, 0xd6, 0x14, 0x45, 0xd2, 0xb6, 0x64, 0x4b, 0xa2,
|
||||
0x3b, 0xa9, 0x93, 0x77, 0xce, 0x8d, 0xdd, 0x64, 0x5e, 0x7c, 0x6e, 0x7b, 0x3e, 0xbf, 0x31, 0x4d,
|
||||
0x42, 0x12, 0x1b, 0x8a, 0xe0, 0x03, 0x21, 0xd9, 0xae, 0xac, 0xef, 0x7e, 0xbb, 0x00, 0x48, 0x91,
|
||||
|
||||
2104
wled00/html_other.h
2104
wled00/html_other.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
549
wled00/html_pxmagic.h
Normal file
549
wled00/html_pxmagic.h
Normal file
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Binary array for the Web UI.
|
||||
* gzip is used for smaller size and improved speeds.
|
||||
*
|
||||
* Please see https://kno.wled.ge/advanced/custom-features/#changing-web-ui
|
||||
* to find out how to easily modify the web UI source!
|
||||
*/
|
||||
|
||||
// Autogenerated from wled00/data/pxmagic/pxmagic.htm, do not edit!!
|
||||
const uint16_t PAGE_pxmagic_L = 8581;
|
||||
const uint8_t PAGE_pxmagic[] PROGMEM = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0xbd, 0x7d, 0xdb, 0x76, 0xdb, 0x46,
|
||||
0xb2, 0xe8, 0x3b, 0xbf, 0x02, 0x86, 0x3d, 0x0e, 0x61, 0x81, 0x20, 0xa9, 0x5b, 0x14, 0x50, 0x90,
|
||||
0x26, 0xb1, 0x9d, 0x89, 0xf7, 0xf2, 0x24, 0x39, 0xb1, 0x66, 0xf6, 0x64, 0x69, 0x6b, 0xc5, 0x4d,
|
||||
0xa2, 0x49, 0x22, 0x06, 0xd1, 0x1c, 0x00, 0xd4, 0x25, 0x14, 0x3e, 0xe8, 0x3c, 0x9f, 0x4f, 0xd8,
|
||||
0x3f, 0x76, 0xaa, 0xaa, 0xbb, 0x81, 0xc6, 0x85, 0xb2, 0x14, 0xef, 0xb5, 0x3d, 0x33, 0x02, 0xd0,
|
||||
0xe8, 0x4b, 0x75, 0xdd, 0xab, 0xba, 0xc0, 0x39, 0x7d, 0xf6, 0xe6, 0xa7, 0xd7, 0x17, 0xbf, 0xfe,
|
||||
0xfc, 0xd6, 0x5a, 0xe6, 0xab, 0xf8, 0xcc, 0x3a, 0xc5, 0x8b, 0x15, 0xb3, 0x64, 0x11, 0xd8, 0x3c,
|
||||
0xb1, 0xb1, 0x81, 0xb3, 0x10, 0x2e, 0x2b, 0x9e, 0x33, 0x6b, 0xb6, 0x64, 0x69, 0xc6, 0xf3, 0xc0,
|
||||
0xfe, 0xc7, 0xc5, 0xf7, 0x83, 0x13, 0x5b, 0x37, 0xf7, 0x12, 0xb6, 0xe2, 0x81, 0x7d, 0x1d, 0xf1,
|
||||
0x9b, 0xb5, 0x48, 0x73, 0xdb, 0x9a, 0x89, 0x24, 0xe7, 0x09, 0xf4, 0xbb, 0x89, 0xc2, 0x7c, 0x19,
|
||||
0x84, 0xfc, 0x3a, 0x9a, 0xf1, 0x01, 0x3d, 0xb8, 0x51, 0x12, 0xe5, 0x11, 0x8b, 0x07, 0xd9, 0x8c,
|
||||
0xc5, 0x3c, 0x18, 0x37, 0x27, 0x61, 0x9b, 0x7c, 0x29, 0x52, 0x63, 0x8a, 0xbf, 0xb2, 0xdf, 0x45,
|
||||
0xce, 0x92, 0x19, 0x76, 0xcc, 0xa3, 0x3c, 0xe6, 0x67, 0x3f, 0x47, 0xb7, 0x3c, 0xb6, 0xfe, 0xce,
|
||||
0x16, 0xd1, 0xcc, 0xba, 0x10, 0x22, 0x3e, 0x1d, 0xca, 0x76, 0xeb, 0x34, 0xcb, 0xef, 0xe0, 0xda,
|
||||
0xf3, 0x53, 0x21, 0xf2, 0xed, 0x60, 0x20, 0xae, 0x79, 0x1a, 0xb3, 0x3b, 0x3f, 0x5d, 0x4c, 0x59,
|
||||
0x7f, 0xe4, 0x5a, 0xea, 0xbf, 0xde, 0x91, 0x33, 0x19, 0x0c, 0xa6, 0x6c, 0xf6, 0x69, 0x91, 0x8a,
|
||||
0x4d, 0x12, 0xfa, 0xcf, 0xc7, 0xe3, 0x31, 0xb4, 0xe4, 0xfc, 0x36, 0xf7, 0x9f, 0x4f, 0xa7, 0x53,
|
||||
0xb8, 0x5f, 0xa4, 0xec, 0x6e, 0x10, 0xb2, 0xf4, 0x93, 0xff, 0x7c, 0x7f, 0x7f, 0x5f, 0x37, 0xac,
|
||||
0x78, 0x18, 0x6d, 0x56, 0xfe, 0xf3, 0x83, 0x83, 0x03, 0xdd, 0x14, 0x47, 0x8b, 0x25, 0x8c, 0xe2,
|
||||
0xf4, 0x0f, 0xa7, 0x8d, 0x37, 0x5c, 0x0f, 0x3c, 0x39, 0x3c, 0x38, 0xda, 0xd7, 0x6d, 0xe5, 0xd8,
|
||||
0xe9, 0xd7, 0xa3, 0x93, 0xa9, 0x6e, 0x55, 0xc3, 0x0f, 0x4f, 0x18, 0xb4, 0x64, 0x9b, 0xd9, 0x8c,
|
||||
0x67, 0x99, 0x1a, 0x3e, 0x3a, 0x38, 0x3c, 0x1c, 0xcd, 0x8c, 0x66, 0x3d, 0xc3, 0xd1, 0xe1, 0xc9,
|
||||
0x6c, 0x7f, 0x6e, 0xbc, 0x50, 0x93, 0x9c, 0xb0, 0xd9, 0x37, 0xfb, 0xc7, 0xd0, 0xce, 0xd3, 0x54,
|
||||
0xa4, 0x6a, 0x16, 0x76, 0x32, 0x62, 0x23, 0x56, 0x36, 0xea, 0x39, 0xb0, 0xe7, 0xfe, 0xb4, 0x6c,
|
||||
0x56, 0x33, 0xcc, 0xe7, 0x47, 0xdf, 0x1c, 0xe1, 0x2e, 0x6e, 0x58, 0x9a, 0x44, 0xc9, 0x42, 0xcd,
|
||||
0x11, 0xc2, 0x72, 0xa3, 0x7d, 0xa3, 0x59, 0xcf, 0xc2, 0x4f, 0x8e, 0xc2, 0xd1, 0xa1, 0xf1, 0x42,
|
||||
0xcf, 0x03, 0x10, 0x8e, 0x8e, 0x0b, 0xdf, 0xcf, 0x78, 0xcc, 0x67, 0x79, 0x24, 0x92, 0xad, 0x81,
|
||||
0xee, 0x6b, 0x96, 0xf6, 0xcd, 0xed, 0x3b, 0xc5, 0xab, 0xed, 0x1c, 0xc8, 0x3d, 0x98, 0xb3, 0x55,
|
||||
0x14, 0xdf, 0xf9, 0x3f, 0xf0, 0xf8, 0x9a, 0xe7, 0xd1, 0x8c, 0xb9, 0xff, 0xe4, 0x69, 0xc8, 0x12,
|
||||
0xe6, 0x66, 0x2c, 0xc9, 0x06, 0x19, 0x4f, 0xa3, 0xf9, 0x64, 0x2a, 0x6e, 0x07, 0x59, 0xf4, 0x07,
|
||||
0x2c, 0xe6, 0x4f, 0x45, 0x1a, 0xf2, 0x74, 0x00, 0x2d, 0x93, 0x15, 0x4b, 0x17, 0x51, 0xe2, 0x8f,
|
||||
0x26, 0x6b, 0x16, 0x86, 0xf8, 0x6e, 0x54, 0x4c, 0x45, 0x78, 0xb7, 0x0d, 0xa3, 0x6c, 0x8d, 0x1c,
|
||||
0x30, 0x8f, 0xf9, 0xed, 0xe4, 0xf7, 0x4d, 0x96, 0x47, 0xf3, 0xbb, 0x81, 0x62, 0x2d, 0x7f, 0x06,
|
||||
0x7f, 0x78, 0x3a, 0x61, 0x00, 0x44, 0x32, 0x88, 0x72, 0xbe, 0xca, 0x74, 0xd3, 0x2a, 0x4a, 0x06,
|
||||
0x4b, 0x4e, 0x7b, 0x19, 0x8f, 0x46, 0xd7, 0xcb, 0x49, 0x1b, 0xfa, 0xb2, 0xc1, 0x29, 0x66, 0x2c,
|
||||
0xb9, 0x66, 0xd9, 0x96, 0xd8, 0x1b, 0xfb, 0xff, 0xa5, 0x98, 0x8b, 0x74, 0xb5, 0x95, 0x30, 0x01,
|
||||
0x78, 0x79, 0x2e, 0x56, 0xfe, 0xfe, 0x68, 0x7d, 0x5b, 0x64, 0x2b, 0x16, 0xc7, 0x25, 0x50, 0xd3,
|
||||
0x58, 0xcc, 0x3e, 0x4d, 0x68, 0xe7, 0x37, 0x72, 0xb1, 0xc3, 0xd1, 0x48, 0x6f, 0x65, 0x7f, 0x7d,
|
||||
0x6b, 0x8d, 0xac, 0xa3, 0xf5, 0xed, 0x64, 0x26, 0x62, 0x91, 0xaa, 0x65, 0x91, 0x45, 0x1d, 0x39,
|
||||
0x04, 0x90, 0xc0, 0xfd, 0x31, 0x74, 0x83, 0xd5, 0x04, 0x00, 0x6d, 0xac, 0x5f, 0xa2, 0xc3, 0x02,
|
||||
0x69, 0x12, 0x16, 0x2e, 0x3d, 0xa9, 0x2f, 0x8a, 0xf3, 0x0c, 0x68, 0xe3, 0x6a, 0xcb, 0x05, 0xdb,
|
||||
0x52, 0x5b, 0xc8, 0x67, 0x22, 0x65, 0x48, 0x31, 0x3f, 0x11, 0x09, 0xaf, 0x2d, 0x6e, 0x50, 0xac,
|
||||
0x01, 0x42, 0x6d, 0x13, 0xc7, 0xa3, 0x51, 0xe1, 0x47, 0x59, 0x9f, 0xf9, 0x4b, 0x14, 0x40, 0x97,
|
||||
0xf9, 0x73, 0x31, 0xdb, 0x64, 0x70, 0x65, 0xc0, 0x0a, 0xd7, 0xdc, 0xd9, 0xb6, 0x26, 0x95, 0xfc,
|
||||
0xe4, 0x14, 0xde, 0x6a, 0xf0, 0x07, 0x4f, 0xc5, 0x56, 0xc3, 0xff, 0x2c, 0x5a, 0xa1, 0x42, 0x61,
|
||||
0x49, 0x8e, 0xaf, 0x24, 0x26, 0x1b, 0x78, 0x1d, 0xc3, 0xe6, 0xea, 0xdd, 0x72, 0xb1, 0xd6, 0x7d,
|
||||
0xe0, 0xb6, 0xd5, 0x01, 0xa9, 0xcf, 0xa2, 0xa4, 0x8e, 0xb0, 0x1a, 0x9f, 0x74, 0x30, 0xc4, 0x0e,
|
||||
0xd6, 0xc1, 0xee, 0x83, 0x30, 0x4a, 0x25, 0x8f, 0xfb, 0xb0, 0xaf, 0xcd, 0x2a, 0x91, 0x4b, 0x40,
|
||||
0x07, 0xb5, 0x00, 0xe8, 0xb9, 0x59, 0x1f, 0x57, 0xb1, 0x06, 0xd6, 0x21, 0x00, 0xe3, 0x00, 0x79,
|
||||
0x6e, 0xa5, 0x32, 0xf4, 0xbf, 0x3e, 0x3e, 0x59, 0x97, 0xdc, 0x4b, 0x2c, 0xe2, 0xa5, 0xe2, 0xa6,
|
||||
0xce, 0xb6, 0xb4, 0xc8, 0x4d, 0xca, 0xd6, 0x40, 0x11, 0xbc, 0xb4, 0x80, 0xc9, 0xd6, 0x0c, 0xb4,
|
||||
0xeb, 0x94, 0xe7, 0x37, 0x9c, 0x27, 0xe6, 0x64, 0xc0, 0x40, 0x23, 0x84, 0x06, 0xa1, 0xda, 0xd2,
|
||||
0x34, 0x53, 0x96, 0x45, 0x99, 0x84, 0xe8, 0x88, 0x00, 0x1a, 0x13, 0x40, 0x6b, 0x91, 0x45, 0xb4,
|
||||
0x83, 0x94, 0xc7, 0x0c, 0x69, 0x54, 0xc9, 0x11, 0xb2, 0xa0, 0x9e, 0x63, 0x30, 0xdf, 0x00, 0xfb,
|
||||
0x1a, 0x13, 0x11, 0xee, 0x3e, 0x37, 0x38, 0x66, 0x53, 0xde, 0x64, 0xfa, 0x3a, 0x0d, 0x8f, 0x1a,
|
||||
0x1c, 0xf4, 0x35, 0x88, 0x41, 0x8b, 0xeb, 0x8b, 0x28, 0x59, 0x6f, 0xf2, 0xcb, 0xfc, 0x6e, 0xcd,
|
||||
0x83, 0x64, 0xb3, 0x9a, 0xf2, 0xf4, 0xca, 0x35, 0x9a, 0xb0, 0xcf, 0x95, 0x2b, 0xf5, 0x8d, 0x8b,
|
||||
0x0f, 0x2c, 0xe5, 0xcc, 0x24, 0xb1, 0x06, 0x0a, 0x77, 0x3c, 0x51, 0xaa, 0x23, 0x65, 0xc0, 0x77,
|
||||
0x99, 0x7f, 0x44, 0x4d, 0xa5, 0x44, 0x0f, 0xcc, 0xb5, 0x0d, 0xbd, 0xef, 0xa8, 0x61, 0xfe, 0x18,
|
||||
0x50, 0x9b, 0x89, 0x38, 0x0a, 0xad, 0x8e, 0x3e, 0x62, 0x93, 0xc7, 0xc0, 0x5e, 0x7e, 0x7d, 0x0b,
|
||||
0x95, 0xad, 0xa8, 0xc9, 0xce, 0x21, 0xe0, 0xc7, 0xd8, 0x04, 0x8d, 0xb8, 0x52, 0x50, 0x1f, 0xa0,
|
||||
0x60, 0x29, 0x2d, 0x44, 0xf7, 0xb3, 0x4d, 0x9a, 0xc1, 0x84, 0x6b, 0x11, 0x11, 0xf3, 0x55, 0x58,
|
||||
0x06, 0x78, 0xaa, 0x65, 0x0b, 0x8f, 0x26, 0x1c, 0xe0, 0x5e, 0xd6, 0x7f, 0x52, 0x01, 0xd6, 0xe6,
|
||||
0xb0, 0xe8, 0x1e, 0x98, 0x2f, 0xef, 0x4b, 0x28, 0x53, 0xf0, 0x0e, 0xf8, 0x95, 0xb3, 0xad, 0x23,
|
||||
0xf1, 0x44, 0xf2, 0x9b, 0x75, 0x82, 0xfc, 0x62, 0x0e, 0x57, 0x0f, 0x21, 0xcf, 0x66, 0x69, 0xb4,
|
||||
0x26, 0x63, 0xa0, 0x36, 0x78, 0x62, 0x6c, 0x10, 0xef, 0x4d, 0x12, 0x59, 0x1d, 0xf8, 0x43, 0x6b,
|
||||
0xe4, 0xb4, 0x75, 0xb1, 0x89, 0xdb, 0x3a, 0x4c, 0xc4, 0x80, 0xf4, 0xbf, 0xd1, 0x83, 0xb4, 0xab,
|
||||
0x0f, 0x8e, 0xf9, 0x3c, 0x07, 0xf2, 0xb5, 0x74, 0x64, 0x83, 0x70, 0x13, 0xc4, 0x77, 0x69, 0x26,
|
||||
0x8e, 0x3b, 0xb4, 0x60, 0x1d, 0x0d, 0xd9, 0xbf, 0x37, 0xc0, 0x93, 0x6d, 0xac, 0x55, 0xca, 0x49,
|
||||
0x8b, 0x05, 0x01, 0x80, 0x48, 0x28, 0x4a, 0x46, 0x4e, 0x39, 0xad, 0x0b, 0xfa, 0x14, 0x0d, 0x63,
|
||||
0x6c, 0x5a, 0xa8, 0xfd, 0x51, 0x9b, 0xa3, 0x89, 0x08, 0xa0, 0x74, 0x41, 0xba, 0x06, 0x52, 0x26,
|
||||
0xb6, 0x2d, 0x31, 0x6d, 0x74, 0xb0, 0x54, 0x3f, 0xb6, 0x5e, 0x73, 0x06, 0x24, 0x9e, 0x71, 0x69,
|
||||
0x01, 0x60, 0x43, 0xd3, 0x4f, 0x11, 0x60, 0xa2, 0xd9, 0xbe, 0x12, 0x7f, 0xb4, 0x1a, 0x0d, 0x21,
|
||||
0x8a, 0x56, 0x6c, 0xa1, 0x5a, 0x15, 0x5d, 0x07, 0xa9, 0x82, 0xb7, 0xc5, 0xcb, 0x4d, 0x50, 0x48,
|
||||
0x65, 0xf8, 0x3e, 0x9b, 0xa3, 0x5d, 0xd3, 0xdc, 0x6a, 0xdb, 0x95, 0xaa, 0x61, 0x53, 0xa0, 0xe1,
|
||||
0x26, 0xe7, 0x13, 0xd4, 0xf0, 0xa5, 0x3a, 0xdb, 0xb3, 0x8e, 0x51, 0x9b, 0xa5, 0x15, 0x45, 0x72,
|
||||
0x80, 0x2d, 0x43, 0x6b, 0x0c, 0x2e, 0x61, 0xce, 0x72, 0xde, 0x1f, 0x1f, 0x1c, 0x85, 0x7c, 0xe1,
|
||||
0x4c, 0x24, 0x07, 0x1e, 0x57, 0x0c, 0x78, 0x5c, 0xe1, 0x10, 0xe7, 0xdc, 0xff, 0x3c, 0x9b, 0xa8,
|
||||
0xdd, 0x3c, 0xd0, 0x51, 0xed, 0x6e, 0xc0, 0xaf, 0x01, 0xfe, 0x8c, 0x70, 0x51, 0x78, 0x61, 0x2a,
|
||||
0xd6, 0x7f, 0xc0, 0x9d, 0xa9, 0x9b, 0x0c, 0xde, 0x0c, 0x59, 0xb6, 0xe4, 0x9d, 0xab, 0x3e, 0xa0,
|
||||
0x9f, 0xa4, 0x60, 0xec, 0xd2, 0x37, 0x6d, 0x46, 0xd6, 0x82, 0x86, 0xe6, 0xc8, 0x1a, 0x77, 0xb2,
|
||||
0x4f, 0xd3, 0x8e, 0x48, 0x54, 0x2a, 0xec, 0xc7, 0xb1, 0xe5, 0x1d, 0x65, 0x16, 0x67, 0x19, 0x1f,
|
||||
0x00, 0x23, 0x82, 0xee, 0xa9, 0xf6, 0x25, 0xad, 0xfe, 0xb6, 0xa1, 0xac, 0x3e, 0x2b, 0xcb, 0x83,
|
||||
0x5d, 0xd0, 0x2b, 0xc8, 0xba, 0x27, 0xa8, 0x96, 0x85, 0x1b, 0xb6, 0xa0, 0x95, 0x1f, 0xa1, 0xc8,
|
||||
0xc1, 0xca, 0xa2, 0x0e, 0x1b, 0x64, 0x40, 0x37, 0x18, 0xf1, 0x00, 0x17, 0xef, 0x82, 0x4a, 0x71,
|
||||
0x0d, 0x22, 0xaa, 0x45, 0x47, 0x8d, 0x45, 0x42, 0x6c, 0x65, 0x0e, 0x14, 0x42, 0x91, 0x2f, 0xd1,
|
||||
0x2c, 0x9b, 0x10, 0xf8, 0xbe, 0x96, 0x32, 0xf9, 0x3c, 0xc8, 0x97, 0x60, 0xe1, 0x5a, 0x70, 0x99,
|
||||
0xba, 0x46, 0xad, 0x7a, 0xfc, 0x19, 0xcb, 0xa5, 0xd0, 0xdc, 0x30, 0x77, 0x7f, 0x69, 0xda, 0x12,
|
||||
0xc5, 0x80, 0x00, 0x56, 0x76, 0x13, 0xe5, 0xb3, 0x65, 0x5b, 0x5b, 0x94, 0x2e, 0x52, 0x94, 0x90,
|
||||
0xde, 0x93, 0x76, 0xbc, 0xad, 0xc8, 0xa5, 0x13, 0x23, 0x67, 0x91, 0x96, 0x63, 0x5b, 0xa1, 0x40,
|
||||
0xcf, 0x21, 0x25, 0x41, 0x76, 0xd2, 0x44, 0x68, 0xcb, 0x76, 0x03, 0x46, 0x14, 0xcb, 0xd1, 0x44,
|
||||
0x29, 0x67, 0x29, 0x7c, 0xa8, 0xd5, 0xc9, 0x83, 0x18, 0x3d, 0xc1, 0x7c, 0x6b, 0x34, 0x1c, 0x1c,
|
||||
0x6a, 0x05, 0x21, 0xd7, 0xf5, 0x0e, 0xb3, 0x06, 0x4c, 0xfe, 0x94, 0x83, 0xee, 0xe0, 0x5d, 0xa0,
|
||||
0x55, 0x3a, 0x49, 0x13, 0xe5, 0xb0, 0x22, 0x0a, 0x19, 0x07, 0x84, 0xf3, 0x80, 0x24, 0x8b, 0x20,
|
||||
0x3c, 0xe8, 0x22, 0x14, 0x04, 0x5c, 0xf3, 0x0e, 0xe2, 0x34, 0x80, 0x92, 0xf6, 0x77, 0xb6, 0xe4,
|
||||
0xb3, 0x4f, 0x3c, 0xdc, 0x6b, 0xa0, 0x6d, 0xc7, 0xbe, 0xcd, 0xe8, 0x4a, 0x8e, 0x27, 0x27, 0xbc,
|
||||
0x35, 0x1a, 0xa3, 0xa9, 0x25, 0x0b, 0xc5, 0x8d, 0x8f, 0xb6, 0x1b, 0x15, 0xd0, 0xae, 0xf1, 0xdd,
|
||||
0xeb, 0x6b, 0x14, 0x55, 0x8a, 0x96, 0xee, 0x80, 0x67, 0xf8, 0xbf, 0xfa, 0x63, 0xe0, 0x0b, 0xa7,
|
||||
0x78, 0x9e, 0x0b, 0x96, 0xe5, 0x83, 0xca, 0xef, 0x2e, 0xd1, 0x39, 0x87, 0x40, 0x3e, 0x9c, 0x18,
|
||||
0x01, 0xd2, 0xc4, 0xb0, 0x10, 0x7f, 0x80, 0x66, 0x09, 0xf9, 0xad, 0xff, 0x0d, 0xfc, 0x2b, 0x3c,
|
||||
0x9a, 0x63, 0xfb, 0x39, 0x37, 0x5d, 0xe2, 0x1f, 0x83, 0x9e, 0x52, 0xc5, 0xa1, 0xb4, 0x51, 0x88,
|
||||
0xa2, 0xc5, 0x4f, 0xeb, 0xb3, 0xb6, 0xc6, 0xeb, 0xd8, 0xc3, 0xaf, 0xfd, 0x03, 0x72, 0x90, 0x05,
|
||||
0xb8, 0xd8, 0x51, 0x7e, 0x07, 0x7c, 0x76, 0x1d, 0x65, 0xd1, 0x34, 0x8a, 0xf1, 0x61, 0x19, 0x85,
|
||||
0x21, 0x4f, 0x14, 0x6c, 0x96, 0xbc, 0x0c, 0x28, 0xec, 0xd4, 0x8b, 0x93, 0x4f, 0xd4, 0x74, 0x0b,
|
||||
0x3a, 0x02, 0xba, 0x98, 0xe7, 0x68, 0x27, 0xd0, 0x91, 0xc7, 0x61, 0x1e, 0xf9, 0xdc, 0x34, 0x9f,
|
||||
0xa7, 0x62, 0xfc, 0x5d, 0x74, 0xae, 0xe7, 0x06, 0x1c, 0x3d, 0x8a, 0xa2, 0xfa, 0x5d, 0x63, 0x8c,
|
||||
0x90, 0xbf, 0x1c, 0xa0, 0x02, 0xf8, 0x5d, 0x43, 0x6a, 0xf1, 0xbd, 0x1e, 0x34, 0x58, 0xa7, 0x62,
|
||||
0x91, 0x22, 0x70, 0x6d, 0x01, 0x21, 0xf6, 0x3f, 0xac, 0xd8, 0xbf, 0x92, 0x0e, 0x33, 0x1c, 0x42,
|
||||
0xfe, 0x28, 0x3d, 0xc0, 0x1a, 0x05, 0x28, 0x3b, 0xf4, 0xaf, 0xfe, 0xc8, 0xa9, 0xda, 0x06, 0x02,
|
||||
0xb8, 0x03, 0x28, 0x88, 0x53, 0x37, 0xa8, 0x17, 0x25, 0x4b, 0x9e, 0x46, 0x79, 0x03, 0x67, 0x56,
|
||||
0x13, 0x4c, 0xc3, 0x73, 0x44, 0x85, 0xc4, 0x52, 0x54, 0x0f, 0x61, 0x04, 0xbc, 0xd3, 0x87, 0x30,
|
||||
0x99, 0x78, 0xcf, 0xad, 0xa3, 0x55, 0xee, 0xd7, 0xed, 0xc4, 0x75, 0x1d, 0xd9, 0x5f, 0xb0, 0x98,
|
||||
0x49, 0x8f, 0x5a, 0x53, 0x73, 0x21, 0x45, 0x85, 0x2f, 0x58, 0xaa, 0x4e, 0xc7, 0x46, 0x63, 0xb5,
|
||||
0x1c, 0xe6, 0xfc, 0x40, 0x50, 0xdb, 0x61, 0x68, 0x33, 0xd6, 0xed, 0x12, 0xc2, 0x2a, 0x2e, 0x19,
|
||||
0x59, 0xd2, 0x1a, 0xc8, 0xe9, 0x2c, 0x6f, 0x0a, 0xa4, 0x0c, 0xeb, 0x79, 0x0a, 0x1d, 0x08, 0x4b,
|
||||
0x27, 0xb6, 0xca, 0xb9, 0xfc, 0xa5, 0x91, 0xb0, 0xa8, 0x6c, 0x48, 0x65, 0xaa, 0x66, 0x0c, 0xf6,
|
||||
0x9c, 0x19, 0xb1, 0x25, 0xc1, 0x69, 0xce, 0x61, 0x2c, 0xd5, 0x72, 0x38, 0xd5, 0x60, 0x2b, 0x5a,
|
||||
0x2d, 0x1a, 0xc1, 0xa9, 0x31, 0xca, 0x9c, 0x4c, 0x39, 0xe7, 0x86, 0x8a, 0x6a, 0x83, 0x82, 0xb3,
|
||||
0xf9, 0x31, 0xa9, 0xbb, 0x65, 0x14, 0x87, 0xdb, 0xda, 0x18, 0xe8, 0x37, 0xdd, 0x80, 0x34, 0x24,
|
||||
0x1d, 0xae, 0xdf, 0xa8, 0x1e, 0xfc, 0xa0, 0xe6, 0xec, 0x0a, 0x52, 0xdb, 0xaa, 0xa3, 0x61, 0x24,
|
||||
0xcb, 0xcc, 0xcf, 0x48, 0xf9, 0x75, 0x9d, 0xc1, 0xd2, 0x63, 0xe2, 0x59, 0xe9, 0x39, 0x3c, 0xec,
|
||||
0xf5, 0x35, 0x23, 0xa2, 0x56, 0x00, 0x24, 0xf7, 0xab, 0x5c, 0xc2, 0x6e, 0x58, 0x4c, 0x0f, 0xe5,
|
||||
0xc1, 0xc8, 0xba, 0x9c, 0xad, 0x8d, 0x5f, 0xed, 0x05, 0xe8, 0x2e, 0xd9, 0x63, 0x58, 0xd7, 0xc8,
|
||||
0xd7, 0x3d, 0x57, 0x99, 0xe2, 0xa6, 0x69, 0xaa, 0xb9, 0x1c, 0x3b, 0xd8, 0x62, 0x87, 0xc6, 0x54,
|
||||
0x33, 0x3a, 0x75, 0x9f, 0x47, 0x2f, 0xe4, 0xc5, 0x82, 0x11, 0xb5, 0xdb, 0x31, 0x4e, 0x9d, 0x17,
|
||||
0x3f, 0x13, 0xf1, 0x0c, 0xac, 0xf1, 0x37, 0xa8, 0x43, 0x09, 0xc4, 0x56, 0xab, 0x12, 0x2d, 0x23,
|
||||
0xca, 0xd9, 0xaf, 0xc2, 0x1c, 0xb2, 0x8c, 0x9f, 0x09, 0x71, 0x60, 0xad, 0xc7, 0xbb, 0x94, 0x2c,
|
||||
0x81, 0x90, 0x8f, 0x60, 0xcd, 0xd6, 0x51, 0x62, 0x8d, 0x33, 0x4b, 0x2a, 0x23, 0xf0, 0x02, 0xe7,
|
||||
0x98, 0xf4, 0x87, 0xdd, 0x03, 0x05, 0x20, 0x98, 0xcd, 0x79, 0xf8, 0x0e, 0x83, 0xc3, 0x6d, 0x2d,
|
||||
0xc4, 0xc0, 0x68, 0xf9, 0x1a, 0xd4, 0x49, 0xb8, 0xdd, 0xc1, 0x0b, 0x55, 0x56, 0xdb, 0x31, 0xf3,
|
||||
0x79, 0x5a, 0x55, 0x66, 0x19, 0x4e, 0x59, 0xc7, 0x5e, 0xdb, 0xea, 0x49, 0xe0, 0xcb, 0xf8, 0xa7,
|
||||
0xd3, 0x3e, 0x37, 0xd2, 0xab, 0x7f, 0x45, 0xfe, 0x63, 0x56, 0xdf, 0xcc, 0xda, 0x7d, 0x0d, 0xe8,
|
||||
0xdd, 0x6a, 0x35, 0xa9, 0xc3, 0xdb, 0x8a, 0x0b, 0x31, 0x87, 0x57, 0xa5, 0xed, 0x28, 0x69, 0xd7,
|
||||
0xcd, 0x83, 0x5a, 0x5c, 0x75, 0x86, 0xcd, 0x7d, 0x30, 0xd3, 0xd6, 0x0c, 0xc9, 0xaa, 0x64, 0x77,
|
||||
0xf1, 0xd7, 0x4f, 0xfc, 0x6e, 0x9e, 0x32, 0x40, 0x83, 0x85, 0xd8, 0xdf, 0xe6, 0x62, 0xdb, 0x8a,
|
||||
0x7d, 0x0f, 0x8e, 0x47, 0x18, 0xfb, 0xd6, 0x3a, 0x97, 0x36, 0xa4, 0x36, 0x40, 0x59, 0xdf, 0x71,
|
||||
0xbd, 0xef, 0x1c, 0x76, 0xfb, 0x2e, 0xd9, 0x1e, 0xfd, 0x65, 0xab, 0xdd, 0xa1, 0xb1, 0xe9, 0x0e,
|
||||
0xd1, 0x6d, 0xcc, 0xbb, 0xdd, 0xa8, 0x91, 0x53, 0x7c, 0x53, 0x1b, 0xb8, 0xab, 0x57, 0xd1, 0x3b,
|
||||
0x1d, 0xca, 0x63, 0x1c, 0xeb, 0x74, 0xa8, 0xce, 0x9e, 0xd0, 0xa7, 0x82, 0x4b, 0x18, 0x5d, 0x5b,
|
||||
0x33, 0x10, 0xfe, 0x2c, 0xb0, 0x4b, 0x67, 0xd2, 0x6e, 0xb7, 0x83, 0x1c, 0x61, 0x2b, 0xce, 0x6d,
|
||||
0xf5, 0xa2, 0x30, 0xb0, 0xf1, 0xee, 0x6f, 0x1c, 0x3a, 0xc3, 0x1a, 0xb6, 0x95, 0x08, 0xe2, 0x32,
|
||||
0xb8, 0xaf, 0x0f, 0x95, 0xc4, 0xc4, 0x91, 0xd9, 0xf5, 0x42, 0x37, 0x92, 0xc5, 0xb2, 0xad, 0xde,
|
||||
0xed, 0x2a, 0x4e, 0xb0, 0x4f, 0x9e, 0xaf, 0xfd, 0xe1, 0xf0, 0xe6, 0xe6, 0xc6, 0xbb, 0x39, 0xf0,
|
||||
0x44, 0xba, 0x18, 0x82, 0xdd, 0x1a, 0x0d, 0x61, 0x80, 0x6d, 0xc9, 0xa3, 0x2e, 0x1b, 0x1a, 0x6c,
|
||||
0x4b, 0x4a, 0x5b, 0x60, 0x8f, 0x0f, 0xe0, 0xa1, 0x87, 0xe7, 0x62, 0xdf, 0x89, 0xdb, 0xc0, 0x96,
|
||||
0x16, 0x11, 0x34, 0x33, 0x34, 0x9f, 0x9d, 0x52, 0x82, 0x64, 0xe7, 0xb0, 0xe1, 0xd9, 0x29, 0xce,
|
||||
0x8b, 0x58, 0x00, 0x20, 0x15, 0xa8, 0x3d, 0x05, 0x16, 0xf0, 0x57, 0x6b, 0xe3, 0xc8, 0x36, 0xb6,
|
||||
0x65, 0xec, 0x8d, 0x92, 0x28, 0x16, 0x6c, 0x1e, 0xe0, 0x16, 0x59, 0x8e, 0xc7, 0x6b, 0xf6, 0xd9,
|
||||
0x0f, 0xea, 0x0e, 0xb0, 0x4c, 0xef, 0xa1, 0x1f, 0xb9, 0xf7, 0x16, 0x65, 0xf6, 0x6c, 0xb4, 0x29,
|
||||
0x80, 0x22, 0x3a, 0x89, 0x2b, 0x07, 0x59, 0x88, 0xc4, 0xea, 0x29, 0xe5, 0xff, 0xde, 0x00, 0x1f,
|
||||
0x87, 0xdd, 0xa0, 0x3d, 0x0c, 0x88, 0x04, 0xe2, 0x67, 0xe0, 0x38, 0x9e, 0x5b, 0x3f, 0xc2, 0x43,
|
||||
0x13, 0x8c, 0x5e, 0x1b, 0x8e, 0x0a, 0x06, 0x79, 0x07, 0x33, 0x6f, 0xa0, 0xf9, 0x47, 0x7e, 0x63,
|
||||
0xc9, 0x89, 0xba, 0x40, 0x92, 0x97, 0x9e, 0x89, 0xa2, 0x47, 0x21, 0xcd, 0x7c, 0x6b, 0xa6, 0xa4,
|
||||
0x6c, 0x9c, 0xcc, 0xd8, 0xc8, 0x9a, 0xa1, 0xc7, 0x9e, 0xc0, 0x5e, 0xe4, 0x4d, 0xb5, 0x0f, 0x95,
|
||||
0xc2, 0x92, 0xb0, 0xeb, 0x6e, 0x04, 0x7e, 0xf9, 0xd0, 0x33, 0xe0, 0x15, 0x94, 0x11, 0x95, 0x9b,
|
||||
0x3a, 0xfb, 0x20, 0xc7, 0xe2, 0x41, 0xab, 0x88, 0x66, 0x80, 0x1c, 0xf9, 0xb6, 0xd1, 0x0d, 0x18,
|
||||
0x04, 0xe6, 0xa0, 0x33, 0xcf, 0xc0, 0xbe, 0xfc, 0x6a, 0x4e, 0xff, 0xbe, 0xba, 0xb2, 0x55, 0x06,
|
||||
0x8f, 0xc3, 0x52, 0xfa, 0x0e, 0xc0, 0x7e, 0x97, 0xc0, 0x9e, 0xa2, 0x70, 0xc3, 0x62, 0x6b, 0xe7,
|
||||
0x7c, 0xfb, 0xc6, 0x7c, 0x23, 0xd7, 0xaa, 0xa6, 0x3c, 0x7b, 0x87, 0x31, 0xd8, 0xce, 0x71, 0x07,
|
||||
0xb6, 0x65, 0x0c, 0x3b, 0xaa, 0x8d, 0xec, 0xfd, 0x82, 0x09, 0x0e, 0x63, 0xe8, 0x50, 0x02, 0xd5,
|
||||
0xa4, 0xd1, 0x23, 0x08, 0xd2, 0xdb, 0x41, 0x11, 0x93, 0x20, 0xe0, 0x8d, 0x00, 0xff, 0xd8, 0x67,
|
||||
0x3f, 0xd1, 0x75, 0x07, 0x39, 0x54, 0x27, 0xa9, 0x16, 0xf4, 0xc3, 0x9f, 0x26, 0x46, 0x4f, 0x61,
|
||||
0xe1, 0xf7, 0x4c, 0x24, 0xdd, 0xc8, 0xff, 0xcf, 0xf7, 0x6f, 0xdf, 0x58, 0xff, 0xf1, 0xe1, 0xa7,
|
||||
0x1f, 0x77, 0x62, 0x70, 0xc9, 0x00, 0x53, 0x3f, 0x88, 0x15, 0xb7, 0xbe, 0xcd, 0x40, 0xcf, 0xa3,
|
||||
0x49, 0xdb, 0xd9, 0x17, 0x5c, 0xbd, 0xd8, 0x3e, 0x7b, 0xfd, 0x8f, 0x5f, 0xde, 0x3f, 0x80, 0xd5,
|
||||
0xde, 0x6e, 0xec, 0x82, 0x00, 0x58, 0x7a, 0xd3, 0xa4, 0x62, 0x03, 0xdb, 0x74, 0x4e, 0x76, 0x08,
|
||||
0x47, 0xaf, 0x5b, 0x92, 0xe5, 0x99, 0xbe, 0x7d, 0xf6, 0x86, 0xae, 0x9f, 0xd7, 0x26, 0xaa, 0xbf,
|
||||
0x44, 0xbd, 0x7e, 0xe8, 0x56, 0x25, 0x9f, 0xd3, 0x24, 0x3d, 0x02, 0x60, 0x93, 0x44, 0xff, 0xde,
|
||||
0xf0, 0x77, 0x80, 0xe5, 0x7f, 0xd0, 0x9d, 0xf5, 0x2e, 0xfc, 0x3c, 0x14, 0xe5, 0x20, 0x09, 0x47,
|
||||
0xf5, 0xf8, 0x25, 0x90, 0xcc, 0x53, 0x08, 0xb5, 0xc2, 0xf8, 0xee, 0x47, 0x52, 0x6e, 0xdf, 0xab,
|
||||
0xa7, 0x4e, 0xf5, 0xd6, 0x86, 0xa8, 0x36, 0x58, 0xd9, 0xab, 0x5a, 0xd3, 0x2e, 0xdd, 0xf6, 0x38,
|
||||
0xd5, 0xd6, 0x7b, 0x9c, 0x6e, 0x33, 0x29, 0x9b, 0xf1, 0xc5, 0x0a, 0xf3, 0xd5, 0x36, 0x48, 0x00,
|
||||
0xdd, 0x99, 0x98, 0xed, 0xd5, 0x05, 0xaa, 0xec, 0x4b, 0x0a, 0xae, 0x1a, 0xd9, 0x64, 0x5d, 0x30,
|
||||
0x6e, 0x00, 0x04, 0x1b, 0x28, 0x6b, 0x37, 0x3e, 0x06, 0xc8, 0xa8, 0xa1, 0x34, 0x79, 0xc7, 0x30,
|
||||
0x48, 0xaf, 0x37, 0xb2, 0x1e, 0xa9, 0x36, 0x1e, 0x67, 0x74, 0xa6, 0x14, 0x7e, 0x25, 0xe0, 0xe5,
|
||||
0xd8, 0x67, 0xdf, 0x95, 0xf7, 0x15, 0x69, 0xcc, 0x99, 0x8c, 0x13, 0x1b, 0xbb, 0x41, 0x35, 0x4a,
|
||||
0xd8, 0x6a, 0xb2, 0x19, 0x73, 0xd2, 0xd6, 0xcd, 0xe7, 0xde, 0x2a, 0x4a, 0x68, 0xcb, 0xe0, 0x31,
|
||||
0x82, 0x6e, 0x3d, 0x3a, 0x2a, 0x6d, 0xd6, 0x78, 0xff, 0xc4, 0x2e, 0x69, 0x66, 0xe4, 0x7f, 0xed,
|
||||
0x4e, 0x06, 0xe9, 0xd5, 0x27, 0xfe, 0x27, 0xce, 0x51, 0x0e, 0x6f, 0x1d, 0xaa, 0x59, 0xf2, 0x7c,
|
||||
0xa9, 0xb6, 0x56, 0x03, 0x69, 0xbd, 0xa7, 0xf1, 0x4e, 0x37, 0x36, 0x4b, 0x37, 0x1f, 0x14, 0xd7,
|
||||
0xb7, 0xfa, 0xbe, 0x42, 0xa6, 0xec, 0xa9, 0x66, 0x92, 0xa9, 0xc2, 0xe6, 0xee, 0x28, 0x93, 0x38,
|
||||
0x15, 0xb7, 0x76, 0x59, 0xf3, 0x53, 0x4e, 0x49, 0xb8, 0x34, 0x56, 0x00, 0xfd, 0xbd, 0x66, 0x49,
|
||||
0x7d, 0xba, 0x12, 0x67, 0xc0, 0x1a, 0xf0, 0x12, 0x37, 0x57, 0x32, 0xe7, 0x13, 0x64, 0x97, 0x36,
|
||||
0x43, 0xbe, 0xe7, 0x1a, 0xd0, 0x96, 0xe4, 0x14, 0x92, 0xc0, 0x9e, 0x2e, 0xaa, 0x26, 0x8b, 0xda,
|
||||
0xbe, 0x6c, 0x6f, 0xad, 0x15, 0x68, 0x8b, 0xed, 0x75, 0x1f, 0xdc, 0x69, 0xaf, 0xb5, 0xd5, 0x27,
|
||||
0xef, 0x54, 0x1e, 0x20, 0xea, 0x4d, 0xfe, 0x42, 0x4f, 0xff, 0x13, 0xfb, 0x33, 0xe7, 0xa5, 0xad,
|
||||
0xd5, 0x16, 0x7a, 0x14, 0xfd, 0x7a, 0xad, 0x5d, 0x75, 0xdb, 0xae, 0xda, 0x52, 0x0f, 0x18, 0xb0,
|
||||
0xc7, 0x69, 0x05, 0x52, 0x45, 0x60, 0xa2, 0xf1, 0xd2, 0xad, 0xa6, 0x65, 0x95, 0x41, 0xb9, 0x53,
|
||||
0x39, 0x80, 0xf6, 0xa8, 0x6e, 0xb5, 0xa4, 0x1d, 0xdb, 0x7f, 0xc6, 0x6c, 0x48, 0xd5, 0x07, 0x2e,
|
||||
0x39, 0x5d, 0x1f, 0x06, 0x41, 0x79, 0xe4, 0x72, 0x84, 0xf4, 0xc7, 0xd5, 0x7d, 0xaf, 0x0b, 0x88,
|
||||
0x6e, 0xfc, 0x19, 0x62, 0xf6, 0xc5, 0xd8, 0x93, 0x21, 0x21, 0x5a, 0x3b, 0xbc, 0xee, 0xf0, 0xe2,
|
||||
0xeb, 0xd0, 0xab, 0x21, 0x96, 0x34, 0x71, 0xf2, 0x5e, 0x01, 0x7f, 0xf8, 0x30, 0x02, 0x77, 0xb9,
|
||||
0x20, 0x9b, 0x54, 0xa9, 0x89, 0x37, 0xea, 0xae, 0xae, 0xd3, 0x3b, 0x55, 0x7a, 0xef, 0x01, 0xfc,
|
||||
0x96, 0x13, 0x12, 0x8c, 0xd5, 0x93, 0x36, 0x62, 0xde, 0x91, 0xe1, 0xbb, 0x23, 0xa7, 0xcb, 0x3b,
|
||||
0x50, 0xf4, 0x4a, 0xe1, 0x67, 0x39, 0x5f, 0x63, 0x3f, 0xf0, 0xcf, 0x69, 0x95, 0x95, 0x08, 0xe5,
|
||||
0x22, 0x3c, 0x8d, 0x66, 0x76, 0xa7, 0xa9, 0x31, 0x34, 0xb8, 0x7d, 0x96, 0xf1, 0x59, 0x83, 0x84,
|
||||
0x8f, 0xe1, 0xaa, 0x5e, 0x4b, 0xa3, 0x45, 0x72, 0xba, 0x8b, 0xf2, 0xfe, 0x11, 0x88, 0x79, 0x88,
|
||||
0x74, 0xc6, 0xa4, 0x95, 0xfa, 0x8a, 0x1a, 0xc8, 0xd9, 0xaf, 0x7c, 0x15, 0x13, 0x37, 0xbd, 0x27,
|
||||
0x21, 0xe7, 0x11, 0xb8, 0xe9, 0x59, 0x9f, 0xc5, 0x11, 0x72, 0x7b, 0x5b, 0xf1, 0x76, 0x33, 0x7d,
|
||||
0xaf, 0x8d, 0x5c, 0xca, 0xbe, 0xec, 0xe2, 0x7c, 0xca, 0x29, 0x81, 0x1b, 0xbe, 0x14, 0x22, 0xe3,
|
||||
0x18, 0x1d, 0xe0, 0xb3, 0xe9, 0x1f, 0x61, 0x8d, 0xdf, 0x99, 0xf5, 0x1a, 0x9b, 0xad, 0x7c, 0xc9,
|
||||
0x72, 0x08, 0xf1, 0xe3, 0x18, 0x50, 0x03, 0x8b, 0xce, 0x38, 0xb4, 0x70, 0xac, 0x53, 0x4d, 0x45,
|
||||
0xb2, 0x38, 0x33, 0x40, 0xb4, 0xd6, 0x58, 0xd4, 0x9a, 0x61, 0xee, 0x83, 0x5e, 0xf5, 0x00, 0x47,
|
||||
0xd4, 0x57, 0x66, 0x09, 0xa0, 0x5d, 0x4e, 0x5b, 0x57, 0xc6, 0x04, 0x8a, 0xa2, 0x91, 0x7a, 0x40,
|
||||
0xf2, 0xa8, 0x5b, 0xad, 0x1a, 0x54, 0x71, 0xaa, 0xfd, 0x67, 0x3c, 0x48, 0x85, 0x8a, 0x3f, 0xe1,
|
||||
0x46, 0x12, 0xe0, 0xa0, 0x21, 0x08, 0xf9, 0x59, 0x33, 0x20, 0xeb, 0x29, 0xa8, 0x55, 0x2f, 0x02,
|
||||
0x5b, 0xdf, 0x3f, 0x39, 0x20, 0xeb, 0x35, 0xbc, 0xcd, 0xcd, 0x1a, 0xd3, 0xab, 0x10, 0x18, 0xd0,
|
||||
0xf5, 0x21, 0x5f, 0x52, 0x62, 0xb5, 0x27, 0x0d, 0x61, 0x66, 0xc9, 0x81, 0x3c, 0xb4, 0x72, 0x61,
|
||||
0x9d, 0x32, 0xa9, 0xea, 0x63, 0x1e, 0xbe, 0x0d, 0x23, 0xd0, 0xb4, 0xcb, 0x94, 0xcf, 0xcb, 0x14,
|
||||
0xd0, 0x25, 0xb6, 0x0f, 0xa2, 0xf5, 0xd5, 0x90, 0xd3, 0xcb, 0x5e, 0xce, 0xd2, 0x05, 0x56, 0x46,
|
||||
0xff, 0x36, 0x8d, 0x59, 0xf2, 0x89, 0x2c, 0x9f, 0xa4, 0x24, 0xc6, 0x80, 0x25, 0x59, 0x61, 0x61,
|
||||
0x76, 0x66, 0x01, 0x63, 0xc8, 0x95, 0x5a, 0xd4, 0x6d, 0xc4, 0x70, 0x88, 0x6a, 0x52, 0x45, 0xaa,
|
||||
0xc8, 0xa1, 0xf4, 0xfe, 0xaa, 0x06, 0x4d, 0x98, 0x5d, 0x2a, 0x7d, 0xad, 0x22, 0x2e, 0x35, 0xe0,
|
||||
0x3d, 0x52, 0x01, 0xda, 0xdf, 0xa4, 0x6c, 0x01, 0x06, 0x21, 0xb4, 0xf0, 0x05, 0xa0, 0x74, 0x1e,
|
||||
0xc5, 0xdc, 0x5a, 0xf2, 0x94, 0x23, 0x70, 0xb3, 0x38, 0x9a, 0x7d, 0x42, 0x1c, 0x64, 0x1a, 0xe3,
|
||||
0xf4, 0xfa, 0x74, 0xb8, 0x6e, 0xea, 0x4f, 0x6c, 0xd7, 0x0c, 0x98, 0x89, 0x4d, 0x3a, 0x53, 0x4e,
|
||||
0x80, 0xbe, 0xef, 0xb1, 0xd9, 0x8c, 0xaf, 0x73, 0x45, 0xdb, 0xe1, 0xef, 0xeb, 0x85, 0xab, 0xef,
|
||||
0xb8, 0xbe, 0x5d, 0x27, 0xfa, 0x6e, 0x11, 0xcd, 0x77, 0x9a, 0xa6, 0x27, 0x24, 0x74, 0x24, 0xcf,
|
||||
0x62, 0xde, 0x90, 0x0e, 0x03, 0x14, 0xa8, 0xf2, 0xc1, 0x2e, 0xd5, 0xaf, 0x7e, 0x26, 0x27, 0x3b,
|
||||
0x4f, 0xca, 0x04, 0xe1, 0x99, 0xa5, 0x6f, 0x61, 0x51, 0xd9, 0xa9, 0x25, 0x38, 0x43, 0x4c, 0x29,
|
||||
0x6a, 0x75, 0x4e, 0xa9, 0x9d, 0x94, 0x63, 0x96, 0xef, 0x41, 0xc3, 0x2a, 0x9d, 0x23, 0x33, 0x01,
|
||||
0x8e, 0x2e, 0x90, 0x9c, 0x50, 0xd7, 0x79, 0x19, 0x5e, 0xd5, 0x5a, 0x24, 0x59, 0xe5, 0x52, 0xa9,
|
||||
0x27, 0xe8, 0x12, 0x8a, 0x24, 0xbe, 0xc3, 0x36, 0x79, 0x87, 0x1a, 0xcc, 0x2a, 0xff, 0x9d, 0x0e,
|
||||
0xf5, 0x4c, 0x75, 0xc4, 0xa8, 0x63, 0x11, 0x7b, 0xa7, 0xd0, 0x37, 0xac, 0xfe, 0x2e, 0xe4, 0x75,
|
||||
0xe3, 0xee, 0xb5, 0x58, 0xdf, 0x5d, 0x88, 0xd7, 0x71, 0xb4, 0x9e, 0x0a, 0x96, 0x82, 0xe0, 0xf5,
|
||||
0x2c, 0x6c, 0x42, 0x0e, 0x2a, 0x1b, 0x3b, 0x90, 0xd9, 0x36, 0x6a, 0x4f, 0xa4, 0xd9, 0x07, 0x76,
|
||||
0x0d, 0x38, 0xc4, 0xbf, 0x4f, 0x9b, 0xbc, 0xf7, 0x98, 0x4d, 0xbd, 0x11, 0x37, 0x09, 0xca, 0xa8,
|
||||
0xca, 0x31, 0x82, 0xc8, 0xa8, 0x86, 0xf6, 0x4e, 0x7a, 0x3b, 0x14, 0xaa, 0x14, 0x85, 0x68, 0xb5,
|
||||
0x89, 0x29, 0xf3, 0xfc, 0x68, 0xa7, 0xeb, 0x61, 0x06, 0x6e, 0x80, 0xdb, 0xd3, 0xc8, 0x50, 0xeb,
|
||||
0x94, 0xf0, 0xea, 0x86, 0x07, 0xd8, 0xb8, 0xe3, 0xd2, 0x3b, 0x95, 0xe5, 0xe4, 0x67, 0xa8, 0x00,
|
||||
0x2b, 0x95, 0x97, 0x81, 0xce, 0x5b, 0x44, 0xf9, 0x72, 0x33, 0xf5, 0x66, 0x62, 0x35, 0x54, 0xdf,
|
||||
0x64, 0x0c, 0xe9, 0x53, 0x0c, 0xfa, 0x12, 0x03, 0x3f, 0xc4, 0xb0, 0xad, 0xa6, 0x16, 0xec, 0x59,
|
||||
0x7f, 0xa3, 0x41, 0xd6, 0xcb, 0x19, 0x30, 0xc4, 0xc4, 0x6a, 0x7e, 0xba, 0x21, 0xf5, 0x21, 0xca,
|
||||
0x93, 0x5a, 0xb3, 0xa1, 0xf8, 0x1a, 0xa5, 0x23, 0x14, 0x09, 0xd5, 0x7b, 0xa8, 0x03, 0xb5, 0x4a,
|
||||
0x94, 0x86, 0xea, 0xb4, 0x40, 0xba, 0x0e, 0x67, 0x3d, 0x18, 0x9c, 0xe5, 0x56, 0x18, 0x84, 0x62,
|
||||
0xb6, 0xc1, 0xec, 0x82, 0x0b, 0x06, 0x97, 0xad, 0xb2, 0x20, 0xe1, 0x37, 0xd6, 0x3f, 0x7e, 0x79,
|
||||
0xff, 0x81, 0xb3, 0x74, 0xb6, 0xfc, 0x99, 0xda, 0xfa, 0x37, 0x51, 0x12, 0x8a, 0x1b, 0x2f, 0x16,
|
||||
0x33, 0xf2, 0xfc, 0xbc, 0x8c, 0x5e, 0x3a, 0x2e, 0x26, 0xbf, 0x03, 0x39, 0xce, 0x83, 0xfd, 0xf5,
|
||||
0xed, 0x65, 0x62, 0x3b, 0xe7, 0xcd, 0x06, 0xbf, 0x39, 0x1c, 0x87, 0x9d, 0x77, 0x35, 0xfa, 0xe0,
|
||||
0x06, 0xd1, 0x7f, 0x6c, 0x77, 0x9d, 0x8a, 0x5c, 0x00, 0xd9, 0xa5, 0x2e, 0xf5, 0xed, 0x20, 0x08,
|
||||
0x9a, 0x23, 0x74, 0x97, 0x73, 0x69, 0x7c, 0x6c, 0x7f, 0x57, 0x07, 0xac, 0x23, 0xb1, 0xd0, 0xde,
|
||||
0xfc, 0x06, 0x1b, 0x0b, 0x3e, 0xbe, 0xd8, 0xea, 0x17, 0xc5, 0x70, 0xf8, 0x62, 0x8b, 0x0b, 0x17,
|
||||
0x1f, 0x27, 0x12, 0x1f, 0x3a, 0x9d, 0x1f, 0x80, 0x86, 0x47, 0xac, 0xf4, 0xab, 0x04, 0xbf, 0x33,
|
||||
0xd1, 0xb7, 0x9e, 0xb4, 0xa7, 0xf8, 0xe8, 0x96, 0x6d, 0x2c, 0x0c, 0xdf, 0x62, 0x3d, 0xe3, 0xfb,
|
||||
0x08, 0x1c, 0x3a, 0xa0, 0x49, 0x1f, 0x62, 0x42, 0xca, 0x8c, 0xb8, 0x2c, 0xbb, 0x4b, 0x66, 0x7d,
|
||||
0x27, 0x38, 0xdb, 0x3e, 0x08, 0x43, 0x35, 0x73, 0xf1, 0xd1, 0x65, 0x37, 0x2c, 0xc2, 0xd2, 0x53,
|
||||
0x99, 0x38, 0xea, 0x3b, 0xaa, 0x41, 0xba, 0x02, 0x7d, 0xa7, 0x5c, 0x96, 0xec, 0x56, 0xdf, 0x29,
|
||||
0xa8, 0x56, 0xc6, 0xc2, 0x8c, 0x2b, 0x8a, 0x3d, 0xae, 0x13, 0x5c, 0x5e, 0xb9, 0xf4, 0xcc, 0x93,
|
||||
0x90, 0x9e, 0xb7, 0xc5, 0x64, 0xbe, 0x49, 0xe8, 0x98, 0xcd, 0xd2, 0xbb, 0xe3, 0xce, 0x36, 0xe5,
|
||||
0xf9, 0x26, 0x4d, 0xac, 0x10, 0xe9, 0xf5, 0x56, 0x36, 0x7f, 0x77, 0xf7, 0x2e, 0x84, 0x57, 0x45,
|
||||
0xd9, 0xbd, 0xb1, 0xda, 0x56, 0xe2, 0xca, 0x40, 0x52, 0xe9, 0x0d, 0x38, 0x13, 0xee, 0x91, 0x74,
|
||||
0xc8, 0x8b, 0xa7, 0xdc, 0xbb, 0xbe, 0x5d, 0x3a, 0x06, 0xb6, 0x5b, 0xdf, 0xac, 0x53, 0x10, 0x7e,
|
||||
0xac, 0x72, 0x31, 0x54, 0x02, 0x31, 0x20, 0x51, 0xaf, 0xb3, 0xa5, 0x6e, 0x3e, 0x2f, 0xaa, 0xe5,
|
||||
0xca, 0x10, 0xc4, 0x71, 0xd5, 0xdb, 0xdc, 0x78, 0x6b, 0x78, 0xe1, 0xe5, 0xfb, 0xc4, 0x78, 0x2f,
|
||||
0xa9, 0xe9, 0xb2, 0x40, 0x93, 0x63, 0xcf, 0x1e, 0xae, 0x49, 0x3b, 0x64, 0x1e, 0xe5, 0xac, 0xdd,
|
||||
0xcc, 0x7c, 0x45, 0x4d, 0x93, 0x3c, 0xbd, 0x53, 0xdb, 0x16, 0x81, 0xa4, 0xc5, 0x9c, 0x43, 0xd0,
|
||||
0xde, 0x67, 0x8e, 0x1b, 0xab, 0x06, 0x41, 0xa3, 0x81, 0x38, 0x51, 0xf0, 0xd3, 0xf4, 0x77, 0x70,
|
||||
0x10, 0xbc, 0x4f, 0xfc, 0x2e, 0xeb, 0xc7, 0x8e, 0x9b, 0x06, 0x91, 0x07, 0x6c, 0x0c, 0xa2, 0xdc,
|
||||
0xe7, 0xc1, 0x99, 0x2d, 0xe8, 0x2d, 0xb0, 0x34, 0x2a, 0x30, 0x31, 0xb7, 0xe2, 0x4b, 0x7e, 0xf5,
|
||||
0xf2, 0xe5, 0x33, 0xbc, 0x78, 0x7a, 0xf7, 0x2f, 0x5f, 0xd2, 0x63, 0xa2, 0xaf, 0x5e, 0x06, 0x3a,
|
||||
0x24, 0xcf, 0xfe, 0x13, 0xd4, 0x46, 0x3f, 0x71, 0x1c, 0x77, 0x46, 0x53, 0x26, 0xe1, 0x03, 0x13,
|
||||
0x3e, 0x38, 0x1f, 0xc8, 0x53, 0xe2, 0xdc, 0xdf, 0xaf, 0xf1, 0xc3, 0xb5, 0x77, 0x80, 0x95, 0xc8,
|
||||
0x5b, 0x8b, 0x75, 0xdf, 0x71, 0xf6, 0xc6, 0x6e, 0x18, 0x6c, 0xd7, 0x19, 0x70, 0x91, 0x5f, 0xbe,
|
||||
0x9c, 0x39, 0x6e, 0xe2, 0x27, 0xae, 0x48, 0xfc, 0x67, 0x23, 0x57, 0xf8, 0xcf, 0xc6, 0xae, 0x9e,
|
||||
0xd6, 0x87, 0xae, 0x7e, 0xea, 0x02, 0x41, 0xfc, 0x6f, 0xd3, 0x94, 0xdd, 0x79, 0xf3, 0x54, 0xac,
|
||||
0xfa, 0xdb, 0x98, 0x27, 0x8b, 0x7c, 0xe9, 0xa7, 0x9e, 0xbc, 0x29, 0x5c, 0x64, 0xff, 0xf1, 0xe8,
|
||||
0x15, 0x77, 0x5c, 0xa3, 0x72, 0xe2, 0x31, 0x23, 0x72, 0xc0, 0x1e, 0x5f, 0x83, 0x6f, 0xe0, 0x8f,
|
||||
0x5c, 0xe0, 0x64, 0x3c, 0xd3, 0x75, 0x57, 0xc1, 0x76, 0xc5, 0xf3, 0xa5, 0x08, 0x7d, 0xfb, 0xe7,
|
||||
0x9f, 0x3e, 0x5c, 0xd8, 0x2e, 0xaa, 0x36, 0x1f, 0xcf, 0x13, 0x00, 0x4b, 0x69, 0x94, 0x80, 0xbf,
|
||||
0x74, 0xd7, 0x0f, 0x9d, 0xc2, 0x20, 0x1a, 0xaf, 0x11, 0x2d, 0x73, 0x57, 0xc0, 0x19, 0xaa, 0x6e,
|
||||
0x09, 0x79, 0x47, 0xbe, 0xe4, 0x8a, 0x80, 0x13, 0xc0, 0x16, 0x69, 0xd8, 0xfe, 0xc7, 0x9f, 0xd5,
|
||||
0x3e, 0x2d, 0xfb, 0xc5, 0x36, 0x29, 0xc0, 0x56, 0x01, 0x5e, 0x2c, 0x35, 0x10, 0xad, 0xd1, 0xdd,
|
||||
0x47, 0xfc, 0xce, 0x09, 0xe7, 0x04, 0x51, 0x92, 0x63, 0xec, 0xb7, 0x54, 0xf7, 0x04, 0x3d, 0xb1,
|
||||
0x26, 0x49, 0x32, 0x96, 0x6f, 0xd9, 0x7b, 0xdc, 0xb5, 0xe9, 0xac, 0xdd, 0x76, 0x8a, 0xe6, 0x10,
|
||||
0xf3, 0x55, 0x43, 0x1a, 0x22, 0xf0, 0x6f, 0x52, 0xec, 0x91, 0x07, 0x80, 0xf6, 0x24, 0x38, 0xe2,
|
||||
0x07, 0x5a, 0xfe, 0x9e, 0xc6, 0xc0, 0xa8, 0x1f, 0x44, 0x30, 0x9a, 0x64, 0x4b, 0x71, 0xd3, 0x77,
|
||||
0x94, 0xba, 0x8b, 0x41, 0x4e, 0x57, 0x6c, 0xdd, 0x97, 0x8b, 0x02, 0x2b, 0x25, 0x74, 0x7a, 0x28,
|
||||
0x56, 0x51, 0xc6, 0xfb, 0xfd, 0xdc, 0x8d, 0x51, 0x6b, 0xc1, 0xbc, 0x17, 0xd1, 0x8a, 0x8b, 0x4d,
|
||||
0xde, 0xaf, 0x54, 0x59, 0x85, 0xda, 0xa4, 0x29, 0x0f, 0x5a, 0x40, 0x12, 0x2d, 0x0f, 0x71, 0x4d,
|
||||
0x1e, 0x04, 0x0a, 0x48, 0x2c, 0x99, 0x37, 0xef, 0x60, 0x5e, 0x71, 0x99, 0xa3, 0x34, 0xe0, 0xc5,
|
||||
0xe0, 0x5e, 0x7a, 0x44, 0xae, 0xe5, 0x5e, 0x8d, 0x6f, 0xe3, 0x8a, 0x6f, 0x53, 0xbd, 0x0c, 0xf8,
|
||||
0x01, 0xd1, 0x22, 0x01, 0x9c, 0x35, 0xf9, 0x38, 0x02, 0x45, 0x09, 0x92, 0xf3, 0x08, 0xee, 0x49,
|
||||
0x6b, 0xdc, 0x93, 0x37, 0xb8, 0x67, 0x66, 0x70, 0x4f, 0xa2, 0xb9, 0x27, 0xd7, 0xdc, 0x93, 0x54,
|
||||
0xdc, 0x23, 0x0f, 0x74, 0x81, 0x77, 0x00, 0xea, 0xff, 0x0d, 0xee, 0x01, 0xa4, 0x42, 0xc0, 0x74,
|
||||
0xb7, 0x05, 0xe5, 0x09, 0x72, 0x92, 0xbc, 0x12, 0x7b, 0x7b, 0xb0, 0x65, 0x67, 0x22, 0x21, 0x54,
|
||||
0x84, 0xf5, 0xa0, 0x0b, 0x6a, 0xa5, 0xfc, 0xbc, 0x93, 0xb2, 0xb2, 0x6f, 0xa5, 0x85, 0x3d, 0x08,
|
||||
0xb7, 0x93, 0x3e, 0xbd, 0x5a, 0x46, 0x21, 0x47, 0x63, 0xe3, 0xa9, 0x75, 0xea, 0xad, 0xb0, 0xa0,
|
||||
0xe3, 0xab, 0x87, 0x26, 0x17, 0x2b, 0xbb, 0x55, 0x4a, 0xa3, 0xc1, 0x9e, 0x18, 0x28, 0x9e, 0xe3,
|
||||
0x52, 0xc1, 0xd0, 0x06, 0x2e, 0x2f, 0xd5, 0xb4, 0x0a, 0x7b, 0x1d, 0xcd, 0xb1, 0xbb, 0x38, 0x8e,
|
||||
0xa3, 0x2a, 0x6f, 0x70, 0x5c, 0x16, 0x5c, 0xda, 0x18, 0x4a, 0xd9, 0x2e, 0x5c, 0xf0, 0x2f, 0x04,
|
||||
0x53, 0xf0, 0x17, 0x03, 0xa9, 0x2b, 0xe4, 0x4f, 0x43, 0x1b, 0x2b, 0x23, 0x83, 0x46, 0x81, 0xac,
|
||||
0x88, 0x7b, 0x99, 0xb8, 0xec, 0x2a, 0xc8, 0x3d, 0xf0, 0x46, 0x23, 0x00, 0xc3, 0x03, 0x08, 0x94,
|
||||
0x8d, 0x04, 0x22, 0xa2, 0x6b, 0x90, 0x57, 0x56, 0x0d, 0x20, 0xb6, 0xc1, 0x94, 0x64, 0x5e, 0x94,
|
||||
0xcc, 0xe2, 0x4d, 0x08, 0x5b, 0x64, 0xc8, 0x62, 0x71, 0x70, 0x49, 0x9f, 0x0d, 0xfa, 0x76, 0x23,
|
||||
0x36, 0xb7, 0x5d, 0x69, 0x8e, 0x6c, 0xbb, 0x70, 0x55, 0x0f, 0x19, 0x8c, 0x97, 0x2f, 0x54, 0x8c,
|
||||
0x5e, 0x5c, 0x4d, 0xc4, 0xcb, 0x97, 0xc8, 0xdd, 0x9b, 0x6c, 0xd9, 0xf7, 0x3c, 0x4f, 0x90, 0x9c,
|
||||
0xf6, 0x25, 0x9c, 0xbc, 0x00, 0xbc, 0xf7, 0xe5, 0x04, 0x5c, 0x8d, 0x04, 0x97, 0x42, 0x23, 0xb5,
|
||||
0x00, 0x8f, 0x02, 0x9c, 0x08, 0x20, 0x3c, 0x10, 0x19, 0x40, 0x03, 0x6f, 0xe4, 0x87, 0x8b, 0xbf,
|
||||
0xbf, 0x0f, 0x6c, 0xdb, 0x05, 0xb9, 0x13, 0xe9, 0x5b, 0x06, 0x68, 0x6b, 0x0c, 0x4f, 0x70, 0xca,
|
||||
0x52, 0xb1, 0xa0, 0x1a, 0xf8, 0x89, 0xb2, 0x03, 0xc0, 0x5d, 0x09, 0xe0, 0xde, 0xc3, 0x9a, 0xfb,
|
||||
0x24, 0x7c, 0x8d, 0xd5, 0x65, 0xb4, 0x47, 0xe7, 0x11, 0x5c, 0xa8, 0x78, 0xa1, 0xc9, 0x0c, 0x95,
|
||||
0x57, 0xd3, 0x76, 0x24, 0xca, 0xa3, 0x32, 0xc7, 0x64, 0x05, 0x5d, 0x21, 0x00, 0x66, 0xc8, 0xf0,
|
||||
0x39, 0x28, 0xd9, 0x8c, 0xc4, 0xaf, 0x7c, 0x35, 0x99, 0xfc, 0xed, 0x60, 0x99, 0x96, 0x42, 0x1c,
|
||||
0x66, 0x58, 0xfb, 0x63, 0xbb, 0x75, 0x6b, 0x9e, 0xa1, 0x60, 0xf3, 0x85, 0x1f, 0x17, 0x6d, 0x9b,
|
||||
0x5e, 0x91, 0x54, 0x9e, 0xc6, 0xbd, 0xe1, 0x73, 0xb6, 0x89, 0x73, 0x4d, 0xb9, 0x91, 0xab, 0x3f,
|
||||
0x3d, 0x70, 0xcb, 0xef, 0x11, 0x80, 0x8a, 0x31, 0x50, 0x31, 0x22, 0x5e, 0x02, 0x7e, 0x19, 0xc1,
|
||||
0x3c, 0x25, 0x45, 0x63, 0x45, 0xd1, 0x28, 0x04, 0x22, 0x24, 0x7e, 0xee, 0x92, 0x85, 0x07, 0x33,
|
||||
0x9b, 0x61, 0x29, 0x1b, 0x93, 0x8f, 0xbf, 0xfa, 0x19, 0x3d, 0xff, 0xea, 0x0b, 0x83, 0xe6, 0xf9,
|
||||
0xfd, 0x7d, 0x09, 0x06, 0xaa, 0x06, 0xe5, 0x21, 0x29, 0x08, 0xd8, 0x20, 0xd1, 0x20, 0x88, 0x41,
|
||||
0x86, 0x5c, 0xe0, 0xb8, 0xbc, 0xce, 0x06, 0x51, 0x93, 0x0d, 0x32, 0x35, 0x87, 0x50, 0x73, 0xc4,
|
||||
0x7a, 0x86, 0xa8, 0x70, 0xd3, 0x8a, 0x33, 0x66, 0x26, 0x67, 0x64, 0xae, 0x00, 0x3b, 0xe2, 0xe1,
|
||||
0x79, 0x25, 0x28, 0x12, 0x4f, 0x9e, 0x61, 0xc6, 0x6e, 0xd5, 0xa2, 0x0e, 0x31, 0x23, 0x77, 0x04,
|
||||
0x7a, 0x3b, 0x05, 0x44, 0xcc, 0xbc, 0xb2, 0x1a, 0x00, 0x1c, 0x89, 0x44, 0xf9, 0xd1, 0xb1, 0xcb,
|
||||
0xd4, 0x5d, 0x04, 0xec, 0xaa, 0xda, 0x5e, 0x45, 0x67, 0x47, 0xe3, 0xfd, 0xf3, 0x03, 0x7f, 0x8c,
|
||||
0xc0, 0x83, 0x73, 0x0d, 0x4e, 0x48, 0xf1, 0x14, 0xa6, 0x7b, 0x56, 0xe7, 0x3a, 0x60, 0xb6, 0xa7,
|
||||
0xfa, 0xd4, 0xa5, 0x95, 0xd4, 0x49, 0x22, 0xc3, 0x01, 0xd5, 0x79, 0x26, 0x90, 0x7d, 0x4a, 0xe9,
|
||||
0x18, 0x1c, 0x2c, 0x53, 0x3c, 0x4e, 0xe5, 0x6c, 0xa3, 0x40, 0x53, 0x5e, 0xc3, 0x70, 0xb7, 0x1b,
|
||||
0x76, 0x36, 0x69, 0x0a, 0x1f, 0xf5, 0x9f, 0xb0, 0x8e, 0xa8, 0x42, 0x6a, 0x8b, 0xbe, 0xb1, 0xaf,
|
||||
0x5c, 0x0a, 0xa4, 0xdb, 0xd5, 0x5b, 0x62, 0xa7, 0xd6, 0x3d, 0xe9, 0xe3, 0x02, 0x64, 0x66, 0xb4,
|
||||
0xb5, 0x51, 0x55, 0x97, 0x12, 0x15, 0xb6, 0xa3, 0x66, 0xcb, 0xd2, 0x59, 0x00, 0x9a, 0xa6, 0x29,
|
||||
0xbe, 0x0b, 0x95, 0x06, 0xea, 0x14, 0x5f, 0xb5, 0x79, 0xd4, 0xaf, 0x3c, 0xbb, 0x1c, 0x5d, 0x75,
|
||||
0xf9, 0xe7, 0x5a, 0xb1, 0x77, 0xf9, 0xe6, 0xaa, 0x0e, 0xa3, 0x43, 0x82, 0x0d, 0x31, 0x2f, 0xf3,
|
||||
0x3e, 0xa8, 0xe8, 0x8d, 0xd6, 0x5a, 0x0e, 0x09, 0xfd, 0x10, 0xad, 0x4d, 0x81, 0xfd, 0xf2, 0x73,
|
||||
0x90, 0x7d, 0x4f, 0xf6, 0x90, 0x6e, 0x02, 0x3c, 0x03, 0x41, 0x40, 0xee, 0xb4, 0xff, 0x5e, 0xd1,
|
||||
0x09, 0x5c, 0x94, 0xad, 0xfc, 0x7a, 0xdd, 0x8f, 0xdc, 0x69, 0x1a, 0x81, 0x87, 0x0b, 0x52, 0x3a,
|
||||
0x73, 0x23, 0x3f, 0x2c, 0x02, 0xbd, 0x0e, 0x98, 0x50, 0x65, 0x57, 0x4d, 0x62, 0xa2, 0x45, 0xa9,
|
||||
0xbb, 0x21, 0x66, 0x10, 0xe6, 0x6e, 0xa5, 0x0f, 0x2d, 0xe7, 0x44, 0x4d, 0xb3, 0x2d, 0x27, 0x06,
|
||||
0xbb, 0x41, 0x66, 0x54, 0x31, 0xdd, 0x2a, 0xc0, 0x64, 0x1a, 0xcb, 0x65, 0xe1, 0x4e, 0x3f, 0x71,
|
||||
0x1b, 0x1e, 0x8a, 0x39, 0x2d, 0x5a, 0x78, 0x25, 0x38, 0x2b, 0x30, 0x46, 0xa6, 0xae, 0x8e, 0xbe,
|
||||
0x40, 0x51, 0x6b, 0x4a, 0x97, 0xc7, 0xd9, 0x8f, 0x23, 0x79, 0x87, 0x0d, 0x37, 0xf5, 0xb6, 0x41,
|
||||
0x3d, 0xc5, 0x00, 0xac, 0x1d, 0x9c, 0xa9, 0x37, 0x99, 0xf1, 0x46, 0x9d, 0x8d, 0x95, 0xef, 0x44,
|
||||
0x07, 0xdb, 0xe8, 0x77, 0xf1, 0x8e, 0x60, 0x91, 0x74, 0x5d, 0xa4, 0x74, 0x5d, 0x5a, 0xa0, 0x95,
|
||||
0x57, 0x0a, 0x49, 0xea, 0x34, 0x84, 0xbf, 0xcd, 0x7a, 0x39, 0x89, 0xe4, 0xf7, 0x40, 0x8e, 0x37,
|
||||
0xa0, 0xd9, 0x26, 0xd1, 0xbc, 0x6f, 0x30, 0x56, 0xea, 0x68, 0xe3, 0xa8, 0xb6, 0x6b, 0xbb, 0x1c,
|
||||
0xa2, 0xe0, 0x38, 0xe3, 0x9d, 0xa1, 0x47, 0x8a, 0xb8, 0xd0, 0xe1, 0xc6, 0x34, 0x16, 0x53, 0xd4,
|
||||
0x43, 0x72, 0x7e, 0xc0, 0x5f, 0xff, 0x32, 0xb9, 0x72, 0x23, 0x80, 0x13, 0x5c, 0x61, 0x3f, 0xf1,
|
||||
0xf0, 0x52, 0x54, 0xd6, 0xb7, 0x5c, 0x00, 0xe4, 0x5d, 0xeb, 0x63, 0x73, 0xee, 0x32, 0x23, 0x45,
|
||||
0x87, 0x26, 0x2b, 0xcc, 0x26, 0xe5, 0x42, 0xc4, 0xde, 0x35, 0x07, 0x0a, 0xc5, 0x38, 0xc9, 0x90,
|
||||
0xad, 0xa3, 0x21, 0x46, 0xe2, 0x43, 0x89, 0xcd, 0x73, 0xb6, 0x12, 0x1b, 0xfc, 0x35, 0x91, 0xbd,
|
||||
0xcc, 0xed, 0xf2, 0x8a, 0x73, 0x60, 0xca, 0xad, 0xaa, 0x21, 0xf6, 0x43, 0x57, 0x0e, 0xf2, 0x57,
|
||||
0xda, 0x3a, 0xce, 0xb4, 0xcb, 0x0b, 0x28, 0x79, 0x36, 0xf3, 0xc4, 0x27, 0x47, 0xa9, 0xb7, 0x6b,
|
||||
0x11, 0xe1, 0x61, 0x01, 0xb2, 0x5b, 0x58, 0xb2, 0xdb, 0xa4, 0x91, 0x9e, 0x50, 0x8c, 0xbe, 0xc1,
|
||||
0x4c, 0xc5, 0x1a, 0xff, 0x2c, 0x83, 0x31, 0x3f, 0x78, 0x15, 0xbb, 0x8b, 0x60, 0x55, 0x45, 0x25,
|
||||
0x18, 0xfa, 0x54, 0xda, 0x31, 0x69, 0xc9, 0x2a, 0xaf, 0x64, 0x35, 0x23, 0xb9, 0x12, 0x28, 0xab,
|
||||
0x31, 0x88, 0x54, 0x64, 0xc8, 0x6a, 0x82, 0x41, 0xb8, 0x21, 0x7c, 0xa2, 0x14, 0x3e, 0xd9, 0xb3,
|
||||
0x80, 0xb0, 0x00, 0x3c, 0x28, 0x56, 0x58, 0x2f, 0xb6, 0xf9, 0xde, 0xb8, 0xf8, 0x38, 0xd9, 0x48,
|
||||
0x43, 0x0d, 0x8d, 0xb3, 0xe2, 0xfe, 0xc5, 0xb6, 0x1d, 0x1f, 0x7c, 0x74, 0xdc, 0xb5, 0xec, 0x03,
|
||||
0x5e, 0x83, 0xb9, 0x35, 0xd9, 0x58, 0x57, 0x02, 0xa9, 0xbb, 0x4d, 0x40, 0xce, 0x21, 0x76, 0x1e,
|
||||
0xa1, 0xef, 0xd4, 0xe5, 0x91, 0x2f, 0xb4, 0xe4, 0xdf, 0x05, 0x1b, 0xda, 0x7e, 0xe9, 0x9c, 0x5e,
|
||||
0x82, 0x81, 0xb8, 0x82, 0xc0, 0x47, 0x79, 0xa4, 0xf7, 0xe4, 0xf4, 0xd4, 0xb4, 0x83, 0x40, 0x27,
|
||||
0x4d, 0xe2, 0x1e, 0x00, 0xbe, 0xc4, 0xf2, 0x39, 0x57, 0xd6, 0xc5, 0x5d, 0x55, 0xae, 0xa9, 0x70,
|
||||
0xce, 0xed, 0xe7, 0xb6, 0x6f, 0x0f, 0x87, 0x36, 0x6d, 0xb3, 0xf8, 0xaf, 0x04, 0x77, 0x0c, 0x7e,
|
||||
0xe2, 0x44, 0x9b, 0xe2, 0x3b, 0xef, 0x77, 0x11, 0x25, 0x7d, 0xfb, 0xbf, 0x50, 0x5a, 0x14, 0xfd,
|
||||
0x20, 0x62, 0x52, 0x5f, 0x71, 0xb4, 0x74, 0xac, 0xbb, 0x76, 0x97, 0x4f, 0xd1, 0x2f, 0xa5, 0x66,
|
||||
0x29, 0xe9, 0xc2, 0xeb, 0x49, 0x1e, 0xd3, 0x4c, 0x54, 0x4e, 0x5f, 0x87, 0x9d, 0x30, 0xfc, 0xc4,
|
||||
0x0e, 0x25, 0x62, 0x54, 0x1d, 0x75, 0xaa, 0x12, 0xed, 0x3a, 0x76, 0x68, 0x12, 0xed, 0x42, 0x02,
|
||||
0x53, 0xc9, 0x0f, 0xfb, 0x6a, 0xba, 0xc4, 0x2c, 0xb5, 0x40, 0x8e, 0x2a, 0x23, 0xcb, 0x0c, 0xe3,
|
||||
0xca, 0xf2, 0x09, 0xed, 0x87, 0xf4, 0xa3, 0x42, 0xed, 0x47, 0xad, 0x3a, 0x81, 0xef, 0x50, 0x3f,
|
||||
0xda, 0x7b, 0x72, 0x37, 0xd5, 0x7c, 0x40, 0x83, 0x75, 0xf5, 0xb4, 0x02, 0x57, 0x05, 0xc3, 0x60,
|
||||
0x06, 0xe4, 0x66, 0x31, 0x15, 0x6a, 0x80, 0xc8, 0x94, 0x0d, 0xb2, 0x6e, 0xc2, 0xbd, 0x0b, 0xe2,
|
||||
0xf3, 0xd4, 0x5f, 0xba, 0x73, 0xb8, 0xce, 0xfc, 0x85, 0x7b, 0x0d, 0xd7, 0x8d, 0x7f, 0xe7, 0xde,
|
||||
0xc0, 0x75, 0xed, 0xcf, 0xdd, 0xf7, 0xc1, 0xdf, 0x59, 0xbe, 0xf4, 0xe6, 0xb1, 0x00, 0x3f, 0xa0,
|
||||
0xbf, 0x19, 0xdc, 0x39, 0xc3, 0x7d, 0xc7, 0x7d, 0x5b, 0x6b, 0x5d, 0x0f, 0xe6, 0xd4, 0x3a, 0x0d,
|
||||
0x0e, 0x4f, 0x5e, 0x5d, 0xbb, 0xbf, 0xe3, 0xe5, 0xc6, 0xbd, 0x0d, 0xa6, 0xa7, 0xc1, 0xd7, 0xc7,
|
||||
0x27, 0xe7, 0xe3, 0x43, 0x7f, 0x7c, 0xe2, 0x7e, 0x40, 0xd1, 0xdd, 0xce, 0xf2, 0x5b, 0xff, 0xa2,
|
||||
0x08, 0x24, 0x59, 0x5f, 0x93, 0x3c, 0xf6, 0xef, 0xdc, 0xb9, 0x33, 0xb9, 0xc0, 0x2f, 0x90, 0x6f,
|
||||
0x94, 0xac, 0xba, 0x23, 0xf8, 0x0f, 0x35, 0x4b, 0x56, 0x7f, 0x13, 0x5c, 0x60, 0xde, 0x91, 0xde,
|
||||
0xa2, 0x6e, 0xed, 0xeb, 0xf7, 0x84, 0x85, 0x52, 0xb0, 0x5f, 0xb8, 0x38, 0xfd, 0xa7, 0xc6, 0xf4,
|
||||
0x53, 0xf7, 0x77, 0x67, 0xf2, 0x09, 0xed, 0x4e, 0xfc, 0x41, 0x1e, 0x21, 0x3c, 0x1f, 0xd1, 0x3f,
|
||||
0xdb, 0x95, 0xad, 0xbf, 0x00, 0x6a, 0x69, 0x46, 0xea, 0x09, 0x02, 0xd3, 0xc7, 0x24, 0x08, 0x0f,
|
||||
0x46, 0x13, 0x7e, 0x7a, 0x33, 0xe1, 0x10, 0x1b, 0xeb, 0xb6, 0x1c, 0xda, 0xf2, 0xd3, 0xeb, 0x49,
|
||||
0x0e, 0x6d, 0x5b, 0x6c, 0x00, 0x7b, 0xf5, 0xea, 0x7a, 0x0f, 0x34, 0x01, 0x48, 0x1a, 0x6c, 0x1a,
|
||||
0x9c, 0x73, 0xbc, 0x70, 0xf0, 0x29, 0xf2, 0xc1, 0x7b, 0x08, 0x06, 0xf8, 0xe0, 0x2d, 0x90, 0xdf,
|
||||
0x56, 0xeb, 0xa1, 0xfe, 0x03, 0x47, 0x5f, 0x9c, 0x05, 0x23, 0xf8, 0x7b, 0x7a, 0xf7, 0xf2, 0x65,
|
||||
0x44, 0xb7, 0xd1, 0xe9, 0xfc, 0xfe, 0xfe, 0x19, 0xbc, 0xc9, 0xb1, 0x8d, 0x9f, 0xce, 0xf5, 0xe4,
|
||||
0xf1, 0x79, 0xf4, 0xea, 0x6e, 0x4f, 0xf8, 0x1c, 0xfe, 0xe6, 0x13, 0xe0, 0x23, 0x54, 0xd8, 0x74,
|
||||
0x34, 0xde, 0x7f, 0x73, 0x79, 0xf8, 0x0a, 0x8c, 0x00, 0x5d, 0xf6, 0xc6, 0xfa, 0x66, 0x5f, 0xdf,
|
||||
0x1c, 0x5c, 0x51, 0xaa, 0x77, 0x9b, 0x82, 0x36, 0x59, 0x00, 0x7b, 0x4d, 0x91, 0xb3, 0x96, 0xfc,
|
||||
0xf6, 0x42, 0xfc, 0xb2, 0x98, 0x82, 0x5a, 0x9a, 0x7c, 0x90, 0xea, 0x07, 0xec, 0x8c, 0x89, 0x9a,
|
||||
0x8f, 0x29, 0xbc, 0x45, 0x55, 0xe6, 0x82, 0xe4, 0x87, 0xf4, 0x77, 0x55, 0x38, 0x1f, 0x4d, 0x44,
|
||||
0x41, 0xc4, 0xe1, 0x1e, 0x9e, 0xc0, 0x7f, 0x9d, 0x02, 0xad, 0x97, 0xa5, 0x26, 0xd2, 0x7b, 0x44,
|
||||
0x54, 0xe3, 0x87, 0x2b, 0xc4, 0x6f, 0xc1, 0x18, 0x46, 0xe2, 0xd9, 0xed, 0x27, 0xae, 0x51, 0x3f,
|
||||
0xa6, 0x7f, 0x76, 0xd9, 0xde, 0x98, 0x93, 0xf2, 0x4f, 0x60, 0xae, 0xf6, 0xf6, 0x0f, 0xdd, 0x30,
|
||||
0xc8, 0xe0, 0x82, 0xa4, 0x13, 0x60, 0x7b, 0x6e, 0xf7, 0xec, 0xf5, 0xad, 0xf5, 0x6d, 0x1a, 0xb1,
|
||||
0xd8, 0xae, 0xc1, 0xac, 0x57, 0x46, 0x23, 0x7b, 0x5e, 0x9e, 0xd6, 0xfb, 0xe6, 0x52, 0x68, 0xcf,
|
||||
0xbf, 0xc5, 0x4f, 0xed, 0x02, 0x5b, 0x7e, 0x65, 0xa7, 0x1b, 0xbf, 0x03, 0x11, 0x42, 0x68, 0x03,
|
||||
0x7b, 0x15, 0x85, 0x61, 0xcc, 0xf5, 0xcc, 0x17, 0xf0, 0x0e, 0x7c, 0xa9, 0x99, 0x1b, 0x3a, 0x85,
|
||||
0x2c, 0xbb, 0xea, 0xe7, 0xa0, 0x82, 0xa0, 0xb7, 0x3d, 0xb6, 0xfd, 0x28, 0xf8, 0x30, 0x99, 0x02,
|
||||
0x8b, 0x7d, 0x9a, 0x50, 0xcb, 0x3e, 0xb6, 0xd0, 0xd7, 0xb6, 0xfd, 0x0f, 0x8e, 0xf9, 0xe2, 0x00,
|
||||
0x5f, 0x50, 0xa1, 0x22, 0xbc, 0x28, 0xa4, 0xde, 0xad, 0x78, 0x15, 0xed, 0x4b, 0x29, 0xac, 0xcc,
|
||||
0x41, 0x73, 0x54, 0x3e, 0x82, 0x1d, 0x22, 0x73, 0x53, 0x69, 0x42, 0x9a, 0x85, 0x4b, 0xc6, 0x00,
|
||||
0x36, 0x04, 0xef, 0x60, 0x84, 0x21, 0x2d, 0x3a, 0x52, 0x19, 0x1a, 0x49, 0x5e, 0x85, 0x6a, 0xc0,
|
||||
0x7e, 0x68, 0x09, 0x81, 0xd9, 0xf8, 0xb3, 0x20, 0x60, 0xe0, 0xca, 0x07, 0x62, 0x32, 0x0e, 0x82,
|
||||
0x64, 0x90, 0x9f, 0x67, 0x92, 0x5a, 0xcc, 0xf1, 0xd5, 0x1d, 0xd8, 0x0c, 0xf0, 0x13, 0xc0, 0x19,
|
||||
0x13, 0x05, 0x43, 0x37, 0x5e, 0x27, 0x31, 0xc6, 0x94, 0x43, 0x93, 0x59, 0xd6, 0xee, 0x71, 0xfa,
|
||||
0x2d, 0x0e, 0xcf, 0x2a, 0x48, 0x0d, 0x1e, 0x05, 0x93, 0x4c, 0xb3, 0x2b, 0xdd, 0xad, 0x35, 0x65,
|
||||
0xd6, 0x4c, 0xc2, 0x9b, 0x65, 0x26, 0x9d, 0xda, 0x56, 0x56, 0x64, 0x94, 0xb0, 0x61, 0x9c, 0xc8,
|
||||
0xce, 0xb3, 0x73, 0x51, 0x65, 0x58, 0x9e, 0x53, 0x86, 0xc5, 0xcb, 0xc5, 0x7b, 0x71, 0xc3, 0xd3,
|
||||
0xd7, 0x80, 0xfd, 0xbe, 0x83, 0x3f, 0x5c, 0x76, 0x21, 0x7e, 0x00, 0xb2, 0xec, 0x1f, 0x1d, 0xb9,
|
||||
0xea, 0x7f, 0x46, 0x2b, 0x81, 0x67, 0x1e, 0x5f, 0x68, 0xf1, 0x00, 0x34, 0x1f, 0xc0, 0x12, 0x60,
|
||||
0x59, 0x79, 0x73, 0x05, 0x47, 0x6d, 0x1a, 0xa2, 0x54, 0xf3, 0xed, 0xb0, 0xef, 0x39, 0xc3, 0x85,
|
||||
0x6b, 0xbf, 0x18, 0xbf, 0x18, 0x43, 0xa7, 0x49, 0x69, 0x8f, 0x31, 0x47, 0x84, 0xb9, 0x53, 0xe4,
|
||||
0xa0, 0xa1, 0xb7, 0xdd, 0x2f, 0x86, 0x0b, 0x47, 0x5b, 0xed, 0x92, 0xda, 0xdc, 0x1d, 0x1f, 0x3b,
|
||||
0x7a, 0x77, 0x20, 0xb2, 0x39, 0x88, 0x6c, 0x02, 0x22, 0xcb, 0x4c, 0x06, 0xa8, 0x43, 0xad, 0x02,
|
||||
0xc4, 0x52, 0xec, 0xf6, 0xfa, 0xfc, 0xf4, 0x74, 0x7c, 0x7c, 0x9f, 0x9f, 0x9e, 0x9e, 0xdc, 0x27,
|
||||
0x88, 0x88, 0x0f, 0xe4, 0x84, 0xf4, 0x71, 0x66, 0x2f, 0xa3, 0xb4, 0xc2, 0xe0, 0xd8, 0xd8, 0xac,
|
||||
0xe4, 0x57, 0x6d, 0x57, 0x81, 0xa5, 0x80, 0x87, 0xca, 0xfc, 0x95, 0xc1, 0x4a, 0x14, 0x72, 0xe6,
|
||||
0x92, 0xe6, 0x09, 0xb8, 0xac, 0xe0, 0xe9, 0xe5, 0xd5, 0x2c, 0x35, 0x45, 0x8b, 0x1e, 0x58, 0xe9,
|
||||
0x7f, 0x85, 0x2a, 0x88, 0x7a, 0x5b, 0xd2, 0x90, 0x3a, 0xd9, 0xe8, 0x44, 0xc8, 0x14, 0x00, 0xcc,
|
||||
0xad, 0x43, 0xff, 0x7c, 0x52, 0x06, 0xb5, 0xa8, 0xe7, 0x5f, 0xe3, 0x67, 0x48, 0x20, 0x80, 0xf6,
|
||||
0x3e, 0x84, 0xb0, 0xdb, 0x1b, 0xd2, 0x3c, 0x2c, 0xfc, 0x1e, 0x0b, 0x5b, 0x60, 0xaa, 0xf8, 0x8e,
|
||||
0xbc, 0x23, 0x0d, 0x2d, 0xf3, 0xc8, 0xdb, 0xfd, 0xb0, 0x12, 0x22, 0x5f, 0xc2, 0x8e, 0xff, 0xcf,
|
||||
0x86, 0xe1, 0xf7, 0x54, 0x81, 0xbd, 0x84, 0xa9, 0xc1, 0x07, 0x6e, 0xbc, 0x7e, 0x9b, 0xb0, 0x69,
|
||||
0x8c, 0x89, 0x85, 0x71, 0x69, 0x36, 0x12, 0x32, 0x1b, 0x26, 0xb2, 0x6b, 0x4e, 0x13, 0x6d, 0x4b,
|
||||
0x2e, 0x86, 0x0e, 0x13, 0xca, 0xc5, 0xf9, 0x1d, 0x5b, 0xc5, 0xa0, 0x11, 0x7c, 0xe9, 0x3c, 0x51,
|
||||
0x13, 0xde, 0x61, 0x93, 0x81, 0x9d, 0x50, 0x1d, 0x79, 0x93, 0xcb, 0xae, 0xe8, 0x86, 0xf2, 0x0b,
|
||||
0xea, 0x6e, 0xa2, 0xb4, 0x4a, 0xa2, 0xb4, 0x0a, 0x25, 0xdf, 0x7d, 0x16, 0xd8, 0xe0, 0x7d, 0x03,
|
||||
0xb1, 0x28, 0x12, 0x19, 0xea, 0x24, 0xbd, 0x7c, 0x6b, 0x6a, 0x16, 0x80, 0xa3, 0xd9, 0xf9, 0x76,
|
||||
0x80, 0x40, 0x51, 0x77, 0xba, 0x31, 0xbb, 0x13, 0x94, 0x38, 0x00, 0xd1, 0x3a, 0x04, 0x96, 0x8d,
|
||||
0xe4, 0xbc, 0xf9, 0x6d, 0x6e, 0x17, 0xfa, 0xb8, 0x0a, 0x83, 0x8b, 0xef, 0x30, 0xd2, 0xb8, 0xe4,
|
||||
0x57, 0x2a, 0xb4, 0x60, 0x94, 0xa4, 0xec, 0x8a, 0x88, 0x29, 0x3b, 0xdf, 0xa2, 0x31, 0x03, 0xf2,
|
||||
0x46, 0xf2, 0x60, 0x0f, 0xfc, 0x65, 0x4f, 0xef, 0x1f, 0x5d, 0xe6, 0xbc, 0xf0, 0x5e, 0x6c, 0xb3,
|
||||
0xe2, 0x23, 0x34, 0x53, 0x7d, 0x0c, 0xc4, 0x33, 0x38, 0x6f, 0xca, 0xaf, 0xc1, 0x08, 0x54, 0xf3,
|
||||
0xc6, 0x06, 0x8b, 0x12, 0x92, 0x1f, 0xf0, 0xfc, 0xd4, 0x67, 0x10, 0x9d, 0x8e, 0x5f, 0xed, 0x23,
|
||||
0x80, 0x4e, 0xe7, 0xaf, 0xfc, 0x78, 0xa1, 0xd3, 0xf5, 0x33, 0x8e, 0x73, 0x41, 0x8f, 0x96, 0x0c,
|
||||
0x80, 0xbf, 0xab, 0x88, 0x3f, 0x22, 0x74, 0x21, 0x7e, 0x45, 0xe0, 0xb6, 0x92, 0x8a, 0x10, 0xeb,
|
||||
0x6c, 0x2f, 0xf3, 0x2b, 0x7f, 0xab, 0x57, 0xfd, 0x8d, 0xd2, 0xaf, 0x89, 0x2b, 0xd7, 0xf8, 0x0d,
|
||||
0x34, 0x3b, 0x73, 0x67, 0x62, 0xb5, 0x62, 0x49, 0xf8, 0x1b, 0x04, 0x17, 0x1f, 0x91, 0x1e, 0xd6,
|
||||
0xe0, 0x5f, 0x16, 0x86, 0x50, 0x96, 0xae, 0x89, 0x42, 0xf4, 0x98, 0x39, 0x47, 0x6b, 0x10, 0x5a,
|
||||
0x5f, 0x61, 0x86, 0xf6, 0x2b, 0x6b, 0xf0, 0x83, 0x65, 0xbf, 0x96, 0xdf, 0xe6, 0x0d, 0x2e, 0x90,
|
||||
0x30, 0x56, 0x8b, 0x4d, 0x3e, 0x56, 0x0b, 0xcc, 0xe7, 0x4f, 0x59, 0x61, 0x6b, 0x23, 0xe7, 0xcd,
|
||||
0x19, 0xd8, 0xf2, 0x47, 0xae, 0x54, 0x14, 0x85, 0xe9, 0xa4, 0x13, 0xe3, 0x3f, 0x40, 0x26, 0x03,
|
||||
0x95, 0x2a, 0xf4, 0xd8, 0x01, 0x5c, 0xfe, 0x25, 0xdb, 0x37, 0xe0, 0xa9, 0x91, 0x08, 0x00, 0x2b,
|
||||
0xdf, 0xa0, 0x2c, 0x83, 0xdd, 0xac, 0x0e, 0xc6, 0x6c, 0xcb, 0xb2, 0x3d, 0x79, 0x6e, 0xd8, 0x2f,
|
||||
0x23, 0x23, 0x4b, 0x85, 0x64, 0xb0, 0x1a, 0x90, 0x13, 0xd4, 0x9a, 0x54, 0xd8, 0x20, 0x16, 0x6e,
|
||||
0x76, 0xe5, 0x54, 0x27, 0x51, 0xcf, 0xf4, 0x49, 0x54, 0x76, 0x7f, 0x2f, 0x8f, 0x28, 0xa3, 0x8c,
|
||||
0xae, 0xe0, 0xe5, 0x9f, 0x53, 0x90, 0x88, 0xd0, 0xfb, 0xe0, 0x42, 0x95, 0x59, 0x35, 0x5e, 0x69,
|
||||
0xee, 0xd6, 0x2c, 0xbc, 0x39, 0x0b, 0x77, 0xce, 0x01, 0x91, 0x38, 0x66, 0x6f, 0xec, 0x14, 0xfd,
|
||||
0x0c, 0x6d, 0xd5, 0x47, 0xbf, 0x9a, 0x18, 0xc3, 0xb2, 0x1c, 0x9b, 0xf1, 0xf5, 0x47, 0xc7, 0x08,
|
||||
0xc9, 0x94, 0xab, 0x81, 0xfb, 0x35, 0xc4, 0x49, 0x87, 0x5d, 0x10, 0xc6, 0xab, 0xb3, 0x25, 0x1b,
|
||||
0xb0, 0xb1, 0xcf, 0x0f, 0xc0, 0x8f, 0x28, 0x2b, 0xb0, 0x9c, 0x32, 0x11, 0xae, 0xe9, 0x47, 0x27,
|
||||
0x75, 0x2d, 0x49, 0x0f, 0xa3, 0x6b, 0xa0, 0xa7, 0xf0, 0xa8, 0x28, 0xc7, 0x2b, 0x4b, 0xa3, 0x03,
|
||||
0x5b, 0x7e, 0xe5, 0x6a, 0xbb, 0xad, 0x57, 0xba, 0xc8, 0x38, 0x00, 0x78, 0x47, 0xa3, 0x3d, 0x7b,
|
||||
0x95, 0x75, 0x74, 0xba, 0x88, 0x56, 0xa0, 0xa3, 0xbf, 0x57, 0x20, 0x07, 0xb6, 0xfc, 0x04, 0x1a,
|
||||
0x3b, 0x52, 0xd9, 0x0e, 0x26, 0x2c, 0x29, 0xc9, 0x2b, 0x2b, 0x5b, 0x6c, 0x37, 0xaf, 0x4e, 0x28,
|
||||
0x5b, 0x20, 0x62, 0x75, 0x3c, 0xc0, 0x18, 0x77, 0x0e, 0xa5, 0x1f, 0x1a, 0x01, 0xd1, 0x8f, 0xc9,
|
||||
0x0d, 0x54, 0xcc, 0x05, 0x26, 0x49, 0xd4, 0xb2, 0x62, 0xb1, 0x9e, 0x3e, 0xda, 0x85, 0x81, 0xa8,
|
||||
0x7b, 0x76, 0xfd, 0x5d, 0xb0, 0x8d, 0x99, 0xfc, 0x16, 0x8e, 0xca, 0xb7, 0xed, 0x97, 0x5d, 0x58,
|
||||
0x6a, 0x77, 0xe2, 0x31, 0x03, 0x03, 0x37, 0x22, 0x0c, 0xd6, 0xb3, 0x78, 0x6e, 0xe5, 0x59, 0x35,
|
||||
0x6a, 0x7f, 0x9c, 0x5a, 0x4f, 0xd0, 0xdf, 0xc6, 0xa9, 0x1e, 0x9d, 0xcf, 0x69, 0x62, 0xa8, 0x8f,
|
||||
0x8c, 0xc1, 0xbf, 0x6c, 0xf7, 0x48, 0xf9, 0x4a, 0x5c, 0x63, 0x8c, 0xee, 0x02, 0x74, 0x74, 0x92,
|
||||
0xa7, 0xa3, 0x78, 0xcc, 0x9d, 0x82, 0x53, 0x94, 0xa9, 0x49, 0x54, 0x95, 0x56, 0x60, 0x53, 0x99,
|
||||
0x96, 0xc1, 0x85, 0x65, 0x92, 0x80, 0xec, 0x61, 0x70, 0x80, 0xe7, 0xd4, 0x64, 0x13, 0x83, 0xd1,
|
||||
0x44, 0xb3, 0xde, 0x0e, 0x5c, 0x67, 0x4d, 0x5c, 0xeb, 0xb9, 0x30, 0x09, 0x61, 0xfa, 0x2c, 0x94,
|
||||
0x08, 0xca, 0xd1, 0x49, 0xbc, 0xbf, 0xef, 0xf3, 0x6e, 0x88, 0x1a, 0xf9, 0x4f, 0x5e, 0x65, 0x54,
|
||||
0x45, 0x50, 0x95, 0xbd, 0x50, 0x38, 0x12, 0x57, 0x39, 0xfa, 0x08, 0x53, 0x9b, 0x31, 0xb0, 0xa4,
|
||||
0xc6, 0x4b, 0x8c, 0x06, 0xb2, 0x89, 0xa7, 0xfc, 0x92, 0x5d, 0x75, 0xae, 0xea, 0xb2, 0xbd, 0x3d,
|
||||
0x97, 0x9d, 0x05, 0x79, 0xe5, 0x45, 0xc2, 0xbe, 0x01, 0xfa, 0x8e, 0x01, 0xf4, 0x09, 0x3e, 0x10,
|
||||
0x1f, 0x0c, 0x25, 0xf9, 0xbb, 0x2f, 0x5f, 0x02, 0x6e, 0x67, 0xa9, 0x80, 0xe0, 0x44, 0x60, 0xb4,
|
||||
0x4a, 0xd8, 0x2f, 0x44, 0xfd, 0xc0, 0xa6, 0xce, 0x0e, 0x99, 0x43, 0xc3, 0xb3, 0x8e, 0x84, 0xff,
|
||||
0x0a, 0x11, 0x87, 0xc5, 0x5f, 0x36, 0x55, 0x50, 0x34, 0x37, 0x55, 0x3c, 0x34, 0x6a, 0x93, 0xab,
|
||||
0x41, 0x11, 0x1d, 0xe7, 0x56, 0x07, 0x76, 0x94, 0x10, 0x6d, 0xa7, 0x7e, 0x75, 0x8d, 0x19, 0x16,
|
||||
0xfd, 0x34, 0x28, 0xa8, 0x4e, 0x14, 0x6c, 0x3c, 0xbc, 0xe9, 0xde, 0xbf, 0x6e, 0x97, 0x3f, 0xd4,
|
||||
0x81, 0x78, 0xc4, 0x1f, 0x63, 0x8b, 0xc1, 0xcb, 0x07, 0xdf, 0x30, 0xf4, 0x50, 0x8c, 0x35, 0xdf,
|
||||
0xc2, 0x32, 0x73, 0x78, 0x81, 0x9e, 0x1f, 0xfe, 0xb2, 0x90, 0x6d, 0x78, 0xf6, 0x94, 0x58, 0x7a,
|
||||
0x2c, 0x64, 0x8a, 0xc9, 0x1f, 0x02, 0x4e, 0x52, 0xb3, 0x09, 0x5b, 0xa8, 0x8f, 0xfa, 0x76, 0xc0,
|
||||
0x85, 0xbf, 0xac, 0x64, 0x40, 0xa5, 0x6b, 0x8f, 0xd1, 0x46, 0x71, 0x0f, 0x35, 0x30, 0x00, 0xa5,
|
||||
0x8e, 0x0b, 0xcb, 0x43, 0x25, 0x23, 0x4b, 0x5e, 0xfb, 0x10, 0xdf, 0xf1, 0xc0, 0xb3, 0x48, 0xef,
|
||||
0xe4, 0xc1, 0xb1, 0x48, 0xbf, 0x8d, 0xe3, 0xbe, 0x2c, 0xfb, 0x77, 0x55, 0xd9, 0xb1, 0x6b, 0xe9,
|
||||
0x5a, 0x56, 0x5b, 0xb2, 0x71, 0x12, 0x3c, 0x1b, 0x95, 0x7e, 0xb6, 0xbd, 0x06, 0x15, 0x48, 0x52,
|
||||
0xdb, 0x4f, 0xd8, 0x75, 0xb4, 0x60, 0x30, 0x87, 0x87, 0xbf, 0x5b, 0xbd, 0x01, 0x67, 0xf9, 0xfe,
|
||||
0xbe, 0x6a, 0x03, 0x82, 0xa7, 0xef, 0x55, 0xbb, 0x73, 0x6e, 0xbf, 0x05, 0x56, 0x00, 0x19, 0x5e,
|
||||
0xad, 0x85, 0xf5, 0xdf, 0xff, 0xd7, 0x12, 0x98, 0x41, 0x63, 0xf9, 0x7f, 0xff, 0xbf, 0x34, 0x12,
|
||||
0x10, 0x71, 0x5f, 0x2c, 0xa3, 0xcc, 0x9a, 0x47, 0x3c, 0x0e, 0x2d, 0xb8, 0x29, 0xbf, 0x61, 0xd0,
|
||||
0x76, 0xb5, 0x92, 0xd1, 0x32, 0x65, 0x89, 0xdb, 0x03, 0xcc, 0x8b, 0x8c, 0x63, 0x4d, 0xc3, 0xa5,
|
||||
0xc6, 0xc8, 0x95, 0x74, 0xbb, 0x9e, 0xe5, 0x2a, 0x51, 0x4c, 0xf0, 0x67, 0x78, 0x18, 0x28, 0x82,
|
||||
0x9c, 0x32, 0x34, 0x13, 0x01, 0xa1, 0xad, 0x44, 0xf3, 0xa4, 0x22, 0xac, 0xaa, 0xec, 0xa3, 0x10,
|
||||
0x62, 0x05, 0xb8, 0xe0, 0x21, 0xa5, 0x08, 0x40, 0xdb, 0x51, 0x36, 0x9e, 0xa8, 0x46, 0x71, 0xad,
|
||||
0x22, 0xe4, 0xfd, 0xbd, 0xe6, 0x15, 0xb3, 0xd5, 0xd9, 0xc2, 0x52, 0x63, 0xe9, 0x3f, 0x17, 0x22,
|
||||
0x10, 0x9e, 0x8c, 0x4f, 0x7f, 0x14, 0x21, 0x2f, 0x60, 0x9a, 0x0c, 0xa4, 0xf6, 0x19, 0x40, 0x8d,
|
||||
0xd1, 0xec, 0x3f, 0x11, 0x60, 0x50, 0x96, 0x7d, 0x07, 0xa6, 0xa2, 0x6a, 0x6e, 0x9a, 0x08, 0x4d,
|
||||
0xfa, 0xcb, 0x97, 0x23, 0xba, 0xa7, 0xf3, 0x0e, 0x25, 0xef, 0x0e, 0x12, 0xba, 0x21, 0x02, 0xea,
|
||||
0x67, 0x3b, 0x6c, 0xa7, 0x54, 0x7f, 0xbc, 0x3c, 0x19, 0x25, 0xd5, 0xfa, 0x77, 0x99, 0x57, 0xbf,
|
||||
0xbf, 0xa7, 0x4a, 0x38, 0xc4, 0x0f, 0x30, 0x4f, 0xd9, 0xc8, 0x54, 0xc5, 0x4e, 0x5e, 0xe7, 0x87,
|
||||
0xbe, 0x5d, 0xff, 0x65, 0x0f, 0x34, 0xd6, 0xa0, 0x0c, 0x77, 0x59, 0xf2, 0xb6, 0x81, 0x6d, 0x8c,
|
||||
0x76, 0xf3, 0x86, 0xf9, 0xc0, 0x21, 0xa4, 0x7a, 0x30, 0x55, 0x12, 0x80, 0x17, 0x02, 0x28, 0xa3,
|
||||
0x84, 0xd0, 0xb6, 0x4b, 0x94, 0x9a, 0x9b, 0x4c, 0x1e, 0x01, 0x2f, 0xd6, 0xc7, 0xa8, 0x09, 0xe4,
|
||||
0xa2, 0xa0, 0xee, 0x40, 0x2f, 0x25, 0x45, 0xf9, 0x9b, 0x85, 0x6d, 0x05, 0xa5, 0x7f, 0xc5, 0x10,
|
||||
0x64, 0x13, 0x58, 0xac, 0x2d, 0x54, 0x30, 0xfe, 0xc1, 0xd1, 0x62, 0xbd, 0x6b, 0x64, 0x5b, 0x1c,
|
||||
0xeb, 0xdf, 0x04, 0x80, 0x79, 0xa2, 0x13, 0x2e, 0x49, 0x6f, 0x45, 0x43, 0xfa, 0x82, 0x68, 0xce,
|
||||
0x53, 0xd9, 0x38, 0x31, 0x4a, 0x48, 0x20, 0x56, 0x31, 0xfb, 0xe3, 0x79, 0x52, 0x5e, 0x73, 0x45,
|
||||
0x3e, 0x52, 0x3a, 0xc4, 0xc2, 0x72, 0xb2, 0xf2, 0xdb, 0xf8, 0x67, 0x1f, 0x5d, 0x43, 0x67, 0x3c,
|
||||
0xbc, 0x17, 0x0a, 0xb2, 0x94, 0x9e, 0x56, 0x2b, 0xa9, 0xb8, 0xab, 0xd0, 0x87, 0xd1, 0x0f, 0xd4,
|
||||
0xa2, 0xd6, 0x04, 0x74, 0xc7, 0x86, 0xcd, 0xb0, 0xcb, 0x93, 0x95, 0xcb, 0x28, 0x65, 0x89, 0xb3,
|
||||
0xad, 0xef, 0x53, 0xbf, 0x7c, 0xda, 0x4e, 0x65, 0x72, 0xb1, 0xde, 0xd3, 0xfe, 0x13, 0x9f, 0x5d,
|
||||
0xd8, 0x93, 0x3a, 0xca, 0xaa, 0xe4, 0x7f, 0xab, 0xe6, 0xdb, 0xd9, 0x8d, 0xc6, 0xaa, 0xec, 0xa9,
|
||||
0xa3, 0x32, 0xc9, 0xac, 0x13, 0xc9, 0x1f, 0x53, 0x35, 0x56, 0x3b, 0x93, 0x2d, 0x3e, 0x5b, 0xb8,
|
||||
0x04, 0xfe, 0x4c, 0x55, 0x47, 0xc6, 0x8a, 0x46, 0x11, 0xd3, 0x84, 0xe9, 0x3a, 0x32, 0xfb, 0x83,
|
||||
0x51, 0x32, 0x66, 0xe9, 0xc2, 0xf9, 0x50, 0x55, 0x87, 0xd9, 0x4f, 0x39, 0x81, 0x69, 0xe0, 0x09,
|
||||
0x3f, 0x14, 0x78, 0x3c, 0x76, 0xca, 0x44, 0x9f, 0x59, 0x8b, 0x5b, 0x7d, 0x3d, 0xd9, 0x59, 0x8c,
|
||||
0xab, 0x02, 0x44, 0x7e, 0xae, 0x8a, 0x2d, 0x64, 0x39, 0xa3, 0x79, 0x5c, 0xe6, 0x3e, 0x1b, 0x39,
|
||||
0x7e, 0xad, 0xc5, 0x28, 0x97, 0xf9, 0xdc, 0xb9, 0xda, 0xb6, 0x70, 0xeb, 0xe7, 0xeb, 0x58, 0x48,
|
||||
0x83, 0x15, 0xaa, 0x54, 0xc2, 0xb0, 0x6b, 0x49, 0xa7, 0xc9, 0x30, 0xcd, 0x2f, 0x35, 0x9e, 0xc4,
|
||||
0x31, 0x1d, 0x27, 0xdb, 0xe0, 0x76, 0x48, 0x66, 0x55, 0xe4, 0x57, 0x94, 0x2d, 0x8d, 0xef, 0x4c,
|
||||
0xaf, 0xe4, 0xdd, 0xa4, 0x51, 0xce, 0x29, 0x2b, 0xad, 0xeb, 0xa1, 0xd5, 0xb9, 0x9b, 0x8d, 0x8d,
|
||||
0x10, 0xf3, 0xae, 0x23, 0xf9, 0xdd, 0xd5, 0xac, 0x02, 0xce, 0xa0, 0x77, 0x39, 0x77, 0xe8, 0xf1,
|
||||
0x5b, 0x3e, 0x7b, 0x2d, 0x53, 0x05, 0x98, 0x58, 0x5d, 0xdf, 0xd9, 0x4f, 0x9b, 0xaa, 0x55, 0x89,
|
||||
0xda, 0xc0, 0x51, 0xe3, 0xc3, 0x0f, 0xe7, 0x33, 0xba, 0x69, 0x57, 0xed, 0x76, 0xfb, 0xf8, 0x3f,
|
||||
0xef, 0xaa, 0xff, 0x68, 0xa4, 0xd8, 0x6c, 0x12, 0x4b, 0x7b, 0x8f, 0x6a, 0x57, 0xde, 0x00, 0xf7,
|
||||
0x3b, 0xe8, 0x0c, 0xa0, 0x5f, 0x0b, 0x7e, 0x70, 0x5e, 0x23, 0xa7, 0x71, 0xba, 0xf6, 0x44, 0x3d,
|
||||
0xa8, 0x8f, 0x05, 0x93, 0xae, 0xe3, 0x40, 0x55, 0x5b, 0xa5, 0xcf, 0xf3, 0x32, 0x43, 0xff, 0xed,
|
||||
0x3e, 0xc4, 0x9b, 0xe8, 0x7a, 0x26, 0x56, 0x56, 0x3b, 0x65, 0x26, 0xac, 0x7a, 0xbb, 0x8f, 0x84,
|
||||
0xd4, 0x2c, 0xd2, 0xcf, 0xbe, 0xbb, 0x7b, 0x8d, 0xe6, 0x18, 0x13, 0x61, 0xed, 0x02, 0x88, 0xe4,
|
||||
0x41, 0xf0, 0x26, 0x46, 0xe5, 0x75, 0xee, 0x54, 0x11, 0x56, 0x95, 0xcf, 0x40, 0x7f, 0xa6, 0xe1,
|
||||
0x1a, 0xcb, 0x14, 0x69, 0x72, 0x6e, 0xe3, 0xcf, 0x6f, 0x81, 0x53, 0x48, 0x4e, 0x57, 0xd1, 0x10,
|
||||
0xa5, 0xc6, 0xaf, 0x32, 0x74, 0x6d, 0x8c, 0x9c, 0xd9, 0x1d, 0x14, 0xe8, 0x3a, 0xb8, 0x35, 0xcd,
|
||||
0x90, 0x0c, 0x28, 0x93, 0xd3, 0x60, 0xff, 0xe8, 0xe8, 0x3c, 0xf1, 0xe1, 0xaf, 0x81, 0xe1, 0x72,
|
||||
0xc3, 0xaa, 0xa1, 0x1b, 0xb0, 0x2f, 0x80, 0x49, 0xed, 0xa9, 0x0b, 0x30, 0xbd, 0x68, 0x62, 0x2e,
|
||||
0xaa, 0xab, 0x5f, 0xfe, 0xac, 0x3d, 0x7e, 0x34, 0x39, 0xeb, 0x15, 0x29, 0x49, 0x47, 0x40, 0xd4,
|
||||
0x34, 0xf1, 0x49, 0x47, 0xc1, 0x1a, 0xff, 0x72, 0x9b, 0x5c, 0x72, 0x39, 0x84, 0xac, 0x79, 0x77,
|
||||
0xe0, 0xa7, 0xed, 0x7f, 0x57, 0xe0, 0x65, 0x22, 0xaf, 0x7d, 0x80, 0xf4, 0xc5, 0x42, 0xd2, 0x75,
|
||||
0x26, 0xa5, 0x4d, 0x9a, 0x49, 0xcc, 0x3f, 0x21, 0x1d, 0x0f, 0x8b, 0x45, 0xad, 0x6c, 0xe0, 0x8b,
|
||||
0xb7, 0x51, 0x2f, 0x42, 0x48, 0x3a, 0x2b, 0x26, 0xf4, 0xb6, 0xd8, 0xd3, 0xb6, 0xc5, 0xce, 0xfb,
|
||||
0x9a, 0x82, 0x07, 0xed, 0xe0, 0x98, 0x76, 0x08, 0xb6, 0x5a, 0x77, 0x19, 0xef, 0x88, 0x9f, 0x9d,
|
||||
0xc6, 0xf6, 0x0d, 0x17, 0xe1, 0x8b, 0x37, 0x6f, 0xba, 0x1b, 0x9d, 0x5b, 0x67, 0x6d, 0xce, 0x76,
|
||||
0x6b, 0x27, 0x94, 0x4f, 0x40, 0x47, 0x76, 0xde, 0x97, 0x66, 0xf1, 0xab, 0x77, 0x73, 0xeb, 0x4e,
|
||||
0x6c, 0xac, 0x1b, 0x96, 0x00, 0xaf, 0xc7, 0xb1, 0xa5, 0x7e, 0xfa, 0xcf, 0xfc, 0x18, 0x1d, 0xe3,
|
||||
0x73, 0xf0, 0x36, 0x72, 0x94, 0x0a, 0x7b, 0x64, 0x7f, 0xe5, 0xda, 0xea, 0x07, 0x64, 0x6d, 0x17,
|
||||
0x3f, 0xda, 0xc0, 0x82, 0x4a, 0x9e, 0x7f, 0x9b, 0x83, 0xb3, 0x38, 0x85, 0x00, 0x16, 0x76, 0x42,
|
||||
0x9f, 0x00, 0xdb, 0xae, 0x5d, 0x7d, 0xe4, 0xeb, 0xec, 0xc0, 0x79, 0x29, 0x56, 0x07, 0x80, 0xfd,
|
||||
0xcf, 0xcc, 0xf3, 0x88, 0x6f, 0x89, 0x77, 0xe6, 0x3d, 0x4a, 0xc2, 0x36, 0x29, 0x68, 0x7e, 0x08,
|
||||
0xfc, 0x39, 0xdf, 0xc8, 0xe2, 0x2d, 0x7f, 0x31, 0xdf, 0xe1, 0x2f, 0x9a, 0x04, 0xd4, 0x79, 0x6a,
|
||||
0x97, 0x3d, 0x50, 0xd2, 0x69, 0x94, 0x7b, 0x96, 0xdf, 0x8f, 0x3a, 0x66, 0x20, 0x00, 0x21, 0xfc,
|
||||
0x0e, 0x4f, 0x32, 0xd9, 0x91, 0x87, 0x62, 0xf5, 0x44, 0x5b, 0x7e, 0xbe, 0x23, 0xd5, 0xa9, 0xbc,
|
||||
0xc9, 0x8e, 0x9a, 0x48, 0xa0, 0x49, 0xd6, 0x4d, 0xb6, 0xfa, 0x10, 0xe8, 0x09, 0x48, 0xc5, 0xdf,
|
||||
0xac, 0x91, 0x9f, 0x60, 0xe2, 0x0f, 0x39, 0xd2, 0xff, 0xb9, 0xd8, 0xff, 0x07, 0xff, 0x03, 0x8d,
|
||||
0x05, 0x6d, 0x6c, 0x00, 0x00
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
2240
wled00/html_simple.h
2240
wled00/html_simple.h
File diff suppressed because it is too large
Load Diff
3956
wled00/html_ui.h
3956
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,11 @@
|
||||
#define DIMPROV_PRINTF(x...)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#undef WLED_DISABLE_IMPROV_WIFISCAN
|
||||
#define WLED_DISABLE_IMPROV_WIFISCAN
|
||||
#endif
|
||||
|
||||
#define IMPROV_VERSION 1
|
||||
|
||||
void parseWiFiCommand(char *rpcData);
|
||||
@@ -28,20 +33,14 @@ enum ImprovPacketByte {
|
||||
RPC_CommandType = 9
|
||||
};
|
||||
|
||||
enum ImprovRPCType {
|
||||
Command_Wifi = 0x01,
|
||||
Request_State = 0x02,
|
||||
Request_Info = 0x03
|
||||
};
|
||||
|
||||
//File dbgf;
|
||||
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
||||
static bool improvWifiScanRunning = false;
|
||||
#endif
|
||||
|
||||
//blocking function to parse an Improv Serial packet
|
||||
void handleImprovPacket() {
|
||||
uint8_t header[6] = {'I','M','P','R','O','V'};
|
||||
|
||||
//dbgf = WLED_FS.open("/improv.log","a");
|
||||
|
||||
bool timeout = false;
|
||||
uint8_t waitTime = 25;
|
||||
uint16_t packetByte = 0;
|
||||
@@ -62,12 +61,11 @@ void handleImprovPacket() {
|
||||
byte next = Serial.read();
|
||||
|
||||
DIMPROV_PRINT("Received improv byte: "); DIMPROV_PRINTF("%x\r\n",next);
|
||||
//f.write(next);
|
||||
|
||||
switch (packetByte) {
|
||||
case ImprovPacketByte::Version: {
|
||||
if (next != IMPROV_VERSION) {
|
||||
DIMPROV_PRINTLN(F("Invalid version"));
|
||||
//dbgf.close();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -75,7 +73,6 @@ void handleImprovPacket() {
|
||||
case ImprovPacketByte::PacketType: {
|
||||
if (next != ImprovPacketType::RPC_Command) {
|
||||
DIMPROV_PRINTF("Non RPC-command improv packet type %i\n",next);
|
||||
//dbgf.close();
|
||||
return;
|
||||
}
|
||||
if (!improvActive) improvActive = 1;
|
||||
@@ -89,7 +86,6 @@ void handleImprovPacket() {
|
||||
if (checksum != next) {
|
||||
DIMPROV_PRINTF("Got RPC checksum %i, expected %i",next,checksum);
|
||||
sendImprovStateResponse(0x01, true);
|
||||
//dbgf.close();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,22 +96,23 @@ void handleImprovPacket() {
|
||||
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
|
||||
if (Network.isConnected()) improvState = 0x04; //provisioned
|
||||
sendImprovStateResponse(improvState, false);
|
||||
if (improvState == 0x04) sendImprovRPCResponse(ImprovRPCType::Request_State);
|
||||
if (improvState == 0x04) sendImprovIPRPCResult(ImprovRPCType::Request_State);
|
||||
break;
|
||||
}
|
||||
case ImprovRPCType::Request_Info: sendImprovInfoResponse(); break;
|
||||
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
||||
case ImprovRPCType::Request_Scan: startImprovWifiScan(); break;
|
||||
#endif
|
||||
default: {
|
||||
DIMPROV_PRINTF("Unknown RPC command %i\n",next);
|
||||
sendImprovStateResponse(0x02, true);
|
||||
}
|
||||
}
|
||||
//dbgf.close();
|
||||
return;
|
||||
}
|
||||
if (packetByte < 6) { //check header
|
||||
if (next != header[packetByte]) {
|
||||
DIMPROV_PRINTLN(F("Invalid improv header"));
|
||||
//dbgf.close();
|
||||
return;
|
||||
}
|
||||
} else if (packetByte > 9) { //RPC data
|
||||
@@ -128,7 +125,6 @@ void handleImprovPacket() {
|
||||
checksum += next;
|
||||
packetByte++;
|
||||
}
|
||||
//dbgf.close();
|
||||
}
|
||||
|
||||
void sendImprovStateResponse(uint8_t state, bool error) {
|
||||
@@ -147,79 +143,116 @@ void sendImprovStateResponse(uint8_t state, bool error) {
|
||||
Serial.write('\n');
|
||||
}
|
||||
|
||||
void sendImprovRPCResponse(byte commandId) {
|
||||
// used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan()
|
||||
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) {
|
||||
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
||||
uint8_t packetLen = 12;
|
||||
char out[64] = {'I','M','P','R','O','V'};
|
||||
char out[256] = {'I','M','P','R','O','V'};
|
||||
out[6] = IMPROV_VERSION;
|
||||
out[7] = ImprovPacketType::RPC_Response;
|
||||
out[8] = 2; //Length (set below)
|
||||
out[9] = commandId;
|
||||
out[10] = 0; //Data len (set below)
|
||||
out[11] = '\0'; //URL len (set below)
|
||||
//out[8] = 2; //Length (set below)
|
||||
out[9] = type;
|
||||
//out[10] = 0; //Data len (set below)
|
||||
uint16_t pos = 11;
|
||||
|
||||
if (Network.isConnected())
|
||||
{
|
||||
IPAddress localIP = Network.localIP();
|
||||
uint8_t len = sprintf(out+12, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
if (len > 24) return; //sprintf fail?
|
||||
out[11] = len;
|
||||
out[10] = 1 + len;
|
||||
out[8] = 3 + len; //RPC command type + data len + url len + url
|
||||
packetLen = 13 + len;
|
||||
for (uint8_t s = 0; s < n_strings; s++) {
|
||||
size_t len = strlen(strings[s]);
|
||||
if (pos + len > 254) continue; // simple buffer overflow guard
|
||||
out[pos++] = len;
|
||||
strcpy(out + pos, strings[s]);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
packetLen = pos +1;
|
||||
out[8] = pos -9; // Length of packet (excluding first 9 header bytes and final checksum byte)
|
||||
out[10] = pos -11; // Data len
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
|
||||
out[packetLen -1] = checksum;
|
||||
Serial.write((uint8_t*)out, packetLen);
|
||||
Serial.write('\n');
|
||||
DIMPROV_PRINT("RPC result checksum");
|
||||
DIMPROV_PRINTLN(checksum);
|
||||
}
|
||||
|
||||
void sendImprovIPRPCResult(ImprovRPCType type) {
|
||||
if (Network.isConnected())
|
||||
{
|
||||
char urlStr[64];
|
||||
IPAddress localIP = Network.localIP();
|
||||
uint8_t len = sprintf(urlStr, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
if (len > 24) return; //sprintf fail?
|
||||
const char *str[1] = {urlStr};
|
||||
sendImprovRPCResult(type, 1, str);
|
||||
} else {
|
||||
sendImprovRPCResult(type, 0);
|
||||
}
|
||||
|
||||
improvActive = 1; //no longer provisioning
|
||||
}
|
||||
|
||||
void sendImprovInfoResponse() {
|
||||
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
||||
uint8_t packetLen = 12;
|
||||
char out[128] = {'I','M','P','R','O','V'};
|
||||
out[6] = IMPROV_VERSION;
|
||||
out[7] = ImprovPacketType::RPC_Response;
|
||||
//out[8] = 2; //Length (set below)
|
||||
out[9] = ImprovRPCType::Request_Info;
|
||||
//out[10] = 0; //Data len (set below)
|
||||
out[11] = 4; //Firmware len ("WLED")
|
||||
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
|
||||
uint8_t lengthSum = 17;
|
||||
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.14.0-b2/%i"),VERSION);
|
||||
out[16] = vlen; lengthSum += vlen;
|
||||
uint8_t hlen = 7;
|
||||
#ifdef ESP8266
|
||||
strcpy(out+lengthSum+1,"esp8266");
|
||||
#else
|
||||
hlen = 5;
|
||||
strcpy(out+lengthSum+1,"esp32");
|
||||
#endif
|
||||
out[lengthSum] = hlen;
|
||||
lengthSum += hlen + 1;
|
||||
const char* bString =
|
||||
#ifdef ESP8266
|
||||
"esp8266"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
"esp32-c3"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
"esp32-s2"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
"esp32-s3";
|
||||
#else // ESP32
|
||||
"esp32";
|
||||
#endif
|
||||
;
|
||||
|
||||
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
||||
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
||||
strcpy(out+lengthSum+1,useMdnsName ? cmDNS : serverDescription);
|
||||
uint8_t nlen = strlen(useMdnsName ? cmDNS : serverDescription);
|
||||
out[lengthSum] = nlen;
|
||||
lengthSum += nlen + 1;
|
||||
char vString[20];
|
||||
sprintf_P(vString, PSTR("0.14.0-b5/%i"), VERSION);
|
||||
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
||||
|
||||
packetLen = lengthSum +1;
|
||||
out[8] = lengthSum -9;
|
||||
out[10] = lengthSum -11;
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
|
||||
out[packetLen -1] = checksum;
|
||||
Serial.write((uint8_t*)out, packetLen);
|
||||
Serial.write('\n');
|
||||
DIMPROV_PRINT("Info checksum");
|
||||
DIMPROV_PRINTLN(checksum);
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
||||
void startImprovWifiScan() {
|
||||
if (improvWifiScanRunning) return;
|
||||
WiFi.scanNetworks(true);
|
||||
improvWifiScanRunning = true;
|
||||
}
|
||||
|
||||
void handleImprovWifiScan() {
|
||||
if (!improvWifiScanRunning) return;
|
||||
int16_t status = WiFi.scanComplete();
|
||||
if (status == WIFI_SCAN_RUNNING) return;
|
||||
// here scan completed or failed (-2)
|
||||
improvWifiScanRunning = false;
|
||||
|
||||
for (int i = 0; i < status; i++) {
|
||||
char rssiStr[8];
|
||||
sprintf(rssiStr, "%d", WiFi.RSSI(i));
|
||||
#ifdef ESP8266
|
||||
bool isOpen = WiFi.encryptionType(i) == ENC_TYPE_NONE;
|
||||
#else
|
||||
bool isOpen = WiFi.encryptionType(i) == WIFI_AUTH_OPEN;
|
||||
#endif
|
||||
|
||||
char ssidStr[33];
|
||||
strcpy(ssidStr, WiFi.SSID(i).c_str());
|
||||
const char *str[3] = {ssidStr, rssiStr, isOpen ? "NO":"YES"};
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Scan, 3, str);
|
||||
}
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Scan, 0);
|
||||
|
||||
WiFi.scanDelete();
|
||||
}
|
||||
#else
|
||||
void startImprovWifiScan() {}
|
||||
void handleImprovWifiScan() {}
|
||||
#endif
|
||||
|
||||
void parseWiFiCommand(char* rpcData) {
|
||||
uint8_t len = rpcData[0];
|
||||
if (!len || len > 126) return;
|
||||
|
||||
@@ -70,13 +70,9 @@ void decBrightness()
|
||||
}
|
||||
}
|
||||
|
||||
// apply preset or fallback to a effect and palette if it doesn't exist
|
||||
void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
|
||||
{
|
||||
applyPreset(presetID, CALL_MODE_BUTTON_PRESET);
|
||||
//these two will be overwritten if preset exists in handlePresets()
|
||||
effectCurrent = effectID;
|
||||
effectPalette = paletteID;
|
||||
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
|
||||
}
|
||||
|
||||
byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define JSON_PATH_PALETTES 5
|
||||
#define JSON_PATH_FXDATA 6
|
||||
#define JSON_PATH_NETWORKS 7
|
||||
#define JSON_PATH_EFFECTS 8
|
||||
|
||||
/*
|
||||
* JSON API (De)serialization
|
||||
@@ -21,19 +22,22 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
int stop = elem["stop"] | -1;
|
||||
|
||||
// if using vectors use this code to append segment
|
||||
// append segment
|
||||
if (id >= strip.getSegmentsNum()) {
|
||||
if (stop <= 0) return false; // ignore empty/inactive segments
|
||||
strip.appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
id = strip.getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
|
||||
//DEBUG_PRINTLN("-- JSON deserialize segment.");
|
||||
Segment& seg = strip.getSegment(id);
|
||||
//DEBUG_PRINTF("-- Original segment: %p\n", &seg);
|
||||
Segment prev = seg; //make a backup so we can tell if something changed
|
||||
//DEBUG_PRINTF("-- Duplicate segment: %p\n", &prev);
|
||||
|
||||
uint16_t start = elem["start"] | seg.start;
|
||||
if (stop < 0) {
|
||||
uint16_t len = elem["len"];
|
||||
int len = elem["len"];
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
}
|
||||
// 2D segments
|
||||
@@ -69,9 +73,10 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
const char * name = elem["n"].as<const char*>();
|
||||
size_t len = 0;
|
||||
if (name != nullptr) len = strlen(name);
|
||||
if (len > 0 && len < 33) {
|
||||
if (len > 0) {
|
||||
if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN;
|
||||
seg.name = new char[len+1];
|
||||
if (seg.name) strlcpy(seg.name, name, 33);
|
||||
if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1);
|
||||
} else {
|
||||
// but is empty (already deleted above)
|
||||
elem.remove("n");
|
||||
@@ -108,7 +113,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
of = offsetAbs;
|
||||
}
|
||||
if (stop > start && of > len -1) of = len -1;
|
||||
seg.setUp(start, stop, grp, spc, of, startY, stopY);
|
||||
|
||||
// update segment (delete if necessary)
|
||||
// do not call seg.setUp() here, as it may cause a crash due to concurrent access if the segment is currently drawing effects
|
||||
// WS2812FX handles queueing of the change
|
||||
strip.setSegment(id, start, stop, grp, spc, of, startY, stopY);
|
||||
|
||||
if (seg.reset && seg.stop == 0) return true; // segment was deleted & is marked for reset, no need to change anything else
|
||||
|
||||
@@ -341,7 +350,9 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
JsonObject udpn = root["udpn"];
|
||||
notifyDirect = udpn["send"] | notifyDirect;
|
||||
syncGroups = udpn["sgrp"] | syncGroups;
|
||||
receiveNotifications = udpn["recv"] | receiveNotifications;
|
||||
receiveGroups = udpn["rgrp"] | receiveGroups;
|
||||
if ((bool)udpn[F("nn")]) callMode = CALL_MODE_NO_NOTIFY; //send no notification just for this request
|
||||
|
||||
unsigned long timein = root["time"] | UINT32_MAX; //backup time source if NTP not synced
|
||||
@@ -424,7 +435,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
|
||||
if (!root["pd"].isNull() && stateChanged) {
|
||||
currentPreset = root[F("pd")] | currentPreset;
|
||||
if (root["win"].isNull()) presetCycCurr = currentPreset;
|
||||
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise it was set in handleSet() [set.cpp]
|
||||
presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after
|
||||
//unloadPlaylist(); // applying a preset unloads the playlist, may be needed here too?
|
||||
} else if (!root["ps"].isNull()) {
|
||||
@@ -466,10 +477,12 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
|
||||
if (segmentBounds) {
|
||||
root["start"] = seg.start;
|
||||
root["stop"] = seg.stop;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (strip.isMatrix) {
|
||||
root[F("startY")] = seg.startY;
|
||||
root[F("stopY")] = seg.stopY;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (!forPreset) root["len"] = seg.stop - seg.start;
|
||||
root["grp"] = seg.grouping;
|
||||
@@ -556,6 +569,8 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
JsonObject udpn = root.createNestedObject("udpn");
|
||||
udpn["send"] = notifyDirect;
|
||||
udpn["recv"] = receiveNotifications;
|
||||
udpn["sgrp"] = syncGroups;
|
||||
udpn["rgrp"] = receiveGroups;
|
||||
|
||||
root[F("lor")] = realtimeOverride;
|
||||
}
|
||||
@@ -727,6 +742,10 @@ void serializeInfo(JsonObject root)
|
||||
#endif
|
||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
char time[32];
|
||||
getTimeString(time);
|
||||
root[F("time")] = time;
|
||||
|
||||
usermods.addToJsonInfo(root);
|
||||
|
||||
uint16_t os = 0;
|
||||
@@ -812,7 +831,7 @@ void setPaletteColors(JsonArray json, byte* tcp)
|
||||
}
|
||||
}
|
||||
|
||||
void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
||||
void serializePalettes(JsonObject root, int page)
|
||||
{
|
||||
byte tcp[72];
|
||||
#ifdef ESP8266
|
||||
@@ -821,11 +840,6 @@ void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
||||
int itemPerPage = 8;
|
||||
#endif
|
||||
|
||||
int page = 0;
|
||||
if (request->hasParam("page")) {
|
||||
page = request->getParam("page")->value().toInt();
|
||||
}
|
||||
|
||||
int palettesCount = strip.getPaletteCount();
|
||||
int customPalettes = strip.customPalettes.size();
|
||||
|
||||
@@ -968,9 +982,10 @@ void serializeNodes(JsonObject root)
|
||||
// deserializes mode data string into JsonArray
|
||||
void serializeModeData(JsonArray fxdata)
|
||||
{
|
||||
char lineBuffer[128];
|
||||
char lineBuffer[256];
|
||||
for (size_t i = 0; i < strip.getModeCount(); i++) {
|
||||
strncpy_P(lineBuffer, strip.getModeData(i), 127);
|
||||
strncpy_P(lineBuffer, strip.getModeData(i), sizeof(lineBuffer)/sizeof(char)-1);
|
||||
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
|
||||
if (lineBuffer[0] != 0) {
|
||||
char* dataPtr = strchr(lineBuffer,'@');
|
||||
if (dataPtr) fxdata.add(dataPtr+1);
|
||||
@@ -981,10 +996,12 @@ void serializeModeData(JsonArray fxdata)
|
||||
|
||||
// deserializes mode names string into JsonArray
|
||||
// also removes effect data extensions (@...) from deserialised names
|
||||
void serializeModeNames(JsonArray arr) {
|
||||
char lineBuffer[128];
|
||||
void serializeModeNames(JsonArray arr)
|
||||
{
|
||||
char lineBuffer[256];
|
||||
for (size_t i = 0; i < strip.getModeCount(); i++) {
|
||||
strncpy_P(lineBuffer, strip.getModeData(i), 127);
|
||||
strncpy_P(lineBuffer, strip.getModeData(i), sizeof(lineBuffer)/sizeof(char)-1);
|
||||
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
|
||||
if (lineBuffer[0] != 0) {
|
||||
char* dataPtr = strchr(lineBuffer,'@');
|
||||
if (dataPtr) *dataPtr = 0; // terminate mode data after name
|
||||
@@ -1001,29 +1018,16 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
else if (url.indexOf("info") > 0) subJson = JSON_PATH_INFO;
|
||||
else if (url.indexOf("si") > 0) subJson = JSON_PATH_STATE_INFO;
|
||||
else if (url.indexOf("nodes") > 0) subJson = JSON_PATH_NODES;
|
||||
else if (url.indexOf("eff") > 0) subJson = JSON_PATH_EFFECTS;
|
||||
else if (url.indexOf("palx") > 0) subJson = JSON_PATH_PALETTES;
|
||||
else if (url.indexOf("fxda") > 0) subJson = JSON_PATH_FXDATA;
|
||||
else if (url.indexOf("net") > 0) subJson = JSON_PATH_NETWORKS;
|
||||
else if (url.indexOf("net") > 0) subJson = JSON_PATH_NETWORKS;
|
||||
#ifdef WLED_ENABLE_JSONLIVE
|
||||
else if (url.indexOf("live") > 0) {
|
||||
serveLiveLeds(request);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
else if (url.indexOf(F("eff")) > 0) {
|
||||
// this serves just effect names without FX data extensions in names
|
||||
if (requestJSONBufferLock(19)) {
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(&doc, true); // array document
|
||||
JsonArray lDoc = response->getRoot();
|
||||
serializeModeNames(lDoc); // remove WLED-SR extensions from effect names
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
releaseJSONBufferLock();
|
||||
} else {
|
||||
request->send(503, "application/json", F("{\"error\":3}"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (url.indexOf("pal") > 0) {
|
||||
request->send_P(200, "application/json", JSON_palette_names);
|
||||
return;
|
||||
@@ -1040,7 +1044,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
request->send(503, "application/json", F("{\"error\":3}"));
|
||||
return;
|
||||
}
|
||||
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==6);
|
||||
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
|
||||
|
||||
JsonVariant lDoc = response->getRoot();
|
||||
|
||||
@@ -1053,9 +1057,11 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
case JSON_PATH_NODES:
|
||||
serializeNodes(lDoc); break;
|
||||
case JSON_PATH_PALETTES:
|
||||
serializePalettes(lDoc, request); break;
|
||||
serializePalettes(lDoc, request->hasParam("page") ? request->getParam("page")->value().toInt() : 0); break;
|
||||
case JSON_PATH_EFFECTS:
|
||||
serializeModeNames(lDoc); break;
|
||||
case JSON_PATH_FXDATA:
|
||||
serializeModeData(lDoc.as<JsonArray>()); break;
|
||||
serializeModeData(lDoc); break;
|
||||
case JSON_PATH_NETWORKS:
|
||||
serializeNetworks(lDoc); break;
|
||||
default: //all
|
||||
@@ -1074,7 +1080,12 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
|
||||
DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", lDoc.memoryUsage(), subJson);
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
size_t len =
|
||||
#endif
|
||||
response->setLength();
|
||||
DEBUG_PRINT(F("JSON content length: ")); DEBUG_PRINTLN(len);
|
||||
|
||||
request->send(response);
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
@@ -1102,9 +1113,13 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
for (size_t i= 0; i < used; i += n)
|
||||
{
|
||||
uint32_t c = strip.getPixelColor(i);
|
||||
uint8_t r = qadd8(W(c), R(c)); //add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
uint8_t g = qadd8(W(c), G(c));
|
||||
uint8_t b = qadd8(W(c), B(c));
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
uint8_t w = W(c);
|
||||
r = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
g = scale8(qadd8(w, g), strip.getBrightness()); //G
|
||||
b = scale8(qadd8(w, b), strip.getBrightness()); //B
|
||||
olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0));
|
||||
}
|
||||
olen -= 1;
|
||||
|
||||
@@ -37,12 +37,12 @@ void applyValuesToSelectedSegs()
|
||||
|
||||
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
||||
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {seg.palette = effectPalette; stateChanged = true;}
|
||||
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette);}
|
||||
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent);}
|
||||
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
||||
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
|
||||
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1); stateChanged = true;}
|
||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0);}
|
||||
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1);}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ void stateUpdated(byte callMode) {
|
||||
if (stateChanged) currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
|
||||
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
|
||||
if (bri != briOld && nodeBroadcastEnabled) sendSysInfoUDP(); // update on state
|
||||
|
||||
//set flag to update ws and mqtt
|
||||
interfaceUpdateCallMode = callMode;
|
||||
@@ -146,8 +147,8 @@ void stateUpdated(byte callMode) {
|
||||
if (transitionActive) {
|
||||
briOld = briT;
|
||||
tperLast = 0;
|
||||
}
|
||||
strip.setTransitionMode(true); // force all segments to transition mode
|
||||
} else
|
||||
strip.setTransitionMode(true); // force all segments to transition mode
|
||||
transitionActive = true;
|
||||
transitionStartTime = millis();
|
||||
} else {
|
||||
@@ -160,6 +161,8 @@ void stateUpdated(byte callMode) {
|
||||
|
||||
void updateInterfaces(uint8_t callMode)
|
||||
{
|
||||
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
|
||||
|
||||
sendDataWs();
|
||||
lastInterfaceUpdate = millis();
|
||||
if (callMode == CALL_MODE_WS_SEND) return;
|
||||
@@ -178,7 +181,7 @@ void updateInterfaces(uint8_t callMode)
|
||||
void handleTransitions()
|
||||
{
|
||||
//handle still pending interface update
|
||||
if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > INTERFACE_UPDATE_COOLDOWN) updateInterfaces(interfaceUpdateCallMode);
|
||||
updateInterfaces(interfaceUpdateCallMode);
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
if (doPublishMqtt) publishMqtt();
|
||||
#endif
|
||||
@@ -186,7 +189,7 @@ void handleTransitions()
|
||||
if (transitionActive && transitionDelayTemp > 0)
|
||||
{
|
||||
float tper = (millis() - transitionStartTime)/(float)transitionDelayTemp;
|
||||
if (tper >= 1.0)
|
||||
if (tper >= 1.0f)
|
||||
{
|
||||
strip.setTransitionMode(false);
|
||||
transitionActive = false;
|
||||
@@ -194,7 +197,7 @@ void handleTransitions()
|
||||
applyFinalBri();
|
||||
return;
|
||||
}
|
||||
if (tper - tperLast < 0.004) return;
|
||||
if (tper - tperLast < 0.004f) return;
|
||||
tperLast = tper;
|
||||
briT = briOld + ((bri - briOld) * tper);
|
||||
|
||||
@@ -204,7 +207,7 @@ void handleTransitions()
|
||||
|
||||
|
||||
// legacy method, applies values from col, effectCurrent, ... to selected segments
|
||||
void colorUpdated(byte callMode){
|
||||
void colorUpdated(byte callMode) {
|
||||
applyValuesToSelectedSegs();
|
||||
stateUpdated(callMode);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/*
|
||||
* Parser for Loxone formats
|
||||
*/
|
||||
bool parseLx(int lxValue, byte rgbw[4])
|
||||
bool parseLx(int lxValue, byte* rgbw)
|
||||
{
|
||||
DEBUG_PRINT(F("LX: Lox = "));
|
||||
DEBUG_PRINTLN(lxValue);
|
||||
@@ -25,7 +25,7 @@ bool parseLx(int lxValue, byte rgbw[4])
|
||||
float tmpBri = floor((lxValue - 200000000) / 10000); ;
|
||||
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
|
||||
|
||||
tmpBri *= 2.55;
|
||||
tmpBri *= 2.55f;
|
||||
tmpBri = constrain(tmpBri, 0, 255);
|
||||
|
||||
colorKtoRGB(ct, rgbw);
|
||||
|
||||
@@ -112,7 +112,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
|
||||
if (playlistEndPreset == 255 && currentPreset > 0) playlistEndPreset = currentPreset;
|
||||
if (playlistEndPreset > 250) playlistEndPreset = 0;
|
||||
shuffle = shuffle || playlistObj["r"];
|
||||
if (shuffle) playlistOptions += PL_OPTION_SHUFFLE;
|
||||
if (shuffle) playlistOptions |= PL_OPTION_SHUFFLE;
|
||||
|
||||
currentPlaylist = presetId;
|
||||
DEBUG_PRINTLN(F("Playlist loaded."));
|
||||
@@ -156,7 +156,7 @@ void serializePlaylist(JsonObject sObj) {
|
||||
JsonArray ps = playlist.createNestedArray("ps");
|
||||
JsonArray dur = playlist.createNestedArray("dur");
|
||||
JsonArray transition = playlist.createNestedArray(F("transition"));
|
||||
playlist[F("repeat")] = (playlistIndex < 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running)
|
||||
playlist[F("repeat")] = (playlistIndex < 0 && playlistRepeat > 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running)
|
||||
playlist["end"] = playlistEndPreset;
|
||||
playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE;
|
||||
for (int i=0; i<playlistLen; i++) {
|
||||
|
||||
@@ -120,6 +120,15 @@ bool applyPreset(byte index, byte callMode)
|
||||
return true;
|
||||
}
|
||||
|
||||
// apply preset or fallback to a effect and palette if it doesn't exist
|
||||
void applyPresetWithFallback(uint8_t index, uint8_t callMode, uint8_t effectID, uint8_t paletteID)
|
||||
{
|
||||
applyPreset(index, callMode);
|
||||
//these two will be overwritten if preset exists in handlePresets()
|
||||
effectCurrent = effectID;
|
||||
effectPalette = paletteID;
|
||||
}
|
||||
|
||||
void handlePresets()
|
||||
{
|
||||
if (presetToSave) {
|
||||
@@ -167,10 +176,11 @@ void handlePresets()
|
||||
changePreset = true;
|
||||
} else {
|
||||
if (!fdo["seg"].isNull() || !fdo["on"].isNull() || !fdo["bri"].isNull() || !fdo["nl"].isNull() || !fdo["ps"].isNull() || !fdo[F("playlist")].isNull()) changePreset = true;
|
||||
fdo.remove("ps"); //remove load request for presets to prevent recursive crash
|
||||
if (!(tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is<const char *>() && strchr(fdo["ps"].as<const char *>(),'~') != strrchr(fdo["ps"].as<const char *>(),'~')))
|
||||
fdo.remove("ps"); // remove load request for presets to prevent recursive crash (if not called by button and contains preset cycling string "1~5~")
|
||||
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
|
||||
}
|
||||
if (!errorFlag && tmpPreset < 255 && changePreset) presetCycCurr = currentPreset = tmpPreset;
|
||||
if (!errorFlag && tmpPreset < 255 && changePreset) currentPreset = tmpPreset;
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
//Aircoookie recommended not to delete buffer
|
||||
|
||||
200
wled00/remote.cpp
Normal file
200
wled00/remote.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "wled.h"
|
||||
|
||||
#define ESP_NOW_STATE_UNINIT 0
|
||||
#define ESP_NOW_STATE_ON 1
|
||||
#define ESP_NOW_STATE_ERROR 2
|
||||
|
||||
#define NIGHT_MODE_DEACTIVATED -1
|
||||
#define NIGHT_MODE_BRIGHTNESS 5
|
||||
|
||||
#define WIZMOTE_BUTTON_ON 1
|
||||
#define WIZMOTE_BUTTON_OFF 2
|
||||
#define WIZMOTE_BUTTON_NIGHT 3
|
||||
#define WIZMOTE_BUTTON_ONE 16
|
||||
#define WIZMOTE_BUTTON_TWO 17
|
||||
#define WIZMOTE_BUTTON_THREE 18
|
||||
#define WIZMOTE_BUTTON_FOUR 19
|
||||
#define WIZMOTE_BUTTON_BRIGHT_UP 9
|
||||
#define WIZMOTE_BUTTON_BRIGHT_DOWN 8
|
||||
|
||||
#ifdef WLED_DISABLE_ESPNOW
|
||||
void handleRemote(){}
|
||||
#else
|
||||
|
||||
// This is kind of an esoteric strucure because it's pulled from the "Wizmote"
|
||||
// product spec. That remote is used as the baseline for behavior and availability
|
||||
// since it's broadly commercially available and works out of the box as a drop-in
|
||||
typedef struct message_structure {
|
||||
uint8_t program; // 0x91 for ON button, 0x81 for all others
|
||||
uint8_t seq[4]; // Incremetal sequence number 32 bit unsigned integer LSB first
|
||||
uint8_t byte5 = 32; // Unknown
|
||||
uint8_t button; // Identifies which button is being pressed
|
||||
uint8_t byte8 = 1; // Unknown, but always 0x01
|
||||
uint8_t byte9 = 100; // Unnkown, but always 0x64
|
||||
|
||||
uint8_t byte10; // Unknown, maybe checksum
|
||||
uint8_t byte11; // Unknown, maybe checksum
|
||||
uint8_t byte12; // Unknown, maybe checksum
|
||||
uint8_t byte13; // Unknown, maybe checksum
|
||||
} message_structure;
|
||||
|
||||
static int esp_now_state = ESP_NOW_STATE_UNINIT;
|
||||
static uint32_t last_seq = UINT32_MAX;
|
||||
static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
|
||||
static message_structure incoming;
|
||||
|
||||
// Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3
|
||||
static const byte brightnessSteps[] = {
|
||||
6, 9, 14, 22, 33, 50, 75, 113, 170, 255
|
||||
};
|
||||
static const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t);
|
||||
|
||||
static bool nightModeActive() {
|
||||
return brightnessBeforeNightMode != NIGHT_MODE_DEACTIVATED;
|
||||
}
|
||||
|
||||
static void activateNightMode() {
|
||||
brightnessBeforeNightMode = bri;
|
||||
bri = NIGHT_MODE_BRIGHTNESS;
|
||||
}
|
||||
|
||||
static bool resetNightMode() {
|
||||
if (!nightModeActive()) {
|
||||
return false;
|
||||
}
|
||||
bri = brightnessBeforeNightMode;
|
||||
brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
|
||||
return true;
|
||||
}
|
||||
|
||||
// increment `bri` to the next `brightnessSteps` value
|
||||
static void brightnessUp() {
|
||||
if (nightModeActive()) { return; }
|
||||
// dumb incremental search is efficient enough for so few items
|
||||
for (uint8_t index = 0; index < numBrightnessSteps; ++index) {
|
||||
if (brightnessSteps[index] > bri) {
|
||||
bri = brightnessSteps[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decrement `bri` to the next `brightnessSteps` value
|
||||
static void brightnessDown() {
|
||||
if (nightModeActive()) { return; }
|
||||
// dumb incremental search is efficient enough for so few items
|
||||
for (int index = numBrightnessSteps - 1; index >= 0; --index) {
|
||||
if (brightnessSteps[index] < bri) {
|
||||
bri = brightnessSteps[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setOn() {
|
||||
if (resetNightMode()) {
|
||||
stateUpdated(CALL_MODE_BUTTON);
|
||||
}
|
||||
if (!bri) {
|
||||
toggleOnOff();
|
||||
}
|
||||
}
|
||||
|
||||
static void setOff() {
|
||||
if (resetNightMode()) {
|
||||
stateUpdated(CALL_MODE_BUTTON);
|
||||
}
|
||||
if (bri) {
|
||||
toggleOnOff();
|
||||
}
|
||||
}
|
||||
|
||||
static void presetWithFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID) {
|
||||
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
|
||||
}
|
||||
|
||||
// Callback function that will be executed when data is received
|
||||
#ifdef ESP8266
|
||||
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
|
||||
#else
|
||||
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
|
||||
#endif
|
||||
|
||||
sprintf (last_signal_src, "%02x%02x%02x%02x%02x%02x",
|
||||
mac [0], mac [1], mac [2], mac [3], mac [4], mac [5]);
|
||||
|
||||
if (strcmp(last_signal_src, linked_remote) != 0) {
|
||||
DEBUG_PRINT(F("ESP Now Message Received from Unlinked Sender: "));
|
||||
DEBUG_PRINTLN(last_signal_src);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len != sizeof(incoming)) {
|
||||
DEBUG_PRINT(F("Unknown incoming ESP Now message received of length "));
|
||||
DEBUG_PRINTLN(len);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&(incoming.program), incomingData, sizeof(incoming));
|
||||
uint32_t cur_seq = incoming.seq[0] | (incoming.seq[1] << 8) | (incoming.seq[2] << 16) | (incoming.seq[3] << 24);
|
||||
|
||||
if (cur_seq == last_seq) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DEBUG_PRINT(F("Incoming ESP Now Packet["));
|
||||
DEBUG_PRINT(cur_seq);
|
||||
DEBUG_PRINT(F("] from sender["));
|
||||
DEBUG_PRINT(last_signal_src);
|
||||
DEBUG_PRINT(F("] button: "));
|
||||
DEBUG_PRINTLN(incoming.button);
|
||||
switch (incoming.button) {
|
||||
case WIZMOTE_BUTTON_ON : setOn(); stateUpdated(CALL_MODE_BUTTON); break;
|
||||
case WIZMOTE_BUTTON_OFF : setOff(); stateUpdated(CALL_MODE_BUTTON); break;
|
||||
case WIZMOTE_BUTTON_ONE : presetWithFallback(1, FX_MODE_STATIC, 0); resetNightMode(); break;
|
||||
case WIZMOTE_BUTTON_TWO : presetWithFallback(2, FX_MODE_BREATH, 0); resetNightMode(); break;
|
||||
case WIZMOTE_BUTTON_THREE : presetWithFallback(3, FX_MODE_FIRE_FLICKER, 0); resetNightMode(); break;
|
||||
case WIZMOTE_BUTTON_FOUR : presetWithFallback(4, FX_MODE_RAINBOW, 0); resetNightMode(); break;
|
||||
case WIZMOTE_BUTTON_NIGHT : activateNightMode(); stateUpdated(CALL_MODE_BUTTON); break;
|
||||
case WIZMOTE_BUTTON_BRIGHT_UP : brightnessUp(); stateUpdated(CALL_MODE_BUTTON); break;
|
||||
case WIZMOTE_BUTTON_BRIGHT_DOWN : brightnessDown(); stateUpdated(CALL_MODE_BUTTON); break;
|
||||
default: break;
|
||||
|
||||
}
|
||||
|
||||
last_seq = cur_seq;
|
||||
}
|
||||
|
||||
void handleRemote() {
|
||||
if (enable_espnow_remote) {
|
||||
if ((esp_now_state == ESP_NOW_STATE_UNINIT) && (interfacesInited || apActive)) { // ESPNOW requires Wifi to be initialized (either STA, or AP Mode)
|
||||
DEBUG_PRINTLN(F("Initializing ESP_NOW listener"));
|
||||
// Init ESP-NOW
|
||||
if (esp_now_init() != 0) {
|
||||
DEBUG_PRINTLN(F("Error initializing ESP-NOW"));
|
||||
esp_now_state = ESP_NOW_STATE_ERROR;
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
|
||||
#endif
|
||||
|
||||
esp_now_register_recv_cb(OnDataRecv);
|
||||
esp_now_state = ESP_NOW_STATE_ON;
|
||||
}
|
||||
} else {
|
||||
if (esp_now_state == ESP_NOW_STATE_ON) {
|
||||
DEBUG_PRINTLN(F("Disabling ESP-NOW Remote Listener"));
|
||||
if (esp_now_deinit() != 0) {
|
||||
DEBUG_PRINTLN(F("Error de-initializing ESP-NOW"));
|
||||
}
|
||||
esp_now_state = ESP_NOW_STATE_UNINIT;
|
||||
} else if (esp_now_state == ESP_NOW_STATE_ERROR) {
|
||||
//Clear any error states (allows retrying by cycling)
|
||||
esp_now_state = ESP_NOW_STATE_UNINIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
138
wled00/set.cpp
138
wled00/set.cpp
@@ -7,19 +7,17 @@
|
||||
//called upon POST settings form submit
|
||||
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
{
|
||||
// PIN code request
|
||||
if (subPage == 252)
|
||||
if (subPage == SUBPAGE_PINREQ)
|
||||
{
|
||||
correctPIN = (strlen(settingsPIN)==0 || strncmp(settingsPIN, request->arg(F("PIN")).c_str(), 4)==0);
|
||||
lastEditTime = millis();
|
||||
checkSettingsPIN(request->arg(F("PIN")).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 7: DMX 8: usermods 9: N/A 10: 2D
|
||||
if (subPage <1 || subPage >10 || !correctPIN) return;
|
||||
if (subPage < 1 || subPage > 10 || !correctPIN) return;
|
||||
|
||||
//WIFI SETTINGS
|
||||
if (subPage == 1)
|
||||
if (subPage == SUBPAGE_WIFI)
|
||||
{
|
||||
strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33);
|
||||
|
||||
@@ -36,6 +34,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
noWifiSleep = request->hasArg(F("WS"));
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
enable_espnow_remote = request->hasArg(F("RE"));
|
||||
strlcpy(linked_remote,request->arg(F("RMAC")).c_str(), 13);
|
||||
|
||||
//Normalize MAC format to lowercase
|
||||
strlcpy(linked_remote,strlwr(linked_remote), 13);
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
ethernetType = request->arg(F("ETH")).toInt();
|
||||
WLED::instance().initEthernet();
|
||||
@@ -58,7 +64,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//LED SETTINGS
|
||||
if (subPage == 2)
|
||||
if (subPage == SUBPAGE_LEDS)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
@@ -85,7 +91,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
|
||||
strip.setTargetFps(request->arg(F("FR")).toInt());
|
||||
strip.useLedsArray = request->hasArg(F("LD"));
|
||||
useGlobalLedBuffer = request->hasArg(F("LD"));
|
||||
|
||||
bool busesChanged = false;
|
||||
for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {
|
||||
@@ -147,7 +153,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freqHz);
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freqHz, useGlobalLedBuffer);
|
||||
busesChanged = true;
|
||||
}
|
||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||
@@ -233,7 +239,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
gammaCorrectCol = request->hasArg(F("GC"));
|
||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
||||
calcGammaTable(gammaCorrectVal);
|
||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
@@ -262,7 +268,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//UI
|
||||
if (subPage == 3)
|
||||
if (subPage == SUBPAGE_UI)
|
||||
{
|
||||
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
|
||||
syncToggleReceive = request->hasArg(F("ST"));
|
||||
@@ -280,7 +286,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//SYNC
|
||||
if (subPage == 4)
|
||||
if (subPage == SUBPAGE_SYNC)
|
||||
{
|
||||
int t = request->arg(F("UP")).toInt();
|
||||
if (t > 0) udpPort = t;
|
||||
@@ -341,14 +347,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
mqttEnabled = request->hasArg(F("MQ"));
|
||||
strlcpy(mqttServer, request->arg(F("MS")).c_str(), 33);
|
||||
strlcpy(mqttServer, request->arg(F("MS")).c_str(), MQTT_MAX_SERVER_LEN+1);
|
||||
t = request->arg(F("MQPORT")).toInt();
|
||||
if (t > 0) mqttPort = t;
|
||||
strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41);
|
||||
if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 65);
|
||||
strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41);
|
||||
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33);
|
||||
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33);
|
||||
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), MQTT_MAX_TOPIC_LEN+1);
|
||||
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), MQTT_MAX_TOPIC_LEN+1);
|
||||
buttonPublishMqtt = request->hasArg(F("BM"));
|
||||
retainMqttMsg = request->hasArg(F("RT"));
|
||||
#endif
|
||||
@@ -379,7 +385,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//TIME
|
||||
if (subPage == 5)
|
||||
if (subPage == SUBPAGE_TIME)
|
||||
{
|
||||
ntpEnabled = request->hasArg(F("NT"));
|
||||
strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33);
|
||||
@@ -453,7 +459,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//SECURITY
|
||||
if (subPage == 6)
|
||||
if (subPage == SUBPAGE_SEC)
|
||||
{
|
||||
if (request->hasArg(F("RS"))) //complete factory reset
|
||||
{
|
||||
@@ -462,7 +468,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
clearEEPROM();
|
||||
#endif
|
||||
serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255);
|
||||
doReboot = true;
|
||||
doReboot = true; // may reboot immediately on dual-core system (race condition) which is desireable in this case
|
||||
}
|
||||
|
||||
if (request->hasArg(F("PIN"))) {
|
||||
@@ -484,7 +490,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
if (otaLock && strcmp(otaPass,request->arg(F("OP")).c_str()) == 0)
|
||||
{
|
||||
// brute force protection: do not unlock even if correct if last save was less than 3 seconds ago
|
||||
if (millis() - lastEditTime > 3000) pwdCorrect = true;
|
||||
if (millis() - lastEditTime > PIN_RETRY_COOLDOWN) pwdCorrect = true;
|
||||
}
|
||||
if (!otaLock && request->arg(F("OP")).length() > 0)
|
||||
{
|
||||
@@ -502,7 +508,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
if (subPage == 7)
|
||||
if (subPage == SUBPAGE_DMX)
|
||||
{
|
||||
int t = request->arg(F("PU")).toInt();
|
||||
if (t >= 0 && t <= 63999) e131ProxyUniverse = t;
|
||||
@@ -532,33 +538,30 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
#endif
|
||||
|
||||
//USERMODS
|
||||
if (subPage == 8)
|
||||
if (subPage == SUBPAGE_UM)
|
||||
{
|
||||
if (!requestJSONBufferLock(5)) return;
|
||||
|
||||
// global I2C & SPI pins
|
||||
int8_t hw_sda_pin = !request->arg(F("SDA")).length() ? -1 : (int)request->arg(F("SDA")).toInt();
|
||||
int8_t hw_scl_pin = !request->arg(F("SCL")).length() ? -1 : (int)request->arg(F("SCL")).toInt();
|
||||
#ifdef ESP8266
|
||||
// cannot change pins on ESP8266
|
||||
if (hw_sda_pin >= 0 && hw_sda_pin != HW_PIN_SDA) hw_sda_pin = HW_PIN_SDA;
|
||||
if (hw_scl_pin >= 0 && hw_scl_pin != HW_PIN_SCL) hw_scl_pin = HW_PIN_SCL;
|
||||
#endif
|
||||
PinManagerPinType i2c[2] = { { hw_sda_pin, true }, { hw_scl_pin, true } };
|
||||
if (hw_sda_pin >= 0 && hw_scl_pin >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
||||
i2c_sda = hw_sda_pin;
|
||||
i2c_scl = hw_scl_pin;
|
||||
#ifdef ESP32
|
||||
Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called)
|
||||
#endif
|
||||
Wire.begin();
|
||||
} else {
|
||||
// there is no Wire.end()
|
||||
DEBUG_PRINTLN(F("Could not allocate I2C pins."));
|
||||
uint8_t i2c[2] = { static_cast<uint8_t>(i2c_scl), static_cast<uint8_t>(i2c_sda) };
|
||||
pinManager.deallocateMultiplePins(i2c, 2, PinOwner::HW_I2C); // just in case deallocation of old pins
|
||||
i2c_sda = -1;
|
||||
i2c_scl = -1;
|
||||
if (i2c_sda != hw_sda_pin || i2c_scl != hw_scl_pin) {
|
||||
// only if pins changed
|
||||
uint8_t old_i2c[2] = { static_cast<uint8_t>(i2c_scl), static_cast<uint8_t>(i2c_sda) };
|
||||
pinManager.deallocateMultiplePins(old_i2c, 2, PinOwner::HW_I2C); // just in case deallocation of old pins
|
||||
|
||||
PinManagerPinType i2c[2] = { { hw_sda_pin, true }, { hw_scl_pin, true } };
|
||||
if (hw_sda_pin >= 0 && hw_scl_pin >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
||||
i2c_sda = hw_sda_pin;
|
||||
i2c_scl = hw_scl_pin;
|
||||
// no bus re-initialisation as usermods do not get any notification
|
||||
//Wire.begin(i2c_sda, i2c_scl);
|
||||
} else {
|
||||
// there is no Wire.end()
|
||||
DEBUG_PRINTLN(F("Could not allocate I2C pins."));
|
||||
i2c_sda = -1;
|
||||
i2c_scl = -1;
|
||||
}
|
||||
}
|
||||
int8_t hw_mosi_pin = !request->arg(F("MOSI")).length() ? -1 : (int)request->arg(F("MOSI")).toInt();
|
||||
int8_t hw_miso_pin = !request->arg(F("MISO")).length() ? -1 : (int)request->arg(F("MISO")).toInt();
|
||||
@@ -569,26 +572,29 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
if (hw_miso_pin >= 0 && hw_miso_pin != HW_PIN_MISOSPI) hw_mosi_pin = HW_PIN_MISOSPI;
|
||||
if (hw_sclk_pin >= 0 && hw_sclk_pin != HW_PIN_CLOCKSPI) hw_sclk_pin = HW_PIN_CLOCKSPI;
|
||||
#endif
|
||||
PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } };
|
||||
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
|
||||
spi_mosi = hw_mosi_pin;
|
||||
spi_miso = hw_miso_pin;
|
||||
spi_sclk = hw_sclk_pin;
|
||||
// no bus re-initialisation as usermods do not get any notification
|
||||
//SPI.end();
|
||||
#ifdef ESP32
|
||||
//SPI.begin(spi_sclk, spi_miso, spi_mosi);
|
||||
#else
|
||||
//SPI.begin();
|
||||
#endif
|
||||
} else {
|
||||
//SPI.end();
|
||||
DEBUG_PRINTLN(F("Could not allocate SPI pins."));
|
||||
uint8_t spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) };
|
||||
pinManager.deallocateMultiplePins(spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins
|
||||
spi_mosi = -1;
|
||||
spi_miso = -1;
|
||||
spi_sclk = -1;
|
||||
if (spi_mosi != hw_mosi_pin || spi_miso != hw_miso_pin || spi_sclk != hw_sclk_pin) {
|
||||
// only if pins changed
|
||||
uint8_t old_spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) };
|
||||
pinManager.deallocateMultiplePins(old_spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins
|
||||
PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } };
|
||||
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
|
||||
spi_mosi = hw_mosi_pin;
|
||||
spi_miso = hw_miso_pin;
|
||||
spi_sclk = hw_sclk_pin;
|
||||
// no bus re-initialisation as usermods do not get any notification
|
||||
//SPI.end();
|
||||
#ifdef ESP32
|
||||
//SPI.begin(spi_sclk, spi_miso, spi_mosi);
|
||||
#else
|
||||
//SPI.begin();
|
||||
#endif
|
||||
} else {
|
||||
//SPI.end();
|
||||
DEBUG_PRINTLN(F("Could not allocate SPI pins."));
|
||||
spi_mosi = -1;
|
||||
spi_miso = -1;
|
||||
spi_sclk = -1;
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject um = doc.createNestedObject("um");
|
||||
@@ -672,7 +678,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
//2D panels
|
||||
if (subPage == 10)
|
||||
if (subPage == SUBPAGE_2D)
|
||||
{
|
||||
strip.isMatrix = request->arg(F("SOMP")).toInt();
|
||||
strip.panel.clear(); // release memory if allocated
|
||||
@@ -708,9 +714,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
#endif
|
||||
|
||||
lastEditTime = millis();
|
||||
if (subPage != 2 && !doReboot) doSerializeConfig = true; //serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||
// do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||
doSerializeConfig = subPage != SUBPAGE_LEDS && !(subPage == SUBPAGE_SEC && doReboot);
|
||||
if (subPage == SUBPAGE_UM) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after doSerializeConfig has been set)
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (subPage == 4) alexaInit();
|
||||
if (subPage == SUBPAGE_SYNC) alexaInit();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -789,7 +797,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
spcI = getNumVal(&req, pos);
|
||||
}
|
||||
selseg.setUp(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
|
||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
|
||||
|
||||
pos = req.indexOf(F("RV=")); //Segment reverse
|
||||
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
||||
|
||||
@@ -669,6 +669,7 @@ void sendSysInfoUDP()
|
||||
#else
|
||||
data[38] = NODE_TYPE_ID_UNDEFINED;
|
||||
#endif
|
||||
if (bri) data[38] |= 0x80U; // add on/off state
|
||||
data[39] = ip[3]; // unit ID == last IP number
|
||||
|
||||
uint32_t build = VERSION;
|
||||
|
||||
@@ -133,6 +133,10 @@
|
||||
#include "../usermods/wizlights/wizlights.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_WIREGUARD
|
||||
#include "../usermods/wireguard/wireguard.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_WORDCLOCK
|
||||
#include "../usermods/usermod_v2_word_clock/usermod_v2_word_clock.h"
|
||||
#endif
|
||||
@@ -173,6 +177,10 @@
|
||||
#include "../usermods/boblight/boblight.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_INTERNAL_TEMPERATURE
|
||||
#include "../usermods/Internal_Temperature_v2/usermod_internal_temperature.h"
|
||||
#endif
|
||||
|
||||
#if defined(WLED_USE_SD_MMC) || defined(WLED_USE_SD_SPI)
|
||||
// This include of SD.h and SD_MMC.h must happen here, else they won't be
|
||||
// resolved correctly (when included in mod's header only)
|
||||
@@ -306,6 +314,10 @@ void registerUsermods()
|
||||
usermods.add(new WizLightsUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_WIREGUARD
|
||||
usermods.add(new WireguardUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_WORDCLOCK
|
||||
usermods.add(new WordClockUsermod());
|
||||
#endif
|
||||
@@ -357,4 +369,8 @@ void registerUsermods()
|
||||
#ifdef USERMOD_SHT
|
||||
usermods.add(new ShtUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_INTERNAL_TEMPERATURE
|
||||
usermods.add(new InternalTemperatureUsermod());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -148,8 +148,14 @@ bool oappendi(int i)
|
||||
bool oappend(const char* txt)
|
||||
{
|
||||
uint16_t len = strlen(txt);
|
||||
if (olen + len >= SETTINGS_STACK_BUF_SIZE)
|
||||
if (olen + len >= SETTINGS_STACK_BUF_SIZE) {
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("oappend() buffer overflow. Cannnot append "));
|
||||
DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\""));
|
||||
DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\""));
|
||||
#endif
|
||||
return false; // buffer full
|
||||
}
|
||||
strcpy(obuf + olen, txt);
|
||||
olen += len;
|
||||
return true;
|
||||
@@ -233,7 +239,8 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
||||
if (mode < strip.getModeCount()) {
|
||||
char lineBuffer[256];
|
||||
//strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode])));
|
||||
strcpy_P(lineBuffer, strip.getModeData(mode));
|
||||
strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
|
||||
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
|
||||
size_t len = strlen(lineBuffer);
|
||||
size_t j = 0;
|
||||
for (; j < maxLen && j < len; j++) {
|
||||
@@ -245,6 +252,12 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) {
|
||||
snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode);
|
||||
dest[maxLen-1] = '\0';
|
||||
return strlen(dest);
|
||||
}
|
||||
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
@@ -355,9 +368,9 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
||||
int16_t extractModeDefaults(uint8_t mode, const char *segVar)
|
||||
{
|
||||
if (mode < strip.getModeCount()) {
|
||||
char lineBuffer[128] = "";
|
||||
strncpy_P(lineBuffer, strip.getModeData(mode), 127);
|
||||
lineBuffer[127] = '\0'; // terminate string
|
||||
char lineBuffer[256];
|
||||
strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
|
||||
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
|
||||
if (lineBuffer[0] != 0) {
|
||||
char* startPtr = strrchr(lineBuffer, ';'); // last ";" in FX data
|
||||
if (!startPtr) return -1;
|
||||
@@ -373,6 +386,16 @@ int16_t extractModeDefaults(uint8_t mode, const char *segVar)
|
||||
}
|
||||
|
||||
|
||||
void checkSettingsPIN(const char* pin) {
|
||||
if (!pin) return;
|
||||
if (!correctPIN && millis() - lastEditTime < PIN_RETRY_COOLDOWN) return; // guard against PIN brute force
|
||||
bool correctBefore = correctPIN;
|
||||
correctPIN = (strlen(settingsPIN) == 0 || strncmp(settingsPIN, pin, 4) == 0);
|
||||
if (correctBefore != correctPIN) createEditHandler(correctPIN);
|
||||
lastEditTime = millis();
|
||||
}
|
||||
|
||||
|
||||
uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||
uint8_t x;
|
||||
uint16_t crc = 0xFFFF;
|
||||
@@ -493,11 +516,11 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
}
|
||||
|
||||
samplePeak = random8() > 250;
|
||||
FFT_MajorPeak = volumeSmth;
|
||||
maxVol = 10; // this gets feedback fro UI
|
||||
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
|
||||
maxVol = 31; // this gets feedback fro UI
|
||||
binNum = 8; // this gets feedback fro UI
|
||||
volumeRaw = volumeSmth;
|
||||
my_magnitude = 10000.0 / 8.0f; //no idea if 10000 is a good value for FFT_Magnitude ???
|
||||
my_magnitude = 10000.0f / 8.0f; //no idea if 10000 is a good value for FFT_Magnitude ???
|
||||
if (volumeSmth < 1 ) my_magnitude = 0.001f; // noise gate closed - mute
|
||||
|
||||
return um_data;
|
||||
@@ -549,4 +572,4 @@ void enumerateLedmaps() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
105
wled00/wled.cpp
105
wled00/wled.cpp
@@ -23,7 +23,7 @@ void WLED::reset()
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
ws.closeAll(1012);
|
||||
#endif
|
||||
long dly = millis();
|
||||
unsigned long dly = millis();
|
||||
while (millis() - dly < 450) {
|
||||
yield(); // enough time to send response to client
|
||||
}
|
||||
@@ -35,10 +35,18 @@ void WLED::reset()
|
||||
void WLED::loop()
|
||||
{
|
||||
#ifdef WLED_DEBUG
|
||||
static unsigned long lastRun = 0;
|
||||
unsigned long loopMillis = millis();
|
||||
size_t loopDelay = loopMillis - lastRun;
|
||||
if (lastRun == 0) loopDelay=0; // startup - don't have valid data from last run.
|
||||
if (loopDelay > 2) DEBUG_PRINTF("Loop delayed more than %ums.\n", loopDelay);
|
||||
static unsigned long maxLoopMillis = 0;
|
||||
static size_t avgLoopMillis = 0;
|
||||
static unsigned long maxUsermodMillis = 0;
|
||||
static uint16_t avgUsermodMillis = 0;
|
||||
static size_t avgUsermodMillis = 0;
|
||||
static unsigned long maxStripMillis = 0;
|
||||
static uint16_t avgStripMillis = 0;
|
||||
static size_t avgStripMillis = 0;
|
||||
unsigned long stripMillis;
|
||||
#endif
|
||||
|
||||
handleTime();
|
||||
@@ -46,7 +54,11 @@ void WLED::loop()
|
||||
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
||||
#endif
|
||||
handleConnection();
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
handleRemote();
|
||||
#endif
|
||||
handleSerial();
|
||||
handleImprovWifiScan();
|
||||
handleNotifications();
|
||||
handleTransitions();
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
@@ -73,18 +85,14 @@ void WLED::loop()
|
||||
handleAlexa();
|
||||
#endif
|
||||
|
||||
yield();
|
||||
|
||||
if (doSerializeConfig) serializeConfig();
|
||||
|
||||
if (doReboot && !doInitBusses) // if busses have to be inited & saved, wait until next iteration
|
||||
reset();
|
||||
|
||||
if (doCloseFile) {
|
||||
closeFile();
|
||||
yield();
|
||||
}
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
stripMillis = millis();
|
||||
#endif
|
||||
if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly)) // block stuff if WARLS/Adalight is enabled
|
||||
{
|
||||
if (apActive) dnsServer.processNextRequest();
|
||||
@@ -103,22 +111,18 @@ void WLED::loop()
|
||||
handlePresets();
|
||||
yield();
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
unsigned long stripMillis = millis();
|
||||
#endif
|
||||
if (!offMode || strip.isOffRefreshRequired())
|
||||
strip.service();
|
||||
#ifdef ESP8266
|
||||
else if (!noWifiSleep)
|
||||
delay(1); //required to make sure ESP enters modem sleep (see #1184)
|
||||
#endif
|
||||
#ifdef WLED_DEBUG
|
||||
stripMillis = millis() - stripMillis;
|
||||
if (stripMillis > 50) DEBUG_PRINTLN("Slow strip.");
|
||||
avgStripMillis += stripMillis;
|
||||
if (stripMillis > maxStripMillis) maxStripMillis = stripMillis;
|
||||
#endif
|
||||
}
|
||||
#ifdef WLED_DEBUG
|
||||
stripMillis = millis() - stripMillis;
|
||||
avgStripMillis += stripMillis;
|
||||
if (stripMillis > maxStripMillis) maxStripMillis = stripMillis;
|
||||
#endif
|
||||
|
||||
yield();
|
||||
#ifdef ESP8266
|
||||
@@ -145,7 +149,7 @@ void WLED::loop()
|
||||
}
|
||||
|
||||
// 15min PIN time-out
|
||||
if (strlen(settingsPIN)>0 && millis() - lastEditTime > 900000) {
|
||||
if (strlen(settingsPIN)>0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) {
|
||||
correctPIN = false;
|
||||
createEditHandler(false);
|
||||
}
|
||||
@@ -157,11 +161,16 @@ void WLED::loop()
|
||||
DEBUG_PRINTLN(F("Re-init busses."));
|
||||
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
uint32_t mem = 0, globalBufMem = 0;
|
||||
uint16_t maxlen = 0;
|
||||
for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
if (busConfigs[i] == nullptr) break;
|
||||
mem += BusManager::memUsage(*busConfigs[i]);
|
||||
if (mem <= MAX_LED_MEMORY) {
|
||||
if (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) {
|
||||
maxlen = busConfigs[i]->start + busConfigs[i]->count;
|
||||
globalBufMem = maxlen * 4;
|
||||
}
|
||||
if (mem + globalBufMem <= MAX_LED_MEMORY) {
|
||||
busses.add(*busConfigs[i]);
|
||||
}
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
@@ -169,20 +178,47 @@ void WLED::loop()
|
||||
strip.finalizeInit(); // also loads default ledmap if present
|
||||
if (aligned) strip.makeAutoSegments();
|
||||
else strip.fixInvalidSegments();
|
||||
yield();
|
||||
serializeConfig();
|
||||
doSerializeConfig = true;
|
||||
}
|
||||
if (loadLedmap >= 0) {
|
||||
if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix();
|
||||
loadLedmap = -1;
|
||||
}
|
||||
yield();
|
||||
if (doSerializeConfig) serializeConfig();
|
||||
|
||||
yield();
|
||||
handleWs();
|
||||
handleStatusLED();
|
||||
|
||||
toki.resetTick();
|
||||
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
// we finished our mainloop, reset the watchdog timer
|
||||
static unsigned long lastWDTFeed = 0;
|
||||
if (!strip.isUpdating() || millis() - lastWDTFeed > (WLED_WATCHDOG_TIMEOUT*500)) {
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
esp_task_wdt_reset();
|
||||
#else
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
lastWDTFeed = millis();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration
|
||||
reset();
|
||||
|
||||
// DEBUG serial logging (every 30s)
|
||||
#ifdef WLED_DEBUG
|
||||
loopMillis = millis() - loopMillis;
|
||||
if (loopMillis > 30) {
|
||||
DEBUG_PRINTF("Loop took %lums.\n", loopMillis);
|
||||
DEBUG_PRINTF("Usermods took %lums.\n", usermodMillis);
|
||||
DEBUG_PRINTF("Strip took %lums.\n", stripMillis);
|
||||
}
|
||||
avgLoopMillis += loopMillis;
|
||||
if (loopMillis > maxLoopMillis) maxLoopMillis = loopMillis;
|
||||
if (millis() - debugTime > 29999) {
|
||||
DEBUG_PRINTLN(F("---DEBUG INFO---"));
|
||||
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
|
||||
@@ -205,11 +241,13 @@ void WLED::loop()
|
||||
DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP());
|
||||
if (loops > 0) { // avoid division by zero
|
||||
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 30);
|
||||
DEBUG_PRINT(F("Loop time[ms]: ")); DEBUG_PRINT(avgLoopMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxLoopMillis);
|
||||
DEBUG_PRINT(F("UM time[ms]: ")); DEBUG_PRINT(avgUsermodMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxUsermodMillis);
|
||||
DEBUG_PRINT(F("Strip time[ms]: ")); DEBUG_PRINT(avgStripMillis/loops); DEBUG_PRINT("/"); DEBUG_PRINTLN(maxStripMillis);
|
||||
}
|
||||
strip.printSize();
|
||||
loops = 0;
|
||||
maxLoopMillis = 0;
|
||||
maxUsermodMillis = 0;
|
||||
maxStripMillis = 0;
|
||||
avgUsermodMillis = 0;
|
||||
@@ -217,18 +255,8 @@ void WLED::loop()
|
||||
debugTime = millis();
|
||||
}
|
||||
loops++;
|
||||
lastRun = millis();
|
||||
#endif // WLED_DEBUG
|
||||
toki.resetTick();
|
||||
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
// we finished our mainloop, reset the watchdog timer
|
||||
if (!strip.isUpdating())
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
esp_task_wdt_reset();
|
||||
#else
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void WLED::enableWatchdog() {
|
||||
@@ -513,7 +541,7 @@ void WLED::initAP(bool resetAP)
|
||||
DEBUG_PRINTLN(apSSID);
|
||||
WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP(apSSID, apPass, apChannel, apHide);
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2))
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3))
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||
#endif
|
||||
|
||||
@@ -648,7 +676,6 @@ void WLED::initConnection()
|
||||
ws.onEvent(wsEvent);
|
||||
#endif
|
||||
|
||||
|
||||
WiFi.disconnect(true); // close old connections
|
||||
#ifdef ESP8266
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
@@ -692,7 +719,7 @@ void WLED::initConnection()
|
||||
|
||||
WiFi.begin(clientSSID, clientPass);
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2))
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3))
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||
#endif
|
||||
WiFi.setSleep(!noWifiSleep);
|
||||
@@ -847,7 +874,7 @@ void WLED::handleConnection()
|
||||
if (improvActive) {
|
||||
if (improvError == 3) sendImprovStateResponse(0x00, true);
|
||||
sendImprovStateResponse(0x04);
|
||||
if (improvActive > 1) sendImprovRPCResponse(0x01);
|
||||
if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi);
|
||||
}
|
||||
initInterfaces();
|
||||
userConnected();
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.14.0-b2
|
||||
@version 0.14.0-b4
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2306020
|
||||
#define VERSION 2309100
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@@ -36,7 +36,7 @@
|
||||
#undef WLED_ENABLE_ADALIGHT // disable has priority over enable
|
||||
#endif
|
||||
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
||||
//#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
|
||||
#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
|
||||
#ifndef WLED_DISABLE_LOXONE
|
||||
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||
#endif
|
||||
@@ -44,6 +44,8 @@
|
||||
#define WLED_ENABLE_WEBSOCKETS
|
||||
#endif
|
||||
|
||||
//#define WLED_DISABLE_ESPNOW // Removes dependence on esp now
|
||||
|
||||
#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing FS content. Will also be disabled with OTA lock
|
||||
|
||||
// to toggle usb serial debug (un)comment the following line
|
||||
@@ -73,6 +75,9 @@
|
||||
{
|
||||
#include <user_interface.h>
|
||||
}
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
#include <espnow.h>
|
||||
#endif
|
||||
#else // ESP32
|
||||
#include <HardwareSerial.h> // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT)
|
||||
#include <WiFi.h>
|
||||
@@ -89,6 +94,10 @@
|
||||
#include <LittleFS.h>
|
||||
#endif
|
||||
#include "esp_task_wdt.h"
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
#include <esp_now.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
@@ -322,12 +331,17 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load
|
||||
//if true, a segment per bus will be created on boot and LED settings save
|
||||
//if false, only one segment spanning the total LEDs is created,
|
||||
//but not on LED settings save if there is more than one segment currently
|
||||
WLED_GLOBAL bool autoSegments _INIT(false);
|
||||
WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color
|
||||
WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct
|
||||
WLED_GLOBAL bool gammaCorrectCol _INIT(true ); // use gamma correction on colors
|
||||
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
|
||||
WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value
|
||||
WLED_GLOBAL bool autoSegments _INIT(false);
|
||||
#ifdef ESP8266
|
||||
WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266
|
||||
#else
|
||||
WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32
|
||||
#endif
|
||||
WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color
|
||||
WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct
|
||||
WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors
|
||||
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
|
||||
WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value
|
||||
|
||||
WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color.
|
||||
WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color
|
||||
@@ -415,12 +429,18 @@ WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count numbe
|
||||
// mqtt
|
||||
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
#ifndef MQTT_MAX_TOPIC_LEN
|
||||
#define MQTT_MAX_TOPIC_LEN 32
|
||||
#endif
|
||||
#ifndef MQTT_MAX_SERVER_LEN
|
||||
#define MQTT_MAX_SERVER_LEN 32
|
||||
#endif
|
||||
WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL);
|
||||
WLED_GLOBAL bool mqttEnabled _INIT(false);
|
||||
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
|
||||
WLED_GLOBAL char mqttDeviceTopic[33] _INIT(""); // main MQTT topic (individual per device, default is wled/mac)
|
||||
WLED_GLOBAL char mqttGroupTopic[33] _INIT("wled/all"); // second MQTT topic (for example to group devices)
|
||||
WLED_GLOBAL char mqttServer[33] _INIT(""); // both domains and IPs should work (no SSL)
|
||||
WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac)
|
||||
WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices)
|
||||
WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL)
|
||||
WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth
|
||||
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
|
||||
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
|
||||
@@ -444,6 +464,12 @@ WLED_GLOBAL bool hueApplyColor _INIT(true);
|
||||
|
||||
WLED_GLOBAL uint16_t serialBaud _INIT(1152); // serial baud rate, multiply by 100
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
WLED_GLOBAL bool enable_espnow_remote _INIT(false);
|
||||
WLED_GLOBAL char linked_remote[13] _INIT("");
|
||||
WLED_GLOBAL char last_signal_src[13] _INIT("");
|
||||
#endif
|
||||
|
||||
// Time CONFIG
|
||||
WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros
|
||||
WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format
|
||||
@@ -493,7 +519,7 @@ WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use i
|
||||
// wifi
|
||||
WLED_GLOBAL bool apActive _INIT(false);
|
||||
WLED_GLOBAL bool forceReconnect _INIT(false);
|
||||
WLED_GLOBAL uint32_t lastReconnectAttempt _INIT(0);
|
||||
WLED_GLOBAL unsigned long lastReconnectAttempt _INIT(0);
|
||||
WLED_GLOBAL bool interfacesInited _INIT(false);
|
||||
WLED_GLOBAL bool wasConnected _INIT(false);
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,387 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Dependencies">
|
||||
<UniqueIdentifier>{72fe60da-ba26-45b4-82c1-bdff809975da}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Dependencies">
|
||||
<UniqueIdentifier>{8880888d-efea-4189-a25a-834b7b3bb756}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="wled00.ino" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="__vm\.wled00.vsarduino.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="html_classic.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="html_mobile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="html_other.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="html_settings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FX.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\json\ArduinoJson-v6.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\json\AsyncJson-v6.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApi.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApiArduino.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkArduinoClient.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkConfig.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDateTime.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDebug.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDetectDevice.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkEveryN.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkFifo.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkHandlers.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkParam.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocol.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocolDefs.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\BlynkSimpleEsp.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTemplates.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTimer.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkUtility.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWidgetBase.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWiFiCommon.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Callbacks.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\DisconnectReasons.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\espalexa\Espalexa.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\espalexa\EspalexaDevice.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\e131\ESPAsyncE131.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Flags.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Helpers.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\MessageProperties.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NpbWrapper.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\Packet.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\ParsingInformation.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Storage.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\time\Time.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\time\TimeLib.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\timezone\Timezone.h">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.hpp">
|
||||
<Filter>Header Files\Dependencies</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="alexa.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="blynk.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="button.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="colors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="const.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cronixie.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dmx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="file.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="html_ui.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ir.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="json.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="led.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mqtt.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="notify.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ntp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="overlay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="set.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="usermod.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="wled.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="wled_eeprom.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="wled_server.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="xml.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ir_codes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="palettes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="FX.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FX_fcn.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\blynk\Blynk\utility.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkDebug.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkHandlers.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkTimer.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\time\DateStrings.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\espalexa\EspalexaDevice.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\e131\ESPAsyncE131.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\time\Time.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\timezone\Timezone.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.cpp">
|
||||
<Filter>Source Files\Dependencies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="alexa.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="blynk.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="button.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="colors.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cronixie.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="file.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hue.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ir.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="json.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="led.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mqtt.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="notify.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ntp.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="overlay.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="set.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="usermod.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wled.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wled_eeprom.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wled_server.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="xml.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
@@ -41,7 +41,7 @@ float sin_t(float x) {
|
||||
|
||||
float tan_t(float x) {
|
||||
float c = cos_t(x);
|
||||
if (c==0.0) return 0;
|
||||
if (c==0.0f) return 0;
|
||||
float res = sin_t(x) / c;
|
||||
#ifdef WLED_DEBUG_MATH
|
||||
Serial.printf("tan: %f,%f,%f,(%f)\n",x,res,tan(x),res-tan(x));
|
||||
@@ -54,14 +54,14 @@ float tan_t(float x) {
|
||||
float acos_t(float x) {
|
||||
float negate = float(x < 0);
|
||||
float xabs = std::abs(x);
|
||||
float ret = -0.0187293;
|
||||
float ret = -0.0187293f;
|
||||
ret = ret * xabs;
|
||||
ret = ret + 0.0742610;
|
||||
ret = ret + 0.0742610f;
|
||||
ret = ret * xabs;
|
||||
ret = ret - 0.2121144;
|
||||
ret = ret - 0.2121144f;
|
||||
ret = ret * xabs;
|
||||
ret = ret + HALF_PI;
|
||||
ret = ret * sqrt(1.0-xabs);
|
||||
ret = ret * sqrt(1.0f-xabs);
|
||||
ret = ret - 2 * negate * ret;
|
||||
float res = negate * PI + ret;
|
||||
#ifdef WLED_DEBUG_MATH
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#ifdef WLED_ENABLE_PIXART
|
||||
#include "html_pixart.h"
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_PXMAGIC
|
||||
#include "html_pxmagic.h"
|
||||
#endif
|
||||
#include "html_cpal.h"
|
||||
|
||||
/*
|
||||
@@ -113,14 +116,6 @@ void initServer()
|
||||
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*");
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveviewws, PAGE_liveviewws_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
//request->send_P(200, "text/html", PAGE_liveviewws);
|
||||
});
|
||||
#ifndef WLED_DISABLE_2D
|
||||
server.on("/liveview2D", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
@@ -128,19 +123,16 @@ void initServer()
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
//request->send_P(200, "text/html", PAGE_liveviewws);
|
||||
});
|
||||
#endif
|
||||
#else
|
||||
#endif
|
||||
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveview, PAGE_liveview_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
//request->send_P(200, "text/html", PAGE_liveview);
|
||||
});
|
||||
#endif
|
||||
|
||||
//settings page
|
||||
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
@@ -164,10 +156,6 @@ void initServer()
|
||||
}
|
||||
});
|
||||
|
||||
server.on("/sliders", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveIndex(request);
|
||||
});
|
||||
|
||||
server.on("/welcome", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveSettings(request);
|
||||
});
|
||||
@@ -195,9 +183,11 @@ void initServer()
|
||||
JsonObject root = doc.as<JsonObject>();
|
||||
if (error || root.isNull()) {
|
||||
releaseJSONBufferLock();
|
||||
request->send(400, "application/json", F("{\"error\":9}"));
|
||||
request->send(400, "application/json", F("{\"error\":9}")); // ERR_JSON
|
||||
return;
|
||||
}
|
||||
if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as<const char*>());
|
||||
|
||||
const String& url = request->url();
|
||||
isConfig = url.indexOf("cfg") > -1;
|
||||
if (!isConfig) {
|
||||
@@ -210,6 +200,11 @@ void initServer()
|
||||
*/
|
||||
verboseResponse = deserializeState(root);
|
||||
} else {
|
||||
if (!correctPIN && strlen(settingsPIN)>0) {
|
||||
request->send(403, "application/json", F("{\"error\":1}")); // ERR_DENIED
|
||||
releaseJSONBufferLock();
|
||||
return;
|
||||
}
|
||||
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
@@ -237,19 +232,15 @@ void initServer()
|
||||
request->send(200, "text/plain", (String)ESP.getFreeHeap());
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_USERMOD_PAGE
|
||||
server.on("/u", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_usermod, PAGE_usermod_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
//request->send_P(200, "text/html", PAGE_usermod);
|
||||
});
|
||||
|
||||
//Deprecated, use of /json/state and presets recommended instead
|
||||
server.on("/url", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
URL_response(request);
|
||||
});
|
||||
#endif
|
||||
|
||||
server.on("/teapot", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 418, F("418. I'm a teapot."), F("(Tangible Embedded Advanced Project Of Twinkling)"), 254);
|
||||
@@ -346,9 +337,14 @@ void initServer()
|
||||
serveMessage(request, 501, "Not implemented", F("DMX support is not enabled in this build."), 254);
|
||||
});
|
||||
#endif
|
||||
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (captivePortal(request)) return;
|
||||
serveIndexOrWelcome(request);
|
||||
if (!showWelcomePage || request->hasArg(F("sliders"))){
|
||||
serveIndex(request);
|
||||
} else {
|
||||
serveSettings(request);
|
||||
}
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_PIXART
|
||||
@@ -362,6 +358,17 @@ void initServer()
|
||||
});
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_PXMAGIC
|
||||
server.on("/pxmagic.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleFileRead(request, "/pxmagic.htm")) return;
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_pxmagic, PAGE_pxmagic_L);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
});
|
||||
#endif
|
||||
|
||||
server.on("/cpal.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleFileRead(request, "/cpal.htm")) return;
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
@@ -399,20 +406,9 @@ void initServer()
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
//request->send_P(404, "text/html", PAGE_404);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void serveIndexOrWelcome(AsyncWebServerRequest *request)
|
||||
{
|
||||
if (!showWelcomePage){
|
||||
serveIndex(request);
|
||||
} else {
|
||||
serveSettings(request);
|
||||
}
|
||||
}
|
||||
|
||||
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
|
||||
{
|
||||
AsyncWebHeader* header = request->getHeader("If-None-Match");
|
||||
@@ -554,64 +550,62 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
|
||||
if (url.indexOf("sett") >= 0)
|
||||
{
|
||||
if (url.indexOf(".js") > 0) subPage = 254;
|
||||
else if (url.indexOf(".css") > 0) subPage = 253;
|
||||
else if (url.indexOf("wifi") > 0) subPage = 1;
|
||||
else if (url.indexOf("leds") > 0) subPage = 2;
|
||||
else if (url.indexOf("ui") > 0) subPage = 3;
|
||||
else if (url.indexOf("sync") > 0) subPage = 4;
|
||||
else if (url.indexOf("time") > 0) subPage = 5;
|
||||
else if (url.indexOf("sec") > 0) subPage = 6;
|
||||
else if (url.indexOf("dmx") > 0) subPage = 7;
|
||||
else if (url.indexOf("um") > 0) subPage = 8;
|
||||
else if (url.indexOf("2D") > 0) subPage = 10;
|
||||
else if (url.indexOf("lock") > 0) subPage = 251;
|
||||
if (url.indexOf(".js") > 0) subPage = SUBPAGE_JS;
|
||||
else if (url.indexOf(".css") > 0) subPage = SUBPAGE_CSS;
|
||||
else if (url.indexOf("wifi") > 0) subPage = SUBPAGE_WIFI;
|
||||
else if (url.indexOf("leds") > 0) subPage = SUBPAGE_LEDS;
|
||||
else if (url.indexOf("ui") > 0) subPage = SUBPAGE_UI;
|
||||
else if (url.indexOf("sync") > 0) subPage = SUBPAGE_SYNC;
|
||||
else if (url.indexOf("time") > 0) subPage = SUBPAGE_TIME;
|
||||
else if (url.indexOf("sec") > 0) subPage = SUBPAGE_SEC;
|
||||
else if (url.indexOf("dmx") > 0) subPage = SUBPAGE_DMX;
|
||||
else if (url.indexOf("um") > 0) subPage = SUBPAGE_UM;
|
||||
else if (url.indexOf("2D") > 0) subPage = SUBPAGE_2D;
|
||||
else if (url.indexOf("lock") > 0) subPage = SUBPAGE_LOCK;
|
||||
}
|
||||
else if (url.indexOf("/update") >= 0) subPage = 9; // update page, for PIN check
|
||||
else if (url.indexOf("/update") >= 0) subPage = SUBPAGE_UPDATE; // update page, for PIN check
|
||||
//else if (url.indexOf("/edit") >= 0) subPage = 10;
|
||||
else subPage = 255; // welcome page
|
||||
else subPage = SUBPAGE_WELCOME;
|
||||
|
||||
if (!correctPIN && strlen(settingsPIN) > 0 && (subPage > 0 && subPage < 11)) {
|
||||
originalSubPage = subPage;
|
||||
subPage = 252; // require PIN
|
||||
subPage = SUBPAGE_PINREQ; // require PIN
|
||||
}
|
||||
|
||||
// if OTA locked or too frequent PIN entry requests fail hard
|
||||
if ((subPage == 1 && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < 3000))
|
||||
if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < PIN_RETRY_COOLDOWN))
|
||||
{
|
||||
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_ota), 254); return;
|
||||
}
|
||||
|
||||
if (post) { //settings/set POST request, saving
|
||||
if (subPage != 1 || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
|
||||
if (subPage != SUBPAGE_WIFI || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
|
||||
|
||||
char s[32];
|
||||
char s2[45] = "";
|
||||
|
||||
switch (subPage) {
|
||||
case 1: strcpy_P(s, PSTR("WiFi")); strcpy_P(s2, PSTR("Please connect to the new IP (if changed)")); forceReconnect = true; break;
|
||||
case 2: strcpy_P(s, PSTR("LED")); break;
|
||||
case 3: strcpy_P(s, PSTR("UI")); break;
|
||||
case 4: strcpy_P(s, PSTR("Sync")); break;
|
||||
case 5: strcpy_P(s, PSTR("Time")); break;
|
||||
case 6: strcpy_P(s, PSTR("Security")); if (doReboot) strcpy_P(s2, PSTR("Rebooting, please wait ~10 seconds...")); break;
|
||||
case 7: strcpy_P(s, PSTR("DMX")); break;
|
||||
case 8: strcpy_P(s, PSTR("Usermods")); break;
|
||||
case 10: strcpy_P(s, PSTR("2D")); break;
|
||||
case 252: strcpy_P(s, correctPIN ? PSTR("PIN accepted") : PSTR("PIN rejected")); break;
|
||||
case SUBPAGE_WIFI : strcpy_P(s, PSTR("WiFi")); strcpy_P(s2, PSTR("Please connect to the new IP (if changed)")); forceReconnect = true; break;
|
||||
case SUBPAGE_LEDS : strcpy_P(s, PSTR("LED")); break;
|
||||
case SUBPAGE_UI : strcpy_P(s, PSTR("UI")); break;
|
||||
case SUBPAGE_SYNC : strcpy_P(s, PSTR("Sync")); break;
|
||||
case SUBPAGE_TIME : strcpy_P(s, PSTR("Time")); break;
|
||||
case SUBPAGE_SEC : strcpy_P(s, PSTR("Security")); if (doReboot) strcpy_P(s2, PSTR("Rebooting, please wait ~10 seconds...")); break;
|
||||
case SUBPAGE_DMX : strcpy_P(s, PSTR("DMX")); break;
|
||||
case SUBPAGE_UM : strcpy_P(s, PSTR("Usermods")); break;
|
||||
case SUBPAGE_2D : strcpy_P(s, PSTR("2D")); break;
|
||||
case SUBPAGE_PINREQ : strcpy_P(s, correctPIN ? PSTR("PIN accepted") : PSTR("PIN rejected")); break;
|
||||
}
|
||||
|
||||
if (subPage == 252) {
|
||||
createEditHandler(correctPIN);
|
||||
} else
|
||||
strcat_P(s, PSTR(" settings saved."));
|
||||
if (subPage != SUBPAGE_PINREQ) strcat_P(s, PSTR(" settings saved."));
|
||||
|
||||
if (subPage == 252 && correctPIN) {
|
||||
if (subPage == SUBPAGE_PINREQ && correctPIN) {
|
||||
subPage = originalSubPage; // on correct PIN load settings page the user intended
|
||||
} else {
|
||||
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
||||
|
||||
serveMessage(request, 200, s, s2, (subPage == 1 || (subPage == 6 && doReboot)) ? 129 : (correctPIN ? 1 : 3));
|
||||
bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot));
|
||||
serveMessage(request, 200, s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -619,30 +613,30 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
AsyncWebServerResponse *response;
|
||||
switch (subPage)
|
||||
{
|
||||
case 1: response = request->beginResponse_P(200, "text/html", PAGE_settings_wifi, PAGE_settings_wifi_length); break;
|
||||
case 2: response = request->beginResponse_P(200, "text/html", PAGE_settings_leds, PAGE_settings_leds_length); break;
|
||||
case 3: response = request->beginResponse_P(200, "text/html", PAGE_settings_ui, PAGE_settings_ui_length); break;
|
||||
case 4: response = request->beginResponse_P(200, "text/html", PAGE_settings_sync, PAGE_settings_sync_length); break;
|
||||
case 5: response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break;
|
||||
case 6: response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
|
||||
case SUBPAGE_WIFI : response = request->beginResponse_P(200, "text/html", PAGE_settings_wifi, PAGE_settings_wifi_length); break;
|
||||
case SUBPAGE_LEDS : response = request->beginResponse_P(200, "text/html", PAGE_settings_leds, PAGE_settings_leds_length); break;
|
||||
case SUBPAGE_UI : response = request->beginResponse_P(200, "text/html", PAGE_settings_ui, PAGE_settings_ui_length); break;
|
||||
case SUBPAGE_SYNC : response = request->beginResponse_P(200, "text/html", PAGE_settings_sync, PAGE_settings_sync_length); break;
|
||||
case SUBPAGE_TIME : response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break;
|
||||
case SUBPAGE_SEC : response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
case 7: response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
|
||||
case SUBPAGE_DMX : response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
|
||||
#endif
|
||||
case 8: response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
|
||||
case 9: response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
|
||||
case SUBPAGE_UM : response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
|
||||
case SUBPAGE_UPDATE : response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
case 10: response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
|
||||
case SUBPAGE_2D : response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
|
||||
#endif
|
||||
case 251: {
|
||||
case SUBPAGE_LOCK : {
|
||||
correctPIN = !strlen(settingsPIN); // lock if a pin is set
|
||||
createEditHandler(correctPIN);
|
||||
serveMessage(request, 200, strlen(settingsPIN) > 0 ? PSTR("Settings locked") : PSTR("No PIN set"), FPSTR(s_redirecting), 1);
|
||||
return;
|
||||
}
|
||||
case 252: response = request->beginResponse_P(200, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
|
||||
case 253: response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length); break;
|
||||
case 254: serveSettingsJS(request); return;
|
||||
case 255: response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
|
||||
case SUBPAGE_PINREQ : response = request->beginResponse_P(200, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
|
||||
case SUBPAGE_CSS : response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length); break;
|
||||
case SUBPAGE_JS : serveSettingsJS(request); return;
|
||||
case SUBPAGE_WELCOME : response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
|
||||
default: response = request->beginResponse_P(200, "text/html", PAGE_settings, PAGE_settings_length); break;
|
||||
}
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
|
||||
@@ -54,14 +54,15 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
}
|
||||
releaseJSONBufferLock(); // will clean fileDoc
|
||||
|
||||
// force broadcast in 500ms after updating client
|
||||
if (verboseResponse) {
|
||||
sendDataWs(client);
|
||||
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
|
||||
} else {
|
||||
// we have to send something back otherwise WS connection closes
|
||||
client->text(F("{\"success\":true}"));
|
||||
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
|
||||
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
|
||||
if (verboseResponse) {
|
||||
sendDataWs(client);
|
||||
} else {
|
||||
// we have to send something back otherwise WS connection closes
|
||||
client->text(F("{\"success\":true}"));
|
||||
}
|
||||
// force broadcast in 500ms after updating client
|
||||
//lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500); // ESP8266 does not like this
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -78,7 +79,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
if((info->index + len) == info->len){
|
||||
if(info->final){
|
||||
if(info->message_opcode == WS_TEXT) {
|
||||
client->text(F("{\"error\":9}")); //we do not handle split packets right now
|
||||
client->text(F("{\"error\":9}")); // ERR_JSON we do not handle split packets right now
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,23 +166,24 @@ bool sendLiveLedsWs(uint32_t wsClient)
|
||||
size_t n = ((used -1)/MAX_LIVE_LEDS_WS) +1; //only serve every n'th LED if count over MAX_LIVE_LEDS_WS
|
||||
size_t pos = (strip.isMatrix ? 4 : 2); // start of data
|
||||
size_t bufSize = pos + (used/n)*3;
|
||||
size_t skipLines = 0;
|
||||
|
||||
AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize);
|
||||
if (!wsBuf) return false; //out of memory
|
||||
uint8_t* buffer = wsBuf->get();
|
||||
buffer[0] = 'L';
|
||||
buffer[1] = 1; //version
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
size_t skipLines = 0;
|
||||
if (strip.isMatrix) {
|
||||
buffer[1] = 2; //version
|
||||
buffer[2] = Segment::maxWidth;
|
||||
buffer[3] = Segment::maxHeight;
|
||||
if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS*4) {
|
||||
if (used > MAX_LIVE_LEDS_WS*4) {
|
||||
buffer[2] = Segment::maxWidth/4;
|
||||
buffer[3] = Segment::maxHeight/4;
|
||||
skipLines = 3;
|
||||
} else if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS) {
|
||||
} else if (used > MAX_LIVE_LEDS_WS) {
|
||||
buffer[2] = Segment::maxWidth/2;
|
||||
buffer[3] = Segment::maxHeight/2;
|
||||
skipLines = 1;
|
||||
@@ -197,9 +199,13 @@ bool sendLiveLedsWs(uint32_t wsClient)
|
||||
}
|
||||
#endif
|
||||
uint32_t c = strip.getPixelColor(i);
|
||||
buffer[pos++] = qadd8(W(c), R(c)); //R, add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
buffer[pos++] = qadd8(W(c), G(c)); //G
|
||||
buffer[pos++] = qadd8(W(c), B(c)); //B
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
uint8_t w = W(c);
|
||||
buffer[pos++] = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
buffer[pos++] = scale8(qadd8(w, g), strip.getBrightness()); //G
|
||||
buffer[pos++] = scale8(qadd8(w, b), strip.getBrightness()); //B
|
||||
}
|
||||
|
||||
wsc->binary(wsBuf);
|
||||
|
||||
104
wled00/xml.cpp
104
wled00/xml.cpp
@@ -72,55 +72,6 @@ void XML_response(AsyncWebServerRequest *request, char* dest)
|
||||
if (request != nullptr) request->send(200, "text/xml", obuf);
|
||||
}
|
||||
|
||||
//Deprecated, use of /json/state and presets recommended instead
|
||||
void URL_response(AsyncWebServerRequest *request)
|
||||
{
|
||||
char sbuf[256];
|
||||
char s2buf[100];
|
||||
obuf = s2buf;
|
||||
olen = 0;
|
||||
|
||||
char s[16];
|
||||
oappend(SET_F("http://"));
|
||||
IPAddress localIP = Network.localIP();
|
||||
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
oappend(s);
|
||||
|
||||
oappend(SET_F("/win&A="));
|
||||
oappendi(bri);
|
||||
oappend(SET_F("&CL=h"));
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
sprintf(s,"%02X", col[i]);
|
||||
oappend(s);
|
||||
}
|
||||
oappend(SET_F("&C2=h"));
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
sprintf(s,"%02X", colSec[i]);
|
||||
oappend(s);
|
||||
}
|
||||
oappend(SET_F("&FX="));
|
||||
oappendi(effectCurrent);
|
||||
oappend(SET_F("&SX="));
|
||||
oappendi(effectSpeed);
|
||||
oappend(SET_F("&IX="));
|
||||
oappendi(effectIntensity);
|
||||
oappend(SET_F("&FP="));
|
||||
oappendi(effectPalette);
|
||||
|
||||
obuf = sbuf;
|
||||
olen = 0;
|
||||
|
||||
oappend(SET_F("<html><body><a href=\""));
|
||||
oappend(s2buf);
|
||||
oappend(SET_F("\" target=\"_blank\">"));
|
||||
oappend(s2buf);
|
||||
oappend(SET_F("</a></body></html>"));
|
||||
|
||||
if (request != nullptr) request->send(200, "text/html", obuf);
|
||||
}
|
||||
|
||||
void extractPin(JsonObject &obj, const char *key) {
|
||||
if (obj[key].is<JsonArray>()) {
|
||||
JsonArray pins = obj[key].as<JsonArray>();
|
||||
@@ -197,7 +148,7 @@ void appendGPIOinfo() {
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17"));
|
||||
#elif defined(ESP32)
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31"));
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31,37,38"));
|
||||
#else
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11"));
|
||||
#endif
|
||||
@@ -285,7 +236,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
if (subPage <0 || subPage >10) return;
|
||||
|
||||
if (subPage == 0)
|
||||
if (subPage == SUBPAGE_MENU)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D // include only if 2D is compiled in
|
||||
oappend(PSTR("gId('2dbtn').style.display='';"));
|
||||
@@ -295,7 +246,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (subPage == 1)
|
||||
if (subPage == SUBPAGE_WIFI)
|
||||
{
|
||||
sappends('s',SET_F("CS"),clientSSID);
|
||||
|
||||
@@ -328,6 +279,14 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("AC"),apChannel);
|
||||
sappend('c',SET_F("WS"),noWifiSleep);
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
sappend('c',SET_F("RE"),enable_espnow_remote);
|
||||
sappends('s',SET_F("RMAC"),linked_remote);
|
||||
#else
|
||||
//hide remote settings if not compiled
|
||||
oappend(SET_F("document.getElementById('remd').style.display='none';"));
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
sappend('v',SET_F("ETH"),ethernetType);
|
||||
#else
|
||||
@@ -360,9 +319,22 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
{
|
||||
sappends('m',SET_F("(\"sip\")[1]"),(char*)F("Not active"));
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
if (last_signal_src[0] != 0) //Have seen an ESP-NOW Remote
|
||||
{
|
||||
sappends('m',SET_F("(\"rlid\")[0]"),last_signal_src);
|
||||
} else if (!enable_espnow_remote)
|
||||
{
|
||||
sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("(Enable remote to listen)"));
|
||||
} else
|
||||
{
|
||||
sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("None"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (subPage == 2)
|
||||
if (subPage == SUBPAGE_LEDS)
|
||||
{
|
||||
char nS[32];
|
||||
|
||||
@@ -383,7 +355,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("CB"),strip.cctBlending);
|
||||
sappend('v',SET_F("FR"),strip.getTargetFps());
|
||||
sappend('v',SET_F("AW"),Bus::getGlobalAWMode());
|
||||
sappend('c',SET_F("LD"),strip.useLedsArray);
|
||||
sappend('c',SET_F("LD"),useGlobalLedBuffer);
|
||||
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
Bus* bus = busses.getBus(s);
|
||||
@@ -410,7 +382,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',lt,bus->getType());
|
||||
sappend('v',co,bus->getColorOrder() & 0x0F);
|
||||
sappend('v',ls,bus->getStart());
|
||||
sappend('c',cv,bus->reversed);
|
||||
sappend('c',cv,bus->isReversed());
|
||||
sappend('v',sl,bus->skippedLeds());
|
||||
sappend('c',rf,bus->isOffRefreshRequired());
|
||||
sappend('v',aw,bus->getAutoWhiteMode());
|
||||
@@ -493,7 +465,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("MSO"),!irApplyToAllSelected);
|
||||
}
|
||||
|
||||
if (subPage == 3)
|
||||
if (subPage == SUBPAGE_UI)
|
||||
{
|
||||
sappends('s',SET_F("DS"),serverDescription);
|
||||
sappend('c',SET_F("ST"),syncToggleReceive);
|
||||
@@ -504,8 +476,9 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (subPage == 4)
|
||||
if (subPage == SUBPAGE_SYNC)
|
||||
{
|
||||
char nS[32];
|
||||
sappend('v',SET_F("UP"),udpPort);
|
||||
sappend('v',SET_F("U2"),udpPort2);
|
||||
sappend('v',SET_F("GS"),syncGroups);
|
||||
@@ -562,6 +535,9 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappends('s',SET_F("MG"),mqttGroupTopic);
|
||||
sappend('c',SET_F("BM"),buttonPublishMqtt);
|
||||
sappend('c',SET_F("RT"),retainMqttMsg);
|
||||
oappend(SET_F("d.Sf.MD.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";"));
|
||||
oappend(SET_F("d.Sf.MG.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";"));
|
||||
oappend(SET_F("d.Sf.MS.maxlength=")); oappend(itoa(MQTT_MAX_SERVER_LEN,nS,10)); oappend(SET_F(";"));
|
||||
#else
|
||||
oappend(SET_F("toggle('MQTT');")); // hide MQTT settings
|
||||
#endif
|
||||
@@ -597,7 +573,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("BD"),serialBaud);
|
||||
}
|
||||
|
||||
if (subPage == 5)
|
||||
if (subPage == SUBPAGE_TIME)
|
||||
{
|
||||
sappend('c',SET_F("NT"),ntpEnabled);
|
||||
sappends('s',SET_F("NS"),ntpServerName);
|
||||
@@ -611,7 +587,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappends('s',SET_F("LT"),tm);
|
||||
getTimeString(tm);
|
||||
sappends('m',SET_F("(\"times\")[0]"),tm);
|
||||
if ((int)(longitude*10.) || (int)(latitude*10.)) {
|
||||
if ((int)(longitude*10.0f) || (int)(latitude*10.0f)) {
|
||||
sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset));
|
||||
sappends('m',SET_F("(\"times\")[1]"),tm);
|
||||
}
|
||||
@@ -661,7 +637,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
}
|
||||
|
||||
if (subPage == 6)
|
||||
if (subPage == SUBPAGE_SEC)
|
||||
{
|
||||
byte l = strlen(settingsPIN);
|
||||
char fpass[l+1]; //fill PIN field with 0000
|
||||
@@ -683,7 +659,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
if (subPage == 7)
|
||||
if (subPage == SUBPAGE_DMX)
|
||||
{
|
||||
sappend('v',SET_F("PU"),e131ProxyUniverse);
|
||||
|
||||
@@ -710,7 +686,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (subPage == 8) //usermods
|
||||
if (subPage == SUBPAGE_UM) //usermods
|
||||
{
|
||||
appendGPIOinfo();
|
||||
oappend(SET_F("numM="));
|
||||
@@ -729,7 +705,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
usermods.appendConfigData();
|
||||
}
|
||||
|
||||
if (subPage == 9) // update
|
||||
if (subPage == SUBPAGE_UPDATE) // update
|
||||
{
|
||||
sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED "));
|
||||
olen -= 2; //delete ";
|
||||
@@ -745,7 +721,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
oappend(SET_F(")\";"));
|
||||
}
|
||||
|
||||
if (subPage == 10) // 2D matrices
|
||||
if (subPage == SUBPAGE_2D) // 2D matrices
|
||||
{
|
||||
sappend('v',SET_F("SOMP"),strip.isMatrix);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
|
||||
Reference in New Issue
Block a user