#include #include #include // For making HTTP POST requests #include // Required for HTTPClient on ESP32 #include #define MOIST_PIN_1 A1 #define MOIST_PIN_2 A2 #define MOIST_PIN_3 A0 const char SENSOR_ID_1[] = "1"; const char SENSOR_ID_2[] = "2"; const char SENSOR_ID_3[] = "3"; // Define the pin connected to the servo's signal wire #define SERVO_PIN D6 // You can choose any suitable digital pin Servo waterValveServo; // Create a Servo object // Define servo control parameters int valveClosedAngle = 30; // Angle to close the valve (adjustable via serial) int valveOpenAngle = 120; // Angle to open the valve (adjustable via serial) // WiFi network credentials const char* ssid = "MIT"; const char* password = "FsPju]6HbE"; // --- FastAPI Server Details (via SSH Tunnel) --- const char* serverIp = "efpi-10.mit.edu"; // Public server address hosting the tunnel entry const uint16_t serverPort = 80; // Port specified in your SSH -R command (remote port) const char* serverPath = "/tunnel_durra/moisture_data"; // Path: FastAPI root_path + specific endpoint unsigned long previousMillis = 0; // Variable to store the last time the sensor was read const long interval = 15000; // Interval to read the sensor (15 seconds = 150000 milliseconds) // Sensor 1 Calibration const int SENSOR_1_AIR_VALUE = 3200; // Example: Dry reading for sensor 1 const int SENSOR_1_WATER_VALUE = 1200; // Example: Wet reading for sensor 1 // Sensor 2 Calibration const int SENSOR_2_AIR_VALUE = 3200; // Example: Dry reading for sensor 2 const int SENSOR_2_WATER_VALUE = 1200; // Example: Wet reading for sensor 2 // Sensor 3 Calibration const int SENSOR_3_AIR_VALUE = 3200; // Example: Dry reading for sensor 3 const int SENSOR_3_WATER_VALUE = 1200; // Example: Wet reading for sensor 3 // Function to read and smooth the analog value from a specified pin int readAnalogSmooth(u_int8_t pin, int samples = 15); int calculateMoisturePercent(int rawValue, int dryValue, int wetValue); void sendMoistureData(const char sensorId[], int moistureRaw, int moisturePercent); void controlWaterValve(int angle); // Function to control the water valve by angle void processSerialCommand(String command); void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.println("\n--- Water Valve Control and Calibration ---"); Serial.println("Type commands followed by Enter:"); Serial.println(" 'o' or 'open' to set open angle."); Serial.println(" 'c' or 'close' to set close angle."); Serial.println(" 'w ' to write a specific angle to the valve (0-180)."); Serial.println("Example: w 45"); Serial.println("-------------------------------------------"); Serial.println("esp32 starting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.print("Connected! IP address: "); Serial.println(WiFi.localIP()); pinMode(MOIST_PIN_1, INPUT); // Set sensor pin as input pinMode(MOIST_PIN_2, INPUT); // Set sensor pin as input pinMode(MOIST_PIN_3, INPUT); // Set sensor pin as input waterValveServo.attach(SERVO_PIN); // Attaches the servo on the defined pin controlWaterValve(valveClosedAngle); // Initialize the valve to the closed position Serial.print("Valve initialized to closed angle: "); Serial.println(valveClosedAngle); delay(1000); // Give the servo time to reach the initial position } void loop() { // Check for serial input for calibration if (Serial.available() > 0) { String command = Serial.readStringUntil('\n'); command.trim(); processSerialCommand(command); } unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; // Read the moisture sensor value int moistureRaw1 = readAnalogSmooth(MOIST_PIN_1, 15); // Read and smooth the sensor value int moistPercent1 = calculateMoisturePercent(moistureRaw1, SENSOR_1_AIR_VALUE, SENSOR_1_WATER_VALUE); Serial.println("Sensor 1 raw: "); Serial.print(moistureRaw1); Serial.print(", Percent: "); Serial.print(moistPercent1); Serial.print("%\n"); sendMoistureData(SENSOR_ID_1, moistureRaw1, moistPercent1); // Send the data to the server int moistureRaw2 = readAnalogSmooth(MOIST_PIN_2, 15); // Read and smooth the sensor value int moistPercent2 = calculateMoisturePercent(moistureRaw2, SENSOR_2_AIR_VALUE, SENSOR_2_WATER_VALUE); Serial.println("Sensor 2 raw: "); Serial.print(moistureRaw2); Serial.print(", Percent: "); Serial.print(moistPercent2); sendMoistureData(SENSOR_ID_2, moistureRaw2, moistPercent2); // Send the data to the server Serial.println("%\n"); int moistureRaw3 = readAnalogSmooth(MOIST_PIN_3, 15); // Read and smooth the sensor value int moistPercent3 = calculateMoisturePercent(moistureRaw3, SENSOR_3_AIR_VALUE, SENSOR_3_WATER_VALUE); Serial.println("Sensor 3 raw: "); Serial.print(moistureRaw3); Serial.print(", Percent: "); Serial.print(moistPercent3); sendMoistureData(SENSOR_ID_3, moistureRaw3, moistPercent3); // Send the data to the server Serial.println("%\n"); Serial.println("Data sent to server"); Serial.println("===================================="); // Basic control logic based on moisture of the first sensor if (moistPercent1 < 30) { // Example: If moisture is below 30%, open the valve Serial.println("Moisture low, opening valve."); controlWaterValve(valveOpenAngle); delay(5000); // Keep the valve open for 5 seconds (adjust as needed) Serial.println("Closing valve."); controlWaterValve(valveClosedAngle); delay(1000); } else { Serial.println("Moisture level sufficient, valve remains closed."); } } } void processSerialCommand(String command) { if (command.startsWith("o") || command.startsWith("open")) { Serial.print("Enter the open angle (0-180): "); while (Serial.available() == 0) { delay(10); } String angleStr = Serial.readStringUntil('\n'); angleStr.trim(); int newAngle = angleStr.toInt(); if (newAngle >= 0 && newAngle <= 180) { valveOpenAngle = newAngle; Serial.print("Open angle set to: "); Serial.println(valveOpenAngle); } else { Serial.println("Invalid angle. Please enter a value between 0 and 180."); } } else if (command.startsWith("c") || command.startsWith("close")) { Serial.print("Enter the closed angle (0-180): "); while (Serial.available() == 0) { delay(10); } String angleStr = Serial.readStringUntil('\n'); angleStr.trim(); int newAngle = angleStr.toInt(); if (newAngle >= 0 && newAngle <= 180) { valveClosedAngle = newAngle; Serial.print("Closed angle set to: "); Serial.println(valveClosedAngle); } else { Serial.println("Invalid angle. Please enter a value between 0 and 180."); } } else if (command.startsWith("w ")) { String angleStr = command.substring(2); angleStr.trim(); int newAngle = angleStr.toInt(); if (newAngle >= 0 && newAngle <= 180) { controlWaterValve(newAngle); Serial.print("Valve moved to angle: "); Serial.println(newAngle); } else { Serial.println("Invalid angle. Please enter a value between 0 and 180."); } } else { Serial.println("Unknown command."); } } int readAnalogSmooth(uint8_t pin, int samples) { long sum = 0; for (int i = 0; i < samples; i++) { sum += analogRead(pin); delay(10); // Small delay to allow for sensor stabilization } return sum / samples; // Return the average value } int calculateMoisturePercent(int rawValue, int dryValue, int wetValue) { int moisturePercent = map(rawValue, dryValue, wetValue, 0, 100); // Map the raw value to a percentage moisturePercent = constrain(moisturePercent, 0, 100); // Ensure the value is within 0-100% return moisturePercent; // Return the calculated percentage } void sendMoistureData(const char sensorId[], int moistureRaw, int moisturePercent) { if (WiFi.status() == WL_CONNECTED) { WiFiClient client; HTTPClient http; // Construct the full URL String fullServerURL = "http://" + String(serverIp) + ":" + String(serverPort) + String(serverPath); Serial.print("[HTTP] Attempting to POST to: "); Serial.println(fullServerURL); http.begin(client, fullServerURL); // Specify URL http.addHeader("Content-Type", "application/json"); // Set content type // Create JSON payload String jsonPayload = "{"; jsonPayload += "\"sensor_id\":\"" + String(sensorId) + "\","; jsonPayload += "\"raw_moisture_value\":" + String(moistureRaw) + ","; jsonPayload += "\"moisture_percent\":" + String(moisturePercent); jsonPayload += "}"; Serial.print("JSON Payload for Sensor " + String(sensorId) + ": "); Serial.println(jsonPayload); // Send the request int httpResponseCode = http.POST(jsonPayload); Serial.print("[HTTP] Response code for Sensor " + String(sensorId) + ": "); Serial.println(httpResponseCode); // Check for successful response if (httpResponseCode > 0) { String response = http.getString(); // Get the response payload Serial.print("[HTTP] Response: "); Serial.println(response); } else { Serial.print("[HTTP] Error on sending POST for Sensor " + String(sensorId) + ": "); Serial.println(http.errorToString(httpResponseCode).c_str()); // More descriptive error } // Close connection http.end(); // Free resources } } // Modified to take an angle directly void controlWaterValve(int angle) { waterValveServo.write(angle); // Move the servo to the specified angle Serial.print("Water valve moved to "); Serial.print(angle); Serial.println(" degrees."); delay(15); // Allow the servo to reach the position }