Thanks for pointing that out. I've modified the code to address the potential issues caused by dropped UDP packets, and to include request retransmission, periodic status updates, and timeout mechanisms. Here's the updated code . Let me know what you think:
// Sensor Node or Pump Controller Code
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
// Wi-Fi credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// Pump controller IP address and port
IPAddress pumpControllerIP(192, 168, 1, 100);
unsigned int pumpControllerPort = 3333;
// Sensor pin and relay pin (for sensor nodes)
const int sensorPin = A0;
const int relayPin = D1; // Pin connected to the relay for the sprinkler valve
// Sensor ID (0, 1, or 2 for sensor nodes, -1 for pump controller)
const int sensorId = -1;
// Pump relay pin (for pump controller)
const int pumpRelayPin = D1;
// Request retransmission parameters
const int MAX_RETRIES = 3;
const unsigned long RETRY_DELAY = 5000; // 5 seconds
// Periodic status update interval (in milliseconds)
const unsigned long STATUS_UPDATE_INTERVAL = 60000; // 1 minute
// Timeout parameters (in milliseconds)
const unsigned long SENSOR_TIMEOUT = 120000; // 2 minutes
const unsigned long PUMP_TIMEOUT = 180000; // 3 minutes
WiFiUDP udp;
// Keep track of active requests (for pump controller)
bool sensorRequests[3] = {false, false, false};
unsigned long lastStatusUpdate[3] = {0, 0, 0};
unsigned long lastPumpUpdate = 0;
bool pumpStatus = false;
void setup() {
Serial.begin(115200);
connectToWiFi();
if (sensorId == -1) {
// Pump controller setup
Serial.println("Setting up pump controller...");
udp.begin(pumpControllerPort);
pinMode(pumpRelayPin, OUTPUT);
digitalWrite(pumpRelayPin, LOW); // Initially turn off pump
Serial.println("Pump controller setup complete!");
} else {
// Sensor node setup
Serial.print("Setting up sensor node ");
Serial.print(sensorId);
Serial.println("...");
udp.begin(WiFi.localIP(), pumpControllerPort);
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW); // Initially turn off the sprinkler valve
Serial.print("Sensor node ");
Serial.print(sensorId);
Serial.println(" setup complete!");
}
}
void loop() {
if (sensorId == -1) {
// Pump controller loop
int packetSize = udp.parsePacket();
if (packetSize) {
Serial.println("Received packet from sensor node...");
byte packet[3];
udp.read(packet, 3);
int sensorId = packet[0];
bool requestStatus = packet[1] == 1;
bool statusUpdate = packet[2] == 2;
if (requestStatus) {
Serial.print("Handling request from sensor node ");
Serial.println(sensorId);
handleRequest(sensorId);
} else if (statusUpdate) {
Serial.print("Handling status update from sensor node ");
Serial.println(sensorId);
handleStatusUpdate(sensorId, requestStatus);
} else {
Serial.print("Handling request removal from sensor node ");
Serial.println(sensorId);
handleRequestRemoval(sensorId);
}
}
// Check for pump timeout
if (millis() - lastPumpUpdate > PUMP_TIMEOUT) {
Serial.println("Pump timeout, turning off pump");
pumpStatus = false;
digitalWrite(pumpRelayPin, LOW);
}
} else {
// Sensor node loop
int moisture = analogRead(sensorPin);
bool soilIsDry = moisture < 300; // Adjust threshold as needed
if (soilIsDry) {
Serial.print("Sensor node ");
Serial.print(sensorId);
Serial.println(" needs water, sending request...");
sendRequest(true);
Serial.print("Turning on sprinkler valve for sensor node ");
Serial.println(sensorId);
digitalWrite(relayPin, HIGH); // Turn on the sprinkler valve
} else {
Serial.print("Sensor node ");
Serial.print(sensorId);
Serial.println(" has enough water, sending removal request...");
sendRequest(false);
Serial.print("Turning off sprinkler valve for sensor node ");
Serial.println(sensorId);
digitalWrite(relayPin, LOW); // Turn off the sprinkler valve
}
// Send periodic status update
if (millis() - lastStatusUpdate[sensorId] > STATUS_UPDATE_INTERVAL) {
sendStatusUpdate(soilIsDry);
lastStatusUpdate[sensorId] = millis();
}
}
}
// Sensor node functions
void sendRequest(bool needsWater) {
byte message[3] = {sensorId, needsWater ? 1 : 0, 0};
int retries = 0;
bool ackReceived = false;
while (retries < MAX_RETRIES && !ackReceived) {
udp.beginPacket(pumpControllerIP, pumpControllerPort);
udp.write(message, 3);
udp.endPacket();
unsigned long startTime = millis();
while (millis() - startTime < RETRY_DELAY) {
int packetSize = udp.parsePacket();
if (packetSize) {
byte ack[1];
udp.read(ack, 1);
if (ack[0] == sensorId) {
ackReceived = true;
break;
}
}
}
retries++;
}
}
void sendStatusUpdate(bool needsWater) {
byte message[3] = {sensorId, needsWater ? 1 : 0, 2};
udp.beginPacket(pumpControllerIP, pumpControllerPort);
udp.write(message, 3);
udp.endPacket();
}
// Pump controller functions
void handleRequest(int sensorId) {
sensorRequests[sensorId] = true;
pumpStatus = needsWater();
Serial.print("Sensor node ");
Serial.print(sensorId);
Serial.print(" needs water. Pump status: ");
Serial.println(pumpStatus ? "ON" : "OFF");
digitalWrite(pumpRelayPin, pumpStatus);
lastPumpUpdate = millis();
sendAck(sensorId);
}
void handleRequestRemoval(int sensorId) {
sensorRequests[sensorId] = false;
pumpStatus = needsWater();
Serial.print("Sensor node ");
Serial.print(sensorId);
Serial.print(" has enough water. Pump status: ");
Serial.println(pumpStatus ? "ON" : "OFF");
digitalWrite(pumpRelayPin, pumpStatus);
lastPumpUpdate = millis();
sendAck(sensorId);
}
void handleStatusUpdate(int sensorId, bool needsWater) {
sensorRequests[sensorId] = needsWater;
pumpStatus = needsWater();
Serial.print("Sensor node ");
Serial.print(sensorId);
Serial.print(" status update: ");
Serial.println(needsWater ? "Needs water" : "Has enough water");
Serial.print("Pump status: ");
Serial.println(pumpStatus ? "ON" : "OFF");
digitalWrite(pumpRelayPin, pumpStatus);
lastPumpUpdate = millis();
sendAck(sensorId);
}
bool needsWater() {
return sensorRequests[0] || sensorRequests[1] || sensorRequests[2];
}
void sendAck(int sensorId) {
byte ack[1] = {sensorId};
udp.beginPacket(udp.remoteIP(), udp.remotePort());
udp.write(ack, 1);
udp.endPacket();
}
// Common function
void connectToWiFi() {
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("\nConnected to WiFi");
}