#include <Wire.h>
#include "GyverEncoder.h"
#include <microDS3231.h>
#include <GyverHTU21D.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
// ПИНЫ
#define rele1 2 // Лампа
#define rele2 3 // Насос 1
#define rele3 4 // Насос 2 (добавь провод на этот пин)
#define CLK 7
#define DT 6
#define SW 5
Encoder enc1(CLK, DT, SW);
MicroDS3231 rtc;
GyverHTU21D htu;
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ПЕРЕМЕННЫЕ НАСТРОЕК
int16_t a1, a2; // Лампа: a1 - старт, a2 - стоп
int16_t b1, b2, b3; // Насос 1: b1 - сек, b2 - дни, b3 - час
int16_t c1, c2, c3; // Насос 2: c1 - сек, c2 - дни, c3 - час
// СИСТЕМНЫЕ ПЕРЕМЕННЫЕ
uint8_t w = 0; // Состояние меню (0-просмотр, 1..8 - настройка)
uint8_t mode = 0; // Экран (0-LAMP, 1-P1, 2-P2)
uint32_t startDay1, startDay2; // Дни отсчета для полива
unsigned long pumpTimer1, pumpTimer2;
bool isWatering1 = false, isWatering2 = false;
bool wateredToday1 = false, wateredToday2 = false;
void setup() {
//rtc.setTime(COMPILE_TIME);
Serial.begin(9600);
htu.begin();
enc1.setType(TYPE2);
Wire.setWireTimeout(3000, true);
pinMode(rele1, OUTPUT);
pinMode(rele2, OUTPUT);
pinMode(rele3, OUTPUT);
digitalWrite(rele1, 1);
digitalWrite(rele2, 1);
digitalWrite(rele3, 1);
lcd.init();
lcd.backlight();
// ЗАГРУЗКА ИЗ EEPROM
EEPROM.get(0, a1); EEPROM.get(2, a2);
EEPROM.get(4, b1); EEPROM.get(6, b2); EEPROM.get(8, b3); EEPROM.get(10, startDay1);
EEPROM.get(14, c1); EEPROM.get(16, c2); EEPROM.get(18, c3); EEPROM.get(20, startDay2);
}
void loop() {
enc1.tick();
static uint32_t sensT;
if (millis() - sensT >= 2000) { sensT = millis(); htu.readTick(); }
handleEncoder();
static uint32_t dispT;
if (millis() - dispT >= 300) { dispT = millis(); updateDisplay(); }
controlHardware();
}
void handleEncoder() {
if (w == 0) {
// Порядок: 0 (LAMP) -> 1 (P1) -> 2 (P2)
if (enc1.isLeft()) { mode++; if (mode > 2) mode = 0; lcd.clear(); }
if (enc1.isRight()) { if (mode == 0) mode = 2; else mode--; lcd.clear(); }
if (enc1.isClick()) {
if (mode == 0) w = 1; // Настройка Лампы
else if (mode == 1) w = 3; // Настройка P1
else if (mode == 2) w = 6; // Настройка P2
}
}
else if (w == 1) {
if (enc1.isRight()) a1--; if (enc1.isLeft()) a1++;
if (a1 > 23) a1 = 0; if (a1 < 0) a1 = 23;
if (enc1.isClick()) { EEPROM.put(0, a1); w = 2; }
}
else if (w == 2) {
if (enc1.isRight()) a2--; if (enc1.isLeft()) a2++;
if (a2 > 23) a2 = 0; if (a2 < 0) a2 = 23;
if (enc1.isClick()) { EEPROM.put(2, a2); w = 0; lcd.clear(); }
}
else if (w == 3) {
if (enc1.isRight()) b1--; if (enc1.isLeft()) b1++;
if (b1 > 300) b1 = 1; if (b1 < 1) b1 = 300;
if (enc1.isClick()) { EEPROM.put(4, b1); w = 4; }
}
else if (w == 4) {
if (enc1.isRight()) b2--; if (enc1.isLeft()) b2++;
if (b2 > 9) b2 = 1; if (b2 < 1) b2 = 9;
if (enc1.isClick()) { EEPROM.put(6, b2); w = 5; }
}
else if (w == 5) {
if (enc1.isRight()) b3--; if (enc1.isLeft()) b3++;
if (b3 > 23) b3 = 0; if (b3 < 0) b3 = 23;
if (enc1.isClick()) {
startDay1 = rtc.getUnix(3) / 86400L;
EEPROM.put(10, startDay1); EEPROM.put(8, b3); w = 0; lcd.clear();
}
}
else if (w == 6) {
if (enc1.isRight()) c1--; if (enc1.isLeft()) c1++;
if (c1 > 300) c1 = 1; if (c1 < 1) c1 = 300;
if (enc1.isClick()) { EEPROM.put(14, c1); w = 7; }
}
else if (w == 7) {
if (enc1.isRight()) c2--; if (enc1.isLeft()) c2++;
if (c2 > 9) c2 = 1; if (c2 < 1) c2 = 9;
if (enc1.isClick()) { EEPROM.put(16, c2); w = 8; }
}
else if (w == 8) {
if (enc1.isRight()) c3--; if (enc1.isLeft()) c3++;
if (c3 > 23) c3 = 0; if (c3 < 0) c3 = 23;
if (enc1.isClick()) {
startDay2 = rtc.getUnix(3) / 86400L;
EEPROM.put(20, startDay2); EEPROM.put(18, c3); w = 0; lcd.clear();
}
}
}
void updateDisplay() {
int8_t hrs = rtc.getHours();
int8_t mins = rtc.getMinutes();
bool blink = (millis() / 500) % 2;
uint32_t currentDay = rtc.getUnix(3) / 86400L;
// --- ВЕРХНЯЯ СТРОКА ---
lcd.setCursor(0, 0);
if (hrs < 10) lcd.print('0'); lcd.print(hrs);
lcd.print(blink ? " " : ":");
if (mins < 10) lcd.print('0'); lcd.print(mins);
lcd.setCursor(6, 0); lcd.print("T:"); lcd.print((int)htu.getTemperature()); lcd.write(223);
lcd.setCursor(11, 0); lcd.print(" ");
lcd.setCursor(12, 0); lcd.print("H:"); lcd.print((int)htu.getHumidity());
// --- НИЖНЯЯ СТРОКА ---
// 1. РЕЖИМ ПРОСМОТРА (Главные экраны)
if (w == 0) {
lcd.setCursor(0, 1);
if (mode == 0) { // Экран LAMP
lcd.print(F("LAMP "));
if (a1 < 10) lcd.print('0'); lcd.print(a1); lcd.print(F(":00-"));
if (a2 < 10) lcd.print('0'); lcd.print(a2); lcd.print(F(":00 "));
}
else { // Экраны P1 или P2
int s = (mode == 1) ? b1 : c1;
int d = (mode == 1) ? b2 : c2;
int h = (mode == 1) ? b3 : c3;
uint32_t sd = (mode == 1) ? startDay1 : startDay2;
int daysToWait = ((currentDay - sd) % d);
lcd.print(mode == 1 ? F("P1") : F("P2"));
lcd.setCursor(2, 1); if (s < 100) lcd.print(' '); if (s < 10) lcd.print(' '); lcd.print(s); lcd.print('s');
lcd.setCursor(7, 1); lcd.print(d); lcd.print('d');
lcd.print('('); lcd.print(daysToWait); lcd.print(')');
lcd.setCursor(13, 1); if (h < 10) lcd.print('0'); lcd.print(h); lcd.print('h');
}
}
// 2. НАСТРОЙКА ЛАМПЫ (Вернули этот блок)
else if (w == 1 || w == 2) {
lcd.setCursor(0, 1);
lcd.print(F("LAMP "));
if (w == 1 && blink) lcd.print(F(" "));
else { if (a1 < 10) lcd.print('0'); lcd.print(a1); }
lcd.print(F(":00-"));
if (w == 2 && blink) lcd.print(F(" "));
else { if (a2 < 10) lcd.print('0'); lcd.print(a2); }
lcd.print(F(":00 "));
}
// 3. НАСТРОЙКА НАСОСОВ (P1: w=3-5, P2: w=6-8)
else if (w >= 3) {
bool isP1 = (w <= 5);
int s = isP1 ? b1 : c1;
int d = isP1 ? b2 : c2;
int h = isP1 ? b3 : c3;
lcd.setCursor(0, 1);
lcd.print(isP1 ? F("P1") : F("P2"));
// Сек (Позиция 2-4)
lcd.setCursor(2, 1);
if ((w == 3 || w == 6) && blink) lcd.print(F(" "));
else {
if (s < 100) lcd.print(' ');
if (s < 10) lcd.print(' ');
lcd.print(s);
}
lcd.print('s'); // Позиция 5
lcd.setCursor(7, 1);
if ((w == 4 || w == 7) && blink) {
lcd.print(F(" ")); // Один пробел для мигания одной цифры
} else {
lcd.print(d);
}
lcd.print(F("d ")); // Позиция 8
// Час запуска (Позиция 10)
lcd.setCursor(10, 1);
if ((w == 5 || w == 8) && blink) {
lcd.print(F(" "));
} else {
if (h < 10) lcd.print('0');
lcd.print(h);
}
lcd.print(F("h ")); // Очистка конца строки
}
}
void controlHardware() {
int8_t hrs = rtc.getHours();
uint32_t currentDay = rtc.getUnix(3) / 86400L;
// ЛАМПА
if (a1 < a2) digitalWrite(rele1, (hrs >= a1 && hrs < a2) ? 0 : 1);
else digitalWrite(rele1, (hrs >= a1 || hrs < a2) ? 0 : 1);
// ПОЛИВ P1
if (hrs == b3 && ((currentDay - startDay1) % b2 == 0) && !wateredToday1) {
digitalWrite(rele2, 0); pumpTimer1 = millis(); isWatering1 = true; wateredToday1 = true;
}
if (hrs != b3) wateredToday1 = false;
if (isWatering1 && (millis() - pumpTimer1 >= (unsigned long)b1 * 1000)) {
digitalWrite(rele2, 1); isWatering1 = false;
}
// ПОЛИВ P2
if (hrs == c3 && ((currentDay - startDay2) % c2 == 0) && !wateredToday2) {
digitalWrite(rele3, 0); pumpTimer2 = millis(); isWatering2 = true; wateredToday2 = true;
}
if (hrs != c3) wateredToday2 = false;
if (isWatering2 && (millis() - pumpTimer2 >= (unsigned long)c1 * 1000)) {
digitalWrite(rele3, 1); isWatering2 = false;
}
}