#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Keypad.h>
#include "DHT.h"
#define DHTPIN 4 // Chân data của DHT22 nối với GPIO4
#define DHTTYPE DHT22
#define RELAY_PIN 5 // Chân điều khiển Relay nối với GPIO5
// Cấu hình màn hình OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Khai báo đối tượng hiển thị (Reset pin là -1 nếu dùng chung pin reset ESP32)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Cấu hình cảm biến DHT
#define DHTPIN 4
#define DHTTYPE DHT22
#define RELAY_PIN 5
DHT dht(DHTPIN, DHTTYPE);
// --- CẤU HÌNH KEYPAD 4x4 ---
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {19, 18, 17, 16};
byte colPins[COLS] = {33, 32, 27, 14};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// --- BIẾN TOÀN CỤC MÁY TRẠNG THÁI ---
enum ChieuMode { MODE_MAIN, MODE_SET_TEMP };
ChieuMode currentMode = MODE_MAIN;
float t = 0.0, h = 0.0;
int threshold = 30; // Ngưỡng mặc định
String inputBuffer = ""; // Chuỗi lưu số đang gõ
// Biến thay thế delay()
unsigned long previousMillis = 0;
const long interval = 2000;
void setup() {
Serial.begin(115200);
// Khởi tạo cảm biến
dht.begin();
pinMode(RELAY_PIN, OUTPUT);
// Khởi tạo màn hình OLED với địa chỉ I2C 0x3C
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 10);
display.println("Dang khoi dong...");
display.display();
delay(2000);
}
void loop() {
// 1. ĐỌC CẢM BIẾN KHÔNG DÙNG DELAY
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
h = dht.readHumidity();
t = dht.readTemperature();
// Logic điều khiển Relay ngầm bên dưới
if (!isnan(t)) {
if (t > threshold) digitalWrite(RELAY_PIN, HIGH);
else digitalWrite(RELAY_PIN, LOW);
}
}
// 2. XỬ LÝ NÚT NHẤN TỨC THÌ (Fast Polling)
char key = keypad.getKey();
if (key) {
if (currentMode == MODE_MAIN) {
if (key == 'A') {
currentMode = MODE_SET_TEMP; // Chuyển sang màn hình cài đặt
inputBuffer = ""; // Xóa bộ đệm phím cũ
}
}
else if (currentMode == MODE_SET_TEMP) {
if (key >= '0' && key <= '9') {
inputBuffer += key; // Ghép thêm số vừa gõ
}
else if (key == '#') {
if (inputBuffer.length() > 0) {
threshold = inputBuffer.toInt(); // Lưu ngưỡng mới
}
currentMode = MODE_MAIN; // Quay lại màn hình chính
}
else if (key == '*') {
currentMode = MODE_MAIN; // Hủy bỏ, quay lại màn hình chính
}
}
}
// 3. VẼ MÀN HÌNH THEO TRẠNG THÁI
display.clearDisplay();
display.setTextColor(WHITE);
if (currentMode == MODE_MAIN) {
// Màn hình 1: Hiển thị thông số
display.setTextSize(1);
display.setCursor(0, 0); display.print("HE THONG GIAM SAT");
display.setCursor(0, 55); display.print("Bam 'A' de cai dat");
display.setTextSize(2);
display.setCursor(0, 15); display.print("T:"); display.print(t, 1); display.print("C");
display.setCursor(0, 35); display.print("Max:"); display.print(threshold); display.print("C");
}
else if (currentMode == MODE_SET_TEMP) {
// Màn hình 2: Đang nhập liệu
display.setTextSize(1);
display.setCursor(0, 0); display.print("CAI DAT NGUONG NHIET");
display.setCursor(0, 55); display.print("*: Huy #: Luu");
display.setTextSize(2);
display.setCursor(0, 25);
display.print("Nhiet: ");
display.print(inputBuffer); // Hiển thị số đang gõ nhấp nháy
}
display.display();
float h = dht.readHumidity();
float t = dht.readTemperature();
Serial.println("Nhiệt độ: " + String(t) + "℃");
if (isnan(h) || isnan(t)) {
Serial.println("Loi doc cam bien!");
return;
}
// Cập nhật lên màn hình OLED
display.clearDisplay(); // Xóa màn hình trước khi vẽ mới
display.setTextSize(1);
display.setCursor(0, 0);
display.println("HE THONG GIAM SAT");
display.setTextSize(2); // Chữ to hơn cho thông số
display.setCursor(0, 20);
display.print("T: "); display.print(t, 1); display.println(" C");
display.setCursor(0, 45);
display.print("H: "); display.print(h, 1); display.println(" %");
display.display(); // Lệnh quan trọng để đẩy dữ liệu ra màn hình
if (t > 22.0) {
digitalWrite(RELAY_PIN, HIGH); // Bật thiết bị
} else {
digitalWrite(RELAY_PIN, LOW); // Tắt thiết bị
}
delay(2000);
}