Spring Time Pond Automation, Part 1
Last year I addressed a water retention issue in our backyard by digging a pond in the Georgia Clay with a pair of post-hole diggers and restless energy.
4 feet and $2,000 later, I have a goldfish pond (they ate the bluegill I ordered earlier. The fingerlings arrived several months late and didn’t stand a chance). I put a skimmer pump in, an aerator, some solar power, and a stock tank for overflow during rainstorms.
This year I want to automate it. Here is my pond’s architecture:

I have an esp 8266 relay board, and will be hunting for a battery charge sensor to attach to one input, and a water level sensor for another. Together these will be able to help me decide when to run the pump, when to fill the stock tank, and when to run the aerator.
I passed this to the OpenAI o3-mini-high model to see what it would give back:
/*************************************************************
* Example Pond Control Sketch for ESP8266
*************************************************************/
// ------------------------------------------------------------
// Pin Definitions
// ------------------------------------------------------------
#define PUMP_PIN D1 // Relay controlling the pump
#define VALVE_PIN D2 // Relay/solenoid controlling valve to stock tank
#define AERATOR_PIN D3 // Relay controlling the aerator
// ------------------------------------------------------------
// Thresholds (tune to your setup)
// ------------------------------------------------------------
#define BATTERY_HIGH_THRESHOLD 80 // Battery % to consider "high"
#define BATTERY_LOW_THRESHOLD 40 // Battery % to consider "low"
// Between low & high is "mid"
// ------------------------------------------------------------
// Placeholder functions to get sensor/battery/weather data
// Replace these with real implementations for your setup
// ------------------------------------------------------------
// Return battery level in % (0–100)
int getBatteryCharge() {
// TODO: implement code for actual battery measuring
return 85; // example stub
}
// Return total inches of rain from weather API call
float getRainInchesFromAPI() {
// TODO: implement your weather API fetch (e.g. HTTP GET)
return 4.2; // example stub
}
// Return tank fill level [0.0 (empty) to 1.0 (full)]
float getStockTankFillLevel() {
// TODO: implement your tank sensor read
return 0.3; // example stub (30% full)
}
// ------------------------------------------------------------
// Helpers to safely control pumps/valves
// ------------------------------------------------------------
// Open/close the valve that directs pump water to the stock tank
void setValve(bool openValve) {
digitalWrite(VALVE_PIN, openValve ? HIGH : LOW);
}
// Turn the pump on/off
void setPump(bool on) {
digitalWrite(PUMP_PIN, on ? HIGH : LOW);
}
// Turn the aerator on/off
void setAerator(bool on) {
digitalWrite(AERATOR_PIN, on ? HIGH : LOW);
}
// Fill the stock tank for the correct fraction of 1 minute.
// Example: if tank is already 30% full, it runs ~42s.
void fillStockTank() {
float tankFillPercent = getStockTankFillLevel(); // 0..1
if (tankFillPercent >= 1.0) {
// tank is already full; nothing to do
return;
}
// Calculate run time in seconds
// 1 minute = 60 seconds -> scaled by how empty the tank is
float runSeconds = (1.0 - tankFillPercent) * 60.0;
// Open the valve, run the pump
setValve(true);
setPump(true);
// Wait for the required time
unsigned long startTime = millis();
while ( (millis() - startTime) < (unsigned long)(runSeconds * 1000) ) {
// You might watch battery or sensor changes here
delay(10);
}
// Turn off pump and close valve
setPump(false);
setValve(false);
}
// ------------------------------------------------------------
// Arduino setup/loop
// ------------------------------------------------------------
void setup() {
Serial.begin(115200);
// Set pin modes
pinMode(PUMP_PIN, OUTPUT);
pinMode(VALVE_PIN, OUTPUT);
pinMode(AERATOR_PIN, OUTPUT);
// Initialize off
setPump(false);
setValve(false);
setAerator(false);
}
void loop() {
// 1. Read sensor/API data
int battery = getBatteryCharge(); // % battery
float rain = getRainInchesFromAPI(); // inches of rain
// 2. Decide battery state: high, mid, or low
bool batteryHigh = (battery >= BATTERY_HIGH_THRESHOLD);
bool batteryLow = (battery < BATTERY_LOW_THRESHOLD);
// 3. Pump control for filling stock tank
// Condition: battery high + rainfall > 4"
if (batteryHigh && (rain > 4.0)) {
fillStockTank();
}
// 4. Aerator and Pump states based on battery
if (batteryHigh) {
// Pump is allowed (already used in fillStockTank),
// but if we simply want the pump OFF except for filling events,
// do nothing here. Ensure aerator is off.
setAerator(false);
// (If you *do* want the pump always on at high charge, uncomment)
// setPump(true);
} else if (!batteryHigh && !batteryLow) {
// "mid" battery => run aerator, not pump
setAerator(true);
setPump(false);
setValve(false); // ensure valve is closed
} else {
// batteryLow => turn off both
setPump(false);
setValve(false);
setAerator(false);
}
// 5. Pause a bit before the next cycle
delay(5000);
}
We’ll see if that’s useful. More to come.