From 7d09a3bdcd0c2041050526b1078343722e1ffcf5 Mon Sep 17 00:00:00 2001 From: stnkl Date: Thu, 24 Mar 2022 22:29:05 +0100 Subject: [PATCH] Improve config serialization --- src/Config.cpp | 44 +++++++++--- src/Config.h | 41 +++--------- src/Fade.cpp | 162 ++++++++++++++++++++++++--------------------- src/Fade.h | 8 +-- src/FastLEDHub.cpp | 7 +- src/WebSocket.cpp | 26 +------- src/Webserver.cpp | 11 +-- 7 files changed, 141 insertions(+), 158 deletions(-) diff --git a/src/Config.cpp b/src/Config.cpp index a9bedcd..1fa5752 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1,5 +1,7 @@ #include "Config.h" + #include "SerialOut.h" +#include "FastLEDHub.h" #include @@ -32,7 +34,7 @@ bool ConfigClass::initialize() bool ConfigClass::parseJson(const char *input) { - DynamicJsonDocument doc(2048); + StaticJsonDocument<1024> doc; DeserializationError error = deserializeJson(doc, input); if (doc.containsKey("timeZone")) @@ -84,7 +86,7 @@ bool ConfigClass::parseJson(const char *input) return !error; } -DynamicJsonDocument ConfigClass::getJson(DynamicJsonDocument doc) +void ConfigClass::getUserConfigJson(JsonDocument &doc) { doc["timeZone"] = timeZone; doc["summerTime"] = summerTime; @@ -109,16 +111,42 @@ DynamicJsonDocument ConfigClass::getJson(DynamicJsonDocument doc) { sliderValueArray.add(sliderValues.get(i)); } +} - return doc; +void ConfigClass::getApplicationStateJson(JsonDocument &doc) +{ + doc["status"] = String(FastLEDHub.status); + doc["currentAnimation"] = FastLEDHub.currentAnimation ? FastLEDHub.currentAnimation->getName() : ""; + JsonArray animations = doc.createNestedArray("animations"); + for (uint8_t i = 0; i < FastLEDHub.animations.size(); i++) + { + animations.add(FastLEDHub.animations.get(i)->getName()); + } + JsonArray sliders = doc.createNestedArray("sliders"); + for (uint8_t i = 0; i < FastLEDHub.sliders.size(); i++) + { + JsonObject slider = sliders.createNestedObject(); + slider["name"] = FastLEDHub.sliders.get(i)->name; + slider["min"] = FastLEDHub.sliders.get(i)->min; + slider["max"] = FastLEDHub.sliders.get(i)->max; + slider["step"] = FastLEDHub.sliders.get(i)->step; + slider["value"] = FastLEDHub.sliders.get(i)->value; + } } -String ConfigClass::getJsonString() +String ConfigClass::asString(bool includeApplicationState) { - DynamicJsonDocument doc(2048); - doc = getJson(doc); + DynamicJsonDocument doc(3072); + + getUserConfigJson(doc); + + if (includeApplicationState) + { + getApplicationStateJson(doc); + } + String buffer = ""; - serializeJson(doc, buffer); + serializeJsonPretty(doc, buffer); return buffer; } @@ -131,7 +159,7 @@ bool ConfigClass::save() return false; } - configFile.println(getJsonString()); + configFile.println(asString()); configFile.close(); return true; diff --git a/src/Config.h b/src/Config.h index 954bd08..393b354 100644 --- a/src/Config.h +++ b/src/Config.h @@ -7,48 +7,27 @@ class ConfigClass { public: - /// Time zone int8_t timeZone = 0; - /// Summer time (0 = false, 1 = true) int8_t summerTime = 0; - /// Longitude float longitude = 0; - /// Latitude float latitude = 0; - // Alarm functionality enabled bool alarmEnabled = false; - /// Alarm duration in minutes uint16_t alarmDuration = 1; - /// Alarm time hour uint8_t alarmHour = 0; - /// Alarm time minute uint8_t alarmMinute = 0; - /// Animation during alarm duration (while the brightness increases) String alarmAnimation = "Color"; - /// Animation triggered after the alarm duration has ended String postAlarmAnimation = "Color"; - /// Sunset functionality enabled bool sunsetEnabled = false; - /// Sunset duration in minutes uint16_t sunsetDuration = 1; - /// Sunset time hour int8_t sunsetHour = 0; - /// Sunset time minute int8_t sunsetMinute = 0; - /// Sunset time offset in minutes relative to the - /// automatically obtained local sunset time int16_t sunsetOffset = 0; - /// Sunset animation String sunsetAnimation = "Color"; - /// Startup animation that gets triggered when powering up the device String startupAnimation = ""; - /// Lastly used color for Color animation String color = "ffffff"; - /// Slider values LinkedList sliderValues; - /// Initialize config object by mounting file system and - /// reading the config file. + /// Initialize config object by reading the config file. /// @return True if successful bool initialize(); @@ -56,23 +35,21 @@ class ConfigClass /// @return True if successful bool save(); - /// Parse a JSON char array and apply its values to the - /// config state. + /// Parse a JSON char array and apply its values to the config. /// @param input JSON char array /// @return True if successful bool parseJson(const char *input); - /// Get config state contained in a DynamicJsonDocument - /// @return DynamicJsonDocument containing config - DynamicJsonDocument getJson(DynamicJsonDocument doc); - - /// Get config state serialized as a JSON string - /// @return JSON string - String getJsonString(); + /// Get config and (optional) application state as JSON String. + /// @param includeApplicationState Wether to include application state + /// @return JSON String + String asString(bool includeApplicationState = false); private: - /// Constant config filename const String configFilename = "/config.txt"; + + void getUserConfigJson(JsonDocument &doc); + void getApplicationStateJson(JsonDocument &doc); }; extern ConfigClass Config; diff --git a/src/Fade.cpp b/src/Fade.cpp index 55ca665..b4bbfdc 100644 --- a/src/Fade.cpp +++ b/src/Fade.cpp @@ -11,10 +11,89 @@ namespace Fade { - FadeMode mode = FadeMode::NONE; - uint16_t targetBrightness = 0; - Ticker fadeTicker; - Ticker debounce; + namespace + { + + FadeMode mode = FadeMode::NONE; + uint16_t targetBrightness = 0; + Ticker fadeTicker; + Ticker debounce; + + void tick() + { + if (FastLEDHub.status == PAUSED) + return; + + if (mode == FadeMode::ALARM && FastLEDHub.brightness10 == 1023) + { + if (Config.postAlarmAnimation != Config.alarmAnimation) + FastLEDHub.begin(FastLEDHub.getAnimation(Config.postAlarmAnimation)); + + stop(); + PRINTLN("[FastLEDHub] End fade 'Alarm'"); + } + else if (mode == FadeMode::SUNSET && FastLEDHub.brightness10 == targetBrightness) + { + stop(); + PRINTLN("[FastLEDHub] End fade 'Sunset'"); + } + else + { + FastLEDHub.brightness10++; + PRINTLN("[FastLEDHub] Fade brightness: " + String(FastLEDHub.brightness10)); + } + + FastLEDHub.brightness10 = FastLEDHub.brightness10; + } + + void getSunsetTime() + { + PRINT("[FastLEDHub] Getting sunset time..."); + + WiFiClient client; + HTTPClient http; + String url = "http://api.sunrise-sunset.org/json?lat=" + String(Config.latitude) + "&lng=" + String(Config.longitude) + "&date=today&formatted=0"; + http.begin(client, url); + String payload = ""; + if (http.GET() > 0) + payload = http.getString(); + http.end(); + + StaticJsonDocument<1024> doc; + deserializeJson(doc, payload); + if (doc.containsKey("results") && doc["results"].containsKey("sunset")) + { + String sunset = doc["results"]["sunset"].as(); + int16_t sunsetHour = (sunset.substring(11, 13).toInt() + Config.timeZone + Config.summerTime + 24) % 24; + int16_t sunsetMinute = sunset.substring(14, 16).toInt(); + int16_t minutesSinceMidnight = sunsetHour * 60 + sunsetMinute; + minutesSinceMidnight = (minutesSinceMidnight + Config.sunsetOffset + 1440) % 1440; + Config.sunsetHour = minutesSinceMidnight / 60; + Config.sunsetMinute = minutesSinceMidnight % 60; + Config.save(); + PRINTLN(" " + String(Config.sunsetHour) + ":" + String(Config.sunsetMinute)); + } + else + { + PRINTLN("failed. Using last known time instead."); + } + } + + bool getCurrentTime(int8_t *hour, int8_t *minute) + { + time_t n = time(nullptr); + + if (!n) + return false; + + tm *now = gmtime(&n); + *hour = (now->tm_hour + Config.timeZone + Config.summerTime) % 24; + *minute = now->tm_min; + + return true; + } + + } // namespace void initialize() { @@ -54,7 +133,7 @@ namespace Fade if (fadeMode == FadeMode::ALARM) { FastLEDHub.begin(FastLEDHub.getAnimation(Config.alarmAnimation)); - fadeTicker.attach_ms(Config.alarmDuration * 60 * 1000 / 1024, tick); + fadeTicker.attach_ms(Config.alarmDuration * 60 * 1000 / 1023, tick); PRINTLN("[FastLEDHub] Start fade 'Alarm'"); } else if (fadeMode == FadeMode::SUNSET) @@ -71,78 +150,9 @@ namespace Fade mode = FadeMode::NONE; } - void tick() - { - if (FastLEDHub.status == PAUSED) - return; - - if (mode == FadeMode::ALARM && FastLEDHub.brightness10 == 1023) - { - if (Config.postAlarmAnimation != Config.alarmAnimation) - FastLEDHub.begin(FastLEDHub.getAnimation(Config.postAlarmAnimation)); - - stop(); - PRINTLN("[FastLEDHub] End fade 'Alarm'"); - } - else if (mode == FadeMode::SUNSET && FastLEDHub.brightness10 == targetBrightness) - { - stop(); - PRINTLN("[FastLEDHub] End fade 'Sunset'"); - } - else - { - FastLEDHub.brightness10++; - PRINTLN("[FastLEDHub] Fade brightness: " + String(FastLEDHub.brightness10)); - } - - FastLEDHub.brightness10 = FastLEDHub.brightness10; - } - - void getSunsetTime() + FadeMode getMode() { - PRINT("[FastLEDHub] Getting sunset time..."); - - WiFiClient client; - HTTPClient http; - String url = "http://api.sunrise-sunset.org/json?lat=" + String(Config.latitude) + "&lng=" + String(Config.longitude) + "&date=today&formatted=0"; - http.begin(client, url); - String payload = ""; - if (http.GET() > 0) - payload = http.getString(); - http.end(); - - DynamicJsonDocument doc(2048); - deserializeJson(doc, payload); - if (doc.containsKey("results") && doc["results"].containsKey("sunset")) - { - String sunset = doc["results"]["sunset"].as(); - int16_t sunsetHour = (sunset.substring(11, 13).toInt() + Config.timeZone + Config.summerTime + 24) % 24; - int16_t sunsetMinute = sunset.substring(14, 16).toInt(); - int16_t minutesSinceMidnight = sunsetHour * 60 + sunsetMinute; - minutesSinceMidnight = (minutesSinceMidnight + Config.sunsetOffset + 1440) % 1440; - Config.sunsetHour = minutesSinceMidnight / 60; - Config.sunsetMinute = minutesSinceMidnight % 60; - Config.save(); - PRINTLN(" " + String(Config.sunsetHour) + ":" + String(Config.sunsetMinute)); - } - else - { - PRINTLN("failed. Using last known time instead."); - } - } - - bool getCurrentTime(int8_t *hour, int8_t *minute) - { - time_t n = time(nullptr); - - if (!n) - return false; - - tm *now = gmtime(&n); - *hour = (now->tm_hour + Config.timeZone + Config.summerTime) % 24; - *minute = now->tm_min; - - return true; + return mode; } } // namespace Fade diff --git a/src/Fade.h b/src/Fade.h index 80995a9..0b09c64 100644 --- a/src/Fade.h +++ b/src/Fade.h @@ -4,8 +4,6 @@ #include -class FastLEDHubClass; - namespace Fade { @@ -16,14 +14,10 @@ namespace Fade SUNSET }; - extern FadeMode mode; - - void tick(); void handle(); void begin(FadeMode fadeMode); void stop(); void initialize(); - void getSunsetTime(); - bool getCurrentTime(int8_t *hour, int8_t *minute); + FadeMode getMode(); } // namespace Fade diff --git a/src/FastLEDHub.cpp b/src/FastLEDHub.cpp index 11ba85e..af0fe73 100644 --- a/src/FastLEDHub.cpp +++ b/src/FastLEDHub.cpp @@ -1,8 +1,9 @@ +#include "FastLEDHub.h" + #include "Animation.h" #include "ColorUtils.h" #include "Config.h" #include "Fade.h" -#include "FastLEDHub.h" #include "SerialOut.h" #include "Webserver.h" #include "WebSocket.h" @@ -222,7 +223,7 @@ Slider *FastLEDHubClass::getSlider(uint8_t i) void FastLEDHubClass::handleInput() { - if (potentiometerPin >= 0 && Fade::mode == Fade::FadeMode::NONE) + if (potentiometerPin >= 0 && Fade::getMode() == Fade::FadeMode::NONE) { // Adjust the range slightly so low and high adc values // span the whole 10bit brightness range @@ -281,7 +282,7 @@ void FastLEDHubClass::autostart() void FastLEDHubClass::begin(Animation *animation) { - if (currentAnimation && currentAnimation->getName() == animation->getName()) + if (animation == NULL || (currentAnimation && currentAnimation->getName() == animation->getName())) return; clear(true); diff --git a/src/WebSocket.cpp b/src/WebSocket.cpp index c15cc82..2d462e1 100644 --- a/src/WebSocket.cpp +++ b/src/WebSocket.cpp @@ -79,30 +79,8 @@ namespace WebSocket break; } case 30: // Request configuration - DynamicJsonDocument doc(2048); - doc = Config.getJson(doc); - doc["status"] = String(FastLEDHub.status); - doc["currentAnimation"] = FastLEDHub.currentAnimation - ? FastLEDHub.currentAnimation->getName() - : ""; - JsonArray animations = doc.createNestedArray("animations"); - for (uint8_t i = 0; i < FastLEDHub.animations.size(); i++) - { - animations.add(FastLEDHub.animations.get(i)->getName()); - } - JsonArray sliders = doc.createNestedArray("sliders"); - for (uint8_t i = 0; i < FastLEDHub.sliders.size(); i++) - { - JsonObject slider = sliders.createNestedObject(); - slider["name"] = FastLEDHub.sliders.get(i)->name; - slider["min"] = FastLEDHub.sliders.get(i)->min; - slider["max"] = FastLEDHub.sliders.get(i)->max; - slider["step"] = FastLEDHub.sliders.get(i)->step; - slider["value"] = FastLEDHub.sliders.get(i)->value; - } - String buffer = ""; - serializeJson(doc, buffer); - WebSocket::socket.sendTXT(id, buffer.c_str()); + String config = Config.asString(true); + WebSocket::socket.sendTXT(id, config.c_str()); break; } } diff --git a/src/Webserver.cpp b/src/Webserver.cpp index 473dc84..a4d0b4b 100644 --- a/src/Webserver.cpp +++ b/src/Webserver.cpp @@ -58,16 +58,11 @@ namespace Webserver FastLEDHub.begin(FastLEDHub.getAnimation(animationName)); WebServer.send(200, "text/plain", "Started '" + animationName + "'"); } - else if (WebServer.hasArg("index")) - { - uint8_t animationIndex = WebServer.arg("index").toInt(); - if (animationIndex < FastLEDHub.animations.size()) - FastLEDHub.begin(FastLEDHub.getAnimation(animationIndex)); - WebServer.send(200, "text/plain", "Started animation #" + String(animationIndex)); - } else { - FastLEDHub.begin(FastLEDHub.getAnimation(0)); + uint8_t animationIndex = WebServer.hasArg("index") ? WebServer.arg("index").toInt() : 0; + FastLEDHub.begin(FastLEDHub.getAnimation(animationIndex)); + WebServer.send(200, "text/plain", "Started animation #" + String(animationIndex)); } }); }