mirror of
https://github.com/wled/WLED.git
synced 2026-04-14 11:14:30 +00:00
Compare commits
11 Commits
v16.0.0-be
...
8MB_partit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38c266d33c | ||
|
|
c8ce317244 | ||
|
|
a5f28d0fcb | ||
|
|
fb8f8f0b08 | ||
|
|
53fdf9a89c | ||
|
|
a1316034c1 | ||
|
|
75df4affa8 | ||
|
|
820c841376 | ||
|
|
34d50710b3 | ||
|
|
d0d62d9493 | ||
|
|
89b2bc2992 |
12
.github/copilot-instructions.md
vendored
12
.github/copilot-instructions.md
vendored
@@ -78,6 +78,18 @@ After making changes to web UI, always test:
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Project Branch / Release Structure
|
||||
```
|
||||
main # Main development trunk (daily/nightly) 17.0.0-dev
|
||||
├── V5 # special branch: code rework for esp-idf 5.5.x (unstable)
|
||||
├── V5-C6 # special branch: integration of new MCU types: esp32-c5, esp32-c6, esp32-p4 (unstable)
|
||||
16_x # current beta, preparations for next release 16.0.0
|
||||
0_15_x # maintainance (bugfixes only) for current release 0.15.4
|
||||
(tag) v0.14.4 # previous version 0.14.4 (no maintainance)
|
||||
(tag) v0.13.3 # old version 0.13.3 (no maintainance)
|
||||
(tag) v0. ... . ... # historical versions 0.12.x and before
|
||||
```
|
||||
|
||||
### Repository Structure
|
||||
```
|
||||
wled00/ # Main firmware source (C++)
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "16.0.0-beta",
|
||||
"version": "17.0.0-dev",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wled",
|
||||
"version": "16.0.0-beta",
|
||||
"version": "17.0.0-dev",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"clean-css": "^5.3.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "16.0.0-beta",
|
||||
"version": "17.0.0-dev",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x200000,
|
||||
app1, app, ota_1, 0x210000,0x200000,
|
||||
spiffs, data, spiffs, 0x410000,0x3E0000,
|
||||
app0, app, ota_0, 0x10000, 0x220000,
|
||||
app1, app, ota_1, 0x230000,0x220000,
|
||||
spiffs, data, spiffs, 0x450000,0x3A0000,
|
||||
coredump, data, coredump,,64K
|
||||
|
||||
|
9
tools/WLED_zigbee_8MB.csv
Normal file
9
tools/WLED_zigbee_8MB.csv
Normal file
@@ -0,0 +1,9 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x270000,
|
||||
app1, app, ota_1, 0x280000,0x270000,
|
||||
spiffs, data, spiffs, 0x4F0000,0x2FB000,
|
||||
zb_storage, data, fat, 0x7EB000,0x4000,
|
||||
zb_fct, data, fat, 0x7EF000,0x1000,
|
||||
coredump, data, coredump,0x7F0000,0x10000,
|
||||
|
@@ -3498,14 +3498,11 @@ void candle(bool multi)
|
||||
{
|
||||
if (multi && SEGLEN > 1) {
|
||||
//allocate segment data
|
||||
unsigned dataSize = sizeof(uint32_t) + max(1, (int)SEGLEN -1) *3;
|
||||
unsigned dataSize = sizeof(uint32_t) + max(1, (int)SEGLEN -1) *3; //max. 1365 pixels (ESP8266)
|
||||
if (!SEGENV.allocateData(dataSize)) candle(false); //allocation failed
|
||||
} else {
|
||||
unsigned dataSize = sizeof(uint32_t); // for last call timestamp
|
||||
if (!SEGENV.allocateData(dataSize)) FX_FALLBACK_STATIC; //allocation failed
|
||||
}
|
||||
uint32_t* lastcall = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||
uint8_t* candleData = reinterpret_cast<uint8_t*>(SEGENV.data + sizeof(uint32_t)); // only used for multi-candle
|
||||
uint8_t* candleData = reinterpret_cast<uint8_t*>(SEGENV.data + sizeof(uint32_t));
|
||||
|
||||
//limit update rate
|
||||
if (strip.now - *lastcall < FRAMETIME_FIXED) return;
|
||||
@@ -4428,8 +4425,7 @@ void mode_flow(void)
|
||||
if (zones & 0x01) zones++; //zones must be even
|
||||
if (zones < 2) zones = 2;
|
||||
int zoneLen = SEGLEN / zones;
|
||||
int requiredZones = (SEGLEN + zoneLen - 1) / zoneLen;
|
||||
zones = requiredZones + 2; //add extra zones to cover beginning and end of segment (compensate integer truncation)
|
||||
zones += 2; //add two extra zones to cover beginning and end of segment (compensate integer truncation)
|
||||
int offset = ((int)SEGLEN - (zones * zoneLen)) / 2; // center the zones on the segment (can not use bit shift on negative number)
|
||||
|
||||
for (int z = 0; z < zones; z++)
|
||||
|
||||
@@ -310,10 +310,10 @@ function onLoad()
|
||||
sl.addEventListener('touchstart', toggleBubble);
|
||||
sl.addEventListener('touchend', toggleBubble);
|
||||
});
|
||||
// limiter for all number inputs except segment inputs: limit inputs instantly note: segment inputs are special if matrix is enabled, they allow for trailing strips, need a lot of special cases to handle that
|
||||
// limiter for all number inputs: limit inputs instantly
|
||||
d.addEventListener("input", function(e) {
|
||||
const t = e.target;
|
||||
if (t.tagName === "INPUT" && t.type === "number" && !(t.id && t.id.startsWith("seg"))) {
|
||||
if (t.tagName === "INPUT" && t.type === "number") {
|
||||
let val = parseFloat(t.value);
|
||||
const max = parseFloat(t.max);
|
||||
const min = parseFloat(t.min);
|
||||
@@ -1182,7 +1182,7 @@ function updateLen(s)
|
||||
let mySD = gId("mkSYD");
|
||||
if (isM) {
|
||||
// do we have 1D segment *after* the matrix?
|
||||
if (start >= mw*mh && s > 0) {
|
||||
if (start >= mw*mh) {
|
||||
if (sY) { sY.value = 0; sY.max = 0; sY.min = 0; }
|
||||
if (eY) { eY.value = 1; eY.max = 1; eY.min = 0; }
|
||||
sX.min = mw*mh; sX.max = ledCount-1;
|
||||
@@ -3413,23 +3413,13 @@ function showVersionUpgradePrompt(info, oldVersion, newVersion) {
|
||||
|
||||
function reportUpgradeEvent(info, oldVersion, alwaysReport) {
|
||||
showToast('Reporting upgrade...');
|
||||
const IR_TYPES = {
|
||||
0: null, // not configured — omit field entirely
|
||||
1: "24-key", // white 24-key remote
|
||||
2: "24-key-ct", // white 24-key with CW, WW, CT+, CT- keys
|
||||
3: "40-key", // blue 40-key remote
|
||||
4: "44-key", // white 44-key remote
|
||||
5: "21-key", // white 21-key remote
|
||||
6: "6-key", // black 6-key learning remote
|
||||
7: "9-key", // 9-key remote
|
||||
8: "json-remote", // ir.json configurable remote
|
||||
};
|
||||
|
||||
// Reuse the info argument and fetch only /json/cfg (serialize requests to avoid 503s on low-heap devices)
|
||||
const infoData = info;
|
||||
fetch(getURL('/json/cfg'), {method: 'get'})
|
||||
.then(res => res.ok ? res.json() : Promise.reject(new Error('Failed to fetch /json/cfg')))
|
||||
.then(cfgData => {
|
||||
// Fetch fresh data from /json/info endpoint as requested
|
||||
fetch(getURL('/json/info'), {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(infoData => {
|
||||
// Map to UpgradeEventRequest structure per OpenAPI spec
|
||||
// Required fields: deviceId, version, previousVersion, releaseName, chip, ledCount, isMatrix, bootloaderSHA256
|
||||
const upgradeData = {
|
||||
@@ -3444,58 +3434,13 @@ function reportUpgradeEvent(info, oldVersion, alwaysReport) {
|
||||
brand: infoData.brand, // Device brand (always present)
|
||||
product: infoData.product, // Product name (always present)
|
||||
flashSize: infoData.flash, // Flash size (always present)
|
||||
repo: infoData.repo, // GitHub repository (always present)
|
||||
fsUsed: infoData.fs?.u, // Filesystem used space in kB
|
||||
fsTotal: infoData.fs?.t, // Filesystem total space in kB
|
||||
|
||||
// LED hardware
|
||||
busCount: cfgData.hw?.led?.ins?.length ?? 1,
|
||||
busTypes: (cfgData.hw?.led?.ins ?? []).map(b => busTypeToString(b.type)),
|
||||
matrixWidth: infoData.leds?.matrix?.w,
|
||||
matrixHeight: infoData.leds?.matrix?.h,
|
||||
ledFeatures: [
|
||||
...(infoData.leds?.lc & 0x02 ? ["rgbw"] : []),
|
||||
...(infoData.leds?.lc & 0x04 ? ["cct"] : []),
|
||||
...((infoData.leds?.maxpwr ?? 0) > 0 ? ["abl"] : []),
|
||||
...(cfgData.hw?.led?.cr ? ["cct-from-rgb"] : []),
|
||||
...(cfgData.hw?.led?.cct ? ["white-balance"] : []),
|
||||
...((cfgData.light?.gc?.col ?? 1.0) > 1.0 || (cfgData.light?.gc?.bri ?? 1.0) > 1.0 ? ["gamma"] : []),
|
||||
...(cfgData.light?.aseg ? ["auto-segments"] : []),
|
||||
...((cfgData.light?.nl?.mode ?? 0) > 0 ? ["nightlight"] : []),
|
||||
],
|
||||
|
||||
// peripherals (note: i2c/spi may reflect board defaults, not user-configured hardware)
|
||||
peripherals: [
|
||||
...((cfgData.hw?.relay?.pin ?? -1) >= 0 ? ["relay"] : []),
|
||||
...((cfgData.hw?.btn?.ins ?? []).filter(b => b.type !== 0).length > 0 ? ["buttons"] : []),
|
||||
...((cfgData.eth?.type ?? 0) > 0 ? ["ethernet"] : []),
|
||||
...((cfgData.if?.live?.dmx?.inputRxPin ?? 0) > 0 ? ["dmx-input"] : []),
|
||||
...((cfgData.hw?.ir?.type ?? 0) > 0 ? ["ir-remote"] : []),
|
||||
],
|
||||
buttonCount: (cfgData.hw?.btn?.ins ?? []).filter(b => b.type !== 0).length,
|
||||
|
||||
// integrations
|
||||
integrations: [
|
||||
...(cfgData.if?.hue?.en ? ["hue"] : []),
|
||||
...(cfgData.if?.mqtt?.en ? ["mqtt"] : []),
|
||||
...(cfgData.if?.va?.alexa ? ["alexa"] : []),
|
||||
...(cfgData.if?.sync?.send?.en ? ["wled-sync"] : []),
|
||||
...(cfgData.nw?.espnow ? ["esp-now"] : []),
|
||||
...(cfgData.if?.sync?.espnow ? ["esp-now-sync"] : []),
|
||||
],
|
||||
|
||||
// usermods
|
||||
usermods: Object.keys(cfgData.um ?? {}),
|
||||
usermodIds: infoData.um ?? [],
|
||||
};
|
||||
|
||||
// IR remote — only include if configured
|
||||
const irType = IR_TYPES[cfgData.hw?.ir?.type ?? 0];
|
||||
if (irType) upgradeData.irRemoteType = irType;
|
||||
repo: infoData.repo // GitHub repository (always present)
|
||||
};
|
||||
|
||||
// Add optional fields if available
|
||||
if (infoData.psrSz !== undefined) upgradeData.psramSize = infoData.psrSz; // Total PSRAM size in MB; can be 0
|
||||
|
||||
// Note: partitionSizes not currently available in /json/info endpoint
|
||||
|
||||
// Make AJAX call to postUpgradeEvent API
|
||||
return fetch('https://usage.wled.me/api/usage/upgrade', {
|
||||
@@ -3526,17 +3471,6 @@ function reportUpgradeEvent(info, oldVersion, alwaysReport) {
|
||||
});
|
||||
}
|
||||
|
||||
function busTypeToString(t) {
|
||||
if (t === 0) return "none";
|
||||
if (t === 40) return "on-off";
|
||||
if (t >= 16 && t <= 39) return "digital"; // WS2812, SK6812, etc.
|
||||
if (t >= 41 && t <= 47) return "pwm"; // analog RGB/CCT/single
|
||||
if (t >= 48 && t <= 63) return "digital-spi"; // APA102, WS2801, etc.
|
||||
if (t >= 64 && t <= 71) return "hub75"; // HUB75 matrix panels
|
||||
if (t >= 80 && t <= 95) return "network"; // DDP, E1.31, ArtNet
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
function updateVersionInfo(version, neverAsk, alwaysReport) {
|
||||
const versionInfo = {
|
||||
version: version,
|
||||
|
||||
@@ -1195,7 +1195,7 @@ async function imgPlay(url,name){
|
||||
on:true,
|
||||
seg: cur!==null && cur!==tgt
|
||||
? [{id:cur,fx:0,n:""},{id:tgt,fx:53,frz:false,sx:128,n:name}]
|
||||
: {id:tgt,fx:53,frz:false,sx:128,ix:0,n:name}
|
||||
: {id:tgt,fx:53,frz:false,sx:128,n:name}
|
||||
};
|
||||
const r=await fetch(getURL('/json/state'),{method:'POST',body:JSON.stringify(j)});
|
||||
const out=await r.json();
|
||||
|
||||
@@ -176,6 +176,7 @@ void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool
|
||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
||||
void serializeInfo(JsonObject root);
|
||||
void serializeModeNames(JsonArray arr);
|
||||
void serializeModeData(JsonArray fxdata);
|
||||
void serializePins(JsonObject root);
|
||||
void serveJson(AsyncWebServerRequest* request);
|
||||
#ifdef WLED_ENABLE_JSONLIVE
|
||||
|
||||
@@ -28,10 +28,6 @@ int fileReadCallback(void) {
|
||||
}
|
||||
|
||||
int fileReadBlockCallback(void * buffer, int numberOfBytes) {
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
unsigned t0 = millis();
|
||||
while (strip.isUpdating() && (millis() - t0 < 15)) yield(); // be nice, but not too nice. Waits up to 15ms to avoid glitches
|
||||
#endif
|
||||
return file.read((uint8_t*)buffer, numberOfBytes);
|
||||
}
|
||||
|
||||
|
||||
@@ -1160,6 +1160,21 @@ void serializePins(JsonObject root)
|
||||
}
|
||||
}
|
||||
|
||||
// deserializes mode data string into JsonArray
|
||||
void serializeModeData(JsonArray fxdata)
|
||||
{
|
||||
char lineBuffer[256];
|
||||
for (size_t i = 0; i < strip.getModeCount(); i++) {
|
||||
strncpy_P(lineBuffer, strip.getModeData(i), sizeof(lineBuffer)/sizeof(char)-1);
|
||||
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
|
||||
if (lineBuffer[0] != 0) {
|
||||
char* dataPtr = strchr(lineBuffer,'@');
|
||||
if (dataPtr) fxdata.add(dataPtr+1);
|
||||
else fxdata.add("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deserializes mode names string into JsonArray
|
||||
// also removes effect data extensions (@...) from deserialised names
|
||||
void serializeModeNames(JsonArray arr)
|
||||
@@ -1176,78 +1191,6 @@ void serializeModeNames(JsonArray arr)
|
||||
}
|
||||
}
|
||||
|
||||
// Writes a JSON-escaped string (with surrounding quotes) into dest[0..maxLen-1].
|
||||
// Returns bytes written, or 0 if the buffer was too small.
|
||||
static size_t writeJSONString(uint8_t* dest, size_t maxLen, const char* src) {
|
||||
size_t pos = 0;
|
||||
|
||||
auto emit = [&](char c) -> bool {
|
||||
if (pos >= maxLen) return false;
|
||||
dest[pos++] = (uint8_t)c;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!emit('"')) return 0;
|
||||
|
||||
for (const char* p = src; *p; ++p) {
|
||||
char esc = ARDUINOJSON_NAMESPACE::EscapeSequence::escapeChar(*p);
|
||||
if (esc) {
|
||||
if (!emit('\\') || !emit(esc)) return 0;
|
||||
} else {
|
||||
if (!emit(*p)) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emit('"')) return 0;
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Writes ,"<escaped_src>" into dest[0..maxLen-1] (no null terminator).
|
||||
// Returns bytes written, or 0 if the buffer was too small.
|
||||
static size_t writeJSONStringElement(uint8_t* dest, size_t maxLen, const char* src) {
|
||||
if (maxLen == 0) return 0;
|
||||
dest[0] = ',';
|
||||
size_t n = writeJSONString(dest + 1, maxLen - 1, src);
|
||||
if (n == 0) return 0;
|
||||
return 1 + n;
|
||||
}
|
||||
|
||||
// Generate a streamed JSON response for the mode data
|
||||
// This uses sendChunked to send the reply in blocks based on how much fit in the outbound
|
||||
// packet buffer, minimizing the required state (ie. just the next index to send). This
|
||||
// allows us to send an arbitrarily large response without using any significant amount of
|
||||
// memory (so no worries about buffer limits).
|
||||
void respondModeData(AsyncWebServerRequest* request) {
|
||||
size_t fx_index = 0;
|
||||
request->sendChunked(FPSTR(CONTENT_TYPE_JSON),
|
||||
[fx_index](uint8_t* data, size_t len, size_t) mutable {
|
||||
size_t bytes_written = 0;
|
||||
char lineBuffer[256];
|
||||
while (fx_index < strip.getModeCount()) {
|
||||
strncpy_P(lineBuffer, strip.getModeData(fx_index), sizeof(lineBuffer)-1); // Copy to stack buffer for strchr
|
||||
if (lineBuffer[0] != 0) {
|
||||
lineBuffer[sizeof(lineBuffer)-1] = '\0'; // terminate string (only needed if strncpy filled the buffer)
|
||||
const char* dataPtr = strchr(lineBuffer,'@'); // Find '@', if there is one
|
||||
size_t mode_bytes = writeJSONStringElement(data, len, dataPtr ? dataPtr + 1 : "");
|
||||
if (mode_bytes == 0) break; // didn't fit; break loop and try again next packet
|
||||
if (fx_index == 0) *data = '[';
|
||||
data += mode_bytes;
|
||||
len -= mode_bytes;
|
||||
bytes_written += mode_bytes;
|
||||
}
|
||||
++fx_index;
|
||||
}
|
||||
|
||||
if ((fx_index == strip.getModeCount()) && (len >= 1)) {
|
||||
*data = ']';
|
||||
++bytes_written;
|
||||
++fx_index; // we're really done
|
||||
}
|
||||
|
||||
return bytes_written;
|
||||
});
|
||||
}
|
||||
|
||||
// Global buffer locking response helper class (to make sure lock is released when AsyncJsonResponse is destroyed)
|
||||
class LockedJsonResponse: public AsyncJsonResponse {
|
||||
bool _holding_lock;
|
||||
@@ -1275,7 +1218,7 @@ class LockedJsonResponse: public AsyncJsonResponse {
|
||||
void serveJson(AsyncWebServerRequest* request)
|
||||
{
|
||||
enum class json_target {
|
||||
all, state, info, state_info, nodes, effects, palettes, networks, config, pins
|
||||
all, state, info, state_info, nodes, effects, palettes, fxdata, networks, config, pins
|
||||
};
|
||||
json_target subJson = json_target::all;
|
||||
|
||||
@@ -1286,7 +1229,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
else if (url.indexOf(F("nodes")) > 0) subJson = json_target::nodes;
|
||||
else if (url.indexOf(F("eff")) > 0) subJson = json_target::effects;
|
||||
else if (url.indexOf(F("palx")) > 0) subJson = json_target::palettes;
|
||||
else if (url.indexOf(F("fxda")) > 0) { respondModeData(request); return; }
|
||||
else if (url.indexOf(F("fxda")) > 0) subJson = json_target::fxdata;
|
||||
else if (url.indexOf(F("net")) > 0) subJson = json_target::networks;
|
||||
else if (url.indexOf(F("cfg")) > 0) subJson = json_target::config;
|
||||
else if (url.indexOf(F("pins")) > 0) subJson = json_target::pins;
|
||||
@@ -1311,7 +1254,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
}
|
||||
// releaseJSONBufferLock() will be called when "response" is destroyed (from AsyncWebServer)
|
||||
// make sure you delete "response" if no "request->send(response);" is made
|
||||
LockedJsonResponse *response = new LockedJsonResponse(pDoc, subJson==json_target::effects); // will clear and convert JsonDocument into JsonArray if necessary
|
||||
LockedJsonResponse *response = new LockedJsonResponse(pDoc, subJson==json_target::fxdata || subJson==json_target::effects); // will clear and convert JsonDocument into JsonArray if necessary
|
||||
|
||||
JsonVariant lDoc = response->getRoot();
|
||||
|
||||
@@ -1327,6 +1270,8 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
serializePalettes(lDoc, request->hasParam(F("page")) ? request->getParam(F("page"))->value().toInt() : 0); break;
|
||||
case json_target::effects:
|
||||
serializeModeNames(lDoc); break;
|
||||
case json_target::fxdata:
|
||||
serializeModeData(lDoc); break;
|
||||
case json_target::networks:
|
||||
serializeNetworks(lDoc); break;
|
||||
case json_target::config:
|
||||
|
||||
@@ -377,7 +377,6 @@ bool isWiFiConfigured() {
|
||||
static u8_t blockRouterAdvertisements(void* arg, struct raw_pcb* pcb, struct pbuf* p, const ip_addr_t* addr) {
|
||||
// ICMPv6 type is the first byte of the payload, so we skip the header
|
||||
if (p->len > 0 && (pbuf_get_at(p, sizeof(struct ip6_hdr)) == ICMP6_TYPE_RA)) {
|
||||
pbuf_free(p);
|
||||
return 1; // claim the packet — lwIP will not pass it further
|
||||
}
|
||||
return 0; // not consumed, pass it on
|
||||
|
||||
@@ -85,7 +85,6 @@ private:
|
||||
IPAddress ipMulti;
|
||||
uint32_t mac24; //bottom 24 bits of mac
|
||||
String escapedMac=""; //lowercase mac address
|
||||
String bridgeId=""; //uppercase EUI-64 bridge ID (16 hex chars)
|
||||
|
||||
//private member functions
|
||||
const char* modeString(EspalexaColorMode m)
|
||||
@@ -298,13 +297,13 @@ private:
|
||||
|
||||
snprintf_P(buf, sizeof(buf), PSTR("HTTP/1.1 200 OK\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=86400\r\n" // SSDP_INTERVAL
|
||||
"CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL
|
||||
"LOCATION: http://%s:80/description.xml\r\n"
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
|
||||
"hue-bridgeid: %s\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:Basic:1\r\n" // _deviceType
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-%s::urn:schemas-upnp-org:device:Basic:1\r\n" // _uuid::_deviceType
|
||||
"\r\n"),s,bridgeId.c_str(),escapedMac.c_str());
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-%s::upnp:rootdevice\r\n" // _uuid::_deviceType
|
||||
"\r\n"),s,escapedMac.c_str(),escapedMac.c_str());
|
||||
|
||||
espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort());
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
@@ -334,11 +333,6 @@ public:
|
||||
escapedMac.replace(":", "");
|
||||
escapedMac.toLowerCase();
|
||||
|
||||
// Compute EUI-64 bridge ID from MAC-48: insert standard "FFFE" padding between
|
||||
// the first 6 hex chars (OUI/manufacturer) and last 6 hex chars (device), then uppercase
|
||||
bridgeId = escapedMac.substring(0, 6) + "fffe" + escapedMac.substring(6);
|
||||
bridgeId.toUpperCase();
|
||||
|
||||
String macSubStr = escapedMac.substring(6, 12);
|
||||
mac24 = strtol(macSubStr.c_str(), 0, 16);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user