Photo by Daniel von Appen on Unsplash

My Prefect Home

Controlling my home’s Internet of Things devices using Prefect and External APIs

Jenny Grange
Published in
6 min readNov 22, 2019

--

At Prefect we deeply value user-empathy and we are proud that Prefect runs on Prefect. To foster user-empathy early on, whenever a new member joins our team, we task them with writing and deploying their own Prefect flow. As a new member back in a sweltering NYC August, I was very concerned about making sure my air conditioner was working effectively so I decided to use my flow to make a smart AC.

I wanted to make sure my apartment was cool but not waste electricity by running the AC when I’m not home. Using a simple schedule or timer wasn’t helpful as that could waste electricity on colder days and anything that involved me remembering to hit a button or activate something from my phone was at risk of being forgotten. I settled for an option that let me check the weather forecast and decide if my AC should be on or not based on the forecasted temperature. The different API calls I needed to make were tasks that created a simple flow which Prefect could schedule and monitor for me. This post talks through the steps I took.

Writing a Flow

Before going any further I should explain that I’m a Frontend Engineer at Prefect and my main language is JavaScript. I had a lot of fun building this flow and it was a great way to learn some more Python but I apologize to any Pythonistas for my JavaScript camel-casing!

Using Prefect, I could break my code down into tasks then pull it all together into a flow at the end. The @task you see at the top of each of my functions is a decorator that tells Prefect these are tasks I may want to include in my flow.

Tasks

I’m a big fan of the Dark Sky app, which provides hyper local weather information, and was happy to see they had an API I could tap into to get really accurate weather forecasts for my apartment. The first task in my flow was to request the weather forecast for the next hour for the latitude and longitude of my apartment. This is my code for that:

The first task in my flow: retrieve the forecasted temperature for my apartment

Next up, I needed to access the API link for the Kasa/TP-Link smart plug, which controlled my AC. This one was a little more complicated. The first step was to get a token to enable access to the Kasa/TP-Link API:

A task for retrieving a Kasa/TP-Link token

Then, I needed to get my device’s id:

A task for retrieving for my device ID

The next step for turning the AC on and off was to send a request to turn the AC plug on or off. Here the device state would be “1” to turn it on and “0” to turn it off.

Turn the AC on / off based on the inputted deviceState

The final step was to use the temperature we got back at the beginning and use that and a target temperature to decide if we want to turn the AC on or off:

Task for determining what the deviceState should be set to

Keeping Secrets

Of course, I need somewhere to keep and access my sensitive information like usernames and API keys. (kUser and kSecret in my code.) . Prefect provides a secure secret storage solution that I can use to save my sensitive information, and I could also choose to subclass this task and connect to my own secret provider if I wanted to.

Initialize my secret tasks which represent secure information in Prefect

Setting a Schedule

To automate the checking process, Prefect lets me set a schedule for the flow to run. I used a simple schedule that ran the flow every hour but there are much more sophisticated scheduling options if you want them.

A simple hourly interval schedule

Running My Flow

Once I had created all the relevant tasks, I could build my flow. Note that none of my code is actually executed here; instead, Prefect builds up the dependency graph for my tasks that will be executed on my provided simple-schedule:

Put all the pieces together into a Prefect Flow

90 is the target temperature I decided on and 40.7885 and -73.9857 are the latitude and longitude of the Empire State Building (though I actually used the latitude and longitude of my apartment).

With the flow written, I have a few options to run it. The first is a simple flow.run()which would run my code using Prefect Core.

The next, since I’m lucky to have a free Prefect Scheduler account (join the wait list!), was to deploy my flow using Prefect Cloud and Docker. Using Scheduler gives me access to the UI so I can easily pause or start the flow’s schedule, and check all the details of my flow and flow-runs.

In order to deploy to Prefect Scheduler I need to provide some extra instructions:

My Prefect Docker configuration for this Flow

Note: registry_url is my personal Docker Hub registry and image_name and image_tag identify my flow in Docker.

I also needed to set up my account and agent following the instructions and tutorial built into our UI.

Screenshot of an interactive Cloud UI tutorial

Then I could deploy my “setAC” flow to my “Temp” project (which I created in the UI) by including this line at the bottom of my code:

flow.deploy(project_name="Temp")

..and run my flow from the CLI by entering:

prefect run cloud -n setAC -p "Temp"

“setAC” is the name I gave to my flow above and “Temp” is the name of the project I want it to run in.

Setting up the flow using docker can take a while as it needs to load all my dependencies. A much simpler version, universal deploy, will be available soon. That allows me to use my local dependencies and basically skip the storage=Docker… step by running:

prefect agent start local -t TOKEN -l setAC

followed by

prefect run cloud -n setAC -p "Temp"

Again, “setAC” is the name of my flow, “Temp” is the name of my project and TOKEN would be a tenant token, which I retrieved from the team settings section of the UI.

Why Prefect?

I can imagine people reading this post and thinking “Ok, nice idea but why do you need Prefect to do that, couldn’t you just run the code?” The simple answer is, yes I could. And if the code worked, all would be well.

But if there were a problem, I don’t have an easy way to see that problem until I come back to a sweltering (or freezing) apartment. I could code my own notifications but that potentially wouldn’t give me the details I need and/or would take extra code and extra work. At Prefect, we call that extra code “negative engineering” and our aim is to eliminate it. By using Prefect Scheduler, I can easily check that every scheduled flow has run. I can check that the flow was successful and, if not, I can see the details and could try re-starting my flow from one of the failed tasks.

Screenshot of the Task Run page from the Prefect Cloud UI

The few extra lines that it takes to add the Prefect flow wrapper to my code give me far more monitoring and reassurance than I could build on my own. It also makes it easy for me to scale that monitoring and code-insurance if, in the future, I want to add extra features to my Prefect Home.

--

--