User Tools

Site Tools


amc:ss2025:group-f:start

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
amc:ss2025:group-f:start [2025/07/28 20:29] – [5. Discussion and Conclusion] 33784_students.hsrwamc:ss2025:group-f:start [2025/07/29 22:36] (current) paul-christian.thoma
Line 1: Line 1:
 ======  Smart Plant Watering with ESP32 and MQTT====== ======  Smart Plant Watering with ESP32 and MQTT======
 +**Applied Measurement and Control 2025**
 +
 Paul-Christian Thoma(32436)-Elham Mohammadi(32475)-Deniz-Zeynep Adem(33784) Paul-Christian Thoma(32436)-Elham Mohammadi(32475)-Deniz-Zeynep Adem(33784)
  
Line 16: Line 18:
 By combining local sensing, cloud-based logic, and remote monitoring tools, this system provides a scalable, modular approach to smart irrigation in home or laboratory environments. By combining local sensing, cloud-based logic, and remote monitoring tools, this system provides a scalable, modular approach to smart irrigation in home or laboratory environments.
  
-{{ amc:ss2025:group-f:prototype2.jpeg |}}+{{ :amc:ss2025:group-f:prototype2.jpeg?direct&600 |{{ amc:ss2025:group-f:prototype2.jpeg |}}}}
 **Figure 1.** Automated Plant Watering System Prototype **Figure 1.** Automated Plant Watering System Prototype
  
Line 123: Line 125:
 The following diagrams, created using Tinkercad, illustrate the complete hardware connections for both the Sensor and Pump nodes in the system.  The following diagrams, created using Tinkercad, illustrate the complete hardware connections for both the Sensor and Pump nodes in the system. 
  
-{{ amc:ss2025:group-f:moisture_sensor_circuit.png |}}+{{ :amc:ss2025:group-f:moisture_sensor_circuit.png?direct&600 |}}
 **Figure 2.** Schematic Diagram of Sensor Setup (designed by Deniz-Zeynep Adem) **Figure 2.** Schematic Diagram of Sensor Setup (designed by Deniz-Zeynep Adem)
                                      
  
-{{ amc:ss2025:group-f:pump_wiring_with_adaptor.png |}}+{{ :amc:ss2025:group-f:pump_wiring_with_adaptor.png?direct&600 |}}
 **Figure 3.** Schematic Diagram of Pump Setup (designed by Deniz-Zeynep Adem) **Figure 3.** Schematic Diagram of Pump Setup (designed by Deniz-Zeynep Adem)
  
Line 138: Line 140:
  
  **Sensor Node Code:**  **Sensor Node Code:**
 +
 <code cpp> <code cpp>
 #include <WiFi.h>              // Library for WiFi connection #include <WiFi.h>              // Library for WiFi connection
Line 151: Line 154:
  
 // Google Apps Script webhook URL for sending data to Google Sheets // Google Apps Script webhook URL for sending data to Google Sheets
-const char GOOGLE_SHEET_URL[] = "https://script.google.com/macros/s/XYZ/exec"; // Replace XYZ with your actual script ID+const char GOOGLE_SHEET_URL[] = "https://script.google.com/macros/s/AKfycbwWx8W6ov2rufz6ODUtUngPOhJMdYazwkHozmzk8-3n6gyL-qNCGgX9YxKtBTL7Qm5Vfg/exec";
  
 // MQTT Topics // MQTT Topics
Line 185: Line 188:
  
   // Format data as JSON payload   // Format data as JSON payload
-  String jsonPayload = "{\"device\":\"ESP32_Sensor_001\",\"event\":\"read\",\"moisture\":\"" + String(moisture) + "\",\"status\":\"" + status + "\"}";+  String action; 
 +  if (status == "Dry"{ 
 +    action = "Pump is ON 💧"
 +  } else if (status == "Moist") { 
 +    action = "OK 👍"
 +  } else { 
 +    action = "Alert ⚠️ Maintenance Needed"
 +  } 
 + 
 +  String jsonPayload = "{\"moisture\":\"" + String(moisture) + 
 +                       "\",\"status\":\"" + status 
 +                       "\",\"action\":\"" + action + "\"}"; 
   Serial.println("POSTing: " + jsonPayload);   Serial.println("POSTing: " + jsonPayload);
  
Line 213: Line 228:
   if (millis() - lastRead > readInterval) {   if (millis() - lastRead > readInterval) {
     int value = analogRead(sensorPin);               // Read analog moisture value     int value = analogRead(sensorPin);               // Read analog moisture value
-    String status = value > threshold ? "Dry" : "Moist"; // Determine status+    String status = value > threshold ? "Dry ☹️" : "Moist 😊"; // Determine status
  
     // Publish raw value and status to MQTT topics     // Publish raw value and status to MQTT topics
Line 229: Line 244:
  
     // If soil is dry, send water command     // If soil is dry, send water command
-    if (status == "Dry") {+    if (status.startsWith("Dry")) {
       mqtt.publish(COMMAND_TOPIC, "WATER"); // Triggers pump       mqtt.publish(COMMAND_TOPIC, "WATER"); // Triggers pump
     }     }
Line 246: Line 261:
 #include <WiFi.h>              // WiFi library for ESP32 #include <WiFi.h>              // WiFi library for ESP32
 #include <PubSubClient.h>      // MQTT library #include <PubSubClient.h>      // MQTT library
-#include <Servo.h>             // Library for controlling servo motor+#include <Servo.h>             // For controlling the servo pump 
 +#include <HTTPClient.h>        // For HTTP POST to Google Sheets
  
-// WiFi credentials +// Wi-Fi credentials 
-const char* ssid = "YOUR_WIFI_SSID"; +const char* ssid = "iotlab"; 
-const char* password = "YOUR_WIFI_PASSWORD";+const char* password = "iotlab18";
  
-// MQTT broker address+// MQTT broker
 const char* mqtt_server = "broker.hivemq.com"; const char* mqtt_server = "broker.hivemq.com";
 +const char* control_topic = "plant/pump/control";
  
-WiFiClient espClient;          // WiFi client +// Google Apps Script Web App URL 
-PubSubClient client(espClient); // MQTT client+const char* google_script_url = "https://script.google.com/macros/s/AKfycbwWx8W6ov2rufz6ODUtUngPOhJMdYazwkHozmzk8-3n6gyL-qNCGgX9YxKtBTL7Qm5Vfg/exec";
  
-Servo pumpServo;               // Servo object to control the pump +WiFiClient espClient; 
-const int servoPin = 5;        // Pin connected to the servo+PubSubClient client(espClient); 
 + 
 +Servo pumpServo; 
 +const int servoPin = 5;
  
-// Function to connect to WiFi 
 void setup_wifi() { void setup_wifi() {
 +  Serial.print("Connecting to WiFi");
   WiFi.begin(ssid, password);   WiFi.begin(ssid, password);
   while (WiFi.status() != WL_CONNECTED) {   while (WiFi.status() != WL_CONNECTED) {
Line 271: Line 291:
 } }
  
-// Callback function that handles incoming MQTT messages+void postToGoogleSheet(const String& status, const String& action) { 
 +  if (WiFi.status() == WL_CONNECTED) { 
 +    HTTPClient http; 
 +    http.begin(google_script_url); 
 +    http.addHeader("Content-Type", "application/json"); 
 + 
 +    // Build JSON payload 
 +    String payload = "{\"status\":\"" + status + "\",\"moisture\":\"-\",\"action\":\"" + action + "\"}"; 
 + 
 +    int httpResponseCode = http.POST(payload); 
 +    Serial.print("Google Sheet POST response: "); 
 +    Serial.println(httpResponseCode); 
 +    http.end(); 
 +  } else { 
 +    Serial.println("WiFi not connected. Could not send to Google Sheets."); 
 +  } 
 +
 void callback(char* topic, byte* payload, unsigned int length) { void callback(char* topic, byte* payload, unsigned int length) {
-  String msg = "";  // String to hold message +  String msg = ""; 
-  for (int i = 0; i < length; i++) msg += (char)payload[i]; +  for (unsigned int i = 0; i < length; i++) 
-  msg.trim(); // Remove any trailing whitespace or newline+    msg += (char)payload[i]; 
 +  } 
 +  msg.trim();
  
-  Serial.print("Received on ");+  Serial.print("Message received [");
   Serial.print(topic);   Serial.print(topic);
-  Serial.print(": ");+  Serial.print("]: ");
   Serial.println(msg);   Serial.println(msg);
  
-  // Check if the topic is the one for pump control +  if (String(topic) == control_topic) { 
-  if (String(topic) == "pump/control") { +    if (msg == "WATER" || msg == "ON") { 
-    if (msg == "ON") { +      pumpServo.write(180); 
-      pumpServo.write(180); // Move servo to ON position+      Serial.println("Pump is ON 💧"); 
 +      postToGoogleSheet("Dry ☹️", "Pump is ON");
     } else if (msg == "OFF") {     } else if (msg == "OFF") {
-      pumpServo.write(90);  // Move servo to OFF position+      pumpServo.write(90); 
 +      Serial.println("Pump is OFF ⛔"); 
 +      postToGoogleSheet("Moist 🙂", "Pump is OFF");
     }     }
   }   }
 } }
  
-// Function to (re)connect to MQTT and subscribe to topic 
 void reconnect() { void reconnect() {
   while (!client.connected()) {   while (!client.connected()) {
-    Serial.print("Connecting to MQTT..."); +    Serial.print("Attempting MQTT connection..."); 
-    if (client.connect("ESP32Pump")) {+    if (client.connect("ESP32_Pump_Node")) {
       Serial.println("connected");       Serial.println("connected");
-      client.subscribe("pump/control"); // Subscribe to control topic+      client.subscribe(control_topic);
     } else {     } else {
       Serial.print("failed, rc=");       Serial.print("failed, rc=");
-      Serial.println(client.state()); +      Serial.print(client.state()); 
-      delay(2000); // Retry every 2 seconds+      delay(2000);
     }     }
   }   }
Line 308: Line 349:
  
 void setup() { void setup() {
-  Serial.begin(115200);       // Start serial monitor +  Serial.begin(115200); 
-  setup_wifi();               // Connect to WiFi +  setup_wifi(); 
-  pumpServo.attach(servoPin); // Attach servo to the pin +  pumpServo.attach(servoPin); 
-  pumpServo.write(90);        // Set initial servo position (OFF) +  pumpServo.write(90); // Default OFF position 
- +  client.setServer(mqtt_server, 1883); 
-  client.setServer(mqtt_server, 1883);   // Set MQTT broker +  client.setCallback(callback);
-  client.setCallback(callback);         // Set message handler+
 } }
  
 void loop() { void loop() {
-  if (!client.connected()) reconnect(); // Reconnect if disconnected +  if (!client.connected()) 
-  client.loop();                        // Process incoming MQTT messages+    reconnect(); 
 +  } 
 +  client.loop();
 } }
 </code> </code>
Line 456: Line 498:
 **4. Integrate the Web App URL into Your ESP32 Code** **4. Integrate the Web App URL into Your ESP32 Code**
  
-In your ESP32 Arduino code, update the `GOOGLE_SHEET_URL`:+In your ESP32 Arduino code, update the `GOOGLE_SHEET_URL` with the copied URL from your own project:
  
 '' ''
Line 464: Line 506:
  
 '' ''
- 
- //Don't forget to replace `"your_script_id"` with the full Web App URL you copied!// 
- 
  
  
Line 472: Line 511:
 **5. Upload and Run the ESP32 Code** **5. Upload and Run the ESP32 Code**
  
-Upload your finalized ESP32 code via Arduino IDE or PlatformIO.+Upload your finalized ESP32 code via Arduino IDE.
  
   * **The ESP32 will:**   * **The ESP32 will:**
Line 495: Line 534:
 **Google Apps Script Codes:** **Google Apps Script Codes:**
  
 +<code cpp> 
 +function doPost(e) {
   try {   try {
     const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");     const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
     const data = JSON.parse(e.postData.contents);     const data = JSON.parse(e.postData.contents);
 +
     const status = data.status || "";     const status = data.status || "";
     const moisture = data.moisture || "";     const moisture = data.moisture || "";
     const action = data.action || "";     const action = data.action || "";
     const timestamp = new Date();     const timestamp = new Date();
-    // Insert new row at top (after header)+ 
 +    // Add new data to top (2nd row)
     sheet.insertRows(2, 1);     sheet.insertRows(2, 1);
-    sheet.getRange(2, 1).setValue(timestamp);   // Column A: Timestamp +    sheet.getRange(2, 1).setValue(timestamp); 
-    sheet.getRange(2, 2).setValue(action);      // Column B: Action (e.g., Pump is ON) +    sheet.getRange(2, 2).setValue(action); 
-    sheet.getRange(2, 3).setValue(moisture);    // Column C: Moisture value +    sheet.getRange(2, 3).setValue(moisture); 
-    sheet.getRange(2, 4).setValue(status);      // Column D: Status (e.g., Moist 😊) +    sheet.getRange(2, 4).setValue(status); 
-    // Optional: Send email alert when there's a maintenance alert+ 
 +    // Send emails if there is an alert
     if (action.toLowerCase().includes("alert")) {     if (action.toLowerCase().includes("alert")) {
-      const emailAddress = "youremail@example.com"; // Replace with your email +      MailApp.sendEmail("youremail@example.com""⚠️ Plant Alert" 
-      const subject = "⚠️ Plant System Alert"; +        `Soil Alert!\nStatus: ${status}\nMoisture: ${moisture}\nAction: ${action}`);
-      const message = `An alert has been logged in your system:\n\n` + +
-                      `Status: ${status}\nMoisture: ${moisture}\nAction: ${action}\nTime: ${timestamp}`+
-      MailApp.sendEmail(emailAddress, subject, message);+
     }     }
 +
     return ContentService.createTextOutput("Success").setMimeType(ContentService.MimeType.TEXT);     return ContentService.createTextOutput("Success").setMimeType(ContentService.MimeType.TEXT);
-  } catch (error) { +  } catch (err) { 
-    Logger.log("Error: " + error); +    return ContentService.createTextOutput("Error: " + err)
-    return ContentService.createTextOutput("Error: " + error)+
                          .setMimeType(ContentService.MimeType.TEXT);                          .setMimeType(ContentService.MimeType.TEXT);
   }   }
 +}
 +
 +</code>
 ======  4. Node-RED Overview====== ======  4. Node-RED Overview======
  
Line 533: Line 576:
 Below is a video showcasing the node-Red flow and showing the code and possible errors that came up and how they were fixed. Starting with the discussion part of this documentation.  Below is a video showcasing the node-Red flow and showing the code and possible errors that came up and how they were fixed. Starting with the discussion part of this documentation. 
  
-https://student-wiki.eolab.de/lib/exe/fetch.php?w=120&h=120&tok=b20d52&media=amc:ss2025:group-f:whatsapp_image_2025-07-28_at_12.23.27_am.jpeg +{{ :amc:ss2025:group-f:file_2025-07-28_14.25.34.png?direct&600 |}}
  
 **Figure 4.** Documentation of the data in note-red (designed by Paul-Christian Thoma) **Figure 4.** Documentation of the data in note-red (designed by Paul-Christian Thoma)
Line 582: Line 624:
  
  
-{{youtube>sK5l7mIVL0s?}} +{{youtube>sK5l7mIVL0s?}}                                         
- +
- +
  
 +{{youtube>vU9CFVkbPiY?}}
  
 +{{youtube>XZt8VXC4Ths?}}
  
  
amc/ss2025/group-f/start.1753727384.txt.gz · Last modified: 2025/07/28 20:29 by 33784_students.hsrw