ESP8266 Solenoid Water Valve With Leak Sensor
by mascka in Circuits > Arduino
1059 Views, 1 Favorites, 0 Comments
ESP8266 Solenoid Water Valve With Leak Sensor
This is a small project for home assistant that can monitorize the home water supply if a leak is detected. Also, the valve can be turned on/off by sending a mqtt payload.
Supplies
Supplies used:
WEMOS D1 Mini
HK19F DPDT Relay
Bicolor led R/G (common anode)
2 1K resistors
3 NPN Transistors (BC549C)
1 PNP Transistor
Jump wires
Breadboard
Solenoid pulse valve
Upload Sketch to Esp8266
For all my esp8266 cips i use the stored WIFI credentials for a faster connection to network. This is realy good when your esp is using the sleep mode so you need to be awake at lowest times as possible. For this project i did not remove the RTC saving credentials for network, not very usefull, but let them there.
How the code works:
Its use 2 mqtt topics.
topic_state : to send and receive the valve status.
topic_alert: on this topic the leak sensor send alert if there is any leakage
On topic_alert, the valve send every second the sensor condition state, dry or wet. The leak sensor can be created from two wires that are close enough.
The sketch:
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#define WLAN_SSID "******"
#define WLAN_PASSWD "*********"
#define mqtt_client "ESP8266-valve-1"
#define mqtt_server "*******"
#define mqtt_user "******"
#define mqtt_password "********"
#define topic_state "esp/leak_bathroom/state"
#define topic_alert "esp/leak_bathroom/alert"
#define SensorPin 0 // D3
int ledPinOn = 14; //---D5
int ledPinOff = 12; //---D6
int pulsePin = 13; // d7
WiFiClient espClient;
PubSubClient client(espClient);
struct {
uint32_t crc32; // 4 bytes
uint8_t channel; // 1 byte, 5 in total
uint8_t bssid[6]; // 6 bytes, 11 in total
} rtcData;
long lastMsg = 0;
String state = "off";
String alert = "off";
uint32_t calculateCRC32(const uint8_t* data, size_t length)
{
uint32_t crc = 0xffffffff;
while (length--) {
uint8_t c = *data++;
for (uint32_t i = 0x80; i > 0; i >>= 1) {
bool bit = crc & 0x80000000;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x04c11db7;
}
}
}
return crc;
}
void setup() {
Serial.begin(9600);
Serial.setTimeout(2000);
while (!Serial) {
}
Serial.println();
// pinMode(A0, INPUT);
pinMode(ledPinOn, OUTPUT);
pinMode(ledPinOff, OUTPUT);
pinMode(pulsePin, OUTPUT);
digitalWrite(ledPinOn, LOW);
digitalWrite(ledPinOff, HIGH);
digitalWrite(pulsePin, LOW);
// Try to read WiFi settings from RTC memory
bool rtcValid = false;
if (ESP.rtcUserMemoryRead(0, (uint32_t*)&rtcData, sizeof(rtcData))) {
// Calculate the CRC of what we just read from RTC memory, but skip the first 4 bytes as that's the checksum itself.
uint32_t crc = calculateCRC32(((uint8_t*)&rtcData) + 4, sizeof(rtcData) - 4);
if (crc == rtcData.crc32) {
rtcValid = true;
}
}
if (rtcValid) {
Serial.println("The RTC data is good, make a quick connection");
WiFi.begin(WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.bssid, true);
}
else {
Serial.println("The RTC data was not valid, so make a regular connection");
WiFi.begin(WLAN_SSID, WLAN_PASSWD);
}
Serial.print("Connecting to ");
Serial.println(WLAN_SSID);
int retries = 0;
int wifiStatus = WiFi.status();
while (wifiStatus != WL_CONNECTED) {
retries++;
if (retries == 100) {
Serial.println("Quick connect is not working, reset WiFi and try regular connection");
WiFi.disconnect();
delay(10);
WiFi.forceSleepBegin();
delay(10);
WiFi.forceSleepWake();
delay(10);
WiFi.begin(WLAN_SSID, WLAN_PASSWD);
}
if (retries == 600) {
Serial.println("Giving up after 30 seconds and going back to sleep");
// Giving up after 30 seconds and going back to sleep
WiFi.disconnect(true);
delay(1);
WiFi.mode(WIFI_OFF);
ESP.deepSleep(0);
return; // Not expecting this to be called, the previous call will never return.
}
delay(50);
wifiStatus = WiFi.status();
}
Serial.print("Connecting to: ");
Serial.println(WLAN_SSID);
Serial.print(" Connected ");
Serial.println(WiFi.localIP());
Serial.print("Connecting to MQTT...");
client.setServer(mqtt_server, 1883);
if (client.connect(mqtt_client, mqtt_user, mqtt_password)) {
Serial.println("connected");
delay(50);
client.publish(topic_state, "reset");
client.subscribe(topic_state);
client.setCallback(callback);
}
else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println("will try again in 5 seconds");
delay(5000);
}
// Write current connection info back to RTC
rtcData.channel = WiFi.channel();
memcpy(rtcData.bssid, WiFi.BSSID(), 6);
rtcData.crc32 = calculateCRC32(((uint8_t*)&rtcData) + 4, sizeof(rtcData) - 4);
ESP.rtcUserMemoryWrite(0, (uint32_t*)&rtcData, sizeof(rtcData));
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 3000) {
lastMsg = now;
if (digitalRead(SensorPin) == 1) {
Serial.println("dry");
client.publish(topic_alert, "off");
} else {
Serial.println("wet");
client.publish(topic_alert, "on");
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
//Serial.print("Message arrived in topic: ");
//Serial.println(topic_state);
String messageTemp;
for (int i = 0; i < length; i++) {
messageTemp = messageTemp + String((char)payload[i]);
}
//Serial.println(messageTemp); // Print out messages.
Serial.print("Valva de apa este:");
if (messageTemp == "on") {
Serial.println(" pornita");
digitalWrite(ledPinOn, HIGH);
digitalWrite(ledPinOff, LOW);
//////////////// send 2 second pulse to relay
digitalWrite(pulsePin, HIGH);
delay(1000);
digitalWrite(pulsePin, LOW);
}
else if (messageTemp == "off") {
Serial.println(" oprita");
digitalWrite(ledPinOn, LOW);
digitalWrite(ledPinOff, HIGH);
//////////////// send 2 second pulse to relay
digitalWrite(pulsePin, HIGH);
delay(1000);
digitalWrite(pulsePin, LOW);
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Restore MQTT connection...");
if (client.connect(mqtt_client, mqtt_user, mqtt_password)) {
Serial.println("reconnected");
client.subscribe(topic_state);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5e+6);
}
}
}
Downloads
Creating the Circuit
The circuit is not that complicated. Carefully follow the parts and wires positions. Or download the Fritzing file for a better view of connections.
For close or open solenoid valve, we must reverse the polarity, so, we have the DPDP relay. Also, the valve must receive only a pulse so we add a NPN transitor to act as a relay for cutting the voltage on DPDT relay.
The other NPN transistor are used for bicolor led, in order to show the valve status, On/Off. Also, we have a PNP transistor used for leak sensor.
I think in the future we also need to add a battery for this valve, in case of power outage and leak.
have fun creating