Merge branch 'master' into master
This commit is contained in:
commit
afaa001738
@ -2,6 +2,13 @@
|
||||
|
||||
### Builds after release 0.12.0
|
||||
|
||||
#### Build 2201260
|
||||
|
||||
- Initial ESP32-C3 and ESP32-S2 support (PRs #2452, )
|
||||
- Full segment sync (PR #2427)
|
||||
- Allow overriding of color order by ranges (PR #2463)
|
||||
- Added white channel to Peek
|
||||
|
||||
#### Build 2112080
|
||||
|
||||
- Version bump to 0.13.0-b6 "Toki"
|
||||
|
@ -12,7 +12,7 @@
|
||||
; default_envs = travis_esp8266, travis_esp32
|
||||
|
||||
# Release binaries
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32s2_saola, esp32c3
|
||||
|
||||
# Build everything
|
||||
; default_envs = esp32dev, esp8285_4CH_MagicHome, esp8285_4CH_H801, codm-controller-0.6-rev2, codm-controller-0.6, esp32s2_saola, d1_mini_5CH_Shojo_PCB, d1_mini, sp501e, travis_esp8266, travis_esp32, nodemcuv2, esp32_eth, anavi_miracle_controller, esp07, esp01_1m_full, m5atom, h803wf, d1_mini_ota, heltec_wifi_kit_8, esp8285_5CH_H801, d1_mini_debug, wemos_shield_esp32, elekstube_ips
|
||||
@ -54,13 +54,14 @@ extra_configs =
|
||||
arduino_core_2_6_3 = espressif8266@2.3.3
|
||||
arduino_core_2_7_4 = espressif8266@2.6.2
|
||||
arduino_core_3_0_0 = espressif8266@3.0.0
|
||||
arduino_core_3_0_2 = espressif8266@3.2.0
|
||||
|
||||
# Development platforms
|
||||
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
|
||||
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
|
||||
|
||||
# Platform to use for ESP8266
|
||||
platform_wled_default = ${common.arduino_core_2_7_4}
|
||||
platform_wled_default = ${common.arduino_core_3_0_2}
|
||||
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
|
||||
platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||
platformio/toolchain-xtensa @ ~2.40802.200502
|
||||
@ -105,6 +106,7 @@ build_flags =
|
||||
-DBEARSSL_SSL_BASIC
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
-D NDEBUG
|
||||
-Dregister=
|
||||
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
|
||||
-D _IR_ENABLE_DEFAULT_=false
|
||||
-D DECODE_HASH=true
|
||||
@ -160,10 +162,9 @@ upload_speed = 115200
|
||||
# ------------------------------------------------------------------------------
|
||||
lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.4.0
|
||||
IRremoteESP8266 @ 2.7.18
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.2
|
||||
fastled/FastLED @ 3.5.0
|
||||
IRremoteESP8266 @ 2.8.1
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.4
|
||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||
#TFT_eSPI
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
@ -185,6 +186,7 @@ build_flags =
|
||||
-DFP_IN_IROM
|
||||
;-Wno-deprecated-declarations
|
||||
;-Wno-register
|
||||
-Wno-misleading-indentation
|
||||
; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
|
||||
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
|
||||
; lwIP 2 - Higher Bandwidth no Features
|
||||
@ -198,6 +200,7 @@ build_flags =
|
||||
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
# ESPAsyncTCP @ 1.2.0
|
||||
ESPAsyncUDP
|
||||
makuna/NeoPixelBus @ 2.6.7 # 2.6.5/2.6.6 and newer do not compile on ESP core < 3.0.0
|
||||
@ -212,13 +215,13 @@ default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
makuna/NeoPixelBus @ 2.6.7
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
|
||||
[esp32s2]
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
-DARDUINO_ARCH_ESP32S2
|
||||
-DCONFIG_IDF_TARGET_ESP32S2
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
@ -229,6 +232,19 @@ lib_deps =
|
||||
makuna/NeoPixelBus @ 2.6.7
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
|
||||
[esp32c3]
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32C3
|
||||
-DCONFIG_IDF_TARGET_ESP32C3
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-DCO
|
||||
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
makuna/NeoPixelBus @ 2.6.7
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# WLED BUILDS
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -314,17 +330,25 @@ lib_deps = ${esp32.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32s2_saola]
|
||||
board = esp32dev
|
||||
board_build.mcu = esp32s2
|
||||
platform = espressif32
|
||||
board = esp32-s2-saola-1
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.1/platform-tasmota-espressif32-2.0.2.1.zip
|
||||
platform_packages =
|
||||
framework = arduino
|
||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
board_build.flash_mode = qio
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
lib_deps = ${esp32s2.lib_deps}
|
||||
|
||||
[env:esp32c3]
|
||||
board = esp32-c3-devkitm-1
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.1/platform-tasmota-espressif32-2.0.2.1.zip
|
||||
platform_packages =
|
||||
toolchain-xtensa32s2
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.0-alpha1
|
||||
framework = arduino
|
||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
lib_deps = ${esp32s2.lib_deps}
|
||||
lib_deps = ${esp32c3.lib_deps}
|
||||
|
||||
[env:esp8285_4CH_MagicHome]
|
||||
board = esp8285
|
||||
|
@ -217,7 +217,7 @@ writeChunks(
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace("%", "%%")
|
||||
.replace(/User Interface\<\/button\>\<\/form\>/gms, "User Interface\<\/button\>\<\/form\>%DMXMENU%"),
|
||||
.replace(/Usermods\<\/button\>\<\/form\>/gms, "Usermods\<\/button\>\<\/form\>%DMXMENU%"),
|
||||
},
|
||||
{
|
||||
file: "settings_wifi.htm",
|
||||
|
@ -111,17 +111,17 @@ class Animated_Staircase : public Usermod {
|
||||
}
|
||||
|
||||
if (i >= onIndex && i < offIndex) {
|
||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||
segments->setOption(SEG_OPTION_ON, 1, i);
|
||||
|
||||
// We may need to copy mode and colors from segment 0 to make sure
|
||||
// changes are propagated even when the config is changed during a wipe
|
||||
// segments->mode = mainsegment.mode;
|
||||
// segments->colors[0] = mainsegment.colors[0];
|
||||
} else {
|
||||
segments->setOption(SEG_OPTION_ON, 0, 1);
|
||||
segments->setOption(SEG_OPTION_ON, 0, i);
|
||||
}
|
||||
// Always mark segments as "transitional", we are animating the staircase
|
||||
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1);
|
||||
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, i);
|
||||
}
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
@ -296,7 +296,7 @@ class Animated_Staircase : public Usermod {
|
||||
maxSegmentId = i - 1;
|
||||
break;
|
||||
}
|
||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||
segments->setOption(SEG_OPTION_ON, 1, i);
|
||||
}
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
DEBUG_PRINTLN(F("Animated Staircase disabled."));
|
||||
|
@ -1,19 +0,0 @@
|
||||
# ESP32 Touch Brightness Control
|
||||
|
||||
Toggle On/Off with a long press (800ms)
|
||||
Switch through 5 brightness levels (defined in usermod_touchbrightness.h, values 0-255) with a short (100ms) touch
|
||||
|
||||
## Installation
|
||||
|
||||
Copy 'usermod_touchbrightness.h' to the wled00 directory.
|
||||
in 'usermod_list.cpp' add this:
|
||||
|
||||
> #include "usermod_touchbrightness.h"
|
||||
above "void registerUsermods()"
|
||||
|
||||
and
|
||||
|
||||
> usermods.add(new TouchBrightnessControl());
|
||||
inside the "registerUsermods()" function
|
||||
|
||||
|
@ -1,89 +0,0 @@
|
||||
//
|
||||
// usermod_touchbrightness.h
|
||||
// github.com/aircoookie/WLED
|
||||
//
|
||||
// Created by Justin Kühner on 14.09.2020.
|
||||
// Copyright © 2020 NeariX. All rights reserved.
|
||||
// https://github.com/NeariX67/
|
||||
// Discord: @NeariX#4799
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#define threshold 40 //Increase value if touches falsely accur. Decrease value if actual touches are not recognized
|
||||
#define touchPin T0 //T0 = D4 / GPIO4
|
||||
|
||||
//Define the 5 brightness levels
|
||||
//Long press to turn off / on
|
||||
#define brightness1 51
|
||||
#define brightness2 102
|
||||
#define brightness3 153
|
||||
#define brightness4 204
|
||||
#define brightness5 255
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
|
||||
class TouchBrightnessControl : public Usermod {
|
||||
private:
|
||||
unsigned long lastTime = 0; //Interval
|
||||
unsigned long lastTouch = 0; //Timestamp of last Touch
|
||||
unsigned long lastRelease = 0; //Timestamp of last Touch release
|
||||
boolean released = true; //current Touch state (touched/released)
|
||||
uint16_t touchReading = 0; //sensor reading, maybe use uint8_t???
|
||||
uint16_t touchDuration = 0; //duration of last touch
|
||||
public:
|
||||
|
||||
void setup() {
|
||||
lastTouch = millis();
|
||||
lastRelease = millis();
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (millis() - lastTime >= 50) { //Check every 50ms if a touch occurs
|
||||
lastTime = millis();
|
||||
touchReading = touchRead(touchPin); //Read touch sensor on pin T0 (GPIO4 / D4)
|
||||
|
||||
if(touchReading < threshold && released) { //Touch started
|
||||
released = false;
|
||||
lastTouch = millis();
|
||||
}
|
||||
else if(touchReading >= threshold && !released) { //Touch released
|
||||
released = true;
|
||||
lastRelease = millis();
|
||||
touchDuration = lastRelease - lastTouch; //Calculate duration
|
||||
}
|
||||
|
||||
//Serial.println(touchDuration);
|
||||
|
||||
if(touchDuration >= 800 && released) { //Toggle power if button press is longer than 800ms
|
||||
touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch
|
||||
toggleOnOff();
|
||||
colorUpdated(2); //Refresh values
|
||||
}
|
||||
else if(touchDuration >= 100 && released) { //Switch to next brightness if touch is between 100 and 800ms
|
||||
touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch
|
||||
if(bri < brightness1) {
|
||||
bri = brightness1;
|
||||
} else if(bri >= brightness1 && bri < brightness2) {
|
||||
bri = brightness2;
|
||||
} else if(bri >= brightness2 && bri < brightness3) {
|
||||
bri = brightness3;
|
||||
} else if(bri >= brightness3 && bri < brightness4) {
|
||||
bri = brightness4;
|
||||
} else if(bri >= brightness4 && bri < brightness5) {
|
||||
bri = brightness5;
|
||||
} else if(bri >= brightness5) {
|
||||
bri = brightness1;
|
||||
}
|
||||
colorUpdated(2); //Refresh values
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
@ -1,9 +0,0 @@
|
||||
# PIR sensor with MQTT
|
||||
|
||||
This simple usermod allows attaching a PIR sensor like the AM312 and publish the readings over MQTT. A message is sent when motion is detected as well as when motion has stopped.
|
||||
|
||||
This usermod has only been tested with the AM312 sensor though should work for any other PIR sensor. Note that this does not control the LED strip directly, it only publishes MQTT readings for use with other integrations like Home Assistant.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and replace the file `usermod.cpp` in wled00 directory.
|
@ -1,55 +0,0 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* This v1 usermod file allows you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
||||
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
|
||||
*
|
||||
* Consider the v2 usermod API if you need a more advanced feature set!
|
||||
*/
|
||||
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
// PIR sensor pin
|
||||
const int MOTION_PIN = 16;
|
||||
// MQTT topic for sensor values
|
||||
const char MQTT_TOPIC[] = "/motion";
|
||||
|
||||
int prevState = LOW;
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup()
|
||||
{
|
||||
pinMode(MOTION_PIN, INPUT);
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void publishMqtt(String state)
|
||||
{
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr){
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, MQTT_TOPIC);
|
||||
mqtt->publish(subuf, 0, true, state.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop()
|
||||
{
|
||||
if (digitalRead(MOTION_PIN) == HIGH && prevState == LOW) { // Motion detected
|
||||
publishMqtt("ON");
|
||||
prevState = HIGH;
|
||||
}
|
||||
if (digitalRead(MOTION_PIN) == LOW && prevState == HIGH) { // Motion stopped
|
||||
publishMqtt("OFF");
|
||||
prevState = LOW;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ This usermod allow to use 240x240 display to display following:
|
||||
## Hardware
|
||||
|
||||
***
|
||||
![Hardware](images/ST7789_guide.jpg)
|
||||
![Hardware](images/ST7789_Guide.jpg)
|
||||
|
||||
## Library used
|
||||
|
||||
|
@ -1,515 +0,0 @@
|
||||
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
|
||||
#ifndef NpbWrapper_h
|
||||
#define NpbWrapper_h
|
||||
|
||||
// make sure we're using esp32 platform
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
#error This version of NbpWrapper.h only works with ESP32 hardware.
|
||||
#endif
|
||||
|
||||
#ifndef NUM_STRIPS
|
||||
#error Need to define number of LED strips using build flag -D NUM_STRIPS=4 for 4 LED strips
|
||||
#endif
|
||||
|
||||
#ifndef PIXEL_COUNTS
|
||||
#error Need to define pixel counts using build flag -D PIXEL_COUNTS="25, 25, 25, 25" for 4 LED strips with 25 LEDs each
|
||||
#endif
|
||||
|
||||
#ifndef DATA_PINS
|
||||
#error Need to define data pins using build flag -D DATA_PINS="1, 2, 3, 4" if LED strips are on data pins 1, 2, 3, and 4
|
||||
#endif
|
||||
|
||||
// //PIN CONFIGURATION
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 1 // Legacy pin def required by some other portions of code. This pin is not used do drive LEDs.
|
||||
#endif
|
||||
|
||||
#ifndef IRPIN
|
||||
#define IRPIN -1 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
||||
#endif
|
||||
|
||||
#ifndef RLYPIN
|
||||
#define RLYPIN -1 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
|
||||
#endif
|
||||
|
||||
#ifndef AUXPIN
|
||||
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
|
||||
#endif
|
||||
|
||||
#ifndef RLYMDE
|
||||
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
|
||||
#endif
|
||||
|
||||
#include <NeoPixelBrightnessBus.h>
|
||||
#include "const.h"
|
||||
|
||||
const uint8_t numStrips = NUM_STRIPS; // max 8 strips allowed on esp32
|
||||
const uint16_t pixelCounts[numStrips] = {PIXEL_COUNTS}; // number of pixels on each strip
|
||||
const uint8_t dataPins[numStrips] = {DATA_PINS}; // change these pins based on your board
|
||||
|
||||
#define PIXELFEATURE3 NeoGrbFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
|
||||
// ESP32 has 8 RMT interfaces available, each of which can drive a strip of pixels
|
||||
// Convenience #defines for creating NeoPixelBrightnessBus on each RMT interface for both GRB and GRBW LED strips
|
||||
#define NeoPixelBrightnessBusGrbRmt0 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt1 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt2 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt3 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt4 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt5 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt6 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt7 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt7Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt0 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt1 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt2 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt3 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt4 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt5 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt6 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt7 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt7Ws2812xMethod>
|
||||
|
||||
enum NeoPixelType
|
||||
{
|
||||
NeoPixelType_None = 0,
|
||||
NeoPixelType_Grb = 1,
|
||||
NeoPixelType_Grbw = 2,
|
||||
NeoPixelType_End = 3
|
||||
};
|
||||
|
||||
class NeoPixelWrapper
|
||||
{
|
||||
public:
|
||||
NeoPixelWrapper() :
|
||||
_type(NeoPixelType_None)
|
||||
{
|
||||
// On initialization fill in the pixelStripStartIdx array with the beginning index of each strip
|
||||
// relative to th entire array.
|
||||
uint16_t totalPixels = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
pixelStripStartIdx[idx] = totalPixels;
|
||||
totalPixels += pixelCounts[idx];
|
||||
}
|
||||
}
|
||||
|
||||
~NeoPixelWrapper()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Begin(NeoPixelType type, uint16_t pixelCount)
|
||||
{
|
||||
|
||||
cleanup();
|
||||
|
||||
_type = type;
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0 = new NeoPixelBrightnessBusGrbRmt0(pixelCounts[idx], dataPins[idx]); pGrb0->Begin(); break;
|
||||
case 1: pGrb1 = new NeoPixelBrightnessBusGrbRmt1(pixelCounts[idx], dataPins[idx]); pGrb1->Begin(); break;
|
||||
case 2: pGrb2 = new NeoPixelBrightnessBusGrbRmt2(pixelCounts[idx], dataPins[idx]); pGrb2->Begin(); break;
|
||||
case 3: pGrb3 = new NeoPixelBrightnessBusGrbRmt3(pixelCounts[idx], dataPins[idx]); pGrb3->Begin(); break;
|
||||
case 4: pGrb4 = new NeoPixelBrightnessBusGrbRmt4(pixelCounts[idx], dataPins[idx]); pGrb4->Begin(); break;
|
||||
case 5: pGrb5 = new NeoPixelBrightnessBusGrbRmt5(pixelCounts[idx], dataPins[idx]); pGrb5->Begin(); break;
|
||||
case 6: pGrb6 = new NeoPixelBrightnessBusGrbRmt6(pixelCounts[idx], dataPins[idx]); pGrb6->Begin(); break;
|
||||
case 7: pGrb7 = new NeoPixelBrightnessBusGrbRmt7(pixelCounts[idx], dataPins[idx]); pGrb7->Begin(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0 = new NeoPixelBrightnessBusGrbwRmt0(pixelCounts[idx], dataPins[idx]); pGrbw0->Begin(); break;
|
||||
case 1: pGrbw1 = new NeoPixelBrightnessBusGrbwRmt1(pixelCounts[idx], dataPins[idx]); pGrbw1->Begin(); break;
|
||||
case 2: pGrbw2 = new NeoPixelBrightnessBusGrbwRmt2(pixelCounts[idx], dataPins[idx]); pGrbw2->Begin(); break;
|
||||
case 3: pGrbw3 = new NeoPixelBrightnessBusGrbwRmt3(pixelCounts[idx], dataPins[idx]); pGrbw3->Begin(); break;
|
||||
case 4: pGrbw4 = new NeoPixelBrightnessBusGrbwRmt4(pixelCounts[idx], dataPins[idx]); pGrbw4->Begin(); break;
|
||||
case 5: pGrbw5 = new NeoPixelBrightnessBusGrbwRmt5(pixelCounts[idx], dataPins[idx]); pGrbw5->Begin(); break;
|
||||
case 6: pGrbw6 = new NeoPixelBrightnessBusGrbwRmt6(pixelCounts[idx], dataPins[idx]); pGrbw6->Begin(); break;
|
||||
case 7: pGrbw7 = new NeoPixelBrightnessBusGrbwRmt7(pixelCounts[idx], dataPins[idx]); pGrbw7->Begin(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Show()
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0->Show(); break;
|
||||
case 1: pGrb1->Show(); break;
|
||||
case 2: pGrb2->Show(); break;
|
||||
case 3: pGrb3->Show(); break;
|
||||
case 4: pGrb4->Show(); break;
|
||||
case 5: pGrb5->Show(); break;
|
||||
case 6: pGrb6->Show(); break;
|
||||
case 7: pGrb7->Show(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0->Show(); break;
|
||||
case 1: pGrbw1->Show(); break;
|
||||
case 2: pGrbw2->Show(); break;
|
||||
case 3: pGrbw3->Show(); break;
|
||||
case 4: pGrbw4->Show(); break;
|
||||
case 5: pGrbw5->Show(); break;
|
||||
case 6: pGrbw6->Show(); break;
|
||||
case 7: pGrbw7->Show(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CanShow()
|
||||
{
|
||||
bool canShow = true;
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: canShow &= pGrb0->CanShow(); break;
|
||||
case 1: canShow &= pGrb1->CanShow(); break;
|
||||
case 2: canShow &= pGrb2->CanShow(); break;
|
||||
case 3: canShow &= pGrb3->CanShow(); break;
|
||||
case 4: canShow &= pGrb4->CanShow(); break;
|
||||
case 5: canShow &= pGrb5->CanShow(); break;
|
||||
case 6: canShow &= pGrb6->CanShow(); break;
|
||||
case 7: canShow &= pGrb7->CanShow(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: canShow &= pGrbw0->CanShow(); break;
|
||||
case 1: canShow &= pGrbw1->CanShow(); break;
|
||||
case 2: canShow &= pGrbw2->CanShow(); break;
|
||||
case 3: canShow &= pGrbw3->CanShow(); break;
|
||||
case 4: canShow &= pGrbw4->CanShow(); break;
|
||||
case 5: canShow &= pGrbw5->CanShow(); break;
|
||||
case 6: canShow &= pGrbw6->CanShow(); break;
|
||||
case 7: canShow &= pGrbw7->CanShow(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return canShow;
|
||||
}
|
||||
|
||||
void SetPixelColorRaw(uint16_t indexPixel, RgbwColor c)
|
||||
{
|
||||
// figure out which strip this pixel index is on
|
||||
uint8_t stripIdx = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
if (indexPixel >= pixelStripStartIdx[idx])
|
||||
{
|
||||
stripIdx = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
RgbColor rgb = RgbColor(c.R, c.G, c.B);
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: pGrb0->SetPixelColor(indexPixel, rgb); break;
|
||||
case 1: pGrb1->SetPixelColor(indexPixel, rgb); break;
|
||||
case 2: pGrb2->SetPixelColor(indexPixel, rgb); break;
|
||||
case 3: pGrb3->SetPixelColor(indexPixel, rgb); break;
|
||||
case 4: pGrb4->SetPixelColor(indexPixel, rgb); break;
|
||||
case 5: pGrb5->SetPixelColor(indexPixel, rgb); break;
|
||||
case 6: pGrb6->SetPixelColor(indexPixel, rgb); break;
|
||||
case 7: pGrb7->SetPixelColor(indexPixel, rgb); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: pGrbw0->SetPixelColor(indexPixel, c); break;
|
||||
case 1: pGrbw1->SetPixelColor(indexPixel, c); break;
|
||||
case 2: pGrbw2->SetPixelColor(indexPixel, c); break;
|
||||
case 3: pGrbw3->SetPixelColor(indexPixel, c); break;
|
||||
case 4: pGrbw4->SetPixelColor(indexPixel, c); break;
|
||||
case 5: pGrbw5->SetPixelColor(indexPixel, c); break;
|
||||
case 6: pGrbw6->SetPixelColor(indexPixel, c); break;
|
||||
case 7: pGrbw7->SetPixelColor(indexPixel, c); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, RgbwColor c)
|
||||
{
|
||||
/*
|
||||
Set pixel color with necessary color order conversion.
|
||||
*/
|
||||
|
||||
RgbwColor col;
|
||||
|
||||
uint8_t co = _colorOrder;
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
//reorder channels to selected order
|
||||
switch (co)
|
||||
{
|
||||
case 0: col.G = c.G; col.R = c.R; col.B = c.B; break; //0 = GRB, default
|
||||
case 1: col.G = c.R; col.R = c.G; col.B = c.B; break; //1 = RGB, common for WS2811
|
||||
case 2: col.G = c.B; col.R = c.R; col.B = c.G; break; //2 = BRG
|
||||
case 3: col.G = c.R; col.R = c.B; col.B = c.G; break; //3 = RBG
|
||||
case 4: col.G = c.B; col.R = c.G; col.B = c.R; break; //4 = BGR
|
||||
default: col.G = c.G; col.R = c.B; col.B = c.R; break; //5 = GBR
|
||||
}
|
||||
col.W = c.W;
|
||||
|
||||
SetPixelColorRaw(indexPixel, col);
|
||||
}
|
||||
|
||||
void SetBrightness(byte b)
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0->SetBrightness(b); break;
|
||||
case 1: pGrb1->SetBrightness(b); break;
|
||||
case 2: pGrb2->SetBrightness(b); break;
|
||||
case 3: pGrb3->SetBrightness(b); break;
|
||||
case 4: pGrb4->SetBrightness(b); break;
|
||||
case 5: pGrb5->SetBrightness(b); break;
|
||||
case 6: pGrb6->SetBrightness(b); break;
|
||||
case 7: pGrb7->SetBrightness(b); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0->SetBrightness(b); break;
|
||||
case 1: pGrbw1->SetBrightness(b); break;
|
||||
case 2: pGrbw2->SetBrightness(b); break;
|
||||
case 3: pGrbw3->SetBrightness(b); break;
|
||||
case 4: pGrbw4->SetBrightness(b); break;
|
||||
case 5: pGrbw5->SetBrightness(b); break;
|
||||
case 6: pGrbw6->SetBrightness(b); break;
|
||||
case 7: pGrbw7->SetBrightness(b); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorOrder(byte colorOrder)
|
||||
{
|
||||
_colorOrder = colorOrder;
|
||||
}
|
||||
|
||||
uint8_t GetColorOrder()
|
||||
{
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
RgbwColor GetPixelColorRaw(uint16_t indexPixel) const
|
||||
{
|
||||
// figure out which strip this pixel index is on
|
||||
uint8_t stripIdx = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
if (indexPixel >= pixelStripStartIdx[idx])
|
||||
{
|
||||
stripIdx = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: return pGrb0->GetPixelColor(indexPixel);
|
||||
case 1: return pGrb1->GetPixelColor(indexPixel);
|
||||
case 2: return pGrb2->GetPixelColor(indexPixel);
|
||||
case 3: return pGrb3->GetPixelColor(indexPixel);
|
||||
case 4: return pGrb4->GetPixelColor(indexPixel);
|
||||
case 5: return pGrb5->GetPixelColor(indexPixel);
|
||||
case 6: return pGrb6->GetPixelColor(indexPixel);
|
||||
case 7: return pGrb7->GetPixelColor(indexPixel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: return pGrbw0->GetPixelColor(indexPixel);
|
||||
case 1: return pGrbw1->GetPixelColor(indexPixel);
|
||||
case 2: return pGrbw2->GetPixelColor(indexPixel);
|
||||
case 3: return pGrbw3->GetPixelColor(indexPixel);
|
||||
case 4: return pGrbw4->GetPixelColor(indexPixel);
|
||||
case 5: return pGrbw5->GetPixelColor(indexPixel);
|
||||
case 6: return pGrbw6->GetPixelColor(indexPixel);
|
||||
case 7: return pGrbw7->GetPixelColor(indexPixel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Due to feature differences, some support RGBW but the method name
|
||||
// here needs to be unique, thus GetPixeColorRgbw
|
||||
uint32_t GetPixelColorRgbw(uint16_t indexPixel) const
|
||||
{
|
||||
RgbwColor col = GetPixelColorRaw(indexPixel);
|
||||
uint8_t co = _colorOrder;
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
switch (co)
|
||||
{
|
||||
// W G R B
|
||||
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
|
||||
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
|
||||
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
|
||||
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
|
||||
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
|
||||
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
NeoPixelType _type;
|
||||
byte _colorOrder = 0;
|
||||
|
||||
uint16_t pixelStripStartIdx[numStrips];
|
||||
|
||||
// pointers for every possible type for up to 8 strips
|
||||
NeoPixelBrightnessBusGrbRmt0 *pGrb0;
|
||||
NeoPixelBrightnessBusGrbRmt1 *pGrb1;
|
||||
NeoPixelBrightnessBusGrbRmt2 *pGrb2;
|
||||
NeoPixelBrightnessBusGrbRmt3 *pGrb3;
|
||||
NeoPixelBrightnessBusGrbRmt4 *pGrb4;
|
||||
NeoPixelBrightnessBusGrbRmt5 *pGrb5;
|
||||
NeoPixelBrightnessBusGrbRmt6 *pGrb6;
|
||||
NeoPixelBrightnessBusGrbRmt7 *pGrb7;
|
||||
NeoPixelBrightnessBusGrbwRmt0 *pGrbw0;
|
||||
NeoPixelBrightnessBusGrbwRmt1 *pGrbw1;
|
||||
NeoPixelBrightnessBusGrbwRmt2 *pGrbw2;
|
||||
NeoPixelBrightnessBusGrbwRmt3 *pGrbw3;
|
||||
NeoPixelBrightnessBusGrbwRmt4 *pGrbw4;
|
||||
NeoPixelBrightnessBusGrbwRmt5 *pGrbw5;
|
||||
NeoPixelBrightnessBusGrbwRmt6 *pGrbw6;
|
||||
NeoPixelBrightnessBusGrbwRmt7 *pGrbw7;
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: delete pGrb0; pGrb0 = NULL; break;
|
||||
case 1: delete pGrb1; pGrb1 = NULL; break;
|
||||
case 2: delete pGrb2; pGrb2 = NULL; break;
|
||||
case 3: delete pGrb3; pGrb3 = NULL; break;
|
||||
case 4: delete pGrb4; pGrb4 = NULL; break;
|
||||
case 5: delete pGrb5; pGrb5 = NULL; break;
|
||||
case 6: delete pGrb6; pGrb6 = NULL; break;
|
||||
case 7: delete pGrb7; pGrb7 = NULL; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: delete pGrbw0; pGrbw0 = NULL; break;
|
||||
case 1: delete pGrbw1; pGrbw1 = NULL; break;
|
||||
case 2: delete pGrbw2; pGrbw2 = NULL; break;
|
||||
case 3: delete pGrbw3; pGrbw3 = NULL; break;
|
||||
case 4: delete pGrbw4; pGrbw4 = NULL; break;
|
||||
case 5: delete pGrbw5; pGrbw5 = NULL; break;
|
||||
case 6: delete pGrbw6; pGrbw6 = NULL; break;
|
||||
case 7: delete pGrbw7; pGrbw7 = NULL; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
@ -1,22 +0,0 @@
|
||||
# esp32_multistrip
|
||||
|
||||
This usermod enables up to 8 data pins to be used from an esp32 module to drive separate LED strands. This only works with one-wire LEDs like the WS2812.
|
||||
|
||||
The esp32 RMT hardware is used for data output. See here for hardware driver implementation details: https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
|
||||
Pass the following variables to the compiler as build flags:
|
||||
|
||||
- `ESP32_MULTISTRIP`
|
||||
- Define this to use usermod NpbWrapper.h instead of default one in WLED.
|
||||
- `NUM_STRIPS`
|
||||
- Number of strips in use
|
||||
- `PIXEL_COUNTS`
|
||||
- List of pixel counts in each strip
|
||||
- `DATA_PINS`
|
||||
- List of data pins each strip is attached to. There may be board-specific restrictions on which pins can be used for RTM.
|
||||
|
||||
From the perspective of WLED software, the LEDs are addressed as one long strand. The modified NbpWrapper.h file addresses the appropriate strand from the overall LED index based on the number of LEDs defined in each strand.
|
||||
|
||||
See `platformio_override.ini` for example configuration.
|
||||
|
||||
Tested on low cost ESP-WROOM-32 dev boards from Amazon, such as those sold by KeeYees.
|
@ -1,16 +0,0 @@
|
||||
; Example platformio_override.ini that shows how to configure your environment to use the multistrip usermod.
|
||||
; Copy this file to the base wled directory that contains platformio.ini.
|
||||
; Multistrip requires ESP32 because it has many more pins that can be used as LED outputs.
|
||||
; Need to define NUM_STRIPS, PIXEL_COUNTS, and DATA_PINS as shown below.
|
||||
|
||||
[platformio]
|
||||
default_envs = esp32_multistrip
|
||||
|
||||
[env:esp32_multistrip]
|
||||
extends=env:esp32dev
|
||||
build_flags = ${env:esp32dev.build_flags}
|
||||
-D ESP32_MULTISTRIP ; define this variable to use ESP32_MULTISTRIP usermod
|
||||
-D NUM_STRIPS=4 ; number of pixel strips in use
|
||||
-D PIXEL_COUNTS="50, 50, 50, 50" ; number of pixels in each strip
|
||||
-D DATA_PINS="25, 26, 32, 33" ; esp32 pins used for each pixel strip. available pins depends on esp32 module.
|
||||
|
@ -1,3 +1,7 @@
|
||||
# DEPRECATION NOTICE
|
||||
This usermod is deprecated and no longer maintained. It will be removed in a future WLED release. Please use usermod multi_relay which has more features.
|
||||
|
||||
|
||||
# MQTT controllable switches
|
||||
This usermod allows controlling switches (e.g. relays) via MQTT.
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#warning "This usermod is deprecated and no longer maintained. It will be removed in a future WLED release. Please use usermod multi_relay which has more features."
|
||||
|
||||
#include "wled.h"
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
|
@ -36,7 +36,7 @@ wled/deviceMAC/relay/0 on|off
|
||||
|
||||
1. Register the usermod by adding `#include "../usermods/multi_relay/usermod_multi_relay.h"` at the top and `usermods.add(new MultiRelay());` at the bottom of `usermods_list.cpp`.
|
||||
or
|
||||
2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY`in your platformio.ini
|
||||
2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY` in your platformio.ini
|
||||
|
||||
You can override the default maximum number (4) of relays by defining MULTI_RELAY_MAX_RELAYS.
|
||||
|
||||
|
@ -45,6 +45,11 @@ class MultiRelay : public Usermod {
|
||||
// status of initialisation
|
||||
bool initDone = false;
|
||||
|
||||
bool HAautodiscovery = false;
|
||||
|
||||
uint16_t periodicBroadcastSec = 60;
|
||||
unsigned long lastBroadcast = 0;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
@ -53,14 +58,15 @@ class MultiRelay : public Usermod {
|
||||
static const char _activeHigh[];
|
||||
static const char _external[];
|
||||
static const char _button[];
|
||||
static const char _broadcast[];
|
||||
static const char _HAautodiscovery[];
|
||||
|
||||
|
||||
void publishMqtt(const char* state, int relay) {
|
||||
void publishMqtt(int relay) {
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED){
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay);
|
||||
mqtt->publish(subuf, 0, false, state);
|
||||
mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,15 +74,19 @@ class MultiRelay : public Usermod {
|
||||
* switch off the strip if the delay has elapsed
|
||||
*/
|
||||
void handleOffTimer() {
|
||||
unsigned long now = millis();
|
||||
bool activeRelays = false;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].active && _switchTimerStart > 0 && millis() - _switchTimerStart > (_relay[i].delay*1000)) {
|
||||
if (_relay[i].active && _switchTimerStart > 0 && now - _switchTimerStart > (_relay[i].delay*1000)) {
|
||||
if (!_relay[i].external) toggleRelay(i);
|
||||
_relay[i].active = false;
|
||||
} else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) {
|
||||
if (_relay[i].pin>=0) publishMqtt(i);
|
||||
}
|
||||
activeRelays = activeRelays || _relay[i].active;
|
||||
}
|
||||
if (!activeRelays) _switchTimerStart = 0;
|
||||
if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) lastBroadcast = now;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,7 +115,7 @@ class MultiRelay : public Usermod {
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
int value = getValue(p->value(), ',', i);
|
||||
if (value==-1) {
|
||||
error = F("There must be as much arugments as relays");
|
||||
error = F("There must be as many arguments as relays");
|
||||
} else {
|
||||
// Switch
|
||||
if (_relay[i].external) switchRelay(i, (bool)value);
|
||||
@ -118,7 +128,7 @@ class MultiRelay : public Usermod {
|
||||
for (int i=0;i<MULTI_RELAY_MAX_RELAYS;i++) {
|
||||
int value = getValue(p->value(), ',', i);
|
||||
if (value==-1) {
|
||||
error = F("There must be as mutch arugments as relays");
|
||||
error = F("There must be as many arguments as relays");
|
||||
} else {
|
||||
// Toggle
|
||||
if (value && _relay[i].external) toggleRelay(i);
|
||||
@ -199,7 +209,7 @@ class MultiRelay : public Usermod {
|
||||
_relay[relay].state = mode;
|
||||
pinMode(_relay[relay].pin, OUTPUT);
|
||||
digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
|
||||
publishMqtt(mode ? "on" : "off", relay);
|
||||
publishMqtt(relay);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,6 +262,50 @@ class MultiRelay : public Usermod {
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat_P(subuf, PSTR("/relay/#"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
if (HAautodiscovery) publishHomeAssistantAutodiscovery();
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin<0) continue;
|
||||
publishMqtt(i); //publish current state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void publishHomeAssistantAutodiscovery() {
|
||||
for (uint8_t i = 0; i < MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
char uid[16], json_str[1024], buf[128];
|
||||
size_t payload_size;
|
||||
sprintf_P(uid, PSTR("%s_sw%d"), escapedMac.c_str(), i);
|
||||
|
||||
if (_relay[i].pin >= 0 && _relay[i].external) {
|
||||
StaticJsonDocument<1024> json;
|
||||
sprintf_P(buf, PSTR("%s Switch %d"), serverDescription, i); //max length: 33 + 8 + 3 = 44
|
||||
json[F("name")] = buf;
|
||||
|
||||
sprintf_P(buf, PSTR("%s/relay/%d"), mqttDeviceTopic, i); //max length: 33 + 7 + 3 = 43
|
||||
json["~"] = buf;
|
||||
strcat_P(buf, PSTR("/command"));
|
||||
mqtt->subscribe(buf, 0);
|
||||
|
||||
json[F("stat_t")] = "~";
|
||||
json[F("cmd_t")] = F("~/command");
|
||||
json[F("pl_off")] = F("off");
|
||||
json[F("pl_on")] = F("on");
|
||||
json[F("uniq_id")] = uid;
|
||||
|
||||
strcpy(buf, mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||
strcat_P(buf, PSTR("/status"));
|
||||
json[F("avty_t")] = buf;
|
||||
json[F("pl_avail")] = F("online");
|
||||
json[F("pl_not_avail")] = F("offline");
|
||||
//TODO: dev
|
||||
payload_size = serializeJson(json, json_str);
|
||||
} else {
|
||||
//Unpublish disabled or internal relays
|
||||
json_str[0] = 0;
|
||||
payload_size = 0;
|
||||
}
|
||||
sprintf_P(buf, PSTR("homeassistant/switch/%s/config"), uid);
|
||||
mqtt->publish(buf, 0, true, json_str, payload_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +320,7 @@ class MultiRelay : public Usermod {
|
||||
if (!pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
|
||||
_relay[i].pin = -1; // allocation failed
|
||||
} else {
|
||||
if (!_relay[i].external) _relay[i].state = offMode;
|
||||
if (!_relay[i].external) _relay[i].state = !offMode;
|
||||
switchRelay(i, _relay[i].state);
|
||||
_relay[i].active = false;
|
||||
}
|
||||
@ -313,13 +367,18 @@ class MultiRelay : public Usermod {
|
||||
*/
|
||||
bool handleButton(uint8_t b) {
|
||||
yield();
|
||||
if (buttonType[b] == BTN_TYPE_NONE || buttonType[b] == BTN_TYPE_RESERVED || buttonType[b] == BTN_TYPE_PIR_SENSOR || buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
|
||||
if (!enabled
|
||||
|| buttonType[b] == BTN_TYPE_NONE
|
||||
|| buttonType[b] == BTN_TYPE_RESERVED
|
||||
|| buttonType[b] == BTN_TYPE_PIR_SENSOR
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].button == b) {
|
||||
if (_relay[i].button == b && _relay[i].external) {
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@ -355,6 +414,8 @@ class MultiRelay : public Usermod {
|
||||
buttonPressedBefore[b] = true;
|
||||
|
||||
if (now - buttonPressedTime[b] > 600) { //long press
|
||||
//longPressAction(b); //not exposed
|
||||
//handled = false; //use if you want to pass to default behaviour
|
||||
buttonLongPressed[b] = true;
|
||||
}
|
||||
|
||||
@ -371,7 +432,8 @@ class MultiRelay : public Usermod {
|
||||
if (!buttonLongPressed[b]) { //short press
|
||||
// if this is second release within 350ms it is a double press (buttonWaitTime!=0)
|
||||
if (doublePress) {
|
||||
//doublePressAction(b);
|
||||
//doublePressAction(b); //not exposed
|
||||
//handled = false; //use if you want to pass to default behaviour
|
||||
} else {
|
||||
buttonWaitTime[b] = now;
|
||||
}
|
||||
@ -379,9 +441,10 @@ class MultiRelay : public Usermod {
|
||||
buttonPressedBefore[b] = false;
|
||||
buttonLongPressed[b] = false;
|
||||
}
|
||||
// if 450ms elapsed since last press/release it is a short press
|
||||
// if 350ms elapsed since last press/release it is a short press
|
||||
if (buttonWaitTime[b] && now - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) {
|
||||
buttonWaitTime[b] = 0;
|
||||
//shortPressAction(b); //not exposed
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin>=0 && _relay[i].button == b) {
|
||||
toggleRelay(i);
|
||||
@ -477,6 +540,7 @@ class MultiRelay : public Usermod {
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
|
||||
top[FPSTR(_enabled)] = enabled;
|
||||
top[FPSTR(_broadcast)] = periodicBroadcastSec;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
JsonObject relay = top.createNestedObject(parName);
|
||||
@ -486,6 +550,7 @@ class MultiRelay : public Usermod {
|
||||
relay[FPSTR(_external)] = _relay[i].external;
|
||||
relay[FPSTR(_button)] = _relay[i].button;
|
||||
}
|
||||
top[FPSTR(_HAautodiscovery)] = HAautodiscovery;
|
||||
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
||||
}
|
||||
|
||||
@ -506,6 +571,9 @@ class MultiRelay : public Usermod {
|
||||
}
|
||||
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
|
||||
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
|
||||
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
|
||||
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
@ -539,7 +607,9 @@ class MultiRelay : public Usermod {
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin>=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) {
|
||||
if (!_relay[i].external) {
|
||||
switchRelay(i, offMode);
|
||||
_relay[i].state = !offMode;
|
||||
switchRelay(i, _relay[i].state);
|
||||
_oldMode = offMode;
|
||||
}
|
||||
} else {
|
||||
_relay[i].pin = -1;
|
||||
@ -549,7 +619,7 @@ class MultiRelay : public Usermod {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[F("relay-0")][FPSTR(_button)].isNull();
|
||||
return !top[FPSTR(_broadcast)].isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -570,3 +640,5 @@ const char MultiRelay::_delay_str[] PROGMEM = "delay-s";
|
||||
const char MultiRelay::_activeHigh[] PROGMEM = "active-high";
|
||||
const char MultiRelay::_external[] PROGMEM = "external";
|
||||
const char MultiRelay::_button[] PROGMEM = "button";
|
||||
const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
|
||||
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
|
||||
|
@ -1,37 +0,0 @@
|
||||
# QuinLED-Dig-Quad Preassembled Unofficial Build
|
||||
|
||||
This usermod targets the [Preassembled QuinLED-Dig-Quad](https://quinled.info/pre-assembled-quinled-dig-quad/). Tested on board revision v1r6b,
|
||||
and includes the following features:
|
||||
|
||||
* **Multi-channel Support** - enabling use of LED1, LED2, LED3, LED4 pins to work using segments
|
||||
* **Temperature Sensor Support** - pulls readings from the built-in temperature sensor and adds the reading to the *Info* page in the UI
|
||||
|
||||
## Background
|
||||
|
||||
As a starting point, you should check out this awesome video from Quindor: [How to compile WLED yourself](https://quinled.info/2020/12/22/livestream-wled-compile/). The usermod you are reading now just provides some shortcuts for parts of what were covered in that video.
|
||||
|
||||
## Build Firmware with Multi-channel and Temp Support
|
||||
|
||||
1. Copy the `platformio_override.ini` file to the project's root directory
|
||||
1. If using VS Code with the PlatformIO plugin like in the video, you will now see this new project task listed in the PLATFORMIO panel at the bottom as `env:QL-DigQuad-Pre-v0.1` (you probably need to hit the refresh button)
|
||||
|
||||
<img src="images/pio-screenshot.png" width="400px"/>
|
||||
|
||||
1. Edit this file from the root directory as needed:
|
||||
|
||||
<img src="images/params.png" width="400px"/>
|
||||
|
||||
* `PIXEL_COUNTS` may need to be adjusted for your set-up. E.g. I have lots of LEDs in Channel 1, but that's probably unusual for most
|
||||
* `DATA_PINS` may need to be changed to "16,3,1,26" instead of "16,1,3,26" apparently depending on the board revision or some such
|
||||
|
||||
1. Build the mod (e.g. click `Build` from the project task circled above) and update your firmware using the `QL-DigQuad-Pre-v0.1` file, e.g. using _Manual OTA_ from the Config menu. Based on the video and my own experience, you might need to build twice 🤷♂️.
|
||||
|
||||
## Observing Temperature
|
||||
|
||||
Hopefully you can now see the Temperature listed in the Info page. If not, use Chrome Developer Tools to find the current temperature
|
||||
|
||||
1. Open the Developer Tools Console
|
||||
2. Enter `lastinfo.u.Temperature` to view the Temperature array
|
||||
|
||||
<img src="images/json-temp.png" width="300px"/>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 296 KiB |
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
Binary file not shown.
Before Width: | Height: | Size: 321 KiB |
@ -1,16 +0,0 @@
|
||||
; QuinLED-Dig-Quad Preassembled Unofficial
|
||||
|
||||
[env:QL-DigQuad-Pre-v0.1]
|
||||
extends = env:esp32dev
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
-D ESP32_MULTISTRIP
|
||||
-D NUM_STRIPS=4
|
||||
-D PIXEL_COUNTS="600, 300, 300, 300"
|
||||
-D DATA_PINS="16,1,3,26"
|
||||
-D RLYPIN=19
|
||||
-D BTNPIN=17
|
||||
-D USERMOD_DALLASTEMPERATURE
|
||||
-D USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL=10000
|
||||
lib_deps = ${env.lib_deps}
|
||||
milesburton/DallasTemperature@^3.9.0
|
||||
OneWire@~2.3.5
|
@ -1,35 +0,0 @@
|
||||
# SSD1306 128x32 OLED via I2C with u8g2
|
||||
This usermod allows to connect 128x32 Oled display to WLED controlled and show
|
||||
the next information:
|
||||
- Current SSID
|
||||
- IP address if obtained
|
||||
* in AP mode and turned off lightning AP password is shown
|
||||
- Current effect
|
||||
- Current palette
|
||||
- On/Off icon (sun/moon)
|
||||
|
||||
## Hardware
|
||||
![Hardware connection](assets/hw_connection.png)
|
||||
|
||||
## Requirements
|
||||
Functionality checked with:
|
||||
- commit 095429a7df4f9e2b34dd464f7bbfd068df6558eb
|
||||
- Wemos d1 mini
|
||||
- PlatformIO
|
||||
- Generic SSD1306 128x32 I2C OLED display from aliexpress
|
||||
|
||||
### Platformio
|
||||
Add `U8g2@~2.27.2` dependency to `lib_deps_external` under `[common]` section in `platformio.ini`:
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
U8g2@~2.27.2
|
||||
...
|
||||
```
|
||||
|
||||
### Arduino IDE
|
||||
Install library `U8g2 by oliver` in `Tools | Include Library | Manage libraries` menu.
|
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
@ -1,175 +0,0 @@
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//Lolin32 boards use SCL=5 SDA=4
|
||||
#define U8X8_PIN_SCL 5
|
||||
#define U8X8_PIN_SDA 4
|
||||
|
||||
|
||||
// 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
|
||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL,
|
||||
U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void userSetup() {
|
||||
u8x8.begin();
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.drawString(0, 0, "Loading...");
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void userConnected() {}
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
bool displayTurnedOff = false;
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||||
|
||||
void userLoop() {
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
||||
u8x8.setPowerSave(1);
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
u8x8.setPowerSave(0);
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
knownSsid = WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
u8x8.setCursor(1, 0);
|
||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols())
|
||||
u8x8.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
u8x8.setCursor(1, 1);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
u8x8.print(apPass);
|
||||
else
|
||||
u8x8.print(knownIp);
|
||||
|
||||
// Third row with mode name
|
||||
u8x8.setCursor(2, 2);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
u8x8.setCursor(2, 3);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownPalette))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
||||
}
|
@ -2091,7 +2091,7 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
}
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
return FRAMETIME_FIXED;
|
||||
}
|
||||
|
||||
|
||||
@ -2876,7 +2876,7 @@ uint16_t WS2812FX::candle(bool multi)
|
||||
}
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
return FRAMETIME_FIXED;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::mode_candle()
|
||||
|
@ -48,7 +48,8 @@
|
||||
|
||||
/* Not used in all effects yet */
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME (1000/WLED_FPS)
|
||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||
#define FRAMETIME _frametime
|
||||
|
||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
@ -71,7 +72,7 @@
|
||||
#define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / MAX_NUM_SEGMENTS)
|
||||
|
||||
#define LED_SKIP_AMOUNT 1
|
||||
#define MIN_SHOW_DELAY 15
|
||||
#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15)
|
||||
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT _segments[_segment_index]
|
||||
@ -655,6 +656,7 @@ class WS2812FX {
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
show(void),
|
||||
setTargetFps(uint8_t fps),
|
||||
setPixelSegment(uint8_t n),
|
||||
deserializeMap(uint8_t n=0);
|
||||
|
||||
@ -685,6 +687,7 @@ class WS2812FX {
|
||||
getActiveSegmentsNum(void),
|
||||
//getFirstSelectedSegment(void),
|
||||
getMainSegmentId(void),
|
||||
getTargetFps(void),
|
||||
gamma8(uint8_t),
|
||||
gamma8_cal(uint8_t, float),
|
||||
sin_gap(uint16_t),
|
||||
@ -856,6 +859,8 @@ class WS2812FX {
|
||||
uint16_t _usedSegmentData = 0;
|
||||
uint16_t _transitionDur = 750;
|
||||
|
||||
uint8_t _targetFps = 42;
|
||||
uint16_t _frametime = (1000/42);
|
||||
uint16_t _cumulativeFps = 2;
|
||||
|
||||
bool
|
||||
|
@ -165,12 +165,12 @@ void WS2812FX::service() {
|
||||
_triggered = false;
|
||||
}
|
||||
|
||||
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
||||
setPixelColor(n, R(c), G(c), B(c), W(c));
|
||||
}
|
||||
|
||||
//used to map from segment index to physical pixel, taking into account grouping, offsets, reverse and mirroring
|
||||
uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
uint16_t IRAM_ATTR WS2812FX::realPixelIndex(uint16_t i) {
|
||||
int16_t iGroup = i * SEGMENT.groupLength();
|
||||
|
||||
/* reverse just an individual segment */
|
||||
@ -187,7 +187,7 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
return realIndex;
|
||||
}
|
||||
|
||||
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
{
|
||||
if (SEGLEN) {//from segment
|
||||
uint16_t realIndex = realPixelIndex(i);
|
||||
@ -350,6 +350,15 @@ uint16_t WS2812FX::getFps() {
|
||||
return _cumulativeFps +1;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getTargetFps() {
|
||||
return _targetFps;
|
||||
}
|
||||
|
||||
void WS2812FX::setTargetFps(uint8_t fps) {
|
||||
if (fps > 0 && fps <= 120) _targetFps = fps;
|
||||
_frametime = 1000 / _targetFps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the next frame to be computed on all active segments.
|
||||
*/
|
||||
@ -775,7 +784,7 @@ void WS2812FX::setTransitionMode(bool t)
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
||||
uint32_t IRAM_ATTR WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
||||
if(blend == 0) return color1;
|
||||
uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
|
||||
if(blend == blendmax) return color2;
|
||||
@ -878,13 +887,13 @@ void WS2812FX::blur(uint8_t blur_amount)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::triwave16(uint16_t in)
|
||||
uint16_t IRAM_ATTR WS2812FX::triwave16(uint16_t in)
|
||||
{
|
||||
if (in < 0x8000) return in *2;
|
||||
return 0xFFFF - (in - 0x8000)*2;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::sin_gap(uint16_t in) {
|
||||
uint8_t IRAM_ATTR WS2812FX::sin_gap(uint16_t in) {
|
||||
if (in & 0x100) return 0;
|
||||
//if (in > 255) return 0;
|
||||
return sin8(in + 192); //correct phase shift of sine so that it starts and stops at 0
|
||||
@ -951,13 +960,13 @@ uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) {
|
||||
}
|
||||
|
||||
|
||||
uint32_t WS2812FX::crgb_to_col(CRGB fastled)
|
||||
uint32_t IRAM_ATTR WS2812FX::crgb_to_col(CRGB fastled)
|
||||
{
|
||||
return RGBW32(fastled.red, fastled.green, fastled.blue, 0);
|
||||
}
|
||||
|
||||
|
||||
CRGB WS2812FX::col_to_crgb(uint32_t color)
|
||||
CRGB IRAM_ATTR WS2812FX::col_to_crgb(uint32_t color)
|
||||
{
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = R(color);
|
||||
@ -1080,7 +1089,7 @@ void WS2812FX::handle_palette(void)
|
||||
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
|
||||
* @returns Single color from palette
|
||||
*/
|
||||
uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
|
||||
uint32_t IRAM_ATTR WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
|
||||
{
|
||||
if (SEGMENT.palette == 0 && mcol < 3) {
|
||||
uint32_t color = SEGCOLOR(mcol);
|
||||
|
@ -73,6 +73,62 @@ struct BusConfig {
|
||||
}
|
||||
};
|
||||
|
||||
// Defines an LED Strip and its color ordering.
|
||||
struct ColorOrderMapEntry {
|
||||
uint16_t start;
|
||||
uint16_t len;
|
||||
uint8_t colorOrder;
|
||||
};
|
||||
|
||||
struct ColorOrderMap {
|
||||
void add(uint16_t start, uint16_t len, uint8_t colorOrder) {
|
||||
if (_count >= WLED_MAX_COLOR_ORDER_MAPPINGS) {
|
||||
return;
|
||||
}
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
if (colorOrder > COL_ORDER_MAX) {
|
||||
return;
|
||||
}
|
||||
_mappings[_count].start = start;
|
||||
_mappings[_count].len = len;
|
||||
_mappings[_count].colorOrder = colorOrder;
|
||||
_count++;
|
||||
}
|
||||
|
||||
uint8_t count() const {
|
||||
return _count;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_count = 0;
|
||||
memset(_mappings, 0, sizeof(_mappings));
|
||||
}
|
||||
|
||||
const ColorOrderMapEntry* get(uint8_t n) const {
|
||||
if (n > _count) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(_mappings[n]);
|
||||
}
|
||||
|
||||
inline uint8_t getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const {
|
||||
if (_count == 0) return defaultColorOrder;
|
||||
|
||||
for (uint8_t i = 0; i < _count; i++) {
|
||||
if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) {
|
||||
return _mappings[i].colorOrder;
|
||||
}
|
||||
}
|
||||
return defaultColorOrder;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _count;
|
||||
ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS];
|
||||
};
|
||||
|
||||
//parent class of BusDigital, BusPwm, and BusNetwork
|
||||
class Bus {
|
||||
public:
|
||||
@ -152,7 +208,7 @@ class Bus {
|
||||
|
||||
class BusDigital : public Bus {
|
||||
public:
|
||||
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) {
|
||||
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start), _colorOrderMap(com) {
|
||||
if (!IS_DIGITAL(bc.type) || !bc.count) return;
|
||||
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
|
||||
_pins[0] = bc.pins[0];
|
||||
@ -197,7 +253,7 @@ class BusDigital : public Bus {
|
||||
//TODO only show if no new show due in the next 50ms
|
||||
void setStatusPixel(uint32_t c) {
|
||||
if (_skip && canShow()) {
|
||||
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrder);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
|
||||
PolyBus::show(_busPtr, _iType);
|
||||
}
|
||||
}
|
||||
@ -207,13 +263,13 @@ class BusDigital : public Bus {
|
||||
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
if (reversed) pix = _len - pix -1;
|
||||
else pix += _skip;
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
|
||||
}
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
else pix += _skip;
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder);
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
|
||||
}
|
||||
|
||||
inline uint8_t getColorOrder() {
|
||||
@ -263,6 +319,7 @@ class BusDigital : public Bus {
|
||||
uint8_t _iType = I_NONE;
|
||||
uint8_t _skip = 0;
|
||||
void * _busPtr = nullptr;
|
||||
const ColorOrderMap &_colorOrderMap;
|
||||
};
|
||||
|
||||
|
||||
@ -288,7 +345,7 @@ class BusPwm : public Bus {
|
||||
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) {
|
||||
deallocatePins(); return;
|
||||
}
|
||||
_pins[i] = currentPin; // store only after allocatePin() succeeds
|
||||
_pins[i] = currentPin; //store only after allocatePin() succeeds
|
||||
#ifdef ESP8266
|
||||
pinMode(_pins[i], OUTPUT);
|
||||
#else
|
||||
@ -397,7 +454,7 @@ class BusPwm : public Bus {
|
||||
|
||||
private:
|
||||
uint8_t _pins[5] = {255, 255, 255, 255, 255};
|
||||
uint8_t _data[5] = {255, 255, 255, 255, 255};
|
||||
uint8_t _data[5] = {0};
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t _ledcStart = 255;
|
||||
#endif
|
||||
@ -555,7 +612,7 @@ class BusManager {
|
||||
if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) {
|
||||
busses[numBusses] = new BusNetwork(bc);
|
||||
} else if (IS_DIGITAL(bc.type)) {
|
||||
busses[numBusses] = new BusDigital(bc, numBusses);
|
||||
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap);
|
||||
} else {
|
||||
busses[numBusses] = new BusPwm(bc);
|
||||
}
|
||||
@ -640,8 +697,17 @@ class BusManager {
|
||||
return len;
|
||||
}
|
||||
|
||||
void updateColorOrderMap(const ColorOrderMap &com) {
|
||||
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
|
||||
}
|
||||
|
||||
const ColorOrderMap& getColorOrderMap() const {
|
||||
return colorOrderMap;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t numBusses = 0;
|
||||
Bus* busses[WLED_MAX_BUSSES];
|
||||
ColorOrderMap colorOrderMap;
|
||||
};
|
||||
#endif
|
||||
|
@ -102,26 +102,34 @@
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
//RGB
|
||||
#define B_32_RN_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
#define B_32_I0_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s0800KbpsMethod>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define B_32_I1_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1800KbpsMethod>
|
||||
#endif
|
||||
//RGBW
|
||||
#define B_32_RN_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32RmtNWs2812xMethod>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
#define B_32_I0_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s0800KbpsMethod>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define B_32_I1_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s1800KbpsMethod>
|
||||
#endif
|
||||
//400Kbps
|
||||
#define B_32_RN_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32RmtN400KbpsMethod>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
#define B_32_I0_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s0400KbpsMethod>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define B_32_I1_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1400KbpsMethod>
|
||||
#endif
|
||||
//TM1814 (RGBW)
|
||||
#define B_32_RN_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32RmtNTm1814Method>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
#define B_32_I0_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32I2s0Tm1814Method>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define B_32_I1_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32I2s1Tm1814Method>
|
||||
#endif
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
@ -190,23 +198,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Begin(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Begin(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Begin(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Begin(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Begin(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Begin(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: beginTM1814<B_32_RN_TM1_4*>(busPtr); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: beginTM1814<B_32_I0_TM1_4*>(busPtr); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: beginTM1814<B_32_I1_TM1_4*>(busPtr); break;
|
||||
#endif
|
||||
// ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin()
|
||||
@ -247,23 +263,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: busPtr = new B_32_RN_NEO_4(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: busPtr = new B_32_RN_400_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: busPtr = new B_32_I1_400_3(len, pins[0]); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: busPtr = new B_32_RN_TM1_4(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: busPtr = new B_32_I1_TM1_4(len, pins[0]); break;
|
||||
#endif
|
||||
#endif
|
||||
@ -305,23 +329,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
#endif
|
||||
@ -360,23 +392,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: return (static_cast<B_32_RN_NEO_3*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: return (static_cast<B_32_I0_NEO_3*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: return (static_cast<B_32_I1_NEO_3*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: return (static_cast<B_32_RN_NEO_4*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: return (static_cast<B_32_I0_NEO_4*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: return (static_cast<B_32_I1_NEO_4*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: return (static_cast<B_32_RN_400_3*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: return (static_cast<B_32_I0_400_3*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: return (static_cast<B_32_I1_400_3*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: return (static_cast<B_32_RN_TM1_4*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: return (static_cast<B_32_I0_TM1_4*>(busPtr))->CanShow(); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: return (static_cast<B_32_I1_TM1_4*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
#endif
|
||||
@ -439,23 +479,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#endif
|
||||
#endif
|
||||
@ -494,23 +542,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
#endif
|
||||
#endif
|
||||
@ -550,23 +606,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: col = (static_cast<B_32_RN_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: col = (static_cast<B_32_I0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: col = (static_cast<B_32_I1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: col = (static_cast<B_32_RN_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: col = (static_cast<B_32_I0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: col = (static_cast<B_32_I1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: col = (static_cast<B_32_RN_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: col = (static_cast<B_32_I0_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: col = (static_cast<B_32_I1_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: col = (static_cast<B_32_RN_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: col = (static_cast<B_32_I0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: col = (static_cast<B_32_I1_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
#endif
|
||||
@ -623,23 +687,31 @@ class PolyBus {
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: delete (static_cast<B_32_RN_NEO_3*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_3: delete (static_cast<B_32_I0_NEO_3*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_3: delete (static_cast<B_32_I1_NEO_3*>(busPtr)); break;
|
||||
#endif
|
||||
case I_32_RN_NEO_4: delete (static_cast<B_32_RN_NEO_4*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_NEO_4: delete (static_cast<B_32_I0_NEO_4*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_NEO_4: delete (static_cast<B_32_I1_NEO_4*>(busPtr)); break;
|
||||
#endif
|
||||
case I_32_RN_400_3: delete (static_cast<B_32_RN_400_3*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_400_3: delete (static_cast<B_32_I0_400_3*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_400_3: delete (static_cast<B_32_I1_400_3*>(busPtr)); break;
|
||||
#endif
|
||||
case I_32_RN_TM1_4: delete (static_cast<B_32_RN_TM1_4*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
case I_32_I0_TM1_4: delete (static_cast<B_32_I0_TM1_4*>(busPtr)); break;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32S2
|
||||
#endif
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
case I_32_I1_TM1_4: delete (static_cast<B_32_I1_TM1_4*>(busPtr)); break;
|
||||
#endif
|
||||
#endif
|
||||
|
@ -17,7 +17,7 @@ void shortPressAction(uint8_t b)
|
||||
if (!macroButton[b]) {
|
||||
switch (b) {
|
||||
case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
default: ++effectCurrent %= strip.getModeCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
case 1: ++effectCurrent %= strip.getModeCount(); effectChanged = true; colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
|
||||
@ -36,7 +36,7 @@ void longPressAction(uint8_t b)
|
||||
if (!macroLongPress[b]) {
|
||||
switch (b) {
|
||||
case 0: _setRandomColor(false,true); break;
|
||||
default: bri += 8; colorUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
|
||||
case 1: bri += 8; colorUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
|
||||
}
|
||||
} else {
|
||||
applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
|
||||
@ -55,7 +55,7 @@ void doublePressAction(uint8_t b)
|
||||
if (!macroDoublePress[b]) {
|
||||
switch (b) {
|
||||
//case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; //instant short press on button 0 if no macro set
|
||||
default: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
case 1: ++effectPalette %= strip.getPaletteCount(); effectChanged = true; colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET);
|
||||
@ -85,7 +85,7 @@ bool isButtonPressed(uint8_t i)
|
||||
if (digitalRead(btnPin[i]) == HIGH) return true;
|
||||
break;
|
||||
case BTN_TYPE_TOUCH:
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
if (touchRead(btnPin[i]) <= touchThreshold) return true;
|
||||
#endif
|
||||
break;
|
||||
@ -210,6 +210,7 @@ void handleAnalog(uint8_t b)
|
||||
void handleButton()
|
||||
{
|
||||
static unsigned long lastRead = 0UL;
|
||||
bool analog = false;
|
||||
|
||||
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
|
||||
#ifdef ESP8266
|
||||
@ -221,7 +222,7 @@ void handleButton()
|
||||
if (usermods.handleButton(b)) continue; // did usermod handle buttons
|
||||
|
||||
if ((buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) && millis() - lastRead > 250) { // button is not a button but a potentiometer
|
||||
if (b+1 == WLED_MAX_BUTTONS) lastRead = millis();
|
||||
analog = true;
|
||||
handleAnalog(b); continue;
|
||||
}
|
||||
|
||||
@ -275,6 +276,7 @@ void handleButton()
|
||||
shortPressAction(b);
|
||||
}
|
||||
}
|
||||
if (analog) lastRead = millis();
|
||||
}
|
||||
|
||||
void handleIO()
|
||||
|
@ -85,6 +85,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(cctFromRgb, hw_led[F("cr")]);
|
||||
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
|
||||
@ -122,6 +123,22 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
}
|
||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||
|
||||
// read color order map configuration
|
||||
JsonArray hw_com = hw[F("com")];
|
||||
if (!hw_com.isNull()) {
|
||||
ColorOrderMap com = {};
|
||||
uint8_t s = 0;
|
||||
for (JsonObject entry : hw_com) {
|
||||
if (s > WLED_MAX_COLOR_ORDER_MAPPINGS) break;
|
||||
uint16_t start = entry[F("start")] | 0;
|
||||
uint16_t len = entry[F("len")] | 0;
|
||||
uint8_t colorOrder = (int)entry[F("order")];
|
||||
com.add(start, len, colorOrder);
|
||||
s++;
|
||||
}
|
||||
busses.updateColorOrderMap(com);
|
||||
}
|
||||
|
||||
// read multiple button configuration
|
||||
JsonObject btn_obj = hw["btn"];
|
||||
JsonArray hw_btn_ins = btn_obj[F("ins")];
|
||||
@ -239,8 +256,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(receiveNotificationColor, if_sync_recv["col"]);
|
||||
CJSON(receiveNotificationEffects, if_sync_recv["fx"]);
|
||||
CJSON(receiveGroups, if_sync_recv["grp"]);
|
||||
CJSON(receiveSegmentOptions, if_sync_recv["seg"]);
|
||||
//! following line might be a problem if called after boot
|
||||
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
|
||||
|
||||
JsonObject if_sync_send = if_sync["send"];
|
||||
prev = notifyDirectDefault;
|
||||
@ -365,7 +383,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(timerMinutes[it], timer["min"]);
|
||||
CJSON(timerMacro[it], timer["macro"]);
|
||||
|
||||
byte dowPrev = timerWeekday[it];
|
||||
byte dowPrev = timerWeekday[it];
|
||||
//note: act is currently only 0 or 1.
|
||||
//the reason we are not using bool is that the on-disk type in 0.11.0 was already int
|
||||
int actPrev = timerWeekday[it] & 0x01;
|
||||
@ -375,7 +393,17 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
int act = timer["en"] | actPrev;
|
||||
if (act) timerWeekday[it]++;
|
||||
}
|
||||
|
||||
if (it<8) {
|
||||
JsonObject start = timer["start"];
|
||||
byte startm = start["mon"];
|
||||
if (startm) timerMonth[it] = (startm << 4);
|
||||
CJSON(timerDay[it], start["day"]);
|
||||
JsonObject end = timer["end"];
|
||||
CJSON(timerDayEnd[it], end["day"]);
|
||||
byte endm = end["mon"];
|
||||
if (startm) timerMonth[it] += endm & 0x0F;
|
||||
if (!(timerMonth[it] & 0x0F)) timerMonth[it] += 12; //default end month to 12
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
@ -539,6 +567,7 @@ void serializeConfig() {
|
||||
hw_led["cct"] = correctWB;
|
||||
hw_led[F("cr")] = cctFromRgb;
|
||||
hw_led[F("cb")] = strip.cctBlending;
|
||||
hw_led["fps"] = strip.getTargetFps();
|
||||
hw_led[F("rgbwm")] = Bus::getAutoWhiteMode();
|
||||
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
@ -561,6 +590,18 @@ void serializeConfig() {
|
||||
ins[F("rgbw")] = bus->isRgbw();
|
||||
}
|
||||
|
||||
JsonArray hw_com = hw.createNestedArray(F("com"));
|
||||
const ColorOrderMap& com = busses.getColorOrderMap();
|
||||
for (uint8_t s = 0; s < com.count(); s++) {
|
||||
const ColorOrderMapEntry *entry = com.get(s);
|
||||
if (!entry) break;
|
||||
|
||||
JsonObject co = hw_com.createNestedObject();
|
||||
co[F("start")] = entry->start;
|
||||
co[F("len")] = entry->len;
|
||||
co[F("order")] = entry->colorOrder;
|
||||
}
|
||||
|
||||
// button(s)
|
||||
JsonObject hw_btn = hw.createNestedObject("btn");
|
||||
hw_btn["max"] = WLED_MAX_BUTTONS; // just information about max number of buttons (not actually used)
|
||||
@ -628,6 +669,7 @@ void serializeConfig() {
|
||||
if_sync_recv["col"] = receiveNotificationColor;
|
||||
if_sync_recv["fx"] = receiveNotificationEffects;
|
||||
if_sync_recv["grp"] = receiveGroups;
|
||||
if_sync_recv["seg"] = receiveSegmentOptions;
|
||||
|
||||
JsonObject if_sync_send = if_sync.createNestedObject("send");
|
||||
if_sync_send[F("dir")] = notifyDirect;
|
||||
@ -740,6 +782,14 @@ void serializeConfig() {
|
||||
timers_ins0["min"] = timerMinutes[i];
|
||||
timers_ins0["macro"] = timerMacro[i];
|
||||
timers_ins0[F("dow")] = timerWeekday[i] >> 1;
|
||||
if (i<8) {
|
||||
JsonObject start = timers_ins0.createNestedObject("start");
|
||||
start["mon"] = (timerMonth[i] >> 4) & 0xF;
|
||||
start["day"] = timerDay[i];
|
||||
JsonObject end = timers_ins0.createNestedObject("end");
|
||||
end["mon"] = timerMonth[i] & 0xF;
|
||||
end["day"] = timerDayEnd[i];
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject ota = doc.createNestedObject("ota");
|
||||
|
@ -22,11 +22,6 @@ void colorFromUint24(uint32_t in, bool secondary)
|
||||
_col[2] = B(in);
|
||||
}
|
||||
|
||||
//store color components in uint32_t
|
||||
uint32_t colorFromRgbw(byte* rgbw) {
|
||||
return RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
|
||||
//relatively change white brightness, minumum A=5
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
||||
{
|
||||
@ -259,7 +254,7 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb)
|
||||
rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G
|
||||
rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B
|
||||
rgbw[3] = W(rgb);
|
||||
return colorFromRgbw(rgbw);
|
||||
return RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||
}
|
||||
|
||||
//approximates a Kelvin color temperature from an RGB color.
|
||||
@ -299,4 +294,4 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
||||
uint16_t k = 8080 + (225-r) *86;
|
||||
return (k > 10091) ? 10091 : k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_COLOR_ORDER_MAPPINGS 5
|
||||
#else
|
||||
#define WLED_MAX_COLOR_ORDER_MAPPINGS 10
|
||||
#endif
|
||||
|
||||
//Usermod IDs
|
||||
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
||||
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
|
||||
@ -171,6 +177,7 @@
|
||||
#define COL_ORDER_RBG 3
|
||||
#define COL_ORDER_BGR 4
|
||||
#define COL_ORDER_GBR 5
|
||||
#define COL_ORDER_MAX 5
|
||||
|
||||
|
||||
//Button type
|
||||
|
@ -609,11 +609,12 @@ input[type=range]:active + .sliderbubble {
|
||||
width: 216px;
|
||||
}
|
||||
.btn-xs {
|
||||
width: 39px;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
.btn-pl-add {
|
||||
margin-left: 9px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
@ -645,7 +646,7 @@ input[type=range]:active + .sliderbubble {
|
||||
.sel-pl {
|
||||
width: 192px;
|
||||
background-position: 168px 16px;
|
||||
margin: 8px 7px 0 0;
|
||||
margin: 8px 3px 0 0;
|
||||
}
|
||||
|
||||
.sel-ple {
|
||||
|
@ -141,7 +141,7 @@
|
||||
<div id="Effects" class="tabcontent">
|
||||
<p class="labels">Effect speed</p>
|
||||
<div class="staytop">
|
||||
<i class="icons slider-icon"></i>
|
||||
<i class="icons slider-icon" onclick="tglFreeze()"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
|
@ -603,7 +603,6 @@ function populateSegments(s)
|
||||
</tr>
|
||||
</table>
|
||||
<div class="h" id="seg${i}len"></div>
|
||||
<button class="btn btn-i btn-xs del" id="segd${i}" onclick="delSeg(${i})"><i class="icons btn-icon"></i></button>
|
||||
<label class="check revchkl">
|
||||
Reverse direction
|
||||
<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev ? "checked":""}>
|
||||
@ -614,6 +613,10 @@ function populateSegments(s)
|
||||
<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi ? "checked":""}>
|
||||
<span class="checkmark schk"></span>
|
||||
</label>
|
||||
<div class="del">
|
||||
<button class="btn btn-i btn-xs" id="segr${i}" title="Repeat until end" onclick="rptSeg(${i})"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-i btn-xs" id="segd${i}" title="Delete" onclick="delSeg(${i})"><i class="icons btn-icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div><br>`;
|
||||
}
|
||||
@ -627,10 +630,13 @@ function populateSegments(s)
|
||||
noNewSegs = false;
|
||||
}
|
||||
for (var i = 0; i <= lSeg; i++) {
|
||||
updateLen(i);
|
||||
updateTrail(d.getElementById(`seg${i}bri`));
|
||||
if (segCount < 2) d.getElementById(`segd${lSeg}`).style.display = "none";
|
||||
updateLen(i);
|
||||
updateTrail(d.getElementById(`seg${i}bri`));
|
||||
let segr = d.getElementById(`segr${i}`);
|
||||
if (segr) segr.style.display = "none";
|
||||
}
|
||||
if (segCount < 2) d.getElementById(`segd${lSeg}`).style.display = "none";
|
||||
if (!noNewSegs && (cfg.comp.seglen?parseInt(d.getElementById(`seg${lSeg}s`).value):0)+parseInt(d.getElementById(`seg${lSeg}e`).value)<ledCount) d.getElementById(`segr${lSeg}`).style.display = "inline";
|
||||
d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none";
|
||||
}
|
||||
|
||||
@ -872,7 +878,7 @@ function updateLen(s)
|
||||
{
|
||||
if (!d.getElementById(`seg${s}s`)) return;
|
||||
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
||||
var stop = parseInt(d.getElementById(`seg${s}e`).value);
|
||||
var stop = parseInt(d.getElementById(`seg${s}e`).value);
|
||||
var len = stop - (cfg.comp.seglen?0:start);
|
||||
var out = "(delete)";
|
||||
if (len > 1) {
|
||||
@ -1491,6 +1497,29 @@ function selSeg(s){
|
||||
requestJson(obj, false);
|
||||
}
|
||||
|
||||
function rptSeg(s)
|
||||
{
|
||||
var name = d.getElementById(`seg${s}t`).value;
|
||||
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
||||
var stop = parseInt(d.getElementById(`seg${s}e`).value);
|
||||
if (stop == 0) {return;}
|
||||
var rev = d.getElementById(`seg${s}rev`).checked;
|
||||
var mi = d.getElementById(`seg${s}mi`).checked;
|
||||
var sel = d.getElementById(`seg${s}sel`).checked;
|
||||
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": !powered[s], "bri": parseInt(d.getElementById(`seg${s}bri`).value), "sel": sel}};
|
||||
if (d.getElementById(`seg${s}grp`)) {
|
||||
var grp = parseInt(d.getElementById(`seg${s}grp`).value);
|
||||
var spc = parseInt(d.getElementById(`seg${s}spc`).value);
|
||||
var ofs = parseInt(d.getElementById(`seg${s}of` ).value);
|
||||
obj.seg.grp = grp;
|
||||
obj.seg.spc = spc;
|
||||
obj.seg.of = ofs;
|
||||
}
|
||||
obj.seg.rpt = true;
|
||||
expand(s);
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setSeg(s){
|
||||
var name = d.getElementById(`seg${s}t`).value;
|
||||
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
||||
@ -1542,6 +1571,13 @@ function setSegBri(s){
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function tglFreeze(s=null)
|
||||
{
|
||||
var obj = {"seg": {"frz": "t"}}; // toggle
|
||||
if (s!==null) obj.id = s;
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setX(ind = null) {
|
||||
if (ind === null) {
|
||||
ind = parseInt(d.querySelector('#fxlist input[name="fx"]:checked').value);
|
||||
|
@ -6,7 +6,7 @@
|
||||
<title>LED Settings</title>
|
||||
<script>
|
||||
var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
|
||||
var customStarts=false,startsDirty=[];
|
||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||
function H()
|
||||
{
|
||||
window.open("https://kno.wled.ge/features/settings/#led-settings");
|
||||
@ -348,6 +348,53 @@ ${i+1}:
|
||||
|
||||
if (!init) UI();
|
||||
}
|
||||
|
||||
function addCOM(start=0,len=1,co=0) {
|
||||
var i = d.getElementsByClassName("com_entry").length;
|
||||
if (i >= 10) return;
|
||||
|
||||
var b = `<div class="com_entry">
|
||||
<hr style="width:260px">
|
||||
${i+1}: Start: <input type="number" name="XS${i}" id="xs${i}" class="l starts" min="0" max="65535" value="${start}" oninput="UI();" required="">
|
||||
Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65535" value="${len}" required="" oninput="UI()">
|
||||
<div style="display:inline">Color Order:
|
||||
<select id="xo${i}" name="XO${i}">
|
||||
<option value="0">GRB</option>
|
||||
<option value="1">RGB</option>
|
||||
<option value="2">BRG</option>
|
||||
<option value="3">RBG</option>
|
||||
<option value="4">BGR</option>
|
||||
<option value="5">GBR</option>
|
||||
</select>
|
||||
</div><br></div>`;
|
||||
gId("com_entries").insertAdjacentHTML("beforeend", b);
|
||||
gId("xo"+i).value = co;
|
||||
btnCOM(i+1);
|
||||
}
|
||||
|
||||
function remCOM() {
|
||||
var entries = d.getElementsByClassName("com_entry");
|
||||
var i = entries.length;
|
||||
if (i === 0) return;
|
||||
entries[i-1].remove();
|
||||
btnCOM(i-1);
|
||||
}
|
||||
|
||||
function resetCOM(_newMaxCOOverrides=undefined) {
|
||||
if (_newMaxCOOverrides) {
|
||||
maxCOOverrides = _newMaxCOOverrides;
|
||||
}
|
||||
for (let e of d.getElementsByClassName("com_entry")) {
|
||||
e.remove();
|
||||
}
|
||||
btnCOM(0);
|
||||
}
|
||||
|
||||
function btnCOM(i) {
|
||||
gId("com_add").style.display = (i<maxCOOverrides) ? "inline":"none";
|
||||
gId("com_rem").style.display = (i>0) ? "inline":"none";
|
||||
}
|
||||
|
||||
function addBtn(i,p,t) {
|
||||
var c = gId("btns").innerHTML;
|
||||
var bt = "BT" + String.fromCharCode((i<10?48:55)+i);;
|
||||
@ -432,6 +479,12 @@ ${i+1}:
|
||||
d.getElementsByName("CV"+i)[0].checked = v.rev;
|
||||
});
|
||||
}
|
||||
if(c.hw.com) {
|
||||
resetCOM();
|
||||
c.hw.com.forEach(e => {
|
||||
addCOM(e.start, e.len, e.order);
|
||||
});
|
||||
}
|
||||
if (c.hw.btn) {
|
||||
var b = c.hw.btn;
|
||||
if (Array.isArray(b.ins)) gId("btns").innerHTML = "";
|
||||
@ -511,6 +564,14 @@ ${i+1}:
|
||||
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>
|
||||
<hr style="width:260px">
|
||||
<div id="color_order_mapping">
|
||||
Color Order Override:
|
||||
<div id="com_entries"></div>
|
||||
<hr style="width:260px">
|
||||
<button type="button" id="com_add" onclick="addCOM();UI()" style="display:none;border-radius:20px;height:36px;">+</button>
|
||||
<button type="button" id="com_rem" onclick="remCOM();UI()" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
|
||||
</div>
|
||||
<hr style="width:260px">
|
||||
<div id="btns"></div>
|
||||
Touch threshold: <input type="number" class="s" min="0" max="100" name="TT" required><br>
|
||||
IR GPIO: <input type="number" min="-1" max="40" name="IR" onchange="UI()" class="xs"><select name="IT" onchange="UI()">
|
||||
@ -572,6 +633,7 @@ ${i+1}:
|
||||
<option value="2">Linear (never wrap)</option>
|
||||
<option value="3">None (not recommended)</option>
|
||||
</select><br>
|
||||
Target refresh rate: <input type="number" class="s" min="1" max="120" name="FR" required> FPS
|
||||
<hr style="width:260px">
|
||||
<div id="cfg">Config template: <input type="file" name="data2" accept=".json"> <input type="button" value="Apply" onclick="loadCfg(d.Sf.data2);"><br></div>
|
||||
<hr>
|
||||
|
@ -85,7 +85,7 @@
|
||||
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||
(c) 2016-2021 Christian Schwinne <br>
|
||||
(c) 2016-2022 Christian Schwinne <br>
|
||||
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
|
||||
Server message: <span class="sip"> Response error! </span><hr>
|
||||
<div id="toast"></div>
|
||||
|
@ -5,7 +5,8 @@ function gId(s)
|
||||
{
|
||||
return d.getElementById(s);
|
||||
}
|
||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}
|
||||
function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; 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;} }
|
||||
function FC()
|
||||
@ -81,7 +82,8 @@ UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required
|
||||
<td><input type="checkbox" id="R8" name="R8"></td>
|
||||
</tr>
|
||||
</table><br>
|
||||
Receive: <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
|
||||
Receive: <input type="checkbox" name="RB"> Brightness, <input type="checkbox" name="RC"> Color, and <input type="checkbox" name="RX"> Effects<br>
|
||||
<input type="checkbox" name="SO"> Segment options<br>
|
||||
Send notifications on direct change: <input type="checkbox" name="SD"><br>
|
||||
Send notifications on button press or IR: <input type="checkbox" name="SB"><br>
|
||||
Send Alexa notifications: <input type="checkbox" name="SA"><br>
|
||||
@ -117,45 +119,45 @@ DMX mode:
|
||||
<option value=5>Dimmer + Multi RGB</option>
|
||||
<option value=6>Multi RGBW</option>
|
||||
</select><br>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank">E1.31 info</a><br>
|
||||
<a href="https://kno.wled.ge/interfaces/e1.31-dmx/" target="_blank">E1.31 info</a><br>
|
||||
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
|
||||
Force max brightness: <input type="checkbox" name="FB"><br>
|
||||
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
||||
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
|
||||
<h3>Alexa Voice Assistant</h3>
|
||||
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||
Alexa invocation name: <input name="AI" maxlength="32">
|
||||
Alexa invocation name: <input type="text" name="AI" maxlength="32">
|
||||
<h3>Blynk</h3>
|
||||
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
|
||||
This may impact the responsiveness of the ESP8266.</b><br>
|
||||
For best results, only use one of these services at a time.<br>
|
||||
(alternatively, connect a second ESP to them and use the UDP sync)<br><br>
|
||||
Host: <input name="BH" maxlength="32">
|
||||
Host: <input type="text" name="BH" maxlength="32">
|
||||
Port: <input name="BP" type="number" min="1" max="65535" value="80" class="d5"><br>
|
||||
Device Auth token: <input name="BK" maxlength="33"><br>
|
||||
<i>Clear the token field to disable. </i><a href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info</a>
|
||||
<i>Clear the token field to disable. </i><a href="https://kno.wled.ge/interfaces/blynk/" target="_blank">Setup info</a>
|
||||
<h3>MQTT</h3>
|
||||
Enable MQTT: <input type="checkbox" name="MQ"><br>
|
||||
Broker: <input name="MS" maxlength="32">
|
||||
Broker: <input type="text" name="MS" maxlength="32">
|
||||
Port: <input name="MQPORT" type="number" min="1" max="65535" class="d5"><br>
|
||||
<b>The MQTT credentials are sent over an unsecured connection.<br>
|
||||
Never use the MQTT password for another service!</b><br>
|
||||
Username: <input name="MQUSER" maxlength="40"><br>
|
||||
Username: <input type="text" name="MQUSER" maxlength="40"><br>
|
||||
Password: <input type="password" name="MQPASS" maxlength="64"><br>
|
||||
Client ID: <input name="MQCID" maxlength="40"><br>
|
||||
Device Topic: <input name="MD" maxlength="32"><br>
|
||||
Group Topic: <input name="MG" maxlength="32"><br>
|
||||
Client ID: <input type="text" name="MQCID" maxlength="40"><br>
|
||||
Device Topic: <input type="text" name="MD" maxlength="32"><br>
|
||||
Group Topic: <input type="text" name="MG" maxlength="32"><br>
|
||||
Publish on button press: <input type="checkbox" name="BM"><br>
|
||||
<i>Reboot required to apply changes. </i><a href="https://github.com/Aircoookie/WLED/wiki/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>
|
||||
<h3>Philips Hue</h3>
|
||||
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
||||
Poll Hue light <input name="HL" type="number" min="1" max="99" > every <input name="HI" type="number" min="100" max="65000"> ms: <input type="checkbox" name="HP"><br>
|
||||
Then, receive <input type="checkbox" name="HO"> On/Off, <input type="checkbox" name="HB"> Brightness, and <input type="checkbox" name="HC"> Color<br>
|
||||
Hue Bridge IP:<br>
|
||||
<input name="H0" type="number" min="0" max="255" > .
|
||||
<input name="H1" type="number" min="0" max="255" > .
|
||||
<input name="H2" type="number" min="0" max="255" > .
|
||||
<input name="H3" type="number" min="0" max="255" ><br>
|
||||
<input name="H0" type="number" class="s" min="0" max="255" > .
|
||||
<input name="H1" type="number" class="s" min="0" max="255" > .
|
||||
<input name="H2" type="number" class="s" min="0" max="255" > .
|
||||
<input name="H3" type="number" class="s" min="0" max="255" ><br>
|
||||
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
|
||||
(when first connecting)<br>
|
||||
Hue status: <span class="sip"> Disabled in this build </span><hr>
|
||||
|
@ -6,9 +6,11 @@
|
||||
<title>Time Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
var cals = 'style="font-size:27px;margin-top:-6px;cursor:pointer"'; //hack as to not repeat CSS on all pages
|
||||
function H()
|
||||
{
|
||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");
|
||||
window.open("https://kno.wled.ge/features/settings/#time-settings");
|
||||
}
|
||||
function B()
|
||||
{
|
||||
@ -22,6 +24,15 @@
|
||||
{
|
||||
return d.getElementById(s);
|
||||
}
|
||||
function gN(s) {
|
||||
return d.getElementsByName(s)[0];
|
||||
}
|
||||
function expand(o,i)
|
||||
{
|
||||
var t = gId("WD"+i);
|
||||
t.style.display = t.style.display!=="none" ? "none" : "";
|
||||
o.innerHTML = t.style.display==="none" ? "🗓" : "✕";
|
||||
}
|
||||
function Cs()
|
||||
{
|
||||
gId("cac").style.display="none";
|
||||
@ -41,56 +52,83 @@
|
||||
gId("coc").style.display="none";
|
||||
}
|
||||
}
|
||||
function BTa()
|
||||
{
|
||||
var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";
|
||||
}
|
||||
ih+="<tr><td><input name=\"W8\" id=\"W8\" type=\"number\" style=\"display:none\"><input id=\"W80\" type=\"checkbox\"></td><td>Sunrise<input name=\"H8\" value=\"255\" type=\"hidden\"></td><td><input name=\"N8\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T8\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W8"+j+"\" type=\"checkbox\"></td>";
|
||||
ih+="<tr><td><input name=\"W9\" id=\"W9\" type=\"number\" style=\"display:none\"><input id=\"W90\" type=\"checkbox\"></td><td>Sunset<input name=\"H9\" value=\"255\" type=\"hidden\"></td><td><input name=\"N9\" type=\"number\" min=\"-59\" max=\"59\"><td><input name=\"T9\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W9"+j+"\" type=\"checkbox\"></td>";
|
||||
gId("TMT").innerHTML=ih;
|
||||
}
|
||||
function FC()
|
||||
{
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
for(i=0;i<10;i++) gId("W"+i+j).checked=gId("W"+i).value>>j&1;
|
||||
}
|
||||
}
|
||||
function Wd()
|
||||
{
|
||||
a=[0,0,0,0,0,0,0,0,0,0];
|
||||
for(i=0;i<10;i++)
|
||||
{
|
||||
m=1;
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a[i]+=gId("W"+i+j).checked*m;m*=2;
|
||||
}
|
||||
gId("W"+i).value=a[i];
|
||||
}
|
||||
if (d.Sf.LTR.value==="S") { d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); }
|
||||
if (d.Sf.LNR.value==="W") { d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); }
|
||||
}
|
||||
function BTa()
|
||||
{
|
||||
var ih="<tr><th>En.</th><th>Hour</th><th>Minute</th><th>Preset</th><th></th></tr>";
|
||||
for (i=0;i<8;i++) {
|
||||
ih+=`<tr><td><input name="W${i}" id="W${i}" type="hidden"><input id="W${i}0" type="checkbox"></td>
|
||||
<td><input name="H${i}" class="xs" type="number" min="0" max="24"></td>
|
||||
<td><input name="N${i}" class="xs" type="number" min="0" max="59"></td>
|
||||
<td><input name="T${i}" class="s" type="number" min="0" max="250"></td>
|
||||
<td><div id="CB${i}" onclick="expand(this,${i})" ${cals}>🗓</div></td></tr>`;
|
||||
ih+=`<tr><td colspan=5><div id="WD${i}" style="display:none;">Run on weekdays`;
|
||||
ih+=`<table style="width:100%%;"><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`
|
||||
for (j=1;j<8;j++) ih+=`<td><input id="W${i}${j}" type="checkbox"></td>`;
|
||||
ih+=`</tr></table>from
|
||||
<select name="M${i}">`;
|
||||
for (j=0;j<12;j++) ih+=`<option value="${j+1}">${ms[j]}</option>`;
|
||||
ih+=`</select><input name="D${i}" class="xs" type="number" min="1" max="31"></input> to
|
||||
<select name="P${i}">`;
|
||||
for (j=0;j<12;j++) ih+=`<option value="${j+1}">${ms[j]}</option>`;
|
||||
ih+=`</select><input name="E${i}" class="xs" type="number" min="1" max="31"></input>
|
||||
<hr></div></td></tr>`;
|
||||
}
|
||||
ih+=`<tr><td><input name="W8" id="W8" type="hidden"><input id="W80" type="checkbox"></td>
|
||||
<td>Sunrise<input name="H8" value="255" type="hidden"></td>
|
||||
<td><input name="N8" class="xs" type="number" min="-59" max="59"></td>
|
||||
<td><input name="T8" class="s" type="number" min="0" max="250"></td>
|
||||
<td><div id="CB8" onclick="expand(this,8)" ${cals}>🗓</div></td></tr><tr><td colspan=5>`;
|
||||
ih+=`<div id="WD8"style="display:none;"><table style="width:100%%;"><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`;
|
||||
for (j=1;j<8;j++) ih+=`<td><input id="W8${j}" type="checkbox"></td>`;
|
||||
ih+="</tr></table><hr></div></td></tr>";
|
||||
ih+=`<tr><td><input name="W9" id="W9" type="hidden"><input id="W90" type="checkbox"></td>
|
||||
<td>Sunset<input name="H9" value="255" type="hidden"></td>
|
||||
<td><input name="N9" class="xs" type="number" min="-59" max="59"></td>
|
||||
<td><input name="T9" class="s" type="number" min="0" max="250"></td>
|
||||
<td><div id="CB9" onclick="expand(this,9)" ${cals}>🗓</div></td></tr><tr><td colspan=5>`;
|
||||
ih+=`<div id="WD9" style="display:none;"><table style="width:100%%;"><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`;
|
||||
for (j=1;j<8;j++) ih+=`<td><input id="W9${j}" type="checkbox"></td>`;
|
||||
ih+="</tr></table><hr></div></td></tr>";
|
||||
gId("TMT").innerHTML=ih;
|
||||
}
|
||||
function FC()
|
||||
{
|
||||
for(i=0;i<10;i++)
|
||||
{
|
||||
let wd = gId("W"+i).value;
|
||||
for(j=0;j<8;j++) {
|
||||
gId("W"+i+j).checked=wd>>j&1;
|
||||
}
|
||||
if ((wd&127) != 127 || (i<8 && (gN("M"+i).value != 1 || gN("D"+i).value != 1 || gN("P"+i).value != 12 || gN("E"+i).value != 31))) {
|
||||
expand(gId("CB"+i),i); //expand macros with custom DOW or date range set
|
||||
}
|
||||
}
|
||||
}
|
||||
function Wd()
|
||||
{
|
||||
a = [0,0,0,0,0,0,0,0,0,0];
|
||||
for (i=0; i<10; i++) {
|
||||
m=1;
|
||||
for(j=0;j<8;j++) { a[i]+=gId(("W"+i)+j).checked*m; m*=2;}
|
||||
gId("W"+i).value=a[i];
|
||||
}
|
||||
if (d.Sf.LTR.value==="S") { d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); }
|
||||
if (d.Sf.LNR.value==="W") { d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); }
|
||||
}
|
||||
function addRow(i,p,l,d) {
|
||||
var t = gId("macros"); // table
|
||||
var rCnt = t.rows.length; // get the number of rows.
|
||||
var tr = t.insertRow(rCnt); // table row.
|
||||
var rCnt = t.rows.length; // get the number of rows.
|
||||
var tr = t.insertRow(rCnt); // table row.
|
||||
var b = String.fromCharCode((i<10?48:55)+i);
|
||||
var td = document.createElement('td'); // TABLE DEFINITION.
|
||||
td = tr.insertCell(0);
|
||||
td.innerHTML = `Button ${i}:`;
|
||||
td = tr.insertCell(1);
|
||||
td.innerHTML = `<input name="MP${b}" type="number" min="0" max="250" value="${p}" required>`;
|
||||
td.innerHTML = `<input name="MP${b}" type="number" class="s" min="0" max="250" value="${p}" required>`;
|
||||
td = tr.insertCell(2);
|
||||
td.innerHTML = `<input name="ML${b}" type="number" min="0" max="250" value="${l}" required>`;
|
||||
td.innerHTML = `<input name="ML${b}" type="number" class="s" min="0" max="250" value="${l}" required>`;
|
||||
td = tr.insertCell(3);
|
||||
td.innerHTML = `<input name="MD${b}" type="number" min="0" max="250" value="${d}" required>`;
|
||||
td.innerHTML = `<input name="MD${b}" type="number" class="s" min="0" max="250" value="${d}" required>`;
|
||||
}
|
||||
function updLoc(i) {
|
||||
if (parseFloat(d.Sf.LT.value)<0) { d.Sf.LTR.value = "S"; d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); } else d.Sf.LTR.value = "N";
|
||||
@ -111,7 +149,7 @@
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>Time setup</h2>
|
||||
Get time from NTP server: <input type="checkbox" name="NT"><br>
|
||||
<input name="NS" maxlength="32"><br>
|
||||
<input type="text" name="NS" maxlength="32"><br>
|
||||
Use 24h format: <input type="checkbox" name="CF"><br>
|
||||
Time zone:
|
||||
<select name="TZ">
|
||||
@ -140,8 +178,8 @@
|
||||
</select><br>
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.<br>
|
||||
Latitude: <select name="LTR"><option value="1">N</option><option value="-1">S</option></select><input name="LT" type="number" min="0" max="66.6" step="0.01"><br>
|
||||
Longitude: <select name="LNR"><option value="1">E</option><option value="-1">W</option></select><input name="LN" type="number" min="0" max="180" step="0.01">
|
||||
Latitude: <select name="LTR"><option value="N">N</option><option value="S">S</option></select><input name="LT" type="number" class="xl" min="0" max="66.6" step="0.01"><br>
|
||||
Longitude: <select name="LNR"><option value="E">E</option><option value="W">W</option></select><input name="LN" type="number" class="xl" min="0" max="180" step="0.01">
|
||||
<div id="sun" class="times"></div>
|
||||
<h3>Clock</h3>
|
||||
Clock Overlay:
|
||||
@ -164,16 +202,16 @@
|
||||
</div>
|
||||
Countdown Mode: <input type="checkbox" name="CE"><br>
|
||||
Countdown Goal:<br>
|
||||
Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
|
||||
Hour: <input name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" type="number" min="0" max="59" required> Second: <input name="CS" type="number" min="0" max="59" required><br>
|
||||
Date: <nowrap>20<input name="CY" class="xs" type="number" min="0" max="99" required>-<input name="CI" class="xs" type="number" min="1" max="12" required>-<input name="CD" class="xs" type="number" min="1" max="31" required></nowrap><br>
|
||||
Time: <nowrap><input name="CH" class="xs" type="number" min="0" max="23" required>:<input name="CM" class="xs" type="number" min="0" max="59" required>:<input name="CS" class="xs" type="number" min="0" max="59" required></nowrap><br>
|
||||
<h3>Macro presets</h3>
|
||||
<b>Macros have moved!</b><br>
|
||||
<i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br>
|
||||
Just enter the preset id below!</i>
|
||||
Just enter the preset ID below!</i>
|
||||
<i>Use 0 for the default action instead of a preset</i><br>
|
||||
Alexa On/Off Preset: <input name="A0" type="number" min="0" max="250" required> <input name="A1" type="number" min="0" max="250" required><br>
|
||||
Countdown-Over Preset: <input name="MC" type="number" min="0" max="250" required><br>
|
||||
Timed-Light-Over Presets: <input name="MN" type="number" min="0" max="250" required><br>
|
||||
Alexa On/Off Preset: <input name="A0" class="m" type="number" min="0" max="250" required> <input name="A1" class="m" type="number" min="0" max="250" required><br>
|
||||
Countdown-Over Preset: <input name="MC" class="m" type="number" min="0" max="250" required><br>
|
||||
Timed-Light-Over Presets: <input name="MN" class="m" type="number" min="0" max="250" required><br>
|
||||
<h3>Button actions</h3>
|
||||
<table style="margin: 0 auto;" id="macros">
|
||||
<thead>
|
||||
@ -187,11 +225,12 @@
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Macros#analog-button" target="_blank">Analog Button setup</a>
|
||||
<a href="https://kno.wled.ge/features/macros/#analog-button" target="_blank">Analog Button setup</a>
|
||||
<h3>Time-controlled presets</h3>
|
||||
<div style="display: inline-block">
|
||||
<table id="TMT">
|
||||
</table></div><hr>
|
||||
<div style="display: inline-block">
|
||||
<table id="TMT" style="min-width:330px;"></table>
|
||||
</div>
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
|
@ -66,7 +66,6 @@ input[type="number"].xs {
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
transform: scale(1.5);
|
||||
margin-right: 10px;
|
||||
}
|
||||
select {
|
||||
background: #333;
|
||||
@ -80,7 +79,6 @@ td {
|
||||
.d5 {
|
||||
width: 4.5em !important;
|
||||
}
|
||||
|
||||
#toast {
|
||||
opacity: 0;
|
||||
background-color: #444;
|
||||
|
@ -15,9 +15,11 @@ void handleAlexa();
|
||||
void onAlexaChange(EspalexaDevice* dev);
|
||||
|
||||
//blynk.cpp
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
void initBlynk(const char* auth, const char* host, uint16_t port);
|
||||
void handleBlynk();
|
||||
void updateBlynk();
|
||||
#endif
|
||||
|
||||
//button.cpp
|
||||
void shortPressAction(uint8_t b=0);
|
||||
@ -56,7 +58,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
//colors.cpp
|
||||
void colorFromUint32(uint32_t in, bool secondary = false);
|
||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||
uint32_t colorFromRgbw(byte* rgbw);
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||
@ -141,7 +143,6 @@ void resetTimebase();
|
||||
void toggleOnOff();
|
||||
void setAllLeds();
|
||||
void setLedsStandard();
|
||||
bool colorChanged();
|
||||
void colorUpdated(int callMode);
|
||||
void updateInterfaces(uint8_t callMode);
|
||||
void handleTransitions();
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 //FS info bare IDF function until FS wrapper is available for ESP32
|
||||
#if WLED_FS != LITTLEFS
|
||||
#if WLED_FS != LITTLEFS && ESP_IDF_VERSION_MAJOR < 4
|
||||
#include "esp_spiffs.h"
|
||||
#endif
|
||||
#endif
|
||||
@ -359,9 +359,9 @@ bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest)
|
||||
|
||||
void updateFSInfo() {
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#if WLED_FS == LITTLEFS
|
||||
fsBytesTotal = LITTLEFS.totalBytes();
|
||||
fsBytesUsed = LITTLEFS.usedBytes();
|
||||
#if WLED_FS == LITTLEFS || ESP_IDF_VERSION_MAJOR >= 4
|
||||
fsBytesTotal = WLED_FS.totalBytes();
|
||||
fsBytesUsed = WLED_FS.usedBytes();
|
||||
#else
|
||||
esp_spiffs_info(nullptr, &fsBytesTotal, &fsBytesUsed);
|
||||
#endif
|
||||
|
File diff suppressed because one or more lines are too long
4370
wled00/html_ui.h
4370
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
203
wled00/json.cpp
203
wled00/json.cpp
@ -8,7 +8,7 @@
|
||||
|
||||
bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255) {
|
||||
if (elem.is<int>()) {
|
||||
if (elem < 0) return false; //ignore e.g. {"ps":-1}
|
||||
if (elem < 0) return false; //ignore e.g. {"ps":-1}
|
||||
*val = elem;
|
||||
return true;
|
||||
} else if (elem.is<const char*>()) {
|
||||
@ -37,6 +37,24 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
}
|
||||
|
||||
//repeat, multiplies segment until all LEDs are used, or max segments reached
|
||||
bool repeat = elem["rpt"] | false;
|
||||
if (repeat && stop>0) {
|
||||
elem.remove("id"); // remove for recursive call
|
||||
elem.remove("rpt"); // remove for recursive call
|
||||
elem.remove("n"); // remove for recursive call
|
||||
uint16_t len = stop - start;
|
||||
for (byte i=id+1; i<strip.getMaxSegments(); i++) {
|
||||
start = start + len;
|
||||
if (start >= strip.getLengthTotal()) break;
|
||||
elem["start"] = start;
|
||||
elem["stop"] = start + len;
|
||||
elem["rev"] = !elem["rev"]; // alternate reverse on even/odd segments
|
||||
deserializeSegment(elem, i, presetId); // recursive call with new id
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (elem["n"]) {
|
||||
// name field exists
|
||||
if (seg.name) { //clear old name
|
||||
@ -64,7 +82,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
uint16_t grp = elem["grp"] | seg.grouping;
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
uint16_t of = seg.offset;
|
||||
uint16_t of = seg.offset;
|
||||
if (!(elem[F("spc")].isNull() && elem["grp"].isNull())) effectChanged = true; //send UDP
|
||||
|
||||
uint16_t len = 1;
|
||||
if (stop > start) len = stop - start;
|
||||
@ -76,7 +95,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
of = offsetAbs;
|
||||
}
|
||||
if (stop > start && of > len -1) of = len -1;
|
||||
strip.setSegment(id, start, stop, grp, spc, of);
|
||||
strip.setSegment(id, start, stop, grp, spc, of);
|
||||
|
||||
byte segbri = 0;
|
||||
if (getVal(elem["bri"], &segbri)) {
|
||||
@ -87,10 +106,13 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
bool on = elem["on"] | seg.getOption(SEG_OPTION_ON);
|
||||
if (elem["on"].is<const char*>() && elem["on"].as<const char*>()[0] == 't') on = !on;
|
||||
seg.setOption(SEG_OPTION_ON, on, id);
|
||||
|
||||
uint8_t cctPrev = seg.cct;
|
||||
bool frz = elem["frz"] | seg.getOption(SEG_OPTION_FREEZE);
|
||||
if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.getOption(SEG_OPTION_FREEZE);
|
||||
seg.setOption(SEG_OPTION_FREEZE, frz, id);
|
||||
|
||||
uint8_t cctPrev = seg.cct;
|
||||
seg.setCCT(elem["cct"] | seg.cct, id);
|
||||
if (seg.cct != cctPrev && id == strip.getMainSegmentId()) effectChanged = true; //send UDP
|
||||
if (seg.cct != cctPrev && id == strip.getMainSegmentId()) effectChanged = true; //send UDP
|
||||
|
||||
JsonArray colarr = elem["col"];
|
||||
if (!colarr.isNull())
|
||||
@ -124,14 +146,11 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
|
||||
if (!colValid) continue;
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
||||
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
||||
} else { //normal case, apply directly to segment
|
||||
seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
|
||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||
}
|
||||
|
||||
uint32_t color = RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||
colorChanged |= (seg.colors[i] != color);
|
||||
seg.setColor(i, color, id);
|
||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,26 +171,21 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
if (id == strip.getMainSegmentId()) {
|
||||
byte effectPrev = effectCurrent;
|
||||
if (getVal(elem["fx"], &effectCurrent, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value)
|
||||
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
effectSpeed = elem[F("sx")] | effectSpeed;
|
||||
effectIntensity = elem[F("ix")] | effectIntensity;
|
||||
getVal(elem["pal"], &effectPalette, 1, strip.getPaletteCount());
|
||||
} else { //permanent
|
||||
byte fx = seg.mode;
|
||||
byte fxPrev = fx;
|
||||
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value)
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId && seg.mode != fxPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
seg.speed = elem[F("sx")] | seg.speed;
|
||||
seg.intensity = elem[F("ix")] | seg.intensity;
|
||||
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
||||
if (!(elem[F("sel")].isNull() && elem["rev"].isNull() && elem["on"].isNull() && elem[F("mi")].isNull())) effectChanged = true; //send UDP
|
||||
|
||||
byte fx = seg.mode;
|
||||
byte fxPrev = fx;
|
||||
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
|
||||
if (!presetId && currentPlaylist>=0) unloadPlaylist();
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId && seg.mode != fxPrev) effectChanged = true; //send UDP
|
||||
}
|
||||
byte prevSpd = seg.speed;
|
||||
byte prevInt = seg.intensity;
|
||||
byte prevPal = seg.palette;
|
||||
if (getVal(elem[F("sx")], &seg.speed, 0, 255) && !presetId && prevSpd != seg.speed) effectChanged = true; //also supports inc/decrementing and random
|
||||
if (getVal(elem[F("ix")], &seg.intensity, 0, 255) && !presetId && prevInt != seg.intensity) effectChanged = true; //also supports inc/decrementing and random
|
||||
if (getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount()) && !presetId && prevPal != seg.palette) effectChanged = true; //also supports inc/decrementing and random
|
||||
|
||||
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
||||
if (!iarr.isNull()) {
|
||||
@ -223,12 +237,13 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
strip.setPixelSegment(255);
|
||||
strip.trigger();
|
||||
} else { //return to regular effect
|
||||
} else if (!elem["frz"] && iarr.isNull()) { //return to regular effect
|
||||
seg.setOption(SEG_OPTION_FREEZE, false);
|
||||
}
|
||||
return; // seg.differs(prev);
|
||||
}
|
||||
|
||||
// deserializes WLED state (fileDoc points to doc object if called from web server)
|
||||
bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
{
|
||||
strip.applyToAllSelected = false;
|
||||
@ -264,16 +279,16 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
tr = root[F("tb")] | -1;
|
||||
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
||||
|
||||
JsonObject nl = root["nl"];
|
||||
JsonObject nl = root["nl"];
|
||||
nightlightActive = nl["on"] | nightlightActive;
|
||||
nightlightDelayMins = nl[F("dur")] | nightlightDelayMins;
|
||||
nightlightMode = nl[F("mode")] | nightlightMode;
|
||||
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
|
||||
|
||||
JsonObject udpn = root["udpn"];
|
||||
JsonObject udpn = root["udpn"];
|
||||
notifyDirect = udpn["send"] | notifyDirect;
|
||||
receiveNotifications = udpn["recv"] | receiveNotifications;
|
||||
bool noNotification = udpn[F("nn")]; //send no notification just for this request
|
||||
if ((bool)udpn[F("nn")]) callMode = CALL_MODE_NO_NOTIFY; //send no notification just for this request
|
||||
|
||||
unsigned long timein = root[F("time")] | UINT32_MAX; //backup time source if NTP not synced
|
||||
if (timein != UINT32_MAX) {
|
||||
@ -294,22 +309,21 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
strip.mainSegment = root[F("mainseg")] | prevMain;
|
||||
if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||
//if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||
|
||||
int it = 0;
|
||||
JsonVariant segVar = root["seg"];
|
||||
if (segVar.is<JsonObject>())
|
||||
{
|
||||
int id = segVar["id"] | -1;
|
||||
|
||||
if (id < 0) { //set all selected segments
|
||||
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
|
||||
if (id < 0) {
|
||||
//apply all selected segments
|
||||
bool didSet = false;
|
||||
byte lowestActive = 99;
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive()) {
|
||||
if (lowestActive == 99) lowestActive = s;
|
||||
if (sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
@ -317,9 +331,10 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: not sure if it is good idea to change first active but unselected segment
|
||||
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId);
|
||||
} else { //set only the segment with the specified ID
|
||||
deserializeSegment(segVar, it, presetId);
|
||||
} else {
|
||||
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
|
||||
}
|
||||
} else {
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
@ -329,6 +344,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
it++;
|
||||
}
|
||||
}
|
||||
setValuesFromMainSeg(); //to make transition work on main segment
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
if (root["nx"].is<const char*>()) {
|
||||
@ -369,63 +385,65 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
JsonObject playlist = root[F("playlist")];
|
||||
if (!playlist.isNull() && loadPlaylist(playlist, presetId)) {
|
||||
//do not notify here, because the first playlist entry will do
|
||||
noNotification = true;
|
||||
if (root["on"].isNull()) callMode = CALL_MODE_NO_NOTIFY;
|
||||
else callMode = CALL_MODE_DIRECT_CHANGE; // possible bugfix for playlist only containing HTTP API preset FX=~
|
||||
} else {
|
||||
interfaceUpdateCallMode = CALL_MODE_WS_SEND;
|
||||
}
|
||||
|
||||
colorUpdated(noNotification ? CALL_MODE_NO_NOTIFY : callMode);
|
||||
colorUpdated(callMode);
|
||||
|
||||
return stateResponse;
|
||||
}
|
||||
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||
{
|
||||
root["id"] = id;
|
||||
root["id"] = id;
|
||||
if (segmentBounds) {
|
||||
root["start"] = seg.start;
|
||||
root["stop"] = seg.stop;
|
||||
}
|
||||
if (!forPreset) root[F("len")] = seg.stop - seg.start;
|
||||
if (!forPreset) root[F("len")] = seg.stop - seg.start;
|
||||
root["grp"] = seg.grouping;
|
||||
root[F("spc")] = seg.spacing;
|
||||
root[F("of")] = seg.offset;
|
||||
root["on"] = seg.getOption(SEG_OPTION_ON);
|
||||
root["frz"] = seg.getOption(SEG_OPTION_FREEZE);
|
||||
byte segbri = seg.opacity;
|
||||
root["bri"] = (segbri) ? segbri : 255;
|
||||
root["cct"] = seg.cct;
|
||||
|
||||
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
||||
|
||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
// to conserve RAM we will serialize the col array manually
|
||||
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
|
||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||
const char *format = strip.isRgbw ? PSTR("[%u,%u,%u,%u]") : PSTR("[%u,%u,%u]");
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
byte segcol[4]; byte* c = segcol;
|
||||
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
c = (i == 0)? col:colSec;
|
||||
} else {
|
||||
segcol[0] = (byte)(seg.colors[i] >> 16); segcol[1] = (byte)(seg.colors[i] >> 8);
|
||||
segcol[2] = (byte)(seg.colors[i]); segcol[3] = (byte)(seg.colors[i] >> 24);
|
||||
segcol[0] = R(seg.colors[i]);
|
||||
segcol[1] = G(seg.colors[i]);
|
||||
segcol[2] = B(seg.colors[i]);
|
||||
segcol[3] = W(seg.colors[i]);
|
||||
}
|
||||
|
||||
char tmpcol[22];
|
||||
if (strip.isRgbw) sprintf_P(tmpcol, PSTR("[%u,%u,%u,%u]"), c[0], c[1], c[2], c[3]);
|
||||
else sprintf_P(tmpcol, PSTR("[%u,%u,%u]"), c[0], c[1], c[2]);
|
||||
|
||||
strcat(colstr, i<2 ? strcat(tmpcol,",") : tmpcol);
|
||||
}
|
||||
strcat(colstr,"]");
|
||||
sprintf_P(tmpcol, format, (unsigned)c[0], (unsigned)c[1], (unsigned)c[2], (unsigned)c[3]);
|
||||
strcat(colstr, i<2 ? strcat_P(tmpcol, PSTR(",")) : tmpcol);
|
||||
}
|
||||
strcat_P(colstr, PSTR("]"));
|
||||
root["col"] = serialized(colstr);
|
||||
|
||||
root["fx"] = seg.mode;
|
||||
root[F("sx")] = seg.speed;
|
||||
root[F("ix")] = seg.intensity;
|
||||
root["pal"] = seg.palette;
|
||||
root[F("sel")] = seg.isSelected();
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
root["fx"] = seg.mode;
|
||||
root[F("sx")] = seg.speed;
|
||||
root[F("ix")] = seg.intensity;
|
||||
root["pal"] = seg.palette;
|
||||
root[F("sel")] = seg.isSelected();
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR);
|
||||
}
|
||||
|
||||
@ -438,7 +456,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
}
|
||||
|
||||
if (!forPreset) {
|
||||
if (errorFlag) root[F("error")] = errorFlag;
|
||||
if (errorFlag) {root[F("error")] = errorFlag; errorFlag = ERR_NONE;} //prevent error message to persist on screen
|
||||
|
||||
root["ps"] = (currentPreset > 0) ? currentPreset : -1;
|
||||
root[F("pl")] = currentPlaylist;
|
||||
@ -466,11 +484,9 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
root[F("mainseg")] = strip.getMainSegmentId();
|
||||
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive()) {
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
serializeSegment(seg0, sg, s, forPreset, segmentBounds);
|
||||
} else if (forPreset && segmentBounds) { //disable segments not part of preset
|
||||
@ -511,15 +527,15 @@ void serializeInfo(JsonObject root)
|
||||
leds[F("rgbw")] = strip.isRgbw;
|
||||
leds[F("wv")] = false;
|
||||
leds["cct"] = correctWB || strip.hasCCTBus();
|
||||
switch (Bus::getAutoWhiteMode()) {
|
||||
case RGBW_MODE_MANUAL_ONLY:
|
||||
case RGBW_MODE_DUAL:
|
||||
if (strip.isRgbw) leds[F("wv")] = true;
|
||||
break;
|
||||
}
|
||||
switch (Bus::getAutoWhiteMode()) {
|
||||
case RGBW_MODE_MANUAL_ONLY:
|
||||
case RGBW_MODE_DUAL:
|
||||
if (strip.isRgbw) leds[F("wv")] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds[F("fps")] = strip.getFps();
|
||||
leds["fps"] = strip.getFps();
|
||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
leds[F("maxseg")] = strip.getMaxSegments();
|
||||
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
|
||||
@ -596,9 +612,11 @@ void serializeInfo(JsonObject root)
|
||||
#endif
|
||||
|
||||
root[F("freeheap")] = ESP.getFreeHeap();
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||
#endif
|
||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
|
||||
usermods.addToJsonInfo(root);
|
||||
|
||||
byte os = 0;
|
||||
@ -645,7 +663,7 @@ void setPaletteColors(JsonArray json, CRGBPalette16 palette)
|
||||
for (int i = 0; i < 16; i++) {
|
||||
JsonArray colors = json.createNestedArray();
|
||||
CRGB color = palette[i];
|
||||
colors.add((((float)i / (float)16) * 255));
|
||||
colors.add(i<<4);
|
||||
colors.add(color.red);
|
||||
colors.add(color.green);
|
||||
colors.add(color.blue);
|
||||
@ -707,9 +725,6 @@ void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
JsonArray curPalette = palettes.createNestedArray(String(i));
|
||||
CRGB prim;
|
||||
CRGB sec;
|
||||
CRGB ter;
|
||||
switch (i) {
|
||||
case 0: //default palette
|
||||
setPaletteColors(curPalette, PartyColors_p);
|
||||
@ -877,13 +892,13 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
{
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
AsyncWebSocketClient * wsc = nullptr;
|
||||
if (!request) { //not HTTP, use Websockets
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
wsc = ws.client(wsClient);
|
||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t used = strip.getLengthTotal();
|
||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||
@ -894,7 +909,11 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
|
||||
for (uint16_t i= 0; i < used; i += n)
|
||||
{
|
||||
olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i) & 0xFFFFFF);
|
||||
uint32_t c = strip.getPixelColor(i);
|
||||
uint8_t r = qadd8(W(c), R(c)); //add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
uint8_t g = qadd8(W(c), G(c));
|
||||
uint8_t b = qadd8(W(c), B(c));
|
||||
olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0));
|
||||
}
|
||||
olen -= 1;
|
||||
oappend((const char*)F("],\"n\":"));
|
||||
|
101
wled00/led.cpp
101
wled00/led.cpp
@ -44,8 +44,8 @@ byte scaledBri(byte in)
|
||||
|
||||
|
||||
void setAllLeds() {
|
||||
strip.setColor(0, col[0], col[1], col[2], col[3]);
|
||||
strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
strip.setColor(0, RGBW32(col[0], col[1], col[2], col[3]));
|
||||
strip.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]));
|
||||
if (!realtimeMode || !arlsForceMaxBri)
|
||||
{
|
||||
strip.setBrightness(scaledBri(briT));
|
||||
@ -61,106 +61,67 @@ void setLedsStandard()
|
||||
}
|
||||
|
||||
|
||||
bool colorChanged()
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
if (col[i] != colIT[i]) return true;
|
||||
if (colSec[i] != colSecIT[i]) return true;
|
||||
}
|
||||
if (bri != briIT) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void colorUpdated(int callMode)
|
||||
{
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa 11: ws send only 12: button preset
|
||||
if (callMode != CALL_MODE_INIT &&
|
||||
callMode != CALL_MODE_DIRECT_CHANGE &&
|
||||
callMode != CALL_MODE_NO_NOTIFY &&
|
||||
callMode != CALL_MODE_BUTTON_PRESET) strip.applyToAllSelected = true; //if not from JSON api, which directly sets segments
|
||||
|
||||
bool someSel = false;
|
||||
|
||||
if (callMode == CALL_MODE_NOTIFICATION) {
|
||||
someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
}
|
||||
|
||||
//Notifier: apply received FX to selected segments only if actually receiving FX
|
||||
if (someSel) strip.applyToAllSelected = receiveNotificationEffects;
|
||||
|
||||
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette) || effectChanged;
|
||||
bool colChanged = colorChanged();
|
||||
|
||||
//Notifier: apply received color to selected segments only if actually receiving color
|
||||
if (someSel) strip.applyToAllSelected = receiveNotificationColor;
|
||||
|
||||
if (fxChanged || colChanged)
|
||||
{
|
||||
effectChanged = false;
|
||||
if (bri != briOld || effectChanged || colorChanged) {
|
||||
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
|
||||
currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
if (effectChanged) currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
|
||||
notify(callMode);
|
||||
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
|
||||
|
||||
//set flag to update blynk, ws and mqtt
|
||||
interfaceUpdateCallMode = callMode;
|
||||
effectChanged = false;
|
||||
colorChanged = false;
|
||||
} else {
|
||||
if (nightlightActive && !nightlightActiveOld &&
|
||||
callMode != CALL_MODE_NOTIFICATION &&
|
||||
callMode != CALL_MODE_NO_NOTIFY)
|
||||
{
|
||||
if (nightlightActive && !nightlightActiveOld && callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) {
|
||||
notify(CALL_MODE_NIGHTLIGHT);
|
||||
interfaceUpdateCallMode = CALL_MODE_NIGHTLIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colChanged) return; //following code is for e.g. initiating transitions
|
||||
|
||||
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE))
|
||||
{
|
||||
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE)) {
|
||||
briNlT = bri;
|
||||
nightlightDelayMs -= (millis() - nightlightStartTime);
|
||||
nightlightStartTime = millis();
|
||||
}
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
colIT[i] = col[i];
|
||||
colSecIT[i] = colSec[i];
|
||||
}
|
||||
if (briT == 0)
|
||||
{
|
||||
if (briT == 0) {
|
||||
if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
|
||||
}
|
||||
|
||||
briIT = bri;
|
||||
if (bri > 0) briLast = bri;
|
||||
|
||||
//deactivate nightlight if target brightness is reached
|
||||
if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
|
||||
|
||||
if (fadeTransition)
|
||||
{
|
||||
if (fadeTransition) {
|
||||
//set correct delay if not using notification delay
|
||||
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
|
||||
jsonTransitionOnce = false;
|
||||
strip.setTransition(transitionDelayTemp);
|
||||
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
|
||||
|
||||
if (transitionActive)
|
||||
{
|
||||
if (transitionDelayTemp == 0) {
|
||||
//setLedsStandard();
|
||||
briOld = briT = bri;
|
||||
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||
strip.trigger();
|
||||
return;
|
||||
}
|
||||
|
||||
if (transitionActive) {
|
||||
briOld = briT;
|
||||
tperLast = 0;
|
||||
}
|
||||
strip.setTransitionMode(true);
|
||||
transitionActive = true;
|
||||
transitionStartTime = millis();
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
strip.setTransition(0);
|
||||
setLedsStandard();
|
||||
//setLedsStandard();
|
||||
briOld = briT = bri;
|
||||
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||
strip.trigger();
|
||||
}
|
||||
}
|
||||
@ -169,10 +130,8 @@ void colorUpdated(int callMode)
|
||||
void updateInterfaces(uint8_t callMode)
|
||||
{
|
||||
sendDataWs();
|
||||
if (callMode == CALL_MODE_WS_SEND) {
|
||||
lastInterfaceUpdate = millis();
|
||||
return;
|
||||
}
|
||||
lastInterfaceUpdate = millis();
|
||||
if (callMode == CALL_MODE_WS_SEND) return;
|
||||
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (espalexaDevice != nullptr && callMode != CALL_MODE_ALEXA) {
|
||||
@ -185,7 +144,6 @@ void updateInterfaces(uint8_t callMode)
|
||||
callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
|
||||
#endif
|
||||
doPublishMqtt = true;
|
||||
lastInterfaceUpdate = millis();
|
||||
}
|
||||
|
||||
|
||||
@ -221,6 +179,13 @@ void handleTransitions()
|
||||
|
||||
void handleNightlight()
|
||||
{
|
||||
/*
|
||||
static unsigned long lastNlUpdate;
|
||||
unsigned long now = millis();
|
||||
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; //take care of millis() rollover
|
||||
if (now - lastNlUpdate < 100) return; //allow only 10 NL updates per second
|
||||
lastNlUpdate = now;
|
||||
*/
|
||||
if (nightlightActive)
|
||||
{
|
||||
if (!nightlightActiveOld) //init
|
||||
|
@ -318,6 +318,32 @@ byte weekdayMondayFirst()
|
||||
return wd;
|
||||
}
|
||||
|
||||
bool isTodayInDateRange(byte monthStart, byte dayStart, byte monthEnd, byte dayEnd)
|
||||
{
|
||||
if (monthStart == 0 || dayStart == 0) return true;
|
||||
if (monthEnd == 0) monthEnd = monthStart;
|
||||
if (dayEnd == 0) dayEnd = 31;
|
||||
byte d = day(localTime);
|
||||
byte m = month(localTime);
|
||||
|
||||
if (monthStart < monthEnd) {
|
||||
if (m > monthStart && m < monthEnd) return true;
|
||||
if (m == monthStart) return (d >= dayStart);
|
||||
if (m == monthEnd) return (d <= dayEnd);
|
||||
return false;
|
||||
}
|
||||
if (monthEnd < monthStart) { //range spans change of year
|
||||
if (m > monthStart || m < monthEnd) return true;
|
||||
if (m == monthStart) return (d >= dayStart);
|
||||
if (m == monthEnd) return (d <= dayEnd);
|
||||
return false;
|
||||
}
|
||||
|
||||
//start month and end month are the same
|
||||
if (dayEnd < dayStart) return (m != monthStart || (d <= dayEnd || d >= dayStart)); //all year, except the designated days in this month
|
||||
return (m == monthStart && d >= dayStart && d <= dayEnd); //just the designated days this month
|
||||
}
|
||||
|
||||
void checkTimers()
|
||||
{
|
||||
if (lastTimerMinute != minute(localTime)) //only check once a new minute begins
|
||||
@ -331,10 +357,12 @@ void checkTimers()
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (timerMacro[i] != 0
|
||||
&& (timerWeekday[i] & 0x01) //timer is enabled
|
||||
&& (timerHours[i] == hour(localTime) || timerHours[i] == 24) //if hour is set to 24, activate every hour
|
||||
&& timerMinutes[i] == minute(localTime)
|
||||
&& (timerWeekday[i] & 0x01) //timer is enabled
|
||||
&& ((timerWeekday[i] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
|
||||
&& ((timerWeekday[i] >> weekdayMondayFirst()) & 0x01) //timer should activate at current day of week
|
||||
&& isTodayInDateRange(((timerMonth[i] >> 4) & 0x0F), timerDay[i], timerMonth[i] & 0x0F, timerDayEnd[i])
|
||||
)
|
||||
{
|
||||
unloadPlaylist();
|
||||
applyPreset(timerMacro[i]);
|
||||
|
@ -107,7 +107,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
|
||||
|
||||
playlistRepeat = rep;
|
||||
if (playlistRepeat > 0) playlistRepeat++; //add one extra repetition immediately since it will be deducted on first start
|
||||
playlistEndPreset = playlistObj[F("end")] | 0;
|
||||
playlistEndPreset = playlistObj["end"] | 0;
|
||||
shuffle = shuffle || playlistObj["r"];
|
||||
if (shuffle) playlistOptions += PL_OPTION_SHUFFLE;
|
||||
|
||||
|
171
wled00/set.cpp
171
wled00/set.cpp
@ -100,6 +100,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
strip.cctBlending = request->arg(F("CB")).toInt();
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
Bus::setAutoWhiteMode(request->arg(F("AW")).toInt());
|
||||
strip.setTargetFps(request->arg(F("FR")).toInt());
|
||||
|
||||
for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) {
|
||||
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||
@ -135,6 +136,20 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
doInitBusses = true;
|
||||
}
|
||||
|
||||
ColorOrderMap com = {};
|
||||
for (uint8_t s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) {
|
||||
char xs[4] = "XS"; xs[2] = 48+s; xs[3] = 0; //start LED
|
||||
char xc[4] = "XC"; xc[2] = 48+s; xc[3] = 0; //strip length
|
||||
char xo[4] = "XO"; xo[2] = 48+s; xo[3] = 0; //color order
|
||||
if (request->hasArg(xs)) {
|
||||
start = request->arg(xs).toInt();
|
||||
length = request->arg(xc).toInt();
|
||||
colorOrder = request->arg(xo).toInt();
|
||||
com.add(start, length, colorOrder);
|
||||
}
|
||||
}
|
||||
busses.updateColorOrderMap(com);
|
||||
|
||||
// upate other pins
|
||||
int hw_ir_pin = request->arg(F("IR")).toInt();
|
||||
if (pinManager.allocatePin(hw_ir_pin,false, PinOwner::IR)) {
|
||||
@ -217,7 +232,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
receiveNotificationBrightness = request->hasArg(F("RB"));
|
||||
receiveNotificationColor = request->hasArg(F("RC"));
|
||||
receiveNotificationEffects = request->hasArg(F("RX"));
|
||||
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
receiveSegmentOptions = request->hasArg(F("SO"));
|
||||
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
|
||||
notifyDirectDefault = request->hasArg(F("SD"));
|
||||
notifyDirect = notifyDirectDefault;
|
||||
notifyButton = request->hasArg(F("SB"));
|
||||
@ -306,6 +322,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
//start ntp if not already connected
|
||||
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
|
||||
ntpLastSyncTime = 0; // force new NTP query
|
||||
|
||||
longitude = request->arg(F("LN")).toFloat();
|
||||
latitude = request->arg(F("LT")).toFloat();
|
||||
@ -351,21 +368,27 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
char k[3]; k[2] = 0;
|
||||
for (int i = 0; i<10; i++)
|
||||
{
|
||||
k[1] = i+48;//ascii 0,1,2,3
|
||||
|
||||
for (int i = 0; i<10; i++) {
|
||||
k[1] = i+48;//ascii 0,1,2,3,...
|
||||
k[0] = 'H'; //timer hours
|
||||
timerHours[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'N'; //minutes
|
||||
timerMinutes[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'T'; //macros
|
||||
timerMacro[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'W'; //weekdays
|
||||
timerWeekday[i] = request->arg(k).toInt();
|
||||
if (i<8) {
|
||||
k[0] = 'M'; //start month
|
||||
timerMonth[i] = request->arg(k).toInt() & 0x0F;
|
||||
timerMonth[i] <<= 4;
|
||||
k[0] = 'P'; //end month
|
||||
timerMonth[i] += (request->arg(k).toInt() & 0x0F);
|
||||
k[0] = 'D'; //start day
|
||||
timerDay[i] = request->arg(k).toInt();
|
||||
k[0] = 'E'; //end day
|
||||
timerDayEnd[i] = request->arg(k).toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,7 +608,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
DEBUG_PRINT(F("API req: "));
|
||||
DEBUG_PRINTLN(req);
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
strip.applyToAllSelected = true;
|
||||
|
||||
//segment select (sets main segment)
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
@ -596,22 +619,28 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
byte selectedSeg = strip.getMainSegmentId();
|
||||
if (selectedSeg != prevMain) setValuesFromMainSeg();
|
||||
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
pos = req.indexOf(F("SS="));
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t < strip.getMaxSegments()) selectedSeg = t;
|
||||
if (t < strip.getMaxSegments()) {
|
||||
selectedSeg = t;
|
||||
strip.applyToAllSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
|
||||
pos = req.indexOf(F("SV=")); //segment selected
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t == 2) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
||||
{
|
||||
strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0);
|
||||
}
|
||||
}
|
||||
if (t == 2) for (uint8_t i = 0; i < strip.getMaxSegments(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
|
||||
selseg.setOption(SEG_OPTION_SELECTED, t);
|
||||
}
|
||||
|
||||
@ -677,26 +706,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
applyPreset(presetCycCurr);
|
||||
}
|
||||
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
//set brightness
|
||||
updateVal(&req, "&A=", &bri);
|
||||
|
||||
bool col0Changed = false, col1Changed = false, col2Changed = false;
|
||||
//set colors
|
||||
updateVal(&req, "&R=", &col[0]);
|
||||
updateVal(&req, "&G=", &col[1]);
|
||||
updateVal(&req, "&B=", &col[2]);
|
||||
updateVal(&req, "&W=", &col[3]);
|
||||
for (byte i=0; i<4; i++) if (prevCol[i]!=col[i]) col0Changed = colorChanged = true;
|
||||
updateVal(&req, "R2=", &colSec[0]);
|
||||
updateVal(&req, "G2=", &colSec[1]);
|
||||
updateVal(&req, "B2=", &colSec[2]);
|
||||
updateVal(&req, "W2=", &colSec[3]);
|
||||
for (byte i=0; i<4; i++) if (prevColSec[i]!=colSec[i]) col1Changed = colorChanged = true;
|
||||
|
||||
#ifdef WLED_ENABLE_LOXONE
|
||||
//lox parser
|
||||
@ -727,52 +751,64 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
tempsat = getNumVal(&req, pos);
|
||||
}
|
||||
colorHStoRGB(temphue,tempsat,(req.indexOf(F("H2"))>0)? colSec:col);
|
||||
byte sec = req.indexOf(F("H2"));
|
||||
colorHStoRGB(temphue, tempsat, (sec>0) ? colSec : col);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//set white spectrum (kelvin)
|
||||
pos = req.indexOf(F("&K="));
|
||||
if (pos > 0) {
|
||||
colorKtoRGB(getNumVal(&req, pos),(req.indexOf(F("K2"))>0)? colSec:col);
|
||||
byte sec = req.indexOf(F("K2"));
|
||||
colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colSec : col);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//set color from HEX or 32bit DEC
|
||||
byte tmpCol[4];
|
||||
pos = req.indexOf(F("CL="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str());
|
||||
selseg.setColor(0, RGBW32(col[0], col[1], col[2], col[3]), selectedSeg); // defined above (SS= or main)
|
||||
col0Changed = colorChanged = true;
|
||||
}
|
||||
pos = req.indexOf(F("C2="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
|
||||
selseg.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]), selectedSeg); // defined above (SS= or main)
|
||||
col1Changed = colorChanged = true;
|
||||
}
|
||||
pos = req.indexOf(F("C3="));
|
||||
if (pos > 0) {
|
||||
byte t[4];
|
||||
colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str());
|
||||
if (selectedSeg != strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
||||
} else {
|
||||
selseg.setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg); // defined above (SS=)
|
||||
}
|
||||
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
||||
selseg.setColor(2, RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]), selectedSeg); // defined above (SS= or main)
|
||||
col2Changed = colorChanged = true;
|
||||
}
|
||||
|
||||
//set to random hue SR=0->1st SR=1->2nd
|
||||
pos = req.indexOf(F("SR"));
|
||||
if (pos > 0) {
|
||||
_setRandomColor(getNumVal(&req, pos));
|
||||
byte sec = getNumVal(&req, pos);
|
||||
_setRandomColor(sec);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//swap 2nd & 1st
|
||||
pos = req.indexOf(F("SC"));
|
||||
if (pos > 0) {
|
||||
byte temp;
|
||||
for (uint8_t i=0; i<4; i++)
|
||||
{
|
||||
temp = col[i];
|
||||
col[i] = colSec[i];
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
temp = col[i];
|
||||
col[i] = colSec[i];
|
||||
colSec[i] = temp;
|
||||
}
|
||||
col0Changed = col1Changed = colorChanged = true;
|
||||
}
|
||||
|
||||
//set effect parameters
|
||||
@ -780,6 +816,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
updateVal(&req, "SX=", &effectSpeed);
|
||||
updateVal(&req, "IX=", &effectIntensity);
|
||||
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1);
|
||||
strip.setMode(selectedSeg, effectCurrent);
|
||||
selseg.speed = effectSpeed;
|
||||
selseg.intensity = effectIntensity;
|
||||
selseg.palette = effectPalette;
|
||||
if (effectCurrent != prevEffect || effectSpeed != prevSpeed || effectIntensity != prevIntensity || effectPalette != prevPalette) effectChanged = true;
|
||||
|
||||
//set advanced overlay
|
||||
pos = req.indexOf(F("OL="));
|
||||
@ -910,45 +951,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
//you can add more if you need
|
||||
|
||||
//apply to all selected manually to prevent #1618. Temporary
|
||||
bool col0Changed = false, col1Changed = false;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (col[i] != prevCol[i]) col0Changed = true;
|
||||
if (colSec[i] != prevColSec[i]) col1Changed = true;
|
||||
}
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isSelected()) continue;
|
||||
if (effectCurrent != prevEffect) {
|
||||
strip.setMode(i, effectCurrent);
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectSpeed != prevSpeed) {
|
||||
seg.speed = effectSpeed;
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectIntensity != prevIntensity) {
|
||||
seg.intensity = effectIntensity;
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectPalette != prevPalette) {
|
||||
seg.palette = effectPalette;
|
||||
effectChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (col0Changed) {
|
||||
if (selectedSeg == strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(0, colorFromRgbw(col));
|
||||
}
|
||||
}
|
||||
if (col1Changed) {
|
||||
if (selectedSeg == strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(1, colorFromRgbw(colSec));
|
||||
if (strip.applyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected() || i == selectedSeg) continue;
|
||||
if (effectCurrent != prevEffect) strip.setMode(i, effectCurrent);
|
||||
if (effectSpeed != prevSpeed) seg.speed = effectSpeed;
|
||||
if (effectIntensity != prevIntensity) seg.intensity = effectIntensity;
|
||||
if (effectPalette != prevPalette) seg.palette = effectPalette;
|
||||
if (col0Changed) seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
if (col1Changed) seg.colors[1] = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
if (col2Changed) seg.colors[2] = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||
}
|
||||
}
|
||||
strip.applyToAllSelected = false;
|
||||
setValuesFromMainSeg();
|
||||
//end of temporary fix code
|
||||
|
||||
if (!apply) return true; //when called by JSON API, do not call colorUpdated() here
|
||||
@ -957,8 +974,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("IN"));
|
||||
if (pos < 1) XML_response(request);
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
|
||||
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
|
||||
colorUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
|
||||
|
||||
|
139
wled00/udp.cpp
139
wled00/udp.cpp
@ -4,7 +4,9 @@
|
||||
* UDP sync notifier / Realtime / Hyperion / TPM2.NET
|
||||
*/
|
||||
|
||||
#define WLEDPACKETSIZE 39
|
||||
#define UDP_SEG_SIZE 28
|
||||
#define SEG_OFFSET (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE))
|
||||
#define WLEDPACKETSIZE (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE)+0)
|
||||
#define UDP_IN_MAXSIZE 1472
|
||||
#define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times
|
||||
|
||||
@ -17,7 +19,7 @@ void notify(byte callMode, bool followUp)
|
||||
case CALL_MODE_INIT: return;
|
||||
case CALL_MODE_DIRECT_CHANGE: if (!notifyDirect) return; break;
|
||||
case CALL_MODE_BUTTON: if (!notifyButton) return; break;
|
||||
case CALL_MODE_BUTTON_PRESET: if (!notifyButton) return; break;
|
||||
case CALL_MODE_BUTTON_PRESET: if (!notifyButton) return; break;
|
||||
case CALL_MODE_NIGHTLIGHT: if (!notifyDirect) return; break;
|
||||
case CALL_MODE_HUE: if (!notifyHue) return; break;
|
||||
case CALL_MODE_PRESET_CYCLE: if (!notifyDirect) return; break;
|
||||
@ -26,7 +28,7 @@ void notify(byte callMode, bool followUp)
|
||||
default: return;
|
||||
}
|
||||
byte udpOut[WLEDPACKETSIZE];
|
||||
WS2812FX::Segment& mainseg = strip.getSegment(strip.getMainSegmentId());
|
||||
WS2812FX::Segment& mainseg = strip.getSegment(strip.getMainSegmentId());
|
||||
udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol
|
||||
udpOut[1] = callMode;
|
||||
udpOut[2] = bri;
|
||||
@ -42,8 +44,8 @@ void notify(byte callMode, bool followUp)
|
||||
//0: old 1: supports white 2: supports secondary color
|
||||
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
|
||||
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet
|
||||
//9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet
|
||||
udpOut[11] = 10;
|
||||
//9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+MAX_NUM_SEGMENTS*3)
|
||||
udpOut[11] = 11;
|
||||
udpOut[12] = colSec[0];
|
||||
udpOut[13] = colSec[1];
|
||||
udpOut[14] = colSec[2];
|
||||
@ -79,12 +81,50 @@ void notify(byte callMode, bool followUp)
|
||||
|
||||
//sync groups
|
||||
udpOut[36] = syncGroups;
|
||||
|
||||
//Might be changed to Kelvin in the future, receiver code should handle that case
|
||||
//0: byte 38 contains 0-255 value, 255: no valid CCT, 1-254: Kelvin value MSB
|
||||
udpOut[37] = strip.hasCCTBus() ? 0 : 255; //check this is 0 for the next value to be significant
|
||||
udpOut[38] = mainseg.cct;
|
||||
|
||||
|
||||
//Might be changed to Kelvin in the future, receiver code should handle that case
|
||||
//0: byte 38 contains 0-255 value, 255: no valid CCT, 1-254: Kelvin value MSB
|
||||
udpOut[37] = strip.hasCCTBus() ? 0 : 255; //check this is 0 for the next value to be significant
|
||||
udpOut[38] = mainseg.cct;
|
||||
|
||||
udpOut[39] = strip.getMaxSegments();
|
||||
udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment)
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment &selseg = strip.getSegment(i);
|
||||
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
|
||||
udpOut[0 +ofs] = i;
|
||||
udpOut[1 +ofs] = selseg.start >> 8;
|
||||
udpOut[2 +ofs] = selseg.start & 0xFF;
|
||||
udpOut[3 +ofs] = selseg.stop >> 8;
|
||||
udpOut[4 +ofs] = selseg.stop & 0xFF;
|
||||
udpOut[5 +ofs] = selseg.grouping;
|
||||
udpOut[6 +ofs] = selseg.spacing;
|
||||
udpOut[7 +ofs] = selseg.offset >> 8;
|
||||
udpOut[8 +ofs] = selseg.offset & 0xFF;
|
||||
udpOut[9 +ofs] = selseg.options & 0x0F; //only take into account mirrored, selected, on, reversed
|
||||
udpOut[10+ofs] = selseg.opacity;
|
||||
udpOut[11+ofs] = selseg.mode;
|
||||
udpOut[12+ofs] = selseg.speed;
|
||||
udpOut[13+ofs] = selseg.intensity;
|
||||
udpOut[14+ofs] = selseg.palette;
|
||||
udpOut[15+ofs] = R(selseg.colors[0]);
|
||||
udpOut[16+ofs] = G(selseg.colors[0]);
|
||||
udpOut[17+ofs] = B(selseg.colors[0]);
|
||||
udpOut[18+ofs] = W(selseg.colors[0]);
|
||||
udpOut[19+ofs] = R(selseg.colors[1]);
|
||||
udpOut[20+ofs] = G(selseg.colors[1]);
|
||||
udpOut[21+ofs] = B(selseg.colors[1]);
|
||||
udpOut[22+ofs] = W(selseg.colors[1]);
|
||||
udpOut[23+ofs] = R(selseg.colors[2]);
|
||||
udpOut[24+ofs] = G(selseg.colors[2]);
|
||||
udpOut[25+ofs] = B(selseg.colors[2]);
|
||||
udpOut[26+ofs] = W(selseg.colors[2]);
|
||||
udpOut[27+ofs] = selseg.cct;
|
||||
}
|
||||
|
||||
//uint16_t offs = SEG_OFFSET;
|
||||
//next value to be added has index: udpOut[offs + 0]
|
||||
|
||||
IPAddress broadcastIp;
|
||||
broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP());
|
||||
|
||||
@ -247,47 +287,78 @@ void handleNotifications()
|
||||
} else if (!(receiveGroups & udpIn[36])) return;
|
||||
|
||||
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
//apply colors from notification
|
||||
if (receiveNotificationColor || !someSel)
|
||||
{
|
||||
|
||||
//apply colors from notification to main segment, only if not syncing full segments
|
||||
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
|
||||
col[0] = udpIn[3];
|
||||
col[1] = udpIn[4];
|
||||
col[2] = udpIn[5];
|
||||
if (version > 0) //sending module's white val is intended
|
||||
{
|
||||
col[3] = udpIn[10];
|
||||
if (version > 1)
|
||||
{
|
||||
if (version > 1) {
|
||||
colSec[0] = udpIn[12];
|
||||
colSec[1] = udpIn[13];
|
||||
colSec[2] = udpIn[14];
|
||||
colSec[3] = udpIn[15];
|
||||
}
|
||||
if (version > 6)
|
||||
{
|
||||
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
|
||||
if (version > 6) {
|
||||
strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); //tertiary color
|
||||
if (version > 9 && version < 200 && udpIn[37] < 255) { //valid CCT/Kelvin value
|
||||
uint8_t cct = udpIn[38];
|
||||
if (udpIn[37] > 0) { //Kelvin
|
||||
cct = (((udpIn[37] << 8) + udpIn[38]) - 1900) >> 5;
|
||||
}
|
||||
uint8_t segid = strip.getMainSegmentId();
|
||||
strip.getSegment(segid).setCCT(cct, segid);
|
||||
}
|
||||
}
|
||||
if (version > 9 && version < 200 && udpIn[37] < 255) { //valid CCT/Kelvin value
|
||||
uint8_t cct = udpIn[38];
|
||||
if (udpIn[37] > 0) { //Kelvin
|
||||
cct = (((udpIn[37] << 8) + udpIn[38]) - 1900) >> 5;
|
||||
}
|
||||
uint8_t segid = strip.getMainSegmentId();
|
||||
strip.getSegment(segid).setCCT(cct, segid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool timebaseUpdated = false;
|
||||
//apply effects from notification
|
||||
if (version < 200 && (receiveNotificationEffects || !someSel))
|
||||
bool applyEffects = (receiveNotificationEffects || !someSel);
|
||||
if (version < 200)
|
||||
{
|
||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||
effectSpeed = udpIn[9];
|
||||
if (version > 2) effectIntensity = udpIn[16];
|
||||
if (version > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
||||
if (version > 5)
|
||||
{
|
||||
if (applyEffects && currentPlaylist >= 0) unloadPlaylist();
|
||||
if (version > 10 && receiveSegmentOptions) {
|
||||
//does not sync start & stop
|
||||
uint8_t srcSegs = udpIn[39];
|
||||
//if (srcSegs > strip.getMaxSegments()) srcSegs = strip.getMaxSegments();
|
||||
for (uint8_t i = 0; i < srcSegs; i++) {
|
||||
uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte
|
||||
uint8_t id = udpIn[0 +ofs];
|
||||
if (id > strip.getMaxSegments()) continue;
|
||||
WS2812FX::Segment& selseg = strip.getSegment(id);
|
||||
//bytes 1+2 contain start, 3+4 stop, unused at this time
|
||||
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
|
||||
selseg.setOpacity(udpIn[10+ofs], id);
|
||||
if (applyEffects) {
|
||||
strip.setMode(id, udpIn[11+ofs]);
|
||||
selseg.speed = udpIn[12+ofs];
|
||||
selseg.intensity = udpIn[13+ofs];
|
||||
selseg.palette = udpIn[14+ofs];
|
||||
}
|
||||
if (receiveNotificationColor || !someSel) {
|
||||
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]), id);
|
||||
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]), id);
|
||||
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]), id);
|
||||
selseg.setCCT(udpIn[27+ofs], id);
|
||||
}
|
||||
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], (udpIn[7+ofs]<<8 | udpIn[8+ofs])); //also properly resets segments
|
||||
}
|
||||
setValuesFromMainSeg();
|
||||
effectChanged = true;
|
||||
colorChanged = true;
|
||||
} else if (applyEffects) { //simple effect sync, applies to all selected
|
||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||
effectSpeed = udpIn[9];
|
||||
if (version > 2) effectIntensity = udpIn[16];
|
||||
if (version > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
||||
}
|
||||
|
||||
if (applyEffects && version > 5) {
|
||||
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
|
||||
t += PRESUMED_NETWORK_DELAY; //adjust trivially for network delay
|
||||
t -= millis();
|
||||
|
@ -193,6 +193,7 @@ void WLED::loop()
|
||||
if (lastMqttReconnectAttempt > millis()) {
|
||||
rolloverMillis++;
|
||||
lastMqttReconnectAttempt = 0;
|
||||
ntpLastSyncTime = 0;
|
||||
strip.restartRuntime();
|
||||
}
|
||||
if (millis() - lastMqttReconnectAttempt > 30000) {
|
||||
@ -572,7 +573,7 @@ void WLED::initConnection()
|
||||
if (staticIP[0] != 0 && staticGateway[0] != 0) {
|
||||
WiFi.config(staticIP, staticGateway, staticSubnet, IPAddress(1, 1, 1, 1));
|
||||
} else {
|
||||
WiFi.config(0U, 0U, 0U);
|
||||
WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0));
|
||||
}
|
||||
|
||||
lastReconnectAttempt = millis();
|
||||
@ -683,8 +684,10 @@ void WLED::handleConnection()
|
||||
|
||||
if (now < 2000 && (!WLED_WIFI_CONFIGURED || apBehavior == AP_BEHAVIOR_ALWAYS))
|
||||
return;
|
||||
if (lastReconnectAttempt == 0)
|
||||
if (lastReconnectAttempt == 0) {
|
||||
initConnection();
|
||||
return;
|
||||
}
|
||||
|
||||
// reconnect WiFi to clear stale allocations if heap gets too low
|
||||
if (now - heapTime > 5000) {
|
||||
@ -801,4 +804,4 @@ void WLED::handleStatusLED()
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2112080
|
||||
#define VERSION 2201260
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -16,6 +16,7 @@
|
||||
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
||||
|
||||
// ESP8266-01 (black) has 1MB flash and can thus fit the whole program, although OTA update is not possible. Use 1M(128K SPIFFS).
|
||||
// 2-step OTA may still be possible: https://github.com/Aircoookie/WLED/issues/2040#issuecomment-981111096
|
||||
// Uncomment some of the following lines to disable features:
|
||||
// Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini
|
||||
|
||||
@ -70,10 +71,14 @@
|
||||
#include <ESPmDNS.h>
|
||||
#include <AsyncTCP.h>
|
||||
//#include "SPIFFS.h"
|
||||
#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
#define CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
#if ESP_IDF_VERSION_MAJOR < 4
|
||||
#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
#define CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
#endif
|
||||
#include <LITTLEFS.h>
|
||||
#else
|
||||
#include <LittleFS.h>
|
||||
#endif
|
||||
#include <LITTLEFS.h>
|
||||
#endif
|
||||
|
||||
#include "src/dependencies/network/Network.h"
|
||||
@ -172,7 +177,11 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
||||
#ifdef ESP8266
|
||||
#define WLED_FS LittleFS
|
||||
#else
|
||||
#define WLED_FS LITTLEFS
|
||||
#if ESP_IDF_VERSION_MAJOR < 4
|
||||
#define WLED_FS LITTLEFS
|
||||
#else
|
||||
#define WLED_FS LittleFS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// GLOBAL VARIABLES
|
||||
@ -305,6 +314,7 @@ WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receiv
|
||||
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
|
||||
WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color
|
||||
WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup
|
||||
WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options
|
||||
WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API
|
||||
WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote
|
||||
WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa
|
||||
@ -416,9 +426,6 @@ WLED_GLOBAL bool interfacesInited _INIT(false);
|
||||
WLED_GLOBAL bool wasConnected _INIT(false);
|
||||
|
||||
// color
|
||||
WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs
|
||||
WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 }));
|
||||
|
||||
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
||||
|
||||
// transitions
|
||||
@ -469,6 +476,7 @@ WLED_GLOBAL byte effectSpeed _INIT(128);
|
||||
WLED_GLOBAL byte effectIntensity _INIT(128);
|
||||
WLED_GLOBAL byte effectPalette _INIT(0);
|
||||
WLED_GLOBAL bool effectChanged _INIT(false);
|
||||
WLED_GLOBAL bool colorChanged _INIT(false);
|
||||
|
||||
// network
|
||||
WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false);
|
||||
@ -497,13 +505,17 @@ WLED_GLOBAL byte dP[] _INIT_N(({ 255, 255, 255, 255, 255, 255 }));
|
||||
WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L);
|
||||
WLED_GLOBAL bool countdownOverTriggered _INIT(true);
|
||||
|
||||
// timer
|
||||
WLED_GLOBAL byte lastTimerMinute _INIT(0);
|
||||
WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
//timer
|
||||
WLED_GLOBAL byte lastTimerMinute _INIT(0);
|
||||
WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 })); // weekdays to activate on
|
||||
// bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity
|
||||
WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
|
||||
//weekdays to activate on, bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity
|
||||
WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }));
|
||||
//upper 4 bits start, lower 4 bits end month (default 28: start month 1 and end month 12)
|
||||
WLED_GLOBAL byte timerMonth[] _INIT_N(({28,28,28,28,28,28,28,28}));
|
||||
WLED_GLOBAL byte timerDay[] _INIT_N(({1,1,1,1,1,1,1,1}));
|
||||
WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31,31,31,31,31,31,31,31}));
|
||||
|
||||
// blynk
|
||||
WLED_GLOBAL bool blynkEnabled _INIT(false);
|
||||
|
@ -382,6 +382,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("CCT"),correctWB);
|
||||
sappend('c',SET_F("CR"),cctFromRgb);
|
||||
sappend('v',SET_F("CB"),strip.cctBlending);
|
||||
sappend('v',SET_F("FR"),strip.getTargetFps());
|
||||
sappend('v',SET_F("AW"),Bus::getAutoWhiteMode());
|
||||
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
@ -420,6 +421,19 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
oappend(SET_F("mA\";"));
|
||||
}
|
||||
|
||||
oappend(SET_F("resetCOM("));
|
||||
oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10));
|
||||
oappend(SET_F(");"));
|
||||
const ColorOrderMap& com = busses.getColorOrderMap();
|
||||
for (uint8_t s=0; s < com.count(); s++) {
|
||||
const ColorOrderMapEntry* entry = com.get(s);
|
||||
if (entry == nullptr) break;
|
||||
oappend(SET_F("addCOM("));
|
||||
oappend(itoa(entry->start,nS,10)); oappend(",");
|
||||
oappend(itoa(entry->len,nS,10)); oappend(",");
|
||||
oappend(itoa(entry->colorOrder,nS,10)); oappend(");");
|
||||
}
|
||||
|
||||
sappend('v',SET_F("CA"),briS);
|
||||
|
||||
sappend('c',SET_F("BO"),turnOnAtBoot);
|
||||
@ -465,6 +479,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("RB"),receiveNotificationBrightness);
|
||||
sappend('c',SET_F("RC"),receiveNotificationColor);
|
||||
sappend('c',SET_F("RX"),receiveNotificationEffects);
|
||||
sappend('c',SET_F("SO"),receiveSegmentOptions);
|
||||
sappend('c',SET_F("SD"),notifyDirectDefault);
|
||||
sappend('c',SET_F("SB"),notifyButton);
|
||||
sappend('c',SET_F("SH"),notifyHue);
|
||||
@ -505,7 +520,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
memset(fpass,'*',l);
|
||||
sappends('s',SET_F("MQPASS"),fpass);
|
||||
sappends('s',SET_F("MQCID"),mqttClientID);
|
||||
sappends('s',SET_F("MD"),mqttDeviceTopic);
|
||||
sappends('s',"MD",mqttDeviceTopic);
|
||||
sappends('s',SET_F("MG"),mqttGroupTopic);
|
||||
sappend('c',SET_F("BM"),buttonPublishMqtt);
|
||||
#endif
|
||||
@ -596,6 +611,12 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
k[0] = 'N'; sappend('v',k,timerMinutes[i]);
|
||||
k[0] = 'T'; sappend('v',k,timerMacro[i]);
|
||||
k[0] = 'W'; sappend('v',k,timerWeekday[i]);
|
||||
if (i<8) {
|
||||
k[0] = 'M'; sappend('v',k,(timerMonth[i] >> 4) & 0x0F);
|
||||
k[0] = 'P'; sappend('v',k,timerMonth[i] & 0x0F);
|
||||
k[0] = 'D'; sappend('v',k,timerDay[i]);
|
||||
k[0] = 'E'; sappend('v',k,timerDayEnd[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user