mqtt_sav2
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <ArduinoJson.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <StackArray.h>
//#include <b64.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP8266HTTPClient.h>
//#include <ArduinoJson.h>
//if (client.connect(" ESP8266Client_Rom55", - измененнй Client
//Бегущая строка
//Time intervals for tasks
const uint32_t draw_topics_interval = 1000;
const uint32_t count_seconds = 30000;
unsigned long yandex_api_call_interval = 43200; // in seconds
//process timers
uint32_t current_time_process_1 = 0;
uint32_t current_time_process_2 = 0;
unsigned long epoch_time = 0;
unsigned long now_epoch_time = yandex_api_call_interval;
// WiFi credentials and MQTT broker information
const char* ssid = "Keenetic-6391";
const char* password = "U7Y6hMeB";
const char* mqtt_server = "192.168.1.75";
const char* mqtt_username = "mqtt";         // если требуется
const char* mqtt_password = "mq485127sav";  // если требуется
// MQTT topics
const char* air_temperature_topic = "air_temperature";
const char* water_temperature_topic = "water_temperature";
const char* humidity_topic = "humidity";
//Добавка от 5.01.2025 навес
const char* air_temp_naves_topic = "air_temp_naves";
const char* humedity_naves_topic = "humedity_naves";
const char* P_naves_topic = "P_naves";
const char* water_level_topic = "water_level";
// Yandex.Weather API information
const char* api_key = "141eea13-8ecd-4900-b928-048976a66f68";
const char* location = "shakhty";
const char* lang = "ru_RU";
bool start_draw = false;
// Matrix dimensions and pins
const int matrix_width = 4;        // количество светодиодов в матрице
const int matrix_height = 1;       // количество строк светодиодов в матрице
//const int matrix_cs_pin = D8;      // пин выбора MAX7219
const int matrix_cs_pin = 15;      // пин выбора MAX7219 io15
//const int matrix_clk_pin = D5;     // пин тактового сигнала MAX7219
const int matrix_clk_pin = 14;     // пин тактового сигнала MAX7219 io14
//const int matrix_data_pin = D7;    // пин данных MAX7219
const int matrix_data_pin = 13;    // пин данных MAX7219 io13
const int matrix_num_devices = 4;  // количество устройств MAX7219 в цепи
   Max72xxPanel matrix = Max72xxPanel(matrix_cs_pin, matrix_height, matrix_width);
// MQTT client and WiFi client
WiFiClient espClient;
WiFiClientSecure espClientDouble;
PubSubClient client(espClient);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
// переменные для хранения показаний датчиков
float air_temperature = 0;
float water_temperature = 0;
float humidity = 0;
//Добавка топиков от навеса от 7.01.2025
float air_temp_naves = 0;
float P_naves = 0;
float humedity_naves = 0;
String water_level = "";
// переменные для хранения данных с Yandex
String y_temperature;
String y_condition;
String y_description;
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    Serial.print(WiFi.status());
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  char msg[length + 1];
  for (int i = 0; i < length; i++) {
    msg[i] = (char)payload[i];
  }
  msg[length] = '\0';
  Serial.println(msg);
  if (strcmp(topic, air_temperature_topic) == 0) {
    Serial.print("air temperature: ");
    air_temperature = atof(msg);
    Serial.println(air_temperature);
  } else if (strcmp(topic, water_temperature_topic) == 0) {
    Serial.print("water temperature: ");
    water_temperature = atof(msg);
    Serial.println(water_temperature);
  } else if (strcmp(topic, humidity_topic) == 0) {
    Serial.print("humidity: ");
    humidity = atof(msg);
    Serial.println(humidity);
  } else if (strcmp(topic, water_level_topic) == 0) {
    Serial.print("water_level: ");
    water_level = "";
    water_level = msg;
    Serial.println(water_level);
    //Добавка топиков от навеса от 7.01.2025
    } else if (strcmp(topic, air_temp_naves_topic) == 0) {
    Serial.print("air_temp_naves: ");
    air_temp_naves = atof(msg);
    Serial.println(air_temp_naves);
  } else if (strcmp(topic, humedity_naves_topic) == 0) {
    Serial.print("humedity_naves: ");
    humedity_naves = atof(msg);
    Serial.println(humedity_naves);
  } else if (strcmp(topic,P_naves_topic) == 0) {
    Serial.print("P_naves: ");
    P_naves = atof(msg);
    
    Serial.println(P_naves);
    //Конец добавки
  }
  Serial.println("END void callback");
}
void setup() {
  Serial.begin(9600);
  SPI.begin();
  matrix.setIntensity(5);
  matrix.fillScreen(LOW);
  matrix.setRotation(1);
  matrix.write();
  setup_wifi();
  timeClient.begin();
 // Set offset time in seconds to adjust for your timezone, for example:
 // GMT +1 = 3600
 // GMT +3 = 10800
 // GMT +8 = 28800
 // GMT -1 = -3600
 // GMT 0 = 0
 timeClient.setTimeOffset(10800);
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  DynamicJsonDocument doc(2048);
  // Предположим, что response - это ваша строка JSON
  String response = "{\"hello\":\"world\"}";
  // Разбираем объект JSON в строке
  DeserializationError error = deserializeJson(doc, response);
  // Проверяем, удалось ли разбор.
  if (error) {
    Serial.print(F("deserializeJson() не удалось: "));
    Serial.println(error.f_str());
    return;
  }
  // Получаем корневой объект JSON
  JsonObject root = doc.as<JsonObject>();
  // Теперь вы можете использовать root для доступа к элементам в JSON
  const char* hello = root["hello"];  // "world"
  Serial.println("End setup");
}
void drawString(const String &str, int16_t x, int16_t y) {
  Serial.println("START-drawString");
  int spacer = 1;
  int width = 5 + spacer;
  for (int i = 0; i < width * str.length() + matrix.width() - 1 - spacer; i++) {
    matrix.fillScreen(LOW);
    int letter = i / width;
    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2;  // центровка по вертикали
    while (x + width - spacer >= 0 && letter >= 0) {
      if (letter < str.length()) {
        matrix.drawChar(x, y, str[letter], HIGH, LOW, 1);
      }
      letter--;
      x -= width;
    }
    matrix.write();
    delay(50);
    client.loop();
  }
  Serial.println("ENDSTART-drawString");
}
const String get_reduced_json(WiFiClient* stream_ptr) {
  StackArray<char> brackets_stack;
  const int max_sizeof_buff = (int)(ESP.getFreeHeap() * 0.2);
  String res("");
  bool begin_search = false;
  bool fact_match = false;
  bool one_bracket_found = false;
  int i = 0;
  char* fact_keyword = "fact";
  while (stream_ptr->available()) {
    fact_match = true;
    char c = stream_ptr->read();
    if (c != fact_keyword[i]) {
      fact_match = false;
      i = 0;
    } else {
      if (fact_match && i == 3) {
        begin_search = true;
        i = 0;
      }
      i++;
    }
    if (begin_search) {
      if (c == '{') {
        brackets_stack.push(c);
      } else if (c == '}') {
        brackets_stack.pop();
        one_bracket_found = true;
      }
      if (brackets_stack.isEmpty() && one_bracket_found) {
        res += c;
        res += '}';
        return res;
      }
    }
    res += c;
  }
  return "";
}
void get_yandex_info() {
  Serial.println("Updating Yandex data");
  HTTPClient http;  // Declare HTTPClient here
  const String url = "https://api.weather.yandex.ru/v2/forecast/?lat=47.709236&lon=40.215405&lang=ru_RU";
  espClientDouble.setInsecure();
  http.begin(espClientDouble, url);
  // http.begin(url);
  http.addHeader("X-Yandex-API-Key", api_key);
  int httpCode = http.GET();
  Serial.println("httpCode: ");
  Serial.println(httpCode);
  if (httpCode > 0) {
    WiFiClient* stream = http.getStreamPtr();
    const String response = get_reduced_json(stream);
    Serial.println(response);
    //ArduinoJson::StaticJsonBuffer<2048> jsonBuffer; // Use StaticJsonBuffer for ArduinoJson 5
    DynamicJsonDocument doc(8128);
    DeserializationError error = deserializeJson(doc, response);
    if (error) {
      Serial.print(F("deserializeJson() не удалось: "));
      Serial.println(error.f_str());
      return;
    }
    //ArduinoJson::JsonObject& root = jsonBuffer.parseObject(response);
    JsonObject root = doc.as<JsonObject>();
    String temperature = root["fact"]["temp"];
    String condition = root["fact"]["condition"];
    String description = root["fact"]["condition"];
    Serial.print("Temperature: ");
    Serial.println(temperature);
    Serial.print("Condition: ");
    Serial.println(condition);
    Serial.print("Description: ");
    Serial.println(description);
    y_temperature = temperature;
    y_condition = condition;
    y_description = description;
  } else {
    Serial.println("response <= 0");
  }
  http.end();  // Properly end the HTTPClient
}
void drawWeather() {
    String weather = "Temp " + y_temperature + "C " + y_condition + " " + y_description;
    drawString(weather.c_str(), matrix_width, 0);
    matrix.fillScreen(LOW);
  
}
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    //if (client.connect(" ESP8266ClientRom", mqtt_username, mqtt_password)) {
      if (client.connect(" ESP8266ClientRom55")) {
      Serial.println("connected");
      client.subscribe(air_temperature_topic);
      client.subscribe(water_temperature_topic);
      client.subscribe(humidity_topic);
      client.subscribe(water_level_topic);
      //добавка от 7.01.2025 навес
      client.subscribe(air_temp_naves_topic);
      client.subscribe(humedity_naves_topic);
      client.subscribe(P_naves_topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" retrying in 5 seconds");
      delay(5000);
    }
  }
}
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  if (now_epoch_time - epoch_time >= yandex_api_call_interval) {
    get_yandex_info();
    epoch_time = now_epoch_time;
  }
//  if (millis() - current_time_process_1 >= count_seconds) {
//    now_epoch_time += 30;
//    Serial.println("Seconds counted");
//    current_time_process_1 = millis();
//  }
  if (millis() - current_time_process_2 >= draw_topics_interval) {
    timeClient.update();
    now_epoch_time = timeClient.getEpochTime();
    Serial.println("elapsed: ");
    Serial.println(now_epoch_time - epoch_time);
    String formatted_time = timeClient.getFormattedTime();
    struct tm * ptm;
    time_t rawtime = timeClient.getEpochTime();
    ptm = localtime (&rawtime);
     int month_day = ptm->tm_mday;
     int current_month = ptm->tm_mon+1;
     int current_year = ptm->tm_year+1900;
     String current_date = String(current_year) + "-" + String(current_month) + "-" + String(month_day);
    matrix.fillScreen(LOW);
    String topics = current_date + " " + formatted_time + " Air temp " + String(air_temperature, 1) + "C " + "water temp " + String(water_temperature, 1) + "C " + "humidity " + String(humidity, 1) + "% " + "water level " + water_level + "";
    drawString(topics.c_str(), matrix_width, 0);
    drawString("Forecast: ", matrix_width, 0);
    drawWeather();
    current_time_process_2 = millis();
  }
}