Laundry Alert!

I had a conundrum.  I was making unnecessary trips down three and a half flights of stairs only to turn around, make the return trip, wait a while, and do it all again.  I could never tell when communal laundry space was in use, nor could I tell whether or not the washer or dryer cycle was finished.  So, having a few Raspberry Pi’s around and an annoying problem to eliminate, I came up with this little guy.

Laundry Alert 1

It has saved me countless, unnecessary trips down to the laundry.  It’s just a raspberry pi, microphone, wifi adapter, a few scripts, Icinga, and Apache.  Put it all together in the right way and you’ve got a lot more free time on your hands… and maybe a bigger belly, if I’m honest.

The OS on the Pi is Raspbian (Raspbian.org).  I then installed the following packages:

  • icinga
  • apache2
  • openssh-server

The microphone I’m using is available over at Sparkfun.

Icinga

Icinga might be a little overkill for something as simple as a laundry alert, but it serves its’ purpose very well.  The parts of Icinga that I’m utilizing are the service checks, notification system, and the event/notification handlers.  Another nice feature that you get with Icinga is the complete history of the alerts & availability of the device you’re monitoring.  You can track how many hours per day/month/year the laundry is being used.

Host & Service Definitions

What I’m monitoring is effectively a microphone service, and the host is the Raspberry Pi.  I created a new host definition called “Washer_Dryer” and a new service by the same name.

The host definition:

define host{
 use generic-host
 host_name Washer_Dryer
 alias Washer_Dryer
 address 127.0.0.1
 }

The service definition:

define service{
 use generic-service
 host_name Washer_Dryer
 service_description Washer_Dryer
 check_command check_noise!30
 check_interval 1
 flap_detection_enabled 0
}

In the service definition, there’s a line that defines the check_commad to be used.  I’m using a custom command that I made just for this project, called “check_noise”.   Here’s the script:

#!/bin/bash

#Get noise value from read_noise process
noise=`cat /var/lib/check_noise/noise`

# Exit codes
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3

while [ "$1" ]; do
 case "$1" in
 -w | --warning | -c | --critical)
 if [[ -z "$2" || "$2" = -* ]]; then
 # Threshold not provided
 echo "$PROGNAME: Option '$1' requires an argument"
 exit $STATE_UNKNOWN
 elif [[ "$2" = +([0-9]) ]]; then
 # Threshold is a number
 thresh=$2
 else
 # Threshold is not a valid number
 echo "ERROR: Threshold must be valid integer"
 exit $STATE_UNKNOWN
 fi
 [[ "$1" = *-w* ]] && thresh_warn=$thresh || thresh_crit=$thresh
 shift 2
 ;;
 *)
 echo "ERROR: Invalid option '$1'"
 exit $STATE_UNKNOWN
 ;;
 esac
done

if [ $noise -lt $thresh ]
then
 echo "OK - Washer/Dryer Not In Use NL:$noise"
 exit $STATE_OK
else
 echo "CRITICAL - Washer/Dryer In User NL:$noise"
 exit $STATE_CRITICAL
fi

This script is checking a file that contains information about how much noise has been picked up by the microphone.  Depending on the value in the file, the script reports back to Icinga with either OK, WARNING, or CRITICAL by using an exit code.  Depending on the state of the service at the time of the check and what the newly reported state is, Icinga will send out notifications based on the defined notification command for the service.

Notification Command

I configured a special notification command for the contact that I defined for myself, “notify-laundry”.  It’s basically just a CASE statement with an element for each possible state of the service (OK, Warning, Critical, or Unknown).

#!/bin/bash

case "$1" in

OK)

 # The service just came back up, we need to tell that world that all's quiet in the Laundry room!
 /usr/bin/printf "%b" "Laundry is now AVAILABLE" | /usr/bin/mail -s "** Laundry Alert **" $2
 echo "<html><body><h1><font size=10 color=green>Laundry is: AVAILABLE</font></h1></body></html>" > /var/www/laundry.html
 ;;

WARNING)
 # Dont need to do anything
 ;;

UNKNOWN)
 # Dont need to anything
 ;;

CRITICAL)

 # Is this a "soft" or a "hard" state?
 /usr/bin/printf "%b" "Laundry is now IN USE" | /usr/bin/mail -s "** Laundry Alert **" $2
 echo "<html><body><h1><font size=10 color=red>Laundry is: IN USE</font></h1></body></html>" > /var/www/laundry.html
 ;;

esac

exit 0

For my purposes, I’m not really concerned with the Warning or Unknown states.  I’m only performing an action if the state changes to or from an OK or Critical state.  For either one, the first action is to send out an email alert about what the current state is, then the second action updates an very simple webpage.

 Reading the noise level

If you’ve read the first few lines of the “check_noise” script, you’ll notice that I’m getting noise information form a “read_noise” process.  That’s another little script that I wrote that is constantly running in the background, polling the microphone to determine whether or not there’s noise in the vicinity.

#!/bin/bash

while [ 1 -eq 1 ]
do

gpio mode 4 in
noiselevel=0
reset=0

 while [ $reset -lt 100 ]
 do
 let reset=reset+1
 let noiselevel=noiselevel+$(`echo gpio read 4`)
 #echo $reset
 #echo $noiselevel
 #echo `gpio read 4`
 done

sleep 2
echo $noiselevel > /var/lib/check_noise/noise
#echo `gpio read 4`

done

The microphone is connected via the GPIO ports, and has a gate output which is able to provide a 0 value for no sound and a value of 1 when there is sound.  I’m polling the gate 100 times, counting up the 1 values, storing the end result in the noise file, waiting 2 seconds, and then repeating,  This is providing me with a measurement of sorts as to how noisy the area is.  This value in conjunction with the thresholds set with the check_noise command is what the alerts are based on.

I have left a lot of configuration and setup details out of this post.  However, I think that there’s enough here that if you wanted to set this up, you could… with an added dose of google.