#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>
/// Đánh dấu các chân cắm của các linh kiện điện tử
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SCL 22 //
#define SDA 21 //
#define aLED_PIN 19 // Led thông báo hệ thống đã khởi động
#define wLED_PIN 18 // Led thông báo cần tưới nước
#define RELAY_PIN 17 // Relay cấp điện máy bơm
#define BUZZER_PIN 23 // Loa
#define LDR_PIN 32 // cảm biến cường độ ánh sáng
#define SOIL_PIN 34 // cảm biến độ ẩm đất
#define PH_PIN 35 // cảm biến đo độ pH đất
#define DHT_PIN 25 // Cảm biến độ ẩm và nhiệt độ không khí
#define DHTTYPE DHT22
/// Setup kết nối wifi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// MQTT Broker information
const char* mqtt_server = "broker.hivemq.com";
const int port = 1883;
const char* mqtt_user = "your-username"; // Thay bằng username của bạn
const char* mqtt_pass = "your-password"; // Thay bằng password của bạn
// MQTT Topics
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";
// WiFi and MQTT clients
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
void mqttConnect() {
while(!mqttClient.connected()) {
Serial.println("Attemping MQTT connection...");
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
if(mqttClient.connect(clientId.c_str())) {
Serial.println("connected");
//***Subscribe all topic you need***
mqttClient.subscribe(temp_topic);
mqttClient.subscribe(hum_topic);
mqttClient.subscribe(ldr_topic);
mqttClient.subscribe(soil_topic);
}
else {
Serial.println(mqttClient.state());
Serial.println("try again in 5 seconds");
delay(5000);
}
}
}
//MQTT Receiver
void callback(char* topic, byte* message, unsigned int length) {
Serial.println(topic);
String strMsg;
for(int i=0; i<length; i++) {
strMsg += (char)message[i];
}
Serial.println(strMsg);
//***Code here to process the received package***
}
// Cấu hình DHT22
DHT dht(DHT_PIN, DHTTYPE);
// Cấu hình RTC DS1307
RTC_DS1307 rtc;
// Cấu hình màn SSD1306 OLED
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void wifiConnect() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" Connected!");
}
String Soil_Status(int i){
String msg = i < 2165 ? "WET" : i > 3135 ? "DRY" : "GOOD";
return msg;
}
void setup(){
Serial.begin(9600);
while(!Serial);
dht.begin();
Serial.println("DHT ready!");
Wire.begin(SDA, SCL);
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__)));
}
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);
pinMode(aLED_PIN, OUTPUT);
pinMode(wLED_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
// Thiếp lập trạng thái mặc định ban đầu
digitalWrite(RELAY_PIN, LOW);
analogWrite(aLED_PIN, LOW);
analogWrite(wLED_PIN, LOW);
Serial.println("OUTPUT ready!");
Serial.print("Connecting to WiFi");
wifiConnect();
// MQTT
mqttClient.setServer(mqtt_server, port);
mqttClient.setCallback(callback);
mqttClient.setKeepAlive(90);
analogWrite(aLED_PIN, HIGH); // Thông báo việc khởi động hoàn thành
Serial.println("All Ready!");
}
int WateringMode = 1; // default
int Automatic_Mode1(){
display.clearDisplay();
display.setCursor(0, 0);
display.print("Watering");
int startTime = millis();
bool status = 1;
while(analogRead(SOIL_PIN) < 2500){
if(status){
display.setCursor(0, 10);
display.print("...");
}
else{
display.setCursor(0, 10);
display.print(" ");
}
status = -1 * status + 1;
}
display.setCursor(0, 20);
int WaterTime = millis() - startTime; // ms
WaterTime /= 1000; // seconds
int WaterAmount = WaterTime * 50;
display.clearDisplay();
display.setCursor(0, 0);
display.print("Finish watering!");
display.setCursor(0, 10);
display.print("Amount of water: ");
display.print(WaterAmount);
display.print(" ml");
return WaterAmount; // pump 3l/m -> 50ml/s
}
unsigned long lastMsgTime = 0; // Biến lưu thời gian lần cuối cùng gửi dữ liệu
const long interval = 5000; // Khoảng thời gian giữa các lần gửi dữ liệu, tính bằng ms (10,000 ms = 10 giây)
void loop() {
// Đọc dữ liệu từ cảm biến DHT22
float h = dht.readHumidity();
while(!h)
h = dht.readHumidity();
float t = dht.readTemperature();
while(!t){
t = dht.readTemperature();
}
// Đọc dữ liệu từ cảm biến cường độ ánh sáng (LDR)
int ldrValue = analogRead(LDR_PIN);
// Đọc trạng thái độ ẩm đất
int soilValue = analogRead(SOIL_PIN);
// Đọc trạng thái pH
int phValue = analogRead(PH_PIN);
// 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();
// OLED DISPLAY
// 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 temperature
String temp_payload = String(t);
mqttClient.publish(temp_topic, temp_payload.c_str());
// Publish humidity
String hum_payload = String(h);
mqttClient.publish(hum_topic, hum_payload.c_str());
// Publish LDR value
String ldr_payload = String(ldrValue);
mqttClient.publish(ldr_topic, ldr_payload.c_str());
// Publish Soil Moisture status
int percentSoil = soilValue * 100 / 4096;
String soil_payload = String(percentSoil);
mqttClient.publish(soil_topic, soil_payload.c_str());
// Publish pH value
String pH_payload = String(phValue);
mqttClient.publish(pH_topic, pH_payload.c_str());
// Không tưới sẽ gửi dữ liệu = 0
String water_payload = String(0);
mqttClient.publish(water_topic, water_payload.c_str());
}
// Watering Logic
if (WateringMode == 1 && 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();
int startTime = millis();
bool status = 1;
const char* loadingDots[] = {". ", ".. ", "..."}; // . .. ... . .. ...
int dotIndex = 0;
digitalWrite(RELAY_PIN, HIGH); // bật relay để khởi động máy bơm
while (analogRead(SOIL_PIN) > 2500) {
display.setCursor(0, 10);
display.print(loadingDots[dotIndex]); // Hiển thị chuỗi dotIndex hiện tại
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
display.setCursor(0, 20);
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());
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); // Kiểm tra lại sau 1 giây
}