#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Wire.h>
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>

// Khai báo chân
#define DHT_PIN 15 // Chân của cảm biến DHT22
#define DHT_TYPE DHT22

#define LIGHT_SENSOR_PIN 34  // Chân của cảm biến ánh sáng

#define TRIG_PIN 19 // Chân TRIG cho HC-SR04
#define ECHO_PIN 18 // Chân ECHO cho HC-SR04

#define RELAY_DHT_PIN_1 14 // Relay điều khiển dựa trên nhiệt độ
#define RELAY_DHT_PIN_2 12 // Relay điều khiển dựa trên độ ẩm
#define RELAY_LIGHT_PIN 32 // Relay điều khiển dựa trên ánh sáng
#define RELAY_ULTRASONIC_PIN 33 // Relay điều khiển cảm biến siêu âm

#define BUTTON_DHT_PIN_1 25 // Nút bấm điều khiển relay DHT 1
#define BUTTON_DHT_PIN_2 13 // Nút bấm điều khiển relay DHT 2
#define BUTTON_LIGHT_PIN 26 // Nút bấm điều khiển relay ánh sáng
#define BUTTON_ULTRASONIC_PIN 27 // Nút bấm điều khiển relay siêu âm

// Màn hình OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Cảm biến DHT22
DHT dht(DHT_PIN, DHT_TYPE);

// Khởi tạo các biến để lưu trạng thái relay và button

  //Trạng thái cuối cùng cho relay
bool dhtRelayState_1 = false; // Trạng thái cuối cùng cho Relay DHT 1
bool dhtRelayState_2 = false; // Trạng thái cuối cùng cho Relay DHT 2
bool lightRelayState = false; // Trạng thái cuối cùng cho Relay ánh sáng
bool ultrasonicRelayState = false; // Trạng thái cuối cùng cho Relay siêu âm
  // Các biến để theo dõi trạng thái nút bấm
volatile bool dhtButtonPressed_1 = false;
volatile bool dhtButtonPressed_2 = false;
volatile bool lightButtonPressed = false;
volatile bool UltraButtonPressed = false;
  // Biến trạng thái điều khiển thủ công
bool dhtManualControl_1 = false; 
bool dhtManualControl_2 = false; 
bool lightManualControl = false; 
bool ultrasonicManualControl = false;

// Khai báo thông tin MQTT
#define MQTT_CLIENT_ID "clientidweather"
#define MQTT_BROKER    "mqtt-dashboard.com"
#define MQTT_TOPIC     "garden" 
#define MQTT_TOPICDK   "gardendk"

const char* ssid = "Wokwi-GUEST";         
const char* password = ""; 

WiFiClient espClient;
PubSubClient client(espClient);

// Hàm kết nối WiFi
void connectWiFi() 
  {
    Serial.print("Connecting to WiFi...");
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      Serial.print(".");
    }
    Serial.println(" Connected!");
  }

// Hàm kết nối lại MQTT
void reconnectMQTT() 
  {
    while (!client.connected()) {
      Serial.print("Connecting to MQTT...");
      if (client.connect(MQTT_CLIENT_ID)) {
        Serial.println(" Connected!");
        client.subscribe(MQTT_TOPICDK); 
      } else {
        Serial.print(" failed, rc=");
        Serial.print(client.state());
        Serial.println(" try again in 5 seconds");
        delay(5000);
      }
    }
  }

// Hàm gửi dữ liệu lên MQTT
void sendToMQTT(float nhietdo, float doam, float anhsang, float mucnuoc) {
  String payload = "{\"temperature\":" + String(nhietdo) +
                   ",\"humidity\":" + String(doam) +
                   ",\"waterLevel\":" + String(mucnuoc) + 
                   ",\"lightIntensity\":" + String(anhsang) +  
                   +",\"RELAY_DHT_1\":" + (dhtRelayState_1 ? "ON" : "OFF") 
                   +",\"RELAY_DHT_2\":" + (dhtRelayState_2 ? "ON" : "OFF") 
                   +",\"RELAY_LIGHT\":" + (lightRelayState ? "ON" : "OFF") 
                   +",\"RELAY_ULTRASONIC\":" + (ultrasonicRelayState ? "ON" : "OFF")
                   +"}"; 
  client.publish(MQTT_TOPIC, payload.c_str());
}

void setup() {
  Serial.begin(115200);
  
  // Cấu hình chân cho cảm biến, relay, nút bấm, và LED
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  pinMode(RELAY_DHT_PIN_1, OUTPUT);
  pinMode(RELAY_DHT_PIN_2, OUTPUT);
  pinMode(RELAY_LIGHT_PIN, OUTPUT);
  pinMode(RELAY_ULTRASONIC_PIN, OUTPUT); 

  pinMode(BUTTON_DHT_PIN_1, INPUT_PULLUP);
  pinMode(BUTTON_DHT_PIN_2, INPUT_PULLUP);
  pinMode(BUTTON_LIGHT_PIN, INPUT_PULLUP);
  pinMode(BUTTON_ULTRASONIC_PIN, INPUT_PULLUP); 

  // Khởi động cảm biến DHT
  dht.begin();

  // Khởi động màn hình OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("OLED initialization failed"));
    for(;;);
  }
  display.clearDisplay();
  display.display();
  
  // Kết nối WiFi và MQTT
  connectWiFi();
  client.setServer(MQTT_BROKER, 1883);
  //client.setCallback(mqttCallback);

  // Cấu hình ngắt
  attachInterrupt(digitalPinToInterrupt(BUTTON_DHT_PIN_1), dhtButtonISR_1, FALLING);
  attachInterrupt(digitalPinToInterrupt(BUTTON_DHT_PIN_2), dhtButtonISR_2, FALLING);
  attachInterrupt(digitalPinToInterrupt(BUTTON_LIGHT_PIN), lightButtonISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(BUTTON_ULTRASONIC_PIN), UltraButtonISR, FALLING);
}

// Ngắt xử lý cho nút bấm
void dhtButtonISR_1() {
  dhtButtonPressed_1 = true;
}
void dhtButtonISR_2() {
  dhtButtonPressed_2 = true;
}
void lightButtonISR() {
  lightButtonPressed = true;
}
void UltraButtonISR() {
  UltraButtonPressed = true;
}

void handleButtons() {
  // Xử lý nút bấm DHT 1
  if (dhtButtonPressed_1) {
    dhtManualControl_1 = !dhtManualControl_1; // Chuyển đổi chế độ thủ công
    dhtRelayState_1 = !dhtRelayState_1; // Đổi trạng thái relay
    digitalWrite(RELAY_DHT_PIN_1, dhtRelayState_1 ? HIGH : LOW);
    dhtButtonPressed_1 = false; // Đặt lại cờ nút bấm
  }

  // Xử lý nút bấm DHT 2
  if (dhtButtonPressed_2) {
    dhtManualControl_2 = !dhtManualControl_2;
    dhtRelayState_2 = !dhtRelayState_2;
    digitalWrite(RELAY_DHT_PIN_2, dhtRelayState_2 ? HIGH : LOW);
    dhtButtonPressed_2 = false;
  }

  // Xử lý nút bấm ánh sáng
  if (lightButtonPressed) {
    lightManualControl = !lightManualControl;
    lightRelayState = !lightRelayState;
    digitalWrite(RELAY_LIGHT_PIN, lightRelayState ? HIGH : LOW);
    lightButtonPressed = false;
  }

  // Xử lý nút bấm siêu âm
  if (UltraButtonPressed) {
    ultrasonicManualControl = !ultrasonicManualControl;
    ultrasonicRelayState = !ultrasonicRelayState;
    digitalWrite(RELAY_ULTRASONIC_PIN, ultrasonicRelayState ? HIGH : LOW);
    UltraButtonPressed = false;
  }
}

// Đọc giá trị từ cảm biến ánh sáng
void readLightLevel(float &lux) {
    int analogValue = analogRead(LIGHT_SENSOR_PIN);
    float voltage = analogValue / 4096.0 * 3.3;
    float resistance = 2000 * voltage / (1 - voltage / 3.3);
    lux = pow(33 * 1e3 * pow(10, 0.7) / resistance, (1 / 0.7));
    Serial.print("Gia tri cuong do a/s: ");
    Serial.print(lux);
    Serial.println(" lux");
}

// Hàm đo khoảng cách từ cảm biến HC-SR04
void measureDistance(float &mucnuochientai) {
  long duration;
  float dodaibenuoc = 200;
  float nguongnuoc = 50;
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
  duration = pulseIn(ECHO_PIN, HIGH);
  float distance = duration * 0.034 / 2; // Tính toán khoảng cách bằng cm
  
  mucnuochientai = dodaibenuoc - distance;
  if(mucnuochientai < 0){
      mucnuochientai=0; 
  }
  Serial.print("Muc nuoc: ");
  Serial.print(mucnuochientai);
  Serial.println(" cm");
  if(mucnuochientai < nguongnuoc && ultrasonicRelayState == LOW){
    digitalWrite(RELAY_ULTRASONIC_PIN, HIGH);
    ultrasonicRelayState = HIGH;
    Serial.print("Dang bom nuoc ");
    Serial.println(" ");
  }else if(mucnuochientai >= nguongnuoc && ultrasonicRelayState == HIGH){
    digitalWrite(RELAY_ULTRASONIC_PIN, LOW);
    ultrasonicRelayState = LOW;
    Serial.print("Khong can bom nuoc ");
    Serial.println(" ");
  }
}

// Đọc nhiệt độ và độ ẩm từ DHT22
void readDHTData(float &temperature, float &humidity) {
  temperature = dht.readTemperature();
  humidity = dht.readHumidity();

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    temperature = humidity = 0; // Đặt giá trị mặc định khi đọc thất bại
  }
  Serial.print("Nhiet do: ");
  Serial.print(temperature);
  Serial.println(" doC");
  Serial.print("Do am: ");
  Serial.print(humidity);
  Serial.println(" %");
}

// Điều khiển relay nhiệt độ và LED 
void controlDHTRelay1(float &temperature) {
    if (temperature > 30 && dhtRelayState_1 == HIGH) { 
        digitalWrite(RELAY_DHT_PIN_1, LOW);
        dhtRelayState_1 = LOW;
        Serial.println(" Nong -> Khong can lo suoi ");
    } else if(temperature <= 30 && dhtRelayState_1 == LOW) {
        digitalWrite(RELAY_DHT_PIN_1, HIGH);
        dhtRelayState_1 = HIGH;
        Serial.println(" Lanh -> Bat lo suoi ");
    }
}

// Điều khiển relay độ ẩm và LED 
void controlDHTRelay2(float &humidity) {
    if (humidity < 65 && dhtRelayState_2 == HIGH) { 
        digitalWrite(RELAY_DHT_PIN_2, LOW);  
        dhtRelayState_2 = LOW;
        Serial.println("DO am thap -> Khong can quat ");
    } else if(humidity >= 65 && dhtRelayState_2 == LOW){
        digitalWrite(RELAY_DHT_PIN_2, HIGH);
        dhtRelayState_2 = HIGH;
        Serial.println("Do am cao -> Bat quat ");
    }
}

// Điều khiển relay dựa trên ánh sáng và LED
void controlLightRelay(float &lux) {
  if (lux < 1000 && lightRelayState == LOW) {
    digitalWrite(RELAY_LIGHT_PIN, HIGH); // Bật LED
    lightRelayState = HIGH;
    Serial.println("Da bat den` ");
  } else if (lux >= 1000 && lightRelayState == HIGH) {
    digitalWrite(RELAY_LIGHT_PIN, LOW); // Tắt LED
    lightRelayState = LOW;
    Serial.println("Khong toi -> Khong can bat den`  ");
  }
}


// Hiển thị thông tin lên màn hình OLED
void displayData(float temperature, float humidity, float lux, float mucnuochientai) {
  display.clearDisplay();
  display.setTextSize(0.6);
  display.setTextColor(WHITE);
  // Hiển thị nhiệt độ và độ ẩm
  display.setCursor(0, 0);
  display.print("Temp: ");
  display.print(temperature);
  display.print(" C");

  display.setCursor(0, 8);
  display.print("Hum: ");
  display.print(humidity);
  display.print(" %");

  // Hiển thị mức ánh sáng
  display.setCursor(0, 16);
  display.print("Light: ");
  display.print(lux);
  display.print(" Lux");

  // Hiển thị khoảng cách
  display.setCursor(0, 24);
  display.print("Muc nuoc ht: ");
  display.print(mucnuochientai);
  display.print(" cm");

  // Hiển thị trạng thái relay 
  display.setCursor(0, 32);
  display.print("Relay DHT 1 : ");
  display.print(dhtRelayState_1 ? "ON" : "OFF");
  
  display.setCursor(0, 40);
  display.print("Relay DHT 2 : ");
  display.print(dhtRelayState_2 ? "ON" : "OFF");

  display.setCursor(0, 48);
  display.print("Relay Light: ");
  display.print(lightRelayState ? "ON" : "OFF");

  display.setCursor(0, 56);
  display.print("Relay Ultrasonic: ");
  display.print(ultrasonicRelayState ? "ON" : "OFF");

  display.display();
}

// Vòng lặp chính
void loop() {
  float temperature, humidity, mucnuochientai;
  float lux;
  if (!client.connected()) {
    reconnectMQTT();
  }
  client.loop(); // Gọi hàm xử lý MQTT
  // Xử lý nút bấm
  handleButtons(); 
  // Đọc dữ liệu từ cảm biến và điều khiển relay nếu không ở chế độ thủ công
  if (!dhtManualControl_1) {
    readDHTData(temperature, humidity);
    controlDHTRelay1(temperature);
  }

  if (!dhtManualControl_2) {
    controlDHTRelay2(humidity);
  }

  if (!lightManualControl) {
    readLightLevel(lux);
    controlLightRelay(lux);
  }

  if (!ultrasonicManualControl) {
    measureDistance(mucnuochientai);
  }
// Hiển thị dữ liệu lên OLED
  displayData(temperature, humidity, lux, mucnuochientai);
  //Gửi dl lên mqtt
  sendToMQTT(temperature, humidity, lux, mucnuochientai);
  // Đợi 2 giây trước khi lặp lại
  delay(2000);
}
Loading
esp32-devkit-c-v4
Loading
ssd1306
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module