Home automation using Python, Flask & Celery

This is first in a series of community posts where we invite users to share how they are using resin. It could be anything from a useful snippet to a fully fledged product they are building as long as it benefits and inspires the community.

Kicking things off we have Dražen Lučanin from CloudFleet, a startup building an open source personal data center for plug-and-play encrypted email. They are currently running a crowdfunding campaign, so be sure to check them out if you're interested in having your own cloud that protects your privacy! In his post he details how to schedule chromecast control from a resin.io device. Enjoy!

We are all a bit lazy in this post-holiday period, so what better project to work on during these relaxed evenings at home, but on a home automation system. Having Docker containers on a physical device that has access to all other IoT devices in our network with exposed APIs like TVs, speakers or maybe even droids and being able to iteratively upgrade these containers gives us ample opportunity to play.

I love the elegance of resin.io's Docker container deployment & upgrade method, so I use it a lot for hobby projects & freelance work. In this tutorial, I'll show you how to create a Python Flask app with periodic Celery tasks for controlling your TV via the Chromecast API. All of the source code can be found in this repo. So, go get a hot cup of tea, clone the repo and let's get started...

image of pi + chromecast

I listed instructions for how to get the development environment running locally directly on your machine or using Docker-machine in the README. Deployment is as easy as setting up a new application by following the Resin.io getting started documentation, setting the remote for your app (something like username@git.resin.io:username/homeautomator.git)
and doing a:

git push resin master

This should be enough to get an app running on your ARM device ready that plays a video at 9:00, stops it at 9:20 and exposes a basic web app for triggering play/pause events using web requests. These web requests can even be sent remotely from outside your LAN by exposing the public url for your Resin device to the internet if you want to surprise the folks at home.

The core of the app lives in src/main.py where we bootstrap the Flask and Celery settings. The interesting part is where we define the times when the tasks are automatically called:

from celery.schedules import crontab  
app.config['CELERYBEAT_SCHEDULE'] = {  
    'play-every-morning': {
        'task': 'tasks.play_task',
        'schedule': crontab(hour=9, minute=0)
    },
    'pause-later': {
        'task': 'tasks.pause_task',
        'schedule': crontab(hour=9, minute=10)
    }
}

Different rules for days of the week (work days), periods (from 9 am - 5 pm) or intervals (e.g. every 5 minutes) can be used to trigger job calls using the Celery periodic task syntax. The tasks are defined as:

@celery.task(name='tasks.play_task')
def play_task():  
    print('play something')
    return play()

@celery.task(name='tasks.pause_task')
def pause_task():  
    print('enough fun')
    return pause()

In this case, they just reach out to the tv.play and tv.pause functions I defined to play or pause a video using the pychromecast Chromecast API wrapper.

The same tasks are also exposed as Flask routes. The delay() method makes sure the task is executed in the Celery worker project asynchronously without blocking the return values.

@app.route('/play')
def get_play():  
    play_task.delay()
    return 'Playing! <a href="/">back</a>'

In the end, both the web and the worker process are started from a Procfile using Honcho (a Python alternative to Ruby's foreman). Redis is used as the Celery message queue.

redis: redis-server  
web: ./venv/bin/gunicorn main:app -b 0.0.0.0:5000 --chdir=src --log-level info --access-logfile=- --error-logfile=-  
worker: ./venv/bin/celery worker -A main.celery --loglevel=info --workdir=src -B  

And that's it. With basically two Python files and a couple of configuration files (for Docker, Honcho), we get an app that we can deploy to as many devices as we want, has an API that we can expose via the Internet and has a task queue supporting periodic tasks. The API functions I showed here are very basic.

I hope you'll let your imagination run wild on this one and pull together some neat APIs your devices at home expose to do cool stuff.

If you have any questions you can ping me(@metakermit) in the resin community forum.

If you’re interested in sharing your resin experience with the rest of the community, say hi to craig - craig[at]resin.io

comments powered by Disqus
Terms of Service | Privacy Statement | Master agreement | Copyright 2019 Balena | All Rights Reserved