#include "DHT.h"
#include <ArduinoJson.h>
#include <WiFi.h>
#include "PubSubClient.h"
#include <Stepper.h>
#include <WiFiClientSecure.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_Sensor.h>
#include "RTClib.h"
#include <SPI.h>
#include <ESP32Servo.h>
// Khai báo các thông số kết nối MQTT
const char *MQTTServer = "broker.emqx.io"; // Địa chỉ máy chủ MQTT
const char *MQTT_Topic = "ON_OFF_LED"; // Chủ đề MQTT
const char *MQTT_Topic2 = "ON_OFF_BUZZER"; // Chủ đề MQTT
const char *MQTT_Topic3 = "ON_OFF_AIR"; // Chủ đề MQTT
const char *MQTT_Topic4 = "ON_OFF_TV"; // Chủ đề MQTT
// Các chủ đề MQTT chứa các thông số thiết lập hệ thống
const char *valueSettings = "valueSettings";
const char *MQTT_ID = "conghoa"; // ID của thiết bị MQTT (có thể thay đổi theo nhu cầu)
int Port = 1883; // Cổng kết nối MQTT
// RTC
RTC_DS1307 rtc;
// Định nghĩa các chân và loại cảm biến DHT
#define DHTPIN 23 // Chân kết nối cảm biến DHT22
#define DHTTYPE DHT22 // Loại cảm biến DHT (DHT22)
// Khởi tạo đối tượng cảm biến DHT
DHT dht(DHTPIN, DHTTYPE);
// Các hằng số dùng cho cảm biến LDR (photoresistor)
const int ldr = 39; // Chân đọc dữ liệu từ cảm biến LDR
const float GAMMA = 0.7; // Hằng số gamma của cảm biến LDR
const float RL10 = 50; // Hằng số RL10 của cảm biến LDR
// Cảm biến HC-SRO4
const int echo = 34;
const int trig = 33;
// Cảm biến độ ẩm đất
const int soil = 35;
// Cảm biến gas
const int gas = 32;
// Cảm biến PIR
const int pir = 13;
// Motor
const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 2, 4, 16, 17);
int stepsCompleted = 0; // Biến lưu trữ số bước đã hoàn thành
// LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Led
const int ledPin = 18;
const int ledPinHouse = 19;
const int airPin = 12;
const int pump = 14;
const int ledPinHouse2 = 25;
// Buzzer
const int buzzerPin = 5;
const int buzzerPinHouse = 15;
// Servo
const int servoPin = 27;
Servo servo;
WiFiClient espClient; // Khởi tạo đối tượng client WiFi
PubSubClient client(espClient); // Khởi tạo đối tượng client MQTT
// Hàm kết nối WiFi
void WIFIConnect()
{
Serial.println("Connecting to SSID: Wokwi-GUEST");
WiFi.begin("Wokwi-GUEST", ""); // Kết nối WiFi với SSID và mật khẩu
while (WiFi.status() != WL_CONNECTED)
{ // Kiểm tra trạng thái kết nối
delay(500);
Serial.print("."); // In dấu . khi đang kết nối
}
Serial.println("");
Serial.print("WiFi connected");
Serial.print(", IP address: ");
Serial.println(WiFi.localIP()); // In địa chỉ IP khi kết nối thành công
}
// Hàm kết nối lại với MQTT nếu bị mất kết nối
void MQTT_Reconnect()
{
while (!client.connected())
{ // Kiểm tra kết nối MQTT
if (client.connect(MQTT_ID))
{ // Thử kết nối với MQTT
Serial.println("MQTT Topic: ");
Serial.print(MQTT_Topic);
Serial.println("MQTT Topic2: ");
Serial.print(MQTT_Topic2);
Serial.println("MQTT Topic3: ");
Serial.print(MQTT_Topic3);
Serial.println("MQTT Topic4: ");
Serial.print(MQTT_Topic4);
Serial.println(" connected");
Serial.print(valueSettings);
Serial.println(" connected");
// Đăng ký topic
client.subscribe(valueSettings);
client.subscribe(MQTT_Topic); // Đăng ký nhận tin nhắn từ chủ đề MQTT
client.subscribe(MQTT_Topic2); // Đăng ký nhận tin nhắn từ chủ đề MQTT
client.subscribe(MQTT_Topic3); // Đăng ký nhận tin nhắn từ chủ đề MQTT
client.subscribe(MQTT_Topic4); // Đăng ký nhận tin nhắn từ chủ đề MQTT
Serial.println("");
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state()); // In mã lỗi nếu không kết nối được
Serial.println(" try again in 5 seconds");
delay(5000); // Thử lại sau 5 giây
}
}
}
// Xử lý thiết bị đầu ra
TaskHandle_t taskHandleLED = NULL;
TaskHandle_t taskHandleBuzzer = NULL;
TaskHandle_t taskHandleAir = NULL;
TaskHandle_t taskHandleTV = NULL;
// Khai báo các hàm xử lý
void handleLED(void *parameter);
void handleBuzzer(void *parameter);
void handleAir(void *parameter);
void handleTV(void *parameter);
// Xử lý cảm biến
TaskHandle_t taskHandleGasSensor = NULL;
TaskHandle_t taskHandleLightSensor = NULL;
TaskHandle_t taskHandleSoilMoistureSensor = NULL;
TaskHandle_t taskHandlePIRSensor = NULL;
TaskHandle_t taskHandleUltrasonicSensor = NULL;
TaskHandle_t taskHandleDHTSensor = NULL;
// Khai báo các hàm xử lý
void handleGasSensor(void *parameter);
void handleLightSensor(void *parameter);
void handleSoilMoistureSensor(void *parameter);
void handlePIRSensor(void *parameter);
void handleUltrasonicSensor(void *parameter);
void handleDHTSensor(void *parameter);
// BIẾN TOÀN CỤC LƯU TRỮ CÁC GIÁ TRỊ MẶC ĐỊNH CỦA HỆ THỐNG
float coolingTemperature = 30;
int curtainStartHour = 18;
int curtainEndHour = 6;
float gasWarningThreshold = 500;
int wateringStartHour = 6;
int wateringEndHour = 18;
int wateringThresholdTemperature = 50;
float lightingBrightness = 500;
int lightingStartHour = 6;
int lightingEndHour = 18;
int handwashDistance = 4;
// Hàm callback để xử lý tin nhắn nhận được từ MQTT
void callback(char *topic, byte *message, unsigned int length)
{
String stMessage;
// Chuyển mảng byte thành chuỗi string
for (int i = 0; i < length; i++)
{
stMessage += (char)message[i];
}
Serial.print("Message arrived on topic: ");
Serial.println(topic);
Serial.print("Message: ");
Serial.println(stMessage);
// Xử lý các chủ đề
if (strcmp(topic, "valueSettings") == 0)
{
StaticJsonDocument<200> doc; // Khai báo đối tượng JSON với dung lượng bộ nhớ phù hợp
// Phân giải JSON
deserializeJson(doc, stMessage);
// Lấy giá trị của từng hệ thống từ JSON và lưu vào các biến toàn cục
coolingTemperature = doc["cooling_system"][0][0].as<float>(); // Lấy nhiệt độ của cooling_system
curtainStartHour = doc["curtain_system"][0][0].as<int>(); // Lấy giờ bắt đầu của curtain_system
curtainEndHour = doc["curtain_system"][0][1].as<int>(); // Lấy giờ kết thúc của curtain_system
gasWarningThreshold = doc["gas_leak_system"][0][0].as<float>(); // Lấy ngưỡng cảnh báo của gas_leak_system
wateringThresholdTemperature = doc["watering_system"][0][0].as<int>(); // Ngưỡng của watering_system
wateringStartHour = doc["watering_system"][0][1].as<int>(); // Lấy giờ bắt đầu của watering_system
wateringEndHour = doc["watering_system"][0][2].as<int>(); // Lấy giờ kết thúc của watering_system
lightingBrightness = doc["lighting_system"][0][0].as<float>(); // Lấy độ sáng của lighting_system
lightingStartHour = doc["lighting_system"][0][1].as<int>(); // Lấy giờ bắt đầu của lighting_system
lightingEndHour = doc["lighting_system"][0][2].as<int>(); // Lấy giờ kết thúc của lighting_system
handwashDistance = doc["touchless_handwash_system"][0][0].as<int>(); // Lấy khoảng cách của touchless_handwash_system
// In các giá trị ra Serial Monitor để kiểm tra
Serial.println("Cooling System Target Temperature: " + String(coolingTemperature));
Serial.println("Lighting System Brightness: " + String(lightingBrightness));
Serial.println("Curtain System Start Hour: " + String(lightingStartHour));
Serial.println("Curtain System End Hour: " + String(lightingEndHour));
Serial.println("Gas Leak System Warning Threshold: " + String(gasWarningThreshold));
Serial.println("Watering System Start Hour: " + String(wateringStartHour));
Serial.println("Watering System End Hour: " + String(wateringEndHour));
Serial.println("Watering System Warning Threshold: " + String(wateringThresholdTemperature));
Serial.println("Lighting System Start Hour: " + String(curtainStartHour));
Serial.println("Lighting System End Hour: " + String(curtainEndHour));
Serial.println("Touchless Handwash System Distance: " + String(handwashDistance));
// Gửi phản hồi rằng dữ liệu đã được nhận
client.publish("ok", "Message received"); // Gửi tin nhắn xác nhận
}
// Xử lý bật tắt các thiết bị dựa trên chủ đề
if (strcmp(topic, "ON_OFF_LED") == 0)
{
// Chuyển stMessage thành char* và truyền vào task
char *message = strdup(stMessage.c_str());
xTaskCreate(handleLED, "LED Task", 2048, message, 1, &taskHandleLED);
}
else if (strcmp(topic, "ON_OFF_BUZZER") == 0)
{
char *message = strdup(stMessage.c_str());
xTaskCreate(handleBuzzer, "Buzzer Task", 2048, message, 1, &taskHandleBuzzer);
}
else if (strcmp(topic, "ON_OFF_AIR") == 0)
{
char *message = strdup(stMessage.c_str());
xTaskCreate(handleAir, "Air Task", 2048, message, 1, &taskHandleAir);
}
else if (strcmp(topic, "ON_OFF_TV") == 0)
{
char *message = strdup(stMessage.c_str());
xTaskCreate(handleTV, "TV Task", 2048, message, 1, &taskHandleTV);
}
}
// Xử lý bật tắt đèn
void handleLED(void *parameter)
{
char *state = (char *)parameter;
if (strcmp(state, "on") == 0)
{
digitalWrite(ledPinHouse2, HIGH);
}
else if (strcmp(state, "off") == 0)
{
digitalWrite(ledPinHouse2, LOW);
}
free(parameter); // Giải phóng bộ nhớ sau khi sử dụng
vTaskDelete(NULL); // Xóa tác vụ sau khi hoàn thành
}
// Xử lý bật tắt buzzer
void handleBuzzer(void *parameter)
{
char *state = (char *)parameter;
if (strcmp(state, "on") == 0)
{
digitalWrite(buzzerPinHouse, 1);
vTaskDelay(1000); // Giữ buzzer bật một chút
digitalWrite(buzzerPinHouse, 0);
}
else if (strcmp(state, "off") == 0)
{
digitalWrite(buzzerPinHouse, 1);
vTaskDelay(1000); // Giữ buzzer bật một chút
digitalWrite(buzzerPinHouse, 0);
}
free(parameter); // Giải phóng bộ nhớ sau khi sử dụng
vTaskDelete(NULL); // Xóa tác vụ sau khi hoàn thành
}
// XUử lý bật tắt máy lạnh/máy lạnh
void handleAir(void *parameter)
{
char *state = (char *)parameter;
if (strcmp(state, "on") == 0)
{
// Bật quạt khi nhận lệnh "on"
digitalWrite(airPin, 1);
}
else if (strcmp(state, "off") == 0)
{
// Dừng quạt khi nhận lệnh "off"
digitalWrite(airPin, 0);
}
free(parameter); // Giải phóng bộ nhớ sau khi sử dụng
vTaskDelete(NULL); // Xóa tác vụ sau khi hoàn thành
}
// Xử lý bật tắt màn hình LCD (TV)
void handleTV(void *parameter)
{
char *state = (char *)parameter;
if (strcmp(state, "on") == 0)
{
lcd.backlight();
DateTime now = rtc.now();
// Hiển thị thời gian lên LCD
lcd.setCursor(0, 0); // Dòng đầu tiên
lcd.print("Date: ");
lcd.print(now.year());
lcd.print('/');
lcd.print(now.month());
lcd.print('/');
lcd.print(now.day());
lcd.setCursor(0, 1); // Dòng thứ hai
lcd.print("Time: ");
lcd.print(now.hour());
lcd.print(':');
lcd.print(now.minute());
lcd.print(':');
lcd.print(now.second());
}
else if (strcmp(state, "off") == 0)
{
lcd.clear();
lcd.noBacklight();
}
free(parameter); // Giải phóng bộ nhớ sau khi sử dụng
vTaskDelete(NULL); // Xóa tác vụ sau khi hoàn thành
}
// Hàm gửi dữ liệu DHT (nhiệt độ và độ ẩm) lên MQTT
void sendDHT()
{
// Đọc nhiệt độ và độ ẩm từ cảm biến DHT
float h = dht.readHumidity();
float t = dht.readTemperature();
// Kiểm tra nếu dữ liệu đọc được từ DHT hợp lệ
if (isnan(h) || isnan(t))
{
Serial.println("Failed to read from DHT sensor!");
return;
}
// Tạo đối tượng JSON để đóng gói dữ liệu
StaticJsonDocument<100> doc;
doc["temp"] = t;
doc["hum"] = h;
// Chuyển đối tượng JSON thành chuỗi để gửi qua MQTT
String payload;
serializeJson(doc, payload);
// Gửi dữ liệu nhiệt độ và độ ẩm lên chủ đề MQTT
client.publish("dht", payload.c_str());
}
// Hàm gửi dữ liệu LDR (đo độ sáng) lên MQTT
void sendLDR()
{
// Chuyển giá trị đọc được từ cảm biến LDR (photoresistor) sang giá trị lux
int analogValue = analogRead(ldr); // Đọc giá trị analog từ chân 39
float voltage = analogValue / 4095.0 * 5.0; // Tính điện áp tương ứng
float resistance = 2000 * voltage / (1 - voltage / 5.0); // Tính trở kháng của LDR
float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA)); // Tính giá trị Lux
// Tạo đối tượng JSON để đóng gói dữ liệu
StaticJsonDocument<50> doc;
doc["ldr"] = lux;
// Chuyển đối tượng JSON thành chuỗi để gửi qua MQTT
String payload;
serializeJson(doc, payload);
// Gửi dữ liệu LDR lên chủ đề MQTT
client.publish("ldr", payload.c_str());
}
// Hàm gửi dữ liệu Soil độ ẩm đất
void sendSoil()
{
// Chuyển giá trị đọc được từ Soil độ ẩm đất sang %
int soilHumidity = map(analogRead(soil), 0, 4095, 0, 100);
// Tạo đối tượng JSON để đóng gói dữ liệu
StaticJsonDocument<50> doc;
doc["soilHumidity"] = soilHumidity;
// Chuyển đối tượng JSON thành chuỗi để gửi qua MQTT
String payload;
serializeJson(doc, payload);
// Gửi dữ liệu Soil lên chủ đề MQTT
client.publish("soilHumidity", payload.c_str());
}
// Gửi dữ liệu từ 3 kênh nhiệt độ, độ ẩm, độ ẩm đất và ánh sáng len MQTT
void sendData()
{
// Gửi dữ liệu DHT (nhiệt độ và độ ẩm) lên MQTT
sendDHT();
// Gửi dữ liệu LDR (đo độ sáng) lên MQTT
sendLDR();
// Gửi dữ liệu độ ẩm đất lên MQTT
sendSoil();
delay(2000);
}
// ========================XỬ LÝ CÁC CẢM BIẾN====================
// GAS
void handleGasSensor(void *parameter)
{
int gasValue = 0;
int checkWarningGas = 0;
while (1)
{
gasValue = analogRead(gas); // Đọc giá trị từ cảm biến khí gas
if (gasValue > gasWarningThreshold) // 600
{ // Ngưỡng cảnh báo khí gas
digitalWrite(ledPin, 1);
// tone(buzzerPin, 600, 8);
digitalWrite(buzzerPin, 1);
vTaskDelay(1000);
digitalWrite(buzzerPin, 0);
if (checkWarningGas == 0)
{
// Tạo đối tượng JSON để đóng gói dữ liệu
StaticJsonDocument<50> doc;
doc["gas"] = gasValue;
// Chuyển đối tượng JSON thành chuỗi để gửi qua MQTT
String payload;
serializeJson(doc, payload);
// Gửi dữ liệu LDR lên chủ đề MQTT
client.publish("gasWarning", payload.c_str());
checkWarningGas = 1;
}
}
else
{
digitalWrite(ledPin, 0);
digitalWrite(buzzerPin, 0);
checkWarningGas = 0;
}
vTaskDelay(2000); // Đọc mỗi giây
}
}
// ÁNH SÁNG
void handleLightSensor(void *parameter)
{
float avgLux = 0;
while (1)
{
// Lấy thời gian hiện tại từ RTC
DateTime now = rtc.now();
for (int i = 0; i < 10; i++)
{
// Chuyển giá trị đọc được từ cảm biến LDR (photoresistor) sang giá trị lux
int analogValue = analogRead(ldr); // Đọc giá trị analog từ chân 39
float voltage = analogValue / 4095.0 * 5.0; // Tính điện áp tương ứng
float resistance = 2000 * voltage / (1 - voltage / 5.0); // Tính trở kháng của LDR
float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA)); // Tính giá trị Lux
avgLux += lux;
vTaskDelay(1000);
}
if (avgLux / 10 < lightingBrightness && (now.hour() >= lightingStartHour || now.hour() <= lightingEndHour))
{
// Nếu số bước đã hoàn thành nhỏ hơn 200, tiếp tục quay theo chiều kim đồng hồ
if (stepsCompleted < 200)
{
myStepper.step(stepsPerRevolution); // Quay một vòng theo chiều kim đồng hồ
stepsCompleted += stepsPerRevolution; // Cập nhật số bước đã hoàn thành
vTaskDelay(500 / portTICK_PERIOD_MS); // Delay cho FreeRTOS
}
}
else
{
// Nếu giá trị ánh sáng nhỏ hơn hoặc bằng 500 Lux và đã quay đủ 200 bước, quay ngược lại
if (stepsCompleted >= 200)
{
myStepper.step(-stepsPerRevolution); // Quay ngược lại một vòng
stepsCompleted -= stepsPerRevolution; // Cập nhật số bước đã hoàn thành
vTaskDelay(500 / portTICK_PERIOD_MS); // Delay cho FreeRTOS
}
}
// Reset biến đếm
avgLux = 0;
vTaskDelay(2000);
}
}
// ĐỘ ẨM ĐẤT
void handleSoilMoistureSensor(void *parameter)
{
float avgSoil = 0;
int checkWarningSoil = 0;
while (1)
{
// Lấy thời gian hiện tại từ RTC
DateTime now = rtc.now();
for (int i = 0; i < 10; i++)
{
// Chuyển giá trị đọc được từ Soil độ ẩm đất sang %
int soilHumidity = map(analogRead(soil), 0, 4095, 0, 100);
avgSoil += soilHumidity;
vTaskDelay(1000);
}
if (avgSoil / 10 < wateringThresholdTemperature && (now.hour() >= wateringStartHour || now.hour() <= wateringEndHour))
{
digitalWrite(pump, 1);
if (checkWarningSoil == 0)
{
// Tạo đối tượng JSON để đóng gói dữ liệu
StaticJsonDocument<50> doc;
doc["soilVal"] = avgSoil / 10;
// Chuyển đối tượng JSON thành chuỗi để gửi qua MQTT
String payload;
serializeJson(doc, payload);
// Gửi dữ liệu LDR lên chủ đề MQTT
client.publish("soilWarning", payload.c_str());
checkWarningSoil = 1;
}
}
else
{
digitalWrite(pump, 0);
checkWarningSoil = 0;
}
// Reset biến đếm
avgSoil = 0;
vTaskDelay(2000);
}
}
// PIR
void handlePIRSensor(void *parameter)
{
while (1)
{
// Lấy thời gian hiện tại từ RTC
DateTime now = rtc.now();
// Kiểm tra nếu thời gian hiện tại từ 7 giờ tối đến 5 giờ sáng
if (now.hour() >= curtainStartHour || now.hour() <= curtainEndHour)
{ // 7 PM đến 5 AM
// Nếu có chuyển động (PIR sensor HIGH), bật LED
if (digitalRead(pir) == HIGH)
{
digitalWrite(ledPinHouse, HIGH); // Bật LED
}
else
{
digitalWrite(ledPinHouse, LOW); // Tắt LED
}
}
else
{
digitalWrite(ledPinHouse, LOW); // Tắt LED ngoài giờ hoạt động
}
vTaskDelay(2000); // Đợi 1 giây trước khi đọc lại cảm biến
}
}
// SIÊU ÂM
void handleUltrasonicSensor(void *parameter)
{
while (1)
{
long duration = 0;
int distance = 0;
// Gửi tín hiệu xung ngắn qua chân Trig
digitalWrite(trig, LOW);
delayMicroseconds(2);
digitalWrite(trig, HIGH);
delayMicroseconds(10);
digitalWrite(trig, LOW);
// Đo độ dài của xung phản hồi qua chân Echo
duration = pulseIn(echo, HIGH);
// Tính toán khoảng cách dựa trên thời gian phản hồi
distance = duration * 0.0344 / 2; // Công thức: distance = (duration / 2) * 0.0344
if (distance <= handwashDistance)
{
servo.write(180);
}
else
{
servo.write(90);
}
vTaskDelay(2000);
}
}
// DHT
void handleDHTSensor(void *parameter)
{
float avgTempo = 0;
int checkWarningTmp = 0;
while (1)
{
// Đọc nhiệt độ và độ ẩm từ cảm biến DHT
float h = dht.readHumidity();
float t = dht.readTemperature();
// Kiểm tra nhiệt độ và điều khiển quạt
for (int i = 0; i < 10; i++)
{
avgTempo += t;
vTaskDelay(1000);
}
if (avgTempo / 10 >= coolingTemperature)
{
// Nếu nhiệt độ trên 22°C, bật quạt
digitalWrite(airPin, HIGH);
if (checkWarningTmp == 0)
{
// Tạo đối tượng JSON để đóng gói dữ liệu
StaticJsonDocument<50> doc;
doc["tmp"] = avgTempo / 10;
// Chuyển đối tượng JSON thành chuỗi để gửi qua MQTT
String payload;
serializeJson(doc, payload);
// Gửi dữ liệu LDR lên chủ đề MQTT
client.publish("tmpWarning", payload.c_str());
checkWarningTmp = 1;
}
}
else
{
// Nếu nhiệt độ dưới hoặc bằng 22°C, tắt quạt
digitalWrite(airPin, LOW);
checkWarningTmp = 0;
}
// Reset biến đếm
avgTempo = 0;
vTaskDelay(2000); // Chờ 2 giây trước khi đo lại
}
}
void setup()
{
Serial.begin(115200); // Khởi tạo kết nối serial với tốc độ 115200 baud
// Kết nối WiFi
WIFIConnect();
// Cấu hình kết nối MQTT
client.setServer(MQTTServer, Port);
client.setCallback(callback);
Serial.println(F("DHTxx test!")); // In ra dòng thông báo khởi tạo DHT
// Khởi tạo cảm biến DHT
dht.begin();
// RTC
if (!rtc.begin())
{
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
// HC-SR04
pinMode(trig, OUTPUT);
pinMode(echo, INPUT);
// Led
pinMode(ledPin, OUTPUT);
pinMode(ledPinHouse, OUTPUT);
pinMode(airPin, OUTPUT);
pinMode(pump, OUTPUT);
pinMode(ledPinHouse2, OUTPUT);
// Buzzer
pinMode(buzzerPin, OUTPUT);
pinMode(buzzerPinHouse, OUTPUT);
// LCD
lcd.init();
// Motor
// Cài đặt tốc độ quay 60 rpm
myStepper.setSpeed(60);
// Servo
servo.attach(servoPin);
// Tạo Stack
xTaskCreate(handleGasSensor, "Gas Sensor", 2048, NULL, 1, &taskHandleGasSensor);
xTaskCreate(handleLightSensor, "Light Sensor", 2048, NULL, 1, &taskHandleLightSensor);
xTaskCreate(handleSoilMoistureSensor, "Soil Moisture Sensor", 2048, NULL, 1, &taskHandleSoilMoistureSensor);
xTaskCreate(handlePIRSensor, "PIR Sensor", 2048, NULL, 1, &taskHandlePIRSensor);
xTaskCreate(handleUltrasonicSensor, "Ultrasonic Sensor", 2048, NULL, 1, &taskHandleUltrasonicSensor);
xTaskCreate(handleDHTSensor, "DHT Sensor", 2048, NULL, 1, &taskHandleDHTSensor);
}
void loop()
{
// Kiểm tra kết nối MQTT, nếu không kết nối thì cố gắng kết nối lại
if (!client.connected())
{
MQTT_Reconnect();
}
// Gọi hàm xử lý nhận tin nhắn từ MQTT
client.loop();
// Gửi dữ liệu từ 3 kênh nhiệt độ, độ ẩm, độ ẩm đất và ánh sáng
sendData();
}