#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <PubSubClient.h>
// Định nghĩa các tham số màn hình OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Định nghĩa chân cảm biến và thiết bị
const int DHT_PIN = 15;
const int DHT_TYPE = DHT22;
const int photoresistorPin = 33;
const int trigPin = 5;
const int echoPin = 18;
const int Pump = 16;
const int LED = 12;
// Định nghĩa chân nút bấm và relay
const int buttonTempPin = 26;
const int buttonHumidPin = 27;
const int buttonLight = 14;
const int buttonPumpPin = 25; // Nút bấm điều khiển Pump
const int buttonModePin = 32; // Chân nút bấm mới
const int nhiet_do = 23;
const int do_am = 19;
const int anh_sang = 17;
float nguonganhsang = 1000;
float nguongnuoc = 50;
float chieucaobe = 100; // Chiều cao bể chứa
volatile bool TempState = false;
volatile bool HumidState = false;
volatile bool LightState = false;
volatile bool PumpState = false; // Trạng thái của bơm
volatile bool ModeState = false; // Biến để lưu trạng thái
volatile unsigned long lastDebounceTimeTemp = 0;
volatile unsigned long lastDebounceTimeHumid = 0;
volatile unsigned long lastDebounceTimeLight = 0;
volatile unsigned long lastDebounceTimePump = 0;
volatile unsigned long lastDebounceTimeMode = 0;
const unsigned long debounceDelay = 200; // 200ms debounce time
unsigned long previousMillisoled = 0; // Biến để lưu thời gian lần cập nhật trước
const long intervaloled = 100;
DHT dht(DHT_PIN, DHT_TYPE);
// Khai báo thông tin MQTT
#define MQTT_CLIENT_ID "clientidweather"
#define MQTT_BROKER "mqtt-dashboard.com"
#define MQTT_TOPIC "VUONTM"
#define MQTT_TOPICDK "VUONTMDK"
const char* ssid = "Wokwi-GUEST";
const char* password = "";
WiFiClient espClient;
PubSubClient client(espClient);
// Hàm kết nối WiFi
void connectWiFi()
{
Serial.print("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" Connected!");
}
// Hàm kết nối lại MQTT
void reconnectMQTT()
{
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
if (client.connect(MQTT_CLIENT_ID)) {
Serial.println(" Connected!");
client.subscribe(MQTT_TOPICDK);
} else {
Serial.print(" failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
// Hàm gửi dữ liệu lên MQTT
void sendToMQTT(float temperature, float humidity, float distanceCm, float lux) {
String payload = "{\"temperature\":" + String(temperature) +
",\"humidity\":" + String(humidity) +
",\"waterLevel\":" + String(chieucaobe - distanceCm) +
",\"lightIntensity\":" + String(lux) +
",\"nhiet_do\":" + (TempState ? "ON" : "OFF") +
",\"do_am\":" + (HumidState ? "ON" : "OFF") +
",\"anh_sang\":" + (LightState ? "ON" : "OFF") +
",\"MODE\":" + (ModeState ? "AUTO" : "THUCONG") +
",\"pump\":" + (PumpState ? "ON" : "OFF") + "}";
client.publish(MQTT_TOPIC, payload.c_str());
}
// Hàm điều khiển relay dựa trên dữ liệu nhận được
void controlRelay(char* message) {
if(!ModeState){
if (strcmp(message, "TEMP_ON") == 0) {
TempState = true;
digitalWrite(nhiet_do, HIGH);
} else if (strcmp(message, "TEMP_OFF") == 0) {
TempState = false;
digitalWrite(nhiet_do, LOW);
} else if (strcmp(message, "HUMID_ON") == 0) {
HumidState = true;
digitalWrite(do_am, HIGH);
} else if (strcmp(message, "HUMID_OFF") == 0) {
HumidState = false;
digitalWrite(do_am, LOW);
} else if (strcmp(message, "LIGH_ON") == 0) {
LightState = true;
digitalWrite(anh_sang, HIGH);
} else if (strcmp(message, "LIGH_OFF") == 0) {
LightState = false;
digitalWrite(anh_sang, LOW);
} else if (strcmp(message, "PUMP_ON") == 0) {
PumpState = true;
digitalWrite(Pump, HIGH);
} else if (strcmp(message, "PUMP_OFF") == 0) {
PumpState = false;
digitalWrite(Pump, LOW);
}
}
if (strcmp(message, "MODE_AUTO") == 0) {
ModeState = true;
digitalWrite(LED, HIGH);
} else if (strcmp(message, "MODE_THUCONG") == 0) {
ModeState = false;
digitalWrite(LED, LOW);
}
}
// Hàm xử lý tin nhắn MQTT
void mqttCallback(char* topic, byte* payload, unsigned int length) {
payload[length] = '\0';
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
Serial.println((char*)payload);
controlRelay((char*)payload);
}
// Ngắt ngoài để điều khiển relay 1 (nhiệt độ)
void IRAM_ATTR button1Interrupt() {
if ((millis() - lastDebounceTimeTemp) > debounceDelay && !ModeState) {
TempState = !TempState;
digitalWrite(nhiet_do, TempState ? HIGH : LOW);
lastDebounceTimeTemp = millis();
}
}
// Ngắt ngoài để điều khiển relay 2 (độ ẩm)
void IRAM_ATTR button2Interrupt() {
if ((millis() - lastDebounceTimeHumid) > debounceDelay && !ModeState) {
HumidState = !HumidState;
digitalWrite(do_am, HumidState ? HIGH : LOW);
lastDebounceTimeHumid = millis();
}
}
// Ngắt ngoài để điều khiển relay 3 (ánh sáng)
void IRAM_ATTR button3Interrupt() {
if ((millis() - lastDebounceTimeLight) > debounceDelay && !ModeState ) {
LightState = !LightState;
digitalWrite(anh_sang, LightState ? HIGH : LOW);
lastDebounceTimeLight = millis();
}
}
// Ngắt ngoài để điều khiển bơm
void IRAM_ATTR buttonPumpInterrupt() {
if ((millis() - lastDebounceTimePump) > debounceDelay && !ModeState) {
PumpState = !PumpState;
digitalWrite(Pump, PumpState ? HIGH : LOW);
lastDebounceTimePump = millis();
}
}
// Ngắt ngoài để điều khiển chế độ (Mode)
void IRAM_ATTR buttonModeInterrupt() {
if ((millis() - lastDebounceTimeMode) > debounceDelay ) {
ModeState = !ModeState;
digitalWrite(LED, ModeState ? HIGH : LOW);
lastDebounceTimeMode = millis();
}
}
// Khởi tạo các cảm biến và thiết bị
void setup() {
Serial.begin(115200);
pinMode(photoresistorPin, INPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(Pump, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(buttonTempPin, INPUT_PULLUP);
pinMode(buttonHumidPin, INPUT_PULLUP);
pinMode(buttonLight, INPUT_PULLUP);
pinMode(buttonModePin, INPUT_PULLUP);
pinMode(buttonPumpPin, INPUT_PULLUP);
pinMode(nhiet_do, OUTPUT);
pinMode(do_am, OUTPUT);
pinMode(anh_sang, OUTPUT);
dht.begin();
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Không tìm thấy màn hình OLED!"));
while (true);
}
display.clearDisplay();
display.display();
// Kết nối WiFi và MQTT
connectWiFi();
client.setServer(MQTT_BROKER, 1883);
client.setCallback(mqttCallback);
// Thiết lập ngắt ngoài cho nút bấm
attachInterrupt(digitalPinToInterrupt(buttonTempPin), button1Interrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonHumidPin), button2Interrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonLight), button3Interrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonPumpPin), buttonPumpInterrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonModePin), buttonModeInterrupt, FALLING);
}
// Hàm đọc nhiệt độ và độ ẩm
void readTemperatureAndControlLED(float &temp, float &humid) {
temp = dht.readTemperature();
humid = dht.readHumidity();
if (isnan(temp) || isnan(humid)) {
Serial.println("Không đọc được nhiệt độ và độ ẩm!");
return;
}
Serial.print("Nhiet do: ");
Serial.print(temp);
Serial.println(" °C");
Serial.print("Do am: ");
Serial.print(humid);
Serial.println(" %");
if(ModeState){
digitalWrite(nhiet_do, (temp < 12 || temp > 35) ? HIGH : LOW);
TempState = (temp < 12 || temp > 35) ? true : false;
digitalWrite(do_am, (humid < 40 || humid > 70) ? HIGH : LOW);
HumidState = (humid < 40 || humid > 70) ? true : false;
}
}
// Hàm đọc cường độ ánh sáng và điều khiển LED
void readLightAndControlLED(float &lux) {
int lightIntensity = analogRead(photoresistorPin);
float voltage = lightIntensity / 4096.0 * 3.3;
float resistance = 2000 * voltage / (1 - voltage / 3.3);
lux = pow(33 * 1e3 * pow(10, 0.7) / resistance, (1 / 0.7));
Serial.print("Cuong do anh sang: ");
Serial.print(lux);
Serial.println(" lux");
if(ModeState){
digitalWrite(anh_sang, (lux < nguonganhsang) ? HIGH : LOW);
LightState = (lux < nguonganhsang) ? true : false;
}
}
// Hàm đọc khoảng cách và điều khiển bơm
void readDistanceAndControlPump(float &distanceCm) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
distanceCm = duration * 0.034 / 2;
Serial.print("Muc nuoc: ");
Serial.print(chieucaobe-distanceCm);
Serial.println(" cm");
if(ModeState){
if (distanceCm > nguongnuoc) {
digitalWrite(Pump, HIGH);
PumpState=true;
} else if (distanceCm < 20) {
digitalWrite(Pump, LOW);
PumpState=false;
}
}
}
// Hàm hiển thị dữ liệu lên OLED
void displayData(float temp, float humid, float lux, float distanceCm) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.print("Nhiet do: ");
display.print(temp);
display.println(" C");
display.print("Do am: ");
display.print(humid);
display.println(" %");
display.print("Cuong do: ");
display.print(lux);
display.println(" lux");
display.print("Muc nuoc: ");
display.print(chieucaobe - distanceCm);
display.println(" cm");
display.print("Mode: ");
display.println( ModeState ? "Auto" : "thucong");
display.print("TEMP: ");
display.println(TempState ? "ON" : "OFF");
display.print("HUMID: ");
display.println(HumidState ? "ON" : "OFF");
display.print("LIGHT: ");
display.println(LightState ? "ON" : "OFF");
display.print("Pump: ");
display.println( PumpState ? "ON" : "OFF");
display.display();
}
// Vòng lặp chính
void loop() {
unsigned long currentMillis = millis(); // Lấy thời gian hiện tại
// Nếu đã đến lúc cập nhật (500ms trôi qua)
if (currentMillis - previousMillisoled >= intervaloled) {
previousMillisoled = currentMillis; // Cập nhật lại thời gian lần trước
float temp, humid, lux, distanceCm;
// Đọc cảm biến và điều khiển LED
readTemperatureAndControlLED(temp, humid);
readLightAndControlLED(lux);
readDistanceAndControlPump(distanceCm);
// Gửi dữ liệu lên MQTT
sendToMQTT(temp, humid, distanceCm, lux); // Gửi tất cả dữ liệu cảm biến
// Hiển thị dữ liệu lên màn hình OLED
displayData(temp, humid, lux, distanceCm);
}
// Kiểm tra kết nối MQTT
if (!client.connected()) {
reconnectMQTT();
}
client.loop(); // Gọi hàm xử lý MQTT
}