#include <WiFi.h>
#include <FirebaseESP32.h>
#include <DHT.h>
// WiFi credentials - use Wokwi's built-in WiFi
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""
// Firebase configuration
#define FIREBASE_HOST "dripcrop-b5e28-default-rtdb.asia-southeast1.firebasedatabase.app" // Without https://
#define FIREBASE_AUTH "LBlsiiYj6b0GzJcjiy6pSJyuM2zUZI6Wf4eBKNeg" // From Firebase Project Settings
// Device configuration
#define DEVICE_ID "sugarcane"
// Sensor pins (Wokwi simulation pins)
#define DHTPIN 4 // DHT11 data pin
#define MOISTURE_PIN 34 // Moisture sensor analog pin
#define RELAY_PIN 5 // Relay control pin
// Sensor type
#define DHTTYPE DHT11
// Firebase objects
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
// DHT sensor
DHT dht(DHTPIN, DHTTYPE);
// Variables
unsigned long sendDataPrevMillis = 0;
float temperature = 0;
float humidity = 0;
int moisture = 0;
String motorMode = "0";
String motorStatus = "off";
int minThreshold = 30;
int maxThreshold = 60;
void setup() {
Serial.begin(115200);
// Initialize sensors and relay
dht.begin();
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // Start with relay off
// Connect to WiFi
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(300);
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
// Firebase configuration
config.host = FIREBASE_HOST;
config.signer.tokens.legacy_token = FIREBASE_AUTH;
Firebase.reconnectWiFi(true);
Firebase.begin(&config, &auth);
Serial.println("Firebase initialized");
readMotorSettings();
}
void loop() {
if (millis() - sendDataPrevMillis > 5000 || sendDataPrevMillis == 0) {
sendDataPrevMillis = millis();
// Read sensors
readSensors();
// Update sensor data to Firebase
updateSensorData();
// Control motor based on mode and thresholds
controlMotor();
// Check for mode/status changes
readMotorSettings();
}
}
void readSensors() {
// Read DHT11 sensor
humidity = dht.readHumidity();
temperature = dht.readTemperature();
// Check if any reads failed
if (isnan(humidity) || isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
// Simulate moisture reading in Wokwi (0-100%)
moisture = random(0, 100);
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("°C, Humidity: ");
Serial.print(humidity);
Serial.print("%, Moisture: ");
Serial.print(moisture);
Serial.println("%");
}
void updateSensorData() {
String basePath = "/devices/" + String(DEVICE_ID) + "/sensor_data/";
String timestamp = getTimestamp();
// Update temperature
if (Firebase.setFloat(fbdo, basePath + "temperature/" + timestamp, temperature)) {
Serial.println("Temperature updated");
} else {
Serial.println("Temperature update failed: " + fbdo.errorReason());
}
// Update humidity
if (Firebase.setFloat(fbdo, basePath + "humidity/" + timestamp, humidity)) {
Serial.println("Humidity updated");
} else {
Serial.println("Humidity update failed: " + fbdo.errorReason());
}
// Update moisture
if (Firebase.setInt(fbdo, basePath + "moisture/" + timestamp, moisture)) {
Serial.println("Moisture updated");
} else {
Serial.println("Moisture update failed: " + fbdo.errorReason());
}
}
void controlMotor() {
if (motorMode == "1") { // Automatic mode
if (moisture < minThreshold && motorStatus != "on") {
// Turn motor on
digitalWrite(RELAY_PIN, HIGH);
motorStatus = "on";
updateMotorStatus();
Serial.println("Motor turned ON (auto)");
}
else if (moisture > maxThreshold && motorStatus != "off") {
// Turn motor off
digitalWrite(RELAY_PIN, LOW);
motorStatus = "off";
updateMotorStatus();
Serial.println("Motor turned OFF (auto)");
}
}
else if (motorMode == "0") { // Manual mode
// Status is controlled by app, we just need to read it
// (handled in readMotorSettings)
}
}
void readMotorSettings() {
String basePath = "/devices/" + String(DEVICE_ID) + "/motor/";
// Read mode
if (Firebase.getString(fbdo, basePath + "mode")) {
motorMode = fbdo.stringData();
}
// Read status (only in manual mode)
if (motorMode == "0" && Firebase.getString(fbdo, basePath + "status")) {
String newStatus = fbdo.stringData();
if (newStatus != motorStatus) {
motorStatus = newStatus;
digitalWrite(RELAY_PIN, motorStatus == "on" ? HIGH : LOW);
Serial.println("Motor turned " + motorStatus + " (manual)");
}
}
// Read thresholds (only once to save bandwidth)
static bool thresholdsRead = false;
if (!thresholdsRead) {
if (Firebase.getInt(fbdo, basePath + "threshold/min")) {
minThreshold = fbdo.intData();
}
if (Firebase.getInt(fbdo, basePath + "threshold/max")) {
maxThreshold = fbdo.intData();
}
thresholdsRead = true;
}
}
void updateMotorStatus() {
String path = "/devices/" + String(DEVICE_ID) + "/motor/status";
if (Firebase.setString(fbdo, path, motorStatus)) {
Serial.println("Motor status updated");
} else {
Serial.println("Failed to update motor status: " + fbdo.errorReason());
}
}
String getTimestamp() {
// Simulated timestamp for Wokwi
unsigned long seconds = millis() / 1000;
unsigned long minutes = seconds / 60;
unsigned long hours = minutes / 60;
return String(hours%24) + "-" + String(minutes%60) + "-" + String(seconds%60);
}