From 65bbe7630ed59f830cdb6be113967e3087b1edac Mon Sep 17 00:00:00 2001 From: Marvin Roger Date: Fri, 19 Aug 2016 20:11:14 +0200 Subject: [PATCH] Implement settable configuration and fix #36 --- src/Homie/Boot/BootNormal.cpp | 13 ++++++-- src/Homie/Config.cpp | 61 +++++++++++++++++++++++++++++++++++ src/Homie/Config.hpp | 1 + 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/Homie/Boot/BootNormal.cpp b/src/Homie/Boot/BootNormal.cpp index fa865228..c9334221 100644 --- a/src/Homie/Boot/BootNormal.cpp +++ b/src/Homie/Boot/BootNormal.cpp @@ -248,9 +248,16 @@ void BootNormal::_onMqttMessage(char* topic, char* payload, uint8_t qos, size_t return; } - /*if (strcmp_P(topic, PSTR("$implementation/config/set")) == 0) { - - }*/ + if (strcmp_P(topic, PSTR("$implementation/config/set")) == 0) { + if (_interface->config->patch(_mqttPayloadBuffer.get())) { + _interface->logger->logln(F("✔ Configuration updated")); + _flaggedForReboot = true; + _interface->logger->logln(F("Flagged for reboot")); + } else { + _interface->logger->logln(F("✖ Configuration not updated")); + } + return; + } // Implicit node properties topic[strlen(topic) - 4] = '\0'; // Remove /set diff --git a/src/Homie/Config.cpp b/src/Homie/Config.cpp index 6bdfff86..68dcb722 100644 --- a/src/Homie/Config.cpp +++ b/src/Homie/Config.cpp @@ -196,6 +196,67 @@ void Config::write(const char* config) { configFile.close(); } +bool Config::patch(const char* patch) { + if (!_spiffsBegin()) { return false; } + + StaticJsonBuffer patchJsonBuffer; + JsonObject& patchObject = patchJsonBuffer.parseObject(patch); + + if (!patchObject.success()) { + _interface->logger->logln(F("✖ Invalid or too big JSON")); + return false; + } + + File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r"); + if (!configFile) { + _interface->logger->logln(F("✖ Cannot open config file")); + return false; + } + + size_t configSize = configFile.size(); + + char configJson[MAX_JSON_CONFIG_FILE_SIZE]; + configFile.readBytes(configJson, configSize); + configFile.close(); + + StaticJsonBuffer configJsonBuffer; + JsonObject& configObject = configJsonBuffer.parseObject(configJson); + + for (JsonObject::iterator it = patchObject.begin(); it != patchObject.end(); ++it) { + if (patchObject[it->key].is()) { + JsonObject& subObject = patchObject[it->key].as(); + for (JsonObject::iterator it2 = subObject.begin(); it2 != subObject.end(); ++it2) { + if (!configObject.containsKey(it->key) || !configObject[it->key].is()) { + String error = "✖ Config does not contain a "; + error.concat(it->key); + error.concat(" object"); + _interface->logger->logln(error); + return false; + } + JsonObject& subConfigObject = configObject[it->key].as(); + subConfigObject[it2->key] = it2->value; + } + } else { + configObject[it->key] = it->value; + } + } + + ConfigValidationResult configValidationResult = Helpers::validateConfig(configObject); + if (!configValidationResult.valid) { + _interface->logger->log(F("✖ Config file is not valid, reason: ")); + _interface->logger->logln(configValidationResult.reason); + return false; + } + + size_t finalBufferLength = configObject.measureLength() + 1; + std::unique_ptr finalConfigString(new char[finalBufferLength]); + configObject.printTo(finalConfigString.get(), finalBufferLength); + + write(finalConfigString.get()); + + return true; +} + BootMode Config::getBootMode() const { return _bootMode; } diff --git a/src/Homie/Config.hpp b/src/Homie/Config.hpp index fe258f22..b3bba10c 100644 --- a/src/Homie/Config.hpp +++ b/src/Homie/Config.hpp @@ -21,6 +21,7 @@ class Config { char* getSafeConfigFile() const; void erase(); void write(const char* config); + bool patch(const char* patch); BootMode getBootMode() const; void log() const; // print the current config to log output