by Vytas Sinkevicius
Damage from appliance water leaks (such as water heaters, dishwashers, fridges and washing machines) cause millions of dollars in insurance claims every year.
There are many different types of water leak detection systems – the most efficient ones react at the first sign of presence of moisture, trigger an audible alarm, and provide an email alert. Audible only alarm type units do not perform well if nobody is there to hear the alarm.
We have created a water leak detection system kit using the PI-SPI Series of products, all that needs to be added is a Raspberry Pi and a 5VDC power supply for the Raspberry Pi.
You will need the following items to build a basic water leak detection system:
Qty. 1 x PI-SPI-8AI-4TEMP-4VDC Analog Input I/O Module
Qty. 1 x PI-SPI-8KO Relay I/O Module
Qty. 1 x PI-SPI-CABLE-40x26-2 Ribbon Cable (Required to connect to the Raspberry Pi)
Qty. 1 x PI-SPI-CABLE-26x26-2 Ribbon Cable (Required to connect the two PI-SPI modules)
Qty. 1 x Raspberry Pi Series 3, 4 or 5
Qty. 1 x 5 VDC Power Supply for the Raspberry Pi
Qty. 1 x 24 VDC Power Supply for the PI-SPI Series Modules
Qty. 1 x Water Sense Cable
Optional items can include temperature sensors for the Hot and Cold water lines of a Hot Water Tank, Alarm Buzzers, and DIN Rail Mount Enclosures.
Kits are available here.
Theory of Operation:
For this demo application, the system will have the following:
- Four zones of water leak detection
- Each zone works with a water leak sense cable (1 x 6’ cable as part of the kit)
- Up to four temperature sensors (2 x 10K NTC thermistor with 36” leads as part of the kit)
The PI-SPI-8KO module has 6 channels of voltage output. For Zone 1 operation, we connect one lead of the water sense cable to the K3 terminal, and connect the other lead of the water sense cable to the PI-SPI-8AI analog input module channel 4 which has been configured as a voltage input (0 to 6.6 VDC).
Sequence of Operation:
1. The K3 output is turned ON providing a 3.3 VDC output for 50 mSeconds.
2. At the end of the pulse, the Analog Input Channel 4 is read.
3. The K3 output is turned off.
4. If the reading is less than 20 AD counts, there is no moisture present on the water sens cable
5. If the reading is greater than 600 AD counts, the water sense cable is conducting and moisture is present on the cable
6. The alarm state is set or reset depending on the AD reading.
Wiring Diagram:
(Zone 1 Example complete with Audible Alarm and Temperature Sensors):
Python Sample Code
The following code sample has been fully tested for all zones and sensor inputs. When a water leak is detected, an alert email is sent to the users email. The program runs once per second.
# pi-spi-h2o-demo.py
# Import libraries
import smtplib
import time
from time import sleep
from widgetlords.pi_spi import *
from widgetlords import *
# initialize modules
init()
inputs = Mod8AI()
relays = Mod8KO()
# Set up the email server and configure
user = 'your_email@gmail.com' # Typically your email account
password = 'Your password is here' # Your password for your email account
sent_from = user
send_to = ['to@gmail.com'] # Send the email to
subject = 'WATER LEAK ALARM'
smtp_server = 'smtp.gmail.com' # Your email provider server
smtp_port = 465 # Typically the port is 465
# Initialize email sent flag to prevent multiple emails
emails_sent = 0
# Define Relay Outputs
K1 = 0
K2 = 1
K3 = 2
K4 = 3
K5 = 4
K6 = 5
K7 = 6
K8 = 7
ON = 1
OFF = 0
# Water leak zones
Zone_Reading = [0,0,0,0]
Zone_Alarms = [0,0,0,0]
Zone_Status = ['OK','OK','OK','OK']
# Alarm threshold AD counts
Alarm_Threshold = 600
# Temperature Sensors
Temp_AD = [0,0,0,0]
Temp_Deg = [0,0,0,0]
Temp_Read = ['-','-','-','-']
# Email send function
def send_email(server,port,_user,_password,_from,_to,text):
try:
smtp_server = smtplib.SMTP_SSL(server, port)
smtp_server.ehlo()
smtp_server.login(_user, _password)
smtp_server.sendmail(_from, _to, text)
smtp_server.close()
#print ("Email sent successfully!")
except Exception as ex:
print ("Something went wrong….",ex)
# Read zone AD counts function
# Each zone relay is turned on for 50 mSec to apply voltage
# to one wire of the water sense cable
# The analog input channel reads the voltage and stores the AD Counts
# Dry condition will read less than 5 AD Counts
# Wet condition will read > 1000 AD counts
def zone_read(zone,relay):
relays.write_single(relay,ON)
sleep(.05)
Zone_Reading[zone] = inputs.read_single(zone+4)
relays.write_single(relay,OFF)
# Get the individual zone alarm conditions function
def get_zone_alarms(zone):
if Zone_Reading[zone] > Alarm_Threshold:
Zone_Alarms[zone] = 1
else:
Zone_Alarms[zone] = 0
while True:
# read all Zones
zone_read(0,K3)
zone_read(1,K4)
zone_read(2,K5)
zone_read(3,K6)
# Get zone alarms
alarms = 0
for i in range(4):
get_zone_alarms(i)
alarms = alarms + Zone_Alarms[i]
# Configure email body for Zone Alarms
for i in range(4):
if Zone_Alarms[i] != 0:
Zone_Status[i] = 'ALARM'
else:
Zone_Status[i] = 'OK'
# Read and Configure Temperature Sensor inputs of email body
for i in range(4):
Temp_AD[i] = inputs.read_single(i)
Temp_Deg[i] = steinhart_hart(10000, 3380, 4095, Temp_AD[i])
if Temp_AD[i] > 4050:
Temp_Read[i] = '-'
else:
Temp_Read[i] = ("%0.1f Deg C" % Temp_Deg[i])
# Temperature Sensor input 4 is used as a push button input
# to send e test email and test the audible
if Temp_AD[3] < 20:
Temp_Read[3] = 'Sending Test Email'
# Read time for the email body for a time stamp
seconds = time.time()
local_time = time.ctime(seconds)
# Prepare the body of the email
body = """\
Status: %s
Zone 1: %s
Zone 2: %s
Zone 3: %s
Zone 4: %s
Temp 1: %s
Temp 2: %s
Temp 3: %s
Temp 4: %s
""" % (local_time, Zone_Status[0], Zone_Status[1], Zone_Status[2], Zone_Status[3], Temp_Read[0], Temp_Read[1], Temp_Read[2], Temp_Read[3])
# Configure the complete email to be sent
email_text = """\
From: %s
To: %s
Subject: %s
%s
""" % (sent_from, ", ".join(send_to), subject, body)
# Check for alarms and send email if required
# Temperature Sensor input 4 is used as a push button input
# to send e test email and test the audible
if alarms > 0 or Temp_AD[3] < 20:
# Turn on Audible relay K1
relays.write_single(K1,ON)
# send email only if flag has not been snet
if emails_sent != 1:
send_email(smtp_server, smtp_port, user,password, sent_from, send_to, email_text)
# Used for debug purposes
#print(body)
# set email flag to prevent multiple emails from one alarm
emails_sent = 1
else:
# if no alarm clear audible relay K1
relays.write_single(K1,OFF)
emails_sent = 0
sleep(1)