thanks all for your comments and suggestions. My son was up at the cottage this weekend and has reported that the internet is even less robust than last year. Hopefully it will get better with a new provider. So with that in mind, I'm putting aside the approach above that leans heavily on the Internet to work and moving to a non-internet based solution using NRF24L01 and nanos in place of the ESP8266 in the previous approach.
Again I've tried to work out that sensor nodes don't interfere with each other with conflicting shutoff commands. Also I've tried to implement Paul's concern about the garden being flooded by placing a command that stops the pump after 30 minutes regardless of other commands. I'd be interested in suggestion or concerns on the sketch.
Here is the sensor node sketch:
#include <RF24.h>
#include <RF24Network.h>
#include <RF24Mesh.h>
// Soil Sensor and Relay Pins
#define SOIL_SENSOR_PIN A0
#define SPRINKLER_RELAY_PIN 3
// RF24 Setup
RF24 radio(7, 8); // CE, CSN
RF24Network network(radio);
RF24Mesh mesh(radio, network);
// Node Address
uint16_t nodeId = 0; // Set unique node ID for each sensor node
// Thresholds for soil moisture (adjust as needed)
const int DRY_THRESHOLD = 300; // Value to be provided by you
const int WET_THRESHOLD = 600; // Value to be provided by you
// Sensor value range
const int SENSOR_MIN_VALUE = 0;
const int SENSOR_MAX_VALUE = 1023;
// Data Structure
struct PayloadData {
uint16_t nodeId;
int soilMoisture;
};
bool sprinklerActive = false;
void setup() {
Serial.begin(115200);
mesh.setNodeID(nodeId);
mesh.begin();
pinMode(SPRINKLER_RELAY_PIN, OUTPUT);
digitalWrite(SPRINKLER_RELAY_PIN, LOW); // Initially turn off the sprinkler
// Check if the provided thresholds are valid
if (DRY_THRESHOLD < SENSOR_MIN_VALUE || DRY_THRESHOLD > SENSOR_MAX_VALUE ||
WET_THRESHOLD < SENSOR_MIN_VALUE || WET_THRESHOLD > SENSOR_MAX_VALUE ||
DRY_THRESHOLD >= WET_THRESHOLD) {
Serial.println("Error: Invalid threshold values provided!");
while (1); // Halt the program
}
Serial.print("Node ID: ");
Serial.println(nodeId);
Serial.print("Dry Threshold: ");
Serial.println(DRY_THRESHOLD);
Serial.print("Wet Threshold: ");
Serial.println(WET_THRESHOLD);
}
void loop() {
mesh.update();
mesh.DHCP();
int soilMoisture = analogRead(SOIL_SENSOR_PIN);
Serial.print("Soil Moisture: ");
Serial.println(soilMoisture);
if (soilMoisture > DRY_THRESHOLD && !sprinklerActive) {
// Soil is dry, request the pump
PayloadData payload = {nodeId, soilMoisture};
mesh.writeTo(mesh.getNodeId(), 'P', &payload, sizeof(payload));
digitalWrite(SPRINKLER_RELAY_PIN, HIGH); // Turn on the sprinkler
sprinklerActive = true;
Serial.println("Sending pump request and turning on sprinkler");
} else if (soilMoisture < WET_THRESHOLD && sprinklerActive) {
// Soil is wet enough, turn off the sprinkler
digitalWrite(SPRINKLER_RELAY_PIN, LOW); // Turn off the sprinkler
sprinklerActive = false;
Serial.println("Turning off sprinkler");
}
delay(5000); // Adjust the delay as needed
}
and here is the Pump sketch:
#include <RF24.h>
#include <RF24Network.h>
#include <RF24Mesh.h>
// Pump Relay Pin
#define PUMP_RELAY_PIN 3
// RF24 Setup
RF24 radio(7, 8); // CE, CSN
RF24Network network(radio);
RF24Mesh mesh(radio, network);
// Node Address
uint16_t nodeId = 1; // Set a unique node ID for the pump node
// Data Structure
struct PayloadData {
uint16_t nodeId;
int soilMoisture;
byte priority; // Add a priority field
};
// Priority mapping for sensor nodes
const byte nodePriority[] = {3, 1, 2}; // Assign priorities based on node IDs
// Maximum pump runtime (in milliseconds)
const unsigned long MAX_PUMP_RUNTIME = 30 * 60 * 1000; // 30 minutes
bool pumpActive = false;
uint16_t activePumpNodeId = 0;
unsigned long pumpStartTime = 0;
void setup() {
Serial.begin(115200);
mesh.setNodeID(nodeId);
mesh.begin();
pinMode(PUMP_RELAY_PIN, OUTPUT);
digitalWrite(PUMP_RELAY_PIN, LOW); // Initially turn off the pump
Serial.print("Node ID: ");
Serial.println(nodeId);
Serial.print("Priority Mapping: ");
for (byte i = 0; i < sizeof(nodePriority); i++) {
Serial.print(nodePriority[i]);
Serial.print(" ");
}
Serial.println();
Serial.print("Maximum Pump Runtime: ");
Serial.print(MAX_PUMP_RUNTIME / 60000);
Serial.println(" minutes");
}
void loop() {
mesh.update();
mesh.DHCP();
if (network.available()) {
RF24NetworkHeader header;
PayloadData payload;
network.read(header, &payload, sizeof(payload));
if (header.type == 'P') {
// Pump request received
Serial.print("Node ID: ");
Serial.print(payload.nodeId);
Serial.print(", Soil Moisture: ");
Serial.print(payload.soilMoisture);
Serial.print(", Priority: ");
Serial.println(payload.priority);
// Check if the new request has a higher priority than the active one
if (!pumpActive || payload.priority > nodePriority[activePumpNodeId - 1]) {
// Turn off the pump if it's active
if (pumpActive) {
digitalWrite(PUMP_RELAY_PIN, LOW);
pumpActive = false;
Serial.println("Turning off pump");
}
// Turn on the pump for the new request
digitalWrite(PUMP_RELAY_PIN, HIGH);
pumpActive = true;
activePumpNodeId = payload.nodeId;
pumpStartTime = millis(); // Record the start time
Serial.println("Turning on pump");
}
}
}
// Check if the pump has been running for too long
if (pumpActive && (millis() - pumpStartTime >= MAX_PUMP_RUNTIME)) {
// Turn off the pump
digitalWrite(PUMP_RELAY_PIN, LOW);
pumpActive = false;
Serial.println("Maximum pump runtime reached. Turning off the pump.");
}
delay(100); // Adjust the delay as needed
}