Updated to ArduinoJson v6

Fixed JSON crash on core v2.5.2
This commit is contained in:
cschwinne 2019-06-21 23:12:58 +02:00
parent 117dc5288d
commit b897a8a35f
8 changed files with 5774 additions and 3479 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// AsyncJson.h // AsyncJson-v6.h
/* /*
Original file at: https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/src/AsyncJson.h Original file at: https://github.com/baggior/ESPAsyncWebServer/blob/master/src/AsyncJson.h
Only changes are ArduinoJson lib path and removed content-type check Only changes are ArduinoJson lib path and removed content-type check
Async Response to use with ArduinoJson and AsyncWebServer Async Response to use with ArduinoJson and AsyncWebServer
@ -12,9 +12,16 @@
*/ */
#ifndef ASYNC_JSON_H_ #ifndef ASYNC_JSON_H_
#define ASYNC_JSON_H_ #define ASYNC_JSON_H_
#include "ArduinoJson-v5.h" #include "ArduinoJson-v6.h"
#include <Print.h>
constexpr char* JSON_MIMETYPE = "application/json"; #if ARDUINOJSON_VERSION_MAJOR == 5
#define ARDUINOJSON_5_COMPATIBILITY
#else
#define DYNAMYC_JSON_DOCUMENT_SIZE 4096
#endif
constexpr const char* JSON_MIMETYPE = "application/json";
/* /*
* Json Response * Json Response
@ -41,14 +48,27 @@ class ChunkPrint : public Print {
} }
return 0; return 0;
} }
size_t write(const uint8_t *buffer, size_t size)
{
return this->Print::write(buffer, size);
}
}; };
class AsyncJsonResponse: public AsyncAbstractResponse { class AsyncJsonResponse: public AsyncAbstractResponse {
private: private:
#ifdef ARDUINOJSON_5_COMPATIBILITY
DynamicJsonBuffer _jsonBuffer; DynamicJsonBuffer _jsonBuffer;
#else
DynamicJsonDocument _jsonBuffer;
#endif
JsonVariant _root; JsonVariant _root;
bool _isValid; bool _isValid;
public: public:
#ifdef ARDUINOJSON_5_COMPATIBILITY
AsyncJsonResponse(bool isArray=false): _isValid{false} { AsyncJsonResponse(bool isArray=false): _isValid{false} {
_code = 200; _code = 200;
_contentType = JSON_MIMETYPE; _contentType = JSON_MIMETYPE;
@ -57,11 +77,28 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
else else
_root = _jsonBuffer.createObject(); _root = _jsonBuffer.createObject();
} }
#else
AsyncJsonResponse(size_t maxJsonBufferSize = DYNAMYC_JSON_DOCUMENT_SIZE, bool isArray=false) : _jsonBuffer(maxJsonBufferSize), _isValid{false} {
_code = 200;
_contentType = JSON_MIMETYPE;
if(isArray)
_root = _jsonBuffer.createNestedArray();
else
_root = _jsonBuffer.createNestedObject();
}
#endif
~AsyncJsonResponse() {} ~AsyncJsonResponse() {}
JsonVariant & getRoot() { return _root; } JsonVariant & getRoot() { return _root; }
bool _sourceValid() const { return _isValid; } bool _sourceValid() const { return _isValid; }
size_t setLength() { size_t setLength() {
#ifdef ARDUINOJSON_5_COMPATIBILITY
_contentLength = _root.measureLength(); _contentLength = _root.measureLength();
#else
_contentLength = measureJson(_root);
#endif
if (_contentLength) { _isValid = true; } if (_contentLength) { _isValid = true; }
return _contentLength; return _contentLength;
} }
@ -70,7 +107,12 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
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);
#ifdef ARDUINOJSON_5_COMPATIBILITY
_root.printTo( dest ) ; _root.printTo( dest ) ;
#else
serializeJson(_root, dest);
#endif
return len; return len;
} }
}; };
@ -84,9 +126,19 @@ protected:
WebRequestMethodComposite _method; WebRequestMethodComposite _method;
ArJsonRequestHandlerFunction _onRequest; ArJsonRequestHandlerFunction _onRequest;
int _contentLength; int _contentLength;
#ifndef ARDUINOJSON_5_COMPATIBILITY
const size_t maxJsonBufferSize;
#endif
int _maxContentLength; int _maxContentLength;
public: public:
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {} #ifdef ARDUINOJSON_5_COMPATIBILITY
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest)
: _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
#else
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize=DYNAMYC_JSON_DOCUMENT_SIZE)
: _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {}
#endif
void setMethod(WebRequestMethodComposite method){ _method = method; } void setMethod(WebRequestMethodComposite method){ _method = method; }
void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; } void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; }
void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; } void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; }
@ -108,14 +160,23 @@ public:
virtual void handleRequest(AsyncWebServerRequest *request) override final { virtual void handleRequest(AsyncWebServerRequest *request) override final {
if(_onRequest) { if(_onRequest) {
if (request->_tempObject != NULL) { if (request->_tempObject != NULL) {
#ifdef ARDUINOJSON_5_COMPATIBILITY
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject)); JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject));
if (json.success()) { if (json.success()) {
#else
DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize);
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject));
if(!error) {
JsonVariant json = jsonBuffer.as<JsonVariant>();
#endif
_onRequest(request, json); _onRequest(request, json);
return; return;
} }
} }
request->send(_contentLength > _maxContentLength ? 413 : 400, "{\"error\":\"Empty body\"}"); request->send(_contentLength > _maxContentLength ? 413 : 400);
} else { } else {
request->send(500); request->send(500);
} }

View File

@ -68,8 +68,8 @@
#endif #endif
#include "src/dependencies/e131/E131.h" #include "src/dependencies/e131/E131.h"
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h" #include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
#include "src/dependencies/json/AsyncJson.h" #include "src/dependencies/json/AsyncJson-v6.h"
#include "src/dependencies/json/ArduinoJson-v5.h" #include "src/dependencies/json/ArduinoJson-v6.h"
#include "html_classic.h" #include "html_classic.h"
#include "html_mobile.h" #include "html_mobile.h"
#include "html_settings.h" #include "html_settings.h"
@ -98,8 +98,8 @@
//version code in format yymmddb (b = daily build) //version code in format yymmddb (b = daily build)
#define VERSION 1906061 #define VERSION 1906201
char versionString[] = "0.8.4"; char versionString[] = "0.8.5-dev";
//AP and OTA default passwords (for maximum change them!) //AP and OTA default passwords (for maximum change them!)

View File

@ -87,16 +87,16 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
if (str == nullptr) return; if (str == nullptr) return;
str += 4; str += 4;
StaticJsonBuffer<512> jb; StaticJsonDocument<512> root;
if (str[0] == '[') //is JSON array if (str[0] == '[') //is JSON array
{ {
JsonArray& root = jb.parseArray(str); auto error = deserializeJson(root, str);
if (!root.success()) if (error)
{ {
strcpy(hueError,"JSON parsing error"); return; strcpy(hueError,"JSON parsing error"); return;
} }
int hueErrorCode = root[0]["error"]["type"];
int hueErrorCode = root[0]["error"]["type"];
if (hueErrorCode)//hue bridge returned error if (hueErrorCode)//hue bridge returned error
{ {
switch (hueErrorCode) switch (hueErrorCode)
@ -130,8 +130,8 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
if (str == nullptr) return; if (str == nullptr) return;
str = strstr(str,"{"); str = strstr(str,"{");
JsonObject& root = jb.parseObject(str); auto error = deserializeJson(root, str);
if (!root.success()) if (error)
{ {
strcpy(hueError,"JSON parsing error"); return; strcpy(hueError,"JSON parsing error"); return;
} }

View File

@ -100,7 +100,8 @@ void publishMqtt()
const char HA_static_JSON[] PROGMEM = R"=====(,"bri_val_tpl":"{{value}}","rgb_cmd_tpl":"{{'#%02x%02x%02x' | format(red, green, blue)}}","rgb_val_tpl":"{{value[1:3]|int(base=16)}},{{value[3:5]|int(base=16)}},{{value[5:7]|int(base=16)}}","qos":0,"opt":true,"pl_on":"ON","pl_off":"OFF","fx_val_tpl":"{{value}}","fx_list":[)====="; const char HA_static_JSON[] PROGMEM = R"=====(,"bri_val_tpl":"{{value}}","rgb_cmd_tpl":"{{'#%02x%02x%02x' | format(red, green, blue)}}","rgb_val_tpl":"{{value[1:3]|int(base=16)}},{{value[3:5]|int(base=16)}},{{value[5:7]|int(base=16)}}","qos":0,"opt":true,"pl_on":"ON","pl_off":"OFF","fx_val_tpl":"{{value}}","fx_list":[)=====";
void sendHADiscoveryMQTT(){ void sendHADiscoveryMQTT()
{
#if ARDUINO_ARCH_ESP32 || LEDPIN != 3 #if ARDUINO_ARCH_ESP32 || LEDPIN != 3
/* /*
@ -148,8 +149,7 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
strcat(bufg, "/g"); strcat(bufg, "/g");
strcat(bufapi, "/api"); strcat(bufapi, "/api");
StaticJsonBuffer<JSON_OBJECT_SIZE(9) +512> jsonBuffer; StaticJsonDocument<JSON_OBJECT_SIZE(9) +512> root;
JsonObject& root = jsonBuffer.createObject();
root["name"] = serverDescription; root["name"] = serverDescription;
root["stat_t"] = bufc; root["stat_t"] = bufc;
root["cmd_t"] = mqttDeviceTopic; root["cmd_t"] = mqttDeviceTopic;
@ -160,10 +160,9 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
root["fx_cmd_t"] = bufapi; root["fx_cmd_t"] = bufapi;
root["fx_stat_t"] = bufapi; root["fx_stat_t"] = bufapi;
size_t jlen = root.measureLength(); size_t jlen = measureJson(root);
char pubt[21 + sizeof(serverDescription) + 8];
DEBUG_PRINTLN(jlen); DEBUG_PRINTLN(jlen);
root.printTo(buffer, jlen); serializeJson(root, buffer, jlen);
//add values which don't change //add values which don't change
strcpy_P(buffer + jlen -1, HA_static_JSON); strcpy_P(buffer + jlen -1, HA_static_JSON);
@ -206,6 +205,7 @@ Send out HA MQTT Discovery message on MQTT connect (~2.4kB):
DEBUG_PRINT("HA Discovery Sending >>"); DEBUG_PRINT("HA Discovery Sending >>");
DEBUG_PRINTLN(buffer); DEBUG_PRINTLN(buffer);
char pubt[25 + 12 + 8];
strcpy(pubt, "homeassistant/light/WLED_"); strcpy(pubt, "homeassistant/light/WLED_");
strcat(pubt, escapedMac.c_str()); strcat(pubt, escapedMac.c_str());
strcat(pubt, "/config"); strcat(pubt, "/config");

View File

@ -71,8 +71,8 @@ void initServer()
}); });
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/json", [](AsyncWebServerRequest *request, JsonVariant &json) { AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/json", [](AsyncWebServerRequest *request, JsonVariant &json) {
JsonObject& root = json.as<JsonObject>(); JsonObject root = json.to<JsonObject>();
if (!root.success()){request->send(500, "application/json", "{\"error\":\"Parsing failed\"}"); return;} if (root.isNull()){request->send(500, "application/json", "{\"error\":\"Parsing failed\"}"); return;}
if (deserializeState(root)) { serveJson(request); return; } //if JSON contains "v" (verbose response) if (deserializeState(root)) { serveJson(request); return; } //if JSON contains "v" (verbose response)
request->send(200, "application/json", "{\"success\":true}"); request->send(200, "application/json", "{\"success\":true}");
}); });

View File

@ -2,7 +2,7 @@
* JSON API (De)serialization * JSON API (De)serialization
*/ */
bool deserializeState(JsonObject& root) bool deserializeState(JsonObject root)
{ {
bool stateResponse = root["v"] | false; bool stateResponse = root["v"] | false;
@ -23,13 +23,13 @@ bool deserializeState(JsonObject& root)
int cy = root["pl"] | -1; int cy = root["pl"] | -1;
presetCyclingEnabled = (cy >= 0); presetCyclingEnabled = (cy >= 0);
JsonObject& nl = root["nl"]; JsonObject nl = root["nl"];
nightlightActive = nl["on"] | nightlightActive; nightlightActive = nl["on"] | nightlightActive;
nightlightDelayMins = nl["dur"] | nightlightDelayMins; nightlightDelayMins = nl["dur"] | nightlightDelayMins;
nightlightFade = nl["fade"] | nightlightFade; nightlightFade = nl["fade"] | nightlightFade;
nightlightTargetBri = nl["tbri"] | nightlightTargetBri; nightlightTargetBri = nl["tbri"] | nightlightTargetBri;
JsonObject& udpn = root["udpn"]; JsonObject udpn = root["udpn"];
notifyDirect = udpn["send"] | notifyDirect; notifyDirect = udpn["send"] | notifyDirect;
receiveNotifications = udpn["recv"] | receiveNotifications; receiveNotifications = udpn["recv"] | receiveNotifications;
bool noNotification = udpn["nn"]; //send no notification just for this request bool noNotification = udpn["nn"]; //send no notification just for this request
@ -38,8 +38,8 @@ bool deserializeState(JsonObject& root)
if (timein != -1) setTime(timein); if (timein != -1) setTime(timein);
int it = 0; int it = 0;
JsonArray& segs = root["seg"]; JsonArray segs = root["seg"];
for (JsonObject& elem : segs) for (JsonObject elem : segs)
{ {
byte id = elem["id"] | it; byte id = elem["id"] | it;
if (id < strip.getMaxSegments()) if (id < strip.getMaxSegments())
@ -54,18 +54,18 @@ bool deserializeState(JsonObject& root)
} }
strip.setSegment(id, start, stop); strip.setSegment(id, start, stop);
JsonArray& colarr = elem["col"]; JsonArray colarr = elem["col"];
if (colarr.success()) if (!colarr.isNull())
{ {
for (uint8_t i = 0; i < 3; i++) for (uint8_t i = 0; i < 3; i++)
{ {
JsonArray& colX = colarr[i]; JsonArray colX = colarr[i];
if (!colX.success()) break; if (colX.isNull()) break;
byte sz = colX.size(); byte sz = colX.size();
if (sz > 0 && sz < 5) if (sz > 0 && sz < 5)
{ {
int rgbw[] = {0,0,0,0}; int rgbw[] = {0,0,0,0};
byte cp = colX.copyTo(rgbw); byte cp = copyArray(colX, rgbw);
seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))); seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0; if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0;
if (id == 0) //temporary if (id == 0) //temporary
@ -101,7 +101,7 @@ bool deserializeState(JsonObject& root)
return stateResponse; return stateResponse;
} }
void serializeState(JsonObject& root) void serializeState(JsonObject root)
{ {
root["on"] = (bri > 0); root["on"] = (bri > 0);
root["bri"] = briLast; root["bri"] = briLast;
@ -110,23 +110,23 @@ void serializeState(JsonObject& root)
root["ps"] = -1; // root["ps"] = -1; //
root["pl"] = (presetCyclingEnabled) ? 0: -1; root["pl"] = (presetCyclingEnabled) ? 0: -1;
JsonObject& nl = root.createNestedObject("nl"); JsonObject nl = root.createNestedObject("nl");
nl["on"] = nightlightActive; nl["on"] = nightlightActive;
nl["dur"] = nightlightDelayMins; nl["dur"] = nightlightDelayMins;
nl["fade"] = nightlightFade; nl["fade"] = nightlightFade;
nl["tbri"] = nightlightTargetBri; nl["tbri"] = nightlightTargetBri;
JsonObject& udpn = root.createNestedObject("udpn"); JsonObject udpn = root.createNestedObject("udpn");
udpn["send"] = notifyDirect; udpn["send"] = notifyDirect;
udpn["recv"] = receiveNotifications; udpn["recv"] = receiveNotifications;
JsonArray& seg = root.createNestedArray("seg"); JsonArray seg = root.createNestedArray("seg");
for (byte s = 0; s < strip.getMaxSegments(); s++) for (byte s = 0; s < strip.getMaxSegments(); s++)
{ {
WS2812FX::Segment sg = strip.getSegment(s); WS2812FX::Segment sg = strip.getSegment(s);
if (sg.isActive()) if (sg.isActive())
{ {
JsonObject& seg0 = seg.createNestedObject(); JsonObject seg0 = seg.createNestedObject();
serializeSegment(seg0, sg, s); serializeSegment(seg0, sg, s);
} }
} }
@ -139,11 +139,11 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
root["stop"] = seg.stop; root["stop"] = seg.stop;
root["len"] = seg.stop - seg.start; root["len"] = seg.stop - seg.start;
JsonArray& colarr = root.createNestedArray("col"); JsonArray colarr = root.createNestedArray("col");
for (uint8_t i = 0; i < 3; i++) for (uint8_t i = 0; i < 3; i++)
{ {
JsonArray& colX = colarr.createNestedArray(); JsonArray colX = colarr.createNestedArray();
colX.add((seg.colors[i] >> 16) & 0xFF); colX.add((seg.colors[i] >> 16) & 0xFF);
colX.add((seg.colors[i] >> 8) & 0xFF); colX.add((seg.colors[i] >> 8) & 0xFF);
colX.add((seg.colors[i] ) & 0xFF); colX.add((seg.colors[i] ) & 0xFF);
@ -160,15 +160,15 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
root["cln"] = -1; root["cln"] = -1;
} }
void serializeInfo(JsonObject& root) void serializeInfo(JsonObject root)
{ {
root["ver"] = versionString; root["ver"] = versionString;
root["vid"] = VERSION; root["vid"] = VERSION;
JsonObject& leds = root.createNestedObject("leds"); JsonObject leds = root.createNestedObject("leds");
leds["count"] = ledCount; leds["count"] = ledCount;
leds["rgbw"] = useRGBW; leds["rgbw"] = useRGBW;
JsonArray& leds_pin = leds.createNestedArray("pin"); JsonArray leds_pin = leds.createNestedArray("pin");
leds_pin.add(LEDPIN); leds_pin.add(LEDPIN);
leds["pwr"] = strip.currentMilliamps; leds["pwr"] = strip.currentMilliamps;
@ -245,7 +245,7 @@ void serveJson(AsyncWebServerRequest* request)
} }
AsyncJsonResponse* response = new AsyncJsonResponse(); AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject& doc = response->getRoot(); JsonObject doc = response->getRoot();
switch (subJson) switch (subJson)
{ {
@ -254,12 +254,12 @@ void serveJson(AsyncWebServerRequest* request)
case 2: //info case 2: //info
serializeInfo(doc); break; serializeInfo(doc); break;
default: //all default: //all
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);
doc["effects"] = RawJson(String(JSON_mode_names)); doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names);
doc["palettes"] = RawJson(String(JSON_palette_names)); doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names);
} }
response->setLength(); response->setLength();