By Jade Wang - 11 Feb 2018
The doorbell finally works! SMS-to-Pebble notification, and no delay on ding-dong audio.
Over my holiday staycation, I decided to start working on my long-delayed doorbell project. Backing up for a moment: I have a confession to make about tech debt. For many years, we have not had a functioning doorbell and relied on a well-documented workaround.
Faded post-it note reads: “Does not work; please knock.”
My husband Kenton has had the idea to make a smart doorbell since the construction of the house but simply got too busy to actually work on it. And continued to be too busy. For seven years. So I took matters into my own hands. (To be fair, some of those years include us co-founding a startup together and then starting our new work at Cloudflare. And he did start by implementing our home security system, and then ran out of free time.)
Note: this is my first Arduino project, and though I have a few small electronics projects under my belt, I do not by any means claim to be an expert.
Ingredients: Node.js, Arduino, Pebble (paired to Android phone), Twilio API, Audacity, Sugru, lead-free solder, a box of Whole Foods mints, hot glue gun, and a bunch of npm packages.
Circuit diagram scrawled on a post-it note with color labels to help me keep track.
That’s the short version, the pretty-straight-forward version. But the truth about building it and no-filter overly-honest-methods story with all the missteps along the way is a more fun story to tell. So here’s how the adventure started.
(as scrawled in dry-erase on a whiteboard.)
In preparation for having some stay-cation time, I order all my supplies early so I have all of my days off to work on the doorbell project. It shouldn’t take long, right? ;)
This is my very satisfying haul:
My holiday Adafruit haul (clockwise from top): mini-breadboard, alligator clips, rubber feet for Arduino, Arduino, jumper cables, resistors.
Actually, before making sure the button works, the first step is to figure out which wires in the server room correspond to the doorbell at the front door. Luckily, Kenton left most things reasonably well-labelled, so the only wire bundle left un-labelled should be the doorbell, but I still needed to use a multi-meter to check which wires in the bundle were actually hooked up to the doorbell.
There were 6 wires in a brown bundle coming out of the wall. Each pairwise connection appeared to have infinitely high resistance, except for one pair, which was negligibly low. That’s good. Lower than I was expecting (is the button stuck in the on position?), but pretty sure those are the relevant wires.
Six wires terminating in the server closet.
Next, I unclipped the doorbell from the wall by the front door, and unscrewed the wires holding it to the plate. Pressed it a few times. Feels like a good button, smooth action, and is not stuck in any way. That’s good. Here’s a diagram of how the doorbell should hook up.
Left: original circuit diagram for how the doorbell is hooked up. Right: after ripping out the bulb. “Computer” here means Arduino, server, and literally everything else. (Scribbles along the periphery: Factorio diagrams.)
Just to be thorough, I test the button with the multimeter to confirm the button does what I think it does. Nope. Fully pressed and not-pressed are both approximately the same as a piece of wire. Huh. Options at this point:
My first choice was (1) so I shopped around on Amazon, but literally all the options were either ugly beige, full of cast-iron-looking frilly decorations (which don’t match the aesthetics of the house and would result in complaints from Kenton, who will definitely notice – in fact he rejected all plausible options for being too ugly), or part of a walled garden smart doorbell system which requires me to use some company’s proprietary app. So I walk to Fry’s and my luck there isn’t any better. But I impulse purchase some LED kits – well, not impulse purchase. I have another project I’m planning. More on that in a future post.
So I might as well take the doorbell apart as a puzzle if I’m planning to buy a new one anyway. So I disassemble it, and the connectivity of the metal parts are exactly what I’m expecting (see diagram above), and there’s a tiny incandescent bulb. Incandescent. Wow, when was the last time I saw one of these?
I measure the resistance across the switch (the two bendy metal parts the button applies pressure on) as I press the metal parts together. That part works fine. Infinite resistance to zero to infinite as I press and lift. Good. Let’s see what happens when I measure across the whole button circuit when pressing it. Doh. There’s no change when I press the button because it’s like it’s always pressed. It’s like the light bulb is a wire.
OH: I’m pretty sure burnt out bulbs are basically, like, insulators.
Let’s measure across the bulb and see. Oh hey, approximately zero ohms.
Me: Nope, I’m pretty sure this burnt out bulb doesn’t care what you think. It’s basically a wire.
Well, I guess I could just rip out this bulb and it would work. Do I really care if the doorbell lights up? Could someone find the button in the dark? Well, there’s other ways to fix that. I have glow-in-the-dark nail polish left over from Halloween. :D
So I rip out the bulb, paint the inside of the button with a few coats of glow-in-the-dark nail polish, let it dry overnight, and reassmbled the button in the morning. Fixed! Now the right side circuit diagram (from above) applies.
Now that I have a working button, I followed the Arduino Button Tutorial. Success, the button tells the LED to light up when pressed!
Next, I integrated the Twilio API (meteor add twilio-meteor), so each button press sends me a text message, which you can see on my Pebble.
Now to play a ding-dong sound. I learned by reading this ChromeCast-Arduino sketch that one can send an HTTP request to a Chromecast to play a sound. So the first step is to make sure my button presses can send an HTTP request, and I used RequestBin to test.
It’s hard to see, but in the beginning, the last request on RequestBin was from 15m ago, and after the refresh, the last request is from 12s ago.
And I was pretty sure I’d prefer to use the breadboard in my next project, so I sacrificed a couple jumper cables, soldered the 10 KΩ resistor to them as per the diagram, and put it in this mint box. Since I don’t have a heat gun, I used a hair dryer on the heat-shrink tubes.
I added some holes on the box to make room for the cables to come out, and used hot glue to make thise edges not sharp. I also hot glued a piece of plastic to the bottom of the tin so the arduino would (1) fit snugly and not jostle about and (2) not be sitting directly on the metal.
Useful things I’ve found in Kenton’s junk drawer: heat-shrink tubes, USB-B cables (a.k.a. “random old printer cables”), lead-free solder, a soldering-kit that I gave him as a birthday gift several years ago, wire-cutters, wire-strippers, various screwdrivers, and hot glue gun (I guess that’s from my random crap).
During testing, sometimes I give the button a nice firm press in the center, and sometimes, I grab it by the edge and maybe it flutters a little on the way down. This is a problem because fluttering (the technical term is switch bounce) would result in me receiving anywhere between 2 and 10 SMS messages from a single button press. Oops.
There are a few options to consider on how to debounce:
Any of them would have worked fine, but I decided to implement the debounce in the Arduino sketch because I have an intuitive bias towards fixing the problem closer to the source. There is a ‘proper’ way to debounce in Arduino-land, and reasons not to implement my quick-and-dirty debounce (which is inserting a simple delay to all processes of half a second after each press), but I don’t intend to have other sensors or components attached to this particular Arduino for this project, so this doesn’t throw other components off.
Also, it was 2AM and I just wanted to fix this one bug before declaring victory and going to sleep.
This resulted in a 12-second delay between button press and DING-DONG.
Of course, starting up the YouTube App in Chromecast might have something to do with it. So, the next implementation plays a ding-dong mp3 file which I edited heavily in Audacity so that it was loud enough and short enough.
This resulted in about a 5-second delay between button press and DING-DONG. Still too long.
Now I’m fresh out of ideas on how to shave off more seconds of latency, so I swivel around and ask Kenton for help, who suggests that I don’t use Chromecast, and play locally through speakers instead. Next steps:
Part of step (2) is making the whole thing a plain Node.js app.
My first implementation was a Meteor app, using this meteor serialport package, because it was super easy and straightforward to use. However, using that particular package pinned me to an older version of Meteor. That was ok at first when I was playing audio via Chromecast and I just wanted to get something working quickly.
But after deciding to ditch Chromecast, I need to play audio via speakers, and as I found myself shopping around, all those npm audio packages required a newer version of Node. Embarrassingly, it took me a bit of time looking at dependencies, wondering if I could get away with just using older versions of the audio packages, before I realized that would be way more work than removing the Meteor layers so I could use the current version of Node. I’m so used to Meteor that this felt like venturing into uncharted waters. I’d hit Command+S and stare at Chrome like a chump, waiting for it to refresh by itself.
One evening of futzing around and one-more-bugfix-and-it’s-ready-to-deploy…
Fast forward to mid-January after the Amp arrives…
After a shipping delay, the amp finally arrived in mid-January, so when I found some free time, I hooked it up to the living room speakers.
Actually, I misread Kenton’s labels and first hooked them up to the speakers in the wrong room before fixing it. And made poor contacts the first time which resulted in a distorted, noisy ding-dong, rather like you’re hearing the ding-dong on a car radio that’s going through the mountains.
Since this was a very basic amp that accepted raw wires, I had to be careful with the amount of pressure I put onto the little pieces of plastic and springs that held it into place. There are plenty of things I’m good at. Not breaking tiny plastic components whilst clipping them into place is not one of them.
I actually did break one of the little buttons, which came loose from the spring, but was able to put it back together. Phew. o_O
Currently, the doorbell functions as described in the how-it-works at the top. It successfully plays exactly one ding-dong every time the button is pressed and sends exactly one SMS message to each of our phones.
Arduino enclosed in mints box, connected to server via USB, and connected to doorbell via wires that go into the wall, with alligator clips extending the reach slightly. And the server is also connected to the amp via USB, which is connected to speaker wires that run through the walls. Next version will have a better wiring solution. But Garply (the cat) isn’t allowed in this part of the server room so it should be fine for now.
Great. Finally it works perfectly. So we keep the server running all the time now, right?
So we leave it running like we intend to, and eat dinner, watch a movie or two. A few hours later… DING-DONG. I run to the door, but there’s no one there. Huh. I test it, and it works as intended. Another few hours later… DING-DONG. And no one there. Maybe one of the alligator clips touched something from a breeze in the server room. So I apply some tape, in case that fixes the issue. A little while later, shortly before bed … DING-DONG. Ugh.
I have a few hypotheses about the phantom ding-dong that I can test, but in the meantime, the doorbell server isn’t up, but I haven’t put up a new post-it note yet. >_>
If any store-bought product did exactly what we wanted, I would almost certainly have bought a product instead. However, every doorbell product I looked at was guilty of at least one of these:
Many people might not consider the last one to be a deal-breaker, but personally, I would prefer that:
If you want to holler at any IoT product makers to make their products self-hostable, please tweet them at me (@qiqing) – I’d love to help make that happen so I can use their products. Until then, great excuses to follow tutorials and build things myself!
Over the course of working on this project I’ve come to appreciate my strengths and weaknesses, which is important for knowing when to ask for help.
I kept thinking, I’ll write the blog post about this project after I’ve fixed this one bug. But I’ve been one issue away from posting for the last several issues…
Next steps: write a logger. Get some logs. Fix this phantom ding-dong bug. Stay tuned!
Big thanks to Kenton for getting me unstuck, and thanks to Kenton’s Minneapolis friends and other LAN party guests for helping eat all those mints since I needed the container.