Introduction: Freezer Alarm Relay
Our freezer is in a utility room which is isolated from our living space. Occasionally the freezer door doesn’t shut properly and the alarm goes off. The problem is that we can’t hear it if we are in our living space. How do we get a message that the freezer door is open? This is a common issue, we have devices in our homes that talk to us,
but what happens if we can't hear them for whatever reason. I started this as a bit of fun, but it may be of use in a more serious application.
There are 2 parts to this problem, we need a method to detect the alarm has gone off and a method to relay this fact to our living space. The design I settled on was to use a Raspberry Pi to listen for the freezer alarm going off, and then to send an audible alarm message to my domestic radio which is uPNP enabled. Universal Plug and Play(UpnP) is a standard for discovering and interacting with services offered by various devices on a network, including media servers and players, though I dont think freezers were envisaged when the standard was developed. The warning message was made loud and irritating and repeats endlessly until the radio is turned off.
I chose to detect the alarm with a Raspberry Pi Zero W and Seeed ReSpeaker 2-Mics Pi HAT The Raspberry PI Zero is a low cost version of the Raspberry Pi and the W option has builtin WiFi, while the Seeed Pi HAT retails for less than $10, has built-in LEDs and a User Button. Pi HAT are extension cards that plug directly onto the Raspberry Pi making a very simple assembly procedure. Any Pi version would be more than capable for the job, and the microphone chosen can be substituted, though I made use of the built-in LEDs in this build.
It is easy to check if a radio or TV would work for you. It will more likely be described as "DLNA enabled" or similar. This uses uPNP to communicate. On a Windows PC, select an mp3 file and “Cast to Device”. If your device shows up and you can play the file, then you are good to go.
I split the software into 2 python scripts, checkFreezer.py to check whether a freezer alert has been triggered and raiseAlarm.py to raise the alarm. These scripts could be developed and tested separately and can easily be adapted or substituted for different microphones alarm raising methods.
Step 1: Designing the Detector
When the freezer door is left open and the temperature rises, the freezer gives an audible "beep beep beep" alarm. In common with most electronic beeps, this is a single frequency. The idea is to sample the audio input, perform a Fast Fourier Transform (FFT) which transforms a time based signal to a frequency based one, in other words is breaks down a signal to display the different frequencies in the signal. See the Instructable Raspberry Pi Spectrum Analyzer With RGB LED Strip We can look for a peak at the buzzer frequency and trigger the alarm when the buzzer has been active for some time.
This detector has 2 requirements
- It should detect the buzzer, even in the presence of ambient noise ( eliminate false negative)
- It should not be triggered by ambient noise (eliminate false positive)
I decided that running a Hoover in the utility room would be a good test. It shouldn’t trigger the alarm, and the alarm should be triggered when the freezer buzzer goes off and the Hoover is running.
Step 2: Configuring the Detector
With my phone, I took audio samples as WAV files of the freezer buzzer alone, with a noisy background, and with the Hoover running. I adapted the code to perform the FFT from the post Reading Audio Stream for FFT (When in doubt, plagarise) and used the script fourierTest.py to plot raw and Fourier Transformed samples of the buzzer in quiet, noisy and very noisy backgrounds. The spike in level at frequency 645 is pronounced in the first plot and is still significant with a very noisy background.
Step 3: Constructing the Detector
Assembling the detector.
Very simple. The Pi W comes with built-in Wifi and the HAT is plugged diectly into the GPIO pins on the Pi. Configuring the software requires the steps
- Install raspbian distro on Raspberry Pi. There are loads of guides on this that can explain it much better that I can.
- Set up the Wifi (ditto above)
- It needs the alsa package installed
$ sudo apt-get install libasound-dev $ pip install pyalsaaudio
- Connect the HAT to the raspberry PI
- Follow the Instructions on the seeed website to install the drivers for the HAT.
- Run the seeed diagnostics to check the HAT is working and properly configured.
The detector program reads a block of data as a sample from the microphone, does the FFT and decides whether or not it has detected the buzzer in the sample. I tried to make the block as long as possible by decreasing the audio sample rate to 16kHz and using the biggest buffer the reader would accept. I was concerned that the FFT calculation might cause frames to be dropped, but that didn’t happen.
Having prerecorded samples on my phone made building the detector much easier as I could do the complete build on the bench before testing in-situ by the freezer.
Training the detector.
The detector was trained by scanning each sample when the WAV recording of the buzzer was played to the detector. The program output the position in the FFT spectrum with the highest power level (the peak frequency), together with the level of that peak frequency. It was simple matter to find the buzzer frequency and the power level it was emitting.
There are 2 ways to detect if a beep had occurred :-
- Was the buzzer frequency the peak frequency in the sample?
- or was the power level at the buzzer frequency over a threshold?
Either method worked in a quiet sample, but the second was better with a noisy sample, so I used that.
Sometimes a sample covered a beep, sometimes it was between beeps, and after every 3 beeps there was a long pause before the next beeps. To reliably detect that a set of beeps had occurred each sample had an upvote if a beep was detected and a downvote if not. These votes were weighted to set a count which would bump up with a beep sample and slowly decay in between times. Once the count reached a threshold the alarm could be triggered. If random noise was detected as a beep sample, the count would drift back to zero.
We need then the weights for the upvote and downvote together with the threshold. This I did with trial and error over a number of samples. I didn’t need to determine the actual buzzer frequency, I just looked for the standout frequency in the fft spectrum.
Step 4: Sending a Message to the Radio
Raising the alarm was a done with a separate script. It's job is to turn on the radio if necessary, break into whatever the radio is playing and repeat the alarm message until the radio is turned off again. I had to reverse engineer the uPnP protocol used as I had great trouble in getting reliable information or examples. A couple of references I found useful were
https://www.electricmonk.nl/log/2016/07/05/exploring-upnp-with-python/ This has a nice overview of how it all fits together
I used Wireshark running on a windows PC to unpick the message sequence when playing a sample file from my PC on my radio, and after a bit of fiddling I got a command sequence that worked. This is
- Launch a popup webserver to serve the warning message when the radio asks for it
- Set the volume level to LOUD ( The warning messsage should attract everyones attention)
- Pass the uri of the warning message to the radio
- Poll the radio until the current state is "STOPPED"
- Get the radio to "PLAY" the uri
- Repeat the last 2 steps until the current state is "NO MEDIA PRESENT", which means the alarm has been acknowledged by turning off the radio
- Finally close down the webserver and exit.
This is the script raiseAlarm.py
Step 5: Doing It Yourself
The "detector" and "raise alarm" model is not just for freezers, it could be useful anywhere where an automated alarm needs to be relayed through another medium. If this would be of interest, feel free to have a go.
Setting up the PI Zero W, including the microphone
- Assemble the hardware as in step 3
- Download the freezer-alarm scripts from this Instructable, or from the git repository which includes a few bonus tracks
$ git clone https://github.com/wapringle/freezer-alarm
- You also need to install the software to use the on-board APA102 LEDs. I have included a copy of apa102.py in the git working directory
Training your detector
I have added a training option to the checkFreezer.py script. This runs it stand-alone and prints a diagnostics to the command line, but first you need to record some samples of the alarm in a quiet environment as WAV files, and do the same in a noisy one. To complete the training you need to first find the FFT frequency with the highest level (the "peak frequency") and then a threshold level for that frequency to set a trigger. To do this, run the script checkFreezer in training mode, with the ‘-t’ option and play the recording of the alarm.
$ python checkFreezer.py -t
This runs the script in training mode. It prints "ready" when the seeed HAT has been initialised and the LED turns green, then a line for each non-trivial noise it hears, eg
$ python checkFreezer.py -t Ready peak frequency 55 trigger level 1 triggered? False peak frequency 645 trigger level 484 triggered? False peak frequency 645 trigger level 380 triggered? False
The peak frequency is, in this case 645 and that becomes the trigger frequency. Now to get the trigger level, rerun checkFreezer, setting the trigger
$ python checkFreezer.py -t --trigger=645 Ready peak frequency 645 trigger level 1273 triggered? False peak frequency 645 trigger level 653 triggered? False peak frequency 645 trigger level 641 triggered? False peak frequency 645 trigger level 616 triggered? False
Finally we need a trigger threshold that fires when a beep is detected, but ignores noise, eg
$ python checkFreezer.py -t --trigger=645 --threshold=500 Ready peak frequency 645 trigger level 581 triggered? True peak frequency 645 trigger level 798 triggered? True peak frequency 645 trigger level 521 triggered? True
Test this against a couple of noisy samples and you should be able to establish a threshold value that discriminates between the sound of the bleeper and ambient noise. You should also see the LED turn red when the beep reording is played for few seconds. If it is to quick/slow in coming on edit the settings in the script
Connecting to the radio
To configure the scripts for your own setup, you need to find the IP address and port number that your device is using for UPnP services. The radio setup should provide these. The default port number is 8080 and it would be a surprise if it is different.
I have supplied a default alarm message, freezer.mp3. Feel free to replace with your own message.
Edit the script with the appropriate IP addresses and run the script.
$ python raiseAlarm.py
If all is well, the loud and irritating alarm message will blast out of your radio until the radio is turned off, cancelling the alarm.
While the script is running it runs a mini web server to serve the alarm mp3 to the radio, possibly a security issue, but it is only active while the alarm message is playing.
Remove the ‘-t’ training flag, and run checkFreezer with your own values, eg
$ python checkFreezer.py --trigger=645 --threshold=200
To make it start on reboot, add to the /etc/rc.local,
cd /home/pi/freezer-alarm ( python checkFreezer.py --trigger=645 --threshold=200 > /tmp/freezer 2> /tmp/freezererror & ) & exit 0
The green LED will light up and you are ready for action. Play the recording of your alarm beep and after a few seconds the LED will turn red and the alarm message will play on your radio.
Position the PI at a location close by the freezer, out of the way and by a power supply. Power up and the green LED should come on. Test triggering the alarm by leaving the door open. Light should turn red and the alarm message play on the radio.
Success !! You’ve done it. Treat yourself to a long drink with ice from the freezer, but don’t forget to close the freezer door!
Participated in the
Assistive Tech Contest