Sump Pump Monitor

Background
I felt the need to monitor my sump pump after my basement flooded. At first I thought I would use a split core current sensor to monitor my pump with an arduino and an ethernet shield. While I was waiting for these parts to arrive from China I thought: "what parts do I have lying around that I can use to make something in the mean time"   A few minutes of rummaging through my box of goodies produced: a Seagate Dockstar, a 2 GB USB thumbdrive and a USB microphone for an Xbox.

That was enough to whip this up in a half a day, not super elegant, and it does sometimes get distracted by ambient noise, but not too shabby for junk I had lying around.

Admittedly this is just a collection of shell scripts, with very poor form.

The meat of the scripting is done by an simple but excellent script I found by Thomer M. Gill written in ruby that I modified just a bit and his tutorial on sound detection using sox.

I just ran some CAT5 down to the dockstar and strapped the microphone near the check valve on the exit pipe. Every time the pump goes off the noise of the check valve triggers an event.

This ramshackle collection of scripts, with cron will:


 * Tweet the total events every day
 * Tweet if there are no events in the last hour
 * Tweet if there are above a threshold number of events in the last hour
 * Email me a graph of the events for the last week every day in the morning

What you need
Any device with network access and a USB port that is capable of running Debian linux will do. I happen to be using a dockstar with Debian installed but you could use a properly debianized linkstation or kurobox instead.

You will Need:


 * Debian based device with Network access and USB port
 * USB Microphone

Need to install


 * Ruby
 * ttytter
 * alsa-utils
 * sox
 * gnuplot
 * mpack

Sound Detect
This script is essentially run as a Daemon it samples 3 second sound clips, gets the maximum sound amplitude and writes a timestamp to a file, in this case

/root/myfile.out

(yes I know that's a real bad idea)


 * 1) !/usr/bin/ruby -w
 * 2) Copyright (C) 2014 Uday K. Paul
 * 3) Aug  28, 2014: Modified for use with sump pump
 * 4) Derived from original version Copyright (C) 2009 Thomer M. Gil
 * 5) Oct  22, 2009: Initial version
 * 6) This program is free software. You may distribute it under the terms of
 * 7) the GNU General Public License as published by the Free Software
 * 8) Foundation, version 2.
 * 9) This program is distributed in the hope that it will be useful, but
 * 10) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 11) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 12) Public License for more details.
 * 13) This program detects the presence of sound and appends a datestamp to a logfile
 * 1) This program is distributed in the hope that it will be useful, but
 * 2) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 3) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 4) Public License for more details.
 * 5) This program detects the presence of sound and appends a datestamp to a logfile
 * 1) This program detects the presence of sound and appends a datestamp to a logfile
 * 1) This program detects the presence of sound and appends a datestamp to a logfile

require 'getoptlong'

MICROPHONE = 'Logitech' HWDEVICE = `cat /proc/asound/cards | grep '#{MICROPHONE}' | awk '{print $1}'`.to_i SAMPLE_DURATION = 3 # seconds FORMAT = 'S16_LE'  # this is the format that my USB microphone generates THRESHOLD = 0.15
 * 1) You need to replace MICROPHONE with the name of your microphone, as reported
 * 2) by /proc/asound/cards

if !File.exists?('/usr/bin/arecord') warn "/usr/bin/arecord not found; install package alsa-utils" exit 1 end

if !File.exists?('/usr/bin/sox') warn "/usr/bin/sox not found; install package sox" exit 1 end

if !File.exists?('/proc/asound/cards') warn "/proc/asound/cards not found" exit 1 end

$options = {} opts = GetoptLong.new(*[ [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], ]) opts.each { |opt, arg| $options[opt] = arg }

time1=0

loop do out = `/usr/bin/arecord -D plughw:#{HWDEVICE},0 -d #{SAMPLE_DURATION} -f #{FORMAT} 2>/dev/null | /usr/bin/sox -t .wav - -n stat 2>&1` out.match(/Maximum amplitude:\s+(.*)/m) amplitude = $1.to_f puts amplitude if $options['--verbose'] if amplitude > THRESHOLD time2=time1 time1 = Time.new diff = time1-time2 if diff.to_f > 8.0 open('/root/myfile.out', 'a') { |f| f.puts time1.inspect }    puts diff else end else end end

waterd-hourly
This writes a log file out of the events in the last hour and deletes the event file. It will tweet if there are no pump events in the last hour or if they fall above a certain threshold


 * 1) !/bin/bash
 * 2) Copyright (C) 2014 Uday K. Paul
 * 3) Aug  28, 2014:
 * 4) Hourly script to Sum up pump events over the last hour and write to an hourly log file that is kept
 * 5) with the pump event file being deleted
 * 6) This program is free software. You may distribute it under the terms of
 * 7) the GNU General Public License as published by the Free Software
 * 8) Foundation, version 2.
 * 9) This program is distributed in the hope that it will be useful, but
 * 10) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 11) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 12) Public License for more details.
 * 13) This program detects the presence of sound and appends a datestamp to a logfile every hour,  it will tweet if there are no events in the last hour or more than the highlimit
 * 1) This program is distributed in the hope that it will be useful, but
 * 2) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 3) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 4) Public License for more details.
 * 5) This program detects the presence of sound and appends a datestamp to a logfile every hour,  it will tweet if there are no events in the last hour or more than the highlimit
 * 1) This program detects the presence of sound and appends a datestamp to a logfile every hour,  it will tweet if there are no events in the last hour or more than the highlimit

highlimit=30

result=`ps aux | grep -i "sound-detect" | grep -v "grep" | wc -l` read lines words chars filename <<< $(wc /root/myfile.out)

paste <(date +%D%t%k ) <(wc -l /root/myfile.out ) | awk '{ print $1" "$2" " $3}' >> /root/hourly.log

if $lines -gt $highlimit then ttytter -status="Pumped in last hour $lines"

elif $lines -eq 0 then ttytter -status="No Pumping in the last Hour"

else echo "pump good" echo $lines "pumped" fi

rm /root/myfile.out

if [ $result -ge 1 ] then echo "script is running" else /usr/local/bin/sound-detect & fi

waterd-minute
This just runs every minute to make sure the daemon is running


 * 1) !/bin/bash
 * 2) Copyright (C) 2014 Uday K. Paul
 * 3) Aug  28, 2014:
 * 4) This program is free software. You may distribute it under the terms of
 * 5) the GNU General Public License as published by the Free Software
 * 6) Foundation, version 2.
 * 7) This program is distributed in the hope that it will be useful, but
 * 8) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 9) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 10) Public License for more details.
 * 1) This program is distributed in the hope that it will be useful, but
 * 2) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 3) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 4) Public License for more details.

result=`ps aux | grep -i "sound-detect" | grep -v "grep" | wc -l`

if [ $result -ge 1 ] then echo "script is running" else /usr/local/bin/sound-detect & fi

waterd-daily

 * 1) !/bin/bash
 * 2) Copyright (C) 2014 Uday K. Paul
 * 3) Aug  28, 2014:
 * 4) Daily script to Sum up pump events over the day, tweet the total and send a graph of the last weeks events
 * 5) This program is free software. You may distribute it under the terms of
 * 6) the GNU General Public License as published by the Free Software
 * 7) Foundation, version 2.
 * 8) This program is distributed in the hope that it will be useful, but
 * 9) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 10) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 11) Public License for more details.
 * 1) This program is distributed in the hope that it will be useful, but
 * 2) WITHOUT ANY WARRANTY; without even the implied warranty of
 * 3) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * 4) Public License for more details.
 * 1) Public License for more details.

times=`grep $(date --date="-1 day" +"%D%t") /root/hourly.log | awk '{total=total + $3}END{print total}'`

ttytter -status="Pumped $times times yesterday"

gnuplot /usr/local/bin/plotgraph && mpack -s Sumppump out.pdf  EMAIL@ADDRESS && rm out.pdf

plotgraph
The gnuplot file that generates a pdf of the last weeks data from the hourly log file

reset
 * 1) !/usr/bin/gnuplot
 * 1) set terminal png size 2048,1536 linewidth 9  enhanced font ',30'
 * 2) set output "graph.png"

set terminal pdf font ',8' set output 'out.pdf'

set xdata time set timefmt "%m/%d/%Y %H" set format x "%m/%d" set xlabel "Date"

set ylabel "Cycles in Hour"

set title "Sump Pump" font ',20'

set key reverse Left outside

set style data lines

plot "< tail -168 /root/hourly.log" using 1:3 smooth unique title ""
 * 1) plot "/root/hourly.log" using 1:3 smooth unique title ""

/etc/crontab
The crontab that runs the above scripts on the day, hour and minute


 * 1) /etc/crontab: system-wide crontab
 * 2) Unlike any other crontab you don't have to run the `crontab'
 * 3) command to install the new version when you edit this file
 * 4) and files in /etc/cron.d. These files also have username fields,
 * 5) that none of the other crontabs do.

SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

17 *	* * *	root   cd / && run-parts --report /etc/cron.hourly 25 6	* * *	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) 47 6	* * 7	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) 52 6	1 * *	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) 00 *   * * *   root    /usr/local/bin/waterd-hourly >/dev/null 2>&1 00 8   * * *   root    /usr/local/bin/waterd-daily >/dev/null 2>&1
 * 1) m h dom mon dow user	command
 * *   * * *   root    /usr/local/bin/waterd-minute >/dev/null 2>&1