#include <Wire.h>
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_SSD1306.h>
// Cấu hình các chân cắm của các thiết bị
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SCL 22
#define SDA 21
#define aLED_PIN 19
#define wLED_PIN 18
#define RELAY_PIN 17
#define BUZZER_PIN 23
#define LDR_PIN 32
#define SOIL_PIN 34
#define PH_PIN 35
#define DHT_PIN 25
#define DHTTYPE DHT22
// Cấu hình trạng thái mặc định
int statusValue = 1; // Thiết bị mặc định là bật
// Cấu hình Wifi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Hàm kết nối Wifi
void wifiConnect() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" Connected!");
}
// Cấu hình kết nối MQTT
const char* mqtt_server = "broker.hivemq.com";
const int port = 1883;
const char* mqtt_user = "your-username";
const char* mqtt_pass = "your-password";
// Cấu hình thời gian gửi dữ liệu qua MQTT
unsigned long lastMsgTime = 0; // Thời gian gửi cuối cùng
const long interval = 5000; // Thời gian giữa mỗi lần gửi là 5s
// Cấu hình các tệp lưu dữ liệu
const char* status_topic = "050439/sensor/status";
const char* temp_topic = "050439/sensor/temperature";
const char* hum_topic = "050439/sensor/humidity";
const char* ldr_topic = "050439/sensor/ldr";
const char* soil_topic = "050439/sensor/soil";
const char* pH_topic = "050439/sensor/ph";
const char* water_topic = "050439/sensor/watering";
// Khởi tạo kết nối
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
void mqttConnect() {
while (!mqttClient.connected()) {
Serial.println("Attempting MQTT connection...");
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str(), mqtt_user, mqtt_pass)) {
Serial.println("connected");
mqttClient.subscribe(status_topic);
mqttClient.subscribe(temp_topic);
mqttClient.subscribe(hum_topic);
mqttClient.subscribe(ldr_topic);
mqttClient.subscribe(soil_topic);
}
else {
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
// Hàm đọc dữ liệu lấy về thông qua MQTT
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.println(topic);
String strMsg;
for (int i = 0; i < length; i++) {
strMsg += (char)payload[i];
}
Serial.print("Message: ");
Serial.println(strMsg);
if (String(topic) == status_topic) {
statusValue = strMsg.toInt();
Serial.print("Received status value: ");
Serial.println(statusValue);
}
}
// Khởi tạo cảm biến DHT22
DHT dht(DHT_PIN, DHTTYPE);
// Khởi tạo RTC
RTC_DS1307 rtc; // 0x68
// Khởi tạo màn OLED
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // 0x3c
// Hàm đọc trạng thái ẩm của đất
String Soil_Status(int i) {
String msg = i < 2165 ? "WET" : i > 3135 ? "DRY" : "GOOD";
return msg;
}
void setup() {
// Khởi chạy Serial Monitor
Serial.begin(9600);
while (!Serial);
// Khởi chạy DHT22
dht.begin();
Serial.println("DHT ready!");
// Khởi tạo kết nối I2C
Wire.begin(SDA, SCL);
// Kiểm tra RTC
while (!rtc.begin()) {
Serial.println("Couldn't find RTC");
}
while (!rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
Serial.println("RTC ready!");
// Kiểm tra màn OLED
while (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
}
Serial.println("OLED ready!");
//
pinMode(LDR_PIN, INPUT);
pinMode(PH_PIN, INPUT);
pinMode(SOIL_PIN, INPUT);
Serial.println("INPUT ready!");
pinMode(aLED_PIN, OUTPUT);
pinMode(wLED_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
// Thiết lập trạng thái mặc định
digitalWrite(RELAY_PIN, LOW); // tắt
analogWrite(aLED_PIN, LOW); // tắt
analogWrite(wLED_PIN, LOW); // tắt
Serial.println("OUTPUT ready!");
// Kết nối Wifi
Serial.print("Connecting to WiFi");
wifiConnect();
// Kết nối MQTT
mqttClient.setServer(mqtt_server, port);
mqttClient.setCallback(callback);
mqttClient.setKeepAlive(90);
analogWrite(aLED_PIN, HIGH); // Hiển thị trạng thái hoạt động của thiết bị
Serial.println("All Ready!");
}
void loop() {
if (!mqttClient.connected()) {
mqttConnect();
}
mqttClient.loop();
// Nếu statusValue là 0, thiết bị không hoạt động
if (statusValue == 0) {
Serial.println("Thiết bị đang ở trạng thái không hoạt động. Vui lòng thay đổi trạng thái ở Website để hoạt động!");
analogWrite(aLED_PIN, LOW); // Hiển thị trạng thái không hoạt động của thiết bị
delay(1000);
}
else{
analogWrite(aLED_PIN, HIGH); // Hiển thị trạng thái hoạt động của thiết bị
// Đọc dữ liệu từ cảm biến DHT22
float h = dht.readHumidity(); // độ ẩm không khí
while(isnan(h)){
h = dht.readHumidity(); // %
}
float t = dht.readTemperature(); // nhiệt độ
while(isnan(t)){
t = dht.readTemperature(); // C
}
// Đọc dữ liệu từ cảm biến cường độ ánh sáng (LDR)
int ldrValue = analogRead(LDR_PIN); // lux
// Đọc dữ liệu từ cảm biến độ ẩm đất
int soilValue = analogRead(SOIL_PIN); //
// Đọc dữ liệu từ cảm biến độ pH
int phValue = analogRead(PH_PIN); // pH
// Lấy thời gian hiện tại từ RTC DS1307
DateTime now = rtc.now();
// Hiển thị dữ liệu lên màn hình OLED
display.clearDisplay();
// Hiển thị nhiệt độ
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Temp: ");
display.print(t);
display.print(" C");
// Hiển thị độ ẩm
display.setCursor(0, 10);
display.print("Hum: ");
display.print(h);
display.print(" %");
// Hiển thị giá trị LDR
display.setCursor(0, 20);
display.print("LDR: ");
display.print(ldrValue);
// Hiển thị độ ẩm đất
display.setCursor(0, 30);
display.print("Soil: ");
display.print(Soil_Status(soilValue));
// Hiển thị độ pH
display.print(" pH: ");
display.print(phValue);
// Hiển thị ngày giờ
display.setCursor(0, 40);
display.print("Time: ");
display.print(now.hour(), DEC);
display.print(":");
display.print(now.minute(), DEC);
display.print(":");
display.print(now.second(), DEC);
display.setCursor(0, 50);
display.print("Date: ");
display.print(now.day(), DEC);
display.print("/");
display.print(now.month(), DEC);
display.print("/");
display.print(now.year(), DEC);
// Cập nhật màn hình
display.display();
// Kiểm tra kết nối MQTT và kết nối lại nếu bị mất
while (!mqttClient.connected()) {
mqttConnect();
}
mqttClient.loop();
// Kiểm tra nếu đã đến thời điểm gửi dữ liệu
unsigned long nowMillis = millis();
if (nowMillis - lastMsgTime > interval) {
lastMsgTime = nowMillis;
// Publish nhiệt độ
String temp_payload = String(t);
mqttClient.publish(temp_topic, temp_payload.c_str());
// Publish độ ẩm không khí
String hum_payload = String(h);
mqttClient.publish(hum_topic, hum_payload.c_str());
// Publish cường độ ánh sáng
String ldr_payload = String(ldrValue);
mqttClient.publish(ldr_topic, ldr_payload.c_str());
// Publish độ ẩm đất
int percentSoil = (3620 - soilValue) * 100 / (3620 - 1680);
String soil_payload = String(percentSoil);
mqttClient.publish(soil_topic, soil_payload.c_str());
// Publish độ pH
String pH_payload = String(phValue);
mqttClient.publish(pH_topic, pH_payload.c_str());
// Publish lượng nước tưới. Không tưới sẽ gửi dữ liệu = 0
String water_payload = String(0);
mqttClient.publish(water_topic, water_payload.c_str());
}
// TƯỚI NƯỚC
// Kiểm tra điều kiện độ ẩm đất
if (analogRead(SOIL_PIN) > 3135) {
analogWrite(wLED_PIN, HIGH); // Bật đèn thông báo đang tưới cây
display.clearDisplay();
display.setCursor(0, 0);
display.print("The soil is dry");
display.setCursor(0, 10);
display.print("Begin watering");
delay(1000);
display.clearDisplay();
display.setCursor(0, 0);
display.print("Watering");
display.display();
bool status = 1;
const char* loadingDots[] = {". ", ".. ", "..."}; // . .. ... . .. ...
int dotIndex = 0;
digitalWrite(RELAY_PIN, HIGH); // bật relay để khởi động máy bơm
int startTime = millis();
tone(BUZZER_PIN, 1000); // Bật buzzer
// giữ đất ở trạng thái tốt nhất cho cây trồng = 65%
while (analogRead(SOIL_PIN) > 2359) {
display.clearDisplay();
display.setCursor(0, 0);
display.print("Watering");
display.setCursor(0, 10);
display.print(loadingDots[dotIndex]); // Cho biết thiết bị vẫn đang hoạt động
display.display();
delay(1000); // Điều chỉnh thời gian delay để thay đổi tốc độ của vòng lặp
// Cập nhật chỉ số dotIndex
dotIndex = (dotIndex + 1) % 3;
}
digitalWrite(RELAY_PIN, LOW); // tắt relay để tắt máy bơm
noTone(BUZZER_PIN); // Tắt buzzer
// Tính toán lượng nước đã tưới. 3l/m -> 50ml/s
int WaterTime = millis() - startTime; // ms
WaterTime /= 1000; // seconds
int WaterAmount = WaterTime * 50;
// Sau khi tưới xong, chỉ gửi lượng nước tưới
String water_payload = String(WaterAmount);
mqttClient.publish(water_topic, water_payload.c_str());
// hiển thị lượng nước đã tưới
display.clearDisplay();
display.setCursor(0, 0);
display.print("Finish watering!");
display.setCursor(0, 10);
display.print("Amount of water: ");
display.setCursor(0, 20);
display.print(WaterAmount);
display.print(" ml");
display.display();
analogWrite(wLED_PIN, LOW); // Tắt khi hoàn thành
delay(1000);
}
delay(1000);
}
}