Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to ArduinoJson version 6 #622

Merged
merged 1 commit into from
Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"dependencies": [
{
"name": "ArduinoJson",
"version": "^5.10.0"
"version": "^6.11.4"
},
{
"name": "AsyncMqttClient",
Expand Down
82 changes: 44 additions & 38 deletions src/Homie/Boot/BootConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ void BootConfig::loop() {

void BootConfig::_onWifiConnectRequest(AsyncWebServerRequest *request) {
Interface::get().getLogger() << F("Received Wi-Fi connect request") << endl;
DynamicJsonBuffer parseJsonBuffer(JSON_OBJECT_SIZE(2));
const char* body = (const char*)(request->_tempObject);
JsonObject& parsedJson = parseJsonBuffer.parseObject(body);
if (!parsedJson.success()) {
StaticJsonDocument<JSON_OBJECT_SIZE(2)> parseJsonDoc;
char* body = reinterpret_cast<char*>(request->_tempObject);
if (deserializeJson(parseJsonDoc, body) != DeserializationError::Ok || !parseJsonDoc.is<JsonObject>()) {
__SendJSONError(request, F("✖ Invalid or too big JSON"));
return;
}

JsonObject parsedJson = parseJsonDoc.as<JsonObject>();
if (!parsedJson.containsKey("ssid") || !parsedJson["ssid"].is<const char*>() || !parsedJson.containsKey("password") || !parsedJson["password"].is<const char*>()) {
__SendJSONError(request, F("✖ SSID and password required"));
return;
Expand All @@ -143,11 +143,11 @@ void BootConfig::_onWifiConnectRequest(AsyncWebServerRequest *request) {
void BootConfig::_onWifiStatusRequest(AsyncWebServerRequest *request) {
Interface::get().getLogger() << F("Received Wi-Fi status request") << endl;

DynamicJsonBuffer generatedJsonBuffer(JSON_OBJECT_SIZE(2));
JsonObject& json = generatedJsonBuffer.createObject();
// Includes memory to duplicate strings for status ("no_ssid_available" -> 18) and local_ip (IPv4 -> 16)
StaticJsonDocument<JSON_OBJECT_SIZE(2) + 18 + 16> generatedJsonDoc;
JsonObject json = generatedJsonDoc.to<JsonObject>();
String status;

//String json = "";
switch (WiFi.status()) {
case WL_IDLE_STATUS:
status = F("idle");
Expand Down Expand Up @@ -175,21 +175,21 @@ void BootConfig::_onWifiStatusRequest(AsyncWebServerRequest *request) {

json["status"] = status;
String output;
json.printTo(output);
serializeJson(generatedJsonDoc, output);

request->send(200, FPSTR(PROGMEM_CONFIG_APPLICATION_JSON), output);
}

void BootConfig::_onProxyControlRequest(AsyncWebServerRequest *request) {
Interface::get().getLogger() << F("Received proxy control request") << endl;
DynamicJsonBuffer parseJsonBuffer(JSON_OBJECT_SIZE(1));
const char* body = (const char*)(request->_tempObject);
JsonObject& parsedJson = parseJsonBuffer.parseObject(body); // do not use plain String, else fails
if (!parsedJson.success()) {
StaticJsonDocument<JSON_OBJECT_SIZE(1)> parseJsonDoc;
char* body = reinterpret_cast<char*>(request->_tempObject);
if (deserializeJson(parseJsonDoc, body) != DeserializationError::Ok || !parseJsonDoc.is<JsonObject>()) {
__SendJSONError(request, F("✖ Invalid or too big JSON"));
return;
}

JsonObject parsedJson = parseJsonDoc.as<JsonObject>();
if (!parsedJson.containsKey("enable") || !parsedJson["enable"].is<bool>()) {
__SendJSONError(request, F("✖ enable parameter is required"));
return;
Expand All @@ -201,12 +201,16 @@ void BootConfig::_onProxyControlRequest(AsyncWebServerRequest *request) {
}

void BootConfig::_generateNetworksJson() {
DynamicJsonBuffer generatedJsonBuffer(JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(_ssidCount) + (_ssidCount * JSON_OBJECT_SIZE(3))); // 1 at root, 3 in childrend
JsonObject& json = generatedJsonBuffer.createObject();

JsonArray& networks = json.createNestedArray("networks");
DynamicJsonDocument generatedJsonDoc(
JSON_OBJECT_SIZE(1) + // Root object
JSON_ARRAY_SIZE(_ssidCount) + // Array "networks"
_ssidCount * JSON_OBJECT_SIZE(3) + // Objects in "networks"
_ssidCount * (32 + 1)); // SSID strings are duplicated and take up to 32 bytes + terminator
JsonObject json = generatedJsonDoc.to<JsonObject>();

JsonArray networks = json.createNestedArray("networks");
for (int network = 0; network < _ssidCount; network++) {
JsonObject& jsonNetwork = generatedJsonBuffer.createObject();
JsonObject jsonNetwork = networks.createNestedObject();
jsonNetwork["ssid"] = WiFi.SSID(network);
jsonNetwork["rssi"] = WiFi.RSSI(network);
#ifdef ESP32
Expand Down Expand Up @@ -249,12 +253,10 @@ void BootConfig::_generateNetworksJson() {
break;
}
#endif // ESP32

networks.add(jsonNetwork);
}

String output;
json.printTo(output);
serializeJson(generatedJsonDoc, output);
_jsonWifiNetworks = output;
}

Expand Down Expand Up @@ -320,7 +322,7 @@ void BootConfig::_proxyHttpRequest(AsyncWebServerRequest *request) {
}

Interface::get().getLogger() << F("Proxy sent request to destination") << endl;
const char* body = (const char*)(request->_tempObject);
const char* body = reinterpret_cast<const char*>(request->_tempObject);
int _httpCode = _httpClient.sendRequest(method.c_str(), body);
Interface::get().getLogger() << F("Destination response code = ") << _httpCode << endl;

Expand All @@ -339,25 +341,30 @@ void BootConfig::_onDeviceInfoRequest(AsyncWebServerRequest *request) {
Interface::get().getLogger() << F("Received device information request") << endl;
auto numSettings = IHomieSetting::settings.size();
auto numNodes = HomieNode::nodes.size();
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(2) + JSON_ARRAY_SIZE(numNodes) + (numNodes * JSON_OBJECT_SIZE(2)) + JSON_ARRAY_SIZE(numSettings) + (numSettings * JSON_OBJECT_SIZE(5)));
JsonObject& json = jsonBuffer.createObject();
DynamicJsonDocument jsonDoc(
JSON_OBJECT_SIZE(5) + // Root object
JSON_OBJECT_SIZE(2) + // Object "firmware"
JSON_ARRAY_SIZE(numNodes) + // Array "nodes"
JSON_OBJECT_SIZE(2) * numNodes + // Objects in "nodes"
JSON_ARRAY_SIZE(numSettings) + // Array "settings"
numSettings * JSON_OBJECT_SIZE(5)); // Objects in "settings"
JsonObject json = jsonDoc.to<JsonObject>();
json["hardware_device_id"] = DeviceId::get();
json["homie_esp8266_version"] = HOMIE_ESP8266_VERSION;
JsonObject& firmware = json.createNestedObject("firmware");
firmware["name"] = Interface::get().firmware.name;
firmware["version"] = Interface::get().firmware.version;
JsonObject firmware = json.createNestedObject("firmware");
firmware["name"] = reinterpret_cast<const char*>(Interface::get().firmware.name);
firmware["version"] = reinterpret_cast<const char*>(Interface::get().firmware.version);

JsonArray& nodes = json.createNestedArray("nodes");
JsonArray nodes = json.createNestedArray("nodes");
for (HomieNode* iNode : HomieNode::nodes) {
JsonObject& jsonNode = jsonBuffer.createObject();
JsonObject jsonNode = nodes.createNestedObject();
jsonNode["id"] = iNode->getId();
jsonNode["type"] = iNode->getType();
nodes.add(jsonNode);
}

JsonArray& settings = json.createNestedArray("settings");
JsonArray settings = json.createNestedArray("settings");
for (IHomieSetting* iSetting : IHomieSetting::settings) {
JsonObject& jsonSetting = jsonBuffer.createObject();
JsonObject jsonSetting = settings.createNestedObject();

if (strcmp(iSetting->getType(), "unknown") != 0) {
jsonSetting["name"] = iSetting->getName();
Expand All @@ -381,12 +388,10 @@ void BootConfig::_onDeviceInfoRequest(AsyncWebServerRequest *request) {
}
}
}

settings.add(jsonSetting);
}

String output;
json.printTo(output);
serializeJson(jsonDoc, output);

request->send(200, FPSTR(PROGMEM_CONFIG_APPLICATION_JSON), output);
}
Expand All @@ -407,14 +412,15 @@ void BootConfig::_onConfigRequest(AsyncWebServerRequest *request) {
return;
}

DynamicJsonBuffer parseJsonBuffer(MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE);
const char* body = (const char*)(request->_tempObject);
JsonObject& parsedJson = parseJsonBuffer.parseObject(body);
if (!parsedJson.success()) {
DynamicJsonDocument parseJsonDoc(MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE);
char* body = reinterpret_cast<char*>(request->_tempObject);
if (deserializeJson(parseJsonDoc, body) != DeserializationError::Ok || !parseJsonDoc.is<JsonObject>()) {
__SendJSONError(request, F("✖ Invalid or too big JSON"));
return;
}

JsonObject parsedJson = parseJsonDoc.as<JsonObject>();

ConfigValidationResult configValidationResult = Validation::validateConfig(parsedJson);
if (!configValidationResult.valid) {
__SendJSONError(request, String(F("✖ Config file is not valid, reason: ")) + configValidationResult.reason);
Expand Down
84 changes: 42 additions & 42 deletions src/Homie/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ bool Config::load() {
configFile.close();
buf[configSize] = '\0';

StaticJsonBuffer<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> jsonBuffer;
JsonObject& parsedJson = jsonBuffer.parseObject(buf);
if (!parsedJson.success()) {
StaticJsonDocument<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> jsonDoc;
if (deserializeJson(jsonDoc, buf) != DeserializationError::Ok || !jsonDoc.is<JsonObject>()) {
Interface::get().getLogger() << F("✖ Invalid JSON in the config file") << endl;
return false;
}

JsonObject parsedJson = jsonDoc.as<JsonObject>();
ConfigValidationResult configValidationResult = Validation::validateConfig(parsedJson);
if (!configValidationResult.valid) {
Interface::get().getLogger() << F("✖ Config file is not valid, reason: ") << configValidationResult.reason << endl;
Expand All @@ -77,65 +77,65 @@ bool Config::load() {
}

const char* reqWifiBssid = "";
if (parsedJson["wifi"].as<JsonObject&>().containsKey("bssid")) {
if (parsedJson["wifi"].as<JsonObject>().containsKey("bssid")) {
reqWifiBssid = parsedJson["wifi"]["bssid"];
}
uint16_t reqWifiChannel = 0;
if (parsedJson["wifi"].as<JsonObject&>().containsKey("channel")) {
if (parsedJson["wifi"].as<JsonObject>().containsKey("channel")) {
reqWifiChannel = parsedJson["wifi"]["channel"];
}
const char* reqWifiIp = "";
if (parsedJson["wifi"].as<JsonObject&>().containsKey("ip")) {
if (parsedJson["wifi"].as<JsonObject>().containsKey("ip")) {
reqWifiIp = parsedJson["wifi"]["ip"];
}
const char* reqWifiMask = "";
if (parsedJson["wifi"].as<JsonObject&>().containsKey("mask")) {
if (parsedJson["wifi"].as<JsonObject>().containsKey("mask")) {
reqWifiMask = parsedJson["wifi"]["mask"];
}
const char* reqWifiGw = "";
if (parsedJson["wifi"].as<JsonObject&>().containsKey("gw")) {
if (parsedJson["wifi"].as<JsonObject>().containsKey("gw")) {
reqWifiGw = parsedJson["wifi"]["gw"];
}
const char* reqWifiDns1 = "";
if (parsedJson["wifi"].as<JsonObject&>().containsKey("dns1")) {
if (parsedJson["wifi"].as<JsonObject>().containsKey("dns1")) {
reqWifiDns1 = parsedJson["wifi"]["dns1"];
}
const char* reqWifiDns2 = "";
if (parsedJson["wifi"].as<JsonObject&>().containsKey("dns2")) {
if (parsedJson["wifi"].as<JsonObject>().containsKey("dns2")) {
reqWifiDns2 = parsedJson["wifi"]["dns2"];
}

uint16_t reqMqttPort = DEFAULT_MQTT_PORT;
if (parsedJson["mqtt"].as<JsonObject&>().containsKey("port")) {
if (parsedJson["mqtt"].as<JsonObject>().containsKey("port")) {
reqMqttPort = parsedJson["mqtt"]["port"];
}
bool reqMqttSsl = false;
if (parsedJson["mqtt"].as<JsonObject&>().containsKey("ssl")) {
if (parsedJson["mqtt"].as<JsonObject>().containsKey("ssl")) {
reqMqttSsl = parsedJson["mqtt"]["ssl"];
}
const char* reqMqttFingerprint = "";
if (parsedJson["mqtt"].as<JsonObject&>().containsKey("ssl_fingerprint")) {
if (parsedJson["mqtt"].as<JsonObject>().containsKey("ssl_fingerprint")) {
reqMqttFingerprint = parsedJson["mqtt"]["ssl_fingerprint"];
}
const char* reqMqttBaseTopic = DEFAULT_MQTT_BASE_TOPIC;
if (parsedJson["mqtt"].as<JsonObject&>().containsKey("base_topic")) {
if (parsedJson["mqtt"].as<JsonObject>().containsKey("base_topic")) {
reqMqttBaseTopic = parsedJson["mqtt"]["base_topic"];
}
bool reqMqttAuth = false;
if (parsedJson["mqtt"].as<JsonObject&>().containsKey("auth")) {
if (parsedJson["mqtt"].as<JsonObject>().containsKey("auth")) {
reqMqttAuth = parsedJson["mqtt"]["auth"];
}
const char* reqMqttUsername = "";
if (parsedJson["mqtt"].as<JsonObject&>().containsKey("username")) {
if (parsedJson["mqtt"].as<JsonObject>().containsKey("username")) {
reqMqttUsername = parsedJson["mqtt"]["username"];
}
const char* reqMqttPassword = "";
if (parsedJson["mqtt"].as<JsonObject&>().containsKey("password")) {
if (parsedJson["mqtt"].as<JsonObject>().containsKey("password")) {
reqMqttPassword = parsedJson["mqtt"]["password"];
}

bool reqOtaEnabled = false;
if (parsedJson["ota"].as<JsonObject&>().containsKey("enabled")) {
if (parsedJson["ota"].as<JsonObject>().containsKey("enabled")) {
reqOtaEnabled = parsedJson["ota"]["enabled"];
}

Expand Down Expand Up @@ -168,7 +168,7 @@ bool Config::load() {

/* Parse the settings */

JsonObject& settingsObject = parsedJson["settings"].as<JsonObject&>();
JsonObject settingsObject = parsedJson["settings"].as<JsonObject>();

for (IHomieSetting* iSetting : IHomieSetting::settings) {
if (iSetting->isBool()) {
Expand Down Expand Up @@ -211,16 +211,16 @@ char* Config::getSafeConfigFile() const {
configFile.close();
buf[configSize] = '\0';

StaticJsonBuffer<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> jsonBuffer;
JsonObject& parsedJson = jsonBuffer.parseObject(buf);
parsedJson["wifi"].as<JsonObject&>().remove("password");
parsedJson["mqtt"].as<JsonObject&>().remove("username");
parsedJson["mqtt"].as<JsonObject&>().remove("password");
StaticJsonDocument<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> jsonDoc;
deserializeJson(jsonDoc, buf);
JsonObject parsedJson = jsonDoc.as<JsonObject>();
parsedJson["wifi"].as<JsonObject>().remove("password");
parsedJson["mqtt"].as<JsonObject>().remove("username");
parsedJson["mqtt"].as<JsonObject>().remove("password");

size_t jsonBufferLength = parsedJson.measureLength() + 1;
size_t jsonBufferLength = measureJson(jsonDoc) + 1;
std::unique_ptr<char[]> jsonString(new char[jsonBufferLength]);
parsedJson.printTo(jsonString.get(), jsonBufferLength);

serializeJson(jsonDoc, jsonString.get(), jsonBufferLength);
return strdup(jsonString.get());
}

Expand Down Expand Up @@ -262,7 +262,7 @@ HomieBootMode Config::getHomieBootModeOnNextBoot() {
}
}

void Config::write(const JsonObject& config) {
void Config::write(const JsonObject config) {
if (!_spiffsBegin()) { return; }

SPIFFS.remove(CONFIG_FILE_PATH);
Expand All @@ -272,22 +272,21 @@ void Config::write(const JsonObject& config) {
Interface::get().getLogger() << F("✖ Cannot open config file") << endl;
return;
}

config.printTo(configFile);
serializeJson(config, configFile);
configFile.close();
}

bool Config::patch(const char* patch) {
if (!_spiffsBegin()) { return false; }

StaticJsonBuffer<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> patchJsonBuffer;
JsonObject& patchObject = patchJsonBuffer.parseObject(patch);
StaticJsonDocument<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> patchJsonDoc;

if (!patchObject.success()) {
if (deserializeJson(patchJsonDoc, patch) != DeserializationError::Ok || !patchJsonDoc.is<JsonObject>()) {
Interface::get().getLogger() << F("✖ Invalid or too big JSON") << endl;
return false;
}

JsonObject patchObject = patchJsonDoc.as<JsonObject>();
File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r");
if (!configFile) {
Interface::get().getLogger() << F("✖ Cannot open config file") << endl;
Expand All @@ -301,27 +300,28 @@ bool Config::patch(const char* patch) {
configFile.close();
configJson[configSize] = '\0';

StaticJsonBuffer<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> configJsonBuffer;
JsonObject& configObject = configJsonBuffer.parseObject(configJson);
StaticJsonDocument<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> configJsonDoc;
deserializeJson(configJsonDoc, configJson);
JsonObject configObject = configJsonDoc.as<JsonObject>();

// To do alow object that dont currently exist to be added like settings.
// if settings wasnt there origionally then it should be allowed to be added by incremental.
for (JsonObject::iterator it = patchObject.begin(); it != patchObject.end(); ++it) {
if (patchObject[it->key].is<JsonObject&>()) {
JsonObject& subObject = patchObject[it->key].as<JsonObject&>();
if (patchObject[it->key()].is<JsonObject>()) {
JsonObject subObject = patchObject[it->key()].as<JsonObject>();
for (JsonObject::iterator it2 = subObject.begin(); it2 != subObject.end(); ++it2) {
if (!configObject.containsKey(it->key) || !configObject[it->key].is<JsonObject&>()) {
if (!configObject.containsKey(it->key()) || !configObject[it->key()].is<JsonObject>()) {
String error = "✖ Config does not contain a ";
error.concat(it->key);
error.concat(it->key().c_str());
error.concat(" object");
Interface::get().getLogger() << error << endl;
return false;
}
JsonObject& subConfigObject = configObject[it->key].as<JsonObject&>();
subConfigObject[it2->key] = it2->value;
JsonObject subConfigObject = configObject[it->key()].as<JsonObject>();
subConfigObject[it2->key()] = it2->value();
}
} else {
configObject[it->key] = it->value;
configObject[it->key()] = it->value();
}
}

Expand Down
Loading