Merge pull request #1683 from blazoncek/autodiscovery

Auto node discovery.
This commit is contained in:
Aircoookie 2021-03-09 17:25:17 +01:00 committed by GitHub
commit 6eacf8ed7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2368 additions and 2063 deletions

34
wled00/NodeStruct.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef WLED_NODESTRUCT_H
#define WLED_NODESTRUCT_H
/*********************************************************************************************\
* NodeStruct from the ESP Easy project (https://github.com/letscontrolit/ESPEasy)
\*********************************************************************************************/
#include <map>
#include <IPAddress.h>
#define NODE_TYPE_ID_UNDEFINED 0
#define NODE_TYPE_ID_ESP8266 82
#define NODE_TYPE_ID_ESP32 32
/*********************************************************************************************\
* NodeStruct
\*********************************************************************************************/
struct NodeStruct
{
String nodeName;
IPAddress ip;
uint8_t unit;
uint8_t age;
uint8_t nodeType;
uint32_t build;
NodeStruct() : age(0), nodeType(0), build(0)
{
for (uint8_t i = 0; i < 4; ++i) { ip[i] = 0; }
}
};
typedef std::map<uint8_t, NodeStruct> NodesMap;
#endif // WLED_NODESTRUCT_H

View File

@ -231,6 +231,13 @@
#define JSON_BUFFER_SIZE 16384 #define JSON_BUFFER_SIZE 16384
#endif #endif
// Maximum size of node map (list of other WLED instances)
#ifdef ESP8266
#define WLED_MAX_NODES 15
#else
#define WLED_MAX_NODES 150
#endif
//this is merely a default now and can be changed at runtime //this is merely a default now and can be changed at runtime
#ifndef LEDPIN #ifndef LEDPIN
#define LEDPIN 2 #define LEDPIN 2

View File

@ -90,9 +90,10 @@ button {
#namelabel { #namelabel {
position: fixed; position: fixed;
bottom: calc(var(--bh) + 5px); bottom: calc(var(--bh) + 6px);
right: 4px; right: 4px;
color: var(--c-6); color: var(--c-6);
cursor: pointer;
writing-mode: vertical-rl; writing-mode: vertical-rl;
} }
@ -366,10 +367,18 @@ button {
z-index: 3; z-index: 3;
} }
#rover { #rover, #nodes {
z-index: 2; z-index: 2;
} }
#ndlt {
margin: 12px 0;
}
.valtd i {
font-size: 14px;
}
#roverstar { #roverstar {
position: fixed; position: fixed;
top: calc(var(--th) + 5px); top: calc(var(--th) + 5px);
@ -394,11 +403,15 @@ button {
display: inline-block; display: inline-block;
} }
#kv { #kv, #kn {
max-width: 490px; max-width: 490px;
display: inline-block; display: inline-block;
} }
#kn td {
padding-bottom: 12px;
}
#lv { #lv {
max-width: 600px; max-width: 600px;
display: inline-block; display: inline-block;
@ -930,6 +943,12 @@ input[type=number]::-webkit-outer-spin-button {
} }
} }
@media all and (max-width: 770px) {
#buttonNodes {
display: none;
}
}
@media all and (max-width: 1249px) { @media all and (max-width: 1249px) {
#buttonPcm { #buttonPcm {
display: none; display: none;

View File

@ -24,6 +24,7 @@
<button id="buttonSync" onclick="toggleSync()"><i class="icons">&#xe116;</i><p class="tab-label">Sync</p></button> <button id="buttonSync" onclick="toggleSync()"><i class="icons">&#xe116;</i><p class="tab-label">Sync</p></button>
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons">&#xe410;</i><p class="tab-label">Peek</p></button> <button id="buttonSr" onclick="toggleLiveview()"><i class="icons">&#xe410;</i><p class="tab-label">Peek</p></button>
<button id="buttonI" onclick="toggleInfo()"><i class="icons">&#xe34b;</i><p class="tab-label">Info</p></button> <button id="buttonI" onclick="toggleInfo()"><i class="icons">&#xe34b;</i><p class="tab-label">Info</p></button>
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons">&#xe22d;</i><p class="tab-label">Nodes</p></button></div>
<button onclick="window.location.href = '/settings';"><i class="icons">&#xe0a2;</i><p class="tab-label">Config</p></button> <button onclick="window.location.href = '/settings';"><i class="icons">&#xe0a2;</i><p class="tab-label">Config</p></button>
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons">&#xe23d;</i><p class="tab-label">PC Mode</p></button> <button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons">&#xe23d;</i><p class="tab-label">PC Mode</p></button>
</div> </div>
@ -66,17 +67,17 @@
</div> </div>
</div> </div>
<div id="qcs-w"> <div id="qcs-w">
<div class="qcs" onclick="pC('#ff0000');" style="background-color:#ff0000;"></div> <div class="qcs" onclick="pC('#ff0000');" title="Red" style="background-color:#ff0000;"></div>
<div class="qcs" onclick="pC('#ffa000');" style="background-color:#ffa000;"></div> <div class="qcs" onclick="pC('#ffa000');" title="Orange" style="background-color:#ffa000;"></div>
<div class="qcs" onclick="pC('#ffc800');" style="background-color:#ffc800;"></div> <div class="qcs" onclick="pC('#ffc800');" title="Yellow" style="background-color:#ffc800;"></div>
<div class="qcs" onclick="pC('#ffe0a0');" style="background-color:#ffe0a0;"></div> <div class="qcs" onclick="pC('#ffe0a0');" title="Warm White" style="background-color:#ffe0a0;"></div>
<div class="qcs" onclick="pC('#ffffff');" style="background-color:#ffffff;"></div> <div class="qcs" onclick="pC('#ffffff');" title="White" style="background-color:#ffffff;"></div>
<div class="qcs qcsb" onclick="pC('#000000');" style="background-color:#000000;"></div><br> <div class="qcs qcsb" onclick="pC('#000000');" title="Black" style="background-color:#000000;"></div><br>
<div class="qcs" onclick="pC('#ff00ff');" style="background-color:#ff00ff;"></div> <div class="qcs" onclick="pC('#ff00ff');" title="Pink" style="background-color:#ff00ff;"></div>
<div class="qcs" onclick="pC('#0000ff');" style="background-color:#0000ff;"></div> <div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
<div class="qcs" onclick="pC('#00ffc8');" style="background-color:#00ffc8;"></div> <div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
<div class="qcs" onclick="pC('#08ff00');" style="background-color:#08ff00;"></div> <div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
<div class="qcs" onclick="pC('rnd');" style="background-color:var(--c-3); padding: 4px 8px; transform: translateY(-10px);">R</div> <div class="qcs" onclick="pC('rnd');" title="Random" style="background-color:var(--c-3); padding: 4px 8px; transform: translateY(-10px);">R</div>
</div> </div>
<div id="csl"> <div id="csl">
<button class="xxs cl btn" onclick="selectSlot(0);">1</button> <button class="xxs cl btn" onclick="selectSlot(0);">1</button>
@ -169,7 +170,7 @@
<div id="connind"></div> <div id="connind"></div>
<div id="toast"></div> <div id="toast"></div>
<div id="namelabel"></div> <div id="namelabel" onclick="toggleNodes()"></div>
<div id="info" class="modal"> <div id="info" class="modal">
<div id="imgw"> <div id="imgw">
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAggAAACMCAYAAAAZQlGEAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKLSURBVHhe7dgxjtwwEADBpf//5zUDwklnpzFAnKoSTigNFTT0AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDcOieX+G5nvNLaznil6f1Nv+/tz3c7+3tmen/Tpu/jbe877c85AQD+EQgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAINY5+aHvdsYRazvjK9jfM7fvz/0+Y3+/2+336w8CABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAADEOudrfLczXmltZ3yF6fuwv2em9+d+n5ne3zT3cZfp+/AHAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAYp3zNb7bGUes7Yz8wO334fmeuf35bmd/z9y+v9ufzx8EACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAIAQCABACAQCIdc4x3+2MV1rbGfmFpr+/6e/l9ue73fT+pt1+H2/bn+/lGX8QAIAQCABACAQAIAQCABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgP/u8/kLYCqAxINTyZkAAAAASUVORK5CYII="> <img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAggAAACMCAYAAAAZQlGEAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKLSURBVHhe7dgxjtwwEADBpf//5zUDwklnpzFAnKoSTigNFTT0AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDcOieX+G5nvNLaznil6f1Nv+/tz3c7+3tmen/Tpu/jbe877c85AQD+EQgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAINY5+aHvdsYRazvjK9jfM7fvz/0+Y3+/2+336w8CABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAADEOudrfLczXmltZ3yF6fuwv2em9+d+n5ne3zT3cZfp+/AHAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAYp3zNb7bGUes7Yz8wO334fmeuf35bmd/z9y+v9ufzx8EACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAIAQCABACAQCIdc4x3+2MV1rbGfmFpr+/6e/l9ue73fT+pt1+H2/bn+/lGX8QAIAQCABACAQAIAQCABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgP/u8/kLYCqAxINTyZkAAAAASUVORK5CYII=">
@ -177,11 +178,18 @@
<div id="kv">Loading...</div><br> <div id="kv">Loading...</div><br>
<button class="btn infobtn" onclick="requestJson(null)">Refresh</button> <button class="btn infobtn" onclick="requestJson(null)">Refresh</button>
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br> <button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
<button class="btn infobtn" onclick="openGH()">WLED Wiki</button> <button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br> <button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
<span class="h">Made with <span id="heart">&#10084;&#xFE0E;</span> by Aircoookie and the WLED community</span> <span class="h">Made with <span id="heart">&#10084;&#xFE0E;</span> by Aircoookie and the WLED community</span>
</div> </div>
<div id="nodes" class="modal">
<div id="ndlt">WLED instances</div>
<div id="kn">Loading...</div><br>
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
</div>
<div id="rover" class="modal"> <div id="rover" class="modal">
<i class="icons huge">&#xe410;</i><br> <i class="icons huge">&#xe410;</i><br>
<div id="lv">?</div><br><br> <div id="lv">?</div><br><br>
@ -191,6 +199,7 @@
<button class="btn" onclick="setLor(2)">Override until reboot</button><br> <button class="btn" onclick="setLor(2)">Override until reboot</button><br>
<span class="h">For best performance, it is recommended to turn off the streaming source when not in use.</span> <span class="h">For best performance, it is recommended to turn off the streaming source when not in use.</span>
</div> </div>
<i id="roverstar" class="icons huge" onclick="setLor(0)">&#xe410;</i><br> <i id="roverstar" class="icons huge" onclick="setLor(0)">&#xe410;</i><br>
<script src="iro.js"></script> <script src="iro.js"></script>
<script src="rangetouch.js"></script> <script src="rangetouch.js"></script>

View File

@ -1,7 +1,7 @@
//page js //page js
var loc = false, locip; var loc = false, locip;
var noNewSegs = false; var noNewSegs = false;
var isOn = false, nlA = false, isLv = false, isInfo = false, syncSend = false, syncTglRecv = true, isRgbw = false; var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true, isRgbw = false;
var whites = [0,0,0]; var whites = [0,0,0];
var expanded = [false]; var expanded = [false];
var powered = [true]; var powered = [true];
@ -463,6 +463,7 @@ function populateInfo(i)
} }
} }
} }
var vcn = "Kuuhaku"; var vcn = "Kuuhaku";
if (i.ver.startsWith("0.12.")) vcn = "Hikari"; if (i.ver.startsWith("0.12.")) vcn = "Hikari";
if (i.cn) vcn = i.cn; if (i.cn) vcn = i.cn;
@ -566,6 +567,68 @@ function populateSegments(s)
d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none"; d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none";
} }
function btype(b){
switch (b) {
case 32: return "ESP32";
case 82: return "ESP8266";
}
return "?";
}
function bname(o){
if (o.name=="WLED") return o.ip;
return o.name;
}
function populateNodes(i,n)
{
var cn="";
var urows="";
var nnodes = 0;
if (n.nodes) {
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
for (var x=0;x<n.nodes.length;x++) {
var o = n.nodes[x];
if (o.name) {
var url = `<button class="btn btna-icon tab" onclick="location.assign('http://${o.ip}');">${bname(o)}</button>`;
urows += inforow(url,`${btype(o.type)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
nnodes++;
}
}
}
if (nnodes == 0) cn += `No other instances found.`;
cn += `<table class="infot">
${urows}
${inforow("Current instance:",i.name)}
</table>`;
d.getElementById('kn').innerHTML = cn;
}
function loadNodes()
{
var url = '/json/nodes';
if (loc) {
url = `http://${locip}/json/nodes`;
}
fetch
(url, {
method: 'get'
})
.then(res => {
if (!res.ok) {
showToast('Could not load Node list!', true);
}
return res.json();
})
.then(json => {
populateNodes(lastinfo, json);
})
.catch(function (error) {
showToast(error, true);
console.log(error);
});
}
function updateTrail(e, slidercol) function updateTrail(e, slidercol)
{ {
if (e==null) return; if (e==null) return;
@ -869,12 +932,21 @@ function toggleLiveview() {
} }
function toggleInfo() { function toggleInfo() {
if (isNodes) toggleNodes();
isInfo = !isInfo; isInfo = !isInfo;
if (isInfo) populateInfo(lastinfo); if (isInfo) populateInfo(lastinfo);
d.getElementById('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)"; d.getElementById('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)";
d.getElementById('buttonI').className = (isInfo) ? "active":""; d.getElementById('buttonI').className = (isInfo) ? "active":"";
} }
function toggleNodes() {
if (isInfo) toggleInfo();
isNodes = !isNodes;
d.getElementById('nodes').style.transform = (isNodes) ? "translateY(0px)":"translateY(100%)";
d.getElementById('buttonNodes').className = (isNodes) ? "active":"";
if (isNodes) loadNodes();
}
function makeSeg() { function makeSeg() {
var ns = 0; var ns = 0;
if (lowestUnused > 0) { if (lowestUnused > 0) {

View File

@ -170,6 +170,8 @@ void notify(byte callMode, bool followUp=false);
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
void handleNotifications(); void handleNotifications();
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
void refreshNodeList();
void sendSysInfoUDP();
//um_manager.cpp //um_manager.cpp
class Usermod { class Usermod {

File diff suppressed because it is too large Load Diff

View File

@ -474,6 +474,8 @@ void serializeInfo(JsonObject root)
fs_info["t"] = fsBytesTotal / 1000; fs_info["t"] = fsBytesTotal / 1000;
fs_info[F("pmt")] = presetsModifiedTime; fs_info[F("pmt")] = presetsModifiedTime;
root[F("ndc")] = Nodes.size();
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
wifi_info[F("txPower")] = (int) WiFi.getTxPower(); wifi_info[F("txPower")] = (int) WiFi.getTxPower();
@ -535,6 +537,24 @@ void serializeInfo(JsonObject root)
root["mac"] = escapedMac; root["mac"] = escapedMac;
} }
void serializeNodes(JsonObject root)
{
JsonArray nodes = root.createNestedArray("nodes");
IPAddress ip = WiFi.localIP();
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it)
{
if (it->second.ip[0] != 0)
{
JsonObject node = nodes.createNestedObject();
node[F("name")] = it->second.nodeName;
node[F("type")] = it->second.nodeType;
node[F("ip")] = it->second.ip.toString();
node[F("age")] = it->second.age;
node[F("vid")] = it->second.build;
}
}
}
void serveJson(AsyncWebServerRequest* request) void serveJson(AsyncWebServerRequest* request)
{ {
byte subJson = 0; byte subJson = 0;
@ -542,6 +562,7 @@ void serveJson(AsyncWebServerRequest* request)
if (url.indexOf("state") > 0) subJson = 1; if (url.indexOf("state") > 0) subJson = 1;
else if (url.indexOf("info") > 0) subJson = 2; else if (url.indexOf("info") > 0) subJson = 2;
else if (url.indexOf("si") > 0) subJson = 3; else if (url.indexOf("si") > 0) subJson = 3;
else if (url.indexOf("nodes") > 0) subJson = 4;
else if (url.indexOf("live") > 0) { else if (url.indexOf("live") > 0) {
serveLiveLeds(request); serveLiveLeds(request);
return; return;
@ -568,6 +589,8 @@ void serveJson(AsyncWebServerRequest* request)
serializeState(doc); break; serializeState(doc); break;
case 2: //info case 2: //info
serializeInfo(doc); break; serializeInfo(doc); break;
case 4: //node list
serializeNodes(doc); break;
default: //all default: //all
JsonObject state = doc.createNestedObject("state"); JsonObject state = doc.createNestedObject("state");
serializeState(state); serializeState(state);

View File

@ -163,8 +163,40 @@ void handleNotifications()
if (!isSupp && notifierUdp.remoteIP() == Network.localIP()) return; //don't process broadcasts we send ourselves if (!isSupp && notifierUdp.remoteIP() == Network.localIP()) return; //don't process broadcasts we send ourselves
uint8_t udpIn[packetSize +1]; uint8_t udpIn[packetSize +1];
if (isSupp) notifier2Udp.read(udpIn, packetSize); uint16_t len;
else notifierUdp.read(udpIn, packetSize); if (isSupp) len = notifier2Udp.read(udpIn, packetSize);
else len = notifierUdp.read(udpIn, packetSize);
// WLED nodes info notifications
if (isSupp && udpIn[0] == 255 && udpIn[1] == 1 && len >= 40) {
if (notifier2Udp.remoteIP() == Network.localIP()) return;
uint8_t unit = udpIn[39];
NodesMap::iterator it = Nodes.find(unit);
if (it == Nodes.end() && Nodes.size() < WLED_MAX_NODES) { // Create a new element when not present
Nodes[unit].age = 0;
it = Nodes.find(unit);
}
if (it != Nodes.end()) {
for (byte x = 0; x < 4; x++) {
it->second.ip[x] = udpIn[x + 2];
}
it->second.age = 0; // reset 'age counter'
char tmpNodeName[33] = { 0 };
memcpy(&tmpNodeName[0], reinterpret_cast<byte *>(&udpIn[6]), 32);
tmpNodeName[32] = 0;
it->second.nodeName = tmpNodeName;
it->second.nodeName.trim();
it->second.nodeType = udpIn[38];
uint32_t build = 0;
if (len >= 44)
for (byte i=0; i<sizeof(uint32_t); i++)
build |= udpIn[40+i]<<(8*i);
it->second.build = build;
}
return;
}
//wled notifier, ignore if realtime packets active //wled notifier, ignore if realtime packets active
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications) if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
@ -358,3 +390,72 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
} }
} }
} }
/*********************************************************************************************\
Refresh aging for remote units, drop if too old...
\*********************************************************************************************/
void refreshNodeList()
{
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end();) {
bool mustRemove = true;
if (it->second.ip[0] != 0) {
if (it->second.age < 10) {
it->second.age++;
mustRemove = false;
++it;
}
}
if (mustRemove) {
it = Nodes.erase(it);
}
}
}
/*********************************************************************************************\
Broadcast system info to other nodes. (to update node lists)
\*********************************************************************************************/
void sendSysInfoUDP()
{
if (!udp2Connected) return;
IPAddress ip = Network.localIP();
// TODO: make a nice struct of it and clean up
// 0: 1 byte 'binary token 255'
// 1: 1 byte id '1'
// 2: 4 byte ip
// 6: 32 char name
// 38: 1 byte node type id
// 39: 1 byte node id
// 40: 4 byte version ID
// 44 bytes total
// send my info to the world...
uint8_t data[44] = {0};
data[0] = 255;
data[1] = 1;
for (byte x = 0; x < 4; x++) {
data[x + 2] = ip[x];
}
memcpy((byte *)data + 6, serverDescription, 32);
#ifdef ESP8266
data[38] = NODE_TYPE_ID_ESP8266;
#elif defined(ARDUINO_ARCH_ESP32)
data[38] = NODE_TYPE_ID_ESP32;
#else
data[38] = NODE_TYPE_ID_UNDEFINED;
#endif
data[39] = ip[3]; // unit ID == last IP number
uint32_t build = VERSION;
for (byte i=0; i<sizeof(uint32_t); i++)
data[40+i] = (build>>(8*i)) & 0xFF;
IPAddress broadcastIP(255, 255, 255, 255);
notifier2Udp.beginPacket(broadcastIP, udpPort2);
notifier2Udp.write(data, sizeof(data));
notifier2Udp.endPacket();
}

View File

@ -248,6 +248,8 @@ void WLED::loop()
if (millis() - lastMqttReconnectAttempt > 30000) { if (millis() - lastMqttReconnectAttempt > 30000) {
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
initMqtt(); initMqtt();
refreshNodeList();
sendSysInfoUDP();
} }
yield(); yield();
handleWs(); handleWs();

View File

@ -117,6 +117,7 @@
#include "FX.h" #include "FX.h"
#include "ir_codes.h" #include "ir_codes.h"
#include "const.h" #include "const.h"
#include "NodeStruct.h"
#include "pin_manager.h" #include "pin_manager.h"
#include "bus_manager.h" #include "bus_manager.h"
@ -257,6 +258,8 @@ WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module
WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise
// Sync CONFIG // Sync CONFIG
WLED_GLOBAL NodesMap Nodes;
WLED_GLOBAL bool buttonEnabled _INIT(true); WLED_GLOBAL bool buttonEnabled _INIT(true);
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver