Serverless Doorbell — Azure Functions and Ring.com
Part 1 — Ring, Azure Functions, and Event Grid
My parents sent me an early Christmas present this year — a Ring video doorbell. The doorbell notifies my phone whenever someone rings the doorbell (or if it detects motion) and can capture video and audio of my doorstep.
I’ve seen these doorbells in more than a few sales this year, and as a result they seem to be growing in popularity. Like any good IoT maker, I wanted to see how I could extend and connect it with my other things. In the space of an afternoon was able to build a simple serverless app to trigger whenever someone rings my doorbell, and push that data instantly wherever my hacker-heart desires (including face/audio detection). All of this functionality will add a grand total of about $0.40 to my Azure subscription each month. In the end, I used Azure Functions to create the trigger for ring.com events, and push the data to Azure Event Grid to notify any listeners of events.
Trigger on device alerts
I firmly believe any good IoT device should have an equally good API. Unfortunately, Ring doorbells have no public API. Luckily, it only took a quick GitHub search to find this project from @davglass who had reverse-engineered the API and published a super easy npm package to access it. The project lives here if interested.
Since there is no way to trigger directly to an event like a doorbell press, I need to poll the ring.com API for events. Azure Functions timer triggers are a great fit for these kind of custom polling triggers. I wrote this simple cron expression so my function will check for rings every 15 seconds: */15 * * * * *
. I poll for new events (either a ‘ring’ or a ‘motion’ event). If the doorbell has sent an event, the function logic executes. If not, the function completes.
Routing ring events to interested subscribers
Once I detect a motion or ring event has occurred, I want to take some action. Maybe I want to create a log in a Cosmos DB database, or make my WiFi connected lightbulb flash. I don’t know when I’m authoring the trigger function what interested entities may exist. This type of event routing and “publish/subscribe” was a nice fit for Event Grid. By forwarding my ring.com events to Event Grid via Azure Functions, I can now add and remove reactive components as needed. A logic app here, a function there — anything that exposes a secure URL. Even my raspberry pi inside my local network can participate by leveraging an Event Hub subscriber to these events.
I followed this tutorial to create an Event Grid and grabbed the endpoint URL and key.
Adding the integration to Event Grid to my function is as easy as adding an outgoing HTTPS request. I POST
the event data in an “event envelope” to the event grid endpoint, and the event is instantly routed (seriously, like no latency). The top-level event envelope allows me to set the right context so my subscribers can listen only to the events or sources they care about — like “filter to only ‘ring’ events from the front door”:
{
"id": "b82a912c-0b8a-4b89-9ec4-2a98f638e3cb",
"eventType": "motion | ring",
"subject": "ring/frontDoor",
"eventTime": "2017-12-20T07:52:21.263Z",
"data": {
// Data from ring.com API
}
}
Event Grid allows for decoupling of the event source and the event actions. This triggering function I wrote doesn’t need any knowledge of what may be listening, and listeners can be added or removed independently.
Here’s the javascript code I added to my function to push data to Event Grid:
Responding to events
Now that the events are pushed to the Event Grid, I can start building the subscribers. Some of the two easiest tools for this are Azure Logic Apps (connecting my doorbell to over 200 connectors) and Azure Functions. In part 2 of this post, I will go into details of creating serverless components to listen to events and react with elements like adding documents to Cosmos DB. If time permits this week, I’m hoping to add some nice Cognitive Service integration to bring my doorbell to the next level of awesomeness 😎.