hastty
A terminal (TUI) viewer for your Home Assistant dashboards — with keyboard shortcuts to trigger commands, no browser required.
hastty mirrors your existing Lovelace views (same views, same entities, same
order) and lets you fire commands with the keyboard: toggle a light, run a
scene, trigger a script or an automation — all from the terminal, with live
state updates.
Features
- Mirrors your Lovelace dashboards — reuses the views and entities you already defined in Home Assistant, no separate dashboard to maintain.
- Live state updates — subscribes to
state_changedevents, no polling, no manual refresh needed. - Keyboard-first — jump between views, move the selection, and fire commands, all without touching the mouse.
- Custom global shortcuts — bind any key to a specific service call (e.g. a scene or script) directly from a config file.
- Single dependency on your side: a Home Assistant Long-Lived Access Token. No add-on, no extra integration to install on the HA side.
Screenshots
Activating an entity — toggling switch.tv with Enter, state updates live:
Scenes view — a second Lovelace dashboard, switched to with the 2 key:
Help screen — generic bindings plus the custom shortcuts from config.yaml:
(Captured against a local mock Home Assistant server, see
tests/mock_ha_server.py — no real HA instance
required to try it out.)
Installation
pip install hastty
(or pipx install hastty to keep it isolated from other Python environments)
To install from source instead — e.g. to contribute or track main — see
CONTRIBUTING.md.
Configuration
You need two things: the URL of your Home Assistant instance, and a Long-Lived Access Token (Home Assistant → your profile, bottom left → Security tab → "Long-lived access tokens" → Create Token).
The simplest option — environment variables:
cp .env.example .env
# edit .env: HA_URL=http://homeassistant.local:8123 and HA_TOKEN=...
Or generate a config file with custom keyboard shortcuts:
hastty --init-config
# edit ~/.config/hastty/config.yaml
The token can stay in .env (recommended, never committed) even if you use
the YAML file for shortcuts.
By default, only your default Lovelace dashboard is mirrored. If you use
several dashboards and want all of them, set include_extra_dashboards: true
under homeassistant: in config.yaml.
Run
hastty
Usage
| Key | Action |
|---|---|
1–9 |
Jump directly to view N (in the order of your HA dashboards) |
← / → |
Previous / next view |
↑ / ↓ |
Move the selection in the table |
Enter / Space |
Activate the selected entity (toggle light/switch, run a scene/script, trigger an automation...) |
r |
Refresh (re-syncs views and states) |
? |
Help (also lists your custom shortcuts) |
q |
Quit |
Custom shortcuts
In config.yaml, under keybindings, you can define global keys (active
from any view) that call a service directly — for example a scene or a
script — without navigating to the entity first:
keybindings:
- key: "g"
description: "Good night (scene)"
service: "scene.turn_on"
target:
entity_id: scene.good_night
- key: "a"
description: "Turn everything off (script)"
service: "script.turn_on"
target:
entity_id: script.turn_everything_off
How it works
- Connection: Home Assistant WebSocket API (
/api/websocket), authenticated with a Long-Lived Access Token (hastty/client.py). - Dashboard mirroring: calls
lovelace/configfor your default dashboard (and, ifinclude_extra_dashboardsis enabled, every dashboard fromlovelace/dashboards/listtoo). Cards (entities,glance,light,vertical-stack,grid, etc.) — whether under a classic top-levelcardslist or under the newer per-sectionsectionslayout used by the default dashboard editor since Home Assistant 2024.9 — are flattened into per-view lists ofentity_id(hastty/lovelace.py). The app doesn't try to reproduce the visual layout of the cards, only the view → entities organization. - Commands:
call_serviceover WebSocket, either through the generic per-domain action (Enter/Space on a selected entity) or through custom shortcuts (keybindingsin the config).
Known limitations
areacards (without an explicit entity list) aren't resolved into individual entities yet.- The generic action (Enter/Space) calls a default service based on the
entity's domain (toggle for light/switch/fan..., turn_on for
scene/script, trigger for automation...); for a precise command with
parameters (color, brightness, cover position...), use a custom shortcut
with
service_data.
Development
pip install -e .
python tests/test_integration.py # end-to-end test against a mock HA server
python tests/capture_screenshots.py # regenerate the SVG screenshots in assets/screenshots
See CONTRIBUTING.md for guidelines before opening a PR.
License
Release files for hastty 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hastty-0.1.2.tar.gz | 17.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hastty-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:33.3 kB
Release files / hastty-0.1.2.tar.gz
| Download URL | hastty-0.1.2.tar.gz |
|---|---|
| Size | 17.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c99c5e93a3547653985b7f663b635578aad6df612e4778f62efc4b8d77e43ca
|
|
BLAKE2b-256 checksum How to use checksums |
bdf4f68652d4baa0e2b29574d14d1d67d1c1cfcabb4c597283521884593fa5e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 12, 2026.
Transparency logRelease files / hastty-0.1.2-py3-none-any.whl
| Download URL | hastty-0.1.2-py3-none-any.whl |
|---|---|
| Size | 15.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7ce6ffb5c4654922ed0c7c1acc30f3e5ee81ac0385d5dc47853192f892b4969f
|
|
BLAKE2b-256 checksum How to use checksums |
77693ebb313fd777ebdd2de543570b4e16b390ffc922bd6fc3fdfc71765d249e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 12, 2026.
Transparency log