#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include "time.h"
#define firebase "https://ef-examen-practica-jamutaq-default-rtdb.firebaseio.com/.json"
// WiFi Configuration
const char* ssid = "Wokwi-GUEST";
const char* password = "";
HTTPClient client;
// Pin Configuration
#define DHT_PIN 22
#define DHT_TYPE DHT22
#define RELAY_PINS {16, 17, 18, 19}
#define LED_PINS {15, 14, 13, 12}
// Constants
const int maxTemperatureThreshold = 30;
const int minHumidityThreshold = 40;
unsigned long lastSendTime = 0;
const int relayActivationIntervals[4][2] = {
{1, 15},
{20, 30},
{35, 45},
{50, 59}
};
// Modes of Operation
enum OperationMode { SCHEDULE_DRIVEN, TEMPERATURE_DRIVEN, HUMIDITY_DRIVEN };
OperationMode currentMode = SCHEDULE_DRIVEN;
// Variables
int relayPins[] = RELAY_PINS;
int ledPins[] = LED_PINS;
bool valveState[4] = {false, false, false, false};
DHT dht(DHT_PIN, DHT_TYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4);
unsigned long lastUpdate = 0;
// NTP Configuration
const char* ntpServer = "1.south-america.pool.ntp.org";
const long gmtOffset_sec = -9000; // Adjust for your timezone
const int daylightOffset_sec = -9000;
String operation_mode = "";
void setup() {
Wire.begin(25, 26);
Serial.begin(115200);
// Connect to WiFi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected.");
// Initialize NTP
configTime(-9000, -9000, "1.south-america.pool.ntp.org");
client.begin(firebase);
int httpResponseCode = client.GET();
lcd.clear();
lcd.setCursor(0, 0);
if (httpResponseCode > 0) {
lcd.print("Firebase Online");
Serial.println("Firebase connected.");
} else {
lcd.print("Firebase Error");
Serial.println("Failed to connect to Firebase.");
}
// Initialize DHT Sensor
dht.begin();
// Initialize Relays and LEDs
for (int i = 0; i < 4; i++) {
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], LOW);
pinMode(ledPins[i], OUTPUT);
digitalWrite(ledPins[i], LOW);
}
// Initialize LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Initializing...");
delay(2000);
Serial.println("Setup complete. Starting operation.");
}
void loop() {
// Get current time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
// Read Sensors
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Failed to read from DHT sensor!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT Error");
delay(2000);
return;
}
// Update Relays based on the current mode
int seconds = timeinfo.tm_sec;
if (humidity < minHumidityThreshold){
currentMode = HUMIDITY_DRIVEN;
} else {
currentMode = SCHEDULE_DRIVEN;
}
if (temperature < maxTemperatureThreshold){
currentMode = TEMPERATURE_DRIVEN;
} else {
currentMode = SCHEDULE_DRIVEN;
}
switch (currentMode) {
case SCHEDULE_DRIVEN:
updateValvesBySchedule(seconds);
operation_mode = "SCHEDULE_DRIVEN";
break;
case TEMPERATURE_DRIVEN:
deactivateAllValves();
operation_mode = "TEMPERATURE_DRIVEN";
break;
case HUMIDITY_DRIVEN:
deactivateAllValves();
operation_mode = "HUMIDITY_DRIVEN";
break;
}
// Update LCD Display
if (millis() - lastUpdate > 1000) {
updateLCD(&timeinfo, temperature, humidity);
lastUpdate = millis();
}
if (millis() - lastSendTime > 2000) {
sendStatusToFirebase(temperature, humidity, operation_mode);
lastSendTime = millis();
}
}
// Function to update valves and LEDs based on the schedule
void updateValvesBySchedule(int seconds) {
for (int i = 0; i < 4; i++) {
if (seconds >= relayActivationIntervals[i][0] && seconds <= relayActivationIntervals[i][1]) {
digitalWrite(relayPins[i], HIGH);
digitalWrite(ledPins[i], HIGH);
valveState[i] = true;
} else {
digitalWrite(relayPins[i], LOW);
digitalWrite(ledPins[i], LOW);
valveState[i] = false;
}
}
}
void sendStatusToFirebase(float temperature, float humidity, String operation_mode){
struct tm timeInfo;
if(!getLocalTime(&timeInfo)) {
Serial.println("Failed to obtain time");
}
char timeStringBuffer[20];
strftime(timeStringBuffer, sizeof(timeStringBuffer), "%d/%m/%Y %H:%M", &timeInfo);
client.PATCH("{\"deviceId\":\"0\"}");
client.PATCH("{\"operationMode\":\"" + operation_mode + "\"}");
client.PATCH("{\"currentTemperature\":\"" + String(temperature) + "\"}");
client.PATCH("{\"currentHumidity\":\"" + String(humidity) + "\"}");
client.PATCH("{\"createdAt\":\"" + String(timeStringBuffer) + "\"}");
}
// Function to deactivate all valves and LEDs
void deactivateAllValves() {
for (int i = 0; i < 4; i++) {
digitalWrite(relayPins[i], LOW);
digitalWrite(ledPins[i], LOW);
valveState[i] = false;
}
}
// Function to update the LCD display
void updateLCD(struct tm* timeinfo, float temperature, float humidity) {
lcd.clear();
// Display current date and time
char buffer[20];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M", timeinfo);
lcd.setCursor(0, 0);
lcd.print(buffer);
// Display Valve States
lcd.setCursor(0, 1);
lcd.print("V1: ");
lcd.print(valveState[0] ? "ON " : "OFF");
lcd.setCursor(10, 1);
lcd.print("V2: ");
lcd.print(valveState[1] ? "ON " : "OFF");
lcd.setCursor(0, 2);
lcd.print("V3: ");
lcd.print(valveState[2] ? "ON " : "OFF");
lcd.setCursor(10, 2);
lcd.print("V4: ");
lcd.print(valveState[3] ? "ON " : "OFF");
// Display Sensor Data
lcd.setCursor(0, 3);
lcd.print("T:");
lcd.print(temperature, 1);
lcd.print("C H:");
lcd.print(humidity, 1);
lcd.print("%");
}