2 #include "AsyncHTTPRequest_Generic.h"
 
   4 #include <ArduinoJson.h>
 
   6 Ticker* weatherTicker = nullptr;
 
   7 AsyncHTTPRequest request;
 
  11 void executeWeatherRequest();
 
  13 void IterateJson(JsonVariant json, const String& rootName, Config& lCfg);
 
  15 void IterateJsonObject(JsonObject json, String rootName, Config& lCfg) {
 
  16   for (JsonPair kv : json) {
 
  17     IterateJson(kv.value(), rootName == "" ? String(kv.key().c_str()) : rootName + "." + String(kv.key().c_str()),lCfg);
 
  21 void IterateJsonArray(JsonArray json, const String& rootName,  Config& lCfg) {
 
  22   for (int i = 0; i < json.size(); i++) {
 
  23     IterateJson(json[i], rootName == "" ? "[" + String(i) + "]" : rootName + "." + "[" + String(i) + "]", lCfg);
 
  27 void IterateJson(JsonVariant json, const String& rootName, Config& lCfg) {
 
  28   if (json.is<JsonObject>()) {
 
  29     IterateJsonObject(json.as<JsonObject>(), rootName, lCfg);
 
  30   } else if (json.is<JsonArray>()) {
 
  31     IterateJsonArray(json.as<JsonArray>(), rootName, lCfg);
 
  33     lCfg.setValue(rootName.c_str(), json.as<String>().c_str());
 
  37 void processTemplates(char* buf, const char* strTemplate, const Config& cfg, int maxLen) {
 
  40   const char* ptr = strTemplate;
 
  42     char* pos = strchr(ptr, '%');
 
  44       strncat(buf, ptr, maxLen);
 
  48     if (len + strlen(buf) >= maxLen) {
 
  49       len = maxLen - strlen(buf);
 
  51     int bufLen = strlen(buf);
 
  52     strncpy(buf + bufLen, ptr, len);
 
  54     char* endpos = strchr(pos+1, '%');
 
  56       Serial.println(F("Незавершенное имя переменной"));
 
  59     int varLen = (endpos-1) - (pos);
 
  61       Serial.println(F("Имя переменной слишком длинное"));
 
  65       strncpy(varName,pos+1,varLen);
 
  67       const char* value = cfg.getCharValue(varName);
 
  69         strncat(buf, value, maxLen);
 
  71         strncat(buf, "??", maxLen);
 
  74       strncat(buf, "%", maxLen);
 
  80 void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState) {
 
  81   const char* weather_template = cfg.getCharValue(F("weather_template"));
 
  83   if (readyState == readyStateDone) {
 
  84     if (request->responseHTTPcode() == 200) {
 
  85       String weather_json = request->responseText();
 
  86       DynamicJsonDocument* current_weather = new DynamicJsonDocument(2048);
 
  87       DeserializationError error = deserializeJson(*current_weather, weather_json);
 
  89         Serial.print(F("Ошибка разбора ответа: "));
 
  90         Serial.println(error.c_str());
 
  91         Serial.println(weather_json);
 
  95       IterateJson(current_weather->as<JsonObject>(), "", weather);
 
  96       weather_json = String();
 
  97       delete current_weather;
 
  98       processTemplates(weatherData,weather_template,weather,255);
 
 100       scroll(weatherData, !isNight());
 
 105 void weatherRequest() {
 
 106   if (!WiFi.isConnected()) { return; }
 
 107   if (WiFi.isConnected() && weatherTicker) {
 
 108     weatherTicker->detach();
 
 109     int weather_min = cfg.getIntValue(F("weather_min"));
 
 110     weather_min = weather_min ? weather_min : 60;
 
 111     weatherTicker->attach(weather_min * 60, executeWeatherRequest);  // reschedule to requested interval
 
 113   static bool requestOpenResult;
 
 114   if (request.readyState() == readyStateUnsent || request.readyState() == readyStateDone) {
 
 115     const char* weather_url = cfg.getCharValue(F("weather_url"));
 
 116     requestOpenResult = request.open("GET", weather_url);
 
 118     if (requestOpenResult) {
 
 121       Serial.println(F("Не удалось отправить запрос"));
 
 124     Serial.println(F("Не удалось отправить запрос"));
 
 128 void executeWeatherRequest() {
 
 129   if (cfg.getBoolValue(F("enable_weather"))) {
 
 130     request.onReadyStateChange(requestCB);
 
 135 void setupWeatherRequest() {
 
 137     weatherTicker->detach();
 
 138     delete weatherTicker;
 
 139     weatherTicker = nullptr;
 
 141   if (cfg.getBoolValue(F("enable_weather"))) {
 
 142     weatherTicker = new Ticker;
 
 143     weatherTicker->attach(30, executeWeatherRequest);  // before connection - every 30s