#include "wled.h" #include "wled_ethernet.h" /* * Sending XML status files to client */ //build XML response to HTTP /win API request void XML_response(AsyncWebServerRequest *request, char* dest) { char sbuf[(dest == nullptr)?1024:1]; //allocate local buffer if none passed obuf = (dest == nullptr)? sbuf:dest; olen = 0; oappend(SET_F("")); oappendi((nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri); oappend(SET_F("")); for (int i = 0; i < 3; i++) { oappend(""); oappendi(col[i]); oappend(""); } for (int i = 0; i < 3; i++) { oappend(""); oappendi(colSec[i]); oappend(""); } oappend(SET_F("")); oappendi(notifyDirect); oappend(SET_F("")); oappendi(receiveGroups!=0); oappend(SET_F("")); oappendi(nightlightActive); oappend(SET_F("")); oappendi(nightlightMode > NL_MODE_SET); oappend(SET_F("")); oappendi(nightlightDelayMins); oappend(SET_F("")); oappendi(nightlightTargetBri); oappend(SET_F("")); oappendi(effectCurrent); oappend(SET_F("")); oappendi(effectSpeed); oappend(SET_F("")); oappendi(effectIntensity); oappend(SET_F("")); oappendi(effectPalette); oappend(SET_F("")); if (strip.hasWhiteChannel()) { oappendi(col[3]); } else { oappend("-1"); } oappend(SET_F("")); oappendi(colSec[3]); oappend(SET_F("")); oappendi(currentPreset); oappend(SET_F("")); oappendi(currentPlaylist >= 0); oappend(SET_F("")); oappend(serverDescription); if (realtimeMode) { oappend(SET_F(" (live)")); } oappend(SET_F("")); oappendi(strip.getFirstSelectedSegId()); oappend(SET_F("")); if (request != nullptr) request->send(200, "text/xml", obuf); } void extractPin(JsonObject &obj, const char *key) { if (obj[key].is()) { JsonArray pins = obj[key].as(); for (JsonVariant pv : pins) { if (pv.as() > -1) { oappend(","); oappendi(pv.as()); } } } else { if (obj[key].as() > -1) { oappend(","); oappendi(obj[key].as()); } } } // oappend used pins by scanning JsonObject (1 level deep) void fillUMPins(JsonObject &mods) { for (JsonPair kv : mods) { // kv.key() is usermod name or subobject key // kv.value() is object itself JsonObject obj = kv.value(); if (!obj.isNull()) { // element is an JsonObject if (!obj["pin"].isNull()) { extractPin(obj, "pin"); } else { // scan keys (just one level deep as is possible with usermods) for (JsonPair so : obj) { const char *key = so.key().c_str(); if (strstr(key, "pin")) { // we found a key containing "pin" substring if (strlen(strstr(key, "pin")) == 3) { // and it is at the end, we found another pin extractPin(obj, key); continue; } } if (!obj[so.key()].is()) continue; JsonObject subObj = obj[so.key()]; if (!subObj["pin"].isNull()) { // get pins from subobject extractPin(subObj, "pin"); } } } } } } void appendGPIOinfo() { char nS[8]; oappend(SET_F("d.um_p=[-1")); // has to have 1 element if (i2c_sda > -1 && i2c_scl > -1) { oappend(","); oappend(itoa(i2c_sda,nS,10)); oappend(","); oappend(itoa(i2c_scl,nS,10)); } if (spi_mosi > -1 && spi_sclk > -1) { oappend(","); oappend(itoa(spi_mosi,nS,10)); oappend(","); oappend(itoa(spi_sclk,nS,10)); } // usermod pin reservations will become unnecessary when settings pages will read cfg.json directly if (requestJSONBufferLock(6)) { // if we can't allocate JSON buffer ignore usermod pins JsonObject mods = pDoc->createNestedObject(F("um")); usermods.addToConfig(mods); if (!mods.isNull()) fillUMPins(mods); releaseJSONBufferLock(); } oappend(SET_F("];")); // add reserved and usermod pins as d.um_p array #if defined(CONFIG_IDF_TARGET_ESP32S2) oappend(SET_F("d.rsvd=[22,23,24,25,26,27,28,29,30,31,32")); #elif defined(CONFIG_IDF_TARGET_ESP32S3) oappend(SET_F("d.rsvd=[19,20,22,23,24,25,26,27,28,29,30,31,32")); // includes 19+20 for USB OTG (JTAG) if (psramFound()) oappend(SET_F(",33,34,35,36,37")); // in use for "octal" PSRAM or "octal" FLASH -seems that octal PSRAM is very common on S3. #elif defined(CONFIG_IDF_TARGET_ESP32C3) oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17")); #elif defined(ESP32) oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31,37,38")); if (!pinManager.isPinOk(16,false)) oappend(SET_F(",16")); // covers PICO & WROVER if (!pinManager.isPinOk(17,false)) oappend(SET_F(",17")); // covers PICO & WROVER #else oappend(SET_F("d.rsvd=[6,7,8,9,10,11")); #endif #ifdef WLED_ENABLE_DMX oappend(SET_F(",2")); // DMX hardcoded pin #endif #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) oappend(SET_F(",")); oappend(itoa(hardwareTX,nS,10)); // debug output (TX) pin #endif //Note: Using pin 3 (RX) disables Adalight / Serial JSON #ifdef WLED_USE_ETHERNET if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { for (uint8_t p=0; p=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); } if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); } if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); } switch (ethernetBoards[ethernetType].eth_clk_mode) { case ETH_CLOCK_GPIO0_IN: case ETH_CLOCK_GPIO0_OUT: oappend(SET_F(",0")); break; case ETH_CLOCK_GPIO16_OUT: oappend(SET_F(",16")); break; case ETH_CLOCK_GPIO17_OUT: oappend(SET_F(",17")); break; } } #endif oappend(SET_F("];")); // add info for read-only GPIO oappend(SET_F("d.ro_gpio=[")); #if defined(CONFIG_IDF_TARGET_ESP32S2) oappendi(46); #elif defined(CONFIG_IDF_TARGET_ESP32S3) // none for S3 #elif defined(CONFIG_IDF_TARGET_ESP32C3) // none for C3 #elif defined(ESP32) oappend(SET_F("34,35,36,37,38,39")); #else // none for ESP8266 #endif oappend(SET_F("];")); // add info about max. # of pins oappend(SET_F("d.max_gpio=")); #if defined(CONFIG_IDF_TARGET_ESP32S2) oappendi(46); #elif defined(CONFIG_IDF_TARGET_ESP32S3) oappendi(48); #elif defined(CONFIG_IDF_TARGET_ESP32C3) oappendi(21); #elif defined(ESP32) oappendi(39); #else oappendi(16); #endif oappend(SET_F(";")); } //get values for settings form in javascript void getSettingsJS(byte subPage, char* dest) { //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec DEBUG_PRINT(F("settings resp")); DEBUG_PRINTLN(subPage); obuf = dest; olen = 0; if (subPage <0 || subPage >10) return; if (subPage == SUBPAGE_MENU) { #ifdef WLED_DISABLE_2D // include only if 2D is not compiled in oappend(PSTR("gId('2dbtn').style.display='none';")); #endif #ifdef WLED_ENABLE_DMX // include only if DMX is enabled oappend(PSTR("gId('dmxbtn').style.display='';")); #endif } if (subPage == SUBPAGE_WIFI) { char nS[10]; size_t l; oappend(SET_F("resetWiFi(")); oappend(itoa(WLED_MAX_WIFI_COUNT,nS,10)); oappend(SET_F(");")); for (size_t n = 0; n < multiWiFi.size(); n++) { l = strlen(multiWiFi[n].clientPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); oappend(SET_F("addWiFi(\"")); oappend(multiWiFi[n].clientSSID); oappend(SET_F("\",\"")); oappend(fpass); oappend(SET_F("\",0x")); oappend(itoa(multiWiFi[n].staticIP,nS,16)); oappend(SET_F(",0x")); oappend(itoa(multiWiFi[n].staticGW,nS,16)); oappend(SET_F(",0x")); oappend(itoa(multiWiFi[n].staticSN,nS,16)); oappend(SET_F(");")); } sappend('v',SET_F("D0"),dnsAddress[0]); sappend('v',SET_F("D1"),dnsAddress[1]); sappend('v',SET_F("D2"),dnsAddress[2]); sappend('v',SET_F("D3"),dnsAddress[3]); sappends('s',SET_F("CM"),cmDNS); sappend('i',SET_F("AB"),apBehavior); sappends('s',SET_F("AS"),apSSID); sappend('c',SET_F("AH"),apHide); l = strlen(apPass); char fapass[l+1]; //fill password field with *** fapass[l] = 0; memset(fapass,'*',l); sappends('s',SET_F("AP"),fapass); sappend('v',SET_F("AC"),apChannel); sappend('c',SET_F("FG"),force802_3g); sappend('c',SET_F("WS"),noWifiSleep); #ifndef WLED_DISABLE_ESPNOW sappend('c',SET_F("RE"),enableESPNow); sappends('s',SET_F("RMAC"),linked_remote); #else //hide remote settings if not compiled oappend(SET_F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif #ifdef WLED_USE_ETHERNET sappend('v',SET_F("ETH"),ethernetType); #else //hide ethernet setting if not compiled in oappend(SET_F("document.getElementById('ethd').style.display='none';")); #endif if (Network.isConnected()) //is connected { char s[32]; IPAddress localIP = Network.localIP(); sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)")); #endif sappends('m',SET_F("(\"sip\")[0]"),s); } else { sappends('m',SET_F("(\"sip\")[0]"),(char*)F("Not connected")); } if (WiFi.softAPIP()[0] != 0) //is active { char s[16]; IPAddress apIP = WiFi.softAPIP(); sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]); sappends('m',SET_F("(\"sip\")[1]"),s); } else { sappends('m',SET_F("(\"sip\")[1]"),(char*)F("Not active")); } #ifndef WLED_DISABLE_ESPNOW if (strlen(last_signal_src) > 0) { //Have seen an ESP-NOW Remote sappends('m',SET_F("(\"rlid\")[0]"),last_signal_src); } else if (!enableESPNow) { sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("(Enable ESP-NOW to listen)")); } else { sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("None")); } #endif } if (subPage == SUBPAGE_LEDS) { char nS[32]; appendGPIOinfo(); // set limits oappend(SET_F("bLimits(")); oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(","); oappend(itoa(WLED_MIN_VIRTUAL_BUSSES,nS,10)); oappend(","); oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(","); oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(","); oappend(itoa(MAX_LEDS,nS,10)); oappend(SET_F(");")); sappend('c',SET_F("MS"),autoSegments); sappend('c',SET_F("CCT"),correctWB); sappend('c',SET_F("IC"),cctICused); sappend('c',SET_F("CR"),cctFromRgb); sappend('v',SET_F("CB"),strip.cctBlending); sappend('v',SET_F("FR"),strip.getTargetFps()); sappend('v',SET_F("AW"),Bus::getGlobalAWMode()); sappend('c',SET_F("LD"),useGlobalLedBuffer); uint16_t sumMa = 0; for (uint8_t s=0; s < BusManager::getNumBusses(); s++) { Bus* bus = BusManager::getBus(s); if (bus == nullptr) continue; char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED char rf[4] = "RF"; rf[2] = 48+s; rf[3] = 0; //off refresh char aw[4] = "AW"; aw[2] = 48+s; aw[3] = 0; //auto white mode char wo[4] = "WO"; wo[2] = 48+s; wo[3] = 0; //swap channels char sp[4] = "SP"; sp[2] = 48+s; sp[3] = 0; //bus clock speed char la[4] = "LA"; la[2] = 48+s; la[3] = 0; //LED current char ma[4] = "MA"; ma[2] = 48+s; ma[3] = 0; //max per-port PSU current oappend(SET_F("addLEDs(1);")); uint8_t pins[5]; uint8_t nPins = bus->getPins(pins); for (uint8_t i = 0; i < nPins; i++) { lp[1] = 48+i; if (pinManager.isPinOk(pins[i]) || IS_VIRTUAL(bus->getType())) sappend('v',lp,pins[i]); } sappend('v',lc,bus->getLength()); sappend('v',lt,bus->getType()); sappend('v',co,bus->getColorOrder() & 0x0F); sappend('v',ls,bus->getStart()); sappend('c',cv,bus->isReversed()); sappend('v',sl,bus->skippedLeds()); sappend('c',rf,bus->isOffRefreshRequired()); sappend('v',aw,bus->getAutoWhiteMode()); sappend('v',wo,bus->getColorOrder() >> 4); uint16_t speed = bus->getFrequency(); if (IS_PWM(bus->getType())) { switch (speed) { case WLED_PWM_FREQ/2 : speed = 0; break; case WLED_PWM_FREQ*2/3 : speed = 1; break; default: case WLED_PWM_FREQ : speed = 2; break; case WLED_PWM_FREQ*2 : speed = 3; break; case WLED_PWM_FREQ*10/3 : speed = 4; break; // uint16_t max (19531 * 3.333) } } else if (IS_DIGITAL(bus->getType()) && IS_2PIN(bus->getType())) { switch (speed) { case 1000 : speed = 0; break; case 2000 : speed = 1; break; default: case 5000 : speed = 2; break; case 10000 : speed = 3; break; case 20000 : speed = 4; break; } } sappend('v',sp,speed); sappend('v',la,bus->getLEDCurrent()); sappend('v',ma,bus->getMaxCurrent()); sumMa += bus->getMaxCurrent(); } sappend('v',SET_F("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); sappend('c',SET_F("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); sappend('c',SET_F("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); oappend(SET_F("resetCOM(")); oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); oappend(SET_F(");")); const ColorOrderMap& com = BusManager::getColorOrderMap(); for (uint8_t s=0; s < com.count(); s++) { const ColorOrderMapEntry* entry = com.get(s); if (entry == nullptr) break; oappend(SET_F("addCOM(")); oappend(itoa(entry->start,nS,10)); oappend(","); oappend(itoa(entry->len,nS,10)); oappend(","); oappend(itoa(entry->colorOrder,nS,10)); oappend(");"); } sappend('v',SET_F("CA"),briS); sappend('c',SET_F("BO"),turnOnAtBoot); sappend('v',SET_F("BP"),bootPreset); sappend('c',SET_F("GB"),gammaCorrectBri); sappend('c',SET_F("GC"),gammaCorrectCol); dtostrf(gammaCorrectVal,3,1,nS); sappends('s',SET_F("GV"),nS); sappend('c',SET_F("TF"),fadeTransition); sappend('c',SET_F("EB"),modeBlending); sappend('v',SET_F("TD"),transitionDelayDefault); sappend('c',SET_F("PF"),strip.paletteFade); sappend('v',SET_F("TP"),randomPaletteChangeTime); sappend('c',SET_F("TH"),useHarmonicRandomPalette); sappend('v',SET_F("BF"),briMultiplier); sappend('v',SET_F("TB"),nightlightTargetBri); sappend('v',SET_F("TL"),nightlightDelayMinsDefault); sappend('v',SET_F("TW"),nightlightMode); sappend('i',SET_F("PB"),strip.paletteBlend); sappend('v',SET_F("RL"),rlyPin); sappend('c',SET_F("RM"),rlyMde); for (uint8_t i=0; i> 4) & 0x0F); k[0] = 'P'; sappend('v',k,timerMonth[i] & 0x0F); k[0] = 'D'; sappend('v',k,timerDay[i]); k[0] = 'E'; sappend('v',k,timerDayEnd[i]); } } } if (subPage == SUBPAGE_SEC) { byte l = strlen(settingsPIN); char fpass[l+1]; //fill PIN field with 0000 fpass[l] = 0; memset(fpass,'0',l); sappends('s',SET_F("PIN"),fpass); sappend('c',SET_F("NO"),otaLock); sappend('c',SET_F("OW"),wifiLock); sappend('c',SET_F("AO"),aOtaEnabled); sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED ")); olen -= 2; //delete "; oappend(versionString); oappend(SET_F(" (build ")); oappendi(VERSION); oappend(SET_F(")\";")); oappend(SET_F("sd=\"")); oappend(serverDescription); oappend(SET_F("\";")); } #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { sappend('v',SET_F("PU"),e131ProxyUniverse); sappend('v',SET_F("CN"),DMXChannels); sappend('v',SET_F("CG"),DMXGap); sappend('v',SET_F("CS"),DMXStart); sappend('v',SET_F("SL"),DMXStartLED); sappend('i',SET_F("CH1"),DMXFixtureMap[0]); sappend('i',SET_F("CH2"),DMXFixtureMap[1]); sappend('i',SET_F("CH3"),DMXFixtureMap[2]); sappend('i',SET_F("CH4"),DMXFixtureMap[3]); sappend('i',SET_F("CH5"),DMXFixtureMap[4]); sappend('i',SET_F("CH6"),DMXFixtureMap[5]); sappend('i',SET_F("CH7"),DMXFixtureMap[6]); sappend('i',SET_F("CH8"),DMXFixtureMap[7]); sappend('i',SET_F("CH9"),DMXFixtureMap[8]); sappend('i',SET_F("CH10"),DMXFixtureMap[9]); sappend('i',SET_F("CH11"),DMXFixtureMap[10]); sappend('i',SET_F("CH12"),DMXFixtureMap[11]); sappend('i',SET_F("CH13"),DMXFixtureMap[12]); sappend('i',SET_F("CH14"),DMXFixtureMap[13]); sappend('i',SET_F("CH15"),DMXFixtureMap[14]); } #endif if (subPage == SUBPAGE_UM) //usermods { appendGPIOinfo(); oappend(SET_F("numM=")); oappendi(usermods.getModCount()); oappend(";"); sappend('v',SET_F("SDA"),i2c_sda); sappend('v',SET_F("SCL"),i2c_scl); sappend('v',SET_F("MOSI"),spi_mosi); sappend('v',SET_F("MISO"),spi_miso); sappend('v',SET_F("SCLK"),spi_sclk); oappend(SET_F("addInfo('SDA','")); oappendi(HW_PIN_SDA); oappend(SET_F("');")); oappend(SET_F("addInfo('SCL','")); oappendi(HW_PIN_SCL); oappend(SET_F("');")); oappend(SET_F("addInfo('MOSI','")); oappendi(HW_PIN_DATASPI); oappend(SET_F("');")); oappend(SET_F("addInfo('MISO','")); oappendi(HW_PIN_MISOSPI); oappend(SET_F("');")); oappend(SET_F("addInfo('SCLK','")); oappendi(HW_PIN_CLOCKSPI); oappend(SET_F("');")); usermods.appendConfigData(); } if (subPage == SUBPAGE_UPDATE) // update { sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED ")); olen -= 2; //delete "; oappend(versionString); oappend(SET_F("
")); oappend((char*)FPSTR(releaseString)); oappend(SET_F("
(")); #if defined(ARDUINO_ARCH_ESP32) oappend(ESP.getChipModel()); #else oappend("esp8266"); #endif oappend(SET_F(" build ")); oappendi(VERSION); oappend(SET_F(")\";")); } if (subPage == SUBPAGE_2D) // 2D matrices { sappend('v',SET_F("SOMP"),strip.isMatrix); #ifndef WLED_DISABLE_2D oappend(SET_F("maxPanels=")); oappendi(WLED_MAX_PANELS); oappend(SET_F(";")); oappend(SET_F("resetPanels();")); if (strip.isMatrix) { if(strip.panels>0){ sappend('v',SET_F("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience sappend('v',SET_F("PH"),strip.panel[0].height); } sappend('v',SET_F("MPC"),strip.panels); // panels for (uint8_t i=0; i