> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpostern.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect Home Assistant

> Stream your Home Assistant devices into Postern. It is the only source an agent can act on.

<Info>
  **Before you start**

  * **A Home Assistant that is up on your own network, and about 5 minutes.** Postern connects to it
    directly. No cloud service, no account.
  * **Postern installed, with the Console open.** Open `http://localhost:8787` in a browser on the
    machine Postern runs on. If that machine has no screen,
    [open the Console over SSH](/start/remote-access#ssh-tunnel).
  * **Your password manager open.** Home Assistant shows the token once, in step 1, and nothing
    re-reveals it.
  * **A Home Assistant account you are willing to lend.** The token carries exactly what that user
    can do, and Postern acts as that user. A sector is one area of your life: finance, mail,
    calendar, contacts, health, home. An agent you grant `home` can run any device action here, with
    no confirmation for each one.
</Info>

<Steps>
  <Step title="Create a token in Home Assistant" titleSize="h2" id="token">
    In Home Assistant, click your own name at the very bottom of the left sidebar. It sits below
    **Settings** and **Notifications**, with a small round picture beside it. Nothing reads “Profile”.

    Your profile opens on the **General** tab. Click the other tab, **Security**. The address now ends
    `/profile/security`.

    Scroll to the bottom of that tab. The section headed **Long-lived access tokens** sits below
    **Change password**, **Multi-factor authentication modules** and **Refresh tokens**.

    Older Home Assistant versions show no tabs. There the same section sits at the bottom of the profile
    page — [Managing account access](https://www.home-assistant.io/docs/authentication/#managing-account-access).

    <Warning>
      Home Assistant shows the token once, at the moment you create it. It keeps no copy of the token
      string, so nothing re-reveals it and the only remedy is a new token. Open your password manager
      before you create the token.
    </Warning>

    Press **Create token**, at the bottom right of that section. A dialog opens, headed **Create token**,
    with one required field labelled **Name\***. Type `Postern` into it. That name is how you tell this
    token apart from your others in Home Assistant.

    The dialog carries **Cancel**, which creates nothing, and a second **Create token** button. That
    button stays greyed out until the field has something in it.

    Press the dialog's **Create token**. Home Assistant replaces the dialog with a screen headed
    **Token created:** followed by the name you typed. It warns *"Copy your access token. It will not
    be shown again."* The token sits in a read-only field, too long to read at that width.

    Press **Copy**, to the right of the field. A message reads *"Copied to clipboard"*. Paste the token
    into your password manager. You paste it into the Console in step 3, and again whenever you
    reconnect.

    A **Generate QR code** control sits below the token. Postern has no use for it.

    Press **Close**. `Postern` appears at the top of the list, with its creation time beside it.
  </Step>

  <Step title="Find the address of the Home Assistant machine" titleSize="h2" id="address">
    Open Home Assistant in a browser and read the address bar. You need that machine's numeric
    address and its port, in the shape of the Console's own example:

    ```text theme={"system"}
    http://192.168.1.50:8123
    ```

    `8123` is Home Assistant's own default port. Keep whatever port your address bar shows.

    If the address bar shows a name instead of numbers, open your router's settings page. Its list of
    connected devices gives each one a numeric address.

    <Warning>
      Postern runs inside its own sandbox, a Docker container. From in there a `.local` name resolves to
      nothing. `localhost` and `127.0.0.1` name the sandbox itself, not your Home Assistant — even when
      both run on one machine. The Console accepts a wrong address of the right shape without
      complaint, creates the connection, and the connection never starts. Use the numbers.
    </Warning>

    Recommended. Reserve that address for the Home Assistant machine on your router's settings page.
    Routers call it a DHCP reservation, a static lease, or an address reservation. Otherwise the address
    changes weeks later and this connection stops.
  </Step>

  <Step title="Paste the address and the token into the Console" titleSize="h2" id="paste">
    In the Console, go to **Sources** → **Add a source** → **Home Assistant**. The card has two fields.

    Put the address from step 2 into **Instance URL**. It must start with `http://` or `https://`.
    Without that the Console answers *"That isn’t a URL — your Home Assistant address starts with
    http\:// or https\://, e.g. [http://192.168.1.50:8123](http://192.168.1.50:8123)."*

    Put the token from step 1 into **Long-lived token**. An empty field answers *"Paste the long-lived
    access token you copied from Home Assistant."*

    Press **Connect Home Assistant**. A message reads *"Home Assistant connected."* The Console returns
    to **Sources**. The new connection appears under **home** with the badge **Awaiting first push**.

    That badge is normal. Home Assistant sends changes the moment they happen, and nothing has arrived
    yet. There is no schedule to set. Postern rescans its connections every 60 seconds, so the
    connection comes up within about a minute. No restart, nothing to press. The badge then disappears
    and the connection reads **Instant — connected**.

    <Note>
      **Unreachable**, with *"can't reach source — retrying"*: nothing answered at that address. Postern
      tries again after 5 seconds, then doubles the wait after each failure, up to 60 seconds. A Home
      Assistant that was not ready yet recovers by itself. A wrong address never does. **Error**, with
      *"auth failed: invalid token"*: Home Assistant refused the token, and Postern will not retry a
      refused token — [Home Assistant throttles repeated sign-in
      failures](/reference/provider-sign-ins#a-refused-source-credential-is-not-retried). Neither state clears
      on a timer; a changed address or token is what clears it.
    </Note>

    To correct either value, paste it on this same card. The card reads *"Home Assistant is already
    connected. Connecting again replaces the stored credential — it won't create a second copy."* Tick
    **Yes — replace the stored credential.** and press **Reconnect Home Assistant**. The next scan
    restarts the connection within a minute.
  </Step>
</Steps>

## Confirm it works

* Console → **Sources** → the **Home Assistant** row: under **Live stream**, the words **Stream
  down** are absent.
* The line beneath reads *last event* with a time on it, not *no events yet*.
* **Entities cached** shows a number above 0.
* Change a light or a switch in Home Assistant. That *last event* time drops to seconds ago.
* Ask an agent granted `home` what it can control in your house. It answers with action ids such as
  `home.light.turn_on` and `home.lock.lock`.

## If something went wrong

| What you see                                                                                                                                                                                           | What to do                                                                                                                                                                                 |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Unreachable**, `can't reach source — retrying`                                                                                                                                                       | Nothing answered there. Paste the numeric address with `http://` in front — never a `.local` name, `localhost` or `127.0.0.1` — and press **Reconnect Home Assistant**.                    |
| **Error**, `auth failed: invalid token`                                                                                                                                                                | [Create a new token in Home Assistant](#token), paste it on the same card, and press **Reconnect Home Assistant**. Take the same path if you lost the token before it reached the Console. |
| The connection sits at **Awaiting first push**; or an agent granted `home` lists no actions; or an action returns `home assistant: no live connection for this connection id — nothing was dispatched` | The live connection is not up, and Postern sent nothing to your house. Correct the address as in row 1 — the Console accepts a wrong address of the right shape.                           |
| An action returns `admin/system service not permitted (device/entity control only)`                                                                                                                    | Postern never runs admin or system services. There is nothing to change here. Run that one in Home Assistant yourself.                                                                     |

## What you have now

The `home` sector, for reads and for actions. Any agent you grant `home` sees your devices' states,
reads the action list, and runs the actions you would run yourself: lights, scenes, switches,
scripts, automations and buttons. Postern works out which actions apply to which device, so the list
arrives instantly. [Home Assistant does not offer that mapping itself](/reference/mcp-actions#where-the-home-assistant-catalogue-comes-from).

Postern never runs an admin or system service. An agent that names one gets `admin/system service
not permitted (device/entity control only)` back — [the domains and services Postern
drops](/reference/mcp-actions#the-admin-and-system-services-postern-never-runs).

Postern grants permission per sector only. A granted sector covers reads and actions together, with
no narrower grant and no confirmation step — [what a grant
covers](/reference/grants-and-sectors#what-a-grant-covers).
Console → **The ledger** holds a row for every call, `invoke_action` among them, under that agent's
own name. Postern only ever adds to the record.

Postern sends each action once and never repeats it. A break mid-action returns `unknown — not
retried` — [Postern cannot know whether Home Assistant acted](/reference/mcp-actions#invoke_action). Check the
device yourself.

Postern stores the token encrypted on your own machine. It stays exactly as powerful as the Home
Assistant user who made it: if that account gains permissions, so does this connection.

To stop it at Home Assistant, go back to **Long-lived access tokens** on your profile's **Security**
tab. Every token's row ends in a trash-can icon, with no words on it. Press the one on the `Postern`
row. The connection then fails at its next check with `auth failed: invalid token`, and stays in
error until you paste a new one.

To stop it at Postern instead, go to Console → **Sources** → the **Home Assistant** row. Press
**Remove token**. A confirm step opens, headed **Remove the token**: *"Deletes the long-lived token
from the vault. Home stops immediately."* Type `Home Assistant` into the field labelled *"Type Home
Assistant to confirm"*, then press **Remove token** again. That second button stays greyed out
until the typed name matches exactly, and reads *"Working…"* while it runs. **Cancel** leaves the
connection as it is. On success the Console reads *"Revoked the Home Assistant credential."*

When the connection is down, an agent still reads device states from cache. The action list and
every action stop.

## Next

<Columns cols={2}>
  <Card title="Connect an agent" href="/start/connect-an-agent">
    a key in hand and the Console open · a few minutes, plus a restart of the client you connect
  </Card>

  <Card title="Connect Google and Gmail" href="/connect/google">
    your own Google Cloud app and one app password · about 20 minutes · weekly re-consent until you
    publish to production
  </Card>
</Columns>
