#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <DHT.h>
#include <Servo.h>
#include <EEPROM.h>
#include <Keypad.h>
// Визначення пінів для енкодера
#define PIN_ENCODER_CLK 2
#define PIN_ENCODER_DT 3
#define PIN_ENCODER_SW 4
// Піни для підключення датчика DHT22, сервоприводу та реле
#define PIN_DHT22 5
#define PIN_SERVO 6
#define PIN_RELAY 9
// Ініціалізація LCD, RTC, DHT, Servo та EEPROM
LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS1307 rtc;
DHT dht(PIN_DHT22, DHT22);
Servo myServo;
// Визначення рядків та стовпців клавіатури
char keys[4][3] = {
{ '1', '2', '3'},
{ '4', '5', '6'},
{ '7', '8', '9'},
{ '*', '0', '#'}
};
// Визначення пінів для рядків та стовпців клавіатури
const uint8_t colPins[3] = { A2, A1, A0};
const uint8_t rowPins[4] = { 12, 11, 10, A3 };
// Ініціалізація клавіатури
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, 4, 3);
// Початкові значення для параметрів
int Values[8] = { 7,0, 24,0, 10,50, 10,50 };
void setup() {
pinMode(PIN_ENCODER_SW, INPUT_PULLUP);
attachInterrupt(0, encoderInterruptFunc, CHANGE);
lcd.init(); lcd.backlight();
// EEPROM.get(0, Values);
rtc.begin();
dht.begin();
myServo.attach(PIN_SERVO);
pinMode(PIN_RELAY, OUTPUT);
}
// Змінні для вмикання/вимикання поливу та освітлення
bool water = 0;
bool light = 0;
// Змінні для курсору та значень екрану
int cursor = 0;
int screen0Values[7] = {0};
int screenNumber = 0;
// Основний цикл програми
void loop() {
// Робота з модулями
modulesWorker();
if (screenNumber == 0){
DateTime now = rtc.now();
screen0Values[0] = dht.readTemperature();
screen0Values[1] = dht.readHumidity();
screen0Values[2] = light;
screen0Values[3] = water;
screen0Values[4] = now.hour();
screen0Values[5] = now.minute();
screen0Values[6] = now.second();
} else if (screenNumber == 1){
if ( cursor == 0 ) Values[0] = keyboardRead(0, 24, Values[0]);
else if(cursor==1) Values[1] = keyboardRead(0, 60, Values[1]);
else if(cursor==2) Values[2] = keyboardRead(0, 24, Values[2]);
else if(cursor==3) Values[3] = keyboardRead(0, 60, Values[3]);
else if(cursor==4) Values[4] = keyboardRead(-40,40, Values[4]);
else if(cursor==5) Values[5] = keyboardRead(-40,40, Values[5]);
else if(cursor==6) Values[6] = keyboardRead(0, 100, Values[6]);
else if(cursor==7) Values[7] = keyboardRead(0, 100, Values[7]);
} else if (screenNumber == 2){
if (cursor==1) light = keyboardRead(0, 1, light);
else if(cursor==0) water = keyboardRead(0, 1, water);
}
screenUpdate();
delay(20);
// Зміна екрану при натисканні кнопки енкодера
if(!digitalRead(PIN_ENCODER_SW)){
screenNumber++;
if(screenNumber >= 3) screenNumber=0;
lcd.clear();
delay(100);
}
}
void modulesWorker(){
digitalWrite(PIN_RELAY, light*250);
myServo.write(water? 90 : 0);
if (screenNumber == 2) return;
int sunriseHour = Values[0];
int sunriseMinute = Values[1];
int sunsetHour = Values[2];
int sunsetMinute = Values[3];
int tempMin = Values[4];
int tempMax = Values[5];
int humiMin = Values[6];
int humiMax = Values[7];
DateTime now = rtc.now();
DateTime sunrise = DateTime(now.year(), now.month(), now.day(),
sunriseHour, sunriseMinute, 0);
DateTime sunset = DateTime(now.year(), now.month(), now.day(),
sunsetHour, sunsetMinute, 0);
light = (sunrise < now and now < sunset);
int humi = dht.readHumidity();
int temp = round(dht.readTemperature());
water = humiMin < humi and humi < humiMax and
tempMin < temp and temp < tempMax;
}
int customMap(int numMin, int numMax, int num){
if (num < numMin) num = numMax;
else if (num > numMax) num = numMin;
return num;
}
String strNumber = "";
int keyboardRead(int numMin, int numMax, int numDefault){
char key = keypad.getKey();
int intNumber = strNumber.toInt();
if (numMin < 0 and key == '*'){
intNumber *= -1;
strNumber = String(intNumber);
return intNumber;
}
else if (key == '#'){
strNumber = '0';
return 0;
}
strNumber += key;
intNumber = strNumber.toInt();
intNumber = customMap(numMin, numMax, intNumber);
strNumber = String(intNumber);
EEPROM.put(0, Values);
return intNumber;
}
const String nameValues[8] = {
"sunriseH",
"sunriseM",
"sunsetH ",
"sunsetM ",
"tempMin ",
"tempMax ",
"humiMin ",
"humiMax "
};
const String screen0nameValues[7] = {
"temp ",
"humi ",
"water",
"light",
"hour ",
"min ",
"sec "
};
const String screen2nameValues[2] = {
"water ",
"light "
};
boolean lastState, turnFlag;
void encoderInterruptFunc(){
bool state0 = bitRead(PIND, PIN_ENCODER_CLK);
if (state0 == lastState) return;
turnFlag = !turnFlag;
if (turnFlag)
cursor += (bitRead(PIND, PIN_ENCODER_DT) != lastState) ? -1 : 1;
lastState = state0;
if (screenNumber == 0)
cursor = customMap(0, 6, cursor);
else if (screenNumber == 1)
cursor = customMap(0, 8, cursor);
else if (screenNumber == 2)
cursor = customMap(0, 1, cursor);
strNumber = String(Values[cursor]);
}
const String screenName[] = {" About "," Info ", " Settings"};
void screenUpdate(){
lcd.setCursor(0,0); lcd.print("Screen"+screenName[screenNumber]);
lcd.setCursor(0,1); lcd.print("=");
if (screenNumber == 0){
for(int i=0; i<3; i++){
lcd.setCursor(1, i+1);
int rowI = cursor+i;
if(rowI >= 7) rowI -=7;
lcd.print(screen0nameValues[rowI]
+ " = " + screen0Values[rowI] + " ");
}
} else if (screenNumber == 1){
for(int i=0; i<3; i++){
lcd.setCursor(1, i+1);
int rowI = cursor+i;
if(rowI >= 8) rowI -=8;
lcd.print(nameValues[rowI]
+ " = " + Values[rowI] + " ");
}
} else if (screenNumber == 2){
int values[2]={water, light};
for(int i=0; i<2; i++){
lcd.setCursor(1, i+1);
int rowI = cursor+i;
if(rowI >= 2) rowI -=2;
lcd.print(screen2nameValues[rowI] + " = "
+ (values[rowI]? "on ":"off"));
}
}
}