Making Home-Assistant Distributed, Modular State Machine Part 1

Minimalistic Example of Home-Assistant Distributed

Why Make Home-Assistant Distributed

Home-Assistant is one of the largest open-source projects on GitHub, integrating with almost every IoT device, mesh protocol, internet platform, and more; it is highly extensible at its core, and easily configured. However, once your system reaches a certain size, many of its limitations become apparent – I believe making Home-Assistant distributed will resolve many of these limitations.

The biggest and most annoying limitation is the inability to change almost any of the configurations without restarting the system. This is compounded when your Z-Wave or Zigbee controller is Home-Assistant, causing the mesh network to be re-initialized because you added a new component or new input-slider for automations. Anecdotally, I have noticed the integrations that require polling to update states to slow as the number of services needed to update states increases, i.e. hundreds of devices on multitudes of platforms.

Separation of concerns is one engineering principle that facilitates maintainability. Home-Assistant has two protocols that facilitate multiple instance communication: web-sockets and MQTT. MQTT, Message Queuing Transport Telemetry, is a lightweight pub/subsystem used by many IoT devices and platforms. While Home-Assistant includes an MQTT Auto-Discovery component that requires a decent amount of upfront planning and it is not the easiest to work with. Home-Assistant’s web-socket api is well documented moreover is fairly easy to work with, especially given this custom component by Lukas Hetzenecker:

The delineation between modules is kind of up to you; I decided to run the following instances:

  • Hubs – Z-Wave, Zigbee, and Insteon
  • Media – Televisions, set-top boxes, and receivers
  • Tracker – LAN-based presence detection, zones, and GPS tracking
  • Security – Security cameras, and alarm control panels
  • Communications – Notifiers, text-to-speak, and voice assistant intents
  • Appliances – Vacuums, litter box, and smart furniture
  • Planning – Shopping lists, calendars, and To-Do lists
  • Settings – Inputs for controlling, and configuring rules
  • AI – Image processing, face detection, and license plate recognition
  • Environmental – Weather, air quality, and neighborhood news
  • Main – Primary UI, people, and history recording

The main instance implements the Home-Assistant Remote Instance custom component configured to connect to the IP and port of all of the slave instances. If you haven’t moved your automation/rules out of Home-Assistant’s YAML-based automation components, this is the time to investigate Node-Red or AppDaemon; Home-Assistant is an amazing aggregation of hundreds of integrations, but it’s a state machine, and following good engineering principles dictates atomic purpose. Following the philosophy of atomic purpose means everything handles one, and only one, purpose very well. YAML-based automations, while probably decent enough for most end-users, cannot compete with writing real applications around your state machine and break the atomic purpose philosophy (combining the state machine with the rules engine).

You have several options for deploying a Home-Assistant distributed state machine: install them side-by-side, configured each on different ports; on the same box using Python Virtual Environments; Docker Compose, which allows you to describe all of the containers that make up the application; or a configuration management system, like Ansible or Salt Stack, to deploy however you wish (Docker containers, separate virtual machines, etc).

As of this post, I have started splitting up the configurations (see repositories below) and am waiting for a good time to unpair all of my Z-Wave and Zigbee devices from the controller – my family has grown quite used to the automations so this needs to happen when everyone is out or asleep. We currently use MaaS to provision our virtual machines; my current plan is to spin up an instance for AI, as it is fairly process-intensive, and either: one for the remaining slaves and one for main, or run the rest on one instance (will try both to see if there are any performance issues running so many instances on one box). Each instance will be deployed as a Docker container via Ansible playbooks. All code related to my Home-Assistant Distributed State-Machine will be hosted on GitHub: