#include "myTimer.h"
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <DHT.h>
#include <Servo.h>
#include <EEPROM.h>
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
#define DHT22PIN 5
#define SERVO_PIN 6
#define RELAY_PIN 9
LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS1307 rtc;
DHT dht(DHT22PIN, DHT22);
Servo myservo;
struct settingsStruct {
uint8_t sunriseMinute; uint8_t sunriseHour;
uint8_t sunsetMinute; uint8_t sunsetHour;
int8_t tempMin; int8_t tempMax;
uint8_t humiMin; uint8_t humiMax; };
settingsStruct settings = {
.sunriseMinute = 0, .sunriseHour = 7,
.sunsetMinute = 0, .sunsetHour = 23,
.tempMin = 10, .tempMax = 50,
.humiMin = 10, .humiMax = 50 };
uint8_t light = 1;
bool water = 0;
enum{
STATUS,
SETTINGS,
SERVISE
};
uint8_t screen = 2;
int cursor = 0;
const uint8_t cursorPosSETTINGS[9][2]={
{11,0}, {10,1},{12,1},{10,2},{12,2},
{2,3},{5,3},{10,3},{13,3}
};
const uint8_t cursorPosSERVISE[3][2]={
{11,0}, {7,1}, {7,2}
};
bool settingsNeedSave = false;
void printScreen() {
switch(screen){
case STATUS:{
DateTime now = rtc.now();
printLcd(9, 3,
String(now.hour()) +":"+
String(now.minute()) +":"+
String(now.second()) + " "
);
printLcd(0, 2,
"Light:" +String(light ? "on " : "off") +
" Water:"+String(water ? "on " : "off")+" "
);
printLcd(0, 1,
"H:" + String(dht.readHumidity())
+" T:"+String(dht.readTemperature())+" "
);
printLcd(0,0, "STATUS: SETTINGS");
printLcd(11, 0, ">");
break;}
case SETTINGS:{
printLcd(0, 3,
"T=" +String(settings.tempMin) +
"-" +String(settings.tempMax) +
" H="+String(settings.humiMin) +
"-" +String(settings.humiMax) + " "
);
printLcd(0, 2,
"Sunrise = "+String(settings.sunriseHour) +
":"+String(settings.sunriseMinute) + " "
);
printLcd(0, 1,
"Sunset = "+String(settings.sunsetHour) +
":"+String(settings.sunsetMinute) + " "
);
printLcd(0,0, "SETTINGS: SERVISE");
printLcd(cursorPosSETTINGS[cursor][0],
cursorPosSETTINGS[cursor][1], ">");
break;}
case SERVISE:{
if(settingsNeedSave){
settingsNeedSave = false;
EEPROM.put(0, settings);
}
printLcd(0, 2,
"Light : " +String(light ? "on " : "off") +" "
// "Light : " +String(light) +" "
);
printLcd(0, 1,
"Water : "+String(water ? "on " : "off")+" "
);
printLcd(0,0, "SERVISE: STATUS");
printLcd(cursorPosSERVISE[cursor][0],
cursorPosSERVISE[cursor][1], ">");
break;}
}
}
void printLcd(int8_t col, int8_t row, String str){
lcd.setCursor(col, row);
lcd.print(str);
// for(uint8_t i=str.length()+col; i<20; i--) lcd.print(' ');
}
bool needScreenUpdate = false;
void fastScreenUpdate(){
if(needScreenUpdate){
needScreenUpdate = false;
printScreen();
}
}
bool buttonPress = false;
void button(){
buttonPress = !digitalRead(ENCODER_SW);
if (!buttonPress) return;
if(cursor == 0) {
screen+=1;
if(screen >= 3) screen = 0;
lcd.clear();
}
printScreen();
}
int encCounter;
boolean lastState, turnFlag;
void encoderInterrupt() {
bool state0 = bitRead(PIND, ENCODER_CLK);
if (state0 == lastState) return;
turnFlag = !turnFlag;
if (turnFlag)
encCounter += (bitRead(PIND, ENCODER_DT) != lastState) ? -1 : 1;
lastState = state0;
needScreenUpdate = true;
switch(screen){
case STATUS:{
cursor = 0;
break;}
case SETTINGS:{
if(!buttonPress){
if( 0 > encCounter or encCounter > 8) encCounter = 0;
cursor = encCounter;
} else{
switch (cursor){
case 1:{
settings.sunsetHour = encCounterToRange(0, 24);
break;}
case 2:{
settings.sunsetMinute = encCounterToRange(0, 60);
break;}
case 3:{
settings.sunriseHour = encCounterToRange(0, 24);
break;}
case 4:{
settings.sunriseMinute= encCounterToRange(0, 60);
break;}
case 5:{
settings.tempMin = encCounterToRange(-40, 80);
break;}
case 6:{
settings.tempMax = encCounterToRange(-40, 80);
break;}
case 7:{
settings.humiMin = encCounterToRange(0, 100);
break;}
case 8:{
settings.humiMax = encCounterToRange(0, 100);
break;}
}
settingsNeedSave = true;
}
break;}
case SERVISE:{
if(!buttonPress){
if( 0 > encCounter or encCounter > 3) encCounter = 0;
cursor = encCounter;
} else{
switch (cursor){
case 1:{
water = encCounterToRange(0, 1);
waterOn();
break;}
case 2:{
light = encCounterToRange(0, 1);
break;}
}
}
break;}
}
}
int encCounterToRange(int rangeMin, int rangeMax){
if (encCounter < rangeMin) encCounter = rangeMax;
else if(encCounter > rangeMax) encCounter = rangeMin;
return encCounter;
}
void lightOn(){
if(light > 0 and light < 240){
light+=10;
}
if(light == 255) light = 0;
digitalWrite(RELAY_PIN, light);
// analogWrite(RELAY_PIN, light);
}
void waterOn(){
myservo.write(water? 90 : 0);
}
void sheduleLight(){
if (screen == 2) return;
DateTime now = rtc.now();
DateTime sunrise = DateTime(now.year(), now.month(), now.day(),
settings.sunriseHour, settings.sunriseMinute, 0);
DateTime sunset = DateTime(now.year(), now.month(), now.day(),
settings.sunsetHour, settings.sunsetMinute, 0);
light = (sunrise < now and now < sunset);
}
void sensorWater(){
if(screen == 2) return;
uint8_t humi = dht.readHumidity();
int8_t temp = round(dht.readTemperature());
water = settings.humiMin < humi and humi < settings.humiMax and
settings.tempMin < temp and temp < settings.tempMax;
waterOn();
}
void setup() {
pinMode(ENCODER_SW, INPUT_PULLUP);
attachInterrupt(0, encoderInterrupt, CHANGE);
lcd.init();
lcd.backlight();
// EEPROM.get(0, settings);
rtc.begin();
dht.begin();
myservo.attach(SERVO_PIN);
pinMode(RELAY_PIN, OUTPUT);
}
myTimer timers[] = {
myTimer(1000, printScreen),
myTimer(250, button),
myTimer(50, fastScreenUpdate),
myTimer(100, lightOn),
myTimer(1000, sheduleLight),
myTimer(1000, sensorWater),
};
const uint8_t timersLen = sizeof(timers)/sizeof(timers[0]);
void loop() {
for(uint8_t i = 0; i < timersLen; i++) timers[i].tick();
}