New hostname handling - add option to enable mDNS in settings - move hostname to "nw" key in config JSON - add new config key in "nw" for mDNS (bool) - remove prepareHostname() function - update mDNS calls - add hostname update for Ethernet - move WiFi configuration to cfg.json - rename LED and WiFi to Hardware and Network in settings - reorder network settings

This commit is contained in:
Blaž Kristan 2025-07-21 12:16:32 +02:00
parent e2edd38de5
commit 2509b1c5d5
14 changed files with 143 additions and 155 deletions

View File

@ -57,25 +57,22 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
#endif #endif
JsonObject id = doc["id"]; JsonObject id = doc["id"];
getStringFromJson(cmDNS, id[F("mdns")], sizeof(cmDNS)); // legacy behaviour
// fill in unique mDNS name if not set (cmDNS can be empty meaning no mDNS is used) getStringFromJson(hostName, id[F("mdns")], sizeof(hostName));
if (strcmp(cmDNS, DEFAULT_MDNS_NAME) == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); if (strlen(hostName) == 0) {
getStringFromJson(serverDescription, id[F("name")], sizeof(serverDescription)); mDNSenabled = false; // if no host name is set, disable mDNS
if (!fromFS) { sprintf_P(hostName, PSTR("wled-%.*s"), 6, escapedMac.c_str() + 6);
char hostname[25];
prepareHostname(hostname, sizeof(hostname)-1);
#ifdef ARDUINO_ARCH_ESP32
WiFi.setHostname(hostname);
#else
WiFi.hostname(hostname);
#endif
} }
getStringFromJson(serverDescription, id["name"], sizeof(serverDescription));
#ifndef WLED_DISABLE_ALEXA #ifndef WLED_DISABLE_ALEXA
getStringFromJson(alexaInvocationName, id[F("inv")], sizeof(alexaInvocationName)); getStringFromJson(alexaInvocationName, id[F("inv")], sizeof(alexaInvocationName));
#endif #endif
CJSON(simplifiedUI, id[F("sui")]); CJSON(simplifiedUI, id[F("sui")]);
JsonObject nw = doc["nw"]; JsonObject nw = doc["nw"];
CJSON(mDNSenabled, nw[F("mdns")]);
getStringFromJson(hostName, nw["name"], sizeof(hostName));
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW
CJSON(enableESPNow, nw[F("espnow")]); CJSON(enableESPNow, nw[F("espnow")]);
linked_remotes.clear(); linked_remotes.clear();
@ -154,13 +151,23 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject wifi = doc[F("wifi")]; JsonObject wifi = doc[F("wifi")];
noWifiSleep = !(wifi[F("sleep")] | !noWifiSleep); // inverted noWifiSleep = !(wifi[F("sleep")] | !noWifiSleep); // inverted
//noWifiSleep = !noWifiSleep;
CJSON(force802_3g, wifi[F("phy")]); //force phy mode g? CJSON(force802_3g, wifi[F("phy")]); //force phy mode g?
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
CJSON(txPower, wifi[F("txpwr")]); CJSON(txPower, wifi[F("txpwr")]);
txPower = min(max((int)txPower, (int)WIFI_POWER_2dBm), (int)WIFI_POWER_19_5dBm); txPower = min(max((int)txPower, (int)WIFI_POWER_2dBm), (int)WIFI_POWER_19_5dBm);
#endif #endif
// apply WiFi options from above (regardless of fromFS or not)
#ifdef ARDUINO_ARCH_ESP32
WiFi.setSleep(!noWifiSleep);
WiFi.setHostname(hostName);
WiFi.setTxPower(wifi_power_t(txPower));
#else
WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N);
wifi_set_sleep_type((noWifiSleep) ? NONE_SLEEP_T : MODEM_SLEEP_T);
WiFi.hostname(hostName);
#endif
JsonObject hw = doc[F("hw")]; JsonObject hw = doc[F("hw")];
// initialize LED pins and lengths prior to other HW (except for ethernet) // initialize LED pins and lengths prior to other HW (except for ethernet)
@ -837,14 +844,15 @@ void serializeConfig(JsonObject root) {
root[F("vid")] = VERSION; root[F("vid")] = VERSION;
JsonObject id = root.createNestedObject("id"); JsonObject id = root.createNestedObject("id");
id[F("mdns")] = cmDNS; id["name"] = serverDescription;
id[F("name")] = serverDescription;
#ifndef WLED_DISABLE_ALEXA #ifndef WLED_DISABLE_ALEXA
id[F("inv")] = alexaInvocationName; id[F("inv")] = alexaInvocationName;
#endif #endif
id[F("sui")] = simplifiedUI; id[F("sui")] = simplifiedUI;
JsonObject nw = root.createNestedObject("nw"); JsonObject nw = root.createNestedObject("nw");
id["name"] = hostName;
id[F("mdns")] = mDNSenabled;
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW
nw[F("espnow")] = enableESPNow; nw[F("espnow")] = enableESPNow;
JsonArray lrem = nw.createNestedArray(F("linked_remote")); JsonArray lrem = nw.createNestedArray(F("linked_remote"));

View File

@ -38,13 +38,13 @@
</head> </head>
<body onload="S()"> <body onload="S()">
<button type=submit id="b" onclick="window.location=getURL('/')">Back</button> <button type=submit id="b" onclick="window.location=getURL('/')">Back</button>
<button type="submit" onclick="window.location=getURL('/settings/wifi')">WiFi Setup</button> <button type="submit" onclick="window.location=getURL('/settings/wifi')">Network Setup</button>
<button type="submit" onclick="window.location=getURL('/settings/leds')">LED Preferences</button> <button type="submit" onclick="window.location=getURL('/settings/leds')">Hardware Setup</button>
<button id="2dbtn" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button> <button id="2dbtn" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
<button type="submit" onclick="window.location=getURL('/settings/ui')">User Interface</button> <button type="submit" onclick="window.location=getURL('/settings/ui')">User Interface</button>
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/dmx')">DMX Output</button> <button id="dmxbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/dmx')">DMX Output</button>
<button type="submit" onclick="window.location=getURL('/settings/sync')">Sync Interfaces</button> <button type="submit" onclick="window.location=getURL('/settings/sync')">Sync Interfaces</button>
<button type="submit" onclick="window.location=getURL('/settings/time')">Time & Macros</button> <button type="submit" onclick="window.location=getURL('/settings/time')">Time & Scheduler</button>
<button type="submit" onclick="window.location=getURL('/settings/um')">Usermods</button> <button type="submit" onclick="window.location=getURL('/settings/um')">Usermods</button>
<button type="submit" onclick="window.location=getURL('/settings/sec')">Security & Updates</button> <button type="submit" onclick="window.location=getURL('/settings/sec')">Security & Updates</button>
</body> </body>

View File

@ -155,14 +155,13 @@
function Save() { function Save() {
SetLS(); SetLS();
if (d.Sf.DS.value != initial_ds || /*d.Sf.ST.checked != initial_st ||*/ d.Sf.SU.checked != initial_su) d.Sf.submit(); if (d.Sf.DS.value != initial_ds || d.Sf.SU.checked != initial_su) d.Sf.submit();
} }
function S() { function S() {
getLoc(); getLoc();
loadJS(getURL('/settings/s.js?p=3'), false, undefined, ()=>{ loadJS(getURL('/settings/s.js?p=3'), false, undefined, ()=>{
initial_ds = d.Sf.DS.value; initial_ds = d.Sf.DS.value;
//initial_st = d.Sf.ST.checked;
initial_su = d.Sf.SU.checked; initial_su = d.Sf.SU.checked;
GetLS(); GetLS();
}); // If we set async false, file is loaded and executed, then next statement is processed }); // If we set async false, file is loaded and executed, then next statement is processed
@ -219,10 +218,9 @@
<span id="lserr" style="color:red; display:none">&#9888; Could not access local storage. Make sure it is enabled in your browser.</span><hr> <span id="lserr" style="color:red; display:none">&#9888; Could not access local storage. Make sure it is enabled in your browser.</span><hr>
</div> </div>
<h2>Web Setup</h2> <h2>Web Setup</h2>
Server description: <input type="text" name="DS" maxlength="32"><br> Device name: <input type="text" name="DS" minlength="2" maxlength="32"><br>
<!-- Sync button toggles both send and receive: <input type="checkbox" name="ST"><br> -->
Enable simplified UI: <input type="checkbox" name="SU"><br> Enable simplified UI: <input type="checkbox" name="SU"><br>
<i>The following UI customization settings are unique both to the WLED device and this browser.<br> <i class="warn">The following UI customization settings are unique both to the WLED device and this browser.<br>
You will need to set them again if using a different browser, device or WLED IP address.<br> You will need to set them again if using a different browser, device or WLED IP address.<br>
Refresh the main UI to apply changes.</i><br> Refresh the main UI to apply changes.</i><br>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<title>WiFi Settings</title> <title>Network Settings</title>
<script src="common.js" async type="text/javascript"></script> <script src="common.js" async type="text/javascript"></script>
<script> <script>
var scanLoops = 0, preScanSSID = ""; var scanLoops = 0, preScanSSID = "";
@ -134,7 +134,7 @@ Static subnet mask:<br>
} }
function S() { function S() {
getLoc(); getLoc();
loadJS(getURL('/settings/s.js?p=1'), false); // If we set async false, file is loaded and executed, then next statement is processed loadJS(getURL('/settings/s.js?p=1'), false, undefined, genUrl); // If we set async false, file is loaded and executed, then next statement is processed
if (loc) d.Sf.action = getURL('/settings/wifi'); if (loc) d.Sf.action = getURL('/settings/wifi');
setTimeout(tE, 500); // wait for DOM to load before calling tE() setTimeout(tE, 500); // wait for DOM to load before calling tE()
} }
@ -177,8 +177,9 @@ Static subnet mask:<br>
rC++; rC++;
gId('+').style.display = gId("rml").childElementCount < 10 ? 'inline' : 'none'; // can't append to list anymore, hide button gId('+').style.display = gId("rml").childElementCount < 10 ? 'inline' : 'none'; // can't append to list anymore, hide button
} }
function vI(i) { function genUrl() {
i.style.color = (i.value.match(/^[a-zA-Z0-9_\-]*$/)) ? 'white' : 'red'; gId("ml").textContent = d.Sf.CM.value;
gId('mi').style.display = d.Sf.MD.checked?'inline':'none'
} }
</script> </script>
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
@ -189,14 +190,15 @@ Static subnet mask:<br>
<div class="helpB"><button type="button" onclick="H('features/settings/#wifi-settings')">?</button></div> <div class="helpB"><button type="button" onclick="H('features/settings/#wifi-settings')">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr> <button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
</div> </div>
<h2>WiFi setup</h2> <h2>Network setup</h2>
Hostname/mDNS address (empty for no mDNS):<br> Hostname<br>
http://<input type="text" name="CM" maxlength="32" pattern="[a-zA-Z0-9_\-]*" oninput="vI(this)">.local<br> <input type="text" name="CM" minlength="2" maxlength="32" pattern="[a-zA-Z0-9_\-]*" oninput="genUrl()"><br>
Enable mDNS: <input type="checkbox" name="MD" checked onchange="genUrl()"><br>
<div id="mi"><i>http://<span id="ml">wled</span>.local</i><br></div>
Client IP: <span class="sip"> Not connected </span><br> Client IP: <span class="sip"> Not connected </span><br>
<h3>Connect to existing network</h3> <h3>WiFi</h3>
<button type="button" id="scan" onclick="N()">Scan</button><br> <button type="button" id="scan" onclick="N()">Scan</button><br>
<div id="wifi"> <div id="wifi">
Wireless networks
<div id="wifi_entries"></div> <div id="wifi_entries"></div>
<hr class="sml"> <hr class="sml">
<button type="button" id="wifi_add" onclick="addWiFi()">+</button> <button type="button" id="wifi_add" onclick="addWiFi()">+</button>
@ -204,20 +206,59 @@ Static subnet mask:<br>
</div> </div>
DNS server address:<br> DNS server address:<br>
<input name="D0" type="number" class="s" min="0" max="255" required>.<input name="D1" type="number" class="s" min="0" max="255" required>.<input name="D2" type="number" class="s" min="0" max="255" required>.<input name="D3" type="number" class="s" min="0" max="255" required><br> <input name="D0" type="number" class="s" min="0" max="255" required>.<input name="D1" type="number" class="s" min="0" max="255" required>.<input name="D2" type="number" class="s" min="0" max="255" required>.<input name="D3" type="number" class="s" min="0" max="255" required><br>
<h3>Configure Access Point</h3> <hr class="sml">
AP SSID (empty for no AP):<br> <input type="text" name="AS" maxlength="32" pattern="[a-zA-Z0-9_\-]*" oninput="vI(this)"><br> <h3>Access Point</h3>
AP SSID (empty for no AP):<br><input type="text" name="AS" maxlength="32" pattern="[a-zA-Z0-9_\-]*"><br>
Hide AP name: <input type="checkbox" name="AH"><br> Hide AP name: <input type="checkbox" name="AH"><br>
AP password (empty for open):<br> <input type="password" name="AP" maxlength="63" pattern="(.{8,63})|()" title="Empty or min. 8 characters"><br> AP password (empty for open):<br><input type="password" name="AP" maxlength="63" pattern="(.{8,63})|()" title="Empty or min. 8 characters"><br>
Access Point WiFi channel: <input name="AC" type="number" class="xs" min="1" max="13" required><br> Access Point WiFi channel: <input name="AC" type="number" class="xs" min="1" max="13" required><br>
AP opens: AP opens:<br>
<select name="AB"> <select name="AB">
<option value="0">No connection after boot</option> <option value="0">No connection after boot</option>
<option value="1">Disconnected</option> <option value="1">Disconnected</option>
<option value="2">Always</option> <option value="2">Always</option>
<option value="3">Never (not recommended)</option> <option value="3">Never (use button!)</option>
<option value="4">Temporary (no connection after boot)</option> <option value="4">Temporary</option>
</select><br> </select><br>
AP IP: <span class="sip"> Not active </span><br> AP IP: <span class="sip">Not active</span><br>
<hr class="sml">
<div id="ethd">
<h3>Ethernet Type</h3>
<select name="ETH" onchange="if(this.selectedIndex!=0)d.Sf.RE.checked=false;">
<option value="0">None</option>
<option value="9">ABC! WLED V43 & compatible</option>
<option value="2">ESP32-POE</option>
<option value="11">ESP32-POE-WROVER</option>
<option value="6">ESP32Deux/RGB2Go Tetra</option>
<option value="7">KIT-VE</option>
<option value="12">LILYGO T-POE Pro</option>
<option value="8">QuinLED-Dig-Octa & T-ETH-POE</option>
<option value="4">QuinLED-ESP32</option>
<option value="10">Serg74-ETH32</option>
<option value="5">TwilightLord-ESP32</option>
<option value="3">WESP32</option>
<option value="1">WT32-ETH01</option>
</select><br>
<i class="warn">ESP-NOW is incompatible with Ethernet.</i>
</div>
<hr class="sml">
<h3>ESP-NOW Wireless</h3>
<div id="NoESPNOW" class="hide">
<i class="warn">This firmware build does not include ESP-NOW support.<br></i>
</div>
<div id="ESPNOW">
Enable ESP-NOW: <input type="checkbox" name="RE" onchange="tE()"><br>
<i>Listen for events over ESP-NOW<br>
Keep disabled if not using a remote or wireless sync, increases power consumption.<br></i>
<div id="rlc">
Last device seen: <span class="rlid" id="ld"></span>
<button type="button" class="sml" id="+" onclick="aR(gId('ld').textContent)">+</button><br>
Linked MACs:<br>
<div id="rml"></div>
</div>
<input type="hidden" name="RMAC" id="rmacs">
</div>
<hr class="sml">
<h3>Experimental</h3> <h3>Experimental</h3>
Force 802.11g mode (ESP8266 only): <input type="checkbox" name="FG"><br> Force 802.11g mode (ESP8266 only): <input type="checkbox" name="FG"><br>
Disable WiFi sleep: <input type="checkbox" name="WS"><br> Disable WiFi sleep: <input type="checkbox" name="WS"><br>
@ -238,43 +279,6 @@ Static subnet mask:<br>
</select><br> </select><br>
<i class="warn">WARNING: Modifying TX power may render device unreachable.</i> <i class="warn">WARNING: Modifying TX power may render device unreachable.</i>
</div> </div>
<h3>ESP-NOW Wireless</h3>
<div id="NoESPNOW" class="hide">
<i class="warn">This firmware build does not include ESP-NOW support.<br></i>
</div>
<div id="ESPNOW">
Enable ESP-NOW: <input type="checkbox" name="RE" onchange="tE()"><br>
<i>Listen for events over ESP-NOW<br>
Keep disabled if not using a remote or ESP-NOW sync, increases power consumption.<br></i>
<div id="rlc">
Last device seen: <span class="rlid" id="ld">None</span>
<button type="button" class="sml" id="+" onclick="aR('RM'+rC,gId('ld').textContent)">+</button><br>
Linked MACs (10 max):<br>
<div id="rml">
</div>
</div>
</div>
<div id="ethd">
<h3>Ethernet Type</h3>
<select name="ETH" onchange="if(this.selectedIndex!=0)d.Sf.RE.checked=false;">
<option value="0">None</option>
<option value="9">ABC! WLED V43 & compatible</option>
<option value="2">ESP32-POE</option>
<option value="11">ESP32-POE-WROVER</option>
<option value="6">ESP32Deux/RGB2Go Tetra</option>
<option value="7">KIT-VE</option>
<option value="12">LILYGO T-POE Pro</option>
<option value="8">QuinLED-Dig-Octa & T-ETH-POE</option>
<option value="4">QuinLED-ESP32</option>
<option value="10">Serg74-ETH32</option>
<option value="5">TwilightLord-ESP32</option>
<option value="3">WESP32</option>
<option value="1">WT32-ETH01</option>
</select><br>
<i class="warn">ESP-NOW is incompatible with Ethernet.</i>
</div>
<hr> <hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button> <button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
</form> </form>

View File

@ -64,7 +64,7 @@ button.sml {
.hide { .hide {
display: none; display: none;
} }
.err { .err, input:invalid {
color: #f00; color: #f00;
} }
.warn { .warn {

View File

@ -371,6 +371,7 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs
//network.cpp //network.cpp
bool initEthernet(); // result is informational bool initEthernet(); // result is informational
int getSignalQuality(int rssi); int getSignalQuality(int rssi);
IPAddress resolveHostname(const String &hostname, bool useMDNS = true);
void fillMAC2Str(char *str, const uint8_t *mac); void fillMAC2Str(char *str, const uint8_t *mac);
void fillStr2MAC(uint8_t *mac, const char *str); void fillStr2MAC(uint8_t *mac, const char *str);
int findWiFi(bool doScan = false); int findWiFi(bool doScan = false);
@ -505,7 +506,6 @@ size_t printSetFormValue(Print& settingsScript, const char* key, int val);
size_t printSetFormValue(Print& settingsScript, const char* key, const char* val); size_t printSetFormValue(Print& settingsScript, const char* key, const char* val);
size_t printSetFormIndex(Print& settingsScript, const char* key, int index); size_t printSetFormIndex(Print& settingsScript, const char* key, int index);
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val); size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val);
void prepareHostname(char* hostname, size_t maxLen = 32);
[[gnu::pure]] bool isAsterisksOnly(const char* str, byte maxLen); [[gnu::pure]] bool isAsterisksOnly(const char* str, byte maxLen);
bool requestJSONBufferLock(uint8_t moduleID=255); bool requestJSONBufferLock(uint8_t moduleID=255);
void releaseJSONBufferLock(); void releaseJSONBufferLock();

View File

@ -206,11 +206,10 @@ void sendImprovInfoResponse() {
#endif #endif
strlwr(bString); strlwr(bString);
#endif #endif
//Use serverDescription if it has been changed from the default "WLED", else mDNS name char vString[33];
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0); snprintf_P(vString, sizeof(vString)-1, PSTR("%s/%i"), versionString, VERSION);
char vString[32]; //Use serverDescription if it has been changed from the default "WLED", else host name
sprintf_P(vString, PSTR("%s/%i"), versionString, VERSION); const char *str[4] = {"WLED", vString, bString, strcmp(serverDescription, "WLED") == 0 ? hostName : serverDescription};
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str); sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
} }

View File

@ -265,6 +265,24 @@ int getSignalQuality(int rssi)
} }
IPAddress resolveHostname(const String &hostname, bool useMDNS) {
IPAddress clnt;
if (Network.isConnected() && hostname.length() > 0) {
#ifdef ARDUINO_ARCH_ESP32
if (mDNSenabled && useMDNS) {
String mDNSname = hostname;
mDNSname.toLowerCase(); // make sure we have a lowercase hostname
int pos = mDNSname.indexOf(F(".local"));
if (pos > 0) mDNSname.remove(pos); // remove .local domain if present (and anything following it)
if (mDNSname.indexOf('.') < 0) clnt = MDNS.queryHost(mDNSname.c_str());
}
#endif
if (clnt == IPAddress()) WiFi.hostByName(hostname.c_str(), clnt); // use full hostname if MDNS failed
}
return clnt;
}
// fill MAC address string with 6 bytes from mac array
void fillMAC2Str(char *str, const uint8_t *mac) { void fillMAC2Str(char *str, const uint8_t *mac) {
sprintf_P(str, PSTR("%02x%02x%02x%02x%02x%02x"), MAC2STR(mac)); sprintf_P(str, PSTR("%02x%02x%02x%02x%02x%02x"), MAC2STR(mac));
byte nul = 0; byte nul = 0;
@ -396,15 +414,12 @@ void WiFiEvent(WiFiEvent_t event)
if (!apActive) { if (!apActive) {
WiFi.disconnect(true); // disable WiFi entirely WiFi.disconnect(true); // disable WiFi entirely
} }
ETH.setHostname(hostName);
if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) { if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) {
ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress); ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress);
} else { } else {
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
} }
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
char hostname[33];
prepareHostname(hostname, sizeof(hostname)-1);
ETH.setHostname(hostname);
showWelcomePage = false; showWelcomePage = false;
break; break;
} }

View File

@ -63,14 +63,17 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
dnsAddress = IPAddress(request->arg(F("D0")).toInt(),request->arg(F("D1")).toInt(),request->arg(F("D2")).toInt(),request->arg(F("D3")).toInt()); dnsAddress = IPAddress(request->arg(F("D0")).toInt(),request->arg(F("D1")).toInt(),request->arg(F("D2")).toInt(),request->arg(F("D3")).toInt());
} }
strlcpy(cmDNS, request->arg(F("CM")).c_str(), sizeof(cmDNS)); strlcpy(hostName, request->arg(F("CM")).c_str(), sizeof(hostName));
char hostname[25]; if (strlen(hostName) == 0) sprintf_P(hostName, PSTR("wled-%.*s"), 6, escapedMac.c_str() + 6); // hostname must not be empty
prepareHostname(hostname, sizeof(hostname)-1);
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
WiFi.setHostname(hostname); #ifdef WLED_USE_ETHERNET
ETH.setHostname(hostName);
#endif
WiFi.setHostname(hostName);
#else #else
WiFi.hostname(hostname); WiFi.hostname(hostName);
#endif #endif
mDNSenabled = request->hasArg(F("MD"));
apBehavior = request->arg(F("AB")).toInt(); apBehavior = request->arg(F("AB")).toInt();
char oldSSID[33]; strcpy(oldSSID, apSSID); char oldSSID[33]; strcpy(oldSSID, apSSID);
@ -89,10 +92,17 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
int tx = request->arg(F("TX")).toInt(); int tx = request->arg(F("TX")).toInt();
txPower = min(max(tx, (int)WIFI_POWER_2dBm), (int)WIFI_POWER_19_5dBm); txPower = min(max(tx, (int)WIFI_POWER_2dBm), (int)WIFI_POWER_19_5dBm);
WiFi.setTxPower(wifi_power_t(txPower));
#endif #endif
force802_3g = request->hasArg(F("FG")); force802_3g = request->hasArg(F("FG"));
noWifiSleep = request->hasArg(F("WS")); noWifiSleep = request->hasArg(F("WS"));
#ifdef ARDUINO_ARCH_ESP32
WiFi.setSleep(!noWifiSleep);
#else
WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N);
wifi_set_sleep_type((noWifiSleep) ? NONE_SLEEP_T : MODEM_SLEEP_T);
#endif
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW
bool oldESPNow = enableESPNow; bool oldESPNow = enableESPNow;
@ -279,8 +289,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
disablePullUp = (bool)request->hasArg(F("IP")); disablePullUp = (bool)request->hasArg(F("IP"));
touchThreshold = request->arg(F("TT")).toInt(); touchThreshold = request->arg(F("TT")).toInt();
for (int i = 0; i < WLED_MAX_BUTTONS; i++) { for (unsigned i = 0; i < WLED_MAX_BUTTONS; i++) {
int offset = i < 10 ? '0' : 'A' - 10; unsigned offset = i < 10 ? '0' : 'A' - 10;
char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10) char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10)
char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10) char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10)
int hw_btn_pin = request->arg(bt).toInt(); int hw_btn_pin = request->arg(bt).toInt();
@ -375,14 +385,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (subPage == SUBPAGE_UI) if (subPage == SUBPAGE_UI)
{ {
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33); strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
char hostname[25];
prepareHostname(hostname, sizeof(hostname)-1);
#ifdef ARDUINO_ARCH_ESP32
WiFi.setHostname(hostname);
#else
WiFi.hostname(hostname);
#endif
//syncToggleReceive = request->hasArg(F("ST"));
simplifiedUI = request->hasArg(F("SU")); simplifiedUI = request->hasArg(F("SU"));
DEBUG_PRINTLN(F("Enumerating ledmaps")); DEBUG_PRINTLN(F("Enumerating ledmaps"));
enumerateLedmaps(); enumerateLedmaps();

View File

@ -114,33 +114,6 @@ size_t printSetClassElementHTML(Print& settingsScript, const char* key, const in
} }
// prepare a unique hostname based on the last 6 digits of the MAC address
// if no mDNS name or serverDescription is set, otherwise use cmDNS or serverDescription
// the hostname will be at most 24 characters long, starting with "wled-"
// and containing only alphanumeric characters and hyphens
// the hostname will not end with a hyphen and will be null-terminated
void prepareHostname(char* hostname, size_t maxLen)
{
// create a unique hostname based on the last 6 digits of the MAC address if no mDNS name or serverDescription is set
sprintf_P(hostname, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6);
const char *pC = cmDNS; // use cmDNS as hostname if set
if (strlen(pC) == 0) pC = serverDescription; // else use serverDescription
unsigned pos = 5; // keep "wled-" from unique name
while (*pC && pos < maxLen) { // while !null and not over length
if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname
hostname[pos++] = *pC;
} else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') {
hostname[pos++] = '-';
}
// else do nothing - no leading hyphens and do not include hyphens for all other characters.
pC++;
}
// last character must not be hyphen
while (pos > 4 && hostname[pos-1] == '-') pos--;
hostname[pos] = '\0'; // terminate string (leave at least "wled")
}
bool isAsterisksOnly(const char* str, byte maxLen) bool isAsterisksOnly(const char* str, byte maxLen)
{ {
for (unsigned i = 0; i < maxLen; i++) { for (unsigned i = 0; i < maxLen; i++) {

View File

@ -138,7 +138,7 @@ void WLED::loop()
yield(); yield();
#ifdef ESP8266 #ifdef ESP8266
MDNS.update(); if (mDNSenabled) MDNS.update();
#endif #endif
//millis() rolls over every 50 days //millis() rolls over every 50 days
@ -419,6 +419,8 @@ void WLED::setup()
escapedMac.replace(":", ""); escapedMac.replace(":", "");
escapedMac.toLowerCase(); escapedMac.toLowerCase();
// generate host name if no compile time default is set
if (strcmp(hostName, DEFAULT_MDNS_NAME) == 0) sprintf_P(hostName, PSTR("wled-%.*s"), 6, escapedMac.c_str() + 6);
WLED_SET_AP_SSID(); // otherwise it is empty on first boot until config is saved WLED_SET_AP_SSID(); // otherwise it is empty on first boot until config is saved
multiWiFi.push_back(WiFiConfig(CLIENT_SSID,CLIENT_PASS)); // initialise vector with default WiFi multiWiFi.push_back(WiFiConfig(CLIENT_SSID,CLIENT_PASS)); // initialise vector with default WiFi
@ -486,8 +488,7 @@ void WLED::setup()
WLED::instance().enableWatchdog(); WLED::instance().enableWatchdog();
#endif #endif
}); });
if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(hostName);
ArduinoOTA.setHostname(cmDNS);
} }
#endif #endif
#ifdef WLED_ENABLE_DMX #ifdef WLED_ENABLE_DMX
@ -652,22 +653,8 @@ void WLED::initConnection()
if (WLED_WIFI_CONFIGURED) { if (WLED_WIFI_CONFIGURED) {
showWelcomePage = false; showWelcomePage = false;
DEBUG_PRINTF_P(PSTR("Connecting to %s...\n"), multiWiFi[selectedWiFi].clientSSID); DEBUG_PRINTF_P(PSTR("Connecting to %s...\n"), multiWiFi[selectedWiFi].clientSSID);
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
char hostname[25];
prepareHostname(hostname);
WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times
#ifdef ARDUINO_ARCH_ESP32
WiFi.setTxPower(wifi_power_t(txPower));
WiFi.setSleep(!noWifiSleep);
WiFi.setHostname(hostname);
#else
wifi_set_sleep_type((noWifiSleep) ? NONE_SLEEP_T : MODEM_SLEEP_T);
WiFi.hostname(hostname);
#endif
} }
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW
@ -715,11 +702,11 @@ void WLED::initInterfaces()
#endif #endif
// Set up mDNS responder: // Set up mDNS responder:
if (strlen(cmDNS) > 0) { if (mDNSenabled) {
// "end" must be called before "begin" is called a 2nd time // "end" must be called before "begin" is called a 2nd time
// see https://github.com/esp8266/Arduino/issues/7213 // see https://github.com/esp8266/Arduino/issues/7213
MDNS.end(); MDNS.end();
MDNS.begin(cmDNS); MDNS.begin(hostName);
DEBUG_PRINTLN(F("mDNS started")); DEBUG_PRINTLN(F("mDNS started"));
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);

View File

@ -336,7 +336,8 @@ WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server
// WiFi CONFIG (all these can be changed via web UI, no need to set them here) // WiFi CONFIG (all these can be changed via web UI, no need to set them here)
WLED_GLOBAL std::vector<WiFiConfig> multiWiFi; WLED_GLOBAL std::vector<WiFiConfig> multiWiFi;
WLED_GLOBAL IPAddress dnsAddress _INIT_N((( 8, 8, 8, 8))); // Google's DNS WLED_GLOBAL IPAddress dnsAddress _INIT_N((( 8, 8, 8, 8))); // Google's DNS
WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) WLED_GLOBAL char hostName[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wled-XXXXXX if default is used)
WLED_GLOBAL bool mDNSenabled _INIT(true); // use mDNS (default is true, can be changed in web UI)
WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup)
#ifdef WLED_SAVE_RAM #ifdef WLED_SAVE_RAM
typedef class WiFiOptions { typedef class WiFiOptions {

View File

@ -232,7 +232,7 @@ static bool captivePortal(AsyncWebServerRequest *request)
if (!request->hasHeader(F("Host"))) return false; if (!request->hasHeader(F("Host"))) return false;
String hostH = request->getHeader(F("Host"))->value(); String hostH = request->getHeader(F("Host"))->value();
if (!isIp(hostH) && hostH.indexOf(F("wled.me")) < 0 && hostH.indexOf(cmDNS) < 0 && hostH.indexOf(':') < 0) { if (!isIp(hostH) && hostH.indexOf(F("wled.me")) < 0 && hostH.indexOf(hostName) < 0 && hostH.indexOf(':') < 0) {
DEBUG_PRINTLN(F("Captive portal")); DEBUG_PRINTLN(F("Captive portal"));
AsyncWebServerResponse *response = request->beginResponse(302); AsyncWebServerResponse *response = request->beginResponse(302);
response->addHeader(F("Location"), F("http://4.3.2.1")); response->addHeader(F("Location"), F("http://4.3.2.1"));

View File

@ -172,6 +172,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
if (subPage == SUBPAGE_WIFI) if (subPage == SUBPAGE_WIFI)
{ {
size_t l; size_t l;
char s[32];
settingsScript.printf_P(PSTR("resetWiFi(%d);"), WLED_MAX_WIFI_COUNT); settingsScript.printf_P(PSTR("resetWiFi(%d);"), WLED_MAX_WIFI_COUNT);
for (size_t n = 0; n < multiWiFi.size(); n++) { for (size_t n = 0; n < multiWiFi.size(); n++) {
l = strlen(multiWiFi[n].clientPass); l = strlen(multiWiFi[n].clientPass);
@ -194,7 +195,8 @@ void getSettingsJS(byte subPage, Print& settingsScript)
printSetFormValue(settingsScript,PSTR("D2"),dnsAddress[2]); printSetFormValue(settingsScript,PSTR("D2"),dnsAddress[2]);
printSetFormValue(settingsScript,PSTR("D3"),dnsAddress[3]); printSetFormValue(settingsScript,PSTR("D3"),dnsAddress[3]);
printSetFormValue(settingsScript,PSTR("CM"),cmDNS); printSetFormValue(settingsScript,PSTR("CM"),hostName);
printSetFormCheckbox(settingsScript,PSTR("MD"),mDNSenabled);
printSetFormIndex(settingsScript,PSTR("AB"),apBehavior); printSetFormIndex(settingsScript,PSTR("AB"),apBehavior);
printSetFormValue(settingsScript,PSTR("AS"),apSSID); printSetFormValue(settingsScript,PSTR("AS"),apSSID);
printSetFormCheckbox(settingsScript,PSTR("AH"),apHide); printSetFormCheckbox(settingsScript,PSTR("AH"),apHide);
@ -235,7 +237,6 @@ void getSettingsJS(byte subPage, Print& settingsScript)
if (Network.isConnected()) //is connected if (Network.isConnected()) //is connected
{ {
char s[32];
IPAddress localIP = Network.localIP(); IPAddress localIP = Network.localIP();
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
@ -248,14 +249,14 @@ void getSettingsJS(byte subPage, Print& settingsScript)
printSetClassElementHTML(settingsScript,PSTR("sip"),0,(char*)F("Not connected")); printSetClassElementHTML(settingsScript,PSTR("sip"),0,(char*)F("Not connected"));
} }
if (WiFi.softAPIP()[0] != 0) //is active if (apActive && WiFi.softAPIP()[0] != 0) //is active
{ {
char s[16];
IPAddress apIP = WiFi.softAPIP(); IPAddress apIP = WiFi.softAPIP();
sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]); snprintf(s, sizeof(s)-1, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]);
printSetClassElementHTML(settingsScript,PSTR("sip"),1,s); printSetClassElementHTML(settingsScript,PSTR("sip"),1,s);
} else } else
{ {
// WiFi.softAPmacAddress() for AP MAC address
printSetClassElementHTML(settingsScript,PSTR("sip"),1,(char*)F("Not active")); printSetClassElementHTML(settingsScript,PSTR("sip"),1,(char*)F("Not active"));
} }