Single json buffer (#2336)
* Single/static JSON buffer for all requests. * Missing json.cpp changes. * Async fix. * Added conditional compile (WLED_USE_DYNAMIC_JSON). * Advanced locking with time-out. * Missing releaseJSONBufferLock() on error response. * Fix for config saving. * Fixes and optimisations. Dadded debugging information. * Fix for ledmaps. * No unsolicited serial sending if GPIO1 allocated * Stray semicolons * Fix JSON ledmap Co-authored-by: Blaz Kristan <blaz@kristan-sp.si>
This commit is contained in:
parent
46ec504743
commit
66bad2b6f8
@ -87,8 +87,6 @@ void WS2812FX::finalizeInit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializeMap();
|
|
||||||
|
|
||||||
_length = 0;
|
_length = 0;
|
||||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||||
Bus *bus = busses.getBus(i);
|
Bus *bus = busses.getBus(i);
|
||||||
@ -1099,7 +1097,7 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//load custom mapping table from JSON file
|
//load custom mapping table from JSON file (called from finalizeInit() or deserializeState())
|
||||||
void WS2812FX::deserializeMap(uint8_t n) {
|
void WS2812FX::deserializeMap(uint8_t n) {
|
||||||
char fileName[32];
|
char fileName[32];
|
||||||
strcpy_P(fileName, PSTR("/ledmap"));
|
strcpy_P(fileName, PSTR("/ledmap"));
|
||||||
@ -1117,11 +1115,19 @@ void WS2812FX::deserializeMap(uint8_t n) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE); // full sized buffer for larger maps
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(7)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
DEBUG_PRINT(F("Reading LED map from "));
|
DEBUG_PRINT(F("Reading LED map from "));
|
||||||
DEBUG_PRINTLN(fileName);
|
DEBUG_PRINTLN(fileName);
|
||||||
|
|
||||||
if (!readObjectFromFile(fileName, nullptr, &doc)) return; //if file does not exist just exit
|
if (!readObjectFromFile(fileName, nullptr, &doc)) {
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return; //if file does not exist just exit
|
||||||
|
}
|
||||||
|
|
||||||
// erase old custom ledmap
|
// erase old custom ledmap
|
||||||
if (customMappingTable != nullptr) {
|
if (customMappingTable != nullptr) {
|
||||||
@ -1138,6 +1144,8 @@ void WS2812FX::deserializeMap(uint8_t n) {
|
|||||||
customMappingTable[i] = (uint16_t) map[i];
|
customMappingTable[i] = (uint16_t) map[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
//gamma 2.8 lookup table used for color correction
|
//gamma 2.8 lookup table used for color correction
|
||||||
|
@ -14,6 +14,7 @@ void getStringFromJson(char* dest, const char* src, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool deserializeConfig(JsonObject doc, bool fromFS) {
|
bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||||
|
bool needsSave = false;
|
||||||
//int rev_major = doc["rev"][0]; // 1
|
//int rev_major = doc["rev"][0]; // 1
|
||||||
//int rev_minor = doc["rev"][1]; // 0
|
//int rev_minor = doc["rev"][1]; // 0
|
||||||
|
|
||||||
@ -410,11 +411,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
DEBUG_PRINTLN(F("Starting usermod config."));
|
DEBUG_PRINTLN(F("Starting usermod config."));
|
||||||
JsonObject usermods_settings = doc["um"];
|
JsonObject usermods_settings = doc["um"];
|
||||||
if (!usermods_settings.isNull()) {
|
if (!usermods_settings.isNull()) {
|
||||||
bool allComplete = usermods.readFromConfig(usermods_settings);
|
needsSave = !usermods.readFromConfig(usermods_settings);
|
||||||
if (!allComplete && fromFS) serializeConfig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromFS) return false;
|
if (fromFS) return needsSave;
|
||||||
doReboot = doc[F("rb")] | doReboot;
|
doReboot = doc[F("rb")] | doReboot;
|
||||||
return (doc["sv"] | true);
|
return (doc["sv"] | true);
|
||||||
}
|
}
|
||||||
@ -426,19 +426,27 @@ void deserializeConfigFromFS() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(1)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
|
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
|
||||||
|
|
||||||
success = readObjectFromFile("/cfg.json", nullptr, &doc);
|
success = readObjectFromFile("/cfg.json", nullptr, &doc);
|
||||||
if (!success) { //if file does not exist, try reading from EEPROM
|
if (!success) { //if file does not exist, try reading from EEPROM
|
||||||
deEEPSettings();
|
deEEPSettings();
|
||||||
|
releaseJSONBufferLock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This routine deserializes *and* applies the configuration
|
// NOTE: This routine deserializes *and* applies the configuration
|
||||||
// Therefore, must also initialize ethernet from this function
|
// Therefore, must also initialize ethernet from this function
|
||||||
deserializeConfig(doc.as<JsonObject>(), true);
|
bool needsSave = deserializeConfig(doc.as<JsonObject>(), true);
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
|
||||||
|
if (needsSave) serializeConfig(); // usermods required new prameters
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializeConfig() {
|
void serializeConfig() {
|
||||||
@ -446,7 +454,11 @@ void serializeConfig() {
|
|||||||
|
|
||||||
DEBUG_PRINTLN(F("Writing settings to /cfg.json..."));
|
DEBUG_PRINTLN(F("Writing settings to /cfg.json..."));
|
||||||
|
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(2)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
JsonArray rev = doc.createNestedArray("rev");
|
JsonArray rev = doc.createNestedArray("rev");
|
||||||
rev.add(1); //major settings revision
|
rev.add(1); //major settings revision
|
||||||
@ -757,16 +769,24 @@ void serializeConfig() {
|
|||||||
File f = WLED_FS.open("/cfg.json", "w");
|
File f = WLED_FS.open("/cfg.json", "w");
|
||||||
if (f) serializeJson(doc, f);
|
if (f) serializeJson(doc, f);
|
||||||
f.close();
|
f.close();
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
//settings in /wsec.json, not accessible via webserver, for passwords and tokens
|
//settings in /wsec.json, not accessible via webserver, for passwords and tokens
|
||||||
bool deserializeConfigSec() {
|
bool deserializeConfigSec() {
|
||||||
DEBUG_PRINTLN(F("Reading settings from /wsec.json..."));
|
DEBUG_PRINTLN(F("Reading settings from /wsec.json..."));
|
||||||
|
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(3)) return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool success = readObjectFromFile("/wsec.json", nullptr, &doc);
|
bool success = readObjectFromFile("/wsec.json", nullptr, &doc);
|
||||||
if (!success) return false;
|
if (!success) {
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject nw_ins_0 = doc["nw"]["ins"][0];
|
JsonObject nw_ins_0 = doc["nw"]["ins"][0];
|
||||||
getStringFromJson(clientPass, nw_ins_0["psk"], 65);
|
getStringFromJson(clientPass, nw_ins_0["psk"], 65);
|
||||||
@ -798,13 +818,18 @@ bool deserializeConfigSec() {
|
|||||||
CJSON(wifiLock, ota[F("lock-wifi")]);
|
CJSON(wifiLock, ota[F("lock-wifi")]);
|
||||||
CJSON(aOtaEnabled, ota[F("aota")]);
|
CJSON(aOtaEnabled, ota[F("aota")]);
|
||||||
|
|
||||||
|
releaseJSONBufferLock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializeConfigSec() {
|
void serializeConfigSec() {
|
||||||
DEBUG_PRINTLN(F("Writing settings to /wsec.json..."));
|
DEBUG_PRINTLN(F("Writing settings to /wsec.json..."));
|
||||||
|
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(4)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
JsonObject nw = doc.createNestedObject("nw");
|
JsonObject nw = doc.createNestedObject("nw");
|
||||||
|
|
||||||
@ -839,4 +864,5 @@ void serializeConfigSec() {
|
|||||||
File f = WLED_FS.open("/wsec.json", "w");
|
File f = WLED_FS.open("/wsec.json", "w");
|
||||||
if (f) serializeJson(doc, f);
|
if (f) serializeJson(doc, f);
|
||||||
f.close();
|
f.close();
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_M
|
|||||||
float low = minf(rgb[0],minf(rgb[1],rgb[2]));
|
float low = minf(rgb[0],minf(rgb[1],rgb[2]));
|
||||||
float high = maxf(rgb[0],maxf(rgb[1],rgb[2]));
|
float high = maxf(rgb[0],maxf(rgb[1],rgb[2]));
|
||||||
if (high < 0.1f) return;
|
if (high < 0.1f) return;
|
||||||
float sat = 100.0f * ((high - low) / high);; // maximum saturation is 100 (corrected from 255)
|
float sat = 100.0f * ((high - low) / high); // maximum saturation is 100 (corrected from 255)
|
||||||
rgb[3] = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3);
|
rgb[3] = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -211,6 +211,17 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
|
|||||||
void refreshNodeList();
|
void refreshNodeList();
|
||||||
void sendSysInfoUDP();
|
void sendSysInfoUDP();
|
||||||
|
|
||||||
|
//util.cpp
|
||||||
|
//bool oappend(const char* txt); // append new c string to temp buffer efficiently
|
||||||
|
//bool oappendi(int i); // append new number to temp buffer efficiently
|
||||||
|
//void sappend(char stype, const char* key, int val);
|
||||||
|
//void sappends(char stype, const char* key, char* val);
|
||||||
|
//void prepareHostname(char* hostname);
|
||||||
|
//void _setRandomColor(bool _sec, bool fromButton);
|
||||||
|
//bool isAsterisksOnly(const char* str, byte maxLen);
|
||||||
|
bool requestJSONBufferLock(uint8_t module=255);
|
||||||
|
void releaseJSONBufferLock();
|
||||||
|
|
||||||
//um_manager.cpp
|
//um_manager.cpp
|
||||||
class Usermod {
|
class Usermod {
|
||||||
public:
|
public:
|
||||||
|
@ -165,6 +165,7 @@ void decodeIR(uint32_t code)
|
|||||||
if (decodeIRCustom(code)) return;
|
if (decodeIRCustom(code)) return;
|
||||||
if (irEnabled == 8) { // any remote configurable with ir.json file
|
if (irEnabled == 8) { // any remote configurable with ir.json file
|
||||||
decodeIRJson(code);
|
decodeIRJson(code);
|
||||||
|
colorUpdated(CALL_MODE_BUTTON);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (code > 0xFFFFFF) return; //invalid code
|
if (code > 0xFFFFFF) return; //invalid code
|
||||||
@ -566,25 +567,33 @@ Sample:
|
|||||||
void decodeIRJson(uint32_t code)
|
void decodeIRJson(uint32_t code)
|
||||||
{
|
{
|
||||||
char objKey[10];
|
char objKey[10];
|
||||||
const char* cmd;
|
|
||||||
String cmdStr;
|
String cmdStr;
|
||||||
DynamicJsonDocument irDoc(JSON_BUFFER_SIZE);
|
|
||||||
JsonObject fdo;
|
JsonObject fdo;
|
||||||
JsonObject jsonCmdObj;
|
JsonObject jsonCmdObj;
|
||||||
|
|
||||||
sprintf(objKey, "\"0x%X\":", code);
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(13)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
readObjectFromFile("/ir.json", objKey, &irDoc);
|
sprintf_P(objKey, PSTR("\"0x%lX\":"), (unsigned long)code);
|
||||||
fdo = irDoc.as<JsonObject>();
|
|
||||||
|
// attempt to read command from ir.json
|
||||||
|
// this may fail for two reasons: ir.json does not exist or IR code not found
|
||||||
|
// if the IR code is not found readObjectFromFile() will clean() doc JSON document
|
||||||
|
// so we can differentiate between the two
|
||||||
|
readObjectFromFile("/ir.json", objKey, &doc);
|
||||||
|
fdo = doc.as<JsonObject>();
|
||||||
lastValidCode = 0;
|
lastValidCode = 0;
|
||||||
if (fdo.isNull()) {
|
if (fdo.isNull()) {
|
||||||
//the received code does not exist
|
//the received code does not exist
|
||||||
if (!WLED_FS.exists("/ir.json")) errorFlag = ERR_FS_IRLOAD; //warn if IR file itself doesn't exist
|
if (!WLED_FS.exists("/ir.json")) errorFlag = ERR_FS_IRLOAD; //warn if IR file itself doesn't exist
|
||||||
|
releaseJSONBufferLock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = fdo["cmd"]; //string
|
cmdStr = fdo["cmd"].as<String>();
|
||||||
cmdStr = String(cmd);
|
|
||||||
jsonCmdObj = fdo["cmd"]; //object
|
jsonCmdObj = fdo["cmd"]; //object
|
||||||
|
|
||||||
if (!cmdStr.isEmpty())
|
if (!cmdStr.isEmpty())
|
||||||
@ -622,11 +631,9 @@ void decodeIRJson(uint32_t code)
|
|||||||
colorUpdated(CALL_MODE_BUTTON);
|
colorUpdated(CALL_MODE_BUTTON);
|
||||||
} else if (!jsonCmdObj.isNull()) {
|
} else if (!jsonCmdObj.isNull()) {
|
||||||
// command is JSON object
|
// command is JSON object
|
||||||
//allow applyPreset() to reuse JSON buffer, or it would alloc. a second buffer and run out of mem.
|
|
||||||
fileDoc = &irDoc;
|
|
||||||
deserializeState(jsonCmdObj, CALL_MODE_BUTTON);
|
deserializeState(jsonCmdObj, CALL_MODE_BUTTON);
|
||||||
fileDoc = nullptr;
|
|
||||||
}
|
}
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initIR()
|
void initIR()
|
||||||
@ -654,9 +661,8 @@ void handleIR()
|
|||||||
{
|
{
|
||||||
if (results.value != 0) // only print results if anything is received ( != 0 )
|
if (results.value != 0) // only print results if anything is received ( != 0 )
|
||||||
{
|
{
|
||||||
Serial.print("IR recv\r\n0x");
|
if (!pinManager.isPinAllocated(1)) //GPIO 1 - Serial TX pin
|
||||||
Serial.println((uint32_t)results.value, HEX);
|
Serial.printf_P(PSTR("IR recv: 0x%lX\n"), (unsigned long)results.value);
|
||||||
Serial.println();
|
|
||||||
}
|
}
|
||||||
decodeIR(results.value);
|
decodeIR(results.value);
|
||||||
irrecv->resume();
|
irrecv->resume();
|
||||||
|
@ -338,6 +338,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
|
|
||||||
usermods.readFromJsonState(root);
|
usermods.readFromJsonState(root);
|
||||||
|
|
||||||
|
loadLedmap = root[F("ledmap")] | loadLedmap;
|
||||||
|
|
||||||
byte ps = root[F("psave")];
|
byte ps = root[F("psave")];
|
||||||
if (ps > 0) {
|
if (ps > 0) {
|
||||||
savePreset(ps, true, nullptr, root);
|
savePreset(ps, true, nullptr, root);
|
||||||
@ -832,23 +834,29 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse(JSON_BUFFER_SIZE);
|
AsyncJsonResponse* response = new AsyncJsonResponse(JSON_BUFFER_SIZE);
|
||||||
JsonObject doc = response->getRoot();
|
#else
|
||||||
|
if (!requestJSONBufferLock(17)) return;
|
||||||
|
AsyncJsonResponse *response = new AsyncJsonResponse(&doc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JsonObject lDoc = response->getRoot();
|
||||||
|
|
||||||
switch (subJson)
|
switch (subJson)
|
||||||
{
|
{
|
||||||
case 1: //state
|
case 1: //state
|
||||||
serializeState(doc); break;
|
serializeState(lDoc); break;
|
||||||
case 2: //info
|
case 2: //info
|
||||||
serializeInfo(doc); break;
|
serializeInfo(lDoc); break;
|
||||||
case 4: //node list
|
case 4: //node list
|
||||||
serializeNodes(doc); break;
|
serializeNodes(lDoc); break;
|
||||||
case 5: //palettes
|
case 5: //palettes
|
||||||
serializePalettes(doc, request); break;
|
serializePalettes(lDoc, request); break;
|
||||||
default: //all
|
default: //all
|
||||||
JsonObject state = doc.createNestedObject("state");
|
JsonObject state = lDoc.createNestedObject("state");
|
||||||
serializeState(state);
|
serializeState(state);
|
||||||
JsonObject info = doc.createNestedObject("info");
|
JsonObject info = lDoc.createNestedObject("info");
|
||||||
serializeInfo(info);
|
serializeInfo(info);
|
||||||
if (subJson != 3)
|
if (subJson != 3)
|
||||||
{
|
{
|
||||||
@ -858,10 +866,11 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("JSON buffer size: ");
|
DEBUG_PRINT("JSON buffer size: ");
|
||||||
DEBUG_PRINTLN(doc.memoryUsage());
|
DEBUG_PRINTLN(lDoc.memoryUsage());
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_LIVE_LEDS 180
|
#define MAX_LIVE_LEDS 180
|
||||||
|
@ -91,11 +91,14 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
|
|||||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||||
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
|
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
|
||||||
if (payload[0] == '{') { //JSON API
|
if (payload[0] == '{') { //JSON API
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(15)) return;
|
||||||
|
#endif
|
||||||
deserializeJson(doc, payloadStr);
|
deserializeJson(doc, payloadStr);
|
||||||
fileDoc = &doc;
|
|
||||||
deserializeState(doc.as<JsonObject>());
|
deserializeState(doc.as<JsonObject>());
|
||||||
fileDoc = nullptr;
|
releaseJSONBufferLock();
|
||||||
} else { //HTTP API
|
} else { //HTTP API
|
||||||
String apireq = "win&";
|
String apireq = "win&";
|
||||||
apireq += (char*)payloadStr;
|
apireq += (char*)payloadStr;
|
||||||
@ -124,22 +127,22 @@ void publishMqtt()
|
|||||||
sprintf_P(s, PSTR("%u"), bri);
|
sprintf_P(s, PSTR("%u"), bri);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/g"));
|
strcat_P(subuf, PSTR("/g"));
|
||||||
mqtt->publish(subuf, 0, true, s);
|
mqtt->publish(subuf, 0, true, s); // retain message
|
||||||
|
|
||||||
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/c"));
|
strcat_P(subuf, PSTR("/c"));
|
||||||
mqtt->publish(subuf, 0, true, s);
|
mqtt->publish(subuf, 0, true, s); // retain message
|
||||||
|
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/status"));
|
strcat_P(subuf, PSTR("/status"));
|
||||||
mqtt->publish(subuf, 0, true, "online");
|
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
|
||||||
|
|
||||||
char apires[1024];
|
char apires[1024]; // allocating 1024 bytes from stack can be risky
|
||||||
XML_response(nullptr, apires);
|
XML_response(nullptr, apires);
|
||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/v"));
|
strcat_P(subuf, PSTR("/v"));
|
||||||
mqtt->publish(subuf, 0, false, apires);
|
mqtt->publish(subuf, 0, false, apires); // do not retain message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -169,7 +172,7 @@ bool initMqtt()
|
|||||||
|
|
||||||
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
||||||
strcat_P(mqttStatusTopic, PSTR("/status"));
|
strcat_P(mqttStatusTopic, PSTR("/status"));
|
||||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline");
|
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
||||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||||
mqtt->connect();
|
mqtt->connect();
|
||||||
return true;
|
return true;
|
||||||
|
@ -7,8 +7,11 @@
|
|||||||
bool applyPreset(byte index, byte callMode)
|
bool applyPreset(byte index, byte callMode)
|
||||||
{
|
{
|
||||||
if (index == 0) return false;
|
if (index == 0) return false;
|
||||||
|
|
||||||
|
const char *filename = index < 255 ? "/presets.json" : "/tmp.json";
|
||||||
|
|
||||||
if (fileDoc) {
|
if (fileDoc) {
|
||||||
errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
errorFlag = readObjectFromFileUsingId(filename, index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||||
JsonObject fdo = fileDoc->as<JsonObject>();
|
JsonObject fdo = fileDoc->as<JsonObject>();
|
||||||
if (fdo["ps"] == index) fdo.remove("ps"); //remove load request for same presets to prevent recursive crash
|
if (fdo["ps"] == index) fdo.remove("ps"); //remove load request for same presets to prevent recursive crash
|
||||||
#ifdef WLED_DEBUG_FS
|
#ifdef WLED_DEBUG_FS
|
||||||
@ -17,41 +20,53 @@ bool applyPreset(byte index, byte callMode)
|
|||||||
deserializeState(fdo, callMode, index);
|
deserializeState(fdo, callMode, index);
|
||||||
} else {
|
} else {
|
||||||
DEBUGFS_PRINTLN(F("Make read buf"));
|
DEBUGFS_PRINTLN(F("Make read buf"));
|
||||||
DynamicJsonDocument fDoc(JSON_BUFFER_SIZE);
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
errorFlag = readObjectFromFileUsingId("/presets.json", index, &fDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
JsonObject fdo = fDoc.as<JsonObject>();
|
#else
|
||||||
|
if (!requestJSONBufferLock(9)) return false;
|
||||||
|
#endif
|
||||||
|
errorFlag = readObjectFromFileUsingId(filename, index, &doc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||||
|
JsonObject fdo = doc.as<JsonObject>();
|
||||||
if (fdo["ps"] == index) fdo.remove("ps");
|
if (fdo["ps"] == index) fdo.remove("ps");
|
||||||
#ifdef WLED_DEBUG_FS
|
#ifdef WLED_DEBUG_FS
|
||||||
serializeJson(fDoc, Serial);
|
serializeJson(doc, Serial);
|
||||||
#endif
|
#endif
|
||||||
deserializeState(fdo, callMode, index);
|
deserializeState(fdo, callMode, index);
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!errorFlag) {
|
if (!errorFlag) {
|
||||||
currentPreset = index;
|
if (index < 255) currentPreset = index;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//persist=false is not currently honored
|
|
||||||
void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
||||||
{
|
{
|
||||||
if (index == 0 || index > 250) return;
|
if (index == 0 || (index > 250 && persist) || (index<255 && !persist)) return;
|
||||||
bool docAlloc = (fileDoc != nullptr);
|
|
||||||
JsonObject sObj = saveobj;
|
JsonObject sObj = saveobj;
|
||||||
|
|
||||||
if (!docAlloc) {
|
const char *filename = persist ? "/presets.json" : "/tmp.json";
|
||||||
|
|
||||||
|
if (!fileDoc) {
|
||||||
DEBUGFS_PRINTLN(F("Allocating saving buffer"));
|
DEBUGFS_PRINTLN(F("Allocating saving buffer"));
|
||||||
DynamicJsonDocument lDoc(JSON_BUFFER_SIZE);
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
sObj = lDoc.to<JsonObject>();
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(10)) return;
|
||||||
|
#endif
|
||||||
|
sObj = doc.to<JsonObject>();
|
||||||
if (pname) sObj["n"] = pname;
|
if (pname) sObj["n"] = pname;
|
||||||
|
|
||||||
DEBUGFS_PRINTLN(F("Save current state"));
|
DEBUGFS_PRINTLN(F("Save current state"));
|
||||||
serializeState(sObj, true);
|
serializeState(sObj, true);
|
||||||
currentPreset = index;
|
if (persist) currentPreset = index;
|
||||||
|
|
||||||
writeObjectToFileUsingId("/presets.json", index, &lDoc);
|
writeObjectToFileUsingId(filename, index, &doc);
|
||||||
} else { //from JSON API
|
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
} else { //from JSON API (fileDoc != nullptr)
|
||||||
DEBUGFS_PRINTLN(F("Reuse recv buffer"));
|
DEBUGFS_PRINTLN(F("Reuse recv buffer"));
|
||||||
sObj.remove(F("psave"));
|
sObj.remove(F("psave"));
|
||||||
sObj.remove(F("v"));
|
sObj.remove(F("v"));
|
||||||
@ -59,7 +74,7 @@ void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
|||||||
if (!sObj["o"]) {
|
if (!sObj["o"]) {
|
||||||
DEBUGFS_PRINTLN(F("Save current state"));
|
DEBUGFS_PRINTLN(F("Save current state"));
|
||||||
serializeState(sObj, true, sObj["ib"], sObj["sb"]);
|
serializeState(sObj, true, sObj["ib"], sObj["sb"]);
|
||||||
currentPreset = index;
|
if (persist) currentPreset = index;
|
||||||
}
|
}
|
||||||
sObj.remove("o");
|
sObj.remove("o");
|
||||||
sObj.remove("ib");
|
sObj.remove("ib");
|
||||||
@ -67,9 +82,9 @@ void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
|||||||
sObj.remove(F("error"));
|
sObj.remove(F("error"));
|
||||||
sObj.remove(F("time"));
|
sObj.remove(F("time"));
|
||||||
|
|
||||||
writeObjectToFileUsingId("/presets.json", index, fileDoc);
|
writeObjectToFileUsingId(filename, index, fileDoc);
|
||||||
}
|
}
|
||||||
presetsModifiedTime = toki.second(); //unix time
|
if (persist) presetsModifiedTime = toki.second(); //unix time
|
||||||
updateFSInfo();
|
updateFSInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +433,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
//USERMODS
|
//USERMODS
|
||||||
if (subPage == 8)
|
if (subPage == 8)
|
||||||
{
|
{
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(5)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
JsonObject um = doc.createNestedObject("um");
|
JsonObject um = doc.createNestedObject("um");
|
||||||
|
|
||||||
size_t args = request->args();
|
size_t args = request->args();
|
||||||
@ -508,6 +513,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
usermods.readFromConfig(um); // force change of usermod parameters
|
usermods.readFromConfig(um); // force change of usermod parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
|
||||||
if (subPage != 2 && (subPage != 6 || !doReboot)) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
if (subPage != 2 && (subPage != 6 || !doReboot)) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||||
if (subPage == 4) alexaInit();
|
if (subPage == 4) alexaInit();
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,15 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
AsyncJsonResponse(JsonDocument *ref, bool isArray=false) : _jsonBuffer(1), _isValid{false} {
|
||||||
|
_code = 200;
|
||||||
|
_contentType = JSON_MIMETYPE;
|
||||||
|
if(isArray)
|
||||||
|
_root = ref->to<JsonArray>();
|
||||||
|
else
|
||||||
|
_root = ref->to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
AsyncJsonResponse(size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE, bool isArray=false) : _jsonBuffer(maxJsonBufferSize), _isValid{false} {
|
AsyncJsonResponse(size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE, bool isArray=false) : _jsonBuffer(maxJsonBufferSize), _isValid{false} {
|
||||||
_code = 200;
|
_code = 200;
|
||||||
_contentType = JSON_MIMETYPE;
|
_contentType = JSON_MIMETYPE;
|
||||||
@ -84,7 +93,7 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
|
|||||||
return _contentLength;
|
return _contentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getSize() { return _jsonBuffer.size(); }
|
size_t getSize() { return _root.size(); }
|
||||||
|
|
||||||
size_t _fillBuffer(uint8_t *data, size_t len){
|
size_t _fillBuffer(uint8_t *data, size_t len){
|
||||||
ChunkPrint dest(data, _sentLength, len);
|
ChunkPrint dest(data, _sentLength, len);
|
||||||
|
33
wled00/util.cpp
Normal file
33
wled00/util.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "wled.h"
|
||||||
|
#include "fcn_declare.h"
|
||||||
|
#include "const.h"
|
||||||
|
|
||||||
|
//threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994
|
||||||
|
bool requestJSONBufferLock(uint8_t module)
|
||||||
|
{
|
||||||
|
unsigned long now = millis();
|
||||||
|
|
||||||
|
while (jsonBufferLock && millis()-now < 1000) delay(1); // wait for a second for buffer lock
|
||||||
|
|
||||||
|
if (millis()-now >= 1000) {
|
||||||
|
DEBUG_PRINT(F("ERROR: Locking JSON buffer failed! ("));
|
||||||
|
DEBUG_PRINT(jsonBufferLock);
|
||||||
|
DEBUG_PRINTLN(")");
|
||||||
|
return false; // waiting time-outed
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBufferLock = module ? module : 255;
|
||||||
|
fileDoc = &doc; // used for applying presets (presets.cpp)
|
||||||
|
doc.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void releaseJSONBufferLock()
|
||||||
|
{
|
||||||
|
DEBUG_PRINT(F("JSON buffer released. ("));
|
||||||
|
DEBUG_PRINT(jsonBufferLock);
|
||||||
|
DEBUG_PRINTLN(")");
|
||||||
|
fileDoc = nullptr;
|
||||||
|
jsonBufferLock = 0;
|
||||||
|
}
|
@ -221,11 +221,16 @@ void WLED::loop()
|
|||||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||||
}
|
}
|
||||||
strip.finalizeInit();
|
strip.finalizeInit();
|
||||||
|
loadLedmap = 0;
|
||||||
if (aligned) strip.makeAutoSegments();
|
if (aligned) strip.makeAutoSegments();
|
||||||
else strip.fixInvalidSegments();
|
else strip.fixInvalidSegments();
|
||||||
yield();
|
yield();
|
||||||
serializeConfig();
|
serializeConfig();
|
||||||
}
|
}
|
||||||
|
if (loadLedmap >= 0) {
|
||||||
|
strip.deserializeMap(loadLedmap);
|
||||||
|
loadLedmap = -1;
|
||||||
|
}
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
handleWs();
|
handleWs();
|
||||||
@ -351,7 +356,9 @@ void WLED::setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_ADALIGHT
|
#ifdef WLED_ENABLE_ADALIGHT
|
||||||
if (!pinManager.isPinAllocated(3)) {
|
//Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused
|
||||||
|
//Serial TX (Debug, Improv, Serial JSON) only possible if GPIO1 unused
|
||||||
|
if (!pinManager.isPinAllocated(3) && !pinManager.isPinAllocated(1)) {
|
||||||
Serial.println(F("Ada"));
|
Serial.println(F("Ada"));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -407,6 +414,7 @@ void WLED::beginStrip()
|
|||||||
{
|
{
|
||||||
// Initialize NeoPixel Strip and button
|
// Initialize NeoPixel Strip and button
|
||||||
strip.finalizeInit(); // busses created during deserializeConfig()
|
strip.finalizeInit(); // busses created during deserializeConfig()
|
||||||
|
strip.deserializeMap();
|
||||||
strip.makeAutoSegments();
|
strip.makeAutoSegments();
|
||||||
strip.setBrightness(0);
|
strip.setBrightness(0);
|
||||||
strip.setShowCallback(handleOverlayDraw);
|
strip.setShowCallback(handleOverlayDraw);
|
||||||
|
@ -522,7 +522,7 @@ WLED_GLOBAL byte presetCycMax _INIT(5);
|
|||||||
// realtime
|
// realtime
|
||||||
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
|
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
|
||||||
WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);
|
WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);
|
||||||
WLED_GLOBAL IPAddress realtimeIP _INIT_N(((0, 0, 0, 0)));;
|
WLED_GLOBAL IPAddress realtimeIP _INIT_N(((0, 0, 0, 0)));
|
||||||
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
|
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
|
||||||
WLED_GLOBAL uint8_t tpmPacketCount _INIT(0);
|
WLED_GLOBAL uint8_t tpmPacketCount _INIT(0);
|
||||||
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
|
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
|
||||||
@ -599,10 +599,17 @@ WLED_GLOBAL BusManager busses _INIT(BusManager());
|
|||||||
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||||
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after
|
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after
|
||||||
WLED_GLOBAL bool doInitBusses _INIT(false);
|
WLED_GLOBAL bool doInitBusses _INIT(false);
|
||||||
|
WLED_GLOBAL int8_t loadLedmap _INIT(-1);
|
||||||
|
|
||||||
// Usermod manager
|
// Usermod manager
|
||||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||||
|
|
||||||
|
#ifndef WLED_USE_DYNAMIC_JSON
|
||||||
|
// global ArduinoJson buffer
|
||||||
|
WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> doc;
|
||||||
|
#endif
|
||||||
|
WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0);
|
||||||
|
|
||||||
// enable additional debug output
|
// enable additional debug output
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
|
@ -382,8 +382,13 @@ void deEEP() {
|
|||||||
|
|
||||||
DEBUG_PRINTLN(F("Preset file not found, attempting to load from EEPROM"));
|
DEBUG_PRINTLN(F("Preset file not found, attempting to load from EEPROM"));
|
||||||
DEBUGFS_PRINTLN(F("Allocating saving buffer for dEEP"));
|
DEBUGFS_PRINTLN(F("Allocating saving buffer for dEEP"));
|
||||||
DynamicJsonDocument dDoc(JSON_BUFFER_SIZE *2);
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
JsonObject sObj = dDoc.to<JsonObject>();
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(8)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JsonObject sObj = doc.to<JsonObject>();
|
||||||
sObj.createNestedObject("0");
|
sObj.createNestedObject("0");
|
||||||
|
|
||||||
EEPROM.begin(EEPSIZE);
|
EEPROM.begin(EEPSIZE);
|
||||||
@ -442,8 +447,6 @@ void deEEP() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (uint16_t index = 1; index <= 16; index++) { //copy macros to presets.json
|
for (uint16_t index = 1; index <= 16; index++) { //copy macros to presets.json
|
||||||
char m[65];
|
char m[65];
|
||||||
readStringFromEEPROM(1024+64*(index-1), m, 64);
|
readStringFromEEPROM(1024+64*(index-1), m, 64);
|
||||||
@ -463,10 +466,14 @@ void deEEP() {
|
|||||||
File f = WLED_FS.open("/presets.json", "w");
|
File f = WLED_FS.open("/presets.json", "w");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
errorFlag = ERR_FS_GENERAL;
|
errorFlag = ERR_FS_GENERAL;
|
||||||
|
releaseJSONBufferLock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
serializeJson(dDoc, f);
|
serializeJson(doc, f);
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
|
||||||
DEBUG_PRINTLN(F("deEEP complete!"));
|
DEBUG_PRINTLN(F("deEEP complete!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,18 +48,21 @@ void handleSerial()
|
|||||||
Serial.print("WLED"); Serial.write(' '); Serial.println(VERSION);
|
Serial.print("WLED"); Serial.write(' '); Serial.println(VERSION);
|
||||||
} else if (next == '{') { //JSON API
|
} else if (next == '{') { //JSON API
|
||||||
bool verboseResponse = false;
|
bool verboseResponse = false;
|
||||||
{
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(16)) return;
|
||||||
|
#endif
|
||||||
Serial.setTimeout(100);
|
Serial.setTimeout(100);
|
||||||
DeserializationError error = deserializeJson(doc, Serial);
|
DeserializationError error = deserializeJson(doc, Serial);
|
||||||
if (error) return;
|
if (error) {
|
||||||
fileDoc = &doc;
|
releaseJSONBufferLock();
|
||||||
verboseResponse = deserializeState(doc.as<JsonObject>());
|
return;
|
||||||
fileDoc = nullptr;
|
|
||||||
}
|
}
|
||||||
|
verboseResponse = deserializeState(doc.as<JsonObject>());
|
||||||
//only send response if TX pin is unused for other purposes
|
//only send response if TX pin is unused for other purposes
|
||||||
if (verboseResponse && !pinManager.isPinAllocated(1)) {
|
if (verboseResponse && !pinManager.isPinAllocated(1)) {
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
doc.clear();
|
||||||
JsonObject state = doc.createNestedObject("state");
|
JsonObject state = doc.createNestedObject("state");
|
||||||
serializeState(state);
|
serializeState(state);
|
||||||
JsonObject info = doc.createNestedObject("info");
|
JsonObject info = doc.createNestedObject("info");
|
||||||
@ -68,6 +71,7 @@ void handleSerial()
|
|||||||
serializeJson(doc, Serial);
|
serializeJson(doc, Serial);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AdaState::Header_d:
|
case AdaState::Header_d:
|
||||||
|
@ -106,11 +106,18 @@ void initServer()
|
|||||||
bool verboseResponse = false;
|
bool verboseResponse = false;
|
||||||
bool isConfig = false;
|
bool isConfig = false;
|
||||||
{ //scope JsonDocument so it releases its buffer
|
{ //scope JsonDocument so it releases its buffer
|
||||||
DynamicJsonDocument jsonBuffer(JSON_BUFFER_SIZE);
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject));
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
JsonObject root = jsonBuffer.as<JsonObject>();
|
#else
|
||||||
|
if (!requestJSONBufferLock(14)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DeserializationError error = deserializeJson(doc, (uint8_t*)(request->_tempObject));
|
||||||
|
JsonObject root = doc.as<JsonObject>();
|
||||||
if (error || root.isNull()) {
|
if (error || root.isNull()) {
|
||||||
request->send(400, "application/json", F("{\"error\":9}")); return;
|
releaseJSONBufferLock();
|
||||||
|
request->send(400, "application/json", F("{\"error\":9}"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const String& url = request->url();
|
const String& url = request->url();
|
||||||
isConfig = url.indexOf("cfg") > -1;
|
isConfig = url.indexOf("cfg") > -1;
|
||||||
@ -120,12 +127,11 @@ void initServer()
|
|||||||
serializeJson(root,Serial);
|
serializeJson(root,Serial);
|
||||||
DEBUG_PRINTLN();
|
DEBUG_PRINTLN();
|
||||||
#endif
|
#endif
|
||||||
fileDoc = &jsonBuffer; // used for applying presets (presets.cpp)
|
|
||||||
verboseResponse = deserializeState(root);
|
verboseResponse = deserializeState(root);
|
||||||
fileDoc = nullptr;
|
|
||||||
} else {
|
} else {
|
||||||
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
||||||
}
|
}
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
if (verboseResponse) {
|
if (verboseResponse) {
|
||||||
if (!isConfig) {
|
if (!isConfig) {
|
||||||
|
@ -34,11 +34,18 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
}
|
}
|
||||||
bool verboseResponse = false;
|
bool verboseResponse = false;
|
||||||
{ //scope JsonDocument so it releases its buffer
|
{ //scope JsonDocument so it releases its buffer
|
||||||
DynamicJsonDocument jsonBuffer(JSON_BUFFER_SIZE);
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DeserializationError error = deserializeJson(jsonBuffer, data, len);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
JsonObject root = jsonBuffer.as<JsonObject>();
|
#else
|
||||||
if (error || root.isNull()) return;
|
if (!requestJSONBufferLock(11)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DeserializationError error = deserializeJson(doc, data, len);
|
||||||
|
JsonObject root = doc.as<JsonObject>();
|
||||||
|
if (error || root.isNull()) {
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (root["v"] && root.size() == 1) {
|
if (root["v"] && root.size() == 1) {
|
||||||
//if the received value is just "{"v":true}", send only to this client
|
//if the received value is just "{"v":true}", send only to this client
|
||||||
verboseResponse = true;
|
verboseResponse = true;
|
||||||
@ -46,14 +53,13 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
{
|
{
|
||||||
wsLiveClientId = root["lv"] ? client->id() : 0;
|
wsLiveClientId = root["lv"] ? client->id() : 0;
|
||||||
} else {
|
} else {
|
||||||
fileDoc = &jsonBuffer;
|
|
||||||
verboseResponse = deserializeState(root);
|
verboseResponse = deserializeState(root);
|
||||||
fileDoc = nullptr;
|
|
||||||
if (!interfaceUpdateCallMode) {
|
if (!interfaceUpdateCallMode) {
|
||||||
//special case, only on playlist load, avoid sending twice in rapid succession
|
//special case, only on playlist load, avoid sending twice in rapid succession
|
||||||
if (millis() - lastInterfaceUpdate > 1700) verboseResponse = false;
|
if (millis() - lastInterfaceUpdate > 1700) verboseResponse = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
releaseJSONBufferLock(); // will clean fileDoc
|
||||||
}
|
}
|
||||||
//update if it takes longer than 300ms until next "broadcast"
|
//update if it takes longer than 300ms until next "broadcast"
|
||||||
if (verboseResponse && (millis() - lastInterfaceUpdate < 1700 || !interfaceUpdateCallMode)) sendDataWs(client);
|
if (verboseResponse && (millis() - lastInterfaceUpdate < 1700 || !interfaceUpdateCallMode)) sendDataWs(client);
|
||||||
@ -92,16 +98,23 @@ void sendDataWs(AsyncWebSocketClient * client)
|
|||||||
AsyncWebSocketMessageBuffer * buffer;
|
AsyncWebSocketMessageBuffer * buffer;
|
||||||
|
|
||||||
{ //scope JsonDocument so it releases its buffer
|
{ //scope JsonDocument so it releases its buffer
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(12)) return;
|
||||||
|
#endif
|
||||||
JsonObject state = doc.createNestedObject("state");
|
JsonObject state = doc.createNestedObject("state");
|
||||||
serializeState(state);
|
serializeState(state);
|
||||||
JsonObject info = doc.createNestedObject("info");
|
JsonObject info = doc.createNestedObject("info");
|
||||||
serializeInfo(info);
|
serializeInfo(info);
|
||||||
size_t len = measureJson(doc);
|
size_t len = measureJson(doc);
|
||||||
buffer = ws.makeBuffer(len);
|
buffer = ws.makeBuffer(len);
|
||||||
if (!buffer) return; //out of memory
|
if (!buffer) {
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return; //out of memory
|
||||||
|
}
|
||||||
serializeJson(doc, (char *)buffer->get(), len +1);
|
serializeJson(doc, (char *)buffer->get(), len +1);
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
if (client) {
|
if (client) {
|
||||||
client->text(buffer);
|
client->text(buffer);
|
||||||
|
@ -316,13 +316,22 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
{
|
{
|
||||||
char nS[8];
|
char nS[8];
|
||||||
|
|
||||||
|
// Pin reservations will become unnecessary when settings pages will read cfg.json directly
|
||||||
// add reserved and usermod pins as d.um_p array
|
// add reserved and usermod pins as d.um_p array
|
||||||
oappend(SET_F("d.um_p=[6,7,8,9,10,11"));
|
oappend(SET_F("d.um_p=[6,7,8,9,10,11"));
|
||||||
|
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
{ // scope so buffer can be released earlier
|
||||||
|
#ifdef WLED_USE_DYNAMIC_JSON
|
||||||
|
DynamicJsonDocument doc(3072);
|
||||||
|
#else
|
||||||
|
if (!requestJSONBufferLock(6)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
JsonObject mods = doc.createNestedObject(F("um"));
|
JsonObject mods = doc.createNestedObject(F("um"));
|
||||||
usermods.addToConfig(mods);
|
usermods.addToConfig(mods);
|
||||||
if (!mods.isNull()) fillUMPins(mods);
|
if (!mods.isNull()) fillUMPins(mods);
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
oappend(SET_F(",2")); // DMX hardcoded pin
|
oappend(SET_F(",2")); // DMX hardcoded pin
|
||||||
|
Loading…
Reference in New Issue
Block a user