# `Hassock.Cache`
[🔗](https://github.com/bbangert/hassock/blob/v0.3.0/lib/hassock/cache.ex#L1)

Optional ETS-backed cache of all Home Assistant entity states.

Subscribes the underlying `Hassock.Connection` to every entity using HA's
`subscribe_entities` command. The first event payload contains the full
initial snapshot; later payloads ship compressed `a`/`c`/`r` deltas
including newly created and deleted entities. ETS is kept in sync.

## Ownership

Starting a cache for a connection **transfers ownership of that
connection to the cache** (`Hassock.Connection.controlling_process/2`).
The transfer is performed inside `start_link/1` itself — so the process
that calls `start_link/1` must currently own the connection.

The same caller becomes the cache's own controlling process and receives:

  * `{:hassock_cache, cache, :ready}` — after the initial snapshot loads, and
    again after each reconnect once the table is back in sync
  * `{:hassock_cache, cache, {:changes, %{added: _, changed: _, removed: _}}}`
     — after each delta event, and before `:ready` after a reconnect with
     whatever changed during the outage (entities removed in the meantime
     are deleted from the table and listed in `removed`)
  * `{:hassock_cache, cache, :disconnected}` — on socket loss (ETS retained)
  * `{:hassock_cache, cache, {:auth_failed, reason}}` — HA rejected the
    token; the connection has stopped retrying

The initial load sends only `:ready`; read the table then.

Use `controlling_process/2` to hand cache events to a different pid. To
override the initial controller (e.g. when starting under a supervisor),
pass `:controlling_pid` in the options.

Read API (`get/2`, `get_all/1`, `get_domain/2`) reads ETS directly with no
GenServer roundtrip, for a cache given by pid or registered name.

Requires Home Assistant >= 2022.4 (when `subscribe_entities` was added).

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `controlling_process`

```elixir
@spec controlling_process(GenServer.server(), pid()) ::
  :ok | {:error, :not_owner | :not_alive}
```

Transfer cache ownership. Only the current controller may transfer.

# `get`

```elixir
@spec get(GenServer.server(), String.t()) :: Hassock.EntityState.t() | nil
```

Look up an entity by id. Returns `nil` if not cached.

# `get_all`

```elixir
@spec get_all(GenServer.server()) :: [Hassock.EntityState.t()]
```

All cached entities.

# `get_domain`

```elixir
@spec get_domain(GenServer.server(), String.t()) :: [Hassock.EntityState.t()]
```

All cached entities whose `entity_id` starts with `"<domain>."`.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Start a state cache wired to a `Connection`.

Options:

  * `:connection` — pid or registered name of a `Hassock.Connection` (required)
  * `:controlling_pid` — pid that should receive cache events (default: caller)
  * `:name` — register the cache under this name (optional)
  * `:table_name` — explicit ETS table name (optional)
  * `:retry` — ms between attempts to re-subscribe after a failed
    `subscribe_entities` (default `5_000`)

The caller must currently own the connection. Ownership is transferred to
the new cache as part of `start_link/1`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
