Instructions for employing a Raspberry PI as a water alarm system
Version 1.0, published in Jan 2015
The Raspberry Pi reads the status of one or two water sensor device(s) on one or two of its GPIO pins. When water is detected the Raspberry Pi emails out an alert to a recipient group and calls a phone number list via VoIP playing a stored wave file with a spoken alert phrase.
If the running system hangs up for some reason, an activated built-in watchdog would automatically start up the system again running the required scripts for the water alarm system. So the system should always be alive!
The phone and email list is kept in a separate simple txt-file. The data will be read in by the main python script on demand. That allows comfortably updating remotely the data on the RasPi via SSH without affecting the running system.
The setup uses the Adafruit RGB Positive 16x2 LCD+Keypad Kit for Raspberry Pi allowing a red or green backlight indicating visually the status of the water sensor(s), see fig. 1. Alternatively, a corresponding monochrome display can be used as well, see figure 2.
The arrangement in figure 1 houses the RasPi with the LCD display in a Perspex enclosure, and the power supplies and the water sensor unit (without the probes) are protected in a waterproof box. That emphasises the beauty and production quality of the RasPi but also allows a good access to the buttons on the LCD display. In contrast is the arrangement in figure 2 with a monochrome display and everything kept tidy in a waterproof enclosure.
On the first day of every third month an email is sent to the first email-recipient reminding that the RasPi is still alive despite the activated built-in hardware watchdog. The email-addresses and phone numbers will be listed allowing comfortably checking whether they are still up to date.
By pushing any of the buttons on the display board a query for shutting down or rebooting the system is prompted. That might be helpful for any kind of maintenance on the hardware.
The video shows the RasPi in operation with many of its features.
Step 1: Hardware Requirements
The following hardware is required for this project:
- Raspberry Pi (Model B or B+)
- 5V power supply (e.g. for enclosure with system 45 grid)
- SD card of at least 4GB
- Internet connection either via LAN cable or USB WiFi dongle
- Adafruit RGB Positive 16x2 LCD+Keypad Kit for Raspberry Pi or Adafruit monochrome Positive 16x2 LCD+Keypad Kit for Raspberry Pi
- Enclosure which suits the LCD Display, eg. for Model B or Model B+
- 1 or 2 water sensor units, for example from Pollin
- 12V power supply for water sensor unit (e.g. for enclosure with system 45 grid)
- 2 Resistors (1 kΩ and 10 kΩ) per sensor unit, stripboard, wires
- Waterproof enclosure (e.g. for system 45 grid)
The water sensor has to be connected to the GPIO pins. The setup from fig. 3 allows reading high or low on GRIO 17 (pin 11) according to the status of the water sensor.
When water is detected, the relay closes and pulls GPIO 17 from 3.3 V (high) down to GND. Alternatively, a sensor can be connected to GPIO 18 (pin 12) accordingly. However, the meaning of high and low is here vice versa, i.e. the relay is closed for dry conditions. That gives more flexibility in using any water sensor unit and the corresponding GPIO pin can be selected in the script and hence indirectly the kind of sensor.
If two sensors are used in total (yes, that is also possible) it is more convenient if they are of different kind. If they are of same kind the script has to be adjusted for either GPIO pin 11 or 12 depending of the type of sensor.
Using a stripboard allows you to assemble tightly the few parts of electronics (resistors and wires) as a kind of prototyping circuit board. It fits nicely on the backside of the LCD plate without causing problems placing the LCD plate onto the GPIO pins of the RasRi.
The stripboard is glued to the LCD plate with a hot melt glue gun (fig. 4). Check the correct position first! The wires can be soldered to the top end of the required GPIO pins and passed through holes on the Adafruit PCB (printed circuit board), see fig. 5.
Step 2: Initialising the Raspberry Pi With Raspbian Wheezy
When starting from scratch, download the Raspbian Wheezy operating system from the Raspberry Pi Foundation and transfer it onto the SD-card. Windows users can do that easily with the Win32DiskImager. Insert the SD-card into the Raspberry Pi and start up. You will end up in the configuration menu to do some settings such as choosing the language, local time, keyboard layout, etc. as explained here.
If you are using an USB WiFi dongle set up your WiFi connection. Raspbian Wheezy offers a WiFi configuration utility. The shortcut for this is on the Desktop (WiFi Config). Before we move on we give the user root privileges for the whole session with the command
With the root privileges we don’t have to type sudo any more at the beginning of each command in the terminal window. However, once we reboot the system we have to type sudo –i once again. Next, we do some updates by typing certain commands in the terminal window. However, it is more convenient if you open the 'Instructions.docx' document and copy and paste the commands from the document into the terminal window. In that case install the office software libreoffice-writer
apt-get install libreoffice-writer
First we update APT, the Advanced Packaging Tool. APT keeps a list of all available packages from the repositories and their dependencies.
The currently installed packages on our system get upgraded to the latest versions by
An update must be performed first so that apt-get knows that new versions of packages are available. Now we remove package files that can no longer be downloaded and are largely useless. That allows a cache not to grow out of control but to be kept minimized.
We remove further packages which were automatically installed by other packages to satisfy dependencies and are no longer needed.
Finally we update the firmware and kernel on the Raspberry Pi. The firmware is a small package of code that helps the software know how to talk to the hardware.
Step 3: Setting Up the GPIO of Your Pi
We need to install RPi.GPIO, the python library for Pi that allows easy GPIO (General Purpose Input Output) access. On Raspbian, just run
apt-get install python-dev
apt-get install python-rpi.gpio
Step 4: Setting Up Your Pi for I2C
The setup uses the Adafruit RGB Positive 16x2 LCD+Keypad Kit for Raspberry Pi which allows a red or green backlight indicating visually the status of the water sensor. Alteratively, the monochrome sister kit can be used, however without the coulor visualisation.
The character LCD display only uses the two I2C pins on the Pi! Therefore the I2C has to be set up on the Pi. Since Raspbian is used as OS, edit /etc/modules with
and add following two lines
to the end of the file. Then save and reboot to enable the hardware I2C driver.
Before you can get started with I2C on the Pi, you'll need to run through a couple of quick steps from the console. Just enter the following commands to add SMBus support (which includes I2C) to Python:
apt-get install python-smbus
apt-get install i2c-tools
i2c-tools isn't strictly required, but it's a useful package since you can use it to scan for any I2C or SMBus devices connected to your board. If you know something is connected, but you don't know it's 7-bit I2C address, this library has a great little tool to help you find it:
i2cdetect -y 0 (if you are using a version 1 Raspberry Pi)
i2cdetect -y 1 (if you are using a version 2 Raspberry Pi)
This will search /dev/i2c-0 or /dev/i2c-1 for all address, and if an Adafruit LCD Plate is connected, it should show up at 0x20 (see fig. 6).
The LCD Pi Plate Python code for Pi is available here on Github. The easiest way to get the code onto your Pi is to hook up an Ethernet cable, and clone it directly using 'git', which is installed by default on most distros. Simply run the following commands from an appropriate location (ex. "/home/pi"):
apt-get install git
git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git
It creates a folder “Adafruit-Raspberry-Pi-Python-Code” with a few sub-folder such as “Adafruit_CharLCDPlate”. Copy the original files (not the shortcuts)
from the appropriate folders to a new folder “water_alarm_system”. They will be used by the main program “water_alarm_system.py” and have to be in the same folder.
Step 5: Setting Up Your Pi for VoIP
Raspberry Pi is supposed to make some alert phone calls using a phone number list and a “prespoken” .wav file. A lot of effort on this subject has been done by Binerry. We incorporate his work into the current project.
Binerry has included a text to speech (TTS) engine which we don’t need since we use a voice file recorded by ourselves. We still install a TTS engine in order to avoid changing too much of his scripts. Hence we install eSpeak.
apt-get install espeak espeak-data
For making calls we use a sip/voip based system. The favorite tool is PJSIP. It delivers not only a command line interface - it provides a powerful library/api (PJSUA) for using within own sip-based projects. At first we install some libraries:
apt-get install subversion build-essential automake autoconf libtool libasound2-dev libpulse-dev libssl-dev libsamplerate0-dev libcommoncpp2-dev libccrtp-dev libzrtpcpp-dev libdbus-1-dev libdbus-c++-dev libyaml-dev libpcre3-dev libgsm1-dev libspeex-dev libspeexdsp-dev libcelt-dev
For start using PJSIP/PJSUA we need to download and compile it. I am using a Fritz!Box to make the phone calls to the outside world. It is recommended for using a Fritz!Box to disable certain codecs and options with PJSIP/PJSUA according to the comment from tgwaste on Binerry’s page. That avoids sound problems. Hence we create a bash file “PJSIP_INSTALL.sh” in the folder water_alarm_system with following content (see appended files):
opts="--disable-floating-point --disable-speex-aec --disable-large-filter"
codecs="--disable-gsm-codec --disable-speex-codec --disable-l16-codec --disable-ilbc-codec --disable-g722-codec --disable-g7221-codec"
rm -rf /usr/src/trunk
svn checkout http://svn.pjsip.org/repos/pjproject/trunk
cd /usr/src/trunk ; ./configure $opts $codecs && make dep && make clean && make && make install
Running the file with the command bash
will download and compile PJSIP/PJSUA with the settings above. Finishing compilation will take some time (you can have a coffee or two meanwhile).
It is necessary to register the Raspberry Pi as a new phone on the Fritz!box to get the user name (such as 625) and the password of your choice.
Binerry developed the tool SIPCALL which can easily make an automated call to a specified number with a text to speech engine or playing a .wav-file. In the current project we only play a .wav-file since it is sufficient for giving an alert.
SIPCALL is easy usable via bash-script for example to check a system or sensor state and place a call if a critical threshold is reached. SIPCALL can be downloaded from Binerry’s github-repository. The files ‘Makefile’ and ‘sipcall.c’ are required and have to be stored in the folder ‘home/pi/water_alarm_system’. General info’s are also available in the readme-file. For compiling sipcall you need the pkg-config-package:
apt-get install pkg-config
Before compling we change the script to avoid using the .wav-file generated by the TTS engine but using our own recorded voice file declared by the variable play_file, for example ‘alarm_phrase.wav’ (see the list of variables at the end of this article).
Search in sipcall.c for ‘synthesize speech’. In the line underneath add ‘// disabled: ‘ to get ‘// disabled: synthesize_speech(app_cfg.tts_file);’ Now compile with the command
If you get error messages “stray ‘\240’” and “stray ‘\302’” they refer most likely to some odd non-visible characters you got into your code by copying from the web browser. That might be due to your keyboard settings. Anyway, you will get rid of these spurious characters by entering the command
tr –d “\240\302” sipcall2.c
Then delete ‘sipcall.c’ and rename ‘sipcall2.c’ to ‘sipcall.c’. Run the ‘make sipcall’ command again and you succeed compiling. To simplify your life, you can just grab the attached ready-to-use files 'sipcall.c' and 'Makefile'.
There is a nice option in 'sipcall.c' which lets you choose a PJSUA_LOG_LEVEL between 0 and 6. That lets you control the amount of messages sipcall will return on executing and is very helpful in tracing problems. But don't forget to recompile after every change.
The .wav-file has to be generated separately by recording your “speech” with a microphone. An easy way is to employ Microsoft's Sound Recorder which is available free on all versions of Window. The resulting wma-file has to be converted into a .wav-file. This can be done on Windows with the commercial software AVS Audio Converter. The settings have to be
codec PCM, channel mono, bitrate 128 kbps, sample rate 8000 Hz, sample size 16 bit
in order to avoid sound problems (at least with a Fritz!Box). The play_file has to be copied into the folder “water_alarm_system” on the Raspberry Pi. This can be done on Windows for instance with the SSH client Tunnelier. It requires SSH to be enabled on the Raspberry Pi. How to do that is well explained in this video.
It is recommended to update regularly the PJSIP/PJSUA source code to the latest version by running the ‘bash PJSIP_INSTALL.sh’ command once again.
Step 6: Activating the Built-in Watchdog
Since the Pi is going to be running unattended in our application, it is important to have it automatically rebooted after it suddenly froze for any reason.
Fortunately, the Raspberry Pi’s BCM2835 SoC (system on card) has a hardware-based “watchdog” on board. The meaning of a watchdog is well explained here. It is basically a countdown timer that counts from some initial value down to zero. When zero is reached, the watchdog timer understands that the system is hung up and resets it.
Therefore, the watchdog timer must be updated periodically with a new value to stop it from reaching zero and causing a reset. In other words, the RasPi has to feed its watchdog periodically with a heartbeat of the running software. When the RasPi is locked up doing a certain task and hence cannot update the watchdog timer any more, the timer will inevitably reach zero and a reset will occur.
A daemon is required for sending the heartbeats. We don’t use the Linux ready-to-use watchdog-daemon but a python wrapper to interface with the Linux watchdog-daemon as described here. That allows us to activate and deactivate the watchdog-daemon and to initiate the heartbeats from our python script.
We load the watchdogdev extension module for Python, i.e. the python wrapper:
apt-get install python-dev (was already done when setting up the GPIO of the Pi)
apt-get install python-pip
pip install watchdogdev
Rebooting the system and loading the watchdog kernel module with the following commands
will create the file “watchdog” in the folder “/dev”.
We need to add a line “bcm2708_wdog” to the file “/etc/modules” in order to let the RasPi load the module the next time the system boots.
nano /etc/modules (add line “bcm2708_wdog”)
Step 7: Autostart of the Python Script
The watchdog only makes sense if our python script for the water alarm system is run on startup. The following steps show how to configure the RasPi. Open “/etc/rc.local” with
Before the last line (“exit 0”) we add commands to guide to our python script and to execute it as we do it in the terminal.
After a reboot the RasPi will automatically run our water-alarm-system script.
Step 8: Configure the Main Script ‘water_alarm_system.py’
Copy with Tunnelier the attached file ‘water_alarm_system.py’ to the folder ‘water_alarm_system’ on the RasPi. Open it with the editor ‘IDLE’ and adjust following data for your requirements:
1 for not activating the watchdog, and for using only the first email
address and first phone number, i.e. for entering a test mode
1 for Adafruit RGB Positive 16x2 LCD+Keypad Kit;
2 for Adafruit monochrome Positive 16x2 LCD+Keypad Kit
0 : one sensor connected to GPIO pin 11 (normally open when dry);
1 : one sensor connected to GPIO pin 12 (normally closed when dry);
2 : two sensors connected to GPIO pin 11 and 12 (types like 0 and 1)
name of the file containing the email addresses and phone numbers,
for example ‘phone_and_email_list.txt’
the domain name (registrar) of your SIP address (example:
fritz.box or tel.congstar.de depending whether to go via your
router’s VoIP capabilities or directly to an external provider
(to which the fritz.box would direct anyway)
the name of your SIP account with the registrar (example:
622 for the fritz.box)
your password to login to your SIP-account
name of the .wav-file containing the alarm message for the
phone calls when water sensor 1 has triggered.
name of the .wav-file containing the alarm message for the
phone calls when water sensor 2 has triggered.
email address of the sender, i.e. RasPi water alarm system
smtp server name for outgoing emails (example: smtp.mail.yahoo.com)
port number for encrypted, secure data transfer
your email account name
your email password to login to your account with the email provider
subject of the reminder email which is sent every third month to the
first email recipient in the data_list
first text passage of the reminder email referring to the email addresses
second text passage of the reminder email referring to the phone numbers
subject of the alarm email which is sent by detecting water
Message of the alarm email in case water sensor 1 has triggered. Give
detailed infos about the apparent source of the problem. That helps
somebody who is not familiar with the set up of the water alarm system.
Keep in mind, after years nobody will be familiar!
alarm message referring to water sensor 2.
subject of the mail containing the log-file.
text underneath the timeline on the LCD display for dry conditions
text underneath the timeline on the LCD display for wet conditions
message in the log file when alarm was triggered by water sensor 1.
message in the log file when alarm was triggered by water sensor 2.
Step 9: Configure the Phone and Email List
The file name for the phone and email list respectively is declared by the variable data_list. The data get read in by the main script water_alarm_system.py on demand. That allows updating the phone and email list at any time while the main script is running. It can be done via SSH (e.g. with Tunnelier) from another device (PC, tablet PC, etc.) within the network.
The attached file 'phone_and_email_list.txt' shows the general set up of the list. The phone numbers are recognised by either integer values or two asterisks followed by integers at the beginning of the corresponding lines in the data file. A phone number given by two asterisks followed by digit(s), i.e. **1 is used by the Fritz!Box for internal phone numbers within its phone network. The text after the numbers should somehow describe the recipients and is used in the log.txt file and the reminder emails created by the main scipt.
The email addresses are listed after the line ‘email recipient list’. It is important that this line starts with the word ‘email’ since the main script is searching for that word and is expecting thereafter the email addresses. The text after the email addresses in each line should somehow describe to whom the email address refers. It won’t be listed in the log.txt file but in the reminder emails.
Step 10: Content of the Folder Water_alarm_system
Finally, let’s summarize the files required in the folder ‘water_alarm_system’:
- alarm_phrase_1.wav + maybe alarm_phrase_2.wav as well (or whatever is declared with play_file_ws_1 or …2)
- Makefile (required for compiling sipcall.c)
- phone_and_email_list.txt (or whatever name is declared with data_list)
Following files are generated once the main script water_alarm_system.py has run.