Metadata-Version: 2.4
Name: ha-tool
Version: 0.4.1
Summary: Home Assistant CLI for discovering, querying, and controlling entities over WebSocket
Project-URL: Homepage, https://github.com/szsolt/ha-tool
Project-URL: Repository, https://github.com/szsolt/ha-tool
Project-URL: Issues, https://github.com/szsolt/ha-tool/issues
Author-email: Zsolt Sz <zsolt@kucko.cc>
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,automation,cli,home-assistant,smart-home,websocket
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Home Automation
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: pydantic>=2.0
Requires-Dist: typer>=0.12
Requires-Dist: websockets>=13.0
Description-Content-Type: text/markdown

# ha-tool

[![PyPI](https://img.shields.io/pypi/v/ha-tool.svg)](https://pypi.org/project/ha-tool/)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A CLI tool for discovering, querying, and controlling Home Assistant over WebSocket. Designed for both human use and AI agent consumption.

## Features

- **Entity Discovery** — Search, inspect, and list entities with flexible filtering
- **Registry Editing** — Rename, re-area, relabel, and bulk-remap entities live
- **Service Calls** — Call any Home Assistant service with JSON data/targets
- **Configuration Reload** — Reload automations, scripts, scenes, and more
- **Template Rendering** — Test Jinja2 templates against your live instance
- **Entity Verification** — Validate entity references in YAML/config files
- **Dual Output** — Human-readable tables or JSON for scripting/AI agents
- **Stateless** — Each invocation opens a connection, performs the action, and exits

## Installation

```bash
# As a standalone CLI (recommended)
uv tool install ha-tool

# Or with pip
pip install ha-tool

# From source
uv tool install .
pip install -e .
```

## Configuration

Set these environment variables:

```bash
export HASS_SERVER=https://your-ha-instance:8123
export HASS_TOKEN=your_long_lived_access_token
```

`HASS_URL` is also accepted as a fallback for `HASS_SERVER`.

Create a long-lived access token in Home Assistant: **Profile → Security → Long-Lived Access Tokens**.

## Usage

### Search entities

```bash
# Substring match
ha-tool search "pool"

# Filter by domain, device class, area
ha-tool search --domain sensor --device-class temperature
ha-tool search --area "Kitchen"
ha-tool search "pool" -d sensor -a "Pool"

# Glob patterns
ha-tool search 'sensor.pool_temp_*'
ha-tool search 'binary_sensor.door_?'

# Regex patterns (auto-detected by metacharacters like [] | ^ $ + ())
ha-tool search 'temperature_[0-9]+'
ha-tool search 'pool|kitchen'

# Include disabled entities
ha-tool search "pool" --include-disabled
```

### Inspect entities

```bash
ha-tool inspect climate.wq3a25a01264
ha-tool inspect sensor.pool_temp light.kitchen climate.hvac
```

### Get entity state

```bash
ha-tool get sensor.pool_temperature
```

### List areas

```bash
ha-tool areas
```

### List domains

```bash
ha-tool domains
```

### List integrations

```bash
ha-tool integrations
```

### List/search services

```bash
ha-tool services
ha-tool services --domain light
ha-tool services "temperature"
```

### Call services

```bash
# Turn on a light
ha-tool call light.turn_on --target '{"entity_id": "light.kitchen"}'

# Set thermostat temperature
ha-tool call climate.set_temperature --data '{"temperature": 22}' --target '{"entity_id": "climate.hvac"}'

# Trigger an automation
ha-tool call automation.trigger --target '{"entity_id": "automation.morning_routine"}'
```

### Reload configuration

```bash
# List available reload domains
ha-tool reload

# Reload specific domain
ha-tool reload automations
ha-tool reload scripts
ha-tool reload scenes

# Reload all configuration
ha-tool reload all
```

### Refresh Lovelace dashboards

```bash
# Discover all yaml-mode dashboards and refresh them + the default dashboard
ha-tool lovelace-refresh

# Refresh specific dashboards by url_path ("default" = the built-in dashboard)
ha-tool lovelace-refresh lovelace
ha-tool lovelace-refresh power default
```

Home Assistant caches parsed YAML-mode dashboards in memory, so replacing the
file on disk is invisible to clients. This sends `lovelace/config` with
`force: true` to re-read each dashboard from disk. Exits 1 if any refresh fails.

### Restart Home Assistant

```bash
ha-tool restart        # Prompts for confirmation
ha-tool restart -y     # Skip confirmation
```

### Render Jinja2 templates

```bash
ha-tool template '{{ states("sensor.temperature") }}'
ha-tool template '{{ now().strftime("%H:%M") }}'
ha-tool template '{{ state_attr("climate.hvac", "current_temperature") }}'
```

### Verify entity references in files

```bash
# Check all entity references in a file
ha-tool verify automations.yaml

# Multiple files
ha-tool verify automations.yaml scripts.yaml configuration.yaml

# Only show missing/invalid references
ha-tool verify --filter missing automations.yaml
```

Extracts all patterns matching `<known_domain>.<object_id>` from the given files, filters out known service names (e.g. `light.turn_on`), and checks each entity against the live HA instance.

### Edit the entity registry

```bash
# Only the fields you pass are changed
ha-tool set-entity sensor.pool_temp --name "Pool Temperature" --area "Pool"
ha-tool set-entity light.kitchen --icon mdi:ceiling-light --category config
ha-tool set-entity switch.old_name --new-id switch.new_name

# rename-entity is a shorthand for set-entity --new-id
ha-tool rename-entity switch.old_name switch.new_name
```

Live edit via `config/entity_registry/update` — no restart. `--new-id` must stay
in the same domain. `--label` is repeatable and replaces the whole label set.

### Bulk rename by regex

```bash
# Dry-run by default — prints every old -> new
ha-tool bulk-rename 'sensor\.old_(.*)' 'sensor.new_\1'

ha-tool bulk-rename -d switch 'switch\.zb_(.*)' 'switch.\1' --apply
```

PATTERN is a Python regex `fullmatch`ed against each entity_id; REPLACEMENT
supports backrefs. A batch containing any collision or cross-domain rename is
refused before anything changes.

### Wrap a switch as another domain

```bash
ha-tool wrap-entity switch.desk_lamp --as light --name "Desk Lamp"
ha-tool wrap-entity switch.vent --as fan -y
```

Creates a new `switch_as_x` entity backed by the source switch. Useful for
re-creating switch→light / switch→fan mappings after an integration rebuild.

### Inspect a device

```bash
ha-tool device-inspect "Kitchen Motion"   # name substring
ha-tool device-inspect a1b2c3d4e5         # exact device_id
```

Device metadata plus its full entity roster. Ambiguous name matches list the
candidates to pick from.

### Report unhealthy entities

```bash
ha-tool stale-report
ha-tool stale-report --stale 2d -d sensor
ha-tool stale-report --only unavailable --only orphaned
```

Read-only sweep flagging `unavailable`, `unknown`, `stale`, `restored`,
`orphaned`, `disabled`, and `hidden` entities. Change-only sensors can
false-positive on `stale`, so treat that flag as advisory.

### Removal commands

```bash
ha-tool remove-entity input_boolean.test_toggle -y
ha-tool remove-device <device_id> <config_entry_id> -y
ha-tool remove-config-entry <entry_id> -y
```

Registry cleanup. Prompts for confirmation unless `-y` / `--yes`.

### Validate config

```bash
ha-tool check-config
```

Validates `configuration.yaml` (exits 1 when invalid).

### Discovery (extra)

```bash
ha-tool info             # core config (version, location, units)
ha-tool panels           # registered UI panels
ha-tool config-entries   # integrations and their config entries
ha-tool labels           # label registry
ha-tool floors           # floor registry
ha-tool categories <scope>  # category registry (default scope: automation)
```

### History and logs

```bash
ha-tool history sensor.outdoor_temperature --since 6h
ha-tool logbook --since 30m -e light.kitchen
ha-tool error-log -n 50
```

`--since` / `--until` accept `1h`, `30m`, `2d`, `today`, `now`, or ISO 8601.

### Diagnostics

```bash
ha-tool health           # system health snapshot per integration
ha-tool repairs          # active repair issues
ha-tool notifications list
ha-tool notifications dismiss <notification_id>
```

### Live event stream and calendar

```bash
ha-tool watch --event-type state_changed
ha-tool watch -t state_changed -e light.kitchen
ha-tool calendars
ha-tool calendar calendar.work --start now --end 7d
```

`watch` outputs NDJSON until Ctrl-C.

## Output formats

Default output is a human-readable table. Use `-o json` for machine-parseable JSON:

```bash
ha-tool -o json search "pool"
ha-tool -o json inspect sensor.pool_temp
ha-tool -o json services --domain climate
```

## Debugging

Use `-v` to see WebSocket connection details on stderr:

```bash
ha-tool -v search "pool"
```

## Architecture

- Single WebSocket connection per invocation, fires all registry queries concurrently, then closes. Stateless.
- Joins entity registry → device registry → area registry to resolve area names, device info, and friendly names.
- Entity's own `area_id` takes precedence over its device's `area_id`.
- Disabled entities are excluded by default.
- Search pattern auto-detection: plain text → substring, `*`/`?` → glob, regex metacharacters → regex.

## For AI Agents

The installable skill at [`skills/ha-tool.md`](skills/ha-tool.md) is structured documentation optimized for AI agent consumption, including:
- Command reference with exact output schemas
- Discovery workflow patterns
- Common usage examples

See [AGENTS.md](AGENTS.md) for guidance on extending or fixing the repo itself.

### Claude Code Integration

Install the ha-tool skill for Claude Code:

```bash
./scripts/install-skill.sh
```

This copies the skill to `~/.claude/commands/ha-tool.md`, making it available globally in Claude Code.

## Dependencies

- Python 3.12+
- [typer](https://typer.tiangolo.com/) — CLI framework
- [pydantic](https://docs.pydantic.dev/) — Data validation
- [websockets](https://websockets.readthedocs.io/) — WebSocket client

## License

MIT License. See [LICENSE](LICENSE) for details.
