This commit is contained in:
Blaž Kristan 2025-06-29 22:42:33 +02:00
parent c0875b36bb
commit a24420ae70
3 changed files with 45 additions and 5 deletions

View File

@ -4,6 +4,7 @@
#include <Arduino.h> #include <Arduino.h>
#include <IPAddress.h> #include <IPAddress.h>
#include "src/dependencies/network/Network.h" // for isConnected() (& WiFi)
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#include "driver/ledc.h" #include "driver/ledc.h"
#include "soc/ledc_struct.h" #include "soc/ledc_struct.h"
@ -95,7 +96,7 @@ void Bus::calculateCCT(uint32_t c, uint8_t &ww, uint8_t &cw) {
} else { } else {
cct = (approximateKelvinFromRGB(c) - 1900) >> 5; // convert K (from RGB value) to relative format cct = (approximateKelvinFromRGB(c) - 1900) >> 5; // convert K (from RGB value) to relative format
} }
//0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold) //0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold)
if (cct < _cctBlend) ww = 255; if (cct < _cctBlend) ww = 255;
else ww = ((255-cct) * 255) / (255 - _cctBlend); else ww = ((255-cct) * 255) / (255 - _cctBlend);
@ -692,6 +693,10 @@ BusNetwork::BusNetwork(const BusConfig &bc)
_hasCCT = false; _hasCCT = false;
_UDPchannels = _hasWhite + 3; _UDPchannels = _hasWhite + 3;
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
#ifdef ARDUINO_ARCH_ESP32
_hostname = bc.text;
resolveHostname(); // resolve hostname to IP address if needed
#endif
_data = (uint8_t*)d_calloc(_len, _UDPchannels); _data = (uint8_t*)d_calloc(_len, _UDPchannels);
_valid = (_data != nullptr); _valid = (_data != nullptr);
DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
@ -726,6 +731,19 @@ size_t BusNetwork::getPins(uint8_t* pinArray) const {
return 4; return 4;
} }
#ifdef ARDUINO_ARCH_ESP32
void BusNetwork::resolveHostname() {
static unsigned long nextResolve = 0;
if (Network.isConnected() && millis() > nextResolve && _hostname.length() > 0) {
nextResolve = millis() + 600000; // resolve only every 10 minutes
IPAddress clnt;
if (strlen(cmDNS) > 0) clnt = MDNS.queryHost(_hostname);
else WiFi.hostByName(_hostname.c_str(), clnt);
if (clnt != IPAddress()) _client = clnt;
}
}
#endif
// credit @willmmiles & @netmindz https://github.com/wled/WLED/pull/4056 // credit @willmmiles & @netmindz https://github.com/wled/WLED/pull/4056
std::vector<LEDType> BusNetwork::getLEDTypes() { std::vector<LEDType> BusNetwork::getLEDTypes() {
return { return {
@ -911,6 +929,13 @@ void BusManager::on() {
} }
} }
} }
#else
for (auto &bus : busses) if (bus->isVirtual()) {
// virtual/network bus should check for IP change if hostname is specified
// otherwise there are no endpoints to force DNS resolution
BusNetwork &b = static_cast<BusNetwork&>(*bus);
b.resolveHostname();
}
#endif #endif
#ifdef ESP32_DATA_IDLE_HIGH #ifdef ESP32_DATA_IDLE_HIGH
esp32RMTInvertIdle(); esp32RMTInvertIdle();

View File

@ -342,6 +342,10 @@ class BusNetwork : public Bus {
size_t getBusSize() const override { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); } size_t getBusSize() const override { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); }
void show() override; void show() override;
void cleanup(); void cleanup();
#ifdef ARDUINO_ARCH_ESP32
void resolveHostname();
const String getCustomText() const override { return _hostname; }
#endif
static std::vector<LEDType> getLEDTypes(); static std::vector<LEDType> getLEDTypes();
@ -351,6 +355,9 @@ class BusNetwork : public Bus {
uint8_t _UDPchannels; uint8_t _UDPchannels;
bool _broadcastLock; bool _broadcastLock;
uint8_t *_data; uint8_t *_data;
#ifdef ARDUINO_ARCH_ESP32
String _hostname;
#endif
}; };

View File

@ -52,6 +52,11 @@
maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32)
maxCO = o; // maxCO - max Color Order mappings maxCO = o; // maxCO - max Color Order mappings
} }
function is8266() { return maxA == 5 && maxD == 3; } // NOTE: see const.h
function is32() { return maxA == 16 && maxD == 16; } // NOTE: see const.h
function isC3() { return maxA == 6 && maxD == 2; } // NOTE: see const.h
function isS2() { return maxA == 8 && maxD == 12 && maxV == 4; } // NOTE: see const.h
function isS3() { return maxA == 8 && maxD == 12 && maxV == 6; } // NOTE: see const.h
function pinsOK() { function pinsOK() {
var ok = true; var ok = true;
var nList = d.Sf.querySelectorAll("#mLC input[name^=L]"); var nList = d.Sf.querySelectorAll("#mLC input[name^=L]");
@ -271,7 +276,7 @@
gRGBW |= hasW(t); // RGBW checkbox gRGBW |= hasW(t); // RGBW checkbox
gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM
gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown
gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping
if (!(isDig(t) && hasW(t))) d.Sf["WO"+n].value = 0; // reset swapping if (!(isDig(t) && hasW(t))) d.Sf["WO"+n].value = 0; // reset swapping
gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog
gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual
@ -281,6 +286,8 @@
gId("dig"+n+"l").style.display = (isD2P(t) || isPWM(t)) ? "inline":"none"; // bus clock speed / PWM speed (relative) (not On/Off) gId("dig"+n+"l").style.display = (isD2P(t) || isPWM(t)) ? "inline":"none"; // bus clock speed / PWM speed (relative) (not On/Off)
gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed"; // change reverse text for analog else (rotated 180°) gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed"; // change reverse text for analog else (rotated 180°)
//gId("psd"+n).innerHTML = isAna(t) ? "Index:":"Start:"; // change analog start description //gId("psd"+n).innerHTML = isAna(t) ? "Index:":"Start:"; // change analog start description
gId("net"+n+"h").style.display = isNet(t) && !is8266() ? "block" : "none"; // show host field for network types except on ESP8266
if (!isNet(t) || is8266()) d.Sf["HS"+n].value = ""; // cleart host field if not network type or ESP8266
}); });
// display global white channel overrides // display global white channel overrides
gId("wc").style.display = (gRGBW) ? 'inline':'none'; gId("wc").style.display = (gRGBW) ? 'inline':'none';
@ -463,6 +470,7 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
<span id="p2d${s}"></span><input type="number" name="L2${s}" class="s" onchange="UI();pinUpd(this);"/> <span id="p2d${s}"></span><input type="number" name="L2${s}" class="s" onchange="UI();pinUpd(this);"/>
<span id="p3d${s}"></span><input type="number" name="L3${s}" class="s" onchange="UI();pinUpd(this);"/> <span id="p3d${s}"></span><input type="number" name="L3${s}" class="s" onchange="UI();pinUpd(this);"/>
<span id="p4d${s}"></span><input type="number" name="L4${s}" class="s" onchange="UI();pinUpd(this);"/> <span id="p4d${s}"></span><input type="number" name="L4${s}" class="s" onchange="UI();pinUpd(this);"/>
<div id="net${s}h" class="hide">Host: <input type="text" name="HS${s}" maxlength="32" pattern="[a-zA-Z0-9_\\-]*" onchange="UI()"/>.local</div>
<div id="dig${s}r" style="display:inline"><br><span id="rev${s}">Reversed</span>: <input type="checkbox" name="CV${s}"></div> <div id="dig${s}r" style="display:inline"><br><span id="rev${s}">Reversed</span>: <input type="checkbox" name="CV${s}"></div>
<div id="dig${s}s" style="display:inline"><br>Skip first LEDs: <input type="number" name="SL${s}" min="0" max="255" value="0" oninput="UI()"></div> <div id="dig${s}s" style="display:inline"><br>Skip first LEDs: <input type="number" name="SL${s}" min="0" max="255" value="0" oninput="UI()"></div>
<div id="dig${s}f" style="display:inline"><br><span id="off${s}">Off Refresh</span>: <input id="rf${s}" type="checkbox" name="RF${s}"></div> <div id="dig${s}f" style="display:inline"><br><span id="off${s}">Off Refresh</span>: <input id="rf${s}" type="checkbox" name="RF${s}"></div>
@ -479,7 +487,7 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
if (type.t != undefined && type.t != "") { if (type.t != undefined && type.t != "") {
opt.setAttribute('data-type', type.t); opt.setAttribute('data-type', type.t);
} }
sel.appendChild(opt); sel.appendChild(opt);
} }
} }
}); });
@ -586,7 +594,7 @@ Swap: <select id="xw${s}" name="XW${s}">
var cs = false; var cs = false;
for (var i=1; i < gEBCN("iST").length; i++) { for (var i=1; i < gEBCN("iST").length; i++) {
var s = chrID(i); var s = chrID(i);
var p = chrID(i-1); // cover edge case 'A' previous char being '9' var p = chrID(i-1); // cover edge case 'A' previous char being '9'
var v = parseInt(gId("ls"+p).value) + parseInt(gN("LC"+p).value); var v = parseInt(gId("ls"+p).value) + parseInt(gN("LC"+p).value);
if (v != parseInt(gId("ls"+s).value)) {cs = true; startsDirty[i] = true;} if (v != parseInt(gId("ls"+s).value)) {cs = true; startsDirty[i] = true;}
} }
@ -617,7 +625,7 @@ Swap: <select id="xw${s}" name="XW${s}">
function receivedText(e) { function receivedText(e) {
let lines = e.target.result; let lines = e.target.result;
let c = JSON.parse(lines); let c = JSON.parse(lines);
if (c.hw) { if (c.hw) {
if (c.hw.led) { if (c.hw.led) {
// remove all existing outputs // remove all existing outputs