#include #include #include "esp_camera.h" #include #include // Wi-Fi credentials const char* ssid = "Test123"; const char* password = "a?=31@#daE313-=;l."; // Supabase details const char* supabaseUrl = "https://nwlikynouhddjwyjrwnl.supabase.co"; const char* supabaseAnonKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im53bGlreW5vdWhkZGp3eWpyd25sIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDk3Mjg3NjYsImV4cCI6MjA2NTMwNDc2Nn0.s5skPnBRa1OepnvNCX1cl3dmzLb1gEs_HnOVdKMq_dU"; const char* bucketName = "photo"; // Firebase details #define API_KEY "AIzaSyBCe-30GPJRp0p7psDH4t2D01WHPcSNIqQ" #define DATABASE_URL "https://apkrafi-default-rtdb.firebaseio.com/" FirebaseData fbdo; FirebaseAuth auth; FirebaseConfig config; // ESP32-CAM pin config #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 #define LED_GPIO_NUM 4 // Flash LED // Relay pin #define RELAY_PIN 13 // Controls the lamp void startCamera() { camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; if (psramFound()) { config.frame_size = FRAMESIZE_VGA; config.jpeg_quality = 10; config.fb_count = 1; } else { config.frame_size = FRAMESIZE_QVGA; config.jpeg_quality = 12; config.fb_count = 1; } esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); } } void uploadImage() { digitalWrite(LED_GPIO_NUM, HIGH); delay(1500); // Let flash stabilize the exposure // Flush old frame camera_fb_t* fb = esp_camera_fb_get(); if (fb) { esp_camera_fb_return(fb); delay(100); } // Capture new frame fb = esp_camera_fb_get(); if (!fb) { Serial.println("Camera capture failed"); digitalWrite(LED_GPIO_NUM, LOW); return; } // Upload to Supabase String fileName = "latest.jpg"; String url = String(supabaseUrl) + "/storage/v1/object/" + bucketName + "/" + fileName; HTTPClient http; http.begin(url); http.addHeader("Authorization", "Bearer " + String(supabaseAnonKey)); http.addHeader("Content-Type", "image/jpeg"); int response = http.PUT(fb->buf, fb->len); Serial.printf("Upload response: %d\n", response); if (response > 0) { Serial.println(http.getString()); } http.end(); esp_camera_fb_return(fb); digitalWrite(LED_GPIO_NUM, LOW); } void setup() { Serial.begin(115200); pinMode(LED_GPIO_NUM, OUTPUT); digitalWrite(LED_GPIO_NUM, LOW); // Relay setup pinMode(RELAY_PIN, OUTPUT); digitalWrite(RELAY_PIN, LOW); // Relay OFF at start WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected to WiFi"); startCamera(); delay(1000); // Let the camera stabilize // Sync NTP Time (UTC) configTime(25200, 0, "time.google.com"); Serial.print("Waiting for time sync"); while (time(nullptr) < 100000) { delay(500); Serial.print("."); } Serial.println("\nTime synced"); // Firebase setup config.api_key = API_KEY; config.database_url = DATABASE_URL; Firebase.begin(&config, &auth); if (Firebase.signUp(&config, &auth, "", "")) { Serial.println("Firebase anonymous sign-up OK"); } else { Serial.printf("Sign-up error: %s\n", config.signer.signupError.message.c_str()); } Firebase.reconnectWiFi(true); } bool hasCaptured = false; // global flag outside loop() void loop() { if (!Firebase.ready()) { Serial.println("Firebase not ready"); delay(2000); return; } // Read scheduled time from Firebase (e.g., "16.31") if (Firebase.RTDB.getString(&fbdo, "/camera/schedule")) { String scheduledTime = fbdo.stringData(); Serial.printf("Scheduled capture time: %s\n", scheduledTime.c_str()); // Get current time time_t now = time(nullptr); struct tm* timeinfo = localtime(&now); char currentTime[6]; sprintf(currentTime, "%02d.%02d", timeinfo->tm_hour, timeinfo->tm_min); Serial.printf("Current time: %s\n", currentTime); // If time matches AND we haven't captured yet if (scheduledTime == String(currentTime) && !hasCaptured) { Serial.println("Time match! Capturing photo..."); uploadImage(); hasCaptured = true; // prevent re-capturing within same minute Serial.println("Capture complete. Waiting for next time."); } // Reset capture flag when the time has moved on if (scheduledTime != String(currentTime)) { hasCaptured = false; } } else { Serial.println("Failed to read schedule from Firebase"); } // Relay control variables bool relayShouldTurnOn = false; // Check temperature if (Firebase.RTDB.getFloat(&fbdo, "/sensors/temperature")) { float temperature = fbdo.floatData(); Serial.printf("Temperature: %.2f°C\n", temperature); if (temperature < 25) { relayShouldTurnOn = true; } } else { Serial.println("Failed to read temperature from Firebase"); } // Check soil moisture if (Firebase.RTDB.getFloat(&fbdo, "/sensors/soilMoisture")) { float soilMoisture = fbdo.floatData(); Serial.printf("Soil Moisture: %.2f%%\n", soilMoisture); if (soilMoisture > 75) { relayShouldTurnOn = true; } } else { Serial.println("Failed to read soil moisture from Firebase"); } // Control relay if (relayShouldTurnOn) { digitalWrite(RELAY_PIN, HIGH); // Relay ON Serial.println("Relay ON (condition met)"); } else { digitalWrite(RELAY_PIN, LOW); // Relay OFF Serial.println("Relay OFF (no condition met)"); } delay(10000); // Check every 10 seconds }