Skip to main content
Connect a device to Home Assistant once, and you can control it just by talking to your agent. No app, no buttons. Say what you want, and it happens.

Lights

“Turn on the kitchen light.” “Dim it to twenty percent.”

Climate

“Set the thermostat to seventy.”

Locks & doors

“Lock the front door.”

Media & scenes

“Start movie night.”

How it works

1

Connect the device in Home Assistant

Add it from the dashboard, as covered in Add integrations.
2

Build a Local Ability for it

Create a small Ability that reaches the device through Home Assistant on your DevKit.
3

Talk to your agent

Trigger the Ability by voice and run the device with natural commands.
This has to be a Local Ability. The action happens on your DevKit, where Home Assistant runs, so only the Local category can reach it.
New to building Abilities? Start with the Local Ability quickstart.

Example: voice-control Tasmota lights

This walkthrough builds a working voice integration end to end: a Local Ability that controls Tasmota smart lights through the Home Assistant instance on your device. Once it’s set up you can say “turn on the kitchen light”, “make it warm”, or “set it to red” and your agent does the rest. It comes in two files, which is the standard Local Ability split:
This is a Local Ability, so it only runs on real OpenHome DevKit hardware, the device where Home Assistant is installed. See Local Abilities for the full reference on how the two files work together.

What you’ll need

  • Home Assistant installed on your DevKit (see Install & manage). The MQTT integration is set up automatically during install.
  • One or more Tasmota smart bulbs or strips on the same network as your DevKit.
  • The OpenHome Live Editor to create the Ability under the Local category.
There are three steps, and the first is automatic. The DevKit already connects to Home Assistant for you, so in practice you just pair your Tasmota device with Home Assistant and build the Ability.

Step 1: Connecting to Home Assistant (automatic)

You don’t set up authentication yourself. When you install Home Assistant through OpenHome, the credentials your Ability needs are provisioned on the device, and the DevKit side authenticates on its own. There’s no file to create, no token to paste, and nothing to configure. For this Tasmota example, it just works.

Reuse the connection in your own Ability

Building a different Ability that talks to Home Assistant? Reuse OpenHome’s connection logic directly. Drop this into your devkit_functions.py and call _ensure_auth() before any Home Assistant request. It finds the saved credentials, exchanges them for a short-lived access token at Home Assistant’s /auth/token endpoint, and caches the token until just before it expires:
Every Home Assistant request goes through _ensure_auth() first, so the access token is fetched and refreshed for you automatically. If a token expires mid-session, the next call refreshes it. (See _ha_request() in the full devkit_functions.py below for how each call uses it.)

Where the credentials live (reference)

You normally never touch this, but for advanced or custom setups it helps to know how the connection is stored. _ensure_auth() reads a small file containing:
It checks these locations in order and uses the first one it finds:
  1. The path in the OPENHOME_HA_AUTH_PATH environment variable
  2. ~/.ha_refresh_token
  3. /home/openhome/.ha_refresh_token
OpenHome saves these credentials during install, so this file already exists at one of the paths above, and this is simply where the code looks. For a custom location, point OPENHOME_HA_AUTH_PATH at your own file.
Treat this file like a password, since anyone with the refresh token can control your Home Assistant. Keep it readable only by your user, and never commit it into an Ability or share it.

Step 2: Connect your Tasmota device to Home Assistant

Now pair the physical light with Home Assistant. Tasmota talks to the same MQTT broker your DevKit’s Home Assistant already uses, so once it connects, Home Assistant discovers it on its own.
1

Find your Tasmota device's IP

Check your router’s list of connected devices, or open tasmota-XXXXX.local in a browser.
2

Open the Tasmota web UI → Configuration → Configure MQTT

Set these values:The Host is your DevKit’s IP address, the same one you use to open the Home Assistant dashboard. You can find it in the DevKit section under MQTT, shown as Device IP.
3

Save

Tasmota restarts and connects to the broker.
4

Home Assistant auto-discovers it

The MQTT integration is already loaded in Home Assistant. Once Tasmota connects, it publishes to the discovery topic and Home Assistant’s Tasmota integration picks it up automatically, with no manual configuration needed. The light then shows up as a light.* entity, which is exactly what the Ability controls.

Step 3: Build the Ability

In the OpenHome Live Editor, create a new Ability and select the Local category (Local Abilities are the only type that can reach Home Assistant on the device; see Local Abilities). Give it trigger words so users can launch it by voice, such as “smart home” or “lights”. A Local Ability is two files. This example needs no third-party packages, so requirements.txt can stay empty, since everything uses the Python standard library.

main.py: voice and intent

main.py runs in the standard Ability runtime. It greets the user, runs a conversation loop, and uses the LLM to convert each spoken request into a structured intent (which integration, which action, which device). It then hands that intent to the DevKit side and speaks a short confirmation.

devkit_functions.py: Home Assistant on the device

devkit_functions.py runs on the DevKit. It authenticates with the credentials file from Step 1, finds the matching Tasmota light entity, and calls Home Assistant’s light services to perform the action. ha_startup is a lightweight ping that also reports which integrations and how many entities are available.
When you save in the Live Editor with the DevKit connected, the files sync to the device automatically. See Sync Local Abilities with the DevKit if your DevKit was offline while editing.

Step 4: Talk to it

Launch the Ability with one of your trigger words, then speak naturally. The conversation loop keeps listening until you say you’re done.
  • “Turn on the kitchen light.”
  • “Make it warm.” (reuses the last light you mentioned)
  • “Set the lamp to red.”
  • “Dim the bedroom to twenty percent.”
  • “That’s all, thanks.” (ends the session)
If you have more than one light, include a short descriptor like “kitchen” or “bedroom lamp”, and the DevKit side matches it against your Home Assistant light names and picks the right one. With a single light, no descriptor is needed.

Extending it

This template is built around an integration registry. To support more than Tasmota lights, add another entry to INTEGRATION_REGISTRY in main.py (a context function describing its actions, and an execute function that maps an intent to a DevKit call) and a matching handler in FUNCTION_REGISTRY in devkit_functions.py. The voice loop, prompt builder, and dispatch logic stay the same.

Edge cases

The Ability checks for a running Home Assistant on the device when it starts. If Home Assistant isn’t installed, or is still starting up, the Ability can’t control anything. Make sure it’s installed and running (see Install & manage), then relaunch.
If the Ability says it can’t find a light, the Tasmota device probably isn’t connected to Home Assistant yet. Recheck Step 2. Once Tasmota connects to the broker, Home Assistant discovers it as a light and the Ability can control it.
This example deliberately ignores lights from other ecosystems (such as Hue, LIFX, Shelly, WLED, Yeelight, and TP-Link) so it only acts on your Tasmota bulbs. To control other brands, extend the Ability as described above.
Add a short descriptor to your command, like “kitchen” or “bedroom lamp”. The DevKit side matches it against your Home Assistant light names. If it can’t match your words to a specific light, it falls back to the first one it finds, so naming your lights clearly in Home Assistant helps.
A bulb that’s cut off from power shows as unavailable in Home Assistant and is skipped. Restore power so it reconnects, then try your command again.
The Ability sends actions; it doesn’t read a light’s current state. It will never claim a light is on or off without performing an action, so ask it to turn things on, off, or toggle rather than asking for status.
If your speech isn’t recognized, the Ability asks you to repeat. After a few unclear tries in a row it ends the session politely. Just relaunch it with your trigger word.

See also