Merge branch 'master' into dev

This commit is contained in:
Blaz Kristan 2021-07-10 17:01:20 +02:00
commit b0cfcb1999
32 changed files with 726 additions and 200 deletions

View File

@ -2,6 +2,17 @@
### Builds after release 0.12.0 ### Builds after release 0.12.0
#### Build 2107091
- Fixed presets using wrong call mode (e.g. causing buttons to send UDP under direct change type)
- Increased hue buffer
- Renamed `NOTIFIER_CALL_MODE_` to `CALL_MODE_`
#### Build 2107090
- Busses extend total configured LEDs if required
- Fixed extra button pins defaulting to 0 on first boot
#### Build 2107080 #### Build 2107080
- Made Peek use the main websocket connection instead of opening a second one - Made Peek use the main websocket connection instead of opening a second one

View File

@ -123,7 +123,7 @@ class Animated_Staircase : public Usermod {
// Always mark segments as "transitional", we are animating the staircase // Always mark segments as "transitional", we are animating the staircase
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1); segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1);
} }
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
} }
/* /*
@ -298,7 +298,7 @@ class Animated_Staircase : public Usermod {
} }
segments->setOption(SEG_OPTION_ON, 1, 1); segments->setOption(SEG_OPTION_ON, 1, 1);
} }
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
DEBUG_PRINTLN(F("Animated Staircase disabled.")); DEBUG_PRINTLN(F("Animated Staircase disabled."));
} }
enabled = enable; enabled = enable;

View File

@ -62,7 +62,7 @@ class PIRsensorSwitch : public Usermod {
// PIR sensor pin // PIR sensor pin
const uint8_t PIRsensorPin = 13; // D7 on D1 mini const uint8_t PIRsensorPin = 13; // D7 on D1 mini
// notification mode for colorUpdated() // notification mode for colorUpdated()
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE
// 1 min delay before switch off after the sensor state goes LOW // 1 min delay before switch off after the sensor state goes LOW
uint32_t m_switchOffDelay = 60000; uint32_t m_switchOffDelay = 60000;
// off timer start time // off timer start time

View File

@ -58,7 +58,7 @@ private:
// PIR sensor pin // PIR sensor pin
int8_t PIRsensorPin = PIR_SENSOR_PIN; int8_t PIRsensorPin = PIR_SENSOR_PIN;
// notification mode for colorUpdated() // notification mode for colorUpdated()
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE
// delay before switch off after the sensor state goes LOW // delay before switch off after the sensor state goes LOW
uint32_t m_switchOffDelay = 600000; // 10min uint32_t m_switchOffDelay = 600000; // 10min
// off timer start time // off timer start time

View File

@ -54,46 +54,46 @@ void userLoop()
switch (myKey) { switch (myKey) {
case '1': case '1':
applyPreset(1); applyPreset(1);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '2': case '2':
applyPreset(2); applyPreset(2);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '3': case '3':
applyPreset(3); applyPreset(3);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '4': case '4':
applyPreset(4); applyPreset(4);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '5': case '5':
applyPreset(5); applyPreset(5);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '6': case '6':
applyPreset(6); applyPreset(6);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case 'A': case 'A':
applyPreset(7); applyPreset(7);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case 'B': case 'B':
applyPreset(8); applyPreset(8);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '7': case '7':
effectCurrent += 1; effectCurrent += 1;
if (effectCurrent >= MODE_COUNT) effectCurrent = 0; if (effectCurrent >= MODE_COUNT) effectCurrent = 0;
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '*': case '*':
effectCurrent -= 1; effectCurrent -= 1;
if (effectCurrent < 0) effectCurrent = (MODE_COUNT-1); if (effectCurrent < 0) effectCurrent = (MODE_COUNT-1);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '8': case '8':
@ -102,7 +102,7 @@ void userLoop()
} else if (effectSpeed < 255) { } else if (effectSpeed < 255) {
effectSpeed += 1; effectSpeed += 1;
} }
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '0': case '0':
if (effectSpeed > 15) { if (effectSpeed > 15) {
@ -110,7 +110,7 @@ void userLoop()
} else if (effectSpeed > 0) { } else if (effectSpeed > 0) {
effectSpeed -= 1; effectSpeed -= 1;
} }
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '9': case '9':
@ -119,7 +119,7 @@ void userLoop()
} else if (effectIntensity < 255) { } else if (effectIntensity < 255) {
effectIntensity += 1; effectIntensity += 1;
} }
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '#': case '#':
if (effectIntensity > 15) { if (effectIntensity > 15) {
@ -127,18 +127,18 @@ void userLoop()
} else if (effectIntensity > 0) { } else if (effectIntensity > 0) {
effectIntensity -= 1; effectIntensity -= 1;
} }
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case 'C': case 'C':
effectPalette += 1; effectPalette += 1;
if (effectPalette >= 50) effectPalette = 0; if (effectPalette >= 50) effectPalette = 0;
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case 'D': case 'D':
effectPalette -= 1; effectPalette -= 1;
if (effectPalette <= 0) effectPalette = 50; if (effectPalette <= 0) effectPalette = 50;
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
} }

View File

@ -0,0 +1,86 @@
# RGB Encoder Board
This usermod-v2 adds support for the awesome RGB Rotary Encoder Board by Adam Zeloof / "Isotope Engineering" to control the overall brightness of your WLED instance: https://github.com/isotope-engineering/RGB-Encoder-Board. A great DIY rotary encoder with 20 tiny SK6805 / "NeoPixel Nano" LEDs.
https://user-images.githubusercontent.com/3090131/124680599-0180ab80-dec7-11eb-9065-a6d08ebe0287.mp4
## Credits
The actual / original code that does the different LED modes is from Adam Zeloof. So I don't take credit for these. But I ported it to WLED, which involved replacing the LED library he used (because, guess what, WLED already has one; so no need to add another one, but use whatever WLED uses), plus the rotary encoder library, because that one was not compatible with ESP, only Arduino.
So it was quite more work than I hoped, but I got there eventually :)
## Requirements
* "ESP Rotary" by Lennart Hennigs, v1.5.0 or higher: https://github.com/LennartHennigs/ESPRotary
## Usermod installation
Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one and add the buildflag `-D RGB_ROTARY_ENCODER`.
ESP32:
```
[env:custom_esp32dev_usermod_rgb_encoder_board]
extends = env:esp32dev
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER
lib_deps = ${esp32.lib_deps}
lennarthennigs/ESP Rotary@^1.5.0
```
ESP8266 / D1 Mini:
```
[env:custom_d1_mini_usermod_rgb_encoder_board]
extends = env:d1_mini
build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER
lib_deps = ${esp8266.lib_deps}
lennarthennigs/ESP Rotary@^1.5.0
```
## How to connect the board to your ESP
We gonna need (minimum) three or (maximum) four GPIOs for the board:
* "ea": Basically tells if the encoder goes into one or the other direction
* "eb": Same thing, but the other direction
* "di": LED data in. To actually control the LEDs
* *(optional)* "sw": The integrated switch in the rotary encoder. Can be omitted for the bare functionality of just controlling the brightness
We also gonna need some power, so:
* "vdd": Needs to be connected to **+5V**.
* "gnd": Well, it's GND.
You can freely pick the GPIOs, it doesn't matter. Those will be configured in the "Usermods" section in the WLED web panel:
## Configuration
Navigate to the "Config" and then to the "Usermods" section. If you compiled WLED with `-D RGB_ROTARY_ENCODER`, you will see the config for it there. The settings there are the GPIOs we mentioned before (*Note: The switch pin is not there, as this can just be configured the "normal" button on the "LED Preferences" page*), plus a few more:
* LED pin:
* Possible values: Any valid and available GPIO
* Default: 3
* What it does: Pin to control the LED ring
* ea pin:
* Possible values: Any valid and available GPIO
* Default: 15
* What it does: First of the two rotary encoder pins
* eb pin:
* Possible values: Any valid and available GPIO
* Default: 32
* What it does: Second of the two rotary encoder pins
* LED Mode:
* Possible values: 1-3
* Default: 3
* What it does: The usermod provides three different modes of how the LEDs can look like. Here's an example: https://github.com/isotope-engineering/RGB-Encoder-Board/blob/master/images/rgb-encoder-animations.gif
* Up left is "1"
* Up right is not supported / doesn't make sense for brightness control
* Bottom left is "2"
* Bottom right is "3"
* LED Brightness:
* Possible values: 1-255
* Default: 64
* What it does: Brightness of the LED ring
* Steps per click:
* Possible values: Any positive number
* Default: 4
* What it does: With each "click", a rotary encoder actually increments it's "steps". Most rotary encoder do four "steps" per "click". I know this sounds super weird, so just leave this the default value, unless your rotary encoder behaves weirdly, like with one click, it makes two LEDs light up, or you sometimes need two click for one LED. Then you should play around with this value or write a small sketch using the same "ESP Rotary" library and read out the steps it does.
* Increment per click:
* Possible values: Any positive number
* Default: 5
* What it does: Most rotary encoder have 20 "clicks", so basically 20 positions. This value should be set to 100 / `number of clicks`
## Change log
2021-07
* First implementation.

View File

@ -0,0 +1,344 @@
#pragma once
#include "ESPRotary.h"
#include <math.h>
#include "wled.h"
class RgbRotaryEncoderUsermod : public Usermod
{
private:
bool enabled = false;
bool initDone = false;
bool isDirty = false;
BusDigital *ledBus;
/*
* Green - eb - Q4 - 32
* Red - ea - Q1 - 15
* Black - sw - Q2 - 12
*/
ESPRotary *rotaryEncoder;
int8_t ledIo = 3; // GPIO to control the LEDs
int8_t eaIo = 15; // "ea" from RGB Encoder Board
int8_t ebIo = 32; // "eb" from RGB Encoder Board
byte stepsPerClick = 4; // How many "steps" your rotary encoder does per click. This varies per rotary encoder
/* This could vary per rotary encoder: Usually rotary encoders have 20 "clicks".
If yours has less/more, adjust this to: 100% = 20 LEDs * incrementPerClick */
byte incrementPerClick = 5;
byte ledMode = 3;
byte ledBrightness = 64;
// This is all needed to calculate the brightness, rotary position, etc.
const byte minPos = 5; // minPos is not zero, because if we want to turn the LEDs off, we use the built-in button ;)
const byte maxPos = 100; // maxPos=100, like 100%
const byte numLeds = 20;
byte lastKnownPos = 0;
byte currentColors[3];
byte lastKnownBri = 0;
void initRotaryEncoder()
{
if (!pinManager.allocatePin(eaIo, false)) {
eaIo = -1;
}
if (!pinManager.allocatePin(ebIo, false)) {
ebIo = -1;
}
if (eaIo == -1 || ebIo == -1) {
cleanup();
return;
}
// I don't know why, but setting the upper bound here does not work. It results into 1717922932 O_o
rotaryEncoder = new ESPRotary(eaIo, ebIo, stepsPerClick, incrementPerClick, maxPos, currentPos, incrementPerClick);
rotaryEncoder->setUpperBound(maxPos); // I have to again set it here and then it works / is actually 100...
rotaryEncoder->setChangedHandler(RgbRotaryEncoderUsermod::cbRotate);
}
void initLedBus()
{
byte _pins[5] = {(byte)ledIo, 255, 255, 255, 255};
BusConfig busCfg = BusConfig(TYPE_WS2812_RGB, _pins, 0, numLeds, COL_ORDER_GRB, false, 0);
ledBus = new BusDigital(busCfg, WLED_MAX_BUSSES - 1);
if (!ledBus->isOk()) {
cleanup();
return;
}
ledBus->setBrightness(ledBrightness);
}
void updateLeds()
{
switch (ledMode) {
case 2:
{
currentColors[0] = 255; currentColors[1] = 0; currentColors[2] = 0;
for (int i = 0; i < currentPos / incrementPerClick - 1; i++) {
ledBus->setPixelColor(i, 0);
}
ledBus->setPixelColor(currentPos / incrementPerClick - 1, colorFromRgbw(currentColors));
for (int i = currentPos / incrementPerClick; i < numLeds; i++) {
ledBus->setPixelColor(i, 0);
}
}
break;
default:
case 1:
case 3:
// WLED orange (of course), which we will use in mode 1
currentColors[0] = 255; currentColors[1] = 160; currentColors[2] = 0;
for (int i = 0; i < currentPos / incrementPerClick; i++) {
if (ledMode == 3) {
hsv2rgb((i) / float(numLeds), 1, .25);
}
ledBus->setPixelColor(i, colorFromRgbw(currentColors));
}
for (int i = currentPos / incrementPerClick; i < numLeds; i++) {
ledBus->setPixelColor(i, 0);
}
break;
}
isDirty = true;
}
void cleanup()
{
// Only deallocate pins if we allocated them ;)
if (eaIo != -1) {
pinManager.deallocatePin(eaIo);
}
if (ebIo != -1) {
pinManager.deallocatePin(ebIo);
}
delete rotaryEncoder;
delete ledBus;
enabled = false;
}
int getPositionForBrightness()
{
return int(((float)bri / (float)255) * 100);
}
float fract(float x) { return x - int(x); }
float mix(float a, float b, float t) { return a + (b - a) * t; }
void hsv2rgb(float h, float s, float v) {
currentColors[0] = int((v * mix(1.0, constrain(abs(fract(h + 1.0) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s)) * 255);
currentColors[1] = int((v * mix(1.0, constrain(abs(fract(h + 0.6666666) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s)) * 255);
currentColors[2] = int((v * mix(1.0, constrain(abs(fract(h + 0.3333333) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s)) * 255);
}
public:
static byte currentPos;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _ledIo[];
static const char _eaIo[];
static const char _ebIo[];
static const char _ledMode[];
static const char _ledBrightness[];
static const char _stepsPerClick[];
static const char _incrementPerClick[];
static void cbRotate(ESPRotary& r) {
currentPos = r.getPosition();
}
/**
* Enable/Disable the usermod
*/
// inline void enable(bool enable) { enabled = enable; }
/**
* Get usermod enabled/disabled state
*/
// inline bool isEnabled() { return enabled; }
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup()
{
if (enabled) {
currentPos = getPositionForBrightness();
lastKnownBri = bri;
initRotaryEncoder();
initLedBus();
// No updating of LEDs here, as that's sometimes not working; loop() will take care of that
initDone = true;
}
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop()
{
if (!enabled || strip.isUpdating()) return;
rotaryEncoder->loop();
// If the rotary was changed
if(lastKnownPos != currentPos) {
lastKnownPos = currentPos;
bri = min(int(round((2.55 * currentPos))), 255);
lastKnownBri = bri;
updateLeds();
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
}
// If the brightness is changed not with the rotary, update the rotary
if (bri != lastKnownBri) {
currentPos = lastKnownPos = getPositionForBrightness();
lastKnownBri = bri;
rotaryEncoder->resetPosition(currentPos);
updateLeds();
}
// Update LEDs here in loop to also validate that we can update/show
if (isDirty && ledBus->canShow()) {
isDirty = false;
ledBus->show();
}
}
void addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = enabled;
top[FPSTR(_ledIo)] = ledIo;
top[FPSTR(_eaIo)] = eaIo;
top[FPSTR(_ebIo)] = ebIo;
top[FPSTR(_ledMode)] = ledMode;
top[FPSTR(_ledBrightness)] = ledBrightness;
top[FPSTR(_stepsPerClick)] = stepsPerClick;
top[FPSTR(_incrementPerClick)] = incrementPerClick;
}
/**
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
*
* The function should return true if configuration was successfully loaded or false if there was no configuration.
*/
bool readFromConfig(JsonObject &root)
{
JsonObject top = root[FPSTR(_name)];
if (top.isNull()) {
DEBUG_PRINTF("[%s] No config found. (Using defaults.)\n", _name);
return false;
}
bool oldEnabled = enabled;
int8_t oldLedIo = ledIo;
int8_t oldEaIo = eaIo;
int8_t oldEbIo = ebIo;
byte oldLedMode = ledMode;
byte oldStepsPerClick = stepsPerClick;
byte oldIncrementPerClick = incrementPerClick;
byte oldLedBrightness = ledBrightness;
getJsonValue(top[FPSTR(_enabled)], enabled);
getJsonValue(top[FPSTR(_ledIo)], ledIo);
getJsonValue(top[FPSTR(_eaIo)], eaIo);
getJsonValue(top[FPSTR(_ebIo)], ebIo);
getJsonValue(top[FPSTR(_stepsPerClick)], stepsPerClick);
getJsonValue(top[FPSTR(_incrementPerClick)], incrementPerClick);
ledMode = top[FPSTR(_ledMode)] > 0 && top[FPSTR(_ledMode)] < 4 ? top[FPSTR(_ledMode)] : ledMode;
ledBrightness = top[FPSTR(_ledBrightness)] > 0 && top[FPSTR(_ledBrightness)] <= 255 ? top[FPSTR(_ledBrightness)] : ledBrightness;
if (!initDone) {
// First run: reading from cfg.json
// Nothing to do here, will be all done in setup()
}
// Mod was disabled, so run setup()
else if (enabled && enabled != oldEnabled) {
DEBUG_PRINTF("[%s] Usermod has been re-enabled\n", _name);
setup();
}
// Config has been changed, so adopt to changes
else {
if (!enabled) {
DEBUG_PRINTF("[%s] Usermod has been disabled\n", _name);
cleanup();
}
else {
DEBUG_PRINTF("[%s] Usermod is enabled\n", _name);
if (ledIo != oldLedIo) {
delete ledBus;
initLedBus();
}
if (ledBrightness != oldLedBrightness) {
ledBus->setBrightness(ledBrightness);
isDirty = true;
}
if (ledMode != oldLedMode) {
updateLeds();
}
if (eaIo != oldEaIo || ebIo != oldEbIo || stepsPerClick != oldStepsPerClick || incrementPerClick != oldIncrementPerClick) {
pinManager.deallocatePin(oldEaIo);
pinManager.deallocatePin(oldEbIo);
delete rotaryEncoder;
initRotaryEncoder();
}
}
DEBUG_PRINTF("[%s] Config (re)loaded\n", _name);
}
return true;
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return 0x4711;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};
byte RgbRotaryEncoderUsermod::currentPos = 5;
// strings to reduce flash memory usage (used more than twice)
const char RgbRotaryEncoderUsermod::_name[] PROGMEM = "RGB-Rotary-Encoder";
const char RgbRotaryEncoderUsermod::_enabled[] PROGMEM = "Enabled";
const char RgbRotaryEncoderUsermod::_ledIo[] PROGMEM = "LED-pin";
const char RgbRotaryEncoderUsermod::_eaIo[] PROGMEM = "ea-pin";
const char RgbRotaryEncoderUsermod::_ebIo[] PROGMEM = "eb-pin";
const char RgbRotaryEncoderUsermod::_ledMode[] PROGMEM = "LED-Mode";
const char RgbRotaryEncoderUsermod::_ledBrightness[] PROGMEM = "LED-Brightness";
const char RgbRotaryEncoderUsermod::_stepsPerClick[] PROGMEM = "Steps-per-Click";
const char RgbRotaryEncoderUsermod::_incrementPerClick[] PROGMEM = "Increment-per-Click";

View File

@ -39,7 +39,7 @@ void userLoop() {
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
lastTime = millis(); lastTime = millis();
} }
} }

View File

@ -42,7 +42,7 @@ class StairwayWipeUsermod : public Usermod {
if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete
effectCurrent = FX_MODE_STATIC; effectCurrent = FX_MODE_STATIC;
timeStaticStart = millis(); timeStaticStart = millis();
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
wipeState = 2; wipeState = 2;
} }
} else if (wipeState == 2) { //static } else if (wipeState == 2) { //static
@ -54,7 +54,7 @@ class StairwayWipeUsermod : public Usermod {
#ifdef STAIRCASE_WIPE_OFF #ifdef STAIRCASE_WIPE_OFF
effectCurrent = FX_MODE_COLOR_WIPE; effectCurrent = FX_MODE_COLOR_WIPE;
strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
wipeState = 4; wipeState = 4;
#else #else
turnOff(); turnOff();
@ -100,7 +100,7 @@ class StairwayWipeUsermod : public Usermod {
bool doReverse = (userVar0 == 2); bool doReverse = (userVar0 == 2);
seg.setOption(1, doReverse); seg.setOption(1, doReverse);
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
} }
void turnOff() void turnOff()
@ -111,7 +111,7 @@ class StairwayWipeUsermod : public Usermod {
transitionDelayTemp = 4000; //fade out slowly transitionDelayTemp = 4000; //fade out slowly
#endif #endif
bri = 0; bri = 0;
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
wipeState = 0; wipeState = 0;
userVar0 = 0; userVar0 = 0;
previousUserVar0 = 0; previousUserVar0 = 0;

View File

@ -47,7 +47,7 @@ void userLoop()
if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete
effectCurrent = FX_MODE_STATIC; effectCurrent = FX_MODE_STATIC;
timeStaticStart = millis(); timeStaticStart = millis();
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
wipeState = 2; wipeState = 2;
} }
} else if (wipeState == 2) { //static } else if (wipeState == 2) { //static
@ -59,7 +59,7 @@ void userLoop()
#ifdef STAIRCASE_WIPE_OFF #ifdef STAIRCASE_WIPE_OFF
effectCurrent = FX_MODE_COLOR_WIPE; effectCurrent = FX_MODE_COLOR_WIPE;
strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
wipeState = 4; wipeState = 4;
#else #else
turnOff(); turnOff();
@ -93,7 +93,7 @@ void startWipe()
bool doReverse = (userVar0 == 2); bool doReverse = (userVar0 == 2);
seg.setOption(1, doReverse); seg.setOption(1, doReverse);
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
} }
void turnOff() void turnOff()
@ -104,7 +104,7 @@ void turnOff()
transitionDelayTemp = 4000; //fade out slowly transitionDelayTemp = 4000; //fade out slowly
#endif #endif
bri = 0; bri = 0;
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
wipeState = 0; wipeState = 0;
userVar0 = 0; userVar0 = 0;
previousUserVar0 = 0; previousUserVar0 = 0;

View File

@ -138,8 +138,8 @@ public:
} }
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); colorUpdated(CALL_MODE_BUTTON);
updateInterfaces(NOTIFIER_CALL_MODE_BUTTON); updateInterfaces(CALL_MODE_BUTTON);
} }
Enc_A_prev = Enc_A; // Store value of A for next time Enc_A_prev = Enc_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime loopTime = currentTime; // Updates loopTime

View File

@ -267,8 +267,8 @@ public:
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
updateInterfaces(NOTIFIER_CALL_MODE_DIRECT_CHANGE); updateInterfaces(CALL_MODE_DIRECT_CHANGE);
} }
void changeBrightness(bool increase) { void changeBrightness(bool increase) {

View File

@ -64,13 +64,13 @@ void hourChime()
{ {
//strip.resetSegments(); //strip.resetSegments();
selectWordSegments(true); selectWordSegments(true);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
savePreset(13, false); savePreset(13, false);
selectWordSegments(false); selectWordSegments(false);
//strip.getSegment(0).setOption(0, true); //strip.getSegment(0).setOption(0, true);
strip.getSegment(0).setOption(2, true); strip.getSegment(0).setOption(2, true);
applyPreset(12); applyPreset(12);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED); colorUpdated(CALL_MODE_FX_CHANGED);
} }
void displayTime(byte hour, byte minute) void displayTime(byte hour, byte minute)

View File

@ -44,10 +44,10 @@ void onAlexaChange(EspalexaDevice* dev)
if (bri == 0) if (bri == 0)
{ {
bri = briLast; bri = briLast;
colorUpdated(NOTIFIER_CALL_MODE_ALEXA); colorUpdated(CALL_MODE_ALEXA);
} }
} else { } else {
applyPreset(macroAlexaOn); applyPreset(macroAlexaOn, CALL_MODE_ALEXA);
if (bri == 0) espalexaDevice->setValue(briLast); //stop Alexa from complaining if macroAlexaOn does not actually turn on if (bri == 0) espalexaDevice->setValue(briLast); //stop Alexa from complaining if macroAlexaOn does not actually turn on
} }
} else if (m == EspalexaDeviceProperty::off) } else if (m == EspalexaDeviceProperty::off)
@ -58,16 +58,16 @@ void onAlexaChange(EspalexaDevice* dev)
{ {
briLast = bri; briLast = bri;
bri = 0; bri = 0;
colorUpdated(NOTIFIER_CALL_MODE_ALEXA); colorUpdated(CALL_MODE_ALEXA);
} }
} else { } else {
applyPreset(macroAlexaOff); applyPreset(macroAlexaOff, CALL_MODE_ALEXA);
if (bri != 0) espalexaDevice->setValue(0); //stop Alexa from complaining if macroAlexaOff does not actually turn off if (bri != 0) espalexaDevice->setValue(0); //stop Alexa from complaining if macroAlexaOff does not actually turn off
} }
} else if (m == EspalexaDeviceProperty::bri) } else if (m == EspalexaDeviceProperty::bri)
{ {
bri = espalexaDevice->getValue(); bri = espalexaDevice->getValue();
colorUpdated(NOTIFIER_CALL_MODE_ALEXA); colorUpdated(CALL_MODE_ALEXA);
} else //color } else //color
{ {
if (espalexaDevice->getColorMode() == EspalexaColorMode::ct) //shade of white if (espalexaDevice->getColorMode() == EspalexaColorMode::ct) //shade of white
@ -93,7 +93,7 @@ void onAlexaChange(EspalexaDevice* dev)
col[2] = ( color & 0xFF); col[2] = ( color & 0xFF);
col[3] = 0; col[3] = 0;
} }
colorUpdated(NOTIFIER_CALL_MODE_ALEXA); colorUpdated(CALL_MODE_ALEXA);
} }
} }

View File

@ -46,45 +46,45 @@ void updateBlynk()
BLYNK_WRITE(V0) BLYNK_WRITE(V0)
{ {
bri = param.asInt();//bri bri = param.asInt();//bri
colorUpdated(NOTIFIER_CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V1) BLYNK_WRITE(V1)
{ {
blHue = param.asInt();//hue blHue = param.asInt();//hue
colorHStoRGB(blHue*10,blSat,(false)? colSec:col); colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(NOTIFIER_CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V2) BLYNK_WRITE(V2)
{ {
blSat = param.asInt();//sat blSat = param.asInt();//sat
colorHStoRGB(blHue*10,blSat,(false)? colSec:col); colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(NOTIFIER_CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V3) BLYNK_WRITE(V3)
{ {
bool on = (param.asInt()>0); bool on = (param.asInt()>0);
if (!on != !bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BLYNK);} if (!on != !bri) {toggleOnOff(); colorUpdated(CALL_MODE_BLYNK);}
} }
BLYNK_WRITE(V4) BLYNK_WRITE(V4)
{ {
effectCurrent = param.asInt()-1;//fx effectCurrent = param.asInt()-1;//fx
colorUpdated(NOTIFIER_CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V5) BLYNK_WRITE(V5)
{ {
effectSpeed = param.asInt();//sx effectSpeed = param.asInt();//sx
colorUpdated(NOTIFIER_CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V6) BLYNK_WRITE(V6)
{ {
effectIntensity = param.asInt();//ix effectIntensity = param.asInt();//ix
colorUpdated(NOTIFIER_CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V7) BLYNK_WRITE(V7)

View File

@ -33,6 +33,18 @@ struct BusConfig {
else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type); else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i]; for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
} }
//validates start and length and extends total if needed
bool adjustBounds(uint16_t& total) {
if (!count) count = 1;
if (count > MAX_LEDS_PER_BUS) count = MAX_LEDS_PER_BUS;
if (start >= MAX_LEDS) return false;
//limit length of strip if it would exceed total permissible LEDs
if (start + count > MAX_LEDS) count = MAX_LEDS - start;
//extend total count accordingly
if (start + count > total) total = start + count;
return true;
}
}; };
//parent class of BusDigital and BusPwm //parent class of BusDigital and BusPwm
@ -112,11 +124,10 @@ class Bus {
class BusDigital : public Bus { class BusDigital : public Bus {
public: public:
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) { BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) {
uint8_t type = bc.type; if (!IS_DIGITAL(bc.type) || !bc.count) return;
if (!IS_DIGITAL(type) || !bc.count) return;
if (!pinManager.allocatePin(bc.pins[0])) return; if (!pinManager.allocatePin(bc.pins[0])) return;
_pins[0] = bc.pins[0]; _pins[0] = bc.pins[0];
if (IS_2PIN(type)) { if (IS_2PIN(bc.type)) {
if (!pinManager.allocatePin(bc.pins[1])) { if (!pinManager.allocatePin(bc.pins[1])) {
cleanup(); return; cleanup(); return;
} }
@ -125,8 +136,8 @@ class BusDigital : public Bus {
reversed = bc.reversed; reversed = bc.reversed;
_skip = bc.skipAmount; //sacrificial pixels _skip = bc.skipAmount; //sacrificial pixels
_len = bc.count + _skip; _len = bc.count + _skip;
_rgbw = bc.rgbwOverride || Bus::isRgbw(type); // RGBW override in bit 7 _rgbw = bc.rgbwOverride || Bus::isRgbw(bc.type); // RGBW override in bit 7
_iType = PolyBus::getI(type, _pins, nr, _rgbw); _iType = PolyBus::getI(bc.type, _pins, nr, _rgbw);
if (_iType == I_NONE) return; if (_iType == I_NONE) return;
_busPtr = PolyBus::create(_iType, _pins, _len, nr); _busPtr = PolyBus::create(_iType, _pins, _len, nr);
_valid = (_busPtr != nullptr); _valid = (_busPtr != nullptr);
@ -237,11 +248,11 @@ class BusPwm : public Bus {
#endif #endif
for (uint8_t i = 0; i < numPins; i++) { for (uint8_t i = 0; i < numPins; i++) {
if (!pinManager.allocatePin(bc.pins[i])) { uint8_t currentPin = bc.pins[i];
deallocatePins(); if (!pinManager.allocatePin(currentPin)) {
return; deallocatePins(); return;
} }
_pins[i] = bc.pins[i]; _pins[i] = currentPin; // store only after allocatePin() succeeds
#ifdef ESP8266 #ifdef ESP8266
pinMode(_pins[i], OUTPUT); pinMode(_pins[i], OUTPUT);
#else #else

View File

@ -13,9 +13,9 @@ void shortPressAction(uint8_t b)
if (!macroButton[b]) if (!macroButton[b])
{ {
toggleOnOff(); toggleOnOff();
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); colorUpdated(CALL_MODE_BUTTON);
} else { } else {
applyPreset(macroButton[b]); applyPreset(macroButton[b], CALL_MODE_BUTTON);
} }
// publish MQTT message // publish MQTT message
@ -62,14 +62,14 @@ void handleSwitch(uint8_t b)
if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce) if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
if (!buttonPressedBefore[b]) { // on -> off if (!buttonPressedBefore[b]) { // on -> off
if (macroButton[b]) applyPreset(macroButton[b]); if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON);
else { //turn on else { //turn on
if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);} if (!bri) {toggleOnOff(); colorUpdated(CALL_MODE_BUTTON);}
} }
} else { // off -> on } else { // off -> on
if (macroLongPress[b]) applyPreset(macroLongPress[b]); if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON);
else { //turn off else { //turn off
if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);} if (bri) {toggleOnOff(); colorUpdated(CALL_MODE_BUTTON);}
} }
} }
@ -154,14 +154,14 @@ void handleAnalog(uint8_t b)
seg.setOption(SEG_OPTION_ON, 1); seg.setOption(SEG_OPTION_ON, 1);
} }
// this will notify clients of update (websockets,mqtt,etc) // this will notify clients of update (websockets,mqtt,etc)
updateInterfaces(NOTIFIER_CALL_MODE_BUTTON); updateInterfaces(CALL_MODE_BUTTON);
} }
} else { } else {
//TODO: //TODO:
// we can either trigger a preset depending on the level (between short and long entries) // we can either trigger a preset depending on the level (between short and long entries)
// or use it for RGBW direct control // or use it for RGBW direct control
} }
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); colorUpdated(CALL_MODE_BUTTON);
} }
void handleButton() void handleButton()
@ -195,7 +195,7 @@ void handleButton()
{ {
if (!buttonLongPressed[b]) if (!buttonLongPressed[b])
{ {
if (macroLongPress[b]) {applyPreset(macroLongPress[b]);} if (macroLongPress[b]) {applyPreset(macroLongPress[b], CALL_MODE_BUTTON);}
else _setRandomColor(false,true); else _setRandomColor(false,true);
// publish MQTT message // publish MQTT message
@ -224,7 +224,7 @@ void handleButton()
if (macroDoublePress[b]) if (macroDoublePress[b])
{ {
if (doublePress) { if (doublePress) {
applyPreset(macroDoublePress[b]); applyPreset(macroDoublePress[b], CALL_MODE_BUTTON);
// publish MQTT message // publish MQTT message
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {

View File

@ -120,12 +120,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (i>4) break; if (i>4) break;
} }
uint16_t length = elm[F("len")]; uint16_t length = elm[F("len")] | 1;
if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
uint8_t colorOrder = (int)elm[F("order")];
uint8_t skipFirst = elm[F("skip")];
uint16_t start = elm[F("start")] | 0; uint16_t start = elm[F("start")] | 0;
if (start > lC+length) continue; // something is very wrong :) if (start > lC+length) continue; // something is very wrong :)
uint8_t colorOrder = elm[F("order")];
uint8_t skipFirst = elm[F("skip")];
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB; uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
bool reversed = elm["rev"]; bool reversed = elm["rev"];
//if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary) //if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary)
@ -134,6 +134,18 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst); BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
mem += BusManager::memUsage(bc); mem += BusManager::memUsage(bc);
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip() if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
/*
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
if (bc.adjustBounds(ledCount)) {
//RGBW mode is enabled if at least one of the strips is RGBW
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(ledType));
//refresh is required to remain off if at least one of the strips requires the refresh.
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(ledType);
s++;
mem += busses.memUsage(bc);
if (mem <= MAX_LED_MEMORY) busses.add(bc);
}
*/
} }
// finalization done in beginStrip() // finalization done in beginStrip()
} }
@ -170,8 +182,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
} else { } else {
// new install/missing configuration (button 0 has defaults) // new install/missing configuration (button 0 has defaults)
if (fromFS) { if (fromFS) {
// relies upon only being called once with fromFS == true, which is currently true.
uint8_t s=0; uint8_t s=0;
if (pinManager.allocatePin(btnPin[0])) s++; // do not clear button 0 if pin successfully allocated if (pinManager.allocatePin(btnPin[0],false)) s++; // do not clear button 0 if pin successfully allocated
for (; s<WLED_MAX_BUTTONS; s++) { for (; s<WLED_MAX_BUTTONS; s++) {
btnPin[s] = -1; btnPin[s] = -1;
buttonType[s] = BTN_TYPE_NONE; buttonType[s] = BTN_TYPE_NONE;
@ -501,7 +514,7 @@ void serializeConfig() {
JsonObject wifi = doc.createNestedObject("wifi"); JsonObject wifi = doc.createNestedObject("wifi");
wifi[F("sleep")] = !noWifiSleep; wifi[F("sleep")] = !noWifiSleep;
wifi[F("phy")] = 1; //wifi[F("phy")] = 1;
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
JsonObject ethernet = doc.createNestedObject("eth"); JsonObject ethernet = doc.createNestedObject("eth");
@ -558,27 +571,18 @@ void serializeConfig() {
hw_btn["max"] = WLED_MAX_BUTTONS; // just information about max number of buttons (not actually used) hw_btn["max"] = WLED_MAX_BUTTONS; // just information about max number of buttons (not actually used)
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins"); JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
// there is always at least one button // configuration for all buttons
for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) {
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject(); JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0["type"] = buttonType[0];
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(btnPin[0]);
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
hw_btn_ins_0_macros.add(macroButton[0]);
hw_btn_ins_0_macros.add(macroLongPress[0]);
hw_btn_ins_0_macros.add(macroDoublePress[0]);
// additional buttons
for (uint8_t i=1; i<WLED_MAX_BUTTONS; i++) {
hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0["type"] = buttonType[i]; hw_btn_ins_0["type"] = buttonType[i];
hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin"); JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(btnPin[i]); hw_btn_ins_0_pin.add(btnPin[i]);
hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros"); JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
hw_btn_ins_0_macros.add(macroButton[i]); hw_btn_ins_0_macros.add(macroButton[i]);
hw_btn_ins_0_macros.add(macroLongPress[i]); hw_btn_ins_0_macros.add(macroLongPress[i]);
hw_btn_ins_0_macros.add(macroDoublePress[i]); hw_btn_ins_0_macros.add(macroDoublePress[i]);
} }
hw_btn[F("tt")] = touchThreshold; hw_btn[F("tt")] = touchThreshold;
hw_btn["mqtt"] = buttonPublishMqtt; hw_btn["mqtt"] = buttonPublishMqtt;

View File

@ -66,18 +66,18 @@
#define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec #define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec
//Notifier callMode //Notifier callMode
#define NOTIFIER_CALL_MODE_INIT 0 //no updates on init, can be used to disable updates #define CALL_MODE_INIT 0 //no updates on init, can be used to disable updates
#define NOTIFIER_CALL_MODE_DIRECT_CHANGE 1 #define CALL_MODE_DIRECT_CHANGE 1
#define NOTIFIER_CALL_MODE_BUTTON 2 #define CALL_MODE_BUTTON 2
#define NOTIFIER_CALL_MODE_NOTIFICATION 3 #define CALL_MODE_NOTIFICATION 3
#define NOTIFIER_CALL_MODE_NIGHTLIGHT 4 #define CALL_MODE_NIGHTLIGHT 4
#define NOTIFIER_CALL_MODE_NO_NOTIFY 5 #define CALL_MODE_NO_NOTIFY 5
#define NOTIFIER_CALL_MODE_FX_CHANGED 6 //no longer used #define CALL_MODE_FX_CHANGED 6 //no longer used
#define NOTIFIER_CALL_MODE_HUE 7 #define CALL_MODE_HUE 7
#define NOTIFIER_CALL_MODE_PRESET_CYCLE 8 #define CALL_MODE_PRESET_CYCLE 8
#define NOTIFIER_CALL_MODE_BLYNK 9 #define CALL_MODE_BLYNK 9
#define NOTIFIER_CALL_MODE_ALEXA 10 #define CALL_MODE_ALEXA 10
#define NOTIFIER_CALL_MODE_WS_SEND 11 //special call mode, not for notifier, updates websocket only #define CALL_MODE_WS_SEND 11 //special call mode, not for notifier, updates websocket only
//RGB to RGBW conversion mode //RGB to RGBW conversion mode
#define RGBW_MODE_MANUAL_ONLY 0 //No automatic white channel calculation. Manual white channel slider #define RGBW_MODE_MANUAL_ONLY 0 //No automatic white channel calculation. Manual white channel slider

View File

@ -157,7 +157,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
colSec[3] = e131_data[DMXAddress+12]; colSec[3] = e131_data[DMXAddress+12];
} }
transitionDelayTemp = 0; // act fast transitionDelayTemp = 0; // act fast
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); // don't send UDP colorUpdated(CALL_MODE_NOTIFICATION); // don't send UDP
return; // don't activate realtime live mode return; // don't activate realtime live mode
break; break;

View File

@ -122,7 +122,7 @@ void handleIR();
#include "FX.h" #include "FX.h"
void deserializeSegment(JsonObject elem, byte it, byte presetId = 0); void deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
bool deserializeState(JsonObject root, byte presetId = 0); bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true); void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true); void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true);
void serializeInfo(JsonObject root); void serializeInfo(JsonObject root);
@ -183,7 +183,7 @@ void loadPlaylist(JsonObject playlistObject, byte presetId = 0);
void handlePlaylist(); void handlePlaylist();
//presets.cpp //presets.cpp
bool applyPreset(byte index); bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE);
void savePreset(byte index, bool persist = true, const char* pname = nullptr, JsonObject saveobj = JsonObject()); void savePreset(byte index, bool persist = true, const char* pname = nullptr, JsonObject saveobj = JsonObject());
void deletePreset(byte index); void deletePreset(byte index);

View File

@ -10,7 +10,7 @@ void handleHue()
{ {
if (hueReceived) if (hueReceived)
{ {
colorUpdated(NOTIFIER_CALL_MODE_HUE); hueReceived = false; colorUpdated(CALL_MODE_HUE); hueReceived = false;
if (hueStoreAllowed && hueNewKey) if (hueStoreAllowed && hueNewKey)
{ {
serializeConfigSec(); //save api key serializeConfigSec(); //save api key
@ -92,7 +92,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
if (str == nullptr) return; if (str == nullptr) return;
str += 4; str += 4;
StaticJsonDocument<512> root; StaticJsonDocument<1024> root;
if (str[0] == '[') //is JSON array if (str[0] == '[') //is JSON array
{ {
auto error = deserializeJson(root, str); auto error = deserializeJson(root, str);

View File

@ -69,9 +69,9 @@ void decBrightness()
} }
// apply preset or fallback to a effect and palette if it doesn't exist // apply preset or fallback to a effect and palette if it doesn't exist
void presetFallback(int8_t presetID, int8_t effectID, int8_t paletteID) void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
{ {
if (!applyPreset(presetID)) { if (!applyPreset(presetID, CALL_MODE_BUTTON)) {
effectCurrent = effectID; effectCurrent = effectID;
effectPalette = paletteID; effectPalette = paletteID;
} }
@ -88,11 +88,11 @@ bool decodeIRCustom(uint32_t code)
{ {
//just examples, feel free to modify or remove //just examples, feel free to modify or remove
case IRCUSTOM_ONOFF : toggleOnOff(); break; case IRCUSTOM_ONOFF : toggleOnOff(); break;
case IRCUSTOM_MACRO1 : applyPreset(1); break; case IRCUSTOM_MACRO1 : applyPreset(1, CALL_MODE_BUTTON); break;
default: return false; default: return false;
} }
if (code != IRCUSTOM_MACRO1) colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //don't update color again if we apply macro, it already does it if (code != IRCUSTOM_MACRO1) colorUpdated(CALL_MODE_BUTTON); //don't update color again if we apply macro, it already does it
return true; return true;
} }
*/ */
@ -187,51 +187,51 @@ void decodeIR(uint32_t code)
} }
if (nightlightActive && bri == 0) nightlightActive = false; if (nightlightActive && bri == 0) nightlightActive = false;
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //for notifier, IR is considered a button input colorUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input
} }
void applyRepeatActions(){ void applyRepeatActions(){
if (lastRepeatableAction == ACTION_BRIGHT_UP) if (lastRepeatableAction == ACTION_BRIGHT_UP)
{ {
incBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); incBrightness(); colorUpdated(CALL_MODE_BUTTON);
} }
else if (lastRepeatableAction == ACTION_BRIGHT_DOWN ) else if (lastRepeatableAction == ACTION_BRIGHT_DOWN )
{ {
decBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); decBrightness(); colorUpdated(CALL_MODE_BUTTON);
} }
if (lastRepeatableAction == ACTION_SPEED_UP) if (lastRepeatableAction == ACTION_SPEED_UP)
{ {
changeEffectSpeed(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); changeEffectSpeed(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON);
} }
else if (lastRepeatableAction == ACTION_SPEED_DOWN ) else if (lastRepeatableAction == ACTION_SPEED_DOWN )
{ {
changeEffectSpeed(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); changeEffectSpeed(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON);
} }
if (lastRepeatableAction == ACTION_INTENSITY_UP) if (lastRepeatableAction == ACTION_INTENSITY_UP)
{ {
changeEffectIntensity(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); changeEffectIntensity(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON);
} }
else if (lastRepeatableAction == ACTION_INTENSITY_DOWN ) else if (lastRepeatableAction == ACTION_INTENSITY_DOWN )
{ {
changeEffectIntensity(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); changeEffectIntensity(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON);
} }
if (lastValidCode == IR40_WPLUS) if (lastValidCode == IR40_WPLUS)
{ {
relativeChangeWhite(10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); relativeChangeWhite(10); colorUpdated(CALL_MODE_BUTTON);
} }
else if (lastValidCode == IR40_WMINUS) else if (lastValidCode == IR40_WMINUS)
{ {
relativeChangeWhite(-10, 5); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); relativeChangeWhite(-10, 5); colorUpdated(CALL_MODE_BUTTON);
} }
else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 ) else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 )
{ {
nightlightActive = true; nightlightActive = true;
nightlightStartTime = millis(); nightlightStartTime = millis();
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); colorUpdated(CALL_MODE_BUTTON);
} }
else if (irEnabled == 8) else if (irEnabled == 8)
{ {
@ -262,10 +262,10 @@ void decodeIR24(uint32_t code)
case IR24_MAGENTA : colorFromUint32(COLOR_MAGENTA); break; case IR24_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
case IR24_PINK : colorFromUint32(COLOR_PINK); break; case IR24_PINK : colorFromUint32(COLOR_PINK); break;
case IR24_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break; case IR24_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
case IR24_FLASH : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break; case IR24_FLASH : presetFallback(1, FX_MODE_COLORTWINKLE, effectPalette); break;
case IR24_STROBE : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break; case IR24_STROBE : presetFallback(2, FX_MODE_RAINBOW_CYCLE, effectPalette); break;
case IR24_FADE : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break; case IR24_FADE : presetFallback(3, FX_MODE_BREATH, effectPalette); break;
case IR24_SMOOTH : if (!applyPreset(4)) effectCurrent = FX_MODE_RAINBOW; break; case IR24_SMOOTH : presetFallback(4, FX_MODE_RAINBOW, effectPalette); break;
default: return; default: return;
} }
lastValidCode = code; lastValidCode = code;
@ -294,10 +294,10 @@ void decodeIR24OLD(uint32_t code)
case IR24_OLD_MAGENTA : colorFromUint32(COLOR_MAGENTA); break; case IR24_OLD_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
case IR24_OLD_PINK : colorFromUint32(COLOR_PINK); break; case IR24_OLD_PINK : colorFromUint32(COLOR_PINK); break;
case IR24_OLD_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break; case IR24_OLD_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
case IR24_OLD_FLASH : if (!applyPreset(1)) { effectCurrent = FX_MODE_COLORTWINKLE; effectPalette = 0; } break; case IR24_OLD_FLASH : presetFallback(1, FX_MODE_COLORTWINKLE, 0); break;
case IR24_OLD_STROBE : if (!applyPreset(2)) { effectCurrent = FX_MODE_RAINBOW_CYCLE; effectPalette = 0; } break; case IR24_OLD_STROBE : presetFallback(2, FX_MODE_RAINBOW_CYCLE, 0); break;
case IR24_OLD_FADE : if (!applyPreset(3)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break; case IR24_OLD_FADE : presetFallback(3, FX_MODE_BREATH, 0); break;
case IR24_OLD_SMOOTH : if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break; case IR24_OLD_SMOOTH : presetFallback(4, FX_MODE_RAINBOW, 0); break;
default: return; default: return;
} }
lastValidCode = code; lastValidCode = code;
@ -386,10 +386,10 @@ void decodeIR40(uint32_t code)
case IR40_SLOW : changeEffectSpeed(-16); break; case IR40_SLOW : changeEffectSpeed(-16); break;
case IR40_JUMP7 : changeEffectIntensity( 16); break; case IR40_JUMP7 : changeEffectIntensity( 16); break;
case IR40_AUTO : changeEffectIntensity(-16); break; case IR40_AUTO : changeEffectIntensity(-16); break;
case IR40_JUMP3 : if (!applyPreset(1)) { effectCurrent = FX_MODE_STATIC; effectPalette = 0; } break; case IR40_JUMP3 : presetFallback(1, FX_MODE_STATIC, 0); break;
case IR40_FADE3 : if (!applyPreset(2)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break; case IR40_FADE3 : presetFallback(2, FX_MODE_BREATH, 0); break;
case IR40_FADE7 : if (!applyPreset(3)) { effectCurrent = FX_MODE_FIRE_FLICKER; effectPalette = 0; } break; case IR40_FADE7 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
case IR40_FLASH : if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break; case IR40_FLASH : presetFallback(4, FX_MODE_RAINBOW, 0); break;
} }
lastValidCode = code; lastValidCode = code;
} }
@ -441,12 +441,12 @@ void decodeIR44(uint32_t code)
case IR44_BLUEMINUS : changeEffectIntensity(-16); break; case IR44_BLUEMINUS : changeEffectIntensity(-16); break;
case IR44_QUICK : changeEffectSpeed( 16); break; case IR44_QUICK : changeEffectSpeed( 16); break;
case IR44_SLOW : changeEffectSpeed(-16); break; case IR44_SLOW : changeEffectSpeed(-16); break;
case IR44_DIY1 : if (!applyPreset(1)) { effectCurrent = FX_MODE_STATIC; effectPalette = 0; } break; case IR44_DIY1 : presetFallback(1, FX_MODE_STATIC, 0); break;
case IR44_DIY2 : if (!applyPreset(2)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break; case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break;
case IR44_DIY3 : if (!applyPreset(3)) { effectCurrent = FX_MODE_FIRE_FLICKER; effectPalette = 0; } break; case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
case IR44_DIY4 : if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break; case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break;
case IR44_DIY5 : if (!applyPreset(5)) { effectCurrent = FX_MODE_METEOR_SMOOTH; effectPalette = 0; } break; case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR_SMOOTH, 0); break;
case IR44_DIY6 : if (!applyPreset(6)) { effectCurrent = FX_MODE_RAIN; effectPalette = 0; } break; case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break;
case IR44_AUTO : effectCurrent = FX_MODE_STATIC; break; case IR44_AUTO : effectCurrent = FX_MODE_STATIC; break;
case IR44_FLASH : effectCurrent = FX_MODE_PALETTE; break; case IR44_FLASH : effectCurrent = FX_MODE_PALETTE; break;
case IR44_JUMP3 : bri = 63; break; case IR44_JUMP3 : bri = 63; break;
@ -477,10 +477,10 @@ void decodeIR21(uint32_t code)
case IR21_PURPLE: colorFromUint32(COLOR_PURPLE); break; case IR21_PURPLE: colorFromUint32(COLOR_PURPLE); break;
case IR21_PINK: colorFromUint32(COLOR_PINK); break; case IR21_PINK: colorFromUint32(COLOR_PINK); break;
case IR21_WHITE: colorFromUint32(COLOR_WHITE); effectCurrent = 0; break; case IR21_WHITE: colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
case IR21_FLASH: if (!applyPreset(1)) { effectCurrent = FX_MODE_COLORTWINKLE; effectPalette = 0; } break; case IR21_FLASH: presetFallback(1, FX_MODE_COLORTWINKLE, 0); break;
case IR21_STROBE: if (!applyPreset(2)) { effectCurrent = FX_MODE_RAINBOW_CYCLE; effectPalette = 0; } break; case IR21_STROBE: presetFallback(2, FX_MODE_RAINBOW_CYCLE, 0); break;
case IR21_FADE: if (!applyPreset(3)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break; case IR21_FADE: presetFallback(3, FX_MODE_BREATH, 0); break;
case IR21_SMOOTH: if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break; case IR21_SMOOTH: presetFallback(4, FX_MODE_RAINBOW, 0); break;
default: return; default: return;
} }
lastValidCode = code; lastValidCode = code;
@ -522,9 +522,9 @@ void decodeIR9(uint32_t code)
{ {
switch (code) { switch (code) {
case IR9_POWER : toggleOnOff(); break; case IR9_POWER : toggleOnOff(); break;
case IR9_A : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break; case IR9_A : presetFallback(1, FX_MODE_COLORTWINKLE, effectPalette); break;
case IR9_B : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break; case IR9_B : presetFallback(2, FX_MODE_RAINBOW_CYCLE, effectPalette); break;
case IR9_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break; case IR9_C : presetFallback(3, FX_MODE_BREATH, effectPalette); break;
case IR9_UP : incBrightness(); break; case IR9_UP : incBrightness(); break;
case IR9_DOWN : decBrightness(); break; case IR9_DOWN : decBrightness(); break;
//case IR9_UP : changeEffectIntensity(16); break; //case IR9_UP : changeEffectIntensity(16); break;
@ -616,7 +616,7 @@ void decodeIRJson(uint32_t code)
// command is JSON object // command is JSON object
//allow applyPreset() to reuse JSON buffer, or it would alloc. a second buffer and run out of mem. //allow applyPreset() to reuse JSON buffer, or it would alloc. a second buffer and run out of mem.
fileDoc = &irDoc; fileDoc = &irDoc;
deserializeState(jsonCmdObj); deserializeState(jsonCmdObj, CALL_MODE_BUTTON);
fileDoc = nullptr; fileDoc = nullptr;
} }
} }

View File

@ -207,7 +207,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
return; // seg.hasChanged(prev); return; // seg.hasChanged(prev);
} }
bool deserializeState(JsonObject root, byte presetId) bool deserializeState(JsonObject root, byte callMode, byte presetId)
{ {
DEBUG_PRINTLN(F("Deserializing state")); DEBUG_PRINTLN(F("Deserializing state"));
@ -337,7 +337,7 @@ bool deserializeState(JsonObject root, byte presetId)
if (ps >= 0) { if (ps >= 0) {
DEBUG_PRINTLN(F("Applying preset")); DEBUG_PRINTLN(F("Applying preset"));
if (!presetId) unloadPlaylist(); //stop playlist if preset changed manually if (!presetId) unloadPlaylist(); //stop playlist if preset changed manually
applyPreset(ps); applyPreset(ps, callMode);
return stateResponse; return stateResponse;
} }
@ -355,10 +355,10 @@ bool deserializeState(JsonObject root, byte presetId)
loadPlaylist(playlist, presetId); loadPlaylist(playlist, presetId);
noNotification = true; //do not notify both for this request and the first playlist entry noNotification = true; //do not notify both for this request and the first playlist entry
} else { } else {
interfaceUpdateCallMode = NOTIFIER_CALL_MODE_WS_SEND; interfaceUpdateCallMode = CALL_MODE_WS_SEND;
} }
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(noNotification ? CALL_MODE_NO_NOTIFY : callMode);
return stateResponse; return stateResponse;
} }

View File

@ -88,13 +88,13 @@ void colorUpdated(int callMode)
{ {
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
if (callMode != NOTIFIER_CALL_MODE_INIT && if (callMode != CALL_MODE_INIT &&
callMode != NOTIFIER_CALL_MODE_DIRECT_CHANGE && callMode != CALL_MODE_DIRECT_CHANGE &&
callMode != NOTIFIER_CALL_MODE_NO_NOTIFY) strip.applyToAllSelected = true; //if not from JSON api, which directly sets segments callMode != CALL_MODE_NO_NOTIFY) strip.applyToAllSelected = true; //if not from JSON api, which directly sets segments
bool someSel = false; bool someSel = false;
if (callMode == NOTIFIER_CALL_MODE_NOTIFICATION) { if (callMode == CALL_MODE_NOTIFICATION) {
someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
} }
@ -119,17 +119,17 @@ void colorUpdated(int callMode)
interfaceUpdateCallMode = callMode; interfaceUpdateCallMode = callMode;
} else { } else {
if (nightlightActive && !nightlightActiveOld && if (nightlightActive && !nightlightActiveOld &&
callMode != NOTIFIER_CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NOTIFICATION &&
callMode != NOTIFIER_CALL_MODE_NO_NOTIFY) callMode != CALL_MODE_NO_NOTIFY)
{ {
notify(NOTIFIER_CALL_MODE_NIGHTLIGHT); notify(CALL_MODE_NIGHTLIGHT);
interfaceUpdateCallMode = NOTIFIER_CALL_MODE_NIGHTLIGHT; interfaceUpdateCallMode = CALL_MODE_NIGHTLIGHT;
} }
} }
if (!colChanged) return; //following code is for e.g. initiating transitions if (!colChanged) return; //following code is for e.g. initiating transitions
if (callMode != NOTIFIER_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; briNlT = bri;
nightlightDelayMs -= (millis() - nightlightStartTime); nightlightDelayMs -= (millis() - nightlightStartTime);
@ -143,19 +143,19 @@ void colorUpdated(int callMode)
if (briT == 0) if (briT == 0)
{ {
//setLedsStandard(true); //do not color transition if starting from off! //setLedsStandard(true); //do not color transition if starting from off!
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
} }
briIT = bri; briIT = bri;
if (bri > 0) briLast = bri; if (bri > 0) briLast = bri;
//deactivate nightlight if target brightness is reached //deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri && callMode != NOTIFIER_CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false; 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 //set correct delay if not using notification delay
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay; if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
jsonTransitionOnce = false; jsonTransitionOnce = false;
strip.setTransition(transitionDelayTemp); strip.setTransition(transitionDelayTemp);
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;} if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
@ -180,20 +180,20 @@ void colorUpdated(int callMode)
void updateInterfaces(uint8_t callMode) void updateInterfaces(uint8_t callMode)
{ {
sendDataWs(); sendDataWs();
if (callMode == NOTIFIER_CALL_MODE_WS_SEND) { if (callMode == CALL_MODE_WS_SEND) {
lastInterfaceUpdate = millis(); lastInterfaceUpdate = millis();
return; return;
} }
#ifndef WLED_DISABLE_ALEXA #ifndef WLED_DISABLE_ALEXA
if (espalexaDevice != nullptr && callMode != NOTIFIER_CALL_MODE_ALEXA) { if (espalexaDevice != nullptr && callMode != CALL_MODE_ALEXA) {
espalexaDevice->setValue(bri); espalexaDevice->setValue(bri);
espalexaDevice->setColor(col[0], col[1], col[2]); espalexaDevice->setColor(col[0], col[1], col[2]);
} }
#endif #endif
#ifndef WLED_DISABLE_BLYNK #ifndef WLED_DISABLE_BLYNK
if (callMode != NOTIFIER_CALL_MODE_BLYNK && if (callMode != CALL_MODE_BLYNK &&
callMode != NOTIFIER_CALL_MODE_NO_NOTIFY) updateBlynk(); callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
#endif #endif
doPublishMqtt = true; doPublishMqtt = true;
lastInterfaceUpdate = millis(); lastInterfaceUpdate = millis();
@ -256,7 +256,7 @@ void handleNightlight()
if (bri) effectSpeed += 60; //sunset if currently on if (bri) effectSpeed += 60; //sunset if currently on
briNlT = !bri; //true == sunrise, false == sunset briNlT = !bri; //true == sunrise, false == sunset
if (!bri) bri = briLast; if (!bri) bri = briLast;
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY); colorUpdated(CALL_MODE_NO_NOTIFY);
} }
} }
float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs); float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs);
@ -267,7 +267,7 @@ void handleNightlight()
{ {
for (byte i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color for (byte i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color
} }
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY); colorUpdated(CALL_MODE_NO_NOTIFY);
} }
if (nper >= 1) //nightlight duration over if (nper >= 1) //nightlight duration over
{ {
@ -275,7 +275,7 @@ void handleNightlight()
if (nightlightMode == NL_MODE_SET) if (nightlightMode == NL_MODE_SET)
{ {
bri = nightlightTargetBri; bri = nightlightTargetBri;
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY); colorUpdated(CALL_MODE_NO_NOTIFY);
} }
if (bri == 0) briLast = briNlT; if (bri == 0) briLast = briNlT;
if (nightlightMode == NL_MODE_SUN) if (nightlightMode == NL_MODE_SUN)
@ -301,7 +301,7 @@ void handleNightlight()
effectCurrent = colNlT[0]; effectCurrent = colNlT[0];
effectSpeed = colNlT[1]; effectSpeed = colNlT[1];
effectPalette = colNlT[2]; effectPalette = colNlT[2];
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY); colorUpdated(CALL_MODE_NO_NOTIFY);
} }
nightlightActiveOld = false; nightlightActiveOld = false;
} }

View File

@ -15,7 +15,7 @@ void parseMQTTBriPayload(char* payload)
uint8_t in = strtoul(payload, NULL, 10); uint8_t in = strtoul(payload, NULL, 10);
if (in == 0 && bri > 0) briLast = bri; if (in == 0 && bri > 0) briLast = bri;
bri = in; bri = in;
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
} }
} }
@ -88,12 +88,14 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
if (strcmp_P(topic, PSTR("/col")) == 0) { if (strcmp_P(topic, PSTR("/col")) == 0) {
colorFromDecOrHexString(col, (char*)payloadStr); colorFromDecOrHexString(col, (char*)payloadStr);
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
} else if (strcmp_P(topic, PSTR("/api")) == 0) { } else if (strcmp_P(topic, PSTR("/api")) == 0) {
if (payload[0] == '{') { //JSON API if (payload[0] == '{') { //JSON API
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
deserializeJson(doc, payloadStr); deserializeJson(doc, payloadStr);
fileDoc = &doc;
deserializeState(doc.as<JsonObject>()); deserializeState(doc.as<JsonObject>());
fileDoc = nullptr;
} else { //HTTP API } else { //HTTP API
String apireq = "win&"; String apireq = "win&";
apireq += (char*)payloadStr; apireq += (char*)payloadStr;

View File

@ -4,7 +4,7 @@
* Methods to handle saving and loading presets to/from the filesystem * Methods to handle saving and loading presets to/from the filesystem
*/ */
bool applyPreset(byte index) bool applyPreset(byte index, byte callMode)
{ {
if (index == 0) return false; if (index == 0) return false;
if (fileDoc) { if (fileDoc) {
@ -14,7 +14,7 @@ bool applyPreset(byte index)
#ifdef WLED_DEBUG_FS #ifdef WLED_DEBUG_FS
serializeJson(*fileDoc, Serial); serializeJson(*fileDoc, Serial);
#endif #endif
deserializeState(fdo, index); deserializeState(fdo, callMode, index);
} else { } else {
DEBUGFS_PRINTLN(F("Make read buf")); DEBUGFS_PRINTLN(F("Make read buf"));
DynamicJsonDocument fDoc(JSON_BUFFER_SIZE); DynamicJsonDocument fDoc(JSON_BUFFER_SIZE);
@ -24,7 +24,7 @@ bool applyPreset(byte index)
#ifdef WLED_DEBUG_FS #ifdef WLED_DEBUG_FS
serializeJson(fDoc, Serial); serializeJson(fDoc, Serial);
#endif #endif
deserializeState(fdo, index); deserializeState(fdo, callMode, index);
} }
if (!errorFlag) { if (!errorFlag) {

View File

@ -918,7 +918,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
strip.applyToAllSelected = false; strip.applyToAllSelected = false;
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
colorUpdated((pos > 0) ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
return true; return true;
} }

View File

@ -13,14 +13,14 @@ void notify(byte callMode, bool followUp)
if (!udpConnected) return; if (!udpConnected) return;
switch (callMode) switch (callMode)
{ {
case NOTIFIER_CALL_MODE_INIT: return; case CALL_MODE_INIT: return;
case NOTIFIER_CALL_MODE_DIRECT_CHANGE: if (!notifyDirect) return; break; case CALL_MODE_DIRECT_CHANGE: if (!notifyDirect) return; break;
case NOTIFIER_CALL_MODE_BUTTON: if (!notifyButton) return; break; case CALL_MODE_BUTTON: if (!notifyButton) return; break;
case NOTIFIER_CALL_MODE_NIGHTLIGHT: if (!notifyDirect) return; break; case CALL_MODE_NIGHTLIGHT: if (!notifyDirect) return; break;
case NOTIFIER_CALL_MODE_HUE: if (!notifyHue) return; break; case CALL_MODE_HUE: if (!notifyHue) return; break;
case NOTIFIER_CALL_MODE_PRESET_CYCLE: if (!notifyDirect) return; break; case CALL_MODE_PRESET_CYCLE: if (!notifyDirect) return; break;
case NOTIFIER_CALL_MODE_BLYNK: if (!notifyDirect) return; break; case CALL_MODE_BLYNK: if (!notifyDirect) return; break;
case NOTIFIER_CALL_MODE_ALEXA: if (!notifyAlexa) return; break; case CALL_MODE_ALEXA: if (!notifyAlexa) return; break;
default: return; default: return;
} }
byte udpOut[WLEDPACKETSIZE]; byte udpOut[WLEDPACKETSIZE];
@ -300,7 +300,7 @@ void handleNotifications()
if (nightlightActive) nightlightDelayMins = udpIn[7]; if (nightlightActive) nightlightDelayMins = udpIn[7];
if (receiveNotificationBrightness || !someSel) bri = udpIn[2]; if (receiveNotificationBrightness || !someSel) bri = udpIn[2];
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); colorUpdated(CALL_MODE_NOTIFICATION);
return; return;
} }

View File

@ -78,6 +78,10 @@
#include "../usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h" #include "../usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h"
#endif #endif
#ifdef RGB_ROTARY_ENCODER
#include "../usermods/rgb-rotary-encoder/rgb-rotary-encoder.h"
#endif
void registerUsermods() void registerUsermods()
{ {
/* /*
@ -151,4 +155,8 @@ void registerUsermods()
#ifdef USERMOD_ROTARY_ENCODER_BRIGHTNESS_COLOR #ifdef USERMOD_ROTARY_ENCODER_BRIGHTNESS_COLOR
usermods.add(new RotaryEncoderBrightnessColor()); usermods.add(new RotaryEncoderBrightnessColor());
#endif #endif
#ifdef RGB_ROTARY_ENCODER
usermods.add(new RgbRotaryEncoderUsermod());
#endif
} }

View File

@ -270,6 +270,18 @@ void WLED::loop()
if (busConfigs[i] == nullptr) break; if (busConfigs[i] == nullptr) break;
mem += BusManager::memUsage(*busConfigs[i]); mem += BusManager::memUsage(*busConfigs[i]);
if (mem <= MAX_LED_MEMORY) busses.add(*busConfigs[i]); if (mem <= MAX_LED_MEMORY) busses.add(*busConfigs[i]);
/*
if (busConfigs[i]->adjustBounds(ledCount)) {
mem += busses.memUsage(*busConfigs[i]);
if (mem <= MAX_LED_MEMORY) {
busses.add(*busConfigs[i]);
//RGBW mode is enabled if at least one of the strips is RGBW
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(busConfigs[i]->type));
//refresh is required to remain off if at least one of the strips requires the refresh.
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(busConfigs[i]->type);
}
}
*/
delete busConfigs[i]; busConfigs[i] = nullptr; delete busConfigs[i]; busConfigs[i] = nullptr;
} }
strip.finalizeInit(); strip.finalizeInit();
@ -354,6 +366,8 @@ void WLED::setup()
pinManager.allocatePin(2); pinManager.allocatePin(2);
#endif #endif
for (uint8_t i=1; i<WLED_MAX_BUTTONS; i++) btnPin[i] = -1;
bool fsinit = false; bool fsinit = false;
DEBUGFS_PRINTLN(F("Mount FS")); DEBUGFS_PRINTLN(F("Mount FS"));
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
@ -450,9 +464,9 @@ void WLED::beginStrip()
briLast = briS; bri = 0; briLast = briS; bri = 0;
} }
if (bootPreset > 0) { if (bootPreset > 0) {
applyPreset(bootPreset); applyPreset(bootPreset, CALL_MODE_INIT);
} }
colorUpdated(NOTIFIER_CALL_MODE_INIT); colorUpdated(CALL_MODE_INIT);
// init relay pin // init relay pin
if (rlyPin>=0) if (rlyPin>=0)
@ -504,7 +518,44 @@ void WLED::initConnection()
// Only initialize ethernet board if not NONE // Only initialize ethernet board if not NONE
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
ethernet_settings es = ethernetBoards[ethernetType]; ethernet_settings es = ethernetBoards[ethernetType];
ETH.begin( // Use PinManager to ensure pins are available for
// ethernet AND to prevent other uses of these pins.
bool s = true;
byte pinsAllocated[4] { 255, 255, 255, 255 };
if (s && (s = pinManager.allocatePin((byte)es.eth_power))) {
pinsAllocated[0] = (byte)es.eth_power;
}
if (s && (s = pinManager.allocatePin((byte)es.eth_mdc))) {
pinsAllocated[1] = (byte)es.eth_mdc;
}
if (s && (s = pinManager.allocatePin((byte)es.eth_mdio))) {
pinsAllocated[2] = (byte)es.eth_mdio;
}
switch(es.eth_clk_mode) {
case ETH_CLOCK_GPIO0_IN:
s = pinManager.allocatePin(0, false);
pinsAllocated[3] = 0;
break;
case ETH_CLOCK_GPIO0_OUT:
s = pinManager.allocatePin(0);
pinsAllocated[3] = 0;
break;
case ETH_CLOCK_GPIO16_OUT:
s = pinManager.allocatePin(16);
pinsAllocated[3] = 16;
break;
case ETH_CLOCK_GPIO17_OUT:
s = pinManager.allocatePin(17);
pinsAllocated[3] = 17;
break;
default:
s = false;
break;
}
if (s) {
s = ETH.begin(
(uint8_t) es.eth_address, (uint8_t) es.eth_address,
(int) es.eth_power, (int) es.eth_power,
(int) es.eth_mdc, (int) es.eth_mdc,
@ -513,6 +564,15 @@ void WLED::initConnection()
(eth_clock_mode_t) es.eth_clk_mode (eth_clock_mode_t) es.eth_clk_mode
); );
} }
if (!s) {
DEBUG_PRINTLN(F("Ethernet init failed"));
// de-allocate only those pins allocated before the failure
for (byte p : pinsAllocated) {
pinManager.deallocatePin(p);
}
}
}
#endif #endif
WiFi.disconnect(true); // close old connections WiFi.disconnect(true); // close old connections

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2107080 #define VERSION 2107101
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -449,7 +449,7 @@ WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESH
WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect); WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect);
WLED_GLOBAL bool receiveNotifications _INIT(true); WLED_GLOBAL bool receiveNotifications _INIT(true);
WLED_GLOBAL unsigned long notificationSentTime _INIT(0); WLED_GLOBAL unsigned long notificationSentTime _INIT(0);
WLED_GLOBAL byte notificationSentCallMode _INIT(NOTIFIER_CALL_MODE_INIT); WLED_GLOBAL byte notificationSentCallMode _INIT(CALL_MODE_INIT);
WLED_GLOBAL bool notificationTwoRequired _INIT(false); WLED_GLOBAL bool notificationTwoRequired _INIT(false);
// effects // effects
@ -515,7 +515,7 @@ WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
// mqtt // mqtt
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0);
WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0); WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0);
WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT); WLED_GLOBAL byte interfaceUpdateCallMode _INIT(CALL_MODE_INIT);
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
// alexa udp // alexa udp