hastty 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hastty-0.1.1/LICENSE +21 -0
- hastty-0.1.1/PKG-INFO +196 -0
- hastty-0.1.1/README.md +164 -0
- hastty-0.1.1/hastty/__init__.py +3 -0
- hastty-0.1.1/hastty/__main__.py +51 -0
- hastty-0.1.1/hastty/app.py +271 -0
- hastty-0.1.1/hastty/client.py +187 -0
- hastty-0.1.1/hastty/config.py +129 -0
- hastty-0.1.1/hastty/lovelace.py +103 -0
- hastty-0.1.1/hastty.egg-info/PKG-INFO +196 -0
- hastty-0.1.1/hastty.egg-info/SOURCES.txt +16 -0
- hastty-0.1.1/hastty.egg-info/dependency_links.txt +1 -0
- hastty-0.1.1/hastty.egg-info/entry_points.txt +2 -0
- hastty-0.1.1/hastty.egg-info/requires.txt +4 -0
- hastty-0.1.1/hastty.egg-info/top_level.txt +1 -0
- hastty-0.1.1/pyproject.toml +45 -0
- hastty-0.1.1/setup.cfg +4 -0
- hastty-0.1.1/tests/test_integration.py +98 -0
hastty-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jmleclercq
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
hastty-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hastty
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A terminal (TUI) viewer for your Home Assistant dashboards, with keyboard shortcuts to trigger commands.
|
|
5
|
+
Author: jmleclercq
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jmleclercq/hastty
|
|
8
|
+
Project-URL: Repository, https://github.com/jmleclercq/hastty
|
|
9
|
+
Project-URL: Issues, https://github.com/jmleclercq/hastty/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/jmleclercq/hastty/releases
|
|
11
|
+
Keywords: home-assistant,homeassistant,tui,terminal,lovelace,dashboard,textual,smart-home
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Home Automation
|
|
23
|
+
Classifier: Topic :: Terminals
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: textual>=0.58.0
|
|
28
|
+
Requires-Dist: aiohttp>=3.9
|
|
29
|
+
Requires-Dist: PyYAML>=6.0
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# hastty
|
|
34
|
+
|
|
35
|
+
[](https://github.com/jmleclercq/hastty/releases/tag/v0.1.1)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
|
|
38
|
+
**A terminal (TUI) viewer for your Home Assistant dashboards — with keyboard
|
|
39
|
+
shortcuts to trigger commands, no browser required.**
|
|
40
|
+
|
|
41
|
+
`hastty` mirrors your existing Lovelace views (same views, same entities, same
|
|
42
|
+
order) and lets you fire commands with the keyboard: toggle a light, run a
|
|
43
|
+
scene, trigger a script or an automation — all from the terminal, with live
|
|
44
|
+
state updates.
|
|
45
|
+
|
|
46
|
+
<p align="center">
|
|
47
|
+
<img src="assets/screenshots/01-view-living-room.svg" width="820" alt="hastty showing the Living Room view, mirrored from Lovelace">
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- **Mirrors your Lovelace dashboards** — reuses the views and entities you
|
|
53
|
+
already defined in Home Assistant, no separate dashboard to maintain.
|
|
54
|
+
- **Live state updates** — subscribes to `state_changed` events, no polling,
|
|
55
|
+
no manual refresh needed.
|
|
56
|
+
- **Keyboard-first** — jump between views, move the selection, and fire
|
|
57
|
+
commands, all without touching the mouse.
|
|
58
|
+
- **Custom global shortcuts** — bind any key to a specific service call
|
|
59
|
+
(e.g. a scene or script) directly from a config file.
|
|
60
|
+
- **Single dependency on your side**: a Home Assistant Long-Lived Access
|
|
61
|
+
Token. No add-on, no extra integration to install on the HA side.
|
|
62
|
+
|
|
63
|
+
## Screenshots
|
|
64
|
+
|
|
65
|
+
**Activating an entity** — toggling `switch.tv` with <kbd>Enter</kbd>, state updates live:
|
|
66
|
+
|
|
67
|
+
<img src="assets/screenshots/02-activate-entity.svg" width="820" alt="Activating an entity: toggling switch.tv with Enter, live state update">
|
|
68
|
+
|
|
69
|
+
**Scenes view** — a second Lovelace dashboard, switched to with the <kbd>2</kbd> key:
|
|
70
|
+
|
|
71
|
+
<img src="assets/screenshots/03-view-scenes.svg" width="820" alt="Scenes view, reached with the 2 key">
|
|
72
|
+
|
|
73
|
+
**Help screen** — generic bindings plus the custom shortcuts from `config.yaml`:
|
|
74
|
+
|
|
75
|
+
<img src="assets/screenshots/04-help.svg" width="820" alt="Help screen listing generic bindings and custom shortcuts">
|
|
76
|
+
|
|
77
|
+
*(Captured against a local mock Home Assistant server, see
|
|
78
|
+
[`tests/mock_ha_server.py`](tests/mock_ha_server.py) — no real HA instance
|
|
79
|
+
required to try it out.)*
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/jmleclercq/hastty.git
|
|
85
|
+
cd hastty
|
|
86
|
+
python3 -m venv .venv
|
|
87
|
+
source .venv/bin/activate
|
|
88
|
+
pip install -e .
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
You need two things: the URL of your Home Assistant instance, and a
|
|
94
|
+
**Long-Lived Access Token** (Home Assistant → your profile, bottom left →
|
|
95
|
+
Security tab → "Long-lived access tokens" → Create Token).
|
|
96
|
+
|
|
97
|
+
The simplest option — environment variables:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
cp .env.example .env
|
|
101
|
+
# edit .env: HA_URL=http://homeassistant.local:8123 and HA_TOKEN=...
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or generate a config file with custom keyboard shortcuts:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
hastty --init-config
|
|
108
|
+
# edit ~/.config/hastty/config.yaml
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The token can stay in `.env` (recommended, never committed) even if you use
|
|
112
|
+
the YAML file for shortcuts.
|
|
113
|
+
|
|
114
|
+
By default, only your **default** Lovelace dashboard is mirrored. If you use
|
|
115
|
+
several dashboards and want all of them, set `include_extra_dashboards: true`
|
|
116
|
+
under `homeassistant:` in `config.yaml`.
|
|
117
|
+
|
|
118
|
+
## Run
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
hastty
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Usage
|
|
125
|
+
|
|
126
|
+
| Key | Action |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `1`–`9` | Jump directly to view N (in the order of your HA dashboards) |
|
|
129
|
+
| `←` / `→` | Previous / next view |
|
|
130
|
+
| `↑` / `↓` | Move the selection in the table |
|
|
131
|
+
| `Enter` / `Space` | Activate the selected entity (toggle light/switch, run a scene/script, trigger an automation...) |
|
|
132
|
+
| `r` | Refresh (re-syncs views and states) |
|
|
133
|
+
| `?` | Help (also lists your custom shortcuts) |
|
|
134
|
+
| `q` | Quit |
|
|
135
|
+
|
|
136
|
+
### Custom shortcuts
|
|
137
|
+
|
|
138
|
+
In `config.yaml`, under `keybindings`, you can define global keys (active
|
|
139
|
+
from any view) that call a service directly — for example a scene or a
|
|
140
|
+
script — without navigating to the entity first:
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
keybindings:
|
|
144
|
+
- key: "g"
|
|
145
|
+
description: "Good night (scene)"
|
|
146
|
+
service: "scene.turn_on"
|
|
147
|
+
target:
|
|
148
|
+
entity_id: scene.good_night
|
|
149
|
+
|
|
150
|
+
- key: "a"
|
|
151
|
+
description: "Turn everything off (script)"
|
|
152
|
+
service: "script.turn_on"
|
|
153
|
+
target:
|
|
154
|
+
entity_id: script.turn_everything_off
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## How it works
|
|
158
|
+
|
|
159
|
+
- **Connection**: Home Assistant WebSocket API (`/api/websocket`),
|
|
160
|
+
authenticated with a Long-Lived Access Token (`hastty/client.py`).
|
|
161
|
+
- **Dashboard mirroring**: calls `lovelace/config` for your default
|
|
162
|
+
dashboard (and, if `include_extra_dashboards` is enabled, every dashboard
|
|
163
|
+
from `lovelace/dashboards/list` too). Cards (`entities`, `glance`, `light`,
|
|
164
|
+
`vertical-stack`, `grid`, etc.) — whether under a classic top-level
|
|
165
|
+
`cards` list or under the newer per-section `sections` layout used by the
|
|
166
|
+
default dashboard editor since Home Assistant 2024.9 — are flattened into
|
|
167
|
+
per-view lists of `entity_id` (`hastty/lovelace.py`). The app doesn't try
|
|
168
|
+
to reproduce the visual layout of the cards, only the view → entities
|
|
169
|
+
organization.
|
|
170
|
+
- **Commands**: `call_service` over WebSocket, either through the generic
|
|
171
|
+
per-domain action (Enter/Space on a selected entity) or through custom
|
|
172
|
+
shortcuts (`keybindings` in the config).
|
|
173
|
+
|
|
174
|
+
## Known limitations
|
|
175
|
+
|
|
176
|
+
- `area` cards (without an explicit entity list) aren't resolved into
|
|
177
|
+
individual entities yet.
|
|
178
|
+
- The generic action (Enter/Space) calls a default service based on the
|
|
179
|
+
entity's domain (toggle for light/switch/fan..., turn_on for
|
|
180
|
+
scene/script, trigger for automation...); for a precise command with
|
|
181
|
+
parameters (color, brightness, cover position...), use a custom shortcut
|
|
182
|
+
with `service_data`.
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pip install -e .
|
|
188
|
+
python tests/test_integration.py # end-to-end test against a mock HA server
|
|
189
|
+
python tests/capture_screenshots.py # regenerate the SVG screenshots in assets/screenshots
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines before opening a PR.
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
[MIT](LICENSE)
|
hastty-0.1.1/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# hastty
|
|
2
|
+
|
|
3
|
+
[](https://github.com/jmleclercq/hastty/releases/tag/v0.1.1)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
**A terminal (TUI) viewer for your Home Assistant dashboards — with keyboard
|
|
7
|
+
shortcuts to trigger commands, no browser required.**
|
|
8
|
+
|
|
9
|
+
`hastty` mirrors your existing Lovelace views (same views, same entities, same
|
|
10
|
+
order) and lets you fire commands with the keyboard: toggle a light, run a
|
|
11
|
+
scene, trigger a script or an automation — all from the terminal, with live
|
|
12
|
+
state updates.
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="assets/screenshots/01-view-living-room.svg" width="820" alt="hastty showing the Living Room view, mirrored from Lovelace">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **Mirrors your Lovelace dashboards** — reuses the views and entities you
|
|
21
|
+
already defined in Home Assistant, no separate dashboard to maintain.
|
|
22
|
+
- **Live state updates** — subscribes to `state_changed` events, no polling,
|
|
23
|
+
no manual refresh needed.
|
|
24
|
+
- **Keyboard-first** — jump between views, move the selection, and fire
|
|
25
|
+
commands, all without touching the mouse.
|
|
26
|
+
- **Custom global shortcuts** — bind any key to a specific service call
|
|
27
|
+
(e.g. a scene or script) directly from a config file.
|
|
28
|
+
- **Single dependency on your side**: a Home Assistant Long-Lived Access
|
|
29
|
+
Token. No add-on, no extra integration to install on the HA side.
|
|
30
|
+
|
|
31
|
+
## Screenshots
|
|
32
|
+
|
|
33
|
+
**Activating an entity** — toggling `switch.tv` with <kbd>Enter</kbd>, state updates live:
|
|
34
|
+
|
|
35
|
+
<img src="assets/screenshots/02-activate-entity.svg" width="820" alt="Activating an entity: toggling switch.tv with Enter, live state update">
|
|
36
|
+
|
|
37
|
+
**Scenes view** — a second Lovelace dashboard, switched to with the <kbd>2</kbd> key:
|
|
38
|
+
|
|
39
|
+
<img src="assets/screenshots/03-view-scenes.svg" width="820" alt="Scenes view, reached with the 2 key">
|
|
40
|
+
|
|
41
|
+
**Help screen** — generic bindings plus the custom shortcuts from `config.yaml`:
|
|
42
|
+
|
|
43
|
+
<img src="assets/screenshots/04-help.svg" width="820" alt="Help screen listing generic bindings and custom shortcuts">
|
|
44
|
+
|
|
45
|
+
*(Captured against a local mock Home Assistant server, see
|
|
46
|
+
[`tests/mock_ha_server.py`](tests/mock_ha_server.py) — no real HA instance
|
|
47
|
+
required to try it out.)*
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/jmleclercq/hastty.git
|
|
53
|
+
cd hastty
|
|
54
|
+
python3 -m venv .venv
|
|
55
|
+
source .venv/bin/activate
|
|
56
|
+
pip install -e .
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
You need two things: the URL of your Home Assistant instance, and a
|
|
62
|
+
**Long-Lived Access Token** (Home Assistant → your profile, bottom left →
|
|
63
|
+
Security tab → "Long-lived access tokens" → Create Token).
|
|
64
|
+
|
|
65
|
+
The simplest option — environment variables:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cp .env.example .env
|
|
69
|
+
# edit .env: HA_URL=http://homeassistant.local:8123 and HA_TOKEN=...
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or generate a config file with custom keyboard shortcuts:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
hastty --init-config
|
|
76
|
+
# edit ~/.config/hastty/config.yaml
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The token can stay in `.env` (recommended, never committed) even if you use
|
|
80
|
+
the YAML file for shortcuts.
|
|
81
|
+
|
|
82
|
+
By default, only your **default** Lovelace dashboard is mirrored. If you use
|
|
83
|
+
several dashboards and want all of them, set `include_extra_dashboards: true`
|
|
84
|
+
under `homeassistant:` in `config.yaml`.
|
|
85
|
+
|
|
86
|
+
## Run
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
hastty
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Usage
|
|
93
|
+
|
|
94
|
+
| Key | Action |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `1`–`9` | Jump directly to view N (in the order of your HA dashboards) |
|
|
97
|
+
| `←` / `→` | Previous / next view |
|
|
98
|
+
| `↑` / `↓` | Move the selection in the table |
|
|
99
|
+
| `Enter` / `Space` | Activate the selected entity (toggle light/switch, run a scene/script, trigger an automation...) |
|
|
100
|
+
| `r` | Refresh (re-syncs views and states) |
|
|
101
|
+
| `?` | Help (also lists your custom shortcuts) |
|
|
102
|
+
| `q` | Quit |
|
|
103
|
+
|
|
104
|
+
### Custom shortcuts
|
|
105
|
+
|
|
106
|
+
In `config.yaml`, under `keybindings`, you can define global keys (active
|
|
107
|
+
from any view) that call a service directly — for example a scene or a
|
|
108
|
+
script — without navigating to the entity first:
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
keybindings:
|
|
112
|
+
- key: "g"
|
|
113
|
+
description: "Good night (scene)"
|
|
114
|
+
service: "scene.turn_on"
|
|
115
|
+
target:
|
|
116
|
+
entity_id: scene.good_night
|
|
117
|
+
|
|
118
|
+
- key: "a"
|
|
119
|
+
description: "Turn everything off (script)"
|
|
120
|
+
service: "script.turn_on"
|
|
121
|
+
target:
|
|
122
|
+
entity_id: script.turn_everything_off
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## How it works
|
|
126
|
+
|
|
127
|
+
- **Connection**: Home Assistant WebSocket API (`/api/websocket`),
|
|
128
|
+
authenticated with a Long-Lived Access Token (`hastty/client.py`).
|
|
129
|
+
- **Dashboard mirroring**: calls `lovelace/config` for your default
|
|
130
|
+
dashboard (and, if `include_extra_dashboards` is enabled, every dashboard
|
|
131
|
+
from `lovelace/dashboards/list` too). Cards (`entities`, `glance`, `light`,
|
|
132
|
+
`vertical-stack`, `grid`, etc.) — whether under a classic top-level
|
|
133
|
+
`cards` list or under the newer per-section `sections` layout used by the
|
|
134
|
+
default dashboard editor since Home Assistant 2024.9 — are flattened into
|
|
135
|
+
per-view lists of `entity_id` (`hastty/lovelace.py`). The app doesn't try
|
|
136
|
+
to reproduce the visual layout of the cards, only the view → entities
|
|
137
|
+
organization.
|
|
138
|
+
- **Commands**: `call_service` over WebSocket, either through the generic
|
|
139
|
+
per-domain action (Enter/Space on a selected entity) or through custom
|
|
140
|
+
shortcuts (`keybindings` in the config).
|
|
141
|
+
|
|
142
|
+
## Known limitations
|
|
143
|
+
|
|
144
|
+
- `area` cards (without an explicit entity list) aren't resolved into
|
|
145
|
+
individual entities yet.
|
|
146
|
+
- The generic action (Enter/Space) calls a default service based on the
|
|
147
|
+
entity's domain (toggle for light/switch/fan..., turn_on for
|
|
148
|
+
scene/script, trigger for automation...); for a precise command with
|
|
149
|
+
parameters (color, brightness, cover position...), use a custom shortcut
|
|
150
|
+
with `service_data`.
|
|
151
|
+
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
pip install -e .
|
|
156
|
+
python tests/test_integration.py # end-to-end test against a mock HA server
|
|
157
|
+
python tests/capture_screenshots.py # regenerate the SVG screenshots in assets/screenshots
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines before opening a PR.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""CLI entry point: `hastty` or `python -m hastty`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import logging
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from .app import HasttyApp
|
|
11
|
+
from .config import DEFAULT_CONFIG_PATH, load_config, write_example_config
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def run() -> None:
|
|
15
|
+
parser = argparse.ArgumentParser(prog="hastty", description=__doc__)
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"--config",
|
|
18
|
+
type=Path,
|
|
19
|
+
default=None,
|
|
20
|
+
help=f"Path to the config file (default: {DEFAULT_CONFIG_PATH})",
|
|
21
|
+
)
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"--init-config",
|
|
24
|
+
action="store_true",
|
|
25
|
+
help="Generate an example config file and exit.",
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument("--debug", action="store_true", help="Enable debug logging to hastty.log")
|
|
28
|
+
args = parser.parse_args()
|
|
29
|
+
|
|
30
|
+
if args.debug:
|
|
31
|
+
logging.basicConfig(filename="hastty.log", level=logging.DEBUG)
|
|
32
|
+
|
|
33
|
+
if args.init_config:
|
|
34
|
+
path = write_example_config(args.config)
|
|
35
|
+
print(f"Example config created: {path}")
|
|
36
|
+
print("Edit this file (or set HA_URL / HA_TOKEN) then run `hastty` again.")
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
config = load_config(args.config)
|
|
41
|
+
except RuntimeError as exc:
|
|
42
|
+
print(f"Configuration error: {exc}", file=sys.stderr)
|
|
43
|
+
print("\nTip: run `hastty --init-config` to generate a starter config file.", file=sys.stderr)
|
|
44
|
+
sys.exit(1)
|
|
45
|
+
|
|
46
|
+
app = HasttyApp(config)
|
|
47
|
+
app.run()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
run()
|