Files
.github
.themes
_deploy
credits_generator
plugins
sass
source
_addons
_components
_cookbook
_docs
_includes
_layouts
_posts
addons
assets
blog
components
cookbook
demo
developers
add_new_platform.markdown
api.markdown
architecture.markdown
architecture_components.markdown
asyncio.markdown
asyncio_101.markdown
asyncio_categorizing_functions.markdown
asyncio_misc.markdown
asyncio_working_with_async.markdown
cla.markdown
cla_sign.html
cla_sign_start.html
code_of_conduct.markdown
code_review_component.markdown
code_review_platform.markdown
component_deps_and_reqs.markdown
component_discovery.markdown
component_events.markdown
component_generic_discovery.markdown
component_loading.markdown
component_states.markdown
component_visibility.markdown
creating_components.markdown
credits.markdown
development.markdown
development_101.markdown
development_catching_up.markdown
development_checklist.markdown
development_config.markdown
development_environment.markdown
development_events.markdown
development_guidelines.markdown
development_hass_object.markdown
development_services.markdown
development_states.markdown
development_submitting.markdown
development_testing.markdown
development_validation.markdown
frontend.markdown
frontend_add_card.markdown
frontend_add_more_info.markdown
frontend_creating_custom_panels.markdown
frontend_creating_custom_ui.markdown
helpers.markdown
index.markdown
license.markdown
maintenance.markdown
multiple_instances.markdown
platform_example_light.markdown
platform_example_sensor.markdown
python_api.markdown
releasing.markdown
rest_api.markdown
server_sent_events.markdown
website.markdown
websocket_api.markdown
docs
font
getting-started
hassio
help
images
javascripts
static
CNAME
atom.xml
favicon.png
googlef4f3693c209fe788.html
index.html
robots.txt
service_worker.js
version.json
.editorconfig
.gitattributes
.gitignore
.gitmodules
.powrc
.ruby-version
.slugignore
.travis.yml
CLA.md
CODE_OF_CONDUCT.md
Gemfile
Gemfile.lock
LICENSE.md
README.markdown
Rakefile
_config.yml
config.rb
config.ru
home-assistant.io/source/developers/asyncio_working_with_async.markdown
2017-03-02 08:43:34 -08:00

5.0 KiB
Raw Blame History

layout, title, description, date, sidebar, comments, sharing, footer
layout title description date sidebar comments sharing footer
page Working with Async A breakdown of all the different ways to work with the asynchronous core of Home Assistant. 2016-10-17 21:49 true false true true

Although we have a backwards compatible API, using the async core directly will be a lot faster. Most core components have already been rewritten to leverage the async core. This includes the EntityComponent helper (foundation of light, switch, etc), scripts, groups and automation.

{% linkable_title Interacting with the core %}

All methods in the Home Assistant core are implemented in two flavors: an async version and a version to be called from other threads. The versions for other are merely wrappers that call the async version in a threadsafe manner using the available async utilities.

So if you are making calls to the core (the hass object) from within a callback or coroutine, use the methods that start with async_. If you need to call an async_ function that is a coroutine, your task must also be a coroutine.

{% linkable_title Implementing an async component %}

To make a component async, implement an async_setup.

def setup(hass, config):
    # Setup your component outside of the event loop.

Will turn into:

import asyncio

@asyncio.coroutine
def async_setup(hass, config):
    # Setup your component inside of the event loop.

{% linkable_title Implementing an async platform %}

For platforms we support async setup. Instead of setup_platform you need to have a coroutine async_setup_platform.

setup_platform(hass, config, add_entities, discovery_info=None):
    # Setup your platform outside of the event loop.

Will turn into:

import asyncio

@asyncio.coroutine
def async_setup_platform(hass, config, async_add_entities,
                         discovery_info=None):
    # Setup your platform inside of the event loop

The only difference with the original parameters is that the add_entities function has been replaced by the async friendly callback async_add_entities.

{% linkable_title Implementing an async entity %}

You can make your entity async friendly by converting your update method to be async. This requires the dependency of your entities to also be async friendly!

class MyEntity(Entity):
    def update(self):
        """Retrieve latest state."""
        self._state = fetch_state()

Will turn into:

import asyncio

class MyEntity(Entity):
    @asyncio.coroutine
    def async_update(self):
        """Retrieve latest state."""
        self._state = yield from async_fetch_state()

Make sure that all properties defined on your entity do not result in I/O being done. All data has to be fetched inside the update method and cached on the entity. This is because these properties are read from within the event loop and thus doing I/O will result in the core of Home Assistant waiting until your I/O is done.

{% linkable_title Calling async functions from threads %}

Sometimes it will happen that youre in a thread and you want to call a function that is only available as async. Home Assistant includes a few async helper utilities to help with this.

In the following example, say_hello will schedule async_say_hello and block till the function has run and get the result back.

from homeassistant.util.async import run_callback_threadsafe

def say_hello(hass, target):
    return run_callback_threadsafe(
        hass.loop, async_say_hello, target).result()

def async_say_hello(hass, target):
    return "Hello {}!".format(target)

{% linkable_title Dealing with passed in functions %}

If your code takes in functions from other code, you will not know which category the function belongs to and how they should be invoked. This usually only occurs if your code supplies an event helper like mqtt.async_subscribe or track_state_change_listener.

To help with this, there are two helper methods on the hass object that you can call from inside the event loop:

{% linkable_title hass.async_run_job %}

Use this method if the function should be called as soon as possible. This will call callbacks immediately, schedule coroutines for execution on the event loop and schedule other functions to be run inside the thread pool.

| Callback | Call immediately. | Coroutine | Schedule for execution on the event loop. | Other functions | Schedule for execution in the thread pool.

{% linkable_title hass.async_add_job %}

Use this method if the function should be called but not get priority over already scheduled calls.

| Callback | Schedule for execution on the event loop. | Coroutine | Schedule for execution on the event loop. | Other functions | Schedule for execution in the thread pool.

Next step: Miscellaneous »