How to set up a sump pump monitor with an ultrasonic sound sensor, Raspberry Pi and Python.
In June 2013, we had the unfortunate luck of a basement flood, caused by a tripped electrical breaker connected to our sump pump. There are so many things that can go wrong with a sump pump. You always are on guard for power outages, blown breakers, sump pump failures, clogged pipes and all manner of issues that can arise, which ultimately can end with a flooded basement. I needed a way to alert me of issues when I was not at home. Audible alarms are fairly cheap and are great when you are physically in the house. They fail miserably when you are ten miles away at work. I had a Raspberry Pi that I had tinkered with periodically but for which I never had a real purpose. I decided to try to put the Pi to work as a dedicated sump pit monitoring device. Hopefully, the Pi could send me SMS alerts if a problem arose while I was away.
Since I did not have a programming background, I started to look for an existing project I could install on the Pi that could act as a sump pit monitor. There are other projects that can monitor sump pump activity; however, it seemed that everything I came across looked overly complicated or didn't have the features I required. I needed something simple that monitored the water level in the sump pit at regular intervals and sent me a text if there was a problem. If it also could display pretty graphs of sump pit activity that I could access easily, that would be a bonus.
Although I had written many scripts through the years at work, I never learned object-oriented programming. I made the decision to learn Python, and a few months later, set myself to work on a monitoring system. I chose Python because it has an active community, and many Raspberry Pi enthusiasts use it as their main scripting language. The Raspberry Pi uses Raspbian Linux, which is based on Debian, so that already was familiar ground. With these tools in hand and in true Linux and Raspberry Pi spirit, I decided to build my own and called it Raspi-Sump.
Raspi-Sump is a sump pit water-level monitoring system written in Python. It uses a Raspberry Pi and an HC-SR04 ultrasonic sensor to monitor the water level in a sump pit, log the readings and send SMS e-mail alerts if the water rises above a predefined level.
In this article, I show the methodology I used to create Raspi-Sump. I also describe the physical setup of the monitor and the scripts that make it work. If you choose to do something similar, the source code and install instructions are available on GitHub. It is free to use and modify as you wish (see Resources).
I determined that the features I required in a monitor included the following:
Regular one-minute-interval readings of the water depth in my sump pit.
Logging of readings to a comma-delimited file for processing graphs and historical pump activity.
Automated SMS e-mail alerts if the water exceeds a predefined level.
Off-site graphical reports of the current water level to a Web site.
Web-based historical information on sump pump activity.
Automatic restart of the raspisump.py process after an unexpected failure.
The complete list of components for Raspi-Sump includes:
Raspberry Pi Model B and case.
Raspbian Linux.
HC-SR04 ultrasonic sensor.
Five feet of Cat5 wire (four 24AWG strands needed).
Two resistors (one 470R Ohm and one 1K Ohm).
Heat-shrink tubing to protect soldered connections.
Plastic bracket to hold the sensor.
One two-foot piece of wood strapping to mount the plastic bracket in the pit.
One floppy drive four-pin power connector salvaged from an old PC.
Two case-fan power connectors, also salvaged from the same PC.
Total cost for materials, including a couple spare sensors, was $80.
The ultrasonic sensor I chose is the HC-SR04, which has four connections that are wired to the GPIO pins of the Raspberry Pi. With the help of a Python script, the sensor, which is mounted inside the sump pit facing the water, sends a sound pulse that reflects off the water and back to the sensor. The script monitors the amount of time it takes for the sound pulse to bounce back to the sensor. It calculates the distance by measuring the time required for the pulse to return at the speed of sound. This gives you a reading of the distance between the sensor and the water. The distance is used to calculate the water depth and log a time-stamped result to a CSV file.
Figure 1 shows a closer look at the connections.
The four pins on the sensor are wired to the Raspberry Pi as follows:
Pin 1 VCC connects to the 5V pin 2.
Pin 2 Trig connects to GPIO17 pin 11.
Pin 3 Echo connects to GPIO27 pin 13.
Pin 4 Ground connects to pin 6 Ground.
I chose GPIO17 and 27, but you can use any available GPIO pins on the Pi as long as they are identified properly in the Python script.
Pin 1 provides 5V of power to the HC-SR04 sensor. A command is initiated on GPIO17 (Trig) that sets the value of the pin to True for 10 micro seconds. This causes the sensor to initiate a series of sound pulses toward the water for that short amount of time. The Echo pin connected to GPIO27 listens for a return pulse. The difference between the send and the return of the pulse gives a time measurement. The measurement is used to calculate the distance of the water.
This causes a small problem as Raspberry Pi GPIO pins are rated only for 3.3V. The sensor sends a 5V current back toward GPIO27. A way is needed to throttle the current to 3.3V, which won't damage the Pi. To protect the Pi from damage, simply insert a voltage divider on the Echo line between the sensor and the Pi.
The purpose of a voltage divider is to reduce the amount of current sent from one component to another. As shown in Figure 1, I soldered a 470R Ohm resistor on the Echo wire and bridged a 1K Ohm resistor between the Echo and Ground wires. This prevents blasting 5V to a pin that is rated only for 3.3V. With these resistors, voltage is actually a touch higher at 3.4V, which is within a tolerable level. All soldered connections are covered with heat-shrinking tube to avoid electrical shorts.
Calculating resistor types required is beyond the scope of this article, but there are many handy Web-based voltage divider calculators available to determine your requirements. In this example, a 1K and 2K Ohm resistor would reduce the current to 3.333V.
The Raspberry Pi is connected to the sensor with a five-foot length of CAT5 cable. Because there are four connections, only four of the eight twisted wires are used. On each end of the selected wires, I soldered connectors that were compatible with the sensor pins and the pins on the Pi. An old 3.5" floppy drive power connector works great for the sensor connection (Figure 2). I used a couple two-pin PC case-fan connectors, salvaged from an old PC, for the connections on the Pi's pins. These connectors are available on-line, but anything you can salvage from an old PC works great.
The HC-SR04 is attached to a plastic case and screwed onto a piece of wood strapping. The wood strapping is inserted into the sump pit facing downward and is easily adjustable and removable if needed. The Cat5 wire is securely taped to the sump pump's ABS pipe and an open wall stud to prevent tangling and disconnection of the wire when removing the sump pit lid.
Finally, the Raspberry Pi is mounted on a wall stud and plugged in to a UPS unit. Figure 4 shows the finished view.
The Raspi-Sump program currently consists of three Python scripts. The main script is raspisump.py. The script is very simple and is only about 100 lines of code. The first thing it does is set the variables of the sump pit, like depth (72cm), critical water level (35cm) and GPIO pin assignments as mentioned earlier. The script then takes a sample of 11 water-level readings every minute and uses the median sample as the best reading (more on this later). Once the reading is established, the script determines if the water is at a safe or critical level. Safe levels are logged to a CSV file, and the script waits for another minute to take the next reading. Critical levels are passed to a function that logs the level to the same CSV file and initiates an SMS e-mail to my cell phone (Figure 5). I use the Python smtplib module to handle e-mail alerts. You can configure any e-mail server to handle the alerts, including a localhost mail server on the Pi, if your ISP allows port 25 traffic. You also can use your ISP's SMTP server or Google's Gmail SMTP server if you are using a Gmail account.
The key Python module used to communicate between the Pi and the sensor is called RPi.GPIO. This module can be used to control so many different types of equipment with your Pi. Without delving into the “nuts and bolts” of RPi.GPIO, the module helps you take control of the pins by turning them on and off. This allows you to control all sorts of equipment, like sensors and LEDs, for example.
You can view the GPIO code in the raspisump.py script within the water_level() function. Similar code is used by many other projects that communicate with the Pi's GPIO pins. Adam Lappin's Byte Creation Blog has a good example that helped me learn how to use the RPi.GPIO module in this project (see Resources).
Raspi-Sump is started automatically on bootup of the Raspberry Pi by adding this line to /etc/rc.local right before the last line exit 0:
/home/pi/raspi-sump/raspisump.py &
The ampersand (&) starts the script as a background process.
Access to GPIO pins requires elevated privileges on the Pi. To start the script manually, issue the command:
sudo /home/pi/raspisump/raspisump.py &
Figure 6 shows using the tail command to demonstrate the CSV file being updated in real time by raspisump.py.
What is displayed in Figure 6 is rather strange. The water depth is bouncing around. You would expect the water to be consistently higher with each reading. The reason for this is that there is a one-centimeter variance in each reading. Linux is a multitasking OS and not a real-time one. It is not optimal for real-time applications like communicating with sensors and returning precise results. The best reason I can come up with is that the OS is busy doing other tasks and allows raspisump.py to record the reading when it is finished dealing with those other processes.
This brings me back to the reason I use the median reading of a sorted sample. Every once in a while, the script gives an invalid reading that can be way off. This can trigger a false warning SMS alert even if the water is below my critical level. However, these readings are rare. By using a sorted sample, I can remove those fringe readings at the high and low end if they occur. The median reading is always accurate within one centimeter of the actual water level. For a residential system, I am not concerned with millimeter accuracy. A small variance in readings still provides safe reporting of the water level. This also helps explain the jagged line in the graphs that are generated and sent to a Web server at regular intervals.
The second script I use is todaychart.py. This script generates graphs, as shown in Figure 7, of water level activity from my CSV log files. It uses the Python matplotlib and NumPy modules to generate the graphs. rsync over SSH copies the graphs and CSV log files hourly to my Web server via a cron script. I chose to generate graphs on the Pi instead of the Web server, because different Linux distributions package different versions of matplotlib and NumPy. I prefer using the packaged versions for simplicity. Always using the Raspberry Pi renders more consistent graphs, no matter which distro you use for your off-site component.
The third and final script is checkpid.py. Its purpose is to monitor the health of the raspisump.py process and restart it if it is stopped. Cron runs the script at regular intervals and looks for one of three outcomes. If the script returns 0, this indicates a failed process. checkpid.py then initiates a restart command. If the script returns 1, the process is fine, and the script exits cleanly. If the number is greater than 1, this indicates more than one raspisump.py process. In this instance, a killall 09 raspisump.py directive is initiated, and the process is restarted.
The HC-SR04 sensor has a fairly wide sonar field. The user manual states that it works best with a 30° angle. My sump pit is a busy place. It has a backup pump that sits higher than the main pump on a 2x6 stud. Each pump has a float ball that bounces around in the pit. This results in false readings when the sensor picks up an object that enters its field. This problem can be mitigated by strategically placing the sensor further away from these objects. If that is not possible, you can vertically insert a 3" or greater piece of PVC pipe in the sump pit and force the sensor to take its reading down the empty pipe. This will focus the pulse and hide the objects in the pit that are causing problems.
Raspi-Sump is still in the early stages of development. There are other features I would like to add, such as:
A manual power button to start and shut down the Raspberry Pi gracefully without logging in.
A small LCD display to show the current water level without opening the lid.
A Web-based reporting system using a Python Web framework.
A Web-based management interface for Raspi-Sump on the Pi (like a home router).
A GSM module component to use the cellular network for alerts instead of the Internet.
A configuration file to store variables as opposed to within the script.
Package management for installation of Raspi-Sump.
A sump pit monitor is just one tool you can use to help avoid a flooded basement. It's not a replacement for a complete strategy that includes a backup pump on a separate electrical breaker. A gas-powered electrical generator is also essential for extended power outages. Also, I kept my cheap Home Depot audible alarm. A text alert at two in the morning is useless if I am sound asleep. I want a “full-out” screech to wake me up.
I welcome all feedback on this project. I am not a professional programmer, and I am sure that I can substantially improve the code or add useful features that I have not even considered.
Although it's not perfect, I now have a system that works and gives me extra peace of mind while I am away. If you are looking for a similar solution, I hope you can use, modify and improve Raspi-Sump to suit your needs. If you do, I would love to hear from you.
Special thanks to Ron Hiller (GitHub user @rhiller) for tirelessly answering my questions about voltage dividers and his own sump pump monitor called pi-distance: https://github.com/rhiller/pi-distance.