Help your dog (or cat!) communicate with buttons using balena
Execution time: 20 - 30 minutes
My work from home co-pilot is an adorable Corgi mix named Brigitte. She is great for reducing stress and generally improving quality of life while working, but she has her own needs too. And when I’m absorbed with a task, it can be easy to forget that. But to my defense, she isn’t the best communicator. Brigitte is a quiet dog, which means when she needs to go outside to relieve herself, she often suffers in silence instead of barking or whining like a normal dog would. But she is also quite intelligent. I was confident that if she had a means of communication, she would use it. So I set out to build something that would teach both of us a new trick or two.
Although I have had little experience with Raspberry Pi’s, coding or Docker, the balena platform made it simple to get started on my project. It also made it easy for me to scale it once I was ready to add more devices. This project uses simple components and minimal code, making it approachable and easy to understand for users of any skill level; even mine!
Part of the balenaLabs Residency Projects
Every new balenista starts their journey by creating a project as part of their onboarding. This project guide is my reflection of my own residency, allowing me to meet new teammates, get to know the platform, and understand how our users put balena products to work.
Pictured: Our beta tester, Brigitte
Since I don’t think I am ready to build a device that will let Brigitte talk (yet) I at least wanted to build something that would let her convey a clear message. I envisioned a button she could press that would tell me she needs something. This need could be configurable on a per device basis for things like outside, play, treats, etc. From there, I could expand the functionality of this to make it more and more useful. At the conception stage, I had a roadmap of functions and features to make the device “smarter” than the simple dog buttons you typically see online. This could mean something like an email, mobile notification, or multi room audio broadcasting. I am even hoping to add tracking and graphing to let the data tell me the times of day she typically makes the request. While I haven’t incorporated those advanced features yet, I did succeed in building a device that lets her “talk”. If you want to follow along and build it out, here is how I did it.
Raspberry 3B/Raspberry 4
A micro SD card (We recommend the SanDisk Extreme Pro SD Cards)
USB speaker (can be substituted with an aux connection)
Since this is simply a board with some wire, a button, and a speaker, you can accomplish it with a wide variety of devices and peripherals. I happened to have a few Pis on hand. I ordered a big arcade button, but there are a lot of different options available online if you want to get creative.
Note: You can use any small enclosure that houses the device and keeps the button in place. I used a small wooden box from a local craft store, but you may want to use something larger and/or sturdier if you have a larger dog.
balenaCloud to deploy the project to your fleet (NOTE: the first ten devices are free and fully-featured)
Connect the wires to the pins between the button and board using M-F wire (GPIO 21)
Connect the wires to the pins between the LED and board using M-F wire (GPIO 20)
Connect your speaker (USB or AUX)
When finished, you should have something that looks like this:
Deploy the App
If you haven’t done so already, you should set up your balenaCloud account for this part. Remember, your first 10 devices are free and fully featured! Once your free account is set up, you can easily deploy the project to your micro SD card by checking the app out on balenaHub! When you land on the balenaHub page, click the ‘get started’ button and it will direct you to a page that looks like this:
Once you have selected your device and filled out your network information, go ahead and click the ‘Flash’ button.
Note: You will need to have balenaEtcher installed for this to work.
Map your chosen sound
After you have set up your hardware and put in an enclosure of your choosing, all that's left is some slight configuration. Out of the box the device is configured to play the 'default' sound. If you were to hit that button immediately after deploying the application, the voice will tell you you need to map a sound using the environmental variable. To adjust this, please see the options below:
Environmental Variable: AUDIO_OUTPUT
Description: Select the default audio output device. Can also be changed at runtime by using the companion library
Options: For all device types:
AUTO: Let PulseAudio decide. Priority is USB > DAC > HEADPHONES > HDMI
DAC: Force default output to be an attached GPIO based DAC
<PULSE_SINK_NAME>: If you know the sink name you can force set it too. Note that you can't use this to set custom sinks as default, in that case use set-default-sink on your custom pa script.
Options: For Raspberry Pi devices:
RPI_AUTO: BCM2835 automatic audio switching as described here. Deprecated for devices running Linux kernel 5.4 or newer.
RPI_HEADPHONES: 3.5mm audio jack
RPI_HDMI0: Main HDMI port
RPI_HDMI1: Secondary HDMI port (only Raspberry Pi 4)
Environment Variable: AUDIO_VOLUME
Description: Initial volume level for the default audio output device.
Options: Any value between 0-100%.
Environment Variable: SENDGRID_API_KEY
Description: Your unique generated API from SendGrid to allow email notifications.
Options: Specific case sensitive key.
Environment Variable: SOUND_FILE
Description: Sound file you want the device to play. More can be added by dropping audio files in the 'woofer' folder.
default.wav: "Please select an environmental variable"
hungry.wav: "I'm hungry"
sorry dave.wav: "I'm sorry Dave, I'm afraid I can't do that."
Environment Variable: TIMEOUT_LIMIT
Description: The number of seconds the device spends in 'cooldown' after a successful push.
Options: Any integer
Once you have read what each variable does, you can modify them by going to the device on your balenaCloud dashboard and going to the ‘Device Variables’ tab. Here is an example of what this page would typically look like for a balena-woof device:
As you can see here, I have my “SOUND_FILE” set to “outside.wav”. So when the button is pressed, I will hear the sound file that says “outside”.
Outside.wav is one of several presets included, but can also easily include your own sounds! Just make sure you convert them to a 16-bit PCM WAV file so they are compatible with pygame. Audacity is a good tool for this.
Quick note: If that voice sounds familiar, you must be a gamer! I made those voice lines using a text to speech application based on GLADOS from the Portal series. The tool I used can be found here: https://glados.c-net.org
Finally, there is also a feature to send you an email when the button is pressed. This is handy if you want to know if your dog pressed the button when you weren't around. This involves setting up a SendGrid account and verified sender. Their free plan lets you send 100 emails a day, which should hopefully be sufficient for this purpose. I won't go into how to set that up since their documentation covers it pretty well, just know that you need to put your 'to' and 'from' addresses into woofer.py, as well as include your API key using the 'SENDGRID_API_KEY' environmental variable.
How it Works
The entire project was written in Python and can be found here on GitHub. The included docker-compose.yml imports the audio container you will need.
In the woofer container, the Dockerfile installs the libraries and copies the code and default sound files. The woofer.py is the code that watches for input from the button and runs the sequence to play sounds and send notifications when it receives that input. The final command in the Dockerfile runs woofer.py on startup, so the button is ready to go as soon as your device powers on.
While I didn’t run into any major challenges with the core of the project, I did struggle to find ways to achieve my stretch goals. Namely, I could not seem to find ways to integrate notifications, SMS or wireless audio broadcast. I did end up successfully integrating SendGrid for emails, but this has a daily limit of 100 emails. I would have preferred to find a way to integrate mobile notifications into an app. If you have an idea for how best to achieve this, please feel free to make contributions to the project via github, comments, or the forums!
While I had confidence in Brigitte’s ability to learn a new trick, I was very surprised just how quickly she learned it. We had previously taught her the “touch” command, which allowed us to point at anything and ask her to put her paw on it. This is our first time asking her to press the button:
This made it very easy for us to help build associations for her. She knew the door we use when we want to go outside, and would typically wait by it when she wants to go out. To piggyback off that routine, we placed the button next to the door and began insisting she press it before we would open the door. It was a bit slow at first. Here is our first attempt:
Once she had made that connection, it was a matter of repetition. Each time she would demonstrate body language telling us she wanted to go out (in her all too subtle way), we would follow her to the door and wait. At first we would have to say “touch” or point at the button to remind her of the new step. In time, it got to the point where she would lead us to the door and press the button without being prompted. Before long, she began using it like an irate hotel customer would use a bell. She often looks at us, then runs over and presses the button demandingly. It’s quite amusing, but some days we wonder if giving her a voice was actually a good idea.
But she has clearly developed the intended association, since she never uses the button unless she has reason to go outside. Our goal now is to see if we can expand to have more buttons that convey different things, to see if she can understand that buttons have different functions based on sound, location, time of day, etc. I have no doubts that she can.
In my prototype I had everything connected to a breadboard and included things like resistors and LEDs. While this helped me learn a lot about wiring, I found that my project did not require all of those extra components at this stage. But my hope is to return to the project later on and expand it to include things like notification lights and additional buttons wired to a single board to play multiple different sounds or code sequences from a single device.
I would also like to expand the capabilities of the device to include more features such as:
Telegram bot integration
Ability to broadcast sound over Bluetooth to one or more speakers
Letting the devices in the fleet “talk” to each other, so the user has the option to broadcast the audio file to all devices in the fleet when a button is pressed. This way if your dog presses the button in the living room, its sound will also play from the device in your office; even if they are configured to play different sounds.
Button press logging with Grafana
Web interface hosted on the device to view data and alter variables