diff --git a/CHANGELOG.md b/CHANGELOG.md index 31c22f52..1277b32e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Development versions after 0.9.1 release +#### Build 2004120 + +- Added Art-Net support +- Added OTA platform to platformio.ini #### Build 2004100 @@ -23,7 +27,7 @@ #### Build 2003262 -- Fixed compilation for Analog LEDs +- Fixed compilation for Analog LEDs - Fixed sync settings network port fields too small #### Build 2003261 diff --git a/platformio.ini b/platformio.ini index 91bdd867..49517613 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,6 +30,7 @@ default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev ; default_envs = d1_mini ; default_envs = heltec_wifi_kit_8 ; default_envs = d1_mini_debug +; default_envs = d1_mini_ota ; default_envs = esp32dev ; default_envs = esp8285_4CH_MagicHome ; default_envs = esp8285_4CH_H801 @@ -241,6 +242,15 @@ platform = ${common.platform_latest} board_build.ldscript = ${common.ldscript_4m1m} build_flags = ${common.build_flags_esp8266} ${common.debug_flags} +[env:d1_mini_ota] +board = d1_mini +upload_protocol = espota +# exchange for your WLED IP +upload_port = "10.10.1.27" +platform = ${common.platform_latest} +board_build.ldscript = ${common.ldscript_4m1m} +build_flags = ${common.build_flags_esp8266} + # ------------------------------------------------------------------------------ # custom board configurations # ------------------------------------------------------------------------------ diff --git a/wled00/const.h b/wled00/const.h index 173d7e7d..5cd4b02f 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -43,6 +43,7 @@ #define REALTIME_MODE_HYPERION 3 #define REALTIME_MODE_E131 4 #define REALTIME_MODE_ADALIGHT 5 +#define REALTIME_MODE_ARTNET 6 //E1.31 DMX modes #define DMX_MODE_DISABLED 0 //not used diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 5cf4b608..91fe8992 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -1,141 +1,105 @@ - - - - Sync Settings - - - - -
-
-
-

Sync setup

-

Button setup

- On/Off button enabled:
- Infrared receiver enabled:
- IR info -

WLED Sync UDP Broadcast

- UDP Port:
- Receive Brightness, Color, and Effects
- Send notifications on direct change:
- Send notifications on button press:
- Send Alexa notifications:
- Send Philips Hue change notifications:
- Send Macro notifications:
- Send notifications twice: -

Realtime

- Receive UDP realtime:

- E1.31 (sACN)
- Skip out-of-sequence packets (freeze instead of flicker):
- Multicast mode:
- E1.31 start universe:
- Reboot required. Check out LedFx!

- DMX start address:
- DMX mode: disabled
- Single RGB (3 Channels for all LEDs: Red Green Blue)
- Single DRGB (4 Channels for all LEDs: Dimmer Red Green Blue)
- Effect (11 Channels parametrizing Effects: Dimmer Effect Speed Intensity Palette PriRed PriGreen PriBlue SecRed SecGreen SecBlue)
- Multiple RGB (3 Channels for each LED: Red Green Blue)
- Multiple DRGB (1+3 Channels for each LED: Dimmer Red1 Green1 Blue1 Red2 Green2 Blue2...)
- Reboot required. Check out LedFx!

- Timeout: ms
- Force max brightness:
- Disable realtime gamma correction:
- Realtime LED offset: -

Alexa Voice Assistant

- Emulate Alexa device:
- Alexa invocation name: -

Blynk

- Blynk, MQTT and Hue sync all connect to external hosts!
- This may impact the responsiveness of the ESP8266.

- For best results, only use one of these services at a time.
- (alternatively, connect a second ESP to them and use the UDP sync)

- Device Auth token:
- Clear the token field to disable. Setup info -

MQTT

- Enable MQTT:
- Broker:
- Port:
- The MQTT credentials are sent over an unsecured connection.
- Never use the MQTT password for another service!

- Username:
- Password:
- Client ID:
- Device Topic:
- Group Topic:
- MQTT info -

Philips Hue

- You can find the bridge IP and the light number in the 'About' section of the hue app.
- Poll Hue light every ms:
- Then, receive On/Off, Brightness, and Color
- Hue Bridge IP:
- . - . - . -
- Press the pushlink button on the bridge, after that save this page!
- (when first connecting)
- Hue status: Internal ESP Error!
- -
+Sync Settings + + + +
+
+
+

Sync setup

+

Button setup

+On/Off button enabled:
+Infrared remote: +
+IR info +

WLED Broadcast

+UDP Port:
+Receive Brightness, Color, and Effects
+Send notifications on direct change:
+Send notifications on button press:
+Send Alexa notifications:
+Send Philips Hue change notifications:
+Send Macro notifications:
+Send notifications twice: +

Realtime

+Receive UDP realtime:

+Network DMX input
+Type: +
+
Port:
+Multicast:
+Start universe:
+Reboot required. Check out LedFx!
+Skip out-of-sequence packets:
+DMX start address:
+DMX mode: +
+E1.31 info
+Timeout: ms
+Force max brightness:
+Disable realtime gamma correction:
+Realtime LED offset: +

Alexa Voice Assistant

+Emulate Alexa device:
+Alexa invocation name: +

Blynk

+Blynk, MQTT and Hue sync all connect to external hosts!
+This may impact the responsiveness of the ESP8266.

+For best results, only use one of these services at a time.
+(alternatively, connect a second ESP to them and use the UDP sync)

+Device Auth token:
+Clear the token field to disable. Setup info +

MQTT

+Enable MQTT:
+Broker: +Port:
+The MQTT credentials are sent over an unsecured connection.
+Never use the MQTT password for another service!

+Username:
+Password:
+Client ID:
+Device Topic:
+Group Topic:
+Reboot required to apply changes. MQTT info +

Philips Hue

+You can find the bridge IP and the light number in the 'About' section of the hue app.
+Poll Hue light every ms:
+Then, receive On/Off, Brightness, and Color
+Hue Bridge IP:
+ . + . + . +
+Press the pushlink button on the bridge, after that save this page!
+(when first connecting)
+Hue status: Disabled in this build
+ +
\ No newline at end of file diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 2034f84d..6e774194 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -4,29 +4,45 @@ * E1.31 handler */ -void handleE131Packet(e131_packet_t* p, IPAddress clientIP){ +void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){ //E1.31 protocol support - uint16_t uni = htons(p->universe); - uint8_t previousUniverses = uni - e131Universe; - uint16_t possibleLEDsInCurrentUniverse; - uint16_t dmxChannels = htons(p->property_value_count) -1; + uint16_t uni = 0, dmxChannels = 0; + uint8_t* e131_data = nullptr; + uint8_t seq = 0, mde = REALTIME_MODE_E131; + + if (isArtnet) + { + uni = p->art_universe; + dmxChannels = htons(p->art_length); + e131_data = p->art_data; + seq = p->art_sequence_number; + mde = REALTIME_MODE_ARTNET; + } else { + uni = htons(p->universe); + dmxChannels = htons(p->property_value_count) -1; + e131_data = p->property_values; + seq = p->sequence_number; + } // only listen for universes we're handling & allocated memory if (uni >= (e131Universe + E131_MAX_UNIVERSE_COUNT)) return; + uint8_t previousUniverses = uni - e131Universe; + uint16_t possibleLEDsInCurrentUniverse; + if (e131SkipOutOfSequence) - if (p->sequence_number < e131LastSequenceNumber[uni-e131Universe] && p->sequence_number > 20 && e131LastSequenceNumber[uni-e131Universe] < 250){ + if (seq < e131LastSequenceNumber[uni-e131Universe] && seq > 20 && e131LastSequenceNumber[uni-e131Universe] < 250){ DEBUG_PRINT("skipping E1.31 frame (last seq="); DEBUG_PRINT(e131LastSequenceNumber[uni-e131Universe]); DEBUG_PRINT(", current seq="); - DEBUG_PRINT(p->sequence_number); + DEBUG_PRINT(seq); DEBUG_PRINT(", universe="); DEBUG_PRINT(uni); DEBUG_PRINTLN(")"); return; } - e131LastSequenceNumber[uni-e131Universe] = p->sequence_number; + e131LastSequenceNumber[uni-e131Universe] = seq; // update status info realtimeIP = clientIP; @@ -39,46 +55,46 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){ case DMX_MODE_SINGLE_RGB: if (uni != e131Universe) return; if (dmxChannels-DMXAddress+1 < 3) return; - arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131); + realtimeLock(realtimeTimeoutMs, mde); for (uint16_t i = 0; i < ledCount; i++) - setRealtimePixel(i, p->property_values[DMXAddress+0], p->property_values[DMXAddress+1], p->property_values[DMXAddress+2], 0); + setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], 0); break; case DMX_MODE_SINGLE_DRGB: if (uni != e131Universe) return; if (dmxChannels-DMXAddress+1 < 4) return; - arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131); - if (DMXOldDimmer != p->property_values[DMXAddress+0]) { - DMXOldDimmer = p->property_values[DMXAddress+0]; - bri = p->property_values[DMXAddress+0]; + realtimeLock(realtimeTimeoutMs, mde); + if (DMXOldDimmer != e131_data[DMXAddress+0]) { + DMXOldDimmer = e131_data[DMXAddress+0]; + bri = e131_data[DMXAddress+0]; strip.setBrightness(bri); } for (uint16_t i = 0; i < ledCount; i++) - setRealtimePixel(i, p->property_values[DMXAddress+1], p->property_values[DMXAddress+2], p->property_values[DMXAddress+3], 0); + setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], 0); break; case DMX_MODE_EFFECT: if (uni != e131Universe) return; if (dmxChannels-DMXAddress+1 < 11) return; - if (DMXOldDimmer != p->property_values[DMXAddress+0]) { - DMXOldDimmer = p->property_values[DMXAddress+0]; - bri = p->property_values[DMXAddress+0]; + if (DMXOldDimmer != e131_data[DMXAddress+0]) { + DMXOldDimmer = e131_data[DMXAddress+0]; + bri = e131_data[DMXAddress+0]; } - if (p->property_values[DMXAddress+1] < MODE_COUNT) - effectCurrent = p->property_values[DMXAddress+ 1]; - effectSpeed = p->property_values[DMXAddress+ 2]; // flickers - effectIntensity = p->property_values[DMXAddress+ 3]; - effectPalette = p->property_values[DMXAddress+ 4]; - col[0] = p->property_values[DMXAddress+ 5]; - col[1] = p->property_values[DMXAddress+ 6]; - col[2] = p->property_values[DMXAddress+ 7]; - colSec[0] = p->property_values[DMXAddress+ 8]; - colSec[1] = p->property_values[DMXAddress+ 9]; - colSec[2] = p->property_values[DMXAddress+10]; + if (e131_data[DMXAddress+1] < MODE_COUNT) + effectCurrent = e131_data[DMXAddress+ 1]; + effectSpeed = e131_data[DMXAddress+ 2]; // flickers + effectIntensity = e131_data[DMXAddress+ 3]; + effectPalette = e131_data[DMXAddress+ 4]; + col[0] = e131_data[DMXAddress+ 5]; + col[1] = e131_data[DMXAddress+ 6]; + col[2] = e131_data[DMXAddress+ 7]; + colSec[0] = e131_data[DMXAddress+ 8]; + colSec[1] = e131_data[DMXAddress+ 9]; + colSec[2] = e131_data[DMXAddress+10]; if (dmxChannels-DMXAddress+1 > 11) { - col[3] = p->property_values[DMXAddress+11]; //white - colSec[3] = p->property_values[DMXAddress+12]; + col[3] = e131_data[DMXAddress+11]; //white + colSec[3] = e131_data[DMXAddress+12]; } transitionDelayTemp = 0; // act fast colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); // don't send UDP @@ -86,13 +102,13 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){ break; case DMX_MODE_MULTIPLE_RGB: - arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131); + realtimeLock(realtimeTimeoutMs, mde); if (previousUniverses == 0) { // first universe of this fixture possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress + 1) / 3; for (uint16_t i = 0; i < ledCount; i++) { if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s) - setRealtimePixel(i, p->property_values[DMXAddress+i*3+0], p->property_values[DMXAddress+i*3+1], p->property_values[DMXAddress+i*3+2], 0); + setRealtimePixel(i, e131_data[DMXAddress+i*3+0], e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], 0); } } else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) { // additional universe(s) of this fixture @@ -102,24 +118,24 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){ for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) { uint8_t j = i - numberOfLEDsInPreviousUniverses; if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s) - setRealtimePixel(i, p->property_values[j*3+1], p->property_values[j*3+2], p->property_values[j*3+3], 0); + setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0); } } break; case DMX_MODE_MULTIPLE_DRGB: - arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131); + realtimeLock(realtimeTimeoutMs, mde); if (previousUniverses == 0) { // first universe of this fixture - if (DMXOldDimmer != p->property_values[DMXAddress+0]) { - DMXOldDimmer = p->property_values[DMXAddress+0]; - bri = p->property_values[DMXAddress+0]; + if (DMXOldDimmer != e131_data[DMXAddress+0]) { + DMXOldDimmer = e131_data[DMXAddress+0]; + bri = e131_data[DMXAddress+0]; strip.setBrightness(bri); } possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress) / 3; for (uint16_t i = 0; i < ledCount; i++) { if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s) - setRealtimePixel(i, p->property_values[DMXAddress+i*3+1], p->property_values[DMXAddress+i*3+2], p->property_values[DMXAddress+i*3+3], 0); + setRealtimePixel(i, e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], e131_data[DMXAddress+i*3+3], 0); } } else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) { // additional universe(s) of this fixture @@ -129,7 +145,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){ for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) { uint8_t j = i - numberOfLEDsInPreviousUniverses; if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s) - setRealtimePixel(i, p->property_values[j*3+1], p->property_values[j*3+2], p->property_values[j*3+3], 0); + setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0); } } break; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 7261efcb..2d8401bc 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -42,7 +42,7 @@ void initDMX(); void handleDMX(); //e131.cpp -void handleE131Packet(e131_packet_t* p, IPAddress clientIP); +void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet); //file.cpp bool handleFileRead(AsyncWebServerRequest*, String path); @@ -103,12 +103,6 @@ void handleNightlight(); bool initMqtt(); void publishMqtt(); -//notify.cpp -void notify(byte callMode, bool followUp=false); -void arlsLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); -void handleNotifications(); -void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); - //ntp.cpp void handleNetworkTime(); void sendNTPPacket(); @@ -140,6 +134,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req); int getNumVal(const String* req, uint16_t pos); bool updateVal(const String* req, const char* key, byte* val, byte minv=0, byte maxv=255); +//udp.cpp +void notify(byte callMode, bool followUp=false); +void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); +void handleNotifications(); +void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); + //usermod.cpp void userSetup(); void userConnected(); diff --git a/wled00/html_settings.h b/wled00/html_settings.h index fa019533..009dda50 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -252,16 +252,16 @@ Sync button toggles both send and receive:
//sync settings const char PAGE_settings_sync[] PROGMEM = R"=====( -Sync Settings -