The Doorbell Notification Project: Part 3
Welcome back! Long time, no see. Been busy with a new job, but I'm trying to get back on track.
In Part 2, I had pretty much wrapped up this project as far as it was going to go, outside of fancy new features like video. So why do a part 3? Well, the inevitable march of progress dictates that sometimes upgrades are forced upon us, and such a case recently happened to me. I won't bore you with the details, but the short version is that the decrepit Mac Mini I was using for my kitchen media center and doorbell ringer was no longer fit for media center duties.
So I replaced it for 10% of the cost of the original Mini with one of these:
Raspberry Pi + Kodi = Winning
I've talked about the Raspberry Pi before, I used one for my arcade project - which I have yet to finish - as well as using one to drive my sprinkler system at home, which I haven't blogged about yet.
Anyway, the Pi version 3 is quite powerful compared to its predecessors, and after watching this video right around the time the 3 came out, I tucked away the knowledge that it could run Kodi, my media center software of choice, quite easily:
So I ordered this $50 kit which comes with everything needed except a microSD card - an 8GB version will do, which can be had for another $5 or so.
Once the hardware arrived, it was brain-dead simple to put together. I actually mounted the Pi under the shelf that my old Mini sat on, behind the monitor, so it wouldn't be visible at all:
As for the software, it's similarly simple. There are a couple different versions of Kodi that run on the Raspberry Pi, but I chose OpenElec because it is very simple and designed only for this purpose. It's very fast and tuned to being a media center. You download the Raspberry Pi 2 diskimage and write it to your microSD card. Pop it into the Pi, and boot up. Done!
Update: It appears that OpenElec is no longer maintained. Its successor, LibreElec does the job just as well, if not better. The following guide applies just as well to LibreElec.
Doorbell 2: Electric Boogaloo
Of course, none of this actually got me any closer to having a doorbell sound play in my house when someone pressed the button on my front porch.
But I figured, how hard could it be? I'd already written a simple Java App to do the work, surely it must be simple to get working on the Pi, right?
Eh, not so much.
What follows is basically documentation for myself in case I ever want to do something this convoluted again.
First things first - as I said, OpenElec is a no-frills, barely-even-Linux distro, designed only for being a media center. It doesn't come preloaded with Java, or even a package manager with which to download Java. So after a bit of Googling, I found out that you can run the Embedded Linux Java distribution on the Raspberry Pi.
To get it working, I downloaded the ejdk-8u101-linux-armv6-vfp-hflt.tar.gz tarball, extracted to the /storage location on my Pi, and then ran the jrecreate.sh script in the bin directory to create a JRE to use. There's a bit of a chicken-and-egg situation here because this script needs Java to run, so you can point it to the linux_armv6_vfp_hflt/jre directory for this purpose. For me, the commands looked like this:
kodi-kitchen:~/ejdk1.8.0_101/bin # export JAVA_HOME=/storage/ejdk1.8.0_101/linux_armv6_vfp_hflt/jre
kodi-kitchen:~/ejdk1.8.0_101/bin # ./jrecreate.sh /storage/jre1.8
The command takes several minutes to complete, but it generates a useable JRE for you in the location of your choice, in my case /storage/jre1.8.
With that in place, I turned my sights to making sure that my doorbell program would work on Linux.
I quickly learned that sound on Linux really sucks.
I had an empty Linux implementation of the audio player class in my old app, so I experimented copiously trying to get any version to work. No matter what I tried, I couldn't get the Pi to make a peep. So I took a step back and tried to simply play the doorbell sound directly from the command line:
# aplay doorbell.wav
Nothing. In fact, I'm pretty sure it resulted in some kind of error, but I can't recreate it at the moment.
I also experimented with changing the sound devices, as the Pi comes with an analogue audio out port that I was using to route to my speakers, as well as HDMI. The command amixer can help here. But this also resulted in errors.
After a lot of digging, I learned I needed to put the following command at the end of /flash/config.txt
file:
dtparam=audio=on
But of course, you can't edit the config.txt file out of the box, so you have to run the following to make the /flash partition writeable:
mount -o remount,rw /flash
After editing config.txt, make it read-only again with:
mount -o remount,ro /flash
After doing this, I was sure I was golden, because amixer and aplay no longer resulted in errors! But when I tried to play the doorbell sound file, it acted like it played it, but no sound ever came through the speakers.
I suspected it was going to HDMI instead of the analogue port, though I didn't have an easy way to test it. Instead, I dug some more and found this wonderful page that explained very clearly how to switch to the analogue port:
amixer cset numid=3 1
Duh. Obviously.
But: boom! Doorbell sound on the commandline with aplay worked!
Unfortunately, playing the sound directly in Java code still did not work after all of this. At this point, I figured I'd cut my losses and simply shell out to the commandline from Java to play the sound:
private static final String[] PLAY_DOORBELL_CMD = {"/usr/bin/aplay", "/storage/downloads/doorbell.wav"};
Runtime.getRuntime().exec(PLAY_DOORBELL_CMD);`
This isn't ideal as it presupposes the location of the doorbell.wav file in some location on disk instead of neatly bundled in the doorbell jar file. I could always abstract this into a config param of some kind, but at this point I figured the whole process was fairly kludgy anyway and called it good enough.
The next step was to update my Vera with the Pi's address so that it "rings" the doorbell when the button outside is pressed. In this case, my Pi's address is 192.168.1.28:
Finally, to make it all work every time the Pi booted up, the following had to be added to the /storage/.config/autostart.sh (in this case I had to create the file):
amixer cset numid=3 1
export PATH=$PATH:/storage/jre1.8/bin
export JAVA_HOME=/storage/jre1.8
/storage/jre1.8/bin/java -jar /storage/doorbell-2.0.jar >> /storage/logs/doorbell.log 2>&1 &`
After all this, every time that Pi boots, my doorbell app is ready to rock 'n roll!