#include <DHT.h>
#include <WiFi.h>
#include "PubSubClient.h"
#include <LiquidCrystal_I2C.h>
#include <AccelStepper.h>
#include <PID_v1_bc.h>
#include <ESP32Servo.h>
#include <SPI.h>
#include "RTClib.h"
#include <HTTPClient.h>
//==================DS1307========================
RTC_DS1307 rtc;
//==================servo=========================
const int servoPin1 = 14;
Servo servo1;
const int servoPin2 = 2;
Servo servo2;
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Định nghĩa các chân động cơ bước
#define STEP_PIN 19
#define DIR_PIN 18
// Đối tượng AccelStepper
AccelStepper stepper(1, STEP_PIN, DIR_PIN);
// Biến PID
double Setpoint = 300; // Giá trị đích mà bạn muốn đạt được (số bước)
double Input; // Số bước hiện tại của stepper motor
double Output;
// Các hằng số PID
double Kp = 2.0, Ki = 0.1, Kd = 0.5;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
DHT dht(4, DHT22);
float temperature ;
float humidity;
// =========================ultrasonic======================
float duration_us, distance_cm;
#define TRIG_PIN 13
#define ECHO_PIN 12
//============================ldr===========================
const int analogInputPin = 27;
int sensorValue = 0;
float convertedValue = 0.0;
//===========================soil============================
const int analogSoil = 33;
//===========================rain============================
const int RAIN = 32;
//=====================pir chuyển động=======================
const int PIR = 27;
//===========================================================
const int ledPin = 2;
const int ledPinAS = 26;
const int button_coi = 5;
const int button_den = 15;
const char * MQTTServer = "broker.hivemq.com";
const char *MQTT_ID = "ESP32_Client";
int Port = 1883;
const char* mqtt_topic_temperature = "nth/temperature";
const char* mqtt_topic_humidity = "nth/humidity";
const char* mqtt_topic_distance = "nth/distance";
const char* mqtt_topic_light = "nth/light";
const char* mqtt_topic_soil = "nth/soil";
const char* mqtt_topic_rain = "nth/rain";
const char* mqtt_topic_pir = "nth/pir";
const char* mqtt_topic_btn_den = "nth/den";
const char* mqtt_topic_btn_coi = "nth/coi";
const char* mqtt_topic_btn_servo1_kc = "nth/servo1_kc";
const char* mqtt_topic_btn_servo2_mua = "nth/servo2_mua";
const char* mqtt_topic_r_nhietdo = "nth/r_nhietdo_nhan";
const char* mqtt_topic_r_doam = "nth/r_doam_nhan";
const char* mqtt_topic_r_anhsang = "nth/r_anhsang_nhan";
const char* mqtt_topic_thoigian1 = "nth/thoigian1";
const char* mqtt_topic_thoigian2 = "nth/thoigian2";
const char *serverURL = "http://xenv7pfsdh.sharedwithexpose.com/baocao_ptud/ketnoi.php";
String stMessage;
String den_nhan, coi_nhan, sv1_nhan, sv2_nhan;
String r_nhietdo , r_doam , r_anhsang, thoigian1, thoigian2 ;
float gt_nhietdo , gt_doam , gt_anhsang ;
int gio1 , gio2 ;
WiFiClient espClient;
PubSubClient client(espClient);
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()) {
Serial.print("Attempting MQTT connection...");
// Tạo kết nối MQTT
if (client.connect(MQTT_ID)) {
Serial.println("connected");
client.subscribe(mqtt_topic_r_nhietdo);
client.subscribe(mqtt_topic_r_doam);
client.subscribe(mqtt_topic_r_anhsang);
client.subscribe(mqtt_topic_thoigian1);
client.subscribe(mqtt_topic_thoigian2);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Đợi 5 giây trước khi thử kết nối lại
// delay(5000);
}
}
}
void callback(char* topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.println(topic);
Serial.print("Message: ");
stMessage = "";
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
stMessage += (char)message[i];
}
if (String(topic) == mqtt_topic_r_nhietdo) {
Serial.print("thong bao nhietdo: ");
Serial.println(topic);
r_nhietdo = stMessage;
}
if (String(topic) == mqtt_topic_r_doam) {
Serial.print("thong bao nhietdo: ");
Serial.println(topic);
r_doam = stMessage ;
}
if (String(topic) == mqtt_topic_r_anhsang) {
Serial.print("thong bao anh sang: ");
Serial.println(topic);
r_anhsang = stMessage;
}
if (String(topic) == mqtt_topic_thoigian1) {
Serial.print("thong bao thoi gian 1: ");
Serial.println(topic);
thoigian1 = stMessage;
}
if (String(topic) == mqtt_topic_thoigian2) {
Serial.print("thong bao thoi gian 2: ");
Serial.println(topic);
thoigian2 = stMessage;
}
Serial.println();
}
void setup() {
WIFIConnect();
client.setServer(MQTTServer, Port);
client.setCallback(callback);
Serial.begin(9600);
//====================led, button, buzzer=============
pinMode(ledPinAS, OUTPUT);
pinMode(23, OUTPUT);
pinMode(button_coi, INPUT);
pinMode(button_den, INPUT);
lcd.init(); // initialize the lcd
lcd.backlight();
// Thiết lập tốc độ và các thông số khác của động cơ bước
stepper.setMaxSpeed(2000);
stepper.setAcceleration(1000);
stepper.setCurrentPosition(0);
// Khởi tạo PID
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(-2000, 2000); // Giới hạn giá trị Output
// Bắt đầu điều khiển động cơ bước
stepper.setSpeed(0);
stepper.moveTo(Setpoint);
//=============ultrasonic==========
pinMode(TRIG_PIN, OUTPUT); // config trigger pin to output mode
pinMode(ECHO_PIN, INPUT);
//==============servo===============
servo1.attach(servoPin1);
servo2.attach(servoPin2);
//===============rain================
pinMode(RAIN, INPUT);
analogReadResolution(10);
//===============pir chuyển động================
pinMode(PIR, INPUT);
//==============DS1307==============
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
}
}
void loop() {
if (!client.connected()) {
MQTT_Reconnect();
}
client.loop();
//=============ds1307===============
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
// Display on LCD
lcd.clear();
lcd.setCursor(5, 0);
lcd.print((now.day() < 10 ? "0" : "") + String(now.day(), DEC));
lcd.print('/');
lcd.print((now.month() < 10 ? "0" : "") + String(now.month(), DEC));
lcd.print('/');
lcd.print(now.year(), DEC);
lcd.setCursor(5, 1);
lcd.print((now.hour() < 10 ? "0" : "") + String(now.hour(), DEC));
lcd.print(':');
lcd.print((now.minute() < 10 ? "0" : "") + String(now.minute(), DEC));
lcd.print(':');
lcd.print((now.second() < 10 ? "0" : "") + String(now.second(), DEC));
gt_anhsang = r_anhsang.toFloat();
gt_nhietdo = r_nhietdo.toFloat();
gt_doam = r_doam.toFloat();
gio1 = thoigian1.toInt();
gio2 = thoigian2.toInt();
Serial.print("gt anh sang: ");
Serial.println(gt_anhsang );
Serial.print("gt nhiet do: ");
Serial.println(gt_nhietdo );
Serial.print("gt do am: ");
Serial.println(gt_doam );
Serial.print("thoi gian1: ");
Serial.println(gio1);
Serial.print("thoi gian2: ");
Serial.println(gio2);
delay(100);
lcd.clear();
//===============dht=================
temperature = dht.readTemperature();
humidity = dht.readHumidity();
//Gửi nhiệt độ & độ ẩm lên MQTT Borker
String a = String(temperature);
String b = String(humidity);
client.publish("nth/temperature", a.c_str());
client.publish("nth/humidity", b.c_str());
lcd.clear();
lcd.setCursor(0,0);
lcd.print("ND: ");
lcd.setCursor(5,0);
lcd.print(temperature);
lcd.setCursor(0,1);
lcd.print("DA: ");
lcd.setCursor(5,1);
lcd.print(humidity);
// nếu nhiệt độ >= 40 và độ ẩm <=50 thì bật động cơ bơm nước.
//Ngược lại thì tắt động cơ bơm nước.
if (temperature >= 35 && humidity <= 50) {
Input = stepper.currentPosition();
myPID.Compute();
stepper.setSpeed(Output);
stepper.runSpeed();
} else {
// Chạy động cơ về vị trí 0
stepper.moveTo(0);
// Chờ cho đến khi động cơ đạt được vị trí mới
while (stepper.distanceToGo() != 0) {
stepper.runToPosition();
}
// Dừng động cơ
stepper.setSpeed(0);
stepper.runSpeed();
}
//=============ultrasonic==========
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
duration_us = pulseIn(ECHO_PIN, HIGH);
float distance_cm = 0.034 * (duration_us / 2);
//Gửi khoảng cách lên MQTT Borker
String c = String(distance_cm);
client.publish("nth/distance", c.c_str());
lcd.setCursor(0,2);
lcd.print("KC: ");
lcd.setCursor(5,2);
lcd.print(distance_cm);
if (distance_cm > 200) {
for (int p = 0; p < 180; p++) {
servo1.write(p);
delay(15);
}
} else if (distance_cm < 150) {
servo1.write(0);
}
//==================ldr====================
sensorValue = analogRead(34);
// Chuyển đổi giá trị analog sang điện áp (V)
float voltage = sensorValue / 4063.0 * 5.0;
// Tính toán điện trở của LDR
float resistance = 2000 * voltage / (1 - voltage / 5.0);
// Công thức tính độ sáng (lux) từ điện trở của LDR
const float GAMMA = 0.7;
const float RL10 = 50.0;
float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
// In giá trị đọc được lên Serial Monitor
// Ánh xạ giá trị từ cảm biến LDR (0 - 4095) sang dải giá trị ánh sáng tương ứng (0 - 1000 lux)
// int lux = map(sensorValue, 0, 4095, 0, 1000);
//Gửi gt ánh sáng lên MQTT Borker
String d = String(lux);
client.publish("nth/light", d.c_str());
lcd.setCursor(0,3);
lcd.print("AS: ");
lcd.setCursor(5,3);
lcd.print(lux);
int tt_den = digitalRead(button_den);
Serial.print("btn_den: ");
Serial.println(tt_den);
lcd.print(" ");
lcd.print(tt_den );
String den ="";
if(tt_den == 0 ){
if(lux < gt_anhsang){
digitalWrite(ledPinAS, HIGH);
}
else{
digitalWrite(ledPinAS, LOW);
}
}
if (tt_den == 1 ) {
digitalWrite(ledPinAS, LOW);
}
client.publish("nth/den", String(den).c_str());
delay(1000);
//========================soil========================
int16_t i = analogRead(33);
String msg = i > 767 ? "WET" : i < 256 ? "DRY" : "OK";
lcd.clear();
lcd.print("Soil: ");
lcd.print(msg);
lcd.setCursor(1,1);
lcd.print(i);
delay(500);
//Gửi gt độ ẩm đất lên MQTT Borker
String f = String(i);
client.publish("nth/soil", f.c_str());
//===========================rain=======================
int digitalRain = digitalRead(RAIN);
String tt_mua ="";
if(digitalRain == HIGH){
servo2.write(180);
tt_mua="Trời mưa";
}
else{
servo2.write(0);
tt_mua="Trời nắng";
}
//Gửi gt mua lên MQTT Borker
String g = String(digitalRain);
client.publish("nth/rain", g.c_str());
//=============================pir chuyển động=================
int tt_pir = digitalRead(PIR);
int tt_btn = digitalRead(button_coi);
Serial.print("button chuyen dong: ");
Serial.println(tt_btn);
Serial.print("PIR: ");
Serial.println(tt_pir);
String coi ="";
int gio = now.hour();
int phut = now.minute();
int giay = now.second();
if( gio >= gio1 || gio <= gio2 ){
if (tt_pir == HIGH ) {
if(tt_btn == LOW){
tone(23, 1000);
} // Bật còi khi PIR phát hiện chuyển động và nút nhấn chưa được nhấn
} else if(tt_pir == LOW) {
noTone(23); // Tắt còi trong các trường hợp khác
}
}
else{
noTone(23);
}
client.publish("nth/coi", String(coi).c_str());
if (coi_nhan == "1") {
tone(23, 1000);
coi_nhan = "1";
}
client.publish(mqtt_topic_btn_coi, coi_nhan.c_str());
//Gửi gt chuyển động lên MQTT Borker
String h = String(tt_pir);
client.publish("nth/pir", h.c_str());
delay(1000);
// String url = String(serverURL) + "?temperature=" + String(temperature) + "&humidity=" + String(humidity);
String url = String(serverURL) + "?nhietdo=" + String(temperature) +
"&doam=" + String(humidity) +
"&khoangcach=" + String(distance_cm) +
"&anhsang=" + String(lux) +
"&doamdat=" + String(i) +
"&mua=" + String(digitalRain) +
"&chuyendong=" + String(tt_pir);
HTTPClient http;
http.begin(url);
http.setTimeout(10000);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
Serial.println("HTTP status code: " + String(httpCode));
Serial.println("Server response: ");
Serial.print(url);
} else {
Serial.println("Error on HTTP request");
}
http.end();
}