#include <WiFi.h>
#include "PubSubClient.h"
#include "DHTesp.h"
#include <LiquidCrystal_I2C.h>
//Kênh gửi
const char * MQTTServer = "broker.emqx.io";
const char* blindsTopic = "IoT/Blinds";
const char* gasSensorTopic = "IoT/GasSensor";
const char* pirSensorTopic = "IoT/PIRSensor";
const char* dhtDataTopic = "IoT/DHTData";
const char* dhtCharTopic = "IoT/CharData";
const char* alertTopic = "IoT/Alert";
// Kênh nhận
const char* doorControlTopic = "IoT/DoorControl";
const char* doorControlTopicResponse = "IoT/DoorControl/Response";
const char* furnaceControlTopic = "IoT/FurnaceControl";
const char* furnaceControlTopicResponse = "IoT/FurnaceControl/Response";
const char* homeControlTopic = "IoT/HomeControl";
const char* homeControlTopicResponse = "IoT/HomeControl/Response";
#define I2C_ADDR 0x27
#define LCD_COLUMNS 20
#define LCD_LINES 4
#define BUZZER_CHANNEL 0
#define BUZZER_FREQUENCY 2000
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
// Tạo ID ngẫu nhiên tại: https://www.guidgen.com/
const char * MQTT_ID = "c5afa5ae-d3a0-48b7-b850-92015a281909";
int Port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
const int ledPin = 19;
const int ledRem = 4;
const int ledTempHum = 25;
const int ledPir = 33;
const int ledDoor = 13;
const int ledFurnace = 12;
const int ledHome = 27;
const int DHT_PIN = 32;
DHTesp dhtSensor;
const int buzzer = 17;
const int gasPin = 16;
const int pir = 35;
const int LDR_PIN = 34;
void WIFIConnect() {
Serial.println("Connecting to SSID: Wokwi-GUEST");
WiFi.begin("Wokwi-GUEST", "");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("WiFi connected");
Serial.print(", IP address: ");
Serial.println(WiFi.localIP());
}
void MQTT_Reconnect() {
while (!client.connected()) {
if (client.connect(MQTT_ID)) {
Serial.print("MQTT Topic: ");
Serial.print(blindsTopic);
Serial.println(" connected");
Serial.println("");
Serial.print("MQTT Topic: ");
Serial.print(gasSensorTopic);
Serial.println(" connected");
Serial.println("");
Serial.print("MQTT Topic: ");
Serial.print(pirSensorTopic);
Serial.println(" connected");
Serial.println("");
Serial.print("MQTT Topic: ");
Serial.print(dhtDataTopic);
Serial.println(" connected");
Serial.println("");
Serial.print("MQTT Topic: ");
Serial.print(alertTopic);
Serial.println(" connected");
Serial.println("");
Serial.print("MQTT Topic: ");
Serial.print(dhtCharTopic);
Serial.println(" connected");
Serial.println("");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void callback(char* topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.println(topic);
Serial.print("Message: ");
String receivedMessage;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
receivedMessage += (char)message[i];
}
Serial.println();
if (String(topic) == doorControlTopic) {
if (receivedMessage == "mở cửa") {
digitalWrite(ledDoor, HIGH); // Mở cửa
client.publish(doorControlTopicResponse, "Cửa đã mở");
} else if (receivedMessage == "đóng cửa") {
digitalWrite(ledDoor, LOW); // Đóng cửa
client.publish(doorControlTopicResponse, "Cửa đã đóng");
}
}
if (String(topic) == furnaceControlTopic) {
if (receivedMessage == "bật lò sưởi") {
digitalWrite(ledFurnace, HIGH); // Bật lò sưởi
client.publish(furnaceControlTopicResponse, "Lò sưởi đã bật");
} else if (receivedMessage == "tắt lò sưởi") {
digitalWrite(ledFurnace, LOW); // Tắt lò sưởi
client.publish(furnaceControlTopicResponse, "Lò sưởi đã tắt");
}
}
if (String(topic) == homeControlTopic) {
if (receivedMessage == "bật đèn") {
digitalWrite(ledHome, HIGH); // Bật ledHome
client.publish(homeControlTopicResponse, "Đèn đã bật");
} else if (receivedMessage == "tắt đèn" || receivedMessage == "Tắt đèn" ) {
digitalWrite(ledHome, LOW); // Tắt ledHome
client.publish(homeControlTopicResponse, "Đèn đã tắt");
}
}
}
void setup() {
// Init
lcd.init();
lcd.backlight();
// Print something
lcd.setCursor(3, 0);
lcd.print("Welcome!");
Serial.begin(115200);
dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
pinMode(ledPin, OUTPUT);
pinMode(ledRem, OUTPUT);
pinMode(ledTempHum, OUTPUT);
pinMode(ledPir, OUTPUT);
pinMode(ledDoor, OUTPUT);
pinMode(ledFurnace, OUTPUT);
pinMode(ledHome, OUTPUT);
digitalWrite(ledRem, LOW);
digitalWrite(ledTempHum, LOW);
digitalWrite(ledPir, LOW);
digitalWrite(ledDoor, LOW);
digitalWrite(ledFurnace, LOW);
digitalWrite(ledHome, LOW);
pinMode(buzzer, OUTPUT);
pinMode(gasPin, INPUT);
pinMode(LDR_PIN, INPUT);
pinMode(pir, INPUT);
// Cấu hình kênh PWM cho buzzer
ledcSetup(BUZZER_CHANNEL, BUZZER_FREQUENCY, 8);
ledcAttachPin(buzzer, BUZZER_CHANNEL);
WIFIConnect();
client.setServer(MQTTServer, Port);
client.setCallback(callback);
//Đăng ký kênh nhận
client.subscribe(doorControlTopic);
client.subscribe(furnaceControlTopic);
client.subscribe(homeControlTopic);
}
// -------------------------------------------------------
void controlBlinds() {
int rawLight = analogRead(LDR_PIN);
int lightValue = map(rawLight, 32, 4063, 100, 0);
if (lightValue > 50) {
digitalWrite(ledRem, HIGH);
// Serial.println("Mo rem cua");
client.publish(blindsTopic, "Mở rèm cửa");
} else {
digitalWrite(ledRem, LOW);
// Serial.println("Dong rem cua");
client.publish(blindsTopic, "Đóng rèm cửa");
}
}
unsigned long previousMillis = 0;
const long interval = 250;
void activateBuzzer() {
// Bật PWM cho buzzer với duty cycle 50%
ledcWrite(BUZZER_CHANNEL, 128); // 128 is xấp xỉ 50% of 255 (8-bit)
}
void deactivateBuzzer() {
// Tắt PWM cho buzzer
ledcWrite(BUZZER_CHANNEL, 0); // Set 0
}
bool displayGasWarning = false;
void checkGasSensor() {
static bool ledState = false;
unsigned long currentMillis = millis();
if (digitalRead(gasPin) == HIGH) {
// Serial.println("Có khí GAS");
displayGasWarning = true;
activateBuzzer();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
ledState = !ledState;
digitalWrite(ledPin, ledState ? HIGH : LOW); // Nhấp nháy đèn LED
lcd.setCursor(0, 2); // Đặt con trỏ tại dòng thứ ba
lcd.print("CANH BAO: Co khi GAS");
// Gửi tin nhắn đến MQTT
client.publish(gasSensorTopic, "CẢNH BÁO: có khí GAS");
}
} else {
// Serial.println("Không có khí GAS");
displayGasWarning = false;
deactivateBuzzer();
digitalWrite(ledPin, LOW); // Đảm bảo đèn LED tắt
ledState = false;
lcd.setCursor(0, 2); // Đặt con trỏ tại dòng thứ ba
lcd.print(" "); // Xóa dòng thứ ba
client.publish(gasSensorTopic, "Không có khí GAS");
}
}
bool pirState = LOW;
void checkPIRSensor() {
bool currentPIRState = digitalRead(pir);
if (currentPIRState != pirState) {
pirState = currentPIRState;
if (pirState == HIGH) {
// Serial.println("Chuyen dong phat hien");
lcd.setCursor(0, 3);
lcd.print("Phat Hien Chuyen Dong");
digitalWrite(ledPir, HIGH);
// Gửi thông điệp MQTT
client.publish(pirSensorTopic, "Phát hiện chuyển động");
} else {
// Serial.println("Khong co chuyen dong");
lcd.setCursor(0, 3);
lcd.print(" ");
digitalWrite(ledPir, LOW);
// Gửi thông điệp MQTT
client.publish(pirSensorTopic, "Không có chuyển động");
}
}
}
const int NUM_READINGS = 5;
float tempReadings[NUM_READINGS] = {0.0};
float humReadings[NUM_READINGS] = {0.0};
int readIndex = 0;
float totalTemp = 0.0;
float totalHum = 0.0;
int numActualReadings = 0; // Biến theo dõi số lượng đọc giá trị thực tế
void readAndDisplayDHT() {
// Đọc giá trị nhiệt độ và độ ẩm
float temperature = dhtSensor.getTemperature();
float humidity = dhtSensor.getHumidity();
// Kiểm tra xem giá trị đọc được có hợp lệ
if (isnan(temperature) || isnan(humidity)) {
lcd.clear();
lcd.print("Error reading DHT");
return;
}
// Định dạng dữ liệu để gửi
String payload = String(temperature) + "," + String(humidity);
// Gửi dữ liệu đến topic MQTT
client.publish(dhtCharTopic, payload.c_str());
// Cập nhật mảng trượt của giá trị nhiệt độ và độ ẩm
totalTemp -= tempReadings[readIndex];
totalHum -= humReadings[readIndex];
tempReadings[readIndex] = temperature;
humReadings[readIndex] = humidity;
totalTemp += temperature;
totalHum += humidity;
if (numActualReadings < NUM_READINGS) {
numActualReadings++;
}
readIndex = (readIndex + 1) % NUM_READINGS;
// Tính trung bình
float avgTemp = (numActualReadings == NUM_READINGS) ? (totalTemp / NUM_READINGS) : (totalTemp / numActualReadings);
float avgHum = (numActualReadings == NUM_READINGS) ? (totalHum / NUM_READINGS) : (totalHum / numActualReadings);
// Gửi dữ liệu nhiệt độ và độ ẩm
char tempHumString[20];
sprintf(tempHumString, "%0.2f,%0.2f", avgTemp, avgHum);
client.publish(dhtDataTopic, tempHumString);
// Kiểm tra ngưỡng và hiển thị giá trị hoặc cảnh báo
if (avgTemp > 40) {
lcd.setCursor(0, 0); // Đặt con trỏ vào vị trí đầu của dòng 1
lcd.print(" "); // Ghi đè dòng 1 bằng khoảng trắng
lcd.setCursor(0, 1); // Đặt con trỏ vào vị trí đầu của dòng 2
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("WARNING:Temp HIGH");
digitalWrite(ledTempHum, HIGH);
client.publish(alertTopic, "Cảnh báo: Nhiệt độ/Độ ẩm đang cao");
} else if(avgTemp < 10) {
lcd.setCursor(0, 0); // Đặt con trỏ vào vị trí đầu của dòng 1
lcd.print(" "); // Ghi đè dòng 1 bằng khoảng trắng
lcd.setCursor(0, 1); // Đặt con trỏ vào vị trí đầu của dòng 2
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("WARNING:Temp LOW");
digitalWrite(ledTempHum, HIGH);
client.publish(alertTopic, "Cảnh báo: Nhiệt độ/Độ ẩm đang thấp");
} else {
// Hiển thị thông thường nếu không vượt ngưỡng
lcd.setCursor(0, 0); // Đặt con trỏ vào vị trí đầu của dòng 1
lcd.print(" "); // Ghi đè dòng 1 bằng khoảng trắng
lcd.setCursor(0, 1); // Đặt con trỏ vào vị trí đầu của dòng 2
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("NhietDo: ");
lcd.print(temperature);
lcd.setCursor(0, 1);
lcd.print("DoAm: ");
lcd.print(humidity);
digitalWrite(ledTempHum, LOW);
client.publish(alertTopic, "Nhiệt độ/Độ ẩm bình thường");
}
}
//--------------------------------------------------------
void process() {
checkPIRSensor();
controlBlinds();
checkGasSensor();
readAndDisplayDHT();
}
void loop() {
if (!client.connected()) {
MQTT_Reconnect();
client.subscribe(doorControlTopic);
client.subscribe(doorControlTopicResponse);
client.subscribe(furnaceControlTopic);
client.subscribe(furnaceControlTopicResponse);
client.subscribe(homeControlTopic);
client.subscribe(homeControlTopicResponse);
}
client.loop();
process();
delay(1000);
}