#include <LCDI2C_Symbols.h>
#include <Wire.h> // Для работы I2C
#include <LCDI2C_Multilingual.h> // Библиотека для LCD с I2C
#include <DHT.h> // Библиотека датчика
#include <RTClib.h> // Библиотека часов RTC
#include "ClickEncoder.h" // Библиотека для обработки энкодера
#include <TimerOne.h> // Библиотека для вызова энкодера из кода программы
#include <EEPROM.h> //Подключение долговременной памяти
// Настройки пинов и типов
#define DHTPIN 6 //пин датчика влажности
#define DHTTYPE DHT22 //тип датчика влажности
#define RELAY_PIN 7 //пин реле
#define ENC_PIN_A 2 //пин энкодера CLK
#define ENC_PIN_B 3 //пин энкодера DT
#define ENC_BUTTON_PIN 4 //пин кнопки энкодера
#define LED_PIN 9 //пин светодиода
RTC_DS1307 rtc; //подключение модуля времени RTC
DHT dht(DHTPIN, DHTTYPE); //обозначение датчика
// Адрес LCD дисплея (обычно 0x27 или 0x3F, проверьте для вашего дисплея)
LCDI2C_Generic lcd(0x27, 16, 2); // Адрес 0x27, 16 символов, 2 строки
// Создаём объект ClickEncoder с указанными пинами
// Последний параметр (4) — число состояний (обычно 4 для 2-клавиатурных энкодеров)
ClickEncoder encoder(ENC_PIN_A, ENC_PIN_B, ENC_BUTTON_PIN, 4);
int16_t lastPosition = 0; // создаем предыдущую позицию энкодера
bool buttonHeld = false; // Флаг удержания (нажатия) кнопки энкодера
bool buttonClick = false; // Флаг одиночного нажатия кнопки энкодера
int deltaEncoder = 0; // Переменная показывающая вращается ли энкодер и в какую сторону
// Переменные для переключения экранов
int currentScreen = 0; // Индекс текущего экрана
const int screenCount = 5; // Общее число экранов для переключения
int8_t RELAY_Stat = HIGH; // состояние реле - по умолчанию выключено
int Humanid_Stay = 55; //значение влажности при котором включается реле
const int min_Humanid_Stay = 0; // Минимальное значение влажности для выбора 0%(определяется датчиком)
const int max_Humanid_Stay = 100; // Максимальное значение влажности для выбора 100%(определяется датчиком)
int Temp_Stay = 40; //Значение температуры при котором включается реле
const int min_Temp_Stay = -40; // Минимальное значение температуры для выбора -40 С (определяется датчиком)
const int max_Temp_Stay = 80; // Максимальное значение температуры для выбора 80 С (определяется датчиком)
float humidity = 0; // Обозначение переменной влажности и задание ей первых значений
float temperature = 0; // Обозначение переменнной температуры
//Переменные для датчика и окна настройки датчиков
enum flagSensChoise_Value { STATE_NONE_SENS, SENS_CHOICE_UP, SENS_VALUE_CHOISE_UP}; //Логика флагов в выборе датчика и его значения
flagSensChoise_Value flagSCV = STATE_NONE_SENS; // Убираем все флаги со страницы
int sensChoise = 1; //переменная для выбора датчика 0 - темп, 1 влажн
const char* setSens [] = {"temp", "vlagn"}; //создание массива с данными для выбора датчика temp - температура. hum - влажность
const int maxlengtSens = (sizeof(setSens) / sizeof(setSens[0]))-1; // Подсчет колличесвта датчиков -1, для программы
enum ModeTypeState { STATE_NONE, STATE_CHOICE_UP, STATE_ARROW}; //Логика флагов в выборе режимов работы
ModeTypeState modeState = STATE_NONE; //Задание первой состояни флагов, где ничего не выбрано
enum ModeTimerState{ STATE_NONE_TIMER, STATE_PAUSE_H, STATE_PAUSE_M, STATE_PAUSE_S, STATE_WORK_H, STATE_WORK_M, STATE_WORK_S}; //Логика флагов переключения таймера
ModeTimerState modeTimer = STATE_NONE_TIMER; //На таймере ничего не выбрано
const uint8_t PosArrowTimerPause = 6; //Позиция на которой рисуется стрелочка выбора
int8_t Pause_Hour= 0; //Колличество часов перерыва в настройке таймера
int8_t Pause_Min= 0; //Колличество минут перерыва в настройке таймера
int8_t Pause_Sec= 0; //Количество секунд перерыва в настройке таймера
int8_t Work_Hour= 0; //Колличество часов Работы в настройке таймера
int8_t Work_Min= 0; //Колличество минут Работы в настройке таймера
int8_t Work_Sec= 0; //Количество секунд Работы в настройке таймера
unsigned long pauseDuration = 0; // Время паузы таймера в миллисекундах
unsigned long workDuration = 0; // Время работы таймера в миллисекундах
unsigned long previousMillisTimer = 0; // Время начала текущего периода (паузы или работы)
bool isPause = true; // Флаг текущего режима: true — пауза, false — работа
enum ModeTimeofDateState{ STATE_NONE_TOD, STATE_START_H, STATE_START_M, STATE_FINISH_H, STATE_FINISH_M}; //Логика флагов настройки по времени суток
ModeTimeofDateState modeTOD = STATE_NONE_TOD; //На странице настройки реле по времени суток
const uint8_t PosArrowTODStart = 8; //Позиция на которой рисуется стрелочка выбора
int8_t Start_Hour= 0; //Время в часах - начала работы
int8_t Start_Min= 0; //Время в минутах - начала работы
int8_t Stop_Hour= 0; //Время в часах - конца работы
int8_t Stop_Min= 0; //Время в минутах - конца работы
bool isInTimeInterval(int currentHour, int currentMin); //Задание функции показа функции, находится ли она в интервале
enum ModeDisplaySensorFrequency{ STATE_NONE_DSF, STATE_SWICH_DIR, STATE_FREQ_M, STATE_FREQ_S}; //Логика флагов Экрана настройки датчиков
ModeDisplaySensorFrequency modeDSF = STATE_NONE_DSF; //Сняты все флаги на экране выбора частоты опроса
bool direction_OFF_ON = true; //Направление включения - выкл на вкл
uint8_t directionHight = HIGH; //Направление выкл переменная для реле
const uint8_t PosArrowDFSdir = 9; //Позиция на которой рисуется стрелочка выбора режима работы
const uint8_t PosArrowDFSPolling = 8; //Позиция отображения стрелочки выбора частоты обращений к датчикам
int8_t Pooling_Rate_Min= 0; //Частота опроса в минутах
int8_t Pooling_Rate_Sec= 5; //Частота опроса в секундах
unsigned long lastTime = 0; //Переменная времени для таймера частоты опроса датчика
unsigned long intervalPooling = 5000; //Начальное значение переменной интервала опроса датчиков
enum ModeDisplayBrightness{FLAG_NONE_DB, DB_AUTOOFF_SWICH, DB_AUTOOFF_M, DB_AUTOOFF_S}; //Флаги включения подсветки дисплея
ModeDisplayBrightness DisplayBrightnessFlags = FLAG_NONE_DB; //Снятие флагов автоотключения дисплея
const uint8_t DisplayOFFPosArrow = 9; //Позиция на которой рисуется стрелочка автоотключения дисплея
const uint8_t TimerOFFMinPosArrow = 9; //Позиция на которой рисуется стрелочка минут автоотключения
bool AutoOff_Display = false; //Автоотключение дисплея отключено
int8_t DisplayOFF_Min= 0; //время отключения в минутах
int8_t DisplayOFF_Sec= 15; //Время отключения в секундах
unsigned long lastActivityTime = 0; // Время последней активности
unsigned long inactivityTimeout = 15000; // 15 секунд
bool backlightOn = true; // Переменная для состояния подсветки
//Работа с графиком влажности
float humidityMax[12]; // Массив для хранения максимальных значений влажности за 12 интервалов по 2 часа
int indexHum = 0; // Индекс текущего интервала
int lastRecordedHour = -1; // Переменная для хранения времени последней фиксации по RTC
float maxHumidity = 0; // поиск самого максимального значения влажности с первого элемента
byte customBar0[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F}; //Переменные с закрашенными квадратами
byte customBar1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F};
byte customBar2[8] = {0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F};
byte customBar3[8] = {0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F};
byte customBar4[8] = {0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F};
byte customBar5[8] = {0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
byte customBar6[8] = {0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
byte customBar7[8] = {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
int ModeTypeChoise = 2; //переменная для отображения выбора режима работы
const char* selectModeType [] = {"Timer","Raspisan","Datchik"}; //Переменная со списком режимов работы -по таймеру, по часам, по датчику
const int maxlengModeType = (sizeof(selectModeType)/sizeof(selectModeType[0]))-1; //Подсчет колличества режимов работы -1, для программы
//Для отображения времени
bool timeScreenNeedsInit = true; // Глобальная переменная, указывающая, что экран времени нужно инициализировать при следующем показе
// Для настройки времени
int8_t setHour = 0; //Задание времени для переменной
int8_t setMinute = 0; //Задание переменнной для минут
bool editHour = false; // Переменная редактирования часов
bool editMinutes = false; //Переменная редактирования минут
bool confirmReTime = false; //Переменная для подтверждения обновления времени
bool selConfirmReTime = false; //Переменная отвечающая за (да / нет)
bool timeSetComplete = false; //Переменная сообщающая, что выполнено перенастройка часов
void showTempHumidity(); //Задание функций для экрана темп-влажность
void showTime(bool forceInit = false); //задание функций для экрана времени
void TimeSetting(); //Экран настройки времени и опроса датчиков
void setSensor(); //Задание функций для выбора датчика
void SelectOperationModeType(); // Задание выбора режима работы - по датчикам или по времени
void Screen_Timer_setting(); //Экран настройки таймера
void Screen_Time_of_Day_setting(); //Экран настройки реле по времени суток
void updateTimer(); // Функция изменения времени на экране настройки
void DisplaySensorFrequency(); //Экран настройки частоты опроса датчиков
void DisplayBrightness(); // Экран регулировки яркости дисплея
void Graph_Humidity(); // Экран Графика влажности
void deleteFlags(); //Функция убирабщая флаги выбора настроек с экрана
void RaleyControl(); //Функция управления реле
void TimeSettingSwichMode(); //Функция переключения флагов в настройки времени
void ChangeTime(); //Функция присваивания времени нового значения
void onButtonPress(); //Функция нажатия на кнопку, для включения автоподсветки
unsigned long lastUpdate = 0; //перменная для отслеживания времени до 1с
const unsigned long updateInterval = 1000; //Интервал 1с для часов
const unsigned long updateIntervalSens = 2000; //Интервал 2с для датчиков
unsigned long previousMillis = 0; // для хранения времени прошлого вызова для вызова функции реле
const unsigned long interval = 5000; // интервал 5 секунд (5000 мс) для вызова функции реле
// Адреса для хранения переменных в EEPROM
const int addr_Humanid_Stay = 0; // int (2 байта)
const int addr_Temp_Stay = 2; // int (2 байта)
const int addr_sensChoise = 4; // int (1 байт)
const int addr_Pause_Hour = 5; // int8_t (1 байт)
const int addr_Pause_Min = 6; // int8_t (1 байт)
const int addr_Pause_Sec = 7; // int8_t (1 байт)
const int addr_Work_Hour = 8; // int8_t (1 байт)
const int addr_Work_Min = 9; // int8_t (1 байт)
const int addr_Work_Sec = 10; // int8_t (1 байт)
const int addr_Start_Hour = 11; // int8_t (1 байт)
const int addr_Start_Min = 12; // int8_t (1 байт)
const int addr_Stop_Hour = 13; // int8_t (1 байт)
const int addr_Stop_Min = 14; // int8_t (1 байт)
const int addr_direction_OFF_ON = 15; // bool (1 байт)
const int addr_Pooling_Rate_Min = 16; // int8_t (1 байт)
const int addr_Pooling_Rate_Sec = 17; // int8_t (1 байт)
const int addr_AutoOff_Display = 18; // bool (1 байт)
const int addr_DisplayOFF_Min = 19; // int8_t (1 байт)
const int addr_DisplayOFF_Sec = 20; // int8_t (1 байт)
const int addr_ModeTypeChoise = 21; // int (2 байта)
//адреса переменных для проверки корректности данных ключей
const int key_addr_Humanid_Stay = 24; // адрес
const int key_addr_Temp_Stay = 25; // адрес
const int key_addr_sensChoise = 26; // адрес
const int key_addr_Pause_Hour = 27; // адрес
const int key_addr_Pause_Min = 28; // адрес
const int key_addr_Pause_Sec = 29; // адрес
const int key_addr_Work_Hour = 30; // адрес
const int key_addr_Work_Min = 31; // адрес
const int key_addr_Work_Sec = 32; // адрес
const int key_addr_Start_Hour = 33; // адрес
const int key_addr_Start_Min = 34; // адрес
const int key_addr_Stop_Hour = 35; // адрес
const int key_addr_Stop_Min = 36; // адрес
const int key_addr_direction_OFF_ON = 37; // адрес
const int key_addr_Pooling_Rate_Min = 38; // адрес
const int key_addr_Pooling_Rate_Sec = 39; // адрес
const int key_addr_AutoOff_Display = 40; // адрес
const int key_addr_DisplayOFF_Min = 41; // адрес
const int key_addr_DisplayOFF_Sec = 42; // адрес
const int key_addr_ModeTypeChoise = 43; // адрес
//ячейки с ключами
int8_t key_Humanid_Stay; // ключ
int8_t key_Temp_Stay ; // ключ
int8_t key_sensChoise; // ключ
int8_t key_Pause_Hour; // ключ
int8_t key_Pause_Min; // ключ
int8_t key_Pause_Sec; // ключ
int8_t key_Work_Hour; // ключ
int8_t key_Work_Min; // ключ
int8_t key_Work_Sec; // ключ
int8_t key_Start_Hour; // ключ
int8_t key_Start_Min; // ключ
int8_t key_Stop_Hour; // ключ
int8_t key_Stop_Min; // ключ
int8_t key_direction_OFF_ON; // ключ
int8_t key_Pooling_Rate_Min; // ключ
int8_t key_Pooling_Rate_Sec; // ключ
int8_t key_AutoOff_Display; // ключ
int8_t key_DisplayOFF_Min; // ключ
int8_t key_DisplayOFF_Sec; //ключ
int8_t key_ModeTypeChoise; //ключ
const int8_t keyValue = 101; //Значение ключа, для ухода от ошибки
unsigned long buttonPressStartTime = 0; //Переменная для счетчика очистки памяти при запуске
// Универсальные функции для работы с памятью EEPROM
// Запись 2 байт (int16_t)
void EEPROM_writeInt(int address, int16_t value) {
EEPROM.write(address, value & 0xFF);
EEPROM.write(address + 1, (value >> 8) & 0xFF);
}
// Чтение 2 байт (int16_t)
int16_t EEPROM_readInt(int address) {
int16_t lowByte = EEPROM.read(address);
int16_t highByte = EEPROM.read(address + 1);
return lowByte | (highByte << 8);
}
// Запись 1 байта для int8_t и bool (они по сути одинаковые)
void EEPROM_writeInt8(int address, int8_t value) {
EEPROM.write(address, value);
}
// Чтение 1 байта
int8_t EEPROM_readInt8(int address) {
return EEPROM.read(address);
}
// Запись логической переменной (bool)
void EEPROM_writeBool(int address, bool value) {
EEPROM.write(address, value ? 1 : 0);
}
// Чтение логической переменной
bool EEPROM_readBool(int address) {
return EEPROM.read(address) != 0;
}
// ЗАГРУЗКА из EEPROM
void loadFromEEPROM() {
EEPROM.get(key_addr_Humanid_Stay, key_Humanid_Stay);
EEPROM.get(key_addr_Temp_Stay, key_Temp_Stay);
EEPROM.get(key_addr_sensChoise, key_sensChoise);
EEPROM.get(key_addr_Pause_Hour, key_Pause_Hour);
EEPROM.get(key_addr_Pause_Min, key_Pause_Min);
EEPROM.get(key_addr_Pause_Sec, key_Pause_Sec);
EEPROM.get(key_addr_Work_Hour, key_Work_Hour);
EEPROM.get(key_addr_Work_Min, key_Work_Min);
EEPROM.get(key_addr_Work_Sec, key_Work_Sec);
EEPROM.get(key_addr_Start_Hour, key_Start_Hour);
EEPROM.get(key_addr_Start_Min, key_Start_Min);
EEPROM.get(key_addr_Stop_Hour, key_Stop_Hour);
EEPROM.get(key_addr_Stop_Min, key_Stop_Min);
EEPROM.get(key_addr_direction_OFF_ON, key_direction_OFF_ON);
EEPROM.get(key_addr_Pooling_Rate_Min, key_Pooling_Rate_Min);
EEPROM.get(key_addr_Pooling_Rate_Sec, key_Pooling_Rate_Sec);
EEPROM.get(key_addr_AutoOff_Display, key_AutoOff_Display);
EEPROM.get(key_addr_DisplayOFF_Min, key_DisplayOFF_Min);
EEPROM.get(key_addr_DisplayOFF_Sec, key_DisplayOFF_Sec);
EEPROM.get(key_addr_ModeTypeChoise, key_ModeTypeChoise);
// Проверка ключей перед загрузкой
if (key_Humanid_Stay == 101) {
Humanid_Stay = EEPROM_readInt(addr_Humanid_Stay); }
if (key_Temp_Stay == 101) {
Temp_Stay = EEPROM_readInt(addr_Temp_Stay); }
if (key_sensChoise == 101) {
sensChoise = EEPROM.read(addr_sensChoise); }
if (key_Pause_Hour == 101) {
Pause_Hour = EEPROM_readInt8(addr_Pause_Hour); } // Ваш код
if (key_Pause_Min == 101) {
Pause_Min = EEPROM_readInt8(addr_Pause_Min);}// Ваш код
if (key_Pause_Sec == 101) {
Pause_Sec = EEPROM_readInt8(addr_Pause_Sec);}// Ваш код
if (key_Work_Hour == 101) {
Work_Hour = EEPROM_readInt8(addr_Work_Hour); }// Ваш код
if (key_Work_Min == 101) {
Work_Min = EEPROM_readInt8(addr_Work_Min); }// Ваш код
if (key_Work_Sec == 101) {
Work_Sec = EEPROM_readInt8(addr_Work_Sec); }// Ваш код
if (key_Start_Hour == 101) {
Start_Hour = EEPROM_readInt8(addr_Start_Hour); }// Ваш код
if (key_Start_Min == 101) {
Start_Min = EEPROM_readInt8(addr_Start_Min); }// Ваш код
if (key_Stop_Hour == 101) {
Stop_Hour = EEPROM_readInt8(addr_Stop_Hour);}
if (key_Stop_Min == 101) {
Stop_Min = EEPROM_readInt8(addr_Stop_Min);}
if (key_direction_OFF_ON == 101) {
direction_OFF_ON = EEPROM_readBool(addr_direction_OFF_ON);}
if (key_Pooling_Rate_Min == 101) {
Pooling_Rate_Min = EEPROM_readInt8(addr_Pooling_Rate_Min);}
if (key_Pooling_Rate_Sec == 101) {
Pooling_Rate_Sec = EEPROM_readInt8(addr_Pooling_Rate_Sec);}
if (key_AutoOff_Display == 101) {
AutoOff_Display = EEPROM_readBool(addr_AutoOff_Display);}
if (key_DisplayOFF_Min == 101) {
DisplayOFF_Min = EEPROM_readInt8(addr_DisplayOFF_Min);}
if (key_DisplayOFF_Sec == 101) {
DisplayOFF_Sec = EEPROM_readInt8(addr_DisplayOFF_Sec);}
if (key_ModeTypeChoise == 101) {
ModeTypeChoise = EEPROM_readInt(addr_ModeTypeChoise);}
//Расчет данных для таймеров
if (key_Pause_Hour == 101) {
pauseDuration = ((unsigned long)Pause_Hour * 3600UL + (unsigned long)Pause_Min * 60UL + (unsigned long)Pause_Sec) * 1000UL; // Перевод времени паузы в миллисекунды
workDuration = ((unsigned long)Work_Hour * 3600UL + (unsigned long)Work_Min * 60UL + (unsigned long)Work_Sec) * 1000UL; // Перевод времени работы в миллисекунды
previousMillisTimer = millis();} // Запоминаем текущее время запуска таймера
if (key_Pooling_Rate_Min == 101 && key_Pooling_Rate_Sec == 101) intervalPooling = (unsigned long)(Pooling_Rate_Min * 60 + Pooling_Rate_Sec) * 1000UL;
if (key_DisplayOFF_Min == 101 && key_DisplayOFF_Sec == 101) inactivityTimeout = (unsigned long)(DisplayOFF_Min * 60 + DisplayOFF_Sec) * 1000UL; //Помещение в переменную времени отключения дисплея
}
// Функция таймера — вызывается регулярно для обработки энкодера
void timerIsr() {
encoder.service();
}
void setup() {
Serial.begin(9600); // Частота для отладки на компьютере
dht.begin(); // Подключение датчика
pinMode(RELAY_PIN, OUTPUT); // Подключение пина реле
pinMode(LED_PIN, OUTPUT); // Устанавливаем пин как выход
// Проверка при запуске — удерживает ли кнопка 5 секунд
if (digitalRead(ENC_BUTTON_PIN) == LOW) { // кнопку зажали (активный LOW)
buttonPressStartTime = millis();
// Пока кнопка удерживается
while (digitalRead(ENC_BUTTON_PIN) == LOW) {
if (millis() - buttonPressStartTime >= 5000) { // 5 секунд
// Очистить EEPROM
for (int i = 0; i < EEPROM.length(); i++) {
EEPROM.write(i, 0); // Заполняем нулями
}
Serial.println("EEPROM очищена");
break; // выходим из цикла
}
}
}
humidity = dht.readHumidity(); //Запись в переменную данных с датчика влажности
temperature = dht.readTemperature(); //Запись в переменную данных с датчика температуры
Timer1.initialize(1000); // Настраиваем таймер на вызов каждые 1000 микросекунд (1 мс)
Timer1.attachInterrupt(timerIsr); // Назначаем функцию timerIsr вызовимой таймером
digitalWrite(RELAY_PIN, HIGH); // Цифровая запись на пин реле - выкл
lcd.init(); // Инициализация LCD
lcd.backlight(); // Включаем подсветку дисплея
lcd.clear(); // Очистка экрана перед запуском
lcd.setCursor(0, 0); // Установка курсора в верхний левый угол
lcd.print("Inicialisation"); // Английская версия
//заполнение ячеек памяти экрана квадратами
lcd.createChar(0, customBar0); //Квадратик с одной полоской
lcd.createChar(1, customBar1);
lcd.createChar(2, customBar2);
lcd.createChar(3, customBar3);
lcd.createChar(4, customBar4);
lcd.createChar(5, customBar5);
lcd.createChar(6, customBar6);
lcd.createChar(7, customBar7); //Полный квадратик
// Инициализация часов
if (!rtc.begin()) { //проверка на ошибки модуля часов RTC
lcd.clear(); //Очистка экрана перед сообщением
lcd.print("RTC lost power"); //Сообщение о том, что часы не подключены
}
if (!rtc.isrunning()) { // Если часы не запущены, запустить их (для DS1307)
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
DateTime now = rtc.now(); //присваивание переменной значения из часов
setHour = now.hour(); //Присваивание переменной значения часов
setMinute = now.minute(); //Присваивание переменной значения минут
for (int i = 0; i < 12; i++) { // Инициализация массива максимумов
humidityMax[i] = 0; //Опустошаем ячейки массива с максимумами
}
lastRecordedHour = now.hour(); // Изначально запоминаем текущий час
loadFromEEPROM(); // Загружаем все переменные из EEPROM при запуске
delay(1000); // Задержка полторы секунды при запуске
showTempHumidity(); // Запуск первого экрана
}
void loop(){
unsigned long currentMillis = millis(); //Задание переменной для отсчетов интервалов
if (AutoOff_Display) { //Если автоотключение дисплея активно
if ((currentMillis - lastActivityTime >= inactivityTimeout) && backlightOn) {
// Выключение подсветки
lcd.setBacklight(false);
backlightOn = false;
}
}
// Проверяем, прошло ли 5 секунд с момента прошлого вызова для управления реле
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis; // обновляем время последнего вызова
ReleyControl(); // вызываем функцию
}
//Интервал Опроса датчиков
if (currentMillis - lastTime >= intervalPooling) {
lastTime = currentMillis; // обновляем время последнего опроса
// чтение датчика
humidity = dht.readHumidity(); //Запись в переменную данных с датчика влажности
temperature = dht.readTemperature(); //Запись в переменную данных с датчика температуры
//Фиксируем текущее время для работы с графиком
DateTime now = rtc.now();
// Проверяем, наступил ли новый интервал (каждые 2 часа)
// интервал, например, в 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22 часов
if (now.minute() == 0 && (now.hour() % 2) == 0 && lastRecordedHour != now.hour()) {
// Время для фиксации максимума
if (!isnan(humidity)) {
if (humidity > humidityMax[indexHum]) {
humidityMax[indexHum] = humidity;
}
} else {
lcd.print("DHT no power"); //Сообщение о том, что датчик не работает
}
// Обновляем индекс для следующего интервала
indexHum = (indexHum + 1) % 12;
lastRecordedHour = now.hour();
}
}
switch (currentScreen) { // Функция обновления экранов для того, что бы часы на месте не стояли
case 0:
if (currentMillis - lastUpdate >= updateIntervalSens) {
lastUpdate = currentMillis;
showTempHumidity (); // обновляем показания датчиков каждую секунду
}
break;
case 1:
if (currentMillis - lastUpdate >= updateInterval) {
lastUpdate = currentMillis;
showTime(false); // обновляем время каждую секунду
}
break;
}
// Считываем состояние кнопки
int buttonState = encoder.getButton(); //Поместить в переменную состояние кнопки энкодера
// Обрабатываем состояния кнопки
switch (buttonState) { //Проверка состояния кнопки энкодера
case ClickEncoder::Clicked: //Одиночное нажатие кнопки
buttonClick = true; //Флаг диночного нажатия
buttonHeld = false; //Кнопка не зажата
if (AutoOff_Display) onButtonPress();
break;
//case ClickEncoder::DoubleClicked: //Двойное нажатие кнопки
// Serial.println("Двойное нажатие кнопки");
// buttonHeld = false;
// break;
case ClickEncoder::Held: //Если произошло зажатие кнопки
buttonHeld = true; //Запись в переменную, что кнопка удерживается
buttonClick = false; //Отмена одиночного нажатия
break;
case ClickEncoder::Open: //Если кнопка отпущена
if (buttonHeld) {
}
buttonClick = false; //Отмена одиночного нажатия
buttonHeld = false; //Отмена зажатия кнопки
break;
}
// Считываем текущую позицию энкодера
int16_t newPosition = encoder.getValue();
// Проверяем, изменилась ли позиция
if (newPosition != lastPosition) {
int delta = newPosition - lastPosition; //Проверка в какую сторону вращается энкодер
if (AutoOff_Display) onButtonPress(); //Таймер активности активировать
if (buttonHeld) { // Если кнопка удерживается — переключение экрана
handleScreenSwitch(delta); //Функция переключения экранов
encoder.setValue(0); // Обнуляем значение энкодера для следующего переключения
lastPosition = 0;
} else {
switch (currentScreen) { //В завиисимоти от выбора экрана передаем данные энкодера
case 0: //Экран выбора датчика
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
showTempHumidity(); // Экран с данными
deltaEncoder = 0; // Обнуление переменной, что бы не оставался в мусоре
break;
case 2: //Экран выбора датчика
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
setSensor(); // Экран выбора датчиков
deltaEncoder = 0; // Обнуление переменной, что бы не оставался в мусоре
break;
case 11: //Экран настроойки времени
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
TimeSetting(); //Экран настройки времени
deltaEncoder = 0; //обнуление переменной, что бы не оставался вмусор
break;
case 3: //Экран выбора режимов работы
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
SelectOperationModeType(); //Экран выбора режимов работы
deltaEncoder = 0; //обнуление переменной, что бы не оставался вмусор
break;
case 31: //Экран настройки режима рботы по таймеру
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
Screen_Timer_setting(); //Экран выбора настройки таймера
deltaEncoder = 0; //обнуление переменной, что бы не оставался вмусор
break;
case 32: //Экран настройки режима работы по времени суток
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
Screen_Time_of_Day_setting(); //Экран выбора настройки таймера
deltaEncoder = 0; //обнуление переменной, что бы не оставался вмусор
break;
case 33: //Экран настройки частоты опроса датчика
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
DisplaySensorFrequency(); //Экран настройки частоты датчика и направления работы
deltaEncoder = 0; //обнуление переменной, что бы не оставался вмусор
break;
case 4: //экран настройки автоотключения дисплея
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
DisplayBrightness(); //Экран настройки автоотключения дисплея
deltaEncoder = 0; //обнуление переменной, что бы не оставался вмусор
break;
case 101: // Экран с графиком влажности
deltaEncoder = delta; // Передача данных о том, что энкодер вращается
Graph_Humidity(); //Экран с графиком влажности
deltaEncoder = 0; //обнуление переменной, что бы не оставался вмусор
break;
}
lastPosition = newPosition;
}
}
if (buttonClick){ //Функция нажатия на кнопку
switch (currentScreen)
{
case 1: // Если это экран со временем
editHour = true; //Устанавливаем флаг настройки часов
TimeSetting(); // Переключаем на экран настройки времени
currentScreen = 11; // Номер экрана настройки времени
break;
case 2: //Экран настройки датчиков
switch (flagSCV) {
case STATE_NONE_SENS:
flagSCV = SENS_CHOICE_UP;
break;
case SENS_CHOICE_UP:
flagSCV = SENS_VALUE_CHOISE_UP;
break;
case SENS_VALUE_CHOISE_UP:
flagSCV = STATE_NONE_SENS;
break;
}
setSensor();
break;
case 11: //Экран настройки времени
TimeSettingSwichMode(); //Функция переключения флагов на экране настройки времени
break;
case 3: //Экран выбора режима работы
switch (modeState) { //Проверка перменной
case STATE_NONE: //Если не выбрано ничего
modeState = STATE_CHOICE_UP; //Присвоить значение выбора режимов
break;
case STATE_CHOICE_UP: //Если выбраны режимы
modeState = STATE_ARROW; //Перевести на стрелку
break;
case STATE_ARROW: //Если выбраны стрелки
modeState = STATE_NONE; //Снять все выборы
break;
}
SelectOperationModeType(); //Экран выбора режима работы таймера
break;
case 31: //Экран настройки работы по таймеру
switch (modeTimer) { //Проверка перменной
case STATE_NONE_TIMER: //Если не выбрано ничего
modeTimer = STATE_PAUSE_H; //Присвоить значение режима паузы
break;
case STATE_PAUSE_H: //Если выбраны режимы
modeTimer = STATE_PAUSE_M; //Перевести на Выбор минут
break;
case STATE_PAUSE_M: //Если выбраны режимы
modeTimer = STATE_PAUSE_S; //Перевести на Выбор секунд
break;
case STATE_PAUSE_S: //Если выбраны режимы
modeTimer = STATE_WORK_H; //Перевести на Выбор минут
break;
case STATE_WORK_H: //Если выбраны стрелки
modeTimer = STATE_WORK_M; //Снять все выборы
break;
case STATE_WORK_M: //Если выбраны стрелки
modeTimer = STATE_WORK_S; //Снять все выборы
break;
case STATE_WORK_S: //Если выбраны стрелки
modeTimer = STATE_NONE_TIMER; //Снять все выборы
break;
}
Screen_Timer_setting(); //Экран настройки таймера
break;
case 32: //Экран настройки работы по таймеру
switch (modeTOD) { //Проверка перменной
case STATE_NONE_TOD: //Если не выбрано ничего
modeTOD = STATE_START_H; //Присвоить значение часов начала запуска
break;
case STATE_START_H: //Если выбраны часы
modeTOD = STATE_START_M; //Перевести на Выбор минут
break;
case STATE_START_M: //Если выбраны минуты запуска
modeTOD = STATE_FINISH_H; //Перевести на Выбор часов остановки
break;
case STATE_FINISH_H: //Если выбраны часы остановки
modeTOD = STATE_FINISH_M; //Перевести на Выбор минут
break;
case STATE_FINISH_M: //Если выбраны минуты
modeTOD = STATE_NONE_TOD; //Снять все выборы
break;
}
Screen_Time_of_Day_setting(); //Экран настройки таймера
break;
case 33: //экран настройки направления работы и частоты опроса датчиков
switch (modeDSF) { //Проверка перменной
case STATE_NONE_DSF: //Если не выбрано ничего
modeDSF = STATE_SWICH_DIR; //Присвоить значение направления работы вкл-выкл или наоборот
break;
case STATE_SWICH_DIR: //Если выбрано направление
modeDSF = STATE_FREQ_M; //Перевести на Выбор минут
break;
case STATE_FREQ_M: //Если выбраны минуты
modeDSF = STATE_FREQ_S; //Перевести на Выбор секунд
break;
case STATE_FREQ_S: //Если выбраны секунды запуска
modeDSF = STATE_NONE_DSF; //Перевести на Выбор часов остановки
break;
}
DisplaySensorFrequency(); //Экран настройки частоты
break;
case 4: //экран настройки автоотключения дисплея
switch (DisplayBrightnessFlags) { //Проверка перменной
case FLAG_NONE_DB: //Если не выбрано ничего
DisplayBrightnessFlags = DB_AUTOOFF_SWICH; //Присвоить значение вкл и выкл подсветки
break;
case DB_AUTOOFF_SWICH: //Если выбрано направление
DisplayBrightnessFlags = DB_AUTOOFF_M; //Перевести на Выбор минут
break;
case DB_AUTOOFF_M: //Если выбраны минуты
DisplayBrightnessFlags = DB_AUTOOFF_S; //Перевести на Выбор секунд
break;
case DB_AUTOOFF_S: //Если выбраны секунды запуска
DisplayBrightnessFlags = FLAG_NONE_DB; //Перевести на Выбор часов остановки
break;
}
DisplayBrightness(); //Экран настройки частоты
break;
}
}
if (backlightOn) delay (100); //Снижаем нагрузку в спящем режиме
delay(10); // Небольшая задержка для снижения частоты цикла
}
// Функция переключения экранов с кольцеванием
void handleScreenSwitch(int diff) {
diff = constrain (diff, -1, 1); // ограничим переменную diff тремя значениями -1, 0 , 1
switch (currentScreen){ //Экран выбора
case 11: currentScreen = 1; break; //Если мы на экране настройки времени то перейти на экран времени
case 31: {
currentScreen = 3; //Переводим на экран выбора редимов работы
pauseDuration = ((unsigned long)Pause_Hour * 3600UL + (unsigned long)Pause_Min * 60UL + (unsigned long)Pause_Sec) * 1000UL; // Перевод времени паузы в миллисекунды
workDuration = ((unsigned long)Work_Hour * 3600UL + (unsigned long)Work_Min * 60UL + (unsigned long)Work_Sec) * 1000UL; // Перевод времени работы в миллисекунды
previousMillisTimer = millis(); // Запоминаем текущее время запуска таймера
saveToEEPROM(); //Сохранение в память
} break; //Если на экране настройки таймера , то на экран выбора
case 32:{
currentScreen = 3; //Переводим на экран выбора режимов работы
}
break;
case 33:{
currentScreen = 3; //Переводим на экран выбора режимов работы
intervalPooling = (unsigned long)(Pooling_Rate_Min * 60 + Pooling_Rate_Sec) * 1000UL;
saveToEEPROM(); //Сохранение в память
} break;
case 101:{
currentScreen = 0; //Переводим на экран показаний
} break;
default: {
currentScreen += diff;
if (currentScreen < 0) currentScreen = screenCount - 1; //Если переменная меньше нуля - то переменная приравнивается к конечному экрану
if (currentScreen >= screenCount) currentScreen = 0; //Если перемення больше кол-ва экранов , то она смещается на нулевой
}
}
lcd.clear(); //Очистка экрана перед переключением на другой
deleteFlags(); //сброс переменных с настройками при переходе на другой экран
switch (currentScreen) { // Отрисовка выбранного экрана
case 0: showTempHumidity (); break; //Экран вывода данных температуры и влажности
case 1: showTime(true); break; //Экран с часами
case 2: setSensor(); break; //Экран выбора датчиков и настройка их данных
case 3: SelectOperationModeType(); break; //экран настройки режимов работы времени
case 4: DisplayBrightness(); break; // Экран регулировки яркости дисплея
}
}
//Экран показа текущих показателей температуры и влажности
void showTempHumidity () {
lcd.clear(); // Очистка экрана перед запуском
if (isnan(humidity) || isnan(temperature)) { // Проверяем успешность чтения датчика
lcd.setCursor(0, 0);
lcd.print("oshibka datchika "); // Очистка 16 символов
lcd.setCursor(0, 1);
lcd.print(" "); // Пустая строка
}
// Вывод на LCD влажности и температуры
lcd.setCursor(0, 0);
lcd.print("Vlagnost:"); //Англ версия
lcd.print(humidity, 1); // 1 знак после запятой
lcd.print("%");
lcd.setCursor(0, 1); //Установка курсора для температуры
lcd.print("Temp:"); // англ версия
lcd.print(temperature, 1); //один знак после запятой
lcd.print(" C");
if (RELAY_Stat == LOW){ //проверка переменной состояния реле
lcd.setCursor(13, 1); //установка курсора
lcd.print("ON "); //Сообщение о состояниии реле - включено
}
else{
lcd.setCursor(13, 1); //установка курсора
lcd.print("OFF"); //Сообщение о состояниии реле - выключено
}
if (deltaEncoder != 0) { // переходим на другой экран при вращении энкодера
deltaEncoder = 0; //Обнуляем изменение энкодера
currentScreen = 101; //Присваиваем экрану переменную графика
Graph_Humidity(); //Экран с графиком влажности
}
}
//Экран графика влажности
void Graph_Humidity() { // Экран Графика влажности
lcd.clear(); // Очистка экрана
lcd.print("V"); //Текущее значение влажности
if (humidity < 10) lcd.print("0"); //Рисуем 0 но, возможно прийдется убирать его
lcd.print(round(humidity)); //Вывод датчика влжности
lcd.setCursor(0,1); //Перевод на 2 строку
lcd.print("Mx"); //Максимальное значение влажности
for (int i = 0; i < 12; i++) {
if (humidityMax[i] > maxHumidity) {
maxHumidity = humidityMax[i];
};}
lcd.print(round(maxHumidity)); //Вывести максимальное значение
if (humidity < 10) lcd.print("0"); //Рисуем 0 но, возможно прийдется убирать его
draw_Graph_of_Humidity(); //Рисуем график наглядный
if (deltaEncoder != 0) { // переходим на другой экран при вращении энкодера
deltaEncoder = 0; //Обнуляем изменение энкодера
currentScreen = 0; //Переключение на экран вывода данных
showTempHumidity (); //Экран вывода данных
}
}
//Рисуем график на экране
void draw_Graph_of_Humidity(){
int8_t graffik_start = 3; //Начальные координаты графика
int tnew[12]={0,0,0,0,0,0,0,0,0,0,0,0}; //Массив для отрисовки данных снизу
int tw[12]={0,0,0,0,0,0,0,0,0,0,0,0}; //массив для отрисовки данных сверху
for (int i = 0; i<12; i++){
lcd.setCursor(i+graffik_start+1,1);
tnew[i] = ceil ((humidityMax[i]) / 5);
if (tnew[i] > 7 ) tnew[i] = 7;
lcd.write(tnew[i]);
//Верхняя строка
tw[i] = ((humidityMax[i] - 50) + 4) / 5;
if (tw[i] < 0 ) tw[i] = 0;
if (tw[i] > 7) tw[i] = 7;
lcd.setCursor(i+graffik_start+1,0);
if (tw[i]==0)lcd.print(" "); else lcd.write(tw[i]);
}
}
//Экран с часами
void showTime(bool forceInit) { //функция экрана отображения времени
static bool initialized = false; // Флаг, был ли уже выведен базовый текст
static int prevHour = -1; // статические переменные Предыдущее значение часов для сравнения
static int prevMinute = -1; // статические переменные Предыдущее значение минут для сравнения
static int prevSecond = -1; // статические переменные Предыдущее значение секунд для сравнения
// Если требуется инициализация (переход на экран времени), сбрасываем флаги и сохранённые значения
if (forceInit) {
initialized = false;
prevHour = -1;
prevMinute = -1;
prevSecond = -1;
}
DateTime now = rtc.now(); // Получаем текущее время из RTC
if (!initialized) {
lcd.clear(); //очищаем экран
lcd.print("Time: 00:00:00"); // Выводим строку с заголовком и временем-заглушкой
initialized = true; // Устанавливаем флаг, что базовый текст выведен
}
if (now.hour() != prevHour) {
lcd.setCursor(6, 0); // Курсор на позицию первых цифр часов ("hh")
if (now.hour() < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(now.hour()); // Выводим число часов
prevHour = now.hour(); // Сохраняем текущее значение часов
}
if (now.minute() != prevMinute) {
lcd.setCursor(9, 0); // Курсор на позицию первых цифр минут ("mm")
if (now.minute() < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных минут
lcd.print(now.minute()); // Выводим число минут
prevMinute = now.minute(); // Сохраняем текущее значение минут
}
if (now.second() != prevSecond) {
lcd.setCursor(12, 0); // Курсор на позицию первых цифр секунд ("ss")
if (now.second() < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных секунд
lcd.print(now.second()); // Выводим число секунд
prevSecond = now.second(); // Сохраняем текущее значение секунд
}
}
void setSensor() { //Экран выбора и настройки сенсора
lcd.clear(); // Очистка экрана
lcd.print("Dachik: ");
// Включить - выключить выбор датчика
if (flagSCV == SENS_CHOICE_UP){ // Если выбран выбор датчика - отображать стрелку настройки
lcd.print(">");
if (deltaEncoder !=0){ // Проверка - вращается ли энкодер
sensChoise += deltaEncoder; // Изменяем на значение поворота энкодера
if (sensChoise > maxlengtSens) { // Проверка не вышло ли значение за максимальное
sensChoise = 0; // Переход на 0 при переполнении
} else if (sensChoise < 0) { // Проверка не стало ли значение отрицательным
sensChoise = maxlengtSens; // переход на max при уходе в минус
}
saveToEEPROM();
}
}
lcd.print(setSens[sensChoise]); //вывод выбранного датчика
//Работа со значениями в программе
lcd.setCursor(0, 1); // Установка курсора на вторую строку
lcd.print(" "); // Стирание второй строки
//Выбрать значение этого датчика
switch (sensChoise){
case 0 : // Если выбран первый датчик - температура
lcd.setCursor(0, 1); // Установка курсора на вторую строку
lcd.print("Nastr tmp: "); // Надпись - "выберите занчение"
if (flagSCV == SENS_VALUE_CHOISE_UP) { // Если выбрана настройка значений датчика отображать стрелку настройки
lcd.print(">");
if (deltaEncoder !=0){ // Проверка - вращается ли энкодер
Temp_Stay += deltaEncoder; // Изменяем на значение поворота энкодера
Temp_Stay = constrain(Temp_Stay, min_Temp_Stay, max_Temp_Stay); // Устанавливаем границы данных для переменной значения температуры
saveToEEPROM();
}}
lcd.print(Temp_Stay); // Значение температуры
break;
case 1: // Если выбран второй датчик - влажность
lcd.setCursor(0, 1); // Установка курсора на вторую строку
lcd.print("Nastr Vlagn: "); // Надпись - "выберите занчение"
if (flagSCV == SENS_VALUE_CHOISE_UP) { // Если выбрана настройка значений датчика отображать стрелку настройки
lcd.print(">");
if (deltaEncoder !=0){ // Проверка - вращается ли энкодер
Humanid_Stay += deltaEncoder; // Изменяем на значение поворота энкодера
Humanid_Stay = constrain(Humanid_Stay, min_Humanid_Stay, max_Humanid_Stay); // Устанавливаем границы данных для переменной значения температуры
saveToEEPROM();
}
}
lcd.print(Humanid_Stay); // Значение влажности
break;
}
}
//Экран настроки времени и частоты опроса датчиков
void TimeSetting(){
if (deltaEncoder == 0) lcd.clear(); // Если мы попали сюда не из-за поворота энкодера то очищаем экран
lcd.setCursor(0, 0); // Устанавливаем курсор в начало первой строки
lcd.print("Vvod:"); // Пишем заголовок - режим настройки времени
// Позиция символа ">" и времени:
const int arrowPosHours = 5; // Посчитаем позиции, чтобы вывести ">" перед часами
const int arrowPosMinutes = 9; // примерно (учитывая "Set: " и пробелы)
if (editHour) {
lcd.setCursor(arrowPosHours, 0); // Устанавливаем курсор на позицию для ">"
lcd.print(">"); // Выводим ">" перед часами
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
setHour += deltaEncoder;
if (setHour < 0) setHour = 23;
if (setHour > 23) setHour = 0;
}
} else {
lcd.setCursor(arrowPosHours, 0); // Если не редактируем часы - стереть стрелку в позиции часов
lcd.print(" "); // Просто пробел, чтобы убрать ">"
}
if (editMinutes) {
lcd.setCursor(arrowPosMinutes, 0); // Вывод стрелки перед минутами
lcd.print(">");
if (deltaEncoder != 0) { //Если происходит вращение
setMinute += deltaEncoder; //То изменяем минуты с помощью энкодера
if (setMinute < 0) setMinute = 59;
if (setMinute > 59) setMinute = 0;
}
} else {
lcd.setCursor(arrowPosMinutes, 0); // Убираем стрелку у минут
lcd.print(" ");
}
// Теперь выводим часы в позиции, например, после "Set: > "
lcd.setCursor(arrowPosHours + 1, 0); // Позиция сразу после стрелки часа
if (setHour < 10) lcd.print("0");
lcd.print(setHour);
lcd.setCursor(arrowPosHours + 3, 0); // Выводим ":" в фиксированной позиции
lcd.print(":");
lcd.setCursor(arrowPosMinutes + 1, 0); // Минуты
if (setMinute < 10) lcd.print("0");
lcd.print(setMinute);
//функция экрана отображения времени
lcd.setCursor(0, 1);
lcd.print(" "); //Очистка второй строки
if (confirmReTime){ //Проверка изменения времени
if (deltaEncoder != 0) { // Если вращается энкодер
selConfirmReTime = !selConfirmReTime; //то меняем - да - нет
}
lcd.setCursor(0, 1); //Помещение курсора на вторую строку
lcd.print("Podtvr izmn: "); //Распечатывание сообщения о подтверждении
if (selConfirmReTime) {
lcd.print("yes"); // распечатать - да
}
else {
lcd.print("no"); //вывести на экран - нет
}
}
}
//Экран выбора режимов работы - по датчикам или по времени
void SelectOperationModeType() { //выбор режима работы реле
lcd.clear(); // Очистка экрана перед запуском
lcd.print("Vibor regima"); //Надпись вверху экрана
lcd.setCursor(0, 1); // Установка курсора на вторую строку
if (modeState == STATE_CHOICE_UP) {lcd.print (">"); //Проверяем активен ли выбор способа - если да - рисуем стрелочку
if (deltaEncoder !=0){
ModeTypeChoise += deltaEncoder; // Изменяем на значение поворота энкодера
if (ModeTypeChoise > maxlengModeType){ // Проверка не вышло ли значение за максимальное
ModeTypeChoise = 0; // Переход на 0 при переполнении
} else if (ModeTypeChoise < 0){ // Проверка не стало ли значение отрицательным
ModeTypeChoise = maxlengModeType; // переход на max при уходе в минус
}
}
saveToEEPROM(); //Сохранение в памяти устройства
}
else lcd.print (" "); //Иначе - ничего не рисуем
lcd.print(selectModeType[ModeTypeChoise]); //Вывести надпись режима из массива
if (modeState == STATE_ARROW){ //Если активны настройки режима, то
lcd.setCursor(13,1); //Перевести курсор на нижний правый край
lcd.print("-->"); //Нарисовать стрелочку
if (deltaEncoder !=0 ){
switch (ModeTypeChoise) { //выбор куда идти по стрелке, посте выбора режима работы
case 0: Screen_Timer_setting(); //Экран настройки тамера
break;
case 1: Screen_Time_of_Day_setting(); //Экран настройки работы по времени суток
break;
case 2: DisplaySensorFrequency(); //Экран настройки частоты опроса датчиков и направления их работы
break;
}
}
}
else {
lcd.setCursor(13,1); //Перевести курсор на нижний правый край
lcd.print(" "); //Нарисовать стрелочку
}
}
void Screen_Timer_setting(){ //Экран настройки таймера
currentScreen = 31; // Номер экрана настройки таймера работы
lcd.clear(); // Очистка экрана перед запуском
lcd.print("Pause: "); //Надпись выбора промежутка работы
if (modeTimer== STATE_PAUSE_H) {
lcd.setCursor(PosArrowTimerPause,0); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Pause_Hour += deltaEncoder;
if (Pause_Hour < 0) Pause_Hour = 23;
if (Pause_Hour > 23) Pause_Hour = 0;
}
}
else {
lcd.setCursor(PosArrowTimerPause,0); //Перевести курсор перед выбором времени
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(PosArrowTimerPause+1,0); //позиция курсора для часов
if (Pause_Hour < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Pause_Hour); //распечатать кол-во часов
if (modeTimer== STATE_PAUSE_M) {
lcd.setCursor(PosArrowTimerPause+3,0); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Pause_Min += deltaEncoder;
if (Pause_Min < 0) Pause_Min = 59;
if (Pause_Min > 59) Pause_Min = 0;
}
}
else {
lcd.setCursor(PosArrowTimerPause+3,0); //Перевести курсор перед выбором времени
lcd.print(":"); //Стереть стрелочку
}
lcd.setCursor(PosArrowTimerPause+4,0); //позиция курсора для минут
if (Pause_Min < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Pause_Min); //распечатать кол-во минут
if (modeTimer== STATE_PAUSE_S) {
lcd.setCursor(PosArrowTimerPause+6,0); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Pause_Sec += 5 * deltaEncoder;
if (Pause_Sec < 0) Pause_Sec = 55;
if (Pause_Sec > 55) Pause_Sec = 5;
}
}
else {
lcd.setCursor(PosArrowTimerPause+6,0); //Перевести курсор перед выбором времени
lcd.print(":"); //Стереть стрелочку
}
lcd.setCursor(PosArrowTimerPause+7,0); //позиция курсора для секунд
if (Pause_Sec < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Pause_Sec); //распечатать кол-во секунд
//Логика настройки времени работы
lcd.setCursor(0,1); //Перевести курсор на нижний левый край
lcd.print("Rabot: "); //Надпись выбора промежутка работы
if (modeTimer== STATE_WORK_H) {
lcd.setCursor(PosArrowTimerPause,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Work_Hour += deltaEncoder;
if (Work_Hour < 0) Work_Hour = 23;
if (Work_Hour > 23) Work_Hour = 0;
}
}
else {
lcd.setCursor(PosArrowTimerPause,1); //Перевести курсор перед выбором времени
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(PosArrowTimerPause+1,1); //позиция курсора для часов
if (Work_Hour < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Work_Hour); //распечатать кол-во часов
if (modeTimer== STATE_WORK_M) {
lcd.setCursor(PosArrowTimerPause+3,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Work_Min += deltaEncoder;
if (Work_Min < 0) Work_Min = 59;
if (Work_Min > 59) Work_Min = 0;
}
}
else {
lcd.setCursor(PosArrowTimerPause+3,1); //Перевести курсор перед выбором времени
lcd.print(":"); //Стереть стрелочку
}
lcd.setCursor(PosArrowTimerPause+4,1); //позиция курсора для минут
if (Work_Min < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Work_Min); //распечатать кол-во минут
if (modeTimer== STATE_WORK_S) {
lcd.setCursor(PosArrowTimerPause+6,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Work_Sec += 5 * deltaEncoder;
if (Work_Sec < 0) Work_Sec = 55;
if (Work_Sec > 55) Work_Sec = 5;
}
}
else {
lcd.setCursor(PosArrowTimerPause+6,1); //Перевести курсор перед выбором времени
lcd.print(":"); //Стереть стрелочку
}
lcd.setCursor(PosArrowTimerPause+7,1); //позиция курсора для секунд
if (Work_Sec < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Work_Sec); //распечатать кол-во секунд
}
//Экран настройки реле по времени суток
void Screen_Time_of_Day_setting(){
currentScreen = 32; // Номер экрана настройки по времени суток
lcd.clear(); // Очистка экрана перед запуском
lcd.print("Start: "); //Надпись начала работы реле
if (modeTOD == STATE_START_H) {
lcd.setCursor(PosArrowTODStart,0); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Start_Hour += deltaEncoder;
if (Start_Hour < 0) Start_Hour = 23;
if (Start_Hour > 23) Start_Hour = 0;
}
saveToEEPROM(); //Сохранение в память данных
}
else {
lcd.setCursor(PosArrowTODStart,0); //Перевести курсор перед выбором времени
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(PosArrowTODStart+1,0); //позиция курсора для часов
if (Start_Hour < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Start_Hour); //распечатать кол-во часов
if (modeTOD== STATE_START_M) {
lcd.setCursor(PosArrowTODStart+3,0); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Start_Min += deltaEncoder;
if (Start_Min < 0) Start_Min = 59;
if (Start_Min > 59) Start_Min = 0;
}
saveToEEPROM();
}
else {
lcd.setCursor(PosArrowTODStart+3,0); //Перевести курсор перед выбором времени
lcd.print(":"); //Заменить стрелочку на :
}
lcd.setCursor(PosArrowTODStart+4,0); //позиция курсора для минут
if (Start_Min < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Start_Min); //распечатать кол-во минут
//Логика настройки времени Отключения
lcd.setCursor(0,1); //Перевести курсор на нижний левый край
lcd.print("Finish: "); //Надпись Окончания работы реле
if (modeTOD== STATE_FINISH_H) {
lcd.setCursor(PosArrowTODStart,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
Stop_Hour += deltaEncoder;
if (Stop_Hour < 0) Stop_Hour = 23;
if (Stop_Hour > 23) Stop_Hour = 0;
}
saveToEEPROM();
}
else {
lcd.setCursor(PosArrowTODStart,1); //Перевести курсор перед выбором времени
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(PosArrowTODStart+1,1); //позиция курсора для часов
if (Stop_Hour < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных часов
lcd.print(Stop_Hour); //распечатать кол-во часов
if (modeTOD== STATE_FINISH_M) {
lcd.setCursor(PosArrowTODStart+3,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем минуты при вращении энкодера
Stop_Min += deltaEncoder;
if (Stop_Min < 0) Stop_Min = 59;
if (Stop_Min > 59) Stop_Min = 0;
}
saveToEEPROM();
}
else {
lcd.setCursor(PosArrowTODStart+3,1); //Перевести курсор перед минутами
lcd.print(":"); //Заменить стрелочку на двоеточие
}
lcd.setCursor(PosArrowTODStart+4,1); //позиция курсора для минут
if (Stop_Min < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных минут
lcd.print(Stop_Min); //распечатать кол-во минут
}
// функция проверки, в промежутке ли сейчас время для работы в промежутке времени
bool isInTimeInterval(int currentHour, int currentMin) {
// переводим в минуты с начала суток
int startMinutes = Start_Hour * 60 + Start_Min;
int stopMinutes = Stop_Hour * 60 + Stop_Min;
int currentMinutes = currentHour * 60 + currentMin;
if (startMinutes <= stopMinutes) {
// диапазон не переходит через полночь
return (currentMinutes >= startMinutes) && (currentMinutes < stopMinutes);
} else {
// диапазон переходит через полночь
return (currentMinutes >= startMinutes) || (currentMinutes < stopMinutes);
}
}
//Экран выбора частоты опроса датчиков и переключения режимов работы
void DisplaySensorFrequency() {
currentScreen = 33; // Номер экрана настройки направления и частоты опроса датчиков
lcd.clear(); // Очистка экрана перед запуском
lcd.print("Regim rab"); //Надпись направления работы
if (modeDSF == STATE_SWICH_DIR) {
lcd.setCursor(PosArrowDFSdir,0); //позиция курсора для часов
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
direction_OFF_ON = !direction_OFF_ON; //меняем значение на противоположное
directionHight = direction_OFF_ON; //Обновить переменную включения реле
}
saveToEEPROM(); //Сохранение значения в память
}
else {
lcd.setCursor(PosArrowDFSdir,0); //Установка курсора где должна быть стрелочка
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(PosArrowDFSdir+1,0); //позиция курсора для часов
if (direction_OFF_ON) lcd.print("OFF-ON"); //Выведем направление ВЫКл-вкл
else lcd.print("ON-OFF"); // Выведем направление ВКЛ-ВЫКЛ
//Логика настройки частоты опроса датчика
lcd.setCursor(0,1); //Перевести курсор на нижний левый край
lcd.print("Chastot:"); //Надпись Частота опроса датчика
if (modeDSF== STATE_FREQ_M) {
lcd.setCursor(PosArrowDFSPolling,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем минуты при вращении энкодера
Pooling_Rate_Min += deltaEncoder;
if (Pooling_Rate_Min < 0) Pooling_Rate_Min = 10;
if (Pooling_Rate_Min > 10) Pooling_Rate_Min = 0;
if (Pooling_Rate_Sec == 0 && Pooling_Rate_Min == 0) Pooling_Rate_Sec = 5; //Что бы время опроса датчиков не стало нулевым
}
}
else {
lcd.setCursor(PosArrowDFSPolling,1); //Перевести курсор перед выбором минут
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(PosArrowDFSPolling+1,1); //позиция курсора для минут
if (Pooling_Rate_Min < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных минут
lcd.print(Pooling_Rate_Min); //распечатать кол-во минут
lcd.print("m"); //распечатать кол-во минут
if (modeDSF== STATE_FREQ_S) {
lcd.setCursor(PosArrowDFSPolling+4,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем минуты при вращении энкодера
Pooling_Rate_Sec += deltaEncoder*5;
if (Pooling_Rate_Sec < 0) Pooling_Rate_Sec = 55;
if (Pooling_Rate_Sec > 55) Pooling_Rate_Sec = 0;
if (Pooling_Rate_Sec == 0 && Pooling_Rate_Min == 0) Pooling_Rate_Sec = 5; //Проверка, что бы не было 0 при опросе датчиков
}
}
else {
lcd.setCursor(PosArrowTODStart+4,1); //Перевести курсор перед минутами
lcd.print(":"); //Заменить стрелочку на двоеточие
}
lcd.setCursor(PosArrowTODStart+5,1); //позиция курсора для минут
if (Pooling_Rate_Sec < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных минут
lcd.print(Pooling_Rate_Sec); //распечатать кол-во минут
lcd.print("s"); //распечатать кол-во минут
}
//Экран регулировки яркости дисплея
void DisplayBrightness() {
currentScreen = 4; // Номер экрана настройки направления и частоты опроса датчиков
lcd.clear(); // Очистка экрана перед запуском
lcd.print("AutoOFF:"); //Надпись направления работы
if (DisplayBrightnessFlags == DB_AUTOOFF_SWICH) {
lcd.setCursor(DisplayOFFPosArrow,0); //позиция курсора для часов
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем часы при вращении энкодера
AutoOff_Display = !AutoOff_Display; //меняем значение на противоположное
}
saveToEEPROM(); //Сохранение в пямяти
}
else {
lcd.setCursor(DisplayOFFPosArrow,0); //Установка курсора где должна быть стрелочка
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(DisplayOFFPosArrow+1,0); //позиция курсора для часов
if (AutoOff_Display) {lcd.print("ON"); //Выведем направление ВЫКл-вкл
onButtonPress();}
else lcd.print("OFF"); // Выведем направление ВКЛ-ВЫКЛ
//Логика настройки таймера автоотключения
lcd.setCursor(0,1); //Перевести курсор на нижний левый край
lcd.print("OFFtimer:"); //Надпись Частота опроса датчика
if (DisplayBrightnessFlags== DB_AUTOOFF_M) {
lcd.setCursor(PosArrowDFSPolling,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем минуты при вращении энкодера
DisplayOFF_Min += deltaEncoder;
if (DisplayOFF_Min < 0) DisplayOFF_Min = 10;
if (DisplayOFF_Min > 10) DisplayOFF_Min = 0;
if (DisplayOFF_Sec < 15 && DisplayOFF_Min == 0) DisplayOFF_Sec = 15; //Что бы время отключения экрана было не меньше 15 сек
}
saveToEEPROM();
}
else {
lcd.setCursor(PosArrowDFSPolling,1); //Перевести курсор перед выбором минут
lcd.print(" "); //Стереть стрелочку
}
lcd.setCursor(PosArrowDFSPolling+1,1); //позиция курсора для минут
if (DisplayOFF_Min < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных минут
lcd.print(DisplayOFF_Min); //распечатать кол-во минут
lcd.print("m"); //распечатать кол-во минут
if (DisplayBrightnessFlags == DB_AUTOOFF_S) {
lcd.setCursor(PosArrowDFSPolling+4,1); //Перевести курсор перед выбором времени
lcd.print(">"); //Нарисовать стрелочку
if (deltaEncoder != 0) { // Обновляем минуты при вращении энкодера
DisplayOFF_Sec += deltaEncoder*5;
if (DisplayOFF_Sec < 0) DisplayOFF_Sec = 55;
if (DisplayOFF_Sec > 55) DisplayOFF_Sec = 0;
if (DisplayOFF_Sec < 15 && DisplayOFF_Min == 0) DisplayOFF_Sec = 15; //Что бы время опроса датчиков экрана было не меньше 15 сек
}
saveToEEPROM(); //Сохранения значения в памяти
}
else {
lcd.setCursor(PosArrowDFSPolling+4,1); //Перевести курсор перед минутами
lcd.print(":"); //Заменить стрелочку на двоеточие
}
lcd.setCursor(PosArrowDFSPolling+5,1); //позиция курсора для секунд
if (DisplayOFF_Sec < 10) lcd.print('0'); // Добавляем ведущий ноль для однозначных секунд
lcd.print(DisplayOFF_Sec); //распечатать кол-во секунд
lcd.print("s"); //распечатать кол-во минут
inactivityTimeout = (unsigned long)(DisplayOFF_Min * 60 + DisplayOFF_Sec) * 1000UL; //Помещение в переменную времени отключения дисплея
}
// Функция вызывается при любом нажатии кнопки
void onButtonPress() {
lastActivityTime = millis(); //Запоминание текущего времени
// Включаем подсветку, если она отключена
if (!backlightOn) {
lcd.setBacklight(true);
backlightOn = true;
}
}
//Функция включения - выключения реле питания
void ReleyControl(){
switch (ModeTypeChoise){
case 2:{ //Если выбраны датчики, в выборе режимов работы
switch (sensChoise) { // Проверка - какой датчик сейчас проверяется
case 0: // Если датчик темпеературный
// Управление реле по температуре
if (temperature > Temp_Stay) { //Проверка выходит ли влажность за границы установленной
digitalWrite(RELAY_PIN, !directionHight); //включение реле
RELAY_Stat = !directionHight; //обновление значения переменной состояния реле
} else {
digitalWrite(RELAY_PIN, directionHight); //выключение реле
RELAY_Stat = directionHight; //обновление значения переменной состояния реле
}
break;
case 1:
// Управление реле по влажности
if (humidity > Humanid_Stay) { //Проверка выходит ли влажность за границы установленной
digitalWrite(RELAY_PIN, !directionHight); //включение реле
RELAY_Stat = !directionHight; //обновление значения переменной состояния реле
} else {
digitalWrite(RELAY_PIN, directionHight); //выключение реле
RELAY_Stat = directionHight; //обновление значения переменной состояния реле
}
break;
}
}
break;
case 0:{ //Если выбран таймер в режимах работы
unsigned long currentMillis = millis(); // Текущее время
unsigned long elapsed = currentMillis - previousMillisTimer; // Время, прошедшее с начала текущего режима
if (isPause) { // Если текущий режим — пауза
if ( workDuration > 0 && elapsed >= pauseDuration) { // Если время паузы истекло
isPause = false; // Переходим к режиму работы
previousMillis = currentMillis; // Сбрасываем таймер для работы
digitalWrite(RELAY_PIN, LOW); //включение реле
RELAY_Stat = LOW; //обновление значения переменной состояния реле
}
} else { // Иначе, если текущий режим — работа
if (pauseDuration > 0 && elapsed >= workDuration) { // Если время работы истекло
isPause = true; // Переходим к режиму паузы
previousMillis = currentMillis; // Сбрасываем таймер для паузы
digitalWrite(RELAY_PIN, HIGH); //выключение реле
RELAY_Stat = HIGH; //обновление значения переменной состояния реле
}
}
}
break;
case 1:{ //Если выбрана работа по времени на часах
DateTime now = rtc.now();
int currentHour = now.hour(); // ваш вызов для получения часов
int currentMin = now.minute(); // ваш вызов для минут
if (isInTimeInterval(currentHour, currentMin)) {
// Выполняем работу, если сейчас в промежутке времени
digitalWrite(RELAY_PIN, LOW); //включение реле
RELAY_Stat = LOW; //обновление значения переменной состояния реле
} else {
// не в рабочем времени — можно бездействовать
digitalWrite(RELAY_PIN, HIGH); //выключение реле
RELAY_Stat = HIGH; //обновление значения переменной состояния реле
}
}
}
if (RELAY_Stat == LOW) digitalWrite (LED_PIN, HIGH); // Включаем светодиод
else digitalWrite(LED_PIN, LOW); //Выключаем светодиод
}
void TimeSettingSwichMode(){ //Функция отвечающая за переключение флагов в экране настройки времени
if (!editHour && !editMinutes && !confirmReTime){ //Если не установлен ни один из флагов настройки времени
editHour = true; //Устанавливаем флаг настройки часов
}
else {if (editHour && !editMinutes && !confirmReTime){ //Если установлен флаг настройки часов
editHour =false; //Снимаем флаг настройки часов
editMinutes=true; //Устанавливаем флаг настройки минут
} else {if (!editHour && editMinutes && !confirmReTime){ //Иначе, если стоит флаг настройки мниут
editHour =false; //Убираем флаг настройки часов
editMinutes=false; //Убираем флаг настройки минут
confirmReTime=true; } // ставим флаг подтверждения времени
else {if (!editHour && !editMinutes && confirmReTime){
if (selConfirmReTime) ChangeTime();
else {
editHour =false; //Убираем флаг настройки часов
editMinutes=false; //Убираем флаг настройки минут
confirmReTime=false; // ставим флаг подтверждения времени
timeSetComplete = true; // сообщение, что настройка закончена
showTime(true); //переключение на экран с часами
}
}
}
}
}
if (!timeSetComplete) TimeSetting(); // Переключаем на экран настройки времени
else timeSetComplete = false; //Убираем флаг выполнения программы перенастройки времени
}
// СОХРАНЕНИЕ в EEPROM
void saveToEEPROM() {
if (sensChoise == 1) {EEPROM_writeInt(addr_Humanid_Stay, Humanid_Stay); EEPROM.put(key_addr_Humanid_Stay, keyValue); }
if (sensChoise == 0) {EEPROM_writeInt(addr_Temp_Stay, Temp_Stay); EEPROM.put(key_addr_Temp_Stay, keyValue); }
EEPROM.write(addr_sensChoise, sensChoise); EEPROM.put(key_addr_sensChoise, keyValue);
EEPROM_writeInt(addr_ModeTypeChoise, ModeTypeChoise); EEPROM.put(key_addr_ModeTypeChoise, keyValue);
if (currentScreen == 3) {
EEPROM_writeInt8(addr_Pause_Hour, Pause_Hour); EEPROM.put(key_addr_Pause_Hour, keyValue);
EEPROM_writeInt8(addr_Pause_Min, Pause_Min); EEPROM.put(key_addr_Pause_Min, keyValue);
EEPROM_writeInt8(addr_Pause_Sec, Pause_Sec); EEPROM.put(key_addr_Pause_Sec, keyValue);
EEPROM_writeInt8(addr_Work_Hour, Work_Hour); EEPROM.put(key_addr_Work_Hour, keyValue);
EEPROM_writeInt8(addr_Work_Min, Work_Min); EEPROM.put(key_addr_Work_Min, keyValue);
EEPROM_writeInt8(addr_Work_Sec, Work_Sec); EEPROM.put(key_addr_Work_Sec, keyValue);
return;
}
if (modeTOD == STATE_START_H) {EEPROM_writeInt8(addr_Start_Hour, Start_Hour); EEPROM.put(key_addr_Start_Hour, keyValue); return; }
if (modeTOD== STATE_START_M) {EEPROM_writeInt8(addr_Start_Min, Start_Min); EEPROM.put(key_addr_Start_Min, keyValue); return; }
if (modeTOD== STATE_FINISH_H) {EEPROM_writeInt8(addr_Stop_Hour, Stop_Hour); EEPROM.put(key_addr_Stop_Hour, keyValue); return; }
if (modeTOD== STATE_FINISH_M) {EEPROM_writeInt8(addr_Stop_Min, Stop_Min); EEPROM.put(key_addr_Stop_Min, keyValue); return; }
if (modeDSF == STATE_SWICH_DIR) {EEPROM_writeBool(addr_direction_OFF_ON, direction_OFF_ON); EEPROM.put(key_addr_direction_OFF_ON, keyValue); return; }
if ((currentScreen == 33)) {
EEPROM_writeInt8(addr_Pooling_Rate_Min, Pooling_Rate_Min); EEPROM.put(key_addr_Pooling_Rate_Min, keyValue);
EEPROM_writeInt8(addr_Pooling_Rate_Sec, Pooling_Rate_Sec); EEPROM.put(key_addr_Pooling_Rate_Sec, keyValue);
return; }
EEPROM_writeBool(addr_AutoOff_Display, AutoOff_Display); EEPROM.put(key_addr_AutoOff_Display, keyValue);
if (DisplayBrightnessFlags== DB_AUTOOFF_M) {EEPROM_writeInt8(addr_DisplayOFF_Min, DisplayOFF_Min); EEPROM.put(key_addr_DisplayOFF_Min, keyValue); return; }
if (DisplayBrightnessFlags == DB_AUTOOFF_S) {EEPROM_writeInt8(addr_DisplayOFF_Sec, DisplayOFF_Sec); EEPROM.put(key_addr_DisplayOFF_Sec, keyValue); return; }
}
void ChangeTime(){ //Функция смены времени после изменения на экране настройки часов
rtc.adjust(DateTime(rtc.now().year(), rtc.now().month(), rtc.now().day(), setHour, setMinute, 0)); //записывание в модуль нового времени
confirmReTime=false; // убираем флаг подтверждения времени
selConfirmReTime = false; //Ставим "нет" в подтверждении изменения времени
buttonClick = false; // отжимаем кнопку, что бы больше не переходило на новый экран
currentScreen = 1; // изменение экрана данных на первый
timeSetComplete = true; // сообщение, что настройка закончена
showTime(true); //переключение на экран с часами
}
// функция удаления флагов переменных настроек после смены экрана
void deleteFlags() {
flagSCV = STATE_NONE_SENS; // флаги выбора на экране датчиков и ввода их значение срабатываний
editHour = false; //Переменная изменения времени на часах
editMinutes = false; //Переменнная изменения минут
confirmReTime = false; // флаг подтверждения обновления времени
selConfirmReTime = false; // подтверждение изменения времени
modeState = STATE_NONE; //Снятие флагов на экране режимов работы
modeTimer = STATE_NONE_TIMER; //Снятие флагов на экране настройки таймера
modeTOD = STATE_NONE_TOD; //Снятие флагов на экране настройки режима работы по часам
modeDSF = STATE_NONE_DSF; //Снятие флагов на экране настройки частоты датчиков и направления работы их
DisplayBrightnessFlags = FLAG_NONE_DB; //Снятие флагов автоотключения дисплея
}