mirror of
https://github.com/wled/WLED.git
synced 2025-07-23 02:36:39 +00:00
Merge pull request #1218 from Aircoookie/mergefs-201002
Update FS branch
This commit is contained in:
commit
8a713b2bbb
23
CHANGELOG.md
23
CHANGELOG.md
@ -2,6 +2,29 @@
|
|||||||
|
|
||||||
### Development versions after the 0.10.2 release
|
### Development versions after the 0.10.2 release
|
||||||
|
|
||||||
|
#### Build 2010020
|
||||||
|
|
||||||
|
- Fixed interaction of `T` and `NL` HTTP API commands (#1214)
|
||||||
|
- Fixed an issue where Sunrise mode nightlight does not activate if toggled on simultaneously
|
||||||
|
|
||||||
|
#### Build 2009291
|
||||||
|
|
||||||
|
- Fixed MQTT bootloop (no F() macro, #1199)
|
||||||
|
|
||||||
|
#### Build 2009290
|
||||||
|
|
||||||
|
- Added basic DDP protocol support
|
||||||
|
- Added Washing Machine effect (PR #1208)
|
||||||
|
|
||||||
|
#### Build 2009260
|
||||||
|
|
||||||
|
- Added Loxone parser (PR #1185)
|
||||||
|
- Added support for kelvin input via `K=` HTTP and `"col":[[val]]` JSON API calls
|
||||||
|
- Added supplementary UDP socket (#1205)
|
||||||
|
- TMP2.net receivable by default
|
||||||
|
- UDP sockets accept HTTP and JSON API commands
|
||||||
|
- Fixed missing timezones (#1201)
|
||||||
|
|
||||||
#### Build 2009202
|
#### Build 2009202
|
||||||
|
|
||||||
- Fixed LPD8806 compilation
|
- Fixed LPD8806 compilation
|
||||||
|
@ -377,3 +377,43 @@ build_flags = ${common.build_flags_esp8266} ${common.debug_flags} ${common.build
|
|||||||
extends = env:esp32dev
|
extends = env:esp32dev
|
||||||
; build_type = debug
|
; build_type = debug
|
||||||
build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features}
|
build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# codm pixel controller board configurations
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[env:codm-controller-0.4]
|
||||||
|
board = esp_wroom_02
|
||||||
|
platform = ${common.platform_wled_default}
|
||||||
|
board_build.ldscript = ${common.ldscript_2m1m}
|
||||||
|
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
|
||||||
|
|
||||||
|
[env:codm-controller-0.4-WS2801]
|
||||||
|
board = esp_wroom_02
|
||||||
|
platform = ${common.platform_latest}
|
||||||
|
board_build.ldscript = ${common.ldscript_2m1m}
|
||||||
|
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 -D CLKPIN=13 -D DATAPIN=3
|
||||||
|
|
||||||
|
[env:codm-controller-0.4-APA102]
|
||||||
|
board = esp_wroom_02
|
||||||
|
platform = ${common.platform_latest}
|
||||||
|
board_build.ldscript = ${common.ldscript_2m1m}
|
||||||
|
build_flags = ${common.build_flags_esp8266} -D USE_APA102 -D CLKPIN=13 -D DATAPIN=3
|
||||||
|
|
||||||
|
[env:codm-controller-0.5]
|
||||||
|
board = esp_wroom_02
|
||||||
|
platform = ${common.platform_wled_default}
|
||||||
|
board_build.ldscript = ${common.ldscript_2m1m}
|
||||||
|
build_flags = ${common.build_flags_esp8266}
|
||||||
|
|
||||||
|
[env:codm-controller-0.5-WS2801]
|
||||||
|
board = esp_wroom_02
|
||||||
|
platform = ${common.platform_latest}
|
||||||
|
board_build.ldscript = ${common.ldscript_2m1m}
|
||||||
|
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 #-D CLKPIN=0 -D DATAPIN=2
|
||||||
|
|
||||||
|
[env:codm-controller-0.5-APA102]
|
||||||
|
board = esp_wroom_02
|
||||||
|
platform = ${common.platform_latest}
|
||||||
|
board_build.ldscript = ${common.ldscript_2m1m}
|
||||||
|
build_flags = ${common.build_flags_esp8266} -D USE_APA102 #-D CLKPIN=0 -D DATAPIN=2
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="/images/wled_logo_akemi.png">
|
<img src="/images/wled_logo_akemi.png">
|
||||||
<a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a>
|
<a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a>
|
||||||
|
<a href="https://raw.githubusercontent.com/Aircoookie/WLED/master/LICENSE"><img src="https://img.shields.io/github/license/Aircoookie/wled?color=blue&style=flat-square"></a>
|
||||||
<a href="https://wled.discourse.group"><img src="https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square"></a>
|
<a href="https://wled.discourse.group"><img src="https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square"></a>
|
||||||
<a href="https://discord.gg/KuqP7NE"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
|
<a href="https://discord.gg/KuqP7NE"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
|
||||||
<a href="https://github.com/Aircoookie/WLED/wiki"><img src="https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square"></a>
|
<a href="https://github.com/Aircoookie/WLED/wiki"><img src="https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square"></a>
|
||||||
<a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a>
|
<a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# Welcome to my project WLED! ✨
|
# Welcome to my project WLED! ✨
|
||||||
|
@ -3712,3 +3712,22 @@ uint16_t WS2812FX::mode_dancing_shadows(void)
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Imitates a washing machine, rotating same waves forward, then pause, then backward.
|
||||||
|
By Stefan Seegel
|
||||||
|
*/
|
||||||
|
uint16_t WS2812FX::mode_washing_machine(void) {
|
||||||
|
float speed = tristate_square8(now >> 7, 90, 15);
|
||||||
|
float quot = 32.0f - ((float)SEGMENT.speed / 16.0f);
|
||||||
|
speed /= quot;
|
||||||
|
|
||||||
|
SEGENV.step += (speed * 128.0f);
|
||||||
|
|
||||||
|
for (int i=0; i<SEGLEN; i++) {
|
||||||
|
uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
|
||||||
|
setPixelColor(i, color_from_palette(col, false, PALETTE_SOLID_WRAP, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FRAMETIME;
|
||||||
|
}
|
||||||
|
12
wled00/FX.h
12
wled00/FX.h
@ -107,7 +107,7 @@
|
|||||||
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
||||||
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
||||||
|
|
||||||
#define MODE_COUNT 113
|
#define MODE_COUNT 114
|
||||||
|
|
||||||
#define FX_MODE_STATIC 0
|
#define FX_MODE_STATIC 0
|
||||||
#define FX_MODE_BLINK 1
|
#define FX_MODE_BLINK 1
|
||||||
@ -222,6 +222,7 @@
|
|||||||
#define FX_MODE_FLOW 110
|
#define FX_MODE_FLOW 110
|
||||||
#define FX_MODE_CHUNCHUN 111
|
#define FX_MODE_CHUNCHUN 111
|
||||||
#define FX_MODE_DANCING_SHADOWS 112
|
#define FX_MODE_DANCING_SHADOWS 112
|
||||||
|
#define FX_MODE_WASHING_MACHINE 113
|
||||||
|
|
||||||
class WS2812FX {
|
class WS2812FX {
|
||||||
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
||||||
@ -426,6 +427,7 @@ class WS2812FX {
|
|||||||
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
|
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
|
||||||
_mode[FX_MODE_CHUNCHUN] = &WS2812FX::mode_chunchun;
|
_mode[FX_MODE_CHUNCHUN] = &WS2812FX::mode_chunchun;
|
||||||
_mode[FX_MODE_DANCING_SHADOWS] = &WS2812FX::mode_dancing_shadows;
|
_mode[FX_MODE_DANCING_SHADOWS] = &WS2812FX::mode_dancing_shadows;
|
||||||
|
_mode[FX_MODE_WASHING_MACHINE] = &WS2812FX::mode_washing_machine;
|
||||||
|
|
||||||
_brightness = DEFAULT_BRIGHTNESS;
|
_brightness = DEFAULT_BRIGHTNESS;
|
||||||
currentPalette = CRGBPalette16(CRGB::Black);
|
currentPalette = CRGBPalette16(CRGB::Black);
|
||||||
@ -485,6 +487,9 @@ class WS2812FX {
|
|||||||
gamma8(uint8_t),
|
gamma8(uint8_t),
|
||||||
get_random_wheel_index(uint8_t);
|
get_random_wheel_index(uint8_t);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
|
||||||
|
|
||||||
uint16_t
|
uint16_t
|
||||||
ablMilliampsMax,
|
ablMilliampsMax,
|
||||||
currentMilliamps,
|
currentMilliamps,
|
||||||
@ -625,7 +630,8 @@ class WS2812FX {
|
|||||||
mode_phased_noise(void),
|
mode_phased_noise(void),
|
||||||
mode_flow(void),
|
mode_flow(void),
|
||||||
mode_chunchun(void),
|
mode_chunchun(void),
|
||||||
mode_dancing_shadows(void);
|
mode_dancing_shadows(void),
|
||||||
|
mode_washing_machine(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoPixelWrapper *bus;
|
NeoPixelWrapper *bus;
|
||||||
@ -712,7 +718,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
|
|||||||
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
|
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
|
||||||
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
|
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
|
||||||
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
|
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
|
||||||
"Flow","Chunchun","Dancing Shadows"
|
"Flow","Chunchun","Dancing Shadows","Washing Machine"
|
||||||
])=====";
|
])=====";
|
||||||
|
|
||||||
|
|
||||||
|
@ -699,6 +699,32 @@ uint16_t WS2812FX::triwave16(uint16_t in)
|
|||||||
return 0xFFFF - (in - 0x8000)*2;
|
return 0xFFFF - (in - 0x8000)*2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates a tristate square wave w/ attac & decay
|
||||||
|
* @param x input value 0-255
|
||||||
|
* @param pulsewidth 0-127
|
||||||
|
* @param attdec attac & decay, max. pulsewidth / 2
|
||||||
|
* @returns signed waveform value
|
||||||
|
*/
|
||||||
|
int8_t WS2812FX::tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
|
||||||
|
int8_t a = 127;
|
||||||
|
if (x > 127) {
|
||||||
|
a = -127;
|
||||||
|
x -= 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x < attdec) { //inc to max
|
||||||
|
return (int16_t) x * a / attdec;
|
||||||
|
}
|
||||||
|
else if (x < pulsewidth - attdec) { //max
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
else if (x < pulsewidth) { //dec to 0
|
||||||
|
return (int16_t) (pulsewidth - x) * a / attdec;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put a value 0 to 255 in to get a color value.
|
* Put a value 0 to 255 in to get a color value.
|
||||||
* The colours are a transition r -> g -> b -> back to r
|
* The colours are a transition r -> g -> b -> back to r
|
||||||
@ -844,7 +870,7 @@ void WS2812FX::handle_palette(void)
|
|||||||
load_gradient_palette(paletteIndex -13);
|
load_gradient_palette(paletteIndex -13);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode
|
if (singleSegmentMode && paletteFade && SEGENV.call > 0) //only blend if just one segment uses FastLED mode
|
||||||
{
|
{
|
||||||
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
|
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
|
||||||
} else
|
} else
|
||||||
|
@ -88,11 +88,20 @@
|
|||||||
#define W2PIN 5 //W2 pin for analog LED strip
|
#define W2PIN 5 //W2 pin for analog LED strip
|
||||||
#undef IR_PIN
|
#undef IR_PIN
|
||||||
#else
|
#else
|
||||||
|
//Enable override of Pins by using the platformio_override.ini file
|
||||||
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
|
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
|
||||||
#define RPIN 5 //R pin for analog LED strip
|
#ifndef RPIN
|
||||||
#define GPIN 12 //G pin for analog LED strip
|
#define RPIN 5 //R pin for analog LED strip
|
||||||
#define BPIN 15 //B pin for analog LED strip
|
#endif
|
||||||
#define WPIN 13 //W pin for analog LED strip
|
#ifndef GPIN
|
||||||
|
#define GPIN 12 //G pin for analog LED strip
|
||||||
|
#endif
|
||||||
|
#ifndef BPIN
|
||||||
|
#define BPIN 15 //B pin for analog LED strip
|
||||||
|
#endif
|
||||||
|
#ifndef WPIN
|
||||||
|
#define WPIN 13 //W pin for analog LED strip
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#undef RLYPIN
|
#undef RLYPIN
|
||||||
#define RLYPIN -1 //disable as pin 12 is used by analog LEDs
|
#define RLYPIN -1 //disable as pin 12 is used by analog LEDs
|
||||||
|
@ -62,7 +62,31 @@ void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
|||||||
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
|
void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc
|
||||||
|
{
|
||||||
|
float r = 0, g = 0, b = 0;
|
||||||
|
float temp = kelvin / 100;
|
||||||
|
if (temp <= 66) {
|
||||||
|
r = 255;
|
||||||
|
g = round(99.4708025861 * log(temp) - 161.1195681661);
|
||||||
|
if (temp <= 19) {
|
||||||
|
b = 0;
|
||||||
|
} else {
|
||||||
|
b = round(138.5177312231 * log((temp - 10)) - 305.0447927307);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = round(329.698727446 * pow((temp - 60), -0.1332047592));
|
||||||
|
g = round(288.1221695283 * pow((temp - 60), -0.0755148492));
|
||||||
|
b = 255;
|
||||||
|
}
|
||||||
|
g += 15; //mod by Aircoookie, a bit less accurate but visibly less pinkish
|
||||||
|
rgb[0] = (uint8_t) constrain(r, 0, 255);
|
||||||
|
rgb[1] = (uint8_t) constrain(g, 0, 255);
|
||||||
|
rgb[2] = (uint8_t) constrain(b, 0, 255);
|
||||||
|
rgb[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb, bins
|
||||||
{
|
{
|
||||||
//this is only an approximation using WS2812B with gamma correction enabled
|
//this is only an approximation using WS2812B with gamma correction enabled
|
||||||
if (mired > 475) {
|
if (mired > 475) {
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
#define REALTIME_MODE_ADALIGHT 5
|
#define REALTIME_MODE_ADALIGHT 5
|
||||||
#define REALTIME_MODE_ARTNET 6
|
#define REALTIME_MODE_ARTNET 6
|
||||||
#define REALTIME_MODE_TPM2NET 7
|
#define REALTIME_MODE_TPM2NET 7
|
||||||
|
#define REALTIME_MODE_DDP 8
|
||||||
|
|
||||||
//realtime override modes
|
//realtime override modes
|
||||||
#define REALTIME_OVERRIDE_NONE 0
|
#define REALTIME_OVERRIDE_NONE 0
|
||||||
|
@ -5,7 +5,7 @@ function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-
|
|||||||
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;}
|
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;} }
|
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 SP(){var p = d.Sf.DI.value; d.getElementById("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
function SP(){var p = d.Sf.DI.value; d.getElementById("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
||||||
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; }; SP();}
|
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();}
|
||||||
function S(){GetV();SetVal();}
|
function S(){GetV();SetVal();}
|
||||||
function GetV(){var d=document;}
|
function GetV(){var d=document;}
|
||||||
</script>
|
</script>
|
||||||
@ -31,13 +31,15 @@ Infrared remote:
|
|||||||
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
|
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
|
||||||
<h3>WLED Broadcast</h3>
|
<h3>WLED Broadcast</h3>
|
||||||
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
||||||
|
2nd Port: <input name="U2" type="number" min="1" max="65535" class="d5" required><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>
|
||||||
Send notifications on direct change: <input type="checkbox" name="SD"><br>
|
Send notifications on direct change: <input type="checkbox" name="SD"><br>
|
||||||
Send notifications on button press: <input type="checkbox" name="SB"><br>
|
Send notifications on button press: <input type="checkbox" name="SB"><br>
|
||||||
Send Alexa notifications: <input type="checkbox" name="SA"><br>
|
Send Alexa notifications: <input type="checkbox" name="SA"><br>
|
||||||
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
|
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
|
||||||
Send Macro notifications: <input type="checkbox" name="SM"><br>
|
Send Macro notifications: <input type="checkbox" name="SM"><br>
|
||||||
Send notifications twice: <input type="checkbox" name="S2">
|
Send notifications twice: <input type="checkbox" name="S2"><br>
|
||||||
|
<i>Reboot required to apply changes. </i>
|
||||||
<h3>Realtime</h3>
|
<h3>Realtime</h3>
|
||||||
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
|
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
|
||||||
<i>Network DMX input</i><br>
|
<i>Network DMX input</i><br>
|
||||||
@ -45,6 +47,7 @@ Type:
|
|||||||
<select name=DI onchange="SP(); adj();">
|
<select name=DI onchange="SP(); adj();">
|
||||||
<option value=5568>E1.31 (sACN)</option>
|
<option value=5568>E1.31 (sACN)</option>
|
||||||
<option value=6454>Art-Net</option>
|
<option value=6454>Art-Net</option>
|
||||||
|
<option value=4048>DDP</option>
|
||||||
<option value=0 selected>Custom port</option>
|
<option value=0 selected>Custom port</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<div id=xp>Port: <input name="EP" type="number" min="1" max="65535" value="5568" class="d5" required><br></div>
|
<div id=xp>Port: <input name="EP" type="number" min="1" max="65535" value="5568" class="d5" required><br></div>
|
||||||
|
@ -103,7 +103,11 @@
|
|||||||
<option value="10">JST(KST)</option>
|
<option value="10">JST(KST)</option>
|
||||||
<option value="11">AEST/AEDT</option>
|
<option value="11">AEST/AEDT</option>
|
||||||
<option value="12">NZST/NZDT</option>
|
<option value="12">NZST/NZDT</option>
|
||||||
<option value="13">North Korea</option>
|
<option value="13">North Korea</option>
|
||||||
|
<option value="14">IST (India)</option>
|
||||||
|
<option value="15">CA-Saskatchewan</option>
|
||||||
|
<option value="16">ACST</option>
|
||||||
|
<option value="17">ACST/ACDT</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<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>.
|
Current local time is <span class="times">unknown</span>.
|
||||||
|
@ -7,25 +7,66 @@
|
|||||||
* E1.31 handler
|
* E1.31 handler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
//DDP protocol support, called by handleE131Packet
|
||||||
//E1.31 protocol support
|
//handles RGB data only
|
||||||
|
void handleDDPPacket(e131_packet_t* p) {
|
||||||
|
int lastPushSeq = e131LastSequenceNumber[0];
|
||||||
|
|
||||||
|
//reject late packets belonging to previous frame (assuming 4 packets max. before push)
|
||||||
|
if (e131SkipOutOfSequence && lastPushSeq) {
|
||||||
|
int sn = p->sequenceNum & 0xF;
|
||||||
|
if (sn) {
|
||||||
|
if (lastPushSeq > 5) {
|
||||||
|
if (sn > (lastPushSeq -5) && sn < lastPushSeq) return;
|
||||||
|
} else {
|
||||||
|
if (sn > (10 + lastPushSeq) || sn < lastPushSeq) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t offsetLeds = htonl(p->channelOffset) /3;
|
||||||
|
uint16_t packetLeds = htons(p->dataLen) /3;
|
||||||
|
uint8_t* data = p->data;
|
||||||
|
uint16_t c = 0;
|
||||||
|
if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later
|
||||||
|
|
||||||
|
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
|
||||||
|
|
||||||
|
for (uint16_t i = offsetLeds; i < offsetLeds + packetLeds; i++) {
|
||||||
|
setRealtimePixel(i, data[c++], data[c++], data[c++], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool push = p->flags & DDP_PUSH_FLAG;
|
||||||
|
if (push) {
|
||||||
|
e131NewData = true;
|
||||||
|
byte sn = p->sequenceNum & 0xF;
|
||||||
|
if (sn) e131LastSequenceNumber[0] = sn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//E1.31 and Art-Net protocol support
|
||||||
|
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||||
|
|
||||||
uint16_t uni = 0, dmxChannels = 0;
|
uint16_t uni = 0, dmxChannels = 0;
|
||||||
uint8_t* e131_data = nullptr;
|
uint8_t* e131_data = nullptr;
|
||||||
uint8_t seq = 0, mde = REALTIME_MODE_E131;
|
uint8_t seq = 0, mde = REALTIME_MODE_E131;
|
||||||
|
|
||||||
if (isArtnet)
|
if (protocol == P_ARTNET)
|
||||||
{
|
{
|
||||||
uni = p->art_universe;
|
uni = p->art_universe;
|
||||||
dmxChannels = htons(p->art_length);
|
dmxChannels = htons(p->art_length);
|
||||||
e131_data = p->art_data;
|
e131_data = p->art_data;
|
||||||
seq = p->art_sequence_number;
|
seq = p->art_sequence_number;
|
||||||
mde = REALTIME_MODE_ARTNET;
|
mde = REALTIME_MODE_ARTNET;
|
||||||
} else {
|
} else if (protocol == P_E131) {
|
||||||
uni = htons(p->universe);
|
uni = htons(p->universe);
|
||||||
dmxChannels = htons(p->property_value_count) -1;
|
dmxChannels = htons(p->property_value_count) -1;
|
||||||
e131_data = p->property_values;
|
e131_data = p->property_values;
|
||||||
seq = p->sequence_number;
|
seq = p->sequence_number;
|
||||||
|
} else { //DDP
|
||||||
|
realtimeIP = clientIP;
|
||||||
|
handleDDPPacket(p);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
@ -133,7 +174,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// All subsequent universes start at the first channel.
|
// All subsequent universes start at the first channel.
|
||||||
dmxOffset = isArtnet ? 0 : 1;
|
dmxOffset = (protocol == P_ARTNET) ? 0 : 1;
|
||||||
uint16_t ledsInFirstUniverse = (MAX_CHANNELS_PER_UNIVERSE - DMXAddress) / 3;
|
uint16_t ledsInFirstUniverse = (MAX_CHANNELS_PER_UNIVERSE - DMXAddress) / 3;
|
||||||
previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * MAX_LEDS_PER_UNIVERSE;
|
previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * MAX_LEDS_PER_UNIVERSE;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ void colorFromUint32(uint32_t in, bool secondary = false);
|
|||||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||||
|
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||||
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
||||||
|
|
||||||
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
||||||
@ -43,7 +44,7 @@ void initDMX();
|
|||||||
void handleDMX();
|
void handleDMX();
|
||||||
|
|
||||||
//e131.cpp
|
//e131.cpp
|
||||||
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet);
|
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol);
|
||||||
|
|
||||||
//file.cpp
|
//file.cpp
|
||||||
bool handleFileRead(AsyncWebServerRequest*, String path);
|
bool handleFileRead(AsyncWebServerRequest*, String path);
|
||||||
@ -106,6 +107,10 @@ void updateInterfaces(uint8_t callMode);
|
|||||||
void handleTransitions();
|
void handleTransitions();
|
||||||
void handleNightlight();
|
void handleNightlight();
|
||||||
|
|
||||||
|
//lx_parser.cpp
|
||||||
|
bool parseLx(int lxValue, byte* rgbw);
|
||||||
|
void parseLxJson(int lxValue, byte segId, bool secondary);
|
||||||
|
|
||||||
//mqtt.cpp
|
//mqtt.cpp
|
||||||
bool initMqtt();
|
bool initMqtt();
|
||||||
void publishMqtt();
|
void publishMqtt();
|
||||||
|
@ -233,23 +233,23 @@ var t = typeof s[i];
|
|||||||
if (gId(fk)) { //already exists
|
if (gId(fk)) { //already exists
|
||||||
if(t === 'boolean')
|
if(t === 'boolean')
|
||||||
{
|
{
|
||||||
gId(fk).checked = s[i];
|
gId(fk).checked = s[i];
|
||||||
} else {
|
} else {
|
||||||
gId(fk).value = s[i];
|
gId(fk).value = s[i];
|
||||||
}
|
}
|
||||||
if (gId(fk).previousElementSibling.matches('.l')) {
|
if (gId(fk).previousElementSibling.matches('.l')) {
|
||||||
gId(fk).previousElementSibling.innerHTML = lb;
|
gId(fk).previousElementSibling.innerHTML = lb;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(t === 'boolean')
|
if(t === 'boolean')
|
||||||
{
|
{
|
||||||
str += `${lb}: <input class="agi cb" type="checkbox" id=${fk} ${s[i]?"checked":""}><br>`;
|
str += `${lb}: <input class="agi cb" type="checkbox" id=${fk} ${s[i]?"checked":""}><br>`;
|
||||||
} else if (t === 'number')
|
} else if (t === 'number')
|
||||||
{
|
{
|
||||||
str += `${lb}: <input class="agi" type="number" id=${fk} value=${s[i]}><br>`;
|
str += `${lb}: <input class="agi" type="number" id=${fk} value=${s[i]}><br>`;
|
||||||
} else if (t === 'string')
|
} else if (t === 'string')
|
||||||
{
|
{
|
||||||
str += `${lb}:<br><input class="agi" id=${fk} value=${s[i]}><br>`;
|
str += `${lb}:<br><input class="agi" id=${fk} value=${s[i]}><br>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ onclick="Save()">Save</button></form></body></html>)=====";
|
|||||||
// Autogenerated from wled00/data/settings_sync.htm, do not edit!!
|
// Autogenerated from wled00/data/settings_sync.htm, do not edit!!
|
||||||
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=500"><meta
|
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=500"><meta
|
||||||
charset="utf-8"><title>Sync Settings</title><script>
|
charset="utf-8"><title>Sync Settings</title><script>
|
||||||
var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings")}function B(){window.open("/settings","_self")}function adj(){6454==d.Sf.DI.value?(1==d.Sf.DA.value&&(d.Sf.DA.value=0),1==d.Sf.EU.value&&(d.Sf.EU.value=0)):5568==d.Sf.DI.value&&(0==d.Sf.DA.value&&(d.Sf.DA.value=1),0==d.Sf.EU.value&&(d.Sf.EU.value=1))}function SP(){var e=d.Sf.DI.value;d.getElementById("xp").style.display=0<e?"none":"block",0<e&&(d.Sf.EP.value=e)}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454}SP()}function S(){GetV(),SetVal()}function GetV() {
|
var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings")}function B(){window.open("/settings","_self")}function adj(){6454==d.Sf.DI.value?(1==d.Sf.DA.value&&(d.Sf.DA.value=0),1==d.Sf.EU.value&&(d.Sf.EU.value=0)):5568==d.Sf.DI.value&&(0==d.Sf.DA.value&&(d.Sf.DA.value=1),0==d.Sf.EU.value&&(d.Sf.EU.value=1))}function SP(){var e=d.Sf.DI.value;d.getElementById("xp").style.display=0<e?"none":"block",0<e&&(d.Sf.EP.value=e)}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454;break;case 4048:d.Sf.DI.value=4048}SP()}function S(){GetV(),SetVal()}function GetV() {
|
||||||
%CSS%%SCSS%</head><body onload="S()"><form
|
%CSS%%SCSS%</head><body onload="S()"><form
|
||||||
id="form_s" name="Sf" method="post"><div class="helpB"><button type="button"
|
id="form_s" name="Sf" method="post"><div class="helpB"><button type="button"
|
||||||
onclick="H()">?</button></div><button type="button" onclick="B()">Back</button>
|
onclick="H()">?</button></div><button type="button" onclick="B()">Back</button>
|
||||||
@ -370,19 +370,22 @@ On/Off button enabled: <input type="checkbox" name="BT"><br>Infrared remote:
|
|||||||
9-key red</option></select><br><a
|
9-key red</option></select><br><a
|
||||||
href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">
|
href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">
|
||||||
IR info</a><h3>WLED Broadcast</h3>UDP Port: <input name="UP" type="number"
|
IR info</a><h3>WLED Broadcast</h3>UDP Port: <input name="UP" type="number"
|
||||||
min="1" max="65535" class="d5" required><br>Receive <input type="checkbox"
|
min="1" max="65535" class="d5" required><br>2nd Port: <input name="U2"
|
||||||
name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input
|
type="number" min="1" max="65535" class="d5" required><br>Receive <input
|
||||||
type="checkbox" name="RX">Effects<br>Send notifications on direct change: <input
|
type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">
|
||||||
type="checkbox" name="SD"><br>Send notifications on button press: <input
|
Color, and <input type="checkbox" name="RX">Effects<br>
|
||||||
type="checkbox" name="SB"><br>Send Alexa notifications: <input type="checkbox"
|
Send notifications on direct change: <input type="checkbox" name="SD"><br>
|
||||||
name="SA"><br>Send Philips Hue change notifications: <input type="checkbox"
|
Send notifications on button press: <input type="checkbox" name="SB"><br>
|
||||||
name="SH"><br>Send Macro notifications: <input type="checkbox" name="SM"><br>
|
Send Alexa notifications: <input type="checkbox" name="SA"><br>
|
||||||
Send notifications twice: <input type="checkbox" name="S2"><h3>Realtime</h3>
|
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
|
||||||
Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i>
|
Send Macro notifications: <input type="checkbox" name="SM"><br>
|
||||||
Network DMX input</i><br>Type: <select name="DI" onchange="SP(),adj()"><option
|
Send notifications twice: <input type="checkbox" name="S2"><br><i>
|
||||||
value="5568">E1.31 (sACN)</option><option value="6454">Art-Net</option><option
|
Reboot required to apply changes.</i><h3>Realtime</h3>Receive UDP realtime:
|
||||||
value="0" selected="selected">Custom port</option></select><br><div id="xp">
|
<input type="checkbox" name="RD"><br><br><i>Network DMX input</i><br>Type:
|
||||||
Port: <input name="EP" type="number" min="1" max="65535" value="5568"
|
<select name="DI" onchange="SP(),adj()"><option value="5568">E1.31 (sACN)
|
||||||
|
</option><option value="6454">Art-Net</option><option value="4048">DDP</option>
|
||||||
|
<option value="0" selected="selected">Custom port</option></select><br><div
|
||||||
|
id="xp">Port: <input name="EP" type="number" min="1" max="65535" value="5568"
|
||||||
class="d5" required><br></div>Multicast: <input type="checkbox" name="EM"><br>
|
class="d5" required><br></div>Multicast: <input type="checkbox" name="EM"><br>
|
||||||
Start universe: <input name="EU" type="number" min="0" max="63999" required><br>
|
Start universe: <input name="EU" type="number" min="0" max="63999" required><br>
|
||||||
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx"
|
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx"
|
||||||
@ -450,7 +453,9 @@ value="5">US-CST/CDT</option><option value="6">US-MST/MDT</option><option
|
|||||||
value="7">US-AZ</option><option value="8">US-PST/PDT</option><option value="9">
|
value="7">US-AZ</option><option value="8">US-PST/PDT</option><option value="9">
|
||||||
CST(AWST)</option><option value="10">JST(KST)</option><option value="11">
|
CST(AWST)</option><option value="10">JST(KST)</option><option value="11">
|
||||||
AEST/AEDT</option><option value="12">NZST/NZDT</option><option value="13">
|
AEST/AEDT</option><option value="12">NZST/NZDT</option><option value="13">
|
||||||
North Korea</option></select><br>UTC offset: <input name="UO" type="number"
|
North Korea</option><option value="14">IST (India)</option><option value="15">
|
||||||
|
CA-Saskatchewan</option><option value="16">ACST</option><option value="17">
|
||||||
|
ACST/ACDT</option></select><br>UTC offset: <input name="UO" type="number"
|
||||||
min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||||
Current local time is <span class="times">unknown</span>.<h3>Clock</h3>
|
Current local time is <span class="times">unknown</span>.<h3>Clock</h3>
|
||||||
Clock Overlay: <select name="OL" onchange="Cs()"><option value="0" id="cn"
|
Clock Overlay: <select name="OL" onchange="Cs()"><option value="0" id="cn"
|
||||||
|
2933
wled00/html_ui.h
2933
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,14 @@ void deserializeSegment(JsonObject elem, byte it)
|
|||||||
int rgbw[] = {0,0,0,0};
|
int rgbw[] = {0,0,0,0};
|
||||||
byte cp = copyArray(colX, rgbw);
|
byte cp = copyArray(colX, rgbw);
|
||||||
|
|
||||||
if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0;
|
if (cp == 1) {
|
||||||
|
if (rgbw[0] == 0) seg.colors[i] = 0;
|
||||||
|
else {
|
||||||
|
byte ctrgb[] = {0,0,0,0};
|
||||||
|
colorKtoRGB(rgbw[0], ctrgb);
|
||||||
|
for (uint8_t c = 0; c < 3; c++) rgbw[c] = ctrgb[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
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 == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
||||||
@ -55,6 +62,18 @@ void deserializeSegment(JsonObject elem, byte it)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lx parser
|
||||||
|
#ifdef WLED_ENABLE_LOXONE
|
||||||
|
int lx = elem[F("lx")] | -1;
|
||||||
|
if (lx > 0) {
|
||||||
|
parseLxJson(lx, id, false);
|
||||||
|
}
|
||||||
|
int ly = elem[F("ly")] | -1;
|
||||||
|
if (ly > 0) {
|
||||||
|
parseLxJson(ly, id, true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
||||||
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
|
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
|
||||||
@ -161,7 +180,7 @@ bool deserializeState(JsonObject root)
|
|||||||
if (tr >= 2) presetCycleTime = tr;
|
if (tr >= 2) presetCycleTime = tr;
|
||||||
|
|
||||||
JsonObject nl = root[F("nl")];
|
JsonObject nl = root[F("nl")];
|
||||||
nightlightActive = nl["on"] | nightlightActive;
|
nightlightActive = nl["on"] | nightlightActive;
|
||||||
nightlightDelayMins = nl[F("dur")] | nightlightDelayMins;
|
nightlightDelayMins = nl[F("dur")] | nightlightDelayMins;
|
||||||
nightlightMode = nl[F("fade")] | nightlightMode; //deprecated
|
nightlightMode = nl[F("fade")] | nightlightMode; //deprecated
|
||||||
nightlightMode = nl[F("mode")] | nightlightMode;
|
nightlightMode = nl[F("mode")] | nightlightMode;
|
||||||
@ -375,6 +394,7 @@ void serializeInfo(JsonObject root)
|
|||||||
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight/TPM2"); break;
|
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight/TPM2"); break;
|
||||||
case REALTIME_MODE_ARTNET: root["lm"] = F("Art-Net"); break;
|
case REALTIME_MODE_ARTNET: root["lm"] = F("Art-Net"); break;
|
||||||
case REALTIME_MODE_TPM2NET: root["lm"] = F("tpm2.net"); break;
|
case REALTIME_MODE_TPM2NET: root["lm"] = F("tpm2.net"); break;
|
||||||
|
case REALTIME_MODE_DDP: root["lm"] = F("DDP"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (realtimeIP[0] == 0)
|
if (realtimeIP[0] == 0)
|
||||||
@ -465,7 +485,7 @@ void serializeInfo(JsonObject root)
|
|||||||
|
|
||||||
root[F("brand")] = "WLED";
|
root[F("brand")] = "WLED";
|
||||||
root[F("product")] = F("FOSS");
|
root[F("product")] = F("FOSS");
|
||||||
root[F("mac")] = escapedMac;
|
root["mac"] = escapedMac;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serveJson(AsyncWebServerRequest* request)
|
void serveJson(AsyncWebServerRequest* request)
|
||||||
|
@ -134,7 +134,7 @@ void colorUpdated(int callMode)
|
|||||||
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) nightlightActive = false;
|
if (bri == nightlightTargetBri && callMode != NOTIFIER_CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
|
||||||
|
|
||||||
if (fadeTransition)
|
if (fadeTransition)
|
||||||
{
|
{
|
||||||
|
77
wled00/lx_parser.cpp
Normal file
77
wled00/lx_parser.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "wled.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parser for Loxone formats
|
||||||
|
*/
|
||||||
|
bool parseLx(int lxValue, byte rgbw[4])
|
||||||
|
{
|
||||||
|
#ifdef WLED_ENABLE_LOXONE
|
||||||
|
DEBUG_PRINT(F("LX: Lox = "));
|
||||||
|
DEBUG_PRINTLN(lxValue);
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
float lxRed = 0, lxGreen = 0, lxBlue = 0;
|
||||||
|
|
||||||
|
if (lxValue < 200000000) {
|
||||||
|
// Loxone RGB
|
||||||
|
ok = true;
|
||||||
|
lxRed = round((lxValue % 1000) * 2.55);
|
||||||
|
lxGreen = round(((lxValue / 1000) % 1000) * 2.55);
|
||||||
|
lxBlue = round(((lxValue / 1000000) % 1000) * 2.55);
|
||||||
|
} else if ((lxValue >= 200000000) && (lxValue <= 201006500)) {
|
||||||
|
// Loxone Lumitech
|
||||||
|
ok = true;
|
||||||
|
float tmpBri = floor((lxValue - 200000000) / 10000); ;
|
||||||
|
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
|
||||||
|
float temp = 0;
|
||||||
|
|
||||||
|
tmpBri *= 2.55;
|
||||||
|
constrain(tmpBri, 0, 255);
|
||||||
|
|
||||||
|
colorKtoRGB(ct, rgbw);
|
||||||
|
lxRed = rgbw[0]; lxGreen = rgbw[1]; lxBlue = rgbw[2];
|
||||||
|
|
||||||
|
lxRed *= (tmpBri/255);
|
||||||
|
lxGreen *= (tmpBri/255);
|
||||||
|
lxBlue *= (tmpBri/255);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
rgbw[0] = (uint8_t) constrain(lxRed, 0, 255);
|
||||||
|
rgbw[1] = (uint8_t) constrain(lxGreen, 0, 255);
|
||||||
|
rgbw[2] = (uint8_t) constrain(lxBlue, 0, 255);
|
||||||
|
rgbw[3] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseLxJson(int lxValue, byte segId, bool secondary)
|
||||||
|
{
|
||||||
|
if (secondary) {
|
||||||
|
DEBUG_PRINT(F("LY: Lox secondary = "));
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINT(F("LX: Lox primary = "));
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN(lxValue);
|
||||||
|
byte rgbw[] = {0,0,0,0};
|
||||||
|
if (parseLx(lxValue, rgbw)) {
|
||||||
|
if (bri == 0) {
|
||||||
|
DEBUG_PRINTLN(F("LX: turn on"));
|
||||||
|
toggleOnOff();
|
||||||
|
}
|
||||||
|
bri = 255;
|
||||||
|
nightlightActive = false; //always disable nightlight when toggling
|
||||||
|
if (segId == strip.getMainSegmentId()) {
|
||||||
|
DEBUG_PRINTLN(F("LX: main segment"));
|
||||||
|
if (secondary) for (byte i = 0; i < 4; i++) colSec[i] = rgbw[i];
|
||||||
|
else for (byte i = 0; i < 4; i++) col[i] = rgbw[i];
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINT(F("LX: segment "));
|
||||||
|
DEBUG_PRINTLN(segId);
|
||||||
|
strip.getSegment(segId).colors[secondary] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -100,7 +100,7 @@ void publishMqtt()
|
|||||||
|
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
strcpy(subuf, mqttDeviceTopic);
|
||||||
strcat(subuf, "/status");
|
strcat(subuf, "/status");
|
||||||
mqtt->publish(subuf, 0, true, (const char*)F("online"));
|
mqtt->publish(subuf, 0, true, "online");
|
||||||
|
|
||||||
char apires[1024];
|
char apires[1024];
|
||||||
XML_response(nullptr, apires);
|
XML_response(nullptr, apires);
|
||||||
@ -137,7 +137,7 @@ bool initMqtt()
|
|||||||
|
|
||||||
strcpy(mqttStatusTopic, mqttDeviceTopic);
|
strcpy(mqttStatusTopic, mqttDeviceTopic);
|
||||||
strcat(mqttStatusTopic, "/status");
|
strcat(mqttStatusTopic, "/status");
|
||||||
mqtt->setWill(mqttStatusTopic, 0, true, (const char*)F("offline"));
|
mqtt->setWill(mqttStatusTopic, 0, true, "offline");
|
||||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||||
mqtt->connect();
|
mqtt->connect();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Receives client input
|
* Receives client input
|
||||||
*/
|
*/
|
||||||
@ -128,6 +129,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
irEnabled = request->arg(F("IR")).toInt();
|
irEnabled = request->arg(F("IR")).toInt();
|
||||||
int t = request->arg(F("UP")).toInt();
|
int t = request->arg(F("UP")).toInt();
|
||||||
if (t > 0) udpPort = t;
|
if (t > 0) udpPort = t;
|
||||||
|
t = request->arg(F("U2")).toInt();
|
||||||
|
if (t > 0) udpPort2 = t;
|
||||||
receiveNotificationBrightness = request->hasArg(F("RB"));
|
receiveNotificationBrightness = request->hasArg(F("RB"));
|
||||||
receiveNotificationColor = request->hasArg(F("RC"));
|
receiveNotificationColor = request->hasArg(F("RC"));
|
||||||
receiveNotificationEffects = request->hasArg(F("RX"));
|
receiveNotificationEffects = request->hasArg(F("RX"));
|
||||||
@ -507,6 +510,27 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
updateVal(&req, "B2=", &colSec[2]);
|
updateVal(&req, "B2=", &colSec[2]);
|
||||||
updateVal(&req, "W2=", &colSec[3]);
|
updateVal(&req, "W2=", &colSec[3]);
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_LOXONE
|
||||||
|
//lox parser
|
||||||
|
pos = req.indexOf(F("LX=")); // Lox primary color
|
||||||
|
if (pos > 0) {
|
||||||
|
int lxValue = getNumVal(&req, pos);
|
||||||
|
if (parseLx(lxValue, col)) {
|
||||||
|
bri = 255;
|
||||||
|
nightlightActive = false; //always disable nightlight when toggling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos = req.indexOf(F("LY=")); // Lox secondary color
|
||||||
|
if (pos > 0) {
|
||||||
|
int lxValue = getNumVal(&req, pos);
|
||||||
|
if(parseLx(lxValue, colSec)) {
|
||||||
|
bri = 255;
|
||||||
|
nightlightActive = false; //always disable nightlight when toggling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
//set hue
|
//set hue
|
||||||
pos = req.indexOf(F("HU="));
|
pos = req.indexOf(F("HU="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
@ -519,6 +543,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
colorHStoRGB(temphue,tempsat,(req.indexOf(F("H2"))>0)? colSec:col);
|
colorHStoRGB(temphue,tempsat,(req.indexOf(F("H2"))>0)? colSec:col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set white spectrum (kelvin)
|
||||||
|
pos = req.indexOf(F("&K="));
|
||||||
|
if (pos > 0) {
|
||||||
|
colorKtoRGB(getNumVal(&req, pos),(req.indexOf(F("K2"))>0)? colSec:col);
|
||||||
|
}
|
||||||
|
|
||||||
//set color from HEX or 32bit DEC
|
//set color from HEX or 32bit DEC
|
||||||
pos = req.indexOf(F("CL="));
|
pos = req.indexOf(F("CL="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
@ -583,6 +613,18 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
pos = req.indexOf(F("RD="));
|
pos = req.indexOf(F("RD="));
|
||||||
if (pos > 0) receiveDirect = (req.charAt(pos+3) != '0');
|
if (pos > 0) receiveDirect = (req.charAt(pos+3) != '0');
|
||||||
|
|
||||||
|
//main toggle on/off (parse before nightlight, #1214)
|
||||||
|
pos = req.indexOf(F("&T="));
|
||||||
|
if (pos > 0) {
|
||||||
|
nightlightActive = false; //always disable nightlight when toggling
|
||||||
|
switch (getNumVal(&req, pos))
|
||||||
|
{
|
||||||
|
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off, only if it was previously on
|
||||||
|
case 1: if (bri == 0) bri = briLast; break; //on, only if it was previously off
|
||||||
|
default: toggleOnOff(); //toggle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//toggle nightlight mode
|
//toggle nightlight mode
|
||||||
bool aNlDef = false;
|
bool aNlDef = false;
|
||||||
if (req.indexOf(F("&ND")) > 0) aNlDef = true;
|
if (req.indexOf(F("&ND")) > 0) aNlDef = true;
|
||||||
@ -592,7 +634,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
if (req.charAt(pos+3) == '0')
|
if (req.charAt(pos+3) == '0')
|
||||||
{
|
{
|
||||||
nightlightActive = false;
|
nightlightActive = false;
|
||||||
bri = briT;
|
|
||||||
} else {
|
} else {
|
||||||
nightlightActive = true;
|
nightlightActive = true;
|
||||||
if (!aNlDef) nightlightDelayMins = getNumVal(&req, pos);
|
if (!aNlDef) nightlightDelayMins = getNumVal(&req, pos);
|
||||||
@ -634,18 +675,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
|||||||
pos = req.indexOf(F("TT="));
|
pos = req.indexOf(F("TT="));
|
||||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||||
|
|
||||||
//main toggle on/off
|
|
||||||
pos = req.indexOf(F("&T="));
|
|
||||||
if (pos > 0) {
|
|
||||||
nightlightActive = false; //always disable nightlight when toggling
|
|
||||||
switch (getNumVal(&req, pos))
|
|
||||||
{
|
|
||||||
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off, only if it was previously on
|
|
||||||
case 1: if (bri == 0) bri = briLast; break; //on, only if it was previously off
|
|
||||||
default: toggleOnOff(); //toggle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Segment reverse
|
//Segment reverse
|
||||||
pos = req.indexOf(F("RV="));
|
pos = req.indexOf(F("RV="));
|
||||||
if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
||||||
|
@ -38,15 +38,15 @@ ESPAsyncE131::ESPAsyncE131(e131_packet_callback_function callback) {
|
|||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool ESPAsyncE131::begin(bool multicast, uint16_t port, uint16_t universe, uint8_t n) {
|
bool ESPAsyncE131::begin(bool multicast, uint16_t port, uint16_t universe, uint8_t n) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
if (multicast) {
|
if (multicast) {
|
||||||
success = initMulticast(port, universe, n);
|
success = initMulticast(port, universe, n);
|
||||||
} else {
|
} else {
|
||||||
success = initUnicast(port);
|
success = initUnicast(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
@ -56,40 +56,38 @@ bool ESPAsyncE131::begin(bool multicast, uint16_t port, uint16_t universe, uint8
|
|||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool ESPAsyncE131::initUnicast(uint16_t port) {
|
bool ESPAsyncE131::initUnicast(uint16_t port) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
if (udp.listen(port)) {
|
if (udp.listen(port)) {
|
||||||
udp.onPacket(std::bind(&ESPAsyncE131::parsePacket, this,
|
udp.onPacket(std::bind(&ESPAsyncE131::parsePacket, this, std::placeholders::_1));
|
||||||
std::placeholders::_1));
|
success = true;
|
||||||
success = true;
|
}
|
||||||
}
|
return success;
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESPAsyncE131::initMulticast(uint16_t port, uint16_t universe, uint8_t n) {
|
bool ESPAsyncE131::initMulticast(uint16_t port, uint16_t universe, uint8_t n) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
IPAddress address = IPAddress(239, 255, ((universe >> 8) & 0xff),
|
IPAddress address = IPAddress(239, 255, ((universe >> 8) & 0xff),
|
||||||
((universe >> 0) & 0xff));
|
((universe >> 0) & 0xff));
|
||||||
|
|
||||||
if (udp.listenMulticast(address, port)) {
|
if (udp.listenMulticast(address, port)) {
|
||||||
ip4_addr_t ifaddr;
|
ip4_addr_t ifaddr;
|
||||||
ip4_addr_t multicast_addr;
|
ip4_addr_t multicast_addr;
|
||||||
|
|
||||||
ifaddr.addr = static_cast<uint32_t>(WiFi.localIP());
|
ifaddr.addr = static_cast<uint32_t>(WiFi.localIP());
|
||||||
for (uint8_t i = 1; i < n; i++) {
|
for (uint8_t i = 1; i < n; i++) {
|
||||||
multicast_addr.addr = static_cast<uint32_t>(IPAddress(239, 255,
|
multicast_addr.addr = static_cast<uint32_t>(IPAddress(239, 255,
|
||||||
(((universe + i) >> 8) & 0xff), (((universe + i) >> 0)
|
(((universe + i) >> 8) & 0xff), (((universe + i) >> 0)
|
||||||
& 0xff)));
|
& 0xff)));
|
||||||
igmp_joingroup(&ifaddr, &multicast_addr);
|
igmp_joingroup(&ifaddr, &multicast_addr);
|
||||||
}
|
|
||||||
|
|
||||||
udp.onPacket(std::bind(&ESPAsyncE131::parsePacket, this,
|
|
||||||
std::placeholders::_1));
|
|
||||||
|
|
||||||
success = true;
|
|
||||||
}
|
}
|
||||||
return success;
|
|
||||||
|
udp.onPacket(std::bind(&ESPAsyncE131::parsePacket, this, std::placeholders::_1));
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
@ -99,15 +97,16 @@ bool ESPAsyncE131::initMulticast(uint16_t port, uint16_t universe, uint8_t n) {
|
|||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ESPAsyncE131::parsePacket(AsyncUDPPacket _packet) {
|
void ESPAsyncE131::parsePacket(AsyncUDPPacket _packet) {
|
||||||
bool error = false, isArtnet = false;
|
bool error = false;
|
||||||
|
uint8_t protocol = P_E131;
|
||||||
|
|
||||||
sbuff = reinterpret_cast<e131_packet_t *>(_packet.data());
|
sbuff = reinterpret_cast<e131_packet_t *>(_packet.data());
|
||||||
|
|
||||||
//E1.31 packet identifier ("ACS-E1.17")
|
//E1.31 packet identifier ("ACS-E1.17")
|
||||||
if (memcmp(sbuff->acn_id, ESPAsyncE131::ACN_ID, sizeof(sbuff->acn_id)))
|
if (memcmp(sbuff->acn_id, ESPAsyncE131::ACN_ID, sizeof(sbuff->acn_id)))
|
||||||
isArtnet = true; //not E1.31
|
protocol = P_ARTNET;
|
||||||
|
|
||||||
if (isArtnet) {
|
if (protocol == P_ARTNET) {
|
||||||
if (memcmp(sbuff->art_id, ESPAsyncE131::ART_ID, sizeof(sbuff->art_id)))
|
if (memcmp(sbuff->art_id, ESPAsyncE131::ART_ID, sizeof(sbuff->art_id)))
|
||||||
error = true; //not "Art-Net"
|
error = true; //not "Art-Net"
|
||||||
if (sbuff->art_opcode != ARTNET_OPCODE_OPDMX)
|
if (sbuff->art_opcode != ARTNET_OPCODE_OPDMX)
|
||||||
@ -121,9 +120,14 @@ void ESPAsyncE131::parsePacket(AsyncUDPPacket _packet) {
|
|||||||
error = true;
|
error = true;
|
||||||
if (sbuff->property_values[0] != 0)
|
if (sbuff->property_values[0] != 0)
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error && _packet.localPort() == DDP_DEFAULT_PORT) { //DDP packet
|
||||||
|
error = false;
|
||||||
|
protocol = P_DDP;
|
||||||
|
}
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
_callback(sbuff, _packet.remoteIP(), isArtnet);
|
_callback(sbuff, _packet.remoteIP(), protocol);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,9 @@
|
|||||||
* Copyright (c) 2019 Shelby Merrick
|
* Copyright (c) 2019 Shelby Merrick
|
||||||
* http://www.forkineye.com
|
* http://www.forkineye.com
|
||||||
*
|
*
|
||||||
|
* Project: ESPAsyncDDP - Asynchronous DDP library for Arduino ESP8266 and ESP32
|
||||||
|
* Copyright (c) 2019 Daniel Kulp
|
||||||
|
*
|
||||||
* This program is provided free for you to use in any way that you wish,
|
* This program is provided free for you to use in any way that you wish,
|
||||||
* subject to the laws and regulations where you are using it. Due diligence
|
* subject to the laws and regulations where you are using it. Due diligence
|
||||||
* is strongly suggested before using this code. Please give credit where due.
|
* is strongly suggested before using this code. Please give credit where due.
|
||||||
@ -45,9 +48,17 @@ typedef struct ip_addr ip4_addr_t;
|
|||||||
// Defaults
|
// Defaults
|
||||||
#define E131_DEFAULT_PORT 5568
|
#define E131_DEFAULT_PORT 5568
|
||||||
#define ARTNET_DEFAULT_PORT 6454
|
#define ARTNET_DEFAULT_PORT 6454
|
||||||
|
#define DDP_DEFAULT_PORT 4048
|
||||||
|
|
||||||
|
#define DDP_PUSH_FLAG 0x01
|
||||||
|
#define DDP_TIMECODE_FLAG 0x10
|
||||||
|
|
||||||
#define ARTNET_OPCODE_OPDMX 0x5000
|
#define ARTNET_OPCODE_OPDMX 0x5000
|
||||||
|
|
||||||
|
#define P_E131 0
|
||||||
|
#define P_ARTNET 1
|
||||||
|
#define P_DDP 2
|
||||||
|
|
||||||
// E1.31 Packet Offsets
|
// E1.31 Packet Offsets
|
||||||
#define E131_ROOT_PREAMBLE_SIZE 0
|
#define E131_ROOT_PREAMBLE_SIZE 0
|
||||||
#define E131_ROOT_POSTAMBLE_SIZE 2
|
#define E131_ROOT_POSTAMBLE_SIZE 2
|
||||||
@ -76,57 +87,78 @@ typedef struct ip_addr ip4_addr_t;
|
|||||||
// E1.31 Packet Structure
|
// E1.31 Packet Structure
|
||||||
typedef union {
|
typedef union {
|
||||||
struct { //E1.31 packet
|
struct { //E1.31 packet
|
||||||
// Root Layer
|
// Root Layer
|
||||||
uint16_t preamble_size;
|
uint16_t preamble_size;
|
||||||
uint16_t postamble_size;
|
uint16_t postamble_size;
|
||||||
uint8_t acn_id[12];
|
uint8_t acn_id[12];
|
||||||
uint16_t root_flength;
|
uint16_t root_flength;
|
||||||
uint32_t root_vector;
|
uint32_t root_vector;
|
||||||
uint8_t cid[16];
|
uint8_t cid[16];
|
||||||
|
|
||||||
// Frame Layer
|
// Frame Layer
|
||||||
uint16_t frame_flength;
|
uint16_t frame_flength;
|
||||||
uint32_t frame_vector;
|
uint32_t frame_vector;
|
||||||
uint8_t source_name[64];
|
uint8_t source_name[64];
|
||||||
uint8_t priority;
|
uint8_t priority;
|
||||||
uint16_t reserved;
|
uint16_t reserved;
|
||||||
uint8_t sequence_number;
|
uint8_t sequence_number;
|
||||||
uint8_t options;
|
uint8_t options;
|
||||||
uint16_t universe;
|
uint16_t universe;
|
||||||
|
|
||||||
// DMP Layer
|
// DMP Layer
|
||||||
uint16_t dmp_flength;
|
uint16_t dmp_flength;
|
||||||
uint8_t dmp_vector;
|
uint8_t dmp_vector;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint16_t first_address;
|
uint16_t first_address;
|
||||||
uint16_t address_increment;
|
uint16_t address_increment;
|
||||||
uint16_t property_value_count;
|
uint16_t property_value_count;
|
||||||
uint8_t property_values[513];
|
uint8_t property_values[513];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct { //Art-Net packet
|
struct { //Art-Net packet
|
||||||
uint8_t art_id[8];
|
uint8_t art_id[8];
|
||||||
uint16_t art_opcode;
|
uint16_t art_opcode;
|
||||||
uint16_t art_protocol_ver;
|
uint16_t art_protocol_ver;
|
||||||
uint8_t art_sequence_number;
|
uint8_t art_sequence_number;
|
||||||
uint8_t art_physical;
|
uint8_t art_physical;
|
||||||
uint16_t art_universe;
|
uint16_t art_universe;
|
||||||
uint16_t art_length;
|
uint16_t art_length;
|
||||||
|
|
||||||
uint8_t art_data[512];
|
uint8_t art_data[512];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
uint8_t raw[638];
|
struct { //DDP Header
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t sequenceNum;
|
||||||
|
uint8_t dataType;
|
||||||
|
uint8_t destination;
|
||||||
|
uint32_t channelOffset;
|
||||||
|
uint16_t dataLen;
|
||||||
|
uint8_t data[1];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/*struct { //DDP Time code Header (unsupported)
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t sequenceNum;
|
||||||
|
uint8_t dataType;
|
||||||
|
uint8_t destination;
|
||||||
|
uint32_t channelOffset;
|
||||||
|
uint16_t dataLen;
|
||||||
|
uint32_t timeCode;
|
||||||
|
uint8_t data[1];
|
||||||
|
} __attribute__((packed));*/
|
||||||
|
|
||||||
|
uint8_t raw[1458];
|
||||||
} e131_packet_t;
|
} e131_packet_t;
|
||||||
|
|
||||||
// new packet callback
|
// new packet callback
|
||||||
typedef void (*e131_packet_callback_function) (e131_packet_t* p, IPAddress clientIP, bool isArtnet);
|
typedef void (*e131_packet_callback_function) (e131_packet_t* p, IPAddress clientIP, byte protocol);
|
||||||
|
|
||||||
class ESPAsyncE131 {
|
class ESPAsyncE131 {
|
||||||
private:
|
private:
|
||||||
// Constants for packet validation
|
// Constants for packet validation
|
||||||
static const uint8_t ACN_ID[];
|
static const uint8_t ACN_ID[];
|
||||||
static const uint8_t ART_ID[];
|
static const uint8_t ART_ID[];
|
||||||
static const uint32_t VECTOR_ROOT = 4;
|
static const uint32_t VECTOR_ROOT = 4;
|
||||||
static const uint32_t VECTOR_FRAME = 2;
|
static const uint32_t VECTOR_FRAME = 2;
|
||||||
static const uint8_t VECTOR_DMP = 2;
|
static const uint8_t VECTOR_DMP = 2;
|
||||||
|
@ -105,7 +105,7 @@ void handleNotifications()
|
|||||||
if(udpConnected && notificationTwoRequired && millis()-notificationSentTime > 250){
|
if(udpConnected && notificationTwoRequired && millis()-notificationSentTime > 250){
|
||||||
notify(notificationSentCallMode,true);
|
notify(notificationSentCallMode,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e131NewData && millis() - strip.getLastShow() > 15)
|
if (e131NewData && millis() - strip.getLastShow() > 15)
|
||||||
{
|
{
|
||||||
e131NewData = false;
|
e131NewData = false;
|
||||||
@ -124,36 +124,44 @@ void handleNotifications()
|
|||||||
//receive UDP notifications
|
//receive UDP notifications
|
||||||
if (!udpConnected || !(receiveNotifications || receiveDirect)) return;
|
if (!udpConnected || !(receiveNotifications || receiveDirect)) return;
|
||||||
|
|
||||||
|
bool isSupp = false;
|
||||||
uint16_t packetSize = notifierUdp.parsePacket();
|
uint16_t packetSize = notifierUdp.parsePacket();
|
||||||
|
if (!packetSize && udp2Connected) {
|
||||||
|
packetSize = notifier2Udp.parsePacket();
|
||||||
|
isSupp = true;
|
||||||
|
}
|
||||||
|
|
||||||
//hyperion / raw RGB
|
//hyperion / raw RGB
|
||||||
if (!packetSize && udpRgbConnected) {
|
if (!packetSize && udpRgbConnected) {
|
||||||
packetSize = rgbUdp.parsePacket();
|
packetSize = rgbUdp.parsePacket();
|
||||||
if (!receiveDirect) return;
|
if (packetSize) {
|
||||||
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return;
|
if (!receiveDirect) return;
|
||||||
realtimeIP = rgbUdp.remoteIP();
|
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return;
|
||||||
DEBUG_PRINTLN(rgbUdp.remoteIP());
|
realtimeIP = rgbUdp.remoteIP();
|
||||||
uint8_t lbuf[packetSize];
|
DEBUG_PRINTLN(rgbUdp.remoteIP());
|
||||||
rgbUdp.read(lbuf, packetSize);
|
uint8_t lbuf[packetSize];
|
||||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
|
rgbUdp.read(lbuf, packetSize);
|
||||||
if (realtimeOverride) return;
|
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
|
||||||
uint16_t id = 0;
|
if (realtimeOverride) return;
|
||||||
for (uint16_t i = 0; i < packetSize -2; i += 3)
|
uint16_t id = 0;
|
||||||
{
|
for (uint16_t i = 0; i < packetSize -2; i += 3)
|
||||||
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
{
|
||||||
|
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
||||||
id++; if (id >= ledCount) break;
|
|
||||||
}
|
id++; if (id >= ledCount) break;
|
||||||
strip.show();
|
}
|
||||||
return;
|
strip.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//notifier and UDP realtime
|
//notifier and UDP realtime
|
||||||
if (!packetSize || packetSize > UDP_IN_MAXSIZE) return;
|
if (!packetSize || packetSize > UDP_IN_MAXSIZE) return;
|
||||||
if (notifierUdp.remoteIP() == WiFi.localIP()) return; //don't process broadcasts we send ourselves
|
if (!isSupp && notifierUdp.remoteIP() == WiFi.localIP()) return; //don't process broadcasts we send ourselves
|
||||||
|
|
||||||
uint8_t udpIn[packetSize];
|
uint8_t udpIn[packetSize +1];
|
||||||
notifierUdp.read(udpIn, packetSize);
|
if (isSupp) notifier2Udp.read(udpIn, packetSize);
|
||||||
|
else notifierUdp.read(udpIn, packetSize);
|
||||||
|
|
||||||
//wled notifier, block if realtime packets active
|
//wled notifier, block if realtime packets active
|
||||||
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
|
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
|
||||||
@ -212,7 +220,7 @@ void handleNotifications()
|
|||||||
|
|
||||||
if (receiveNotificationBrightness || !someSel) bri = udpIn[2];
|
if (receiveNotificationBrightness || !someSel) bri = udpIn[2];
|
||||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!receiveDirect) return;
|
if (!receiveDirect) return;
|
||||||
|
|
||||||
@ -227,7 +235,7 @@ void handleNotifications()
|
|||||||
}
|
}
|
||||||
if (tpmType != 0xda) return; //return if notTPM2.NET data
|
if (tpmType != 0xda) return; //return if notTPM2.NET data
|
||||||
|
|
||||||
realtimeIP = notifierUdp.remoteIP();
|
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
|
||||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
|
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
|
||||||
if (realtimeOverride) return;
|
if (realtimeOverride) return;
|
||||||
|
|
||||||
@ -251,13 +259,14 @@ void handleNotifications()
|
|||||||
tpmPacketCount = 0;
|
tpmPacketCount = 0;
|
||||||
strip.show();
|
strip.show();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//UDP realtime: 1 warls 2 drgb 3 drgbw
|
//UDP realtime: 1 warls 2 drgb 3 drgbw
|
||||||
if (udpIn[0] > 0 && udpIn[0] < 5)
|
if (udpIn[0] > 0 && udpIn[0] < 5)
|
||||||
{
|
{
|
||||||
realtimeIP = notifierUdp.remoteIP();
|
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
|
||||||
DEBUG_PRINTLN(notifierUdp.remoteIP());
|
DEBUG_PRINTLN(realtimeIP);
|
||||||
if (packetSize < 2) return;
|
if (packetSize < 2) return;
|
||||||
|
|
||||||
if (udpIn[1] == 0)
|
if (udpIn[1] == 0)
|
||||||
@ -304,6 +313,21 @@ void handleNotifications()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
strip.show();
|
strip.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API over UDP
|
||||||
|
udpIn[packetSize] = '\0';
|
||||||
|
|
||||||
|
if (udpIn[0] >= 'A' && udpIn[0] <= 'Z') { //HTTP API
|
||||||
|
String apireq = "win&";
|
||||||
|
apireq += (char*)udpIn;
|
||||||
|
handleSet(nullptr, apireq);
|
||||||
|
} else if (udpIn[0] == '{') { //JSON API
|
||||||
|
DynamicJsonDocument jsonBuffer(2048);
|
||||||
|
DeserializationError error = deserializeJson(jsonBuffer, udpIn);
|
||||||
|
JsonObject root = jsonBuffer.as<JsonObject>();
|
||||||
|
if (!error && !root.isNull()) deserializeState(root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ void WLED::reset()
|
|||||||
bool oappendi(int i)
|
bool oappendi(int i)
|
||||||
{
|
{
|
||||||
char s[11];
|
char s[11];
|
||||||
sprintf(s, "%ld", i);
|
sprintf(s, "%d", i);
|
||||||
return oappend(s);
|
return oappend(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,15 +273,15 @@ void WLED::initAP(bool resetAP)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!apSSID[0] || resetAP)
|
if (!apSSID[0] || resetAP)
|
||||||
strcpy(apSSID, (const char*)F("WLED-AP"));
|
strcpy_P(apSSID, PSTR("WLED-AP"));
|
||||||
if (resetAP)
|
if (resetAP)
|
||||||
strcpy(apPass, DEFAULT_AP_PASS);
|
strcpy_P(apPass, PSTR(DEFAULT_AP_PASS));
|
||||||
DEBUG_PRINT(F("Opening access point "));
|
DEBUG_PRINT(F("Opening access point "));
|
||||||
DEBUG_PRINTLN(apSSID);
|
DEBUG_PRINTLN(apSSID);
|
||||||
WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0));
|
WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0));
|
||||||
WiFi.softAP(apSSID, apPass, apChannel, apHide);
|
WiFi.softAP(apSSID, apPass, apChannel, apHide);
|
||||||
|
|
||||||
if (!apActive) // start captive portal if AP active
|
if (!apActive) // start captive portal if AP active
|
||||||
{
|
{
|
||||||
DEBUG_PRINTLN(F("Init AP interfaces"));
|
DEBUG_PRINTLN(F("Init AP interfaces"));
|
||||||
server.begin();
|
server.begin();
|
||||||
@ -291,7 +291,10 @@ void WLED::initAP(bool resetAP)
|
|||||||
if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) {
|
if (udpRgbPort > 0 && udpRgbPort != ntpLocalPort && udpRgbPort != udpPort) {
|
||||||
udpRgbConnected = rgbUdp.begin(udpRgbPort);
|
udpRgbConnected = rgbUdp.begin(udpRgbPort);
|
||||||
}
|
}
|
||||||
|
if (udpPort2 > 0 && udpPort2 != ntpLocalPort && udpPort2 != udpPort && udpPort2 != udpRgbPort) {
|
||||||
|
udp2Connected = notifier2Udp.begin(udpPort2);
|
||||||
|
}
|
||||||
|
|
||||||
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
|
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
|
||||||
dnsServer.start(53, "*", WiFi.softAPIP());
|
dnsServer.start(53, "*", WiFi.softAPIP());
|
||||||
}
|
}
|
||||||
@ -417,6 +420,8 @@ void WLED::initInterfaces()
|
|||||||
udpConnected = notifierUdp.begin(udpPort);
|
udpConnected = notifierUdp.begin(udpPort);
|
||||||
if (udpConnected && udpRgbPort != udpPort)
|
if (udpConnected && udpRgbPort != udpPort)
|
||||||
udpRgbConnected = rgbUdp.begin(udpRgbPort);
|
udpRgbConnected = rgbUdp.begin(udpRgbPort);
|
||||||
|
if (udpConnected && udpPort2 != udpPort && udpPort2 != udpRgbPort)
|
||||||
|
udp2Connected = notifier2Udp.begin(udpPort2);
|
||||||
}
|
}
|
||||||
if (ntpEnabled)
|
if (ntpEnabled)
|
||||||
ntpConnected = ntpUdp.begin(ntpLocalPort);
|
ntpConnected = ntpUdp.begin(ntpLocalPort);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2009202
|
#define VERSION 2010020
|
||||||
|
|
||||||
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
||||||
|
|
||||||
@ -30,13 +30,14 @@
|
|||||||
#endif
|
#endif
|
||||||
#define WLED_ENABLE_ADALIGHT // saves 500b only
|
#define WLED_ENABLE_ADALIGHT // saves 500b only
|
||||||
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
||||||
|
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||||
#ifndef WLED_DISABLE_WEBSOCKETS
|
#ifndef WLED_DISABLE_WEBSOCKETS
|
||||||
#define WLED_ENABLE_WEBSOCKETS
|
#define WLED_ENABLE_WEBSOCKETS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define WLED_DISABLE_FILESYSTEM // SPIFFS is not used by any WLED feature yet
|
//#define WLED_DISABLE_FILESYSTEM // FS used by new preset functionality
|
||||||
#define WLED_ENABLE_FS_SERVING // Enable sending html file from SPIFFS before serving progmem version
|
//#define WLED_ENABLE_FS_SERVING // Enable sending html file from SPIFFS before serving progmem version
|
||||||
#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing SPIFFS content. Will also be disabled with OTA lock
|
//#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing SPIFFS content. Will also be disabled with OTA lock
|
||||||
|
|
||||||
// to toggle usb serial debug (un)comment the following line
|
// to toggle usb serial debug (un)comment the following line
|
||||||
//#define WLED_DEBUG
|
//#define WLED_DEBUG
|
||||||
@ -213,6 +214,7 @@ WLED_GLOBAL bool buttonEnabled _INIT(true);
|
|||||||
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
|
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
|
||||||
|
|
||||||
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
|
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
|
||||||
|
WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port
|
||||||
WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port
|
WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port
|
||||||
|
|
||||||
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
|
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
|
||||||
@ -376,7 +378,7 @@ WLED_GLOBAL byte effectIntensity _INIT(128);
|
|||||||
WLED_GLOBAL byte effectPalette _INIT(0);
|
WLED_GLOBAL byte effectPalette _INIT(0);
|
||||||
|
|
||||||
// network
|
// network
|
||||||
WLED_GLOBAL bool udpConnected _INIT(false), udpRgbConnected _INIT(false);
|
WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false);
|
||||||
|
|
||||||
// ui style
|
// ui style
|
||||||
WLED_GLOBAL bool showWelcomePage _INIT(false);
|
WLED_GLOBAL bool showWelcomePage _INIT(false);
|
||||||
@ -492,7 +494,7 @@ WLED_GLOBAL AsyncClient* hueClient _INIT(NULL);
|
|||||||
WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL);
|
WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL);
|
||||||
|
|
||||||
// udp interface objects
|
// udp interface objects
|
||||||
WLED_GLOBAL WiFiUDP notifierUdp, rgbUdp;
|
WLED_GLOBAL WiFiUDP notifierUdp, rgbUdp, notifier2Udp;
|
||||||
WLED_GLOBAL WiFiUDP ntpUdp;
|
WLED_GLOBAL WiFiUDP ntpUdp;
|
||||||
WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet)));
|
WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet)));
|
||||||
WLED_GLOBAL bool e131NewData _INIT(false);
|
WLED_GLOBAL bool e131NewData _INIT(false);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//eeprom Version code, enables default settings instead of 0 init on update
|
//eeprom Version code, enables default settings instead of 0 init on update
|
||||||
#define EEPVER 21
|
#define EEPVER 22
|
||||||
//0 -> old version, default
|
//0 -> old version, default
|
||||||
//1 -> 0.4p 1711272 and up
|
//1 -> 0.4p 1711272 and up
|
||||||
//2 -> 0.4p 1711302 and up
|
//2 -> 0.4p 1711302 and up
|
||||||
@ -30,6 +30,7 @@
|
|||||||
//19-> 0.9.1n
|
//19-> 0.9.1n
|
||||||
//20-> 0.9.1p
|
//20-> 0.9.1p
|
||||||
//21-> 0.10.1p
|
//21-> 0.10.1p
|
||||||
|
//22-> 2009260
|
||||||
|
|
||||||
void commit()
|
void commit()
|
||||||
{
|
{
|
||||||
@ -146,6 +147,9 @@ void saveSettingsToEEPROM()
|
|||||||
|
|
||||||
EEPROM.write(377, EEPVER); //eeprom was updated to latest
|
EEPROM.write(377, EEPVER); //eeprom was updated to latest
|
||||||
|
|
||||||
|
EEPROM.write(378, udpPort2 & 0xFF);
|
||||||
|
EEPROM.write(379, (udpPort2 >> 8) & 0xFF);
|
||||||
|
|
||||||
EEPROM.write(382, strip.paletteBlend);
|
EEPROM.write(382, strip.paletteBlend);
|
||||||
EEPROM.write(383, strip.colorOrder);
|
EEPROM.write(383, strip.colorOrder);
|
||||||
|
|
||||||
@ -538,6 +542,10 @@ void loadSettingsFromEEPROM(bool first)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (lastEEPROMversion > 21) {
|
||||||
|
udpPort2 = EEPROM.read(378) + ((EEPROM.read(379) << 8) & 0xFF00);
|
||||||
|
}
|
||||||
|
|
||||||
receiveDirect = !EEPROM.read(2200);
|
receiveDirect = !EEPROM.read(2200);
|
||||||
notifyMacro = EEPROM.read(2201);
|
notifyMacro = EEPROM.read(2201);
|
||||||
|
|
||||||
|
@ -292,6 +292,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
sappend('c',SET_F("BT"),buttonEnabled);
|
sappend('c',SET_F("BT"),buttonEnabled);
|
||||||
sappend('v',SET_F("IR"),irEnabled);
|
sappend('v',SET_F("IR"),irEnabled);
|
||||||
sappend('v',SET_F("UP"),udpPort);
|
sappend('v',SET_F("UP"),udpPort);
|
||||||
|
sappend('v',SET_F("U2"),udpPort2);
|
||||||
sappend('c',SET_F("RB"),receiveNotificationBrightness);
|
sappend('c',SET_F("RB"),receiveNotificationBrightness);
|
||||||
sappend('c',SET_F("RC"),receiveNotificationColor);
|
sappend('c',SET_F("RC"),receiveNotificationColor);
|
||||||
sappend('c',SET_F("RX"),receiveNotificationEffects);
|
sappend('c',SET_F("RX"),receiveNotificationEffects);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user