/***** BLYNK *****/
#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "TMPL6tQgKJGsK"
#define BLYNK_TEMPLATE_NAME "IOT"
#define BLYNK_AUTH_TOKEN "eoue6E5pm7um0FLCUCPkI2-LdM1CwJHq"
#include <WiFiClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
// ===== WIFI =====
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// ===== LCD =====
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ===== RELAY =====
#define RELAY_FAN 18
#define RELAY_HEATER 19
// ===== BUTTON =====
#define BTN_FAN 25
#define BTN_HEATER 26
#define BTN_MODE 27
// ===== STATE =====
bool fanState = false;
bool heaterState = false;
bool autoMode = false;
// ===== DATA =====
float temp = 25;
float hum = 50;
// ===== ALERT =====
bool sentHigh = false;
bool sentLow = false;
// ===== TIMER =====
BlynkTimer timer;
// ===== BLYNK =====
BLYNK_WRITE(V0) { if (!autoMode) fanState = param.asInt(); }
BLYNK_WRITE(V1) { if (!autoMode) heaterState = param.asInt(); }
BLYNK_WRITE(V2) { autoMode = param.asInt(); }
// ===== SLIDER (MANUAL ONLY) =====
BLYNK_WRITE(V7) {
if (!autoMode) temp = param.asFloat();
}
BLYNK_WRITE(V8) {
if (!autoMode) hum = param.asFloat();
}
// ===== AUTO RANDOM =====
void autoControl() {
if (autoMode) {
temp = random(0, 800) / 10.0;
hum = random(0, 1000) / 10.0;
if (temp > 27) {
fanState = true;
heaterState = false;
}
else if (temp < 20) {
heaterState = true;
fanState = false;
}
else {
fanState = false;
heaterState = false;
}
}
}
// ===== BUTTON =====
void readButton() {
static bool lastFan = HIGH;
static bool lastHeater = HIGH;
static bool lastMode = HIGH;
// MODE
bool curMode = digitalRead(BTN_MODE);
if (lastMode == HIGH && curMode == LOW) {
autoMode = !autoMode;
Blynk.virtualWrite(V2, autoMode);
}
lastMode = curMode;
// FAN
bool curFan = digitalRead(BTN_FAN);
if (lastFan == HIGH && curFan == LOW && !autoMode) {
fanState = !fanState;
Blynk.virtualWrite(V0, fanState);
}
lastFan = curFan;
// HEATER
bool curHeater = digitalRead(BTN_HEATER);
if (lastHeater == HIGH && curHeater == LOW && !autoMode) {
heaterState = !heaterState;
Blynk.virtualWrite(V1, heaterState);
}
lastHeater = curHeater;
}
// ===== ALERT =====
void checkAlert() {
// nhiệt độ cao
if (temp > 27) {
if (!sentHigh) {
Blynk.logEvent("temp_high", "Nhiet do vuot nguong >27C!");
sentHigh = true;
}
} else {
sentHigh = false;
}
// nhiệt độ thấp
if (temp < 20) {
if (!sentLow) {
Blynk.logEvent("temp_low", "Nhiet do thap <20C!");
sentLow = true;
}
} else {
sentLow = false;
}
}
// ===== LCD =====
void updateLCD() {
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temp,1);
lcd.print("C H:");
lcd.print(hum,0);
lcd.print("% ");
lcd.setCursor(0, 1);
lcd.print(autoMode ? "AUTO " : "MAN ");
lcd.print("F:");
lcd.print(fanState ? "ON " : "OFF");
lcd.print(" H:");
lcd.print(heaterState ? "ON" : "OFF");
}
// ===== SEND =====
void sendData() {
Blynk.virtualWrite(V3, temp);
Blynk.virtualWrite(V4, hum);
Blynk.virtualWrite(V5, fanState);
Blynk.virtualWrite(V6, heaterState);
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_FAN, OUTPUT);
pinMode(RELAY_HEATER, OUTPUT);
pinMode(BTN_FAN, INPUT_PULLUP);
pinMode(BTN_HEATER, INPUT_PULLUP);
pinMode(BTN_MODE, INPUT_PULLUP);
lcd.init();
lcd.backlight();
Blynk.begin(auth, ssid, pass);
randomSeed(analogRead(0));
// TIMER
timer.setInterval(100L, readButton);
timer.setInterval(5000L, autoControl);
timer.setInterval(1000L, checkAlert);
timer.setInterval(2000L, sendData);
timer.setInterval(0L, updateLCD);
lcd.print("System Start...");
delay(100);
lcd.clear();
}
void loop() {
Blynk.run();
timer.run();
digitalWrite(RELAY_FAN, fanState);
digitalWrite(RELAY_HEATER, heaterState);
}