Home Assistant OS Deep Dive
I have been running Home Assistant continuously since the days when it was called hass.io and shipped as a single-board computer image with a handful of supported devices. That was before the Supervisor existed, before Z-Wave JS rewrote the book on Z-Wave reliability, and long before anyone thought a $20 ESP32 could serve as a local voice satellite. The platform has matured into something genuinely impressive — and genuinely complex. This post is the guide I wish existed when I started: a thorough, honest walkthrough of every major subsystem, covering what works well, what will bite you, and how to make deliberate architectural decisions rather than stumbling into a configuration you can never untangle.
We are running 2026.5 of Home Assistant Core and Home Assistant OS 17.3. Most of what is written here applies to the entire 2026.x generation, with notes where things differ.
Deployment Options: Choosing Your Installation Method
The Home Assistant project ships four distinct installation methods, and the choice you make on day one has ramifications you will live with for years. There is no migration path that is painless.
Home Assistant OS (HAOS) is the recommended path and the one this post focuses on. It is a purpose-built, minimal Linux operating system maintained by the HA team. You flash it to a microSD card, NVMe drive, or VM disk image, and it boots into a fully managed environment. The Supervisor — a privileged container that acts as a system orchestrator — handles updates to the OS, the core HA container, individual add-on containers, and the host kernel. You never touch a package manager. You never systemctl restart anything. The tradeoff is that you own only the HA layer; the OS layer is opaque by design.
Home Assistant Container strips everything down to a single Docker image. You run it with docker run or in a compose.yml alongside whatever other containers you want. There is no Supervisor, which means there are no add-ons. Every service that would be an add-on under HAOS — Mosquitto, Zigbee2MQTT, Whisper, InfluxDB — becomes a separate container that you manage, update, and configure yourself. You get maximum control and zero hand-holding. This is a reasonable choice if you are already running a Docker host for other services and want HA to live alongside them.
Home Assistant Core is a bare Python virtual environment installation. No Docker, no Supervisor, no add-ons. You install it with pip, manage a venv, and write every integration to disk by hand. This is the domain of people who want to contribute to HA development or who are integrating HA into a larger system they control at the OS level. Avoid this path unless you have a specific reason for it.
Home Assistant Supervised occupies a genuinely awkward middle ground. It installs the Supervisor on an existing Debian system, giving you add-ons while keeping the underlying OS under your control. It sounds like the best of both worlds. In practice it is the worst. The Supervisor performs a continuous health check of the host environment and will mark your installation as “unhealthy” or “unsupported” the moment anything deviates from its expected configuration — a custom kernel module, a non-standard network interface name, a package that modified a system library. The HA team officially supports only one OS (Debian) for Supervised, and even then, they reserve the right to drop support or change requirements. Unless you have a compelling reason to own the host OS and also want add-ons, skip Supervised. Run HAOS in a VM instead and pass through the hardware you need.
Hardware Recommendations
The hardware question comes up in every HA forum thread, and the answer has changed meaningfully as the platform has grown. The Raspberry Pi 4 was the de facto recommendation for several years. It is still usable for a minimal installation, but the moment you add Whisper, InfluxDB, and a few active add-ons, you will feel it. The SD card is also a legitimate failure point — use a USB-attached SSD or NVMe via a USB 3.0 adapter, not a microSD card, for your primary storage.
The Raspberry Pi 5 with 8GB RAM and an NVMe HAT is the current sweet spot for a dedicated HA box. The CPU is meaningfully faster, the memory bandwidth is better, and booting from NVMe eliminates the storage reliability problem. Expect $80–$120 in total hardware cost.
An Intel N100 mini-PC (often sold as the Beelink EQ12, GMKtec NucBox, or similar) is what I have been running for the past two years. The N100 is a quad-core Alder Lake-N chip that draws 6–12 watts at idle, boots HAOS from NVMe, handles Whisper small model inference in real time, and still has headroom for Grafana, InfluxDB, and whatever else you throw at it. These units sell for $100–$180, and the performance-per-watt case is excellent. If you are building a full home automation stack with voice, logging, and multiple add-ons, buy an N100 box.
Running HAOS inside a Proxmox VM is also a solid choice. You get snapshots, live migration if you have multiple Proxmox nodes, and the ability to run other VMs on the same hardware. The main complexity is device passthrough: if you are using a USB Zigbee coordinator or Z-Wave stick, you need to pass it through to the VM. This works reliably, but the USB path inside the VM may differ from the host. Always reference the coordinator by its stable /dev/serial/by-id/ path rather than /dev/ttyUSB0, which changes whenever you replug the device or the kernel assigns a different device number. An alternative is to use a network-attached coordinator like the Nabu Casa SkyConnect via its IP-based serial proxy, which sidesteps the passthrough issue entirely.
Update Cadence
HAOS uses a calendar versioning scheme: 2026.5 means the fifth monthly release of 2026, and it shipped on the first Wednesday of May. Patch releases follow as 2026.5.1, 2026.5.2, and so on. The OS layer (currently 17.3) and the Supervisor version number update independently. You will see three version numbers in your System settings: Core, Supervisor, and OS. Core is the number most people refer to when they say “I’m running 2026.5.”
The update cadence is aggressive. Monthly major releases mean something changes every single month, and occasionally those changes are breaking for specific integrations or automations. The release notes are thorough and worth reading before updating a production instance. If stability matters more than features, staying one or two minor versions behind is a reasonable policy.
The Supervisor and Add-on Ecosystem
The Supervisor is a privileged Docker container running alongside the HA Core container. It watches the health of the system, manages add-on container lifecycles (start, stop, update, restart on failure), handles backup creation, and provides the infrastructure for the UI-based management experience. When you click “Install” on an add-on, the Supervisor pulls a Docker image, creates a container with the appropriate mounts and network settings, and starts it. When you click “Update,” it pulls the new image, stops the old container, and starts the new one. You never write a compose.yml for this.
Add-on Stores
There are three tiers of add-ons.
The official add-on repository is maintained by the HA team and ships a curated set of high-value add-ons: Mosquitto MQTT broker, File Editor, SSH and Web Terminal, Let’s Encrypt, DuckDNS, and the Samba share add-on. These are well-tested and supported.
The community add-on repository by Franck Nijhof (frenck) is a separately maintained repo that ships a larger set of high-quality add-ons: Studio Code Server, Portainer, Grafana, InfluxDB, WireGuard, and many others. Add it via Settings > Add-ons > Add-on Store > three-dot menu > Repositories.
Third-party repositories are added the same way using a GitHub URL. The Zigbee2MQTT add-on, Z-Wave JS UI, Whisper, Piper, and openWakeWord all ship through third-party repos, though several are now available through the official store or community store directly.
HACS (Home Assistant Community Store) deserves its own paragraph. HACS is not an add-on store — it is a frontend integration that gives you access to custom integrations, Lovelace frontend cards and themes, Python scripts, and AppDaemon apps maintained by the community. Installing HACS requires running a one-line script via the SSH add-on or the Terminal add-on, then restarting HA and completing the GitHub OAuth flow. Once installed, HACS appears as a sidebar item and provides a searchable catalog of hundreds of community components. A significant fraction of active HA installations use HACS. It is unofficial, it is not endorsed by the HA team, and it is nearly universal. Be aware that HACS components are not subject to the quality or security review that official integrations receive, and a HACS component can break during a HA core update because it is not coordinating with the core release cycle.
The Add-on Architecture
+----------------------------------------------------------+
| Host OS (HAOS 17.x) |
| |
| +------------------+ +--------------------------+ |
| | Supervisor | | Home Assistant Core | |
| | (orchestrator) |<->| (Python, integrations) | |
| +------------------+ +--------------------------+ |
| | |
| | manages |
| v |
| +----------+ +----------+ +----------+ +--------+ |
| | Mosquitto| |Zigbee2MQTT| | Whisper | | Z-Wave | |
| | (add-on) | | (add-on) | | (add-on) | | JS UI | |
| +----------+ +----------+ +----------+ +--------+ |
| +----------+ +----------+ +----------+ |
| | InfluxDB | | Grafana | | Piper | |
| | (add-on) | | (add-on) | | (add-on) | |
| +----------+ +----------+ +----------+ |
| |
| Shared /config volume Shared /data volume |
+----------------------------------------------------------+
Each add-on is an isolated container. They communicate with HA Core via the Supervisor API, the internal MQTT broker, or direct HTTP/WebSocket connections. Most add-ons can be configured through the UI, but the underlying config files live in the /config directory that is also where your configuration.yaml lives.
Resource Reality Check
Adding up an N100 recommendation is not idle advice. Whisper small model inference runs about 2–4 GB RAM and keeps one or two CPU cores busy during transcription. InfluxDB with a year of sensor data sits at 300–500 MB RAM. Grafana adds another 200 MB. Zigbee2MQTT is lightweight. The HA Core process itself needs 400–800 MB depending on how many integrations you have loaded. On a Pi 4 with 4 GB RAM, running the full stack leaves you with margins too thin for comfort. On an N100 with 16 GB RAM, it is relaxed.
Core Concepts: Entities, Devices, Areas, and the State Machine
Before diving into automations and specific protocols, it is worth spending time on HA’s data model, because misunderstanding it leads to confusion that persists for months.
An entity is the fundamental unit of Home Assistant. Every piece of state that HA knows about is an entity: sensor.living_room_temperature, light.kitchen_ceiling, binary_sensor.front_door_contact, switch.dehumidifier. Each entity has a unique entity_id, a state (a string: on, off, 23.4, home, unavailable), and a set of attributes (a dictionary: brightness, color_temp, unit_of_measurement). The entity’s state and attributes are stored in memory and updated in real time.
A device is a grouping concept. A Zigbee temperature sensor might expose three entities: sensor.bedroom_sensor_temperature, sensor.bedroom_sensor_humidity, and sensor.bedroom_sensor_battery. All three are grouped under one device entry in HA’s device registry. The device entry holds metadata about the physical thing: manufacturer, model, firmware version, hardware identifiers. Devices matter for UI organization and for voice commands — “Hey Home Assistant, what’s the humidity in the bedroom?” resolves against the device’s area assignment.
Areas are rooms or zones you define. You assign devices to areas. Areas power voice commands, dashboard organization, and service calls: service: light.turn_off, target: area_id: living_room turns off every light entity in the living room.
The state machine is the engine underneath everything. Every entity state change is an event — state_changed — that fires on the event bus. Automations listen to this event bus. The history integration records state changes to the database. The logbook shows a human-readable record of state changes. Developer Tools > States lets you inspect every entity’s current state and attributes in real time and manually set states for testing. This is an essential debugging tool that most new users discover too late.
configuration.yaml is the master configuration file. Modern HA has moved aggressively toward UI-managed configuration: integrations, automations, scripts, scenes, helpers, and the energy dashboard are all manageable through the UI and stored in the .storage/ directory. But configuration.yaml still matters for things the UI cannot express: manual MQTT sensors, template sensors, custom command line sensors, input_boolean/input_number helpers defined in YAML (though the UI can do these now too), and advanced logger configuration. Keep it as minimal as possible; use UI configuration where available.
secrets.yaml lives in the same /config directory. It is a simple key-value file:
|
|
Reference secrets from configuration.yaml with !secret key_name. This keeps credentials out of your main config and out of screenshots you share on forums.
Automations and Blueprints
Automations are the reason most people run Home Assistant. The platform’s automation engine is powerful, nuanced, and occasionally maddening. Understanding its structure before you start clicking in the UI will save you from building a pile of brittle automations that you cannot reason about six months later.
Every automation has the same skeleton:
|
|
The mode field controls what happens if the automation is triggered while it is already running. single (default) ignores subsequent triggers. restart aborts the current run and starts fresh. queued queues them up. parallel runs them concurrently. Getting mode wrong is a common source of subtle bugs, especially in automations with delays.
Triggers
Triggers are what starts an automation. The most common trigger is state:
|
|
You can also trigger on time, numeric state thresholds, sun position, MQTT messages, webhooks, zone entry/exit (GPS from the mobile app), templates that evaluate to true, and calendar events. Multiple triggers are OR’d together — the automation fires if any one of them occurs. Use trigger_id to distinguish which trigger fired inside the action block.
The for: key on a state trigger adds a duration requirement:
|
|
This fires only if the garage door has been open continuously for 10 minutes — invaluable for “you left X open” notifications.
Conditions
Conditions gate the action. They all evaluate synchronously when the trigger fires. If any condition fails, the automation stops.
|
|
Template conditions give you arbitrary logic:
|
|
Actions
Actions are a sequence of steps executed in order. Key action types:
service(call a Home Assistant service)delaywait_template(pause until a template becomes true, with optional timeout)choose(if/then/else branching)repeat(loop with count or while condition)parallel(run multiple action sequences concurrently)variables(set local variables for use later in the action sequence)
Realistic Example 1: Motion-Activated Light with Lux Condition
|
|
Realistic Example 2: Dehumidifier Hysteresis Control
This automation implements a hysteresis band to prevent the dehumidifier from short-cycling. It turns on when humidity exceeds 65%, and turns off only when humidity drops to 58% or below. Without hysteresis, an automation that turns on at 65% and off at 64% will cycle the compressor every few minutes.
|
|
Realistic Example 3: Garage Door Left Open Notification
|
|
Scripts and Scenes
A script is a reusable sequence of actions — think of it as a function you call from multiple automations. Define a script once in the UI or in scripts.yaml, then call it from any automation with service: script.your_script_name. Scripts accept variables, which makes them genuinely parameterizable:
|
|
A scene is a snapshot of entity states. Create a scene called “Movie Mode” that sets the living room lights to 15% warm white, turns off the overhead light, and dims the hallway. Activate it from an automation, a dashboard button, or a voice command. Scenes are simpler than scripts but only deal with state, not actions that have side effects.
Blueprints
Blueprints are shareable automation templates. A blueprint defines the automation logic with configurable inputs — you fill in the entity IDs and parameters, and the blueprint generates the automation. The community shares blueprints at blueprints.home-assistant.io. Common examples include motion-activated lights, presence-based heating, and Zigbee button-to-action mappings.
Creating your own blueprint is straightforward: build an automation, export it to YAML, add a blueprint: header with input: definitions, and replace the hardcoded entity IDs with !input reference_name. The UI will present these inputs as form fields when someone imports the blueprint.
The Jinja2 Template Engine
Templates appear in conditions, actions, sensor value calculations, and notification messages. HA uses Jinja2, the same engine as Ansible. Useful patterns:
{# Get a sensor value as a float #}
{{ states('sensor.outdoor_temperature') | float(0) }}
{# Current hour as integer #}
{{ now().hour }}
{# Friendly time since last state change #}
{{ relative_time(states.binary_sensor.front_door.last_changed) }}
{# Conditional string #}
{{ 'open' if is_state('cover.garage', 'open') else 'closed' }}
{# List of lights that are on in the living room area #}
{{ expand(area_entities('living_room'))
| selectattr('domain', 'eq', 'light')
| selectattr('state', 'eq', 'on')
| map(attribute='entity_id')
| list }}
Use Developer Tools > Template to test templates interactively. It updates live as you type, which makes iterating on complex expressions fast.
Zigbee2MQTT
Zigbee is a mesh networking protocol operating at 2.4 GHz designed for low-power IoT devices. It is the most widely supported protocol in the budget-to-midrange smart home device market, with thousands of compatible sensors, bulbs, switches, and actuators from manufacturers including Ikea, Aqara, Sonoff, Philips Hue, and many others.
Home Assistant includes its own Zigbee implementation called ZHA (Zigbee Home Automation). ZHA is a solid choice for getting started — it requires only a USB coordinator and integrates directly into HA without an external MQTT broker. Zigbee2MQTT (Z2M) is the alternative that I and most experienced users prefer, for reasons that become clearer as your network grows.
Why Zigbee2MQTT Over ZHA
Z2M supports a broader device list. The z2m device database at zigbee2mqtt.io currently lists over 4,000 supported devices, and the project adds new definitions continuously. ZHA has a smaller supported list because each device quirk must be written in Python and merged into the zigpy project. Many obscure or newer devices work in Z2M months before a ZHA quirk appears.
More importantly, Z2M exposes everything over MQTT. Every Zigbee device publishes its state to a topic like zigbee2mqtt/device_name, and you can subscribe to that topic from any MQTT client — Node-RED, Python scripts, custom dashboards, or anything else in your infrastructure. This transparency makes debugging straightforward and gives you integration options that do not depend on HA at all. The MQTT raw data is also useful for building custom sensors in HA using the MQTT platform.
Z2M’s homeassistant: true configuration key enables MQTT discovery, which automatically creates HA entities for every paired device. You get the best of both worlds: raw MQTT access plus automatic HA integration.
Hardware Coordinators
The Zigbee coordinator is the USB (or network-attached) device that runs the Zigbee controller. It is not a router node — it is the brain of the network.
| Coordinator | Chip | Notes |
|---|---|---|
| SONOFF Zigbee 3.0 Dongle Plus | CC2652P | Recommended, $15–$20, external antenna |
| SONOFF Dongle-E | EFR32MG21 | Silicon Labs chip, firmware support growing |
| Nabu Casa SkyConnect | MGM210P | USB or PoE, also supports Z-Wave, Thread |
| ConBee II | Atmel | Older, still works, less firmware flexibility |
| HUSBZB-1 | CC2538 | Dual Zigbee+Z-Wave, aging chip |
The CC2652P-based Dongle Plus has been the community standard for several years. It is inexpensive, its firmware is actively maintained by the Koenkk and ptvo communities, and its external antenna gives it better range than stick-style coordinators. The SkyConnect is the Nabu Casa hardware recommendation — it is more expensive but supports multiple protocols and can run as a network-attached coordinator, which is valuable in VM setups.
If you need to update coordinator firmware (occasionally necessary for new features or bug fixes), use cc2538-bsl for CC2652P devices: put the dongle in bootloader mode (hold boot button while plugging in), run the flash command, and you are done in under 60 seconds.
The Zigbee Mesh
Zigbee is a mesh protocol. Devices come in three roles: the coordinator (one per network), routers, and end devices.
[Coordinator]
/ | \
/ | \
[Router 1] [Router 2] [Router 3]
(Ikea bulb) (Sonoff plug)(Aqara hub)
/ | \ | |
/ | \ | |
[Sensor] [Sensor] [Lock] [Sensor] [Sensor]
(batt) (batt) (batt) (batt) (batt)
Routers are mains-powered devices: smart bulbs, smart plugs, in-wall switches. They stay awake, forward messages for other devices, and extend the mesh’s reach. End devices are typically battery-powered: sensors, remote controls, door contacts. They sleep most of the time to save battery and connect to the nearest router or coordinator.
A healthy mesh has multiple routers distributed throughout the space. The most common Zigbee reliability problem is a sensor that repeatedly drops off the network — almost always because it is too far from its nearest router, or because the only router between it and the coordinator is an Ikea bulb that your spouse turned off at the physical wall switch. (Ikea bulbs configured as routers stop routing when they lose power. This is a well-known trap. Always leave smart bulbs powered and use smart switches to control them logically.)
Use /dev/serial/by-id/ to reference your coordinator. The full path looks like /dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_xxxx-if00-port0. This path is stable across reboots and replugs; /dev/ttyUSB0 is not.
Z2M Configuration Essentials
The core of configuration.yaml for Z2M:
|
|
The GENERATE values tell Z2M to create random PAN ID and network key on first start. Store these after generation — if you ever need to rebuild Z2M, you can restore the network by providing the same values.
Enabling permit_join opens a 254-second window during which new devices can join. Set it back to false after pairing. There is a UI toggle in the Z2M frontend and a HA entity (switch.zigbee2mqtt_bridge_permit_join) you can toggle from automations.
Groups and OTA Updates
Zigbee groups allow you to control multiple bulbs simultaneously using a single Zigbee command, with the group command executed in the Zigbee mesh itself rather than routing through HA. This is meaningfully faster and more reliable for synchronous lighting changes — the latency drops from 100–300ms (HA round trip) to under 50ms (direct mesh command).
Configure groups in the Z2M group settings, add bulbs to a group, then use the group’s entity in HA automations.
OTA firmware updates push manufacturer firmware to supported Zigbee devices through Z2M. Aqara, Ikea, Sonoff, and others provide firmware files that Z2M can stage and deliver. The device downloads the firmware over the mesh in chunks — a process that can take 15–45 minutes for a single device, during which it should not be disturbed. Check the Z2M OTA page before manually searching for device firmware updates.
Z-Wave JS
Z-Wave and Zigbee often get discussed together, but they are quite different protocols with different strengths. Z-Wave operates at 868 MHz in Europe and 908 MHz in North America — frequencies that penetrate walls significantly better than 2.4 GHz Zigbee. The lower frequency means lower bandwidth, but Z-Wave devices are not transmitting audio or video; they are sending short state messages. The practical effect is fewer dead zones in a typical home.
Z-Wave also has strict certification requirements. Every Z-Wave device must be certified by the Z-Wave Alliance before it can be sold as Z-Wave compatible. This certification process enforces interoperability standards that do not exist in Zigbee — a Z-Wave lock from one manufacturer will work with a controller from any other manufacturer, and it will expose a standardized set of capabilities. This matters most for locks, garage door controllers, and motorized covers where reliability is non-negotiable.
The downsides are cost and network size. Z-Wave devices cost more — a Z-Wave in-wall switch runs $30–$50, where a comparable Zigbee switch might be $15–$25. Z-Wave networks cap at 232 nodes in classic mode (though Z-Wave Long Range changes this dramatically).
Hardware
| Controller | Notes |
|---|---|
| Z-Wave.Me UZB7 | Gen7 700-series chip, solid Linux support |
| Zooz ZST39 LR | 800-series, supports Z-Wave LR, recommended |
| Nabu Casa SkyConnect | Supports Z-Wave alongside Zigbee and Thread |
| Aeotec Z-Stick 7 | 700-series, reliable, widely available |
The 800-series controllers (Zooz ZST39 LR, Aeotec Z-Stick 800) support Z-Wave Long Range, which extends range up to 1.6 km from the controller, eliminates the routing mesh for LR devices, and supports up to 4,000 nodes on the LR network. Z-Wave LR is ideal for outbuildings, detached garages, and mailbox sensors where mesh routing would require intermediate nodes.
Z-Wave JS UI
Z-Wave JS UI (previously called zwavejs2mqtt) is the add-on that handles Z-Wave in Home Assistant. It provides a full network map showing every node, its neighbors, its security class, and its signal strength. It handles S2 security pairing, OTA firmware updates, and exposes devices to HA via the Z-Wave JS integration.
Security classes matter. The legacy S0 security class encrypts messages but with significant overhead — every message is sent three times, which bloats network traffic and slows devices. S2 Authenticated is the current standard for locks and entry devices. S2 Unauthenticated works for non-security devices. During inclusion, the controller displays a DSK (Device Specific Key) — a 5-digit PIN typically printed on the device or its packaging — that you enter to complete S2 pairing. Do not skip this step for locks.
The inclusion process: open Z-Wave JS UI, click “Add Node,” put the controller in inclusion mode, then put the device in inclusion mode (usually by triple-clicking the button on the device). The controller discovers the device, negotiates security, and interviews it to enumerate its capabilities. Interview sometimes takes 1–3 minutes on first inclusion.
When to Reach for Z-Wave
Use Z-Wave for:
- Light switches and dimmers: Inovelli Red series, GE/Jasco, Leviton. These are mains-powered, double as mesh routers, and Z-Wave certification ensures they work reliably with any controller.
- Locks: Schlage, Yale, Kwikset. Always pair over S2 Authenticated. Never use S0 for locks if avoidable.
- Garage door controllers: GoControl, Zooz ZAC38.
- Anywhere wall penetration is an issue: thick concrete or brick walls that attenuate 2.4 GHz significantly less affect 900 MHz.
Use Zigbee for battery sensors, bulbs, and anything cost-sensitive.
ESPHome
ESPHome is one of the genuinely excellent pieces of the home automation ecosystem. It is a firmware framework for ESP8266 and ESP32 microcontrollers that lets you describe the entire firmware in YAML — hardware pins, connected sensors, WiFi credentials, integration method, OTA update configuration — and it compiles and flashes the device for you. The resulting firmware integrates natively with Home Assistant via an encrypted binary protocol (the native API) that requires no MQTT broker.
The appeal is enormous for DIY hardware. A $5 ESP32 dev board, a $2 BME280 environmental sensor, and an afternoon of work give you a temperature/humidity/pressure sensor that updates every 10 seconds, receives OTA firmware updates, and automatically appears in HA with full entity discovery. Compare this to a commercial Zigbee temperature sensor at $15–$30 with no customization possible.
ESPHome Add-on
The ESPHome add-on provides a web UI for managing your fleet of ESPHome devices. You write the YAML configuration in the editor, click “Install” to compile and OTA-push the firmware, and use the live log view to debug sensor readings. The add-on stores your device configs in /config/esphome/.
Complete BME280 Sensor Configuration
|
|
The !secret references point to a secrets.yaml file in your ESPHome config directory. Keeping credentials out of device configs is essential because device configs are often shared on forums or GitHub.
Native API vs MQTT
ESPHome supports both its native encrypted API and MQTT. For Home Assistant use, the native API is preferred: it is encrypted by default, lower overhead than MQTT, and provides tighter integration including real-time log streaming from the add-on. Use MQTT only if you need the device to integrate with multiple systems simultaneously (HA plus Node-RED plus a custom dashboard, for example).
Common ESPHome Use Cases
The community has created ready-made ESPHome configs for many popular commercial devices. Shelly devices can be reflashed with ESPHome firmware, giving you a locally-controlled, no-cloud switch with full customization. The ESPHome Device Builder at devices.esphome.io catalogs verified configs for dozens of popular ESP-based products.
Beyond sensors: garage door openers (monitor the reed switch, control the relay), CO2 monitors with SenseAir S8 or MH-Z19 sensors, power monitoring with PZEM-004T, IR blasters for controlling dumb AC units and TVs, and retrofitting older appliances with relay switches. If it can run an ESP chip, ESPHome can automate it.
Local Voice Assistants: Whisper and Piper
The local voice stack is the most hardware-demanding and most satisfying part of modern Home Assistant. The goal is simple: a wake word triggers local speech recognition, the spoken command is processed entirely on your hardware, and the response is spoken back — no audio ever leaves your network.
The architecture has four layers:
[Voice Satellite Device]
| (audio stream via Wyoming protocol)
v
[openWakeWord / microWakeWord]
| (wake word detected, forward audio)
v
[Whisper STT Add-on]
| (transcript)
v
[HA Assist Pipeline / NLU]
| (intent: turn_on, entity: living room lights)
v
[Piper TTS Add-on]
| (synthesized audio response)
v
[Voice Satellite Device] <-- plays response
Whisper
Whisper is OpenAI’s open-source speech-to-text model, originally released as a research artifact and subsequently adopted by dozens of projects including the HA Whisper add-on. The add-on runs the model locally and exposes it via the Wyoming protocol.
| Model | RAM (approx) | Relative Speed | Accuracy |
|---|---|---|---|
| tiny | ~400 MB | Fastest | Acceptable for clear speech |
| base | ~650 MB | Fast | Better vocabulary coverage |
| small | ~1.4 GB | Moderate | Good, recommended sweet spot |
| medium | ~3 GB | Slow | Very good |
| large-v3 | ~6 GB | Slow | Near-human accuracy |
On a Raspberry Pi 4, even the tiny model takes 2–4 seconds to transcribe a typical command. The experience feels sluggish. On an N100 mini-PC with 16 GB RAM, the small model transcribes in under a second and the experience is acceptable for daily use. If you are on a Pi 4, start with tiny or base and set expectations accordingly.
The int8 quantized variants of each model run significantly faster at modest accuracy cost, and the Whisper add-on supports them. The small-int8 model is worth trying before committing to base — on an N100 it approaches the speed of tiny with meaningfully better accuracy.
Piper
Piper is a fast neural text-to-speech system designed to run on low-power hardware. It generates speech from text using VITS neural vocoder models and can synthesize audio faster than real-time on a Pi 4. The voice quality is far better than Festival or eSpeak — actual prosody, not robotic monotone.
Piper ships with dozens of voice models covering English regional accents (US, UK, Australian), German, French, Dutch, Spanish, and others. Each model is a few hundred MB. The en_US-lessac-high and en_US-ryan-high voices are popular starting points for English-language installs. The high quality variants sound better but require marginally more compute.
openWakeWord and Hardware Satellites
Wake word detection is the front door. openWakeWord is a lightweight Python-based wake word engine that runs on the HA host or on a satellite device (Pi Zero 2W, Pi 4). It ships with several built-in wake words: “Hey Jarvis,” “OK Nabu,” “Hey Mycroft,” and “Alexa” (for testing). Custom wake words can be trained using the openWakeWord tooling and a set of positive/negative audio examples — the training process is documented and accessible without deep ML expertise.
For satellite devices that run on ESP32-S3 hardware, microWakeWord is the alternative — a lightweight model that runs directly on the ESP32-S3’s neural processing unit, enabling wake word detection without a Pi host.
Satellite hardware options:
| Device | Price (approx) | Notes |
|---|---|---|
| ESP32-S3-BOX-3 | $35 | Pre-built, microphone array, speaker, display |
| M5Stack Atom Echo | $15 | Compact puck, basic mic, small speaker |
| M5Stack ATOM S3R | $20 | Newer, better mic, speaker |
| DIY ESP32-S3 + INMP441 mic | $8–$15 | Maximum customization |
| Raspberry Pi Zero 2W + mic hat | $20–$30 | Runs openWakeWord on Pi, better accuracy |
The ESP32-S3-BOX-3 flashed with the HA voice satellite firmware (via ESPHome) is the fastest path to a working satellite. It auto-discovers via the Wyoming integration and appears in HA within minutes. The Pi Zero 2W running wyoming-satellite + wyoming-openwakeword is more complex to set up but delivers better wake word accuracy because it runs the full openWakeWord model rather than the compressed microWakeWord variant.
Configuring the Assist Pipeline
In HA Settings > Voice Assistants, create a pipeline and select your Whisper instance for STT, your Piper instance for TTS, and your openWakeWord instance for wake word detection. Assign this pipeline to your satellite devices.
Entity exposure matters. Not every entity is exposed to Assist by default. In Settings > Voice Assistants > Expose, you control which entities are addressable by voice. Keeping this list curated improves intent recognition — the NLU does not have to disambiguate between fifty lights named “light.xxxx_1” and similar.
Custom sentences extend what Assist can understand beyond the built-in intents. In custom_sentences/en/ you can define sentence patterns that map to arbitrary scripts or services:
|
|
The Energy Dashboard
The energy dashboard, introduced in late 2021 and substantially improved since, is Home Assistant’s built-in energy monitoring and analytics tool. It aggregates electricity consumption, solar production, and optionally gas and water usage into a single view with daily, monthly, and historical breakdowns.
What It Tracks
- Grid consumption: power drawn from the utility grid
- Grid return: excess solar power exported back to the grid (net metering)
- Solar production: total solar panel output (from an inverter integration)
- Individual device consumption: per-device wattage from smart plugs with power monitoring
- Gas usage: from a gas smart meter or pulse counter
- Water usage: from a flow sensor or smart meter
Feeding Data Into the Energy Dashboard
The dashboard requires sensors with the energy device class (measuring kWh, not watts). For live power sensors (watts), HA can derive energy consumption using the “Riemann Sum” integration helper, which integrates the power reading over time.
For grid metering, options include:
- P1 port adapters (DSMR): Netherlands and Belgium smart meters expose a serial P1 port. Adapters like the Homewizard P1 or a custom ESP32 with ESPHome provide WiFi-accessible energy data with per-tariff breakdown.
- Shelly EM: a DIN-rail or panel-mount energy monitor with CT clamps that measures whole-home or per-circuit consumption. Integrates via the Shelly HA integration.
- Emporia Vue 2: US-market energy monitor with up to 16 circuit-level CT clamps. Integrates via a local-polling HACS integration.
- CT clamp sensors: a DIY ESP32 with YHDC SCT013 CT clamps running ESPHome measures current on each circuit leg.
- Utility Meter helper: tracks daily/monthly totals from any energy sensor.
Cost Tracking
Enter your electricity tariff in the energy dashboard settings. For time-of-use rates, you can define different pricing for peak/off-peak periods. Dynamic pricing integration (for markets with real-time pricing — ENTSO-E in Europe, Amber Electric in Australia) lets you track actual costs against variable spot prices, which is genuinely useful for managing EV charging and high-draw appliances.
Long-term Storage and Grafana
Home Assistant stores energy statistics in its internal SQLite (or MariaDB, if configured) database. The statistics are retained indefinitely and form the basis of the energy dashboard charts. However, HA’s built-in charting is not a replacement for a proper time-series database and visualization tool.
Pushing sensor data to InfluxDB (via the InfluxDB integration or the InfluxDB add-on) gives you a schema-free time-series store that Grafana queries natively. Build dashboards that correlate power consumption with outdoor temperature, compare this week’s usage against last month, or visualize real-time whole-home power draw with sub-second resolution. The combination of InfluxDB + Grafana running as HAOS add-ons on an N100 mini-PC is a genuinely capable monitoring stack.
Remote Access: Nabu Casa vs Self-Hosted Options
Your HA instance runs on your local network. Accessing it from your phone while you are away from home requires one of several approaches. The choice involves tradeoffs between cost, complexity, security exposure, and feature completeness.
Why Remote Access Is Not Optional
The HA mobile app (iOS and Android) provides location tracking, actionable push notifications, and a full UI for controlling your home. All of this works locally when you are on your home network. For off-network access, you need remote access. The mobile app also needs a valid HTTPS certificate to function reliably — plain HTTP causes certificate errors and iOS connection drops.
Push notifications are a specific dependency to understand. The HA mobile app’s push notification system routes through Nabu Casa’s cloud infrastructure regardless of your remote access method. If you use Tailscale and not Nabu Casa, your remote access works fine, but push notifications still go through Nabu Casa’s servers (as relay infrastructure). If you opt out of Nabu Casa entirely, you can configure a self-hosted notification alternative (Ntfy or Gotify via the REST notification platform) but lose the convenience of the native push integration.
Nabu Casa (Home Assistant Cloud)
Nabu Casa operates the cloud relay service for HA. For $6.50/month (USD, as of mid-2026; annual plans available at $65/year), you get encrypted remote access via their relay infrastructure with no port forwarding, no DDNS setup, and no TLS certificate management. You also get Google Assistant and Amazon Alexa cloud integration without writing any code, improved TTS voices for Assist, and cloud-backup of your latest HA backup.
The security model is straightforward: Nabu Casa acts as a proxy between your HA instance (which makes an outbound connection to Nabu Casa servers) and your external client. Your home IP is never exposed. The TLS certificate is managed automatically.
The ethical argument for Nabu Casa is real: Nabu Casa is the company founded by the HA core team, and subscription revenue funds HA development. The project is open source; the cloud service is how the team sustains itself commercially. If you use Home Assistant seriously, paying for Nabu Casa is a reasonable way to support the project.
Self-Hosted Remote Access Options
Reverse proxy with DDNS + port forwarding is the traditional approach. Set up DuckDNS or Cloudflare DDNS to point a domain at your home IP, open port 443 on your router, and run Nginx or Caddy as a reverse proxy inside your network with a Let’s Encrypt certificate. This works and costs nothing beyond the domain registration. The downsides: your home IP is publicly exposed (even behind a domain), you are trusting your router’s firewall and the reverse proxy’s configuration to be correct, and your IP is crawled by internet scanners constantly.
Cloudflare Tunnel eliminates port forwarding. The cloudflared daemon running in your network makes an outbound connection to Cloudflare’s edge, and Cloudflare routes incoming requests back through the tunnel. No ports open, no home IP exposed, free tier is sufficient for HA traffic. The privacy tradeoff is that Cloudflare can see your HA traffic — the TLS tunnel terminates at Cloudflare, not at your home. Cloudflare has a strong privacy reputation, but it is a third-party sitting in the path.
Tailscale is a WireGuard-based VPN mesh that creates a private network between your devices. Install the Tailscale add-on in HAOS (or the Tailscale integration), install the Tailscale client on your phone, and your HA instance is accessible at its Tailscale IP from anywhere. No open ports, WireGuard’s modern cryptography, free for personal use (up to 100 devices). The UX requires you to configure HA’s external URL to use the Tailscale IP or DNS name, and to route only HA traffic over Tailscale (rather than all traffic from your phone, which kills battery). The HA integration generates a Let’s Encrypt certificate for the Tailscale hostname automatically.
Comparison Table
| Method | Monthly Cost | Setup Complexity | Exposes Home IP | Open Ports Required | Push Notifications | Alexa/Google |
|---|---|---|---|---|---|---|
| Nabu Casa | $6.50 | Minimal (one-click) | No | No | Yes (native) | Yes (built-in) |
| Cloudflare Tunnel | Free | Moderate | No | No | Via Nabu Casa relay | Manual setup |
| Tailscale | Free (personal) | Low-Moderate | No | No | Via Nabu Casa relay | Manual setup |
| DDNS + Port Forward | ~$0–$15/yr | High | Yes | Yes (443) | Via Nabu Casa relay | Manual setup |
My current setup is Tailscale for access and Nabu Casa for push notifications only. The $6.50/month is worth it for reliable push notifications and Alexa integration, and the fact that it funds HA development makes the decision easier. If privacy is paramount and you are willing to forgo push notifications, Tailscale alone is technically complete.
Putting It Together: Architecture for a Full Stack Install
After years of iterating, a full-featured home automation stack on a single N100 mini-PC running HAOS looks roughly like this:
+----------------------------------------------------------+
| N100 Mini-PC (HAOS 17.3) |
| |
| HA Core 2026.5 |
| - 150+ integrations |
| - 400+ entities |
| |
| Add-ons: |
| Mosquitto <-- MQTT backbone |
| Zigbee2MQTT <-- CC2652P USB dongle (serial by-id) |
| Z-Wave JS UI <-- ZST39 LR USB dongle |
| ESPHome <-- manages 12 ESP32 sensors |
| Whisper <-- small-int8 model |
| Piper <-- en_US-ryan-high |
| openWakeWord <-- "Hey Jarvis" |
| InfluxDB <-- long-term time-series |
| Grafana <-- visualization |
| Tailscale <-- remote access |
| |
| USB: |
| /dev/serial/by-id/..Dongle_Plus (Zigbee) |
| /dev/serial/by-id/..ZST39_LR (Z-Wave) |
| |
| Storage: 256 GB NVMe |
+----------------------------------------------------------+
Voice satellites (3x ESP32-S3-BOX-3) connect over WiFi using the Wyoming protocol. Six rooms each have an Aqara TVOC/temperature/humidity sensor on Zigbee. Light switches throughout are Inovelli Red Z-Wave dimmers. DIY ESPHome sensors cover the garage (temperature, door state, CO sensor), the crawl space (humidity), and the HVAC return air (temperature differential for filter monitoring).
The honest assessment after years of running this: Home Assistant is not a weekend project. The initial setup takes a week of focused work. Keeping it updated, debugging integrations that break after a core update, and maintaining automations as your device fleet grows requires ongoing attention. But the payoff — genuine local control, rich automation, no cloud dependencies for core functionality, complete data ownership — is worth it for anyone who wants to understand and control their home rather than subscribe to a series of vendor ecosystems that will eventually be sunsetted, merged, or pivoted into something unrecognizable.
The YAML learning curve is real. The Jinja2 templating has sharp edges. The documentation is good but vast. Start small: get HAOS running, pair a few devices, write two or three automations. Build confidence in the data model before you try to automate your entire house. Blueprints from the community are an excellent shortcut while you are learning — they work out of the box and the underlying YAML is readable, which teaches you the automation schema better than any tutorial.
The platform in 2026 is more polished, more capable, and more approachable than it has ever been. The fundamentals described in this post have been stable for years, which means time spent learning them compounds rather than deprecates.
Comments