Merge branch 'main' into AC-ES8388
This commit is contained in:
commit
76acb7bb58
70
CHANGELOG.md
70
CHANGELOG.md
@ -1,5 +1,75 @@
|
|||||||
## WLED changelog
|
## WLED changelog
|
||||||
|
|
||||||
|
#### 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)
|
||||||
|
- Changes for allowing Alexa to change light color to White when auto-calculating from RGB (PR #3211)
|
||||||
|
|
||||||
|
#### Build 2305280
|
||||||
|
- DDP protocol update (#3193)
|
||||||
|
- added PCF8574 I2C port expander support for Multi relay usermod
|
||||||
|
- MQTT multipacket (fragmented) message fix
|
||||||
|
- added option to retain MQTT brightness and color messages
|
||||||
|
- new ethernet board: @srg74 Ethernet Shield
|
||||||
|
- new 2D effects: Soap (#3184) & Octopus & Waving cell (credit @St3P40 https://github.com/80Stepko08)
|
||||||
|
- various fixes and enhancements
|
||||||
|
|
||||||
|
#### Build 2305090
|
||||||
|
- new ethernet board: @Wladi ABC! WLED Eth
|
||||||
|
- Battery usermod voltage calculation (#3116)
|
||||||
|
- custom palette editor (#3164)
|
||||||
|
- improvements in Dancing Shadows and Tartan effects
|
||||||
|
- UCS389x support
|
||||||
|
- switched to NeoPixelBus 2.7.5 (replaced NeoPixelBrightnessBus with NeoPixelBusLg)
|
||||||
|
- SPI bus clock selection (for LEDs) (#3173)
|
||||||
|
- DMX mode preset fix (#3134)
|
||||||
|
- iOS fix for scroll (#3182)
|
||||||
|
- Wordclock "Norddeutsch" fix (#3161)
|
||||||
|
- various fixes and enhancements
|
||||||
|
|
||||||
#### Build 2304090
|
#### Build 2304090
|
||||||
- updated Arduino ESP8266 core to 4.1.0 (newer compiler)
|
- updated Arduino ESP8266 core to 4.1.0 (newer compiler)
|
||||||
- updated NeoPixelBus to 2.7.3 (with support for UCS890x chipset)
|
- updated NeoPixelBus to 2.7.3 (with support for UCS890x chipset)
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.14.0-b2",
|
"version": "0.14.0-b3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1409,9 +1409,9 @@
|
|||||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="
|
||||||
},
|
},
|
||||||
"semver-diff": {
|
"semver-diff": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.14.0-b2",
|
"version": "0.14.0-b3",
|
||||||
"description": "Tools for WLED project",
|
"description": "Tools for WLED project",
|
||||||
"main": "tools/cdata.js",
|
"main": "tools/cdata.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
# CI binaries
|
# 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 # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
|
||||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
|
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
|
||||||
|
|
||||||
# Release binaries
|
# Release binaries
|
||||||
@ -40,6 +40,8 @@ default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_
|
|||||||
; default_envs = esp32dev_qio80
|
; default_envs = esp32dev_qio80
|
||||||
; default_envs = esp32_eth_ota1mapp
|
; default_envs = esp32_eth_ota1mapp
|
||||||
; default_envs = esp32s2_saola
|
; default_envs = esp32s2_saola
|
||||||
|
; default_envs = esp32c3dev
|
||||||
|
; default_envs = lolin_s2_mini
|
||||||
|
|
||||||
src_dir = ./wled00
|
src_dir = ./wled00
|
||||||
data_dir = ./wled00/data
|
data_dir = ./wled00/data
|
||||||
@ -60,13 +62,14 @@ arduino_core_2_7_4 = espressif8266@2.6.2
|
|||||||
arduino_core_3_0_0 = espressif8266@3.0.0
|
arduino_core_3_0_0 = espressif8266@3.0.0
|
||||||
arduino_core_3_2_0 = espressif8266@3.2.0
|
arduino_core_3_2_0 = espressif8266@3.2.0
|
||||||
arduino_core_4_1_0 = espressif8266@4.1.0
|
arduino_core_4_1_0 = espressif8266@4.1.0
|
||||||
|
arduino_core_3_1_2 = espressif8266@4.2.0
|
||||||
|
|
||||||
# Development platforms
|
# Development platforms
|
||||||
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
|
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
|
||||||
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
|
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
|
||||||
|
|
||||||
# Platform to use for ESP8266
|
# Platform to use for ESP8266
|
||||||
platform_wled_default = ${common.arduino_core_4_1_0}
|
platform_wled_default = ${common.arduino_core_3_1_2}
|
||||||
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
|
# 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 = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||||
platform_packages = platformio/framework-arduinoespressif8266
|
platform_packages = platformio/framework-arduinoespressif8266
|
||||||
@ -178,12 +181,10 @@ lib_deps =
|
|||||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7
|
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7
|
||||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||||
#TFT_eSPI
|
#TFT_eSPI
|
||||||
#For use SSD1306 OLED display uncomment following
|
#For compatible OLED display uncomment following
|
||||||
#U8g2@~2.28.8
|
#U8g2 #@ ~2.33.15
|
||||||
#U8g2@~2.32.10
|
#For Dallas sensor uncomment following
|
||||||
#For Dallas sensor uncomment following 2 lines
|
#OneWire @ ~2.3.7
|
||||||
#OneWire@~2.3.5
|
|
||||||
#milesburton/DallasTemperature@^3.9.0
|
|
||||||
#For BME280 sensor uncomment following
|
#For BME280 sensor uncomment following
|
||||||
#BME280 @ ~3.0.0
|
#BME280 @ ~3.0.0
|
||||||
; adafruit/Adafruit BMP280 Library @ 2.1.0
|
; adafruit/Adafruit BMP280 Library @ 2.1.0
|
||||||
@ -461,8 +462,8 @@ board = esp32-c3-devkitm-1
|
|||||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
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
|
-D WLED_WATCHDOG_TIMEOUT=0
|
||||||
; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
|
-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=0 ;; for serial-to-USB chip
|
||||||
upload_speed = 460800
|
upload_speed = 460800
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
lib_deps = ${esp32c3.lib_deps}
|
lib_deps = ${esp32c3.lib_deps}
|
||||||
@ -574,10 +575,10 @@ platform = ${esp32s2.platform}
|
|||||||
platform_packages = ${esp32s2.platform_packages}
|
platform_packages = ${esp32s2.platform_packages}
|
||||||
board = lolin_s2_mini
|
board = lolin_s2_mini
|
||||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||||
build_unflags = ${common.build_unflags} -DARDUINO_USB_CDC_ON_BOOT=1
|
build_unflags = ${common.build_unflags} #-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2
|
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2
|
||||||
-DBOARD_HAS_PSRAM
|
-DBOARD_HAS_PSRAM
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=0
|
-DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial
|
||||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||||
|
@ -21,9 +21,7 @@ click==8.1.3
|
|||||||
# platformio
|
# platformio
|
||||||
# uvicorn
|
# uvicorn
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
# via
|
# via platformio
|
||||||
# click
|
|
||||||
# platformio
|
|
||||||
h11==0.14.0
|
h11==0.14.0
|
||||||
# via
|
# via
|
||||||
# uvicorn
|
# uvicorn
|
||||||
@ -42,7 +40,7 @@ pyelftools==0.29
|
|||||||
# via platformio
|
# via platformio
|
||||||
pyserial==3.5
|
pyserial==3.5
|
||||||
# via platformio
|
# via platformio
|
||||||
requests==2.28.2
|
requests==2.31.0
|
||||||
# via platformio
|
# via platformio
|
||||||
semantic-version==2.10.0
|
semantic-version==2.10.0
|
||||||
# via platformio
|
# via platformio
|
||||||
@ -52,8 +50,6 @@ starlette==0.23.1
|
|||||||
# via platformio
|
# via platformio
|
||||||
tabulate==0.9.0
|
tabulate==0.9.0
|
||||||
# via platformio
|
# via platformio
|
||||||
typing-extensions==4.5.0
|
|
||||||
# via starlette
|
|
||||||
urllib3==1.26.15
|
urllib3==1.26.15
|
||||||
# via requests
|
# via requests
|
||||||
uvicorn==0.20.0
|
uvicorn==0.20.0
|
||||||
|
@ -222,6 +222,7 @@ writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index');
|
|||||||
writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple');
|
writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple');
|
||||||
writeHtmlGzipped("wled00/data/pixart/pixart.htm", "wled00/html_pixart.h", 'pixart');
|
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/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal');
|
||||||
|
writeHtmlGzipped("wled00/data/pxmagic/pxmagic.htm", "wled00/html_pxmagic.h", 'pxmagic');
|
||||||
/*
|
/*
|
||||||
writeChunks(
|
writeChunks(
|
||||||
"wled00/data",
|
"wled00/data",
|
||||||
@ -389,12 +390,6 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
|||||||
method: "gzip",
|
method: "gzip",
|
||||||
filter: "html-minify",
|
filter: "html-minify",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
file: "liveviewws.htm",
|
|
||||||
name: "PAGE_liveviewws",
|
|
||||||
method: "gzip",
|
|
||||||
filter: "html-minify",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
file: "liveviewws2D.htm",
|
file: "liveviewws2D.htm",
|
||||||
name: "PAGE_liveviewws2D",
|
name: "PAGE_liveviewws2D",
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <Wire.h>
|
|
||||||
#include <BH1750.h>
|
#include <BH1750.h>
|
||||||
|
|
||||||
// the max frequency to check photoresistor, 10 seconds
|
// the max frequency to check photoresistor, 10 seconds
|
||||||
@ -56,15 +55,6 @@ private:
|
|||||||
static const char _offset[];
|
static const char _offset[];
|
||||||
static const char _HomeAssistantDiscovery[];
|
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 initDone = false;
|
||||||
bool sensorFound = false;
|
bool sensorFound = false;
|
||||||
|
|
||||||
@ -123,14 +113,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
bool HW_Pins_Used = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); // note whether architecture-based hardware SCL/SDA pins used
|
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||||
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();
|
sensorFound = lightMeter.begin();
|
||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
@ -190,7 +173,9 @@ public:
|
|||||||
user = root.createNestedObject(F("u"));
|
user = root.createNestedObject(F("u"));
|
||||||
|
|
||||||
JsonArray lux_json = user.createNestedArray(F("Luminance"));
|
JsonArray lux_json = user.createNestedArray(F("Luminance"));
|
||||||
if (!sensorFound) {
|
if (!enabled) {
|
||||||
|
lux_json.add(F("disabled"));
|
||||||
|
} else if (!sensorFound) {
|
||||||
// if no sensor
|
// if no sensor
|
||||||
lux_json.add(F("BH1750 "));
|
lux_json.add(F("BH1750 "));
|
||||||
lux_json.add(F("Not Found"));
|
lux_json.add(F("Not Found"));
|
||||||
@ -216,9 +201,6 @@ public:
|
|||||||
top[FPSTR(_minReadInterval)] = minReadingInterval;
|
top[FPSTR(_minReadInterval)] = minReadingInterval;
|
||||||
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
|
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
|
||||||
top[FPSTR(_offset)] = offset;
|
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."));
|
DEBUG_PRINTLN(F("BH1750 config saved."));
|
||||||
}
|
}
|
||||||
@ -226,8 +208,6 @@ public:
|
|||||||
// called before setup() to populate properties from values stored in cfg.json
|
// called before setup() to populate properties from values stored in cfg.json
|
||||||
bool readFromConfig(JsonObject &root)
|
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.
|
// we look for JSON object.
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull())
|
if (top.isNull())
|
||||||
@ -244,27 +224,12 @@ public:
|
|||||||
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
|
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
|
||||||
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
|
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
|
||||||
configComplete &= getJsonValue(top[FPSTR(_offset)], offset, 1);
|
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));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// first run: reading from cfg.json
|
|
||||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
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;
|
return configComplete;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
|
||||||
#include <BME280I2C.h> // BME280 sensor
|
#include <BME280I2C.h> // BME280 sensor
|
||||||
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ private:
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||||
#endif
|
#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;
|
bool initDone = false;
|
||||||
|
|
||||||
// BME280 sensor settings
|
// BME280 sensor settings
|
||||||
@ -186,13 +184,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
bool HW_Pins_Used = (ioPin[0]==i2c_scl && ioPin[1]==i2c_sda); // note whether architecture-based hardware SCL/SDA pins used
|
if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; }
|
||||||
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())
|
if (!bme.begin())
|
||||||
{
|
{
|
||||||
@ -415,9 +407,6 @@ public:
|
|||||||
top[F("PublishAlways")] = PublishAlways;
|
top[F("PublishAlways")] = PublishAlways;
|
||||||
top[F("UseCelsius")] = UseCelsius;
|
top[F("UseCelsius")] = UseCelsius;
|
||||||
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
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."));
|
DEBUG_PRINTLN(F("BME280 config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,8 +416,6 @@ public:
|
|||||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
// 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)
|
// 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)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
DEBUG_PRINT(F(_name));
|
DEBUG_PRINT(F(_name));
|
||||||
@ -447,27 +434,14 @@ public:
|
|||||||
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||||
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||||
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
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));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// first run: reading from cfg.json
|
// first run: reading from cfg.json
|
||||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
// changing parameters from settings page
|
// 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;
|
return configComplete;
|
||||||
|
@ -133,13 +133,13 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
read32(bmpFS); // filesize in bytes
|
(void) read32(bmpFS); // filesize in bytes
|
||||||
read32(bmpFS); // reserved
|
(void) read32(bmpFS); // reserved
|
||||||
seekOffset = read32(bmpFS); // start of bitmap
|
seekOffset = read32(bmpFS); // start of bitmap
|
||||||
headerSize = read32(bmpFS); // header size
|
headerSize = read32(bmpFS); // header size
|
||||||
w = read32(bmpFS); // width
|
w = read32(bmpFS); // width
|
||||||
h = read32(bmpFS); // height
|
h = read32(bmpFS); // height
|
||||||
read16(bmpFS); // color planes (must be 1)
|
(void) read16(bmpFS); // color planes (must be 1)
|
||||||
bitDepth = read16(bmpFS);
|
bitDepth = read16(bmpFS);
|
||||||
|
|
||||||
if (read32(bmpFS) != 0 || (bitDepth != 24 && bitDepth != 1 && bitDepth != 4 && bitDepth != 8)) {
|
if (read32(bmpFS) != 0 || (bitDepth != 24 && bitDepth != 1 && bitDepth != 4 && bitDepth != 8)) {
|
||||||
@ -151,9 +151,9 @@ private:
|
|||||||
uint32_t palette[256];
|
uint32_t palette[256];
|
||||||
if (bitDepth <= 8) // 1,4,8 bit bitmap: read color palette
|
if (bitDepth <= 8) // 1,4,8 bit bitmap: read color palette
|
||||||
{
|
{
|
||||||
read32(bmpFS); read32(bmpFS); read32(bmpFS); // size, w resolution, h resolution
|
(void) read32(bmpFS); (void) read32(bmpFS); (void) read32(bmpFS); // size, w resolution, h resolution
|
||||||
paletteSize = read32(bmpFS);
|
paletteSize = read32(bmpFS);
|
||||||
if (paletteSize == 0) paletteSize = bitDepth * bitDepth; //if 0, size is 2^bitDepth
|
if (paletteSize == 0) paletteSize = 1 << bitDepth; //if 0, size is 2^bitDepth
|
||||||
bmpFS.seek(14 + headerSize); // start of color palette
|
bmpFS.seek(14 + headerSize); // start of color palette
|
||||||
for (uint16_t i = 0; i < paletteSize; i++) {
|
for (uint16_t i = 0; i < paletteSize; i++) {
|
||||||
palette[i] = read32(bmpFS);
|
palette[i] = read32(bmpFS);
|
||||||
@ -198,7 +198,7 @@ private:
|
|||||||
}
|
}
|
||||||
b = c; g = c >> 8; r = c >> 16;
|
b = c; g = c >> 8; r = c >> 16;
|
||||||
}
|
}
|
||||||
if (dimming != 255) { // only dimm when needed
|
if (dimming != 255) { // only dim when needed
|
||||||
r *= dimming; g *= dimming; b *= dimming;
|
r *= dimming; g *= dimming; b *= dimming;
|
||||||
r = r >> 8; g = g >> 8; b = b >> 8;
|
r = r >> 8; g = g >> 8; b = b >> 8;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* This usermod handles PIR sensor states.
|
* This usermod handles PIR sensor states.
|
||||||
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
* 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.
|
* 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
|
* Usermods allow you to add own functionality to WLED more easily
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||||
@ -38,21 +38,21 @@ public:
|
|||||||
~PIRsensorSwitch() {}
|
~PIRsensorSwitch() {}
|
||||||
|
|
||||||
//Enable/Disable the PIR sensor
|
//Enable/Disable the PIR sensor
|
||||||
void EnablePIRsensor(bool en) { enabled = en; }
|
inline void EnablePIRsensor(bool en) { enabled = en; }
|
||||||
|
|
||||||
// Get PIR sensor enabled/disabled state
|
// Get PIR sensor enabled/disabled state
|
||||||
bool PIRsensorEnabled() { return enabled; }
|
inline bool PIRsensorEnabled() { return enabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
byte prevPreset = 0;
|
byte prevPreset = 0;
|
||||||
byte prevPlaylist = 0;
|
byte prevPlaylist = 0;
|
||||||
|
|
||||||
uint32_t offTimerStart = 0; // off timer start time
|
volatile unsigned long offTimerStart = 0; // off timer start time
|
||||||
|
volatile bool PIRtriggered = false; // did PIR trigger?
|
||||||
byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for stateUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE
|
byte 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
|
byte sensorPinState = LOW; // current PIR sensor pin state
|
||||||
bool initDone = false; // status of initialization
|
bool initDone = false; // status of initialization
|
||||||
bool PIRtriggered = false;
|
|
||||||
unsigned long lastLoop = 0;
|
unsigned long lastLoop = 0;
|
||||||
|
|
||||||
// configurable parameters
|
// configurable parameters
|
||||||
@ -66,6 +66,7 @@ private:
|
|||||||
// flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR)
|
// 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_offOnly = false;
|
||||||
bool m_offMode = offMode;
|
bool m_offMode = offMode;
|
||||||
|
bool m_override = false;
|
||||||
|
|
||||||
// Home Assistant
|
// Home Assistant
|
||||||
bool HomeAssistantDiscovery = false; // is HA discovery turned on
|
bool HomeAssistantDiscovery = false; // is HA discovery turned on
|
||||||
@ -81,12 +82,122 @@ private:
|
|||||||
static const char _offOnly[];
|
static const char _offOnly[];
|
||||||
static const char _haDiscovery[];
|
static const char _haDiscovery[];
|
||||||
static const char _notify[];
|
static const char _notify[];
|
||||||
|
static const char _override[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check if it is daytime
|
* check if it is daytime
|
||||||
* if sunrise/sunset is not defined (no NTP or lat/lon) default to nighttime
|
* if sunrise/sunset is not defined (no NTP or lat/lon) default to nighttime
|
||||||
*/
|
*/
|
||||||
bool isDayTime() {
|
static bool isDayTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switch strip on/off
|
||||||
|
*/
|
||||||
|
void switchStrip(bool switchOn);
|
||||||
|
void publishMqtt(const char* state);
|
||||||
|
|
||||||
|
// Create an MQTT Binary Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||||
|
void publishHomeAssistantAutodiscovery();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read and update PIR sensor state.
|
||||||
|
* Initilize/reset switch off timer
|
||||||
|
*/
|
||||||
|
bool updatePIRsensorState();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switch off the strip if the delay has elapsed
|
||||||
|
*/
|
||||||
|
bool handleOffTimer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
//Functions called by WLED
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
//void connected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onMqttConnect() is called when MQTT connection is established
|
||||||
|
*/
|
||||||
|
void onMqttConnect(bool sessionPresent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
|
*/
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
|
*
|
||||||
|
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||||
|
*/
|
||||||
|
void addToJsonInfo(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onStateChanged() is used to detect WLED state change
|
||||||
|
*/
|
||||||
|
void onStateChange(uint8_t mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||||
|
* Values in the state object may be modified by connected clients
|
||||||
|
*/
|
||||||
|
//void addToJsonState(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide the changeable values
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide UI information and allow extending UI options
|
||||||
|
*/
|
||||||
|
void appendConfigData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* restore the changeable values
|
||||||
|
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||||
|
*
|
||||||
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
|
*/
|
||||||
|
bool readFromConfig(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||||
|
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||||
|
*/
|
||||||
|
uint16_t getId() { return USERMOD_ID_PIRSWITCH; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
|
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
||||||
|
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
||||||
|
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
||||||
|
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
||||||
|
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
||||||
|
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
||||||
|
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();
|
updateLocalTime();
|
||||||
uint8_t hr = hour(localTime);
|
uint8_t hr = hour(localTime);
|
||||||
uint8_t mi = minute(localTime);
|
uint8_t mi = minute(localTime);
|
||||||
@ -106,10 +217,7 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::switchStrip(bool switchOn)
|
||||||
* switch strip on/off
|
|
||||||
*/
|
|
||||||
void switchStrip(bool switchOn)
|
|
||||||
{
|
{
|
||||||
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return; //if lights on and off only, do nothing
|
if (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
|
if (PIRtriggered && switchOn) return; //if already on and triggered before, do nothing
|
||||||
@ -158,21 +266,19 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishMqtt(const char* state)
|
void PIRsensorSwitch::publishMqtt(const char* state)
|
||||||
{
|
{
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
if (WLED_MQTT_CONNECTED) {
|
if (WLED_MQTT_CONNECTED) {
|
||||||
char subuf[64];
|
char buf[64];
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||||
strcat_P(subuf, PSTR("/motion"));
|
mqtt->publish(buf, 0, false, state);
|
||||||
mqtt->publish(subuf, 0, false, state);
|
|
||||||
}
|
}
|
||||||
#endif
|
#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 PIRsensorSwitch::publishHomeAssistantAutodiscovery()
|
||||||
void publishHomeAssistantAutodiscovery()
|
|
||||||
{
|
{
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
if (WLED_MQTT_CONNECTED) {
|
if (WLED_MQTT_CONNECTED) {
|
||||||
@ -207,11 +313,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool PIRsensorSwitch::updatePIRsensorState()
|
||||||
* Read and update PIR sensor state.
|
|
||||||
* Initilize/reset switch off timer
|
|
||||||
*/
|
|
||||||
bool updatePIRsensorState()
|
|
||||||
{
|
{
|
||||||
bool pinState = digitalRead(PIRsensorPin);
|
bool pinState = digitalRead(PIRsensorPin);
|
||||||
if (pinState != sensorPinState) {
|
if (pinState != sensorPinState) {
|
||||||
@ -232,10 +334,7 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool PIRsensorSwitch::handleOffTimer()
|
||||||
* switch off the strip if the delay has elapsed
|
|
||||||
*/
|
|
||||||
bool handleOffTimer()
|
|
||||||
{
|
{
|
||||||
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
||||||
offTimerStart = 0;
|
offTimerStart = 0;
|
||||||
@ -249,14 +348,9 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::setup()
|
||||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
|
||||||
* You can use it to initialize variables, sensors or similar.
|
|
||||||
*/
|
|
||||||
void setup()
|
|
||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||||
@ -275,27 +369,14 @@ public:
|
|||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::onMqttConnect(bool sessionPresent)
|
||||||
* connected() is called every time the WiFi is (re)connected
|
|
||||||
* Use it to initialize network interfaces
|
|
||||||
*/
|
|
||||||
void connected()
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* onMqttConnect() is called when MQTT connection is established
|
|
||||||
*/
|
|
||||||
void onMqttConnect(bool sessionPresent) {
|
|
||||||
if (HomeAssistantDiscovery) {
|
if (HomeAssistantDiscovery) {
|
||||||
publishHomeAssistantAutodiscovery();
|
publishHomeAssistantAutodiscovery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::loop()
|
||||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
|
||||||
*/
|
|
||||||
void loop()
|
|
||||||
{
|
{
|
||||||
// only check sensors 4x/s
|
// only check sensors 4x/s
|
||||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||||
@ -306,12 +387,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::addToJsonInfo(JsonObject &root)
|
||||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
|
||||||
*
|
|
||||||
* Add PIR sensor state and switch off timer duration to jsoninfo
|
|
||||||
*/
|
|
||||||
void addToJsonInfo(JsonObject &root)
|
|
||||||
{
|
{
|
||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
@ -371,13 +447,10 @@ public:
|
|||||||
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::onStateChange(uint8_t mode) {
|
||||||
* onStateChanged() is used to detect WLED state change
|
|
||||||
*/
|
|
||||||
void onStateChange(uint8_t mode) {
|
|
||||||
if (!initDone) return;
|
if (!initDone) return;
|
||||||
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
||||||
if (PIRtriggered && offTimerStart) {
|
if (m_override && PIRtriggered && offTimerStart) { // debounce
|
||||||
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
||||||
DEBUG_PRINTLN(F("PIR: Canceled."));
|
DEBUG_PRINTLN(F("PIR: Canceled."));
|
||||||
offTimerStart = 0;
|
offTimerStart = 0;
|
||||||
@ -385,22 +458,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::readFromJsonState(JsonObject &root)
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
|
||||||
* Values in the state object may be modified by connected clients
|
|
||||||
*/
|
|
||||||
|
|
||||||
void readFromJsonState(JsonObject &root)
|
|
||||||
{
|
{
|
||||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
JsonObject usermod = root[FPSTR(_name)];
|
JsonObject usermod = root[FPSTR(_name)];
|
||||||
@ -411,11 +469,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::addToConfig(JsonObject &root)
|
||||||
/**
|
|
||||||
* provide the changeable values
|
|
||||||
*/
|
|
||||||
void addToConfig(JsonObject &root)
|
|
||||||
{
|
{
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
@ -426,24 +480,20 @@ public:
|
|||||||
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
||||||
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
||||||
top[FPSTR(_offOnly)] = m_offOnly;
|
top[FPSTR(_offOnly)] = m_offOnly;
|
||||||
|
top[FPSTR(_override)] = m_override;
|
||||||
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
||||||
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
||||||
DEBUG_PRINTLN(F("PIR config saved."));
|
DEBUG_PRINTLN(F("PIR config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendConfigData()
|
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: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: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)
|
||||||
* restore the changeable values
|
|
||||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
|
||||||
*
|
|
||||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
|
||||||
*/
|
|
||||||
bool readFromConfig(JsonObject &root)
|
|
||||||
{
|
{
|
||||||
bool oldEnabled = enabled;
|
bool oldEnabled = enabled;
|
||||||
int8_t oldPin = PIRsensorPin;
|
int8_t oldPin = PIRsensorPin;
|
||||||
@ -469,6 +519,7 @@ public:
|
|||||||
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
||||||
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
||||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||||
|
m_override = top[FPSTR(_override)] | m_override;
|
||||||
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
||||||
|
|
||||||
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
||||||
@ -498,27 +549,5 @@ public:
|
|||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_haDiscovery)].isNull();
|
return !top[FPSTR(_override)].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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
|
||||||
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
|
||||||
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
|
||||||
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
|
||||||
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
|
||||||
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
|
||||||
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
|
||||||
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";
|
|
||||||
|
@ -12,8 +12,7 @@ class RTCUsermod : public Usermod {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
if (i2c_scl<0 || i2c_sda<0) { disabled = true; return; }
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { disabled = true; return; }
|
|
||||||
RTC.begin();
|
RTC.begin();
|
||||||
time_t rtcTime = RTC.get();
|
time_t rtcTime = RTC.get();
|
||||||
if (rtcTime) {
|
if (rtcTime) {
|
||||||
@ -25,8 +24,8 @@ class RTCUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (strip.isUpdating()) return;
|
if (disabled || strip.isUpdating()) return;
|
||||||
if (!disabled && toki.isTick()) {
|
if (toki.isTick()) {
|
||||||
time_t t = toki.second();
|
time_t t = toki.second();
|
||||||
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
|
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,6 @@
|
|||||||
#ifndef TFT_HEIGHT
|
#ifndef TFT_HEIGHT
|
||||||
#error Please define TFT_HEIGHT
|
#error Please define TFT_HEIGHT
|
||||||
#endif
|
#endif
|
||||||
#ifndef TFT_MOSI
|
|
||||||
#error Please define TFT_MOSI
|
|
||||||
#endif
|
|
||||||
#ifndef TFT_SCLK
|
|
||||||
#error Please define TFT_SCLK
|
|
||||||
#endif
|
|
||||||
#ifndef TFT_DC
|
#ifndef TFT_DC
|
||||||
#error Please define TFT_DC
|
#error Please define TFT_DC
|
||||||
#endif
|
#endif
|
||||||
@ -140,8 +134,14 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
*/
|
*/
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
PinManagerPinType pins[] = { { TFT_MOSI, true }, { TFT_MISO, false}, { TFT_SCLK, true }, { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
PinManagerPinType spiPins[] = { { spi_mosi, true }, { spi_miso, false}, { spi_sclk, true } };
|
||||||
if (!pinManager.allocateMultiplePins(pins, 7, PinOwner::UM_FourLineDisplay)) { enabled = false; return; }
|
if (!pinManager.allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) { enabled = false; return; }
|
||||||
|
PinManagerPinType displayPins[] = { { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
||||||
|
if (!pinManager.allocateMultiplePins(displayPins, sizeof(displayPins)/sizeof(PinManagerPinType), PinOwner::UM_FourLineDisplay)) {
|
||||||
|
pinManager.deallocateMultiplePins(spiPins, 3, PinOwner::HW_SPI);
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tft.init();
|
tft.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.
|
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
|
||||||
@ -365,9 +365,6 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
{
|
{
|
||||||
JsonObject top = root.createNestedObject("ST7789");
|
JsonObject top = root.createNestedObject("ST7789");
|
||||||
JsonArray pins = top.createNestedArray("pin");
|
JsonArray pins = top.createNestedArray("pin");
|
||||||
pins.add(TFT_MOSI);
|
|
||||||
pins.add(TFT_MISO);
|
|
||||||
pins.add(TFT_SCLK);
|
|
||||||
pins.add(TFT_CS);
|
pins.add(TFT_CS);
|
||||||
pins.add(TFT_DC);
|
pins.add(TFT_DC);
|
||||||
pins.add(TFT_RST);
|
pins.add(TFT_RST);
|
||||||
@ -376,6 +373,13 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void appendConfigData() {
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI BL');"));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
* 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)
|
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
|
||||||
|
@ -13,14 +13,6 @@
|
|||||||
|
|
||||||
Adafruit_Si7021 si7021;
|
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
|
class Si7021_MQTT_HA : public Usermod
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -184,7 +176,6 @@ class Si7021_MQTT_HA : public Usermod
|
|||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Serial.println("Si7021_MQTT_HA: Starting!");
|
Serial.println("Si7021_MQTT_HA: Starting!");
|
||||||
Wire.begin(SDA_PIN, SCL_PIN);
|
|
||||||
Serial.println("Si7021_MQTT_HA: Initializing sensors.. ");
|
Serial.println("Si7021_MQTT_HA: Initializing sensors.. ");
|
||||||
_initializeSensor();
|
_initializeSensor();
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,7 @@ class UsermodVL53L0XGestures : public Usermod {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
|
||||||
Wire.begin();
|
|
||||||
|
|
||||||
sensor.setTimeout(150);
|
sensor.setTimeout(150);
|
||||||
if (!sensor.init())
|
if (!sensor.init())
|
||||||
|
@ -569,16 +569,6 @@ class AudioReactive : public Usermod {
|
|||||||
#else
|
#else
|
||||||
int8_t i2sckPin = I2S_CKPIN;
|
int8_t i2sckPin = I2S_CKPIN;
|
||||||
#endif
|
#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
|
#ifndef MCLK_PIN
|
||||||
int8_t mclkPin = I2S_PIN_NO_CHANGE; /* ESP32: only -1, 0, 1, 3 allowed*/
|
int8_t mclkPin = I2S_PIN_NO_CHANGE; /* ESP32: only -1, 0, 1, 3 allowed*/
|
||||||
#else
|
#else
|
||||||
@ -1136,7 +1126,7 @@ class AudioReactive : public Usermod {
|
|||||||
DEBUGSR_PRINTLN(F("AR: ES7243 Microphone (right channel only)."));
|
DEBUGSR_PRINTLN(F("AR: ES7243 Microphone (right channel only)."));
|
||||||
audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE);
|
audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE);
|
||||||
delay(100);
|
delay(100);
|
||||||
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
|
DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
|
||||||
@ -1664,8 +1654,6 @@ class AudioReactive : public Usermod {
|
|||||||
pinArray.add(i2swsPin);
|
pinArray.add(i2swsPin);
|
||||||
pinArray.add(i2sckPin);
|
pinArray.add(i2sckPin);
|
||||||
pinArray.add(mclkPin);
|
pinArray.add(mclkPin);
|
||||||
pinArray.add(sdaPin);
|
|
||||||
pinArray.add(sclPin);
|
|
||||||
|
|
||||||
JsonObject cfg = top.createNestedObject("config");
|
JsonObject cfg = top.createNestedObject("config");
|
||||||
cfg[F("squelch")] = soundSquelch;
|
cfg[F("squelch")] = soundSquelch;
|
||||||
@ -1726,8 +1714,6 @@ class AudioReactive : public Usermod {
|
|||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][1], i2swsPin);
|
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][1], i2swsPin);
|
||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][2], i2sckPin);
|
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][2], i2sckPin);
|
||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][3], mclkPin);
|
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("squelch")], soundSquelch);
|
||||||
configComplete &= getJsonValue(top["config"][F("gain")], sampleGain);
|
configComplete &= getJsonValue(top["config"][F("gain")], sampleGain);
|
||||||
@ -1793,8 +1779,6 @@ class AudioReactive : public Usermod {
|
|||||||
#else
|
#else
|
||||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>master clock</i>','I2S MCLK');"));
|
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>master clock</i>','I2S MCLK');"));
|
||||||
#endif
|
#endif
|
||||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',4,'','I2C SDA');"));
|
|
||||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',5,'','I2C SCL');"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Wire.h>
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <driver/i2s.h>
|
#include <driver/i2s.h>
|
||||||
#include <driver/adc.h>
|
#include <driver/adc.h>
|
||||||
@ -383,21 +382,12 @@ class I2SSource : public AudioSource {
|
|||||||
*/
|
*/
|
||||||
class ES7243 : public I2SSource {
|
class ES7243 : public I2SSource {
|
||||||
private:
|
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) {
|
void _es7243I2cWrite(uint8_t reg, uint8_t val) {
|
||||||
#ifndef ES7243_ADDR
|
#ifndef ES7243_ADDR
|
||||||
Wire.beginTransmission(0x13);
|
|
||||||
#define ES7243_ADDR 0x13 // default address
|
#define ES7243_ADDR 0x13 // default address
|
||||||
#else
|
|
||||||
Wire.beginTransmission(ES7243_ADDR);
|
|
||||||
#endif
|
#endif
|
||||||
|
Wire.beginTransmission(ES7243_ADDR);
|
||||||
Wire.write((uint8_t)reg);
|
Wire.write((uint8_t)reg);
|
||||||
Wire.write((uint8_t)val);
|
Wire.write((uint8_t)val);
|
||||||
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
|
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
|
||||||
@ -407,7 +397,6 @@ class ES7243 : public I2SSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _es7243InitAdc() {
|
void _es7243InitAdc() {
|
||||||
_es7243I2cBegin();
|
|
||||||
_es7243I2cWrite(0x00, 0x01);
|
_es7243I2cWrite(0x00, 0x01);
|
||||||
_es7243I2cWrite(0x06, 0x00);
|
_es7243I2cWrite(0x06, 0x00);
|
||||||
_es7243I2cWrite(0x05, 0x1B);
|
_es7243I2cWrite(0x05, 0x1B);
|
||||||
@ -422,44 +411,20 @@ public:
|
|||||||
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
|
void initialize(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)) {
|
if ((i2sckPin < 0) || (mclkPin < 0)) {
|
||||||
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
|
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
|
||||||
return;
|
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
|
// First route mclk, then configure ADC over I2C, then configure I2S
|
||||||
_es7243InitAdc();
|
_es7243InitAdc();
|
||||||
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinitialize() {
|
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();
|
I2SSource::deinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
int8_t pin_ES7243_SDA;
|
|
||||||
int8_t pin_ES7243_SCL;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ES8388 Sound Modude
|
/* ES8388 Sound Modude
|
||||||
|
@ -85,12 +85,9 @@ class MPU6050Driver : public Usermod {
|
|||||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||||
*/
|
*/
|
||||||
void setup() {
|
void setup() {
|
||||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||||
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
|
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
||||||
Wire.begin();
|
Wire.setClock(400000U); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
|
||||||
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
||||||
Fastwire::setup(400, true);
|
Fastwire::setup(400, true);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
# Multi Relay
|
# Multi Relay
|
||||||
|
|
||||||
This usermod-v2 modification allows the connection of multiple relays, each with individual delay and on/off mode.
|
This usermod-v2 modification allows the connection of multiple relays, each with individual delay and on/off mode.
|
||||||
|
Usermod supports PCF8574 I2C port expander to reduce GPIO use.
|
||||||
|
PCF8574 supports 8 outputs and each output corresponds to a relay in WLED (relay 0 = port 0, etc). I you are using more than 8 relays with multiple PCF8574 make sure their addresses are set conscutively (e.g. 0x20 and 0x21). You can set address of first expander in settings.
|
||||||
|
(**NOTE:** Will require Wire library and global I2C pins defined.)
|
||||||
|
|
||||||
## HTTP API
|
## HTTP API
|
||||||
All responses are returned in JSON format.
|
All responses are returned in JSON format.
|
||||||
@ -81,13 +84,15 @@ void registerUsermods()
|
|||||||
Usermod can be configured via the Usermods settings page.
|
Usermod can be configured via the Usermods settings page.
|
||||||
|
|
||||||
* `enabled` - enable/disable usermod
|
* `enabled` - enable/disable usermod
|
||||||
|
* `use-PCF8574` - use PCF8574 port expander instead of GPIO pins
|
||||||
|
* `first-PCF8574` - I2C address of first expander (WARNING: enter *decimal* value)
|
||||||
|
* `broadcast`- time in seconds between MQTT relay-state broadcasts
|
||||||
|
* `HA-discovery`- enable Home Assistant auto discovery
|
||||||
* `pin` - ESP GPIO pin the relay is connected to (can be configured at compile time `-D MULTI_RELAY_PINS=xx,xx,...`)
|
* `pin` - ESP GPIO pin the relay is connected to (can be configured at compile time `-D MULTI_RELAY_PINS=xx,xx,...`)
|
||||||
* `delay-s` - delay in seconds after on/off command is received
|
* `delay-s` - delay in seconds after on/off command is received
|
||||||
* `active-high` - assign high/low activation of relay (can be used to reverse relay states)
|
* `active-high` - assign high/low activation of relay (can be used to reverse relay states)
|
||||||
* `external` - if enabled, WLED does not control relay, it can only be triggered by an external command (MQTT, HTTP, JSON or button)
|
* `external` - if enabled, WLED does not control relay, it can only be triggered by an external command (MQTT, HTTP, JSON or button)
|
||||||
* `button` - button (from LED Settings) that controls this relay
|
* `button` - button (from LED Settings) that controls this relay
|
||||||
* `broadcast`- time in seconds between MQTT relay-state broadcasts
|
|
||||||
* `HA-discovery`- enable Home Assistant auto discovery
|
|
||||||
|
|
||||||
If there is no MultiRelay section, just save current configuration and re-open Usermods settings page.
|
If there is no MultiRelay section, just save current configuration and re-open Usermods settings page.
|
||||||
|
|
||||||
@ -100,3 +105,6 @@ Have fun - @blazoncek
|
|||||||
2021-11
|
2021-11
|
||||||
* Added information about dynamic configuration options
|
* Added information about dynamic configuration options
|
||||||
* Added button support.
|
* Added button support.
|
||||||
|
|
||||||
|
2023-05
|
||||||
|
* Added support for PCF8574 I2C port expander (multiple)
|
@ -4,10 +4,19 @@
|
|||||||
|
|
||||||
#ifndef MULTI_RELAY_MAX_RELAYS
|
#ifndef MULTI_RELAY_MAX_RELAYS
|
||||||
#define MULTI_RELAY_MAX_RELAYS 4
|
#define MULTI_RELAY_MAX_RELAYS 4
|
||||||
|
#else
|
||||||
|
#if MULTI_RELAY_MAX_RELAYS>8
|
||||||
|
#undef MULTI_RELAY_MAX_RELAYS
|
||||||
|
#define MULTI_RELAY_MAX_RELAYS 8
|
||||||
|
#warning Maximum relays set to 8
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MULTI_RELAY_PINS
|
#ifndef MULTI_RELAY_PINS
|
||||||
#define MULTI_RELAY_PINS -1
|
#define MULTI_RELAY_PINS -1
|
||||||
|
#define MULTI_RELAY_ENABLED false
|
||||||
|
#else
|
||||||
|
#define MULTI_RELAY_ENABLED true
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
|
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
|
||||||
@ -15,21 +24,37 @@
|
|||||||
#define ON true
|
#define ON true
|
||||||
#define OFF false
|
#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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This usermod handles multiple relay outputs.
|
* This usermod handles multiple relay outputs.
|
||||||
* These outputs complement built-in relay output in a way that the activation can be delayed.
|
* These outputs complement built-in relay output in a way that the activation can be delayed.
|
||||||
* They can also activate/deactivate in reverse logic independently.
|
* They can also activate/deactivate in reverse logic independently.
|
||||||
|
*
|
||||||
|
* Written and maintained by @blazoncek
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
typedef struct relay_t {
|
typedef struct relay_t {
|
||||||
int8_t pin;
|
int8_t pin;
|
||||||
bool active;
|
struct { // reduces memory footprint
|
||||||
bool mode;
|
bool active : 1; // is the relay waiting to be switched
|
||||||
bool state;
|
bool invert : 1; // does On mean 1 or 0
|
||||||
bool external;
|
bool state : 1; // 1 relay is On, 0 relay is Off
|
||||||
uint16_t delay;
|
bool external : 1; // is the relay externally controlled
|
||||||
int8_t button;
|
int8_t button : 4; // which button triggers relay
|
||||||
|
};
|
||||||
|
uint16_t delay; // amount of ms to wait after it is activated
|
||||||
} Relay;
|
} Relay;
|
||||||
|
|
||||||
|
|
||||||
@ -39,20 +64,15 @@ class MultiRelay : public Usermod {
|
|||||||
// array of relays
|
// array of relays
|
||||||
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
||||||
|
|
||||||
// switch timer start time
|
uint32_t _switchTimerStart; // switch timer start time
|
||||||
uint32_t _switchTimerStart = 0;
|
bool _oldMode; // old brightness
|
||||||
// old brightness
|
bool enabled; // usermod enabled
|
||||||
bool _oldMode;
|
bool initDone; // status of initialisation
|
||||||
|
bool usePcf8574;
|
||||||
// usermod enabled
|
uint8_t addrPcf8574;
|
||||||
bool enabled = false; // needs to be configured (no default config)
|
bool HAautodiscovery;
|
||||||
// status of initialisation
|
uint16_t periodicBroadcastSec;
|
||||||
bool initDone = false;
|
unsigned long lastBroadcast;
|
||||||
|
|
||||||
bool HAautodiscovery = false;
|
|
||||||
|
|
||||||
uint16_t periodicBroadcastSec = 60;
|
|
||||||
unsigned long lastBroadcast = 0;
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
static const char _name[];
|
static const char _name[];
|
||||||
@ -64,8 +84,127 @@ class MultiRelay : public Usermod {
|
|||||||
static const char _button[];
|
static const char _button[];
|
||||||
static const char _broadcast[];
|
static const char _broadcast[];
|
||||||
static const char _HAautodiscovery[];
|
static const char _HAautodiscovery[];
|
||||||
|
static const char _pcf8574[];
|
||||||
|
static const char _pcfAddress[];
|
||||||
|
|
||||||
void publishMqtt(int relay) {
|
void handleOffTimer();
|
||||||
|
void InitHtmlAPIHandle();
|
||||||
|
int getValue(String data, char separator, int index);
|
||||||
|
uint8_t getActiveRelayCount();
|
||||||
|
|
||||||
|
byte IOexpanderWrite(byte address, byte _data);
|
||||||
|
byte IOexpanderRead(int address);
|
||||||
|
|
||||||
|
void publishMqtt(int relay);
|
||||||
|
#ifndef WLED_DISABLE_MQTT
|
||||||
|
void publishHomeAssistantAutodiscovery();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*/
|
||||||
|
MultiRelay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* desctructor
|
||||||
|
*/
|
||||||
|
//~MultiRelay() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable the usermod
|
||||||
|
*/
|
||||||
|
inline void enable(bool enable) { enabled = enable; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get usermod enabled/disabled state
|
||||||
|
*/
|
||||||
|
inline bool isEnabled() { return enabled; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
inline uint16_t getId() { return USERMOD_ID_MULTI_RELAY; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switch relay on/off
|
||||||
|
*/
|
||||||
|
void switchRelay(uint8_t relay, bool mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggle relay
|
||||||
|
*/
|
||||||
|
inline void toggleRelay(uint8_t relay) {
|
||||||
|
switchRelay(relay, !_relay[relay].state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
inline void connected() { InitHtmlAPIHandle(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
|
*/
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_MQTT
|
||||||
|
bool onMqttMessage(char* topic, char* payload);
|
||||||
|
void onMqttConnect(bool sessionPresent);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handleButton() can be used to override default button behaviour. Returning true
|
||||||
|
* will prevent button working in a default way.
|
||||||
|
* Replicating button.cpp
|
||||||
|
*/
|
||||||
|
bool handleButton(uint8_t b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
|
*/
|
||||||
|
void addToJsonInfo(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide the changeable values
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject &root);
|
||||||
|
|
||||||
|
void appendConfigData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* restore the changeable values
|
||||||
|
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||||
|
*
|
||||||
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
|
*/
|
||||||
|
bool readFromConfig(JsonObject &root);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// class implementetion
|
||||||
|
|
||||||
|
void MultiRelay::publishMqtt(int relay) {
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
if (WLED_MQTT_CONNECTED){
|
if (WLED_MQTT_CONNECTED){
|
||||||
@ -79,12 +218,12 @@ class MultiRelay : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* switch off the strip if the delay has elapsed
|
* switch off the strip if the delay has elapsed
|
||||||
*/
|
*/
|
||||||
void handleOffTimer() {
|
void MultiRelay::handleOffTimer() {
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
bool activeRelays = false;
|
bool activeRelays = false;
|
||||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
if (_relay[i].active && _switchTimerStart > 0 && now - _switchTimerStart > (_relay[i].delay*1000)) {
|
if (_relay[i].active && _switchTimerStart > 0 && now - _switchTimerStart > (_relay[i].delay*1000)) {
|
||||||
if (!_relay[i].external) toggleRelay(i);
|
if (!_relay[i].external) switchRelay(i, !offMode);
|
||||||
_relay[i].active = false;
|
_relay[i].active = false;
|
||||||
} else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) {
|
} else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) {
|
||||||
if (_relay[i].pin>=0) publishMqtt(i);
|
if (_relay[i].pin>=0) publishMqtt(i);
|
||||||
@ -101,7 +240,7 @@ class MultiRelay : public Usermod {
|
|||||||
* https://github.com/gsieben/WLED/blob/master/usermods/GeoGab-Relays/usermod_GeoGab.h
|
* https://github.com/gsieben/WLED/blob/master/usermods/GeoGab-Relays/usermod_GeoGab.h
|
||||||
*/
|
*/
|
||||||
#define GEOGABVERSION "0.1.3"
|
#define GEOGABVERSION "0.1.3"
|
||||||
void InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer
|
void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer
|
||||||
DEBUG_PRINTLN(F("Relays: Initialize HTML API"));
|
DEBUG_PRINTLN(F("Relays: Initialize HTML API"));
|
||||||
|
|
||||||
server.on("/relays", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
server.on("/relays", HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||||
@ -163,7 +302,7 @@ class MultiRelay : public Usermod {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int getValue(String data, char separator, int index) {
|
int MultiRelay::getValue(String data, char separator, int index) {
|
||||||
int found = 0;
|
int found = 0;
|
||||||
int strIndex[] = {0, -1};
|
int strIndex[] = {0, -1};
|
||||||
int maxIndex = data.length()-1;
|
int maxIndex = data.length()-1;
|
||||||
@ -178,60 +317,78 @@ class MultiRelay : public Usermod {
|
|||||||
return found>index ? data.substring(strIndex[0], strIndex[1]).toInt() : -1;
|
return found>index ? data.substring(strIndex[0], strIndex[1]).toInt() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
//Write a byte to the IO expander
|
||||||
/**
|
byte MultiRelay::IOexpanderWrite(byte address, byte _data ) {
|
||||||
* constructor
|
Wire.beginTransmission(address);
|
||||||
*/
|
Wire.write(_data);
|
||||||
MultiRelay() {
|
return Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read a byte from the IO expander
|
||||||
|
byte MultiRelay::IOexpanderRead(int address) {
|
||||||
|
byte _data = 0;
|
||||||
|
Wire.requestFrom(address, 1);
|
||||||
|
if (Wire.available()) {
|
||||||
|
_data = Wire.read();
|
||||||
|
}
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public methods
|
||||||
|
|
||||||
|
MultiRelay::MultiRelay()
|
||||||
|
: _switchTimerStart(0)
|
||||||
|
, enabled(MULTI_RELAY_ENABLED)
|
||||||
|
, initDone(false)
|
||||||
|
, usePcf8574(USE_PCF8574)
|
||||||
|
, addrPcf8574(PCF8574_ADDRESS)
|
||||||
|
, HAautodiscovery(false)
|
||||||
|
, periodicBroadcastSec(60)
|
||||||
|
, lastBroadcast(0)
|
||||||
|
{
|
||||||
const int8_t defPins[] = {MULTI_RELAY_PINS};
|
const int8_t defPins[] = {MULTI_RELAY_PINS};
|
||||||
for (size_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (size_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
_relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1;
|
_relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1;
|
||||||
_relay[i].delay = 0;
|
_relay[i].delay = 0;
|
||||||
_relay[i].mode = false;
|
_relay[i].invert = false;
|
||||||
_relay[i].active = false;
|
_relay[i].active = false;
|
||||||
_relay[i].state = false;
|
_relay[i].state = false;
|
||||||
_relay[i].external = false;
|
_relay[i].external = false;
|
||||||
_relay[i].button = -1;
|
_relay[i].button = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* desctructor
|
|
||||||
*/
|
|
||||||
~MultiRelay() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable/Disable the usermod
|
|
||||||
*/
|
|
||||||
inline void enable(bool enable) { enabled = enable; }
|
|
||||||
/**
|
|
||||||
* Get usermod enabled/disabled state
|
|
||||||
*/
|
|
||||||
inline bool isEnabled() { return enabled; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch relay on/off
|
* switch relay on/off
|
||||||
*/
|
*/
|
||||||
void switchRelay(uint8_t relay, bool mode) {
|
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) return;
|
||||||
_relay[relay].state = mode;
|
_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) {
|
||||||
pinMode(_relay[relay].pin, OUTPUT);
|
pinMode(_relay[relay].pin, OUTPUT);
|
||||||
digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
|
digitalWrite(_relay[relay].pin, _relay[relay].invert ? !_relay[relay].state : _relay[relay].state);
|
||||||
|
} else return;
|
||||||
publishMqtt(relay);
|
publishMqtt(relay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
uint8_t MultiRelay::getActiveRelayCount() {
|
||||||
* toggle relay
|
|
||||||
*/
|
|
||||||
inline void toggleRelay(uint8_t relay) {
|
|
||||||
switchRelay(relay, !_relay[relay].state);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t getActiveRelayCount() {
|
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) if (_relay[i].pin>=0) count++;
|
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) if (_relay[i].pin>=0) count++;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
@ -240,7 +397,7 @@ class MultiRelay : public Usermod {
|
|||||||
* topic only contains stripped topic (part after /wled/MAC)
|
* topic only contains stripped topic (part after /wled/MAC)
|
||||||
* topic should look like: /relay/X/command; where X is relay number, 0 based
|
* topic should look like: /relay/X/command; where X is relay number, 0 based
|
||||||
*/
|
*/
|
||||||
bool onMqttMessage(char* topic, char* payload) {
|
bool MultiRelay::onMqttMessage(char* topic, char* payload) {
|
||||||
if (strlen(topic) > 8 && strncmp_P(topic, PSTR("/relay/"), 7) == 0 && strncmp_P(topic+8, PSTR("/command"), 8) == 0) {
|
if (strlen(topic) > 8 && strncmp_P(topic, PSTR("/relay/"), 7) == 0 && strncmp_P(topic+8, PSTR("/command"), 8) == 0) {
|
||||||
uint8_t relay = strtoul(topic+7, NULL, 10);
|
uint8_t relay = strtoul(topic+7, NULL, 10);
|
||||||
if (relay<MULTI_RELAY_MAX_RELAYS) {
|
if (relay<MULTI_RELAY_MAX_RELAYS) {
|
||||||
@ -263,7 +420,7 @@ class MultiRelay : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* subscribe to MQTT topic for controlling relays
|
* subscribe to MQTT topic for controlling relays
|
||||||
*/
|
*/
|
||||||
void onMqttConnect(bool sessionPresent) {
|
void MultiRelay::onMqttConnect(bool sessionPresent) {
|
||||||
//(re)subscribe to required topics
|
//(re)subscribe to required topics
|
||||||
char subuf[64];
|
char subuf[64];
|
||||||
if (mqttDeviceTopic[0] != 0) {
|
if (mqttDeviceTopic[0] != 0) {
|
||||||
@ -278,7 +435,7 @@ class MultiRelay : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishHomeAssistantAutodiscovery() {
|
void MultiRelay::publishHomeAssistantAutodiscovery() {
|
||||||
for (int i = 0; i < MULTI_RELAY_MAX_RELAYS; i++) {
|
for (int i = 0; i < MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
char uid[24], json_str[1024], buf[128];
|
char uid[24], json_str[1024], buf[128];
|
||||||
size_t payload_size;
|
size_t payload_size;
|
||||||
@ -322,34 +479,39 @@ class MultiRelay : public Usermod {
|
|||||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||||
* You can use it to initialize variables, sensors or similar.
|
* You can use it to initialize variables, sensors or similar.
|
||||||
*/
|
*/
|
||||||
void setup() {
|
void MultiRelay::setup() {
|
||||||
// pins retrieved from cfg.json (readFromConfig()) prior to running 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;
|
||||||
|
|
||||||
|
uint8_t state = 0;
|
||||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
if (_relay[i].pin<0) continue;
|
if (usePcf8574 && _relay[i].pin >= 100) {
|
||||||
if (!pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
|
uint8_t pin = _relay[i].pin - 100;
|
||||||
_relay[i].pin = -1; // allocation failed
|
if (!_relay[i].external) _relay[i].state = !offMode;
|
||||||
} else {
|
state |= (uint8_t)(_relay[i].invert ? !_relay[i].state : _relay[i].state) << pin;
|
||||||
|
} else if (_relay[i].pin<100 && _relay[i].pin>=0) {
|
||||||
|
if (pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
|
||||||
if (!_relay[i].external) _relay[i].state = !offMode;
|
if (!_relay[i].external) _relay[i].state = !offMode;
|
||||||
switchRelay(i, _relay[i].state);
|
switchRelay(i, _relay[i].state);
|
||||||
_relay[i].active = false;
|
_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;
|
_oldMode = offMode;
|
||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* connected() is called every time the WiFi is (re)connected
|
|
||||||
* Use it to initialize network interfaces
|
|
||||||
*/
|
|
||||||
void connected() {
|
|
||||||
InitHtmlAPIHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
*/
|
*/
|
||||||
void loop() {
|
void MultiRelay::loop() {
|
||||||
yield();
|
yield();
|
||||||
if (!enabled || strip.isUpdating()) return;
|
if (!enabled || strip.isUpdating()) return;
|
||||||
|
|
||||||
@ -362,7 +524,7 @@ class MultiRelay : public Usermod {
|
|||||||
_oldMode = offMode;
|
_oldMode = offMode;
|
||||||
_switchTimerStart = millis();
|
_switchTimerStart = millis();
|
||||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
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) && !_relay[i].external) _relay[i].active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +536,7 @@ class MultiRelay : public Usermod {
|
|||||||
* will prevent button working in a default way.
|
* will prevent button working in a default way.
|
||||||
* Replicating button.cpp
|
* Replicating button.cpp
|
||||||
*/
|
*/
|
||||||
bool handleButton(uint8_t b) {
|
bool MultiRelay::handleButton(uint8_t b) {
|
||||||
yield();
|
yield();
|
||||||
if (!enabled
|
if (!enabled
|
||||||
|| buttonType[b] == BTN_TYPE_NONE
|
|| buttonType[b] == BTN_TYPE_NONE
|
||||||
@ -466,7 +628,7 @@ class MultiRelay : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
*/
|
*/
|
||||||
void addToJsonInfo(JsonObject &root) {
|
void MultiRelay::addToJsonInfo(JsonObject &root) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull())
|
if (user.isNull())
|
||||||
@ -503,7 +665,7 @@ class MultiRelay : public Usermod {
|
|||||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
void addToJsonState(JsonObject &root) {
|
void MultiRelay::addToJsonState(JsonObject &root) {
|
||||||
if (!initDone || !enabled) return; // prevent crash on boot applyPreset()
|
if (!initDone || !enabled) return; // prevent crash on boot applyPreset()
|
||||||
JsonObject multiRelay = root[FPSTR(_name)];
|
JsonObject multiRelay = root[FPSTR(_name)];
|
||||||
if (multiRelay.isNull()) {
|
if (multiRelay.isNull()) {
|
||||||
@ -527,7 +689,7 @@ class MultiRelay : public Usermod {
|
|||||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject &root) {
|
void MultiRelay::readFromJsonState(JsonObject &root) {
|
||||||
if (!initDone || !enabled) return; // prevent crash on boot applyPreset()
|
if (!initDone || !enabled) return; // prevent crash on boot applyPreset()
|
||||||
JsonObject usermod = root[FPSTR(_name)];
|
JsonObject usermod = root[FPSTR(_name)];
|
||||||
if (!usermod.isNull()) {
|
if (!usermod.isNull()) {
|
||||||
@ -557,31 +719,40 @@ class MultiRelay : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* provide the changeable values
|
* provide the changeable values
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject &root) {
|
void MultiRelay::addToConfig(JsonObject &root) {
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
|
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
|
top[FPSTR(_pcf8574)] = usePcf8574;
|
||||||
|
top[FPSTR(_pcfAddress)] = addrPcf8574;
|
||||||
top[FPSTR(_broadcast)] = periodicBroadcastSec;
|
top[FPSTR(_broadcast)] = periodicBroadcastSec;
|
||||||
|
top[FPSTR(_HAautodiscovery)] = HAautodiscovery;
|
||||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||||
JsonObject relay = top.createNestedObject(parName);
|
JsonObject relay = top.createNestedObject(parName);
|
||||||
relay["pin"] = _relay[i].pin;
|
relay["pin"] = _relay[i].pin;
|
||||||
relay[FPSTR(_activeHigh)] = _relay[i].mode;
|
relay[FPSTR(_activeHigh)] = _relay[i].invert;
|
||||||
relay[FPSTR(_delay_str)] = _relay[i].delay;
|
relay[FPSTR(_delay_str)] = _relay[i].delay;
|
||||||
relay[FPSTR(_external)] = _relay[i].external;
|
relay[FPSTR(_external)] = _relay[i].external;
|
||||||
relay[FPSTR(_button)] = _relay[i].button;
|
relay[FPSTR(_button)] = _relay[i].button;
|
||||||
}
|
}
|
||||||
top[FPSTR(_HAautodiscovery)] = HAautodiscovery;
|
|
||||||
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiRelay::appendConfigData() {
|
||||||
|
oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||||
|
oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
|
||||||
|
//oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
|
||||||
|
oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* restore the changeable values
|
* restore the changeable values
|
||||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||||
*
|
*
|
||||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
*/
|
*/
|
||||||
bool readFromConfig(JsonObject &root) {
|
bool MultiRelay::readFromConfig(JsonObject &root) {
|
||||||
int8_t oldPin[MULTI_RELAY_MAX_RELAYS];
|
int8_t oldPin[MULTI_RELAY_MAX_RELAYS];
|
||||||
|
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
@ -591,7 +762,13 @@ class MultiRelay : public Usermod {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//bool configComplete = !top.isNull();
|
||||||
|
//configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
|
||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
|
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;
|
||||||
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
|
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
|
||||||
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
|
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
|
||||||
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
|
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
|
||||||
@ -600,14 +777,14 @@ class MultiRelay : public Usermod {
|
|||||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||||
oldPin[i] = _relay[i].pin;
|
oldPin[i] = _relay[i].pin;
|
||||||
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
|
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
|
||||||
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
|
_relay[i].invert = top[parName][FPSTR(_activeHigh)] | _relay[i].invert;
|
||||||
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
||||||
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
||||||
_relay[i].button = top[parName][FPSTR(_button)] | _relay[i].button;
|
_relay[i].button = top[parName][FPSTR(_button)] | _relay[i].button;
|
||||||
// begin backwards compatibility (beta) remove when 0.13 is released
|
// begin backwards compatibility (beta) remove when 0.13 is released
|
||||||
parName += '-';
|
parName += '-';
|
||||||
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
||||||
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
_relay[i].invert = top[parName+FPSTR(_activeHigh)] | _relay[i].invert;
|
||||||
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
||||||
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
||||||
// end compatibility
|
// end compatibility
|
||||||
@ -621,38 +798,17 @@ class MultiRelay : public Usermod {
|
|||||||
} else {
|
} else {
|
||||||
// deallocate all pins 1st
|
// deallocate all pins 1st
|
||||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++)
|
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++)
|
||||||
if (oldPin[i]>=0) {
|
if (oldPin[i]>=0 && oldPin[i]<100) {
|
||||||
pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
|
pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
|
||||||
}
|
}
|
||||||
// allocate new pins
|
// allocate new pins
|
||||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
setup();
|
||||||
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."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_HAautodiscovery)].isNull();
|
return !top[FPSTR(_pcf8574)].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_MULTI_RELAY;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
const char MultiRelay::_name[] PROGMEM = "MultiRelay";
|
const char MultiRelay::_name[] PROGMEM = "MultiRelay";
|
||||||
const char MultiRelay::_enabled[] PROGMEM = "enabled";
|
const char MultiRelay::_enabled[] PROGMEM = "enabled";
|
||||||
@ -663,3 +819,5 @@ const char MultiRelay::_external[] PROGMEM = "external";
|
|||||||
const char MultiRelay::_button[] PROGMEM = "button";
|
const char MultiRelay::_button[] PROGMEM = "button";
|
||||||
const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
|
const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
|
||||||
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
|
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
|
||||||
|
const char MultiRelay::_pcf8574[] PROGMEM = "use-PCF8574";
|
||||||
|
const char MultiRelay::_pcfAddress[] PROGMEM = "PCF8574-address";
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
|
||||||
#include <Adafruit_Sensor.h>
|
#include <Adafruit_Sensor.h>
|
||||||
#include <Adafruit_BMP280.h>
|
#include <Adafruit_BMP280.h>
|
||||||
#include <Adafruit_CCS811.h>
|
#include <Adafruit_CCS811.h>
|
||||||
@ -16,14 +15,6 @@ Adafruit_BMP280 bmp;
|
|||||||
Adafruit_Si7021 si7021;
|
Adafruit_Si7021 si7021;
|
||||||
Adafruit_CCS811 ccs811;
|
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
|
class UserMod_SensorsToMQTT : public Usermod
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -231,7 +222,6 @@ public:
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.println("Starting!");
|
Serial.println("Starting!");
|
||||||
Wire.begin(SDA_PIN, SCL_PIN);
|
|
||||||
Serial.println("Initializing sensors.. ");
|
Serial.println("Initializing sensors.. ");
|
||||||
_initialize();
|
_initialize();
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ class ShtUsermod : public Usermod
|
|||||||
private:
|
private:
|
||||||
bool enabled = false; // Is usermod enabled or not
|
bool enabled = false; // Is usermod enabled or not
|
||||||
bool firstRunDone = false; // Remembers if the first config load run had been done
|
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 initDone = false; // Remembers if the mod has been completely initialised
|
||||||
bool haMqttDiscovery = false; // Is MQTT discovery enabled or not
|
bool haMqttDiscovery = false; // Is MQTT discovery enabled or not
|
||||||
bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics
|
bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics
|
||||||
@ -94,7 +93,7 @@ void ShtUsermod::initShtTempHumiditySensor()
|
|||||||
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
|
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
|
shtTempHumidSensor->begin(shtI2cAddress); // uses &Wire
|
||||||
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
|
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
|
||||||
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
|
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
|
||||||
cleanup();
|
cleanup();
|
||||||
@ -132,13 +131,6 @@ void ShtUsermod::cleanupShtTempHumiditySensor()
|
|||||||
void ShtUsermod::cleanup()
|
void ShtUsermod::cleanup()
|
||||||
{
|
{
|
||||||
cleanupShtTempHumiditySensor();
|
cleanupShtTempHumiditySensor();
|
||||||
|
|
||||||
if (pinAllocDone) {
|
|
||||||
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
|
||||||
pinManager.deallocateMultiplePins(pins, 2, PinOwner::HW_I2C);
|
|
||||||
pinAllocDone = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,14 +229,12 @@ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
|
|||||||
void ShtUsermod::setup()
|
void ShtUsermod::setup()
|
||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
// GPIOs can be set to -1 , so check they're gt zero
|
||||||
// GPIOs can be set to -1 and allocateMultiplePins() will return true, so check they're gt zero
|
if (i2c_sda < 0 || i2c_scl < 0) {
|
||||||
if (i2c_sda < 0 || i2c_scl < 0 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) {
|
DEBUG_PRINTF("[%s] I2C bus not initialised!\n", _name);
|
||||||
DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name);
|
|
||||||
cleanup();
|
cleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pinAllocDone = true;
|
|
||||||
|
|
||||||
initShtTempHumiditySensor();
|
initShtTempHumiditySensor();
|
||||||
|
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
#undef U8X8_NO_HW_I2C // borrowed from WLEDMM: we do want I2C hardware drivers - if possible
|
||||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||||
#include "4LD_wled_fonts.c"
|
#include "4LD_wled_fonts.c"
|
||||||
|
|
||||||
|
#ifndef FLD_ESP32_NO_THREADS
|
||||||
|
#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!!
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Insired by the usermod_v2_four_line_display
|
// Inspired by the usermod_v2_four_line_display
|
||||||
//
|
//
|
||||||
// v2 usermod for using 128x32 or 128x64 i2c
|
// v2 usermod for using 128x32 or 128x64 i2c
|
||||||
// OLED displays to provide a four line display
|
// OLED displays to provide a four line display
|
||||||
// for WLED.
|
// for WLED.
|
||||||
//
|
//
|
||||||
// Dependencies
|
// Dependencies
|
||||||
// * This usermod REQURES the ModeSortUsermod
|
|
||||||
// * This Usermod works best, by far, when coupled
|
// * This Usermod works best, by far, when coupled
|
||||||
// with RotaryEncoderUIUsermod.
|
// with RotaryEncoderUI ALT Usermod.
|
||||||
//
|
//
|
||||||
// Make sure to enable NTP and set your time zone in WLED Config | Time.
|
// Make sure to enable NTP and set your time zone in WLED Config | Time.
|
||||||
//
|
//
|
||||||
@ -23,22 +27,14 @@
|
|||||||
// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine)
|
// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine)
|
||||||
// REQUIREMENT: * Wire
|
// REQUIREMENT: * Wire
|
||||||
//
|
//
|
||||||
|
// If display does not work or looks corrupted check the
|
||||||
|
// constructor reference:
|
||||||
|
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||||
|
// or check the gallery:
|
||||||
|
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||||
|
|
||||||
//The SCL and SDA pins are defined here.
|
|
||||||
#ifndef FLD_PIN_SCL
|
|
||||||
#define FLD_PIN_SCL i2c_scl
|
|
||||||
#endif
|
|
||||||
#ifndef FLD_PIN_SDA
|
|
||||||
#define FLD_PIN_SDA i2c_sda
|
|
||||||
#endif
|
|
||||||
#ifndef FLD_PIN_CLOCKSPI
|
|
||||||
#define FLD_PIN_CLOCKSPI spi_sclk
|
|
||||||
#endif
|
|
||||||
#ifndef FLD_PIN_DATASPI
|
|
||||||
#define FLD_PIN_DATASPI spi_mosi
|
|
||||||
#endif
|
|
||||||
#ifndef FLD_PIN_CS
|
#ifndef FLD_PIN_CS
|
||||||
#define FLD_PIN_CS spi_cs
|
#define FLD_PIN_CS 15
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
@ -92,14 +88,17 @@ typedef enum {
|
|||||||
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
|
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
|
||||||
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
|
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
|
||||||
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
|
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
|
||||||
SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI
|
SSD1306_SPI64, // U8X8_SSD1306_128X64_NONAME_HW_SPI
|
||||||
|
SSD1309_SPI64 // U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI
|
||||||
} DisplayType;
|
} DisplayType;
|
||||||
|
|
||||||
|
|
||||||
class FourLineDisplayUsermod : public Usermod {
|
class FourLineDisplayUsermod : public Usermod {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
public:
|
public:
|
||||||
FourLineDisplayUsermod() { if (!instance) instance = this; }
|
FourLineDisplayUsermod() { if (!instance) instance = this; }
|
||||||
static FourLineDisplayUsermod* getInstance(void) { return instance; }
|
static FourLineDisplayUsermod* getInstance(void) { return instance; }
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -112,10 +111,10 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
||||||
|
|
||||||
#ifndef FLD_SPI_DEFAULT
|
#ifndef FLD_SPI_DEFAULT
|
||||||
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
|
int8_t ioPin[3] = {-1, -1, -1}; // I2C pins: SCL, SDA
|
||||||
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
|
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
|
||||||
#else
|
#else
|
||||||
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
|
int8_t ioPin[3] = {FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // custom SPI pins: CS, DC, RST
|
||||||
uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
|
uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -178,7 +177,194 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||||
|
|
||||||
// some displays need this to properly apply contrast
|
// some displays need this to properly apply contrast
|
||||||
void setVcomh(bool highContrast) {
|
void setVcomh(bool highContrast);
|
||||||
|
void startDisplay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrappers for screen drawing
|
||||||
|
*/
|
||||||
|
void setFlipMode(uint8_t mode);
|
||||||
|
void setContrast(uint8_t contrast);
|
||||||
|
void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false);
|
||||||
|
void draw2x2String(uint8_t col, uint8_t row, const char *string);
|
||||||
|
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false);
|
||||||
|
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font);
|
||||||
|
void draw2x2GlyphIcons();
|
||||||
|
uint8_t getCols();
|
||||||
|
void clear();
|
||||||
|
void setPowerSave(uint8_t save);
|
||||||
|
void center(String &line, uint8_t width);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the current date and time in large characters
|
||||||
|
* on the middle rows. Based 24 or 12 hour depending on
|
||||||
|
* the useAMPM configuration.
|
||||||
|
*/
|
||||||
|
void showTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable sleep (turn the display off) or clock mode.
|
||||||
|
*/
|
||||||
|
void sleepOrClock(bool enabled);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// gets called once at boot. Do all initialization that doesn't depend on
|
||||||
|
// network here
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||||
|
// interfaces here
|
||||||
|
void connected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Da loop.
|
||||||
|
*/
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
//function to update lastredraw
|
||||||
|
inline void updateRedrawTime() { lastRedraw = millis(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redraw the screen (but only if things have changed
|
||||||
|
* or if forceRedraw).
|
||||||
|
*/
|
||||||
|
void redraw(bool forceRedraw);
|
||||||
|
|
||||||
|
void updateBrightness();
|
||||||
|
void updateSpeed();
|
||||||
|
void updateIntensity();
|
||||||
|
void drawStatusIcons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* marks the position of the arrow showing
|
||||||
|
* the current setting being changed
|
||||||
|
* pass line and colum info
|
||||||
|
*/
|
||||||
|
void setMarkLine(byte newMarkLineNum, byte newMarkColNum);
|
||||||
|
|
||||||
|
//Draw the arrow for the current setting beiong changed
|
||||||
|
void drawArrow();
|
||||||
|
|
||||||
|
//Display the current effect or palette (desiredEntry)
|
||||||
|
// on the appropriate line (row).
|
||||||
|
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there screen is off or in clock is displayed,
|
||||||
|
* this will return true. This allows us to throw away
|
||||||
|
* the first input from the rotary encoder but
|
||||||
|
* to wake up the screen.
|
||||||
|
*/
|
||||||
|
bool wakeDisplay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to show one line and a glyph as overlay for a period of time.
|
||||||
|
* Clears the screen and prints.
|
||||||
|
* Used in Rotary Encoder usermod.
|
||||||
|
*/
|
||||||
|
void overlay(const char* line1, long showHowLong, byte glyphType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to show Akemi WLED logo overlay for a period of time.
|
||||||
|
* Clears the screen and prints.
|
||||||
|
*/
|
||||||
|
void overlayLogo(long showHowLong);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to show two lines as overlay for a period of time.
|
||||||
|
* Clears the screen and prints.
|
||||||
|
* Used in Auto Save usermod
|
||||||
|
*/
|
||||||
|
void overlay(const char* line1, const char* line2, long showHowLong);
|
||||||
|
|
||||||
|
void networkOverlay(const char* line1, long showHowLong);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handleButton() can be used to override default button behaviour. Returning true
|
||||||
|
* will prevent button working in a default way.
|
||||||
|
* Replicating button.cpp
|
||||||
|
*/
|
||||||
|
bool handleButton(uint8_t b);
|
||||||
|
|
||||||
|
void onUpdateBegin(bool init);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
|
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||||
|
* Below it is shown how this could be used for e.g. a light sensor
|
||||||
|
*/
|
||||||
|
//void addToJsonInfo(JsonObject& root);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 appendConfigData();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||||
|
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||||
|
* If you want to force saving the current state, use serializeConfig() in your loop().
|
||||||
|
*
|
||||||
|
* CAUTION: serializeConfig() will initiate a filesystem write operation.
|
||||||
|
* It might cause the LEDs to stutter and will cause flash wear if called too often.
|
||||||
|
* Use it sparingly and always in the loop, never in network callbacks!
|
||||||
|
*
|
||||||
|
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
|
||||||
|
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
||||||
|
*
|
||||||
|
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject& root);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||||
|
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||||
|
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||||
|
*/
|
||||||
|
bool readFromConfig(JsonObject& root);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||||
|
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||||
|
*/
|
||||||
|
uint16_t getId() {
|
||||||
|
return USERMOD_ID_FOUR_LINE_DISP;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
|
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
|
||||||
|
const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled";
|
||||||
|
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
|
||||||
|
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRate-ms";
|
||||||
|
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
|
||||||
|
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
|
||||||
|
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
||||||
|
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
||||||
|
const char FourLineDisplayUsermod::_showSeconds[] PROGMEM = "showSeconds";
|
||||||
|
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
||||||
|
const char FourLineDisplayUsermod::_contrastFix[] PROGMEM = "contrastFix";
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
FourLineDisplayUsermod *FourLineDisplayUsermod::instance = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// some displays need this to properly apply contrast
|
||||||
|
void FourLineDisplayUsermod::setVcomh(bool highContrast) {
|
||||||
|
if (type == NONE || !enabled) return;
|
||||||
u8x8_t *u8x8_struct = u8x8->getU8x8();
|
u8x8_t *u8x8_struct = u8x8->getU8x8();
|
||||||
u8x8_cad_StartTransfer(u8x8_struct);
|
u8x8_cad_StartTransfer(u8x8_struct);
|
||||||
u8x8_cad_SendCmd(u8x8_struct, 0x0db); //address of value
|
u8x8_cad_SendCmd(u8x8_struct, 0x0db); //address of value
|
||||||
@ -186,18 +372,32 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
u8x8_cad_EndTransfer(u8x8_struct);
|
u8x8_cad_EndTransfer(u8x8_struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FourLineDisplayUsermod::startDisplay() {
|
||||||
|
if (type == NONE || !enabled) return;
|
||||||
|
lineHeight = u8x8->getRows() > 4 ? 2 : 1;
|
||||||
|
DEBUG_PRINTLN(F("Starting display."));
|
||||||
|
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
|
u8x8->begin();
|
||||||
|
setFlipMode(flip);
|
||||||
|
setVcomh(contrastFix);
|
||||||
|
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||||
|
setPowerSave(0);
|
||||||
|
//drawString(0, 0, "Loading...");
|
||||||
|
overlayLogo(3500);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrappers for screen drawing
|
* Wrappers for screen drawing
|
||||||
*/
|
*/
|
||||||
void setFlipMode(uint8_t mode) {
|
void FourLineDisplayUsermod::setFlipMode(uint8_t mode) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
u8x8->setFlipMode(mode);
|
u8x8->setFlipMode(mode);
|
||||||
}
|
}
|
||||||
void setContrast(uint8_t contrast) {
|
void FourLineDisplayUsermod::setContrast(uint8_t contrast) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
u8x8->setContrast(contrast);
|
u8x8->setContrast(contrast);
|
||||||
}
|
}
|
||||||
void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) {
|
void FourLineDisplayUsermod::drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
||||||
@ -205,14 +405,14 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
else u8x8->drawString(col, row, string);
|
else u8x8->drawString(col, row, string);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void draw2x2String(uint8_t col, uint8_t row, const char *string) {
|
void FourLineDisplayUsermod::draw2x2String(uint8_t col, uint8_t row, const char *string) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
||||||
u8x8->draw2x2String(col, row, string);
|
u8x8->draw2x2String(col, row, string);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) {
|
void FourLineDisplayUsermod::drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(font);
|
u8x8->setFont(font);
|
||||||
@ -220,35 +420,35 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
else u8x8->drawGlyph(col, row, glyph);
|
else u8x8->drawGlyph(col, row, glyph);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font) {
|
void FourLineDisplayUsermod::draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(font);
|
u8x8->setFont(font);
|
||||||
u8x8->draw2x2Glyph(col, row, glyph);
|
u8x8->draw2x2Glyph(col, row, glyph);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
uint8_t getCols() {
|
uint8_t FourLineDisplayUsermod::getCols() {
|
||||||
if (type==NONE || !enabled) return 0;
|
if (type==NONE || !enabled) return 0;
|
||||||
return u8x8->getCols();
|
return u8x8->getCols();
|
||||||
}
|
}
|
||||||
void clear() {
|
void FourLineDisplayUsermod::clear() {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->clear();
|
u8x8->clear();
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void setPowerSave(uint8_t save) {
|
void FourLineDisplayUsermod::setPowerSave(uint8_t save) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
u8x8->setPowerSave(save);
|
u8x8->setPowerSave(save);
|
||||||
}
|
}
|
||||||
|
|
||||||
void center(String &line, uint8_t width) {
|
void FourLineDisplayUsermod::center(String &line, uint8_t width) {
|
||||||
int len = line.length();
|
int len = line.length();
|
||||||
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
|
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
|
||||||
for (byte i=line.length(); i<width; i++) line += ' ';
|
for (byte i=line.length(); i<width; i++) line += ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw2x2GlyphIcons() {
|
void FourLineDisplayUsermod::draw2x2GlyphIcons() {
|
||||||
drawing = true;
|
drawing = true;
|
||||||
if (lineHeight == 2) {
|
if (lineHeight == 2) {
|
||||||
drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon
|
drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon
|
||||||
@ -271,7 +471,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* on the middle rows. Based 24 or 12 hour depending on
|
* on the middle rows. Based 24 or 12 hour depending on
|
||||||
* the useAMPM configuration.
|
* the useAMPM configuration.
|
||||||
*/
|
*/
|
||||||
void showTime() {
|
void FourLineDisplayUsermod::showTime() {
|
||||||
if (type == NONE || !enabled || !displayTurnedOff) return;
|
if (type == NONE || !enabled || !displayTurnedOff) return;
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
@ -317,7 +517,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* Enable sleep (turn the display off) or clock mode.
|
* Enable sleep (turn the display off) or clock mode.
|
||||||
*/
|
*/
|
||||||
void sleepOrClock(bool enabled) {
|
void FourLineDisplayUsermod::sleepOrClock(bool enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
displayTurnedOff = true;
|
displayTurnedOff = true;
|
||||||
if (clockMode && ntpEnabled) {
|
if (clockMode && ntpEnabled) {
|
||||||
@ -331,143 +531,56 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// gets called once at boot. Do all initialization that doesn't depend on
|
// gets called once at boot. Do all initialization that doesn't depend on
|
||||||
// network here
|
// network here
|
||||||
void setup() {
|
void FourLineDisplayUsermod::setup() {
|
||||||
if (type == NONE || !enabled) return;
|
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64);
|
||||||
|
|
||||||
bool isHW, isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
|
// check if pins are -1 and disable usermod as PinManager::allocateMultiplePins() will accept -1 as a valid pin
|
||||||
PinOwner po = PinOwner::UM_FourLineDisplay;
|
|
||||||
if (isSPI) {
|
if (isSPI) {
|
||||||
uint8_t hw_sclk = spi_sclk<0 ? HW_PIN_CLOCKSPI : spi_sclk;
|
if (spi_sclk<0 || spi_mosi<0 || ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) {
|
||||||
uint8_t hw_mosi = spi_mosi<0 ? HW_PIN_DATASPI : spi_mosi;
|
|
||||||
if (ioPin[0] < 0 || ioPin[1] < 0) {
|
|
||||||
ioPin[0] = hw_sclk;
|
|
||||||
ioPin[1] = hw_mosi;
|
|
||||||
}
|
|
||||||
isHW = (ioPin[0]==hw_sclk && ioPin[1]==hw_mosi);
|
|
||||||
PinManagerPinType cspins[3] = { { ioPin[2], true }, { ioPin[3], true }, { ioPin[4], true } };
|
|
||||||
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type=NONE; return; }
|
|
||||||
if (isHW) po = PinOwner::HW_SPI; // allow multiple allocations of HW I2C bus pins
|
|
||||||
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } };
|
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) {
|
|
||||||
pinManager.deallocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay);
|
|
||||||
type = NONE;
|
type = NONE;
|
||||||
return;
|
} else {
|
||||||
|
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
|
||||||
|
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type = NONE; }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint8_t hw_scl = i2c_scl<0 ? HW_PIN_SCL : i2c_scl;
|
if (i2c_scl<0 || i2c_sda<0) { type=NONE; }
|
||||||
uint8_t hw_sda = i2c_sda<0 ? HW_PIN_SDA : i2c_sda;
|
|
||||||
if (ioPin[0] < 0 || ioPin[1] < 0) {
|
|
||||||
ioPin[0] = hw_scl;
|
|
||||||
ioPin[1] = hw_sda;
|
|
||||||
}
|
|
||||||
isHW = (ioPin[0]==hw_scl && ioPin[1]==hw_sda);
|
|
||||||
if (isHW) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
|
||||||
PinManagerPinType pins[2] = { {ioPin[0], true }, { ioPin[1], true } };
|
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) { type=NONE; return; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINTLN(F("Allocating display."));
|
DEBUG_PRINTLN(F("Allocating display."));
|
||||||
/*
|
|
||||||
// At some point it may be good to not new/delete U8X8 object but use this instead
|
|
||||||
// (does not currently work)
|
|
||||||
//-------------------------------------------------------------------------------
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SSD1306:
|
// U8X8 uses Wire (or Wire1 with 2ND constructor) and will use existing Wire properties (calls Wire.begin() though)
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
case SSD1306: u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(); break;
|
||||||
break;
|
case SH1106: u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(); break;
|
||||||
case SH1106:
|
case SSD1306_64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(); break;
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_sh1106_128x64_winstar, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
case SSD1305: u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(); break;
|
||||||
break;
|
case SSD1305_64: u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(); break;
|
||||||
case SSD1306_64:
|
// U8X8 uses global SPI variable that is attached to VSPI bus on ESP32
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
case SSD1306_SPI: u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
|
||||||
break;
|
case SSD1306_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
|
||||||
case SSD1305:
|
case SSD1309_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x32_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
// catchall
|
||||||
break;
|
default: u8x8 = (U8X8 *) new U8X8_NULL(); enabled = false; break; // catchall to create U8x8 instance
|
||||||
case SSD1305_64:
|
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI:
|
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI64:
|
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
type = NONE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isSPI) {
|
|
||||||
if (!isHW) u8x8_SetPin_4Wire_SW_SPI(u8x8.getU8x8(), ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
|
|
||||||
else u8x8_SetPin_4Wire_HW_SPI(u8x8.getU8x8(), ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
|
|
||||||
} else {
|
|
||||||
if (!isHW) u8x8_SetPin_SW_I2C(u8x8.getU8x8(), ioPin[0], ioPin[1], U8X8_PIN_NONE); // SCL, SDA, reset
|
|
||||||
else u8x8_SetPin_HW_I2C(u8x8.getU8x8(), U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
switch (type) {
|
|
||||||
case SSD1306:
|
|
||||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
|
||||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
|
||||||
break;
|
|
||||||
case SH1106:
|
|
||||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
|
||||||
else u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
|
||||||
break;
|
|
||||||
case SSD1306_64:
|
|
||||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
|
||||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
|
||||||
break;
|
|
||||||
case SSD1305:
|
|
||||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
|
||||||
else u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
|
||||||
break;
|
|
||||||
case SSD1305_64:
|
|
||||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
|
||||||
else u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI:
|
|
||||||
// u8x8 uses global SPI variable that is attached to VSPI bus on ESP32
|
|
||||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
|
|
||||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI64:
|
|
||||||
// u8x8 uses global SPI variable that is attached to VSPI bus on ESP32
|
|
||||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
|
|
||||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
u8x8 = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nullptr == u8x8) {
|
if (nullptr == u8x8) {
|
||||||
DEBUG_PRINTLN(F("Display init failed."));
|
DEBUG_PRINTLN(F("Display init failed."));
|
||||||
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, isSPI ? 5 : 2, po);
|
if (isSPI) {
|
||||||
|
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, 3, PinOwner::UM_FourLineDisplay);
|
||||||
|
}
|
||||||
type = NONE;
|
type = NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineHeight = u8x8->getRows() > 4 ? 2 : 1;
|
startDisplay();
|
||||||
DEBUG_PRINTLN(F("Starting display."));
|
|
||||||
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
|
||||||
u8x8->begin();
|
|
||||||
setFlipMode(flip);
|
|
||||||
setVcomh(contrastFix);
|
|
||||||
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
|
||||||
setPowerSave(0);
|
|
||||||
//drawString(0, 0, "Loading...");
|
|
||||||
overlayLogo(3500);
|
|
||||||
onUpdateBegin(false); // create Display task
|
onUpdateBegin(false); // create Display task
|
||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||||
// interfaces here
|
// interfaces here
|
||||||
void connected() {
|
void FourLineDisplayUsermod::connected() {
|
||||||
knownSsid = WiFi.SSID(); //apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() :
|
knownSsid = WiFi.SSID(); //apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() :
|
||||||
knownIp = Network.localIP(); //apActive ? IPAddress(4, 3, 2, 1) : Network.localIP();
|
knownIp = Network.localIP(); //apActive ? IPAddress(4, 3, 2, 1) : Network.localIP();
|
||||||
networkOverlay(PSTR("NETWORK INFO"),7000);
|
networkOverlay(PSTR("NETWORK INFO"),7000);
|
||||||
@ -476,8 +589,8 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* Da loop.
|
* Da loop.
|
||||||
*/
|
*/
|
||||||
void loop() {
|
void FourLineDisplayUsermod::loop() {
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
#if !(defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS))
|
||||||
if (!enabled || strip.isUpdating()) return;
|
if (!enabled || strip.isUpdating()) return;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
if (now < nextUpdate) return;
|
if (now < nextUpdate) return;
|
||||||
@ -486,16 +599,11 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//function to update lastredraw
|
|
||||||
void updateRedrawTime() {
|
|
||||||
lastRedraw = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redraw the screen (but only if things have changed
|
* Redraw the screen (but only if things have changed
|
||||||
* or if forceRedraw).
|
* or if forceRedraw).
|
||||||
*/
|
*/
|
||||||
void redraw(bool forceRedraw) {
|
void FourLineDisplayUsermod::redraw(bool forceRedraw) {
|
||||||
bool needRedraw = false;
|
bool needRedraw = false;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
@ -607,7 +715,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); //Effect Mode info
|
showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); //Effect Mode info
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBrightness() {
|
void FourLineDisplayUsermod::updateBrightness() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
knownBrightness = bri;
|
knownBrightness = bri;
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -619,7 +732,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSpeed() {
|
void FourLineDisplayUsermod::updateSpeed() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
knownEffectSpeed = effectSpeed;
|
knownEffectSpeed = effectSpeed;
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -631,7 +749,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateIntensity() {
|
void FourLineDisplayUsermod::updateIntensity() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
knownEffectIntensity = effectIntensity;
|
knownEffectIntensity = effectIntensity;
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -643,7 +766,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawStatusIcons() {
|
void FourLineDisplayUsermod::drawStatusIcons() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
uint8_t col = 15;
|
uint8_t col = 15;
|
||||||
uint8_t row = 0;
|
uint8_t row = 0;
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -660,13 +788,18 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* the current setting being changed
|
* the current setting being changed
|
||||||
* pass line and colum info
|
* pass line and colum info
|
||||||
*/
|
*/
|
||||||
void setMarkLine(byte newMarkLineNum, byte newMarkColNum) {
|
void FourLineDisplayUsermod::setMarkLine(byte newMarkLineNum, byte newMarkColNum) {
|
||||||
markLineNum = newMarkLineNum;
|
markLineNum = newMarkLineNum;
|
||||||
markColNum = newMarkColNum;
|
markColNum = newMarkColNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Draw the arrow for the current setting beiong changed
|
//Draw the arrow for the current setting beiong changed
|
||||||
void drawArrow() {
|
void FourLineDisplayUsermod::drawArrow() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 21, u8x8_4LineDisplay_WLED_icons_1x1);
|
if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 21, u8x8_4LineDisplay_WLED_icons_1x1);
|
||||||
lockRedraw = false;
|
lockRedraw = false;
|
||||||
@ -674,7 +807,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
|
|
||||||
//Display the current effect or palette (desiredEntry)
|
//Display the current effect or palette (desiredEntry)
|
||||||
// on the appropriate line (row).
|
// on the appropriate line (row).
|
||||||
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
|
void FourLineDisplayUsermod::showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
char lineBuffer[MAX_JSON_CHARS];
|
char lineBuffer[MAX_JSON_CHARS];
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -740,12 +878,14 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* the first input from the rotary encoder but
|
* the first input from the rotary encoder but
|
||||||
* to wake up the screen.
|
* to wake up the screen.
|
||||||
*/
|
*/
|
||||||
bool wakeDisplay() {
|
bool FourLineDisplayUsermod::wakeDisplay() {
|
||||||
if (type == NONE || !enabled) return false;
|
if (type == NONE || !enabled) return false;
|
||||||
if (displayTurnedOff) {
|
if (displayTurnedOff) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return false;
|
if (drawing || lockRedraw) return false;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
clear();
|
clear();
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
@ -761,10 +901,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Clears the screen and prints.
|
* Clears the screen and prints.
|
||||||
* Used in Rotary Encoder usermod.
|
* Used in Rotary Encoder usermod.
|
||||||
*/
|
*/
|
||||||
void overlay(const char* line1, long showHowLong, byte glyphType) {
|
void FourLineDisplayUsermod::overlay(const char* line1, long showHowLong, byte glyphType) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
if (!wakeDisplay()) clear();
|
if (!wakeDisplay()) clear();
|
||||||
@ -786,10 +928,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Allows you to show Akemi WLED logo overlay for a period of time.
|
* Allows you to show Akemi WLED logo overlay for a period of time.
|
||||||
* Clears the screen and prints.
|
* Clears the screen and prints.
|
||||||
*/
|
*/
|
||||||
void overlayLogo(long showHowLong) {
|
void FourLineDisplayUsermod::overlayLogo(long showHowLong) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
if (!wakeDisplay()) clear();
|
if (!wakeDisplay()) clear();
|
||||||
@ -848,10 +992,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Clears the screen and prints.
|
* Clears the screen and prints.
|
||||||
* Used in Auto Save usermod
|
* Used in Auto Save usermod
|
||||||
*/
|
*/
|
||||||
void overlay(const char* line1, const char* line2, long showHowLong) {
|
void FourLineDisplayUsermod::overlay(const char* line1, const char* line2, long showHowLong) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
if (!wakeDisplay()) clear();
|
if (!wakeDisplay()) clear();
|
||||||
@ -870,10 +1016,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
lockRedraw = false;
|
lockRedraw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void networkOverlay(const char* line1, long showHowLong) {
|
void FourLineDisplayUsermod::networkOverlay(const char* line1, long showHowLong) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
|
|
||||||
String line;
|
String line;
|
||||||
@ -915,7 +1063,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* will prevent button working in a default way.
|
* will prevent button working in a default way.
|
||||||
* Replicating button.cpp
|
* Replicating button.cpp
|
||||||
*/
|
*/
|
||||||
bool handleButton(uint8_t b) {
|
bool FourLineDisplayUsermod::handleButton(uint8_t b) {
|
||||||
yield();
|
yield();
|
||||||
if (!enabled
|
if (!enabled
|
||||||
|| b // butto 0 only
|
|| b // butto 0 only
|
||||||
@ -989,8 +1137,8 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
#else
|
#else
|
||||||
#define ARDUINO_RUNNING_CORE 1
|
#define ARDUINO_RUNNING_CORE 1
|
||||||
#endif
|
#endif
|
||||||
void onUpdateBegin(bool init) {
|
void FourLineDisplayUsermod::onUpdateBegin(bool init) {
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
if (init && Display_Task) {
|
if (init && Display_Task) {
|
||||||
vTaskSuspend(Display_Task); // update is about to begin, disable task to prevent crash
|
vTaskSuspend(Display_Task); // update is about to begin, disable task to prevent crash
|
||||||
} else {
|
} else {
|
||||||
@ -1026,7 +1174,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||||
* Below it is shown how this could be used for e.g. a light sensor
|
* Below it is shown how this could be used for e.g. a light sensor
|
||||||
*/
|
*/
|
||||||
//void addToJsonInfo(JsonObject& root) {
|
//void FourLineDisplayUsermod::addToJsonInfo(JsonObject& root) {
|
||||||
//JsonObject user = root["u"];
|
//JsonObject user = root["u"];
|
||||||
//if (user.isNull()) user = root.createNestedObject("u");
|
//if (user.isNull()) user = root.createNestedObject("u");
|
||||||
//JsonArray data = user.createNestedArray(F("4LineDisplay"));
|
//JsonArray data = user.createNestedArray(F("4LineDisplay"));
|
||||||
@ -1037,18 +1185,18 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
//void addToJsonState(JsonObject& root) {
|
//void FourLineDisplayUsermod::addToJsonState(JsonObject& root) {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
//void readFromJsonState(JsonObject& root) {
|
//void FourLineDisplayUsermod::readFromJsonState(JsonObject& root) {
|
||||||
// if (!initDone) return; // prevent crash on boot applyPreset()
|
// if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void appendConfigData() {
|
void FourLineDisplayUsermod::appendConfigData() {
|
||||||
oappend(SET_F("dd=addDropdown('4LineDisplay','type');"));
|
oappend(SET_F("dd=addDropdown('4LineDisplay','type');"));
|
||||||
oappend(SET_F("addOption(dd,'None',0);"));
|
oappend(SET_F("addOption(dd,'None',0);"));
|
||||||
oappend(SET_F("addOption(dd,'SSD1306',1);"));
|
oappend(SET_F("addOption(dd,'SSD1306',1);"));
|
||||||
@ -1058,11 +1206,11 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
|
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
|
||||||
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
|
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
|
||||||
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
|
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'<i>-1 use global</i>','I2C/SPI CLK');"));
|
oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'<i>-1 use global</i>','I2C/SPI DTA');"));
|
oappend(SET_F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI CS');"));
|
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',3,'','SPI DC');"));
|
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',4,'','SPI RST');"));
|
oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1079,27 +1227,13 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
*
|
*
|
||||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject& root) {
|
void FourLineDisplayUsermod::addToConfig(JsonObject& root) {
|
||||||
// determine if we are using global HW pins (data & clock)
|
|
||||||
int8_t hw_dta, hw_clk;
|
|
||||||
if ((type == SSD1306_SPI || type == SSD1306_SPI64)) {
|
|
||||||
hw_clk = spi_sclk<0 ? HW_PIN_CLOCKSPI : spi_sclk;
|
|
||||||
hw_dta = spi_mosi<0 ? HW_PIN_DATASPI : spi_mosi;
|
|
||||||
} else {
|
|
||||||
hw_clk = i2c_scl<0 ? HW_PIN_SCL : i2c_scl;
|
|
||||||
hw_dta = i2c_sda<0 ? HW_PIN_SDA : i2c_sda;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
|
|
||||||
JsonArray io_pin = top.createNestedArray("pin");
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
if (i==0 && ioPin[i]==hw_clk) io_pin.add(-1); // do not store global HW pin
|
|
||||||
else if (i==1 && ioPin[i]==hw_dta) io_pin.add(-1); // do not store global HW pin
|
|
||||||
else io_pin.add(ioPin[i]);
|
|
||||||
}
|
|
||||||
top["type"] = type;
|
top["type"] = type;
|
||||||
|
JsonArray io_pin = top.createNestedArray("pin");
|
||||||
|
for (int i=0; i<3; i++) io_pin.add(ioPin[i]);
|
||||||
top[FPSTR(_flip)] = (bool) flip;
|
top[FPSTR(_flip)] = (bool) flip;
|
||||||
top[FPSTR(_contrast)] = contrast;
|
top[FPSTR(_contrast)] = contrast;
|
||||||
top[FPSTR(_contrastFix)] = (bool) contrastFix;
|
top[FPSTR(_contrastFix)] = (bool) contrastFix;
|
||||||
@ -1122,10 +1256,10 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||||
*/
|
*/
|
||||||
bool readFromConfig(JsonObject& root) {
|
bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
|
||||||
bool needsRedraw = false;
|
bool needsRedraw = false;
|
||||||
DisplayType newType = type;
|
DisplayType newType = type;
|
||||||
int8_t oldPin[5]; for (byte i=0; i<5; i++) oldPin[i] = ioPin[i];
|
int8_t oldPin[3]; for (byte i=0; i<3; i++) oldPin[i] = ioPin[i];
|
||||||
|
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
@ -1136,7 +1270,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
|
|
||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
newType = top["type"] | newType;
|
newType = top["type"] | newType;
|
||||||
for (byte i=0; i<5; i++) ioPin[i] = top["pin"][i] | ioPin[i];
|
for (byte i=0; i<3; i++) ioPin[i] = top["pin"][i] | ioPin[i];
|
||||||
flip = top[FPSTR(_flip)] | flip;
|
flip = top[FPSTR(_flip)] | flip;
|
||||||
contrast = top[FPSTR(_contrast)] | contrast;
|
contrast = top[FPSTR(_contrast)] | contrast;
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
#ifndef ARDUINO_ARCH_ESP32
|
||||||
@ -1162,26 +1296,72 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
// changing parameters from settings page
|
// changing parameters from settings page
|
||||||
bool pinsChanged = false;
|
bool pinsChanged = false;
|
||||||
for (byte i=0; i<5; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; }
|
for (byte i=0; i<3; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; }
|
||||||
if (pinsChanged || type!=newType) {
|
if (pinsChanged || type!=newType) {
|
||||||
if (type != NONE) delete u8x8;
|
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64);
|
||||||
PinOwner po = PinOwner::UM_FourLineDisplay;
|
bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64 || newType == SSD1309_SPI64);
|
||||||
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
|
|
||||||
if (isSPI) {
|
if (isSPI) {
|
||||||
pinManager.deallocateMultiplePins((const uint8_t *)(&oldPin[2]), 3, po);
|
if (pinsChanged || !newSPI) pinManager.deallocateMultiplePins((const uint8_t*)oldPin, 3, PinOwner::UM_FourLineDisplay);
|
||||||
uint8_t hw_sclk = spi_sclk<0 ? HW_PIN_CLOCKSPI : spi_sclk;
|
if (!newSPI) {
|
||||||
uint8_t hw_mosi = spi_mosi<0 ? HW_PIN_DATASPI : spi_mosi;
|
// was SPI but is no longer SPI
|
||||||
bool isHW = (oldPin[0]==hw_sclk && oldPin[1]==hw_mosi);
|
if (i2c_scl<0 || i2c_sda<0) { newType=NONE; }
|
||||||
if (isHW) po = PinOwner::HW_SPI;
|
|
||||||
} else {
|
} else {
|
||||||
uint8_t hw_scl = i2c_scl<0 ? HW_PIN_SCL : i2c_scl;
|
// still SPI but pins changed
|
||||||
uint8_t hw_sda = i2c_sda<0 ? HW_PIN_SDA : i2c_sda;
|
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
|
||||||
bool isHW = (oldPin[0]==hw_scl && oldPin[1]==hw_sda);
|
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
|
||||||
if (isHW) po = PinOwner::HW_I2C;
|
else if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
|
||||||
|
}
|
||||||
|
} else if (newSPI) {
|
||||||
|
// was I2C but is now SPI
|
||||||
|
if (spi_sclk<0 || spi_mosi<0) {
|
||||||
|
newType=NONE;
|
||||||
|
} else {
|
||||||
|
PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
|
||||||
|
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
|
||||||
|
else if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just I2C type changed
|
||||||
}
|
}
|
||||||
pinManager.deallocateMultiplePins((const uint8_t *)oldPin, 2, po);
|
|
||||||
type = newType;
|
type = newType;
|
||||||
setup();
|
switch (type) {
|
||||||
|
case SSD1306:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SH1106:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_sh1106_128x64_winstar, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1306_64:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1305:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1305_128x32_adafruit, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1305_64:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1306_SPI:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
|
||||||
|
break;
|
||||||
|
case SSD1306_SPI64:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
|
||||||
|
break;
|
||||||
|
case SSD1309_SPI64:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1309_128x64_noname0, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
|
||||||
|
default:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_null_cb, u8x8_cad_empty, u8x8_byte_empty, u8x8_dummy_cb);
|
||||||
|
enabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
startDisplay();
|
||||||
needsRedraw |= true;
|
needsRedraw |= true;
|
||||||
} else {
|
} else {
|
||||||
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
@ -1196,27 +1376,3 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_contrastFix)].isNull();
|
return !top[FPSTR(_contrastFix)].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_FOUR_LINE_DISP;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
|
||||||
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
|
|
||||||
const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled";
|
|
||||||
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
|
|
||||||
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRate-ms";
|
|
||||||
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
|
|
||||||
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
|
|
||||||
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
|
||||||
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
|
||||||
const char FourLineDisplayUsermod::_showSeconds[] PROGMEM = "showSeconds";
|
|
||||||
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
|
||||||
const char FourLineDisplayUsermod::_contrastFix[] PROGMEM = "contrastFix";
|
|
||||||
|
|
||||||
FourLineDisplayUsermod *FourLineDisplayUsermod::instance = nullptr;
|
|
||||||
|
@ -45,7 +45,27 @@
|
|||||||
#define ENCODER_SW_PIN 19
|
#define ENCODER_SW_PIN 19
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The last UI state, remove color and saturation option if diplay not active(too many options)
|
#ifndef ENCODER_MAX_DELAY_MS // max delay between polling encoder pins
|
||||||
|
#define ENCODER_MAX_DELAY_MS 8 // 8 milliseconds => max 120 change impulses in 1 second, for full turn of a 30/30 encoder (4 changes per segment, 30 segments for one turn)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#ifndef PCF8574_INT_PIN
|
||||||
|
#define PCF8574_INT_PIN -1 // GPIO connected to INT pin on PCF8574
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The last UI state, remove color and saturation option if display not active (too many options)
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
#define LAST_UI_STATE 11
|
#define LAST_UI_STATE 11
|
||||||
#else
|
#else
|
||||||
@ -113,62 +133,83 @@ static int re_qstringCmp(const void *ap, const void *bp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static volatile uint8_t pcfPortData = 0; // port expander port state
|
||||||
|
static volatile uint8_t addrPcf8574 = PCF8574_ADDRESS; // has to be accessible in ISR
|
||||||
|
|
||||||
|
// Interrupt routine to read I2C rotary state
|
||||||
|
// if we are to use PCF8574 port expander we will need to rely on interrupts as polling I2C every 2ms
|
||||||
|
// is a waste of resources and causes 4LD to fail.
|
||||||
|
// in such case rely on ISR to read pin values and store them into static variable
|
||||||
|
static void IRAM_ATTR i2cReadingISR() {
|
||||||
|
Wire.requestFrom(addrPcf8574, 1U);
|
||||||
|
if (Wire.available()) {
|
||||||
|
pcfPortData = Wire.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class RotaryEncoderUIUsermod : public Usermod {
|
class RotaryEncoderUIUsermod : public Usermod {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int8_t fadeAmount = 5; // Amount to change every step (brightness)
|
|
||||||
|
const int8_t fadeAmount; // Amount to change every step (brightness)
|
||||||
unsigned long loopTime;
|
unsigned long loopTime;
|
||||||
|
|
||||||
unsigned long buttonPressedTime = 0;
|
unsigned long buttonPressedTime;
|
||||||
unsigned long buttonWaitTime = 0;
|
unsigned long buttonWaitTime;
|
||||||
bool buttonPressedBefore = false;
|
bool buttonPressedBefore;
|
||||||
bool buttonLongPressed = false;
|
bool buttonLongPressed;
|
||||||
|
|
||||||
int8_t pinA = ENCODER_DT_PIN; // DT from encoder
|
int8_t pinA; // DT from encoder
|
||||||
int8_t pinB = ENCODER_CLK_PIN; // CLK from encoder
|
int8_t pinB; // CLK from encoder
|
||||||
int8_t pinC = ENCODER_SW_PIN; // SW from encoder
|
int8_t pinC; // SW from encoder
|
||||||
|
|
||||||
unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed, ...
|
unsigned char select_state; // 0: brightness, 1: effect, 2: effect speed, ...
|
||||||
|
|
||||||
uint16_t currentHue1 = 16; // default boot color
|
uint16_t currentHue1; // default boot color
|
||||||
byte currentSat1 = 255;
|
byte currentSat1;
|
||||||
|
uint8_t currentCCT;
|
||||||
|
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
FourLineDisplayUsermod *display;
|
FourLineDisplayUsermod *display;
|
||||||
#else
|
#else
|
||||||
void* display = nullptr;
|
void* display;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Pointers the start of the mode names within JSON_mode_names
|
// Pointers the start of the mode names within JSON_mode_names
|
||||||
const char **modes_qstrings = nullptr;
|
const char **modes_qstrings;
|
||||||
|
|
||||||
// Array of mode indexes in alphabetical order.
|
// Array of mode indexes in alphabetical order.
|
||||||
byte *modes_alpha_indexes = nullptr;
|
byte *modes_alpha_indexes;
|
||||||
|
|
||||||
// Pointers the start of the palette names within JSON_palette_names
|
// Pointers the start of the palette names within JSON_palette_names
|
||||||
const char **palettes_qstrings = nullptr;
|
const char **palettes_qstrings;
|
||||||
|
|
||||||
// Array of palette indexes in alphabetical order.
|
// Array of palette indexes in alphabetical order.
|
||||||
byte *palettes_alpha_indexes = nullptr;
|
byte *palettes_alpha_indexes;
|
||||||
|
|
||||||
unsigned char Enc_A;
|
struct { // reduce memory footprint
|
||||||
unsigned char Enc_B;
|
bool Enc_A : 1;
|
||||||
unsigned char Enc_A_prev = 0;
|
bool Enc_B : 1;
|
||||||
|
bool Enc_A_prev : 1;
|
||||||
|
};
|
||||||
|
|
||||||
bool currentEffectAndPaletteInitialized = false;
|
bool currentEffectAndPaletteInitialized;
|
||||||
uint8_t effectCurrentIndex = 0;
|
uint8_t effectCurrentIndex;
|
||||||
uint8_t effectPaletteIndex = 0;
|
uint8_t effectPaletteIndex;
|
||||||
uint8_t knownMode = 0;
|
uint8_t knownMode;
|
||||||
uint8_t knownPalette = 0;
|
uint8_t knownPalette;
|
||||||
|
|
||||||
uint8_t currentCCT = 128;
|
byte presetHigh;
|
||||||
|
byte presetLow;
|
||||||
|
|
||||||
byte presetHigh = 0;
|
bool applyToAll;
|
||||||
byte presetLow = 0;
|
|
||||||
|
|
||||||
bool applyToAll = true;
|
bool initDone;
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
bool initDone = false;
|
bool usePcf8574;
|
||||||
bool enabled = true;
|
int8_t pinIRQ;
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
static const char _name[];
|
static const char _name[];
|
||||||
@ -179,12 +220,179 @@ private:
|
|||||||
static const char _presetHigh[];
|
static const char _presetHigh[];
|
||||||
static const char _presetLow[];
|
static const char _presetLow[];
|
||||||
static const char _applyToAll[];
|
static const char _applyToAll[];
|
||||||
|
static const char _pcf8574[];
|
||||||
|
static const char _pcfAddress[];
|
||||||
|
static const char _pcfINTpin[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* readPin() - read rotary encoder pin value
|
||||||
|
*/
|
||||||
|
byte readPin(uint8_t pin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the modes and palettes to the index arrays
|
* Sort the modes and palettes to the index arrays
|
||||||
* modes_alpha_indexes and palettes_alpha_indexes.
|
* modes_alpha_indexes and palettes_alpha_indexes.
|
||||||
*/
|
*/
|
||||||
void sortModesAndPalettes() {
|
void sortModesAndPalettes();
|
||||||
|
byte *re_initIndexArray(int numModes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array of mode or palette names from the JSON string.
|
||||||
|
* They don't end in '\0', they end in '"'.
|
||||||
|
*/
|
||||||
|
const char **re_findModeStrings(const char json[], int numModes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort either the modes or the palettes using quicksort.
|
||||||
|
*/
|
||||||
|
void re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RotaryEncoderUIUsermod()
|
||||||
|
: fadeAmount(5)
|
||||||
|
, buttonPressedTime(0)
|
||||||
|
, buttonWaitTime(0)
|
||||||
|
, buttonPressedBefore(false)
|
||||||
|
, buttonLongPressed(false)
|
||||||
|
, pinA(ENCODER_DT_PIN)
|
||||||
|
, pinB(ENCODER_CLK_PIN)
|
||||||
|
, pinC(ENCODER_SW_PIN)
|
||||||
|
, select_state(0)
|
||||||
|
, currentHue1(16)
|
||||||
|
, currentSat1(255)
|
||||||
|
, currentCCT(128)
|
||||||
|
, display(nullptr)
|
||||||
|
, modes_qstrings(nullptr)
|
||||||
|
, modes_alpha_indexes(nullptr)
|
||||||
|
, palettes_qstrings(nullptr)
|
||||||
|
, palettes_alpha_indexes(nullptr)
|
||||||
|
, currentEffectAndPaletteInitialized(false)
|
||||||
|
, effectCurrentIndex(0)
|
||||||
|
, effectPaletteIndex(0)
|
||||||
|
, knownMode(0)
|
||||||
|
, knownPalette(0)
|
||||||
|
, presetHigh(0)
|
||||||
|
, presetLow(0)
|
||||||
|
, applyToAll(true)
|
||||||
|
, initDone(false)
|
||||||
|
, enabled(true)
|
||||||
|
, usePcf8574(USE_PCF8574)
|
||||||
|
, pinIRQ(PCF8574_INT_PIN)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_ROTARY_ENC_UI; }
|
||||||
|
/**
|
||||||
|
* Enable/Disable the usermod
|
||||||
|
*/
|
||||||
|
inline void enable(bool enable) { if (!(pinA<0 || pinB<0 || pinC<0)) enabled = enable; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get usermod enabled/disabled state
|
||||||
|
*/
|
||||||
|
inline bool isEnabled() { return enabled; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
//void connected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
|
*/
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_MQTT
|
||||||
|
//bool onMqttMessage(char* topic, char* payload);
|
||||||
|
//void onMqttConnect(bool sessionPresent);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handleButton() can be used to override default button behaviour. Returning true
|
||||||
|
* will prevent button working in a default way.
|
||||||
|
* Replicating button.cpp
|
||||||
|
*/
|
||||||
|
//bool handleButton(uint8_t b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
|
*/
|
||||||
|
//void addToJsonInfo(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide the changeable values
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject &root);
|
||||||
|
|
||||||
|
void appendConfigData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* restore the changeable values
|
||||||
|
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||||
|
*
|
||||||
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
|
*/
|
||||||
|
bool readFromConfig(JsonObject &root);
|
||||||
|
|
||||||
|
// custom methods
|
||||||
|
void displayNetworkInfo();
|
||||||
|
void findCurrentEffectAndPalette();
|
||||||
|
bool changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph);
|
||||||
|
void lampUdated();
|
||||||
|
void changeBrightness(bool increase);
|
||||||
|
void changeEffect(bool increase);
|
||||||
|
void changeEffectSpeed(bool increase);
|
||||||
|
void changeEffectIntensity(bool increase);
|
||||||
|
void changeCustom(uint8_t par, bool increase);
|
||||||
|
void changePalette(bool increase);
|
||||||
|
void changeHue(bool increase);
|
||||||
|
void changeSat(bool increase);
|
||||||
|
void changePreset(bool increase);
|
||||||
|
void changeCCT(bool increase);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* readPin() - read rotary encoder pin value
|
||||||
|
*/
|
||||||
|
byte RotaryEncoderUIUsermod::readPin(uint8_t pin) {
|
||||||
|
if (usePcf8574) {
|
||||||
|
if (pin >= 100) pin -= 100; // PCF I/O ports
|
||||||
|
return (pcfPortData>>pin) & 1;
|
||||||
|
} else {
|
||||||
|
return digitalRead(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the modes and palettes to the index arrays
|
||||||
|
* modes_alpha_indexes and palettes_alpha_indexes.
|
||||||
|
*/
|
||||||
|
void RotaryEncoderUIUsermod::sortModesAndPalettes() {
|
||||||
|
DEBUG_PRINTLN(F("Sorting modes and palettes."));
|
||||||
//modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
|
//modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
|
||||||
modes_qstrings = strip.getModeDataSrc();
|
modes_qstrings = strip.getModeDataSrc();
|
||||||
modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
|
modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
|
||||||
@ -200,7 +408,7 @@ private:
|
|||||||
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount);
|
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte *re_initIndexArray(int numModes) {
|
byte *RotaryEncoderUIUsermod::re_initIndexArray(int numModes) {
|
||||||
byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
|
byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
|
||||||
for (byte i = 0; i < numModes; i++) {
|
for (byte i = 0; i < numModes; i++) {
|
||||||
indexes[i] = i;
|
indexes[i] = i;
|
||||||
@ -212,7 +420,7 @@ private:
|
|||||||
* Return an array of mode or palette names from the JSON string.
|
* Return an array of mode or palette names from the JSON string.
|
||||||
* They don't end in '\0', they end in '"'.
|
* They don't end in '\0', they end in '"'.
|
||||||
*/
|
*/
|
||||||
const char **re_findModeStrings(const char json[], int numModes) {
|
const char **RotaryEncoderUIUsermod::re_findModeStrings(const char json[], int numModes) {
|
||||||
const char **modeStrings = (const char **)malloc(sizeof(const char *) * numModes);
|
const char **modeStrings = (const char **)malloc(sizeof(const char *) * numModes);
|
||||||
uint8_t modeIndex = 0;
|
uint8_t modeIndex = 0;
|
||||||
bool insideQuotes = false;
|
bool insideQuotes = false;
|
||||||
@ -250,7 +458,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Sort either the modes or the palettes using quicksort.
|
* Sort either the modes or the palettes using quicksort.
|
||||||
*/
|
*/
|
||||||
void re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip) {
|
void RotaryEncoderUIUsermod::re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip) {
|
||||||
if (!modeNames) return;
|
if (!modeNames) return;
|
||||||
listBeingSorted = modeNames;
|
listBeingSorted = modeNames;
|
||||||
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
|
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
|
||||||
@ -258,21 +466,37 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
// public methods
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||||
* You can use it to initialize variables, sensors or similar.
|
* You can use it to initialize variables, sensors or similar.
|
||||||
*/
|
*/
|
||||||
void setup()
|
void RotaryEncoderUIUsermod::setup()
|
||||||
{
|
{
|
||||||
DEBUG_PRINTLN(F("Usermod Rotary Encoder init."));
|
DEBUG_PRINTLN(F("Usermod Rotary Encoder init."));
|
||||||
|
|
||||||
|
if (usePcf8574) {
|
||||||
|
if (i2c_sda < 0 || i2c_scl < 0 || pinA < 0 || pinB < 0 || pinC < 0) {
|
||||||
|
DEBUG_PRINTLN(F("I2C and/or PCF8574 pins unused, disabling."));
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (pinIRQ >= 0 && pinManager.allocatePin(pinIRQ, false, PinOwner::UM_RotaryEncoderUI)) {
|
||||||
|
pinMode(pinIRQ, INPUT_PULLUP);
|
||||||
|
attachInterrupt(pinIRQ, i2cReadingISR, FALLING); // RISING, FALLING, CHANGE, ONLOW, ONHIGH
|
||||||
|
DEBUG_PRINTLN(F("Interrupt attached."));
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTLN(F("Unable to allocate interrupt pin, disabling."));
|
||||||
|
pinIRQ = -1;
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } };
|
PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } };
|
||||||
if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) {
|
if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) {
|
||||||
// BUG: configuring this usermod with conflicting pins
|
|
||||||
// will cause it to de-allocate pins it does not own
|
|
||||||
// (at second config)
|
|
||||||
// This is the exact type of bug solved by pinManager
|
|
||||||
// tracking the owner tags....
|
|
||||||
pinA = pinB = pinC = -1;
|
pinA = pinB = pinC = -1;
|
||||||
enabled = false;
|
enabled = false;
|
||||||
return;
|
return;
|
||||||
@ -284,6 +508,7 @@ public:
|
|||||||
pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO);
|
pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO);
|
||||||
pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO);
|
pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO);
|
||||||
pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO);
|
pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO);
|
||||||
|
}
|
||||||
|
|
||||||
loopTime = millis();
|
loopTime = millis();
|
||||||
|
|
||||||
@ -301,20 +526,11 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
initDone = true;
|
initDone = true;
|
||||||
Enc_A = digitalRead(pinA); // Read encoder pins
|
Enc_A = readPin(pinA); // Read encoder pins
|
||||||
Enc_B = digitalRead(pinB);
|
Enc_B = readPin(pinB);
|
||||||
Enc_A_prev = Enc_A;
|
Enc_A_prev = Enc_A;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* connected() is called every time the WiFi is (re)connected
|
|
||||||
* Use it to initialize network interfaces
|
|
||||||
*/
|
|
||||||
void connected()
|
|
||||||
{
|
|
||||||
//Serial.println("Connected to WiFi!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
*
|
*
|
||||||
@ -325,10 +541,11 @@ public:
|
|||||||
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
||||||
* Instead, use a timer check as shown here.
|
* Instead, use a timer check as shown here.
|
||||||
*/
|
*/
|
||||||
void loop()
|
void RotaryEncoderUIUsermod::loop()
|
||||||
{
|
{
|
||||||
if (!enabled || strip.isUpdating()) return;
|
if (!enabled) return;
|
||||||
unsigned long currentTime = millis(); // get the current elapsed time
|
unsigned long currentTime = millis(); // get the current elapsed time
|
||||||
|
if (strip.isUpdating() && ((currentTime - loopTime) < ENCODER_MAX_DELAY_MS)) return; // be nice, but not too nice
|
||||||
|
|
||||||
// Initialize effectCurrentIndex and effectPaletteIndex to
|
// Initialize effectCurrentIndex and effectPaletteIndex to
|
||||||
// current state. We do it here as (at least) effectCurrent
|
// current state. We do it here as (at least) effectCurrent
|
||||||
@ -339,14 +556,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (modes_alpha_indexes[effectCurrentIndex] != effectCurrent || palettes_alpha_indexes[effectPaletteIndex] != effectPalette) {
|
if (modes_alpha_indexes[effectCurrentIndex] != effectCurrent || palettes_alpha_indexes[effectPaletteIndex] != effectPalette) {
|
||||||
|
DEBUG_PRINTLN(F("Current mode or palette changed."));
|
||||||
currentEffectAndPaletteInitialized = false;
|
currentEffectAndPaletteInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
|
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
|
||||||
{
|
{
|
||||||
loopTime = currentTime; // Updates loopTime
|
bool buttonPressed = !readPin(pinC); //0=pressed, 1=released
|
||||||
|
|
||||||
bool buttonPressed = !digitalRead(pinC); //0=pressed, 1=released
|
|
||||||
if (buttonPressed) {
|
if (buttonPressed) {
|
||||||
if (!buttonPressedBefore) buttonPressedTime = currentTime;
|
if (!buttonPressedBefore) buttonPressedTime = currentTime;
|
||||||
buttonPressedBefore = true;
|
buttonPressedBefore = true;
|
||||||
@ -413,8 +629,8 @@ public:
|
|||||||
if (changedState) select_state = newState;
|
if (changedState) select_state = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
Enc_A = digitalRead(pinA); // Read encoder pins
|
Enc_A = readPin(pinA); // Read encoder pins
|
||||||
Enc_B = digitalRead(pinB);
|
Enc_B = readPin(pinB);
|
||||||
if ((Enc_A) && (!Enc_A_prev))
|
if ((Enc_A) && (!Enc_A_prev))
|
||||||
{ // A has gone from high to low
|
{ // A has gone from high to low
|
||||||
if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse
|
if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse
|
||||||
@ -453,16 +669,18 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Enc_A_prev = Enc_A; // Store value of A for next time
|
Enc_A_prev = Enc_A; // Store value of A for next time
|
||||||
|
loopTime = currentTime; // Updates loopTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayNetworkInfo() {
|
void RotaryEncoderUIUsermod::displayNetworkInfo() {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
display->networkOverlay(PSTR("NETWORK INFO"), 10000);
|
display->networkOverlay(PSTR("NETWORK INFO"), 10000);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void findCurrentEffectAndPalette() {
|
void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() {
|
||||||
|
DEBUG_PRINTLN(F("Finding current mode and palette."));
|
||||||
currentEffectAndPaletteInitialized = true;
|
currentEffectAndPaletteInitialized = true;
|
||||||
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
|
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
|
||||||
if (modes_alpha_indexes[i] == effectCurrent) {
|
if (modes_alpha_indexes[i] == effectCurrent) {
|
||||||
@ -470,6 +688,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DEBUG_PRINTLN(F("Found current mode."));
|
||||||
|
|
||||||
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) {
|
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) {
|
||||||
if (palettes_alpha_indexes[i] == effectPalette) {
|
if (palettes_alpha_indexes[i] == effectPalette) {
|
||||||
@ -477,9 +696,10 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DEBUG_PRINTLN(F("Found palette."));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) {
|
bool RotaryEncoderUIUsermod::changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display != nullptr) {
|
if (display != nullptr) {
|
||||||
if (display->wakeDisplay()) {
|
if (display->wakeDisplay()) {
|
||||||
@ -494,7 +714,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lampUdated() {
|
void RotaryEncoderUIUsermod::lampUdated() {
|
||||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||||
//setValuesFromFirstSelectedSeg(); //to make transition work on main segment (should no longer be required)
|
//setValuesFromFirstSelectedSeg(); //to make transition work on main segment (should no longer be required)
|
||||||
@ -502,7 +722,7 @@ public:
|
|||||||
updateInterfaces(CALL_MODE_BUTTON);
|
updateInterfaces(CALL_MODE_BUTTON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeBrightness(bool increase) {
|
void RotaryEncoderUIUsermod::changeBrightness(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -519,7 +739,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeEffect(bool increase) {
|
void RotaryEncoderUIUsermod::changeEffect(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -548,7 +768,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeEffectSpeed(bool increase) {
|
void RotaryEncoderUIUsermod::changeEffectSpeed(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -576,7 +796,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeEffectIntensity(bool increase) {
|
void RotaryEncoderUIUsermod::changeEffectIntensity(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -604,7 +824,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeCustom(uint8_t par, bool increase) {
|
void RotaryEncoderUIUsermod::changeCustom(uint8_t par, bool increase) {
|
||||||
uint8_t val = 0;
|
uint8_t val = 0;
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
@ -649,7 +869,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changePalette(bool increase) {
|
void RotaryEncoderUIUsermod::changePalette(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -678,7 +898,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeHue(bool increase){
|
void RotaryEncoderUIUsermod::changeHue(bool increase){
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -708,7 +928,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeSat(bool increase){
|
void RotaryEncoderUIUsermod::changeSat(bool increase){
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -737,7 +957,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void changePreset(bool increase) {
|
void RotaryEncoderUIUsermod::changePreset(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -769,7 +989,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeCCT(bool increase){
|
void RotaryEncoderUIUsermod::changeCCT(bool increase){
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -803,7 +1023,7 @@ public:
|
|||||||
* Below it is shown how this could be used for e.g. a light sensor
|
* Below it is shown how this could be used for e.g. a light sensor
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void addToJsonInfo(JsonObject& root)
|
void RotaryEncoderUIUsermod::addToJsonInfo(JsonObject& root)
|
||||||
{
|
{
|
||||||
int reading = 20;
|
int reading = 20;
|
||||||
//this code adds "u":{"Light":[20," lux"]} to the info object
|
//this code adds "u":{"Light":[20," lux"]} to the info object
|
||||||
@ -820,7 +1040,7 @@ public:
|
|||||||
* Values in the state object may be modified by connected clients
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void addToJsonState(JsonObject &root)
|
void RotaryEncoderUIUsermod::addToJsonState(JsonObject &root)
|
||||||
{
|
{
|
||||||
//root["user0"] = userVar0;
|
//root["user0"] = userVar0;
|
||||||
}
|
}
|
||||||
@ -831,7 +1051,7 @@ public:
|
|||||||
* Values in the state object may be modified by connected clients
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void readFromJsonState(JsonObject &root)
|
void RotaryEncoderUIUsermod::readFromJsonState(JsonObject &root)
|
||||||
{
|
{
|
||||||
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||||
@ -841,7 +1061,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
|
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject &root) {
|
void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) {
|
||||||
// we add JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
// we add JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
|
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
@ -851,15 +1071,23 @@ public:
|
|||||||
top[FPSTR(_presetLow)] = presetLow;
|
top[FPSTR(_presetLow)] = presetLow;
|
||||||
top[FPSTR(_presetHigh)] = presetHigh;
|
top[FPSTR(_presetHigh)] = presetHigh;
|
||||||
top[FPSTR(_applyToAll)] = applyToAll;
|
top[FPSTR(_applyToAll)] = applyToAll;
|
||||||
|
top[FPSTR(_pcf8574)] = usePcf8574;
|
||||||
|
top[FPSTR(_pcfAddress)] = addrPcf8574;
|
||||||
|
top[FPSTR(_pcfINTpin)] = pinIRQ;
|
||||||
DEBUG_PRINTLN(F("Rotary Encoder config saved."));
|
DEBUG_PRINTLN(F("Rotary Encoder config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RotaryEncoderUIUsermod::appendConfigData() {
|
||||||
|
oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||||
|
oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||||
*
|
*
|
||||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
*/
|
*/
|
||||||
bool readFromConfig(JsonObject &root) {
|
bool RotaryEncoderUIUsermod::readFromConfig(JsonObject &root) {
|
||||||
// we look for JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
// we look for JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
@ -870,6 +1098,8 @@ public:
|
|||||||
int8_t newDTpin = top[FPSTR(_DT_pin)] | pinA;
|
int8_t newDTpin = top[FPSTR(_DT_pin)] | pinA;
|
||||||
int8_t newCLKpin = top[FPSTR(_CLK_pin)] | pinB;
|
int8_t newCLKpin = top[FPSTR(_CLK_pin)] | pinB;
|
||||||
int8_t newSWpin = top[FPSTR(_SW_pin)] | pinC;
|
int8_t newSWpin = top[FPSTR(_SW_pin)] | pinC;
|
||||||
|
int8_t newIRQpin = top[FPSTR(_pcfINTpin)] | pinIRQ;
|
||||||
|
bool oldPcf8574 = usePcf8574;
|
||||||
|
|
||||||
presetHigh = top[FPSTR(_presetHigh)] | presetHigh;
|
presetHigh = top[FPSTR(_presetHigh)] | presetHigh;
|
||||||
presetLow = top[FPSTR(_presetLow)] | presetLow;
|
presetLow = top[FPSTR(_presetLow)] | presetLow;
|
||||||
@ -879,6 +1109,9 @@ public:
|
|||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
applyToAll = top[FPSTR(_applyToAll)] | applyToAll;
|
applyToAll = top[FPSTR(_applyToAll)] | applyToAll;
|
||||||
|
|
||||||
|
usePcf8574 = top[FPSTR(_pcf8574)] | usePcf8574;
|
||||||
|
addrPcf8574 = top[FPSTR(_pcfAddress)] | addrPcf8574;
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// first run: reading from cfg.json
|
// first run: reading from cfg.json
|
||||||
@ -889,10 +1122,20 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
// changing parameters from settings page
|
// changing parameters from settings page
|
||||||
if (pinA!=newDTpin || pinB!=newCLKpin || pinC!=newSWpin) {
|
if (pinA!=newDTpin || pinB!=newCLKpin || pinC!=newSWpin || pinIRQ!=newIRQpin) {
|
||||||
|
if (oldPcf8574) {
|
||||||
|
if (pinIRQ >= 0) {
|
||||||
|
detachInterrupt(pinIRQ);
|
||||||
|
pinManager.deallocatePin(pinIRQ, PinOwner::UM_RotaryEncoderUI);
|
||||||
|
DEBUG_PRINTLN(F("Deallocated old IRQ pin."));
|
||||||
|
}
|
||||||
|
pinIRQ = newIRQpin<100 ? newIRQpin : -1; // ignore PCF8574 pins
|
||||||
|
} else {
|
||||||
pinManager.deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI);
|
pinManager.deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI);
|
||||||
pinManager.deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI);
|
pinManager.deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI);
|
||||||
pinManager.deallocatePin(pinC, PinOwner::UM_RotaryEncoderUI);
|
pinManager.deallocatePin(pinC, PinOwner::UM_RotaryEncoderUI);
|
||||||
|
DEBUG_PRINTLN(F("Deallocated old pins."));
|
||||||
|
}
|
||||||
pinA = newDTpin;
|
pinA = newDTpin;
|
||||||
pinB = newCLKpin;
|
pinB = newCLKpin;
|
||||||
pinC = newSWpin;
|
pinC = newSWpin;
|
||||||
@ -904,18 +1147,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_applyToAll)].isNull();
|
return !top[FPSTR(_pcfINTpin)].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_ROTARY_ENC_UI;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
const char RotaryEncoderUIUsermod::_name[] PROGMEM = "Rotary-Encoder";
|
const char RotaryEncoderUIUsermod::_name[] PROGMEM = "Rotary-Encoder";
|
||||||
@ -926,3 +1160,6 @@ const char RotaryEncoderUIUsermod::_SW_pin[] PROGMEM = "SW-pin";
|
|||||||
const char RotaryEncoderUIUsermod::_presetHigh[] PROGMEM = "preset-high";
|
const char RotaryEncoderUIUsermod::_presetHigh[] PROGMEM = "preset-high";
|
||||||
const char RotaryEncoderUIUsermod::_presetLow[] PROGMEM = "preset-low";
|
const char RotaryEncoderUIUsermod::_presetLow[] PROGMEM = "preset-low";
|
||||||
const char RotaryEncoderUIUsermod::_applyToAll[] PROGMEM = "apply-2-all-seg";
|
const char RotaryEncoderUIUsermod::_applyToAll[] PROGMEM = "apply-2-all-seg";
|
||||||
|
const char RotaryEncoderUIUsermod::_pcf8574[] PROGMEM = "use-PCF8574";
|
||||||
|
const char RotaryEncoderUIUsermod::_pcfAddress[] PROGMEM = "PCF8574-address";
|
||||||
|
const char RotaryEncoderUIUsermod::_pcfINTpin[] PROGMEM = "PCF8574-INT-pin";
|
||||||
|
25
wled00.sln
25
wled00.sln
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio 15
|
|
||||||
VisualStudioVersion = 15.0.28010.2046
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wled00", "wled00\wled00.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|x86 = Debug|x86
|
|
||||||
Release|x86 = Release|x86
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {9A679C2B-61D3-400B-B96F-06E604E9CED2}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
@ -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));
|
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), fade));
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!";
|
static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!;01";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -433,7 +433,7 @@ uint16_t mode_rainbow(void) {
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!";
|
static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!;01";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2805,7 +2805,7 @@ uint16_t mode_bouncing_balls(void) {
|
|||||||
// number of balls based on intensity setting to max of 7 (cycles colors)
|
// number of balls based on intensity setting to max of 7 (cycles colors)
|
||||||
// non-chosen color is a random color
|
// non-chosen color is a random color
|
||||||
uint16_t numBalls = (SEGMENT.intensity * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball
|
uint16_t numBalls = (SEGMENT.intensity * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball
|
||||||
const float gravity = -9.81; // standard value of gravity
|
const float gravity = -9.81f; // standard value of gravity
|
||||||
const bool hasCol2 = SEGCOLOR(2);
|
const bool hasCol2 = SEGCOLOR(2);
|
||||||
const unsigned long time = millis();
|
const unsigned long time = millis();
|
||||||
|
|
||||||
@ -4175,11 +4175,9 @@ static const char _data_FX_MODE_DANCING_SHADOWS[] PROGMEM = "Dancing Shadows@!,#
|
|||||||
By Stefan Seegel
|
By Stefan Seegel
|
||||||
*/
|
*/
|
||||||
uint16_t mode_washing_machine(void) {
|
uint16_t mode_washing_machine(void) {
|
||||||
float speed = tristate_square8(strip.now >> 7, 90, 15);
|
int speed = tristate_square8(strip.now >> 7, 90, 15);
|
||||||
float quot = 32.0f - ((float)SEGMENT.speed / 16.0f);
|
|
||||||
speed /= quot;
|
|
||||||
|
|
||||||
SEGENV.step += (speed * 128.0f);
|
SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed);
|
||||||
|
|
||||||
for (int i = 0; i < SEGLEN; i++) {
|
for (int i = 0; i < SEGLEN; i++) {
|
||||||
uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
|
uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
|
||||||
@ -4593,7 +4591,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma
|
|||||||
}
|
}
|
||||||
|
|
||||||
SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails
|
SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails
|
||||||
float t = (float)(millis())/128; // timebase
|
unsigned long t = millis()/128; // timebase
|
||||||
// outer stars
|
// outer stars
|
||||||
for (size_t i = 0; i < 8; i++) {
|
for (size_t i = 0; i < 8; i++) {
|
||||||
x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i);
|
x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i);
|
||||||
@ -5097,21 +5095,22 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
|
|||||||
const uint16_t rows = SEGMENT.virtualHeight();
|
const uint16_t rows = SEGMENT.virtualHeight();
|
||||||
|
|
||||||
SEGMENT.fadeToBlackBy(SEGMENT.intensity);
|
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 < 4*(cols+rows); i ++) {
|
||||||
for (int i=0; i < 256; i ++) {
|
for (int i=0; i < 256; i ++) {
|
||||||
//float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f;
|
//float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f;
|
||||||
//float ylocn = float(cos8(now/4+i*2)) / 255.0f;
|
//float ylocn = float(cos8(now/4+i*2)) / 255.0f;
|
||||||
uint8_t xlocn = sin8(millis()/4+i*(SEGMENT.speed>>5));
|
uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/32);
|
||||||
uint8_t ylocn = cos8(millis()/4+i*2);
|
uint_fast8_t ylocn = cos8(phase/2 + i*2);
|
||||||
xlocn = map(xlocn,0,255,0,cols-1);
|
xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding
|
||||||
ylocn = map(ylocn,0,255,0,rows-1);
|
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(xlocn, ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
|
SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_2DLissajous()
|
} // mode_2DLissajous()
|
||||||
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate;!;!;2";
|
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,,,Speed;!;!;2;;c3=15";
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -5275,7 +5274,7 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito
|
|||||||
|
|
||||||
SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2);
|
SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2);
|
||||||
|
|
||||||
float t = millis() / (33 - SEGMENT.speed/8);
|
uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float
|
||||||
for (int i = 0; i < cols; i++) {
|
for (int i = 0; i < cols; i++) {
|
||||||
uint16_t thisVal = inoise8(i * 30, t, t);
|
uint16_t thisVal = inoise8(i * 30, t, t);
|
||||||
uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1);
|
uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1);
|
||||||
@ -5878,11 +5877,17 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
case 4: letterWidth = 7; letterHeight = 9; break;
|
case 4: letterWidth = 7; letterHeight = 9; break;
|
||||||
case 5: letterWidth = 5; letterHeight = 12; 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;
|
const int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-letterHeight)/2;
|
||||||
char text[33] = {'\0'};
|
char text[WLED_MAX_SEGNAME_LEN+1] = {'\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 (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];
|
char sec[5];
|
||||||
byte AmPmHour = hour(localTime);
|
byte AmPmHour = hour(localTime);
|
||||||
boolean isitAM = true;
|
boolean isitAM = true;
|
||||||
@ -5892,12 +5897,12 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
}
|
}
|
||||||
if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
|
if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
|
||||||
else sprintf_P(sec, PSTR(":%02d"), second(localTime));
|
else sprintf_P(sec, PSTR(":%02d"), second(localTime));
|
||||||
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, PSTR("%d.%d.%d"), day(localTime), month(localTime), year(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, PSTR("%d.%d"), day(localTime), month(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, PSTR("%d/%d"), month(localTime), day(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, PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
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, PSTR("%2d:%02d"), AmPmHour, minute(localTime));
|
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, PSTR("%s %d, %d %2d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
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);
|
||||||
}
|
}
|
||||||
const int numberOfLetters = strlen(text);
|
const int numberOfLetters = strlen(text);
|
||||||
|
|
||||||
@ -5924,7 +5929,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
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";
|
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";
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
@ -6835,7 +6840,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_freqmatrix()
|
} // mode_freqmatrix()
|
||||||
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
|
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensivity;;;1f;m12=3,si=0"; // Corner, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -6939,7 +6944,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_freqwave()
|
} // mode_freqwave()
|
||||||
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
|
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
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
14
wled00/FX.h
14
wled00/FX.h
@ -353,7 +353,8 @@ typedef struct Segment {
|
|||||||
bool mirror_y : 1; // 8 : mirrored Y (2D)
|
bool mirror_y : 1; // 8 : mirrored Y (2D)
|
||||||
bool transpose : 1; // 9 : transposed (2D, swapped X & Y)
|
bool transpose : 1; // 9 : transposed (2D, swapped X & Y)
|
||||||
uint8_t map1D2D : 3; // 10-12 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
|
uint8_t map1D2D : 3; // 10-12 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
|
||||||
uint8_t soundSim : 3; // 13-15 : 0-7 sound simulation types
|
uint8_t soundSim : 1; // 13 : 0-1 sound simulation types ("soft" & "hard" or "on"/"off")
|
||||||
|
uint8_t set : 2; // 14-15 : 0-3 UI segment sets/groups
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
uint8_t grouping, spacing;
|
uint8_t grouping, spacing;
|
||||||
@ -486,7 +487,7 @@ typedef struct Segment {
|
|||||||
//if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB));
|
//if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB));
|
||||||
//Serial.println();
|
//Serial.println();
|
||||||
//#endif
|
//#endif
|
||||||
if (!Segment::_globalLeds && leds) free(leds);
|
if (!Segment::_globalLeds && leds) { free(leds); leds = nullptr;} // reset to nullptr, to avoid race conditions
|
||||||
if (name) delete[] name;
|
if (name) delete[] name;
|
||||||
if (_t) delete _t;
|
if (_t) delete _t;
|
||||||
deallocateData();
|
deallocateData();
|
||||||
@ -506,8 +507,8 @@ typedef struct Segment {
|
|||||||
inline bool hasRGB(void) const { return _isRGB; }
|
inline bool hasRGB(void) const { return _isRGB; }
|
||||||
inline bool hasWhite(void) const { return _hasW; }
|
inline bool hasWhite(void) const { return _hasW; }
|
||||||
inline bool isCCT(void) const { return _isCCT; }
|
inline bool isCCT(void) const { return _isCCT; }
|
||||||
inline uint16_t width(void) const { return stop - start; } // segment width in physical pixels (length if 1D)
|
inline uint16_t width(void) const { return (stop > start) ? (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
|
inline uint16_t height(void) const { return (stopY > startY) ? (stopY - startY) : 0; } // segment height (if 2D) in physical pixels // softhack007: make sure its always > 0
|
||||||
inline uint16_t length(void) const { return width() * height(); } // segment length (count) 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 uint16_t groupLength(void) const { return grouping + spacing; }
|
||||||
inline uint8_t getLightCapabilities(void) const { return _capabilities; }
|
inline uint8_t getLightCapabilities(void) const { return _capabilities; }
|
||||||
@ -515,7 +516,7 @@ typedef struct Segment {
|
|||||||
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
|
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
|
||||||
static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
||||||
|
|
||||||
void set(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
|
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
|
||||||
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
|
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
|
||||||
void setCCT(uint16_t k);
|
void setCCT(uint16_t k);
|
||||||
void setOpacity(uint8_t o);
|
void setOpacity(uint8_t o);
|
||||||
@ -709,7 +710,7 @@ class WS2812FX { // 96 bytes
|
|||||||
panel.clear();
|
panel.clear();
|
||||||
#endif
|
#endif
|
||||||
customPalettes.clear();
|
customPalettes.clear();
|
||||||
if (useLedsArray && Segment::_globalLeds) free(Segment::_globalLeds);
|
if (useLedsArray && Segment::_globalLeds) {free(Segment::_globalLeds); Segment::_globalLeds = nullptr;} // reset to nullptr, to avoid race conditions
|
||||||
}
|
}
|
||||||
|
|
||||||
static WS2812FX* getInstance(void) { return instance; }
|
static WS2812FX* getInstance(void) { return instance; }
|
||||||
@ -771,6 +772,7 @@ class WS2812FX { // 96 bytes
|
|||||||
getActiveSegmentsNum(void),
|
getActiveSegmentsNum(void),
|
||||||
getFirstSelectedSegId(void),
|
getFirstSelectedSegId(void),
|
||||||
getLastActiveSegmentId(void),
|
getLastActiveSegmentId(void),
|
||||||
|
getActiveSegsLightCapabilities(bool selectedOnly = false),
|
||||||
setPixelSegment(uint8_t n);
|
setPixelSegment(uint8_t n);
|
||||||
|
|
||||||
inline uint8_t getBrightness(void) { return _brightness; }
|
inline uint8_t getBrightness(void) { return _brightness; }
|
||||||
|
@ -191,6 +191,8 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
|||||||
uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) {
|
uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) {
|
||||||
uint16_t width = virtualWidth(); // segment width in logical pixels
|
uint16_t width = virtualWidth(); // segment width in logical pixels
|
||||||
uint16_t height = virtualHeight(); // segment height in logical pixels
|
uint16_t height = virtualHeight(); // segment height in logical pixels
|
||||||
|
if (width == 0) return 0; // softhack007 avoid div/0
|
||||||
|
if (height == 0) return (x%width); // softhack007 avoid div/0
|
||||||
return (x%width) + (y%height) * width;
|
return (x%width) + (y%height) * width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +204,6 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
|||||||
if (leds) leds[XY(x,y)] = col;
|
if (leds) leds[XY(x,y)] = col;
|
||||||
|
|
||||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||||
if (!_bri_t && !transitional) return;
|
|
||||||
if (_bri_t < 255) {
|
if (_bri_t < 255) {
|
||||||
byte r = scale8(R(col), _bri_t);
|
byte r = scale8(R(col), _bri_t);
|
||||||
byte g = scale8(G(col), _bri_t);
|
byte g = scale8(G(col), _bri_t);
|
||||||
@ -305,6 +306,7 @@ 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.
|
// Adds the specified color with the existing pixel color perserving color balance.
|
||||||
void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
|
void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
|
||||||
|
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);
|
uint32_t col = getPixelColorXY(x,y);
|
||||||
uint8_t r = R(col);
|
uint8_t r = R(col);
|
||||||
uint8_t g = G(col);
|
uint8_t g = G(col);
|
||||||
@ -329,24 +331,26 @@ void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
|
|||||||
|
|
||||||
// blurRow: perform a blur on a row of a rectangular matrix
|
// blurRow: perform a blur on a row of a rectangular matrix
|
||||||
void Segment::blurRow(uint16_t row, fract8 blur_amount) {
|
void Segment::blurRow(uint16_t row, fract8 blur_amount) {
|
||||||
const uint16_t cols = virtualWidth();
|
const uint_fast16_t cols = virtualWidth();
|
||||||
const uint16_t rows = virtualHeight();
|
const uint_fast16_t rows = virtualHeight();
|
||||||
|
|
||||||
if (row >= rows) return;
|
if (row >= rows) return;
|
||||||
// blur one row
|
// blur one row
|
||||||
uint8_t keep = 255 - blur_amount;
|
uint8_t keep = 255 - blur_amount;
|
||||||
uint8_t seep = blur_amount >> 1;
|
uint8_t seep = blur_amount >> 1;
|
||||||
CRGB carryover = CRGB::Black;
|
CRGB carryover = CRGB::Black;
|
||||||
for (uint16_t x = 0; x < cols; x++) {
|
for (uint_fast16_t x = 0; x < cols; x++) {
|
||||||
CRGB cur = getPixelColorXY(x, row);
|
CRGB cur = getPixelColorXY(x, row);
|
||||||
|
CRGB before = cur; // remember color before blur
|
||||||
CRGB part = cur;
|
CRGB part = cur;
|
||||||
part.nscale8(seep);
|
part.nscale8(seep);
|
||||||
cur.nscale8(keep);
|
cur.nscale8(keep);
|
||||||
cur += carryover;
|
cur += carryover;
|
||||||
if (x) {
|
if (x>0) {
|
||||||
CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part;
|
CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part;
|
||||||
setPixelColorXY(x-1, row, prev);
|
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;
|
carryover = part;
|
||||||
}
|
}
|
||||||
@ -354,25 +358,27 @@ void Segment::blurRow(uint16_t row, fract8 blur_amount) {
|
|||||||
|
|
||||||
// blurCol: perform a blur on a column of a rectangular matrix
|
// blurCol: perform a blur on a column of a rectangular matrix
|
||||||
void Segment::blurCol(uint16_t col, fract8 blur_amount) {
|
void Segment::blurCol(uint16_t col, fract8 blur_amount) {
|
||||||
const uint16_t cols = virtualWidth();
|
const uint_fast16_t cols = virtualWidth();
|
||||||
const uint16_t rows = virtualHeight();
|
const uint_fast16_t rows = virtualHeight();
|
||||||
|
|
||||||
if (col >= cols) return;
|
if (col >= cols) return;
|
||||||
// blur one column
|
// blur one column
|
||||||
uint8_t keep = 255 - blur_amount;
|
uint8_t keep = 255 - blur_amount;
|
||||||
uint8_t seep = blur_amount >> 1;
|
uint8_t seep = blur_amount >> 1;
|
||||||
CRGB carryover = CRGB::Black;
|
CRGB carryover = CRGB::Black;
|
||||||
for (uint16_t i = 0; i < rows; i++) {
|
for (uint_fast16_t y = 0; y < rows; y++) {
|
||||||
CRGB cur = getPixelColorXY(col, i);
|
CRGB cur = getPixelColorXY(col, y);
|
||||||
CRGB part = cur;
|
CRGB part = cur;
|
||||||
|
CRGB before = cur; // remember color before blur
|
||||||
part.nscale8(seep);
|
part.nscale8(seep);
|
||||||
cur.nscale8(keep);
|
cur.nscale8(keep);
|
||||||
cur += carryover;
|
cur += carryover;
|
||||||
if (i) {
|
if (y>0) {
|
||||||
CRGB prev = CRGB(getPixelColorXY(col, i-1)) + part;
|
CRGB prev = CRGB(getPixelColorXY(col, y-1)) + part;
|
||||||
setPixelColorXY(col, i-1, prev);
|
setPixelColorXY(col, y-1, prev);
|
||||||
}
|
}
|
||||||
setPixelColorXY(col, i, cur);
|
if (before != cur) // optimization: only set pixel if color has changed
|
||||||
|
setPixelColorXY(col, y, cur);
|
||||||
carryover = part;
|
carryover = part;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,8 +397,8 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
|||||||
for (uint16_t j = 0; j < dim1; j++) {
|
for (uint16_t j = 0; j < dim1; j++) {
|
||||||
uint16_t x = vertical ? i : j;
|
uint16_t x = vertical ? i : j;
|
||||||
uint16_t y = vertical ? j : i;
|
uint16_t y = vertical ? j : i;
|
||||||
uint16_t xp = vertical ? x : x-1;
|
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
|
||||||
uint16_t yp = vertical ? y-1 : y;
|
int16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow
|
||||||
uint16_t xn = vertical ? x : x+1;
|
uint16_t xn = vertical ? x : x+1;
|
||||||
uint16_t yn = vertical ? y+1 : y;
|
uint16_t yn = vertical ? y+1 : y;
|
||||||
CRGB curr = getPixelColorXY(x,y);
|
CRGB curr = getPixelColorXY(x,y);
|
||||||
|
@ -90,18 +90,18 @@ Segment::Segment(const Segment &orig) {
|
|||||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
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.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()); }
|
if (orig.leds && !Segment::_globalLeds && length() > 0) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// move constructor
|
// move constructor
|
||||||
Segment::Segment(Segment &&orig) noexcept {
|
Segment::Segment(Segment &&orig) noexcept {
|
||||||
//DEBUG_PRINTLN(F("-- Move segment constructor --"));
|
//DEBUG_PRINTLN(F("-- Move segment constructor --"));
|
||||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||||
|
orig.leds = nullptr;
|
||||||
orig.name = nullptr;
|
orig.name = nullptr;
|
||||||
orig.data = nullptr;
|
orig.data = nullptr;
|
||||||
orig._dataLen = 0;
|
orig._dataLen = 0;
|
||||||
orig._t = nullptr;
|
orig._t = nullptr;
|
||||||
orig.leds = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy assignment
|
// copy assignment
|
||||||
@ -111,7 +111,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
|||||||
// clean destination
|
// clean destination
|
||||||
if (name) delete[] name;
|
if (name) delete[] name;
|
||||||
if (_t) delete _t;
|
if (_t) delete _t;
|
||||||
if (leds && !Segment::_globalLeds) free(leds);
|
if (leds && !Segment::_globalLeds) {free(leds); leds=nullptr;}
|
||||||
deallocateData();
|
deallocateData();
|
||||||
// copy source
|
// copy source
|
||||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||||
@ -125,7 +125,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
|||||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
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.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()); }
|
if (orig.leds && !Segment::_globalLeds && length() > 0) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
|
|||||||
if (name) delete[] name; // free old name
|
if (name) delete[] name; // free old name
|
||||||
deallocateData(); // free old runtime data
|
deallocateData(); // free old runtime data
|
||||||
if (_t) delete _t;
|
if (_t) delete _t;
|
||||||
if (leds && !Segment::_globalLeds) free(leds);
|
if (leds && !Segment::_globalLeds) {free(leds); leds=nullptr;}
|
||||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||||
orig.name = nullptr;
|
orig.name = nullptr;
|
||||||
orig.data = nullptr;
|
orig.data = nullptr;
|
||||||
@ -152,12 +152,12 @@ bool Segment::allocateData(size_t len) {
|
|||||||
if (data && _dataLen == len) return true; //already allocated
|
if (data && _dataLen == len) return true; //already allocated
|
||||||
deallocateData();
|
deallocateData();
|
||||||
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||||
// if possible use SPI RAM on ESP32
|
// do not use SPI RAM on ESP32 since it is slow
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
//#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||||
if (psramFound())
|
//if (psramFound())
|
||||||
data = (byte*) ps_malloc(len);
|
// data = (byte*) ps_malloc(len);
|
||||||
else
|
//else
|
||||||
#endif
|
//#endif
|
||||||
data = (byte*) malloc(len);
|
data = (byte*) malloc(len);
|
||||||
if (!data) return false; //allocation failed
|
if (!data) return false; //allocation failed
|
||||||
Segment::addUsedSegmentData(len);
|
Segment::addUsedSegmentData(len);
|
||||||
@ -184,7 +184,7 @@ void Segment::deallocateData() {
|
|||||||
void Segment::resetIfRequired() {
|
void Segment::resetIfRequired() {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; }
|
if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; }
|
||||||
if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
|
//if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
|
||||||
deallocateData();
|
deallocateData();
|
||||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||||
reset = false; // setOption(SEG_OPTION_RESET, false);
|
reset = false; // setOption(SEG_OPTION_RESET, false);
|
||||||
@ -305,23 +305,26 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Segment::startTransition(uint16_t dur) {
|
void Segment::startTransition(uint16_t dur) {
|
||||||
if (transitional || _t) return; // already in transition no need to store anything
|
if (!dur) {
|
||||||
|
transitional = false;
|
||||||
|
if (_t) {
|
||||||
|
delete _t;
|
||||||
|
_t = nullptr;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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
|
// starting a transition has to occur before change so we get current values 1st
|
||||||
uint8_t _briT = currentBri(on ? opacity : 0);
|
_t = new Transition(dur); // no previous transition running
|
||||||
uint8_t _cctT = currentBri(cct, true);
|
|
||||||
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
|
|
||||||
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
|
if (!_t) return; // failed to allocate data
|
||||||
_t->_briT = _briT;
|
|
||||||
_t->_cctT = _cctT;
|
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
|
||||||
|
_t->_briT = on ? opacity : 0;
|
||||||
|
_t->_cctT = cct;
|
||||||
_t->_palT = _palT;
|
_t->_palT = _palT;
|
||||||
_t->_modeP = _modeP;
|
_t->_modeP = mode;
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = _colorT[i];
|
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
|
||||||
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
|
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,10 +337,10 @@ uint16_t Segment::progress() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
|
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
|
||||||
if (transitional && _t) {
|
uint32_t prog = progress();
|
||||||
uint32_t prog = progress() + 1;
|
if (transitional && _t && prog < 0xFFFFU) {
|
||||||
if (useCct) return ((briNew * prog) + _t->_cctT * (0x10000 - prog)) >> 16;
|
if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16;
|
||||||
else return ((briNew * prog) + _t->_briT * (0x10000 - prog)) >> 16;
|
else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16;
|
||||||
} else {
|
} else {
|
||||||
return briNew;
|
return briNew;
|
||||||
}
|
}
|
||||||
@ -367,19 +370,18 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal
|
|||||||
|
|
||||||
void Segment::handleTransition() {
|
void Segment::handleTransition() {
|
||||||
if (!transitional) return;
|
if (!transitional) return;
|
||||||
unsigned long maxWait = millis() + 20;
|
uint16_t _progress = progress();
|
||||||
if (mode == FX_MODE_STATIC && next_time > maxWait) next_time = maxWait;
|
if (_progress == 0xFFFFU) transitional = false; // finish transitioning segment
|
||||||
if (progress() == 0xFFFFU) {
|
if (_t) { // thanks to @nXm AKA https://github.com/NMeirer
|
||||||
if (_t) {
|
if (_progress >= 32767U && _t->_modeP != mode) markForReset();
|
||||||
if (_t->_modeP != mode) markForReset();
|
if (_progress == 0xFFFFU) {
|
||||||
delete _t;
|
delete _t;
|
||||||
_t = nullptr;
|
_t = nullptr;
|
||||||
}
|
}
|
||||||
transitional = false; // finish transitioning segment
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Segment::set(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
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
|
//return if neither bounds nor grouping have changed
|
||||||
bool boundsUnchanged = (start == i1 && stop == i2);
|
bool boundsUnchanged = (start == i1 && stop == i2);
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
@ -474,7 +476,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
|||||||
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
|
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
|
||||||
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 7);
|
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 1);
|
||||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
||||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||||
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
||||||
@ -545,6 +547,7 @@ uint16_t Segment::virtualLength() const {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
uint16_t groupLen = groupLength();
|
uint16_t groupLen = groupLength();
|
||||||
|
if (groupLen < 1) groupLen = 1; // prevent division by zero - better safe than sorry ...
|
||||||
uint16_t vLength = (length() + groupLen - 1) / groupLen;
|
uint16_t vLength = (length() + groupLen - 1) / groupLen;
|
||||||
if (mirror) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
if (mirror) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||||
return vLength;
|
return vLength;
|
||||||
@ -623,7 +626,6 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
|||||||
|
|
||||||
uint16_t len = length();
|
uint16_t len = length();
|
||||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
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) {
|
if (_bri_t < 255) {
|
||||||
byte r = scale8(R(col), _bri_t);
|
byte r = scale8(R(col), _bri_t);
|
||||||
byte g = scale8(G(col), _bri_t);
|
byte g = scale8(G(col), _bri_t);
|
||||||
@ -728,7 +730,7 @@ uint32_t Segment::getPixelColor(int i)
|
|||||||
i += start;
|
i += start;
|
||||||
/* offset/phase */
|
/* offset/phase */
|
||||||
i += offset;
|
i += offset;
|
||||||
if (i >= stop) i -= length();
|
if ((i >= stop) && (stop>0)) i -= length(); // avoids negative pixel index (stop = 0 is a possible value)
|
||||||
return strip.getPixelColor(i);
|
return strip.getPixelColor(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -750,7 +752,7 @@ uint8_t Segment::differs(Segment& b) const {
|
|||||||
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
|
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
|
||||||
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
|
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
|
||||||
|
|
||||||
//bit pattern: (msb first) sound:3, mapping:3, transposed, mirrorY, reverseY, [transitional, reset,] paused, mirrored, on, reverse, [selected]
|
//bit pattern: (msb first) set:2, sound:1, mapping:3, transposed, mirrorY, reverseY, [transitional, reset,] paused, mirrored, on, reverse, [selected]
|
||||||
if ((options & 0b1111111110011110U) != (b.options & 0b1111111110011110U)) d |= SEG_DIFFERS_OPT;
|
if ((options & 0b1111111110011110U) != (b.options & 0b1111111110011110U)) d |= SEG_DIFFERS_OPT;
|
||||||
if ((options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL;
|
if ((options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL;
|
||||||
for (uint8_t i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
|
for (uint8_t i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
|
||||||
@ -885,6 +887,7 @@ void Segment::fade_out(uint8_t rate) {
|
|||||||
|
|
||||||
// fades all pixels to black using nscale8()
|
// fades all pixels to black using nscale8()
|
||||||
void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||||
|
if (fadeBy == 0) return; // optimization - no scaling to apply
|
||||||
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
|
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
|
||||||
const uint16_t rows = virtualHeight(); // will be 1 for 1D
|
const uint16_t rows = virtualHeight(); // will be 1 for 1D
|
||||||
|
|
||||||
@ -899,23 +902,26 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
|||||||
*/
|
*/
|
||||||
void Segment::blur(uint8_t blur_amount)
|
void Segment::blur(uint8_t blur_amount)
|
||||||
{
|
{
|
||||||
|
if (blur_amount == 0) return; // optimization: 0 means "don't blur"
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (is2D()) {
|
if (is2D()) {
|
||||||
// compatibility with 2D
|
// compatibility with 2D
|
||||||
const uint16_t cols = virtualWidth();
|
const uint_fast16_t cols = virtualWidth();
|
||||||
const uint16_t rows = virtualHeight();
|
const uint_fast16_t rows = virtualHeight();
|
||||||
for (uint16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
|
for (uint_fast16_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
|
for (uint_fast16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
uint8_t keep = 255 - blur_amount;
|
uint8_t keep = 255 - blur_amount;
|
||||||
uint8_t seep = blur_amount >> 1;
|
uint8_t seep = blur_amount >> 1;
|
||||||
CRGB carryover = CRGB::Black;
|
CRGB carryover = CRGB::Black;
|
||||||
for(uint16_t i = 0; i < virtualLength(); i++)
|
uint_fast16_t vlength = virtualLength();
|
||||||
|
for(uint_fast16_t i = 0; i < vlength; i++)
|
||||||
{
|
{
|
||||||
CRGB cur = CRGB(getPixelColor(i));
|
CRGB cur = CRGB(getPixelColor(i));
|
||||||
CRGB part = cur;
|
CRGB part = cur;
|
||||||
|
CRGB before = cur; // remember color before blur
|
||||||
part.nscale8(seep);
|
part.nscale8(seep);
|
||||||
cur.nscale8(keep);
|
cur.nscale8(keep);
|
||||||
cur += carryover;
|
cur += carryover;
|
||||||
@ -924,9 +930,10 @@ void Segment::blur(uint8_t blur_amount)
|
|||||||
uint8_t r = R(c);
|
uint8_t r = R(c);
|
||||||
uint8_t g = G(c);
|
uint8_t g = G(c);
|
||||||
uint8_t b = B(c);
|
uint8_t b = B(c);
|
||||||
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
|
setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
|
||||||
}
|
}
|
||||||
setPixelColor(i,cur.red, cur.green, cur.blue);
|
if (before != cur) // optimization: only set pixel if color has changed
|
||||||
|
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue);
|
||||||
carryover = part;
|
carryover = part;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1076,7 +1083,7 @@ void WS2812FX::finalizeInit(void)
|
|||||||
//else
|
//else
|
||||||
//#endif
|
//#endif
|
||||||
Segment::_globalLeds = (CRGB*) malloc(arrSize);
|
Segment::_globalLeds = (CRGB*) malloc(arrSize);
|
||||||
memset(Segment::_globalLeds, 0, arrSize);
|
if (Segment::_globalLeds && (arrSize > 0)) memset(Segment::_globalLeds, 0, arrSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
//segments are created in makeAutoSegments();
|
//segments are created in makeAutoSegments();
|
||||||
@ -1095,6 +1102,8 @@ void WS2812FX::service() {
|
|||||||
_isServicing = true;
|
_isServicing = true;
|
||||||
_segment_index = 0;
|
_segment_index = 0;
|
||||||
for (segment &seg : _segments) {
|
for (segment &seg : _segments) {
|
||||||
|
// process transition (mode changes in the middle of transition)
|
||||||
|
seg.handleTransition();
|
||||||
// reset the segment runtime data if needed
|
// reset the segment runtime data if needed
|
||||||
seg.resetIfRequired();
|
seg.resetIfRequired();
|
||||||
|
|
||||||
@ -1123,8 +1132,6 @@ void WS2812FX::service() {
|
|||||||
delay = (*_mode[seg.currentMode(seg.mode)])();
|
delay = (*_mode[seg.currentMode(seg.mode)])();
|
||||||
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
||||||
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||||
|
|
||||||
seg.handleTransition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seg.next_time = nowUp + delay;
|
seg.next_time = nowUp + delay;
|
||||||
@ -1221,7 +1228,8 @@ void WS2812FX::estimateCurrentAndLimitBri() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t powerSum0 = powerSum;
|
uint32_t powerSum0 = powerSum;
|
||||||
powerSum *= _brightness;
|
//powerSum *= _brightness; // for NPBrightnessBus
|
||||||
|
powerSum *= 255; // no need to scale down powerSum - NPB-LG getPixelColor returns colors scaled down by brightness
|
||||||
|
|
||||||
if (powerSum > powerBudget) //scale brightness down to stay in current limit
|
if (powerSum > powerBudget) //scale brightness down to stay in current limit
|
||||||
{
|
{
|
||||||
@ -1229,11 +1237,14 @@ void WS2812FX::estimateCurrentAndLimitBri() {
|
|||||||
uint16_t scaleI = scale * 255;
|
uint16_t scaleI = scale * 255;
|
||||||
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
||||||
uint8_t newBri = scale8(_brightness, scaleB);
|
uint8_t newBri = scale8(_brightness, scaleB);
|
||||||
busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too
|
// to keep brightness uniform, sets virtual busses too - softhack007: apply reductions immediately
|
||||||
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
|
if (scaleB < 255) busses.setBrightness(scaleB, true); // NPB-LG has already applied brightness, so its suffifient to post-apply scaling ==> use scaleB instead of newBri
|
||||||
|
busses.setBrightness(newBri, false); // set new brightness for next frame
|
||||||
|
//currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; // for NPBrightnessBus
|
||||||
|
currentMilliamps = (powerSum0 * scaleB) / puPerMilliamp; // for NPBus-LG
|
||||||
} else {
|
} else {
|
||||||
currentMilliamps = powerSum / puPerMilliamp;
|
currentMilliamps = powerSum / puPerMilliamp;
|
||||||
busses.setBrightness(_brightness);
|
busses.setBrightness(_brightness, false); // set new brightness for next frame
|
||||||
}
|
}
|
||||||
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
|
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
|
||||||
currentMilliamps += pLen; //add standby power back to estimate
|
currentMilliamps += pLen; //add standby power back to estimate
|
||||||
@ -1330,6 +1341,14 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t WS2812FX::getActiveSegsLightCapabilities(bool selectedOnly) {
|
||||||
|
uint8_t totalLC = 0;
|
||||||
|
for (segment &seg : _segments) {
|
||||||
|
if (seg.isActive() && (!selectedOnly || seg.isSelected())) totalLC |= seg.getLightCapabilities();
|
||||||
|
}
|
||||||
|
return totalLC;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t WS2812FX::getFirstSelectedSegId(void)
|
uint8_t WS2812FX::getFirstSelectedSegId(void)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@ -1427,7 +1446,7 @@ Segment& WS2812FX::getSegment(uint8_t id) {
|
|||||||
|
|
||||||
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) {
|
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;
|
if (n >= _segments.size()) return;
|
||||||
_segments[n].set(i1, i2, grouping, spacing, offset, startY, stopY);
|
_segments[n].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::restartRuntime() {
|
void WS2812FX::restartRuntime() {
|
||||||
@ -1583,7 +1602,7 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::setTransitionMode(bool t) {
|
void WS2812FX::setTransitionMode(bool t) {
|
||||||
for (segment &seg : _segments) if (!seg.transitional) seg.startTransition(t ? _transitionDur : 0);
|
for (segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
|
|
||||||
#define NODE_TYPE_ID_UNDEFINED 0
|
#define NODE_TYPE_ID_UNDEFINED 0
|
||||||
#define NODE_TYPE_ID_ESP8266 82
|
#define NODE_TYPE_ID_ESP8266 82 // should be 1
|
||||||
#define NODE_TYPE_ID_ESP32 32
|
#define NODE_TYPE_ID_ESP32 32 // should be 2
|
||||||
#define NODE_TYPE_ID_ESP32S2 33
|
#define NODE_TYPE_ID_ESP32S2 33 // etc
|
||||||
#define NODE_TYPE_ID_ESP32S3 34
|
#define NODE_TYPE_ID_ESP32S3 34
|
||||||
#define NODE_TYPE_ID_ESP32C3 35
|
#define NODE_TYPE_ID_ESP32C3 35
|
||||||
|
|
||||||
@ -23,7 +23,13 @@ struct NodeStruct
|
|||||||
String nodeName;
|
String nodeName;
|
||||||
IPAddress ip;
|
IPAddress ip;
|
||||||
uint8_t age;
|
uint8_t age;
|
||||||
uint8_t nodeType;
|
union {
|
||||||
|
uint8_t nodeType; // a waste of space as we only have 5 types
|
||||||
|
struct {
|
||||||
|
uint8_t type : 7; // still a waste of space (4 bits would be enough and future-proof)
|
||||||
|
bool on : 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
uint32_t build;
|
uint32_t build;
|
||||||
|
|
||||||
NodeStruct() : age(0), nodeType(0), build(0)
|
NodeStruct() : age(0), nodeType(0), build(0)
|
||||||
|
@ -105,8 +105,15 @@ void onAlexaChange(EspalexaDevice* dev)
|
|||||||
uint16_t k = 1000000 / ct; //mireds to kelvin
|
uint16_t k = 1000000 / ct; //mireds to kelvin
|
||||||
|
|
||||||
if (strip.hasCCTBus()) {
|
if (strip.hasCCTBus()) {
|
||||||
|
bool hasManualWhite = strip.getActiveSegsLightCapabilities(true) & SEG_CAPABILITY_W;
|
||||||
|
|
||||||
strip.setCCT(k);
|
strip.setCCT(k);
|
||||||
|
if (hasManualWhite) {
|
||||||
rgbw[0] = 0; rgbw[1] = 0; rgbw[2] = 0; rgbw[3] = 255;
|
rgbw[0] = 0; rgbw[1] = 0; rgbw[2] = 0; rgbw[3] = 255;
|
||||||
|
} else {
|
||||||
|
rgbw[0] = 255; rgbw[1] = 255; rgbw[2] = 255; rgbw[3] = 0;
|
||||||
|
dev->setValue(255);
|
||||||
|
}
|
||||||
} else if (strip.hasWhiteChannel()) {
|
} else if (strip.hasWhiteChannel()) {
|
||||||
switch (ct) { //these values empirically look good on RGBW
|
switch (ct) { //these values empirically look good on RGBW
|
||||||
case 199: rgbw[0]=255; rgbw[1]=255; rgbw[2]=255; rgbw[3]=255; break;
|
case 199: rgbw[0]=255; rgbw[1]=255; rgbw[2]=255; rgbw[3]=255; break;
|
||||||
|
@ -126,15 +126,15 @@ bool BusDigital::canShow() {
|
|||||||
return PolyBus::canShow(_busPtr, _iType);
|
return PolyBus::canShow(_busPtr, _iType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusDigital::setBrightness(uint8_t b) {
|
void BusDigital::setBrightness(uint8_t b, bool immediate) {
|
||||||
//Fix for turning off onboard LED breaking bus
|
//Fix for turning off onboard LED breaking bus
|
||||||
#ifdef LED_BUILTIN
|
#ifdef LED_BUILTIN
|
||||||
if (_bri == 0 && b > 0) {
|
if (_bri == 0 && b > 0) {
|
||||||
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
|
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Bus::setBrightness(b);
|
Bus::setBrightness(b, immediate);
|
||||||
PolyBus::setBrightness(_busPtr, _iType, b);
|
PolyBus::setBrightness(_busPtr, _iType, b, immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
//If LEDs are skipped, it is possible to use the first as a status LED.
|
//If LEDs are skipped, it is possible to use the first as a status LED.
|
||||||
@ -515,9 +515,9 @@ void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusManager::setBrightness(uint8_t b) {
|
void BusManager::setBrightness(uint8_t b, bool immediate) {
|
||||||
for (uint8_t i = 0; i < numBusses; i++) {
|
for (uint8_t i = 0; i < numBusses; i++) {
|
||||||
busses[i]->setBrightness(b);
|
busses[i]->setBrightness(b, immediate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ class Bus {
|
|||||||
virtual void setStatusPixel(uint32_t c) {}
|
virtual void setStatusPixel(uint32_t c) {}
|
||||||
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
|
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
|
||||||
virtual uint32_t getPixelColor(uint16_t pix) { return 0; }
|
virtual uint32_t getPixelColor(uint16_t pix) { return 0; }
|
||||||
virtual void setBrightness(uint8_t b) { _bri = b; };
|
virtual void setBrightness(uint8_t b, bool immediate=false) { _bri = b; };
|
||||||
virtual void cleanup() = 0;
|
virtual void cleanup() = 0;
|
||||||
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
|
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
|
||||||
virtual uint16_t getLength() { return _len; }
|
virtual uint16_t getLength() { return _len; }
|
||||||
@ -181,7 +181,7 @@ class BusDigital : public Bus {
|
|||||||
|
|
||||||
bool canShow();
|
bool canShow();
|
||||||
|
|
||||||
void setBrightness(uint8_t b);
|
void setBrightness(uint8_t b, bool immediate);
|
||||||
|
|
||||||
void setStatusPixel(uint32_t c);
|
void setStatusPixel(uint32_t c);
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ class BusManager {
|
|||||||
|
|
||||||
void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
|
void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
|
||||||
|
|
||||||
void setBrightness(uint8_t b);
|
void setBrightness(uint8_t b, bool immediate=false); // immediate=true is for use in ABL, it applies brightness immediately (warning: inefficient)
|
||||||
|
|
||||||
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||||
|
|
||||||
|
@ -122,6 +122,9 @@
|
|||||||
#define I_SS_LPO_3 48
|
#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 ***/
|
/*** ESP8266 Neopixel methods ***/
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
//RGB
|
//RGB
|
||||||
@ -247,7 +250,11 @@
|
|||||||
#define B_SS_LPO_3 NeoPixelBusLg<Lpd6803GrbFeature, Lpd6803Method, NeoGammaNullMethod>
|
#define B_SS_LPO_3 NeoPixelBusLg<Lpd6803GrbFeature, Lpd6803Method, NeoGammaNullMethod>
|
||||||
|
|
||||||
//WS2801
|
//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>
|
#define B_HS_WS1_3 NeoPixelBusLg<NeoRbgFeature, Ws2801SpiHzMethod, NeoGammaNullMethod>
|
||||||
|
#endif
|
||||||
#define B_SS_WS1_3 NeoPixelBusLg<NeoRbgFeature, Ws2801Method, NeoGammaNullMethod>
|
#define B_SS_WS1_3 NeoPixelBusLg<NeoRbgFeature, Ws2801Method, NeoGammaNullMethod>
|
||||||
|
|
||||||
//P9813
|
//P9813
|
||||||
@ -799,101 +806,101 @@ class PolyBus {
|
|||||||
case I_SS_P98_3: (static_cast<B_SS_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) {
|
static void setBrightness(void* busPtr, uint8_t busType, uint8_t b, bool immediate) { // immediate=true is for use in ABL, it applies brightness immediately (warning: inefficient)
|
||||||
switch (busType) {
|
switch (busType) {
|
||||||
case I_NONE: break;
|
case I_NONE: break;
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->SetLuminance(b); break;
|
case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_U1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_DM_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->SetLuminance(b); break;
|
case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_8266_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); break;
|
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetLuminance(b); break;
|
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetLuminance(b); break;
|
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||||
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); break;
|
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetLuminance(b); break;
|
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_RN_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); break;
|
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_I1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetLuminance(b); break;
|
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_32_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
#endif
|
#endif
|
||||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); break;
|
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetLuminance(b); break;
|
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetLuminance(b); break;
|
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetLuminance(b); break;
|
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->SetLuminance(b); break;
|
case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->SetLuminance(b); break;
|
case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetLuminance(b); break;
|
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetLuminance(b); break;
|
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); break;
|
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_HS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); break;
|
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); if (immediate) (static_cast<B_SS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
|
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
|
||||||
|
@ -227,9 +227,8 @@ void handleButton()
|
|||||||
static unsigned long lastRun = 0UL;
|
static unsigned long lastRun = 0UL;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
//if (strip.isUpdating()) return; // don't interfere with strip updates. Our button will still be there in 1ms (next cycle)
|
if (strip.isUpdating() && (now - lastRun < 400)) return; // don't interfere with strip update (unless strip is updating continuously, e.g. very long strips)
|
||||||
if (strip.isUpdating() && (millis() - lastRun < 400)) return; // be niced, but avoid button starvation
|
lastRun = now;
|
||||||
lastRun = millis();
|
|
||||||
|
|
||||||
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
|
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -257,6 +256,15 @@ void handleButton()
|
|||||||
// momentary button logic
|
// momentary button logic
|
||||||
if (isButtonPressed(b)) { // pressed
|
if (isButtonPressed(b)) { // pressed
|
||||||
|
|
||||||
|
// if all macros are the same, fire action immediately on rising edge
|
||||||
|
if (macroButton[b] && macroButton[b] == macroLongPress[b] && macroButton[b] == macroDoublePress[b]) {
|
||||||
|
if (!buttonPressedBefore[b])
|
||||||
|
shortPressAction(b);
|
||||||
|
buttonPressedBefore[b] = true;
|
||||||
|
buttonPressedTime[b] = now; // continually update (for debouncing to work in release handler)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!buttonPressedBefore[b]) buttonPressedTime[b] = now;
|
if (!buttonPressedBefore[b]) buttonPressedTime[b] = now;
|
||||||
buttonPressedBefore[b] = true;
|
buttonPressedBefore[b] = true;
|
||||||
|
|
||||||
@ -270,8 +278,14 @@ void handleButton()
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released
|
} else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released
|
||||||
|
|
||||||
long dur = now - buttonPressedTime[b];
|
long dur = now - buttonPressedTime[b];
|
||||||
|
|
||||||
|
// released after rising-edge short press action
|
||||||
|
if (macroButton[b] && macroButton[b] == macroLongPress[b] && macroButton[b] == macroDoublePress[b]) {
|
||||||
|
if (dur > WLED_DEBOUNCE_THRESHOLD) buttonPressedBefore[b] = false; // debounce, blocks button for 50 ms once it has been released
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} // too short "press", debounce
|
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} // too short "press", debounce
|
||||||
bool doublePress = buttonWaitTime[b]; //did we have a short press before?
|
bool doublePress = buttonWaitTime[b]; //did we have a short press before?
|
||||||
buttonWaitTime[b] = 0;
|
buttonWaitTime[b] = 0;
|
||||||
|
@ -297,9 +297,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
||||||
if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called prior)
|
if (!Wire.setPins(i2c_sda, i2c_scl)) { i2c_scl = i2c_sda = -1; } // this will fail if Wire is initilised (Wire.begin() called prior)
|
||||||
|
else Wire.begin();
|
||||||
|
#else
|
||||||
|
Wire.begin(i2c_sda, i2c_scl);
|
||||||
#endif
|
#endif
|
||||||
Wire.begin();
|
|
||||||
} else {
|
} else {
|
||||||
i2c_sda = -1;
|
i2c_sda = -1;
|
||||||
i2c_scl = -1;
|
i2c_scl = -1;
|
||||||
@ -336,7 +338,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
||||||
else gammaCorrectCol = false;
|
else gammaCorrectCol = false;
|
||||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
||||||
if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal);
|
if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||||
} else {
|
} else {
|
||||||
gammaCorrectVal = 1.0f; // no gamma correction
|
gammaCorrectVal = 1.0f; // no gamma correction
|
||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
@ -438,8 +440,16 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
|
|
||||||
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
|
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
|
||||||
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
|
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
|
||||||
|
CJSON(retainMqttMsg, if_mqtt[F("rtn")]);
|
||||||
#endif
|
#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
|
#ifndef WLED_DISABLE_HUESYNC
|
||||||
JsonObject if_hue = interfaces["hue"];
|
JsonObject if_hue = interfaces["hue"];
|
||||||
CJSON(huePollingEnabled, if_hue["en"]);
|
CJSON(huePollingEnabled, if_hue["en"]);
|
||||||
@ -885,12 +895,20 @@ void serializeConfig() {
|
|||||||
if_mqtt[F("user")] = mqttUser;
|
if_mqtt[F("user")] = mqttUser;
|
||||||
if_mqtt[F("pskl")] = strlen(mqttPass);
|
if_mqtt[F("pskl")] = strlen(mqttPass);
|
||||||
if_mqtt[F("cid")] = mqttClientID;
|
if_mqtt[F("cid")] = mqttClientID;
|
||||||
|
if_mqtt[F("rtn")] = retainMqttMsg;
|
||||||
|
|
||||||
JsonObject if_mqtt_topics = if_mqtt.createNestedObject(F("topics"));
|
JsonObject if_mqtt_topics = if_mqtt.createNestedObject(F("topics"));
|
||||||
if_mqtt_topics[F("device")] = mqttDeviceTopic;
|
if_mqtt_topics[F("device")] = mqttDeviceTopic;
|
||||||
if_mqtt_topics[F("group")] = mqttGroupTopic;
|
if_mqtt_topics[F("group")] = mqttGroupTopic;
|
||||||
#endif
|
#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
|
#ifndef WLED_DISABLE_HUESYNC
|
||||||
JsonObject if_hue = interfaces.createNestedObject("hue");
|
JsonObject if_hue = interfaces.createNestedObject("hue");
|
||||||
if_hue["en"] = huePollingEnabled;
|
if_hue["en"] = huePollingEnabled;
|
||||||
|
@ -302,7 +302,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//gamma 2.8 lookup table used for color correction
|
//gamma 2.8 lookup table used for color correction
|
||||||
static byte gammaT[] = {
|
uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
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,
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||||
@ -320,27 +320,22 @@ static byte gammaT[] = {
|
|||||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
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 };
|
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||||
|
|
||||||
uint8_t gamma8_cal(uint8_t b, float gamma)
|
|
||||||
{
|
|
||||||
return (int)(powf((float)b / 255.0f, gamma) * 255.0f + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// re-calculates & fills gamma table
|
// re-calculates & fills gamma table
|
||||||
void calcGammaTable(float gamma)
|
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||||
{
|
{
|
||||||
for (uint16_t i = 0; i < 256; i++) {
|
for (size_t i = 0; i < 256; i++) {
|
||||||
gammaT[i] = gamma8_cal(i, gamma);
|
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used for individual channel or brightness gamma correction
|
uint8_t NeoGammaWLEDMethod::Correct(uint8_t value)
|
||||||
uint8_t gamma8(uint8_t b)
|
|
||||||
{
|
{
|
||||||
return gammaT[b];
|
if (!gammaCorrectCol) return value;
|
||||||
|
return gammaT[value];
|
||||||
}
|
}
|
||||||
|
|
||||||
// used for color gamma correction
|
// used for color gamma correction
|
||||||
uint32_t gamma32(uint32_t color)
|
uint32_t NeoGammaWLEDMethod::Correct32(uint32_t color)
|
||||||
{
|
{
|
||||||
if (!gammaCorrectCol) return color;
|
if (!gammaCorrectCol) return color;
|
||||||
uint8_t w = W(color);
|
uint8_t w = W(color);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#define DEFAULT_AP_SSID "WLED-AP"
|
#define DEFAULT_AP_SSID "WLED-AP"
|
||||||
#define DEFAULT_AP_PASS "wled1234"
|
#define DEFAULT_AP_PASS "wled1234"
|
||||||
#define DEFAULT_OTA_PASS "wledota"
|
#define DEFAULT_OTA_PASS "wledota"
|
||||||
|
#define DEFAULT_MDNS_NAME "x"
|
||||||
|
|
||||||
//increase if you need more
|
//increase if you need more
|
||||||
#ifndef WLED_MAX_USERMODS
|
#ifndef WLED_MAX_USERMODS
|
||||||
@ -90,6 +91,21 @@
|
|||||||
#endif
|
#endif
|
||||||
#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
|
//Usermod IDs
|
||||||
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
#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
|
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
|
||||||
@ -319,7 +335,8 @@
|
|||||||
|
|
||||||
// WLED Error modes
|
// WLED Error modes
|
||||||
#define ERR_NONE 0 // All good :)
|
#define ERR_NONE 0 // All good :)
|
||||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)
|
#define ERR_DENIED 1 // Permission denied
|
||||||
|
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) OBSOLETE
|
||||||
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
|
#define ERR_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_JSON 9 // JSON parsing failed (input too large?)
|
||||||
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
||||||
@ -337,6 +354,23 @@
|
|||||||
#define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color 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.
|
#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
|
#define NTP_PACKET_SIZE 48
|
||||||
|
|
||||||
@ -369,7 +403,7 @@
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define SETTINGS_STACK_BUF_SIZE 2048
|
#define SETTINGS_STACK_BUF_SIZE 2048
|
||||||
#else
|
#else
|
||||||
#define SETTINGS_STACK_BUF_SIZE 3096
|
#define SETTINGS_STACK_BUF_SIZE 3608 // warning: quite a large value for stack
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#ifdef WLED_USE_ETHERNET
|
||||||
@ -441,7 +475,10 @@
|
|||||||
#define DEFAULT_LED_COUNT 30
|
#define DEFAULT_LED_COUNT 30
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
|
#define INTERFACE_UPDATE_COOLDOWN 1000 // time in ms to wait between websockets, alexa, and MQTT updates
|
||||||
|
|
||||||
|
#define PIN_RETRY_COOLDOWN 3000 // time in ms after an incorrect attempt PIN and OTA pass will be rejected even if correct
|
||||||
|
#define PIN_TIMEOUT 900000 // time in ms after which the PIN will be required again, 15 minutes
|
||||||
|
|
||||||
// HW_PIN_SCL & HW_PIN_SDA are used for information in usermods settings page and usermods themselves
|
// 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)
|
// which GPIO pins are actually used in a hardwarea layout (controller board)
|
||||||
|
@ -42,6 +42,6 @@
|
|||||||
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAbUExURQAAAAB81gCU/zKq/////9bW1oCAgGhoaAAAAGPLX8AAAAAJdFJOU///////////AFNPeBIAAAAJcEhZcwAADsAAAA7AAWrWiQkAAACdSURBVDhPxc9bDoUgEANQebP/FUuHMjBGY/B+3EYR7RH0qC/ZBc6HwCljgHO+xZIVSI2sYgHaG7EBWh8jWoxTrCBFdDJ+BD4lbIHxAcz8APAVLTsrZE4eQD5qzt3cAFTYokC4YCN9Gybgu4yAQtBFLQXHuHABA7JMeOEC/E0W5uy9gv4vo5QHK2i7yq2C8UABM4HmL+CSTXCTF1DrCX6+Gp9zB5dsAAAAAElFTkSuQmCC">
|
<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>
|
<h1>404 Not Found</h1>
|
||||||
<b>Akemi does not know where you are headed...</b><br><br>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
@ -134,7 +134,7 @@ button {
|
|||||||
|
|
||||||
.off {
|
.off {
|
||||||
color: var(--c-6) !important;
|
color: var(--c-6) !important;
|
||||||
cursor: default !important;
|
/* cursor: default !important; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.top .icons, .bot .icons {
|
.top .icons, .bot .icons {
|
||||||
@ -174,37 +174,62 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.slider-icon {
|
.slider-icon {
|
||||||
/*transform: translate(3px,3px);*/
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 8px;
|
left: 8px;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.e-icon {
|
|
||||||
transform: translateY(3px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sel-icon {
|
.sel-icon {
|
||||||
transform: translateX(3px);
|
transform: translateX(3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.e-icon, .sel-icon, .slider-icon {
|
.e-icon, .g-icon, .sel-icon, .slider-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--c-d);
|
color: var(--c-d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.g-icon {
|
||||||
|
font-style: normal;
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pop-up container */
|
||||||
|
.pop {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pop-up content (segment sets) */
|
||||||
|
.pop-c {
|
||||||
|
position: absolute;
|
||||||
|
background-color: var(--c-2);
|
||||||
|
border: 1px solid var(--c-8);
|
||||||
|
border-radius: 20px;
|
||||||
|
z-index: 1;
|
||||||
|
top: 3px;
|
||||||
|
right: 35px;
|
||||||
|
padding: 3px 8px 1px;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
.pop-c span {
|
||||||
|
padding: 2px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.search-icon {
|
.search-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
left: 12px;
|
left: 12px;
|
||||||
/*pointer-events: none;*/
|
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clear-icon {
|
.clear-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: none;
|
|
||||||
top: 8px;
|
top: 8px;
|
||||||
right: 9px;
|
right: 9px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -232,14 +257,12 @@ button {
|
|||||||
|
|
||||||
#liveview {
|
#liveview {
|
||||||
height: 4px;
|
height: 4px;
|
||||||
display: none;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#liveview2D {
|
#liveview2D {
|
||||||
height: 90%;
|
height: 90%;
|
||||||
display: none;
|
|
||||||
width: 90%;
|
width: 90%;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -387,6 +410,7 @@ button {
|
|||||||
position: -webkit-sticky;
|
position: -webkit-sticky;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sliders .labels {
|
#sliders .labels {
|
||||||
@ -395,7 +419,7 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.slider {
|
.slider {
|
||||||
max-width: 300px;
|
/*max-width: 300px;*/
|
||||||
/* margin: 5px auto; add 5px; if you want some vertical space but looks ugly */
|
/* margin: 5px auto; add 5px; if you want some vertical space but looks ugly */
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -411,12 +435,16 @@ button {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sliders .slider {
|
||||||
|
padding-right: 64px; /* offset for bubble */
|
||||||
|
}
|
||||||
|
|
||||||
#sliders .slider, #info .slider {
|
#sliders .slider, #info .slider {
|
||||||
background-color: var(--c-2);
|
background-color: var(--c-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#sliders .sliderwrap, .sbs .sliderwrap {
|
#sliders .sliderwrap, .sbs .sliderwrap {
|
||||||
left: 16px; /* offset for icon */
|
left: 32px; /* offset for icon */
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter, .option {
|
.filter, .option {
|
||||||
@ -482,13 +510,6 @@ button {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pql, .edit-icon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hide {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
.fade {
|
.fade {
|
||||||
visibility: hidden; /* hide it */
|
visibility: hidden; /* hide it */
|
||||||
opacity: 0; /* make it transparent */
|
opacity: 0; /* make it transparent */
|
||||||
@ -567,7 +588,6 @@ button {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: calc(var(--th) + 5px);
|
top: calc(var(--th) + 5px);
|
||||||
left: 1px;
|
left: 1px;
|
||||||
display: none;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,24 +682,27 @@ img {
|
|||||||
#wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); }
|
#wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); }
|
||||||
|
|
||||||
/* wrapper divs hidden by default */
|
/* wrapper divs hidden by default */
|
||||||
#rgbwrap, #swrap, #hwrap, #kwrap, #wwrap, #wbal, #qcs-w, #hexw {
|
#liveview, #liveview2D, #roverstar, #pql
|
||||||
|
#rgbwrap, #swrap, #hwrap, #kwrap, #wwrap, #wbal, #qcs-w, #hexw,
|
||||||
|
.clear-icon, .edit-icon, .ptxt {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sliderbubble {
|
.sliderbubble {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
position: relative;
|
position: absolute;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 10px;
|
border-radius: 16px;
|
||||||
background: var(--c-3);
|
background: var(--c-3);
|
||||||
color: var(--c-f);
|
color: var(--c-f);
|
||||||
padding: 2px 4px;
|
padding: 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
right: 3px;
|
right: 6px;
|
||||||
transition: visibility 0.25s ease, opacity 0.25s ease;
|
transition: visibility .25s ease,opacity .25s ease;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
left: 8px;
|
/* left: 8px; */
|
||||||
|
top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
output.sliderbubbleshow {
|
output.sliderbubbleshow {
|
||||||
@ -771,8 +794,8 @@ input[type=range]::-moz-range-thumb {
|
|||||||
-webkit-transform:translate3d(0,0,0);
|
-webkit-transform:translate3d(0,0,0);
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
transform:translate3d(0,0,0);
|
transform:translate3d(0,0,0);
|
||||||
overflow: clip;
|
overflow: hidden;
|
||||||
text-overflow: clip;
|
text-overflow: ellipsis;
|
||||||
border: 1px solid var(--c-3);
|
border: 1px solid var(--c-3);
|
||||||
background-color: var(--c-3);
|
background-color: var(--c-3);
|
||||||
}
|
}
|
||||||
@ -803,6 +826,7 @@ input[type=range]::-moz-range-thumb {
|
|||||||
.btn-xs, .btn-pl-del, .btn-pl-add {
|
.btn-xs, .btn-pl-del, .btn-pl-add {
|
||||||
width: 42px !important;
|
width: 42px !important;
|
||||||
height: 42px !important;
|
height: 42px !important;
|
||||||
|
text-overflow: clip;
|
||||||
}
|
}
|
||||||
.btn-xs {
|
.btn-xs {
|
||||||
margin: 2px 0 0 0;
|
margin: 2px 0 0 0;
|
||||||
@ -980,23 +1004,25 @@ textarea {
|
|||||||
|
|
||||||
.ptxt {
|
.ptxt {
|
||||||
margin: -1px 4px 8px !important;
|
margin: -1px 4px 8px !important;
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stxt {
|
.stxt {
|
||||||
width: 50px !important;
|
width: 50px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.segname, .pname {
|
.segname, .pname, .bname {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: clip;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
padding: 8px 24px;
|
padding: 8px 24px;
|
||||||
max-width: 170px;
|
max-width: 170px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.bname {
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.segname .flr, .pname .flr {
|
.segname .flr, .pname .flr {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
@ -1005,8 +1031,9 @@ textarea {
|
|||||||
|
|
||||||
/* segment power wrapper */
|
/* segment power wrapper */
|
||||||
.sbs {
|
.sbs {
|
||||||
padding: 1px 0 1px 20px;
|
/*padding: 1px 0 1px 20px;*/
|
||||||
display: var(--sgp);
|
display: var(--sgp);
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pname {
|
.pname {
|
||||||
@ -1048,11 +1075,9 @@ textarea {
|
|||||||
|
|
||||||
#csl .xxs {
|
#csl .xxs {
|
||||||
border: 2px solid var(--c-d) !important;
|
border: 2px solid var(--c-d) !important;
|
||||||
/*box-shadow: 0 0 0 2px var(--c-d);*/
|
|
||||||
}
|
}
|
||||||
#csl .xxs-w {
|
#csl .xxs-w {
|
||||||
border-width: 5px !important;
|
border-width: 5px !important;
|
||||||
/*box-shadow: 0 0 0 5px var(--c-d);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.qcs, #namelabel { /* text shadow for name to be legible on grey backround */
|
.qcs, #namelabel { /* text shadow for name to be legible on grey backround */
|
||||||
@ -1066,7 +1091,6 @@ textarea {
|
|||||||
|
|
||||||
.pwr {
|
.pwr {
|
||||||
color: var(--c-6);
|
color: var(--c-6);
|
||||||
transform: translate(1px, 1px);
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1081,18 +1105,13 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.frz {
|
.frz {
|
||||||
left: 32px;
|
left: 10px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -3px;
|
top: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 8px;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expanded .frz {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* radiobuttons and checkmarks */
|
/* radiobuttons and checkmarks */
|
||||||
.check, .radio {
|
.check, .radio {
|
||||||
display: block;
|
display: block;
|
||||||
@ -1234,7 +1253,6 @@ TD .checkmark, TD .radiomark {
|
|||||||
|
|
||||||
.lbl-s {
|
.lbl-s {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
/* margin: 10px 4px 0 0; */
|
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
width: 48%;
|
width: 48%;
|
||||||
@ -1284,10 +1302,6 @@ TD .checkmark, TD .radiomark {
|
|||||||
background-color: var(--c-3);
|
background-color: var(--c-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*.selected .radiomark {
|
|
||||||
border: 1px solid var(--c-3);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/* selected list item */
|
/* selected list item */
|
||||||
.lstI.selected {
|
.lstI.selected {
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -1405,7 +1419,7 @@ TD .checkmark, TD .radiomark {
|
|||||||
.expanded {
|
.expanded {
|
||||||
display: inline-block !important;
|
display: inline-block !important;
|
||||||
}
|
}
|
||||||
.expanded .segin.hide, .expanded .presin.hide, .expanded .sbs.hide {
|
.hide, .expanded .segin.hide, .expanded .presin.hide, .expanded .sbs.hide, .expanded .frz, .expanded .g-icon {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1534,18 +1548,17 @@ TD .checkmark, TD .radiomark {
|
|||||||
#sliders .sliderbubble {
|
#sliders .sliderbubble {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.sliderwrap {
|
#sliders .sliderwrap, .sbs .sliderwrap {
|
||||||
width: calc(100% - 28px);
|
width: calc(100% - 42px);
|
||||||
|
}
|
||||||
|
#sliders .slider {
|
||||||
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
#sliders .sliderwrap {
|
#sliders .sliderwrap {
|
||||||
left: 12px;
|
left: 12px;
|
||||||
}
|
}
|
||||||
.segname {
|
.segname {
|
||||||
padding: 8px 16px;
|
max-width: calc(100% - 110px);
|
||||||
max-width: 140px;
|
|
||||||
}
|
|
||||||
.segname, .pname {
|
|
||||||
max-width: 134px;
|
|
||||||
}
|
}
|
||||||
.segt TD {
|
.segt TD {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
@ -67,12 +67,12 @@
|
|||||||
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons"></i><p class="tab-label">Peek</p></button>
|
<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="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 id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button>
|
||||||
<button onclick="window.location.href='/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
<button onclick="window.location.href=getURL('/settings');"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||||
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="briwrap">
|
<div id="briwrap">
|
||||||
<p class="hd">Brightness</p>
|
<p class="hd">Brightness</p>
|
||||||
<div class="slider" style="left:24px;">
|
<div class="slider" style="padding-right:32px;">
|
||||||
<i class="icons slider-icon" onclick="tglTheme()" style="transform: translate(-32px,5px);"></i>
|
<i class="icons slider-icon" onclick="tglTheme()" style="transform: translate(-32px,5px);"></i>
|
||||||
<div class="sliderwrap il">
|
<div class="sliderwrap il">
|
||||||
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
||||||
@ -88,7 +88,7 @@
|
|||||||
<div class ="container">
|
<div class ="container">
|
||||||
<div id="Colors" class="tabcontent">
|
<div id="Colors" class="tabcontent">
|
||||||
<div id="picker" class="noslide"></div>
|
<div id="picker" class="noslide"></div>
|
||||||
<div id="hwrap" class="slider">
|
<div id="hwrap" class="slider" style="margin-top: 20px;">
|
||||||
<div class="sliderwrap il">
|
<div class="sliderwrap il">
|
||||||
<input id="sliderH" class="noslide" oninput="fromH()" onchange="setColor(0)" max="359" min="0" type="range" value="0" step="any">
|
<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>
|
<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>
|
</div>
|
||||||
<div style="padding-bottom: 10px;">
|
<div style="padding-bottom: 10px;">
|
||||||
<button class="btn btn-xs" type="button" onclick="window.location.href=(loc?'http://'+locip:'')+'/cpal.htm'"><i class="icons btn-icon"></i></button>
|
<button class="btn btn-xs" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||||
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon"></i></button>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
@ -363,7 +363,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<button class="btn infobtn" onclick="requestJson()">Refresh</button>
|
<button class="btn infobtn" onclick="requestJson()">Refresh</button>
|
||||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||||
<button class="btn infobtn" onclick="window.open('/update','_self');">Update WLED</button>
|
<button class="btn infobtn" onclick="window.open(getURL('/update'),'_self');">Update WLED</button>
|
||||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button>
|
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
@ -379,8 +379,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="mliveview2D" class="modal">
|
<div id="mlv2D" class="modal">
|
||||||
<div id="kliveview2D" style="width:100%; height:100%">Loading...</div><br>
|
<div id="klv2D" style="width:100%; height:100%">Loading...</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="rover" class="modal">
|
<div id="rover" class="modal">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//page js
|
//page js
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
|
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
|
||||||
var hasWhite = false, hasRGB = false, hasCCT = false;
|
var hasWhite = false, hasRGB = false, hasCCT = false;
|
||||||
var nlDur = 60, nlTar = 0;
|
var nlDur = 60, nlTar = 0;
|
||||||
@ -22,11 +22,12 @@ var pN = "", pI = 0, pNum = 0;
|
|||||||
var pmt = 1, pmtLS = 0, pmtLast = 0;
|
var pmt = 1, pmtLS = 0, pmtLast = 0;
|
||||||
var lastinfo = {};
|
var lastinfo = {};
|
||||||
var isM = false, mw = 0, mh=0;
|
var isM = false, mw = 0, mh=0;
|
||||||
var ws, cpick, ranges;
|
var ws, cpick, ranges, wsRpt=0;
|
||||||
var cfg = {
|
var cfg = {
|
||||||
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
|
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
|
||||||
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
|
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
|
||||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false, css:true, hdays:false}
|
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false,
|
||||||
|
css:true, hdays:false, fxdef:true}
|
||||||
};
|
};
|
||||||
var hol = [
|
var hol = [
|
||||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||||
@ -193,21 +194,39 @@ function loadSkinCSS(cId)
|
|||||||
l.id = cId;
|
l.id = cId;
|
||||||
l.rel = 'stylesheet';
|
l.rel = 'stylesheet';
|
||||||
l.type = 'text/css';
|
l.type = 'text/css';
|
||||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
l.href = getURL('/skin.css');
|
||||||
l.media = 'all';
|
l.media = 'all';
|
||||||
h.appendChild(l);
|
h.appendChild(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
|
}
|
||||||
function onLoad()
|
function onLoad()
|
||||||
{
|
{
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
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');
|
var sett = localStorage.getItem('wledUiCfg');
|
||||||
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
||||||
@ -217,7 +236,7 @@ function onLoad()
|
|||||||
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
|
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
|
||||||
applyCfg();
|
applyCfg();
|
||||||
if (cfg.comp.hdays) { //load custom holiday list
|
if (cfg.comp.hdays) { //load custom holiday list
|
||||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", { // may be loaded from external source
|
fetch(getURL("/holidays.json"), { // may be loaded from external source
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -433,9 +452,7 @@ function loadPresets(callback = null)
|
|||||||
// afterwards
|
// afterwards
|
||||||
if (!callback && pmt == pmtLast) return;
|
if (!callback && pmt == pmtLast) return;
|
||||||
|
|
||||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
fetch(getURL('/presets.json'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -459,9 +476,7 @@ function loadPresets(callback = null)
|
|||||||
|
|
||||||
function loadPalettes(callback = null)
|
function loadPalettes(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
fetch(getURL('/json/palettes'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -483,9 +498,7 @@ function loadPalettes(callback = null)
|
|||||||
|
|
||||||
function loadFX(callback = null)
|
function loadFX(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
fetch(getURL('/json/effects'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -497,6 +510,7 @@ function loadFX(callback = null)
|
|||||||
populateEffects();
|
populateEffects();
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch((e)=>{
|
||||||
|
//setTimeout(loadFX, 250); // retry
|
||||||
showToast(e, true);
|
showToast(e, true);
|
||||||
})
|
})
|
||||||
.finally(()=>{
|
.finally(()=>{
|
||||||
@ -507,9 +521,7 @@ function loadFX(callback = null)
|
|||||||
|
|
||||||
function loadFXData(callback = null)
|
function loadFXData(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
fetch(getURL('/json/fxdata'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -524,6 +536,7 @@ function loadFXData(callback = null)
|
|||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch((e)=>{
|
||||||
fxdata = [];
|
fxdata = [];
|
||||||
|
//setTimeout(loadFXData, 250); // retry
|
||||||
showToast(e, true);
|
showToast(e, true);
|
||||||
})
|
})
|
||||||
.finally(()=>{
|
.finally(()=>{
|
||||||
@ -702,6 +715,14 @@ function populateSegments(s)
|
|||||||
let sg = gId(`seg${i}`);
|
let sg = gId(`seg${i}`);
|
||||||
let exp = sg ? (sg.classList.contains('expanded') || (i===0 && cfg.comp.segexp)) : false;
|
let exp = sg ? (sg.classList.contains('expanded') || (i===0 && cfg.comp.segexp)) : false;
|
||||||
|
|
||||||
|
// segment set icon color
|
||||||
|
let cG = "var(--c-b)";
|
||||||
|
switch (inst.set) {
|
||||||
|
case 1: cG = "var(--c-r)"; break;
|
||||||
|
case 2: cG = "var(--c-g)"; break;
|
||||||
|
case 3: cG = "var(--c-l)"; break;
|
||||||
|
}
|
||||||
|
|
||||||
let segp = `<div id="segp${i}" class="sbs">`+
|
let segp = `<div id="segp${i}" class="sbs">`+
|
||||||
`<i class="icons slider-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})"></i>`+
|
`<i class="icons slider-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})"></i>`+
|
||||||
`<div class="sliderwrap il">`+
|
`<div class="sliderwrap il">`+
|
||||||
@ -713,10 +734,11 @@ function populateSegments(s)
|
|||||||
let stoX = inst.stop;
|
let stoX = inst.stop;
|
||||||
let staY = inst.startY;
|
let staY = inst.startY;
|
||||||
let stoY = inst.stopY;
|
let stoY = inst.stopY;
|
||||||
|
let isMSeg = isM && staX<mw*mh; // 2D matrix segment
|
||||||
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`;
|
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`;
|
||||||
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`;
|
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`;
|
||||||
let rvYck = "", miYck ="";
|
let rvYck = "", miYck ="";
|
||||||
if (isM && staX<mw*mh) {
|
if (isMSeg) {
|
||||||
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`;
|
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`;
|
||||||
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`;
|
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`;
|
||||||
}
|
}
|
||||||
@ -732,36 +754,38 @@ function populateSegments(s)
|
|||||||
`<div class="sel-p"><select class="sel-p" id="seg${i}si" onchange="setSi(${i})">`+
|
`<div class="sel-p"><select class="sel-p" id="seg${i}si" onchange="setSi(${i})">`+
|
||||||
`<option value="0" ${inst.si==0?' selected':''}>BeatSin</option>`+
|
`<option value="0" ${inst.si==0?' selected':''}>BeatSin</option>`+
|
||||||
`<option value="1" ${inst.si==1?' selected':''}>WeWillRockYou</option>`+
|
`<option value="1" ${inst.si==1?' selected':''}>WeWillRockYou</option>`+
|
||||||
`<option value="2" ${inst.si==2?' selected':''}>U10_3</option>`+
|
|
||||||
`<option value="3" ${inst.si==3?' selected':''}>U14_3</option>`+
|
|
||||||
`</select></div>`+
|
`</select></div>`+
|
||||||
`</div>`;
|
`</div>`;
|
||||||
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">`+
|
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}" data-set="${inst.set}">`+
|
||||||
`<label class="check schkl">`+
|
`<label class="check schkl">`+
|
||||||
`<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>`+
|
`<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>`+
|
||||||
`<span class="checkmark"></span>`+
|
`<span class="checkmark"></span>`+
|
||||||
`</label>`+
|
`</label>`+
|
||||||
`<i class="icons e-icon frz" id="seg${i}frz" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>`+
|
|
||||||
`<div class="segname" onclick="selSegEx(${i})">`+
|
`<div class="segname" onclick="selSegEx(${i})">`+
|
||||||
|
`<i class="icons e-icon frz" id="seg${i}frz" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>`+
|
||||||
(inst.n ? inst.n : "Segment "+i) +
|
(inst.n ? inst.n : "Segment "+i) +
|
||||||
|
`<div class="pop hide" onclick="event.preventDefault();event.stopPropagation();">`+
|
||||||
|
`<i class="icons g-icon" style="color:${cG};" onclick="this.nextElementSibling.classList.toggle('hide');">ɸ${String.fromCharCode(inst.set+"A".charCodeAt(0))};</i>`+
|
||||||
|
`<div class="pop-c hide"><span style="color:var(--c-f);" onclick="setGrp(${i},0);">➊</span><span style="color:var(--c-r);" onclick="setGrp(${i},1);">➋</span><span style="color:var(--c-g);" onclick="setGrp(${i},2);">➌</span><span style="color:var(--c-l);" onclick="setGrp(${i},3);">➍</span></div>`+
|
||||||
|
`</div> `+
|
||||||
`<i class="icons edit-icon flr" id="seg${i}nedit" onclick="tglSegn(${i})"></i>`+
|
`<i class="icons edit-icon flr" id="seg${i}nedit" onclick="tglSegn(${i})"></i>`+
|
||||||
`</div>`+
|
`</div>`+
|
||||||
`<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})"></i>`+
|
`<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})"></i>`+
|
||||||
(cfg.comp.segpwr ? segp : '') +
|
(cfg.comp.segpwr ? segp : '') +
|
||||||
`<div class="segin" id="seg${i}in">`+
|
`<div class="segin" id="seg${i}in">`+
|
||||||
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
|
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=${li.arch=="esp8266"?32:64} value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
|
||||||
`<table class="infot segt">`+
|
`<table class="infot segt">`+
|
||||||
`<tr>`+
|
`<tr>`+
|
||||||
`<td>${isM&&staX<mw*mh?'Start X':'Start LED'}</td>`+
|
`<td>${isMSeg?'Start X':'Start LED'}</td>`+
|
||||||
`<td>${isM&&staX<mw*mh?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>`+
|
`<td>${isMSeg?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>`+
|
||||||
`<td>${isM&&staX<mw*mh?'':'Offset'}</td>`+
|
`<td>${isMSeg?'':'Offset'}</td>`+
|
||||||
`</tr>`+
|
`</tr>`+
|
||||||
`<tr>`+
|
`<tr>`+
|
||||||
`<td><input class="segn" id="seg${i}s" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
`<td><input class="segn" id="seg${i}s" type="number" min="0" max="${(isMSeg?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
||||||
`<td><input class="segn" id="seg${i}e" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
`<td><input class="segn" id="seg${i}e" type="number" min="0" max="${(isMSeg?mw:ledCount)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
||||||
`<td style="text-align:revert;">${isM&&staX<mw*mh?miXck+'<br>'+rvXck:''}<input class="segn ${isM&&staX<mw*mh?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>`+
|
`<td ${isMSeg?'style="text-align:revert;"':''}>${isMSeg?miXck+'<br>'+rvXck:''}<input class="segn ${isMSeg?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>`+
|
||||||
`</tr>`+
|
`</tr>`+
|
||||||
(isM && staX<mw*mh ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></td></tr>'+
|
(isMSeg ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></td></tr>'+
|
||||||
'<tr>'+
|
'<tr>'+
|
||||||
'<td><input class="segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
'<td><input class="segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||||
'<td><input class="segn" id="seg'+i+'eY" type="number" min="0" max="'+mh+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
'<td><input class="segn" id="seg'+i+'eY" type="number" min="0" max="'+mh+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||||
@ -775,15 +799,15 @@ function populateSegments(s)
|
|||||||
`<tr>`+
|
`<tr>`+
|
||||||
`<td><input class="segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
`<td><input class="segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
||||||
`<td><input class="segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
`<td><input class="segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
|
||||||
`<td style="text-align:revert;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}"></i></button></td>`+
|
`<td><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}"></i></button></td>`+
|
||||||
`</tr>`+
|
`</tr>`+
|
||||||
`</table>`+
|
`</table>`+
|
||||||
`<div class="h bp" id="seg${i}len"></div>`+
|
`<div class="h bp" id="seg${i}len"></div>`+
|
||||||
(!(isM&&staX<mw*mh) ? rvXck : '') +
|
(!isMSeg ? rvXck : '') +
|
||||||
(isM&&staX<mw*mh&&stoY-staY>1&&stoX-staX>1 ? map2D : '') +
|
(isMSeg&&stoY-staY>1&&stoX-staX>1 ? map2D : '') +
|
||||||
(s.AudioReactive && s.AudioReactive.on ? "" : sndSim) +
|
(s.AudioReactive && s.AudioReactive.on ? "" : sndSim) +
|
||||||
`<label class="check revchkl" id="seg${i}lbtm">`+
|
`<label class="check revchkl" id="seg${i}lbtm">`+
|
||||||
(isM&&staX<mw*mh?'Transpose':'Mirror effect') + (isM&&staX<mw*mh ?
|
(isMSeg?'Transpose':'Mirror effect') + (isMSeg ?
|
||||||
'<input type="checkbox" id="seg'+i+'tp" onchange="setTp('+i+')" '+(inst.tp?"checked":"")+'>':
|
'<input type="checkbox" id="seg'+i+'tp" onchange="setTp('+i+')" '+(inst.tp?"checked":"")+'>':
|
||||||
'<input type="checkbox" id="seg'+i+'mi" onchange="setMi('+i+')" '+(inst.mi?"checked":"")+'>') +
|
'<input type="checkbox" id="seg'+i+'mi" onchange="setMi('+i+')" '+(inst.mi?"checked":"")+'>') +
|
||||||
`<span class="checkmark"></span>`+
|
`<span class="checkmark"></span>`+
|
||||||
@ -802,6 +826,7 @@ function populateSegments(s)
|
|||||||
resetUtil(noNewSegs);
|
resetUtil(noNewSegs);
|
||||||
if (gId('selall')) gId('selall').checked = true;
|
if (gId('selall')) gId('selall').checked = true;
|
||||||
for (var i = 0; i <= lSeg; i++) {
|
for (var i = 0; i <= lSeg; i++) {
|
||||||
|
if (!gId(`seg${i}`)) continue;
|
||||||
updateLen(i);
|
updateLen(i);
|
||||||
updateTrail(gId(`seg${i}bri`));
|
updateTrail(gId(`seg${i}bri`));
|
||||||
gId(`segr${i}`).classList.add("hide");
|
gId(`segr${i}`).classList.add("hide");
|
||||||
@ -811,7 +836,7 @@ function populateSegments(s)
|
|||||||
gId(`segd${lSeg}`).classList.add("hide");
|
gId(`segd${lSeg}`).classList.add("hide");
|
||||||
gId(`segp0`).classList.add("hide");
|
gId(`segp0`).classList.add("hide");
|
||||||
}
|
}
|
||||||
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline";
|
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).classList.remove("hide");
|
||||||
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
|
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
|
||||||
|
|
||||||
if (Array.isArray(li.maps) && li.maps.length>1) {
|
if (Array.isArray(li.maps) && li.maps.length>1) {
|
||||||
@ -966,7 +991,7 @@ function genPalPrevCss(id)
|
|||||||
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', effectPar = '')
|
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', effectPar = '')
|
||||||
{
|
{
|
||||||
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" ${effectPar===''?'':'data-opt="'+effectPar+'" '}onClick="${clickAction}(${id})">`+
|
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" ${effectPar===''?'':'data-opt="'+effectPar+'" '}onClick="${clickAction}(${id})">`+
|
||||||
`<label class="radio schkl" onclick="event.preventDefault()">`+
|
`<label title="(${id})" class="radio schkl" onclick="event.preventDefault()">`+ // (#1984)
|
||||||
`<input type="radio" value="${id}" name="${listName}">`+
|
`<input type="radio" value="${id}" name="${listName}">`+
|
||||||
`<span class="radiomark"></span>`+
|
`<span class="radiomark"></span>`+
|
||||||
`<div class="lstIcontent">`+
|
`<div class="lstIcontent">`+
|
||||||
@ -980,10 +1005,15 @@ function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', e
|
|||||||
function btype(b)
|
function btype(b)
|
||||||
{
|
{
|
||||||
switch (b) {
|
switch (b) {
|
||||||
|
case 2:
|
||||||
case 32: return "ESP32";
|
case 32: return "ESP32";
|
||||||
|
case 3:
|
||||||
case 33: return "ESP32-S2";
|
case 33: return "ESP32-S2";
|
||||||
|
case 4:
|
||||||
case 34: return "ESP32-S3";
|
case 34: return "ESP32-S3";
|
||||||
|
case 5:
|
||||||
case 35: return "ESP32-C3";
|
case 35: return "ESP32-C3";
|
||||||
|
case 1:
|
||||||
case 82: return "ESP8266";
|
case 82: return "ESP8266";
|
||||||
}
|
}
|
||||||
return "?";
|
return "?";
|
||||||
@ -1004,8 +1034,9 @@ function populateNodes(i,n)
|
|||||||
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
|
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||||
for (var o of n.nodes) {
|
for (var o of n.nodes) {
|
||||||
if (o.name) {
|
if (o.name) {
|
||||||
var url = `<button class="btn" title="${o.ip}" onclick="location.assign('http://${o.ip}');">${bname(o)}</button>`;
|
let onoff = `<i class="icons e-icon flr ${o.type&0x80?'':'off'}" onclick="rmtTgl('${o.ip}',this);""></i>`;
|
||||||
urows += inforow(url,`${btype(o.type)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
|
var url = `<button class="btn" title="${o.ip}" onclick="location.assign('http://${o.ip}');"><div class="bname">${bname(o)}</div>${o.vid<2307130?'':onoff}</button>`;
|
||||||
|
urows += inforow(url,`${btype(o.type&0x7F)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
|
||||||
nnodes++;
|
nnodes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1021,8 +1052,7 @@ function populateNodes(i,n)
|
|||||||
|
|
||||||
function loadNodes()
|
function loadNodes()
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
fetch(getURL('/json/nodes'), {
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -1242,6 +1272,7 @@ function updateSelectedFx()
|
|||||||
// hide non-0D effects if segment only has 1 pixel (0D)
|
// hide non-0D effects if segment only has 1 pixel (0D)
|
||||||
var fxs = parent.querySelectorAll('.lstI');
|
var fxs = parent.querySelectorAll('.lstI');
|
||||||
for (const fx of fxs) {
|
for (const fx of fxs) {
|
||||||
|
if (!fx.dataset.opt) continue;
|
||||||
let opts = fx.dataset.opt.split(";");
|
let opts = fx.dataset.opt.split(";");
|
||||||
if (fx.dataset.id>0) {
|
if (fx.dataset.id>0) {
|
||||||
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
|
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
|
||||||
@ -1256,7 +1287,7 @@ function updateSelectedFx()
|
|||||||
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
||||||
for (const seg of segs) if (selectedName.indexOf("\u25A6")<0) seg.classList.remove('hide'); else seg.classList.add('hide');
|
for (const seg of segs) if (selectedName.indexOf("\u25A6")<0) seg.classList.remove('hide'); else seg.classList.add('hide');
|
||||||
var segs = gId("segcont").querySelectorAll(`div[data-snd="si"]`);
|
var segs = gId("segcont").querySelectorAll(`div[data-snd="si"]`);
|
||||||
for (const seg of segs) if (selectedName.indexOf("\u266A")<0 && selectedName.indexOf("\266B")<0) seg.classList.add('hide'); else seg.classList.remove('hide'); // also "♫ "?
|
for (const seg of segs) if (selectedName.indexOf("\u266A")<0 && selectedName.indexOf("\u266B")<0) seg.classList.add('hide'); else seg.classList.remove('hide'); // also "♫ "?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,7 +1313,8 @@ function cmpP(a, b)
|
|||||||
|
|
||||||
function makeWS() {
|
function makeWS() {
|
||||||
if (ws || lastinfo.ws < 0) return;
|
if (ws || lastinfo.ws < 0) return;
|
||||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+'://'+(loc?locip:window.location.hostname)+'/ws');
|
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||||
|
ws = new WebSocket(url);
|
||||||
ws.binaryType = "arraybuffer";
|
ws.binaryType = "arraybuffer";
|
||||||
ws.onmessage = (e)=>{
|
ws.onmessage = (e)=>{
|
||||||
if (e.data instanceof ArrayBuffer) return; // liveview packet
|
if (e.data instanceof ArrayBuffer) return; // liveview packet
|
||||||
@ -1306,11 +1338,12 @@ function makeWS() {
|
|||||||
};
|
};
|
||||||
ws.onclose = (e)=>{
|
ws.onclose = (e)=>{
|
||||||
gId('connind').style.backgroundColor = "var(--c-r)";
|
gId('connind').style.backgroundColor = "var(--c-r)";
|
||||||
setTimeout(makeWS,1500); // retry WS connection
|
if (wsRpt++ < 5) setTimeout(makeWS,1500); // retry WS connection
|
||||||
ws = null;
|
ws = null;
|
||||||
}
|
}
|
||||||
ws.onopen = (e)=>{
|
ws.onopen = (e)=>{
|
||||||
//ws.send("{'v':true}"); // unnecessary (https://github.com/Aircoookie/WLED/blob/master/wled00/ws.cpp#L18)
|
//ws.send("{'v':true}"); // unnecessary (https://github.com/Aircoookie/WLED/blob/master/wled00/ws.cpp#L18)
|
||||||
|
wsRpt = 0;
|
||||||
reqsLegal = true;
|
reqsLegal = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1368,6 +1401,8 @@ function readState(s,command=false)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s.seg.length>2) d.querySelectorAll(".pop").forEach((e)=>{e.classList.remove("hide");});
|
||||||
|
|
||||||
var cd = gId('csl').children;
|
var cd = gId('csl').children;
|
||||||
for (let e = cd.length-1; e >= 0; e--) {
|
for (let e = cd.length-1; e >= 0; e--) {
|
||||||
cd[e].dataset.r = i.col[e][0];
|
cd[e].dataset.r = i.col[e][0];
|
||||||
@ -1559,7 +1594,6 @@ function requestJson(command=null)
|
|||||||
if (command && !reqsLegal) return; // stop post requests from chrome onchange event on page restore
|
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);
|
if (!jsonTimeout) jsonTimeout = setTimeout(()=>{if (ws) ws.close(); ws=null; showErrorToast()}, 3000);
|
||||||
var req = null;
|
var req = null;
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/si';
|
|
||||||
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
||||||
var type = command ? 'post':'get';
|
var type = command ? 'post':'get';
|
||||||
if (command) {
|
if (command) {
|
||||||
@ -1580,7 +1614,7 @@ function requestJson(command=null)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(url, {
|
fetch(getURL('/json/si'), {
|
||||||
method: type,
|
method: type,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
@ -1611,6 +1645,7 @@ function requestJson(command=null)
|
|||||||
//load presets and open websocket sequentially
|
//load presets and open websocket sequentially
|
||||||
if (!pJson || isEmpty(pJson)) setTimeout(()=>{
|
if (!pJson || isEmpty(pJson)) setTimeout(()=>{
|
||||||
loadPresets(()=>{
|
loadPresets(()=>{
|
||||||
|
wsRpt = 0;
|
||||||
if (!(ws && ws.readyState === WebSocket.OPEN)) makeWS();
|
if (!(ws && ws.readyState === WebSocket.OPEN)) makeWS();
|
||||||
});
|
});
|
||||||
},25);
|
},25);
|
||||||
@ -1658,27 +1693,22 @@ function toggleSync()
|
|||||||
|
|
||||||
function toggleLiveview()
|
function toggleLiveview()
|
||||||
{
|
{
|
||||||
//WLEDSR adding liveview2D support
|
|
||||||
if (isInfo && isM) toggleInfo();
|
if (isInfo && isM) toggleInfo();
|
||||||
if (isNodes && isM) toggleNodes();
|
if (isNodes && isM) toggleNodes();
|
||||||
isLv = !isLv;
|
isLv = !isLv;
|
||||||
|
let wsOn = ws && ws.readyState === WebSocket.OPEN;
|
||||||
|
|
||||||
var lvID = "liveview";
|
var lvID = "liveview";
|
||||||
if (isM) {
|
if (isM && wsOn) {
|
||||||
lvID = "liveview2D"
|
lvID += "2D";
|
||||||
if (isLv) {
|
if (isLv) gId('klv2D').innerHTML = `<iframe id="${lvID}" src="about:blank"></iframe>`;
|
||||||
var cn = '<iframe id="liveview2D" src="about:blank"></iframe>';
|
gId('mlv2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
|
||||||
d.getElementById('kliveview2D').innerHTML = cn;
|
|
||||||
}
|
|
||||||
|
|
||||||
gId('mliveview2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gId(lvID).style.display = (isLv) ? "block":"none";
|
gId(lvID).style.display = (isLv) ? "block":"none";
|
||||||
var url = (loc?`http://${locip}`:'') + "/" + lvID;
|
gId(lvID).src = (isLv) ? getURL("/" + lvID + ((wsOn) ? "?ws":"")):"about:blank";
|
||||||
gId(lvID).src = (isLv) ? url:"about:blank";
|
gId('buttonSr').classList.toggle("active");
|
||||||
gId('buttonSr').className = (isLv) ? "active":"";
|
if (!isLv && wsOn) ws.send('{"lv":false}');
|
||||||
if (!isLv && ws && ws.readyState === WebSocket.OPEN) ws.send('{"lv":false}');
|
|
||||||
size();
|
size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1749,9 +1779,13 @@ function makeSeg()
|
|||||||
|
|
||||||
function resetUtil(off=false)
|
function resetUtil(off=false)
|
||||||
{
|
{
|
||||||
gId('segutil').innerHTML = `<div class="seg btn btn-s ${off?'off':''}" style="border-radius:24px;padding:0;">`
|
gId('segutil').innerHTML = `<div class="seg btn btn-s${off?' off':''}" style="padding:0;">`
|
||||||
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark"></span></label>'
|
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark"></span></label>'
|
||||||
+ `<div class="segname" ${off?'':'onclick="makeSeg()"'}><i class="icons btn-icon"></i>Add segment</div></div>`;
|
+ `<div class="segname" ${off?'':'onclick="makeSeg()"'}><i class="icons btn-icon"></i>Add segment</div>`
|
||||||
|
+ '<div class="pop hide" onclick="event.stopPropagation();">'
|
||||||
|
+ `<i class="icons g-icon" onclick="this.nextElementSibling.classList.toggle('hide');"></i>`
|
||||||
|
+ '<div class="pop-c hide"><span style="color:var(--c-f);" onclick="selGrp(0);">➊</span><span style="color:var(--c-r);" onclick="selGrp(1);">➋</span><span style="color:var(--c-g);" onclick="selGrp(2);">➌</span><span style="color:var(--c-l);" onclick="selGrp(3);">➍</span></div>'
|
||||||
|
+ '</div></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePlSel(el, incPl=false)
|
function makePlSel(el, incPl=false)
|
||||||
@ -2018,14 +2052,14 @@ function tglSegn(s)
|
|||||||
function selSegAll(o)
|
function selSegAll(o)
|
||||||
{
|
{
|
||||||
var obj = {"seg":[]};
|
var obj = {"seg":[]};
|
||||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":o.checked});
|
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":o.checked});
|
||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selSegEx(s)
|
function selSegEx(s)
|
||||||
{
|
{
|
||||||
var obj = {"seg":[]};
|
var obj = {"seg":[]};
|
||||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
|
for (let i=0; i<=lSeg; i++) if (gId(`seg${i}`)) obj.seg.push({"id":i,"sel":(i==s)});
|
||||||
obj.mainseg = s;
|
obj.mainseg = s;
|
||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
@ -2037,6 +2071,20 @@ function selSeg(s)
|
|||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selGrp(g)
|
||||||
|
{
|
||||||
|
event.preventDefault();
|
||||||
|
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});
|
||||||
|
if (sel) for (let s of sel||[]) {
|
||||||
|
let i = parseInt(s.id.substring(3));
|
||||||
|
obj.seg[i] = {"id":i,"sel":true};
|
||||||
|
}
|
||||||
|
if (obj.seg.length) requestJson(obj);
|
||||||
|
}
|
||||||
|
|
||||||
function rptSeg(s)
|
function rptSeg(s)
|
||||||
{
|
{
|
||||||
//TODO: 2D support
|
//TODO: 2D support
|
||||||
@ -2157,6 +2205,14 @@ function setTp(s)
|
|||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setGrp(s, g)
|
||||||
|
{
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
var obj = {"seg": {"id": s, "set": g}};
|
||||||
|
requestJson(obj);
|
||||||
|
}
|
||||||
|
|
||||||
function setSegPwr(s)
|
function setSegPwr(s)
|
||||||
{
|
{
|
||||||
var pwr = gId(`seg${s}pwr`).classList.contains('act');
|
var pwr = gId(`seg${s}pwr`).classList.contains('act');
|
||||||
@ -2188,8 +2244,7 @@ function setFX(ind = null)
|
|||||||
} else {
|
} else {
|
||||||
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
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);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2523,6 +2578,24 @@ function setBalance(b)
|
|||||||
requestJson(obj);
|
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;
|
var hc = 0;
|
||||||
setInterval(()=>{
|
setInterval(()=>{
|
||||||
if (!isInfo) return;
|
if (!isInfo) return;
|
||||||
@ -2545,7 +2618,7 @@ function cnfReset()
|
|||||||
bt.innerHTML = "Confirm Reboot";
|
bt.innerHTML = "Confirm Reboot";
|
||||||
cnfr = true; return;
|
cnfr = true; return;
|
||||||
}
|
}
|
||||||
window.location.href = "/reset";
|
window.location.href = getURL("/reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
var cnfrS = false;
|
var cnfrS = false;
|
||||||
@ -2599,9 +2672,7 @@ function loadPalettesData(callback = null)
|
|||||||
|
|
||||||
function getPalettesData(page, callback)
|
function getPalettesData(page, callback)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
fetch(getURL(`/json/palx?page=${page}`), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
|
@ -17,21 +17,17 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="canv" />
|
|
||||||
<script>
|
<script>
|
||||||
update();
|
var ws;
|
||||||
|
|
||||||
var tmout = null;
|
var tmout = null;
|
||||||
function update()
|
function update() // via HTTP (/json/live)
|
||||||
{
|
{
|
||||||
if (document.hidden) {
|
if (document.hidden) {
|
||||||
clearTimeout(tmout);
|
clearTimeout(tmout);
|
||||||
tmout = setTimeout(update, 250);
|
tmout = setTimeout(update, 250);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fetch('/json/live')
|
fetch('./json/live')
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
clearTimeout(tmout);
|
clearTimeout(tmout);
|
||||||
@ -57,8 +53,57 @@
|
|||||||
clearTimeout(tmout);
|
clearTimeout(tmout);
|
||||||
tmout = setTimeout(update, 2500);
|
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>
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="S()">
|
||||||
|
<div id="canv"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,61 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="theme-color" content="#222222">
|
|
||||||
<title>WLED Live Preview</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#canv {
|
|
||||||
background: black;
|
|
||||||
filter: brightness(175%);
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="canv"></div>
|
|
||||||
<script>
|
|
||||||
var ws;
|
|
||||||
try {
|
|
||||||
ws = top.window.ws;
|
|
||||||
} catch (e) {}
|
|
||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
||||||
//console.info("Peek uses top WS");
|
|
||||||
ws.send("{'lv':true}");
|
|
||||||
} else {
|
|
||||||
console.info("Peek WS opening");
|
|
||||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
|
||||||
ws.onopen = function () {
|
|
||||||
//console.info("Peek WS open");
|
|
||||||
ws.send("{'lv':true}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ws.binaryType = "arraybuffer";
|
|
||||||
ws.addEventListener('message', (e) => {
|
|
||||||
try {
|
|
||||||
if (toString.call(e.data) === '[object ArrayBuffer]') {
|
|
||||||
let leds = new Uint8Array(event.data);
|
|
||||||
if (leds[0] != 76) return; //'L'
|
|
||||||
let str = "linear-gradient(90deg,";
|
|
||||||
let len = leds.length;
|
|
||||||
let start = leds[1]==2 ? 4 : 2; // 1 = 1D, 2 = 1D/2D (leds[2]=w, leds[3]=h)
|
|
||||||
for (i = start; i < len; i+=3) {
|
|
||||||
str += `rgb(${leds[i]},${leds[i+1]},${leds[i+2]})`;
|
|
||||||
if (i < len -3) str += ","
|
|
||||||
}
|
|
||||||
str += ")";
|
|
||||||
document.getElementById("canv").style.background = str;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Peek WS error:",err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -33,7 +33,14 @@
|
|||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send("{'lv':true}");
|
ws.send("{'lv':true}");
|
||||||
} else {
|
} else {
|
||||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
let l = window.location;
|
||||||
|
let pathn = l.pathname;
|
||||||
|
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||||
|
let url = l.origin.replace("http","ws");
|
||||||
|
if (paths.length > 1) {
|
||||||
|
url += "/" + paths[0];
|
||||||
|
}
|
||||||
|
ws = new WebSocket(url+"/ws");
|
||||||
ws.onopen = ()=>{
|
ws.onopen = ()=>{
|
||||||
ws.send("{'lv':true}");
|
ws.send("{'lv':true}");
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<title>WLED Message</title>
|
<title>WLED Message</title>
|
||||||
<script>
|
<script>
|
||||||
function B() { window.history.back() };
|
function B() { window.history.back() };
|
||||||
function RS() { window.location = "/settings"; }
|
function RS() { window.location = "../settings"; }
|
||||||
function RP() { top.location.href = "/"; }
|
function RP() { top.location.href = "../"; }
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@import url("style.css");
|
@import url("style.css");
|
||||||
|
2026
wled00/data/pxmagic/pxmagic.htm
Normal file
2026
wled00/data/pxmagic/pxmagic.htm
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
|||||||
<title>WLED Settings</title>
|
<title>WLED Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
function loadJS(FILE_URL, async = true) {
|
function loadJS(FILE_URL, async = true) {
|
||||||
@ -27,16 +27,28 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 1) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=0';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=0'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@ -65,15 +77,15 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body onload="S()">
|
<body onload="S()">
|
||||||
<button type=submit id="b" onclick="window.location='/'">Back</button>
|
<button type=submit id="b" onclick="window.location=getURL('/')">Back</button>
|
||||||
<button type="submit" onclick="window.location='./settings/wifi'">WiFi Setup</button>
|
<button type="submit" onclick="window.location=getURL('/settings/wifi')">WiFi Setup</button>
|
||||||
<button type="submit" onclick="window.location='./settings/leds'">LED Preferences</button>
|
<button type="submit" onclick="window.location=getURL('/settings/leds')">LED Preferences</button>
|
||||||
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location='./settings/2D'">2D Configuration</button>
|
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
|
||||||
<button type="submit" onclick="window.location='./settings/ui'">User Interface</button>
|
<button type="submit" onclick="window.location=getURL('/settings/ui')">User Interface</button>
|
||||||
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location='./settings/dmx'">DMX Output</button>
|
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/dmx')">DMX Output</button>
|
||||||
<button type="submit" onclick="window.location='./settings/sync'">Sync Interfaces</button>
|
<button type="submit" onclick="window.location=getURL('/settings/sync')">Sync Interfaces</button>
|
||||||
<button type="submit" onclick="window.location='./settings/time'">Time & Macros</button>
|
<button type="submit" onclick="window.location=getURL('/settings/time')">Time & Macros</button>
|
||||||
<button type="submit" onclick="window.location='./settings/um'">Usermods</button>
|
<button type="submit" onclick="window.location=getURL('/settings/um')">Usermods</button>
|
||||||
<button type="submit" onclick="window.location='./settings/sec'">Security & Updates</button>
|
<button type="submit" onclick="window.location=getURL('/settings/sec')">Security & Updates</button>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -7,11 +7,11 @@
|
|||||||
<title>2D Set-up</title>
|
<title>2D Set-up</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var maxPanels=64;
|
var maxPanels=64;
|
||||||
var ctx = null; // WLEDMM
|
var ctx = null; // WLEDMM
|
||||||
function H(){window.open("https://kno.wled.ge/features/2D");}
|
function H(){window.open("https://kno.wled.ge/features/2D");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
function fS(){d.Sf.submit();} // <button type=submit> sometimes didn't work
|
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
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -35,16 +35,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=10'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/2D');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
function UI() {
|
function UI() {
|
||||||
@ -322,7 +335,7 @@ Y:<input name="P${i}Y" type="number" min="0" max="255" value="0" oninput="UI()">
|
|||||||
<option value="1">Vertical</option>
|
<option value="1">Vertical</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
Serpentine: <input type="checkbox" name="PS"><br>
|
Serpentine: <input type="checkbox" name="PS"><br>
|
||||||
<i style="color:#fa0;">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<br>
|
<i class="warn">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<br>
|
||||||
WARNING: You may need to update each panel parameters after they are generated.</i><br>
|
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>
|
<button type="button" onclick="gen();expand(gId('expGen'),gId('mxGen'));">Populate</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
<title>DMX Settings</title>
|
<title>DMX Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
|
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
|
||||||
function B(){window.history.back();}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function GCH(num) {
|
function GCH(num) {
|
||||||
d.getElementById('dmxchannels').innerHTML += "";
|
d.getElementById('dmxchannels').innerHTML += "";
|
||||||
for (i=0;i<num;i++) {
|
for (i=0;i<num;i++) {
|
||||||
@ -54,16 +54,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S(){
|
function S(){
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=7';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=7'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/dmx');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
d.um_p = [];
|
d.um_p = [];
|
||||||
d.rsvd = [];
|
d.rsvd = [];
|
||||||
d.ro_gpio = [];
|
d.ro_gpio = [];
|
||||||
d.max_gpio = 39;
|
d.max_gpio = 50;
|
||||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
function off(n){d.getElementsByName(n)[0].value = -1;}
|
function off(n){d.getElementsByName(n)[0].value = -1;}
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -26,8 +26,12 @@
|
|||||||
d.body.appendChild(scE);
|
d.body.appendChild(scE);
|
||||||
// success event
|
// success event
|
||||||
scE.addEventListener("load", () => {
|
scE.addEventListener("load", () => {
|
||||||
GetV();checkSi();setABL();
|
GetV();
|
||||||
|
checkSi();
|
||||||
|
setABL();
|
||||||
|
d.Sf.addEventListener("submit", trySubmit);
|
||||||
if (d.um_p[0]==-1) d.um_p.shift();
|
if (d.um_p[0]==-1) d.um_p.shift();
|
||||||
|
pinDropdowns();
|
||||||
});
|
});
|
||||||
// error event
|
// error event
|
||||||
scE.addEventListener("error", (ev) => {
|
scE.addEventListener("error", (ev) => {
|
||||||
@ -49,7 +53,7 @@
|
|||||||
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
||||||
}
|
}
|
||||||
function pinsOK() {
|
function pinsOK() {
|
||||||
var LCs = d.getElementsByTagName("input");
|
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||||
for (i=0; i<LCs.length; i++) {
|
for (i=0; i<LCs.length; i++) {
|
||||||
var nm = LCs[i].name.substring(0,2);
|
var nm = LCs[i].name.substring(0,2);
|
||||||
// ignore IP address
|
// ignore IP address
|
||||||
@ -59,23 +63,36 @@
|
|||||||
if (t>=80) continue;
|
if (t>=80) continue;
|
||||||
}
|
}
|
||||||
//check for pin conflicts
|
//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") {
|
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||||
var p = []; // used pin array
|
var p = d.rsvd.concat(d.um_p); // used pin array
|
||||||
for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations
|
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||||
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))) {
|
||||||
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;}
|
alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);
|
||||||
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;}
|
LCs[i].value="";
|
||||||
for (j=i+1; j<LCs.length; j++)
|
LCs[i].focus();
|
||||||
{
|
return false;
|
||||||
|
}
|
||||||
|
else if (/*!(nm == "IR" || nm=="BT") &&*/ d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))) {
|
||||||
|
alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);
|
||||||
|
LCs[i].value="";
|
||||||
|
LCs[i].focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (j=i+1; j<LCs.length; j++) {
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
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") {
|
if (n2.substring(0,1)==="L") {
|
||||||
var m = LCs[j].name.substring(2);
|
var m = LCs[j].name.substring(2);
|
||||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||||
if (t2>=80) continue;
|
if (t2>=80) continue;
|
||||||
}
|
}
|
||||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);LCs[j].value="";LCs[j].focus();return false;}
|
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {
|
||||||
|
alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);
|
||||||
|
LCs[j].value="";
|
||||||
|
LCs[j].focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,6 +113,7 @@
|
|||||||
gId('abl').style.display = (en) ? 'inline':'none';
|
gId('abl').style.display = (en) ? 'inline':'none';
|
||||||
gId('psu2').style.display = (en) ? 'inline':'none';
|
gId('psu2').style.display = (en) ? 'inline':'none';
|
||||||
if (d.Sf.LA.value > 0) setABL();
|
if (d.Sf.LA.value > 0) setABL();
|
||||||
|
UI();
|
||||||
}
|
}
|
||||||
function enLA()
|
function enLA()
|
||||||
{
|
{
|
||||||
@ -117,28 +135,28 @@
|
|||||||
default: gId('LAdis').style.display = 'inline';
|
default: gId('LAdis').style.display = 'inline';
|
||||||
}
|
}
|
||||||
gId('m1').innerHTML = maxM;
|
gId('m1').innerHTML = maxM;
|
||||||
d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
|
|
||||||
UI();
|
|
||||||
}
|
}
|
||||||
//returns mem usage
|
//returns mem usage
|
||||||
function getMem(t, n) {
|
function getMem(t, n) {
|
||||||
let len = parseInt(d.getElementsByName("LC"+n)[0].value);
|
let len = parseInt(d.getElementsByName("LC"+n)[0].value);
|
||||||
len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too
|
len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too
|
||||||
|
let dbl = 0;
|
||||||
|
if (d.Sf.LD.checked) dbl = len * 3; // double buffering
|
||||||
if (t < 32) {
|
if (t < 32) {
|
||||||
if (t==26 || t==29) len *= 2; // 16 bit LEDs
|
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 (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem
|
||||||
if (t > 28) return len*20; //RGBW
|
if (t > 28) return len*20 + dbl; //RGBW
|
||||||
return len*15;
|
return len*15 + dbl;
|
||||||
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
||||||
{
|
{
|
||||||
if (t > 28) return len*8; //RGBW
|
if (t > 28) return len*8 + dbl; //RGBW
|
||||||
return len*6;
|
return len*6 + dbl;
|
||||||
}
|
}
|
||||||
if (t > 28) return len*4; //RGBW
|
if (t > 28) return len*4 + dbl; //RGBW
|
||||||
return len*3;
|
return len*3 + dbl;
|
||||||
}
|
}
|
||||||
if (t > 31 && t < 48) return 5;
|
if (t > 31 && t < 48) return 5; // analog
|
||||||
return len*3;
|
return len*3 + dbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
function UI(change=false)
|
function UI(change=false)
|
||||||
@ -151,15 +169,13 @@
|
|||||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||||
|
|
||||||
// enable/disable LED fields
|
// enable/disable LED fields
|
||||||
var s = d.getElementsByTagName("select");
|
d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((s)=>{
|
||||||
for (i=0; i<s.length; i++) {
|
|
||||||
// is the field a LED type?
|
// is the field a LED type?
|
||||||
if (s[i].name.substring(0,2)=="LT") {
|
var n = s.name.substring(2);
|
||||||
var n = s[i].name.substring(2);
|
var t = parseInt(s.value);
|
||||||
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("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:" : "";
|
gId("p1d"+n).innerHTML = (t> 49 && t<64) ? "Clk GPIO:" : "";
|
||||||
var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
//var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
||||||
|
|
||||||
memu += getMem(t, n); // calc memory
|
memu += getMem(t, n); // calc memory
|
||||||
|
|
||||||
@ -196,8 +212,7 @@
|
|||||||
gId("dig"+n+"l").style.display = (t > 48 && t < 64) ? "inline":"none"; // bus clock speed
|
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("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
|
gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description
|
||||||
}
|
});
|
||||||
}
|
|
||||||
// display global white channel overrides
|
// display global white channel overrides
|
||||||
gId("wc").style.display = (gRGBW) ? 'inline':'none';
|
gId("wc").style.display = (gRGBW) ? 'inline':'none';
|
||||||
if (!gRGBW) {
|
if (!gRGBW) {
|
||||||
@ -205,7 +220,7 @@
|
|||||||
d.Sf.CR.checked = false;
|
d.Sf.CR.checked = false;
|
||||||
}
|
}
|
||||||
// check for pin conflicts
|
// check for pin conflicts
|
||||||
var LCs = d.getElementsByTagName("input");
|
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||||
var sLC = 0, sPC = 0, maxLC = 0;
|
var sLC = 0, sPC = 0, maxLC = 0;
|
||||||
for (i=0; i<LCs.length; i++) {
|
for (i=0; i<LCs.length; i++) {
|
||||||
var nm = LCs[i].name.substring(0,2); // field name
|
var nm = LCs[i].name.substring(0,2); // field name
|
||||||
@ -243,15 +258,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check for pin conflicts
|
// 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") {
|
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||||
var p = []; // used pin array
|
var p = d.rsvd.concat(d.um_p); // used pin array
|
||||||
for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations
|
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||||
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++) {
|
for (j=0; j<LCs.length; j++) {
|
||||||
if (i==j) continue;
|
if (i==j) continue;
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
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") {
|
if (n2.substring(0,1)==="L") {
|
||||||
var m = LCs[j].name.substring(2);
|
var m = LCs[j].name.substring(2);
|
||||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||||
@ -261,13 +275,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// now check for conflicts
|
// now check for conflicts
|
||||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color=d.ro_gpio.some((e)=>e==parseInt(LCs[i].value,10))?"orange":"#fff";
|
if (p.some((e)=>e==parseInt(LCs[i].value))) LCs[i].style.color="red"; else LCs[i].style.color=d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))?"orange":"#fff";
|
||||||
}
|
}
|
||||||
// check buttons, IR & relay
|
// check buttons, IR & relay
|
||||||
if (nm=="IR" || nm=="BT" || nm=="RL") {
|
//if (nm=="IR" || nm=="BT" || nm=="RL") {
|
||||||
LCs[i].max = d.max_gpio;
|
// LCs[i].max = d.max_gpio;
|
||||||
LCs[i].min = -1;
|
// LCs[i].min = -1;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
// update total led count
|
// update total led count
|
||||||
gId("lc").textContent = sLC;
|
gId("lc").textContent = sLC;
|
||||||
@ -366,11 +380,11 @@ ${i+1}:
|
|||||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />
|
<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 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>
|
</div>
|
||||||
<span id="p0d${i}">GPIO:</span> <input type="number" name="L0${i}" required class="s" onchange="UI()"/>
|
<span id="p0d${i}">GPIO:</span><input type="number" name="L0${i}" required class="s" onchange="UI();pinUpd(this);"/>
|
||||||
<span id="p1d${i}"></span><input type="number" name="L1${i}" class="s" onchange="UI()"/>
|
<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()"/>
|
<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()"/>
|
<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()"/>
|
<span id="p4d${i}"></span><input type="number" name="L4${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||||
<div id="dig${i}r" style="display:inline"><br><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div>
|
<div id="dig${i}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}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>
|
<div id="dig${i}f" style="display:inline"><br>Off Refresh: <input id="rf${i}" type="checkbox" name="RF${i}"></div>
|
||||||
@ -546,17 +560,126 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function 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() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=2';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=2'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/leds');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
@ -576,7 +699,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||||
<div id="abl">
|
<div id="abl">
|
||||||
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||||
<div id="ampwarning" style="color: orange; display: none;">
|
<div id="ampwarning" class="warn" style="display: none;">
|
||||||
⚠ Your power supply provides high current.<br>
|
⚠ Your power supply provides high current.<br>
|
||||||
To improve the safety of your setup,<br>
|
To improve the safety of your setup,<br>
|
||||||
please use thick cables,<br>
|
please use thick cables,<br>
|
||||||
@ -604,14 +727,14 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
<button type="button" id="-" onclick="addLEDs(-1,false)">-</button><br>
|
<button type="button" id="-" onclick="addLEDs(-1,false)">-</button><br>
|
||||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<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="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||||
<div id="ledwarning" style="color: orange; display: none;">
|
<div id="ledwarning" class="warn" style="display: none;">
|
||||||
⚠ You might run into stability or lag issues.<br>
|
⚠ 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>
|
Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br>
|
||||||
</div>
|
</div>
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
Make a segment for each output: <input type="checkbox" name="MS"><br>
|
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>
|
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br>
|
||||||
Use global LED buffer: <input type="checkbox" name="LD"><br>
|
Use global LED buffer: <input type="checkbox" name="LD" onchange="UI()"><br>
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<div id="color_order_mapping">
|
<div id="color_order_mapping">
|
||||||
Color Order Override:
|
Color Order Override:
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<title>PIN required</title>
|
<title>PIN required</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open("../settings","_self"); }
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@import url("style.css");
|
@import url("style.css");
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
<title>Misc Settings</title>
|
<title>Misc Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
|
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
function U() { window.open("/update","_self"); }
|
function U() { window.open(getURL("/update"),"_self"); }
|
||||||
function gId(s) { return d.getElementById(s); }
|
function gId(s) { return d.getElementById(s); }
|
||||||
function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); }
|
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
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -47,7 +47,7 @@
|
|||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
|
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
|
||||||
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
||||||
req.open("POST", "/upload");
|
req.open("POST", getURL("/upload"));
|
||||||
var formData = new FormData();
|
var formData = new FormData();
|
||||||
formData.append("data", fO.files[0], name);
|
formData.append("data", fO.files[0], name);
|
||||||
req.send(formData);
|
req.send(formData);
|
||||||
@ -65,16 +65,33 @@
|
|||||||
x.setAttribute("download","wled_" + x.getAttribute("download") + (sd=="WLED"?"":("_" +sd)));
|
x.setAttribute("download","wled_" + x.getAttribute("download") + (sd=="WLED"?"":("_" +sd)));
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=6';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
if (loc) {
|
||||||
|
gId("bckcfg").setAttribute('href',getURL(gId("bckcfg").pathname));
|
||||||
|
gId("bckpresets").setAttribute('href',getURL(gId("bckpresets").pathname));
|
||||||
|
}
|
||||||
|
loadJS(getURL('/settings/s.js?p=6'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/sec');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@ -89,7 +106,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h2>Security & Update setup</h2>
|
<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>
|
Settings PIN: <input type="password" id="PIN" name="PIN" size="4" maxlength="4" minlength="4" onkeydown="checkNum(this)" pattern="[0-9]*" inputmode="numeric" title="Please enter a 4 digit number"><br>
|
||||||
<div style="color: #fa0;">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
<div class="warn">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
||||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||||
Passphrase: <input type="password" name="OP" maxlength="32"><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>
|
To enable OTA, for security reasons you need to also enter the correct password!<br>
|
||||||
@ -99,7 +116,7 @@
|
|||||||
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
|
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
|
||||||
Factory reset: <input type="checkbox" name="RS"><br>
|
Factory reset: <input type="checkbox" name="RS"><br>
|
||||||
All settings and presets will be erased.<br><br>
|
All settings and presets will be erased.<br><br>
|
||||||
<div style="color: #fa0;">⚠ Unencrypted transmission. An attacker on the same network can intercept form data!</div>
|
<div class="warn">⚠ Unencrypted transmission. An attacker on the same network can intercept form data!</div>
|
||||||
<hr>
|
<hr>
|
||||||
<h3>Software Update</h3>
|
<h3>Software Update</h3>
|
||||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||||
@ -110,7 +127,7 @@
|
|||||||
<div>Restore presets<br><input type="file" name="data" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data,'/presets.json');">Upload</button><br></div><br>
|
<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>
|
<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>Restore configuration<br><input type="file" name="data2" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data2,'/cfg.json');">Upload</button><br></div>
|
||||||
<div style="color: #fa0;">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
<div class="warn">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||||
Incorrect configuration may require a factory reset or re-flashing of your ESP.</div>
|
Incorrect configuration may require a factory reset or re-flashing of your ESP.</div>
|
||||||
For security reasons, passwords are not backed up.
|
For security reasons, passwords are not backed up.
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Sync Settings</title>
|
<title>Sync Settings</title>
|
||||||
<script>var d=document;
|
<script>var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function gId(s){return d.getElementById(s);}
|
function gId(s){return d.getElementById(s);}
|
||||||
function toggle(el){gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide");}
|
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 H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
|
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;} }
|
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
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -56,16 +56,28 @@
|
|||||||
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
function 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 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(){
|
function S(){
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let paths = l.pathname.slice(1,l.pathname.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=4';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=4'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/sync');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
@ -172,7 +184,7 @@ Realtime LED offset: <input name="WO" type="number" min="-255" max="255" require
|
|||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<h3>Alexa Voice Assistant</h3>
|
<h3>Alexa Voice Assistant</h3>
|
||||||
<div id="NoAlexa" class="hide">
|
<div id="NoAlexa" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include Alexa support.<br></em><br>
|
<i class="warn">This firmware build does not include Alexa support.<br></i><br>
|
||||||
</div>
|
</div>
|
||||||
<div id="Alexa">
|
<div id="Alexa">
|
||||||
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||||
@ -180,7 +192,7 @@ Alexa invocation name: <input type="text" name="AI" maxlength="32"><br>
|
|||||||
Also emulate devices to call the first <input name="AP" type="number" class="s" min="0" max="9" required> presets<br><br>
|
Also emulate devices to call the first <input name="AP" type="number" class="s" min="0" max="9" required> presets<br><br>
|
||||||
</div>
|
</div>
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<div style="color: #fa0;">⚠ <b>MQTT and Hue sync all connect to external hosts!<br>
|
<div class="warn">⚠ <b>MQTT and Hue sync all connect to external hosts!<br>
|
||||||
This may impact the responsiveness of WLED.</b><br>
|
This may impact the responsiveness of WLED.</b><br>
|
||||||
</div>
|
</div>
|
||||||
For best results, only use one of these services at a time.<br>
|
For best results, only use one of these services at a time.<br>
|
||||||
@ -188,7 +200,7 @@ For best results, only use one of these services at a time.<br>
|
|||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<h3>MQTT</h3>
|
<h3>MQTT</h3>
|
||||||
<div id="NoMQTT" class="hide">
|
<div id="NoMQTT" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include MQTT support.<br></em>
|
<i class="warn">This firmware build does not include MQTT support.<br></i>
|
||||||
</div>
|
</div>
|
||||||
<div id="MQTT">
|
<div id="MQTT">
|
||||||
Enable MQTT: <input type="checkbox" name="MQ"><br>
|
Enable MQTT: <input type="checkbox" name="MQ"><br>
|
||||||
@ -202,11 +214,12 @@ Client ID: <input type="text" name="MQCID" maxlength="40"><br>
|
|||||||
Device Topic: <input type="text" name="MD" maxlength="32"><br>
|
Device Topic: <input type="text" name="MD" maxlength="32"><br>
|
||||||
Group Topic: <input type="text" name="MG" maxlength="32"><br>
|
Group Topic: <input type="text" name="MG" maxlength="32"><br>
|
||||||
Publish on button press: <input type="checkbox" name="BM"><br>
|
Publish on button press: <input type="checkbox" name="BM"><br>
|
||||||
|
Retain brightness & color messages: <input type="checkbox" name="RT"><br>
|
||||||
<i>Reboot required to apply changes. </i><a href="https://kno.wled.ge/interfaces/mqtt/" target="_blank">MQTT info</a>
|
<i>Reboot required to apply changes. </i><a href="https://kno.wled.ge/interfaces/mqtt/" target="_blank">MQTT info</a>
|
||||||
</div>
|
</div>
|
||||||
<h3>Philips Hue</h3>
|
<h3>Philips Hue</h3>
|
||||||
<div id="NoHue" class="hide">
|
<div id="NoHue" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include Philips Hue support.<br></em>
|
<em class="warn">This firmware build does not include Philips Hue support.<br></em>
|
||||||
</div>
|
</div>
|
||||||
<div id="Hue">
|
<div id="Hue">
|
||||||
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
<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>
|
<title>Time Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var el=false;
|
var el=false;
|
||||||
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
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 H() { window.open("https://kno.wled.ge/features/settings/#time-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
function gId(s) { return d.getElementById(s); }
|
function gId(s) { return d.getElementById(s); }
|
||||||
function gN(s) { return d.getElementsByName(s)[0]; }
|
function gN(s) { return d.getElementsByName(s)[0]; }
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -33,16 +33,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=5';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=5'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/time');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
function expand(o,i)
|
function expand(o,i)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<title>UI Settings</title>
|
<title>UI Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var initial_ds, initial_st, initial_su;
|
var initial_ds, initial_st, initial_su;
|
||||||
var sett = null;
|
var sett = null;
|
||||||
var l = {
|
var l = {
|
||||||
@ -26,7 +26,8 @@
|
|||||||
"segpwr": "Hide segment power & brightness",
|
"segpwr": "Hide segment power & brightness",
|
||||||
"segexp" : "Always expand first segment",
|
"segexp" : "Always expand first segment",
|
||||||
"css": "Enable custom CSS",
|
"css": "Enable custom CSS",
|
||||||
"hdays": "Enable custom Holidays list"
|
"hdays": "Enable custom Holidays list",
|
||||||
|
"fxdef": "Use effect default parameters"
|
||||||
},
|
},
|
||||||
"theme":{
|
"theme":{
|
||||||
"alpha": {
|
"alpha": {
|
||||||
@ -185,21 +186,33 @@
|
|||||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S()
|
function S() {
|
||||||
{
|
let l = window.location;
|
||||||
if (window.location.protocol == "file:") {
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=3';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=3'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/ui');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
|
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
function UI()
|
function UI()
|
||||||
{
|
{
|
||||||
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
|
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
|
||||||
@ -249,7 +262,7 @@
|
|||||||
Server description: <input type="text" name="DS" maxlength="32"><br>
|
Server description: <input type="text" name="DS" maxlength="32"><br>
|
||||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
||||||
<div id="NoSimple" class="hide">
|
<div id="NoSimple" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include simplified UI support.<br></em>
|
<i class="warn">This firmware build does not include simplified UI support.<br></i>
|
||||||
</div>
|
</div>
|
||||||
<div id="Simple">Enable simplified UI: <input type="checkbox" name="SU"><br></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>
|
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
|
||||||
|
@ -7,19 +7,20 @@
|
|||||||
<title>Usermod Settings</title>
|
<title>Usermod Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
d.max_gpio = 39;
|
d.max_gpio = 50;
|
||||||
d.um_p = [];
|
d.um_p = [];
|
||||||
d.rsvd = [];
|
d.rsvd = [];
|
||||||
d.ro_gpio = [];
|
d.ro_gpio = [];
|
||||||
|
d.extra = [];
|
||||||
var umCfg = {};
|
var umCfg = {};
|
||||||
var pins = [], pinO = [], owner;
|
var pins = [], pinO = [], owner;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var urows;
|
var urows;
|
||||||
var numM = 0;
|
var numM = 0;
|
||||||
function gId(s) { return d.getElementById(s); }
|
function gId(s) { return d.getElementById(s); }
|
||||||
function isO(i) { return (i && typeof i === 'object' && !Array.isArray(i)); }
|
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 H() { window.open("https://github.com/Aircoookie/WLED/wiki/Settings#usermod-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
function loadJS(FILE_URL, async = true) {
|
function loadJS(FILE_URL, async = true) {
|
||||||
let scE = d.createElement("script");
|
let scE = d.createElement("script");
|
||||||
@ -30,15 +31,11 @@
|
|||||||
// success event
|
// success event
|
||||||
scE.addEventListener("load", () => {
|
scE.addEventListener("load", () => {
|
||||||
GetV();
|
GetV();
|
||||||
for (let k=0; k<d.rsvd.length; k++) { pins.push(d.rsvd[k]); pinO.push("rsvd"); }
|
for (let r of d.rsvd) { pins.push(r); pinO.push("rsvd"); } // reserved pins
|
||||||
if (d.um_p[0]==-1) d.um_p.shift();
|
if (d.um_p[0]==-1) d.um_p.shift(); // remove filler
|
||||||
d.Sf.SDA.max = d.max_gpio;
|
d.Sf.SDA.max = d.Sf.SCL.max = d.Sf.MOSI.max = d.Sf.SCLK.max = d.Sf.MISO.max = d.max_gpio;
|
||||||
d.Sf.SCL.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;
|
||||||
d.Sf.MOSI.max = d.max_gpio;
|
pinDropdowns(); // convert INPUT to SELECT for pins
|
||||||
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
|
// error event
|
||||||
scE.addEventListener("error", (ev) => {
|
scE.addEventListener("error", (ev) => {
|
||||||
@ -47,21 +44,36 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ldS();
|
ldS();
|
||||||
if (!numM) gId("um").innerHTML = "No Usermods installed.";
|
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
|
// 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 isF(n) { return n === +n && n !== (n|0); }
|
||||||
function isI(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
|
function check(o,k) { // input object, pin owner key
|
||||||
|
/* no longer necessary with pin dropdown fields
|
||||||
var n = o.name.replace("[]","").substr(-3);
|
var n = o.name.replace("[]","").substr(-3);
|
||||||
if (o.type=="number" && n.substr(0,3)=="pin") {
|
if (o.type=="number" && n.substr(0,3)=="pin") {
|
||||||
for (var i=0; i<pins.length; i++) {
|
for (var i=0; i<pins.length; i++) {
|
||||||
@ -84,13 +96,16 @@
|
|||||||
if (o.value==pins[i] || o.value<-1 || o.value>d.max_gpio) { o.style.color="red"; break; } else o.style.color=d.ro_gpio.some((e)=>e==parseInt(o.value,10))?"orange":"#fff";
|
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) {
|
function getPins(o) {
|
||||||
if (isO(o)) {
|
if (isO(o)) {
|
||||||
for (const [k,v] of Object.entries(o)) {
|
for (const [k,v] of Object.entries(o)) {
|
||||||
if (isO(v)) {
|
if (isO(v)) {
|
||||||
|
let oldO = owner; // keep parent name
|
||||||
owner = k;
|
owner = k;
|
||||||
getPins(v);
|
getPins(v);
|
||||||
|
owner = oldO;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.replace("[]","").substr(-3)=="pin") {
|
if (k.replace("[]","").substr(-3)=="pin") {
|
||||||
@ -149,11 +164,76 @@
|
|||||||
urows += `<input type="${t==="int"?"number":t}" name="${k}:${f}${a?"[]":""}" ${c} oninput="check(this,'${k.substr(k.indexOf(":")+1)}')"><br>`;
|
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
|
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
||||||
function addDropdown(um,fld) {
|
function addDropdown(um,fld) {
|
||||||
let sel = d.createElement('select');
|
let sel = d.createElement('select');
|
||||||
let arr = d.getElementsByName(um+":"+fld);
|
if (typeof(fld) === "string") { // parameter from usermod (field name)
|
||||||
let inp = arr[1]; // assume 1st field to be hidden (type)
|
if (fld.includes("pin")) sel.classList.add("pin");
|
||||||
|
um += ":"+fld;
|
||||||
|
} else if (typeof(fld) === "number") sel.classList.add("pin"); // a hack to add a class
|
||||||
|
let arr = d.getElementsByName(um);
|
||||||
|
let idx = arr[0].type==="hidden"?1:0; // ignore hidden field
|
||||||
|
if (arr.length > 2) {
|
||||||
|
// we have array of values (usually pins)
|
||||||
|
for (let i of arr) {
|
||||||
|
if (i.type === "number") break;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let inp = arr[idx];
|
||||||
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||||
let v = inp.value;
|
let v = inp.value;
|
||||||
let n = inp.name;
|
let n = inp.name;
|
||||||
@ -162,11 +242,12 @@
|
|||||||
var att = inp.attributes[i];
|
var att = inp.attributes[i];
|
||||||
// type and value don't apply, so skip them
|
// type and value don't apply, so skip them
|
||||||
// ** you might also want to skip style, or others -- modify as needed **
|
// ** you might also want to skip style, or others -- modify as needed **
|
||||||
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style') {
|
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style' && att.name != 'oninput' && att.name != 'max' && att.name != 'min') {
|
||||||
sel.setAttribute(att.name, att.value);
|
sel.setAttribute(att.name, att.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sel.setAttribute("data-val", v);
|
sel.setAttribute("data-val", v);
|
||||||
|
sel.setAttribute("onchange", "UI(this)");
|
||||||
// finally, replace the old input element with the new select element
|
// finally, replace the old input element with the new select element
|
||||||
inp.parentElement.replaceChild(sel, inp);
|
inp.parentElement.replaceChild(sel, inp);
|
||||||
return sel;
|
return sel;
|
||||||
@ -183,6 +264,7 @@
|
|||||||
let c = sel.childNodes[i];
|
let c = sel.childNodes[i];
|
||||||
if (c.value == sel.dataset.val) sel.selectedIndex = 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
|
// https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript
|
||||||
function addInfo(name,el,txt, txt2="") {
|
function addInfo(name,el,txt, txt2="") {
|
||||||
@ -194,10 +276,13 @@
|
|||||||
if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + ' '); //add pre texts
|
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
|
// load settings and insert values into DOM
|
||||||
function ldS() {
|
function ldS() {
|
||||||
var url = (loc?`http://${locip}`:'') + '/cfg.json';
|
fetch(getURL('/cfg.json'), {
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -216,8 +301,7 @@
|
|||||||
}
|
}
|
||||||
if (urows==="") urows = "Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults.";
|
if (urows==="") urows = "Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults.";
|
||||||
gId("um").innerHTML = urows;
|
gId("um").innerHTML = urows;
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=8';
|
loadJS(getURL('/settings/s.js?p=8'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
|
||||||
})
|
})
|
||||||
.catch((error)=>{
|
.catch((error)=>{
|
||||||
gId('lserr').style.display = "inline";
|
gId('lserr').style.display = "inline";
|
||||||
@ -242,15 +326,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<h2>Usermod Setup</h2>
|
<h2>Usermod Setup</h2>
|
||||||
Global I<sup>2</sup>C GPIOs (HW)<br>
|
Global I<sup>2</sup>C GPIOs (HW)<br>
|
||||||
<i style="color: orange;">(only changable on ESP32, change requires reboot!)</i><br>
|
<i class="warn">(change requires reboot!)</i><br>
|
||||||
SDA:<input type="number" min="-1" max="48" name="SDA" onchange="check(this,'if')" class="s" placeholder="SDA">
|
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">
|
SCL:<input type="number" min="-1" max="48" name="SCL" onchange="check(this,'if')" class="s" placeholder="SCL">
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
Global SPI GPIOs (HW)<br>
|
Global SPI GPIOs (HW)<br>
|
||||||
<i style="color: orange;">(only changable on ESP32, change requires reboot!)</i><br>
|
<i class="warn">(only changable on ESP32, change requires reboot!)</i><br>
|
||||||
MOSI:<input type="number" min="-1" max="48" name="MOSI" onchange="check(this,'if')" class="s" placeholder="MOSI">
|
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">
|
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">
|
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>
|
<div id="um">Loading settings...</div>
|
||||||
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -7,21 +7,19 @@
|
|||||||
<title>WiFi Settings</title>
|
<title>WiFi Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var scanLoops = 0, preScanSSID = "";
|
var scanLoops = 0, preScanSSID = "";
|
||||||
|
|
||||||
function gId(e) { return d.getElementById(e); }
|
function gId(e) { return d.getElementById(e); }
|
||||||
function cE(e) { return d.createElement(e); }
|
function cE(e) { return d.createElement(e); }
|
||||||
function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");}
|
function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function N() {
|
function N() {
|
||||||
const url = (loc?`http://${locip}`:"") + "/json/net";
|
|
||||||
|
|
||||||
const button = gId("scan");
|
const button = gId("scan");
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
button.innerHTML = "Scanning...";
|
button.textContent = "Scanning...";
|
||||||
|
|
||||||
fetch(url).then((response) => {
|
fetch(getURL("/json/net")).then((response) => {
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then((json) => {
|
}).then((json) => {
|
||||||
// Get the list of networks only, defaulting to an empty array.
|
// Get the list of networks only, defaulting to an empty array.
|
||||||
@ -70,7 +68,7 @@
|
|||||||
const option = cE("option");
|
const option = cE("option");
|
||||||
|
|
||||||
option.setAttribute("value", networks[i].ssid);
|
option.setAttribute("value", networks[i].ssid);
|
||||||
option.innerHTML = `${networks[i].ssid} (${networks[i].rssi} dBm)`;
|
option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`;
|
||||||
|
|
||||||
if (networks[i].ssid === cs.value) {
|
if (networks[i].ssid === cs.value) {
|
||||||
option.setAttribute("selected", "selected");
|
option.setAttribute("selected", "selected");
|
||||||
@ -81,14 +79,14 @@
|
|||||||
const option = cE("option");
|
const option = cE("option");
|
||||||
|
|
||||||
option.setAttribute("value", "!Cs");
|
option.setAttribute("value", "!Cs");
|
||||||
option.innerHTML = `Other network...`;
|
option.textContent = `Other network...`;
|
||||||
select.appendChild(option);
|
select.appendChild(option);
|
||||||
|
|
||||||
cs.replaceWith(select);
|
cs.replaceWith(select);
|
||||||
}
|
}
|
||||||
|
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
button.innerHTML = "Scan";
|
button.textContent = "Scan";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// replace WiFi select with custom SSID input field again
|
// replace WiFi select with custom SSID input field again
|
||||||
@ -122,16 +120,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem("locIp");
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem("locIp", locip);
|
localStorage.setItem('locIp', locip);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let url = (loc?`http://${locip}`:'') + '/settings/s.js?p=1';
|
loadJS(getURL('/settings/s.js?p=1'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
if (loc) d.Sf.action = getURL('/settings/wifi');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
@ -182,15 +193,26 @@
|
|||||||
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
||||||
<i>Can help with connectivity issues.<br>
|
<i>Can help with connectivity issues.<br>
|
||||||
Do not enable if WiFi is working correctly, increases power consumption.</i>
|
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">
|
<div id="ethd">
|
||||||
<h3>Ethernet Type</h3>
|
<h3>Ethernet Type</h3>
|
||||||
<select name="ETH">
|
<select name="ETH">
|
||||||
<option value="0">None</option>
|
<option value="0">None</option>
|
||||||
<option value="9">ABC! WLED V43 Controller & compatible</option>
|
<option value="9">ABC! WLED V43 & compatible</option>
|
||||||
<option value="2">ESP32-POE</option>
|
<option value="2">ESP32-POE</option>
|
||||||
<option value="6">ESP32Deux</option>
|
<option value="6">ESP32Deux</option>
|
||||||
<option value="7">KIT-VE</option>
|
<option value="7">KIT-VE</option>
|
||||||
<option value="8">QuinLED-Dig-Octa</option>
|
<option value="8">QuinLED-Dig-Octa & T-ETH-POE</option>
|
||||||
<option value="4">QuinLED-ESP32</option>
|
<option value="4">QuinLED-ESP32</option>
|
||||||
<option value="10">Serg74-ETH32</option>
|
<option value="10">Serg74-ETH32</option>
|
||||||
<option value="5">TwilightLord-ESP32</option>
|
<option value="5">TwilightLord-ESP32</option>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//page js
|
//page js
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var noNewSegs = false;
|
var noNewSegs = false;
|
||||||
var isOn = false, isInfo = false, isNodes = false, isRgbw = false, cct = false;
|
var isOn = false, isInfo = false, isNodes = false, isRgbw = false, cct = false;
|
||||||
var whites = [0,0,0];
|
var whites = [0,0,0];
|
||||||
@ -148,22 +148,39 @@ function loadSkinCSS(cId)
|
|||||||
l.id = cId;
|
l.id = cId;
|
||||||
l.rel = 'stylesheet';
|
l.rel = 'stylesheet';
|
||||||
l.type = 'text/css';
|
l.type = 'text/css';
|
||||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
l.href = getURL('/skin.css');
|
||||||
l.media = 'all';
|
l.media = 'all';
|
||||||
h.appendChild(l);
|
h.appendChild(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
|
}
|
||||||
async function onLoad()
|
async function onLoad()
|
||||||
{
|
{
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip)
|
if (!locip) {
|
||||||
{
|
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
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');
|
var sett = localStorage.getItem('wledUiCfg');
|
||||||
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
||||||
@ -173,7 +190,7 @@ async function onLoad()
|
|||||||
applyCfg();
|
applyCfg();
|
||||||
if (cfg.theme.bg.url=="" || cfg.theme.bg.url === "https://picsum.photos/1920/1080") {
|
if (cfg.theme.bg.url=="" || cfg.theme.bg.url === "https://picsum.photos/1920/1080") {
|
||||||
var iUrl = cfg.theme.bg.url;
|
var iUrl = cfg.theme.bg.url;
|
||||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", {
|
fetch(getURL("/holidays.json"), {
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -330,9 +347,7 @@ function loadPresets(callback = null)
|
|||||||
|
|
||||||
pmtLast = pmt;
|
pmtLast = pmt;
|
||||||
|
|
||||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
fetch(getURL('/presets.json'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -355,9 +370,7 @@ function loadPresets(callback = null)
|
|||||||
|
|
||||||
function loadPalettes(callback = null)
|
function loadPalettes(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
fetch(getURL('/json/palettes'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -379,9 +392,7 @@ function loadPalettes(callback = null)
|
|||||||
|
|
||||||
function loadFX(callback = null)
|
function loadFX(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
fetch(getURL('/json/effects'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -403,9 +414,7 @@ function loadFX(callback = null)
|
|||||||
|
|
||||||
function loadFXData(callback = null)
|
function loadFXData(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
fetch(getURL('/json/fxdata'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -611,8 +620,7 @@ function populateNodes(i,n)
|
|||||||
|
|
||||||
function loadNodes()
|
function loadNodes()
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
fetch(getURL('/json/nodes'), {
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -855,7 +863,8 @@ function cmpP(a, b)
|
|||||||
|
|
||||||
function makeWS() {
|
function makeWS() {
|
||||||
if (ws) return;
|
if (ws) return;
|
||||||
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
|
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||||
|
ws = new WebSocket(url);
|
||||||
ws.onmessage = (e)=>{
|
ws.onmessage = (e)=>{
|
||||||
var json = JSON.parse(e.data);
|
var json = JSON.parse(e.data);
|
||||||
if (json.leds) return; //liveview packet
|
if (json.leds) return; //liveview packet
|
||||||
@ -974,7 +983,6 @@ function requestJson(command=null)
|
|||||||
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
|
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
|
||||||
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
|
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
|
||||||
var req = null;
|
var req = null;
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/si';
|
|
||||||
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
||||||
var type = command ? 'post':'get';
|
var type = command ? 'post':'get';
|
||||||
if (command) {
|
if (command) {
|
||||||
@ -991,7 +999,7 @@ function requestJson(command=null)
|
|||||||
setTimeout(requestJson,200);
|
setTimeout(requestJson,200);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(url, {
|
fetch(getURL('/json/si'), {
|
||||||
method: type,
|
method: type,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
@ -1314,9 +1322,7 @@ function loadPalettesData(callback = null)
|
|||||||
|
|
||||||
function getPalettesData(page, callback)
|
function getPalettesData(page, callback)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
fetch(getURL(`/json/palx?page=${page}`), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
|
@ -61,6 +61,12 @@ button.sml {
|
|||||||
.hide {
|
.hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.err {
|
||||||
|
color: #f00;
|
||||||
|
}
|
||||||
|
.warn {
|
||||||
|
color: #fa0;
|
||||||
|
}
|
||||||
input {
|
input {
|
||||||
background: #333;
|
background: #333;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -114,6 +120,10 @@ select {
|
|||||||
font-family: Verdana, sans-serif;
|
font-family: Verdana, sans-serif;
|
||||||
border: 0.5ch solid #333;
|
border: 0.5ch solid #333;
|
||||||
}
|
}
|
||||||
|
select.pin {
|
||||||
|
max-width: 120px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
tr {
|
tr {
|
||||||
line-height: 100%;
|
line-height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<body onload="GetV()">
|
<body onload="GetV()">
|
||||||
<h2>WLED Software Update</h2>
|
<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>
|
Installed version: <span class="sip">##VERSION##</span><br>
|
||||||
Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases" target="_blank">
|
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>
|
<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>
|
<h3>Thank you for installing my application!</h3>
|
||||||
<b>Next steps:</b><br><br>
|
<b>Next steps:</b><br><br>
|
||||||
Connect the module to your local WiFi here!<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>
|
<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>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -25,7 +25,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ddpChannelsPerLed = (p->dataType == DDP_TYPE_RGBW32) ? 4 : 3; // data type 0x1A is RGBW (type 3, 8 bit/channel)
|
uint8_t ddpChannelsPerLed = ((p->dataType & 0b00111000)>>3 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
|
||||||
|
|
||||||
uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed;
|
uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed;
|
||||||
start += DMXAddress / ddpChannelsPerLed;
|
start += DMXAddress / ddpChannelsPerLed;
|
||||||
|
@ -50,6 +50,18 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
|||||||
|
|
||||||
|
|
||||||
//colors.cpp
|
//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_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||||
uint32_t color_add(uint32_t,uint32_t);
|
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]))); }
|
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||||
@ -63,10 +75,6 @@ bool colorFromHexString(byte* rgb, const char* in);
|
|||||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||||
void setRandomColor(byte* 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
|
//dmx.cpp
|
||||||
void initDMX();
|
void initDMX();
|
||||||
@ -96,10 +104,20 @@ void sendHuePoll();
|
|||||||
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
||||||
|
|
||||||
//improv.cpp
|
//improv.cpp
|
||||||
|
enum ImprovRPCType {
|
||||||
|
Command_Wifi = 0x01,
|
||||||
|
Request_State = 0x02,
|
||||||
|
Request_Info = 0x03,
|
||||||
|
Request_Scan = 0x04
|
||||||
|
};
|
||||||
|
|
||||||
void handleImprovPacket();
|
void handleImprovPacket();
|
||||||
|
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings = 0, const char **strings = nullptr);
|
||||||
void sendImprovStateResponse(uint8_t state, bool error = false);
|
void sendImprovStateResponse(uint8_t state, bool error = false);
|
||||||
void sendImprovInfoResponse();
|
void sendImprovInfoResponse();
|
||||||
void sendImprovRPCResponse(uint8_t commandId);
|
void startImprovWifiScan();
|
||||||
|
void handleImprovWifiScan();
|
||||||
|
void sendImprovIPRPCResult(ImprovRPCType type);
|
||||||
|
|
||||||
//ir.cpp
|
//ir.cpp
|
||||||
void applyRepeatActions();
|
void applyRepeatActions();
|
||||||
@ -129,8 +147,8 @@ bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE,
|
|||||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
void 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 serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
||||||
void serializeInfo(JsonObject root);
|
void serializeInfo(JsonObject root);
|
||||||
void serializeModeNames(JsonArray arr, const char *qstring);
|
void serializeModeNames(JsonArray root);
|
||||||
void serializeModeData(JsonObject root);
|
void serializeModeData(JsonArray root);
|
||||||
void serveJson(AsyncWebServerRequest* request);
|
void serveJson(AsyncWebServerRequest* request);
|
||||||
#ifdef WLED_ENABLE_JSONLIVE
|
#ifdef WLED_ENABLE_JSONLIVE
|
||||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||||
@ -152,9 +170,11 @@ void handleTransitions();
|
|||||||
void handleNightlight();
|
void handleNightlight();
|
||||||
byte scaledBri(byte in);
|
byte scaledBri(byte in);
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_LOXONE
|
||||||
//lx_parser.cpp
|
//lx_parser.cpp
|
||||||
bool parseLx(int lxValue, byte* rgbw);
|
bool parseLx(int lxValue, byte* rgbw);
|
||||||
void parseLxJson(int lxValue, byte segId, bool secondary);
|
void parseLxJson(int lxValue, byte segId, bool secondary);
|
||||||
|
#endif
|
||||||
|
|
||||||
//mqtt.cpp
|
//mqtt.cpp
|
||||||
bool initMqtt();
|
bool initMqtt();
|
||||||
@ -190,12 +210,16 @@ void serializePlaylist(JsonObject obj);
|
|||||||
void initPresetsFile();
|
void initPresetsFile();
|
||||||
void handlePresets();
|
void handlePresets();
|
||||||
bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE);
|
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);};
|
inline bool applyTemporaryPreset() {return applyPreset(255);};
|
||||||
void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject());
|
void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject());
|
||||||
inline void saveTemporaryPreset() {savePreset(255);};
|
inline void saveTemporaryPreset() {savePreset(255);};
|
||||||
void deletePreset(byte index);
|
void deletePreset(byte index);
|
||||||
bool getPresetName(byte index, String& name);
|
bool getPresetName(byte index, String& name);
|
||||||
|
|
||||||
|
//remote.cpp
|
||||||
|
void handleRemote();
|
||||||
|
|
||||||
//set.cpp
|
//set.cpp
|
||||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||||
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage);
|
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage);
|
||||||
@ -203,7 +227,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=tru
|
|||||||
|
|
||||||
//udp.cpp
|
//udp.cpp
|
||||||
void notify(byte callMode, bool followUp=false);
|
void notify(byte callMode, bool followUp=false);
|
||||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false);
|
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false);
|
||||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||||
void exitRealtime();
|
void exitRealtime();
|
||||||
void handleNotifications();
|
void handleNotifications();
|
||||||
@ -325,6 +349,7 @@ void releaseJSONBufferLock();
|
|||||||
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
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);
|
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);
|
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);
|
uint16_t crc16(const unsigned char* data_p, size_t length);
|
||||||
um_data_t* simulateSound(uint8_t simulationId);
|
um_data_t* simulateSound(uint8_t simulationId);
|
||||||
void enumerateLedmaps();
|
void enumerateLedmaps();
|
||||||
@ -372,7 +397,6 @@ void serveIndexOrWelcome(AsyncWebServerRequest *request);
|
|||||||
void serveIndex(AsyncWebServerRequest* request);
|
void serveIndex(AsyncWebServerRequest* request);
|
||||||
String msgProcessor(const String& var);
|
String msgProcessor(const String& var);
|
||||||
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255);
|
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);
|
String dmxProcessor(const String& var);
|
||||||
void serveSettings(AsyncWebServerRequest* request, bool post = false);
|
void serveSettings(AsyncWebServerRequest* request, bool post = false);
|
||||||
void serveSettingsJS(AsyncWebServerRequest* request);
|
void serveSettingsJS(AsyncWebServerRequest* request);
|
||||||
|
2104
wled00/html_other.h
2104
wled00/html_other.h
File diff suppressed because it is too large
Load Diff
549
wled00/html_pxmagic.h
Normal file
549
wled00/html_pxmagic.h
Normal file
@ -0,0 +1,549 @@
|
|||||||
|
/*
|
||||||
|
* Binary array for the Web UI.
|
||||||
|
* gzip is used for smaller size and improved speeds.
|
||||||
|
*
|
||||||
|
* Please see https://kno.wled.ge/advanced/custom-features/#changing-web-ui
|
||||||
|
* to find out how to easily modify the web UI source!
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Autogenerated from wled00/data/pxmagic/pxmagic.htm, do not edit!!
|
||||||
|
const uint16_t PAGE_pxmagic_L = 8581;
|
||||||
|
const uint8_t PAGE_pxmagic[] PROGMEM = {
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0xbd, 0x7d, 0xdb, 0x76, 0xdb, 0x46,
|
||||||
|
0xb2, 0xe8, 0x3b, 0xbf, 0x02, 0x86, 0x3d, 0x0e, 0x61, 0x81, 0x20, 0xa9, 0x5b, 0x14, 0x50, 0x90,
|
||||||
|
0x26, 0xb1, 0x9d, 0x89, 0xf7, 0xf2, 0x24, 0x39, 0xb1, 0x66, 0xf6, 0x64, 0x69, 0x6b, 0xc5, 0x4d,
|
||||||
|
0xa2, 0x49, 0x22, 0x06, 0xd1, 0x1c, 0x00, 0xd4, 0x25, 0x14, 0x3e, 0xe8, 0x3c, 0x9f, 0x4f, 0xd8,
|
||||||
|
0x3f, 0x76, 0xaa, 0xaa, 0xbb, 0x81, 0xc6, 0x85, 0xb2, 0x14, 0xef, 0xb5, 0x3d, 0x33, 0x02, 0xd0,
|
||||||
|
0xe8, 0x4b, 0x75, 0xdd, 0xab, 0xba, 0xc0, 0x39, 0x7d, 0xf6, 0xe6, 0xa7, 0xd7, 0x17, 0xbf, 0xfe,
|
||||||
|
0xfc, 0xd6, 0x5a, 0xe6, 0xab, 0xf8, 0xcc, 0x3a, 0xc5, 0x8b, 0x15, 0xb3, 0x64, 0x11, 0xd8, 0x3c,
|
||||||
|
0xb1, 0xb1, 0x81, 0xb3, 0x10, 0x2e, 0x2b, 0x9e, 0x33, 0x6b, 0xb6, 0x64, 0x69, 0xc6, 0xf3, 0xc0,
|
||||||
|
0xfe, 0xc7, 0xc5, 0xf7, 0x83, 0x13, 0x5b, 0x37, 0xf7, 0x12, 0xb6, 0xe2, 0x81, 0x7d, 0x1d, 0xf1,
|
||||||
|
0x9b, 0xb5, 0x48, 0x73, 0xdb, 0x9a, 0x89, 0x24, 0xe7, 0x09, 0xf4, 0xbb, 0x89, 0xc2, 0x7c, 0x19,
|
||||||
|
0x84, 0xfc, 0x3a, 0x9a, 0xf1, 0x01, 0x3d, 0xb8, 0x51, 0x12, 0xe5, 0x11, 0x8b, 0x07, 0xd9, 0x8c,
|
||||||
|
0xc5, 0x3c, 0x18, 0x37, 0x27, 0x61, 0x9b, 0x7c, 0x29, 0x52, 0x63, 0x8a, 0xbf, 0xb2, 0xdf, 0x45,
|
||||||
|
0xce, 0x92, 0x19, 0x76, 0xcc, 0xa3, 0x3c, 0xe6, 0x67, 0x3f, 0x47, 0xb7, 0x3c, 0xb6, 0xfe, 0xce,
|
||||||
|
0x16, 0xd1, 0xcc, 0xba, 0x10, 0x22, 0x3e, 0x1d, 0xca, 0x76, 0xeb, 0x34, 0xcb, 0xef, 0xe0, 0xda,
|
||||||
|
0xf3, 0x53, 0x21, 0xf2, 0xed, 0x60, 0x20, 0xae, 0x79, 0x1a, 0xb3, 0x3b, 0x3f, 0x5d, 0x4c, 0x59,
|
||||||
|
0x7f, 0xe4, 0x5a, 0xea, 0xbf, 0xde, 0x91, 0x33, 0x19, 0x0c, 0xa6, 0x6c, 0xf6, 0x69, 0x91, 0x8a,
|
||||||
|
0x4d, 0x12, 0xfa, 0xcf, 0xc7, 0xe3, 0x31, 0xb4, 0xe4, 0xfc, 0x36, 0xf7, 0x9f, 0x4f, 0xa7, 0x53,
|
||||||
|
0xb8, 0x5f, 0xa4, 0xec, 0x6e, 0x10, 0xb2, 0xf4, 0x93, 0xff, 0x7c, 0x7f, 0x7f, 0x5f, 0x37, 0xac,
|
||||||
|
0x78, 0x18, 0x6d, 0x56, 0xfe, 0xf3, 0x83, 0x83, 0x03, 0xdd, 0x14, 0x47, 0x8b, 0x25, 0x8c, 0xe2,
|
||||||
|
0xf4, 0x0f, 0xa7, 0x8d, 0x37, 0x5c, 0x0f, 0x3c, 0x39, 0x3c, 0x38, 0xda, 0xd7, 0x6d, 0xe5, 0xd8,
|
||||||
|
0xe9, 0xd7, 0xa3, 0x93, 0xa9, 0x6e, 0x55, 0xc3, 0x0f, 0x4f, 0x18, 0xb4, 0x64, 0x9b, 0xd9, 0x8c,
|
||||||
|
0x67, 0x99, 0x1a, 0x3e, 0x3a, 0x38, 0x3c, 0x1c, 0xcd, 0x8c, 0x66, 0x3d, 0xc3, 0xd1, 0xe1, 0xc9,
|
||||||
|
0x6c, 0x7f, 0x6e, 0xbc, 0x50, 0x93, 0x9c, 0xb0, 0xd9, 0x37, 0xfb, 0xc7, 0xd0, 0xce, 0xd3, 0x54,
|
||||||
|
0xa4, 0x6a, 0x16, 0x76, 0x32, 0x62, 0x23, 0x56, 0x36, 0xea, 0x39, 0xb0, 0xe7, 0xfe, 0xb4, 0x6c,
|
||||||
|
0x56, 0x33, 0xcc, 0xe7, 0x47, 0xdf, 0x1c, 0xe1, 0x2e, 0x6e, 0x58, 0x9a, 0x44, 0xc9, 0x42, 0xcd,
|
||||||
|
0x11, 0xc2, 0x72, 0xa3, 0x7d, 0xa3, 0x59, 0xcf, 0xc2, 0x4f, 0x8e, 0xc2, 0xd1, 0xa1, 0xf1, 0x42,
|
||||||
|
0xcf, 0x03, 0x10, 0x8e, 0x8e, 0x0b, 0xdf, 0xcf, 0x78, 0xcc, 0x67, 0x79, 0x24, 0x92, 0xad, 0x81,
|
||||||
|
0xee, 0x6b, 0x96, 0xf6, 0xcd, 0xed, 0x3b, 0xc5, 0xab, 0xed, 0x1c, 0xc8, 0x3d, 0x98, 0xb3, 0x55,
|
||||||
|
0x14, 0xdf, 0xf9, 0x3f, 0xf0, 0xf8, 0x9a, 0xe7, 0xd1, 0x8c, 0xb9, 0xff, 0xe4, 0x69, 0xc8, 0x12,
|
||||||
|
0xe6, 0x66, 0x2c, 0xc9, 0x06, 0x19, 0x4f, 0xa3, 0xf9, 0x64, 0x2a, 0x6e, 0x07, 0x59, 0xf4, 0x07,
|
||||||
|
0x2c, 0xe6, 0x4f, 0x45, 0x1a, 0xf2, 0x74, 0x00, 0x2d, 0x93, 0x15, 0x4b, 0x17, 0x51, 0xe2, 0x8f,
|
||||||
|
0x26, 0x6b, 0x16, 0x86, 0xf8, 0x6e, 0x54, 0x4c, 0x45, 0x78, 0xb7, 0x0d, 0xa3, 0x6c, 0x8d, 0x1c,
|
||||||
|
0x30, 0x8f, 0xf9, 0xed, 0xe4, 0xf7, 0x4d, 0x96, 0x47, 0xf3, 0xbb, 0x81, 0x62, 0x2d, 0x7f, 0x06,
|
||||||
|
0x7f, 0x78, 0x3a, 0x61, 0x00, 0x44, 0x32, 0x88, 0x72, 0xbe, 0xca, 0x74, 0xd3, 0x2a, 0x4a, 0x06,
|
||||||
|
0x4b, 0x4e, 0x7b, 0x19, 0x8f, 0x46, 0xd7, 0xcb, 0x49, 0x1b, 0xfa, 0xb2, 0xc1, 0x29, 0x66, 0x2c,
|
||||||
|
0xb9, 0x66, 0xd9, 0x96, 0xd8, 0x1b, 0xfb, 0xff, 0xa5, 0x98, 0x8b, 0x74, 0xb5, 0x95, 0x30, 0x01,
|
||||||
|
0x78, 0x79, 0x2e, 0x56, 0xfe, 0xfe, 0x68, 0x7d, 0x5b, 0x64, 0x2b, 0x16, 0xc7, 0x25, 0x50, 0xd3,
|
||||||
|
0x58, 0xcc, 0x3e, 0x4d, 0x68, 0xe7, 0x37, 0x72, 0xb1, 0xc3, 0xd1, 0x48, 0x6f, 0x65, 0x7f, 0x7d,
|
||||||
|
0x6b, 0x8d, 0xac, 0xa3, 0xf5, 0xed, 0x64, 0x26, 0x62, 0x91, 0xaa, 0x65, 0x91, 0x45, 0x1d, 0x39,
|
||||||
|
0x04, 0x90, 0xc0, 0xfd, 0x31, 0x74, 0x83, 0xd5, 0x04, 0x00, 0x6d, 0xac, 0x5f, 0xa2, 0xc3, 0x02,
|
||||||
|
0x69, 0x12, 0x16, 0x2e, 0x3d, 0xa9, 0x2f, 0x8a, 0xf3, 0x0c, 0x68, 0xe3, 0x6a, 0xcb, 0x05, 0xdb,
|
||||||
|
0x52, 0x5b, 0xc8, 0x67, 0x22, 0x65, 0x48, 0x31, 0x3f, 0x11, 0x09, 0xaf, 0x2d, 0x6e, 0x50, 0xac,
|
||||||
|
0x01, 0x42, 0x6d, 0x13, 0xc7, 0xa3, 0x51, 0xe1, 0x47, 0x59, 0x9f, 0xf9, 0x4b, 0x14, 0x40, 0x97,
|
||||||
|
0xf9, 0x73, 0x31, 0xdb, 0x64, 0x70, 0x65, 0xc0, 0x0a, 0xd7, 0xdc, 0xd9, 0xb6, 0x26, 0x95, 0xfc,
|
||||||
|
0xe4, 0x14, 0xde, 0x6a, 0xf0, 0x07, 0x4f, 0xc5, 0x56, 0xc3, 0xff, 0x2c, 0x5a, 0xa1, 0x42, 0x61,
|
||||||
|
0x49, 0x8e, 0xaf, 0x24, 0x26, 0x1b, 0x78, 0x1d, 0xc3, 0xe6, 0xea, 0xdd, 0x72, 0xb1, 0xd6, 0x7d,
|
||||||
|
0xe0, 0xb6, 0xd5, 0x01, 0xa9, 0xcf, 0xa2, 0xa4, 0x8e, 0xb0, 0x1a, 0x9f, 0x74, 0x30, 0xc4, 0x0e,
|
||||||
|
0xd6, 0xc1, 0xee, 0x83, 0x30, 0x4a, 0x25, 0x8f, 0xfb, 0xb0, 0xaf, 0xcd, 0x2a, 0x91, 0x4b, 0x40,
|
||||||
|
0x07, 0xb5, 0x00, 0xe8, 0xb9, 0x59, 0x1f, 0x57, 0xb1, 0x06, 0xd6, 0x21, 0x00, 0xe3, 0x00, 0x79,
|
||||||
|
0x6e, 0xa5, 0x32, 0xf4, 0xbf, 0x3e, 0x3e, 0x59, 0x97, 0xdc, 0x4b, 0x2c, 0xe2, 0xa5, 0xe2, 0xa6,
|
||||||
|
0xce, 0xb6, 0xb4, 0xc8, 0x4d, 0xca, 0xd6, 0x40, 0x11, 0xbc, 0xb4, 0x80, 0xc9, 0xd6, 0x0c, 0xb4,
|
||||||
|
0xeb, 0x94, 0xe7, 0x37, 0x9c, 0x27, 0xe6, 0x64, 0xc0, 0x40, 0x23, 0x84, 0x06, 0xa1, 0xda, 0xd2,
|
||||||
|
0x34, 0x53, 0x96, 0x45, 0x99, 0x84, 0xe8, 0x88, 0x00, 0x1a, 0x13, 0x40, 0x6b, 0x91, 0x45, 0xb4,
|
||||||
|
0x83, 0x94, 0xc7, 0x0c, 0x69, 0x54, 0xc9, 0x11, 0xb2, 0xa0, 0x9e, 0x63, 0x30, 0xdf, 0x00, 0xfb,
|
||||||
|
0x1a, 0x13, 0x11, 0xee, 0x3e, 0x37, 0x38, 0x66, 0x53, 0xde, 0x64, 0xfa, 0x3a, 0x0d, 0x8f, 0x1a,
|
||||||
|
0x1c, 0xf4, 0x35, 0x88, 0x41, 0x8b, 0xeb, 0x8b, 0x28, 0x59, 0x6f, 0xf2, 0xcb, 0xfc, 0x6e, 0xcd,
|
||||||
|
0x83, 0x64, 0xb3, 0x9a, 0xf2, 0xf4, 0xca, 0x35, 0x9a, 0xb0, 0xcf, 0x95, 0x2b, 0xf5, 0x8d, 0x8b,
|
||||||
|
0x0f, 0x2c, 0xe5, 0xcc, 0x24, 0xb1, 0x06, 0x0a, 0x77, 0x3c, 0x51, 0xaa, 0x23, 0x65, 0xc0, 0x77,
|
||||||
|
0x99, 0x7f, 0x44, 0x4d, 0xa5, 0x44, 0x0f, 0xcc, 0xb5, 0x0d, 0xbd, 0xef, 0xa8, 0x61, 0xfe, 0x18,
|
||||||
|
0x50, 0x9b, 0x89, 0x38, 0x0a, 0xad, 0x8e, 0x3e, 0x62, 0x93, 0xc7, 0xc0, 0x5e, 0x7e, 0x7d, 0x0b,
|
||||||
|
0x95, 0xad, 0xa8, 0xc9, 0xce, 0x21, 0xe0, 0xc7, 0xd8, 0x04, 0x8d, 0xb8, 0x52, 0x50, 0x1f, 0xa0,
|
||||||
|
0x60, 0x29, 0x2d, 0x44, 0xf7, 0xb3, 0x4d, 0x9a, 0xc1, 0x84, 0x6b, 0x11, 0x11, 0xf3, 0x55, 0x58,
|
||||||
|
0x06, 0x78, 0xaa, 0x65, 0x0b, 0x8f, 0x26, 0x1c, 0xe0, 0x5e, 0xd6, 0x7f, 0x52, 0x01, 0xd6, 0xe6,
|
||||||
|
0xb0, 0xe8, 0x1e, 0x98, 0x2f, 0xef, 0x4b, 0x28, 0x53, 0xf0, 0x0e, 0xf8, 0x95, 0xb3, 0xad, 0x23,
|
||||||
|
0xf1, 0x44, 0xf2, 0x9b, 0x75, 0x82, 0xfc, 0x62, 0x0e, 0x57, 0x0f, 0x21, 0xcf, 0x66, 0x69, 0xb4,
|
||||||
|
0x26, 0x63, 0xa0, 0x36, 0x78, 0x62, 0x6c, 0x10, 0xef, 0x4d, 0x12, 0x59, 0x1d, 0xf8, 0x43, 0x6b,
|
||||||
|
0xe4, 0xb4, 0x75, 0xb1, 0x89, 0xdb, 0x3a, 0x4c, 0xc4, 0x80, 0xf4, 0xbf, 0xd1, 0x83, 0xb4, 0xab,
|
||||||
|
0x0f, 0x8e, 0xf9, 0x3c, 0x07, 0xf2, 0xb5, 0x74, 0x64, 0x83, 0x70, 0x13, 0xc4, 0x77, 0x69, 0x26,
|
||||||
|
0x8e, 0x3b, 0xb4, 0x60, 0x1d, 0x0d, 0xd9, 0xbf, 0x37, 0xc0, 0x93, 0x6d, 0xac, 0x55, 0xca, 0x49,
|
||||||
|
0x8b, 0x05, 0x01, 0x80, 0x48, 0x28, 0x4a, 0x46, 0x4e, 0x39, 0xad, 0x0b, 0xfa, 0x14, 0x0d, 0x63,
|
||||||
|
0x6c, 0x5a, 0xa8, 0xfd, 0x51, 0x9b, 0xa3, 0x89, 0x08, 0xa0, 0x74, 0x41, 0xba, 0x06, 0x52, 0x26,
|
||||||
|
0xb6, 0x2d, 0x31, 0x6d, 0x74, 0xb0, 0x54, 0x3f, 0xb6, 0x5e, 0x73, 0x06, 0x24, 0x9e, 0x71, 0x69,
|
||||||
|
0x01, 0x60, 0x43, 0xd3, 0x4f, 0x11, 0x60, 0xa2, 0xd9, 0xbe, 0x12, 0x7f, 0xb4, 0x1a, 0x0d, 0x21,
|
||||||
|
0x8a, 0x56, 0x6c, 0xa1, 0x5a, 0x15, 0x5d, 0x07, 0xa9, 0x82, 0xb7, 0xc5, 0xcb, 0x4d, 0x50, 0x48,
|
||||||
|
0x65, 0xf8, 0x3e, 0x9b, 0xa3, 0x5d, 0xd3, 0xdc, 0x6a, 0xdb, 0x95, 0xaa, 0x61, 0x53, 0xa0, 0xe1,
|
||||||
|
0x26, 0xe7, 0x13, 0xd4, 0xf0, 0xa5, 0x3a, 0xdb, 0xb3, 0x8e, 0x51, 0x9b, 0xa5, 0x15, 0x45, 0x72,
|
||||||
|
0x80, 0x2d, 0x43, 0x6b, 0x0c, 0x2e, 0x61, 0xce, 0x72, 0xde, 0x1f, 0x1f, 0x1c, 0x85, 0x7c, 0xe1,
|
||||||
|
0x4c, 0x24, 0x07, 0x1e, 0x57, 0x0c, 0x78, 0x5c, 0xe1, 0x10, 0xe7, 0xdc, 0xff, 0x3c, 0x9b, 0xa8,
|
||||||
|
0xdd, 0x3c, 0xd0, 0x51, 0xed, 0x6e, 0xc0, 0xaf, 0x01, 0xfe, 0x8c, 0x70, 0x51, 0x78, 0x61, 0x2a,
|
||||||
|
0xd6, 0x7f, 0xc0, 0x9d, 0xa9, 0x9b, 0x0c, 0xde, 0x0c, 0x59, 0xb6, 0xe4, 0x9d, 0xab, 0x3e, 0xa0,
|
||||||
|
0x9f, 0xa4, 0x60, 0xec, 0xd2, 0x37, 0x6d, 0x46, 0xd6, 0x82, 0x86, 0xe6, 0xc8, 0x1a, 0x77, 0xb2,
|
||||||
|
0x4f, 0xd3, 0x8e, 0x48, 0x54, 0x2a, 0xec, 0xc7, 0xb1, 0xe5, 0x1d, 0x65, 0x16, 0x67, 0x19, 0x1f,
|
||||||
|
0x00, 0x23, 0x82, 0xee, 0xa9, 0xf6, 0x25, 0xad, 0xfe, 0xb6, 0xa1, 0xac, 0x3e, 0x2b, 0xcb, 0x83,
|
||||||
|
0x5d, 0xd0, 0x2b, 0xc8, 0xba, 0x27, 0xa8, 0x96, 0x85, 0x1b, 0xb6, 0xa0, 0x95, 0x1f, 0xa1, 0xc8,
|
||||||
|
0xc1, 0xca, 0xa2, 0x0e, 0x1b, 0x64, 0x40, 0x37, 0x18, 0xf1, 0x00, 0x17, 0xef, 0x82, 0x4a, 0x71,
|
||||||
|
0x0d, 0x22, 0xaa, 0x45, 0x47, 0x8d, 0x45, 0x42, 0x6c, 0x65, 0x0e, 0x14, 0x42, 0x91, 0x2f, 0xd1,
|
||||||
|
0x2c, 0x9b, 0x10, 0xf8, 0xbe, 0x96, 0x32, 0xf9, 0x3c, 0xc8, 0x97, 0x60, 0xe1, 0x5a, 0x70, 0x99,
|
||||||
|
0xba, 0x46, 0xad, 0x7a, 0xfc, 0x19, 0xcb, 0xa5, 0xd0, 0xdc, 0x30, 0x77, 0x7f, 0x69, 0xda, 0x12,
|
||||||
|
0xc5, 0x80, 0x00, 0x56, 0x76, 0x13, 0xe5, 0xb3, 0x65, 0x5b, 0x5b, 0x94, 0x2e, 0x52, 0x94, 0x90,
|
||||||
|
0xde, 0x93, 0x76, 0xbc, 0xad, 0xc8, 0xa5, 0x13, 0x23, 0x67, 0x91, 0x96, 0x63, 0x5b, 0xa1, 0x40,
|
||||||
|
0xcf, 0x21, 0x25, 0x41, 0x76, 0xd2, 0x44, 0x68, 0xcb, 0x76, 0x03, 0x46, 0x14, 0xcb, 0xd1, 0x44,
|
||||||
|
0x29, 0x67, 0x29, 0x7c, 0xa8, 0xd5, 0xc9, 0x83, 0x18, 0x3d, 0xc1, 0x7c, 0x6b, 0x34, 0x1c, 0x1c,
|
||||||
|
0x6a, 0x05, 0x21, 0xd7, 0xf5, 0x0e, 0xb3, 0x06, 0x4c, 0xfe, 0x94, 0x83, 0xee, 0xe0, 0x5d, 0xa0,
|
||||||
|
0x55, 0x3a, 0x49, 0x13, 0xe5, 0xb0, 0x22, 0x0a, 0x19, 0x07, 0x84, 0xf3, 0x80, 0x24, 0x8b, 0x20,
|
||||||
|
0x3c, 0xe8, 0x22, 0x14, 0x04, 0x5c, 0xf3, 0x0e, 0xe2, 0x34, 0x80, 0x92, 0xf6, 0x77, 0xb6, 0xe4,
|
||||||
|
0xb3, 0x4f, 0x3c, 0xdc, 0x6b, 0xa0, 0x6d, 0xc7, 0xbe, 0xcd, 0xe8, 0x4a, 0x8e, 0x27, 0x27, 0xbc,
|
||||||
|
0x35, 0x1a, 0xa3, 0xa9, 0x25, 0x0b, 0xc5, 0x8d, 0x8f, 0xb6, 0x1b, 0x15, 0xd0, 0xae, 0xf1, 0xdd,
|
||||||
|
0xeb, 0x6b, 0x14, 0x55, 0x8a, 0x96, 0xee, 0x80, 0x67, 0xf8, 0xbf, 0xfa, 0x63, 0xe0, 0x0b, 0xa7,
|
||||||
|
0x78, 0x9e, 0x0b, 0x96, 0xe5, 0x83, 0xca, 0xef, 0x2e, 0xd1, 0x39, 0x87, 0x40, 0x3e, 0x9c, 0x18,
|
||||||
|
0x01, 0xd2, 0xc4, 0xb0, 0x10, 0x7f, 0x80, 0x66, 0x09, 0xf9, 0xad, 0xff, 0x0d, 0xfc, 0x2b, 0x3c,
|
||||||
|
0x9a, 0x63, 0xfb, 0x39, 0x37, 0x5d, 0xe2, 0x1f, 0x83, 0x9e, 0x52, 0xc5, 0xa1, 0xb4, 0x51, 0x88,
|
||||||
|
0xa2, 0xc5, 0x4f, 0xeb, 0xb3, 0xb6, 0xc6, 0xeb, 0xd8, 0xc3, 0xaf, 0xfd, 0x03, 0x72, 0x90, 0x05,
|
||||||
|
0xb8, 0xd8, 0x51, 0x7e, 0x07, 0x7c, 0x76, 0x1d, 0x65, 0xd1, 0x34, 0x8a, 0xf1, 0x61, 0x19, 0x85,
|
||||||
|
0x21, 0x4f, 0x14, 0x6c, 0x96, 0xbc, 0x0c, 0x28, 0xec, 0xd4, 0x8b, 0x93, 0x4f, 0xd4, 0x74, 0x0b,
|
||||||
|
0x3a, 0x02, 0xba, 0x98, 0xe7, 0x68, 0x27, 0xd0, 0x91, 0xc7, 0x61, 0x1e, 0xf9, 0xdc, 0x34, 0x9f,
|
||||||
|
0xa7, 0x62, 0xfc, 0x5d, 0x74, 0xae, 0xe7, 0x06, 0x1c, 0x3d, 0x8a, 0xa2, 0xfa, 0x5d, 0x63, 0x8c,
|
||||||
|
0x90, 0xbf, 0x1c, 0xa0, 0x02, 0xf8, 0x5d, 0x43, 0x6a, 0xf1, 0xbd, 0x1e, 0x34, 0x58, 0xa7, 0x62,
|
||||||
|
0x91, 0x22, 0x70, 0x6d, 0x01, 0x21, 0xf6, 0x3f, 0xac, 0xd8, 0xbf, 0x92, 0x0e, 0x33, 0x1c, 0x42,
|
||||||
|
0xfe, 0x28, 0x3d, 0xc0, 0x1a, 0x05, 0x28, 0x3b, 0xf4, 0xaf, 0xfe, 0xc8, 0xa9, 0xda, 0x06, 0x02,
|
||||||
|
0xb8, 0x03, 0x28, 0x88, 0x53, 0x37, 0xa8, 0x17, 0x25, 0x4b, 0x9e, 0x46, 0x79, 0x03, 0x67, 0x56,
|
||||||
|
0x13, 0x4c, 0xc3, 0x73, 0x44, 0x85, 0xc4, 0x52, 0x54, 0x0f, 0x61, 0x04, 0xbc, 0xd3, 0x87, 0x30,
|
||||||
|
0x99, 0x78, 0xcf, 0xad, 0xa3, 0x55, 0xee, 0xd7, 0xed, 0xc4, 0x75, 0x1d, 0xd9, 0x5f, 0xb0, 0x98,
|
||||||
|
0x49, 0x8f, 0x5a, 0x53, 0x73, 0x21, 0x45, 0x85, 0x2f, 0x58, 0xaa, 0x4e, 0xc7, 0x46, 0x63, 0xb5,
|
||||||
|
0x1c, 0xe6, 0xfc, 0x40, 0x50, 0xdb, 0x61, 0x68, 0x33, 0xd6, 0xed, 0x12, 0xc2, 0x2a, 0x2e, 0x19,
|
||||||
|
0x59, 0xd2, 0x1a, 0xc8, 0xe9, 0x2c, 0x6f, 0x0a, 0xa4, 0x0c, 0xeb, 0x79, 0x0a, 0x1d, 0x08, 0x4b,
|
||||||
|
0x27, 0xb6, 0xca, 0xb9, 0xfc, 0xa5, 0x91, 0xb0, 0xa8, 0x6c, 0x48, 0x65, 0xaa, 0x66, 0x0c, 0xf6,
|
||||||
|
0x9c, 0x19, 0xb1, 0x25, 0xc1, 0x69, 0xce, 0x61, 0x2c, 0xd5, 0x72, 0x38, 0xd5, 0x60, 0x2b, 0x5a,
|
||||||
|
0x2d, 0x1a, 0xc1, 0xa9, 0x31, 0xca, 0x9c, 0x4c, 0x39, 0xe7, 0x86, 0x8a, 0x6a, 0x83, 0x82, 0xb3,
|
||||||
|
0xf9, 0x31, 0xa9, 0xbb, 0x65, 0x14, 0x87, 0xdb, 0xda, 0x18, 0xe8, 0x37, 0xdd, 0x80, 0x34, 0x24,
|
||||||
|
0x1d, 0xae, 0xdf, 0xa8, 0x1e, 0xfc, 0xa0, 0xe6, 0xec, 0x0a, 0x52, 0xdb, 0xaa, 0xa3, 0x61, 0x24,
|
||||||
|
0xcb, 0xcc, 0xcf, 0x48, 0xf9, 0x75, 0x9d, 0xc1, 0xd2, 0x63, 0xe2, 0x59, 0xe9, 0x39, 0x3c, 0xec,
|
||||||
|
0xf5, 0x35, 0x23, 0xa2, 0x56, 0x00, 0x24, 0xf7, 0xab, 0x5c, 0xc2, 0x6e, 0x58, 0x4c, 0x0f, 0xe5,
|
||||||
|
0xc1, 0xc8, 0xba, 0x9c, 0xad, 0x8d, 0x5f, 0xed, 0x05, 0xe8, 0x2e, 0xd9, 0x63, 0x58, 0xd7, 0xc8,
|
||||||
|
0xd7, 0x3d, 0x57, 0x99, 0xe2, 0xa6, 0x69, 0xaa, 0xb9, 0x1c, 0x3b, 0xd8, 0x62, 0x87, 0xc6, 0x54,
|
||||||
|
0x33, 0x3a, 0x75, 0x9f, 0x47, 0x2f, 0xe4, 0xc5, 0x82, 0x11, 0xb5, 0xdb, 0x31, 0x4e, 0x9d, 0x17,
|
||||||
|
0x3f, 0x13, 0xf1, 0x0c, 0xac, 0xf1, 0x37, 0xa8, 0x43, 0x09, 0xc4, 0x56, 0xab, 0x12, 0x2d, 0x23,
|
||||||
|
0xca, 0xd9, 0xaf, 0xc2, 0x1c, 0xb2, 0x8c, 0x9f, 0x09, 0x71, 0x60, 0xad, 0xc7, 0xbb, 0x94, 0x2c,
|
||||||
|
0x81, 0x90, 0x8f, 0x60, 0xcd, 0xd6, 0x51, 0x62, 0x8d, 0x33, 0x4b, 0x2a, 0x23, 0xf0, 0x02, 0xe7,
|
||||||
|
0x98, 0xf4, 0x87, 0xdd, 0x03, 0x05, 0x20, 0x98, 0xcd, 0x79, 0xf8, 0x0e, 0x83, 0xc3, 0x6d, 0x2d,
|
||||||
|
0xc4, 0xc0, 0x68, 0xf9, 0x1a, 0xd4, 0x49, 0xb8, 0xdd, 0xc1, 0x0b, 0x55, 0x56, 0xdb, 0x31, 0xf3,
|
||||||
|
0x79, 0x5a, 0x55, 0x66, 0x19, 0x4e, 0x59, 0xc7, 0x5e, 0xdb, 0xea, 0x49, 0xe0, 0xcb, 0xf8, 0xa7,
|
||||||
|
0xd3, 0x3e, 0x37, 0xd2, 0xab, 0x7f, 0x45, 0xfe, 0x63, 0x56, 0xdf, 0xcc, 0xda, 0x7d, 0x0d, 0xe8,
|
||||||
|
0xdd, 0x6a, 0x35, 0xa9, 0xc3, 0xdb, 0x8a, 0x0b, 0x31, 0x87, 0x57, 0xa5, 0xed, 0x28, 0x69, 0xd7,
|
||||||
|
0xcd, 0x83, 0x5a, 0x5c, 0x75, 0x86, 0xcd, 0x7d, 0x30, 0xd3, 0xd6, 0x0c, 0xc9, 0xaa, 0x64, 0x77,
|
||||||
|
0xf1, 0xd7, 0x4f, 0xfc, 0x6e, 0x9e, 0x32, 0x40, 0x83, 0x85, 0xd8, 0xdf, 0xe6, 0x62, 0xdb, 0x8a,
|
||||||
|
0x7d, 0x0f, 0x8e, 0x47, 0x18, 0xfb, 0xd6, 0x3a, 0x97, 0x36, 0xa4, 0x36, 0x40, 0x59, 0xdf, 0x71,
|
||||||
|
0xbd, 0xef, 0x1c, 0x76, 0xfb, 0x2e, 0xd9, 0x1e, 0xfd, 0x65, 0xab, 0xdd, 0xa1, 0xb1, 0xe9, 0x0e,
|
||||||
|
0xd1, 0x6d, 0xcc, 0xbb, 0xdd, 0xa8, 0x91, 0x53, 0x7c, 0x53, 0x1b, 0xb8, 0xab, 0x57, 0xd1, 0x3b,
|
||||||
|
0x1d, 0xca, 0x63, 0x1c, 0xeb, 0x74, 0xa8, 0xce, 0x9e, 0xd0, 0xa7, 0x82, 0x4b, 0x18, 0x5d, 0x5b,
|
||||||
|
0x33, 0x10, 0xfe, 0x2c, 0xb0, 0x4b, 0x67, 0xd2, 0x6e, 0xb7, 0x83, 0x1c, 0x61, 0x2b, 0xce, 0x6d,
|
||||||
|
0xf5, 0xa2, 0x30, 0xb0, 0xf1, 0xee, 0x6f, 0x1c, 0x3a, 0xc3, 0x1a, 0xb6, 0x95, 0x08, 0xe2, 0x32,
|
||||||
|
0xb8, 0xaf, 0x0f, 0x95, 0xc4, 0xc4, 0x91, 0xd9, 0xf5, 0x42, 0x37, 0x92, 0xc5, 0xb2, 0xad, 0xde,
|
||||||
|
0xed, 0x2a, 0x4e, 0xb0, 0x4f, 0x9e, 0xaf, 0xfd, 0xe1, 0xf0, 0xe6, 0xe6, 0xc6, 0xbb, 0x39, 0xf0,
|
||||||
|
0x44, 0xba, 0x18, 0x82, 0xdd, 0x1a, 0x0d, 0x61, 0x80, 0x6d, 0xc9, 0xa3, 0x2e, 0x1b, 0x1a, 0x6c,
|
||||||
|
0x4b, 0x4a, 0x5b, 0x60, 0x8f, 0x0f, 0xe0, 0xa1, 0x87, 0xe7, 0x62, 0xdf, 0x89, 0xdb, 0xc0, 0x96,
|
||||||
|
0x16, 0x11, 0x34, 0x33, 0x34, 0x9f, 0x9d, 0x52, 0x82, 0x64, 0xe7, 0xb0, 0xe1, 0xd9, 0x29, 0xce,
|
||||||
|
0x8b, 0x58, 0x00, 0x20, 0x15, 0xa8, 0x3d, 0x05, 0x16, 0xf0, 0x57, 0x6b, 0xe3, 0xc8, 0x36, 0xb6,
|
||||||
|
0x65, 0xec, 0x8d, 0x92, 0x28, 0x16, 0x6c, 0x1e, 0xe0, 0x16, 0x59, 0x8e, 0xc7, 0x6b, 0xf6, 0xd9,
|
||||||
|
0x0f, 0xea, 0x0e, 0xb0, 0x4c, 0xef, 0xa1, 0x1f, 0xb9, 0xf7, 0x16, 0x65, 0xf6, 0x6c, 0xb4, 0x29,
|
||||||
|
0x80, 0x22, 0x3a, 0x89, 0x2b, 0x07, 0x59, 0x88, 0xc4, 0xea, 0x29, 0xe5, 0xff, 0xde, 0x00, 0x1f,
|
||||||
|
0x87, 0xdd, 0xa0, 0x3d, 0x0c, 0x88, 0x04, 0xe2, 0x67, 0xe0, 0x38, 0x9e, 0x5b, 0x3f, 0xc2, 0x43,
|
||||||
|
0x13, 0x8c, 0x5e, 0x1b, 0x8e, 0x0a, 0x06, 0x79, 0x07, 0x33, 0x6f, 0xa0, 0xf9, 0x47, 0x7e, 0x63,
|
||||||
|
0xc9, 0x89, 0xba, 0x40, 0x92, 0x97, 0x9e, 0x89, 0xa2, 0x47, 0x21, 0xcd, 0x7c, 0x6b, 0xa6, 0xa4,
|
||||||
|
0x6c, 0x9c, 0xcc, 0xd8, 0xc8, 0x9a, 0xa1, 0xc7, 0x9e, 0xc0, 0x5e, 0xe4, 0x4d, 0xb5, 0x0f, 0x95,
|
||||||
|
0xc2, 0x92, 0xb0, 0xeb, 0x6e, 0x04, 0x7e, 0xf9, 0xd0, 0x33, 0xe0, 0x15, 0x94, 0x11, 0x95, 0x9b,
|
||||||
|
0x3a, 0xfb, 0x20, 0xc7, 0xe2, 0x41, 0xab, 0x88, 0x66, 0x80, 0x1c, 0xf9, 0xb6, 0xd1, 0x0d, 0x18,
|
||||||
|
0x04, 0xe6, 0xa0, 0x33, 0xcf, 0xc0, 0xbe, 0xfc, 0x6a, 0x4e, 0xff, 0xbe, 0xba, 0xb2, 0x55, 0x06,
|
||||||
|
0x8f, 0xc3, 0x52, 0xfa, 0x0e, 0xc0, 0x7e, 0x97, 0xc0, 0x9e, 0xa2, 0x70, 0xc3, 0x62, 0x6b, 0xe7,
|
||||||
|
0x7c, 0xfb, 0xc6, 0x7c, 0x23, 0xd7, 0xaa, 0xa6, 0x3c, 0x7b, 0x87, 0x31, 0xd8, 0xce, 0x71, 0x07,
|
||||||
|
0xb6, 0x65, 0x0c, 0x3b, 0xaa, 0x8d, 0xec, 0xfd, 0x82, 0x09, 0x0e, 0x63, 0xe8, 0x50, 0x02, 0xd5,
|
||||||
|
0xa4, 0xd1, 0x23, 0x08, 0xd2, 0xdb, 0x41, 0x11, 0x93, 0x20, 0xe0, 0x8d, 0x00, 0xff, 0xd8, 0x67,
|
||||||
|
0x3f, 0xd1, 0x75, 0x07, 0x39, 0x54, 0x27, 0xa9, 0x16, 0xf4, 0xc3, 0x9f, 0x26, 0x46, 0x4f, 0x61,
|
||||||
|
0xe1, 0xf7, 0x4c, 0x24, 0xdd, 0xc8, 0xff, 0xcf, 0xf7, 0x6f, 0xdf, 0x58, 0xff, 0xf1, 0xe1, 0xa7,
|
||||||
|
0x1f, 0x77, 0x62, 0x70, 0xc9, 0x00, 0x53, 0x3f, 0x88, 0x15, 0xb7, 0xbe, 0xcd, 0x40, 0xcf, 0xa3,
|
||||||
|
0x49, 0xdb, 0xd9, 0x17, 0x5c, 0xbd, 0xd8, 0x3e, 0x7b, 0xfd, 0x8f, 0x5f, 0xde, 0x3f, 0x80, 0xd5,
|
||||||
|
0xde, 0x6e, 0xec, 0x82, 0x00, 0x58, 0x7a, 0xd3, 0xa4, 0x62, 0x03, 0xdb, 0x74, 0x4e, 0x76, 0x08,
|
||||||
|
0x47, 0xaf, 0x5b, 0x92, 0xe5, 0x99, 0xbe, 0x7d, 0xf6, 0x86, 0xae, 0x9f, 0xd7, 0x26, 0xaa, 0xbf,
|
||||||
|
0x44, 0xbd, 0x7e, 0xe8, 0x56, 0x25, 0x9f, 0xd3, 0x24, 0x3d, 0x02, 0x60, 0x93, 0x44, 0xff, 0xde,
|
||||||
|
0xf0, 0x77, 0x80, 0xe5, 0x7f, 0xd0, 0x9d, 0xf5, 0x2e, 0xfc, 0x3c, 0x14, 0xe5, 0x20, 0x09, 0x47,
|
||||||
|
0xf5, 0xf8, 0x25, 0x90, 0xcc, 0x53, 0x08, 0xb5, 0xc2, 0xf8, 0xee, 0x47, 0x52, 0x6e, 0xdf, 0xab,
|
||||||
|
0xa7, 0x4e, 0xf5, 0xd6, 0x86, 0xa8, 0x36, 0x58, 0xd9, 0xab, 0x5a, 0xd3, 0x2e, 0xdd, 0xf6, 0x38,
|
||||||
|
0xd5, 0xd6, 0x7b, 0x9c, 0x6e, 0x33, 0x29, 0x9b, 0xf1, 0xc5, 0x0a, 0xf3, 0xd5, 0x36, 0x48, 0x00,
|
||||||
|
0xdd, 0x99, 0x98, 0xed, 0xd5, 0x05, 0xaa, 0xec, 0x4b, 0x0a, 0xae, 0x1a, 0xd9, 0x64, 0x5d, 0x30,
|
||||||
|
0x6e, 0x00, 0x04, 0x1b, 0x28, 0x6b, 0x37, 0x3e, 0x06, 0xc8, 0xa8, 0xa1, 0x34, 0x79, 0xc7, 0x30,
|
||||||
|
0x48, 0xaf, 0x37, 0xb2, 0x1e, 0xa9, 0x36, 0x1e, 0x67, 0x74, 0xa6, 0x14, 0x7e, 0x25, 0xe0, 0xe5,
|
||||||
|
0xd8, 0x67, 0xdf, 0x95, 0xf7, 0x15, 0x69, 0xcc, 0x99, 0x8c, 0x13, 0x1b, 0xbb, 0x41, 0x35, 0x4a,
|
||||||
|
0xd8, 0x6a, 0xb2, 0x19, 0x73, 0xd2, 0xd6, 0xcd, 0xe7, 0xde, 0x2a, 0x4a, 0x68, 0xcb, 0xe0, 0x31,
|
||||||
|
0x82, 0x6e, 0x3d, 0x3a, 0x2a, 0x6d, 0xd6, 0x78, 0xff, 0xc4, 0x2e, 0x69, 0x66, 0xe4, 0x7f, 0xed,
|
||||||
|
0x4e, 0x06, 0xe9, 0xd5, 0x27, 0xfe, 0x27, 0xce, 0x51, 0x0e, 0x6f, 0x1d, 0xaa, 0x59, 0xf2, 0x7c,
|
||||||
|
0xa9, 0xb6, 0x56, 0x03, 0x69, 0xbd, 0xa7, 0xf1, 0x4e, 0x37, 0x36, 0x4b, 0x37, 0x1f, 0x14, 0xd7,
|
||||||
|
0xb7, 0xfa, 0xbe, 0x42, 0xa6, 0xec, 0xa9, 0x66, 0x92, 0xa9, 0xc2, 0xe6, 0xee, 0x28, 0x93, 0x38,
|
||||||
|
0x15, 0xb7, 0x76, 0x59, 0xf3, 0x53, 0x4e, 0x49, 0xb8, 0x34, 0x56, 0x00, 0xfd, 0xbd, 0x66, 0x49,
|
||||||
|
0x7d, 0xba, 0x12, 0x67, 0xc0, 0x1a, 0xf0, 0x12, 0x37, 0x57, 0x32, 0xe7, 0x13, 0x64, 0x97, 0x36,
|
||||||
|
0x43, 0xbe, 0xe7, 0x1a, 0xd0, 0x96, 0xe4, 0x14, 0x92, 0xc0, 0x9e, 0x2e, 0xaa, 0x26, 0x8b, 0xda,
|
||||||
|
0xbe, 0x6c, 0x6f, 0xad, 0x15, 0x68, 0x8b, 0xed, 0x75, 0x1f, 0xdc, 0x69, 0xaf, 0xb5, 0xd5, 0x27,
|
||||||
|
0xef, 0x54, 0x1e, 0x20, 0xea, 0x4d, 0xfe, 0x42, 0x4f, 0xff, 0x13, 0xfb, 0x33, 0xe7, 0xa5, 0xad,
|
||||||
|
0xd5, 0x16, 0x7a, 0x14, 0xfd, 0x7a, 0xad, 0x5d, 0x75, 0xdb, 0xae, 0xda, 0x52, 0x0f, 0x18, 0xb0,
|
||||||
|
0xc7, 0x69, 0x05, 0x52, 0x45, 0x60, 0xa2, 0xf1, 0xd2, 0xad, 0xa6, 0x65, 0x95, 0x41, 0xb9, 0x53,
|
||||||
|
0x39, 0x80, 0xf6, 0xa8, 0x6e, 0xb5, 0xa4, 0x1d, 0xdb, 0x7f, 0xc6, 0x6c, 0x48, 0xd5, 0x07, 0x2e,
|
||||||
|
0x39, 0x5d, 0x1f, 0x06, 0x41, 0x79, 0xe4, 0x72, 0x84, 0xf4, 0xc7, 0xd5, 0x7d, 0xaf, 0x0b, 0x88,
|
||||||
|
0x6e, 0xfc, 0x19, 0x62, 0xf6, 0xc5, 0xd8, 0x93, 0x21, 0x21, 0x5a, 0x3b, 0xbc, 0xee, 0xf0, 0xe2,
|
||||||
|
0xeb, 0xd0, 0xab, 0x21, 0x96, 0x34, 0x71, 0xf2, 0x5e, 0x01, 0x7f, 0xf8, 0x30, 0x02, 0x77, 0xb9,
|
||||||
|
0x20, 0x9b, 0x54, 0xa9, 0x89, 0x37, 0xea, 0xae, 0xae, 0xd3, 0x3b, 0x55, 0x7a, 0xef, 0x01, 0xfc,
|
||||||
|
0x96, 0x13, 0x12, 0x8c, 0xd5, 0x93, 0x36, 0x62, 0xde, 0x91, 0xe1, 0xbb, 0x23, 0xa7, 0xcb, 0x3b,
|
||||||
|
0x50, 0xf4, 0x4a, 0xe1, 0x67, 0x39, 0x5f, 0x63, 0x3f, 0xf0, 0xcf, 0x69, 0x95, 0x95, 0x08, 0xe5,
|
||||||
|
0x22, 0x3c, 0x8d, 0x66, 0x76, 0xa7, 0xa9, 0x31, 0x34, 0xb8, 0x7d, 0x96, 0xf1, 0x59, 0x83, 0x84,
|
||||||
|
0x8f, 0xe1, 0xaa, 0x5e, 0x4b, 0xa3, 0x45, 0x72, 0xba, 0x8b, 0xf2, 0xfe, 0x11, 0x88, 0x79, 0x88,
|
||||||
|
0x74, 0xc6, 0xa4, 0x95, 0xfa, 0x8a, 0x1a, 0xc8, 0xd9, 0xaf, 0x7c, 0x15, 0x13, 0x37, 0xbd, 0x27,
|
||||||
|
0x21, 0xe7, 0x11, 0xb8, 0xe9, 0x59, 0x9f, 0xc5, 0x11, 0x72, 0x7b, 0x5b, 0xf1, 0x76, 0x33, 0x7d,
|
||||||
|
0xaf, 0x8d, 0x5c, 0xca, 0xbe, 0xec, 0xe2, 0x7c, 0xca, 0x29, 0x81, 0x1b, 0xbe, 0x14, 0x22, 0xe3,
|
||||||
|
0x18, 0x1d, 0xe0, 0xb3, 0xe9, 0x1f, 0x61, 0x8d, 0xdf, 0x99, 0xf5, 0x1a, 0x9b, 0xad, 0x7c, 0xc9,
|
||||||
|
0x72, 0x08, 0xf1, 0xe3, 0x18, 0x50, 0x03, 0x8b, 0xce, 0x38, 0xb4, 0x70, 0xac, 0x53, 0x4d, 0x45,
|
||||||
|
0xb2, 0x38, 0x33, 0x40, 0xb4, 0xd6, 0x58, 0xd4, 0x9a, 0x61, 0xee, 0x83, 0x5e, 0xf5, 0x00, 0x47,
|
||||||
|
0xd4, 0x57, 0x66, 0x09, 0xa0, 0x5d, 0x4e, 0x5b, 0x57, 0xc6, 0x04, 0x8a, 0xa2, 0x91, 0x7a, 0x40,
|
||||||
|
0xf2, 0xa8, 0x5b, 0xad, 0x1a, 0x54, 0x71, 0xaa, 0xfd, 0x67, 0x3c, 0x48, 0x85, 0x8a, 0x3f, 0xe1,
|
||||||
|
0x46, 0x12, 0xe0, 0xa0, 0x21, 0x08, 0xf9, 0x59, 0x33, 0x20, 0xeb, 0x29, 0xa8, 0x55, 0x2f, 0x02,
|
||||||
|
0x5b, 0xdf, 0x3f, 0x39, 0x20, 0xeb, 0x35, 0xbc, 0xcd, 0xcd, 0x1a, 0xd3, 0xab, 0x10, 0x18, 0xd0,
|
||||||
|
0xf5, 0x21, 0x5f, 0x52, 0x62, 0xb5, 0x27, 0x0d, 0x61, 0x66, 0xc9, 0x81, 0x3c, 0xb4, 0x72, 0x61,
|
||||||
|
0x9d, 0x32, 0xa9, 0xea, 0x63, 0x1e, 0xbe, 0x0d, 0x23, 0xd0, 0xb4, 0xcb, 0x94, 0xcf, 0xcb, 0x14,
|
||||||
|
0xd0, 0x25, 0xb6, 0x0f, 0xa2, 0xf5, 0xd5, 0x90, 0xd3, 0xcb, 0x5e, 0xce, 0xd2, 0x05, 0x56, 0x46,
|
||||||
|
0xff, 0x36, 0x8d, 0x59, 0xf2, 0x89, 0x2c, 0x9f, 0xa4, 0x24, 0xc6, 0x80, 0x25, 0x59, 0x61, 0x61,
|
||||||
|
0x76, 0x66, 0x01, 0x63, 0xc8, 0x95, 0x5a, 0xd4, 0x6d, 0xc4, 0x70, 0x88, 0x6a, 0x52, 0x45, 0xaa,
|
||||||
|
0xc8, 0xa1, 0xf4, 0xfe, 0xaa, 0x06, 0x4d, 0x98, 0x5d, 0x2a, 0x7d, 0xad, 0x22, 0x2e, 0x35, 0xe0,
|
||||||
|
0x3d, 0x52, 0x01, 0xda, 0xdf, 0xa4, 0x6c, 0x01, 0x06, 0x21, 0xb4, 0xf0, 0x05, 0xa0, 0x74, 0x1e,
|
||||||
|
0xc5, 0xdc, 0x5a, 0xf2, 0x94, 0x23, 0x70, 0xb3, 0x38, 0x9a, 0x7d, 0x42, 0x1c, 0x64, 0x1a, 0xe3,
|
||||||
|
0xf4, 0xfa, 0x74, 0xb8, 0x6e, 0xea, 0x4f, 0x6c, 0xd7, 0x0c, 0x98, 0x89, 0x4d, 0x3a, 0x53, 0x4e,
|
||||||
|
0x80, 0xbe, 0xef, 0xb1, 0xd9, 0x8c, 0xaf, 0x73, 0x45, 0xdb, 0xe1, 0xef, 0xeb, 0x85, 0xab, 0xef,
|
||||||
|
0xb8, 0xbe, 0x5d, 0x27, 0xfa, 0x6e, 0x11, 0xcd, 0x77, 0x9a, 0xa6, 0x27, 0x24, 0x74, 0x24, 0xcf,
|
||||||
|
0x62, 0xde, 0x90, 0x0e, 0x03, 0x14, 0xa8, 0xf2, 0xc1, 0x2e, 0xd5, 0xaf, 0x7e, 0x26, 0x27, 0x3b,
|
||||||
|
0x4f, 0xca, 0x04, 0xe1, 0x99, 0xa5, 0x6f, 0x61, 0x51, 0xd9, 0xa9, 0x25, 0x38, 0x43, 0x4c, 0x29,
|
||||||
|
0x6a, 0x75, 0x4e, 0xa9, 0x9d, 0x94, 0x63, 0x96, 0xef, 0x41, 0xc3, 0x2a, 0x9d, 0x23, 0x33, 0x01,
|
||||||
|
0x8e, 0x2e, 0x90, 0x9c, 0x50, 0xd7, 0x79, 0x19, 0x5e, 0xd5, 0x5a, 0x24, 0x59, 0xe5, 0x52, 0xa9,
|
||||||
|
0x27, 0xe8, 0x12, 0x8a, 0x24, 0xbe, 0xc3, 0x36, 0x79, 0x87, 0x1a, 0xcc, 0x2a, 0xff, 0x9d, 0x0e,
|
||||||
|
0xf5, 0x4c, 0x75, 0xc4, 0xa8, 0x63, 0x11, 0x7b, 0xa7, 0xd0, 0x37, 0xac, 0xfe, 0x2e, 0xe4, 0x75,
|
||||||
|
0xe3, 0xee, 0xb5, 0x58, 0xdf, 0x5d, 0x88, 0xd7, 0x71, 0xb4, 0x9e, 0x0a, 0x96, 0x82, 0xe0, 0xf5,
|
||||||
|
0x2c, 0x6c, 0x42, 0x0e, 0x2a, 0x1b, 0x3b, 0x90, 0xd9, 0x36, 0x6a, 0x4f, 0xa4, 0xd9, 0x07, 0x76,
|
||||||
|
0x0d, 0x38, 0xc4, 0xbf, 0x4f, 0x9b, 0xbc, 0xf7, 0x98, 0x4d, 0xbd, 0x11, 0x37, 0x09, 0xca, 0xa8,
|
||||||
|
0xca, 0x31, 0x82, 0xc8, 0xa8, 0x86, 0xf6, 0x4e, 0x7a, 0x3b, 0x14, 0xaa, 0x14, 0x85, 0x68, 0xb5,
|
||||||
|
0x89, 0x29, 0xf3, 0xfc, 0x68, 0xa7, 0xeb, 0x61, 0x06, 0x6e, 0x80, 0xdb, 0xd3, 0xc8, 0x50, 0xeb,
|
||||||
|
0x94, 0xf0, 0xea, 0x86, 0x07, 0xd8, 0xb8, 0xe3, 0xd2, 0x3b, 0x95, 0xe5, 0xe4, 0x67, 0xa8, 0x00,
|
||||||
|
0x2b, 0x95, 0x97, 0x81, 0xce, 0x5b, 0x44, 0xf9, 0x72, 0x33, 0xf5, 0x66, 0x62, 0x35, 0x54, 0xdf,
|
||||||
|
0x64, 0x0c, 0xe9, 0x53, 0x0c, 0xfa, 0x12, 0x03, 0x3f, 0xc4, 0xb0, 0xad, 0xa6, 0x16, 0xec, 0x59,
|
||||||
|
0x7f, 0xa3, 0x41, 0xd6, 0xcb, 0x19, 0x30, 0xc4, 0xc4, 0x6a, 0x7e, 0xba, 0x21, 0xf5, 0x21, 0xca,
|
||||||
|
0x93, 0x5a, 0xb3, 0xa1, 0xf8, 0x1a, 0xa5, 0x23, 0x14, 0x09, 0xd5, 0x7b, 0xa8, 0x03, 0xb5, 0x4a,
|
||||||
|
0x94, 0x86, 0xea, 0xb4, 0x40, 0xba, 0x0e, 0x67, 0x3d, 0x18, 0x9c, 0xe5, 0x56, 0x18, 0x84, 0x62,
|
||||||
|
0xb6, 0xc1, 0xec, 0x82, 0x0b, 0x06, 0x97, 0xad, 0xb2, 0x20, 0xe1, 0x37, 0xd6, 0x3f, 0x7e, 0x79,
|
||||||
|
0xff, 0x81, 0xb3, 0x74, 0xb6, 0xfc, 0x99, 0xda, 0xfa, 0x37, 0x51, 0x12, 0x8a, 0x1b, 0x2f, 0x16,
|
||||||
|
0x33, 0xf2, 0xfc, 0xbc, 0x8c, 0x5e, 0x3a, 0x2e, 0x26, 0xbf, 0x03, 0x39, 0xce, 0x83, 0xfd, 0xf5,
|
||||||
|
0xed, 0x65, 0x62, 0x3b, 0xe7, 0xcd, 0x06, 0xbf, 0x39, 0x1c, 0x87, 0x9d, 0x77, 0x35, 0xfa, 0xe0,
|
||||||
|
0x06, 0xd1, 0x7f, 0x6c, 0x77, 0x9d, 0x8a, 0x5c, 0x00, 0xd9, 0xa5, 0x2e, 0xf5, 0xed, 0x20, 0x08,
|
||||||
|
0x9a, 0x23, 0x74, 0x97, 0x73, 0x69, 0x7c, 0x6c, 0x7f, 0x57, 0x07, 0xac, 0x23, 0xb1, 0xd0, 0xde,
|
||||||
|
0xfc, 0x06, 0x1b, 0x0b, 0x3e, 0xbe, 0xd8, 0xea, 0x17, 0xc5, 0x70, 0xf8, 0x62, 0x8b, 0x0b, 0x17,
|
||||||
|
0x1f, 0x27, 0x12, 0x1f, 0x3a, 0x9d, 0x1f, 0x80, 0x86, 0x47, 0xac, 0xf4, 0xab, 0x04, 0xbf, 0x33,
|
||||||
|
0xd1, 0xb7, 0x9e, 0xb4, 0xa7, 0xf8, 0xe8, 0x96, 0x6d, 0x2c, 0x0c, 0xdf, 0x62, 0x3d, 0xe3, 0xfb,
|
||||||
|
0x08, 0x1c, 0x3a, 0xa0, 0x49, 0x1f, 0x62, 0x42, 0xca, 0x8c, 0xb8, 0x2c, 0xbb, 0x4b, 0x66, 0x7d,
|
||||||
|
0x27, 0x38, 0xdb, 0x3e, 0x08, 0x43, 0x35, 0x73, 0xf1, 0xd1, 0x65, 0x37, 0x2c, 0xc2, 0xd2, 0x53,
|
||||||
|
0x99, 0x38, 0xea, 0x3b, 0xaa, 0x41, 0xba, 0x02, 0x7d, 0xa7, 0x5c, 0x96, 0xec, 0x56, 0xdf, 0x29,
|
||||||
|
0xa8, 0x56, 0xc6, 0xc2, 0x8c, 0x2b, 0x8a, 0x3d, 0xae, 0x13, 0x5c, 0x5e, 0xb9, 0xf4, 0xcc, 0x93,
|
||||||
|
0x90, 0x9e, 0xb7, 0xc5, 0x64, 0xbe, 0x49, 0xe8, 0x98, 0xcd, 0xd2, 0xbb, 0xe3, 0xce, 0x36, 0xe5,
|
||||||
|
0xf9, 0x26, 0x4d, 0xac, 0x10, 0xe9, 0xf5, 0x56, 0x36, 0x7f, 0x77, 0xf7, 0x2e, 0x84, 0x57, 0x45,
|
||||||
|
0xd9, 0xbd, 0xb1, 0xda, 0x56, 0xe2, 0xca, 0x40, 0x52, 0xe9, 0x0d, 0x38, 0x13, 0xee, 0x91, 0x74,
|
||||||
|
0xc8, 0x8b, 0xa7, 0xdc, 0xbb, 0xbe, 0x5d, 0x3a, 0x06, 0xb6, 0x5b, 0xdf, 0xac, 0x53, 0x10, 0x7e,
|
||||||
|
0xac, 0x72, 0x31, 0x54, 0x02, 0x31, 0x20, 0x51, 0xaf, 0xb3, 0xa5, 0x6e, 0x3e, 0x2f, 0xaa, 0xe5,
|
||||||
|
0xca, 0x10, 0xc4, 0x71, 0xd5, 0xdb, 0xdc, 0x78, 0x6b, 0x78, 0xe1, 0xe5, 0xfb, 0xc4, 0x78, 0x2f,
|
||||||
|
0xa9, 0xe9, 0xb2, 0x40, 0x93, 0x63, 0xcf, 0x1e, 0xae, 0x49, 0x3b, 0x64, 0x1e, 0xe5, 0xac, 0xdd,
|
||||||
|
0xcc, 0x7c, 0x45, 0x4d, 0x93, 0x3c, 0xbd, 0x53, 0xdb, 0x16, 0x81, 0xa4, 0xc5, 0x9c, 0x43, 0xd0,
|
||||||
|
0xde, 0x67, 0x8e, 0x1b, 0xab, 0x06, 0x41, 0xa3, 0x81, 0x38, 0x51, 0xf0, 0xd3, 0xf4, 0x77, 0x70,
|
||||||
|
0x10, 0xbc, 0x4f, 0xfc, 0x2e, 0xeb, 0xc7, 0x8e, 0x9b, 0x06, 0x91, 0x07, 0x6c, 0x0c, 0xa2, 0xdc,
|
||||||
|
0xe7, 0xc1, 0x99, 0x2d, 0xe8, 0x2d, 0xb0, 0x34, 0x2a, 0x30, 0x31, 0xb7, 0xe2, 0x4b, 0x7e, 0xf5,
|
||||||
|
0xf2, 0xe5, 0x33, 0xbc, 0x78, 0x7a, 0xf7, 0x2f, 0x5f, 0xd2, 0x63, 0xa2, 0xaf, 0x5e, 0x06, 0x3a,
|
||||||
|
0x24, 0xcf, 0xfe, 0x13, 0xd4, 0x46, 0x3f, 0x71, 0x1c, 0x77, 0x46, 0x53, 0x26, 0xe1, 0x03, 0x13,
|
||||||
|
0x3e, 0x38, 0x1f, 0xc8, 0x53, 0xe2, 0xdc, 0xdf, 0xaf, 0xf1, 0xc3, 0xb5, 0x77, 0x80, 0x95, 0xc8,
|
||||||
|
0x5b, 0x8b, 0x75, 0xdf, 0x71, 0xf6, 0xc6, 0x6e, 0x18, 0x6c, 0xd7, 0x19, 0x70, 0x91, 0x5f, 0xbe,
|
||||||
|
0x9c, 0x39, 0x6e, 0xe2, 0x27, 0xae, 0x48, 0xfc, 0x67, 0x23, 0x57, 0xf8, 0xcf, 0xc6, 0xae, 0x9e,
|
||||||
|
0xd6, 0x87, 0xae, 0x7e, 0xea, 0x02, 0x41, 0xfc, 0x6f, 0xd3, 0x94, 0xdd, 0x79, 0xf3, 0x54, 0xac,
|
||||||
|
0xfa, 0xdb, 0x98, 0x27, 0x8b, 0x7c, 0xe9, 0xa7, 0x9e, 0xbc, 0x29, 0x5c, 0x64, 0xff, 0xf1, 0xe8,
|
||||||
|
0x15, 0x77, 0x5c, 0xa3, 0x72, 0xe2, 0x31, 0x23, 0x72, 0xc0, 0x1e, 0x5f, 0x83, 0x6f, 0xe0, 0x8f,
|
||||||
|
0x5c, 0xe0, 0x64, 0x3c, 0xd3, 0x75, 0x57, 0xc1, 0x76, 0xc5, 0xf3, 0xa5, 0x08, 0x7d, 0xfb, 0xe7,
|
||||||
|
0x9f, 0x3e, 0x5c, 0xd8, 0x2e, 0xaa, 0x36, 0x1f, 0xcf, 0x13, 0x00, 0x4b, 0x69, 0x94, 0x80, 0xbf,
|
||||||
|
0x74, 0xd7, 0x0f, 0x9d, 0xc2, 0x20, 0x1a, 0xaf, 0x11, 0x2d, 0x73, 0x57, 0xc0, 0x19, 0xaa, 0x6e,
|
||||||
|
0x09, 0x79, 0x47, 0xbe, 0xe4, 0x8a, 0x80, 0x13, 0xc0, 0x16, 0x69, 0xd8, 0xfe, 0xc7, 0x9f, 0xd5,
|
||||||
|
0x3e, 0x2d, 0xfb, 0xc5, 0x36, 0x29, 0xc0, 0x56, 0x01, 0x5e, 0x2c, 0x35, 0x10, 0xad, 0xd1, 0xdd,
|
||||||
|
0x47, 0xfc, 0xce, 0x09, 0xe7, 0x04, 0x51, 0x92, 0x63, 0xec, 0xb7, 0x54, 0xf7, 0x04, 0x3d, 0xb1,
|
||||||
|
0x26, 0x49, 0x32, 0x96, 0x6f, 0xd9, 0x7b, 0xdc, 0xb5, 0xe9, 0xac, 0xdd, 0x76, 0x8a, 0xe6, 0x10,
|
||||||
|
0xf3, 0x55, 0x43, 0x1a, 0x22, 0xf0, 0x6f, 0x52, 0xec, 0x91, 0x07, 0x80, 0xf6, 0x24, 0x38, 0xe2,
|
||||||
|
0x07, 0x5a, 0xfe, 0x9e, 0xc6, 0xc0, 0xa8, 0x1f, 0x44, 0x30, 0x9a, 0x64, 0x4b, 0x71, 0xd3, 0x77,
|
||||||
|
0x94, 0xba, 0x8b, 0x41, 0x4e, 0x57, 0x6c, 0xdd, 0x97, 0x8b, 0x02, 0x2b, 0x25, 0x74, 0x7a, 0x28,
|
||||||
|
0x56, 0x51, 0xc6, 0xfb, 0xfd, 0xdc, 0x8d, 0x51, 0x6b, 0xc1, 0xbc, 0x17, 0xd1, 0x8a, 0x8b, 0x4d,
|
||||||
|
0xde, 0xaf, 0x54, 0x59, 0x85, 0xda, 0xa4, 0x29, 0x0f, 0x5a, 0x40, 0x12, 0x2d, 0x0f, 0x71, 0x4d,
|
||||||
|
0x1e, 0x04, 0x0a, 0x48, 0x2c, 0x99, 0x37, 0xef, 0x60, 0x5e, 0x71, 0x99, 0xa3, 0x34, 0xe0, 0xc5,
|
||||||
|
0xe0, 0x5e, 0x7a, 0x44, 0xae, 0xe5, 0x5e, 0x8d, 0x6f, 0xe3, 0x8a, 0x6f, 0x53, 0xbd, 0x0c, 0xf8,
|
||||||
|
0x01, 0xd1, 0x22, 0x01, 0x9c, 0x35, 0xf9, 0x38, 0x02, 0x45, 0x09, 0x92, 0xf3, 0x08, 0xee, 0x49,
|
||||||
|
0x6b, 0xdc, 0x93, 0x37, 0xb8, 0x67, 0x66, 0x70, 0x4f, 0xa2, 0xb9, 0x27, 0xd7, 0xdc, 0x93, 0x54,
|
||||||
|
0xdc, 0x23, 0x0f, 0x74, 0x81, 0x77, 0x00, 0xea, 0xff, 0x0d, 0xee, 0x01, 0xa4, 0x42, 0xc0, 0x74,
|
||||||
|
0xb7, 0x05, 0xe5, 0x09, 0x72, 0x92, 0xbc, 0x12, 0x7b, 0x7b, 0xb0, 0x65, 0x67, 0x22, 0x21, 0x54,
|
||||||
|
0x84, 0xf5, 0xa0, 0x0b, 0x6a, 0xa5, 0xfc, 0xbc, 0x93, 0xb2, 0xb2, 0x6f, 0xa5, 0x85, 0x3d, 0x08,
|
||||||
|
0xb7, 0x93, 0x3e, 0xbd, 0x5a, 0x46, 0x21, 0x47, 0x63, 0xe3, 0xa9, 0x75, 0xea, 0xad, 0xb0, 0xa0,
|
||||||
|
0xe3, 0xab, 0x87, 0x26, 0x17, 0x2b, 0xbb, 0x55, 0x4a, 0xa3, 0xc1, 0x9e, 0x18, 0x28, 0x9e, 0xe3,
|
||||||
|
0x52, 0xc1, 0xd0, 0x06, 0x2e, 0x2f, 0xd5, 0xb4, 0x0a, 0x7b, 0x1d, 0xcd, 0xb1, 0xbb, 0x38, 0x8e,
|
||||||
|
0xa3, 0x2a, 0x6f, 0x70, 0x5c, 0x16, 0x5c, 0xda, 0x18, 0x4a, 0xd9, 0x2e, 0x5c, 0xf0, 0x2f, 0x04,
|
||||||
|
0x53, 0xf0, 0x17, 0x03, 0xa9, 0x2b, 0xe4, 0x4f, 0x43, 0x1b, 0x2b, 0x23, 0x83, 0x46, 0x81, 0xac,
|
||||||
|
0x88, 0x7b, 0x99, 0xb8, 0xec, 0x2a, 0xc8, 0x3d, 0xf0, 0x46, 0x23, 0x00, 0xc3, 0x03, 0x08, 0x94,
|
||||||
|
0x8d, 0x04, 0x22, 0xa2, 0x6b, 0x90, 0x57, 0x56, 0x0d, 0x20, 0xb6, 0xc1, 0x94, 0x64, 0x5e, 0x94,
|
||||||
|
0xcc, 0xe2, 0x4d, 0x08, 0x5b, 0x64, 0xc8, 0x62, 0x71, 0x70, 0x49, 0x9f, 0x0d, 0xfa, 0x76, 0x23,
|
||||||
|
0x36, 0xb7, 0x5d, 0x69, 0x8e, 0x6c, 0xbb, 0x70, 0x55, 0x0f, 0x19, 0x8c, 0x97, 0x2f, 0x54, 0x8c,
|
||||||
|
0x5e, 0x5c, 0x4d, 0xc4, 0xcb, 0x97, 0xc8, 0xdd, 0x9b, 0x6c, 0xd9, 0xf7, 0x3c, 0x4f, 0x90, 0x9c,
|
||||||
|
0xf6, 0x25, 0x9c, 0xbc, 0x00, 0xbc, 0xf7, 0xe5, 0x04, 0x5c, 0x8d, 0x04, 0x97, 0x42, 0x23, 0xb5,
|
||||||
|
0x00, 0x8f, 0x02, 0x9c, 0x08, 0x20, 0x3c, 0x10, 0x19, 0x40, 0x03, 0x6f, 0xe4, 0x87, 0x8b, 0xbf,
|
||||||
|
0xbf, 0x0f, 0x6c, 0xdb, 0x05, 0xb9, 0x13, 0xe9, 0x5b, 0x06, 0x68, 0x6b, 0x0c, 0x4f, 0x70, 0xca,
|
||||||
|
0x52, 0xb1, 0xa0, 0x1a, 0xf8, 0x89, 0xb2, 0x03, 0xc0, 0x5d, 0x09, 0xe0, 0xde, 0xc3, 0x9a, 0xfb,
|
||||||
|
0x24, 0x7c, 0x8d, 0xd5, 0x65, 0xb4, 0x47, 0xe7, 0x11, 0x5c, 0xa8, 0x78, 0xa1, 0xc9, 0x0c, 0x95,
|
||||||
|
0x57, 0xd3, 0x76, 0x24, 0xca, 0xa3, 0x32, 0xc7, 0x64, 0x05, 0x5d, 0x21, 0x00, 0x66, 0xc8, 0xf0,
|
||||||
|
0x39, 0x28, 0xd9, 0x8c, 0xc4, 0xaf, 0x7c, 0x35, 0x99, 0xfc, 0xed, 0x60, 0x99, 0x96, 0x42, 0x1c,
|
||||||
|
0x66, 0x58, 0xfb, 0x63, 0xbb, 0x75, 0x6b, 0x9e, 0xa1, 0x60, 0xf3, 0x85, 0x1f, 0x17, 0x6d, 0x9b,
|
||||||
|
0x5e, 0x91, 0x54, 0x9e, 0xc6, 0xbd, 0xe1, 0x73, 0xb6, 0x89, 0x73, 0x4d, 0xb9, 0x91, 0xab, 0x3f,
|
||||||
|
0x3d, 0x70, 0xcb, 0xef, 0x11, 0x80, 0x8a, 0x31, 0x50, 0x31, 0x22, 0x5e, 0x02, 0x7e, 0x19, 0xc1,
|
||||||
|
0x3c, 0x25, 0x45, 0x63, 0x45, 0xd1, 0x28, 0x04, 0x22, 0x24, 0x7e, 0xee, 0x92, 0x85, 0x07, 0x33,
|
||||||
|
0x9b, 0x61, 0x29, 0x1b, 0x93, 0x8f, 0xbf, 0xfa, 0x19, 0x3d, 0xff, 0xea, 0x0b, 0x83, 0xe6, 0xf9,
|
||||||
|
0xfd, 0x7d, 0x09, 0x06, 0xaa, 0x06, 0xe5, 0x21, 0x29, 0x08, 0xd8, 0x20, 0xd1, 0x20, 0x88, 0x41,
|
||||||
|
0x86, 0x5c, 0xe0, 0xb8, 0xbc, 0xce, 0x06, 0x51, 0x93, 0x0d, 0x32, 0x35, 0x87, 0x50, 0x73, 0xc4,
|
||||||
|
0x7a, 0x86, 0xa8, 0x70, 0xd3, 0x8a, 0x33, 0x66, 0x26, 0x67, 0x64, 0xae, 0x00, 0x3b, 0xe2, 0xe1,
|
||||||
|
0x79, 0x25, 0x28, 0x12, 0x4f, 0x9e, 0x61, 0xc6, 0x6e, 0xd5, 0xa2, 0x0e, 0x31, 0x23, 0x77, 0x04,
|
||||||
|
0x7a, 0x3b, 0x05, 0x44, 0xcc, 0xbc, 0xb2, 0x1a, 0x00, 0x1c, 0x89, 0x44, 0xf9, 0xd1, 0xb1, 0xcb,
|
||||||
|
0xd4, 0x5d, 0x04, 0xec, 0xaa, 0xda, 0x5e, 0x45, 0x67, 0x47, 0xe3, 0xfd, 0xf3, 0x03, 0x7f, 0x8c,
|
||||||
|
0xc0, 0x83, 0x73, 0x0d, 0x4e, 0x48, 0xf1, 0x14, 0xa6, 0x7b, 0x56, 0xe7, 0x3a, 0x60, 0xb6, 0xa7,
|
||||||
|
0xfa, 0xd4, 0xa5, 0x95, 0xd4, 0x49, 0x22, 0xc3, 0x01, 0xd5, 0x79, 0x26, 0x90, 0x7d, 0x4a, 0xe9,
|
||||||
|
0x18, 0x1c, 0x2c, 0x53, 0x3c, 0x4e, 0xe5, 0x6c, 0xa3, 0x40, 0x53, 0x5e, 0xc3, 0x70, 0xb7, 0x1b,
|
||||||
|
0x76, 0x36, 0x69, 0x0a, 0x1f, 0xf5, 0x9f, 0xb0, 0x8e, 0xa8, 0x42, 0x6a, 0x8b, 0xbe, 0xb1, 0xaf,
|
||||||
|
0x5c, 0x0a, 0xa4, 0xdb, 0xd5, 0x5b, 0x62, 0xa7, 0xd6, 0x3d, 0xe9, 0xe3, 0x02, 0x64, 0x66, 0xb4,
|
||||||
|
0xb5, 0x51, 0x55, 0x97, 0x12, 0x15, 0xb6, 0xa3, 0x66, 0xcb, 0xd2, 0x59, 0x00, 0x9a, 0xa6, 0x29,
|
||||||
|
0xbe, 0x0b, 0x95, 0x06, 0xea, 0x14, 0x5f, 0xb5, 0x79, 0xd4, 0xaf, 0x3c, 0xbb, 0x1c, 0x5d, 0x75,
|
||||||
|
0xf9, 0xe7, 0x5a, 0xb1, 0x77, 0xf9, 0xe6, 0xaa, 0x0e, 0xa3, 0x43, 0x82, 0x0d, 0x31, 0x2f, 0xf3,
|
||||||
|
0x3e, 0xa8, 0xe8, 0x8d, 0xd6, 0x5a, 0x0e, 0x09, 0xfd, 0x10, 0xad, 0x4d, 0x81, 0xfd, 0xf2, 0x73,
|
||||||
|
0x90, 0x7d, 0x4f, 0xf6, 0x90, 0x6e, 0x02, 0x3c, 0x03, 0x41, 0x40, 0xee, 0xb4, 0xff, 0x5e, 0xd1,
|
||||||
|
0x09, 0x5c, 0x94, 0xad, 0xfc, 0x7a, 0xdd, 0x8f, 0xdc, 0x69, 0x1a, 0x81, 0x87, 0x0b, 0x52, 0x3a,
|
||||||
|
0x73, 0x23, 0x3f, 0x2c, 0x02, 0xbd, 0x0e, 0x98, 0x50, 0x65, 0x57, 0x4d, 0x62, 0xa2, 0x45, 0xa9,
|
||||||
|
0xbb, 0x21, 0x66, 0x10, 0xe6, 0x6e, 0xa5, 0x0f, 0x2d, 0xe7, 0x44, 0x4d, 0xb3, 0x2d, 0x27, 0x06,
|
||||||
|
0xbb, 0x41, 0x66, 0x54, 0x31, 0xdd, 0x2a, 0xc0, 0x64, 0x1a, 0xcb, 0x65, 0xe1, 0x4e, 0x3f, 0x71,
|
||||||
|
0x1b, 0x1e, 0x8a, 0x39, 0x2d, 0x5a, 0x78, 0x25, 0x38, 0x2b, 0x30, 0x46, 0xa6, 0xae, 0x8e, 0xbe,
|
||||||
|
0x40, 0x51, 0x6b, 0x4a, 0x97, 0xc7, 0xd9, 0x8f, 0x23, 0x79, 0x87, 0x0d, 0x37, 0xf5, 0xb6, 0x41,
|
||||||
|
0x3d, 0xc5, 0x00, 0xac, 0x1d, 0x9c, 0xa9, 0x37, 0x99, 0xf1, 0x46, 0x9d, 0x8d, 0x95, 0xef, 0x44,
|
||||||
|
0x07, 0xdb, 0xe8, 0x77, 0xf1, 0x8e, 0x60, 0x91, 0x74, 0x5d, 0xa4, 0x74, 0x5d, 0x5a, 0xa0, 0x95,
|
||||||
|
0x57, 0x0a, 0x49, 0xea, 0x34, 0x84, 0xbf, 0xcd, 0x7a, 0x39, 0x89, 0xe4, 0xf7, 0x40, 0x8e, 0x37,
|
||||||
|
0xa0, 0xd9, 0x26, 0xd1, 0xbc, 0x6f, 0x30, 0x56, 0xea, 0x68, 0xe3, 0xa8, 0xb6, 0x6b, 0xbb, 0x1c,
|
||||||
|
0xa2, 0xe0, 0x38, 0xe3, 0x9d, 0xa1, 0x47, 0x8a, 0xb8, 0xd0, 0xe1, 0xc6, 0x34, 0x16, 0x53, 0xd4,
|
||||||
|
0x43, 0x72, 0x7e, 0xc0, 0x5f, 0xff, 0x32, 0xb9, 0x72, 0x23, 0x80, 0x13, 0x5c, 0x61, 0x3f, 0xf1,
|
||||||
|
0xf0, 0x52, 0x54, 0xd6, 0xb7, 0x5c, 0x00, 0xe4, 0x5d, 0xeb, 0x63, 0x73, 0xee, 0x32, 0x23, 0x45,
|
||||||
|
0x87, 0x26, 0x2b, 0xcc, 0x26, 0xe5, 0x42, 0xc4, 0xde, 0x35, 0x07, 0x0a, 0xc5, 0x38, 0xc9, 0x90,
|
||||||
|
0xad, 0xa3, 0x21, 0x46, 0xe2, 0x43, 0x89, 0xcd, 0x73, 0xb6, 0x12, 0x1b, 0xfc, 0x35, 0x91, 0xbd,
|
||||||
|
0xcc, 0xed, 0xf2, 0x8a, 0x73, 0x60, 0xca, 0xad, 0xaa, 0x21, 0xf6, 0x43, 0x57, 0x0e, 0xf2, 0x57,
|
||||||
|
0xda, 0x3a, 0xce, 0xb4, 0xcb, 0x0b, 0x28, 0x79, 0x36, 0xf3, 0xc4, 0x27, 0x47, 0xa9, 0xb7, 0x6b,
|
||||||
|
0x11, 0xe1, 0x61, 0x01, 0xb2, 0x5b, 0x58, 0xb2, 0xdb, 0xa4, 0x91, 0x9e, 0x50, 0x8c, 0xbe, 0xc1,
|
||||||
|
0x4c, 0xc5, 0x1a, 0xff, 0x2c, 0x83, 0x31, 0x3f, 0x78, 0x15, 0xbb, 0x8b, 0x60, 0x55, 0x45, 0x25,
|
||||||
|
0x18, 0xfa, 0x54, 0xda, 0x31, 0x69, 0xc9, 0x2a, 0xaf, 0x64, 0x35, 0x23, 0xb9, 0x12, 0x28, 0xab,
|
||||||
|
0x31, 0x88, 0x54, 0x64, 0xc8, 0x6a, 0x82, 0x41, 0xb8, 0x21, 0x7c, 0xa2, 0x14, 0x3e, 0xd9, 0xb3,
|
||||||
|
0x80, 0xb0, 0x00, 0x3c, 0x28, 0x56, 0x58, 0x2f, 0xb6, 0xf9, 0xde, 0xb8, 0xf8, 0x38, 0xd9, 0x48,
|
||||||
|
0x43, 0x0d, 0x8d, 0xb3, 0xe2, 0xfe, 0xc5, 0xb6, 0x1d, 0x1f, 0x7c, 0x74, 0xdc, 0xb5, 0xec, 0x03,
|
||||||
|
0x5e, 0x83, 0xb9, 0x35, 0xd9, 0x58, 0x57, 0x02, 0xa9, 0xbb, 0x4d, 0x40, 0xce, 0x21, 0x76, 0x1e,
|
||||||
|
0xa1, 0xef, 0xd4, 0xe5, 0x91, 0x2f, 0xb4, 0xe4, 0xdf, 0x05, 0x1b, 0xda, 0x7e, 0xe9, 0x9c, 0x5e,
|
||||||
|
0x82, 0x81, 0xb8, 0x82, 0xc0, 0x47, 0x79, 0xa4, 0xf7, 0xe4, 0xf4, 0xd4, 0xb4, 0x83, 0x40, 0x27,
|
||||||
|
0x4d, 0xe2, 0x1e, 0x00, 0xbe, 0xc4, 0xf2, 0x39, 0x57, 0xd6, 0xc5, 0x5d, 0x55, 0xae, 0xa9, 0x70,
|
||||||
|
0xce, 0xed, 0xe7, 0xb6, 0x6f, 0x0f, 0x87, 0x36, 0x6d, 0xb3, 0xf8, 0xaf, 0x04, 0x77, 0x0c, 0x7e,
|
||||||
|
0xe2, 0x44, 0x9b, 0xe2, 0x3b, 0xef, 0x77, 0x11, 0x25, 0x7d, 0xfb, 0xbf, 0x50, 0x5a, 0x14, 0xfd,
|
||||||
|
0x20, 0x62, 0x52, 0x5f, 0x71, 0xb4, 0x74, 0xac, 0xbb, 0x76, 0x97, 0x4f, 0xd1, 0x2f, 0xa5, 0x66,
|
||||||
|
0x29, 0xe9, 0xc2, 0xeb, 0x49, 0x1e, 0xd3, 0x4c, 0x54, 0x4e, 0x5f, 0x87, 0x9d, 0x30, 0xfc, 0xc4,
|
||||||
|
0x0e, 0x25, 0x62, 0x54, 0x1d, 0x75, 0xaa, 0x12, 0xed, 0x3a, 0x76, 0x68, 0x12, 0xed, 0x42, 0x02,
|
||||||
|
0x53, 0xc9, 0x0f, 0xfb, 0x6a, 0xba, 0xc4, 0x2c, 0xb5, 0x40, 0x8e, 0x2a, 0x23, 0xcb, 0x0c, 0xe3,
|
||||||
|
0xca, 0xf2, 0x09, 0xed, 0x87, 0xf4, 0xa3, 0x42, 0xed, 0x47, 0xad, 0x3a, 0x81, 0xef, 0x50, 0x3f,
|
||||||
|
0xda, 0x7b, 0x72, 0x37, 0xd5, 0x7c, 0x40, 0x83, 0x75, 0xf5, 0xb4, 0x02, 0x57, 0x05, 0xc3, 0x60,
|
||||||
|
0x06, 0xe4, 0x66, 0x31, 0x15, 0x6a, 0x80, 0xc8, 0x94, 0x0d, 0xb2, 0x6e, 0xc2, 0xbd, 0x0b, 0xe2,
|
||||||
|
0xf3, 0xd4, 0x5f, 0xba, 0x73, 0xb8, 0xce, 0xfc, 0x85, 0x7b, 0x0d, 0xd7, 0x8d, 0x7f, 0xe7, 0xde,
|
||||||
|
0xc0, 0x75, 0xed, 0xcf, 0xdd, 0xf7, 0xc1, 0xdf, 0x59, 0xbe, 0xf4, 0xe6, 0xb1, 0x00, 0x3f, 0xa0,
|
||||||
|
0xbf, 0x19, 0xdc, 0x39, 0xc3, 0x7d, 0xc7, 0x7d, 0x5b, 0x6b, 0x5d, 0x0f, 0xe6, 0xd4, 0x3a, 0x0d,
|
||||||
|
0x0e, 0x4f, 0x5e, 0x5d, 0xbb, 0xbf, 0xe3, 0xe5, 0xc6, 0xbd, 0x0d, 0xa6, 0xa7, 0xc1, 0xd7, 0xc7,
|
||||||
|
0x27, 0xe7, 0xe3, 0x43, 0x7f, 0x7c, 0xe2, 0x7e, 0x40, 0xd1, 0xdd, 0xce, 0xf2, 0x5b, 0xff, 0xa2,
|
||||||
|
0x08, 0x24, 0x59, 0x5f, 0x93, 0x3c, 0xf6, 0xef, 0xdc, 0xb9, 0x33, 0xb9, 0xc0, 0x2f, 0x90, 0x6f,
|
||||||
|
0x94, 0xac, 0xba, 0x23, 0xf8, 0x0f, 0x35, 0x4b, 0x56, 0x7f, 0x13, 0x5c, 0x60, 0xde, 0x91, 0xde,
|
||||||
|
0xa2, 0x6e, 0xed, 0xeb, 0xf7, 0x84, 0x85, 0x52, 0xb0, 0x5f, 0xb8, 0x38, 0xfd, 0xa7, 0xc6, 0xf4,
|
||||||
|
0x53, 0xf7, 0x77, 0x67, 0xf2, 0x09, 0xed, 0x4e, 0xfc, 0x41, 0x1e, 0x21, 0x3c, 0x1f, 0xd1, 0x3f,
|
||||||
|
0xdb, 0x95, 0xad, 0xbf, 0x00, 0x6a, 0x69, 0x46, 0xea, 0x09, 0x02, 0xd3, 0xc7, 0x24, 0x08, 0x0f,
|
||||||
|
0x46, 0x13, 0x7e, 0x7a, 0x33, 0xe1, 0x10, 0x1b, 0xeb, 0xb6, 0x1c, 0xda, 0xf2, 0xd3, 0xeb, 0x49,
|
||||||
|
0x0e, 0x6d, 0x5b, 0x6c, 0x00, 0x7b, 0xf5, 0xea, 0x7a, 0x0f, 0x34, 0x01, 0x48, 0x1a, 0x6c, 0x1a,
|
||||||
|
0x9c, 0x73, 0xbc, 0x70, 0xf0, 0x29, 0xf2, 0xc1, 0x7b, 0x08, 0x06, 0xf8, 0xe0, 0x2d, 0x90, 0xdf,
|
||||||
|
0x56, 0xeb, 0xa1, 0xfe, 0x03, 0x47, 0x5f, 0x9c, 0x05, 0x23, 0xf8, 0x7b, 0x7a, 0xf7, 0xf2, 0x65,
|
||||||
|
0x44, 0xb7, 0xd1, 0xe9, 0xfc, 0xfe, 0xfe, 0x19, 0xbc, 0xc9, 0xb1, 0x8d, 0x9f, 0xce, 0xf5, 0xe4,
|
||||||
|
0xf1, 0x79, 0xf4, 0xea, 0x6e, 0x4f, 0xf8, 0x1c, 0xfe, 0xe6, 0x13, 0xe0, 0x23, 0x54, 0xd8, 0x74,
|
||||||
|
0x34, 0xde, 0x7f, 0x73, 0x79, 0xf8, 0x0a, 0x8c, 0x00, 0x5d, 0xf6, 0xc6, 0xfa, 0x66, 0x5f, 0xdf,
|
||||||
|
0x1c, 0x5c, 0x51, 0xaa, 0x77, 0x9b, 0x82, 0x36, 0x59, 0x00, 0x7b, 0x4d, 0x91, 0xb3, 0x96, 0xfc,
|
||||||
|
0xf6, 0x42, 0xfc, 0xb2, 0x98, 0x82, 0x5a, 0x9a, 0x7c, 0x90, 0xea, 0x07, 0xec, 0x8c, 0x89, 0x9a,
|
||||||
|
0x8f, 0x29, 0xbc, 0x45, 0x55, 0xe6, 0x82, 0xe4, 0x87, 0xf4, 0x77, 0x55, 0x38, 0x1f, 0x4d, 0x44,
|
||||||
|
0x41, 0xc4, 0xe1, 0x1e, 0x9e, 0xc0, 0x7f, 0x9d, 0x02, 0xad, 0x97, 0xa5, 0x26, 0xd2, 0x7b, 0x44,
|
||||||
|
0x54, 0xe3, 0x87, 0x2b, 0xc4, 0x6f, 0xc1, 0x18, 0x46, 0xe2, 0xd9, 0xed, 0x27, 0xae, 0x51, 0x3f,
|
||||||
|
0xa6, 0x7f, 0x76, 0xd9, 0xde, 0x98, 0x93, 0xf2, 0x4f, 0x60, 0xae, 0xf6, 0xf6, 0x0f, 0xdd, 0x30,
|
||||||
|
0xc8, 0xe0, 0x82, 0xa4, 0x13, 0x60, 0x7b, 0x6e, 0xf7, 0xec, 0xf5, 0xad, 0xf5, 0x6d, 0x1a, 0xb1,
|
||||||
|
0xd8, 0xae, 0xc1, 0xac, 0x57, 0x46, 0x23, 0x7b, 0x5e, 0x9e, 0xd6, 0xfb, 0xe6, 0x52, 0x68, 0xcf,
|
||||||
|
0xbf, 0xc5, 0x4f, 0xed, 0x02, 0x5b, 0x7e, 0x65, 0xa7, 0x1b, 0xbf, 0x03, 0x11, 0x42, 0x68, 0x03,
|
||||||
|
0x7b, 0x15, 0x85, 0x61, 0xcc, 0xf5, 0xcc, 0x17, 0xf0, 0x0e, 0x7c, 0xa9, 0x99, 0x1b, 0x3a, 0x85,
|
||||||
|
0x2c, 0xbb, 0xea, 0xe7, 0xa0, 0x82, 0xa0, 0xb7, 0x3d, 0xb6, 0xfd, 0x28, 0xf8, 0x30, 0x99, 0x02,
|
||||||
|
0x8b, 0x7d, 0x9a, 0x50, 0xcb, 0x3e, 0xb6, 0xd0, 0xd7, 0xb6, 0xfd, 0x0f, 0x8e, 0xf9, 0xe2, 0x00,
|
||||||
|
0x5f, 0x50, 0xa1, 0x22, 0xbc, 0x28, 0xa4, 0xde, 0xad, 0x78, 0x15, 0xed, 0x4b, 0x29, 0xac, 0xcc,
|
||||||
|
0x41, 0x73, 0x54, 0x3e, 0x82, 0x1d, 0x22, 0x73, 0x53, 0x69, 0x42, 0x9a, 0x85, 0x4b, 0xc6, 0x00,
|
||||||
|
0x36, 0x04, 0xef, 0x60, 0x84, 0x21, 0x2d, 0x3a, 0x52, 0x19, 0x1a, 0x49, 0x5e, 0x85, 0x6a, 0xc0,
|
||||||
|
0x7e, 0x68, 0x09, 0x81, 0xd9, 0xf8, 0xb3, 0x20, 0x60, 0xe0, 0xca, 0x07, 0x62, 0x32, 0x0e, 0x82,
|
||||||
|
0x64, 0x90, 0x9f, 0x67, 0x92, 0x5a, 0xcc, 0xf1, 0xd5, 0x1d, 0xd8, 0x0c, 0xf0, 0x13, 0xc0, 0x19,
|
||||||
|
0x13, 0x05, 0x43, 0x37, 0x5e, 0x27, 0x31, 0xc6, 0x94, 0x43, 0x93, 0x59, 0xd6, 0xee, 0x71, 0xfa,
|
||||||
|
0x2d, 0x0e, 0xcf, 0x2a, 0x48, 0x0d, 0x1e, 0x05, 0x93, 0x4c, 0xb3, 0x2b, 0xdd, 0xad, 0x35, 0x65,
|
||||||
|
0xd6, 0x4c, 0xc2, 0x9b, 0x65, 0x26, 0x9d, 0xda, 0x56, 0x56, 0x64, 0x94, 0xb0, 0x61, 0x9c, 0xc8,
|
||||||
|
0xce, 0xb3, 0x73, 0x51, 0x65, 0x58, 0x9e, 0x53, 0x86, 0xc5, 0xcb, 0xc5, 0x7b, 0x71, 0xc3, 0xd3,
|
||||||
|
0xd7, 0x80, 0xfd, 0xbe, 0x83, 0x3f, 0x5c, 0x76, 0x21, 0x7e, 0x00, 0xb2, 0xec, 0x1f, 0x1d, 0xb9,
|
||||||
|
0xea, 0x7f, 0x46, 0x2b, 0x81, 0x67, 0x1e, 0x5f, 0x68, 0xf1, 0x00, 0x34, 0x1f, 0xc0, 0x12, 0x60,
|
||||||
|
0x59, 0x79, 0x73, 0x05, 0x47, 0x6d, 0x1a, 0xa2, 0x54, 0xf3, 0xed, 0xb0, 0xef, 0x39, 0xc3, 0x85,
|
||||||
|
0x6b, 0xbf, 0x18, 0xbf, 0x18, 0x43, 0xa7, 0x49, 0x69, 0x8f, 0x31, 0x47, 0x84, 0xb9, 0x53, 0xe4,
|
||||||
|
0xa0, 0xa1, 0xb7, 0xdd, 0x2f, 0x86, 0x0b, 0x47, 0x5b, 0xed, 0x92, 0xda, 0xdc, 0x1d, 0x1f, 0x3b,
|
||||||
|
0x7a, 0x77, 0x20, 0xb2, 0x39, 0x88, 0x6c, 0x02, 0x22, 0xcb, 0x4c, 0x06, 0xa8, 0x43, 0xad, 0x02,
|
||||||
|
0xc4, 0x52, 0xec, 0xf6, 0xfa, 0xfc, 0xf4, 0x74, 0x7c, 0x7c, 0x9f, 0x9f, 0x9e, 0x9e, 0xdc, 0x27,
|
||||||
|
0x88, 0x88, 0x0f, 0xe4, 0x84, 0xf4, 0x71, 0x66, 0x2f, 0xa3, 0xb4, 0xc2, 0xe0, 0xd8, 0xd8, 0xac,
|
||||||
|
0xe4, 0x57, 0x6d, 0x57, 0x81, 0xa5, 0x80, 0x87, 0xca, 0xfc, 0x95, 0xc1, 0x4a, 0x14, 0x72, 0xe6,
|
||||||
|
0x92, 0xe6, 0x09, 0xb8, 0xac, 0xe0, 0xe9, 0xe5, 0xd5, 0x2c, 0x35, 0x45, 0x8b, 0x1e, 0x58, 0xe9,
|
||||||
|
0x7f, 0x85, 0x2a, 0x88, 0x7a, 0x5b, 0xd2, 0x90, 0x3a, 0xd9, 0xe8, 0x44, 0xc8, 0x14, 0x00, 0xcc,
|
||||||
|
0xad, 0x43, 0xff, 0x7c, 0x52, 0x06, 0xb5, 0xa8, 0xe7, 0x5f, 0xe3, 0x67, 0x48, 0x20, 0x80, 0xf6,
|
||||||
|
0x3e, 0x84, 0xb0, 0xdb, 0x1b, 0xd2, 0x3c, 0x2c, 0xfc, 0x1e, 0x0b, 0x5b, 0x60, 0xaa, 0xf8, 0x8e,
|
||||||
|
0xbc, 0x23, 0x0d, 0x2d, 0xf3, 0xc8, 0xdb, 0xfd, 0xb0, 0x12, 0x22, 0x5f, 0xc2, 0x8e, 0xff, 0xcf,
|
||||||
|
0x86, 0xe1, 0xf7, 0x54, 0x81, 0xbd, 0x84, 0xa9, 0xc1, 0x07, 0x6e, 0xbc, 0x7e, 0x9b, 0xb0, 0x69,
|
||||||
|
0x8c, 0x89, 0x85, 0x71, 0x69, 0x36, 0x12, 0x32, 0x1b, 0x26, 0xb2, 0x6b, 0x4e, 0x13, 0x6d, 0x4b,
|
||||||
|
0x2e, 0x86, 0x0e, 0x13, 0xca, 0xc5, 0xf9, 0x1d, 0x5b, 0xc5, 0xa0, 0x11, 0x7c, 0xe9, 0x3c, 0x51,
|
||||||
|
0x13, 0xde, 0x61, 0x93, 0x81, 0x9d, 0x50, 0x1d, 0x79, 0x93, 0xcb, 0xae, 0xe8, 0x86, 0xf2, 0x0b,
|
||||||
|
0xea, 0x6e, 0xa2, 0xb4, 0x4a, 0xa2, 0xb4, 0x0a, 0x25, 0xdf, 0x7d, 0x16, 0xd8, 0xe0, 0x7d, 0x03,
|
||||||
|
0xb1, 0x28, 0x12, 0x19, 0xea, 0x24, 0xbd, 0x7c, 0x6b, 0x6a, 0x16, 0x80, 0xa3, 0xd9, 0xf9, 0x76,
|
||||||
|
0x80, 0x40, 0x51, 0x77, 0xba, 0x31, 0xbb, 0x13, 0x94, 0x38, 0x00, 0xd1, 0x3a, 0x04, 0x96, 0x8d,
|
||||||
|
0xe4, 0xbc, 0xf9, 0x6d, 0x6e, 0x17, 0xfa, 0xb8, 0x0a, 0x83, 0x8b, 0xef, 0x30, 0xd2, 0xb8, 0xe4,
|
||||||
|
0x57, 0x2a, 0xb4, 0x60, 0x94, 0xa4, 0xec, 0x8a, 0x88, 0x29, 0x3b, 0xdf, 0xa2, 0x31, 0x03, 0xf2,
|
||||||
|
0x46, 0xf2, 0x60, 0x0f, 0xfc, 0x65, 0x4f, 0xef, 0x1f, 0x5d, 0xe6, 0xbc, 0xf0, 0x5e, 0x6c, 0xb3,
|
||||||
|
0xe2, 0x23, 0x34, 0x53, 0x7d, 0x0c, 0xc4, 0x33, 0x38, 0x6f, 0xca, 0xaf, 0xc1, 0x08, 0x54, 0xf3,
|
||||||
|
0xc6, 0x06, 0x8b, 0x12, 0x92, 0x1f, 0xf0, 0xfc, 0xd4, 0x67, 0x10, 0x9d, 0x8e, 0x5f, 0xed, 0x23,
|
||||||
|
0x80, 0x4e, 0xe7, 0xaf, 0xfc, 0x78, 0xa1, 0xd3, 0xf5, 0x33, 0x8e, 0x73, 0x41, 0x8f, 0x96, 0x0c,
|
||||||
|
0x80, 0xbf, 0xab, 0x88, 0x3f, 0x22, 0x74, 0x21, 0x7e, 0x45, 0xe0, 0xb6, 0x92, 0x8a, 0x10, 0xeb,
|
||||||
|
0x6c, 0x2f, 0xf3, 0x2b, 0x7f, 0xab, 0x57, 0xfd, 0x8d, 0xd2, 0xaf, 0x89, 0x2b, 0xd7, 0xf8, 0x0d,
|
||||||
|
0x34, 0x3b, 0x73, 0x67, 0x62, 0xb5, 0x62, 0x49, 0xf8, 0x1b, 0x04, 0x17, 0x1f, 0x91, 0x1e, 0xd6,
|
||||||
|
0xe0, 0x5f, 0x16, 0x86, 0x50, 0x96, 0xae, 0x89, 0x42, 0xf4, 0x98, 0x39, 0x47, 0x6b, 0x10, 0x5a,
|
||||||
|
0x5f, 0x61, 0x86, 0xf6, 0x2b, 0x6b, 0xf0, 0x83, 0x65, 0xbf, 0x96, 0xdf, 0xe6, 0x0d, 0x2e, 0x90,
|
||||||
|
0x30, 0x56, 0x8b, 0x4d, 0x3e, 0x56, 0x0b, 0xcc, 0xe7, 0x4f, 0x59, 0x61, 0x6b, 0x23, 0xe7, 0xcd,
|
||||||
|
0x19, 0xd8, 0xf2, 0x47, 0xae, 0x54, 0x14, 0x85, 0xe9, 0xa4, 0x13, 0xe3, 0x3f, 0x40, 0x26, 0x03,
|
||||||
|
0x95, 0x2a, 0xf4, 0xd8, 0x01, 0x5c, 0xfe, 0x25, 0xdb, 0x37, 0xe0, 0xa9, 0x91, 0x08, 0x00, 0x2b,
|
||||||
|
0xdf, 0xa0, 0x2c, 0x83, 0xdd, 0xac, 0x0e, 0xc6, 0x6c, 0xcb, 0xb2, 0x3d, 0x79, 0x6e, 0xd8, 0x2f,
|
||||||
|
0x23, 0x23, 0x4b, 0x85, 0x64, 0xb0, 0x1a, 0x90, 0x13, 0xd4, 0x9a, 0x54, 0xd8, 0x20, 0x16, 0x6e,
|
||||||
|
0x76, 0xe5, 0x54, 0x27, 0x51, 0xcf, 0xf4, 0x49, 0x54, 0x76, 0x7f, 0x2f, 0x8f, 0x28, 0xa3, 0x8c,
|
||||||
|
0xae, 0xe0, 0xe5, 0x9f, 0x53, 0x90, 0x88, 0xd0, 0xfb, 0xe0, 0x42, 0x95, 0x59, 0x35, 0x5e, 0x69,
|
||||||
|
0xee, 0xd6, 0x2c, 0xbc, 0x39, 0x0b, 0x77, 0xce, 0x01, 0x91, 0x38, 0x66, 0x6f, 0xec, 0x14, 0xfd,
|
||||||
|
0x0c, 0x6d, 0xd5, 0x47, 0xbf, 0x9a, 0x18, 0xc3, 0xb2, 0x1c, 0x9b, 0xf1, 0xf5, 0x47, 0xc7, 0x08,
|
||||||
|
0xc9, 0x94, 0xab, 0x81, 0xfb, 0x35, 0xc4, 0x49, 0x87, 0x5d, 0x10, 0xc6, 0xab, 0xb3, 0x25, 0x1b,
|
||||||
|
0xb0, 0xb1, 0xcf, 0x0f, 0xc0, 0x8f, 0x28, 0x2b, 0xb0, 0x9c, 0x32, 0x11, 0xae, 0xe9, 0x47, 0x27,
|
||||||
|
0x75, 0x2d, 0x49, 0x0f, 0xa3, 0x6b, 0xa0, 0xa7, 0xf0, 0xa8, 0x28, 0xc7, 0x2b, 0x4b, 0xa3, 0x03,
|
||||||
|
0x5b, 0x7e, 0xe5, 0x6a, 0xbb, 0xad, 0x57, 0xba, 0xc8, 0x38, 0x00, 0x78, 0x47, 0xa3, 0x3d, 0x7b,
|
||||||
|
0x95, 0x75, 0x74, 0xba, 0x88, 0x56, 0xa0, 0xa3, 0xbf, 0x57, 0x20, 0x07, 0xb6, 0xfc, 0x04, 0x1a,
|
||||||
|
0x3b, 0x52, 0xd9, 0x0e, 0x26, 0x2c, 0x29, 0xc9, 0x2b, 0x2b, 0x5b, 0x6c, 0x37, 0xaf, 0x4e, 0x28,
|
||||||
|
0x5b, 0x20, 0x62, 0x75, 0x3c, 0xc0, 0x18, 0x77, 0x0e, 0xa5, 0x1f, 0x1a, 0x01, 0xd1, 0x8f, 0xc9,
|
||||||
|
0x0d, 0x54, 0xcc, 0x05, 0x26, 0x49, 0xd4, 0xb2, 0x62, 0xb1, 0x9e, 0x3e, 0xda, 0x85, 0x81, 0xa8,
|
||||||
|
0x7b, 0x76, 0xfd, 0x5d, 0xb0, 0x8d, 0x99, 0xfc, 0x16, 0x8e, 0xca, 0xb7, 0xed, 0x97, 0x5d, 0x58,
|
||||||
|
0x6a, 0x77, 0xe2, 0x31, 0x03, 0x03, 0x37, 0x22, 0x0c, 0xd6, 0xb3, 0x78, 0x6e, 0xe5, 0x59, 0x35,
|
||||||
|
0x6a, 0x7f, 0x9c, 0x5a, 0x4f, 0xd0, 0xdf, 0xc6, 0xa9, 0x1e, 0x9d, 0xcf, 0x69, 0x62, 0xa8, 0x8f,
|
||||||
|
0x8c, 0xc1, 0xbf, 0x6c, 0xf7, 0x48, 0xf9, 0x4a, 0x5c, 0x63, 0x8c, 0xee, 0x02, 0x74, 0x74, 0x92,
|
||||||
|
0xa7, 0xa3, 0x78, 0xcc, 0x9d, 0x82, 0x53, 0x94, 0xa9, 0x49, 0x54, 0x95, 0x56, 0x60, 0x53, 0x99,
|
||||||
|
0x96, 0xc1, 0x85, 0x65, 0x92, 0x80, 0xec, 0x61, 0x70, 0x80, 0xe7, 0xd4, 0x64, 0x13, 0x83, 0xd1,
|
||||||
|
0x44, 0xb3, 0xde, 0x0e, 0x5c, 0x67, 0x4d, 0x5c, 0xeb, 0xb9, 0x30, 0x09, 0x61, 0xfa, 0x2c, 0x94,
|
||||||
|
0x08, 0xca, 0xd1, 0x49, 0xbc, 0xbf, 0xef, 0xf3, 0x6e, 0x88, 0x1a, 0xf9, 0x4f, 0x5e, 0x65, 0x54,
|
||||||
|
0x45, 0x50, 0x95, 0xbd, 0x50, 0x38, 0x12, 0x57, 0x39, 0xfa, 0x08, 0x53, 0x9b, 0x31, 0xb0, 0xa4,
|
||||||
|
0xc6, 0x4b, 0x8c, 0x06, 0xb2, 0x89, 0xa7, 0xfc, 0x92, 0x5d, 0x75, 0xae, 0xea, 0xb2, 0xbd, 0x3d,
|
||||||
|
0x97, 0x9d, 0x05, 0x79, 0xe5, 0x45, 0xc2, 0xbe, 0x01, 0xfa, 0x8e, 0x01, 0xf4, 0x09, 0x3e, 0x10,
|
||||||
|
0x1f, 0x0c, 0x25, 0xf9, 0xbb, 0x2f, 0x5f, 0x02, 0x6e, 0x67, 0xa9, 0x80, 0xe0, 0x44, 0x60, 0xb4,
|
||||||
|
0x4a, 0xd8, 0x2f, 0x44, 0xfd, 0xc0, 0xa6, 0xce, 0x0e, 0x99, 0x43, 0xc3, 0xb3, 0x8e, 0x84, 0xff,
|
||||||
|
0x0a, 0x11, 0x87, 0xc5, 0x5f, 0x36, 0x55, 0x50, 0x34, 0x37, 0x55, 0x3c, 0x34, 0x6a, 0x93, 0xab,
|
||||||
|
0x41, 0x11, 0x1d, 0xe7, 0x56, 0x07, 0x76, 0x94, 0x10, 0x6d, 0xa7, 0x7e, 0x75, 0x8d, 0x19, 0x16,
|
||||||
|
0xfd, 0x34, 0x28, 0xa8, 0x4e, 0x14, 0x6c, 0x3c, 0xbc, 0xe9, 0xde, 0xbf, 0x6e, 0x97, 0x3f, 0xd4,
|
||||||
|
0x81, 0x78, 0xc4, 0x1f, 0x63, 0x8b, 0xc1, 0xcb, 0x07, 0xdf, 0x30, 0xf4, 0x50, 0x8c, 0x35, 0xdf,
|
||||||
|
0xc2, 0x32, 0x73, 0x78, 0x81, 0x9e, 0x1f, 0xfe, 0xb2, 0x90, 0x6d, 0x78, 0xf6, 0x94, 0x58, 0x7a,
|
||||||
|
0x2c, 0x64, 0x8a, 0xc9, 0x1f, 0x02, 0x4e, 0x52, 0xb3, 0x09, 0x5b, 0xa8, 0x8f, 0xfa, 0x76, 0xc0,
|
||||||
|
0x85, 0xbf, 0xac, 0x64, 0x40, 0xa5, 0x6b, 0x8f, 0xd1, 0x46, 0x71, 0x0f, 0x35, 0x30, 0x00, 0xa5,
|
||||||
|
0x8e, 0x0b, 0xcb, 0x43, 0x25, 0x23, 0x4b, 0x5e, 0xfb, 0x10, 0xdf, 0xf1, 0xc0, 0xb3, 0x48, 0xef,
|
||||||
|
0xe4, 0xc1, 0xb1, 0x48, 0xbf, 0x8d, 0xe3, 0xbe, 0x2c, 0xfb, 0x77, 0x55, 0xd9, 0xb1, 0x6b, 0xe9,
|
||||||
|
0x5a, 0x56, 0x5b, 0xb2, 0x71, 0x12, 0x3c, 0x1b, 0x95, 0x7e, 0xb6, 0xbd, 0x06, 0x15, 0x48, 0x52,
|
||||||
|
0xdb, 0x4f, 0xd8, 0x75, 0xb4, 0x60, 0x30, 0x87, 0x87, 0xbf, 0x5b, 0xbd, 0x01, 0x67, 0xf9, 0xfe,
|
||||||
|
0xbe, 0x6a, 0x03, 0x82, 0xa7, 0xef, 0x55, 0xbb, 0x73, 0x6e, 0xbf, 0x05, 0x56, 0x00, 0x19, 0x5e,
|
||||||
|
0xad, 0x85, 0xf5, 0xdf, 0xff, 0xd7, 0x12, 0x98, 0x41, 0x63, 0xf9, 0x7f, 0xff, 0xbf, 0x34, 0x12,
|
||||||
|
0x10, 0x71, 0x5f, 0x2c, 0xa3, 0xcc, 0x9a, 0x47, 0x3c, 0x0e, 0x2d, 0xb8, 0x29, 0xbf, 0x61, 0xd0,
|
||||||
|
0x76, 0xb5, 0x92, 0xd1, 0x32, 0x65, 0x89, 0xdb, 0x03, 0xcc, 0x8b, 0x8c, 0x63, 0x4d, 0xc3, 0xa5,
|
||||||
|
0xc6, 0xc8, 0x95, 0x74, 0xbb, 0x9e, 0xe5, 0x2a, 0x51, 0x4c, 0xf0, 0x67, 0x78, 0x18, 0x28, 0x82,
|
||||||
|
0x9c, 0x32, 0x34, 0x13, 0x01, 0xa1, 0xad, 0x44, 0xf3, 0xa4, 0x22, 0xac, 0xaa, 0xec, 0xa3, 0x10,
|
||||||
|
0x62, 0x05, 0xb8, 0xe0, 0x21, 0xa5, 0x08, 0x40, 0xdb, 0x51, 0x36, 0x9e, 0xa8, 0x46, 0x71, 0xad,
|
||||||
|
0x22, 0xe4, 0xfd, 0xbd, 0xe6, 0x15, 0xb3, 0xd5, 0xd9, 0xc2, 0x52, 0x63, 0xe9, 0x3f, 0x17, 0x22,
|
||||||
|
0x10, 0x9e, 0x8c, 0x4f, 0x7f, 0x14, 0x21, 0x2f, 0x60, 0x9a, 0x0c, 0xa4, 0xf6, 0x19, 0x40, 0x8d,
|
||||||
|
0xd1, 0xec, 0x3f, 0x11, 0x60, 0x50, 0x96, 0x7d, 0x07, 0xa6, 0xa2, 0x6a, 0x6e, 0x9a, 0x08, 0x4d,
|
||||||
|
0xfa, 0xcb, 0x97, 0x23, 0xba, 0xa7, 0xf3, 0x0e, 0x25, 0xef, 0x0e, 0x12, 0xba, 0x21, 0x02, 0xea,
|
||||||
|
0x67, 0x3b, 0x6c, 0xa7, 0x54, 0x7f, 0xbc, 0x3c, 0x19, 0x25, 0xd5, 0xfa, 0x77, 0x99, 0x57, 0xbf,
|
||||||
|
0xbf, 0xa7, 0x4a, 0x38, 0xc4, 0x0f, 0x30, 0x4f, 0xd9, 0xc8, 0x54, 0xc5, 0x4e, 0x5e, 0xe7, 0x87,
|
||||||
|
0xbe, 0x5d, 0xff, 0x65, 0x0f, 0x34, 0xd6, 0xa0, 0x0c, 0x77, 0x59, 0xf2, 0xb6, 0x81, 0x6d, 0x8c,
|
||||||
|
0x76, 0xf3, 0x86, 0xf9, 0xc0, 0x21, 0xa4, 0x7a, 0x30, 0x55, 0x12, 0x80, 0x17, 0x02, 0x28, 0xa3,
|
||||||
|
0x84, 0xd0, 0xb6, 0x4b, 0x94, 0x9a, 0x9b, 0x4c, 0x1e, 0x01, 0x2f, 0xd6, 0xc7, 0xa8, 0x09, 0xe4,
|
||||||
|
0xa2, 0xa0, 0xee, 0x40, 0x2f, 0x25, 0x45, 0xf9, 0x9b, 0x85, 0x6d, 0x05, 0xa5, 0x7f, 0xc5, 0x10,
|
||||||
|
0x64, 0x13, 0x58, 0xac, 0x2d, 0x54, 0x30, 0xfe, 0xc1, 0xd1, 0x62, 0xbd, 0x6b, 0x64, 0x5b, 0x1c,
|
||||||
|
0xeb, 0xdf, 0x04, 0x80, 0x79, 0xa2, 0x13, 0x2e, 0x49, 0x6f, 0x45, 0x43, 0xfa, 0x82, 0x68, 0xce,
|
||||||
|
0x53, 0xd9, 0x38, 0x31, 0x4a, 0x48, 0x20, 0x56, 0x31, 0xfb, 0xe3, 0x79, 0x52, 0x5e, 0x73, 0x45,
|
||||||
|
0x3e, 0x52, 0x3a, 0xc4, 0xc2, 0x72, 0xb2, 0xf2, 0xdb, 0xf8, 0x67, 0x1f, 0x5d, 0x43, 0x67, 0x3c,
|
||||||
|
0xbc, 0x17, 0x0a, 0xb2, 0x94, 0x9e, 0x56, 0x2b, 0xa9, 0xb8, 0xab, 0xd0, 0x87, 0xd1, 0x0f, 0xd4,
|
||||||
|
0xa2, 0xd6, 0x04, 0x74, 0xc7, 0x86, 0xcd, 0xb0, 0xcb, 0x93, 0x95, 0xcb, 0x28, 0x65, 0x89, 0xb3,
|
||||||
|
0xad, 0xef, 0x53, 0xbf, 0x7c, 0xda, 0x4e, 0x65, 0x72, 0xb1, 0xde, 0xd3, 0xfe, 0x13, 0x9f, 0x5d,
|
||||||
|
0xd8, 0x93, 0x3a, 0xca, 0xaa, 0xe4, 0x7f, 0xab, 0xe6, 0xdb, 0xd9, 0x8d, 0xc6, 0xaa, 0xec, 0xa9,
|
||||||
|
0xa3, 0x32, 0xc9, 0xac, 0x13, 0xc9, 0x1f, 0x53, 0x35, 0x56, 0x3b, 0x93, 0x2d, 0x3e, 0x5b, 0xb8,
|
||||||
|
0x04, 0xfe, 0x4c, 0x55, 0x47, 0xc6, 0x8a, 0x46, 0x11, 0xd3, 0x84, 0xe9, 0x3a, 0x32, 0xfb, 0x83,
|
||||||
|
0x51, 0x32, 0x66, 0xe9, 0xc2, 0xf9, 0x50, 0x55, 0x87, 0xd9, 0x4f, 0x39, 0x81, 0x69, 0xe0, 0x09,
|
||||||
|
0x3f, 0x14, 0x78, 0x3c, 0x76, 0xca, 0x44, 0x9f, 0x59, 0x8b, 0x5b, 0x7d, 0x3d, 0xd9, 0x59, 0x8c,
|
||||||
|
0xab, 0x02, 0x44, 0x7e, 0xae, 0x8a, 0x2d, 0x64, 0x39, 0xa3, 0x79, 0x5c, 0xe6, 0x3e, 0x1b, 0x39,
|
||||||
|
0x7e, 0xad, 0xc5, 0x28, 0x97, 0xf9, 0xdc, 0xb9, 0xda, 0xb6, 0x70, 0xeb, 0xe7, 0xeb, 0x58, 0x48,
|
||||||
|
0x83, 0x15, 0xaa, 0x54, 0xc2, 0xb0, 0x6b, 0x49, 0xa7, 0xc9, 0x30, 0xcd, 0x2f, 0x35, 0x9e, 0xc4,
|
||||||
|
0x31, 0x1d, 0x27, 0xdb, 0xe0, 0x76, 0x48, 0x66, 0x55, 0xe4, 0x57, 0x94, 0x2d, 0x8d, 0xef, 0x4c,
|
||||||
|
0xaf, 0xe4, 0xdd, 0xa4, 0x51, 0xce, 0x29, 0x2b, 0xad, 0xeb, 0xa1, 0xd5, 0xb9, 0x9b, 0x8d, 0x8d,
|
||||||
|
0x10, 0xf3, 0xae, 0x23, 0xf9, 0xdd, 0xd5, 0xac, 0x02, 0xce, 0xa0, 0x77, 0x39, 0x77, 0xe8, 0xf1,
|
||||||
|
0x5b, 0x3e, 0x7b, 0x2d, 0x53, 0x05, 0x98, 0x58, 0x5d, 0xdf, 0xd9, 0x4f, 0x9b, 0xaa, 0x55, 0x89,
|
||||||
|
0xda, 0xc0, 0x51, 0xe3, 0xc3, 0x0f, 0xe7, 0x33, 0xba, 0x69, 0x57, 0xed, 0x76, 0xfb, 0xf8, 0x3f,
|
||||||
|
0xef, 0xaa, 0xff, 0x68, 0xa4, 0xd8, 0x6c, 0x12, 0x4b, 0x7b, 0x8f, 0x6a, 0x57, 0xde, 0x00, 0xf7,
|
||||||
|
0x3b, 0xe8, 0x0c, 0xa0, 0x5f, 0x0b, 0x7e, 0x70, 0x5e, 0x23, 0xa7, 0x71, 0xba, 0xf6, 0x44, 0x3d,
|
||||||
|
0xa8, 0x8f, 0x05, 0x93, 0xae, 0xe3, 0x40, 0x55, 0x5b, 0xa5, 0xcf, 0xf3, 0x32, 0x43, 0xff, 0xed,
|
||||||
|
0x3e, 0xc4, 0x9b, 0xe8, 0x7a, 0x26, 0x56, 0x56, 0x3b, 0x65, 0x26, 0xac, 0x7a, 0xbb, 0x8f, 0x84,
|
||||||
|
0xd4, 0x2c, 0xd2, 0xcf, 0xbe, 0xbb, 0x7b, 0x8d, 0xe6, 0x18, 0x13, 0x61, 0xed, 0x02, 0x88, 0xe4,
|
||||||
|
0x41, 0xf0, 0x26, 0x46, 0xe5, 0x75, 0xee, 0x54, 0x11, 0x56, 0x95, 0xcf, 0x40, 0x7f, 0xa6, 0xe1,
|
||||||
|
0x1a, 0xcb, 0x14, 0x69, 0x72, 0x6e, 0xe3, 0xcf, 0x6f, 0x81, 0x53, 0x48, 0x4e, 0x57, 0xd1, 0x10,
|
||||||
|
0xa5, 0xc6, 0xaf, 0x32, 0x74, 0x6d, 0x8c, 0x9c, 0xd9, 0x1d, 0x14, 0xe8, 0x3a, 0xb8, 0x35, 0xcd,
|
||||||
|
0x90, 0x0c, 0x28, 0x93, 0xd3, 0x60, 0xff, 0xe8, 0xe8, 0x3c, 0xf1, 0xe1, 0xaf, 0x81, 0xe1, 0x72,
|
||||||
|
0xc3, 0xaa, 0xa1, 0x1b, 0xb0, 0x2f, 0x80, 0x49, 0xed, 0xa9, 0x0b, 0x30, 0xbd, 0x68, 0x62, 0x2e,
|
||||||
|
0xaa, 0xab, 0x5f, 0xfe, 0xac, 0x3d, 0x7e, 0x34, 0x39, 0xeb, 0x15, 0x29, 0x49, 0x47, 0x40, 0xd4,
|
||||||
|
0x34, 0xf1, 0x49, 0x47, 0xc1, 0x1a, 0xff, 0x72, 0x9b, 0x5c, 0x72, 0x39, 0x84, 0xac, 0x79, 0x77,
|
||||||
|
0xe0, 0xa7, 0xed, 0x7f, 0x57, 0xe0, 0x65, 0x22, 0xaf, 0x7d, 0x80, 0xf4, 0xc5, 0x42, 0xd2, 0x75,
|
||||||
|
0x26, 0xa5, 0x4d, 0x9a, 0x49, 0xcc, 0x3f, 0x21, 0x1d, 0x0f, 0x8b, 0x45, 0xad, 0x6c, 0xe0, 0x8b,
|
||||||
|
0xb7, 0x51, 0x2f, 0x42, 0x48, 0x3a, 0x2b, 0x26, 0xf4, 0xb6, 0xd8, 0xd3, 0xb6, 0xc5, 0xce, 0xfb,
|
||||||
|
0x9a, 0x82, 0x07, 0xed, 0xe0, 0x98, 0x76, 0x08, 0xb6, 0x5a, 0x77, 0x19, 0xef, 0x88, 0x9f, 0x9d,
|
||||||
|
0xc6, 0xf6, 0x0d, 0x17, 0xe1, 0x8b, 0x37, 0x6f, 0xba, 0x1b, 0x9d, 0x5b, 0x67, 0x6d, 0xce, 0x76,
|
||||||
|
0x6b, 0x27, 0x94, 0x4f, 0x40, 0x47, 0x76, 0xde, 0x97, 0x66, 0xf1, 0xab, 0x77, 0x73, 0xeb, 0x4e,
|
||||||
|
0x6c, 0xac, 0x1b, 0x96, 0x00, 0xaf, 0xc7, 0xb1, 0xa5, 0x7e, 0xfa, 0xcf, 0xfc, 0x18, 0x1d, 0xe3,
|
||||||
|
0x73, 0xf0, 0x36, 0x72, 0x94, 0x0a, 0x7b, 0x64, 0x7f, 0xe5, 0xda, 0xea, 0x07, 0x64, 0x6d, 0x17,
|
||||||
|
0x3f, 0xda, 0xc0, 0x82, 0x4a, 0x9e, 0x7f, 0x9b, 0x83, 0xb3, 0x38, 0x85, 0x00, 0x16, 0x76, 0x42,
|
||||||
|
0x9f, 0x00, 0xdb, 0xae, 0x5d, 0x7d, 0xe4, 0xeb, 0xec, 0xc0, 0x79, 0x29, 0x56, 0x07, 0x80, 0xfd,
|
||||||
|
0xcf, 0xcc, 0xf3, 0x88, 0x6f, 0x89, 0x77, 0xe6, 0x3d, 0x4a, 0xc2, 0x36, 0x29, 0x68, 0x7e, 0x08,
|
||||||
|
0xfc, 0x39, 0xdf, 0xc8, 0xe2, 0x2d, 0x7f, 0x31, 0xdf, 0xe1, 0x2f, 0x9a, 0x04, 0xd4, 0x79, 0x6a,
|
||||||
|
0x97, 0x3d, 0x50, 0xd2, 0x69, 0x94, 0x7b, 0x96, 0xdf, 0x8f, 0x3a, 0x66, 0x20, 0x00, 0x21, 0xfc,
|
||||||
|
0x0e, 0x4f, 0x32, 0xd9, 0x91, 0x87, 0x62, 0xf5, 0x44, 0x5b, 0x7e, 0xbe, 0x23, 0xd5, 0xa9, 0xbc,
|
||||||
|
0xc9, 0x8e, 0x9a, 0x48, 0xa0, 0x49, 0xd6, 0x4d, 0xb6, 0xfa, 0x10, 0xe8, 0x09, 0x48, 0xc5, 0xdf,
|
||||||
|
0xac, 0x91, 0x9f, 0x60, 0xe2, 0x0f, 0x39, 0xd2, 0xff, 0xb9, 0xd8, 0xff, 0x07, 0xff, 0x03, 0x8d,
|
||||||
|
0x05, 0x6d, 0x6c, 0x00, 0x00
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
2243
wled00/html_simple.h
2243
wled00/html_simple.h
File diff suppressed because it is too large
Load Diff
3955
wled00/html_ui.h
3955
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,11 @@
|
|||||||
#define DIMPROV_PRINTF(x...)
|
#define DIMPROV_PRINTF(x...)
|
||||||
#endif
|
#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
|
#define IMPROV_VERSION 1
|
||||||
|
|
||||||
void parseWiFiCommand(char *rpcData);
|
void parseWiFiCommand(char *rpcData);
|
||||||
@ -28,20 +33,14 @@ enum ImprovPacketByte {
|
|||||||
RPC_CommandType = 9
|
RPC_CommandType = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ImprovRPCType {
|
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
||||||
Command_Wifi = 0x01,
|
static bool improvWifiScanRunning = false;
|
||||||
Request_State = 0x02,
|
#endif
|
||||||
Request_Info = 0x03
|
|
||||||
};
|
|
||||||
|
|
||||||
//File dbgf;
|
|
||||||
|
|
||||||
//blocking function to parse an Improv Serial packet
|
//blocking function to parse an Improv Serial packet
|
||||||
void handleImprovPacket() {
|
void handleImprovPacket() {
|
||||||
uint8_t header[6] = {'I','M','P','R','O','V'};
|
uint8_t header[6] = {'I','M','P','R','O','V'};
|
||||||
|
|
||||||
//dbgf = WLED_FS.open("/improv.log","a");
|
|
||||||
|
|
||||||
bool timeout = false;
|
bool timeout = false;
|
||||||
uint8_t waitTime = 25;
|
uint8_t waitTime = 25;
|
||||||
uint16_t packetByte = 0;
|
uint16_t packetByte = 0;
|
||||||
@ -62,12 +61,11 @@ void handleImprovPacket() {
|
|||||||
byte next = Serial.read();
|
byte next = Serial.read();
|
||||||
|
|
||||||
DIMPROV_PRINT("Received improv byte: "); DIMPROV_PRINTF("%x\r\n",next);
|
DIMPROV_PRINT("Received improv byte: "); DIMPROV_PRINTF("%x\r\n",next);
|
||||||
//f.write(next);
|
|
||||||
switch (packetByte) {
|
switch (packetByte) {
|
||||||
case ImprovPacketByte::Version: {
|
case ImprovPacketByte::Version: {
|
||||||
if (next != IMPROV_VERSION) {
|
if (next != IMPROV_VERSION) {
|
||||||
DIMPROV_PRINTLN(F("Invalid version"));
|
DIMPROV_PRINTLN(F("Invalid version"));
|
||||||
//dbgf.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -75,7 +73,6 @@ void handleImprovPacket() {
|
|||||||
case ImprovPacketByte::PacketType: {
|
case ImprovPacketByte::PacketType: {
|
||||||
if (next != ImprovPacketType::RPC_Command) {
|
if (next != ImprovPacketType::RPC_Command) {
|
||||||
DIMPROV_PRINTF("Non RPC-command improv packet type %i\n",next);
|
DIMPROV_PRINTF("Non RPC-command improv packet type %i\n",next);
|
||||||
//dbgf.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!improvActive) improvActive = 1;
|
if (!improvActive) improvActive = 1;
|
||||||
@ -89,7 +86,6 @@ void handleImprovPacket() {
|
|||||||
if (checksum != next) {
|
if (checksum != next) {
|
||||||
DIMPROV_PRINTF("Got RPC checksum %i, expected %i",next,checksum);
|
DIMPROV_PRINTF("Got RPC checksum %i, expected %i",next,checksum);
|
||||||
sendImprovStateResponse(0x01, true);
|
sendImprovStateResponse(0x01, true);
|
||||||
//dbgf.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,22 +96,23 @@ void handleImprovPacket() {
|
|||||||
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
|
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
|
||||||
if (Network.isConnected()) improvState = 0x04; //provisioned
|
if (Network.isConnected()) improvState = 0x04; //provisioned
|
||||||
sendImprovStateResponse(improvState, false);
|
sendImprovStateResponse(improvState, false);
|
||||||
if (improvState == 0x04) sendImprovRPCResponse(ImprovRPCType::Request_State);
|
if (improvState == 0x04) sendImprovIPRPCResult(ImprovRPCType::Request_State);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ImprovRPCType::Request_Info: sendImprovInfoResponse(); break;
|
case ImprovRPCType::Request_Info: sendImprovInfoResponse(); break;
|
||||||
|
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
||||||
|
case ImprovRPCType::Request_Scan: startImprovWifiScan(); break;
|
||||||
|
#endif
|
||||||
default: {
|
default: {
|
||||||
DIMPROV_PRINTF("Unknown RPC command %i\n",next);
|
DIMPROV_PRINTF("Unknown RPC command %i\n",next);
|
||||||
sendImprovStateResponse(0x02, true);
|
sendImprovStateResponse(0x02, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//dbgf.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packetByte < 6) { //check header
|
if (packetByte < 6) { //check header
|
||||||
if (next != header[packetByte]) {
|
if (next != header[packetByte]) {
|
||||||
DIMPROV_PRINTLN(F("Invalid improv header"));
|
DIMPROV_PRINTLN(F("Invalid improv header"));
|
||||||
//dbgf.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (packetByte > 9) { //RPC data
|
} else if (packetByte > 9) { //RPC data
|
||||||
@ -128,7 +125,6 @@ void handleImprovPacket() {
|
|||||||
checksum += next;
|
checksum += next;
|
||||||
packetByte++;
|
packetByte++;
|
||||||
}
|
}
|
||||||
//dbgf.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendImprovStateResponse(uint8_t state, bool error) {
|
void sendImprovStateResponse(uint8_t state, bool error) {
|
||||||
@ -147,79 +143,116 @@ void sendImprovStateResponse(uint8_t state, bool error) {
|
|||||||
Serial.write('\n');
|
Serial.write('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendImprovRPCResponse(byte commandId) {
|
// used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan()
|
||||||
|
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) {
|
||||||
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
||||||
uint8_t packetLen = 12;
|
uint8_t packetLen = 12;
|
||||||
char out[64] = {'I','M','P','R','O','V'};
|
char out[256] = {'I','M','P','R','O','V'};
|
||||||
out[6] = IMPROV_VERSION;
|
out[6] = IMPROV_VERSION;
|
||||||
out[7] = ImprovPacketType::RPC_Response;
|
out[7] = ImprovPacketType::RPC_Response;
|
||||||
out[8] = 2; //Length (set below)
|
//out[8] = 2; //Length (set below)
|
||||||
out[9] = commandId;
|
out[9] = type;
|
||||||
out[10] = 0; //Data len (set below)
|
//out[10] = 0; //Data len (set below)
|
||||||
out[11] = '\0'; //URL len (set below)
|
uint16_t pos = 11;
|
||||||
|
|
||||||
if (Network.isConnected())
|
for (uint8_t s = 0; s < n_strings; s++) {
|
||||||
{
|
size_t len = strlen(strings[s]);
|
||||||
IPAddress localIP = Network.localIP();
|
if (pos + len > 254) continue; // simple buffer overflow guard
|
||||||
uint8_t len = sprintf(out+12, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
out[pos++] = len;
|
||||||
if (len > 24) return; //sprintf fail?
|
strcpy(out + pos, strings[s]);
|
||||||
out[11] = len;
|
pos += 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;
|
uint8_t checksum = 0;
|
||||||
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
|
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
|
||||||
out[packetLen -1] = checksum;
|
out[packetLen -1] = checksum;
|
||||||
Serial.write((uint8_t*)out, packetLen);
|
Serial.write((uint8_t*)out, packetLen);
|
||||||
Serial.write('\n');
|
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
|
improvActive = 1; //no longer provisioning
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendImprovInfoResponse() {
|
void sendImprovInfoResponse() {
|
||||||
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
const char* bString =
|
||||||
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
|
#ifdef ESP8266
|
||||||
strcpy(out+lengthSum+1,"esp8266");
|
"esp8266"
|
||||||
#else
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||||
hlen = 5;
|
"esp32-c3"
|
||||||
strcpy(out+lengthSum+1,"esp32");
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||||
|
"esp32-s2"
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
"esp32-s3";
|
||||||
|
#else // ESP32
|
||||||
|
"esp32";
|
||||||
#endif
|
#endif
|
||||||
out[lengthSum] = hlen;
|
;
|
||||||
lengthSum += hlen + 1;
|
|
||||||
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
||||||
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
||||||
strcpy(out+lengthSum+1,useMdnsName ? cmDNS : serverDescription);
|
char vString[20];
|
||||||
uint8_t nlen = strlen(useMdnsName ? cmDNS : serverDescription);
|
sprintf_P(vString, PSTR("0.14.0-b3/%i"), VERSION);
|
||||||
out[lengthSum] = nlen;
|
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
||||||
lengthSum += nlen + 1;
|
|
||||||
|
|
||||||
packetLen = lengthSum +1;
|
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
||||||
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) {
|
void parseWiFiCommand(char* rpcData) {
|
||||||
uint8_t len = rpcData[0];
|
uint8_t len = rpcData[0];
|
||||||
if (!len || len > 126) return;
|
if (!len || len > 126) return;
|
||||||
|
@ -70,13 +70,9 @@ void decBrightness()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply preset or fallback to a effect and palette if it doesn't exist
|
|
||||||
void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
|
void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
|
||||||
{
|
{
|
||||||
applyPreset(presetID, CALL_MODE_BUTTON_PRESET);
|
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
|
||||||
//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)
|
byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#define JSON_PATH_PALETTES 5
|
#define JSON_PATH_PALETTES 5
|
||||||
#define JSON_PATH_FXDATA 6
|
#define JSON_PATH_FXDATA 6
|
||||||
#define JSON_PATH_NETWORKS 7
|
#define JSON_PATH_NETWORKS 7
|
||||||
|
#define JSON_PATH_EFFECTS 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSON API (De)serialization
|
* JSON API (De)serialization
|
||||||
@ -33,7 +34,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
|
|
||||||
uint16_t start = elem["start"] | seg.start;
|
uint16_t start = elem["start"] | seg.start;
|
||||||
if (stop < 0) {
|
if (stop < 0) {
|
||||||
uint16_t len = elem["len"];
|
int len = elem["len"];
|
||||||
stop = (len > 0) ? start + len : seg.stop;
|
stop = (len > 0) ? start + len : seg.stop;
|
||||||
}
|
}
|
||||||
// 2D segments
|
// 2D segments
|
||||||
@ -69,9 +70,10 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
const char * name = elem["n"].as<const char*>();
|
const char * name = elem["n"].as<const char*>();
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
if (name != nullptr) len = strlen(name);
|
if (name != nullptr) len = strlen(name);
|
||||||
if (len > 0 && len < 33) {
|
if (len > 0) {
|
||||||
|
if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN;
|
||||||
seg.name = new char[len+1];
|
seg.name = new char[len+1];
|
||||||
if (seg.name) strlcpy(seg.name, name, 33);
|
if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1);
|
||||||
} else {
|
} else {
|
||||||
// but is empty (already deleted above)
|
// but is empty (already deleted above)
|
||||||
elem.remove("n");
|
elem.remove("n");
|
||||||
@ -93,7 +95,10 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
|
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
|
||||||
|
|
||||||
seg.map1D2D = constrain(map1D2D, 0, 7);
|
seg.map1D2D = constrain(map1D2D, 0, 7);
|
||||||
seg.soundSim = constrain(soundSim, 0, 7);
|
seg.soundSim = constrain(soundSim, 0, 1);
|
||||||
|
|
||||||
|
uint8_t set = elem[F("set")] | seg.set;
|
||||||
|
seg.set = constrain(set, 0, 3);
|
||||||
|
|
||||||
uint16_t len = 1;
|
uint16_t len = 1;
|
||||||
if (stop > start) len = stop - start;
|
if (stop > start) len = stop - start;
|
||||||
@ -105,7 +110,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
of = offsetAbs;
|
of = offsetAbs;
|
||||||
}
|
}
|
||||||
if (stop > start && of > len -1) of = len -1;
|
if (stop > start && of > len -1) of = len -1;
|
||||||
seg.set(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
|
if (seg.reset && seg.stop == 0) return true; // segment was deleted & is marked for reset, no need to change anything else
|
||||||
|
|
||||||
@ -127,6 +132,8 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
JsonArray colarr = elem["col"];
|
JsonArray colarr = elem["col"];
|
||||||
if (!colarr.isNull())
|
if (!colarr.isNull())
|
||||||
{
|
{
|
||||||
|
if (seg.getLightCapabilities() & 3) {
|
||||||
|
// segment has RGB or White
|
||||||
for (size_t i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
int rgbw[] = {0,0,0,0};
|
int rgbw[] = {0,0,0,0};
|
||||||
@ -158,6 +165,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]));
|
seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]));
|
||||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// non RGB & non White segment (usually On/Off bus)
|
||||||
|
seg.setColor(0, ULTRAWHITE);
|
||||||
|
seg.setColor(1, BLACK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// lx parser
|
// lx parser
|
||||||
@ -199,7 +211,9 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
getVal(elem["ix"], &seg.intensity);
|
getVal(elem["ix"], &seg.intensity);
|
||||||
|
|
||||||
uint8_t pal = seg.palette;
|
uint8_t pal = seg.palette;
|
||||||
|
if (seg.getLightCapabilities() & 1) { // ignore palette for White and On/Off segments
|
||||||
if (getVal(elem["pal"], &pal)) seg.setPalette(pal);
|
if (getVal(elem["pal"], &pal)) seg.setPalette(pal);
|
||||||
|
}
|
||||||
|
|
||||||
getVal(elem["c1"], &seg.custom1);
|
getVal(elem["c1"], &seg.custom1);
|
||||||
getVal(elem["c2"], &seg.custom2);
|
getVal(elem["c2"], &seg.custom2);
|
||||||
@ -412,7 +426,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
|
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
|
||||||
if (!root["pd"].isNull() && stateChanged) {
|
if (!root["pd"].isNull() && stateChanged) {
|
||||||
currentPreset = root[F("pd")] | currentPreset;
|
currentPreset = root[F("pd")] | currentPreset;
|
||||||
if (root["win"].isNull()) presetCycCurr = currentPreset;
|
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise it was set in handleSet() [set.cpp]
|
||||||
presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after
|
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?
|
//unloadPlaylist(); // applying a preset unloads the playlist, may be needed here too?
|
||||||
} else if (!root["ps"].isNull()) {
|
} else if (!root["ps"].isNull()) {
|
||||||
@ -459,7 +473,7 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
|
|||||||
root[F("stopY")] = seg.stopY;
|
root[F("stopY")] = seg.stopY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!forPreset) root["len"] = seg.stop - seg.start;
|
if (!forPreset) root["len"] = (seg.stop >= seg.start) ? (seg.stop - seg.start) : 0;
|
||||||
root["grp"] = seg.grouping;
|
root["grp"] = seg.grouping;
|
||||||
root[F("spc")] = seg.spacing;
|
root[F("spc")] = seg.spacing;
|
||||||
root[F("of")] = seg.offset;
|
root[F("of")] = seg.offset;
|
||||||
@ -468,6 +482,7 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
|
|||||||
byte segbri = seg.opacity;
|
byte segbri = seg.opacity;
|
||||||
root["bri"] = (segbri) ? segbri : 255;
|
root["bri"] = (segbri) ? segbri : 255;
|
||||||
root["cct"] = seg.cct;
|
root["cct"] = seg.cct;
|
||||||
|
root[F("set")] = seg.set;
|
||||||
|
|
||||||
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
||||||
|
|
||||||
@ -709,7 +724,7 @@ void serializeInfo(JsonObject root)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
root[F("freeheap")] = ESP.getFreeHeap();
|
root[F("freeheap")] = ESP.getFreeHeap();
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||||
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||||
#endif
|
#endif
|
||||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||||
@ -799,7 +814,7 @@ void setPaletteColors(JsonArray json, byte* tcp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
void serializePalettes(JsonObject root, int page)
|
||||||
{
|
{
|
||||||
byte tcp[72];
|
byte tcp[72];
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -808,11 +823,6 @@ void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
|||||||
int itemPerPage = 8;
|
int itemPerPage = 8;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int page = 0;
|
|
||||||
if (request->hasParam("page")) {
|
|
||||||
page = request->getParam("page")->value().toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
int palettesCount = strip.getPaletteCount();
|
int palettesCount = strip.getPaletteCount();
|
||||||
int customPalettes = strip.customPalettes.size();
|
int customPalettes = strip.customPalettes.size();
|
||||||
|
|
||||||
@ -988,6 +998,7 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
else if (url.indexOf("info") > 0) subJson = JSON_PATH_INFO;
|
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("si") > 0) subJson = JSON_PATH_STATE_INFO;
|
||||||
else if (url.indexOf("nodes") > 0) subJson = JSON_PATH_NODES;
|
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("palx") > 0) subJson = JSON_PATH_PALETTES;
|
||||||
else if (url.indexOf("fxda") > 0) subJson = JSON_PATH_FXDATA;
|
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;
|
||||||
@ -997,20 +1008,6 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
else if (url.indexOf("pal") > 0) {
|
||||||
request->send_P(200, "application/json", JSON_palette_names);
|
request->send_P(200, "application/json", JSON_palette_names);
|
||||||
return;
|
return;
|
||||||
@ -1027,7 +1024,7 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
request->send(503, "application/json", F("{\"error\":3}"));
|
request->send(503, "application/json", F("{\"error\":3}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==6);
|
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
|
||||||
|
|
||||||
JsonVariant lDoc = response->getRoot();
|
JsonVariant lDoc = response->getRoot();
|
||||||
|
|
||||||
@ -1040,9 +1037,11 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
case JSON_PATH_NODES:
|
case JSON_PATH_NODES:
|
||||||
serializeNodes(lDoc); break;
|
serializeNodes(lDoc); break;
|
||||||
case JSON_PATH_PALETTES:
|
case JSON_PATH_PALETTES:
|
||||||
serializePalettes(lDoc, request); break;
|
serializePalettes(lDoc, request->hasParam("page") ? request->getParam("page")->value().toInt() : 0); break;
|
||||||
|
case JSON_PATH_EFFECTS:
|
||||||
|
serializeModeNames(lDoc); break;
|
||||||
case JSON_PATH_FXDATA:
|
case JSON_PATH_FXDATA:
|
||||||
serializeModeData(lDoc.as<JsonArray>()); break;
|
serializeModeData(lDoc); break;
|
||||||
case JSON_PATH_NETWORKS:
|
case JSON_PATH_NETWORKS:
|
||||||
serializeNetworks(lDoc); break;
|
serializeNetworks(lDoc); break;
|
||||||
default: //all
|
default: //all
|
||||||
@ -1061,7 +1060,9 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", lDoc.memoryUsage(), subJson);
|
DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", lDoc.memoryUsage(), subJson);
|
||||||
|
|
||||||
response->setLength();
|
size_t len = response->setLength();
|
||||||
|
DEBUG_PRINT(F("JSON content length: ")); DEBUG_PRINTLN(len);
|
||||||
|
|
||||||
request->send(response);
|
request->send(response);
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ void applyValuesToSelectedSegs()
|
|||||||
|
|
||||||
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
||||||
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
||||||
if (effectPalette != selsegPrev.palette) {seg.palette = effectPalette; stateChanged = true;}
|
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette); stateChanged = true;}
|
||||||
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
|
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent); stateChanged = true;}
|
||||||
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
||||||
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
|
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
|
||||||
@ -104,6 +104,7 @@ void stateUpdated(byte callMode) {
|
|||||||
if (stateChanged) currentPreset = 0; //something changed, so we are no longer in the preset
|
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 (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
|
//set flag to update ws and mqtt
|
||||||
interfaceUpdateCallMode = callMode;
|
interfaceUpdateCallMode = callMode;
|
||||||
@ -146,7 +147,7 @@ void stateUpdated(byte callMode) {
|
|||||||
if (transitionActive) {
|
if (transitionActive) {
|
||||||
briOld = briT;
|
briOld = briT;
|
||||||
tperLast = 0;
|
tperLast = 0;
|
||||||
}
|
} else
|
||||||
strip.setTransitionMode(true); // force all segments to transition mode
|
strip.setTransitionMode(true); // force all segments to transition mode
|
||||||
transitionActive = true;
|
transitionActive = true;
|
||||||
transitionStartTime = millis();
|
transitionStartTime = millis();
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/*
|
/*
|
||||||
* Parser for Loxone formats
|
* Parser for Loxone formats
|
||||||
*/
|
*/
|
||||||
bool parseLx(int lxValue, byte rgbw[4])
|
bool parseLx(int lxValue, byte* rgbw)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT(F("LX: Lox = "));
|
DEBUG_PRINT(F("LX: Lox = "));
|
||||||
DEBUG_PRINTLN(lxValue);
|
DEBUG_PRINTLN(lxValue);
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
void parseMQTTBriPayload(char* payload)
|
void parseMQTTBriPayload(char* payload)
|
||||||
{
|
{
|
||||||
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(1);}
|
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
||||||
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(1);}
|
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
||||||
else {
|
else {
|
||||||
uint8_t in = strtoul(payload, NULL, 10);
|
uint8_t in = strtoul(payload, NULL, 10);
|
||||||
if (in == 0 && bri > 0) briLast = bri;
|
if (in == 0 && bri > 0) briLast = bri;
|
||||||
@ -142,12 +142,12 @@ void publishMqtt()
|
|||||||
sprintf_P(s, PSTR("%u"), bri);
|
sprintf_P(s, PSTR("%u"), bri);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/g"));
|
strcat_P(subuf, PSTR("/g"));
|
||||||
mqtt->publish(subuf, 0, true, s); // retain message
|
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||||
|
|
||||||
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/c"));
|
strcat_P(subuf, PSTR("/c"));
|
||||||
mqtt->publish(subuf, 0, true, s); // retain message
|
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||||
|
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/status"));
|
strcat_P(subuf, PSTR("/status"));
|
||||||
@ -157,7 +157,7 @@ void publishMqtt()
|
|||||||
XML_response(nullptr, apires);
|
XML_response(nullptr, apires);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/v"));
|
strcat_P(subuf, PSTR("/v"));
|
||||||
mqtt->publish(subuf, 0, false, apires); // do not retain message
|
mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,3 +23,4 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//#define MAX_LEDS 1500 // Maximum total LEDs. More than 1500 might create a low memory situation on ESP8266.
|
//#define MAX_LEDS 1500 // Maximum total LEDs. More than 1500 might create a low memory situation on ESP8266.
|
||||||
|
//#define MDNS_NAME "wled" // mDNS hostname, ie: *.local
|
||||||
|
@ -152,16 +152,13 @@ int getSignalQuality(int rssi)
|
|||||||
//handle Ethernet connection event
|
//handle Ethernet connection event
|
||||||
void WiFiEvent(WiFiEvent_t event)
|
void WiFiEvent(WiFiEvent_t event)
|
||||||
{
|
{
|
||||||
#ifdef WLED_USE_ETHERNET
|
|
||||||
char hostname[25];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
case SYSTEM_EVENT_ETH_START:
|
case SYSTEM_EVENT_ETH_START:
|
||||||
DEBUG_PRINTLN(F("ETH Started"));
|
DEBUG_PRINTLN(F("ETH Started"));
|
||||||
break;
|
break;
|
||||||
case SYSTEM_EVENT_ETH_CONNECTED:
|
case SYSTEM_EVENT_ETH_CONNECTED:
|
||||||
|
{
|
||||||
DEBUG_PRINTLN(F("ETH Connected"));
|
DEBUG_PRINTLN(F("ETH Connected"));
|
||||||
if (!apActive) {
|
if (!apActive) {
|
||||||
WiFi.disconnect(true);
|
WiFi.disconnect(true);
|
||||||
@ -172,10 +169,12 @@ void WiFiEvent(WiFiEvent_t event)
|
|||||||
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||||
}
|
}
|
||||||
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
|
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
|
||||||
|
char hostname[64];
|
||||||
prepareHostname(hostname);
|
prepareHostname(hostname);
|
||||||
ETH.setHostname(hostname);
|
ETH.setHostname(hostname);
|
||||||
showWelcomePage = false;
|
showWelcomePage = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||||
DEBUG_PRINTLN(F("ETH Disconnected"));
|
DEBUG_PRINTLN(F("ETH Disconnected"));
|
||||||
// This doesn't really affect ethernet per se,
|
// This doesn't really affect ethernet per se,
|
||||||
|
@ -52,7 +52,7 @@ static void doSaveState() {
|
|||||||
size_t len = measureJson(*fileDoc) + 1;
|
size_t len = measureJson(*fileDoc) + 1;
|
||||||
DEBUG_PRINTLN(len);
|
DEBUG_PRINTLN(len);
|
||||||
// if possible use SPI RAM on ESP32
|
// if possible use SPI RAM on ESP32
|
||||||
#ifdef WLED_USE_PSRAM
|
#if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||||
if (psramFound())
|
if (psramFound())
|
||||||
tmpRAMbuffer = (char*) ps_malloc(len);
|
tmpRAMbuffer = (char*) ps_malloc(len);
|
||||||
else
|
else
|
||||||
@ -120,6 +120,15 @@ bool applyPreset(byte index, byte callMode)
|
|||||||
return true;
|
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()
|
void handlePresets()
|
||||||
{
|
{
|
||||||
if (presetToSave) {
|
if (presetToSave) {
|
||||||
@ -167,10 +176,11 @@ void handlePresets()
|
|||||||
changePreset = true;
|
changePreset = true;
|
||||||
} else {
|
} else {
|
||||||
if (!fdo["seg"].isNull() || !fdo["on"].isNull() || !fdo["bri"].isNull() || !fdo["nl"].isNull() || !fdo["ps"].isNull() || !fdo[F("playlist")].isNull()) changePreset = true;
|
if (!fdo["seg"].isNull() || !fdo["on"].isNull() || !fdo["bri"].isNull() || !fdo["nl"].isNull() || !fdo["ps"].isNull() || !fdo[F("playlist")].isNull()) changePreset = true;
|
||||||
fdo.remove("ps"); //remove load request for presets to prevent recursive crash
|
if (!(tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is<const char *>() && strchr(fdo["ps"].as<const char *>(),'~') != strrchr(fdo["ps"].as<const char *>(),'~')))
|
||||||
|
fdo.remove("ps"); // remove load request for presets to prevent recursive crash (if not called by button and contains preset cycling string "1~5~")
|
||||||
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
|
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
|
||||||
}
|
}
|
||||||
if (!errorFlag && tmpPreset < 255 && changePreset) presetCycCurr = currentPreset = tmpPreset;
|
if (!errorFlag && tmpPreset < 255 && changePreset) currentPreset = tmpPreset;
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
//Aircoookie recommended not to delete buffer
|
//Aircoookie recommended not to delete buffer
|
||||||
|
200
wled00/remote.cpp
Normal file
200
wled00/remote.cpp
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#include "wled.h"
|
||||||
|
|
||||||
|
#define ESP_NOW_STATE_UNINIT 0
|
||||||
|
#define ESP_NOW_STATE_ON 1
|
||||||
|
#define ESP_NOW_STATE_ERROR 2
|
||||||
|
|
||||||
|
#define NIGHT_MODE_DEACTIVATED -1
|
||||||
|
#define NIGHT_MODE_BRIGHTNESS 5
|
||||||
|
|
||||||
|
#define WIZMOTE_BUTTON_ON 1
|
||||||
|
#define WIZMOTE_BUTTON_OFF 2
|
||||||
|
#define WIZMOTE_BUTTON_NIGHT 3
|
||||||
|
#define WIZMOTE_BUTTON_ONE 16
|
||||||
|
#define WIZMOTE_BUTTON_TWO 17
|
||||||
|
#define WIZMOTE_BUTTON_THREE 18
|
||||||
|
#define WIZMOTE_BUTTON_FOUR 19
|
||||||
|
#define WIZMOTE_BUTTON_BRIGHT_UP 9
|
||||||
|
#define WIZMOTE_BUTTON_BRIGHT_DOWN 8
|
||||||
|
|
||||||
|
#ifdef WLED_DISABLE_ESPNOW
|
||||||
|
void handleRemote(){}
|
||||||
|
#else
|
||||||
|
|
||||||
|
// This is kind of an esoteric strucure because it's pulled from the "Wizmote"
|
||||||
|
// product spec. That remote is used as the baseline for behavior and availability
|
||||||
|
// since it's broadly commercially available and works out of the box as a drop-in
|
||||||
|
typedef struct message_structure {
|
||||||
|
uint8_t program; // 0x91 for ON button, 0x81 for all others
|
||||||
|
uint8_t seq[4]; // Incremetal sequence number 32 bit unsigned integer LSB first
|
||||||
|
uint8_t byte5 = 32; // Unknown
|
||||||
|
uint8_t button; // Identifies which button is being pressed
|
||||||
|
uint8_t byte8 = 1; // Unknown, but always 0x01
|
||||||
|
uint8_t byte9 = 100; // Unnkown, but always 0x64
|
||||||
|
|
||||||
|
uint8_t byte10; // Unknown, maybe checksum
|
||||||
|
uint8_t byte11; // Unknown, maybe checksum
|
||||||
|
uint8_t byte12; // Unknown, maybe checksum
|
||||||
|
uint8_t byte13; // Unknown, maybe checksum
|
||||||
|
} message_structure;
|
||||||
|
|
||||||
|
static int esp_now_state = ESP_NOW_STATE_UNINIT;
|
||||||
|
static uint32_t last_seq = -1;
|
||||||
|
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
|
||||||
|
const byte brightnessSteps[] = {
|
||||||
|
6, 9, 14, 22, 33, 50, 75, 113, 170, 255
|
||||||
|
};
|
||||||
|
const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t);
|
||||||
|
|
||||||
|
bool nightModeActive() {
|
||||||
|
return brightnessBeforeNightMode != NIGHT_MODE_DEACTIVATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void activateNightMode() {
|
||||||
|
brightnessBeforeNightMode = bri;
|
||||||
|
bri = NIGHT_MODE_BRIGHTNESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resetNightMode() {
|
||||||
|
if (!nightModeActive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bri = brightnessBeforeNightMode;
|
||||||
|
brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment `bri` to the next `brightnessSteps` value
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOn() {
|
||||||
|
if (resetNightMode()) {
|
||||||
|
stateUpdated(CALL_MODE_BUTTON);
|
||||||
|
}
|
||||||
|
if (!bri) {
|
||||||
|
toggleOnOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOff() {
|
||||||
|
if (resetNightMode()) {
|
||||||
|
stateUpdated(CALL_MODE_BUTTON);
|
||||||
|
}
|
||||||
|
if (bri) {
|
||||||
|
toggleOnOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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
|
@ -7,11 +7,9 @@
|
|||||||
//called upon POST settings form submit
|
//called upon POST settings form submit
|
||||||
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||||
{
|
{
|
||||||
// PIN code request
|
if (subPage == SUBPAGE_PINREQ)
|
||||||
if (subPage == 252)
|
|
||||||
{
|
{
|
||||||
correctPIN = (strlen(settingsPIN)==0 || strncmp(settingsPIN, request->arg(F("PIN")).c_str(), 4)==0);
|
checkSettingsPIN(request->arg(F("PIN")).c_str());
|
||||||
lastEditTime = millis();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,7 +17,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
if (subPage < 1 || subPage > 10 || !correctPIN) return;
|
if (subPage < 1 || subPage > 10 || !correctPIN) return;
|
||||||
|
|
||||||
//WIFI SETTINGS
|
//WIFI SETTINGS
|
||||||
if (subPage == 1)
|
if (subPage == SUBPAGE_WIFI)
|
||||||
{
|
{
|
||||||
strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33);
|
strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33);
|
||||||
|
|
||||||
@ -36,6 +34,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
|
|
||||||
noWifiSleep = request->hasArg(F("WS"));
|
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
|
#ifdef WLED_USE_ETHERNET
|
||||||
ethernetType = request->arg(F("ETH")).toInt();
|
ethernetType = request->arg(F("ETH")).toInt();
|
||||||
WLED::instance().initEthernet();
|
WLED::instance().initEthernet();
|
||||||
@ -58,7 +64,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//LED SETTINGS
|
//LED SETTINGS
|
||||||
if (subPage == 2)
|
if (subPage == SUBPAGE_LEDS)
|
||||||
{
|
{
|
||||||
int t = 0;
|
int t = 0;
|
||||||
|
|
||||||
@ -233,7 +239,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
gammaCorrectCol = request->hasArg(F("GC"));
|
gammaCorrectCol = request->hasArg(F("GC"));
|
||||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
||||||
calcGammaTable(gammaCorrectVal);
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||||
else {
|
else {
|
||||||
gammaCorrectVal = 1.0f; // no gamma correction
|
gammaCorrectVal = 1.0f; // no gamma correction
|
||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
@ -262,7 +268,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//UI
|
//UI
|
||||||
if (subPage == 3)
|
if (subPage == SUBPAGE_UI)
|
||||||
{
|
{
|
||||||
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
|
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
|
||||||
syncToggleReceive = request->hasArg(F("ST"));
|
syncToggleReceive = request->hasArg(F("ST"));
|
||||||
@ -280,7 +286,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//SYNC
|
//SYNC
|
||||||
if (subPage == 4)
|
if (subPage == SUBPAGE_SYNC)
|
||||||
{
|
{
|
||||||
int t = request->arg(F("UP")).toInt();
|
int t = request->arg(F("UP")).toInt();
|
||||||
if (t > 0) udpPort = t;
|
if (t > 0) udpPort = t;
|
||||||
@ -350,6 +356,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33);
|
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33);
|
||||||
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33);
|
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33);
|
||||||
buttonPublishMqtt = request->hasArg(F("BM"));
|
buttonPublishMqtt = request->hasArg(F("BM"));
|
||||||
|
retainMqttMsg = request->hasArg(F("RT"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_HUESYNC
|
#ifndef WLED_DISABLE_HUESYNC
|
||||||
@ -378,7 +385,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TIME
|
//TIME
|
||||||
if (subPage == 5)
|
if (subPage == SUBPAGE_TIME)
|
||||||
{
|
{
|
||||||
ntpEnabled = request->hasArg(F("NT"));
|
ntpEnabled = request->hasArg(F("NT"));
|
||||||
strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33);
|
strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33);
|
||||||
@ -452,7 +459,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//SECURITY
|
//SECURITY
|
||||||
if (subPage == 6)
|
if (subPage == SUBPAGE_SEC)
|
||||||
{
|
{
|
||||||
if (request->hasArg(F("RS"))) //complete factory reset
|
if (request->hasArg(F("RS"))) //complete factory reset
|
||||||
{
|
{
|
||||||
@ -461,7 +468,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
clearEEPROM();
|
clearEEPROM();
|
||||||
#endif
|
#endif
|
||||||
serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255);
|
serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255);
|
||||||
doReboot = true;
|
doReboot = true; // may reboot immediately on dual-core system (race condition) which is desireable in this case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request->hasArg(F("PIN"))) {
|
if (request->hasArg(F("PIN"))) {
|
||||||
@ -483,7 +490,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
if (otaLock && strcmp(otaPass,request->arg(F("OP")).c_str()) == 0)
|
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
|
// brute force protection: do not unlock even if correct if last save was less than 3 seconds ago
|
||||||
if (millis() - lastEditTime > 3000) pwdCorrect = true;
|
if (millis() - lastEditTime > PIN_RETRY_COOLDOWN) pwdCorrect = true;
|
||||||
}
|
}
|
||||||
if (!otaLock && request->arg(F("OP")).length() > 0)
|
if (!otaLock && request->arg(F("OP")).length() > 0)
|
||||||
{
|
{
|
||||||
@ -501,7 +508,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||||
if (subPage == 7)
|
if (subPage == SUBPAGE_DMX)
|
||||||
{
|
{
|
||||||
int t = request->arg(F("PU")).toInt();
|
int t = request->arg(F("PU")).toInt();
|
||||||
if (t >= 0 && t <= 63999) e131ProxyUniverse = t;
|
if (t >= 0 && t <= 63999) e131ProxyUniverse = t;
|
||||||
@ -531,34 +538,31 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//USERMODS
|
//USERMODS
|
||||||
if (subPage == 8)
|
if (subPage == SUBPAGE_UM)
|
||||||
{
|
{
|
||||||
if (!requestJSONBufferLock(5)) return;
|
if (!requestJSONBufferLock(5)) return;
|
||||||
|
|
||||||
// global I2C & SPI pins
|
// global I2C & SPI pins
|
||||||
int8_t hw_sda_pin = !request->arg(F("SDA")).length() ? -1 : (int)request->arg(F("SDA")).toInt();
|
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();
|
int8_t hw_scl_pin = !request->arg(F("SCL")).length() ? -1 : (int)request->arg(F("SCL")).toInt();
|
||||||
#ifdef ESP8266
|
if (i2c_sda != hw_sda_pin || i2c_scl != hw_scl_pin) {
|
||||||
// cannot change pins on ESP8266
|
// only if pins changed
|
||||||
if (hw_sda_pin >= 0 && hw_sda_pin != HW_PIN_SDA) hw_sda_pin = HW_PIN_SDA;
|
uint8_t old_i2c[2] = { static_cast<uint8_t>(i2c_scl), static_cast<uint8_t>(i2c_sda) };
|
||||||
if (hw_scl_pin >= 0 && hw_scl_pin != HW_PIN_SCL) hw_scl_pin = HW_PIN_SCL;
|
pinManager.deallocateMultiplePins(old_i2c, 2, PinOwner::HW_I2C); // just in case deallocation of old pins
|
||||||
#endif
|
|
||||||
PinManagerPinType i2c[2] = { { hw_sda_pin, true }, { hw_scl_pin, true } };
|
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)) {
|
if (hw_sda_pin >= 0 && hw_scl_pin >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
||||||
i2c_sda = hw_sda_pin;
|
i2c_sda = hw_sda_pin;
|
||||||
i2c_scl = hw_scl_pin;
|
i2c_scl = hw_scl_pin;
|
||||||
#ifdef ESP32
|
// no bus re-initialisation as usermods do not get any notification
|
||||||
Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called)
|
//Wire.begin(i2c_sda, i2c_scl);
|
||||||
#endif
|
|
||||||
Wire.begin();
|
|
||||||
} else {
|
} else {
|
||||||
// there is no Wire.end()
|
// there is no Wire.end()
|
||||||
DEBUG_PRINTLN(F("Could not allocate I2C pins."));
|
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_sda = -1;
|
||||||
i2c_scl = -1;
|
i2c_scl = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
int8_t hw_mosi_pin = !request->arg(F("MOSI")).length() ? -1 : (int)request->arg(F("MOSI")).toInt();
|
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();
|
int8_t hw_miso_pin = !request->arg(F("MISO")).length() ? -1 : (int)request->arg(F("MISO")).toInt();
|
||||||
int8_t hw_sclk_pin = !request->arg(F("SCLK")).length() ? -1 : (int)request->arg(F("SCLK")).toInt();
|
int8_t hw_sclk_pin = !request->arg(F("SCLK")).length() ? -1 : (int)request->arg(F("SCLK")).toInt();
|
||||||
@ -568,6 +572,10 @@ 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_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;
|
if (hw_sclk_pin >= 0 && hw_sclk_pin != HW_PIN_CLOCKSPI) hw_sclk_pin = HW_PIN_CLOCKSPI;
|
||||||
#endif
|
#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 } };
|
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)) {
|
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
|
||||||
spi_mosi = hw_mosi_pin;
|
spi_mosi = hw_mosi_pin;
|
||||||
@ -583,12 +591,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
} else {
|
} else {
|
||||||
//SPI.end();
|
//SPI.end();
|
||||||
DEBUG_PRINTLN(F("Could not allocate SPI pins."));
|
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_mosi = -1;
|
||||||
spi_miso = -1;
|
spi_miso = -1;
|
||||||
spi_sclk = -1;
|
spi_sclk = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject um = doc.createNestedObject("um");
|
JsonObject um = doc.createNestedObject("um");
|
||||||
|
|
||||||
@ -671,7 +678,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
//2D panels
|
//2D panels
|
||||||
if (subPage == 10)
|
if (subPage == SUBPAGE_2D)
|
||||||
{
|
{
|
||||||
strip.isMatrix = request->arg(F("SOMP")).toInt();
|
strip.isMatrix = request->arg(F("SOMP")).toInt();
|
||||||
strip.panel.clear(); // release memory if allocated
|
strip.panel.clear(); // release memory if allocated
|
||||||
@ -707,9 +714,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
lastEditTime = millis();
|
lastEditTime = millis();
|
||||||
if (subPage != 2 && !doReboot) doSerializeConfig = true; //serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
// do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||||
|
doSerializeConfig = subPage != SUBPAGE_LEDS && !(subPage == SUBPAGE_SEC && doReboot);
|
||||||
|
if (subPage == SUBPAGE_UM) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after doSerializeConfig has been set)
|
||||||
#ifndef WLED_DISABLE_ALEXA
|
#ifndef WLED_DISABLE_ALEXA
|
||||||
if (subPage == 4) alexaInit();
|
if (subPage == SUBPAGE_SYNC) alexaInit();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,7 +797,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
spcI = getNumVal(&req, pos);
|
spcI = getNumVal(&req, pos);
|
||||||
}
|
}
|
||||||
selseg.set(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
|
pos = req.indexOf(F("RV=")); //Segment reverse
|
||||||
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
||||||
|
@ -53,8 +53,8 @@ typedef struct ip_addr ip4_addr_t;
|
|||||||
#define DDP_PUSH_FLAG 0x01
|
#define DDP_PUSH_FLAG 0x01
|
||||||
#define DDP_TIMECODE_FLAG 0x10
|
#define DDP_TIMECODE_FLAG 0x10
|
||||||
|
|
||||||
#define DDP_TYPE_RGB24 0x0A
|
#define DDP_TYPE_RGB24 0x0B // 00 001 011 (RGB , 8 bits per channel, 3 channels)
|
||||||
#define DDP_TYPE_RGBW32 0x1A
|
#define DDP_TYPE_RGBW32 0x1B // 00 011 011 (RGBW, 8 bits per channel, 4 channels)
|
||||||
|
|
||||||
#define ARTNET_OPCODE_OPDMX 0x5000
|
#define ARTNET_OPCODE_OPDMX 0x5000
|
||||||
#define ARTNET_OPCODE_OPPOLL 0x2000
|
#define ARTNET_OPCODE_OPPOLL 0x2000
|
||||||
|
@ -362,7 +362,7 @@ void handleNotifications()
|
|||||||
uint16_t stopY = 1, stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
uint16_t stopY = 1, stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
||||||
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
||||||
if (!receiveSegmentOptions) {
|
if (!receiveSegmentOptions) {
|
||||||
selseg.set(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//for (size_t j = 1; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, on, reversed; ignore selected
|
//for (size_t j = 1; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, on, reversed; ignore selected
|
||||||
@ -396,9 +396,9 @@ void handleNotifications()
|
|||||||
stopY = (udpIn[34+ofs] << 8 | udpIn[35+ofs]);
|
stopY = (udpIn[34+ofs] << 8 | udpIn[35+ofs]);
|
||||||
}
|
}
|
||||||
if (receiveSegmentBounds) {
|
if (receiveSegmentBounds) {
|
||||||
selseg.set(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||||
} else {
|
} else {
|
||||||
selseg.set(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stateChanged = true;
|
stateChanged = true;
|
||||||
@ -669,6 +669,7 @@ void sendSysInfoUDP()
|
|||||||
#else
|
#else
|
||||||
data[38] = NODE_TYPE_ID_UNDEFINED;
|
data[38] = NODE_TYPE_ID_UNDEFINED;
|
||||||
#endif
|
#endif
|
||||||
|
if (bri) data[38] |= 0x80U; // add on/off state
|
||||||
data[39] = ip[3]; // unit ID == last IP number
|
data[39] = ip[3]; // unit ID == last IP number
|
||||||
|
|
||||||
uint32_t build = VERSION;
|
uint32_t build = VERSION;
|
||||||
|
@ -373,6 +373,16 @@ int16_t extractModeDefaults(uint8_t mode, const char *segVar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void checkSettingsPIN(const char* pin) {
|
||||||
|
if (!pin) return;
|
||||||
|
if (!correctPIN && millis() - lastEditTime < PIN_RETRY_COOLDOWN) return; // guard against PIN brute force
|
||||||
|
bool correctBefore = correctPIN;
|
||||||
|
correctPIN = (strlen(settingsPIN) == 0 || strncmp(settingsPIN, pin, 4) == 0);
|
||||||
|
if (correctBefore != correctPIN) createEditHandler(correctPIN);
|
||||||
|
lastEditTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t crc16(const unsigned char* data_p, size_t length) {
|
uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||||
uint8_t x;
|
uint8_t x;
|
||||||
uint16_t crc = 0xFFFF;
|
uint16_t crc = 0xFFFF;
|
||||||
@ -390,11 +400,12 @@ uint16_t crc16(const unsigned char* data_p, size_t length) {
|
|||||||
// Begin simulateSound (to enable audio enhanced effects to display something)
|
// Begin simulateSound (to enable audio enhanced effects to display something)
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Currently 4 types defined, to be fine tuned and new types added
|
// Currently 4 types defined, to be fine tuned and new types added
|
||||||
|
// (only 2 used as stored in 1 bit in segment options, consider switching to a single global simulation type)
|
||||||
typedef enum UM_SoundSimulations {
|
typedef enum UM_SoundSimulations {
|
||||||
UMS_BeatSin = 0,
|
UMS_BeatSin = 0,
|
||||||
UMS_WeWillRockYou,
|
UMS_WeWillRockYou
|
||||||
UMS_10_3,
|
//UMS_10_13,
|
||||||
UMS_14_3
|
//UMS_14_3
|
||||||
} um_soundSimulations_t;
|
} um_soundSimulations_t;
|
||||||
|
|
||||||
um_data_t* simulateSound(uint8_t simulationId)
|
um_data_t* simulateSound(uint8_t simulationId)
|
||||||
@ -479,7 +490,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
fftResult[i] = 0;
|
fftResult[i] = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case UMS_10_3:
|
/*case UMS_10_3:
|
||||||
for (int i = 0; i<16; i++)
|
for (int i = 0; i<16; i++)
|
||||||
fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
||||||
volumeSmth = fftResult[8];
|
volumeSmth = fftResult[8];
|
||||||
@ -488,12 +499,12 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
for (int i = 0; i<16; i++)
|
for (int i = 0; i<16; i++)
|
||||||
fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
|
fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
|
||||||
volumeSmth = fftResult[8];
|
volumeSmth = fftResult[8];
|
||||||
break;
|
break;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
samplePeak = random8() > 250;
|
samplePeak = random8() > 250;
|
||||||
FFT_MajorPeak = volumeSmth;
|
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
|
||||||
maxVol = 10; // this gets feedback fro UI
|
maxVol = 31; // this gets feedback fro UI
|
||||||
binNum = 8; // this gets feedback fro UI
|
binNum = 8; // this gets feedback fro UI
|
||||||
volumeRaw = volumeSmth;
|
volumeRaw = volumeSmth;
|
||||||
my_magnitude = 10000.0 / 8.0f; //no idea if 10000 is a good value for FFT_Magnitude ???
|
my_magnitude = 10000.0 / 8.0f; //no idea if 10000 is a good value for FFT_Magnitude ???
|
||||||
|
@ -46,7 +46,9 @@ void WLED::loop()
|
|||||||
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
||||||
#endif
|
#endif
|
||||||
handleConnection();
|
handleConnection();
|
||||||
|
handleRemote();
|
||||||
handleSerial();
|
handleSerial();
|
||||||
|
handleImprovWifiScan();
|
||||||
handleNotifications();
|
handleNotifications();
|
||||||
handleTransitions();
|
handleTransitions();
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
@ -73,13 +75,6 @@ void WLED::loop()
|
|||||||
handleAlexa();
|
handleAlexa();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
yield();
|
|
||||||
|
|
||||||
if (doSerializeConfig) serializeConfig();
|
|
||||||
|
|
||||||
if (doReboot && !doInitBusses) // if busses have to be inited & saved, wait until next iteration
|
|
||||||
reset();
|
|
||||||
|
|
||||||
if (doCloseFile) {
|
if (doCloseFile) {
|
||||||
closeFile();
|
closeFile();
|
||||||
yield();
|
yield();
|
||||||
@ -145,7 +140,7 @@ void WLED::loop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 15min PIN time-out
|
// 15min PIN time-out
|
||||||
if (strlen(settingsPIN)>0 && millis() - lastEditTime > 900000) {
|
if (strlen(settingsPIN)>0 && correctPIN && millis() - lastEditTime > PIN_TIMEOUT) {
|
||||||
correctPIN = false;
|
correctPIN = false;
|
||||||
createEditHandler(false);
|
createEditHandler(false);
|
||||||
}
|
}
|
||||||
@ -169,13 +164,14 @@ void WLED::loop()
|
|||||||
strip.finalizeInit(); // also loads default ledmap if present
|
strip.finalizeInit(); // also loads default ledmap if present
|
||||||
if (aligned) strip.makeAutoSegments();
|
if (aligned) strip.makeAutoSegments();
|
||||||
else strip.fixInvalidSegments();
|
else strip.fixInvalidSegments();
|
||||||
yield();
|
doSerializeConfig = true;
|
||||||
serializeConfig();
|
|
||||||
}
|
}
|
||||||
if (loadLedmap >= 0) {
|
if (loadLedmap >= 0) {
|
||||||
if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix();
|
if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix();
|
||||||
loadLedmap = -1;
|
loadLedmap = -1;
|
||||||
}
|
}
|
||||||
|
yield();
|
||||||
|
if (doSerializeConfig) serializeConfig();
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
handleWs();
|
handleWs();
|
||||||
@ -188,12 +184,11 @@ void WLED::loop()
|
|||||||
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
|
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
|
||||||
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
|
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
|
||||||
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||||
if (psramFound()) {
|
if (psramFound()) {
|
||||||
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
|
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
|
||||||
DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
|
DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
|
||||||
} else
|
}
|
||||||
DEBUG_PRINTLN(F("No PSRAM"));
|
|
||||||
#endif
|
#endif
|
||||||
DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status());
|
DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status());
|
||||||
|
|
||||||
@ -230,6 +225,9 @@ void WLED::loop()
|
|||||||
ESP.wdtFeed();
|
ESP.wdtFeed();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WLED::enableWatchdog() {
|
void WLED::enableWatchdog() {
|
||||||
@ -321,25 +319,33 @@ void WLED::setup()
|
|||||||
#endif
|
#endif
|
||||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||||
if (psramFound()) {
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
// S3: reserve GPIO 33-37 for "octal" PSRAM
|
||||||
|
managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} };
|
||||||
|
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
// S2: reserve GPIO 26-32 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation)
|
||||||
|
managed_pin_type pins[] = { {26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true} };
|
||||||
|
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
// C3: reserve GPIO 12-17 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation)
|
||||||
|
managed_pin_type pins[] = { {12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true} };
|
||||||
|
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||||
|
#else
|
||||||
// GPIO16/GPIO17 reserved for SPI RAM
|
// GPIO16/GPIO17 reserved for SPI RAM
|
||||||
managed_pin_type pins[2] = { {16, true}, {17, true} };
|
managed_pin_type pins[] = { {16, true}, {17, true} };
|
||||||
pinManager.allocateMultiplePins(pins, 2, PinOwner::SPI_RAM);
|
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
|
||||||
// S3: add GPIO 33-37 for "octal" PSRAM
|
|
||||||
managed_pin_type pins[5] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} };
|
|
||||||
pinManager.allocateMultiplePins(pins, 5, PinOwner::SPI_RAM);
|
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(WLED_USE_PSRAM)
|
||||||
|
if (psramFound()) {
|
||||||
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
|
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
|
||||||
DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
|
DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
|
||||||
} else
|
}
|
||||||
DEBUG_PRINTLN(F("No PSRAM found."));
|
#else
|
||||||
#endif
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && !defined(WLED_USE_PSRAM)
|
|
||||||
DEBUG_PRINTLN(F("PSRAM not used."));
|
DEBUG_PRINTLN(F("PSRAM not used."));
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
|
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
|
||||||
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
|
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
|
||||||
@ -429,8 +435,6 @@ void WLED::setup()
|
|||||||
if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket();
|
if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strip.service(); // why?
|
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_OTA
|
#ifndef WLED_DISABLE_OTA
|
||||||
if (aOtaEnabled) {
|
if (aOtaEnabled) {
|
||||||
ArduinoOTA.onStart([]() {
|
ArduinoOTA.onStart([]() {
|
||||||
@ -480,7 +484,10 @@ void WLED::beginStrip()
|
|||||||
if (briS > 0) bri = briS;
|
if (briS > 0) bri = briS;
|
||||||
else if (bri == 0) bri = 128;
|
else if (bri == 0) bri = 128;
|
||||||
} else {
|
} else {
|
||||||
|
// fix for #3196
|
||||||
briLast = briS; bri = 0;
|
briLast = briS; bri = 0;
|
||||||
|
strip.fill(BLACK);
|
||||||
|
strip.show();
|
||||||
}
|
}
|
||||||
if (bootPreset > 0) {
|
if (bootPreset > 0) {
|
||||||
applyPreset(bootPreset, CALL_MODE_INIT);
|
applyPreset(bootPreset, CALL_MODE_INIT);
|
||||||
@ -640,7 +647,6 @@ void WLED::initConnection()
|
|||||||
ws.onEvent(wsEvent);
|
ws.onEvent(wsEvent);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
WiFi.disconnect(true); // close old connections
|
WiFi.disconnect(true); // close old connections
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||||
@ -718,8 +724,6 @@ void WLED::initInterfaces()
|
|||||||
ArduinoOTA.begin();
|
ArduinoOTA.begin();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strip.service();
|
|
||||||
|
|
||||||
// Set up mDNS responder:
|
// Set up mDNS responder:
|
||||||
if (strlen(cmDNS) > 0) {
|
if (strlen(cmDNS) > 0) {
|
||||||
// "end" must be called before "begin" is called a 2nd time
|
// "end" must be called before "begin" is called a 2nd time
|
||||||
@ -841,7 +845,7 @@ void WLED::handleConnection()
|
|||||||
if (improvActive) {
|
if (improvActive) {
|
||||||
if (improvError == 3) sendImprovStateResponse(0x00, true);
|
if (improvError == 3) sendImprovStateResponse(0x00, true);
|
||||||
sendImprovStateResponse(0x04);
|
sendImprovStateResponse(0x04);
|
||||||
if (improvActive > 1) sendImprovRPCResponse(0x01);
|
if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi);
|
||||||
}
|
}
|
||||||
initInterfaces();
|
initInterfaces();
|
||||||
userConnected();
|
userConnected();
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
/*
|
/*
|
||||||
Main sketch, global variable declarations
|
Main sketch, global variable declarations
|
||||||
@title WLED project sketch
|
@title WLED project sketch
|
||||||
@version 0.14.0-b2
|
@version 0.14.0-b3
|
||||||
@author Christian Schwinne
|
@author Christian Schwinne
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2305090
|
#define VERSION 2307130
|
||||||
|
|
||||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
@ -36,7 +36,7 @@
|
|||||||
#undef WLED_ENABLE_ADALIGHT // disable has priority over enable
|
#undef WLED_ENABLE_ADALIGHT // disable has priority over enable
|
||||||
#endif
|
#endif
|
||||||
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
//#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
|
#ifndef WLED_DISABLE_LOXONE
|
||||||
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||||
#endif
|
#endif
|
||||||
@ -44,6 +44,8 @@
|
|||||||
#define WLED_ENABLE_WEBSOCKETS
|
#define WLED_ENABLE_WEBSOCKETS
|
||||||
#endif
|
#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
|
#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
|
// to toggle usb serial debug (un)comment the following line
|
||||||
@ -73,6 +75,9 @@
|
|||||||
{
|
{
|
||||||
#include <user_interface.h>
|
#include <user_interface.h>
|
||||||
}
|
}
|
||||||
|
#ifndef WLED_DISABLE_ESPNOW
|
||||||
|
#include <espnow.h>
|
||||||
|
#endif
|
||||||
#else // ESP32
|
#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 <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>
|
#include <WiFi.h>
|
||||||
@ -89,6 +94,10 @@
|
|||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
#endif
|
#endif
|
||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_ESPNOW
|
||||||
|
#include <esp_now.h>
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
@ -145,7 +154,7 @@
|
|||||||
// The following is a construct to enable code to compile without it.
|
// The following is a construct to enable code to compile without it.
|
||||||
// There is a code thet will still not use PSRAM though:
|
// There is a code thet will still not use PSRAM though:
|
||||||
// AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h)
|
// AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h)
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||||
struct PSRAM_Allocator {
|
struct PSRAM_Allocator {
|
||||||
void* allocate(size_t size) {
|
void* allocate(size_t size) {
|
||||||
if (psramFound()) return ps_malloc(size); // use PSRAM if it exists
|
if (psramFound()) return ps_malloc(size); // use PSRAM if it exists
|
||||||
@ -179,6 +188,10 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
|||||||
#define CLIENT_PASS ""
|
#define CLIENT_PASS ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MDNS_NAME
|
||||||
|
#define MDNS_NAME DEFAULT_MDNS_NAME
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(WLED_AP_PASS) && !defined(WLED_AP_SSID)
|
#if defined(WLED_AP_PASS) && !defined(WLED_AP_SSID)
|
||||||
#error WLED_AP_PASS is defined but WLED_AP_SSID is still the default. \
|
#error WLED_AP_PASS is defined but WLED_AP_SSID is still the default. \
|
||||||
Please change WLED_AP_SSID to something unique.
|
Please change WLED_AP_SSID to something unique.
|
||||||
@ -289,7 +302,7 @@ WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server
|
|||||||
// WiFi CONFIG (all these can be changed via web UI, no need to set them here)
|
// WiFi CONFIG (all these can be changed via web UI, no need to set them here)
|
||||||
WLED_GLOBAL char clientSSID[33] _INIT(CLIENT_SSID);
|
WLED_GLOBAL char clientSSID[33] _INIT(CLIENT_SSID);
|
||||||
WLED_GLOBAL char clientPass[65] _INIT(CLIENT_PASS);
|
WLED_GLOBAL char clientPass[65] _INIT(CLIENT_PASS);
|
||||||
WLED_GLOBAL char cmDNS[33] _INIT("x"); // mDNS address (placeholder, is replaced by wledXXXXXX.local)
|
WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used)
|
||||||
WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup)
|
WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup)
|
||||||
WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13)
|
WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13)
|
||||||
WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID
|
WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID
|
||||||
@ -421,6 +434,7 @@ WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username
|
|||||||
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
|
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
|
||||||
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
|
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
|
||||||
WLED_GLOBAL uint16_t mqttPort _INIT(1883);
|
WLED_GLOBAL uint16_t mqttPort _INIT(1883);
|
||||||
|
WLED_GLOBAL bool retainMqttMsg _INIT(false); // retain brightness and color
|
||||||
#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected())
|
#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected())
|
||||||
#else
|
#else
|
||||||
#define WLED_MQTT_CONNECTED false
|
#define WLED_MQTT_CONNECTED false
|
||||||
@ -439,6 +453,12 @@ WLED_GLOBAL bool hueApplyColor _INIT(true);
|
|||||||
|
|
||||||
WLED_GLOBAL uint16_t serialBaud _INIT(1152); // serial baud rate, multiply by 100
|
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
|
// 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 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
|
WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,387 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="Source Files">
|
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files">
|
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Resource Files">
|
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files\Dependencies">
|
|
||||||
<UniqueIdentifier>{72fe60da-ba26-45b4-82c1-bdff809975da}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\Dependencies">
|
|
||||||
<UniqueIdentifier>{8880888d-efea-4189-a25a-834b7b3bb756}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="wled00.ino" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="__vm\.wled00.vsarduino.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="html_classic.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="html_mobile.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="html_other.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="html_settings.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="FX.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\json\ArduinoJson-v6.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\json\AsyncJson-v6.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApi.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkApiArduino.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkArduinoClient.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkConfig.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDateTime.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDebug.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkDetectDevice.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkEveryN.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkFifo.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkHandlers.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkParam.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocol.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkProtocolDefs.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\BlynkSimpleEsp.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTemplates.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkTimer.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkUtility.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWidgetBase.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\blynk\Blynk\BlynkWiFiCommon.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Callbacks.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\DisconnectReasons.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\espalexa\Espalexa.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\espalexa\EspalexaDevice.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\e131\ESPAsyncE131.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Flags.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Helpers.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\MessageProperties.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="NpbWrapper.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\Packet.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\ParsingInformation.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Storage.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\time\Time.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\time\TimeLib.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\timezone\Timezone.h">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.hpp">
|
|
||||||
<Filter>Header Files\Dependencies</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="alexa.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="blynk.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="button.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="colors.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="const.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="cronixie.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="dmx.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="file.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="html_ui.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="hue.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="ir.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="json.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="led.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="mqtt.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="notify.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="ntp.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="overlay.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="set.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="usermod.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="wled.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="wled_eeprom.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="wled_server.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="xml.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="ir_codes.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="palettes.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="FX.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="FX_fcn.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\blynk\Blynk\utility.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkDebug.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkHandlers.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\blynk\Blynk\BlynkTimer.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\ConnAckPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\time\DateStrings.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\espalexa\EspalexaDevice.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\e131\ESPAsyncE131.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PingRespPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubAckPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubCompPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PublishPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRecPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\PubRelPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\SubAckPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\time\Time.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\timezone\Timezone.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\dependencies\async-mqtt-client\AsyncMqttClient\Packets\UnsubAckPacket.cpp">
|
|
||||||
<Filter>Source Files\Dependencies</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="alexa.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="blynk.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="button.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="colors.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="cronixie.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="file.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="hue.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="ir.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="json.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="led.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="mqtt.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="notify.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="ntp.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="overlay.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="set.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="usermod.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="wled.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="wled_eeprom.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="wled_server.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="xml.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup />
|
|
||||||
</Project>
|
|
@ -9,6 +9,9 @@
|
|||||||
#ifdef WLED_ENABLE_PIXART
|
#ifdef WLED_ENABLE_PIXART
|
||||||
#include "html_pixart.h"
|
#include "html_pixart.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef WLED_DISABLE_PXMAGIC
|
||||||
|
#include "html_pxmagic.h"
|
||||||
|
#endif
|
||||||
#include "html_cpal.h"
|
#include "html_cpal.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -113,14 +116,6 @@ void initServer()
|
|||||||
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*");
|
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*");
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
#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
|
#ifndef WLED_DISABLE_2D
|
||||||
server.on("/liveview2D", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/liveview2D", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||||
@ -128,19 +123,16 @@ void initServer()
|
|||||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||||
setStaticContentCacheHeaders(response);
|
setStaticContentCacheHeaders(response);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
//request->send_P(200, "text/html", PAGE_liveviewws);
|
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
#else
|
#endif
|
||||||
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveview, PAGE_liveview_length);
|
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveview, PAGE_liveview_length);
|
||||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||||
setStaticContentCacheHeaders(response);
|
setStaticContentCacheHeaders(response);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
//request->send_P(200, "text/html", PAGE_liveview);
|
|
||||||
});
|
});
|
||||||
#endif
|
|
||||||
|
|
||||||
//settings page
|
//settings page
|
||||||
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
@ -164,10 +156,6 @@ void initServer()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/sliders", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
serveIndex(request);
|
|
||||||
});
|
|
||||||
|
|
||||||
server.on("/welcome", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/welcome", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
serveSettings(request);
|
serveSettings(request);
|
||||||
});
|
});
|
||||||
@ -195,9 +183,11 @@ void initServer()
|
|||||||
JsonObject root = doc.as<JsonObject>();
|
JsonObject root = doc.as<JsonObject>();
|
||||||
if (error || root.isNull()) {
|
if (error || root.isNull()) {
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
request->send(400, "application/json", F("{\"error\":9}"));
|
request->send(400, "application/json", F("{\"error\":9}")); // ERR_JSON
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as<const char*>());
|
||||||
|
|
||||||
const String& url = request->url();
|
const String& url = request->url();
|
||||||
isConfig = url.indexOf("cfg") > -1;
|
isConfig = url.indexOf("cfg") > -1;
|
||||||
if (!isConfig) {
|
if (!isConfig) {
|
||||||
@ -210,6 +200,11 @@ void initServer()
|
|||||||
*/
|
*/
|
||||||
verboseResponse = deserializeState(root);
|
verboseResponse = deserializeState(root);
|
||||||
} else {
|
} 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
|
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
||||||
}
|
}
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
@ -237,19 +232,15 @@ void initServer()
|
|||||||
request->send(200, "text/plain", (String)ESP.getFreeHeap());
|
request->send(200, "text/plain", (String)ESP.getFreeHeap());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_USERMOD_PAGE
|
||||||
server.on("/u", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/u", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_usermod, PAGE_usermod_length);
|
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_usermod, PAGE_usermod_length);
|
||||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||||
setStaticContentCacheHeaders(response);
|
setStaticContentCacheHeaders(response);
|
||||||
request->send(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){
|
server.on("/teapot", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
serveMessage(request, 418, F("418. I'm a teapot."), F("(Tangible Embedded Advanced Project Of Twinkling)"), 254);
|
serveMessage(request, 418, F("418. I'm a teapot."), F("(Tangible Embedded Advanced Project Of Twinkling)"), 254);
|
||||||
@ -346,9 +337,14 @@ void initServer()
|
|||||||
serveMessage(request, 501, "Not implemented", F("DMX support is not enabled in this build."), 254);
|
serveMessage(request, 501, "Not implemented", F("DMX support is not enabled in this build."), 254);
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
if (captivePortal(request)) return;
|
if (captivePortal(request)) return;
|
||||||
serveIndexOrWelcome(request);
|
if (!showWelcomePage || request->hasArg(F("sliders"))){
|
||||||
|
serveIndex(request);
|
||||||
|
} else {
|
||||||
|
serveSettings(request);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_PIXART
|
#ifdef WLED_ENABLE_PIXART
|
||||||
@ -362,6 +358,17 @@ void initServer()
|
|||||||
});
|
});
|
||||||
#endif
|
#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){
|
server.on("/cpal.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
if (handleFileRead(request, "/cpal.htm")) return;
|
if (handleFileRead(request, "/cpal.htm")) return;
|
||||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||||
@ -399,20 +406,9 @@ void initServer()
|
|||||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||||
setStaticContentCacheHeaders(response);
|
setStaticContentCacheHeaders(response);
|
||||||
request->send(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)
|
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
|
||||||
{
|
{
|
||||||
AsyncWebHeader* header = request->getHeader("If-None-Match");
|
AsyncWebHeader* header = request->getHeader("If-None-Match");
|
||||||
@ -554,64 +550,62 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
|||||||
|
|
||||||
if (url.indexOf("sett") >= 0)
|
if (url.indexOf("sett") >= 0)
|
||||||
{
|
{
|
||||||
if (url.indexOf(".js") > 0) subPage = 254;
|
if (url.indexOf(".js") > 0) subPage = SUBPAGE_JS;
|
||||||
else if (url.indexOf(".css") > 0) subPage = 253;
|
else if (url.indexOf(".css") > 0) subPage = SUBPAGE_CSS;
|
||||||
else if (url.indexOf("wifi") > 0) subPage = 1;
|
else if (url.indexOf("wifi") > 0) subPage = SUBPAGE_WIFI;
|
||||||
else if (url.indexOf("leds") > 0) subPage = 2;
|
else if (url.indexOf("leds") > 0) subPage = SUBPAGE_LEDS;
|
||||||
else if (url.indexOf("ui") > 0) subPage = 3;
|
else if (url.indexOf("ui") > 0) subPage = SUBPAGE_UI;
|
||||||
else if (url.indexOf("sync") > 0) subPage = 4;
|
else if (url.indexOf("sync") > 0) subPage = SUBPAGE_SYNC;
|
||||||
else if (url.indexOf("time") > 0) subPage = 5;
|
else if (url.indexOf("time") > 0) subPage = SUBPAGE_TIME;
|
||||||
else if (url.indexOf("sec") > 0) subPage = 6;
|
else if (url.indexOf("sec") > 0) subPage = SUBPAGE_SEC;
|
||||||
else if (url.indexOf("dmx") > 0) subPage = 7;
|
else if (url.indexOf("dmx") > 0) subPage = SUBPAGE_DMX;
|
||||||
else if (url.indexOf("um") > 0) subPage = 8;
|
else if (url.indexOf("um") > 0) subPage = SUBPAGE_UM;
|
||||||
else if (url.indexOf("2D") > 0) subPage = 10;
|
else if (url.indexOf("2D") > 0) subPage = SUBPAGE_2D;
|
||||||
else if (url.indexOf("lock") > 0) subPage = 251;
|
else if (url.indexOf("lock") > 0) subPage = SUBPAGE_LOCK;
|
||||||
}
|
}
|
||||||
else if (url.indexOf("/update") >= 0) subPage = 9; // update page, for PIN check
|
else if (url.indexOf("/update") >= 0) subPage = SUBPAGE_UPDATE; // update page, for PIN check
|
||||||
//else if (url.indexOf("/edit") >= 0) subPage = 10;
|
//else if (url.indexOf("/edit") >= 0) subPage = 10;
|
||||||
else subPage = 255; // welcome page
|
else subPage = SUBPAGE_WELCOME;
|
||||||
|
|
||||||
if (!correctPIN && strlen(settingsPIN) > 0 && (subPage > 0 && subPage < 11)) {
|
if (!correctPIN && strlen(settingsPIN) > 0 && (subPage > 0 && subPage < 11)) {
|
||||||
originalSubPage = subPage;
|
originalSubPage = subPage;
|
||||||
subPage = 252; // require PIN
|
subPage = SUBPAGE_PINREQ; // require PIN
|
||||||
}
|
}
|
||||||
|
|
||||||
// if OTA locked or too frequent PIN entry requests fail hard
|
// if OTA locked or too frequent PIN entry requests fail hard
|
||||||
if ((subPage == 1 && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < 3000))
|
if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < PIN_RETRY_COOLDOWN))
|
||||||
{
|
{
|
||||||
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_ota), 254); return;
|
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_ota), 254); return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post) { //settings/set POST request, saving
|
if (post) { //settings/set POST request, saving
|
||||||
if (subPage != 1 || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
|
if (subPage != SUBPAGE_WIFI || !(wifiLock && otaLock)) handleSettingsSet(request, subPage);
|
||||||
|
|
||||||
char s[32];
|
char s[32];
|
||||||
char s2[45] = "";
|
char s2[45] = "";
|
||||||
|
|
||||||
switch (subPage) {
|
switch (subPage) {
|
||||||
case 1: strcpy_P(s, PSTR("WiFi")); strcpy_P(s2, PSTR("Please connect to the new IP (if changed)")); forceReconnect = true; break;
|
case SUBPAGE_WIFI : 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 SUBPAGE_LEDS : strcpy_P(s, PSTR("LED")); break;
|
||||||
case 3: strcpy_P(s, PSTR("UI")); break;
|
case SUBPAGE_UI : strcpy_P(s, PSTR("UI")); break;
|
||||||
case 4: strcpy_P(s, PSTR("Sync")); break;
|
case SUBPAGE_SYNC : strcpy_P(s, PSTR("Sync")); break;
|
||||||
case 5: strcpy_P(s, PSTR("Time")); break;
|
case SUBPAGE_TIME : 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 SUBPAGE_SEC : 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 SUBPAGE_DMX : strcpy_P(s, PSTR("DMX")); break;
|
||||||
case 8: strcpy_P(s, PSTR("Usermods")); break;
|
case SUBPAGE_UM : strcpy_P(s, PSTR("Usermods")); break;
|
||||||
case 10: strcpy_P(s, PSTR("2D")); break;
|
case SUBPAGE_2D : strcpy_P(s, PSTR("2D")); break;
|
||||||
case 252: strcpy_P(s, correctPIN ? PSTR("PIN accepted") : PSTR("PIN rejected")); break;
|
case SUBPAGE_PINREQ : strcpy_P(s, correctPIN ? PSTR("PIN accepted") : PSTR("PIN rejected")); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 252) {
|
if (subPage != SUBPAGE_PINREQ) strcat_P(s, PSTR(" settings saved."));
|
||||||
createEditHandler(correctPIN);
|
|
||||||
} else
|
|
||||||
strcat_P(s, PSTR(" settings saved."));
|
|
||||||
|
|
||||||
if (subPage == 252 && correctPIN) {
|
if (subPage == SUBPAGE_PINREQ && correctPIN) {
|
||||||
subPage = originalSubPage; // on correct PIN load settings page the user intended
|
subPage = originalSubPage; // on correct PIN load settings page the user intended
|
||||||
} else {
|
} else {
|
||||||
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
||||||
|
|
||||||
serveMessage(request, 200, s, s2, (subPage == 1 || (subPage == 6 && doReboot)) ? 129 : (correctPIN ? 1 : 3));
|
bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot));
|
||||||
|
serveMessage(request, 200, s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,30 +613,30 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
|||||||
AsyncWebServerResponse *response;
|
AsyncWebServerResponse *response;
|
||||||
switch (subPage)
|
switch (subPage)
|
||||||
{
|
{
|
||||||
case 1: response = request->beginResponse_P(200, "text/html", PAGE_settings_wifi, PAGE_settings_wifi_length); break;
|
case SUBPAGE_WIFI : 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 SUBPAGE_LEDS : 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 SUBPAGE_UI : 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 SUBPAGE_SYNC : 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 SUBPAGE_TIME : response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break;
|
||||||
case 6: response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
|
case SUBPAGE_SEC : response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
case 7: response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
|
case SUBPAGE_DMX : response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
|
||||||
#endif
|
#endif
|
||||||
case 8: response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
|
case SUBPAGE_UM : response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
|
||||||
case 9: response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
|
case SUBPAGE_UPDATE : response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
case 10: response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
|
case SUBPAGE_2D : response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
|
||||||
#endif
|
#endif
|
||||||
case 251: {
|
case SUBPAGE_LOCK : {
|
||||||
correctPIN = !strlen(settingsPIN); // lock if a pin is set
|
correctPIN = !strlen(settingsPIN); // lock if a pin is set
|
||||||
createEditHandler(correctPIN);
|
createEditHandler(correctPIN);
|
||||||
serveMessage(request, 200, strlen(settingsPIN) > 0 ? PSTR("Settings locked") : PSTR("No PIN set"), FPSTR(s_redirecting), 1);
|
serveMessage(request, 200, strlen(settingsPIN) > 0 ? PSTR("Settings locked") : PSTR("No PIN set"), FPSTR(s_redirecting), 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 252: response = request->beginResponse_P(200, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
|
case SUBPAGE_PINREQ : 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 SUBPAGE_CSS : response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length); break;
|
||||||
case 254: serveSettingsJS(request); return;
|
case SUBPAGE_JS : serveSettingsJS(request); return;
|
||||||
case 255: response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
|
case SUBPAGE_WELCOME : response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
|
||||||
default: response = request->beginResponse_P(200, "text/html", PAGE_settings, PAGE_settings_length); break;
|
default: response = request->beginResponse_P(200, "text/html", PAGE_settings, PAGE_settings_length); break;
|
||||||
}
|
}
|
||||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||||
|
@ -54,14 +54,15 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
}
|
}
|
||||||
releaseJSONBufferLock(); // will clean fileDoc
|
releaseJSONBufferLock(); // will clean fileDoc
|
||||||
|
|
||||||
// force broadcast in 500ms after updating client
|
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
|
||||||
if (verboseResponse) {
|
if (verboseResponse) {
|
||||||
sendDataWs(client);
|
sendDataWs(client);
|
||||||
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
|
|
||||||
} else {
|
} else {
|
||||||
// we have to send something back otherwise WS connection closes
|
// we have to send something back otherwise WS connection closes
|
||||||
client->text(F("{\"success\":true}"));
|
client->text(F("{\"success\":true}"));
|
||||||
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
|
}
|
||||||
|
// force broadcast in 500ms after updating client
|
||||||
|
//lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500); // ESP8266 does not like this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -78,7 +79,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
if((info->index + len) == info->len){
|
if((info->index + len) == info->len){
|
||||||
if(info->final){
|
if(info->final){
|
||||||
if(info->message_opcode == WS_TEXT) {
|
if(info->message_opcode == WS_TEXT) {
|
||||||
client->text(F("{\"error\":9}")); //we do not handle split packets right now
|
client->text(F("{\"error\":9}")); // ERR_JSON we do not handle split packets right now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,55 +72,6 @@ void XML_response(AsyncWebServerRequest *request, char* dest)
|
|||||||
if (request != nullptr) request->send(200, "text/xml", obuf);
|
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) {
|
void extractPin(JsonObject &obj, const char *key) {
|
||||||
if (obj[key].is<JsonArray>()) {
|
if (obj[key].is<JsonArray>()) {
|
||||||
JsonArray pins = obj[key].as<JsonArray>();
|
JsonArray pins = obj[key].as<JsonArray>();
|
||||||
@ -197,7 +148,7 @@ void appendGPIOinfo() {
|
|||||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17"));
|
oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17"));
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31"));
|
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31,37,38"));
|
||||||
#else
|
#else
|
||||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11"));
|
oappend(SET_F("d.rsvd=[6,7,8,9,10,11"));
|
||||||
#endif
|
#endif
|
||||||
@ -212,7 +163,7 @@ void appendGPIOinfo() {
|
|||||||
|
|
||||||
//Note: Using pin 3 (RX) disables Adalight / Serial JSON
|
//Note: Using pin 3 (RX) disables Adalight / Serial JSON
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM on ESP32 (not on S2, S3 or C3)
|
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM on ESP32 (not on S2, S3 or C3)
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
@ -285,7 +236,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
|
|
||||||
if (subPage <0 || subPage >10) return;
|
if (subPage <0 || subPage >10) return;
|
||||||
|
|
||||||
if (subPage == 0)
|
if (subPage == SUBPAGE_MENU)
|
||||||
{
|
{
|
||||||
#ifndef WLED_DISABLE_2D // include only if 2D is compiled in
|
#ifndef WLED_DISABLE_2D // include only if 2D is compiled in
|
||||||
oappend(PSTR("gId('2dbtn').style.display='';"));
|
oappend(PSTR("gId('2dbtn').style.display='';"));
|
||||||
@ -295,7 +246,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 1)
|
if (subPage == SUBPAGE_WIFI)
|
||||||
{
|
{
|
||||||
sappends('s',SET_F("CS"),clientSSID);
|
sappends('s',SET_F("CS"),clientSSID);
|
||||||
|
|
||||||
@ -328,6 +279,14 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
sappend('v',SET_F("AC"),apChannel);
|
sappend('v',SET_F("AC"),apChannel);
|
||||||
sappend('c',SET_F("WS"),noWifiSleep);
|
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
|
#ifdef WLED_USE_ETHERNET
|
||||||
sappend('v',SET_F("ETH"),ethernetType);
|
sappend('v',SET_F("ETH"),ethernetType);
|
||||||
#else
|
#else
|
||||||
@ -360,9 +319,22 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
{
|
{
|
||||||
sappends('m',SET_F("(\"sip\")[1]"),(char*)F("Not active"));
|
sappends('m',SET_F("(\"sip\")[1]"),(char*)F("Not active"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_ESPNOW
|
||||||
|
if (last_signal_src[0] != 0) //Have seen an ESP-NOW Remote
|
||||||
|
{
|
||||||
|
sappends('m',SET_F("(\"rlid\")[0]"),last_signal_src);
|
||||||
|
} else if (!enable_espnow_remote)
|
||||||
|
{
|
||||||
|
sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("(Enable remote to listen)"));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("None"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 2)
|
if (subPage == SUBPAGE_LEDS)
|
||||||
{
|
{
|
||||||
char nS[32];
|
char nS[32];
|
||||||
|
|
||||||
@ -493,7 +465,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
sappend('c',SET_F("MSO"),!irApplyToAllSelected);
|
sappend('c',SET_F("MSO"),!irApplyToAllSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 3)
|
if (subPage == SUBPAGE_UI)
|
||||||
{
|
{
|
||||||
sappends('s',SET_F("DS"),serverDescription);
|
sappends('s',SET_F("DS"),serverDescription);
|
||||||
sappend('c',SET_F("ST"),syncToggleReceive);
|
sappend('c',SET_F("ST"),syncToggleReceive);
|
||||||
@ -504,7 +476,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 4)
|
if (subPage == SUBPAGE_SYNC)
|
||||||
{
|
{
|
||||||
sappend('v',SET_F("UP"),udpPort);
|
sappend('v',SET_F("UP"),udpPort);
|
||||||
sappend('v',SET_F("U2"),udpPort2);
|
sappend('v',SET_F("U2"),udpPort2);
|
||||||
@ -561,6 +533,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
sappends('s',"MD",mqttDeviceTopic);
|
sappends('s',"MD",mqttDeviceTopic);
|
||||||
sappends('s',SET_F("MG"),mqttGroupTopic);
|
sappends('s',SET_F("MG"),mqttGroupTopic);
|
||||||
sappend('c',SET_F("BM"),buttonPublishMqtt);
|
sappend('c',SET_F("BM"),buttonPublishMqtt);
|
||||||
|
sappend('c',SET_F("RT"),retainMqttMsg);
|
||||||
#else
|
#else
|
||||||
oappend(SET_F("toggle('MQTT');")); // hide MQTT settings
|
oappend(SET_F("toggle('MQTT');")); // hide MQTT settings
|
||||||
#endif
|
#endif
|
||||||
@ -596,7 +569,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
sappend('v',SET_F("BD"),serialBaud);
|
sappend('v',SET_F("BD"),serialBaud);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 5)
|
if (subPage == SUBPAGE_TIME)
|
||||||
{
|
{
|
||||||
sappend('c',SET_F("NT"),ntpEnabled);
|
sappend('c',SET_F("NT"),ntpEnabled);
|
||||||
sappends('s',SET_F("NS"),ntpServerName);
|
sappends('s',SET_F("NS"),ntpServerName);
|
||||||
@ -660,7 +633,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 6)
|
if (subPage == SUBPAGE_SEC)
|
||||||
{
|
{
|
||||||
byte l = strlen(settingsPIN);
|
byte l = strlen(settingsPIN);
|
||||||
char fpass[l+1]; //fill PIN field with 0000
|
char fpass[l+1]; //fill PIN field with 0000
|
||||||
@ -682,7 +655,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||||
if (subPage == 7)
|
if (subPage == SUBPAGE_DMX)
|
||||||
{
|
{
|
||||||
sappend('v',SET_F("PU"),e131ProxyUniverse);
|
sappend('v',SET_F("PU"),e131ProxyUniverse);
|
||||||
|
|
||||||
@ -709,7 +682,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (subPage == 8) //usermods
|
if (subPage == SUBPAGE_UM) //usermods
|
||||||
{
|
{
|
||||||
appendGPIOinfo();
|
appendGPIOinfo();
|
||||||
oappend(SET_F("numM="));
|
oappend(SET_F("numM="));
|
||||||
@ -728,7 +701,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
usermods.appendConfigData();
|
usermods.appendConfigData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 9) // update
|
if (subPage == SUBPAGE_UPDATE) // update
|
||||||
{
|
{
|
||||||
sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED "));
|
sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED "));
|
||||||
olen -= 2; //delete ";
|
olen -= 2; //delete ";
|
||||||
@ -744,7 +717,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
oappend(SET_F(")\";"));
|
oappend(SET_F(")\";"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 10) // 2D matrices
|
if (subPage == SUBPAGE_2D) // 2D matrices
|
||||||
{
|
{
|
||||||
sappend('v',SET_F("SOMP"),strip.isMatrix);
|
sappend('v',SET_F("SOMP"),strip.isMatrix);
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
|
Loading…
Reference in New Issue
Block a user