amc:ss2025:group-f:start
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| amc:ss2025:group-f:start [2025/07/28 20:29] – [5. Discussion and Conclusion] 33784_students.hsrw | amc:ss2025:group-f:start [2025/10/17 09:58] (current) – elham.mohammadi | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== | ====== | ||
| + | **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: | + | {{ : |
| **Figure 1.** Automated Plant Watering System Prototype | **Figure 1.** Automated Plant Watering System Prototype | ||
| Line 123: | Line 126: | ||
| 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: | + | {{ :amc: |
| **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: | + | {{ :amc: |
| **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 141: | ||
| | | ||
| + | |||
| <code cpp> | <code cpp> | ||
| #include < | #include < | ||
| Line 151: | Line 155: | ||
| // 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[] = " | + | const char GOOGLE_SHEET_URL[] = " |
| // MQTT Topics | // MQTT Topics | ||
| Line 185: | Line 189: | ||
| // Format data as JSON payload | // Format data as JSON payload | ||
| - | String | + | String |
| + | if (status == "Dry" | ||
| + | action = "Pump is ON 💧"; | ||
| + | } else if (status == "Moist") { | ||
| + | action = "OK 👍"; | ||
| + | } else { | ||
| + | action = "Alert ⚠️ Maintenance Needed"; | ||
| + | } | ||
| + | |||
| + | String jsonPayload = "{\" | ||
| + | " | ||
| + | " | ||
| Serial.println(" | Serial.println(" | ||
| Line 213: | Line 229: | ||
| if (millis() - lastRead > readInterval) { | if (millis() - lastRead > readInterval) { | ||
| int value = analogRead(sensorPin); | int value = analogRead(sensorPin); | ||
| - | String status = value > threshold ? " | + | String status = value > threshold ? " |
| // Publish raw value and status to MQTT topics | // Publish raw value and status to MQTT topics | ||
| Line 229: | Line 245: | ||
| // If soil is dry, send water command | // If soil is dry, send water command | ||
| - | if (status | + | if (status.startsWith(" |
| mqtt.publish(COMMAND_TOPIC, | mqtt.publish(COMMAND_TOPIC, | ||
| } | } | ||
| Line 246: | Line 262: | ||
| #include < | #include < | ||
| #include < | #include < | ||
| - | #include < | + | #include < |
| + | #include < | ||
| - | // 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 | + | // MQTT broker |
| const char* mqtt_server = " | const char* mqtt_server = " | ||
| + | const char* control_topic = " | ||
| - | WiFiClient espClient; | + | // Google Apps Script Web App URL |
| - | PubSubClient client(espClient); | + | const char* google_script_url = " |
| - | Servo pumpServo; | + | 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(" | ||
| WiFi.begin(ssid, | WiFi.begin(ssid, | ||
| while (WiFi.status() != WL_CONNECTED) { | while (WiFi.status() != WL_CONNECTED) { | ||
| Line 271: | Line 292: | ||
| } | } | ||
| - | // 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(" | ||
| + | |||
| + | | ||
| + | String payload = " | ||
| + | |||
| + | int httpResponseCode = http.POST(payload); | ||
| + | Serial.print(" | ||
| + | Serial.println(httpResponseCode); | ||
| + | http.end(); | ||
| + | } else { | ||
| + | Serial.println(" | ||
| + | } | ||
| + | } | ||
| void callback(char* topic, byte* payload, unsigned int length) { | void callback(char* topic, byte* payload, unsigned int length) { | ||
| - | String msg = ""; | + | String msg = ""; |
| - | for (int i = 0; i < length; i++) msg += (char)payload[i]; | + | for (unsigned |
| - | msg.trim(); | + | |
| + | } | ||
| + | msg.trim(); | ||
| - | Serial.print(" | + | Serial.print(" |
| Serial.print(topic); | Serial.print(topic); | ||
| - | Serial.print(": | + | Serial.print(" |
| Serial.println(msg); | Serial.println(msg); | ||
| - | | + | if (String(topic) == control_topic) { |
| - | | + | if (msg == " |
| - | if (msg == " | + | pumpServo.write(180); |
| - | pumpServo.write(180); | + | Serial.println(" |
| + | postToGoogleSheet(" | ||
| } else if (msg == " | } else if (msg == " | ||
| - | pumpServo.write(90); | + | pumpServo.write(90); |
| + | Serial.println(" | ||
| + | postToGoogleSheet(" | ||
| } | } | ||
| } | } | ||
| } | } | ||
| - | // Function to (re)connect to MQTT and subscribe to topic | ||
| void reconnect() { | void reconnect() { | ||
| while (!client.connected()) { | while (!client.connected()) { | ||
| - | Serial.print(" | + | Serial.print(" |
| - | if (client.connect(" | + | if (client.connect(" |
| Serial.println(" | Serial.println(" | ||
| - | client.subscribe(" | + | client.subscribe(control_topic); |
| } else { | } else { | ||
| Serial.print(" | Serial.print(" | ||
| - | Serial.println(client.state()); | + | Serial.print(client.state()); |
| - | delay(2000); | + | delay(2000); |
| } | } | ||
| } | } | ||
| Line 308: | Line 350: | ||
| void setup() { | void setup() { | ||
| - | Serial.begin(115200); | + | Serial.begin(115200); |
| - | setup_wifi(); | + | setup_wifi(); |
| - | pumpServo.attach(servoPin); | + | pumpServo.attach(servoPin); |
| - | pumpServo.write(90); | + | pumpServo.write(90); |
| - | + | client.setServer(mqtt_server, | |
| - | client.setServer(mqtt_server, | + | client.setCallback(callback); |
| - | client.setCallback(callback); | + | |
| } | } | ||
| void loop() { | void loop() { | ||
| - | if (!client.connected()) reconnect(); | + | if (!client.connected()) |
| - | client.loop(); | + | |
| + | } | ||
| + | client.loop(); | ||
| } | } | ||
| </ | </ | ||
| Line 456: | Line 499: | ||
| **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` |
| '' | '' | ||
| Line 464: | Line 507: | ||
| '' | '' | ||
| - | |||
| - | // | ||
| - | |||
| Line 472: | Line 512: | ||
| **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 535: | ||
| **Google Apps Script Codes:** | **Google Apps Script Codes:** | ||
| + | <code cpp> | ||
| + | function doPost(e) { | ||
| try { | try { | ||
| const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(" | const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(" | ||
| 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(); | ||
| - | | + | |
| + | | ||
| sheet.insertRows(2, | sheet.insertRows(2, | ||
| - | sheet.getRange(2, | + | sheet.getRange(2, |
| - | sheet.getRange(2, | + | sheet.getRange(2, |
| - | sheet.getRange(2, | + | sheet.getRange(2, |
| - | sheet.getRange(2, | + | sheet.getRange(2, |
| - | // Optional: | + | |
| + | // Send emails if there is an alert | ||
| if (action.toLowerCase().includes(" | if (action.toLowerCase().includes(" | ||
| - | | + | |
| - | const subject = " | + | `Soil Alert!\nStatus: ${status}\nMoisture: |
| - | const message = `An alert has been logged in your system:\n\n` + | + | |
| - | `Status: ${status}\nMoisture: | + | |
| - | MailApp.sendEmail(emailAddress, | + | |
| } | } | ||
| + | |||
| return ContentService.createTextOutput(" | return ContentService.createTextOutput(" | ||
| - | } catch (error) { | + | } catch (err) { |
| - | Logger.log(" | + | return ContentService.createTextOutput(" |
| - | return ContentService.createTextOutput(" | + | |
| | | ||
| } | } | ||
| + | } | ||
| + | |||
| + | </ | ||
| ====== | ====== | ||
| Line 533: | Line 577: | ||
| 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:// | + | {{ : |
| **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 625: | ||
| - | {{youtube> | + | {{youtube> |
| - | + | ||
| - | + | ||
| + | {{youtube> | ||
| + | {{youtube> | ||
amc/ss2025/group-f/start.1753727384.txt.gz · Last modified: 2025/07/28 20:29 by 33784_students.hsrw