// Константы температуры и влажности
// Идеальные температура и влажность
#define ideal_temperature 22.0
#define ideal_humidity 97.0
// Допустимые отклонения от идельных температуры и влажности
#define delta_ideal_temperature 2.0
#define delta_ideal_humidity 2.0
// Энкодер для изменения настроек
#define ENC_CLK_PIN 3
#define ENC_DT_PIN 4
#define ENC_SW_PIN 5
#include "EncButton.h"
EncButton enc(ENC_CLK_PIN, ENC_DT_PIN, ENC_SW_PIN);
// DHT22 для получения температуры и влажности
#include "DHT.h"
#define DHT_PIN 2
#define DHTTYPE DHT22
DHT dht(DHT_PIN, DHTTYPE);
// LCD-1602 для отображения температуры и влажности
#include "LiquidCrystal_I2C.h"
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C адрес 0x27(0х26, 0x27 или 0x3F), 16 символов и 2 строки
float Display_Tc = 0.0;
float Display_Tt = ideal_temperature;
float Display_Hc = 0.0;
float Display_Ht = ideal_humidity;
// Константы для селекторов на одном экране дисплея
// Константы селектора режима вкл/выкл и таймер
#define DISPLAY_SELECTOR_MODE 0
#define WORKER_MODE_HARD 0
#define DISPLAY_SELECTOR_STATE 1
// Константы селектора таймера
#define WORKER_MODE_TIME 1
#define DISPLAY_SELECTOR_WAITING_TIME 1
#define DISPLAY_SELECTOR_EXECUTION_TIME 2
// Переменные разных экранов дисплея
// Экран статистики
#define DISPLAY_SCREEN_STATS 0
#define DISPLAY_STATS_TEMPERATURE 0
#define DISPLAY_STATS_HUMIDITY 1
int Display_Selector_Max_Stats = 2;
// Экран кулера
#define DISPLAY_SCREEN_COOLER 1
bool Cooler_Mode = WORKER_MODE_HARD;
int Display_Selector_Max_Cooler = 2;
// Экран увлажнителя
#define DISPLAY_SCREEN_HUMIDIFIER 2
bool Humidifier_Mode = WORKER_MODE_HARD;
int Display_Selector_Max_Humidifier = 2;
// Экран нагревателя
#define DISPLAY_SCREEN_HEATER 3
bool Heater_Mode = WORKER_MODE_HARD;
int Display_Selector_Max_Heater = 2;
// Общие настройки экранов
#define SCREENS_COUNT 4
int Display_Screen_Current = 0;
int Display_Selector_Current = 0;
// Мосфеты для питания высокоточной нагрузки
#define MOS_COOLER_PIN 6
#define MOS_HUMIDIFIER_PIN 7
#define MOS_HEATER_PIN 8
// Программный таймер для частоты опроса датчиков
#include "TimerMs.h"
TimerMs tmr(10000, 1, 0); // (период, мс), (0 не запущен / 1 запущен), (режим: 0 период / 1 таймер)
// Переменные для определения нагрузок
int worker_COOLER = 0;
int worker_HUMIDIFIER = 0;
int worker_HEATER = 0;
// Инициализация глобальных переменных
float Tt = Display_Tt;
float Ht = Display_Ht;
float Tc = Tt;
float Hc = Ht;
void update_display(float Tc = -1000, float Hc = -1000)
{
if (Display_Screen_Current == DISPLAY_SCREEN_STATS)
{
Display_Tt = Tt;
Display_Tc = Tc == -1000 ? Display_Tc : Tc;
Display_Ht = Ht;
Display_Hc = Hc == -1000 ? Display_Hc : Hc;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Tc:"));
lcd.print(Display_Tc,1 );
lcd.print(F(" Tt:"));
lcd.print(Display_Tt, 1);
if (Display_Selector_Current == DISPLAY_STATS_TEMPERATURE)
{
lcd.print(F("_"));
}
lcd.setCursor(0, 1);
lcd.print(F("Hc:"));
lcd.print(Display_Hc, 1);
lcd.print(F(" Ht:"));
lcd.print(Display_Ht, 1);
if (Display_Selector_Current == DISPLAY_STATS_HUMIDITY)
{
lcd.print(F("_"));
}
}
else if (Display_Screen_Current == DISPLAY_SCREEN_COOLER)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Cooler "));
if (Cooler_Mode == WORKER_MODE_TIME)
{
lcd.print(F("Time"));
}
else
{
lcd.print(F("Hard"));
}
lcd.setCursor(0, 1);
if (worker_COOLER)
{
lcd.print(F(" On"));
}
else
{
lcd.print(F(" Off"));
}
if (Display_Selector_Current == DISPLAY_SELECTOR_MODE)
{
lcd.setCursor(0, 0);
lcd.print(F("_"));
}
else
{
lcd.setCursor(0, 1);
lcd.print(F("_"));
}
}
else if (Display_Screen_Current == DISPLAY_SCREEN_HUMIDIFIER)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Humidifier "));
if (Humidifier_Mode == WORKER_MODE_TIME)
{
lcd.print(F("Time"));
}
else
{
lcd.print(F("Hard"));
}
lcd.setCursor(0, 1);
if (worker_HUMIDIFIER)
{
lcd.print(F(" On"));
}
else
{
lcd.print(F(" Off"));
}
if (Display_Selector_Current == DISPLAY_SELECTOR_MODE)
{
lcd.setCursor(0, 0);
lcd.print(F("_"));
}
else
{
lcd.setCursor(0, 1);
lcd.print(F("_"));
}
}
else if ( Display_Screen_Current == DISPLAY_SCREEN_HEATER)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Heater "));
if (Heater_Mode == WORKER_MODE_TIME)
{
lcd.print(F("Time"));
}
else
{
lcd.print(F("Hard"));
}
lcd.setCursor(0, 1);
if (worker_HEATER)
{
lcd.print(F(" On"));
}
else
{
lcd.print(F(" Off"));
}
if (Display_Selector_Current == DISPLAY_SELECTOR_MODE)
{
lcd.setCursor(0, 0);
lcd.print(F("_"));
}
else
{
lcd.setCursor(0, 1);
lcd.print(F("_"));
}
}
}
void check_workers_conditions()
{
// если недостаточная влажность, включить увлажнитель
if (Hc < Ht - delta_ideal_humidity)
{
worker_HUMIDIFIER = 1;
}
else if (Hc > Ht)
{
worker_HUMIDIFIER = 0;
}
// если слишком жарко, включить кулер
if (Tc > Tt + delta_ideal_temperature)
{
worker_COOLER = 1;
}
else if (Tc < Tt)
{
worker_COOLER = 0;
}
// если слишком холодно, включить обогреватель
if (Tc < Tt - delta_ideal_temperature)
{
worker_HEATER = 1;
}
else if (Tc > Tt)
{
worker_HEATER = 0;
}
}
void setup()
{
// Инициализация
// Инициализация мониторинга
Serial.begin(9600);
// Инициализация пинов
pinMode(MOS_COOLER_PIN, OUTPUT);
pinMode(MOS_HUMIDIFIER_PIN, OUTPUT);
pinMode(MOS_HEATER_PIN, OUTPUT);
digitalWrite(MOS_COOLER_PIN, 0);
digitalWrite(MOS_HUMIDIFIER_PIN, 0);
digitalWrite(MOS_HEATER_PIN, 0);
// DHT22
dht.begin();
// LCD-1602
lcd.begin(16, 2); // 16 символов и 2 строки
lcd.backlight(); // включить подсветку
}
void loop() {
// Программный таймер
if (tmr.tick())
{
// DHT22 прочитать значения
Hc = dht.readHumidity();
Tc = dht.readTemperature();
// обновить текущие температуры на дисплее, если они изменились
if (Display_Screen_Current == DISPLAY_SCREEN_STATS)
{
if (Display_Tc != Tc || Display_Hc != Hc)
{
update_display(Tc, Hc);
}
}
// проверить, нужно ли включить приборы по датчикам
check_workers_conditions();
}
// Энкодер
if (enc.tick())
{
// Поворот энкодера
if (enc.turn())
{
// Экран статистики
if (Display_Screen_Current == DISPLAY_SCREEN_STATS)
{
if (Display_Selector_Current == DISPLAY_STATS_TEMPERATURE)
{
Tt += (enc.fast() ? 1 : 0.1) * enc.dir();
}
else if (Display_Selector_Current == DISPLAY_STATS_HUMIDITY)
{
Ht += (enc.fast() ? 1 : 0.1) * enc.dir();
}
}
// Экран кулера
else if(Display_Screen_Current == DISPLAY_SCREEN_COOLER)
{
if (Display_Selector_Current == DISPLAY_SELECTOR_MODE)
{
Cooler_Mode = !Cooler_Mode;
}
}
// Экран Увлажнителя
else if(Display_Screen_Current == DISPLAY_SCREEN_HUMIDIFIER)
{
if (Display_Selector_Current == DISPLAY_SELECTOR_MODE)
{
Humidifier_Mode = !Humidifier_Mode;
}
}
// Экран нагревателя
else if(Display_Screen_Current == DISPLAY_SCREEN_HEATER)
{
if (Display_Selector_Current == DISPLAY_SELECTOR_MODE)
{
Heater_Mode = !Heater_Mode;
}
}
update_display();
}
// Нажатия на энкодер
if (enc.hasClicks())
{
int clicks = enc.getClicks();
// Смена настроек еа экране
if(clicks == 1)
{
Display_Selector_Current += 1;
if(Display_Screen_Current == DISPLAY_SCREEN_STATS)
{
Display_Selector_Current %= Display_Selector_Max_Stats;
}
else if(Display_Screen_Current == DISPLAY_SCREEN_COOLER)
{
Display_Selector_Current %= Display_Selector_Max_Cooler;
}
else if(Display_Screen_Current == DISPLAY_SCREEN_HEATER)
{
Display_Selector_Current %= Display_Selector_Max_Heater;
}
else if(Display_Screen_Current == DISPLAY_SCREEN_HUMIDIFIER)
{
Display_Selector_Current %= Display_Selector_Max_Humidifier;
}
}
// Смена текущего окна
else if (clicks == 2)
{
Display_Selector_Current = 0;
Display_Screen_Current += 1;
Display_Screen_Current %= SCREENS_COUNT;
}
update_display();
}
}
}