Build an audio notification system to tie in to my smart house. This is a "smart speaker" which can intelligently play audio messages notifying me if the front door was left open or if the kids leave their room after bedtime.
I'm a pretty big fan of DIY smart home automation. I have an extensive system based around OpenHAB including lighting, water shutoff, access control, security, etc and even a pretty fancy Smart Range Hood that I designed two years ago as part of the Element 14 Pi Chef Challenge.
A little earlier in the pandemic, my wife and I were both working from home and locked into hours of back-to-back Teams meetings. I happened to glance up at the camera and saw our 4 year old rolling down the driveway on a skateboard going towards the street... alone... Another time within a few weeks, at about 5:30 a.m. as my wife and I were still waking up, I heard the front door open. I jumped out of bed and ran down and looked out the front door. I could see on my way that both kids (4 and 2.5 years old) weren't in their bedroom or in the living room. The front yard was empty. I ran around to the back yard to find the pair toddling along over to the swing set like nothing was unusual...
So the solution came to me slowly in phases. I knew that simply locking the door wasn't the answer - the 4 year old had already figured that out; plus in an emergency I don't want them locked inside. (And yes, the door was locked in one of those two instances.) I quickly made an automation routine that flashes a bunch of lights and runs the super annoying buzzer inside the range hood if the door is opened at some point during the night time hours. This wasn't feasible during 'work from home' hours though as it was pretty intrusive and I don't really want it doing all that during normal hours.
I had seen a recent video from GreatScott talking about using I2S and an ESP32. In that case, he created a recording and saved it on an SD card. Later, the recording could be played back from the SD into a speaker through the ESP32. He actually talked about using it as a digital music player. This seemed close to what I wanted; but lacked a large amount of functionality - things like MQTT connectivity, and having to pre-record files and save them on a microSD inserted into the device was a hindrance for maintenance and updating. I was hoping to have a few around the house (bedroom, garage, basement workshop, and one on the main floor). The GreatScott video also introduced me to the ESP8266 Audio library.
Shortly after I saw this, someone pointed me to a different project by Mr. DIY shown in this video (actually posted within one day of GreatScott's) where he had combined basically all of the functionality that I was looking for. The microcontroller was the D1 Mini this time. He was showing a different approach where had had combined the ESP8266 audio library along with ESP8266SAM for speech syntheses (text to speech), IotWebConf library (creating a hotspot on first boot with landing page and basic user configurable options), and PubSubClient for MQTT connectivity. So this solution could read a text string pushed via MQTT, play an MP3 when given a URL, play an ICEcast stream, and also play old school RTTTL Nokia ringtones.
Mr. DIY also showed a function of the ESP8266Audio library to bit-bang the Rx pin of the micro and run it through a bare-bones amp consisting of one 2.2k resistor and an NPN transistor feeding a speaker. I was hoping for slightly improved audio quality and really wanted to use an I2S device, so for my project that's the route that I went.
I2S (Inter-IC Sound) is a stereo audio protocol that uses three pins - One clock signal, one Left/Right "word select" indication signal, and one data pin. There are I2S microchips that can function as DAC (Digital to Analog converter) to generate analog signals and push to an external amplifier. I later found the MAX98357A chip which functions as both the I2S DAC and also a 3 watt amplifier. It can be had on Adafruit (GreatScott used a version from SparkFun) with a pre-made breakout board for $5.95 USD.
Bingo - this was the key.
Putting it together
I went a few rounds looking at different I2S DACs & amplifiers, plus combo units like MAX98357A before setting. My concern was how loud it would actually be since I did want the ability to be LOUD if I needed it (like when linking to my smoke detectors). I saw a lot of amps in the 3 watt range but didn't have the confidence until I tore apart an old boombox from the 90's to find a very similar 3W amplifier (although a large DIP8 with much more thermal controls). That at least gave me confidence in the achievable volume levels.
For the speaker, I decided on a 3" unit that matched the 4 Ohm, 3 Watt rating of the MAX98357A chip; again I picked these up from Adafruit.
I was able to bench test this pretty well with a breadboard and I initially was using an older Huzzah board since that was all I had around while I waited on the D1 Minis to arrive. The setup was precarious with the breadboard, jumper wires and all just flying around in the breeze.
There really isn't too much going on with the schematic. Just a few wires to connect the D1 Mini to the I2S board; plus an LED. The Amplifier board has a way to select different gains for the amplifier, so I put down solder pads and a few passives. The entire unit is powered from USB into the D1 Mini.
Main schematic above. Solder jumpers for gain selection shown below.
I have made exactly two PCBs before; both for the PiChef challenge; and I've been itching to do it again. This time around I used the version of Eagle built into Fusion 360 and was able to get it all laid out. I did a few things I had wanted to do way back but with the time pressures of the PiChef challenge I wasn't able. They aren't complicated, but each was just 'one more thing' on the list to learn and do. These included proper custom components - not just sticking a header into my schematic and calling it something; but actually creating a custom library & custom component. I was able to add the MAX98357A as a custom component complete with layout, package, footprint (I did skip the 3D package though of this part). This let me drop it into my design and I can wire it in the schematic, and when doing the board layout it will have the plated through-holes for the pins correct plus the other non-plated holes for mounting. Pin names would also become silkscreened onto the board. This was a "lesson learned" from Pi Chef - label all your pins (if you have room). It makes trouble shooting so much easier.
I also spent a lot of time doing some generative design on the shape of the PCB. During the PiChef challenge, my boards were exactly the default size in Eagle. It wasn't immediately obvious to me how to change them and I literally didn't have time to look it up; so they just came out that size. This time around, I was able to make some nice rounded corners, carefully place mounting holes; and move things to fit properly. One other thing I did this time that I didn't during PiChef was to have my 'complete enclosure' modeled in Fusion. With PiChef, I just assumed that everything would have room; but really it was too tight. This time, I spent a few rounds playing with the board shape in Fusion360 to get it to fit properly inside the round enclosure. I pushed the LED out farther (custom board shape; and I also created a custom library component for a 'bent pins' through-hole LED) and I pushed the D1 Mini out the opposite side so the USB connector was as close to the outside as possible.
Another thing I tried out here was doing a solder mask cutout. I noticed how close the USB connector sits to the carrier board I was creating, so I decided that I can flow some solder on to an exposed ground plane and use it to mechanically (and electronically) connect the Micro USB port to the board and it should be pretty strong. This /mostly/ worked out, but was a pain to solder with just an old-school iron; and on one of the boards, some solder got inside the USB port and almost rendered it unusable.
One design note - when I mounted the I2S component - Adafruit ships it with screw terminals for the speaker. I chose to /not/ mount that on their board, but rather just use pin headers and solder down to the carrier PCB. The screw terminals I moved a little bit farther away. The reason for this was to provide mechanical stability since I would have otherwise needed to use stand-offs to hold that portion of the board up. I did also make a "rev2" of this PCB that uses through-hole resistors instead of 0805 surface-mount because some people I was talking to about the project aren't set up to do surface mount work.
I spent some (actually a lot) of time doing the enclosure. It proved pretty tricky to get a clean design look, simple construction, and 3D Printable. I ended up with a 3-part design - bottom, center, and top that make up the device.
The bottom piece holds the PCB, and has cutouts for the LED and USB cable.
The center piece is where the speaker mounts to, facing down into a cone to disperse the sound 360°. There is a hole running through the center section to route the speaker wire through cleanly.
The top piece is just a cap to cover the back of the speaker.
All three pieces use a twist-lock that I designed. One part has a small 'nub' that sticks out, and the other side has a track that it slides into. As you twist the two pieces, the nub slips over a slight bump in the track and locks into position. This turned out very well, but took a few tries to get it right. I ran into an issue with a test print where I used layer heights of 0.32 mm and the parts didn't fit as well as an earlier print. The other print had a layer height of 0.20 mm. The difference in height was too great for the tolerance of the parts I was building. I used a 5mm tall channel with a 4.85mm circular nub to ride through it. The dims are all shown in the image gallery below. The most difficult part was finding the best way to 'wrap' the shape into my curved surface. A simple extrude was crude and sort of worked. But I later found that I could use the "Emboss" to get the 2D sketch properly projected & cut into the model.
The final result turned out really good. It has a nice, solid feel. Good construction with a solid 'click' to lock/unlock the components.
Here is some of the 'test' pieces that I did to get it dialed in...
Doesn't fit!: I had to massage this corner of the D1 Mini to get it to fit properly...
IMAGE TITLE: ...using a file...
IMAGE TITLE: The first unit base is assembled! I have started 3D printing the PCB so I can test fit components (in the top left) before I order the actual PCB.
IMAGE TITLE: All 5 PCBs assembled; and the first one mounted in the enclosure.
IMAGE TITLE: First two units fully assembled!
IMAGE TITLE: Dims showing how the channel was cut out. The hump at the bottom is 0.5mm tall and provided just the right amount to securely lock the two sections together.
IMAGE TITLE: This is the size and position of the nub
How does it work?
The notifier works by subscribing to a series of MQTT topics after joining your Wifi network.
See excerpt from Mr. DIY's code here:
- Play MP3 MQTT topic: "mqttFullTopic()/play" MQTT load: http://url-to-the-mp3-file/file.mp3 - Play Icecast Stream MQTT topic: "mqttFullTopic()/stream" MQTT load: http://url-to-the-icecast-stream/file.mp3, example: http://22203.live.streamtheworld.com/WHTAFM.mp3 - Play Ringtone MQTT topic: "mqttFullTopic()/tone" MQTT load: RTTTL formated text, example: Soap:d=8,o=5,b=125:g,a,c6,p,a,4c6,4p,a,g,e,c,4p,4g,a - Say Text MQTT topic: "mqttFullTopic()/say" MQTT load: Text to be read, example: Hello There. How. Are. You? - Change Volume MQTT topic: "mqttFullTopic()/volume" MQTT load: a double between 0.00 and 1.00, example: 0.7 - Stop Playing MQTT topic: "mqttFullTopic()/stop"
So I can have my rules engine post things to the appropriate MQTT topics and the notifier announces accordingly. I recorded audio from a website that does text-to-speech in a Siri or Alexa style voice and have that saved as an MP3 on my main computer. I can then publish "http://192.168.n.n/FrontDoor.mp3" to the topic "Notifier/Basement/play" and I get a nice audible notification that the door was opened. The built-in text to speech is pretty rough and hard to understand; but could be useful for 'on the fly' notifications where I may not be able to pre-record all possible notifications. (Note: for anyone wanting to do this, you'll also need something like Apache HTTP/web server to make the folder accessible on your network.)
I was in contact with Mr. DIY and was able to get some changes pushed into the main branch on his Gitlab page https://gitlab.com/MrDIYca/mrdiy-audio-notifier - things like using LWT topic on Mqtt and broadcasting the IP address on startup. I also added a switch in the code to go between I2S DAC and non-I2S where just a speaker and a transistor can be used. The LED was another addition where it only comes to full brightness after successful MQTT connection is established and it dims while reading an announcement. I also updated the code to allow a unique SSID on startup and unique MQTT device name; and worked with Mr DIY to get unique MQTT topic names. This was all required to allow multiple devices to exist on the same network without causing confusion. I had one single device working properly but as soon as I powered up the second then things went haywire. I wanted a total of 5 so I had to work through all the issues.
I've got automation rules to play a tune (RTTTL Star Wars theme song) when my 3D printer finishes, and lots of future plans like the following:
- Voice announcement in the kids' room if there is an emergency (yes, they already have normal fire alarms) "Please leave the house" or "Go to our emergency location"
- Read my kids a book when I'm traveling for work (the wife can just hit a button and I'll have a pre-recorded story saved in MP3 to play back in their room)
- Intruder alerts tied to the security system "Intruder detected - The police are being called"
- Notifiy if the kids leave their room after bedtime (actually this is already implemented)
The nice thing is that through my automation system (OpenHAB) and the use of 5x devices, I can really tailor the notifications. If a person is easily within line of sight of the front door, then the closest Notifier doesn't need to announce it. The one for our master bedroom doesn't require the notification for the kids room door since it is 2 feet away from our heads. But the basement workshop is so far away, the kids could be running and screaming up and down the hall and we would never hear them.
As noted before, these work in a completely 'local' environment. They don't require any cloud services or subscriptions. The total BOM cost is around $10 for the speaker, I2S board, and D1 Mini. The PCB was $20 for 10 boards with shipping, so $2 each. Including filament, we are still under $15 for all components. Compared with $25 for a Google Home Mini or something similar. Yes, those devices do a lot more, but they aren't what I was looking for.
A big thanks to Mr. DIY https://www.mrdiy.ca/ for creating the original software as a nice bundled unit, and inspiring me to get this all put together.
Wanna see a video of it???
Of course you do! Here is a quick walk-though of the final hardware.