Зависание Arduino Mega 2560

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Добрый день. Зависает Arduino Mega 2560 при работе с GSM модемом A6 + MQTT. Зависание прыгает от 2 часов работы до 12. Система считывает данные с датчиков и отправляет на сервер. Питается вся система от блока питания 12 вольт 3 ампера. Что можно сделать?

Код:

#define DS1307_ADDRESS 0x68                                     // Адрес часов DS1307 расположенных в шиелде
#define LSD2004_ADDRESS 0x27                                    // Адрес дисплея 2004 I2C 20х4
#define pinBeep 24                                              // Пин зуммера - пищалка 
#define rele1VentPinAdress 50                                   // Пин к которому подключено 1е реле - вентиляции
#define rele2Heater1PinAdress 48                                // Пин к которому подключено 2е реле - отопление
#define rele3Heater2PinAdress 49                                // Пин к которому подключено 3е реле - отопление
#define rele4ModemPinAdress 46                                  // Пин к которому подключено 4е реле - отопление
#define SG90Zaslon1Pin 43                                       // Пин сервопривода SG90
#define SG90Zaslon2Pin 45                                       // Пин сервопривода SG90
#define SG90Zaslon3Pin 42                                       // Пин сервопривода SG90
#define TX 11                                                   // Пин TX GSM модема - A6
#define RX 10                                                   // Пин RX GSM модема - A6
#define sensorPin 4                                             // Пин датчика движения
//#define ds18b20 6                                              // Пин внешнего датчика температуры DS18B20
#define CLK 2                                                   // Пин CLK цифрового 4 сегментного дисплея для вывода времени
#define DIO 3                                                   // Пин DIO цифрового 4 сегментного дисплея для вывода времени
#define IRPin 51                                                // Пин пульта
#define DHTPIN1 47                                              // Пин внутреннего датчика температуры и влажности DHT22
#define DHTPIN2 44                                              // Пин внутреннего датчика температуры и влажности DHT22
#define pinMQ7 40                                               // Пин датчика качества воздуха MQ7
#define ledVent A9                                              // Пин светодиода вентиляции
#define ledHeater1 A1                                           // Пин светодиода обогревателя 1
#define ledHeater2 A0                                           // Пин светодиода обогревателя 2
#define ledZaslon1 A6                                           // Пин светодиода впускной заслонки
#define ledZaslon2 A5                                           // Пин светодиода выпускной заслонки 1
#define ledZaslon3 A4                                           // Пин светодиода выпускной заслонки 2
#define ledAtention A3                                          // Пин светодиода предупреждений
#define ledCPU A2                                               // Пин светодиода режима работы 
#define ledCall A1                                              // Пин светодиода поступившего звонка
#define ledCO2 A0                                               // Пин светодиода включение заслонки выхлопных газов
#define SEALEVELPRESSURE_HPA (1013.25)                          // Переменная для определения высоты
//#define MQTT_MAX_PACKET_SIZE 1800                               // Размер отправляемого пакета пакета на MQTT сервер
//#define MQTT_KEEPALIVE 15                                       // keepAlive interval in Seconds
//#define MQTT_SOCKET_TIMEOUT 15                                  // socket timeout interval in Seconds

#define TINY_GSM_MODEM_A6                                       // Указываем что GSM модем - A6
#define TINY_GSM_DEBUG SerialMon                                // Переменная для отладки GSM модема
#define GSM_AUTOBAUD_MIN 9600                                   // Минимальная скорость общения с GSM модемом
#define GSM_AUTOBAUD_MAX 9600                                   // Максимальная скорость общения с GSM модемом
#define SerialMon Serial                                        // Переменная для отладки GSM модема
#define TINY_GSM_TEST_GPRS true                                 // Переменная для отладки GSM модема
#define GSM_PIN ""                                              // Пин GSM модема
#define DUMP_AT_COMMANDS                                      // Просмотр всех AT команд

#define PIN_PHOTO_SENSOR A15                                    // Пин фото сенсора управляющего режимом работы устройства
#define TTPH2 7                                                 // Пин сенсорной кнопки обогревателя 2
#define TTPH1 6                                                 // Пин сенсорной кнопки обогревателя 1
#define TTPV 5                                                  // Пин сенсорной кнопки вентилятора
#define TTPZ3 13                                                // Пин сенсорной кнопки заслонки 3
#define TTPZ2 12                                                // Пин сенсорной кнопки заслонки 2
#define TTPZ1 9                                                 // Пин сенсорной кнопки заслонки 1

#include <SoftwareSerial.h>                                     // Библиотека программной реализации обмена по UART-протоколу для А6
#include "TM1637.h"                                             // Библиотека цифрового 4 сегментного дисплея для вывода времени
#include <IRremote.h>                                           // Библиотека для работы с пультом
#include <Wire.h>                                               // Библиотека для работы с часами DS1307 расположенными в шиелде
#include <LiquidCrystal_I2C.h>                                  // Библиотева для работы с дисплеем 2004 I2C 20х4
#include "DHT.h"                                                // Библиотека для работы с внутренним датчиком температуры и влажности DHT22
#include <SPI.h>                                                // Библиотека для работы с SD карточкой
#include <EEPROM.h>                                             // Библиотека для работы с памятью Arduino Mega
#include <MenuBackend.h>                                        // Библиотека для работы с меню
#include <RTClib.h>                                             // Библиотека для работы с часами
#include <TimerFreeTone.h>                                      // Библиотека для пищалкой
#include <TinyGsmClient.h>                                      // Библиотека для работы с GSM модемом
#include <PubSubClient.h>                                       // Библиотека для работы с GSM модемом
#include <Adafruit_Sensor.h>                                    // Библиотека для работы с BME280
#include <Adafruit_BME280.h>                                    // Библиотека для работы с BME280

//#include "GyverTimer.h"

SoftwareSerial SerialAT(RX, TX);                                // Обьявляем RX, TX GSM модема

#ifdef DUMP_AT_COMMANDS                                         // Если переменная есть то выводим все AT комманды    
#include <StreamDebugger.h>                                     // Библиотека для выполнения отладочных работ с GSM модемом
StreamDebugger debugger(SerialAT, SerialMon);                   // Обьявляем отладчика
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);                                        // Если отладка не ведется то работаем напрямую с модемом
#endif

const char* topicTemperatureIn = "garaj558/temperaturein";      // Топик температуры внутри
const char* topicHumidityIn = "garaj558/humidityin";            // Топик влажности внутри
const char* topicTemperatureOut = "garaj558/temperatureout";    // Топик температуры снаружы
const char* topicHumidityOut = "garaj558/humidityout";          // Топик влажности снаружы
const char* topicPressureOut = "garaj558/pressureout";          // Топик атмосферного давления
const char* topicHeightOut = "garaj558/heightout";              // Топик высоты
const char* topicZaslon1 = "garaj558/zaslon1";                  // Топик впускной заслонки
const char* topicZaslon2 = "garaj558/zaslon2";                  // Топик выпускной заслонки 1
const char* topicZaslon3 = "garaj558/zaslon3";                  // Топик выпускной заслонки 2
const char* topicZaslon1i = "garaj558/zaslon1i";                // Топик индикатора впускной заслонки
const char* topicZaslon2i = "garaj558/zaslon2i";                // Топик индикатора выпускной заслонки 1
const char* topicZaslon3i = "garaj558/zaslon3i";                // Топик индикатора выпускной заслонки 2
const char* topicGetBalance = "garaj558/getbalance";            // Топик запроса баланса
const char* topicBalance = "garaj558/balance";                  // Топик хранения баланса
const char* topicSMS = "garaj558/sms";                          // Топик хранения смс
const char* topicVent = "garaj558/vent";                        // Топик состояния вентиляции
const char* topicVenti = "garaj558/venti";                      // Топик индикатора состояния вентиляции
const char* topicRejim = "garaj558/rejim";                      // Топик режима автоматический/ручной
const char* topicHeater1 = "garaj558/heater1";                  // Топик обогревателя 1
const char* topicHeater2 = "garaj558/heater2";                  // Топик обогревателя 2
const char* topicHeater1i = "garaj558/heater1i";                // Топик индикатора обогревателя 1
const char* topicHeater2i = "garaj558/heater2i";                // Топик индикатора обогревателя 2
const char* topicLog = "garaj558/log";                          // Топик ведения лога

const char* topicSettingsHumidityzaslon2 = "garaj558/humidityzaslon2";   // Топик настроек влажности выпускной заслонки 1
const char* topicSettingsHumidityzaslon3 = "garaj558/humidityzaslon3";   // Топик настроек влажности выпускной заслонки 2
const char* topicSettingsMaxTemperatureIn = "garaj558/maxtemperaturein"; // Топик максимальной температуры в гараже

const char apn[]  = "internet.beeline.ru";                      // APN для оператора beeline
const char gprsUser[] = "beeline";                              // Логин для APN для оператора beeline
const char gprsPass[] = "beeline";                              // Пароль для APN для оператора beeline

const char *mqtt_server = 123.com";                  // Адрес MQTT сервера
const int mqtt_port = 0000;                                    // Порт для подключения MQTT серверу
const char *mqtt_user = "****";                             // Логин для подключения MQTT серверу
const char *mqtt_pass = "****";                         // Пароль для подключения MQTT серверу

int pos_open_zaslon1 = 1400;                                    // Открытая позиция заслонки 1
int pos_close_zaslon1 = 490;                                    // Закрытая позиция заслонки 1
int pos_open_zaslon2 = 1800;                                    // Открытая позиция заслонки 2
int pos_close_zaslon2 = 544;                                    // Закрытая позиция заслонки 2
int pos_open_zaslon3 = 1400;                                    // Открытая позиция заслонки 3
int pos_close_zaslon3 = 490;                                    // Закрытая позиция заслонки 3

bool statusHeater1 = false;                                     // Переменная для хранения статуса отопления 1
bool statusHeater2 = false;                                     // Переменная для хранения статуса отопления 2
bool statusZaslon1 = false;                                     // Переменная для хранения статуса положения заслонки входной 1
bool statusZaslon2 = false;                                     // Переменная для хранения статуса положения заслонки выходной 1
bool statusZaslon3 = false;                                     // Переменная для хранения статуса положения заслонки выходной 2
bool statusVent = false;                                        // Переменная для хранения статуса вентиляции
bool rejim = true;                                              // Переменная для хранения статуса режима автоматический/ручной
bool statusRing = false;
bool republicStatus = false;                                    // Переменная для хранения статуса повторной отправки статуса
bool GPRSStatus = false;                                        // Переменная для хранения состояния подключения к интернету
bool MQTTStatus = false;                                        // Переменная для хранения состояния подключения к MQTT серверу
bool AtentionLed_on_off = false;                                // Переменная для хранения состояния светодиода ошибки
bool Atention = false;                                          // Переменная для хранения состояния присутствия ошибки в системе
bool Retained  = true;                                         // Переменная для хранения статуса, надо ли сохранять сообщения MQTT
bool SIMStatus = false;                                         // Переменная для хранения статуса присутствия симкарты

String MQTTState = "";                                          // Переменная для хранения состояния последнего подключения
String Balance = "0.0";                                         // Переменная для хранения текущего баланса симкарты

float humidity_in = 0;                                          // Переменная для хранения уровня влажности внутри помещения с датчика DHT22
float temperature_in = 0;                                       // Переменная для хранения температуры внутри помещения с датчика DHT22
float humidity_out = 0;                                         // Переменная для хранения уровня влажности снаружы помещения с датчика BME280
float temperature_out = 0;                                      // Переменная для хранения температуры снаружы помещения с датчика BME280
float Pressure = 0;                                             // Переменная для хранения атмосферного давления с датчика BME280

float SettingsHumidityzaslon2 = 0;                              // Переменная для хранения настроек заслонки 2
float SettingsHumidityzaslon3 = 0;                              // Переменная для хранения настроек заслонки 2
float SettingsMaxTemperatureIn = 0;                             // Переменная для хранения настроек максимальной температуры внутри

long lastReconnectAttempt = 0;                                  // Переменная для хранения времени переподключения к MQTT

byte Date;                                                      // Переменная для даты
byte Month;                                                     // Переменная для месяца
int Year;                                                       // Переменная для года
byte Hour, Minute;                                              // Переменная для часов и минут

int pos = 0;                                                    // Переменная для поворота SG90
int incomingByte = 0;                                           // Переменная для поворота SG90

int8_t NoDisplayTime_[] = {31, 31, 31, 31};
int8_t DisplayMenu[] = {23, 14, 24, 28};
int8_t NoDisplayTime[] = {32, 32, 32, 32};

//7
byte pictureBlock7[8] = {
  0x02,  0x03,  0x03,  0x03,  0x07,  0x07,  0x07,  0x03
};
//8
byte pictureBlock8[8] = {
  0x10,  0x11,  0x11,  0x13,  0x1B,  0x1B,  0x19,  0x10
};
//9
byte pictureBlock9[8] = {
  0x10,  0x18,  0x18,  0x1C,  0x1C,  0x1C,  0x18,  0x00
};
//18
byte pictureBlock18[8] = {
  0x00,  0x00,  0x01,  0x02,  0x02,  0x02,  0x02,  0x02
};
//19
byte pictureBlock19[8] = {
  0x00,  0x00,  0x00,  0x10,  0x10,  0x10,  0x10,  0x10
};
//20
byte pictureBlock20[8] = {
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x10
};


String fileLogName = "TemperatureLOG.csv";                      //название файла лога

byte MenuOnOff = 0;
byte Temperature = 30;                                          //температура в градусах
byte Humidity = 60;                                             //влажность в процентах
char Buffer[17];                                                //буфер для вывода времени
unsigned long key_value = 0;
boolean point_on_off = false;                                   // Переменная для хранения состояния точек на 4х сегментном дисплее



TinyGsmClient client(modem);                                    // Объявляем GSM модем
PubSubClient mqtt(client);                                      // Объявляем MQTT клиента
DHT dht1(DHTPIN1, DHT22);                                       // Объявляем внутренний датчик температуры и влажности DHT22 1
DHT dht2(DHTPIN2, DHT22);                                       // Объявляем внутренний датчик температуры и влажности DHT22 2
IRrecv irrecv(IRPin);                                           // Объявляем IR приемник
LiquidCrystal_I2C lcd(LSD2004_ADDRESS, 20, 4);                  // Обьявляем дисплей 2004 I2C 20х4
TM1637 tm1637(CLK, DIO);                                        // Обьявляем цифровой 4 сегментный дисплей для вывода времени
RTC_DS1307 rtc;                                                 // Обьявляем часы
Adafruit_BME280 bme;                                            // Обьявляем BME280
decode_results results;                                         // Переменная получения нажатой клафиши на пульте

unsigned long TimerTTP;                                         // Период опроса сенсорных кнопок - 2 секунды
unsigned long TimerAutoRejim;                                   // Период работы автоматического режима - 1 минута
unsigned long TimerRepublicStatus;                              // Период отключения режима перепубликации статуса - 1 минута
unsigned long TimerGetValueSensors;                             // Период период опроса датчиков - 5 минут
unsigned long TimingAtentionAlert;                              // Период мигания светодиода сообщающим об ошибке - 1 секунда
unsigned long TimingPublishMQTT;                                // Период публикации данных на MQTT - 5 минут
unsigned long TimerPhotoSensor;                                 // Период опроса датчика света - 10 минут
unsigned long TimerShowDijit;                                   // Период обновления времени на 4х сегментном дисплее - 1 секунда
unsigned long TimerShowSensorValue;                             // Период вывода информации с датчиков на дисплей 2004 I2C 20х4
unsigned long TimerDisplayOnOff;                                // Период проверки фотосенсора для включения/выключения дисплея
/*
  GTimer_ms TimerTTP(2000);                                       // Период опроса сенсорных кнопок - 2 секунды
  GTimer_ms TimerAutoRejim(60000);                                // Период работы автоматического режима - 1 минута
  GTimer_ms TimerRepublicStatus(60000);                           // Период отключения режима перепубликации статуса - 1 минута
  GTimer_ms TimerGetValueSensors(300000);                         // Период период опроса датчиков - 5 минут
  GTimer_ms TimingAtentionAlert(1000);                            // Период мигания светодиода сообщающим об ошибке - 1 секунда
  GTimer_ms TimingPublishMQTT(300000);                            // Период публикации данных на MQTT - 5 минут
  GTimer_ms TimerPhotoSensor(600000);                             // Период опроса датчика света - 10 минут
  GTimer_ms TimerShowDijit(1000);                                 // Период обновления времени на 4х сегментном дисплее - 1 секунда
  GTimer_ms TimerShowSensorValue(60000);                          // Период вывода информации с датчиков на дисплей 2004 I2C 20х4
*/
void mqttCallback(char* topic, byte* payload, unsigned int len);// Шапка Функции Callback для объявления и Инициализации PubSubClient
void menuChangeEvent(MenuChangeEvent changed);
void menuUseEvent(MenuUseEvent used);

MenuBackend menu = MenuBackend(menuUseEvent, menuChangeEvent);
MenuItem menu1Item1 = MenuItem("System Status");
MenuItem menuItem1SubItem1 = MenuItem("Alert Information", '1');
MenuItem menuItem1SubItem2 = MenuItem("Connect Status", '2');

MenuItem menu1Item2 = MenuItem("DHT Sensor");
MenuItem menuItem2SubItem1 = MenuItem("Temperature", '3');
MenuItem menuItem2SubItem2 = MenuItem("Humidity", '4');

MenuItem menu1Item3 = MenuItem("Set DateTime");
MenuItem menuItem3SubItem1 = MenuItem("Date", '5');
MenuItem menuItem3SubItem2 = MenuItem("Month", '6');
MenuItem menuItem3SubItem3 = MenuItem("Year", '7');
MenuItem menuItem3SubItem4 = MenuItem("Hour", '8');
MenuItem menuItem3SubItem5 = MenuItem("Minute", '9');

MenuItem menu1Item4 = MenuItem("Save Data", '10');
MenuItem menu1Item5 = MenuItem("Load Data", '11');

void setup()
{
  pinMode(ledZaslon1, OUTPUT);                                  // Устанавливаем режим работы светодиода
  pinMode(ledZaslon2, OUTPUT);                                  // Устанавливаем режим работы светодиода
  pinMode(ledZaslon3, OUTPUT);                                  // Устанавливаем режим работы светодиода
  pinMode(ledVent, OUTPUT);                                     // Устанавливаем режим работы светодиода
  pinMode(ledAtention, OUTPUT);                                 // Устанавливаем режим работы светодиода
  pinMode(ledCPU, OUTPUT);                                      // Устанавливаем режим работы светодиода
  pinMode(ledCall, OUTPUT);                                     // Устанавливаем режим работы светодиода
  pinMode(ledCO2, OUTPUT);                                      // Устанавливаем режим работы светодиода

  pinMode(rele1VentPinAdress, OUTPUT);                          // Устанавливаем режим работы - выход для реле 1
  pinMode(rele2Heater1PinAdress, OUTPUT);                       // Устанавливаем режим работы - выход для реле 2
  pinMode(rele3Heater2PinAdress, OUTPUT);                       // Устанавливаем режим работы - выход для реле 3
  pinMode(rele4ModemPinAdress, OUTPUT);                         // Устанавливаем режим работы - выход для реле 4

  pinMode(sensorPin, INPUT);                                    // Устанавливаем режим работы - вход для датчика движения
  pinMode(pinBeep,  OUTPUT);                                    // Устанавливаем режим работы - выход для зуммера

  pinMode(SG90Zaslon1Pin, OUTPUT);                              // Устанавливаем режим работы сервопривода заслонки 1
  pinMode(SG90Zaslon2Pin, OUTPUT);                              // Устанавливаем режим работы сервопривода заслонки 2
  pinMode(SG90Zaslon3Pin, OUTPUT);                              // Устанавливаем режим работы сервопривода заслонки 3

  pinMode(TTPH2, INPUT);                                        // Устанавливаем режим работы сенсорной кнопки обогревателя 2
  pinMode(TTPH1, INPUT);                                        // Устанавливаем режим работы сенсорной кнопки обогревателя 1
  pinMode(TTPV, INPUT);                                         // Устанавливаем режим работы сенсорной кнопки вентилятора
  pinMode(TTPZ3, INPUT);                                        // Устанавливаем режим работы сенсорной кнопки заслонки 3
  pinMode(TTPZ2, INPUT);                                        // Устанавливаем режим работы сенсорной кнопки заслонки 2
  pinMode(TTPZ1, INPUT);                                        // Устанавливаем режим работы сенсорной кнопки заслонки 1

  digitalWrite(ledZaslon1, LOW);                                // Выключаем светодиод заслонки 1
  digitalWrite(ledZaslon2, LOW);                                // Выключаем светодиод заслонки 2
  digitalWrite(ledZaslon3, LOW);                                // Выключаем светодиод заслонки 3
  digitalWrite(ledVent, LOW);                                   // Выключаем светодиод электрической вентиляции
  digitalWrite(ledAtention, LOW);                               // Выключаем светодиод отображения ошибок/предупреждений
  digitalWrite(ledCPU, LOW);                                    // Выключаем светодиод CPU - автоматического режима
  digitalWrite(ledCall, LOW);                                   // Выключаем светодиод входящего звонка
  digitalWrite(ledCO2, LOW);                                    // Выключаем светодиод отображения превышения уровня CO2

  lcd.begin();                                                  // Иницыализируем дисплей
  lcd.home();                                                   // Иницыализируем дисплей

  lcd.createChar(0, pictureBlock7);                             // Создаем 0 блок эмблемы устройства на дисплее
  lcd.createChar(1, pictureBlock8);                             // Создаем 1 блок эмблемы устройства на дисплее
  lcd.createChar(2, pictureBlock9);                             // Создаем 2 блок эмблемы устройства на дисплее
  lcd.createChar(3, pictureBlock18);                            // Создаем 3 блок эмблемы устройства на дисплее
  lcd.createChar(4, pictureBlock19);                            // Создаем 4 блок эмблемы устройства на дисплее
  lcd.createChar(5, pictureBlock20);                            // Создаем 5 блок эмблемы устройства на дисплее
  lcd.setCursor(2, 1); lcd.write(byte(3));                      // Выводим эмблему устройства на дисплее
  lcd.setCursor(3, 1); lcd.write(byte(4));                      // Выводим эмблему устройства на дисплее
  lcd.setCursor(4, 1); lcd.write(byte(5));                      // Выводим эмблему устройства на дисплее
  lcd.setCursor(2, 2); lcd.write(byte(0));                      // Выводим эмблему устройства на дисплее
  lcd.setCursor(3, 2); lcd.write(byte(1));                      // Выводим эмблему устройства на дисплее
  lcd.setCursor(4, 2); lcd.write(byte(2));                      // Выводим эмблему устройства на дисплее

  lcd.setCursor(7, 1);                                          // Переводим курсор дисплея на 1 строку, 7 позиция
  lcd.print("Climate");                                         // Выводим название устройства на дисплее
  lcd.setCursor(8, 2);                                          // Переводим курсор дисплея на 2 строку, 8 позиция
  lcd.print("Control");                                         // Выводим название устройства на дисплее
  TimerFreeTone(pinBeep, 2048, 1000);                           // Выводим звуковой сигнал с частотой 2048 Гц и длительностью 1 секунда
  delay(3000);                                                  // Задерживаем название устройства на дисплее на 3 секунды

  dht1.begin();                                                 // Инициализируем внутренний датчик температуры и влажности DHT22 1
  dht2.begin();                                                 // Инициализируем внутренний датчик температуры и влажности DHT22 2
  bme.begin();                                                  // Инициализируем внешний датчик температуры и влажности BME280
  irrecv.enableIRIn();                                          // Инициализируем прием данных с пульта
  tm1637.init();                                                // Инициализируем цифровой 4 сегментный дисплей
  tm1637.set(7);                                                // Устанавливаем уровень яркости - 7, цифрового 4 сегментного дисплея для вывода времени

  LoadData();                                                   // Загружаем настройки из памяти EEROM

  Date = rtc.now().day();                                       // Получаем дату от часов
  Month = rtc.now().month();                                    // Получаем месяц от часов
  Year = rtc.now().year();                                      // Получаем год от часов
  Hour = rtc.now().hour();                                      // Получаем час от часов
  Minute = rtc.now().minute();                                  // Получаем минуты от часов
  //--------------------Выключение всех реле--------------------
  lcd.clear();                                                  // Очищаем дисплей
  lcd.setCursor(0, 0);                                          // Переводим курсор дисплея на 0 строку, 0 позиция
  lcd.print("Vent: ");                                          // Выводим сообщение о статусе электрической вентиляции
  digitalWrite(rele1VentPinAdress, HIGH);                       // Выключаем реле 1 - электрической вентиляции
  delay(1000);                                                  // Задерживаем вывод сообщения на 1 секунду
  lcd.print("OFF");                                             // Выводим сообщение о статусе электрической вентиляции

  lcd.setCursor(0, 1);                                          // Переводим курсор дисплея на 1 строку, 0 позиция
  lcd.print("Heater 1: ");                                      // Выводим сообщение о статусе обогревателя 1
  digitalWrite(rele2Heater1PinAdress, HIGH);                    // Выключаем реле 2 - обогреватель 1
  delay(1000);                                                  // Задерживаем вывод сообщения на 1 секунду
  lcd.print("OFF");                                             // Выводим сообщение о статусе обогревателя 1

  lcd.setCursor(0, 2);                                          // Переводим курсор дисплея на 2 строку, 0 позиция
  lcd.print("Heater 2: ");                                      // Выводим сообщение о статусе обогревателя 2
  digitalWrite(rele3Heater2PinAdress, HIGH);                    // Выключаем реле 3 - обогреватель 2
  delay(1000);                                                  // Задерживаем вывод сообщения на 1 секунду
  lcd.print("OFF");                                             // Выводим сообщение о статусе обогревателя 2

  lcd.setCursor(0, 3);                                          // Переводим курсор дисплея на 0 строку, 3 позиция
  lcd.print("Modem: ");                                         // Выводим сообщение о статусе заслонки 1
  digitalWrite(rele4ModemPinAdress, HIGH);                      // Выключаем реле 4 - модем
  delay(1000);                                                  // Задерживаем вывод сообщения на 1 секунду
  lcd.print("OFF");                                             // Выводим сообщение о статусе модема
  delay(4000);                                                  // Задерживаем сообщения на дисплее на 4 секунды
  //--------------------Закрытие заслонок-----------------------
  lcd.clear();                                                  // Очищаем дисплей
  lcd.setCursor(0, 0);                                          // Переводим курсор дисплея на 0 строку, 0 позиция
  lcd.print("Zaslon 1: ");                                      // Выводим сообщение о статусе заслонки 1
  servo(pos_close_zaslon1, SG90Zaslon1Pin);                     // Закрываем заслонку 1
  lcd.print("Close");                                           // Выводим сообщение о статусе заслонки 1
  delay(1000);                                                  // Задерживаем сообщение на 1 секунду

  lcd.setCursor(0, 1);                                          // Переводим курсор дисплея на 1 строку, 0 позиция
  lcd.print("Zaslon 2: ");                                      // Выводим сообщение о статусе заслонки 2
  servo(pos_close_zaslon2, SG90Zaslon2Pin);                     // Закрываем заслонку 2
  lcd.print("Close");                                           // Выводим сообщение о статусе заслонки 2
  delay(1000);                                                  // Задерживаем сообщение на 1 секунду

  lcd.setCursor(0, 2);                                          // Переводим курсор дисплея на 2 строку, 0 позиция
  lcd.print("Zaslon 3: ");                                      // Выводим сообщение о статусе заслонки 3
  servo(pos_close_zaslon3, SG90Zaslon3Pin);                     // Закрываем заслонку 3
  lcd.print("Close");                                           // Выводим сообщение о статусе заслонки 3
  delay(1000);                                                  // Задержка сообщения на дисплее на 1 секунду

  //--------------------Получение значений с датчиков-----------
  humidity_out = bme.readHumidity();                            // Получаем значние влажности снаружы
  temperature_out = bme.readTemperature();                      // Получаем значение температуры снаружы
  humidity_in = (dht1.readHumidity() + dht2.readHumidity()) / 2;// Получение средней влажности с двух датчиков DHT22
  temperature_in = (dht1.readTemperature() + dht2.readTemperature()) / 2;// Получение средней температуры с двух датчиков DHT22
  if (isnan(humidity_in) || isnan(temperature_in)) {            // Если значения не получено то
    temperature_in = 0;                                         // Заносим в переменную температуры внутри - 0
    humidity_in = 0;                                            // Заносим в переменную влажности внутри - 0
  }

  //--------------------Запускаем модем---------------------------
  lcd.clear();                                                  // Очищаем дисплей
  lcd.setCursor(0, 0);                                          // Переводим курсор дисплея на 0 строку, 0 позиция
  lcd.print("Init modem...");                                   // Выводим сообщение о начале инициализации модема
  digitalWrite(rele4ModemPinAdress, LOW);                       // Включаем реле 4 - питание модема
  TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);// Переводим модем на частоту 9600
  delay(3000);                                                  // Делаем задержку на время перевода модема на частоту 9600

  SerialMon.begin(9600);                                        // Преводим порт модема на скорость 9600
  delay(10);                                                    // Выполняем задержку для перевода порта на скорость 9600
  SerialAT.begin(9600);                                         // Преводим порт модема на скорость 9600
  delay(3000);                                                  // Выполняем задержку для перевода порта на скорость 9600

  modem.init();                                                 // Инициализируем модем
  SIMStatusModem();                                             // Выполняем проверку состояния сим-карты
  if (SIMStatus == true) {                                      // Если сим-карта готова то
    lcd.clear();                                                  // Очищаем дисплей
    lcd.setCursor(0, 0);                                          // Переводим курсор дисплея на 0 строку, 0 позиция
    lcd.print("Operator:");                                       // Выводим сообщение о текущем балансе на сим-карте
    lcd.print(modem.getOperator());                               // Получение текущего оператора сим-карты
    lcd.setCursor(0, 1);                                          // Переводим курсор дисплея на 1 строку, 0 позиция
    lcd.print("Balance:");                                        // Выводим сообщение о текущем балансе на сим-карте
    lcd.print(BalanceSIM());                                      // Выполняем запрос баланса на сим-карте
    lcd.setCursor(0, 2);                                          // Переводим курсор дисплея на 2 строку, 0 позиция
    lcd.print("Connect GPRS:");                                   // Выводим сообщение о подключении к GPRS (13 символов)
    modem.gprsConnect(apn, gprsUser, gprsPass);                   // Выполняем подключение к GPRS

    if (!modem.waitForNetwork(240000L))                           // Ожидание GPRS
    {
      lcd.setCursor(14, 2);                                       // Переводим курсор дисплея на 2 строку, 14 позиция
      lcd.print("ERR");                                           // Выводим сообщение о подключении к GPRS
      digitalWrite(ledAtention, HIGH);                            // Включаем светодиод сообщения об ошибке
      Atention = true;                                            // Сохраняем присутствие ошибки в системе
      GPRSStatus = false;                                         // Сохраняем статус GPRS подключения - ошибка
      delay(4000);                                                // Задержка сообщения на дисплее на 4 секунды
      return;
    }
    else
    {
      lcd.setCursor(14, 2);                                       // Переводим курсор дисплея на 2 строку, 14 позиция
      lcd.print("OK");                                            // Выводим сообщение о подключении к GPRS
      GPRSStatus = true;                                          // Сохраняем статус GPRS подключения - подключено
    }

    IPAddress local = modem.localIP();                            // Объявляем переменную для IP адреса
    lcd.setCursor(0, 3);                                          // Переводим курсор дисплея на 3 строку, 0 позиция
    lcd.print(local);                                             // Выводим IP адрес
    delay(4000);                                                  // Задержка сообщения на дисплее на 4 секунды

    //--------------------Запускаем MQTT--------------------------
    if (GPRSStatus == true)                                       // Если интернет соединение есть то подключаемся к MQTT
    {
      lcd.clear();                                                // Очищаем дисплей
      lcd.setCursor(0, 0);                                        // Переводим курсор дисплея на 0 строку, 0 позиция
      lcd.print("MQTT connect:");                                 // Выводим сообщение о подключении к MQTT (13 символов)

      //mqtt.setClient(modem);                                      // Устанавливаем клиента
      mqtt.setServer(mqtt_server, mqtt_port);                     // Устанавливаем сервер и порт для подключения
      mqtt.setCallback(mqttCallback);                             // Устанавливаем функцию считывания событий с брокера
      boolean status = mqtt.connect("GsmClient558", mqtt_user, mqtt_pass);// Выполняем подключение к MQTT
      StateMQTT();                                                // Выполняем запрос текущей попытки подключения
      if (status == false)                                        // Проверяем статус подключения
      {
        lcd.setCursor(0, 1);                                      // Переводим курсор дисплея на 1 строку, 0 позиция
        lcd.print(MQTTState);                                     // Выводим сообщение об ошибке подключении к MQTT
        digitalWrite(ledAtention, HIGH);                          // Включаем светодиод сообщения об ошибке
        Atention = true;                                          // Сохраняем присутствие ошибки в системе
        MQTTStatus = false;                                       // Сохраняем статус MQTT подключения - ошибка
        delay(4000);                                              // Задержка сообщения на дисплее на 4 секунды
        return;
      }
      else
      {
        lcd.setCursor(0, 1);                                      // Переводим курсор дисплея на 1 строку, 0 позиция
        lcd.print(MQTTState);                                     // Выводим сообщение об ошибке подключении к MQTT
        lcd.setCursor(0, 2);                                      // Переводим курсор дисплея на 1 строку, 0 позиция
        lcd.print("MQTT publish status");                         // Выводим сообщение о начале публикации статусов
        SubscribeAndPublicMQTT();                                 // Подписка на топики и публикация статуса оборудования
        PublishMQTTSensorsValue();                                // Публикация данных с датчиков
        Atention = false;                                         // Сохраняем присутствие ошибки в системе
        MQTTStatus = true;                                        // Сохраняем статус MQTT подключения - ошибка
      }
    }
    else
    {
      lcd.clear();                                                // Очищаем дисплей
      lcd.setCursor(0, 1);                                        // Переводим курсор дисплея на 0 строку, 14 позиция
      lcd.print("MQTT:OFF");                                      // Выводим сообщение об ошибке подключении к MQTT
      Atention = true;                                            // Сохраняем присутствие ошибки в системе
      MQTTStatus = false;                                         // Сохраняем статус MQTT подключения - ошибка
      delay(4000);                                                // Задержка сообщения на дисплее на 4 секунды
    }
  } else {
    lcd.setCursor(0, 1);                                          // Переводим курсор дисплея на 1 строку, 0 позиция
    lcd.print("SIMCARD Beeline ERR");                             // Выводим сообщение о текущем балансе на сим-карте
    delay(4000);                                                  // Задержка сообщения на дисплее на 4 секунды
  }

  menuSetup();                                                  // Запускаем инициализацию меню

  lcd.clear();                                                  // Очищаем дисплей
  int colSvet = analogRead(PIN_PHOTO_SENSOR);                   // Считываем состояние датчика уровня освещенности
  if (colSvet > 700)                                            // Проверяем уровень освещенности
  {
    rejim = true;                                               // Сохраняем статус режима устройства - автоматический
    PublishMassageMQTT(topicRejim, "1");                        // Публикуем статус режима устройства - автоматический
    digitalWrite(ledCPU, HIGH);                                 // Включаем светодиод CPU
    lcd.setCursor(8, 1);                                        // Переводим курсор дисплея на 1 строку, 9 позиция
    lcd.print("REJIM");                                         // Выводим сообщение о режиме устройства
    lcd.setCursor(9, 2);                                        // Переводим курсор дисплея на 2 строку, 9 позиция
    lcd.print("AUTO");                                          // Выводим сообщение о режиме устройства - автоматический
  }
  else
  {
    rejim = false;                                              // Сохраняем статус режима устройства - ручной
    digitalWrite(ledCPU, LOW);                                  // Выключаем светодиод CPU
    PublishMassageMQTT(topicRejim, "0");                        // Публикуем статус режима устройства - ручной
    lcd.setCursor(8, 1);                                        // Переводим курсор дисплея на 1 строку, 8 позиция
    lcd.print("REJIM");                                         // Выводим сообщение о режиме устройства
    lcd.setCursor(8, 2);                                        // Переводим курсор дисплея на 2 строку, 8 позиция
    lcd.print("MANUAL");                                        // Выводим сообщение о режиме устройства - ручной
  }
  delay(4000);                                                  // Задержка сообщения на дисплее на 2 секунды

  lcd.clear();                                                  // Очищаем дисплей
  lcd.setCursor(9, 1);                                          // Переводим курсор дисплея на 1 строку, 9 позиция
  lcd.print("LOAD");                                            // Выводим сообщение о завершении загрузки
  lcd.setCursor(7, 2);                                          // Переводим курсор дисплея на 1 строку, 7 позиция
  lcd.print("COMPLATE");                                        // Выводим сообщение о завершении загрузки
  delay(4000);                                                  // Задержка сообщения на дисплее на 2 секунды
  lcd.clear();                                                  // Очищаем дисплей
  TimerFreeTone(pinBeep, 2048, 1000);                           // Выводим звуковой сигнал с частотой 2048 Гц и длительностью 1 секунда

  DisplaySensorsValue();                                        // Вывод информацию полученной с датчиков
  DisplayTimeOnDigit();                                         // Вывод текущего времени на 4х сегментном дисплеее
  ShowDateOnDisplay();                                          // Вывод даты и времени в правом верхнем углу дисплея 2004 I2C 20х4

  Date = rtc.now().day();                                       // Получаем дату от часов
  Month = rtc.now().month();                                    // Получаем месяц от часов
  Year = rtc.now().year();                                      // Получаем год от часов
  Hour = rtc.now().hour();                                      // Получаем час от часов
  Minute = rtc.now().minute();                                  // Получаем минуты от часов
  //PublishMassageMQTT("S" + String(Hour) + ":" + String(Minute) + " " + String(Date) + "." + String(Month) + "." + String(Year) + "", topicLog);
  //mqtt.loop();
}

boolean GPRSConnect()                                           // Функция проверки/подключения к GPRS
{
  DBG("Проверяем интернет", "");
  if (modem.isGprsConnected() == false)                         // Если нет подключения к GPRS
  {
    DBG("Интрнета нет", "");
    digitalWrite(rele4ModemPinAdress, HIGH);                    // Выключаем реле 4 - питание модема
    delay(500);                                                 // Пауза после выключения модема
    digitalWrite(rele4ModemPinAdress, LOW);                     // Включаем реле 4 - питание модема
    TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);// Переводим модем на частоту 9600
    delay(1000);                                                // Делаем задержку на время перевода модема на частоту 9600

    SerialMon.begin(9600);                                      // Переводим порт модема на скорость 9600
    delay(10);                                                  // Выполняем задержку для перевода порта на скорость 9600
    SerialAT.begin(9600);                                       // Переводим порт модема на скорость 9600
    delay(1000);                                                // Выполняем задержку для перевода порта на скорость 9600

    modem.init();                                               // Инициализируем модем
    SIMStatusModem();                                           // Выполняем проверку состояния сим-карты
    if (SIMStatus == true) {                                      // Если сим-карта готова то
      modem.gprsConnect(apn, gprsUser, gprsPass);                 // Выполняем подключение к GPRS
      if (!modem.waitForNetwork(240000L)) {                       // Ожидание GPRS
        Atention = true;                                          // Сохраняем присутствие ошибки в системе
        GPRSStatus = false;                                       // Сохраняем статус GPRS подключения - ошибка
      }
      else {
        Atention = false;
        GPRSStatus = true;                                        // Сохраняем статус GPRS подключения - подключено
      }
    }
  }
  else {
    Atention = false;
    GPRSStatus = true;                                          // Сохраняем статус GPRS подключения - подключено
  }

  return GPRSStatus;                                            // Возвращаем состояние GPRS подключения
}
//-------------------Функция проверки состояния сим-карты-------
void SIMStatusModem()
{
  switch (modem.getSimStatus()) {                              // Выполняем запрос состояния сим-карты
    case SIM_READY:
      SIMStatus = true;                                        // Сим-карты готова к использованию
      break;
    case SIM_ERROR:                                            // Ошибка сим-карты
      SIMStatus = false;
      break;
    default:
      SIMStatus = false;                                       // Получено неизвестное значение, сохраняем статус сим-карты - ошибка
  }
}
//-------------------Функция запроса баланса на сим-карте-------
String BalanceSIM()
{
  String ussd_balance = modem.sendUSSD("#100#");                // Отправляем USSD запрос на получение баланса на английском языке
  Balance = GetFloatFromString(ussd_balance);                   // Парсинг текущего баланса
  return String(Balance);                                       // Возвращение полученного баланса на сим-карте
}

void StateMQTT()                                                // Функция получения состояния попытки подключения к MQTT
{
  switch (mqtt.state()) {
    case -4:
      MQTTState = "MQTT_CONNECTION_TIMEOUT";                    // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case -3:
      MQTTState = "MQTT_CONNECTION_LOST";                       // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case -2:
      MQTTState = "MQTT_CONNECT_FAILED";                        // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case -1:
      MQTTState = "MQTT_DISCONNECTED";                          // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case 0:
      MQTTState = "MQTT_CONNECTED";                             // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case 1:
      MQTTState = "MQTT_CONNECT_BAD_PROTOCOL";                  // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case 2:
      MQTTState = "MQTT_CONNECT_BAD_CLIENT_ID";                 // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case 3:
      MQTTState = "MQTT_CONNECT_UNAVAILABLE";                   // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case 4:
      MQTTState = "MQTT_CONNECT_BAD_CREDENTIALS";               // Сохраняем текущее состояние попытки подключения к MQTT
      break;
    case 5:
      MQTTState = "MQTT_CONNECT_UNAUTHORIZED";                  // Сохраняем текущее состояние попытки подключения к MQTT
      break;
  }
}

boolean MQTTConnect()                                           // Функция проверки/подключения к MQTT
{
  DBG("Проверяем интернет с MQTT", "");
  if (GPRSConnect() == true) {                                // Если есть подключение к GPRS то
    if (mqtt.connected() == false) {                              // Если нет подключения к MQTT то
      boolean status = mqtt.connect("GsmClient558", mqtt_user, mqtt_pass);// Выполняем подключение к MQTT
      if (status == false)                                      // Если не удалось выполнить подключение к MQTT серверу то
      {
        Atention = true;                                        // Сохраняем статус - ошибка в системе
        MQTTStatus = false;                                     // Сохраняем статус - нет подключения
        return false;                                           // Возвращаем false
      }
      else {                                                    // Удалось выполнить подключение к MQTT серверу
        Atention = false;                                       // Убираем статус ошибки в системе
        MQTTStatus = true;                                      // Сохраняем статус - подключено
        SubscribeAndPublicMQTT();                               // Выполняем подписку и публикацию состояния системы
      }
    }
    else {                                                      // MQTT подключение есть
      return true;
    }
  }
  else {                                                        // интернета нет
    return false;                                               // Возвращаем нет
  }
}

/*
  boolean MQTTConnect()                                           // Функция проверки/подключения к MQTT
  {
  DBG("Проверяем интернет с MQTT", "");
  if (mqtt.connected() == false) {                              // Если нет подключения к MQTT то
    if (GPRSConnect() == true) {                                // Если есть подключение к GPRS то
      boolean status = mqtt.connect("GsmClient558", mqtt_user, mqtt_pass);// Выполняем подключение к MQTT
      if (status == false)                                      // Если не удалось выполнить подключение к MQTT серверу то
      {
        Atention = true;                                        // Сохраняем статус - ошибка в системе
        MQTTStatus = false;                                     // Сохраняем статус - нет подключения
        return false;                                           // Возвращаем false
      }
      else {                                                    // Удалось выполнить подключение к MQTT серверу
        Atention = false;                                       // Убираем статус ошибки в системе
        MQTTStatus = true;                                      // Сохраняем статус - подключено
        SubscribeAndPublicMQTT();                               // Выполняем подписку и публикацию состояния системы
      }
    }
    else {                                                      // Нет GPRS подключения, возвращаем false
      return false;
    }
  }
  else {                                                        // MQTT подключение есть,
    return true;                                                // Возвращаем true
  }
  }*/

/*
  boolean MQTTConnect()                                           // Функция проверки/подключения к MQTT
  {
  if (GPRSConnect() == true)                                    // Если есть подключение к GPRS то
  {
    if (mqtt.connected() == false) {                            // Если нет подключения к MQTT то
      boolean status = mqtt.connect("GsmClient558", mqtt_user, mqtt_pass);// Выполняем подключение к MQTT
      if (status == false)                                      // Если не удалось выполнить подключение к MQTT серверу то
      {
        Atention = true;                                        // Сохраняем статус ошибки в системе
        return false;                                           // Возвращаем false
      }
      else {                                                    // Удалось выполнить подключение к MQTT серверу
        Atention = false;                                       // Убираем статус ошибки в системе
        SubscribeAndPublicMQTT();                               // Выполняем подписку и публикацию состояния системы
      }
    }
    else {                                                      // MQTT подключение есть,
      return true;                                              // Возвращаем true
    }
  }
  else {                                                        // Нет GPRS подключения, возвращаем false
    return false;
  }
  }
*/

//-------------------Функция вывода информации об ошибках-----
void ConnectInfo()
{
  lcd.clear();                                                // Выполняем очистку дисплея
  lcd.setCursor(0, 0);                                        // Переводим курсор дисплея на 0 строку, 0 позиция
  lcd.print("GPRS: ");                                        // Выводим сообщение о GPRS соединении
  if (modem.isGprsConnected() == true) {                      // Выполняем проверку GPRS соединения, если есть то
    lcd.print("OK");                                          // Выводим сообщение, что GPRS соединение есть

    IPAddress local = modem.localIP();                        // Объявляем переменную для IP адреса
    lcd.setCursor(0, 1);                                      // Переводим курсор дисплея на 1 строку, 0 позиция
    lcd.print(local);                                         // Выводим IP адрес

    lcd.setCursor(0, 2);                                      // Переводим курсор дисплея на 2 строку, 0 позиция
    lcd.print("MQTT: ");                                      // Выводим сообщение о MQTT соединении
    StateMQTT();                                              // Выполняем проверку MQTT соединения
    lcd.print(MQTTState);                                     // Выводим статус MQTT соединения
  } else {
    lcd.print("Error");                                       // Выводим сообщение, что GPRS соединение есть

    lcd.setCursor(0, 3);                                      // Переводим курсор дисплея на 2 строку, 0 позиция
    lcd.print("MQTT: -");                                     // Выводим сообщение о MQTT соединении
  }
  delay(8000);                                                // Задерживаем сообщение на дисплее на 5 секунд
}

//-------------------Функция вывода информации об ошибках-----
void AlertInfo()
{
  if (Atention == false) {
    lcd.clear();                                              // Очищаем дисплей
    lcd.setCursor(0, 0);                                      // Переводим курсор дисплея на 0 строку, 0 позиция
    lcd.print("System status: OK");                           // Выводим сообщение об отсутствии ошибок в системе
  } else {
    lcd.clear();                                              // Очищаем дисплей

    lcd.setCursor(0, 0);                                      // Переводим курсор дисплея на 0 строку, 0 позиция
    lcd.print("Sim status: ");                                // Выводим сообщение о статусе сим-карты
    if (SIMStatus == false) {
      lcd.print("Error");                                     // Выводим сообщение, что есть проблемы с сим-картой

      lcd.setCursor(0, 1);                                    // Переводим курсор дисплея на 1 строку, 0 позиция
      lcd.print("Balance: - ");                               // Выводим сообщение о балансе на сим-карте

      lcd.setCursor(0, 2);                                    // Переводим курсор дисплея на 1 строку, 0 позиция
      lcd.print("GPRSS tatus: - ");                           // Выводим сообщение о статусе интрнета

      lcd.setCursor(0, 3);                                    // Переводим курсор дисплея на 1 строку, 0 позиция
      lcd.print("MQTT Status: - ");                           // Выводим сообщение о статусе подключения к MQTT

    } else {
      lcd.print("OK");                                        // Выводим сообщение, что сим-карта установлена и готова

      lcd.setCursor(0, 1);                                    // Переводим курсор дисплея на 1 строку, 0 позиция
      lcd.print("Balance: ");                                 // Выводим сообщение о балансе на сим-карте
      lcd.print(BalanceSIM());                                // Выполняем запрос баланса на сим-карте

      lcd.setCursor(0, 2);                                    // Переводим курсор дисплея на 2 строку, 0 позиция
      lcd.print("GPRS: ");                                    // Выводим сообщение о GPRS соединении
      if (modem.isGprsConnected() == true) {                  // Выполняем проверку GPRS соединения, если есть то
        lcd.print("OK");                                      // Выводим сообщение, что GPRS соединение есть

        lcd.setCursor(0, 3);                                  // Переводим курсор дисплея на 3 строку, 0 позиция
        lcd.print("MQTT: ");                                  // Выводим сообщение о MQTT соединении
        StateMQTT();                                          // Выполняем проверку MQTT соединения
        lcd.print(MQTTState);                                 // Выводим статус MQTT соединения
      } else {
        lcd.print("Error");                                   // Выводим сообщение, что GPRS соединение есть

        lcd.setCursor(0, 3);                                  // Переводим курсор дисплея на 3 строку, 0 позиция
        lcd.print("MQTT: -");                                 // Выводим сообщение о MQTT соединении
      }
    }
  }
  delay(8000);                                                // Задерживаем сообщение на дисплее на 5 секунд
}
//-------------------Функция подписки и публикации состояния--
void SubscribeAndPublicMQTT()
{
  DBG("Подписываемся", MQTTState);
  mqtt.publish(topicZaslon1, String(statusZaslon1 ? "1" : "0").c_str(), Retained);  // Публикуем статус заслонки 1
  mqtt.publish(topicZaslon2, String(statusZaslon2 ? "1" : "0").c_str(), Retained);  // Публикуем статус заслонки 2
  mqtt.publish(topicZaslon3, String(statusZaslon3 ? "1" : "0").c_str(), Retained);  // Публикуем статус заслонки 3
  mqtt.publish(topicVent, String(statusVent ? "1" : "0").c_str(), Retained);        // Публикуем статус электрической вентиляции
  mqtt.publish(topicHeater1, String(statusHeater1 ? "1" : "0").c_str(), Retained);  // Публикуем статус обогревателя 1
  mqtt.publish(topicHeater2, String(statusHeater2 ? "1" : "0").c_str(), Retained);  // Публикуем статус обогревателя 2
  mqtt.publish(topicRejim, String(rejim ? "1" : "0").c_str(), Retained);            // Публикуем статус ражима автоматический/ручной

  mqtt.publish(topicZaslon1i, String(statusZaslon1 ? "1" : "0").c_str(), Retained); // Публикуем статус - индикатор заслонки 1
  mqtt.publish(topicZaslon2i, String(statusZaslon2 ? "1" : "0").c_str(), Retained); // Публикуем статус - индикатор заслонки 2
  mqtt.publish(topicZaslon3i, String(statusZaslon3 ? "1" : "0").c_str(), Retained); // Публикуем статус - индикатор заслонки 3
  mqtt.publish(topicVenti, String(statusVent ? "1" : "0").c_str(), Retained);       // Публикуем статус - индикатор электрической вентиляции
  mqtt.publish(topicHeater1i, String(statusHeater1 ? "1" : "0").c_str(), Retained); // Публикуем статус - индикатор обогревателя 1
  mqtt.publish(topicHeater2i, String(statusHeater2 ? "1" : "0").c_str(), Retained); // Публикуем статус - индикатор обогревателя 2
  mqtt.publish(topicBalance, String(Balance).c_str(), Retained);                    // Публикуем текущий баланс на сим-карте

  mqtt.subscribe(topicZaslon1);                               // Подписываемся на топик заслонки 1
  mqtt.subscribe(topicZaslon2);                               // Подписываемся на топик заслонки 2
  mqtt.subscribe(topicZaslon3);                               // Подписываемся на топик заслонки 3
  mqtt.subscribe(topicVent);                                  // Подписываемся на топик электрической вентиляции
  mqtt.subscribe(topicHeater1);                               // Подписываемся на топик обогревателя 1
  mqtt.subscribe(topicHeater2);                               // Подписываемся на топик обогревателя 2
  mqtt.subscribe(topicGetBalance);                            // Подписываемся на топик запроса баланса
  mqtt.subscribe(topicSettingsHumidityzaslon2);               // Подписываемся на топик влажности заслонки 2
  mqtt.subscribe(topicSettingsHumidityzaslon3);               // Подписываемся на топик влажности заслонки 3
  mqtt.subscribe(topicSettingsMaxTemperatureIn);              // Подписываемся на топик максимальной температуры в гараже
}

//-------------------Функция публикации данных с датчиков------
void PublishMQTTSensorsValue()
{
  DBG("MQTT STate", MQTTState);
  DBG("MQTT STate", MQTTState);
  DBG("END send data sensor", "++");

  lcd.setCursor(18, 3);                                       // Переводим курсор дисплея на 3 строку, 18 позиция
  lcd.print("->");                                            // Выводим сообщение о завершении загрузки
  mqtt.publish (topicTemperatureIn, String(temperature_in).c_str(), Retained);  // Публикация температуры внутри гаража
  mqtt.publish (topicHumidityIn, String(humidity_in).c_str(), Retained);        // Публикация влажности внутри гаража

  mqtt.publish (topicTemperatureOut, String(temperature_out).c_str(), Retained);// Публикация температуры с наружи гаража
  mqtt.publish (topicHumidityOut, String(humidity_out).c_str(), Retained);      // Публикация влажности с наружи гаража
  Pressure = bme.readPressure();                                                // Получение текущего атмосферного давления
  Pressure = Pressure * 0.0075006157584565633395127122506607;                   // Корректировка атмосферного давления
  mqtt.publish(topicPressureOut, String(Pressure).c_str(), Retained);           // Публикация атмосферного давлени снаружи гаража
  //mqtt.publish(topicHeightOut, String(bme.readAltitude(SEALEVELPRESSURE_HPA)).c_str(), true); // Публикация данных о высоте датчика над уровнем моря
  lcd.setCursor(18, 3);                                      // Переводим курсор дисплея на 3 строку, 18 позиция
  lcd.print("OK");                                           // Выводим сообщение о завершении загрузки

}

//-------------------Функция публикации сообщения на MQTT----
void PublishMassageMQTT(const char* Topic, String Massage)
{
  if (MQTTStatus == true) {
    lcd.setCursor(18, 3);                                    // Переводим курсор дисплея на 3 строку, 18 позиция
    lcd.print("->");                                         // Выводим сообщение о завершении загрузки
    if (mqtt.publish(Topic, String(Massage).c_str(), Retained)) { // Публикация сообщения на MQTT
      lcd.setCursor(18, 3);                                  // Переводим курсор дисплея на 3 строку, 18 позиция
      lcd.print("OK");                                       // Выводим сообщение о завершении загрузки
    }
    else {
      lcd.setCursor(18, 3);                                  // Переводим курсор дисплея на 3 строку, 18 позиция
      lcd.print("ER");                                       // Выводим сообщение о завершении загрузки
    }
  }
}

//-------------------Функция проверки изменений в подписанных топиках
void mqttCallback(char* topic, byte * payload, unsigned int len)
{
  payload[len] = '\0';
  String s = String((char*)payload);
  int f = s.toInt();                                          // Переводим значение полученное из топика в числовое
  if (republicStatus == false)
  {
    //-------------------- Заслонка 1-------------------------
    if (String(topic) == topicZaslon1) {                      // Значение из топика заслонки 1
      if (rejim == false) {                                   // Если автоматический режим выключен то
        if (f == 1) {                                         // Если значение топика ровно 1
          setZaslon1(true);                                   // Открываем заслонку 1
        }
        else {                                                // Если значение топика равно 0
          setZaslon1(false);                                  // Закрываем заслонку 1
        }
        republicStatus = true;                                // Включаем режим повторной публикации
      }
      else                                                    // Если автоматический режим включен то
        PublishMassageMQTT(topicZaslon1, String(0).c_str());  // Публикуем обратно в топик значение 0
    }
    //-------------------- Заслонка 2-------------------------
    if (String(topic) == topicZaslon2) {                      // Значение из топика заслонки 2
      if ( rejim == false) {                                  // Если автоматический режим выключен то
        if (f == 1) {                                         // Если значение топика ровно 1
          setZaslon2(true);                                   // Открываем заслонку 2
        }
        else {                                                // Если значение топика равно 0
          setZaslon2(false);                                  // Закрываем заслонку 2
        }
        republicStatus = true;                                // Включаем режим повторной публикации
      }
      else                                                    // Если автоматический режим включен то
        PublishMassageMQTT(topicZaslon2, String(0).c_str());  // Публикуем обратно в топик значение 0
    }
    //-------------------- Заслонка 3-------------------------
    if (String(topic) == topicZaslon3) {                      // Значение из топика заслонки 3
      if ( rejim == false) {                                  // Если автоматический режим выключен то
        if (f == 1) {                                         // Если значение топика ровно 1
          setZaslon3(true);                                   // Открываем заслонку 3
        }
        else {                                                // Если значение топика равно 0
          setZaslon3(false);                                  // Закрываем заслонку 3
        }
        republicStatus = true;                                // Включаем режим повторной публикации
      }
      else                                                    // Если автоматический режим включен то
        PublishMassageMQTT(topicZaslon3, String(0).c_str());  // Публикуем обратно в топик значение 0
    }
    //-------------------- Электрическая вентиляция-----------
    if (String(topic) == topicVent) {                         // Значение из топика электрической вентиляции
      if ( rejim == false) {                                  // Если автоматический режим выключен то
        if (f == 1) {                                         // Если значение топика ровно 1
          setVent(true);                                      // Включаем электрическую вентиляцию
        }
        else {                                                // Если значение топика равно 0
          setVent(false);                                     // Выключаем электрическую вентиляцию
        }
        republicStatus = true;                                // Включаем режим повторной публикации
      }
      else                                                    // Если автоматический режим включен то
        PublishMassageMQTT(topicVent, String(0).c_str());     // Публикуем обратно в топик значение 0
    }
    //-------------------- Обогреватель 1---------------------
    if (String(topic) == topicHeater1) {                      // Значение из топика обогревателя 1
      if (f == 1) {                                           // Если значение топика ровно 1
        setHeater1(true);                                     // Включаем обогреватель 1
      }
      else {                                                  // Если значение топика ровно 0
        setHeater1(false);                                    // Выключаем обогреватель 1
      }
      republicStatus = true;                                  // Включаем режим повторной публикации
    }
    //-------------------- Обогреватель 2---------------------
    if (String(topic) == topicHeater2) {                      // Значение из топика обогревателя 2
      if (f == 1) {                                           // Если значение топика ровно 1
        setHeater2(true);                                     // Включаем обогреватель 2
      }
      else {                                                  // Если значение топика ровно 0
        setHeater2(false);                                    // Выключаем обогреватель 2
      }
      republicStatus = true;                                  // Включаем режим повторной публикации
    }
  }
  //-------------------- Запрос баланса-----------------------
  if (String(topic) == topicGetBalance)                       // Значение из топика запроса баланса
  {
    if (f == 1) {                                             // Если значение топика ровно 1
      BalanceSIM();                                           // Выполняем запрос баланса
      PublishMassageMQTT(topicBalance, Balance);              // Публикуем полученный баланс сим-карты в топик
      PublishMassageMQTT(topicGetBalance, "0");               // Возвращаем 0 в топик запроса баланса
    }
  }
  //-------------------- Настройки влажности заслонки 2-------
  if (String(topic) == topicSettingsHumidityzaslon2)          // Значение из топика установки влажности заслонки 2
  {
    SettingsHumidityzaslon2 = f;                              // Устанавливаем в переменную полученного значения
    SaveData();                                               // Выполняем сохранение настроек
  }
  //-------------------- Настройки влажности заслонки 3-------
  if (String(topic) == topicSettingsHumidityzaslon3)          // Значение из топика установки влажности заслонки 3
  {
    SettingsHumidityzaslon3 = f;                              // Устанавливаем в переменную полученного значения
    SaveData();                                               // Выполняем сохранение настроек
  }
  //-------------------- Настройки максимальной температуры в гараже
  if (String(topic) == topicSettingsMaxTemperatureIn)         // Значение из топика установки максимальной температуры в гараже
  {
    SettingsMaxTemperatureIn = f;                             // Устанавливаем в переменную полученного значения
    SaveData();                                               // Выполняем сохранение настроек
  }
}

//-------------------Вывод сообщений на дисплей 20х4----------
void DisplayMessage(String message)
{
  lcd.clear();                                                // Очищаем дисплей
  int lenMassage = message.length();                          // Получаем длину выводимой сообщения
  int halfMassage = lenMassage / 2;                           // Получаем длину половины сообщения
  int stratMassege = 11 - halfMassage;                        // Получаем позицию начала вывода сообщения
  lcd.setCursor(stratMassege, 2);                             // Переводим курсор дисплея на 2 строку, расчетная позиция
  lcd.print(message);                                         // Выводим сообщение
  delay(2000);                                                // Задерживаем сообщение на 2 секунды
  lcd.clear();                                                // Очищаем дисплей
}
//------------------Функция извлечения числа из строки--------
float GetFloatFromString(String str)                          // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
{
  bool flag = false;
  String result = "";
  str.replace(",", ".");                                      // Если в качестве разделителя десятичных используется запятая - меняем её на точку.

  for (int i = 0; i < str.length(); i++) {
    if (isDigit(str[i]) || (str[i] == (char)46 && flag)) {    // Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания),
      if (result == "" && i > 0 && (String)str[i - 1] == "-") {// Нельзя забывать, что баланс может быть отрицательным
        result += "-";                                        // Добавляем знак в начале
      }
      result += str[i];                                       // начинаем собирать их вместе
      if (!flag) flag = true;                                 // Выставляем флаг, который указывает на то, что сборка числа началась.
    }
    else  {                                                   // Если цифры закончились и флаг говорит о том, что сборка уже была,
      if (str[i] != (char)32) {                               // Если порядок числа отделен пробелом - игнорируем его, иначе...
        if (flag) break;                                      // ...считаем, что все.
      }
    }
  }
  return result.toFloat();                                    // Возвращаем полученное число.
}
//------------------Получение температуры и влажности с внутреннего датчика DHT22 и внешнего датчика BME280
void GetValueSensors(void)
{
  if (millis() - TimerGetValueSensors > 300000)//TimerGetValueSensors.isReady())
  {
    TimerGetValueSensors = millis();
    humidity_out = bme.readHumidity();                        // Получаем значение влажности снаружи
    temperature_out = bme.readTemperature();                  // Получаем значение температуры снаружи
    humidity_in = (dht1.readHumidity() + dht2.readHumidity()) / 2; // Получение средней влажности с двух датчиков DHT22
    temperature_in = (dht1.readTemperature() + dht2.readTemperature()) / 2; // Получение средней температуры с двух датчиков DHT22
    if (isnan(humidity_in) || isnan(temperature_in)) {        // Если значения не получено то
      temperature_in = 0;                                     // Заносим в переменную температуры внутри - 0
      humidity_in = 0;                                        // Заносим в переменную влажности внутри - 0
      return;
    }
  }
}
//--------------------Проверка фото сенсора для включения/выключения дисплея
void OnOffDisplay()
{
  if (millis() - TimerDisplayOnOff > 1000)//TimerPhotoSensor.isReady())//Выполняем проверку 1 раз в 1 секунду
  {
    TimerDisplayOnOff = millis();
    int val = analogRead(PIN_PHOTO_SENSOR);                 // Получаем значение уровня света в помечени
    if (val > 700) {                                        // Если значение больше 700 то темно, включаем автоматический режим
      lcd.noDisplay();                                      //  Выключаем  дисплей 2004 I2C 20х4
      lcd.setBacklight(0);                                  //  Отключаем подсветку дисплея 2004 I2C 20х4
    } else {
      lcd.display();                                        //  Включаем  дисплей 2004 I2C 20х4
      lcd.setBacklight(1);                                  //  Включаем  подсветку дисплея 2004 I2C 20х4
    }
  }
}
//--------------------Проверка фото сенсора для включения/выключения автоматического режима
void StateRejim()
{
  if (millis() - TimerPhotoSensor > 600000)//TimerPhotoSensor.isReady())//Выполняем проверку 1 раз в 10 минут
  {
    TimerPhotoSensor = millis();
    int val = analogRead(PIN_PHOTO_SENSOR);                 // Получаем значение уровня света в помечени
    // DBG("уровень света - ", val);
    if (val > 700) {                                        // Если значение больше 700 то темно, включаем автоматический режим
      rejim = true;                                         // Сохраняем статус автоматического режима - включен
      PublishMassageMQTT(topicRejim, String(1).c_str());    // Отправляем статус автоматического режима в MQTT - включен
      digitalWrite(ledCPU, HIGH);                           // Включаем светодиод CPU - автоматически режим
    }
    else {
      rejim = false;                                        // Сохраняем статус автоматического режима - выключен
      PublishMassageMQTT(topicRejim, String(0).c_str());    // Отправляем статус автоматического режима в MQTT - выключен
      digitalWrite(ledCPU, LOW);                            // Выключаем светодиод CPU - автоматически режим
    }
  }
}
//--------------------Время на 4 сегментном дисплее----------
void DisplayTimeOnDigit(void)
{
  if (millis() - TimerShowDijit > 1000)//TimerShowDijit.isReady())
  {
    TimerShowDijit = millis();
    DateTime now = rtc.now();                                 // Считывание с RTC DS1307 текущей даты/времени
    Hour = now.hour(), DEC;                                   // Считываем часы с RTC DS1307
    Minute = now.minute(), DEC;                               // Считываем минуты с RTC DS1307

    tm1637.display(0, Hour / 10);                             // Отображаем час в 1 сегменте
    tm1637.display(1, Hour % 10);                             // Отображаем час в 2 сегменте
    tm1637.display(2, Minute / 10);                           // Отображаем минуты во 1 сегменте
    tm1637.display(3, Minute % 10);                           // Отображаем минуты во 2 сегменте

    if (point_on_off) {                                       // Если отображать точку то
      tm1637.point(POINT_ON);                                 // Отображаем точку на часах
      point_on_off = false;                                   // Отменяем отображение точек
    } else {                                                  // Если точку не отображать то
      tm1637.point(POINT_OFF);                                // Скрываем точку на часах
      point_on_off = true;                                    // Включаем отображение точек
    }
  }
}
//--------------------Функция вывода даты---------------------
void ShowDateOnDisplay(void)
{
  lcd.setCursor(15, 0);                                       // Переводим курсор дисплея на 0 строку, 15 позиция
  if (Date < 10)                                              // Если дата меньше 10, добавляем 0
    lcd.print("0");                                           // Добавляем 0 к текущей дате
  lcd.print(Date);                                            // Выводим текущий день
  lcd.print(".");                                             // Добавляем точку после даты
  if (Month < 10)                                             // Если месяц меньше 10, добавляем 0
    lcd.print("0");                                           // Добавляем 0 к текущему месяцу
  lcd.print(Month);                                           // Выводим текущий месяц
}
//--------------------Вывод информации с датчиков-------------
void DisplaySensorsValue(void)
{
  lcd.clear();                                                // Очищаем дисплей
  lcd.setCursor(0, 0);                                        // Переводим курсор дисплея на 0 строку, 0 позиция
  lcd.print("T.in:");                                         // Выводим текст - температура внутри
  lcd.print(temperature_in);                                  // Выводим значение - температура внутри
  lcd.print("C");                                             // Выводим текст - градус Цельсия

  lcd.setCursor(0, 1);                                        // Переводим курсор дисплея на 1 строку, 0 позиция
  lcd.print("T.ou:");                                         // Выводим текст - температура снаружи
  lcd.print(temperature_out);                                 // Выводим значение - температура снаружи
  lcd.print("C");                                             // Выводим текст - градус Цельсия

  lcd.setCursor(0, 2);                                        // Переводим курсор дисплея на 2 строку, 0 позиция
  lcd.print("H.in:");                                         // Выводим текст - влажность внутри
  lcd.print(humidity_in);                                     // Выводим значение - влажность внутри
  lcd.print("%");                                             // Выводим текст - влажность

  lcd.setCursor(0, 3);                                        // Переводим курсор дисплея на 3 строку, 0 позиция
  lcd.print("H.ou:");                                         // Выводим текст - влажность снаружи
  lcd.print(humidity_out);                                    // Выводим значение - влажность снаружи
  lcd.print("%");                                             // Выводим текст - влажность
}
//--------------------Управление сервоприводом без библиотеки-
void servo(int servopos, int servopin)
{
  digitalWrite(servopin, LOW);
  incomingByte = servopos - 48;
  pos = pos * 10 + incomingByte;
  for (int i = 1; i <= 180; i++) {
    digitalWrite(servopin, HIGH);
    delayMicroseconds(pos);
    digitalWrite(servopin, LOW);
    delayMicroseconds(20000 - pos);
    delay(1);
  }
  pos = 0;
}
//--------------------Загрузка настроек-----------------------
void LoadData() {
  byte addr = 0;
  SettingsHumidityzaslon2 = EEPROM.read(addr++);
  SettingsHumidityzaslon3 =    EEPROM.read(addr++);
  SettingsMaxTemperatureIn = float((((EEPROM.read(addr++) << 0) & 0xFF) + ((EEPROM.read(addr++) << 8) & 0xFF00)) / 100.00);
}

//--------------------Обновление настроек---------------------
void UpdateData()
{
  EEPROM.update(0, SettingsHumidityzaslon2);
  EEPROM.update(1, SettingsHumidityzaslon3);
  EEPROM.update(2, SettingsMaxTemperatureIn);
}
//--------------------Сохранение настроек---------------------
void SaveData() {
  byte addr = 0;
  EEPROM.write(addr++, SettingsHumidityzaslon2);
  EEPROM.write(addr++, SettingsHumidityzaslon3);
  EEPROM.write(addr++, ((int(SettingsMaxTemperatureIn * 100) >> 0) & 0xFF));
  EEPROM.write(addr++, ((int(SettingsMaxTemperatureIn * 100) >> 8) & 0xFF));
}
//--------------------Управление заслонкой 1------------------
void setZaslon1(bool Zaslon)                                  // Функция открытия/закрытия заслонки 1
{
  //--------------------Открываем заслонку 1------------------
  if (Zaslon == true && statusZaslon1 == false) {
    if (statusHeater1 == true) {                              // Выключаем обогреватель 1 если он включен, чтобы не тратить тепло
      statusHeater1 = false;                                  // Сохраняем статус обогревателя 1 - выключено
      digitalWrite(rele2Heater1PinAdress, HIGH);              // Выключаем реле 2 - обогревателя 1
      digitalWrite(ledHeater1, LOW);                          // Выключаем светодиод обогревателя 1
      PublishMassageMQTT(topicHeater1i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 1
      PublishMassageMQTT(topicHeater1, String(0).c_str());    // Отправляем статус обогревателя 1
    }
    if (statusHeater2 == true) {                              // Выключаем обогреватель 2 если он включен, чтобы не тратить тепло
      statusHeater2 = false;                                  // Сохраняем статус обогревателя 2 - выключено
      digitalWrite(rele3Heater2PinAdress, HIGH);              // Выключаем реле 3 - обогревателя 2
      digitalWrite(ledHeater2, LOW);                          // Выключаем светодиод обогревателя 2
      PublishMassageMQTT(topicHeater2i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 2
      PublishMassageMQTT(topicHeater2, String(0).c_str());    // Отправляем статус обогревателя 2
    }

    DisplayMessage("OPEN ZASLON 1");                          // Выводим сообщение об открытии заслонки 1
    statusZaslon1 = true;                                     // Сохраняем статус заслонки 1 - открыта
    servo(pos_open_zaslon1, SG90Zaslon1Pin);                  // Открываем заслонку 1
    digitalWrite(ledZaslon1, HIGH);                           // Включаем светодиод заслонки 1
    PublishMassageMQTT(topicZaslon1i, String(1).c_str());     // Отправляем статус - индикатор заслонки 1
    PublishMassageMQTT(topicZaslon1, String(1).c_str());      // Отправляем статус заслонки 1
  }
  //--------------------Закрываем заслонку 1------------------
  if (Zaslon == false && statusZaslon1 == true) {
    DisplayMessage("CLOSE ZASLON 1");                         // Выводим сообщение о закрытии заслонки 1
    statusZaslon1 = false;                                    // Сохраняем статус заслонки 1 - закрыта
    servo(pos_close_zaslon1, SG90Zaslon1Pin);                 // Закрываем заслонку 1
    digitalWrite(ledZaslon1, LOW);                            // Выключаем светодиод заслонки 1
    PublishMassageMQTT(topicZaslon1i, String(0).c_str());     // Отправляем статус - индикатор заслонки 1
    PublishMassageMQTT(topicZaslon1, String(0).c_str());      // Отправляем статус заслонки 1
  }
}
//--------------------Управление заслонкой 2------------------
void setZaslon2(bool Zaslon)                                  // Функция открытия/закрытия заслонки 2
{
  //--------------------Открываем заслонку 2------------------
  if (Zaslon == true && statusZaslon2 == false) {             // Открываем заслонку 2
    if (statusHeater1 == true) {                              // Выключаем обогреватель 1 если он включен, чтобы не тратить тепло
      statusHeater1 = false;                                  // Сохраняем статус обогревателя 1 - выключено
      digitalWrite(rele2Heater1PinAdress, HIGH);              // Выключаем реле 2 - обогревателя 1
      digitalWrite(ledHeater1, LOW);                          // Выключаем светодиод обогревателя 1
      PublishMassageMQTT(topicHeater1i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 1
      PublishMassageMQTT(topicHeater1, String(0).c_str());    // Отправляем статус обогревателя 1
    }
    if (statusHeater2 == true) {                              // Выключаем обогреватель 2 если он включен, чтобы не тратить тепло
      statusHeater2 = false;                                  // Сохраняем статус обогревателя 2 - выключено
      digitalWrite(rele3Heater2PinAdress, HIGH);              // Выключаем реле 3 - обогревателя 2
      digitalWrite(ledHeater2, LOW);                          // Выключаем светодиод обогревателя 2
      PublishMassageMQTT(topicHeater2i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 2
      PublishMassageMQTT(topicHeater2, String(0).c_str());    // Отправляем статус обогревателя 2
    }
    if (statusZaslon1 == false) {                             // Открываем заслонку 1
      statusZaslon1 = true;                                   // Сохраняем статус заслонки 1 - открыта
      servo(pos_open_zaslon1, SG90Zaslon1Pin);                // Открываем заслонку 1
      digitalWrite(ledZaslon1, HIGH);                         // Включаем светодиод заслонки 1
      PublishMassageMQTT(topicZaslon1i, String(1).c_str());   // Отправляем статус заслонки 1
      PublishMassageMQTT(topicZaslon1, String(1).c_str());    // Отправляем статус заслонки 1
    }

    DisplayMessage("OPEN ZASLON 2");                          // Выводим сообщение об открытии заслонки 2
    statusZaslon2 = true;                                     // Сохраняем статус заслонки 2 - открыта
    servo(pos_open_zaslon2, SG90Zaslon2Pin);                  // Открываем заслонку 2
    digitalWrite(ledZaslon2, HIGH);                           // Включаем светодиод заслонки 2
    PublishMassageMQTT(topicZaslon2i, String(1).c_str());     // Отправляем статус - индикатор заслонки 2
    PublishMassageMQTT(topicZaslon2, String(1).c_str());      // Отправляем статус заслонки 2
  }
  //--------------------Закрываем заслонку 2------------------
  if (Zaslon == false && statusZaslon2 == true)               // Закрываем заслонку 2
  {
    if (statusZaslon1 == true) {                              // Закрываем заслонку 1
      statusZaslon1 = false;                                  // Сохраняем статус заслонки 1 - закрыта
      servo(pos_close_zaslon1, SG90Zaslon1Pin);               // Закрываем заслонку 1
      digitalWrite(ledZaslon1, LOW);                          // Выключаем светодиод заслонки 1
      PublishMassageMQTT(topicZaslon1i, String(0).c_str());   // Отправляем статус - индикатор заслонки 1
      PublishMassageMQTT(topicZaslon1, String(0).c_str());    // Отправляем статус заслонки 1
    }
    if (statusZaslon3 == true) {                              // Закрываем заслонку 3
      statusZaslon3 = false;                                  // Сохраняем статус заслонки 3 - закрыта
      servo(pos_close_zaslon3, SG90Zaslon3Pin);               // Закрываем заслонку 3
      digitalWrite(ledZaslon3, LOW);                          // Выключаем светодиод заслонки 3
      PublishMassageMQTT(topicZaslon3i, String(0).c_str());   // Отправляем статус - индикатор заслонки 3
      PublishMassageMQTT(topicZaslon3, String(0).c_str());    // Отправляем статус заслонки 3
    }
    if (statusVent == true) {                                 // Выключаем электрический вентилятор
      statusVent = false;                                     // Сохраняем статус электрического вентилятора - отключен
      digitalWrite(rele1VentPinAdress, HIGH);                 // Выключаем реле 1 - электрического вентилятора
      digitalWrite(ledVent, LOW);                             // Выключаем светодиод электрического вентилятора
      PublishMassageMQTT(topicVenti, String(0).c_str());      // Отправляем статус - индикатор электрического вентилятора
      PublishMassageMQTT(topicVent, String(0).c_str());       // Отправляем статус электрического вентилятора
    }

    DisplayMessage("CLOSE ZASLON 2");                         // Выводим сообщение о закрытии заслонки 2
    statusZaslon2 = false;                                    // Сохраняем статус заслонки 2 - закрыта
    servo(pos_close_zaslon2, SG90Zaslon2Pin);                 // Закрываем заслонку 2
    digitalWrite(ledZaslon2, LOW);                            // Выключаем светодиод заслонки 2
    PublishMassageMQTT(topicZaslon2i, String(0).c_str());     // Отправляем статус - индикатор заслонки 2
    PublishMassageMQTT(topicZaslon2, String(0).c_str());      // Отправляем статус заслонки 2
  }
}
//--------------------Управление заслонкой 2------------------
void setZaslon3(bool Zaslon)                                  // Функция открытия/закрытия заслонки 3
{
  //--------------------Открываем заслонку 3------------------
  if (Zaslon == true && statusZaslon3 == false)               // Открываем заслонку 3
  {
    if (statusHeater1 == true) {                              // Выключаем обогреватель 1 если он включен, чтобы не тратить тепло
      statusHeater1 = false;                                  // Сохраняем статус обогревателя 1 - выключено
      digitalWrite(rele2Heater1PinAdress, HIGH);              // Выключаем реле 2 - обогревателя 1
      digitalWrite(ledHeater1, LOW);                          // Выключаем светодиод обогревателя 1
      PublishMassageMQTT(topicHeater1i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 1
      PublishMassageMQTT(topicHeater1, String(0).c_str());    // Отправляем статус обогревателя 1
    }
    if (statusHeater2 == true) {                              // Выключаем обогреватель 2 если он включен, чтобы не тратить тепло
      statusHeater2 = false;                                  // Сохраняем статус обогревателя 2 - выключено
      digitalWrite(rele3Heater2PinAdress, HIGH);              // Выключаем реле 3 - обогревателя 2
      digitalWrite(ledHeater2, LOW);                          // Выключаем светодиод обогревателя 2
      PublishMassageMQTT(topicHeater2i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 2
      PublishMassageMQTT(topicHeater2, String(0).c_str());    // Отправляем статус обогревателя 2
    }

    DisplayMessage("OPEN ZASLON 3");                          // Выводим сообщение об открытии заслонки 3
    statusZaslon3 = true;                                     // Сохраняем статус заслонки 3 - открыта
    servo(pos_open_zaslon3, SG90Zaslon3Pin);                  // Открываем заслонку 3
    digitalWrite(ledZaslon3, HIGH);                           // Включаем светодиод заслонки 3
    PublishMassageMQTT(topicZaslon3i, String(1).c_str());     // Отправляем статус - индикатор заслонки 3
    PublishMassageMQTT(topicZaslon3, String(1).c_str());      // Отправляем статус заслонки 3
  }
  //--------------------Закрываем заслонку 3------------------
  if (Zaslon == false && statusZaslon3 == true) {             // Закрываем заслонку 3
    DisplayMessage("CLOSE ZASLON 3");                         // Выводим сообщение о закрытии заслонки 3
    statusZaslon3 = false;                                    // Сохраняем статус заслонки 3 - закрыта
    servo(pos_close_zaslon3, SG90Zaslon3Pin);                 // Закрываем заслонку 3
    digitalWrite(ledZaslon3, LOW);                            // Выключаем светодиод заслонки 3
    PublishMassageMQTT(topicZaslon3i, String(0).c_str());     // Отправляем статус - индикатор заслонки 3
    PublishMassageMQTT(topicZaslon3, String(0).c_str());      // Отправляем статус заслонки 3
  }
}
//--------------------Управление электрической вентиляцией----
void setVent(bool Vent)                                       // Функция включения/выключения электронной вентиляции
{
  //--------------------Включаем электрическую вентиляцию-----
  if (Vent == true && statusVent == false)                    // Включаем электронную вентиляцию
  {
    if (statusZaslon1 == false) {                             // Открываем заслонку 1 если она закрыта
      statusZaslon1 = true;                                   // Сохраняем статус заслонки 1 - открыта
      servo(pos_open_zaslon1, SG90Zaslon1Pin);                // Открываем заслонку 1
      digitalWrite(ledZaslon1, HIGH);                         // Включаем светодиод заслонки 1
      PublishMassageMQTT(topicZaslon1i, String(1).c_str());   // Отправляем статус - индикатор заслонки 1
      PublishMassageMQTT(topicZaslon1, String(1).c_str());    // Отправляем статус заслонки 1
    }
    if (statusZaslon2 == false) {                             // Открываем заслонку 2 если она закрыта
      statusZaslon2 = true;                                   // Сохраняем статус заслонки 2 - открыта
      servo(pos_open_zaslon2, SG90Zaslon2Pin);                // Открываем заслонку 2
      digitalWrite(ledZaslon2, HIGH);                         // Включаем светодиод заслонки 2
      PublishMassageMQTT(topicZaslon2i, String(1).c_str());   // Отправляем статус - индикатор заслонки 2
      PublishMassageMQTT(topicZaslon2, String(1).c_str());    // Отправляем статус заслонки 2
    }
    if (statusHeater1 == true) {                              // Выключаем обогреватель 1 если он включен, чтобы не тратить тепло
      statusHeater1 = false;                                  // Сохраняем статус обогревателя 1 - выключено
      digitalWrite(rele2Heater1PinAdress, HIGH);              // Выключаем реле 2 - обогревателя 1
      digitalWrite(ledHeater1, LOW);                          // Выключаем светодиод обогревателя 1
      PublishMassageMQTT(topicHeater1i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 1
      PublishMassageMQTT(topicHeater1, String(0).c_str());    // Отправляем статус обогревателя 1
    }
    if (statusHeater2 == true) {                              // Выключаем обогреватель 2 если он включен, чтобы не тратить тепло
      statusHeater2 = false;                                  // Сохраняем статус обогревателя 2 - выключено
      digitalWrite(rele3Heater2PinAdress, HIGH);              // Выключаем реле 3 - обогревателя 2
      digitalWrite(ledHeater2, LOW);                          // Выключаем светодиод обогревателя 2
      PublishMassageMQTT(topicHeater2i, String(0).c_str());   // Отправляем статус - индикатор обогревателя 2
      PublishMassageMQTT(topicHeater2, String(0).c_str());    // Отправляем статус обогревателя 2
    }

    DisplayMessage("ON VENT");                                // Выводим сообщение о включении электронной вентиляции
    statusVent = true;                                        // Сохраняем статус электрической вентиляции - запущена
    digitalWrite(rele1VentPinAdress, LOW);                    // Включаем реле 1 - электрической вентиляции
    digitalWrite(ledVent, HIGH);                              // Включаем светодиод электрической вентиляции
    PublishMassageMQTT(topicVenti, String(1).c_str());        // Отправляем статус - индикатор электрической вентиляции
    PublishMassageMQTT(topicVent, String(1).c_str());         // Отправляем статус электрической вентиляции
  }
  //--------------------Выключаем электрическую вентиляцию----
  if (Vent == false && statusVent == true)                    // Выключаем вентиляцию
  {
    if (statusZaslon1 == true) {                              // Закрываем заслонку 1 если она открыта
      statusZaslon1 = false;                                  // Сохраняем статус заслонки 1 - закрыта
      servo(pos_close_zaslon1, SG90Zaslon1Pin);               // Закрываем заслонку 1
      digitalWrite(ledZaslon1, LOW);                          // Выключаем светодиод заслонки 1
      PublishMassageMQTT(topicZaslon1i, String(0).c_str());   // Отправляем статус - индикатор заслонки 1
      PublishMassageMQTT(topicZaslon1, String(0).c_str());    // Отправляем статус заслонки 1
    }
    if (statusZaslon2 == true) {                              // Закрываем заслонку 2 если она открыта
      statusZaslon2 = false;                                  // Сохраняем статус заслонки 2 - закрыта
      servo(pos_close_zaslon2, SG90Zaslon2Pin);               // Закрываем заслонку 2
      digitalWrite(ledZaslon2, LOW);                          // Включаем светодиод заслонки 2
      PublishMassageMQTT(topicZaslon2i, String(0).c_str());   // Отправляем статус - индикатор заслонки 2
      PublishMassageMQTT(topicZaslon2, String(0).c_str());    // Отправляем статус заслонки 2
    }
    if (statusZaslon3 == true) {                              // Закрываем заслонку 3 если она открыта
      statusZaslon3 = false;                                  // Сохраняем статус заслонки 3 - открыта
      servo(pos_close_zaslon3, SG90Zaslon3Pin);               // Закрываем заслонку 3
      digitalWrite(ledZaslon3, LOW);                          // Включаем светодиод заслонки 3
      PublishMassageMQTT(topicZaslon3i, String(0).c_str());   // Отправляем статус - индикатор заслонки 3
      PublishMassageMQTT(topicZaslon3, String(0).c_str());    // Отправляем статус заслонки 3
    }

    DisplayMessage("OFF VENT");                               // Выводим сообщение о выключении электрической вентиляции
    statusVent = false;                                       // Сохраняем статус электрической вентиляции - отключена
    digitalWrite(rele1VentPinAdress, HIGH);                   // Выключаем реле 1 - электрической вентиляции
    digitalWrite(ledVent, LOW);                               // Выключаем светодиод электрической вентиляции
    PublishMassageMQTT(topicVenti, String(0).c_str());        // Отправляем статус - индикатор электрической вентиляции
    PublishMassageMQTT(topicVent, String(0).c_str());         // Отправляем статус электрической вентиляции
  }
}
//--------------------Управление обогревателем 1--------------
void setHeater1(bool Heater)                                  // Функция включении/выключения обогревателя 1
{
  //--------------------Включаем обогреватель 1---------------
  if (Heater == true && statusHeater1 == false) {             // Включаем обогреватель 1
    if (statusZaslon1 == true) {                              // Закрываем заслонку 1 если она открыта, чтобы не терять тепло
      statusZaslon1 = false;                                  // Сохраняем статус заслонки 1 - закрыта
      servo(pos_close_zaslon1, SG90Zaslon1Pin);               // Закрываем заслонку 1
      digitalWrite(ledZaslon1, LOW);                          // Выключаем светодиод заслонки 1
      PublishMassageMQTT(topicZaslon1i, String(0).c_str());   // Отправляем статус - индикатор заслонки 1
      PublishMassageMQTT(topicZaslon1, String(0).c_str());    // Отправляем статус заслонки 1
    }
    if (statusZaslon2 == true) {                              // Закрываем заслонку 2 если она открыта, чтобы не терять тепло
      statusZaslon2 = false;                                  // Сохраняем статус заслонки 2 - закрыта
      servo(pos_close_zaslon2, SG90Zaslon2Pin);               // Закрываем заслонку 2
      digitalWrite(ledZaslon2, LOW);                          // Выключаем светодиод заслонки 2
      PublishMassageMQTT(topicZaslon2i, String(0).c_str());   // Отправляем статус - индикатор заслонки 2
      PublishMassageMQTT(topicZaslon2, String(0).c_str());    // Отправляем статус заслонки 2
    }
    if (statusZaslon3 == true) {                              // Закрываем заслонку 3 если она открыта, чтобы не терять тепло
      statusZaslon3 = false;                                  // Сохраняем статус заслонки 3 - закрыта
      servo(pos_close_zaslon3, SG90Zaslon3Pin);               // Закрываем заслонку 3
      digitalWrite(ledZaslon3, LOW);                          // Выключаем светодиод заслонки 3
      PublishMassageMQTT(topicZaslon3i, String(0).c_str());   // Отправляем статус - индикатор заслонки 3
      PublishMassageMQTT(topicZaslon3, String(0).c_str());    // Отправляем статус заслонки 3
    }
    if (statusVent == true) {                                 // Выключаем электрическую вентиляцию если она включена, чтобы не терять тепло
      statusVent = false;                                     // Сохраняем статус электрической вентиляции - отключена
      digitalWrite(rele1VentPinAdress, HIGH);                 // Выключаем реле 1 - электрической вентиляции
      digitalWrite(ledVent, LOW);                             // Выключаем светодиод электрической вентиляции
      PublishMassageMQTT(topicVenti, String(0).c_str());      // Отправляем статус - индикатор электрической вентиляции
      PublishMassageMQTT(topicVent, String(0).c_str());       // Отправляем статус электрической вентиляции
    }

    DisplayMessage("ON HEATER 1");                            // Выводим сообщение о включении обогревателя 1
    statusHeater1 = true;                                     // Сохраняем статус обогревателя 1 - включен
    digitalWrite(rele2Heater1PinAdress, LOW);                 // Включаем реле 2 - обогревателя 1
    digitalWrite(ledHeater1, HIGH);                           // Включаем светодиод обогревателя 1
    PublishMassageMQTT(topicHeater1i, String(1).c_str());     // Отправляем статус - индикатор обогревателя 1
    PublishMassageMQTT(topicHeater1, String(1).c_str());      // Отправляем статус обогревателя 1
  }
  //--------------------Выключаем обогреватель 1--------------
  if (Heater == false && statusHeater1 == true) {             // Выключаем обогреватель 1
    DisplayMessage("OFF HEATER 1");                           // Выводим сообщение о выключении обогревателя 1
    statusHeater1 = false;                                    // Сохраняем статус обогревателя 1 - выключен
    digitalWrite(rele2Heater1PinAdress, HIGH);                // Выключаем реле 2 - обогревателя 1
    digitalWrite(ledHeater1, LOW);                            // Выключаем светодиод обогревателя 1
    PublishMassageMQTT(topicHeater1i, String(0).c_str());     // Отправляем статус - индикатор обогревателя 1
    PublishMassageMQTT(topicHeater1, String(0).c_str());      // Отправляем статус обогревателя 1
  }
}
//--------------------Включаем обогреватель 2-----------------
void setHeater2(bool Heater)                                  // Функция включени/выключения обогревателя 2
{
  if (Heater == true && statusHeater2 == false)               // Включаем обогреватель 2
  {
    if (statusZaslon1 == true) {                              // Закрываем заслонку 1 если она открыта, чтобы не терять тепло
      statusZaslon1 = false;                                  // Сохраняем статус заслонки 1 - закрыта
      servo(pos_close_zaslon1, SG90Zaslon1Pin);               // Закрываем заслонку 1
      digitalWrite(ledZaslon1, LOW);                          // Выключаем светодиод заслонки 1
      PublishMassageMQTT(topicZaslon1i, String(0).c_str());   // Отправляем статус - индикатор заслонки 1
      PublishMassageMQTT(topicZaslon1, String(0).c_str());    // Отправляем статус заслонки 1
    }
    if (statusZaslon2 == true) {                              // Закрываем заслонку 2 если она открыта, чтобы не терять тепло
      statusZaslon2 = false;                                  // Сохраняем статус заслонки 2 - закрыта
      servo(pos_close_zaslon2, SG90Zaslon2Pin);               // Закрываем заслонку 2
      digitalWrite(ledZaslon2, LOW);                          // Выключаем светодиод заслонки 2
      PublishMassageMQTT(topicZaslon2i, String(0).c_str());   // Отправляем статус - индикатор заслонки 2
      PublishMassageMQTT(topicZaslon2, String(0).c_str());    // Отправляем статус заслонки 2
    }
    if (statusZaslon3 == true) {                              // Закрываем заслонку если она открыта, чтобы не терять тепло
      statusZaslon3 = false;                                  // Сохраняем статус заслонки - закрыта
      servo(pos_close_zaslon3, SG90Zaslon3Pin);               // Закрываем заслонку 3
      digitalWrite(ledZaslon3, LOW);                          // Выключаем светодиод заслонки 3
      PublishMassageMQTT(topicZaslon3i, String(0).c_str());   // Отправляем статус - индикатор заслонки 3
      PublishMassageMQTT(topicZaslon3, String(0).c_str());    // Отправляем статус заслонки 3
    }
    if (statusVent == true) {                                 // Выключаем электрическую вентиляцию если она включена, чтобы не терять тепло
      statusVent = false;                                     // Сохраняем статус электрической вентиляции - отключена
      digitalWrite(rele1VentPinAdress, HIGH);                 // Выключаем реле 1 - электрической вентиляции
      digitalWrite(ledVent, LOW);                             // Выключаем светодиод электрической вентиляции
      PublishMassageMQTT(topicVenti, String(0).c_str());      // Отправляем статус - индикатор заслонки 3
      PublishMassageMQTT(topicVent, String(0).c_str());       // Отправляем статус заслонки 3
    }

    DisplayMessage("ON HEATER 2");                            // Выводим сообщение о включении обогревателя 2
    statusHeater2 = true;                                     // Сохраняем статус обогревателя 2 - включен
    digitalWrite(rele3Heater2PinAdress, LOW);                 // Включаем реле 3 - обогревателя 2
    digitalWrite(ledHeater2, HIGH);                           // Включаем светодиод обогревателя 2
    PublishMassageMQTT(topicHeater2i, String(1).c_str());     // Отправляем статус - индикатор обогревателя 2
    PublishMassageMQTT(topicHeater2, String(1).c_str());      // Отправляем статус обогревателя 2
  }

  if (Heater == false && statusHeater2 == true) {             // Выключаем обогреватель 2
    DisplayMessage("OFF HEATER 2");                           // Выводим сообщение о  выключении обогревателя 2
    statusHeater2 = false;                                    // Сохраняем статус обогревателя 2 - выключен
    digitalWrite(rele3Heater2PinAdress, HIGH);                // Выключаем реле 3 - обогревателя 2
    digitalWrite(ledHeater2, LOW);                            // Выключаем светодиод обогревателя 2
    PublishMassageMQTT(topicHeater2i, String(0).c_str());     // Отправляем статус - индикатор обогревателя 2
    PublishMassageMQTT(topicHeater2, String(0).c_str());      // Отправляем статус обогревателя 2
  }
}
void loop()
{
  StateRejim();                                               // Включение/выключение автоматического режима
  OnOffDisplay();                                             // Включение выключение дисплея в зависимости от уровня света
  if (irrecv.decode(&results))                                // Считывание данных с пульта
  {
    if (results.value == 0XFFFFFFFF)
      results.value = key_value;
    switch (results.value) {
      case 0xFF6897:                                          // Если полученный код равен кнопке *
        MenuOnOff = 1;                                        // Включаем режим меню
        lcd.clear();                                          // Очищаем дисплей
        lcd.setCursor(0, 0);                                  // Переводим курсор на 0 строку 0 позиция
        lcd.print("Main Menu");                               // Выводим сообщение, что мы в меню       
        tm1637.clearDisplay();                                // Очистка цифрового 4х сегментного дисплея 
        point_on_off = false;                                 // Выключаем отображение точек
        tm1637.point(POINT_OFF);                              // Скрываем точку на часах
        point_on_off = true;                                  // Включаем отображение точек
        break;
      case 0xFFB04F:                                          // Если полученный код равен кнопке #
        MenuOnOff = 0;                                        // Выключаем режим меню
        lcd.clear();                                          // Очищаем дисплей
        DisplaySensorsValue();                                // Выводим информацию с датчиков (DHT22, BME280)
        ShowDateOnDisplay();                                  // Выводим дату и время в правом верхнем углу дисплея 2004 I2C 20х4
        break;
    }
    translateIR();                                            // Функция распознования кодов с пульта
  }

  if (MenuOnOff == 0)                                         // Если режим меню выключен то
  {
    GetValueSensors();                                        // Получение данных с датчиков - 1 раз в 5 минут
    DisplayTimeOnDigit();                                     // Обновление время на 4х сегментном дисплее - 1 раз в 1 секунду

    if (millis() - TimerShowSensorValue > 60000)              // Выполнение функций 1 раз в 1 минуту
    {
      TimerShowSensorValue = millis();
      DisplaySensorsValue();                                  // Выводим информацию с датчиков (DHT22, BME280)
      ShowDateOnDisplay();                                    // Выводим дату и время в правом верхнем углу дисплея 2004 I2C 20х4
    }

    if (millis() - TimingPublishMQTT > 300000)                // Публикация значений на MQTT сервер 1 раз 5 минут
    {
      TimingPublishMQTT = millis();
      MQTTStatus = MQTTConnect();                             // Проверка состояния подключения к MQTT серверу и  сохранения статуса подключения
      if (MQTTStatus == true) {                               // Если подключение есть то публикуем значения на MQTT сервер
        PublishMQTTSensorsValue();                            // Публикация данных с датчиков на MQTT сервер
      }
    }
  }

  mqtt.loop();                                               // Это должно вызываться регулярно, чтобы позволить клиенту обрабатывать входящие сообщения и поддерживать его соединение с сервером.
}

//-----------------Управление меню-----------------------------------------
void menuSetup()
{
  menu.getRoot().add(menu1Item1);
  //************************************
  menu1Item1.addRight(menu1Item2).addRight(menu1Item3).addRight(menu1Item4).addRight(menu1Item5).addRight(menu1Item1);
  menu1Item1.addLeft(menu1Item5).addLeft(menu1Item4).addLeft(menu1Item3).addLeft(menu1Item2).addLeft(menu1Item1);
  //*******************************************
  menu1Item1.add(menuItem1SubItem1).addRight(menuItem1SubItem2).addRight(menuItem1SubItem1);
  menuItem1SubItem1.addLeft(menuItem1SubItem2).addLeft(menuItem1SubItem1);
  //*******************************************
  menu1Item2.add(menuItem2SubItem1).addRight(menuItem2SubItem2).addRight(menuItem2SubItem1);
  menuItem2SubItem1.addLeft(menuItem2SubItem2).addLeft(menuItem2SubItem1);
  //*******************************************
  menu1Item3.add(menuItem3SubItem1).addRight(menuItem3SubItem2).addRight(menuItem3SubItem3).addRight(menuItem3SubItem4).addRight(menuItem3SubItem5).addRight(menuItem3SubItem1);
  menuItem3SubItem1.addLeft(menuItem3SubItem5).addLeft(menuItem3SubItem4).addLeft(menuItem3SubItem3).addLeft(menuItem3SubItem2).addLeft(menuItem3SubItem1);
  //*******************************************

  menu.toRoot();
}

void menuUseEvent(MenuUseEvent used)
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Please wait");
  if (used.item.getShortkey() == '1') {
    AlertInfo();
  }
  if (used.item.getShortkey() == '2') {
    ConnectInfo();
  }
  if (used.item.getShortkey() == '11') {
    LoadData();
    lcd.print("LoadData");
  }
  if (used.item.getShortkey() == '5' || used.item.getShortkey() == '6' || used.item.getShortkey() == '7' || used.item.getShortkey() == '8' || used.item.getShortkey() == '9')  {
    CorrectTime();
  }
  menu.toRoot();
}

void menuChangeEvent(MenuChangeEvent changed)
{

  MenuItem newMenuItem = changed.to;
  lcd.clear();
  lcd.setCursor(0, 0);
  if (newMenuItem.getName() == "MenuRoot") {
    lcd.print("Main Menu");
  }
  else lcd.print(newMenuItem.getName());
  lcd.setCursor(0, 1);
  switch (newMenuItem.getShortkey()) {
    case '3':
      lcd.print(Temperature);
      break;
    case '4':
      lcd.print(Humidity);
      break;
    case '5':
      PrintTime();
      break;
    case '6':
      PrintTime();
      break;
    case '7':
      PrintTime();
      break;
    case '8':
      PrintTime();
      break;
    case '9':
      PrintTime();
      break;
  }
}

void PrintTime() {
  sprintf(Buffer, "%02d.%02d.%04d %02d:%02d", Date, Month, Year, Hour, Minute);
  lcd.print(Buffer);
}

void translateIR()
{
  // 0 -  0xFF9867
  // 1 -  0xFFA25D
  // 2 -  0xFF629D
  // 3 -  0xFFE21D
  // 4 -  0xFF22DD
  // 5 -  0xFF02FD
  // 6 -  0xFFC23D
  // 7 -  0xFFE01F
  // 8 -  0xFFA857
  // 9 -  0xFF906F
  // * -  0xFF6897
  // # -  0xFFB04F
  // /\ - 0xFF18E7
  // > -  0xFF5AA5
  // < -  0xFF10EF
  // \/ - 0xFF4AB5
  // OK - 0xFF38C7
  MenuItem currentMenu = menu.getCurrent();
  lcd.setCursor(0, 1);
  switch (results.value)
  {
    //Заслонка 1 - кнопка 1
    case 0xFFA25D: 
        if (statusZaslon1 == false)                           // Если заслонка закрыта то
          setZaslon1(true);                                   // Открываем заслонку 1
        else
          setZaslon1(false);                                  // Закрываем заслонку 1
        break;
      

    //Заслонка 2 - кнопка 2
    case 0xFF629D: 
        if (statusZaslon2 == false)                           // Если заслонка закрыта то
          setZaslon2(true);                                   // Открываем заслонку 2
        else
          setZaslon2(false);                                  // Закрываем заслонку 2
        break;
      

    //Заслонка 3 - кнопка 3
    case 0xFFE21D: 
        if (statusZaslon3 == false)                           // Если заслонка закрыта то
          setZaslon3(true);                                   // Открываем заслонку 3
        else
          setZaslon3(false);                                  // Закрываем заслонку 3
        break;
      

    //Обогреватель 1 - кнопка 4
    case 0xFF22DD: 
        if (statusHeater1 == false)                           // Если заслонка закрыта то
          setHeater1(true);                                   // Включаем обогреватель 1
        else
          setHeater1(false);                                  // Выключаем обогреватель 1
        break;
      

    //Обогреватель 2 - кнопка 5
    case 0xFF02FD: 
        if (statusHeater2 == false)                           // Если заслонка закрыта то
          setHeater2(true);                                   // Включаем обогреватель 2
        else
          setHeater2(false);                                  // Выключаем обогреватель 2
        break;
      

    //Электрическая вентиляция - кнопка 6
    case 0xFFC23D: 
        if (statusVent == false)                              // Если заслонка закрыта то
          setVent(true);                                      // Включаем электрическую вентиляцию
        else
          setVent(false);                                     // Выключаем электрическую вентиляцию
        break;
      
    //Кнопка вниз
    case 0xFF4AB5:
      if (!(currentMenu.moveDown())) {
        menu.use();
      }
      else {
        menu.moveDown();
      }
      break;

    //Прибавление значения - кнопка 8
    case 0xFFA857:
      lcd.setCursor(0, 1);
      if (currentMenu.getShortkey() == '1') {
        Temperature++;
        if (Temperature == 101) Temperature = 1;
        lcd.print(Temperature);
        lcd.print(" ");
      }
      else if (currentMenu.getShortkey() == '2') {
        Humidity++;
        if (Humidity == 101) Humidity = 1;
        lcd.print(Humidity);
        lcd.print(" ");
      }
      else if (currentMenu.getShortkey() == '3') {
        Date++;
        if (Date == 32) Date = 1;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '4') {
        Month++;
        if (Month == 13) Month = 1;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '5') {
        Year++;
        if (Year == 2050) Year = 2019;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '6') {
        Hour++;
        if (Hour == 24) Hour = 0;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '7') {
        Minute++;
        if (Minute == 60) Minute = 0;
        PrintTime();
      }
      break;

    // Кнопка вверх
    case 0xFF18E7:
      if (!(currentMenu.moveUp())) {
        menu.moveLeft();
        menu.moveUp();
      }
      else {
        menu.moveUp();
      }
      break;
      
    // Кнопка влево
    case 0xFF10EF:
      menu.moveLeft();
      break;
      
    // Кнопка ОК
    case 0xFF38C7:
      menu.use();
      break;
      
    // Кнопка вправо
    case 0xFF5AA5:
      menu.moveRight();
      break;

    //Уменьшение значения - кнопка 0
    case 0xFF9867:
      lcd.setCursor(0, 1);
      if (currentMenu.getShortkey() == '1') {
        Temperature--;
        if (Temperature == 0) Temperature = 100;
        lcd.print(Temperature);
        lcd.print(" ");
      }
      else if (currentMenu.getShortkey() == '2') {
        Humidity--;
        if (Humidity == 0) Humidity = 100;
        lcd.print(Humidity);
        lcd.print(" ");
      }
      else if (currentMenu.getShortkey() == '3') {
        Date--;
        if (Date == 0) Date = 31;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '4') {
        Month--;
        if (Month == 0) Month = 12;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '5') {
        Year--;
        if (Year == 2013) Year = 2020;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '6') {
        Hour--;
        if (Hour == -1) Hour = 23;
        PrintTime();
      }
      else if (currentMenu.getShortkey() == '7') {
        Minute--;
        if (Minute == -1) Minute = 59;
        PrintTime();
      }
      break;
  }
  irrecv.resume();
  delay(500);
}
//-----------------Корректировка времени из меню-----------------------------------------
void CorrectTime() {
  char AdjTime[9];
  char AdjDate[12];
  sprintf(AdjTime, "%02d:%02d:%02d", Hour, Minute, 0);
  switch (Month) {
    case 1:
      sprintf(AdjDate, "Jan %02d %04d", Date, Year);
      break;
    case 2:
      sprintf(AdjDate, "Feb %02d %04d", Date, Year);
      break;
    case 3:
      sprintf(AdjDate, "Mar %02d %04d", Date, Year);
      break;
    case 4:
      sprintf(AdjDate, "Apr %02d %04d", Date, Year);
      break;
    case 5:
      sprintf(AdjDate, "May %02d %04d", Date, Year);
      break;
    case 6:
      sprintf(AdjDate, "Jun %02d %04d", Date, Year);
      break;
    case 7:
      sprintf(AdjDate, "Jul %02d %04d", Date, Year);
      break;
    case 8:
      sprintf(AdjDate, "Aug %02d %04d", Date, Year);
      break;
    case 9:
      sprintf(AdjDate, "Sep %02d %04d", Date, Year);
      break;
    case 10:
      sprintf(AdjDate, "Oct %02d %04d", Date, Year);
      break;
    case 11:
      sprintf(AdjDate, "Nov %02d %04d", Date, Year);
      break;
    case 12:
      sprintf(AdjDate, "Dec %02d %04d", Date, Year);
      break;
  }
  rtc.adjust(DateTime(AdjDate, AdjTime));
  lcd.clear();                                                  // Очищаем дисплей
  lcd.setCursor(3, 2);                                          // Переносим курсор на третью строку
  lcd.print("TIME SAVED");
  delay(3000);
  lcd.clear();
}

 

b707
Offline
Зарегистрирован: 26.05.2017

обратитесь к автору кода

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Я автор кода и всей конструкции. Это мой первый проект. Я В программировании и электротехнике ноль. Все что в интернете вычитал, то и применил.

b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko пишет:

Я автор кода и всей конструкции. Это мой первый проект.

и сразу 2 тысячи строк?

Попытайтесь хотя бы сделать предположение, почему зависает? Памяти достаточно? Потому как искать чужую ошибку в жутком беспорядочном коде бесплатно вряд ли кто возьмется

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

2 тысячи строк появились в течении 3 месяцев проекта. 

Память:

Скетч использует 55598 байт (21%) памяти устройства. Всего доступно 253952 байт.
Глобальные переменные используют 4461 байт (54%) динамической памяти, оставляя 3731 байт для локальных переменных. Максимум: 8192 байт
 
Прочитав кучу форумов я так и не смог выяснить где кроется проблема. Поэтому и выложил сюда. Код думаю не сильно "беспорядочен", иерархия в нем все-таки есть.
b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko пишет:

Код думаю не сильно "беспорядочен", иерархия в нем все-таки есть.

Иерархия есть. но структура совершенно не продумана. Видно, что вы писали его по принципу копирования - написали для одной заслонки - скопировали кусок для остальных. В итоге скетч получился очень избыточным. Например процедура MQTTCallback - сначала один кусок кода скопирован 4 раза, потом другой тоже 4 раза...

Это плохой стиль программирования. Когда вы копируете куски кода несколько раз - во столько же раз растет вероятность ошибки. Разбираться в таком коде - тяжкий труд.

 

 

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

а я считал, что в программировании не нулевой, но мой максимум сотня строк )))

b707
Offline
Зарегистрирован: 26.05.2017

ua6em пишет:

а я считал, что в программировании не нулевой, но мой максимум сотня строк )))

не шуми, Лоджика разбудишь :) Он тут с пару недель назад убеждал меня. что 6 тыс строк для электронных часов - это нормальный код :)

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Когда я процентов на 80 закончил проект, у меня  было более 4000 строк кода. Но немного его причесав и добавив почти везде комментария, получилось это.

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

b707 пишет:

ua6em пишет:

а я считал, что в программировании не нулевой, но мой максимум сотня строк )))

не шуми, Лоджика разбудишь :) Он тут с пару недель назад убеждал меня. что 6 тыс строк для электронных часов - это нормальный код :)

Лоджик для меня вне критики, он мне помог - цифровой фильтр реализовал для катушки Мишина, правда так и не воспользовался, но опыт то остался

Valex60
Offline
Зарегистрирован: 14.11.2019

Я тоже новичок в программировании,тоже написал одну прогу простенькую,но с ней пришлось потрудиться.Прыгает у тебя ардуинка не от напряжения и тока,а от программы.Кода твоего не видно,но скорее всего ты не добавил задержку по времени при срабатывании исполнительных механизмов(реле и т.д.)Добавь оператор delay(80) и будет тебе счастье)),но это только мое мнение исходя из своих проблем и ошибок.

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Спасибо. Зависание происходит без реле, я их пробовал вообще отключить.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Хотел предложить wdt, но там столько delay, что просто жуть...

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

b707 пишет:

обратитесь к автору кода

IliyaBoiko пишет:

Я автор кода

Ну, дык ...

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Кстати setup выполняется отлично, а вот loop через 1-2 часа зависает. Были случаи когда и день и ночь отработал, а потом завис. Магнитные бури ?

b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko пишет:
Кстати setup выполняется отлично, а вот loop через 1-2 часа зависает. Были случаи когда и день и ночь отработал, а потом завис. Магнитные бури ?

Могут быть как аппаратные, так и программные проблемы. По коду наиболее вероятна нехватка памяти и выход за границы массива - но в ваших программных джунглях черт ногу сломит.

По аппаратной части чаще всего влияют импульсные помехи на входах МК - атмеги этого не любят и виснут наглухо

sadman41
Offline
Зарегистрирован: 19.10.2016

Вижу подсоединение периферии к Ардуине проводами типа Dupont. Поэтом зависание вызывать может даже пуканье кота.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

sadman41 пишет:

Поэтом зависание вызывать может даже пуканье кота.

Я нипричом. :)

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

sadman41 пишет:

Вижу подсоединение периферии к Ардуине проводами типа Dupont. Поэтом зависание вызывать может даже пуканье кота.


Припаять?

b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko пишет:
Припаять?

Там такие контакты. к которым и не припаяешь толком. Лучше изготовить плату типа самодельного шилда, смысл в том чтобы все контакты были гребенкой на одной плате и втыкались в мегу разом - тогда они входят с натягом и значительно надежнее держатся

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Такая пойдет? К ней можно припаять и целиком вставить. 118,79 руб. | MEGA 2560 R3 Proto Прототип Щит V3.0 плата расширения + мини Макет pcb 170 точек связи для arduino
https://s.click.aliexpress.com/e/bPJAn9CI

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Или вот этот 89,76 руб. 10%СКИДКА | Прототип PCB для Arduino MEGA 2560 R3 Щит DIY
https://s.click.aliexpress.com/e/bThdqh5C

b707
Offline
Зарегистрирован: 26.05.2017

вторая лучше

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

А если поставить ферритовые бусины между Arduino и проводами? 65,02 руб. | 50 шт./лот бусины индуктора 3,5*4,7*0,8 осевые ферритовые бусины 3,5x4,7x0,8 индуктивность
https://s.click.aliexpress.com/e/bOjDqL8Q

А также поставить ферритовые кольца на провод до блока питания и после.

sadman41
Offline
Зарегистрирован: 19.10.2016

Да хоть святой водой окропляйте. Всё равно же наугад действуете.

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Статистика показала , зависание происходит если включить выключить реле . Видимо создаются помехи и Arduino зависает. Если реле не трогать, то все хорошо. Без реле проработал более 18 часов.

b707
Offline
Зарегистрирован: 26.05.2017

обратные диоды на реле стоят?

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Не знаю, стоит 4х канальное реле:
https://s.click.aliexpress.com/e/t5hwRby.

1 включает питание на модем А6
2 включает электрическую вентиляцию
3 включает обогреватель 1
4 включает обогреватель 2

nik182
Offline
Зарегистрирован: 04.05.2015

Мне помогло отдельное питание реле. На плате есть опторазвязка, но она не задействована как развязка, если стоит перемычка по питанию на плате. Полностью разделить земли входа и питания и запитать реле от отдельного источника. 

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Arduino и реле питаются отдельными проводами от lm2596. Вы можете скинуть фото как надо сделать?

nik182
Offline
Зарегистрирован: 04.05.2015

Фото не покажет соединений.

Вытащить перемычку питания (Vcc JD-Vcc на плате реле). На разъёме соединения с ардуино не подключать землю. Только +5 вольт от ардуины  к Vcc платы реле и провода управления.  Этого достаточно для управления оптронами. Отдельный (!!!) блок питания подключен к GND и пину JD-Vcc. Все обозначения с фото четырёхрелейной платы вашей ссылки на али.  

Serzh251
Offline
Зарегистрирован: 15.11.2017

у меня аналогичная проблема. УД трудился пару лет на меге, добавил MQTT и W5500 зависает MQTT после 1-2 часа нормальной работы,не принимается ничего от меги и не реагирует на топики, при этом W5500 отображается в списке подключений роутера. Через полдня, день мега зависает наглухо

rkit
Offline
Зарегистрирован: 23.11.2016

Сборка безобразная. Нужно развести 2-3 нормальные платы, и соединить шлейфами со всеми требуемыми фильтрами. 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Пока не прикрутится wdt даже спаяная плата долго работать не будет думаю, где то утечка памяти.

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

Как с использованием Arduino nano реализовать wdt? День потратил на эксперименты, ничего не получается.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

В поиске забанили?
Первая же ссылка
https://m.habr.com/ru/post/189744
Но суть в написании кода, который не блокирует задержками loop код, т е пересмотреть всю концепцию работы. Если корректно напишите то и wdt её нужен.

rkit
Offline
Зарегистрирован: 23.11.2016

Не надо колдовать с софтом, пока нет доверия железу. Зачем делать себе жизнь сложнее? Поговорка про двух зайцев известна?

b707
Offline
Зарегистрирован: 26.05.2017

rkit пишет:

Не надо колдовать с софтом, пока нет доверия железу.

Зачем колдовать над железом, пока нет доверия софту?

b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko пишет:
Как с использованием Arduino nano реализовать wdt? День потратил на эксперименты, ничего не получается.

почему Нано? - вроде тема была про Мегу

Рассказывайте, что за эксперименты ставили

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

andycat пишет:
В поиске забанили?
Первая же ссылка
https://m.habr.com/ru/post/189744
Но суть в написании кода, который не блокирует задержками loop код, т е пересмотреть всю концепцию работы. Если корректно напишите то и wdt её нужен.

Вы дали ссылку на wdt, а мне надо чтобы стороннее устройство следило за откликом текущего. Если первое зависнет, то второе по пину reset его перезапустит.

b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko][quote=andycat пишет:
мне надо чтобы стороннее устройство следило за откликом текущего. Если первое зависнет, то второе по пину reset его перезапустит.

Вы не думаете, что это порочный круг? Сначала написали кривой код, потом собрали глючную схему... Теперь. вместо того чтоб разбираться в сути проблем - вы хотите приладить сбоку "хрень и бантик" - еще одну ардуину, которая будет дергать первую...

А если эта вторая тоже зависнет - что делать будете? А это вероятно - вы же учиться правильно писать код не желаете...

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

b707] </p> <p>[quote=IliyaBoiko пишет:
andycat пишет:
мне надо чтобы стороннее устройство следило за откликом текущего. Если первое зависнет, то второе по пину reset его перезапустит.

Вы не думаете, что это порочный круг? Сначала написали кривой код, потом собрали глючную схему... Теперь. вместо того чтоб разбираться в сути проблем - вы хотите приладить сбоку "хрень и бантик" - еще одну ардуину, которая будет дергать первую...

А если эта вторая тоже зависнет - что делать будете? А это вероятно - вы же учиться правильно писать код не желаете...


Осуждать других я тож могу, я пытаюсь найти выход из ситуации. Предлагайте варианты решения, если есть. Данная проблема очень распространена, но толкового и полноценного решения на просторах интернета я не увидел. И если бы все было так просто, не было бы смысла в этом форуме...

b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko пишет:
Предлагайте варианты решения, если есть. Данная проблема очень распространена, но толкового и полноценного решения на просторах интернета я не увидел.

"толковое и полноценное решение" тут может быть только одно - "вылизать" код и схему до такого состояния, чтобы ардуина не зависала

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Ну ка расскажите плиз про распространенность некой мифической проблемы....
Поговорку про плохого танцора помните?
Но да, тут частенько встречаются личности которым то модем мешает, то МК, то индикатор то что то ещё....вместо того чтоб учиться.

IliyaBoiko
Offline
Зарегистрирован: 14.11.2019

b707 пишет:

IliyaBoiko пишет:
Предлагайте варианты решения, если есть. Данная проблема очень распространена, но толкового и полноценного решения на просторах интернета я не увидел.

"толковое и полноценное решение" тут может быть только одно - "вылизать" код и схему до такого состояния, чтобы ардуина не зависала


Вам помогли "вылизать " вашу схему http://arduino.ru/forum/apparatnye-voprosy/podskazhite-po-kondensatoram-... ? Сколько кондеров поставили?

b707
Offline
Зарегистрирован: 26.05.2017

IliyaBoiko пишет:
Вам помогли "вылизать " вашу схему http://arduino.ru/forum/apparatnye-voprosy/podskazhite-po-kondensatoram-... ? Сколько кондеров поставили?

тот проект в итоге до реальной жизни не дошел.

Зато был другой проект, где плата с контроллером укреплена на станине мощного электромотора и где поначалу я столкнулся с зависанием ардуины в среднем 2-3 раза в сутки.

Для начала тщательно вылизал код, переписаны все подозрительные места. В ходе этого выловил один неприятный баг, после устранения которого система стала виснуть в несколько раз реже.

Потом добавил в схему конденсаторы - два больших электролита на питание(400- 680 мкФ) и по маленькой керамике 0.1мкф на каждый используемый вход

Ну и конечно в системе был инсталлирован ватчдог - программно в ардуине - чтобы если система все-таки зависнет, она ресетилась сама.

В таком виде все это работает в режиме 24,7 с июня 2018 г

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

IliyaBoiko][quote=andycat пишет:
Вы дали ссылку на wdt, а мне надо чтобы стороннее устройство следило за откликом текущего. Если первое зависнет, то второе по пину reset его перезапустит.

MAX813L купи. Если в loop() не шыпка на.уеверчено, то 1.6 секунды (время неответа для перезагрузки) должно хватить