#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "TMPL6I11ZZf9j"
#define BLYNK_TEMPLATE_NAME "WaterMonitor"
#define BLYNK_AUTH_TOKEN "gGZ29McJmOGDwNRYN2NIyBL3vCDTOJ9e"
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// #include <Preferences.h> // For persistent storage (optional)
//--- CONFIGURATION ---//
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// Pin assignments
#define SOLENOID_PIN 2 // Solenoid control (via 5V relay)
#define ONE_WIRE_BUS 4 // DS18B20 data pin
// Relay logic: set false if your module is active-LOW (most common)
const bool RELAY_ACTIVE_HIGH = false;
// Setup OneWire for DS18B20
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Preferences for saving values (optional)
// Preferences preferences;
//--- VIRTUAL PINS ---//
#define VPIN_MODE V2 // Button: 0 = auto, 1 = manual
#define VPIN_OPEN_TIME V0 // Slider: open duration (seconds)
#define VPIN_OFF_TIME V1 // Slider: off duration (seconds)
#define VPIN_TEMP V3 // Label: temperature reading
BlynkTimer timer;
// Mode and timing state
bool autoMode = true; // true=automatic mode, false=manual
unsigned long openDuration = 5000; // how long valve stays open (ms)
unsigned long offDuration = 5000; // how long valve stays closed (ms)
bool solenoidState = false; // current valve state (on/off)
unsigned long lastSwitchTime = 0; // last time we toggled the valve
// Helper to set the solenoid (relay) on/off with correct logic
void setSolenoid(bool on) {
if (RELAY_ACTIVE_HIGH) {
digitalWrite(SOLENOID_PIN, on ? HIGH : LOW);
} else {
digitalWrite(SOLENOID_PIN, on ? LOW : HIGH);
}
solenoidState = on;
}
// Sync values from server after reconnect
BLYNK_CONNECTED() {
Blynk.syncVirtual(VPIN_MODE, VPIN_OPEN_TIME, VPIN_OFF_TIME);
}
// Mode switch handler: 0=auto, 1=manual
BLYNK_WRITE(VPIN_MODE) {
int value = param.asInt();
if (value == 1) {
autoMode = false;
// Immediately turn off valve in manual mode
setSolenoid(false);
} else {
autoMode = true;
// Reset cycle when returning to auto mode
solenoidState = false;
lastSwitchTime = millis();
}
}
// Slider handlers: set durations (in seconds from slider) → convert to ms
BLYNK_WRITE(VPIN_OPEN_TIME) {
openDuration = (unsigned long)param.asInt() * 1000UL;
// Optionally store persistently: preferences.putUInt("openTime", openDuration);
}
BLYNK_WRITE(VPIN_OFF_TIME) {
offDuration = (unsigned long)param.asInt() * 1000UL;
// Optionally store persistently: preferences.putUInt("offTime", offDuration);
}
// Read temperature and send to Blynk (updates label widget)
void sendTemperature() {
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
Blynk.virtualWrite(VPIN_TEMP, String(tempC, 1));
}
// Automatic control logic: toggle solenoid based on elapsed time
void autoControl() {
if (!autoMode) return;
unsigned long now = millis();
if (!solenoidState) {
// Valve is closed: check if it's time to open
if (now - lastSwitchTime >= offDuration) {
setSolenoid(true);
lastSwitchTime = now;
}
}
else {
// Valve is open: check if it's time to close
if (now - lastSwitchTime >= openDuration) {
setSolenoid(false);
lastSwitchTime = now;
}
}
}
void setup() {
Serial.begin(115200);
pinMode(SOLENOID_PIN, OUTPUT);
sensors.begin();
setSolenoid(false);
// (Optional) Load saved durations from flash on startup
// preferences.begin("my-app", false);
// openDuration = preferences.getUInt("openTime", openDuration);
// offDuration = preferences.getUInt("offTime", offDuration);
// preferences.end();
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
// Schedule tasks every 1 second: read temp and control solenoid
timer.setInterval(1000L, sendTemperature);
timer.setInterval(1000L, autoControl);
}
void loop() {
Blynk.run();
timer.run();
}