mirror of
https://github.com/wled/WLED.git
synced 2026-07-02 18:14:42 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 59025e317e |
+1
-56
@@ -1,62 +1,7 @@
|
||||
## WLED changelog
|
||||
|
||||
#### 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)
|
||||
|
||||
Generated
+4
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.14.0-b4",
|
||||
"version": "0.14.0-b2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1409,9 +1409,9 @@
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||
},
|
||||
"semver-diff": {
|
||||
"version": "2.1.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.14.0-b4",
|
||||
"version": "0.14.0-b2",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
||||
+28
-36
@@ -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, esp32s3dev_8MB_PSRAM_opi
|
||||
;; 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
|
||||
|
||||
# Release binaries
|
||||
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
|
||||
@@ -40,8 +40,6 @@ 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
|
||||
@@ -62,14 +60,13 @@ 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_3_1_2}
|
||||
platform_wled_default = ${common.arduino_core_4_1_0}
|
||||
# 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
|
||||
@@ -175,7 +172,7 @@ upload_speed = 115200
|
||||
# ------------------------------------------------------------------------------
|
||||
lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.6.0
|
||||
fastled/FastLED @ 3.5.0
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.7.5
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7
|
||||
@@ -201,7 +198,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)
|
||||
@@ -249,8 +246,9 @@ 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.3.0
|
||||
platform = espressif32@5.2.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
|
||||
@@ -264,8 +262,9 @@ lib_deps =
|
||||
|
||||
[esp32s2]
|
||||
;; generic definitions for all ESP32-S2 boards
|
||||
platform = espressif32@5.3.0
|
||||
platform = espressif32@5.2.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
|
||||
@@ -283,8 +282,9 @@ lib_deps =
|
||||
|
||||
[esp32c3]
|
||||
;; generic definitions for all ESP32-C3 boards
|
||||
platform = espressif32@5.3.0
|
||||
platform = espressif32@5.2.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,8 +301,9 @@ lib_deps =
|
||||
|
||||
[esp32s3]
|
||||
;; generic definitions for all ESP32-S3 boards
|
||||
platform = espressif32@5.3.0
|
||||
platform = espressif32@5.2.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
|
||||
@@ -433,7 +434,6 @@ 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,7 +447,6 @@ 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}
|
||||
|
||||
@@ -458,11 +457,10 @@ 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
|
||||
-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
|
||||
; -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}
|
||||
@@ -474,10 +472,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} -D WLED_RELEASE_NAME=ESP32-S3_8MB
|
||||
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=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=0 ;; 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
|
||||
@@ -486,18 +484,19 @@ 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_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
|
||||
[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
|
||||
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=1 ;; 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=0 ;; 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}
|
||||
@@ -506,13 +505,6 @@ 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}
|
||||
@@ -580,10 +572,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=ESP32-S2
|
||||
build_unflags = ${common.build_unflags} -DARDUINO_USB_CDC_ON_BOOT=1
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ anyio==3.6.2
|
||||
# via starlette
|
||||
bottle==0.12.25
|
||||
# via platformio
|
||||
certifi==2023.7.22
|
||||
certifi==2022.12.7
|
||||
# via requests
|
||||
charset-normalizer==3.1.0
|
||||
# via requests
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# 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,5 +3,4 @@ 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,0x3E0000,
|
||||
coredump, data, coredump,,64K
|
||||
spiffs, data, spiffs, 0x410000,0x3F0000,
|
||||
|
+6
-1
@@ -222,7 +222,6 @@ 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",
|
||||
@@ -390,6 +389,12 @@ 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",
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
|
||||
const express = require("express");
|
||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||
const path = require("path");
|
||||
const nopt = require("nopt");
|
||||
const app = express();
|
||||
|
||||
var knownOpts = {
|
||||
"help": Boolean,
|
||||
"port": Number,
|
||||
"settings": [path],
|
||||
"host": String,
|
||||
"verbose": Boolean
|
||||
};
|
||||
var shortHands = {
|
||||
"?":["--help"],
|
||||
"p":["--port"],
|
||||
"s":["--settings"],
|
||||
"h":["--host"],
|
||||
"v":["--verbose"]
|
||||
};
|
||||
|
||||
nopt.invalidHandler = function(k,v,t) {
|
||||
// TODO: console.log(k,v,t);
|
||||
}
|
||||
|
||||
var parsedArgs = nopt(knownOpts,shortHands,process.argv,2);
|
||||
|
||||
if (parsedArgs.help) {
|
||||
console.log("WLED Dev Server");
|
||||
console.log("Usage: wled [-v] [-?] [--settings settings.js] [--userDir DIR]");
|
||||
console.log(" [--port PORT] [--host HOST]");
|
||||
console.log("");
|
||||
console.log("Options:");
|
||||
console.log(" -p, --port PORT port to listen on");
|
||||
console.log(" -s, --settings FILE use specified settings file");
|
||||
console.log(" --host HOST WLED instance for dynamic content");
|
||||
console.log(" -v, --verbose enable verbose output");
|
||||
console.log(" -?, --help show this help");
|
||||
console.log("");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
// WLED_HOME - the root directory where the html files are
|
||||
process.env.WLED_HOME = process.env.WLED_HOME || path.resolve(__dirname,'..','wled00','data');
|
||||
|
||||
parsedArgs.port = parsedArgs.port || 8080;
|
||||
parsedArgs.host = parsedArgs.host || "0.0.0.0";
|
||||
|
||||
// get the static file reference
|
||||
function static(page) {
|
||||
return express.static(process.env.WLED_HOME, {index: page});
|
||||
}
|
||||
|
||||
// add routes for each setting page
|
||||
function useSettingsRoutes() {
|
||||
app.use(`/settings`, static(`settings.htm`));
|
||||
|
||||
const settings = ['wifi', 'leds', 'ui', 'sync','time','um', 'sec'];
|
||||
settings.forEach(function(setting) {
|
||||
app.use(`/settings/${setting}`, static(`settings_${setting}.htm`));
|
||||
});
|
||||
}
|
||||
|
||||
// dynamic content that is proxied to real WLED instance
|
||||
function useWebProxyRoutes(host) {
|
||||
const httpProxy = createProxyMiddleware({ target: `http://${host}`, changeOrigin: true, logLevel: 'warn' });
|
||||
const proxyRoutes = ['json', 'presets.json', 'skins.css', 'liveview'];
|
||||
proxyRoutes.forEach(function(route) {
|
||||
app.use(`/${route}`, httpProxy);
|
||||
});
|
||||
}
|
||||
|
||||
// proxy data to a real WLED instance
|
||||
function useWebSocketProxy(host, server) {
|
||||
const wsProxy = createProxyMiddleware(`ws://${host}`, { changeOrigin: true, logLevel: 'warn' });
|
||||
app.use(wsProxy);
|
||||
server.on('upgrade', wsProxy.upgrade);
|
||||
}
|
||||
|
||||
// first matching route
|
||||
app.use('/', static("index.htm"));
|
||||
useSettingsRoutes(); // map the setting pages
|
||||
useWebProxyRoutes(parsedArgs.host);
|
||||
|
||||
// use static files like style sheets etc
|
||||
app.use(express.static(process.env.WLED_HOME));
|
||||
|
||||
const server = app.listen(parsedArgs.port, () => {
|
||||
if (parsedArgs.verbose) {
|
||||
console.log(`WLED UI listening at http://localhost:${parsedArgs.port}`)
|
||||
}
|
||||
});
|
||||
|
||||
useWebSocketProxy(parsedArgs.host, server);
|
||||
|
||||
var stopping = false;
|
||||
function exitWhenStopped() {
|
||||
if (!stopping) {
|
||||
stopping = true;
|
||||
server.close(function() {
|
||||
console.log('WLED UI closed');
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
process.on('uncaughtException',function(err) {
|
||||
util.log('[WLED] Uncaught Exception:');
|
||||
if (err.stack) {
|
||||
console.log(err.stack);
|
||||
} else {
|
||||
console.log(err);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('SIGINT', exitWhenStopped);
|
||||
process.on('SIGTERM', exitWhenStopped);
|
||||
process.on('SIGHUP', exitWhenStopped);
|
||||
process.on('SIGUSR2', exitWhenStopped); // for nodemon restart
|
||||
process.on('SIGBREAK', exitWhenStopped); // for windows ctrl-break
|
||||
@@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <Wire.h>
|
||||
#include <BH1750.h>
|
||||
|
||||
// the max frequency to check photoresistor, 10 seconds
|
||||
@@ -55,6 +56,15 @@ 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;
|
||||
|
||||
@@ -113,7 +123,14 @@ private:
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
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]);
|
||||
|
||||
sensorFound = lightMeter.begin();
|
||||
initDone = true;
|
||||
}
|
||||
@@ -173,9 +190,7 @@ public:
|
||||
user = root.createNestedObject(F("u"));
|
||||
|
||||
JsonArray lux_json = user.createNestedArray(F("Luminance"));
|
||||
if (!enabled) {
|
||||
lux_json.add(F("disabled"));
|
||||
} else if (!sensorFound) {
|
||||
if (!sensorFound) {
|
||||
// if no sensor
|
||||
lux_json.add(F("BH1750 "));
|
||||
lux_json.add(F("Not Found"));
|
||||
@@ -201,6 +216,9 @@ 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."));
|
||||
}
|
||||
@@ -208,6 +226,8 @@ 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())
|
||||
@@ -224,12 +244,27 @@ 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,6 +9,7 @@
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <BME280I2C.h> // BME280 sensor
|
||||
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
||||
|
||||
@@ -33,6 +34,7 @@ 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
|
||||
@@ -184,8 +186,14 @@ private:
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; }
|
||||
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; }
|
||||
|
||||
Wire.begin(ioPin[1], ioPin[0]);
|
||||
|
||||
if (!bme.begin())
|
||||
{
|
||||
sensorType = 0;
|
||||
@@ -407,6 +415,9 @@ 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."));
|
||||
}
|
||||
|
||||
@@ -416,6 +427,8 @@ 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));
|
||||
@@ -434,14 +447,27 @@ 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;
|
||||
|
||||
@@ -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
|
||||
inline void EnablePIRsensor(bool en) { enabled = en; }
|
||||
void EnablePIRsensor(bool en) { enabled = en; }
|
||||
|
||||
// Get PIR sensor enabled/disabled state
|
||||
inline bool PIRsensorEnabled() { return enabled; }
|
||||
bool PIRsensorEnabled() { return enabled; }
|
||||
|
||||
private:
|
||||
|
||||
byte prevPreset = 0;
|
||||
byte prevPlaylist = 0;
|
||||
|
||||
volatile unsigned long offTimerStart = 0; // off timer start time
|
||||
volatile bool PIRtriggered = false; // did PIR trigger?
|
||||
uint32_t offTimerStart = 0; // off timer start time
|
||||
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,7 +66,6 @@ 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
|
||||
@@ -82,33 +81,173 @@ 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
|
||||
*/
|
||||
static bool isDayTime();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* switch strip on/off
|
||||
*/
|
||||
void switchStrip(bool switchOn);
|
||||
void publishMqtt(const char* state);
|
||||
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
|
||||
}
|
||||
|
||||
// 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();
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and update PIR sensor state.
|
||||
* Initilize/reset switch off timer
|
||||
*/
|
||||
bool updatePIRsensorState();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* switch off the strip if the delay has elapsed
|
||||
*/
|
||||
bool handleOffTimer();
|
||||
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;
|
||||
}
|
||||
|
||||
public:
|
||||
//Functions called by WLED
|
||||
@@ -117,57 +256,186 @@ 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();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
void onMqttConnect(bool sessionPresent) {
|
||||
if (HomeAssistantDiscovery) {
|
||||
publishHomeAssistantAutodiscovery();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*/
|
||||
void loop();
|
||||
void loop()
|
||||
{
|
||||
// only check sensors 4x/s
|
||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||
lastLoop = millis();
|
||||
|
||||
if (!updatePIRsensorState()) {
|
||||
handleOffTimer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* onStateChanged() is used to detect WLED state change
|
||||
*/
|
||||
void onStateChange(uint8_t mode);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* provide the changeable values
|
||||
*/
|
||||
void addToConfig(JsonObject &root);
|
||||
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."));
|
||||
}
|
||||
|
||||
/**
|
||||
* provide UI information and allow extending UI options
|
||||
*/
|
||||
void appendConfigData();
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* restore the changeable values
|
||||
@@ -175,13 +443,72 @@ public:
|
||||
*
|
||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||
*/
|
||||
bool readFromConfig(JsonObject &root);
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
@@ -195,359 +522,3 @@ 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,7 +12,8 @@ class RTCUsermod : public Usermod {
|
||||
public:
|
||||
|
||||
void setup() {
|
||||
if (i2c_scl<0 || i2c_sda<0) { disabled = true; return; }
|
||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { disabled = true; return; }
|
||||
RTC.begin();
|
||||
time_t rtcTime = RTC.get();
|
||||
if (rtcTime) {
|
||||
@@ -24,8 +25,8 @@ class RTCUsermod : public Usermod {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (disabled || strip.isUpdating()) return;
|
||||
if (toki.isTick()) {
|
||||
if (strip.isUpdating()) return;
|
||||
if (!disabled && toki.isTick()) {
|
||||
time_t t = toki.second();
|
||||
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
#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
|
||||
@@ -134,14 +140,8 @@ class St7789DisplayUsermod : public Usermod {
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
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;
|
||||
}
|
||||
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; }
|
||||
|
||||
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,6 +365,9 @@ 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);
|
||||
@@ -373,13 +376,6 @@ 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,6 +13,14 @@
|
||||
|
||||
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:
|
||||
@@ -176,6 +184,7 @@ 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,7 +50,9 @@ class UsermodVL53L0XGestures : public Usermod {
|
||||
public:
|
||||
|
||||
void setup() {
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
||||
Wire.begin();
|
||||
|
||||
sensor.setTimeout(150);
|
||||
if (!sensor.init())
|
||||
|
||||
@@ -569,6 +569,16 @@ 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
|
||||
@@ -1126,7 +1136,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(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
break;
|
||||
case 3:
|
||||
DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
|
||||
@@ -1149,13 +1159,6 @@ 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:
|
||||
@@ -1654,6 +1657,8 @@ 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;
|
||||
@@ -1714,6 +1719,8 @@ 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);
|
||||
@@ -1745,8 +1752,6 @@ 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);"));
|
||||
@@ -1779,6 +1784,8 @@ 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');"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Wire.h>
|
||||
#include "wled.h"
|
||||
#include <driver/i2s.h>
|
||||
#include <driver/adc.h>
|
||||
@@ -382,12 +383,21 @@ 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
|
||||
#define ES7243_ADDR 0x13 // default address
|
||||
#endif
|
||||
#ifndef ES7243_ADDR
|
||||
Wire.beginTransmission(0x13);
|
||||
#define ES7243_ADDR 0x13 // default address
|
||||
#else
|
||||
Wire.beginTransmission(ES7243_ADDR);
|
||||
#endif
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)val);
|
||||
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
|
||||
@@ -397,6 +407,7 @@ class ES7243 : public I2SSource {
|
||||
}
|
||||
|
||||
void _es7243InitAdc() {
|
||||
_es7243I2cBegin();
|
||||
_es7243I2cWrite(0x00, 0x01);
|
||||
_es7243I2cWrite(0x06, 0x00);
|
||||
_es7243I2cWrite(0x05, 0x1B);
|
||||
@@ -411,139 +422,47 @@ public:
|
||||
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
||||
};
|
||||
|
||||
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -85,9 +85,12 @@ class MPU6050Driver : public Usermod {
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
*/
|
||||
void setup() {
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
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 I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
||||
Wire.setClock(400000U); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
||||
Fastwire::setup(400, true);
|
||||
#endif
|
||||
|
||||
@@ -5,18 +5,14 @@
|
||||
#ifndef MULTI_RELAY_MAX_RELAYS
|
||||
#define MULTI_RELAY_MAX_RELAYS 4
|
||||
#else
|
||||
#if MULTI_RELAY_MAX_RELAYS>8
|
||||
#if MULTI_RELAY_MAX_RELAYS>16
|
||||
#undef MULTI_RELAY_MAX_RELAYS
|
||||
#define MULTI_RELAY_MAX_RELAYS 8
|
||||
#warning Maximum relays set to 8
|
||||
#define MULTI_RELAY_MAX_RELAYS 16
|
||||
#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)
|
||||
@@ -24,14 +20,6 @@
|
||||
#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
|
||||
@@ -49,7 +37,7 @@ typedef struct relay_t {
|
||||
int8_t pin;
|
||||
struct { // reduces memory footprint
|
||||
bool active : 1; // is the relay waiting to be switched
|
||||
bool invert : 1; // does On mean 1 or 0
|
||||
bool mode : 1; // does On mean 1 or 0 (inverted output)
|
||||
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
|
||||
@@ -62,17 +50,23 @@ class MultiRelay : public Usermod {
|
||||
|
||||
private:
|
||||
// array of relays
|
||||
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
||||
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
||||
|
||||
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;
|
||||
// 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;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
@@ -109,7 +103,7 @@ class MultiRelay : public Usermod {
|
||||
/**
|
||||
* desctructor
|
||||
*/
|
||||
//~MultiRelay() {}
|
||||
~MultiRelay() {}
|
||||
|
||||
/**
|
||||
* Enable/Disable the usermod
|
||||
@@ -319,7 +313,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(address);
|
||||
Wire.beginTransmission(addrPcf8574 + address);
|
||||
Wire.write(_data);
|
||||
return Wire.endTransmission();
|
||||
}
|
||||
@@ -327,7 +321,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(address, 1);
|
||||
Wire.requestFrom(addrPcf8574 + address, 1);
|
||||
if (Wire.available()) {
|
||||
_data = Wire.read();
|
||||
}
|
||||
@@ -337,21 +331,12 @@ byte MultiRelay::IOexpanderRead(int address) {
|
||||
|
||||
// public methods
|
||||
|
||||
MultiRelay::MultiRelay()
|
||||
: _switchTimerStart(0)
|
||||
, enabled(MULTI_RELAY_ENABLED)
|
||||
, initDone(false)
|
||||
, usePcf8574(USE_PCF8574)
|
||||
, addrPcf8574(PCF8574_ADDRESS)
|
||||
, HAautodiscovery(false)
|
||||
, periodicBroadcastSec(60)
|
||||
, lastBroadcast(0)
|
||||
{
|
||||
MultiRelay::MultiRelay() {
|
||||
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].invert = false;
|
||||
_relay[i].mode = false;
|
||||
_relay[i].active = false;
|
||||
_relay[i].state = false;
|
||||
_relay[i].external = false;
|
||||
@@ -363,27 +348,25 @@ MultiRelay::MultiRelay()
|
||||
* switch relay on/off
|
||||
*/
|
||||
void MultiRelay::switchRelay(uint8_t relay, bool mode) {
|
||||
if (relay>=MULTI_RELAY_MAX_RELAYS || _relay[relay].pin<0) return;
|
||||
if (relay>=MULTI_RELAY_MAX_RELAYS || (_relay[relay].pin<0 && !usePcf8574)) return;
|
||||
_relay[relay].state = mode;
|
||||
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) {
|
||||
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 {
|
||||
pinMode(_relay[relay].pin, OUTPUT);
|
||||
digitalWrite(_relay[relay].pin, _relay[relay].invert ? !_relay[relay].state : _relay[relay].state);
|
||||
} else return;
|
||||
digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -482,28 +465,29 @@ 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<0 || i2c_scl<0) usePcf8574 = false;
|
||||
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
|
||||
|
||||
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 (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 {
|
||||
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;
|
||||
}
|
||||
@@ -524,7 +508,7 @@ void MultiRelay::loop() {
|
||||
_oldMode = offMode;
|
||||
_switchTimerStart = millis();
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if ((_relay[i].pin>=0) && !_relay[i].external) _relay[i].active = true;
|
||||
if ((_relay[i].pin>=0 || usePcf8574) && !_relay[i].external) _relay[i].active = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,7 +624,7 @@ void MultiRelay::addToJsonInfo(JsonObject &root) {
|
||||
|
||||
String uiDomString;
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin<0 || !_relay[i].external) continue;
|
||||
if ((_relay[i].pin<0 && !usePcf8574) || !_relay[i].external) continue;
|
||||
uiDomString = F("Relay "); uiDomString += i;
|
||||
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
|
||||
|
||||
@@ -731,7 +715,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].invert;
|
||||
relay[FPSTR(_activeHigh)] = _relay[i].mode;
|
||||
relay[FPSTR(_delay_str)] = _relay[i].delay;
|
||||
relay[FPSTR(_external)] = _relay[i].external;
|
||||
relay[FPSTR(_button)] = _relay[i].button;
|
||||
@@ -740,10 +724,9 @@ void MultiRelay::addToConfig(JsonObject &root) {
|
||||
}
|
||||
|
||||
void MultiRelay::appendConfigData() {
|
||||
oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||
oappend(SET_F("addInfo('MultiRelay:first-PCF8574',1,'<i>(not hex!)</i>','address');"));
|
||||
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("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||
oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -768,7 +751,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<0 || i2c_scl<0) usePcf8574 = false;
|
||||
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
|
||||
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
|
||||
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
|
||||
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
|
||||
@@ -777,14 +760,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].invert = top[parName][FPSTR(_activeHigh)] | _relay[i].invert;
|
||||
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
|
||||
_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].invert = top[parName+FPSTR(_activeHigh)] | _relay[i].invert;
|
||||
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
||||
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
||||
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
||||
// end compatibility
|
||||
@@ -798,11 +781,22 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
|
||||
} else {
|
||||
// deallocate all pins 1st
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++)
|
||||
if (oldPin[i]>=0 && oldPin[i]<100) {
|
||||
if (oldPin[i]>=0) {
|
||||
pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
|
||||
}
|
||||
// allocate new pins
|
||||
setup();
|
||||
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;
|
||||
}
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
@@ -820,4 +814,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 = "PCF8574-address";
|
||||
const char MultiRelay::_pcfAddress[] PROGMEM = "first-PCF8574";
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP280.h>
|
||||
#include <Adafruit_CCS811.h>
|
||||
@@ -15,6 +16,14 @@ 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:
|
||||
@@ -222,6 +231,7 @@ public:
|
||||
void setup()
|
||||
{
|
||||
Serial.println("Starting!");
|
||||
Wire.begin(SDA_PIN, SCL_PIN);
|
||||
Serial.println("Initializing sensors.. ");
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ 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
|
||||
@@ -93,7 +94,7 @@ void ShtUsermod::initShtTempHumiditySensor()
|
||||
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
|
||||
}
|
||||
|
||||
shtTempHumidSensor->begin(shtI2cAddress); // uses &Wire
|
||||
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
|
||||
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
|
||||
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
|
||||
cleanup();
|
||||
@@ -131,6 +132,13 @@ 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;
|
||||
}
|
||||
|
||||
@@ -229,12 +237,14 @@ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
|
||||
void ShtUsermod::setup()
|
||||
{
|
||||
if (enabled) {
|
||||
// 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);
|
||||
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);
|
||||
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
@@ -1,22 +0,0 @@
|
||||
# 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
|
||||
@@ -1,19 +0,0 @@
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
#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
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28010.2046
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wled00", "wled00\wled00.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9A679C2B-61D3-400B-B96F-06E604E9CED2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+82
-57
@@ -278,7 +278,7 @@ uint16_t mode_random_color(void) {
|
||||
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), fade));
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!;01";
|
||||
static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!";
|
||||
|
||||
|
||||
/*
|
||||
@@ -289,6 +289,7 @@ uint16_t mode_dynamic(void) {
|
||||
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||
|
||||
if(SEGENV.call == 0) {
|
||||
//SEGMENT.setUpLeds(); //lossless getPixelColor()
|
||||
//SEGMENT.fill(BLACK);
|
||||
for (int i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8();
|
||||
}
|
||||
@@ -432,7 +433,7 @@ uint16_t mode_rainbow(void) {
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!;01";
|
||||
static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!";
|
||||
|
||||
|
||||
/*
|
||||
@@ -606,6 +607,7 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0";
|
||||
uint16_t dissolve(uint32_t color) {
|
||||
//bool wa = (SEGCOLOR(1) != 0 && strip.getBrightness() < 255); //workaround, can't compare getPixel to color if not full brightness
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds(); //lossless getPixelColor()
|
||||
SEGMENT.fill(SEGCOLOR(1));
|
||||
}
|
||||
|
||||
@@ -713,7 +715,7 @@ uint16_t mode_hyper_sparkle(void) {
|
||||
|
||||
if (strip.now - SEGENV.aux0 > SEGENV.step) {
|
||||
if (random8((255-SEGMENT.intensity) >> 4) == 0) {
|
||||
for (int i = 0; i < max(1, SEGLEN/3); i++) {
|
||||
for (int i = 0; i < MAX(1, SEGLEN/3); i++) {
|
||||
SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1));
|
||||
}
|
||||
}
|
||||
@@ -1204,6 +1206,7 @@ uint16_t mode_fireworks() {
|
||||
const uint16_t height = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds(); //lossless getPixelColor()
|
||||
SEGMENT.fill(SEGCOLOR(1));
|
||||
SEGENV.aux0 = UINT16_MAX;
|
||||
SEGENV.aux1 = UINT16_MAX;
|
||||
@@ -1212,21 +1215,19 @@ uint16_t mode_fireworks() {
|
||||
|
||||
bool valid1 = (SEGENV.aux0 < width*height);
|
||||
bool valid2 = (SEGENV.aux1 < width*height);
|
||||
uint8_t x = SEGENV.aux0%width, y = SEGENV.aux0/width; // 2D coordinates stored in upper and lower byte
|
||||
uint32_t sv1 = 0, sv2 = 0;
|
||||
if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
|
||||
if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux1);
|
||||
if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
|
||||
if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width) : SEGMENT.getPixelColor(SEGENV.aux1);
|
||||
if (!SEGENV.step) SEGMENT.blur(16);
|
||||
if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
|
||||
if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
|
||||
if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
|
||||
if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
|
||||
|
||||
for (int i=0; i<max(1, width/20); i++) {
|
||||
for (int i=0; i<MAX(1, width/20); i++) {
|
||||
if (random8(129 - (SEGMENT.intensity >> 1)) == 0) {
|
||||
uint16_t index = random16(width*height);
|
||||
x = index % width;
|
||||
y = index / width;
|
||||
uint16_t j = index % width, k = index / width;
|
||||
uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0);
|
||||
if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, col);
|
||||
if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(j, k, col);
|
||||
else SEGMENT.setPixelColor(index, col);
|
||||
SEGENV.aux1 = SEGENV.aux0; // old spark
|
||||
SEGENV.aux0 = index; // remember where spark occured
|
||||
@@ -1904,6 +1905,7 @@ static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
|
||||
uint16_t mode_juggle(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds(); //lossless getPixelColor()
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -3023,7 +3025,7 @@ uint16_t candle(bool multi)
|
||||
if (multi)
|
||||
{
|
||||
//allocate segment data
|
||||
uint16_t dataSize = max(1, SEGLEN -1) *3; //max. 1365 pixels (ESP8266)
|
||||
uint16_t dataSize = (SEGLEN -1) *3; //max. 1365 pixels (ESP8266)
|
||||
if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed
|
||||
}
|
||||
|
||||
@@ -3156,7 +3158,7 @@ uint16_t mode_starburst(void) {
|
||||
if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0)
|
||||
{
|
||||
// Pick a random color and location.
|
||||
uint16_t startPos = (SEGLEN > 1) ? random16(SEGLEN-1) : 0;
|
||||
uint16_t startPos = random16(SEGLEN-1);
|
||||
float multiplier = (float)(random8())/255.0 * 1.0;
|
||||
|
||||
stars[j].color = CRGB(SEGMENT.color_wheel(random8()));
|
||||
@@ -3400,7 +3402,7 @@ uint16_t mode_drip(void)
|
||||
uint8_t numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
|
||||
|
||||
float gravity = -0.0005 - (SEGMENT.speed/50000.0);
|
||||
gravity *= max(1, SEGLEN-1);
|
||||
gravity *= SEGLEN-1;
|
||||
int sourcedrop = 12;
|
||||
|
||||
for (int j=0;j<numDrops;j++) {
|
||||
@@ -4584,6 +4586,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma
|
||||
|
||||
// initialize on first call
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -4593,22 +4596,22 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i);
|
||||
y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i);
|
||||
SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(i*32, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255));
|
||||
SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255));
|
||||
}
|
||||
// inner stars
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i);
|
||||
y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i);
|
||||
SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(255-i*64, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255));
|
||||
SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255));
|
||||
}
|
||||
// central white dot
|
||||
SEGMENT.setPixelColorXY(cols/2, rows/2, WHITE);
|
||||
SEGMENT.setPixelColorXY(cols/2, rows/2, CHSV(0, 0, 255));
|
||||
// blur everything a bit
|
||||
SEGMENT.blur(16);
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DBlackHole()
|
||||
static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.,Solid;!;!;2;pal=11";
|
||||
static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.;;;2";
|
||||
|
||||
|
||||
////////////////////////////
|
||||
@@ -4621,6 +4624,7 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
SEGENV.aux0 = 0; // start with red hue
|
||||
}
|
||||
@@ -4674,6 +4678,7 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -4700,6 +4705,7 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -4745,6 +4751,7 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -4752,12 +4759,11 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli
|
||||
|
||||
const uint16_t maxDim = MAX(cols, rows)/2;
|
||||
unsigned long t = millis() / (32 - (SEGMENT.speed>>3));
|
||||
unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup
|
||||
for (float i = 1; i < maxDim; i += 0.25) {
|
||||
float angle = radians(t * (maxDim - i));
|
||||
uint16_t myX = (cols>>1) + (uint16_t)(sin_t(angle) * i) + (cols%2);
|
||||
uint16_t myY = (rows>>1) + (uint16_t)(cos_t(angle) * i) + (rows%2);
|
||||
SEGMENT.setPixelColorXY(myX, myY, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND));
|
||||
SEGMENT.setPixelColorXY(myX, myY, ColorFromPalette(SEGPALETTE, (i * 20) + (t / 20), 255, LINEARBLEND));
|
||||
}
|
||||
SEGMENT.blur(SEGMENT.intensity>>3);
|
||||
|
||||
@@ -4776,6 +4782,7 @@ uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -4810,6 +4817,7 @@ uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.so
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -4848,6 +4856,8 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
|
||||
|
||||
CRGB backgroundColor = SEGCOLOR(1);
|
||||
|
||||
if (SEGENV.call == 0) SEGMENT.setUpLeds();
|
||||
|
||||
if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) {
|
||||
SEGENV.step = strip.now;
|
||||
SEGENV.aux0 = 0;
|
||||
@@ -4904,7 +4914,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
|
||||
} // i,j
|
||||
|
||||
// Rules of Life
|
||||
uint32_t col = uint32_t(prevLeds[XY(x,y)]) & 0x00FFFFFF; // uint32_t operator returns RGBA, we want RGBW -> cut off "alpha" byte
|
||||
uint32_t col = prevLeds[XY(x,y)];
|
||||
uint32_t bgc = RGBW32(backgroundColor.r, backgroundColor.g, backgroundColor.b, 0);
|
||||
if ((col != bgc) && (neighbors < 2)) SEGMENT.setPixelColorXY(x,y, bgc); // Loneliness
|
||||
else if ((col != bgc) && (neighbors > 3)) SEGMENT.setPixelColorXY(x,y, bgc); // Overpopulation
|
||||
@@ -5085,22 +5095,21 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
SEGMENT.fadeToBlackBy(SEGMENT.intensity);
|
||||
uint_fast16_t phase = (millis() * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed
|
||||
|
||||
//for (int i=0; i < 4*(cols+rows); i ++) {
|
||||
for (int i=0; i < 256; i ++) {
|
||||
//float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f;
|
||||
//float ylocn = float(cos8(now/4+i*2)) / 255.0f;
|
||||
uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/32);
|
||||
uint_fast8_t ylocn = cos8(phase/2 + i*2);
|
||||
xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding
|
||||
ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map()
|
||||
SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
|
||||
uint8_t xlocn = sin8(millis()/4+i*(SEGMENT.speed>>5));
|
||||
uint8_t ylocn = cos8(millis()/4+i*2);
|
||||
xlocn = map(xlocn,0,255,0,cols-1);
|
||||
ylocn = map(ylocn,0,255,0,rows-1);
|
||||
SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DLissajous()
|
||||
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,,,Speed;!;!;2;;c3=15";
|
||||
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate;!;!;2";
|
||||
|
||||
|
||||
///////////////////////
|
||||
@@ -5113,6 +5122,7 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -5257,12 +5267,13 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2);
|
||||
|
||||
uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float
|
||||
float t = millis() / (33 - SEGMENT.speed/8);
|
||||
for (int i = 0; i < cols; i++) {
|
||||
uint16_t thisVal = inoise8(i * 30, t, t);
|
||||
uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1);
|
||||
@@ -5304,6 +5315,7 @@ uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https
|
||||
CRGBPalette16 auroraPalette = {0x000000, 0x003300, 0x006600, 0x009900, 0x00cc00, 0x00ff00, 0x33ff00, 0x66ff00, 0x99ff00, 0xccff00, 0xffff00, 0xffcc00, 0xff9900, 0xff6600, 0xff3300, 0xff0000};
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
SEGENV.step = 0;
|
||||
}
|
||||
@@ -5353,6 +5365,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -5380,6 +5393,7 @@ uint16_t mode_2DSindots(void) { // By: ldirko http
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -5411,6 +5425,7 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -5453,6 +5468,7 @@ uint16_t mode_2DSunradiation(void) { // By: ldirko https://edi
|
||||
byte *bump = reinterpret_cast<byte*>(SEGENV.data);
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -5500,6 +5516,7 @@ uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.so
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -5539,6 +5556,7 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -5607,6 +5625,7 @@ uint16_t mode_2Dcrazybees(void) {
|
||||
bee_t *bee = reinterpret_cast<bee_t*>(SEGENV.data);
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
bee[i].posX = random8(0, cols);
|
||||
@@ -5676,6 +5695,7 @@ uint16_t mode_2Dghostrider(void) {
|
||||
|
||||
const size_t maxLighters = min(cols + rows, LIGHTERS_AM);
|
||||
|
||||
if (SEGENV.call == 0) SEGMENT.setUpLeds();
|
||||
if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
|
||||
SEGENV.aux0 = cols;
|
||||
SEGENV.aux1 = rows;
|
||||
@@ -5760,6 +5780,7 @@ uint16_t mode_2Dfloatingblobs(void) {
|
||||
if (!SEGENV.allocateData(sizeof(blob_t))) return mode_static(); //allocation failed
|
||||
blob_t *blob = reinterpret_cast<blob_t*>(SEGENV.data);
|
||||
|
||||
if (SEGENV.call == 0) SEGMENT.setUpLeds();
|
||||
if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
|
||||
SEGENV.aux0 = cols; // re-initialise if virtual size changes
|
||||
SEGENV.aux1 = rows;
|
||||
@@ -5855,17 +5876,11 @@ uint16_t mode_2Dscrollingtext(void) {
|
||||
case 4: letterWidth = 7; letterHeight = 9; break;
|
||||
case 5: letterWidth = 5; letterHeight = 12; break;
|
||||
}
|
||||
const bool zero = SEGMENT.check3;
|
||||
const int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-letterHeight)/2;
|
||||
char text[WLED_MAX_SEGNAME_LEN+1] = {'\0'};
|
||||
char text[33] = {'\0'};
|
||||
if (SEGMENT.name) for (size_t i=0,j=0; i<strlen(SEGMENT.name); i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i];
|
||||
|
||||
if (!strlen(text)
|
||||
|| !strncmp_P(text,PSTR("#DATE"),5)
|
||||
|| !strncmp_P(text,PSTR("#DDMM"),5)
|
||||
|| !strncmp_P(text,PSTR("#MMDD"),5)
|
||||
|| !strncmp_P(text,PSTR("#TIME"),5)
|
||||
|| !strncmp_P(text,PSTR("#HHMM"),5)) { // fallback if empty segment name: display date and time
|
||||
if (!strlen(text) || !strncmp_P(text,PSTR("#DATE"),5) || !strncmp_P(text,PSTR("#DDMM"),5) || !strncmp_P(text,PSTR("#MMDD"),5) || !strncmp_P(text,PSTR("#TIME"),5) || !strncmp_P(text,PSTR("#HHMM"),5)) { // fallback if empty segment name: display date and time
|
||||
char sec[5];
|
||||
byte AmPmHour = hour(localTime);
|
||||
boolean isitAM = true;
|
||||
@@ -5875,12 +5890,12 @@ uint16_t mode_2Dscrollingtext(void) {
|
||||
}
|
||||
if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
|
||||
else sprintf_P(sec, PSTR(":%02d"), second(localTime));
|
||||
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d"):PSTR("%d.%d"), day(localTime), month(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d"):PSTR("%d/%d"), month(localTime), day(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s"):PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
||||
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d"):PSTR("%d:%02d"), AmPmHour, minute(localTime));
|
||||
else sprintf_P(text, zero?PSTR("%s %02d, %04d %02d:%02d%s"):PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
||||
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, PSTR("%d.%d"), day(localTime), month(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, PSTR("%d/%d"), month(localTime), day(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
||||
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, PSTR("%2d:%02d"), AmPmHour, minute(localTime));
|
||||
else sprintf_P(text, PSTR("%s %d, %d %2d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
||||
}
|
||||
const int numberOfLetters = strlen(text);
|
||||
|
||||
@@ -5907,7 +5922,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,,Gradient,Overlay,0;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";
|
||||
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,,Gradient,Overlay;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";
|
||||
|
||||
|
||||
////////////////////////////
|
||||
@@ -5925,6 +5940,7 @@ uint16_t mode_2Ddriftrose(void) {
|
||||
const float L = min(cols, rows) / 2.f;
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6079,6 +6095,7 @@ uint16_t mode_2DSwirl(void) {
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6125,6 +6142,7 @@ uint16_t mode_2DWaverly(void) {
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6353,6 +6371,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
|
||||
int16_t volumeRaw = *(int16_t*)um_data->u_data[1];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6480,6 +6499,7 @@ uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline.
|
||||
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6679,7 +6699,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
|
||||
SEGENV.step += FRAMETIME;
|
||||
if (SEGENV.step > SPEED_FORMULA_L) {
|
||||
uint16_t segLoc = random16(SEGLEN);
|
||||
SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16]));
|
||||
SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/(SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16]));
|
||||
++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16
|
||||
|
||||
SEGENV.step = 1;
|
||||
@@ -6705,6 +6725,7 @@ uint16_t mode_DJLight(void) { // Written by ??? Adapted by Wil
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6773,6 +6794,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
|
||||
float volumeSmth = *(float*)um_data->u_data[0];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6811,7 +6833,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_freqmatrix()
|
||||
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensivity;;;1f;m12=3,si=0"; // Corner, Beatsin
|
||||
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Time delay,Sound effect,Low bin,High bin,Sensivity;;;1f;m12=3,si=0"; // Corner, Beatsin
|
||||
|
||||
|
||||
//////////////////////
|
||||
@@ -6874,6 +6896,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
|
||||
float volumeSmth = *(float*)um_data->u_data[0];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -6914,7 +6937,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_freqwave()
|
||||
static const char _data_FX_MODE_FREQWAVE[] PROGMEM = "Freqwave@Speed,Sound effect,Low bin,High bin,Pre-amp;;;1f;m12=2,si=0"; // Circle, Beatsin
|
||||
static const char _data_FX_MODE_FREQWAVE[] PROGMEM = "Freqwave@Time delay,Sound effect,Low bin,High bin,Pre-amp;;;1f;m12=2,si=0"; // Circle, Beatsin
|
||||
|
||||
|
||||
///////////////////////
|
||||
@@ -7058,6 +7081,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
|
||||
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
SEGENV.aux0 = 255;
|
||||
SEGMENT.custom1 = *binNum;
|
||||
@@ -7174,6 +7198,7 @@ uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Wil
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
@@ -7386,6 +7411,7 @@ uint16_t mode_2Dsoap() {
|
||||
|
||||
// init
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
*noise32_x = random16();
|
||||
*noise32_y = random16();
|
||||
*noise32_z = random16();
|
||||
@@ -7419,7 +7445,6 @@ uint16_t mode_2Dsoap() {
|
||||
int amplitude;
|
||||
int8_t shiftX = 0; //(SEGMENT.custom1 - 128) / 4;
|
||||
int8_t shiftY = 0; //(SEGMENT.custom2 - 128) / 4;
|
||||
CRGB ledsbuff[MAX(cols,rows)];
|
||||
|
||||
amplitude = (cols >= 16) ? (cols-8)/8 : 1;
|
||||
for (int y = 0; y < rows; y++) {
|
||||
@@ -7440,9 +7465,9 @@ uint16_t mode_2Dsoap() {
|
||||
CRGB PixelB = CRGB::Black;
|
||||
if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y);
|
||||
else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zF),y)]*3);
|
||||
ledsbuff[x] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
|
||||
CRGB pix = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
|
||||
SEGMENT.setPixelColorXY(x, y, pix);
|
||||
}
|
||||
for (int x = 0; x < cols; x++) SEGMENT.setPixelColorXY(x, y, ledsbuff[x]);
|
||||
}
|
||||
|
||||
amplitude = (rows >= 16) ? (rows-8)/8 : 1;
|
||||
@@ -7464,9 +7489,9 @@ uint16_t mode_2Dsoap() {
|
||||
CRGB PixelB = CRGB::Black;
|
||||
if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF);
|
||||
else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zF))]*3);
|
||||
ledsbuff[y] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
|
||||
CRGB pix = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
|
||||
SEGMENT.setPixelColorXY(x, y, pix);
|
||||
}
|
||||
for (int y = 0; y < rows; y++) SEGMENT.setPixelColorXY(x, y, ledsbuff[y]);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
@@ -7504,12 +7529,12 @@ uint16_t mode_2Doctopus() {
|
||||
SEGENV.aux1 = rows;
|
||||
*offsX = SEGMENT.custom1;
|
||||
*offsY = SEGMENT.custom2;
|
||||
const int C_X = (cols / 2) + ((SEGMENT.custom1 - 128)*cols)/255;
|
||||
const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255;
|
||||
const uint8_t C_X = cols / 2 + (SEGMENT.custom1 - 128)*cols/255;
|
||||
const uint8_t C_Y = rows / 2 + (SEGMENT.custom2 - 128)*rows/255;
|
||||
for (int x = 0; x < cols; x++) {
|
||||
for (int y = 0; y < rows; y++) {
|
||||
rMap[XY(x, y)].angle = 40.7436f * atan2f((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI
|
||||
rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu
|
||||
rMap[XY(x, y)].angle = 40.7436f * atan2f(y - C_Y, x - C_X); // avoid 128*atan2()/PI
|
||||
rMap[XY(x, y)].radius = hypotf(x - C_X, y - C_Y) * mapp; //thanks Sutaburosu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-40
@@ -329,7 +329,7 @@ typedef enum mapping1D2D {
|
||||
M12_pCorner = 3
|
||||
} mapping1D2D_t;
|
||||
|
||||
// segment, 80 bytes
|
||||
// segment, 72 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,7 +378,9 @@ typedef struct Segment {
|
||||
uint32_t call; // call counter
|
||||
uint16_t aux0; // custom var
|
||||
uint16_t aux1; // custom var
|
||||
byte *data; // effect data pointer
|
||||
byte* data; // effect data pointer
|
||||
CRGB* leds; // local leds[] array (may be a pointer to global)
|
||||
static CRGB *_globalLeds; // global leds[] array
|
||||
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
|
||||
|
||||
private:
|
||||
@@ -392,15 +394,10 @@ typedef struct Segment {
|
||||
uint8_t _reserved : 4;
|
||||
};
|
||||
};
|
||||
uint16_t _dataLen;
|
||||
uint16_t _dataLen;
|
||||
static uint16_t _usedSegmentData;
|
||||
|
||||
// perhaps this should be per segment, not static
|
||||
static CRGBPalette16 _randomPalette;
|
||||
static CRGBPalette16 _newRandomPalette;
|
||||
static unsigned long _lastPaletteChange;
|
||||
|
||||
// transition data, valid only if transitional==true, holds values during transition (72 bytes)
|
||||
// transition data, valid only if transitional==true, holds values during transition
|
||||
struct Transition {
|
||||
uint32_t _colorT[NUM_COLORS];
|
||||
uint8_t _briT; // temporary brightness
|
||||
@@ -411,7 +408,7 @@ typedef struct Segment {
|
||||
//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
|
||||
unsigned long _start; // must accommodate millis()
|
||||
uint32_t _start;
|
||||
uint16_t _dur;
|
||||
Transition(uint16_t dur=750)
|
||||
: _briT(255)
|
||||
@@ -466,6 +463,7 @@ typedef struct Segment {
|
||||
aux0(0),
|
||||
aux1(0),
|
||||
data(nullptr),
|
||||
leds(nullptr),
|
||||
_capabilities(0),
|
||||
_dataLen(0),
|
||||
_t(nullptr)
|
||||
@@ -486,10 +484,12 @@ typedef struct Segment {
|
||||
//Serial.print(F("Destroying segment:"));
|
||||
//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 (name) { delete[] name; name = nullptr; }
|
||||
if (_t) { transitional = false; delete _t; _t = nullptr; }
|
||||
if (!Segment::_globalLeds && leds) free(leds);
|
||||
if (name) delete[] name;
|
||||
if (_t) delete _t;
|
||||
deallocateData();
|
||||
}
|
||||
|
||||
@@ -497,7 +497,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); }
|
||||
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); }
|
||||
#endif
|
||||
|
||||
inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); }
|
||||
@@ -507,17 +507,16 @@ 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 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 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 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; }
|
||||
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, uint8_t segId = 255);
|
||||
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);
|
||||
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
|
||||
void setCCT(uint16_t k);
|
||||
void setOpacity(uint8_t o);
|
||||
@@ -539,6 +538,7 @@ 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
|
||||
@@ -579,7 +579,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
|
||||
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment (for leds[])
|
||||
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
|
||||
@@ -692,15 +692,7 @@ class WS2812FX { // 96 bytes
|
||||
customMappingSize(0),
|
||||
_lastShow(0),
|
||||
_segment_index(0),
|
||||
_mainSegment(0),
|
||||
_queuedChangesSegId(255),
|
||||
_qStart(0),
|
||||
_qStop(0),
|
||||
_qStartY(0),
|
||||
_qStopY(0),
|
||||
_qGrouping(0),
|
||||
_qSpacing(0),
|
||||
_qOffset(0)
|
||||
_mainSegment(0)
|
||||
{
|
||||
WS2812FX::instance = this;
|
||||
_mode.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size())
|
||||
@@ -718,6 +710,7 @@ class WS2812FX { // 96 bytes
|
||||
panel.clear();
|
||||
#endif
|
||||
customPalettes.clear();
|
||||
if (useLedsArray && Segment::_globalLeds) free(Segment::_globalLeds);
|
||||
}
|
||||
|
||||
static WS2812FX* getInstance(void) { return instance; }
|
||||
@@ -756,7 +749,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()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
|
||||
inline void appendSegment(const Segment &seg = Segment()) { _segments.push_back(seg); }
|
||||
|
||||
bool
|
||||
checkSegmentAlignment(void),
|
||||
@@ -764,7 +757,8 @@ class WS2812FX { // 96 bytes
|
||||
hasCCTBus(void),
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void),
|
||||
deserializeMap(uint8_t n=0);
|
||||
deserializeMap(uint8_t n=0),
|
||||
useLedsArray = false;
|
||||
|
||||
inline bool isServicing(void) { return _isServicing; }
|
||||
inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
|
||||
@@ -906,20 +900,13 @@ class WS2812FX { // 96 bytes
|
||||
uint16_t* customMappingTable;
|
||||
uint16_t customMappingSize;
|
||||
|
||||
unsigned long _lastShow;
|
||||
uint32_t _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
|
||||
setUpSegmentFromQueuedChanges(void);
|
||||
estimateCurrentAndLimitBri(void);
|
||||
};
|
||||
|
||||
extern const char JSON_mode_names[];
|
||||
|
||||
+25
-40
@@ -189,17 +189,20 @@ 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 (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;
|
||||
uint16_t width = virtualWidth(); // segment width in logical pixels
|
||||
uint16_t height = virtualHeight(); // segment height in logical pixels
|
||||
return (x%width) + (y%height) * width;
|
||||
}
|
||||
|
||||
void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
if (Segment::maxHeight==1) return; // not a matrix set-up
|
||||
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);
|
||||
@@ -241,7 +244,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 (!isActive()) return; // not active
|
||||
if (Segment::maxHeight==1) return; // not a matrix set-up
|
||||
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||
|
||||
const uint16_t cols = virtualWidth();
|
||||
@@ -284,8 +287,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) {
|
||||
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
|
||||
int i = XY(x,y);
|
||||
if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0);
|
||||
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
|
||||
@@ -302,8 +305,6 @@ 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);
|
||||
@@ -322,70 +323,62 @@ 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) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_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 (uint_fast16_t x = 0; x < cols; x++) {
|
||||
for (uint16_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>0) {
|
||||
if (x) {
|
||||
CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part;
|
||||
setPixelColorXY(x-1, row, prev);
|
||||
}
|
||||
if (before != cur) // optimization: only set pixel if color has changed
|
||||
setPixelColorXY(x, row, cur);
|
||||
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) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_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 (uint_fast16_t y = 0; y < rows; y++) {
|
||||
CRGB cur = getPixelColorXY(col, y);
|
||||
for (uint16_t i = 0; i < rows; i++) {
|
||||
CRGB cur = getPixelColorXY(col, i);
|
||||
CRGB part = cur;
|
||||
CRGB before = cur; // remember color before blur
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if (y>0) {
|
||||
CRGB prev = CRGB(getPixelColorXY(col, y-1)) + part;
|
||||
setPixelColorXY(col, y-1, prev);
|
||||
if (i) {
|
||||
CRGB prev = CRGB(getPixelColorXY(col, i-1)) + part;
|
||||
setPixelColorXY(col, i-1, prev);
|
||||
}
|
||||
if (before != cur) // optimization: only set pixel if color has changed
|
||||
setPixelColorXY(col, y, cur);
|
||||
setPixelColorXY(col, i, 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;
|
||||
@@ -398,8 +391,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;
|
||||
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
|
||||
int16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow
|
||||
uint16_t xp = vertical ? x : x-1;
|
||||
uint16_t yp = vertical ? y-1 : y;
|
||||
uint16_t xn = vertical ? x : x+1;
|
||||
uint16_t yn = vertical ? y+1 : y;
|
||||
CRGB curr = getPixelColorXY(x,y);
|
||||
@@ -438,7 +431,6 @@ 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;
|
||||
@@ -456,7 +448,6 @@ 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;
|
||||
@@ -492,7 +483,6 @@ 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;
|
||||
@@ -517,7 +507,6 @@ 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++) {
|
||||
@@ -531,7 +520,6 @@ 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++) {
|
||||
@@ -541,7 +529,6 @@ 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;
|
||||
@@ -566,7 +553,6 @@ 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) {
|
||||
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();
|
||||
@@ -602,7 +588,6 @@ 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
|
||||
|
||||
+190
-201
@@ -74,36 +74,34 @@
|
||||
// Segment class implementation
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
|
||||
CRGB *Segment::_globalLeds = nullptr;
|
||||
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
|
||||
uint16_t Segment::maxHeight = 1;
|
||||
|
||||
CRGBPalette16 Segment::_randomPalette = CRGBPalette16(DEFAULT_COLOR);
|
||||
CRGBPalette16 Segment::_newRandomPalette = CRGBPalette16(DEFAULT_COLOR);
|
||||
unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment
|
||||
|
||||
// copy constructor
|
||||
Segment::Segment(const Segment &orig) {
|
||||
//DEBUG_PRINTLN(F("-- Copy segment constructor --"));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
transitional = false; // copied segment cannot be in transition
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
_t = nullptr;
|
||||
if (leds && !Segment::_globalLeds) leds = nullptr;
|
||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
||||
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
||||
//if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
|
||||
if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
|
||||
if (orig.leds && !Segment::_globalLeds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
|
||||
}
|
||||
|
||||
// move constructor
|
||||
Segment::Segment(Segment &&orig) noexcept {
|
||||
//DEBUG_PRINTLN(F("-- Move segment constructor --"));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
orig.transitional = false; // old segment cannot be in transition any more
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
orig._t = nullptr;
|
||||
orig.leds = nullptr;
|
||||
}
|
||||
|
||||
// copy assignment
|
||||
@@ -111,22 +109,23 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
//DEBUG_PRINTLN(F("-- Copying segment --"));
|
||||
if (this != &orig) {
|
||||
// clean destination
|
||||
transitional = false; // copied segment cannot be in transition
|
||||
if (name) delete[] name;
|
||||
if (_t) delete _t;
|
||||
if (leds && !Segment::_globalLeds) free(leds);
|
||||
deallocateData();
|
||||
// copy source
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
transitional = false;
|
||||
// erase pointers to allocated data
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
_t = nullptr;
|
||||
if (!Segment::_globalLeds) leds = nullptr;
|
||||
// copy source data
|
||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
||||
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
||||
//if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
|
||||
if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
|
||||
if (orig.leds && !Segment::_globalLeds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -135,16 +134,16 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
//DEBUG_PRINTLN(F("-- Moving segment --"));
|
||||
if (this != &orig) {
|
||||
transitional = false; // just temporary
|
||||
if (name) { delete[] name; name = nullptr; } // free old name
|
||||
if (name) delete[] name; // free old name
|
||||
deallocateData(); // free old runtime data
|
||||
if (_t) { delete _t; _t = nullptr; }
|
||||
if (_t) delete _t;
|
||||
if (leds && !Segment::_globalLeds) free(leds);
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
orig.transitional = false; // old segment cannot be in transition
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
orig._t = nullptr;
|
||||
orig.leds = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -154,7 +153,12 @@ bool Segment::allocateData(size_t len) {
|
||||
deallocateData();
|
||||
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
// do not use SPI RAM on ESP32 since it is slow
|
||||
data = (byte*) malloc(len);
|
||||
//#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
//if (psramFound())
|
||||
// data = (byte*) ps_malloc(len);
|
||||
//else
|
||||
//#endif
|
||||
data = (byte*) malloc(len);
|
||||
if (!data) return false; //allocation failed
|
||||
Segment::addUsedSegmentData(len);
|
||||
_dataLen = len;
|
||||
@@ -178,14 +182,38 @@ void Segment::deallocateData() {
|
||||
* may free that data buffer.
|
||||
*/
|
||||
void Segment::resetIfRequired() {
|
||||
if (!reset) return;
|
||||
|
||||
deallocateData();
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
reset = false;
|
||||
if (reset) {
|
||||
if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; }
|
||||
if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
|
||||
deallocateData();
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
reset = false; // setOption(SEG_OPTION_RESET, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Segment::setUpLeds() {
|
||||
// deallocation happens in resetIfRequired() as it is called when segment changes or in destructor
|
||||
if (Segment::_globalLeds)
|
||||
#ifndef WLED_DISABLE_2D
|
||||
leds = &Segment::_globalLeds[start + startY*Segment::maxWidth];
|
||||
#else
|
||||
leds = &Segment::_globalLeds[start];
|
||||
#endif
|
||||
else if (leds == nullptr && length() > 0) { //softhack007 quickfix - avoid malloc(0) which is undefined behaviour (should not happen, but i've seen it)
|
||||
//#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
//if (psramFound())
|
||||
// leds = (CRGB*)ps_malloc(sizeof(CRGB)*length()); // softhack007 disabled; putting leds into psram leads to horrible slowdown on WROVER boards
|
||||
//else
|
||||
//#endif
|
||||
leds = (CRGB*)malloc(sizeof(CRGB)*length());
|
||||
}
|
||||
}
|
||||
|
||||
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment
|
||||
static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR);
|
||||
static CRGBPalette16 prevRandomPalette = CRGBPalette16(CRGB(BLACK));
|
||||
byte tcp[72];
|
||||
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
|
||||
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0;
|
||||
//default palette. Differs depending on effect
|
||||
@@ -206,18 +234,27 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
case 0: //default palette. Exceptions for specific effects above
|
||||
targetPalette = PartyColors_p; break;
|
||||
case 1: {//periodically replace palette with a random one. Transition palette change in 500ms
|
||||
unsigned long timeSinceLastChange = millis() - _lastPaletteChange;
|
||||
uint32_t timeSinceLastChange = millis() - _lastPaletteChange;
|
||||
if (timeSinceLastChange > randomPaletteChangeTime * 1000U) {
|
||||
_randomPalette = _newRandomPalette;
|
||||
_newRandomPalette = CRGBPalette16(
|
||||
prevRandomPalette = randomPalette;
|
||||
randomPalette = CRGBPalette16(
|
||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||
CHSV(random8(), random8(160, 255), random8(128, 255)));
|
||||
_lastPaletteChange = millis();
|
||||
handleRandomPalette(); // do initial blend
|
||||
timeSinceLastChange = 0;
|
||||
}
|
||||
if (timeSinceLastChange <= 250) {
|
||||
targetPalette = prevRandomPalette;
|
||||
// there needs to be 255 palette blends (48) for full blend but that is too resource intensive
|
||||
// so 128 is a compromise (we need to perform full blend of the two palettes as each segment can have random
|
||||
// palette selected but only 2 static palettes are used)
|
||||
size_t noOfBlends = ((128U * timeSinceLastChange) / 250U);
|
||||
for (size_t i=0; i<noOfBlends; i++) nblendPaletteTowardPalette(targetPalette, randomPalette, 48);
|
||||
} else {
|
||||
targetPalette = randomPalette;
|
||||
}
|
||||
targetPalette = _randomPalette;
|
||||
break;}
|
||||
case 2: {//primary color only
|
||||
CRGB prim = gamma32(colors[0]);
|
||||
@@ -259,7 +296,6 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
if (pal>245) {
|
||||
targetPalette = strip.customPalettes[255-pal]; // we checked bounds above
|
||||
} else {
|
||||
byte tcp[72];
|
||||
memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[pal-13])), 72);
|
||||
targetPalette.loadDynamicGradientPalette(tcp);
|
||||
}
|
||||
@@ -269,42 +305,39 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
}
|
||||
|
||||
void Segment::startTransition(uint16_t dur) {
|
||||
if (!dur) {
|
||||
transitional = false;
|
||||
if (_t) {
|
||||
delete _t;
|
||||
_t = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (transitional && _t) return; // already in transition no need to store anything
|
||||
if (transitional || _t) return; // already in transition no need to store anything
|
||||
|
||||
// starting a transition has to occur before change so we get current values 1st
|
||||
_t = new Transition(dur); // no previous transition running
|
||||
if (!_t) return; // failed to allocate data
|
||||
|
||||
uint8_t _briT = currentBri(on ? opacity : 0);
|
||||
uint8_t _cctT = currentBri(cct, true);
|
||||
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
|
||||
_t->_briT = on ? opacity : 0;
|
||||
_t->_cctT = cct;
|
||||
uint8_t _modeP = mode;
|
||||
uint32_t _colorT[NUM_COLORS];
|
||||
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = currentColor(i, colors[i]);
|
||||
|
||||
if (!_t) _t = new Transition(dur); // no previous transition running
|
||||
if (!_t) return; // failed to allocate data
|
||||
_t->_briT = _briT;
|
||||
_t->_cctT = _cctT;
|
||||
_t->_palT = _palT;
|
||||
_t->_modeP = mode;
|
||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
|
||||
_t->_modeP = _modeP;
|
||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = _colorT[i];
|
||||
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
|
||||
}
|
||||
|
||||
// transition progression between 0-65535
|
||||
uint16_t Segment::progress() {
|
||||
if (!transitional || !_t) return 0xFFFFU;
|
||||
unsigned long timeNow = millis();
|
||||
uint32_t timeNow = millis();
|
||||
if (timeNow - _t->_start > _t->_dur || _t->_dur == 0) return 0xFFFFU;
|
||||
return (timeNow - _t->_start) * 0xFFFFU / _t->_dur;
|
||||
}
|
||||
|
||||
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
|
||||
uint32_t prog = progress();
|
||||
if (transitional && _t && prog < 0xFFFFU) {
|
||||
if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16;
|
||||
else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16;
|
||||
if (transitional && _t) {
|
||||
uint32_t prog = progress() + 1;
|
||||
if (useCct) return ((briNew * prog) + _t->_cctT * (0x10000 - prog)) >> 16;
|
||||
else return ((briNew * prog) + _t->_briT * (0x10000 - prog)) >> 16;
|
||||
} else {
|
||||
return briNew;
|
||||
}
|
||||
@@ -324,7 +357,7 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal
|
||||
// blend palettes
|
||||
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
|
||||
// minimum blend time is 100ms maximum is 65535ms
|
||||
unsigned long timeMS = millis() - _t->_start;
|
||||
uint32_t timeMS = millis() - _t->_start;
|
||||
uint16_t noOfBlends = (255U * timeMS / _t->_dur) - _t->_prevPaletteBlends;
|
||||
for (int i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48);
|
||||
targetPalette = _t->_palT; // copy transitioning/temporary palette
|
||||
@@ -334,26 +367,20 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal
|
||||
|
||||
void Segment::handleTransition() {
|
||||
if (!transitional) return;
|
||||
uint16_t _progress = progress();
|
||||
if (_progress == 0xFFFFU) transitional = false; // finish transitioning segment
|
||||
if (_t) { // thanks to @nXm AKA https://github.com/NMeirer
|
||||
if (_progress == 0xFFFFU) {
|
||||
unsigned long maxWait = millis() + 20;
|
||||
if (mode == FX_MODE_STATIC && next_time > maxWait) next_time = maxWait;
|
||||
if (progress() == 0xFFFFU) {
|
||||
if (_t) {
|
||||
if (_t->_modeP != mode) markForReset();
|
||||
delete _t;
|
||||
_t = nullptr;
|
||||
}
|
||||
transitional = false; // finish transitioning segment
|
||||
}
|
||||
}
|
||||
|
||||
// relies on WS2812FX::service() to call it max every 8ms or more (MIN_SHOW_DELAY)
|
||||
void Segment::handleRandomPalette() {
|
||||
// just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette)
|
||||
// this will slowly blend _newRandomPalette into _randomPalette every 15ms or 8ms (depending on MIN_SHOW_DELAY)
|
||||
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
||||
}
|
||||
|
||||
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function
|
||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t segId) {
|
||||
// return if neither bounds nor grouping have changed
|
||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
||||
//return if neither bounds nor grouping have changed
|
||||
bool boundsUnchanged = (start == i1 && stop == i2);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (Segment::maxHeight>1) boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D
|
||||
@@ -362,22 +389,10 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
&& (!grp || (grouping == grp && spacing == spc))
|
||||
&& (ofs == UINT16_MAX || ofs == offset)) return;
|
||||
|
||||
if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
|
||||
if (grp) { // prevent assignment of 0
|
||||
grouping = grp;
|
||||
spacing = spc;
|
||||
} else {
|
||||
grouping = 1;
|
||||
spacing = 0;
|
||||
}
|
||||
if (ofs < UINT16_MAX) offset = ofs;
|
||||
|
||||
markForReset();
|
||||
if (boundsUnchanged) return;
|
||||
|
||||
// apply change immediately
|
||||
if (stop) fill(BLACK); //turn old segment range off
|
||||
if (i2 <= i1) { //disable segment
|
||||
stop = 0;
|
||||
markForReset();
|
||||
return;
|
||||
}
|
||||
if (i1 < Segment::maxWidth || (i1 >= Segment::maxWidth*Segment::maxHeight && i1 < strip.getLengthTotal())) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D
|
||||
@@ -390,12 +405,13 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
stopY = i2Y > Segment::maxHeight ? Segment::maxHeight : MAX(1,i2Y);
|
||||
}
|
||||
#endif
|
||||
// safety check
|
||||
if (start >= stop || startY >= stopY) {
|
||||
stop = 0;
|
||||
return;
|
||||
if (grp) {
|
||||
grouping = grp;
|
||||
spacing = spc;
|
||||
}
|
||||
refreshLightCapabilities();
|
||||
if (ofs < UINT16_MAX) offset = ofs;
|
||||
markForReset();
|
||||
if (!boundsUnchanged) refreshLightCapabilities();
|
||||
}
|
||||
|
||||
|
||||
@@ -442,7 +458,8 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
// if we have a valid mode & is not reserved
|
||||
if (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4)) {
|
||||
if (fx != mode) {
|
||||
if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions
|
||||
startTransition(strip.getTransition()); // set effect transitions
|
||||
//markForReset(); // transition will handle this
|
||||
mode = fx;
|
||||
|
||||
// load default values from effect string
|
||||
@@ -464,7 +481,6 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
|
||||
}
|
||||
markForReset();
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
}
|
||||
@@ -528,7 +544,7 @@ uint16_t Segment::virtualLength() const {
|
||||
return vLen;
|
||||
}
|
||||
#endif
|
||||
uint16_t groupLen = groupLength(); // is always >= 1
|
||||
uint16_t groupLen = groupLength();
|
||||
uint16_t vLength = (length() + groupLen - 1) / groupLen;
|
||||
if (mirror) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vLength;
|
||||
@@ -536,7 +552,6 @@ uint16_t Segment::virtualLength() const {
|
||||
|
||||
void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
#ifndef WLED_DISABLE_2D
|
||||
int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows)
|
||||
#endif
|
||||
@@ -604,8 +619,11 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (leds) leds[i] = col;
|
||||
|
||||
uint16_t len = length();
|
||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||
if (!_bri_t && !transitional && fadeTransition) return; // if _bri_t == 0 && segment is not transitionig && transitions are enabled then save a few CPU cycles
|
||||
if (_bri_t < 255) {
|
||||
byte r = scale8(R(col), _bri_t);
|
||||
byte g = scale8(G(col), _bri_t);
|
||||
@@ -645,7 +663,6 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
// anti-aliased normalized version of setPixelColor()
|
||||
void Segment::setPixelColor(float i, uint32_t col, bool aa)
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
int vStrip = int(i/10.0f); // hack to allow running on virtual strips (2D segment columns/rows)
|
||||
i -= int(i);
|
||||
|
||||
@@ -677,7 +694,6 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
|
||||
|
||||
uint32_t Segment::getPixelColor(int i)
|
||||
{
|
||||
if (!isActive()) return 0; // not active
|
||||
#ifndef WLED_DISABLE_2D
|
||||
int vStrip = i>>16;
|
||||
#endif
|
||||
@@ -705,12 +721,14 @@ uint32_t Segment::getPixelColor(int i)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0);
|
||||
|
||||
if (reverse) i = virtualLength() - i - 1;
|
||||
i *= groupLength();
|
||||
i += start;
|
||||
/* offset/phase */
|
||||
i += offset;
|
||||
if ((i >= stop) && (stop>0)) i -= length(); // avoids negative pixel index (stop = 0 is a possible value)
|
||||
if (i >= stop) i -= length();
|
||||
return strip.getPixelColor(i);
|
||||
}
|
||||
|
||||
@@ -745,11 +763,6 @@ void Segment::refreshLightCapabilities() {
|
||||
uint16_t segStartIdx = 0xFFFFU;
|
||||
uint16_t segStopIdx = 0;
|
||||
|
||||
if (!isActive()) {
|
||||
_capabilities = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (start < Segment::maxWidth * Segment::maxHeight) {
|
||||
// we are withing 2D matrix (includes 1D segments)
|
||||
for (int y = startY; y < stopY; y++) for (int x = start; x < stop; x++) {
|
||||
@@ -794,7 +807,6 @@ void Segment::refreshLightCapabilities() {
|
||||
* Fills segment with color
|
||||
*/
|
||||
void Segment::fill(uint32_t c) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const uint16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
@@ -810,7 +822,6 @@ void Segment::blendPixelColor(int n, uint32_t color, uint8_t blend) {
|
||||
|
||||
// Adds the specified color with the existing pixel color perserving color balance.
|
||||
void Segment::addPixelColor(int n, uint32_t color, bool fast) {
|
||||
if (!isActive()) return; // not active
|
||||
uint32_t col = getPixelColor(n);
|
||||
uint8_t r = R(col);
|
||||
uint8_t g = G(col);
|
||||
@@ -829,7 +840,6 @@ void Segment::addPixelColor(int n, uint32_t color, bool fast) {
|
||||
}
|
||||
|
||||
void Segment::fadePixelColor(uint16_t n, uint8_t fade) {
|
||||
if (!isActive()) return; // not active
|
||||
CRGB pix = CRGB(getPixelColor(n)).nscale8_video(fade);
|
||||
setPixelColor(n, pix);
|
||||
}
|
||||
@@ -838,7 +848,6 @@ void Segment::fadePixelColor(uint16_t n, uint8_t fade) {
|
||||
* fade out function, higher rate = quicker fade
|
||||
*/
|
||||
void Segment::fade_out(uint8_t rate) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const uint16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
|
||||
@@ -876,7 +885,6 @@ void Segment::fade_out(uint8_t rate) {
|
||||
|
||||
// fades all pixels to black using nscale8()
|
||||
void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply
|
||||
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const uint16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
|
||||
@@ -891,26 +899,23 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
*/
|
||||
void Segment::blur(uint8_t blur_amount)
|
||||
{
|
||||
if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur"
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (is2D()) {
|
||||
// compatibility with 2D
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
for (uint_fast16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
|
||||
for (uint_fast16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (uint16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
|
||||
for (uint16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
uint_fast16_t vlength = virtualLength();
|
||||
for(uint_fast16_t i = 0; i < vlength; i++)
|
||||
for(uint16_t i = 0; i < virtualLength(); i++)
|
||||
{
|
||||
CRGB cur = CRGB(getPixelColor(i));
|
||||
CRGB part = cur;
|
||||
CRGB before = cur; // remember color before blur
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
@@ -919,10 +924,9 @@ void Segment::blur(uint8_t blur_amount)
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
|
||||
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
|
||||
}
|
||||
if (before != cur) // optimization: only set pixel if color has changed
|
||||
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue);
|
||||
setPixelColor(i,cur.red, cur.green, cur.blue);
|
||||
carryover = part;
|
||||
}
|
||||
}
|
||||
@@ -1057,6 +1061,24 @@ void WS2812FX::finalizeInit(void)
|
||||
Segment::maxHeight = 1;
|
||||
}
|
||||
|
||||
//initialize leds array. TBD: realloc if nr of leds change
|
||||
if (Segment::_globalLeds) {
|
||||
purgeSegments(true);
|
||||
free(Segment::_globalLeds);
|
||||
Segment::_globalLeds = nullptr;
|
||||
}
|
||||
if (useLedsArray) {
|
||||
size_t arrSize = sizeof(CRGB) * getLengthTotal();
|
||||
// softhack007 disabled; putting leds into psram leads to horrible slowdown on WROVER boards (see setUpLeds())
|
||||
//#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
//if (psramFound())
|
||||
// Segment::_globalLeds = (CRGB*) ps_malloc(arrSize);
|
||||
//else
|
||||
//#endif
|
||||
Segment::_globalLeds = (CRGB*) malloc(arrSize);
|
||||
memset(Segment::_globalLeds, 0, arrSize);
|
||||
}
|
||||
|
||||
//segments are created in makeAutoSegments();
|
||||
DEBUG_PRINTLN(F("Loading custom palettes"));
|
||||
loadCustomPalettes(); // (re)load all custom palettes
|
||||
@@ -1065,23 +1087,23 @@ void WS2812FX::finalizeInit(void)
|
||||
}
|
||||
|
||||
void WS2812FX::service() {
|
||||
unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
now = nowUp + timebase;
|
||||
if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
|
||||
bool doShow = false;
|
||||
|
||||
_isServicing = true;
|
||||
_segment_index = 0;
|
||||
Segment::handleRandomPalette(); // move it into for loop when each segment has individual random palette
|
||||
for (segment &seg : _segments) {
|
||||
// process transition (mode changes in the middle of transition)
|
||||
seg.handleTransition();
|
||||
// reset the segment runtime data if needed
|
||||
seg.resetIfRequired();
|
||||
|
||||
if (!seg.isActive()) continue;
|
||||
|
||||
// last condition ensures all solid segments are updated at the same time
|
||||
if (seg.isActive() && (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)))
|
||||
if(nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
|
||||
{
|
||||
if (seg.grouping == 0) seg.grouping = 1; //sanity check
|
||||
doShow = true;
|
||||
uint16_t delay = FRAMETIME;
|
||||
|
||||
@@ -1101,28 +1123,22 @@ void WS2812FX::service() {
|
||||
delay = (*_mode[seg.currentMode(seg.mode)])();
|
||||
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
||||
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||
|
||||
seg.handleTransition();
|
||||
}
|
||||
|
||||
seg.next_time = nowUp + delay;
|
||||
}
|
||||
if (_segment_index == _queuedChangesSegId) setUpSegmentFromQueuedChanges();
|
||||
_segment_index++;
|
||||
}
|
||||
_virtualSegmentLength = 0;
|
||||
busses.setSegmentCCT(-1);
|
||||
_isServicing = false;
|
||||
_triggered = false;
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTLN(F("Slow effects."));
|
||||
#endif
|
||||
if (doShow) {
|
||||
if(doShow) {
|
||||
yield();
|
||||
show();
|
||||
}
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTLN(F("Slow strip."));
|
||||
#endif
|
||||
_triggered = false;
|
||||
_isServicing = false;
|
||||
}
|
||||
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col)
|
||||
@@ -1151,7 +1167,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
#define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
|
||||
uint8_t WS2812FX::estimateCurrentAndLimitBri() {
|
||||
void WS2812FX::estimateCurrentAndLimitBri() {
|
||||
//power limit calculation
|
||||
//each LED can draw up 195075 "power units" (approx. 53mA)
|
||||
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step
|
||||
@@ -1159,28 +1175,35 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() {
|
||||
bool useWackyWS2815PowerModel = false;
|
||||
byte actualMilliampsPerLed = milliampsPerLed;
|
||||
|
||||
if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
|
||||
currentMilliamps = 0;
|
||||
return _brightness;
|
||||
}
|
||||
|
||||
if (milliampsPerLed == 255) {
|
||||
if(milliampsPerLed == 255) {
|
||||
useWackyWS2815PowerModel = true;
|
||||
actualMilliampsPerLed = 12; // from testing an actual strip
|
||||
}
|
||||
|
||||
size_t powerBudget = (ablMilliampsMax - MA_FOR_ESP); //100mA for ESP power
|
||||
if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
|
||||
currentMilliamps = 0;
|
||||
busses.setBrightness(_brightness);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t pLen = getLengthPhysical();
|
||||
uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed;
|
||||
uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power
|
||||
if (powerBudget > puPerMilliamp * pLen) { //each LED uses about 1mA in standby, exclude that from power budget
|
||||
powerBudget -= puPerMilliamp * pLen;
|
||||
} else {
|
||||
powerBudget = 0;
|
||||
}
|
||||
|
||||
uint32_t powerSum = 0;
|
||||
|
||||
size_t pLen = 0; //getLengthPhysical();
|
||||
size_t powerSum = 0;
|
||||
for (uint_fast8_t bNum = 0; bNum < busses.getNumBusses(); bNum++) {
|
||||
Bus *bus = busses.getBus(bNum);
|
||||
if (!IS_DIGITAL(bus->getType())) continue; //exclude non-digital network busses
|
||||
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
|
||||
uint16_t len = bus->getLength();
|
||||
pLen += len;
|
||||
uint32_t busPowerSum = 0;
|
||||
for (uint_fast16_t i = 0; i < len; i++) { //sum up the usage of each LED
|
||||
uint32_t c = bus->getPixelColor(i); // always returns original or restored color without brightness scaling
|
||||
uint32_t c = bus->getPixelColor(i);
|
||||
byte r = R(c), g = G(c), b = B(c), w = W(c);
|
||||
|
||||
if(useWackyWS2815PowerModel) { //ignore white component on WS2815 power calculation
|
||||
@@ -1192,56 +1215,47 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() {
|
||||
|
||||
if (bus->hasWhite()) { //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
|
||||
busPowerSum *= 3;
|
||||
busPowerSum >>= 2; //same as /= 4
|
||||
busPowerSum = busPowerSum >> 2; //same as /= 4
|
||||
}
|
||||
powerSum += busPowerSum;
|
||||
}
|
||||
|
||||
if (powerBudget > pLen) { //each LED uses about 1mA in standby, exclude that from power budget
|
||||
powerBudget -= pLen;
|
||||
} else {
|
||||
powerBudget = 0;
|
||||
}
|
||||
uint32_t powerSum0 = powerSum;
|
||||
powerSum *= _brightness;
|
||||
|
||||
// powerSum has all the values of channels summed (max would be pLen*765 as white is excluded) so convert to milliAmps
|
||||
powerSum = (powerSum * actualMilliampsPerLed) / 765;
|
||||
|
||||
uint8_t newBri = _brightness;
|
||||
if (powerSum * _brightness / 255 > powerBudget) { //scale brightness down to stay in current limit
|
||||
float scale = (float)(powerBudget * 255) / (float)(powerSum * _brightness);
|
||||
if (powerSum > powerBudget) //scale brightness down to stay in current limit
|
||||
{
|
||||
float scale = (float)powerBudget / (float)powerSum;
|
||||
uint16_t scaleI = scale * 255;
|
||||
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
||||
newBri = scale8(_brightness, scaleB) + 1;
|
||||
uint8_t newBri = scale8(_brightness, scaleB);
|
||||
busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too
|
||||
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
|
||||
} else {
|
||||
currentMilliamps = powerSum / puPerMilliamp;
|
||||
busses.setBrightness(_brightness);
|
||||
}
|
||||
currentMilliamps = (powerSum * newBri) / 255;
|
||||
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
|
||||
currentMilliamps += pLen; //add standby power (1mA/LED) back to estimate
|
||||
return newBri;
|
||||
currentMilliamps += pLen; //add standby power back to estimate
|
||||
}
|
||||
|
||||
void WS2812FX::show(void) {
|
||||
|
||||
// avoid race condition, caputre _callback value
|
||||
show_callback callback = _callback;
|
||||
if (callback) callback();
|
||||
|
||||
uint8_t newBri = estimateCurrentAndLimitBri();
|
||||
busses.setBrightness(newBri); // "repaints" all pixels if brightness changed
|
||||
estimateCurrentAndLimitBri();
|
||||
|
||||
// some buses send asynchronously and this method will return before
|
||||
// all of the data has been sent.
|
||||
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
busses.show();
|
||||
|
||||
// restore bus brightness to its original value
|
||||
// this is done right after show, so this is only OK if LED updates are completed before show() returns
|
||||
// or async show has a separate buffer (ESP32 RMT and I2S are ok)
|
||||
if (newBri < _brightness) busses.setBrightness(_brightness);
|
||||
|
||||
unsigned long now = millis();
|
||||
size_t diff = now - _lastShow;
|
||||
size_t fpsCurr = 200;
|
||||
unsigned long diff = now - _lastShow;
|
||||
uint16_t fpsCurr = 200;
|
||||
if (diff > 0) fpsCurr = 1000 / diff;
|
||||
_cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5)
|
||||
_cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2;
|
||||
_lastShow = now;
|
||||
}
|
||||
|
||||
@@ -1274,7 +1288,7 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||
|
||||
if (_segments[segid].mode != m) {
|
||||
_segments[segid].startTransition(_transitionDur); // set effect transitions
|
||||
_segments[segid].markForReset();
|
||||
//_segments[segid].markForReset();
|
||||
_segments[segid].mode = m;
|
||||
}
|
||||
}
|
||||
@@ -1298,8 +1312,6 @@ void WS2812FX::setCCT(uint16_t k) {
|
||||
}
|
||||
}
|
||||
|
||||
// direct=true either expects the caller to call show() themselves (realtime modes) or be ok waiting for the next frame for the change to apply
|
||||
// direct=false immediately triggers an effect redraw
|
||||
void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
if (gammaCorrectBri) b = gamma8(b);
|
||||
if (_brightness == b) return;
|
||||
@@ -1309,12 +1321,12 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
seg.freeze = false;
|
||||
}
|
||||
}
|
||||
// setting brightness with NeoPixelBusLg has no effect on already painted pixels,
|
||||
// so we need to force an update to existing buffer
|
||||
busses.setBrightness(b);
|
||||
if (!direct) {
|
||||
if (direct) {
|
||||
// would be dangerous if applied immediately (could exceed ABL), but will not output until the next show()
|
||||
busses.setBrightness(b);
|
||||
} else {
|
||||
unsigned long t = millis();
|
||||
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon
|
||||
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1421,32 +1433,9 @@ Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors
|
||||
}
|
||||
|
||||
// sets new segment bounds, queues if that segment is currently running
|
||||
void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
|
||||
if (segId >= getSegmentsNum()) {
|
||||
if (i2 <= i1) return; // do not append empty/inactive segments
|
||||
appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
segId = getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
|
||||
if (_queuedChangesSegId == segId) _queuedChangesSegId = 255; // cancel queued change if already queued for this segment
|
||||
|
||||
if (segId < getMaxSegments() && segId == getCurrSegmentId() && isServicing()) { // queue change to prevent concurrent access
|
||||
// queuing a change for a second segment will lead to the loss of the first change if not yet applied
|
||||
// however this is not a problem as the queued change is applied immediately after the effect function in that segment returns
|
||||
_qStart = i1; _qStop = i2; _qStartY = startY; _qStopY = stopY;
|
||||
_qGrouping = grouping; _qSpacing = spacing; _qOffset = offset;
|
||||
_queuedChangesSegId = segId;
|
||||
return; // queued changes are applied immediately after effect function returns
|
||||
}
|
||||
|
||||
_segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||
}
|
||||
|
||||
void WS2812FX::setUpSegmentFromQueuedChanges() {
|
||||
if (_queuedChangesSegId >= getSegmentsNum()) return;
|
||||
getSegment(_queuedChangesSegId).setUp(_qStart, _qStop, _qGrouping, _qSpacing, _qOffset, _qStartY, _qStopY);
|
||||
_queuedChangesSegId = 255;
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
|
||||
if (n >= _segments.size()) return;
|
||||
_segments[n].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||
}
|
||||
|
||||
void WS2812FX::restartRuntime() {
|
||||
@@ -1602,7 +1591,7 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) {
|
||||
}
|
||||
|
||||
void WS2812FX::setTransitionMode(bool t) {
|
||||
for (segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0);
|
||||
for (segment &seg : _segments) if (!seg.transitional) seg.startTransition(t ? _transitionDur : 0);
|
||||
}
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
@@ -1614,7 +1603,7 @@ void WS2812FX::printSize() {
|
||||
DEBUG_PRINTF("Data: %d*%d=%uB\n", sizeof(const char *), _modeData.size(), (_modeData.capacity()*sizeof(const char *)));
|
||||
DEBUG_PRINTF("Map: %d*%d=%uB\n", sizeof(uint16_t), (int)customMappingSize, customMappingSize*sizeof(uint16_t));
|
||||
size = getLengthTotal();
|
||||
if (useGlobalLedBuffer) DEBUG_PRINTF("Buffer: %d*%u=%uB\n", sizeof(CRGB), size, size*sizeof(CRGB));
|
||||
if (useLedsArray) DEBUG_PRINTF("Buffer: %d*%u=%uB\n", sizeof(CRGB), size, size*sizeof(CRGB));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+4
-10
@@ -9,9 +9,9 @@
|
||||
#include <IPAddress.h>
|
||||
|
||||
#define NODE_TYPE_ID_UNDEFINED 0
|
||||
#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_ESP8266 82
|
||||
#define NODE_TYPE_ID_ESP32 32
|
||||
#define NODE_TYPE_ID_ESP32S2 33
|
||||
#define NODE_TYPE_ID_ESP32S3 34
|
||||
#define NODE_TYPE_ID_ESP32C3 35
|
||||
|
||||
@@ -23,13 +23,7 @@ struct NodeStruct
|
||||
String nodeName;
|
||||
IPAddress ip;
|
||||
uint8_t age;
|
||||
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;
|
||||
};
|
||||
};
|
||||
uint8_t nodeType;
|
||||
uint32_t build;
|
||||
|
||||
NodeStruct() : age(0), nodeType(0), build(0)
|
||||
|
||||
+66
-138
@@ -91,168 +91,96 @@ 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, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
|
||||
, _skip(bc.skipAmount) //sacrificial pixels
|
||||
, _colorOrder(bc.colorOrder)
|
||||
, _colorOrderMap(com)
|
||||
{
|
||||
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite), _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;
|
||||
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);
|
||||
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);
|
||||
_valid = (_busPtr != nullptr);
|
||||
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);
|
||||
_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);
|
||||
}
|
||||
|
||||
void BusDigital::show() {
|
||||
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;
|
||||
else pix += _skip;
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
|
||||
}
|
||||
}
|
||||
PolyBus::show(_busPtr, _iType, !_buffering); // faster if buffer consistency is not important
|
||||
PolyBus::show(_busPtr, _iType);
|
||||
}
|
||||
|
||||
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, covered by guard if above
|
||||
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) reinit();
|
||||
if (_bri == 0 && b > 0) {
|
||||
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
|
||||
}
|
||||
#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 (_valid && _skip) {
|
||||
if (_skip && canShow()) {
|
||||
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
|
||||
if (canShow()) PolyBus::show(_busPtr, _iType);
|
||||
PolyBus::show(_busPtr, _iType);
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (!_valid) return;
|
||||
if (Bus::hasWhite(_type)) c = autoWhiteCalc(c);
|
||||
if (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814 || _type == TYPE_WS2812_1CH_X3) c = autoWhiteCalc(c);
|
||||
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
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 (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 (Bus::hasWhite(_type)) _data[offset] = W(c);
|
||||
} else {
|
||||
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 = 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 (!_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;
|
||||
else 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, co);
|
||||
}
|
||||
|
||||
uint8_t BusDigital::getPins(uint8_t* pinArray) {
|
||||
@@ -268,7 +196,6 @@ void BusDigital::setColorOrder(uint8_t colorOrder) {
|
||||
}
|
||||
|
||||
void BusDigital::reinit() {
|
||||
if (!_valid) return;
|
||||
PolyBus::begin(_busPtr, _iType, _pins);
|
||||
}
|
||||
|
||||
@@ -278,15 +205,13 @@ 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, 1, bc.reversed)
|
||||
{
|
||||
BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
_valid = false;
|
||||
if (!IS_PWM(bc.type)) return;
|
||||
uint8_t numPins = NUM_PWM_PINS(bc.type);
|
||||
_frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ;
|
||||
@@ -304,7 +229,7 @@ BusPwm::BusPwm(BusConfig &bc)
|
||||
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
|
||||
@@ -314,7 +239,7 @@ BusPwm::BusPwm(BusConfig &bc)
|
||||
ledcAttachPin(_pins[i], _ledcStart + i);
|
||||
#endif
|
||||
}
|
||||
_data = _pwmdata; // avoid malloc() and use stack
|
||||
reversed = bc.reversed;
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
@@ -382,7 +307,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
|
||||
@@ -417,10 +342,8 @@ void BusPwm::deallocatePins() {
|
||||
}
|
||||
|
||||
|
||||
BusOnOff::BusOnOff(BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
||||
, _onoffdata(0)
|
||||
{
|
||||
BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
_valid = false;
|
||||
if (bc.type != TYPE_ONOFF) return;
|
||||
|
||||
uint8_t currentPin = bc.pins[0];
|
||||
@@ -429,7 +352,7 @@ BusOnOff::BusOnOff(BusConfig &bc)
|
||||
}
|
||||
_pin = currentPin; //store only after allocatePin() succeeds
|
||||
pinMode(_pin, OUTPUT);
|
||||
_data = &_onoffdata; // avoid malloc() and use stack
|
||||
reversed = bc.reversed;
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
@@ -440,17 +363,18 @@ 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[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
|
||||
_data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) {
|
||||
if (!_valid) return 0;
|
||||
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
|
||||
return RGBW32(_data, _data, _data, _data);
|
||||
}
|
||||
|
||||
void BusOnOff::show() {
|
||||
if (!_valid) return;
|
||||
digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]);
|
||||
digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data);
|
||||
}
|
||||
|
||||
uint8_t BusOnOff::getPins(uint8_t* pinArray) {
|
||||
@@ -460,10 +384,8 @@ uint8_t BusOnOff::getPins(uint8_t* pinArray) {
|
||||
}
|
||||
|
||||
|
||||
BusNetwork::BusNetwork(BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count)
|
||||
, _broadcastLock(false)
|
||||
{
|
||||
BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
_valid = false;
|
||||
switch (bc.type) {
|
||||
case TYPE_NET_ARTNET_RGB:
|
||||
_rgbw = false;
|
||||
@@ -479,13 +401,18 @@ BusNetwork::BusNetwork(BusConfig &bc)
|
||||
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]);
|
||||
_valid = (allocData(_len * _UDPchannels) != nullptr);
|
||||
_broadcastLock = false;
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (!_valid || pix >= _len) return;
|
||||
if (_rgbw) c = autoWhiteCalc(c);
|
||||
if (hasWhite()) c = autoWhiteCalc(c);
|
||||
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
uint16_t offset = pix * _UDPchannels;
|
||||
_data[offset] = R(c);
|
||||
@@ -497,7 +424,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] : 0));
|
||||
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], _rgbw ? (_data[offset+3] << 24) : 0);
|
||||
}
|
||||
|
||||
void BusNetwork::show() {
|
||||
@@ -517,7 +444,8 @@ uint8_t BusNetwork::getPins(uint8_t* pinArray) {
|
||||
void BusNetwork::cleanup() {
|
||||
_type = I_NONE;
|
||||
_valid = false;
|
||||
freeData();
|
||||
if (_data != nullptr) free(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -578,7 +506,7 @@ void BusManager::setStatusPixel(uint32_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
Bus* b = busses[i];
|
||||
uint16_t bstart = b->getStart();
|
||||
|
||||
+149
-109
@@ -18,10 +18,6 @@
|
||||
#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;
|
||||
@@ -34,25 +30,15 @@ struct BusConfig {
|
||||
uint8_t autoWhite;
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||
uint16_t frequency;
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
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)
|
||||
size_t nPins = 1;
|
||||
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; autoWhite = aw; frequency = clock_kHz;
|
||||
uint8_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 (size_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
}
|
||||
|
||||
//validates start and length and extends total if needed
|
||||
@@ -68,7 +54,6 @@ struct BusConfig {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Defines an LED Strip and its color ordering.
|
||||
struct ColorOrderMapEntry {
|
||||
uint16_t start;
|
||||
@@ -79,7 +64,9 @@ 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;
|
||||
@@ -100,63 +87,56 @@ 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, uint16_t len = 1, bool reversed = false, bool refresh = false)
|
||||
: _type(type)
|
||||
, _bri(255)
|
||||
, _start(start)
|
||||
, _len(len)
|
||||
, _reversed(reversed)
|
||||
Bus(uint8_t type, uint16_t start, uint8_t aw)
|
||||
: _bri(255)
|
||||
, _len(1)
|
||||
, _valid(false)
|
||||
, _needsRefresh(refresh)
|
||||
, _data(nullptr) // keep data access consistent across all types of buses
|
||||
, _needsRefresh(false)
|
||||
{
|
||||
_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 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; }
|
||||
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; }
|
||||
bool containsPixel(uint16_t pix) { return pix >= _start && pix < _start+_len; }
|
||||
|
||||
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;
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
virtual bool hasWhite(void) { return Bus::hasWhite(_type); }
|
||||
virtual bool hasWhite() { 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(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;
|
||||
virtual bool hasCCT() {
|
||||
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) {
|
||||
@@ -175,87 +155,107 @@ 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(); }
|
||||
|
||||
void show();
|
||||
inline void show();
|
||||
|
||||
bool canShow();
|
||||
|
||||
void setBrightness(uint8_t b);
|
||||
|
||||
void setStatusPixel(uint32_t c);
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
void setColorOrder(uint8_t colorOrder);
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
void reinit();
|
||||
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
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;
|
||||
~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;
|
||||
const ColorOrderMap &_colorOrderMap;
|
||||
};
|
||||
|
||||
|
||||
class BusPwm : public Bus {
|
||||
public:
|
||||
BusPwm(BusConfig &bc);
|
||||
~BusPwm() { cleanup(); }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
uint32_t getPixelColor(uint16_t pix); //does no index check
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
uint16_t getFrequency() { return _frequency; }
|
||||
|
||||
//does no index check
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
void show();
|
||||
void cleanup() { deallocatePins(); }
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
|
||||
uint16_t getFrequency() { return _frequency; }
|
||||
|
||||
void cleanup() {
|
||||
deallocatePins();
|
||||
}
|
||||
|
||||
~BusPwm() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _pins[5];
|
||||
uint8_t _pwmdata[5];
|
||||
uint8_t _pins[5] = {255, 255, 255, 255, 255};
|
||||
uint8_t _data[5] = {0};
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t _ledcStart;
|
||||
uint8_t _ledcStart = 255;
|
||||
#endif
|
||||
uint16_t _frequency;
|
||||
uint16_t _frequency = 0U;
|
||||
|
||||
void deallocatePins();
|
||||
};
|
||||
@@ -264,46 +264,72 @@ 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();
|
||||
void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); }
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
|
||||
void cleanup() {
|
||||
pinManager.deallocatePin(_pin, PinOwner::BusOnOff);
|
||||
}
|
||||
|
||||
~BusOnOff() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _pin;
|
||||
uint8_t _onoffdata;
|
||||
uint8_t _pin = 255;
|
||||
uint8_t _data = 0;
|
||||
};
|
||||
|
||||
|
||||
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() : numBusses(0) {};
|
||||
BusManager() {};
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
static uint32_t memUsage(BusConfig &bc);
|
||||
@@ -314,24 +340,38 @@ class BusManager {
|
||||
void removeAll();
|
||||
|
||||
void show();
|
||||
bool canAllShow();
|
||||
|
||||
void setStatusPixel(uint32_t c);
|
||||
void setPixelColor(uint16_t pix, 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();
|
||||
|
||||
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 void updateColorOrderMap(const ColorOrderMap &com) {
|
||||
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
|
||||
}
|
||||
|
||||
inline const ColorOrderMap& getColorOrderMap() const {
|
||||
return colorOrderMap;
|
||||
}
|
||||
|
||||
inline uint8_t getNumBusses() {
|
||||
return numBusses;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t numBusses;
|
||||
uint8_t numBusses = 0;
|
||||
Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||
ColorOrderMap colorOrderMap;
|
||||
|
||||
@@ -341,4 +381,4 @@ class BusManager {
|
||||
return j;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
+72
-87
@@ -122,9 +122,6 @@
|
||||
#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
|
||||
@@ -250,11 +247,7 @@
|
||||
#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
|
||||
@@ -280,7 +273,6 @@ 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) {
|
||||
@@ -289,7 +281,6 @@ 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;
|
||||
@@ -392,8 +383,7 @@ 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) {
|
||||
@@ -494,106 +484,104 @@ class PolyBus {
|
||||
}
|
||||
begin(busPtr, busType, pins, clock_kHz);
|
||||
return busPtr;
|
||||
}
|
||||
|
||||
static void show(void* busPtr, uint8_t busType, bool consistent = true) {
|
||||
};
|
||||
static void show(void* busPtr, uint8_t busType) {
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
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;
|
||||
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;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
// 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;
|
||||
// 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;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
// 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;
|
||||
// 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;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
// 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;
|
||||
// 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;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
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;
|
||||
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;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
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;
|
||||
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;
|
||||
#endif
|
||||
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->Show(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
// 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;
|
||||
// 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;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
static bool canShow(void* busPtr, uint8_t busType) {
|
||||
switch (busType) {
|
||||
case I_NONE: return true;
|
||||
@@ -690,8 +678,7 @@ 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;
|
||||
@@ -811,8 +798,7 @@ 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;
|
||||
@@ -909,8 +895,7 @@ 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) {
|
||||
@@ -1217,4 +1202,4 @@ class PolyBus {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+11
-37
@@ -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(useGlobalLedBuffer, hw_led[F("ld")]);
|
||||
CJSON(strip.useLedsArray, hw_led[F("ld")]);
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
@@ -134,8 +134,7 @@ 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, globalBufMem = 0;
|
||||
uint16_t maxlen = 0;
|
||||
uint32_t mem = 0;
|
||||
bool busesChanged = false;
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
|
||||
@@ -161,16 +160,12 @@ 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, useGlobalLedBuffer);
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz);
|
||||
mem += BusManager::memUsage(bc);
|
||||
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()
|
||||
if (mem <= 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, freqkHz, useGlobalLedBuffer);
|
||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
|
||||
busesChanged = true;
|
||||
}
|
||||
s++;
|
||||
@@ -178,7 +173,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
doInitBusses = busesChanged;
|
||||
// finalization done in beginStrip()
|
||||
}
|
||||
if (hw_led["rev"]) busses.getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
|
||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||
|
||||
// read color order map configuration
|
||||
JsonArray hw_com = hw[F("com")];
|
||||
@@ -202,9 +197,6 @@ 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"]);
|
||||
@@ -272,7 +264,6 @@ 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 {
|
||||
@@ -285,7 +276,6 @@ 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);
|
||||
@@ -307,11 +297,9 @@ 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
|
||||
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);
|
||||
Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called prior)
|
||||
#endif
|
||||
Wire.begin();
|
||||
} else {
|
||||
i2c_sda = -1;
|
||||
i2c_scl = -1;
|
||||
@@ -348,7 +336,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) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal);
|
||||
} else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
@@ -453,13 +441,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
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"]);
|
||||
@@ -716,7 +697,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")] = useGlobalLedBuffer;
|
||||
hw_led[F("ld")] = strip.useLedsArray;
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
@@ -751,7 +732,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->isReversed();
|
||||
ins["rev"] = bus->reversed;
|
||||
ins[F("skip")] = bus->skippedLeds();
|
||||
ins["type"] = bus->getType() & 0x7F;
|
||||
ins["ref"] = bus->isOffRefreshRequired();
|
||||
@@ -912,13 +893,6 @@ 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;
|
||||
|
||||
+14
-9
@@ -302,7 +302,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
||||
}
|
||||
|
||||
//gamma 2.8 lookup table used for color correction
|
||||
uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
||||
static byte gammaT[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
@@ -320,22 +320,27 @@ uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
||||
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 };
|
||||
|
||||
// re-calculates & fills gamma table
|
||||
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||
uint8_t gamma8_cal(uint8_t b, float gamma)
|
||||
{
|
||||
for (size_t i = 0; i < 256; i++) {
|
||||
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
|
||||
return (int)(powf((float)b / 255.0f, gamma) * 255.0f + 0.5f);
|
||||
}
|
||||
|
||||
// re-calculates & fills gamma table
|
||||
void calcGammaTable(float gamma)
|
||||
{
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
gammaT[i] = gamma8_cal(i, gamma);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t NeoGammaWLEDMethod::Correct(uint8_t value)
|
||||
// used for individual channel or brightness gamma correction
|
||||
uint8_t gamma8(uint8_t b)
|
||||
{
|
||||
if (!gammaCorrectCol) return value;
|
||||
return gammaT[value];
|
||||
return gammaT[b];
|
||||
}
|
||||
|
||||
// used for color gamma correction
|
||||
uint32_t NeoGammaWLEDMethod::Correct32(uint32_t color)
|
||||
uint32_t gamma32(uint32_t color)
|
||||
{
|
||||
if (!gammaCorrectCol) return color;
|
||||
uint8_t w = W(color);
|
||||
|
||||
+4
-41
@@ -91,21 +91,6 @@
|
||||
#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
|
||||
@@ -148,7 +133,6 @@
|
||||
#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_WIREGUARD 41 //Usermod "wireguard.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@@ -336,8 +320,7 @@
|
||||
|
||||
// WLED Error modes
|
||||
#define ERR_NONE 0 // All good :)
|
||||
#define ERR_DENIED 1 // Permission denied
|
||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) OBSOLETE
|
||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)
|
||||
#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?)
|
||||
@@ -349,29 +332,12 @@
|
||||
#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
|
||||
|
||||
@@ -404,7 +370,7 @@
|
||||
#ifdef ESP8266
|
||||
#define SETTINGS_STACK_BUF_SIZE 2048
|
||||
#else
|
||||
#define SETTINGS_STACK_BUF_SIZE 3608 // warning: quite a large value for stack
|
||||
#define SETTINGS_STACK_BUF_SIZE 3096
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
@@ -476,10 +442,7 @@
|
||||
#define DEFAULT_LED_COUNT 30
|
||||
#endif
|
||||
|
||||
#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
|
||||
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
|
||||
|
||||
// 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)
|
||||
|
||||
+1
-1
@@ -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>
|
||||
@@ -0,0 +1,129 @@
|
||||
@font-face {
|
||||
font-family: "CIcons";
|
||||
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAApMAAsAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIGEWNtYXAAAAFoAAAAVAAAAFQXVtKTZ2FzcAAAAbwAAAAIAAAACAAAABBnbHlmAAABxAAABfwAAAX8iNRp/2hlYWQAAAfAAAAANgAAADYd+7tRaGhlYQAAB/gAAAAkAAAAJAeYA9JobXR4AAAIHAAAAEQAAABEOgAGTGxvY2EAAAhgAAAAJAAAACQItgqAbWF4cAAACIQAAAAgAAAAIAAWAExuYW1lAAAIpAAAAYYAAAGGmUoJ+3Bvc3QAAAosAAAAIAAAACAAAwAAAAMD2wGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA6QwDwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADgAAAAKAAgAAgACAAEAIOkM//3//wAAAAAAIOkA//3//wAB/+MXBAADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQDWAIEDKgLVAAsAAAEhESMRITUhETMRIQMq/wBU/wABAFQBAAGB/wABAFQBAP8AAAAAAAIAgAArA7gDYwANABEAAAEXBzMRIREzJxUhESEVAREhEQLG8vK6/qqc8P6qAVb+qgFWA2Py8P6qAVbwnAFWuv26AVb+qgAAAAEAqgABA4ADVQAlAAABMxEhERQHBisBIicmNREhNSMVFAcGIyEiJyY9ATQ3NjMhMhcWFQMAgP6qDAwSVhIMDAGqKgwMEv4AEg0NDQ0SAgASDAwDAf6q/oASDAwMDBIB1qoqEg0NDQ0SqhIMDAwMEgABAQAAKwMqAysAEwAAASEVIxEjBgcGIyInJjU0NzYzMhcCAAEqqgIINjZKUDg4ODhQHCQDK4D+KkgxMTg4UFA4OAwAAAIAVgArA4ADKwALAB0AAAEWFRQHAScBNjMyFwEyFxYVFAcGIyInMjc2NTQ3NgN0DAz+gnYBfgwSEgz98DQmJjIyRmhCHhsbJiYC5QwSEgz+gnYBfgwM/jYmJjRGMjJWFxcmNCYmAAAAAQCSAIEDgAK9AAUAACUBFwEnNwGAAcQ8/gDuPPkBxDz+AO48AAAAAAIAqv/VA1YDgQAQACEAAAEWFRQHBiMVJzcVMjc2NTQnJyIHBhUUFwcmNTQ3NjM1FwcDIDZlZYyqqmpLSx7iaktLHj42ZWWMqqoCYVJkjGVlgKyqgEtLajw8iEtLakA4PlJkjGVlgKyqAAAAAAEAVgABA9YDgQA/AAABMhcWFRQHBisBFRQHBisBNTQnJiMiBwYdASMiJyY9ATMyNzY1NCcmKwE1NDc2OwE1NDc2MzIXFh0BMzIXFh0BA2osICAgICxAGRkioiIiMDAiIqIiGRlAMCEhISEwQBkZIqwfHywsHx+sIhkZAdUfHywsHx+sIhkZQDAhISEhMEAZGSKiIiIwMCIioiIZGUAsICAgICxAGRkirAAAAAACAFYAHQOqAysAIgA+AAAlNjc2NzY3NjU0JyYjIgcGByMmJyYjIgcGFRQXFhcWFxYfARMyFxYVFAcGBwYHBg8BJyYnJicmNTQ3NjMyFzYCBGAuLjY2FRUrK0AyKysQUBArKzJAKysVFTY2Li5gBMBkQ0MWFjs7MDBqPj6KPT00NENDZHRMTJNWLCw8PC4uLEAqKhwcLCwcHCoqQCwuLjw8LCxWBAKcRERiOjc3REQuLmA4Nnw+PlRUTmJERFpaAAAEAFYAAQOqA1UAAwATACMAJwAAATUzFQMyNzY1NCcmIyIHBhUUFxYTMhcWFRQHBiMiJyY1NDc2ExEzEQHWVCqMZWVlZYyMZWVlZYywfX19fbCwfX19fYZUAitWVv4qZWWMjGVlZWWMjGVlAwB9fbCwfX19fbCwfX39gAEA/wAAAAIAZAABA5wDVQAPAEkAAAEyNzY1NCcmIyIHBhUUFxYlFxYPAQYvAQYPAQYrASIvASYnBwYvASY/ASY1NDcnJj8BNh8BNj8BNjsBMh8BFhc3Nh8BFg8BFhUUAgA+LCwsLD4+LCwsLAF8Wg4KVggSaioeEAQQrBAEECYiahIIVgoOWgICWg4KVggSaioeEAQQrBAEECYiahIIVgoOWgIBFSwsPj4sLCwsPj4sLGxGChKUDgYqHgxwEhJwEBoqBg6UEgpGDhwcDkYKEpQOBioeDHASEnAQGioGDpQSCkYOHBwAAwAq/9UD1gOBAAcADwAXAAABPwEvAQ8BFwUnDwEfAT8BFw8BHwE/AScDKjZ2djY0dnb+9Gpq7OxqauxUNHZ2NDZ2dgIrdjQ2dnY2NIzs7Gpq7OxqgHY0NnZ2NjQAAAAAAwAqAFUD1gLtAA0AEwAdAAATNjMyFwcmJyYjIgcGBxc2MzIXBwE2ISAXByYjIgfWfK+velQkPz80ND8/JFY2Sko2gP4qxAETARPCVqDg4KABgXp6ViQaGhoaJFY2NoAB1sLCVp6eAAABAAAAAAAA3GG4ZV8PPPUACwQAAAAAAN2Du38AAAAA3YO7fwAA/9UD1gOBAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAAAAAPWAAEAAAAAAAAAAAAAAAAAAAARBAAAAAAAAAAAAAAAAgAAAAQAANYEAACABAAAqgQAAQAEAABWBAAAkgQAAKoEAABWBAAAVgQAAFYEAABkBAAAKgQAACoAAAAAAAoAFAAeADgAXACUALYA6gD+ATQBigHqAioCmgLKAv4AAQAAABEASgAEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGljb21vb24AaQBjAG8AbQBvAG8AblZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGljb21vb24AaQBjAG8AbQBvAG8Abmljb21vb24AaQBjAG8AbQBvAG8AblJlZ3VsYXIAUgBlAGcAdQBsAGEAcmljb21vb24AaQBjAG8AbQBvAG8AbkZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format('woff');
|
||||
}
|
||||
|
||||
:root {
|
||||
--c-1: #111;
|
||||
--c-f: #fff;
|
||||
--c-2: #222;
|
||||
--c-3: #333;
|
||||
--c-4: #444;
|
||||
--c-5: #555;
|
||||
--c-6: #666;
|
||||
--c-8: #888;
|
||||
--c-b: #bbb;
|
||||
--c-c: #ccc;
|
||||
--c-e: #eee;
|
||||
--c-d: #ddd;
|
||||
--c-r: #831;
|
||||
}
|
||||
|
||||
html {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: var(--c-2);
|
||||
font-family: Helvetica, Verdana, sans-serif;
|
||||
font-size: 17px;
|
||||
color: var(--c-f);
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
scrollbar-width: 6px;
|
||||
scrollbar-color: var(--c-sb) transparent;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
.icons {
|
||||
font-family: "CIcons";
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#header {
|
||||
width: 100%;
|
||||
background-color: var(--c-3);
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
#menu {
|
||||
height: calc(100% - 45px);
|
||||
background-color: var(--c-3);
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.entry {
|
||||
height: 45px;
|
||||
color: var(--c-b);
|
||||
}
|
||||
|
||||
.entry:hover {
|
||||
color: var(--c-f);
|
||||
background-color: var(--c-4);
|
||||
}
|
||||
|
||||
.e-icon {
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
width: 45px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.e-label {
|
||||
display: inline-block;
|
||||
height: 45px;
|
||||
vertical-align: top;
|
||||
padding: 14px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 9px;
|
||||
color: var(--c-b);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
color: var(--c-f);
|
||||
background-color: var(--c-4);
|
||||
}
|
||||
|
||||
.save {
|
||||
float: right;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.b-icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.b-label {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
#menu {
|
||||
width: 45px;
|
||||
}
|
||||
.e-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<!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">
|
||||
<link rel="stylesheet" href="cfg.css">
|
||||
<script src="cfg_lang.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="header">
|
||||
<div class="e-icon"><i class="icons"></i></div>
|
||||
<div class="l e-label l10n" id="h-cfg"></div>
|
||||
<div class="btn save">
|
||||
<div class="b-icon"><i class="icons"></i></div>
|
||||
<div class="l b-label l10n" id="b-save">Save</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="menu">
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-nw">Network</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-hw">Hardware</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-ui">Customization</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-if">Interfaces</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-tm">Schedules</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-dx">DMX Out</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-sr">Sound Reactive</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-um">Usermods</div></div>
|
||||
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-ab">About</div></div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<!-- simulate sections for each menu item -->
|
||||
<div id="nw">
|
||||
<h2 class="l10n">Network</h2>
|
||||
</div>
|
||||
<div id="hw">
|
||||
<h2 class="l10n">Hardware</h2>
|
||||
</div>
|
||||
<div id="ui">
|
||||
<h2 class="l10n">Customization</h2>
|
||||
</div>
|
||||
<div id="if">
|
||||
<h2 class="l10n">Interfaces</h2>
|
||||
</div>
|
||||
<div id="tm">
|
||||
<h2 class="l10n">Schedules</h2>
|
||||
</div>
|
||||
<div id="sr">
|
||||
<h2 class="l10n">Sound Reactive</h2>
|
||||
</div>
|
||||
<div id="um">
|
||||
<h2 class="l10n">Usermods</h2>
|
||||
</div>
|
||||
<div id="dx">
|
||||
<h2 class="l10n">DMX Out</h2>
|
||||
</div>
|
||||
<div id="ab">
|
||||
<h2 class="l10n">About</h2>
|
||||
</div>
|
||||
<div id="up">
|
||||
<h2 class="l10n">Update</h2>
|
||||
</div>
|
||||
<div id="rb">
|
||||
<h2 class="l10n">Reboot</h2>
|
||||
</div>
|
||||
</div>
|
||||
<script src="cfg.js" type="module"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,30 @@
|
||||
import $ from './dom.mjs'
|
||||
import translate from './translator.mjs'
|
||||
|
||||
/* Dynamically create the menu
|
||||
const menuItems = [
|
||||
{ "icon": "", "id": "e-nw", "text": "Network" },
|
||||
{ "icon": "", "id": "e-hw", "text": "Hardware" },
|
||||
{ "icon": "", "id": "e-ui", "text": "Customization" },
|
||||
{ "icon": "", "id": "e-if", "text": "Interfaces" },
|
||||
{ "icon": "", "id": "e-tm", "text": "Schedules" },
|
||||
{ "icon": "", "id": "e-dx", "text": "DMX Out" },
|
||||
{ "icon": "", "id": "e-sr", "text": "Sound Reactive" },
|
||||
{ "icon": "", "id": "e-um", "text": "Usermods" },
|
||||
{ "icon": "", "id": "e-ab", "text": "About" }
|
||||
];
|
||||
|
||||
$().ready(function() {
|
||||
const menu = $('#menu');
|
||||
menuItems.map(item =>
|
||||
menu.append(`<div class="entry"><div class="e-icon"><i class="icons">${item.icon}</i></div><div class="l e-label l10n" id="${item.id}">${item.text}</div></div>`)
|
||||
);
|
||||
});
|
||||
*/
|
||||
|
||||
// populate labels when to dom is ready but before it is rendered
|
||||
$().ready(function() {
|
||||
// https://www.w3.org/International/questions/qa-i18n
|
||||
// Localization is sometimes written in English as l10n
|
||||
translate('.l10n');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
(function() {
|
||||
// self executing function to ensure translations is set on page load
|
||||
// so we dont have to wait for fetch/xhr request
|
||||
window.translations = {
|
||||
"About": "Über",
|
||||
"Save": "Speichern",
|
||||
"Schedules": "Zeitpläne",
|
||||
"Sound Reactive": "Tonreaktiv"
|
||||
};
|
||||
}());
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
** DOM module - base on https://github.com/kylebarrow/chibi with IE hacks removed
|
||||
**
|
||||
*/
|
||||
var readyfn = [],
|
||||
loadedfn = [],
|
||||
domready = false,
|
||||
pageloaded = false,
|
||||
d = document,
|
||||
w = window;
|
||||
|
||||
// Fire any function calls on ready event
|
||||
function fireReady() {
|
||||
var i;
|
||||
domready = true;
|
||||
for (i = 0; i < readyfn.length; i += 1) {
|
||||
readyfn[i]();
|
||||
}
|
||||
readyfn = [];
|
||||
}
|
||||
|
||||
// Fire any function calls on loaded event
|
||||
function fireLoaded() {
|
||||
var i;
|
||||
pageloaded = true;
|
||||
for (i = 0; i < loadedfn.length; i += 1) {
|
||||
loadedfn[i]();
|
||||
}
|
||||
loadedfn = [];
|
||||
}
|
||||
|
||||
// Check DOM ready, page loaded
|
||||
if (d.addEventListener) {
|
||||
// Standards
|
||||
d.addEventListener('DOMContentLoaded', fireReady, false);
|
||||
w.addEventListener('load', fireLoaded, false);
|
||||
}
|
||||
|
||||
// Loop through node array
|
||||
function nodeLoop(fn, nodes) {
|
||||
var i;
|
||||
// Good idea to walk up the DOM
|
||||
for (i = nodes.length - 1; i >= 0; i -= 1) {
|
||||
fn(nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function dom(selector) {
|
||||
var self, nodes = [],
|
||||
json = false,
|
||||
nodelist;
|
||||
|
||||
if (selector) {
|
||||
|
||||
// Element node
|
||||
if (selector instanceof HTMLElement) {
|
||||
nodes = [selector]; // return element as node list
|
||||
} else if (selector instanceof NodeList) {
|
||||
// JSON, document object or node list
|
||||
json = (typeof selector.length !== 'number');
|
||||
nodes = selector;
|
||||
} else if (typeof selector === 'string') {
|
||||
nodelist = d.querySelectorAll(selector);
|
||||
nodes = Array.from(nodelist);
|
||||
}
|
||||
}
|
||||
|
||||
// Only attach nodes if not JSON
|
||||
self = json ? {} : nodes;
|
||||
|
||||
// Public functions
|
||||
|
||||
// Fire on DOM ready
|
||||
self.ready = function(fn) {
|
||||
if (fn) {
|
||||
if (domready) {
|
||||
fn();
|
||||
return self;
|
||||
} else {
|
||||
readyfn.push(fn);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Fire on page loaded
|
||||
self.loaded = function(fn) {
|
||||
if (fn) {
|
||||
if (pageloaded) {
|
||||
fn();
|
||||
return self;
|
||||
} else {
|
||||
loadedfn.push(fn);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Executes a function on nodes
|
||||
self.each = function(fn) {
|
||||
if (typeof fn === 'function') {
|
||||
nodeLoop(fn, nodes);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
self.first = function() {
|
||||
return dom(nodes.shift());
|
||||
};
|
||||
|
||||
// Find last
|
||||
self.last = function() {
|
||||
return dom(nodes.pop());
|
||||
};
|
||||
|
||||
// append html before end of the of the tag
|
||||
self.append = function(value) {
|
||||
if (value) {
|
||||
nodeLoop(function(elm) {
|
||||
elm.insertAdjacentHTML('beforeend', value);
|
||||
}, nodes);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
export default dom;
|
||||
+13
-26
@@ -134,7 +134,7 @@ button {
|
||||
|
||||
.off {
|
||||
color: var(--c-6) !important;
|
||||
/* cursor: default !important; */
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.top .icons, .bot .icons {
|
||||
@@ -410,7 +410,6 @@ button {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
#sliders .labels {
|
||||
@@ -419,7 +418,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;
|
||||
@@ -435,16 +434,12 @@ 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: 32px; /* offset for icon */
|
||||
left: 16px; /* offset for icon */
|
||||
}
|
||||
|
||||
.filter, .option {
|
||||
@@ -690,19 +685,18 @@ img {
|
||||
|
||||
.sliderbubble {
|
||||
width: 24px;
|
||||
position: absolute;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border-radius: 16px;
|
||||
border-radius: 10px;
|
||||
background: var(--c-3);
|
||||
color: var(--c-f);
|
||||
padding: 4px;
|
||||
padding: 2px 4px;
|
||||
font-size: 14px;
|
||||
right: 6px;
|
||||
transition: visibility .25s ease,opacity .25s ease;
|
||||
right: 3px;
|
||||
transition: visibility 0.25s ease, opacity 0.25s ease;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
/* left: 8px; */
|
||||
top: 4px;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
output.sliderbubbleshow {
|
||||
@@ -1010,7 +1004,7 @@ textarea {
|
||||
width: 50px !important;
|
||||
}
|
||||
|
||||
.segname, .pname, .bname {
|
||||
.segname, .pname {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
@@ -1020,9 +1014,6 @@ textarea {
|
||||
max-width: 170px;
|
||||
position: relative;
|
||||
}
|
||||
.bname {
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.segname .flr, .pname .flr {
|
||||
transform: rotate(0deg);
|
||||
@@ -1031,9 +1022,8 @@ textarea {
|
||||
|
||||
/* segment power wrapper */
|
||||
.sbs {
|
||||
/*padding: 1px 0 1px 20px;*/
|
||||
padding: 1px 0 1px 20px;
|
||||
display: var(--sgp);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pname {
|
||||
@@ -1548,11 +1538,8 @@ TD .checkmark, TD .radiomark {
|
||||
#sliders .sliderbubble {
|
||||
display: none;
|
||||
}
|
||||
#sliders .sliderwrap, .sbs .sliderwrap {
|
||||
width: calc(100% - 42px);
|
||||
}
|
||||
#sliders .slider {
|
||||
padding-right: 0;
|
||||
.sliderwrap {
|
||||
width: calc(100% - 28px);
|
||||
}
|
||||
#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=getURL('/settings');"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button onclick="window.location.href='/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" style="margin-top: 20px;">
|
||||
<div id="hwrap" class="slider">
|
||||
<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=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||
<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="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(getURL('/update'),'_self');">Update WLED</button>
|
||||
<button class="btn infobtn" onclick="window.open('/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="mlv2D" class="modal">
|
||||
<div id="klv2D" style="width:100%; height:100%">Loading...</div>
|
||||
<div id="mliveview2D" class="modal">
|
||||
<div id="kliveview2D" style="width:100%; height:100%">Loading...</div><br>
|
||||
</div>
|
||||
|
||||
<div id="rover" class="modal">
|
||||
|
||||
+49
-81
@@ -1,5 +1,5 @@
|
||||
//page js
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
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,12 +22,11 @@ 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, wsRpt=0;
|
||||
var ws, cpick, ranges;
|
||||
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, fxdef:true}
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false, css:true, hdays:false}
|
||||
};
|
||||
var hol = [
|
||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||
@@ -194,39 +193,21 @@ function loadSkinCSS(cId)
|
||||
l.id = cId;
|
||||
l.rel = 'stylesheet';
|
||||
l.type = 'text/css';
|
||||
l.href = getURL('/skin.css');
|
||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
||||
l.media = 'all';
|
||||
h.appendChild(l);
|
||||
}
|
||||
}
|
||||
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
function onLoad()
|
||||
{
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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));
|
||||
@@ -236,7 +217,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(getURL("/holidays.json"), { // may be loaded from external source
|
||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", { // may be loaded from external source
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -452,7 +433,9 @@ function loadPresets(callback = null)
|
||||
// afterwards
|
||||
if (!callback && pmt == pmtLast) return;
|
||||
|
||||
fetch(getURL('/presets.json'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -476,7 +459,9 @@ function loadPresets(callback = null)
|
||||
|
||||
function loadPalettes(callback = null)
|
||||
{
|
||||
fetch(getURL('/json/palettes'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -498,7 +483,9 @@ function loadPalettes(callback = null)
|
||||
|
||||
function loadFX(callback = null)
|
||||
{
|
||||
fetch(getURL('/json/effects'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -510,7 +497,6 @@ function loadFX(callback = null)
|
||||
populateEffects();
|
||||
})
|
||||
.catch((e)=>{
|
||||
//setTimeout(loadFX, 250); // retry
|
||||
showToast(e, true);
|
||||
})
|
||||
.finally(()=>{
|
||||
@@ -521,7 +507,9 @@ function loadFX(callback = null)
|
||||
|
||||
function loadFXData(callback = null)
|
||||
{
|
||||
fetch(getURL('/json/fxdata'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -536,7 +524,6 @@ function loadFXData(callback = null)
|
||||
})
|
||||
.catch((e)=>{
|
||||
fxdata = [];
|
||||
//setTimeout(loadFXData, 250); // retry
|
||||
showToast(e, true);
|
||||
})
|
||||
.finally(()=>{
|
||||
@@ -773,7 +760,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=${li.arch=="esp8266"?32:64} value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
|
||||
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
|
||||
`<table class="infot segt">`+
|
||||
`<tr>`+
|
||||
`<td>${isMSeg?'Start X':'Start LED'}</td>`+
|
||||
@@ -826,7 +813,6 @@ 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");
|
||||
@@ -1005,15 +991,10 @@ 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 "?";
|
||||
@@ -1034,9 +1015,8 @@ function populateNodes(i,n)
|
||||
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
for (var o of n.nodes) {
|
||||
if (o.name) {
|
||||
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>`);
|
||||
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>`);
|
||||
nnodes++;
|
||||
}
|
||||
}
|
||||
@@ -1052,7 +1032,8 @@ function populateNodes(i,n)
|
||||
|
||||
function loadNodes()
|
||||
{
|
||||
fetch(getURL('/json/nodes'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -1272,7 +1253,6 @@ 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)
|
||||
@@ -1313,8 +1293,7 @@ function cmpP(a, b)
|
||||
|
||||
function makeWS() {
|
||||
if (ws || lastinfo.ws < 0) return;
|
||||
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||
ws = new WebSocket(url);
|
||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+'://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.onmessage = (e)=>{
|
||||
if (e.data instanceof ArrayBuffer) return; // liveview packet
|
||||
@@ -1338,12 +1317,11 @@ function makeWS() {
|
||||
};
|
||||
ws.onclose = (e)=>{
|
||||
gId('connind').style.backgroundColor = "var(--c-r)";
|
||||
if (wsRpt++ < 5) setTimeout(makeWS,1500); // retry WS connection
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1594,6 +1572,7 @@ 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) {
|
||||
@@ -1614,7 +1593,7 @@ function requestJson(command=null)
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(getURL('/json/si'), {
|
||||
fetch(url, {
|
||||
method: type,
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
@@ -1645,7 +1624,6 @@ 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);
|
||||
@@ -1693,22 +1671,27 @@ 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 && wsOn) {
|
||||
lvID += "2D";
|
||||
if (isLv) gId('klv2D').innerHTML = `<iframe id="${lvID}" src="about:blank"></iframe>`;
|
||||
gId('mlv2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
|
||||
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%)";
|
||||
}
|
||||
|
||||
gId(lvID).style.display = (isLv) ? "block":"none";
|
||||
gId(lvID).src = (isLv) ? getURL("/" + lvID + ((wsOn) ? "?ws":"")):"about:blank";
|
||||
gId('buttonSr').classList.toggle("active");
|
||||
if (!isLv && wsOn) ws.send('{"lv":false}');
|
||||
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}');
|
||||
size();
|
||||
}
|
||||
|
||||
@@ -2052,14 +2035,14 @@ function tglSegn(s)
|
||||
function selSegAll(o)
|
||||
{
|
||||
var obj = {"seg":[]};
|
||||
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":o.checked});
|
||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":o.checked});
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function selSegEx(s)
|
||||
{
|
||||
var obj = {"seg":[]};
|
||||
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":(i==s)});
|
||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
|
||||
obj.mainseg = s;
|
||||
requestJson(obj);
|
||||
}
|
||||
@@ -2077,7 +2060,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++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":false});
|
||||
for (let i=0; i<=lSeg; 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};
|
||||
@@ -2244,7 +2227,8 @@ function setFX(ind = null)
|
||||
} else {
|
||||
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
||||
}
|
||||
var obj = {"seg": {"fx": parseInt(ind), "fxdef": cfg.comp.fxdef}}; // fxdef sets effect parameters to default values
|
||||
|
||||
var obj = {"seg": {"fx": parseInt(ind),"fxdef":1}}; // fxdef sets effect parameters to default values, TODO add client setting
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
@@ -2578,24 +2562,6 @@ 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;
|
||||
@@ -2618,7 +2584,7 @@ function cnfReset()
|
||||
bt.innerHTML = "Confirm Reboot";
|
||||
cnfr = true; return;
|
||||
}
|
||||
window.location.href = getURL("/reset");
|
||||
window.location.href = "/reset";
|
||||
}
|
||||
|
||||
var cnfrS = false;
|
||||
@@ -2672,7 +2638,9 @@ function loadPalettesData(callback = null)
|
||||
|
||||
function getPalettesData(page, callback)
|
||||
{
|
||||
fetch(getURL(`/json/palx?page=${page}`), {
|
||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
||||
|
||||
fetch(url, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
|
||||
@@ -17,17 +17,21 @@
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="canv" />
|
||||
<script>
|
||||
var ws;
|
||||
update();
|
||||
|
||||
var tmout = null;
|
||||
function update() // via HTTP (/json/live)
|
||||
function update()
|
||||
{
|
||||
if (document.hidden) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 250);
|
||||
return;
|
||||
}
|
||||
fetch('./json/live')
|
||||
fetch('/json/live')
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
clearTimeout(tmout);
|
||||
@@ -53,57 +57,8 @@
|
||||
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>
|
||||
@@ -0,0 +1,61 @@
|
||||
<!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,14 +33,7 @@
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send("{'lv':true}");
|
||||
} else {
|
||||
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 = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
||||
ws.onopen = ()=>{
|
||||
ws.send("{'lv':true}");
|
||||
}
|
||||
|
||||
+2
-2
@@ -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");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+15
-27
@@ -6,7 +6,7 @@
|
||||
<title>WLED Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
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,29 +26,17 @@
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
function S(){
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@@ -77,15 +65,15 @@
|
||||
</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<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>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
@@ -7,11 +7,11 @@
|
||||
<title>2D Set-up</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
var maxPanels=64;
|
||||
var ctx = null; // WLEDMM
|
||||
function H(){window.open("https://kno.wled.ge/features/2D");}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function B(){window.open("/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,29 +35,16 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
|
||||
function UI() {
|
||||
@@ -335,7 +322,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 class="warn">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<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>
|
||||
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, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function B(){window.history.back();}
|
||||
function GCH(num) {
|
||||
d.getElementById('dmxchannels').innerHTML += "";
|
||||
for (i=0;i<num;i++) {
|
||||
@@ -54,29 +54,16 @@
|
||||
});
|
||||
}
|
||||
function S(){
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
|
||||
+90
-213
@@ -10,11 +10,11 @@
|
||||
d.um_p = [];
|
||||
d.rsvd = [];
|
||||
d.ro_gpio = [];
|
||||
d.max_gpio = 50;
|
||||
d.max_gpio = 39;
|
||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function B(){window.open("/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,12 +26,8 @@
|
||||
d.body.appendChild(scE);
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
GetV();
|
||||
checkSi();
|
||||
setABL();
|
||||
d.Sf.addEventListener("submit", trySubmit);
|
||||
GetV();checkSi();setABL();
|
||||
if (d.um_p[0]==-1) d.um_p.shift();
|
||||
pinDropdowns();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
@@ -53,7 +49,7 @@
|
||||
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
||||
}
|
||||
function pinsOK() {
|
||||
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
// ignore IP address
|
||||
@@ -63,36 +59,23 @@
|
||||
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 = 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 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 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;}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +96,6 @@
|
||||
gId('abl').style.display = (en) ? 'inline':'none';
|
||||
gId('psu2').style.display = (en) ? 'inline':'none';
|
||||
if (d.Sf.LA.value > 0) setABL();
|
||||
UI();
|
||||
}
|
||||
function enLA()
|
||||
{
|
||||
@@ -135,28 +117,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 + dbl; //RGBW
|
||||
return len*15 + dbl;
|
||||
if (t > 28) return len*20; //RGBW
|
||||
return len*15;
|
||||
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
||||
{
|
||||
if (t > 28) return len*8 + dbl; //RGBW
|
||||
return len*6 + dbl;
|
||||
if (t > 28) return len*8; //RGBW
|
||||
return len*6;
|
||||
}
|
||||
if (t > 28) return len*4 + dbl; //RGBW
|
||||
return len*3 + dbl;
|
||||
if (t > 28) return len*4; //RGBW
|
||||
return len*3;
|
||||
}
|
||||
if (t > 31 && t < 48) return 5; // analog
|
||||
return len*3 + dbl;
|
||||
if (t > 31 && t < 48) return 5;
|
||||
return len*3;
|
||||
}
|
||||
|
||||
function UI(change=false)
|
||||
@@ -169,50 +151,53 @@
|
||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||
|
||||
// enable/disable LED fields
|
||||
d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((s)=>{
|
||||
var s = d.getElementsByTagName("select");
|
||||
for (i=0; i<s.length; i++) {
|
||||
// is the field a LED type?
|
||||
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
|
||||
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
|
||||
|
||||
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) {
|
||||
@@ -220,7 +205,7 @@
|
||||
d.Sf.CR.checked = false;
|
||||
}
|
||||
// check for pin conflicts
|
||||
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
var sLC = 0, sPC = 0, maxLC = 0;
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2); // field name
|
||||
@@ -258,14 +243,15 @@
|
||||
}
|
||||
}
|
||||
// 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 = 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
|
||||
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
|
||||
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);
|
||||
@@ -275,13 +261,13 @@
|
||||
}
|
||||
}
|
||||
// now check for conflicts
|
||||
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";
|
||||
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";
|
||||
}
|
||||
// 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;
|
||||
@@ -380,11 +366,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();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);"/>
|
||||
<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()"/>
|
||||
<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>
|
||||
@@ -560,126 +546,17 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
}
|
||||
}
|
||||
}
|
||||
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:") {
|
||||
function S(){
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
@@ -699,7 +576,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" class="warn" style="display: none;">
|
||||
<div id="ampwarning" style="color: orange; display: none;">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
@@ -727,14 +604,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" class="warn" style="display: none;">
|
||||
<div id="ledwarning" style="color: orange; 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" onchange="UI()"><br>
|
||||
Use global LED buffer: <input type="checkbox" name="LD"><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, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
|
||||
function B() { window.open(getURL("/settings"),"_self"); }
|
||||
function U() { window.open(getURL("/update"),"_self"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function U() { window.open("/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", getURL("/upload"));
|
||||
req.open("POST", "/upload");
|
||||
var formData = new FormData();
|
||||
formData.append("data", fO.files[0], name);
|
||||
req.send(formData);
|
||||
@@ -65,33 +65,16 @@
|
||||
x.setAttribute("download","wled_" + x.getAttribute("download") + (sd=="WLED"?"":("_" +sd)));
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@@ -106,7 +89,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 class="warn">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
||||
<div style="color: #fa0;">⚠ 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>
|
||||
@@ -116,7 +99,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 class="warn">⚠ Unencrypted transmission. An attacker on the same network can intercept form data!</div>
|
||||
<div style="color: #fa0;">⚠ 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>
|
||||
@@ -127,7 +110,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 class="warn">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||
<div style="color: #fa0;">⚠ 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, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
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(getURL("/settings"),"_self");}
|
||||
function B(){window.open("/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,28 +56,16 @@
|
||||
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(){
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
@@ -184,7 +172,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">
|
||||
<i class="warn">This firmware build does not include Alexa support.<br></i><br>
|
||||
<em style="color:#fa0;">This firmware build does not include Alexa support.<br></em><br>
|
||||
</div>
|
||||
<div id="Alexa">
|
||||
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||
@@ -192,7 +180,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 class="warn">⚠ <b>MQTT and Hue sync all connect to external hosts!<br>
|
||||
<div style="color: #fa0;">⚠ <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>
|
||||
@@ -200,7 +188,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">
|
||||
<i class="warn">This firmware build does not include MQTT support.<br></i>
|
||||
<em style="color:#fa0;">This firmware build does not include MQTT support.<br></em>
|
||||
</div>
|
||||
<div id="MQTT">
|
||||
Enable MQTT: <input type="checkbox" name="MQ"><br>
|
||||
@@ -219,7 +207,7 @@ Retain brightness & color messages: <input type="checkbox" name="RT"><br>
|
||||
</div>
|
||||
<h3>Philips Hue</h3>
|
||||
<div id="NoHue" class="hide">
|
||||
<em class="warn">This firmware build does not include Philips Hue support.<br></em>
|
||||
<em style="color:#fa0;">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, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
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(getURL("/settings"),"_self"); }
|
||||
function B() { window.open("/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,29 +33,16 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
function expand(o,i)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<title>UI Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
var initial_ds, initial_st, initial_su;
|
||||
var sett = null;
|
||||
var l = {
|
||||
@@ -26,8 +26,7 @@
|
||||
"segpwr": "Hide segment power & brightness",
|
||||
"segexp" : "Always expand first segment",
|
||||
"css": "Enable custom CSS",
|
||||
"hdays": "Enable custom Holidays list",
|
||||
"fxdef": "Use effect default parameters"
|
||||
"hdays": "Enable custom Holidays list"
|
||||
},
|
||||
"theme":{
|
||||
"alpha": {
|
||||
@@ -186,33 +185,21 @@
|
||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
function S()
|
||||
{
|
||||
if (window.location.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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
|
||||
function B() { window.open(getURL("/settings"),"_self"); }
|
||||
function B() { window.open("/settings","_self"); }
|
||||
function UI()
|
||||
{
|
||||
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
|
||||
@@ -262,7 +249,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">
|
||||
<i class="warn">This firmware build does not include simplified UI support.<br></i>
|
||||
<em style="color:#fa0;">This firmware build does not include simplified UI support.<br></em>
|
||||
</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>
|
||||
|
||||
+22
-108
@@ -7,20 +7,19 @@
|
||||
<title>Usermod Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
d.max_gpio = 50;
|
||||
d.max_gpio = 39;
|
||||
d.um_p = [];
|
||||
d.rsvd = [];
|
||||
d.ro_gpio = [];
|
||||
d.extra = [];
|
||||
var umCfg = {};
|
||||
var pins = [], pinO = [], owner;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
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(getURL("/settings"),"_self"); }
|
||||
function B() { window.open("/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");
|
||||
@@ -31,11 +30,15 @@
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
GetV();
|
||||
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
|
||||
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;
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
@@ -44,36 +47,21 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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++) {
|
||||
@@ -96,16 +84,13 @@
|
||||
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") {
|
||||
@@ -164,76 +149,11 @@
|
||||
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');
|
||||
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];
|
||||
let arr = d.getElementsByName(um+":"+fld);
|
||||
let inp = arr[1]; // assume 1st field to be hidden (type)
|
||||
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||
let v = inp.value;
|
||||
let n = inp.name;
|
||||
@@ -242,12 +162,11 @@
|
||||
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' && att.name != 'oninput' && att.name != 'max' && att.name != 'min') {
|
||||
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", "UI(this)");
|
||||
// finally, replace the old input element with the new select element
|
||||
inp.parentElement.replaceChild(sel, inp);
|
||||
return sel;
|
||||
@@ -264,7 +183,6 @@
|
||||
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="") {
|
||||
@@ -276,13 +194,10 @@
|
||||
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() {
|
||||
fetch(getURL('/cfg.json'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/cfg.json';
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -301,7 +216,8 @@
|
||||
}
|
||||
if (urows==="") urows = "Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults.";
|
||||
gId("um").innerHTML = urows;
|
||||
loadJS(getURL('/settings/s.js?p=8'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||
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
|
||||
})
|
||||
.catch((error)=>{
|
||||
gId('lserr').style.display = "inline";
|
||||
@@ -326,17 +242,15 @@
|
||||
</div>
|
||||
<h2>Usermod Setup</h2>
|
||||
Global I<sup>2</sup>C GPIOs (HW)<br>
|
||||
<i class="warn">(change requires reboot!)</i><br>
|
||||
<i style="color: orange;">(only changable on ESP32, 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 class="warn">(only changable on ESP32, change requires reboot!)</i><br>
|
||||
<i style="color: orange;">(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,19 +7,21 @@
|
||||
<title>WiFi Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
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(getURL("/settings"),"_self");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function N() {
|
||||
const url = (loc?`http://${locip}`:"") + "/json/net";
|
||||
|
||||
const button = gId("scan");
|
||||
button.disabled = true;
|
||||
button.textContent = "Scanning...";
|
||||
button.innerHTML = "Scanning...";
|
||||
|
||||
fetch(getURL("/json/net")).then((response) => {
|
||||
fetch(url).then((response) => {
|
||||
return response.json();
|
||||
}).then((json) => {
|
||||
// Get the list of networks only, defaulting to an empty array.
|
||||
@@ -68,7 +70,7 @@
|
||||
const option = cE("option");
|
||||
|
||||
option.setAttribute("value", networks[i].ssid);
|
||||
option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`;
|
||||
option.innerHTML = `${networks[i].ssid} (${networks[i].rssi} dBm)`;
|
||||
|
||||
if (networks[i].ssid === cs.value) {
|
||||
option.setAttribute("selected", "selected");
|
||||
@@ -79,14 +81,14 @@
|
||||
const option = cE("option");
|
||||
|
||||
option.setAttribute("value", "!Cs");
|
||||
option.textContent = `Other network...`;
|
||||
option.innerHTML = `Other network...`;
|
||||
select.appendChild(option);
|
||||
|
||||
cs.replaceWith(select);
|
||||
}
|
||||
|
||||
button.disabled = false;
|
||||
button.textContent = "Scan";
|
||||
button.innerHTML = "Scan";
|
||||
});
|
||||
}
|
||||
// replace WiFi select with custom SSID input field again
|
||||
@@ -120,29 +122,16 @@
|
||||
});
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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);
|
||||
}
|
||||
} 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];
|
||||
localStorage.setItem("locIp", locip);
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
@@ -193,17 +182,6 @@
|
||||
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">
|
||||
|
||||
+26
-32
@@ -1,5 +1,5 @@
|
||||
//page js
|
||||
var loc = false, locip, locproto = "http:";
|
||||
var loc = false, locip;
|
||||
var noNewSegs = false;
|
||||
var isOn = false, isInfo = false, isNodes = false, isRgbw = false, cct = false;
|
||||
var whites = [0,0,0];
|
||||
@@ -148,39 +148,22 @@ function loadSkinCSS(cId)
|
||||
l.id = cId;
|
||||
l.rel = 'stylesheet';
|
||||
l.type = 'text/css';
|
||||
l.href = getURL('/skin.css');
|
||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
||||
l.media = 'all';
|
||||
h.appendChild(l);
|
||||
}
|
||||
}
|
||||
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
async function onLoad()
|
||||
{
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
if (window.location.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));
|
||||
@@ -190,7 +173,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(getURL("/holidays.json"), {
|
||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", {
|
||||
method: 'get'
|
||||
})
|
||||
.then((res)=>{
|
||||
@@ -347,7 +330,9 @@ function loadPresets(callback = null)
|
||||
|
||||
pmtLast = pmt;
|
||||
|
||||
fetch(getURL('/presets.json'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -370,7 +355,9 @@ function loadPresets(callback = null)
|
||||
|
||||
function loadPalettes(callback = null)
|
||||
{
|
||||
fetch(getURL('/json/palettes'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -392,7 +379,9 @@ function loadPalettes(callback = null)
|
||||
|
||||
function loadFX(callback = null)
|
||||
{
|
||||
fetch(getURL('/json/effects'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -414,7 +403,9 @@ function loadFX(callback = null)
|
||||
|
||||
function loadFXData(callback = null)
|
||||
{
|
||||
fetch(getURL('/json/fxdata'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
||||
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -620,7 +611,8 @@ function populateNodes(i,n)
|
||||
|
||||
function loadNodes()
|
||||
{
|
||||
fetch(getURL('/json/nodes'), {
|
||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
||||
fetch(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
@@ -863,8 +855,7 @@ function cmpP(a, b)
|
||||
|
||||
function makeWS() {
|
||||
if (ws) return;
|
||||
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||
ws = new WebSocket(url);
|
||||
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
ws.onmessage = (e)=>{
|
||||
var json = JSON.parse(e.data);
|
||||
if (json.leds) return; //liveview packet
|
||||
@@ -983,6 +974,7 @@ 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) {
|
||||
@@ -999,7 +991,7 @@ function requestJson(command=null)
|
||||
setTimeout(requestJson,200);
|
||||
}
|
||||
|
||||
fetch(getURL('/json/si'), {
|
||||
fetch(url, {
|
||||
method: type,
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
@@ -1322,7 +1314,9 @@ function loadPalettesData(callback = null)
|
||||
|
||||
function getPalettesData(page, callback)
|
||||
{
|
||||
fetch(getURL(`/json/palx?page=${page}`), {
|
||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
||||
|
||||
fetch(url, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
|
||||
@@ -61,12 +61,6 @@ button.sml {
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.err {
|
||||
color: #f00;
|
||||
}
|
||||
.warn {
|
||||
color: #fa0;
|
||||
}
|
||||
input {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
@@ -120,10 +114,6 @@ select {
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
select.pin {
|
||||
max-width: 120px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
tr {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import $ from './dom.mjs'
|
||||
|
||||
var w = window;
|
||||
|
||||
function getText(elm) {
|
||||
return elm.textContent; // or innerText ?
|
||||
}
|
||||
|
||||
function setText(elm, value) {
|
||||
if (value) {
|
||||
elm.textContent = value; // or innerText ?
|
||||
}
|
||||
}
|
||||
|
||||
// perform simple translation
|
||||
function translateElement(elm) {
|
||||
const text = getText(elm);
|
||||
setText(elm, w.translations[text]);
|
||||
}
|
||||
|
||||
export default function translate(selector) {
|
||||
if (w.translations) {
|
||||
$(selector).each(translateElement)
|
||||
} else {
|
||||
console.info("no translations");
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
+1
-1
@@ -25,7 +25,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ddpChannelsPerLed = ((p->dataType & 0b00111000)>>3 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
|
||||
uint8_t ddpChannelsPerLed = (p->dataType & 0b00111000 == 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;
|
||||
|
||||
+9
-33
@@ -50,18 +50,6 @@ 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]))); }
|
||||
@@ -75,6 +63,10 @@ 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();
|
||||
@@ -104,20 +96,10 @@ 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 startImprovWifiScan();
|
||||
void handleImprovWifiScan();
|
||||
void sendImprovIPRPCResult(ImprovRPCType type);
|
||||
void sendImprovRPCResponse(uint8_t commandId);
|
||||
|
||||
//ir.cpp
|
||||
void applyRepeatActions();
|
||||
@@ -147,8 +129,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 root);
|
||||
void serializeModeData(JsonArray root);
|
||||
void serializeModeNames(JsonArray arr, const char *qstring);
|
||||
void serializeModeData(JsonObject root);
|
||||
void serveJson(AsyncWebServerRequest* request);
|
||||
#ifdef WLED_ENABLE_JSONLIVE
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||
@@ -170,11 +152,9 @@ 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();
|
||||
@@ -210,16 +190,12 @@ 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);
|
||||
@@ -227,7 +203,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, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false);
|
||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false);
|
||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||
void exitRealtime();
|
||||
void handleNotifications();
|
||||
@@ -349,7 +325,6 @@ 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();
|
||||
@@ -397,6 +372,7 @@ 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);
|
||||
|
||||
+1059
-1037
File diff suppressed because it is too large
Load Diff
@@ -1,549 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
+2005
-2166
File diff suppressed because it is too large
Load Diff
+1117
-1126
File diff suppressed because it is too large
Load Diff
+1769
-1816
File diff suppressed because it is too large
Load Diff
+69
-102
@@ -10,11 +10,6 @@
|
||||
#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);
|
||||
@@ -33,14 +28,20 @@ enum ImprovPacketByte {
|
||||
RPC_CommandType = 9
|
||||
};
|
||||
|
||||
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
||||
static bool improvWifiScanRunning = false;
|
||||
#endif
|
||||
enum ImprovRPCType {
|
||||
Command_Wifi = 0x01,
|
||||
Request_State = 0x02,
|
||||
Request_Info = 0x03
|
||||
};
|
||||
|
||||
//File dbgf;
|
||||
|
||||
//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;
|
||||
@@ -61,11 +62,12 @@ 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;
|
||||
@@ -73,6 +75,7 @@ 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;
|
||||
@@ -86,6 +89,7 @@ void handleImprovPacket() {
|
||||
if (checksum != next) {
|
||||
DIMPROV_PRINTF("Got RPC checksum %i, expected %i",next,checksum);
|
||||
sendImprovStateResponse(0x01, true);
|
||||
//dbgf.close();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,23 +100,22 @@ void handleImprovPacket() {
|
||||
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
|
||||
if (Network.isConnected()) improvState = 0x04; //provisioned
|
||||
sendImprovStateResponse(improvState, false);
|
||||
if (improvState == 0x04) sendImprovIPRPCResult(ImprovRPCType::Request_State);
|
||||
if (improvState == 0x04) sendImprovRPCResponse(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
|
||||
@@ -125,6 +128,7 @@ void handleImprovPacket() {
|
||||
checksum += next;
|
||||
packetByte++;
|
||||
}
|
||||
//dbgf.close();
|
||||
}
|
||||
|
||||
void sendImprovStateResponse(uint8_t state, bool error) {
|
||||
@@ -143,116 +147,79 @@ void sendImprovStateResponse(uint8_t state, bool error) {
|
||||
Serial.write('\n');
|
||||
}
|
||||
|
||||
// used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan()
|
||||
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) {
|
||||
void sendImprovRPCResponse(byte commandId) {
|
||||
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
||||
uint8_t packetLen = 12;
|
||||
char out[256] = {'I','M','P','R','O','V'};
|
||||
char out[64] = {'I','M','P','R','O','V'};
|
||||
out[6] = IMPROV_VERSION;
|
||||
out[7] = ImprovPacketType::RPC_Response;
|
||||
//out[8] = 2; //Length (set below)
|
||||
out[9] = type;
|
||||
//out[10] = 0; //Data len (set below)
|
||||
uint16_t pos = 11;
|
||||
out[8] = 2; //Length (set below)
|
||||
out[9] = commandId;
|
||||
out[10] = 0; //Data len (set below)
|
||||
out[11] = '\0'; //URL len (set below)
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
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
|
||||
;
|
||||
|
||||
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;
|
||||
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
||||
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
||||
char vString[20];
|
||||
sprintf_P(vString, PSTR("0.14.0-b4/%i"), VERSION);
|
||||
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
||||
strcpy(out+lengthSum+1,useMdnsName ? cmDNS : serverDescription);
|
||||
uint8_t nlen = strlen(useMdnsName ? cmDNS : serverDescription);
|
||||
out[lengthSum] = nlen;
|
||||
lengthSum += nlen + 1;
|
||||
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
||||
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);
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
+5
-1
@@ -70,9 +70,13 @@ 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)
|
||||
{
|
||||
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
|
||||
applyPreset(presetID, CALL_MODE_BUTTON_PRESET);
|
||||
//these two will be overwritten if preset exists in handlePresets()
|
||||
effectCurrent = effectID;
|
||||
effectPalette = paletteID;
|
||||
}
|
||||
|
||||
byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||
|
||||
+33
-34
@@ -9,7 +9,6 @@
|
||||
#define JSON_PATH_PALETTES 5
|
||||
#define JSON_PATH_FXDATA 6
|
||||
#define JSON_PATH_NETWORKS 7
|
||||
#define JSON_PATH_EFFECTS 8
|
||||
|
||||
/*
|
||||
* JSON API (De)serialization
|
||||
@@ -22,7 +21,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
int stop = elem["stop"] | -1;
|
||||
|
||||
// append segment
|
||||
// if using vectors use this code to append segment
|
||||
if (id >= strip.getSegmentsNum()) {
|
||||
if (stop <= 0) return false; // ignore empty/inactive segments
|
||||
strip.appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
@@ -34,7 +33,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
uint16_t start = elem["start"] | seg.start;
|
||||
if (stop < 0) {
|
||||
int len = elem["len"];
|
||||
uint16_t len = elem["len"];
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
}
|
||||
// 2D segments
|
||||
@@ -70,10 +69,9 @@ 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) {
|
||||
if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN;
|
||||
if (len > 0 && len < 33) {
|
||||
seg.name = new char[len+1];
|
||||
if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1);
|
||||
if (seg.name) strlcpy(seg.name, name, 33);
|
||||
} else {
|
||||
// but is empty (already deleted above)
|
||||
elem.remove("n");
|
||||
@@ -110,11 +108,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
of = offsetAbs;
|
||||
}
|
||||
if (stop > start && of > len -1) of = len -1;
|
||||
|
||||
// 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);
|
||||
seg.setUp(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
|
||||
|
||||
@@ -430,7 +424,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; // otherwise it was set in handleSet() [set.cpp]
|
||||
if (root["win"].isNull()) presetCycCurr = currentPreset;
|
||||
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()) {
|
||||
@@ -472,12 +466,10 @@ 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;
|
||||
@@ -820,7 +812,7 @@ void setPaletteColors(JsonArray json, byte* tcp)
|
||||
}
|
||||
}
|
||||
|
||||
void serializePalettes(JsonObject root, int page)
|
||||
void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
||||
{
|
||||
byte tcp[72];
|
||||
#ifdef ESP8266
|
||||
@@ -829,6 +821,11 @@ void serializePalettes(JsonObject root, int page)
|
||||
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();
|
||||
|
||||
@@ -1004,16 +1001,29 @@ 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;
|
||||
@@ -1030,7 +1040,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
request->send(503, "application/json", F("{\"error\":3}"));
|
||||
return;
|
||||
}
|
||||
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
|
||||
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==6);
|
||||
|
||||
JsonVariant lDoc = response->getRoot();
|
||||
|
||||
@@ -1043,11 +1053,9 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
case JSON_PATH_NODES:
|
||||
serializeNodes(lDoc); break;
|
||||
case JSON_PATH_PALETTES:
|
||||
serializePalettes(lDoc, request->hasParam("page") ? request->getParam("page")->value().toInt() : 0); break;
|
||||
case JSON_PATH_EFFECTS:
|
||||
serializeModeNames(lDoc); break;
|
||||
serializePalettes(lDoc, request); break;
|
||||
case JSON_PATH_FXDATA:
|
||||
serializeModeData(lDoc); break;
|
||||
serializeModeData(lDoc.as<JsonArray>()); break;
|
||||
case JSON_PATH_NETWORKS:
|
||||
serializeNetworks(lDoc); break;
|
||||
default: //all
|
||||
@@ -1066,12 +1074,7 @@ 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();
|
||||
}
|
||||
@@ -1099,13 +1102,9 @@ 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 = 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
|
||||
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));
|
||||
olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0));
|
||||
}
|
||||
olen -= 1;
|
||||
|
||||
+6
-7
@@ -37,8 +37,8 @@ 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.setPalette(effectPalette); stateChanged = true;}
|
||||
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent); stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {seg.palette = effectPalette; stateChanged = true;}
|
||||
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
|
||||
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;}
|
||||
@@ -104,7 +104,6 @@ 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;
|
||||
@@ -147,8 +146,8 @@ void stateUpdated(byte callMode) {
|
||||
if (transitionActive) {
|
||||
briOld = briT;
|
||||
tperLast = 0;
|
||||
} else
|
||||
strip.setTransitionMode(true); // force all segments to transition mode
|
||||
}
|
||||
strip.setTransitionMode(true); // force all segments to transition mode
|
||||
transitionActive = true;
|
||||
transitionStartTime = millis();
|
||||
} else {
|
||||
@@ -195,7 +194,7 @@ void handleTransitions()
|
||||
applyFinalBri();
|
||||
return;
|
||||
}
|
||||
if (tper - tperLast < 0.004f) return;
|
||||
if (tper - tperLast < 0.004) return;
|
||||
tperLast = tper;
|
||||
briT = briOld + ((bri - briOld) * tper);
|
||||
|
||||
@@ -205,7 +204,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)
|
||||
bool parseLx(int lxValue, byte rgbw[4])
|
||||
{
|
||||
DEBUG_PRINT(F("LX: Lox = "));
|
||||
DEBUG_PRINTLN(lxValue);
|
||||
|
||||
+2
-12
@@ -120,15 +120,6 @@ 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) {
|
||||
@@ -176,11 +167,10 @@ 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;
|
||||
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~")
|
||||
fdo.remove("ps"); //remove load request for presets to prevent recursive crash
|
||||
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
|
||||
}
|
||||
if (!errorFlag && tmpPreset < 255 && changePreset) currentPreset = tmpPreset;
|
||||
if (!errorFlag && tmpPreset < 255 && changePreset) presetCycCurr = currentPreset = tmpPreset;
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
//Aircoookie recommended not to delete buffer
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
#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
|
||||
+62
-70
@@ -7,17 +7,19 @@
|
||||
//called upon POST settings form submit
|
||||
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
{
|
||||
if (subPage == SUBPAGE_PINREQ)
|
||||
// PIN code request
|
||||
if (subPage == 252)
|
||||
{
|
||||
checkSettingsPIN(request->arg(F("PIN")).c_str());
|
||||
correctPIN = (strlen(settingsPIN)==0 || strncmp(settingsPIN, request->arg(F("PIN")).c_str(), 4)==0);
|
||||
lastEditTime = millis();
|
||||
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 == SUBPAGE_WIFI)
|
||||
if (subPage == 1)
|
||||
{
|
||||
strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33);
|
||||
|
||||
@@ -34,14 +36,6 @@ 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();
|
||||
@@ -64,7 +58,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//LED SETTINGS
|
||||
if (subPage == SUBPAGE_LEDS)
|
||||
if (subPage == 2)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
@@ -91,7 +85,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());
|
||||
useGlobalLedBuffer = request->hasArg(F("LD"));
|
||||
strip.useLedsArray = request->hasArg(F("LD"));
|
||||
|
||||
bool busesChanged = false;
|
||||
for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {
|
||||
@@ -153,7 +147,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, useGlobalLedBuffer);
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freqHz);
|
||||
busesChanged = true;
|
||||
}
|
||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||
@@ -239,7 +233,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
gammaCorrectCol = request->hasArg(F("GC"));
|
||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
calcGammaTable(gammaCorrectVal);
|
||||
else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
@@ -268,7 +262,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//UI
|
||||
if (subPage == SUBPAGE_UI)
|
||||
if (subPage == 3)
|
||||
{
|
||||
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
|
||||
syncToggleReceive = request->hasArg(F("ST"));
|
||||
@@ -286,7 +280,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//SYNC
|
||||
if (subPage == SUBPAGE_SYNC)
|
||||
if (subPage == 4)
|
||||
{
|
||||
int t = request->arg(F("UP")).toInt();
|
||||
if (t > 0) udpPort = t;
|
||||
@@ -385,7 +379,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//TIME
|
||||
if (subPage == SUBPAGE_TIME)
|
||||
if (subPage == 5)
|
||||
{
|
||||
ntpEnabled = request->hasArg(F("NT"));
|
||||
strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33);
|
||||
@@ -459,7 +453,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
//SECURITY
|
||||
if (subPage == SUBPAGE_SEC)
|
||||
if (subPage == 6)
|
||||
{
|
||||
if (request->hasArg(F("RS"))) //complete factory reset
|
||||
{
|
||||
@@ -468,7 +462,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; // may reboot immediately on dual-core system (race condition) which is desireable in this case
|
||||
doReboot = true;
|
||||
}
|
||||
|
||||
if (request->hasArg(F("PIN"))) {
|
||||
@@ -490,7 +484,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 > PIN_RETRY_COOLDOWN) pwdCorrect = true;
|
||||
if (millis() - lastEditTime > 3000) pwdCorrect = true;
|
||||
}
|
||||
if (!otaLock && request->arg(F("OP")).length() > 0)
|
||||
{
|
||||
@@ -508,7 +502,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
if (subPage == SUBPAGE_DMX)
|
||||
if (subPage == 7)
|
||||
{
|
||||
int t = request->arg(F("PU")).toInt();
|
||||
if (t >= 0 && t <= 63999) e131ProxyUniverse = t;
|
||||
@@ -538,30 +532,33 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
#endif
|
||||
|
||||
//USERMODS
|
||||
if (subPage == SUBPAGE_UM)
|
||||
if (subPage == 8)
|
||||
{
|
||||
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();
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
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();
|
||||
@@ -572,29 +569,26 @@ 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
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
JsonObject um = doc.createNestedObject("um");
|
||||
@@ -678,7 +672,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
//2D panels
|
||||
if (subPage == SUBPAGE_2D)
|
||||
if (subPage == 10)
|
||||
{
|
||||
strip.isMatrix = request->arg(F("SOMP")).toInt();
|
||||
strip.panel.clear(); // release memory if allocated
|
||||
@@ -714,11 +708,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
#endif
|
||||
|
||||
lastEditTime = millis();
|
||||
// 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)
|
||||
if (subPage != 2 && !doReboot) doSerializeConfig = true; //serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (subPage == SUBPAGE_SYNC) alexaInit();
|
||||
if (subPage == 4) alexaInit();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -797,7 +789,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
spcI = getNumVal(&req, pos);
|
||||
}
|
||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
|
||||
selseg.setUp(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,7 +669,6 @@ 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,10 +133,6 @@
|
||||
#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
|
||||
@@ -310,10 +306,6 @@ void registerUsermods()
|
||||
usermods.add(new WizLightsUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_WIREGUARD
|
||||
usermods.add(new WireguardUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_WORDCLOCK
|
||||
usermods.add(new WordClockUsermod());
|
||||
#endif
|
||||
|
||||
+2
-12
@@ -373,16 +373,6 @@ 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;
|
||||
@@ -503,8 +493,8 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
}
|
||||
|
||||
samplePeak = random8() > 250;
|
||||
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
|
||||
maxVol = 31; // this gets feedback fro UI
|
||||
FFT_MajorPeak = volumeSmth;
|
||||
maxVol = 10; // 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 ???
|
||||
|
||||
+39
-63
@@ -23,7 +23,7 @@ void WLED::reset()
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
ws.closeAll(1012);
|
||||
#endif
|
||||
unsigned long dly = millis();
|
||||
long dly = millis();
|
||||
while (millis() - dly < 450) {
|
||||
yield(); // enough time to send response to client
|
||||
}
|
||||
@@ -35,18 +35,10 @@ 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 size_t avgUsermodMillis = 0;
|
||||
static uint16_t avgUsermodMillis = 0;
|
||||
static unsigned long maxStripMillis = 0;
|
||||
static size_t avgStripMillis = 0;
|
||||
unsigned long stripMillis;
|
||||
static uint16_t avgStripMillis = 0;
|
||||
#endif
|
||||
|
||||
handleTime();
|
||||
@@ -54,11 +46,7 @@ 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
|
||||
@@ -85,14 +73,18 @@ 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();
|
||||
@@ -111,18 +103,22 @@ 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
|
||||
@@ -149,7 +145,7 @@ void WLED::loop()
|
||||
}
|
||||
|
||||
// 15min PIN time-out
|
||||
if (strlen(settingsPIN)>0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) {
|
||||
if (strlen(settingsPIN)>0 && millis() - lastEditTime > 900000) {
|
||||
correctPIN = false;
|
||||
createEditHandler(false);
|
||||
}
|
||||
@@ -161,16 +157,11 @@ 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, globalBufMem = 0;
|
||||
uint16_t maxlen = 0;
|
||||
uint32_t mem = 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 (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) {
|
||||
maxlen = busConfigs[i]->start + busConfigs[i]->count;
|
||||
globalBufMem = maxlen * 4;
|
||||
}
|
||||
if (mem + globalBufMem <= MAX_LED_MEMORY) {
|
||||
if (mem <= MAX_LED_MEMORY) {
|
||||
busses.add(*busConfigs[i]);
|
||||
}
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
@@ -178,44 +169,20 @@ void WLED::loop()
|
||||
strip.finalizeInit(); // also loads default ledmap if present
|
||||
if (aligned) strip.makeAutoSegments();
|
||||
else strip.fixInvalidSegments();
|
||||
doSerializeConfig = true;
|
||||
yield();
|
||||
serializeConfig();
|
||||
}
|
||||
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
|
||||
if (!strip.isUpdating())
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
esp_task_wdt_reset();
|
||||
#else
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
#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());
|
||||
@@ -238,13 +205,11 @@ 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;
|
||||
@@ -252,8 +217,18 @@ 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() {
|
||||
@@ -538,7 +513,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) || defined(ARDUINO_ARCH_ESP32S3))
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2))
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||
#endif
|
||||
|
||||
@@ -673,6 +648,7 @@ void WLED::initConnection()
|
||||
ws.onEvent(wsEvent);
|
||||
#endif
|
||||
|
||||
|
||||
WiFi.disconnect(true); // close old connections
|
||||
#ifdef ESP8266
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
@@ -716,7 +692,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) || defined(ARDUINO_ARCH_ESP32S3))
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2))
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||
#endif
|
||||
WiFi.setSleep(!noWifiSleep);
|
||||
@@ -871,7 +847,7 @@ void WLED::handleConnection()
|
||||
if (improvActive) {
|
||||
if (improvError == 3) sendImprovStateResponse(0x00, true);
|
||||
sendImprovStateResponse(0x04);
|
||||
if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi);
|
||||
if (improvActive > 1) sendImprovRPCResponse(0x01);
|
||||
}
|
||||
initInterfaces();
|
||||
userConnected();
|
||||
|
||||
+10
-30
@@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.14.0-b4
|
||||
@version 0.14.0-b2
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2308110
|
||||
#define VERSION 2306020
|
||||
|
||||
//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,8 +44,6 @@
|
||||
#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
|
||||
@@ -75,9 +73,6 @@
|
||||
{
|
||||
#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>
|
||||
@@ -94,10 +89,6 @@
|
||||
#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>
|
||||
@@ -331,17 +322,12 @@ 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);
|
||||
#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 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 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
|
||||
@@ -458,12 +444,6 @@ 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
|
||||
@@ -513,7 +493,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 unsigned long lastReconnectAttempt _INIT(0);
|
||||
WLED_GLOBAL uint32_t 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
@@ -0,0 +1,387 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
+83
-77
@@ -9,9 +9,6 @@
|
||||
#ifdef WLED_ENABLE_PIXART
|
||||
#include "html_pixart.h"
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_PXMAGIC
|
||||
#include "html_pxmagic.h"
|
||||
#endif
|
||||
#include "html_cpal.h"
|
||||
|
||||
/*
|
||||
@@ -116,6 +113,14 @@ 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;
|
||||
@@ -123,16 +128,19 @@ void initServer()
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
//request->send_P(200, "text/html", PAGE_liveviewws);
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
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){
|
||||
@@ -156,6 +164,10 @@ void initServer()
|
||||
}
|
||||
});
|
||||
|
||||
server.on("/sliders", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveIndex(request);
|
||||
});
|
||||
|
||||
server.on("/welcome", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveSettings(request);
|
||||
});
|
||||
@@ -183,11 +195,9 @@ void initServer()
|
||||
JsonObject root = doc.as<JsonObject>();
|
||||
if (error || root.isNull()) {
|
||||
releaseJSONBufferLock();
|
||||
request->send(400, "application/json", F("{\"error\":9}")); // ERR_JSON
|
||||
request->send(400, "application/json", F("{\"error\":9}"));
|
||||
return;
|
||||
}
|
||||
if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as<const char*>());
|
||||
|
||||
const String& url = request->url();
|
||||
isConfig = url.indexOf("cfg") > -1;
|
||||
if (!isConfig) {
|
||||
@@ -200,11 +210,6 @@ 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();
|
||||
@@ -232,15 +237,19 @@ 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);
|
||||
@@ -337,14 +346,9 @@ 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;
|
||||
if (!showWelcomePage || request->hasArg(F("sliders"))){
|
||||
serveIndex(request);
|
||||
} else {
|
||||
serveSettings(request);
|
||||
}
|
||||
serveIndexOrWelcome(request);
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_PIXART
|
||||
@@ -358,17 +362,6 @@ 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;
|
||||
@@ -406,9 +399,20 @@ 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");
|
||||
@@ -550,62 +554,64 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
|
||||
if (url.indexOf("sett") >= 0)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
else if (url.indexOf("/update") >= 0) subPage = SUBPAGE_UPDATE; // update page, for PIN check
|
||||
else if (url.indexOf("/update") >= 0) subPage = 9; // update page, for PIN check
|
||||
//else if (url.indexOf("/edit") >= 0) subPage = 10;
|
||||
else subPage = SUBPAGE_WELCOME;
|
||||
else subPage = 255; // welcome page
|
||||
|
||||
if (!correctPIN && strlen(settingsPIN) > 0 && (subPage > 0 && subPage < 11)) {
|
||||
originalSubPage = subPage;
|
||||
subPage = SUBPAGE_PINREQ; // require PIN
|
||||
subPage = 252; // require PIN
|
||||
}
|
||||
|
||||
// if OTA locked or too frequent PIN entry requests fail hard
|
||||
if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < PIN_RETRY_COOLDOWN))
|
||||
if ((subPage == 1 && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < 3000))
|
||||
{
|
||||
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_ota), 254); return;
|
||||
}
|
||||
|
||||
if (post) { //settings/set POST request, saving
|
||||
if (subPage != SUBPAGE_WIFI || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
|
||||
if (subPage != 1 || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
|
||||
|
||||
char s[32];
|
||||
char s2[45] = "";
|
||||
|
||||
switch (subPage) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
if (subPage != SUBPAGE_PINREQ) strcat_P(s, PSTR(" settings saved."));
|
||||
if (subPage == 252) {
|
||||
createEditHandler(correctPIN);
|
||||
} else
|
||||
strcat_P(s, PSTR(" settings saved."));
|
||||
|
||||
if (subPage == SUBPAGE_PINREQ && correctPIN) {
|
||||
if (subPage == 252 && correctPIN) {
|
||||
subPage = originalSubPage; // on correct PIN load settings page the user intended
|
||||
} else {
|
||||
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
||||
|
||||
bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot));
|
||||
serveMessage(request, 200, s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3));
|
||||
serveMessage(request, 200, s, s2, (subPage == 1 || (subPage == 6 && doReboot)) ? 129 : (correctPIN ? 1 : 3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -613,30 +619,30 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
AsyncWebServerResponse *response;
|
||||
switch (subPage)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
case SUBPAGE_DMX : response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
|
||||
case 7: response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
|
||||
#endif
|
||||
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;
|
||||
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;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
case SUBPAGE_2D : response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
|
||||
case 10: response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
|
||||
#endif
|
||||
case SUBPAGE_LOCK : {
|
||||
case 251: {
|
||||
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 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;
|
||||
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;
|
||||
default: response = request->beginResponse_P(200, "text/html", PAGE_settings, PAGE_settings_length); break;
|
||||
}
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
|
||||
+15
-21
@@ -54,15 +54,14 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
}
|
||||
releaseJSONBufferLock(); // will clean fileDoc
|
||||
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -79,7 +78,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}")); // ERR_JSON we do not handle split packets right now
|
||||
client->text(F("{\"error\":9}")); //we do not handle split packets right now
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,24 +165,23 @@ 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 (used > MAX_LIVE_LEDS_WS*4) {
|
||||
if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS*4) {
|
||||
buffer[2] = Segment::maxWidth/4;
|
||||
buffer[3] = Segment::maxHeight/4;
|
||||
skipLines = 3;
|
||||
} else if (used > MAX_LIVE_LEDS_WS) {
|
||||
} else if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS) {
|
||||
buffer[2] = Segment::maxWidth/2;
|
||||
buffer[3] = Segment::maxHeight/2;
|
||||
skipLines = 1;
|
||||
@@ -199,13 +197,9 @@ bool sendLiveLedsWs(uint32_t wsClient)
|
||||
}
|
||||
#endif
|
||||
uint32_t c = strip.getPixelColor(i);
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
wsc->binary(wsBuf);
|
||||
|
||||
+63
-35
@@ -72,6 +72,55 @@ 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>();
|
||||
@@ -148,7 +197,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,37,38"));
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31"));
|
||||
#else
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11"));
|
||||
#endif
|
||||
@@ -236,7 +285,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
if (subPage <0 || subPage >10) return;
|
||||
|
||||
if (subPage == SUBPAGE_MENU)
|
||||
if (subPage == 0)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D // include only if 2D is compiled in
|
||||
oappend(PSTR("gId('2dbtn').style.display='';"));
|
||||
@@ -246,7 +295,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (subPage == SUBPAGE_WIFI)
|
||||
if (subPage == 1)
|
||||
{
|
||||
sappends('s',SET_F("CS"),clientSSID);
|
||||
|
||||
@@ -279,14 +328,6 @@ 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
|
||||
@@ -319,22 +360,9 @@ 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 == SUBPAGE_LEDS)
|
||||
if (subPage == 2)
|
||||
{
|
||||
char nS[32];
|
||||
|
||||
@@ -355,7 +383,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"),useGlobalLedBuffer);
|
||||
sappend('c',SET_F("LD"),strip.useLedsArray);
|
||||
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
Bus* bus = busses.getBus(s);
|
||||
@@ -382,7 +410,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->isReversed());
|
||||
sappend('c',cv,bus->reversed);
|
||||
sappend('v',sl,bus->skippedLeds());
|
||||
sappend('c',rf,bus->isOffRefreshRequired());
|
||||
sappend('v',aw,bus->getAutoWhiteMode());
|
||||
@@ -465,7 +493,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("MSO"),!irApplyToAllSelected);
|
||||
}
|
||||
|
||||
if (subPage == SUBPAGE_UI)
|
||||
if (subPage == 3)
|
||||
{
|
||||
sappends('s',SET_F("DS"),serverDescription);
|
||||
sappend('c',SET_F("ST"),syncToggleReceive);
|
||||
@@ -476,7 +504,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (subPage == SUBPAGE_SYNC)
|
||||
if (subPage == 4)
|
||||
{
|
||||
sappend('v',SET_F("UP"),udpPort);
|
||||
sappend('v',SET_F("U2"),udpPort2);
|
||||
@@ -569,7 +597,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("BD"),serialBaud);
|
||||
}
|
||||
|
||||
if (subPage == SUBPAGE_TIME)
|
||||
if (subPage == 5)
|
||||
{
|
||||
sappend('c',SET_F("NT"),ntpEnabled);
|
||||
sappends('s',SET_F("NS"),ntpServerName);
|
||||
@@ -633,7 +661,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
}
|
||||
|
||||
if (subPage == SUBPAGE_SEC)
|
||||
if (subPage == 6)
|
||||
{
|
||||
byte l = strlen(settingsPIN);
|
||||
char fpass[l+1]; //fill PIN field with 0000
|
||||
@@ -655,7 +683,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
if (subPage == SUBPAGE_DMX)
|
||||
if (subPage == 7)
|
||||
{
|
||||
sappend('v',SET_F("PU"),e131ProxyUniverse);
|
||||
|
||||
@@ -682,7 +710,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (subPage == SUBPAGE_UM) //usermods
|
||||
if (subPage == 8) //usermods
|
||||
{
|
||||
appendGPIOinfo();
|
||||
oappend(SET_F("numM="));
|
||||
@@ -701,7 +729,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
usermods.appendConfigData();
|
||||
}
|
||||
|
||||
if (subPage == SUBPAGE_UPDATE) // update
|
||||
if (subPage == 9) // update
|
||||
{
|
||||
sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED "));
|
||||
olen -= 2; //delete ";
|
||||
@@ -717,7 +745,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
oappend(SET_F(")\";"));
|
||||
}
|
||||
|
||||
if (subPage == SUBPAGE_2D) // 2D matrices
|
||||
if (subPage == 10) // 2D matrices
|
||||
{
|
||||
sappend('v',SET_F("SOMP"),strip.isMatrix);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
|
||||
Reference in New Issue
Block a user