Alternatives

Here are some objective comparisons between the Opsdroid Home Assistant bridge and other similar projects.

AppDaemon

AppDaemon is a well established Python framework for creating Home Assistant automations.

You write your automations as generic Python classes and then configure them using YAML files. Your Python code needs to use a callback model where you define methods in your class which perform the actions you want to happen and then in an initialize method you register your callbacks with methods like run_at, run_daily or listen_state.

Opsdroid uses asyncio to handle concurrency. Automations are also defined as methods on a class but you use decorators like match_hass_state_changed, match_crontab, match_webhook, etc to define when your functions should be called.

The differences in the way they handle concurrency is most noticeable when setting up timelines. In AppDaemon you must register a series of callbacks at the specified times which can result in a complex chain of callbacks.

import appdaemon.plugins.hass.hassapi as hass

class MotionLights(hass.Hass):

    def initialize(self):
        self.listen_state(self.motion, "binary_sensor.drive", new="on")

    def motion(self, entity, attribute, old, new, kwargs):
        if self.sun_down():
            self.turn_on("light.drive")
            self.run_in(self.light_off, 60)
            self.flashcount = 0
            self.run_in(self.flash_warning, 1)

    def light_off(self, kwargs):
        self.turn_off("light.drive")

    def flash_warning(self, kwargs):
        self.toggle("light.living_room")
        self.flashcount += 1
        if self.flashcount < 10:
            self.run_in(self.flash_warning, 1)

In the above example we are registering our motion method to be called when a motion sensor changes state to on. We then turn on a light and register a callback to turn it off again in 60 seconds. Then in the mean time we register a recursive callback which toggles another light 10 times over 10 seconds.

In opsdroid we would define something like this.

from asyncio import sleep
from opsdroid_homeassistant import HassSkill, match_hass_state_changed


class MotionLights(HassSkill):

    @match_hass_state_changed("binary_sensor.drive", state="on")
    async def motion_lights(self, event):
        if await self.sun_down():
            await self.turn_on("light.drive")
            for _ in range(10):
                await self.toggle("light.living_room")
                await sleep(1)
            await sleep(50)  # Because 10 seconds have already elapsed
            await self.turn_off("light.drive")

Here we can see we just have one method which contains all of our logic. The flow is laid out in order of what we want to happen, we perform an action, then sleep the amount of time we want to wait, then perform the next action. This makes our automation much more readable. As we are using asyncio we are able to run this concurrently with other skills thanks to the async/await syntax. A downside to this approach is that each sleep needs to be a time delta, if we want our drive light to turn off after 60 seconds we need to keep track of how long we’ve slept since turning it on.

Reasons to choose AppDaemon

  • Stability and maturity, AppDaemon is at version 3

  • Tight integration, AppDaemon has many more Home Assistant helper functions

  • Community, AppDaemon is a Home Assistant community project

  • Doesn’t use asyncio, which has a small learning curve

  • You want to use the built in HADashboard dashboards

Reasons to choose Opsdroid

  • More readable automation code

  • You’re building a chatbot and want to use the AI and NLP capabilities of Opsdroid

  • You want to natively trigger automations on external events like cron timings or webhooks