# moltbot-ha 🏠

**Home Assistant control CLI for Moltbot agents and humans.**

Control your smart home via Home Assistant REST API with powerful safety features, configurable confirmations, and agent-friendly design.

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)

---

## ✨ Features

- 🎮 **Full Control**: Lights, switches, covers, scenes, climate, and all Home Assistant domains
- 🛡️ **Safety First**: 3-level safety system with confirmations for critical actions (locks, alarms, garage doors)
- 🤖 **Agent-Friendly**: Designed for AI agents with clear error messages and confirmation workflows
- ⚙️ **Configurable**: Flexible allowlist/blocklist, custom critical domains, logging
- 🚀 **Fast**: Direct REST API calls with retry logic and connection pooling
- 📊 **Output Formats**: Human-readable tables or JSON for programmatic use

---

## 📦 Installation

### Via uv (recommended)
```bash
uv tool install moltbot-ha
```

### Via pip
```bash
pip install moltbot-ha
```

### From source (development)
```bash
git clone https://github.com/iamvaleriofantozzi/moltbot-ha.git
cd moltbot-ha
uv tool install .
```

---

## 🚀 Quick Start

### 1. Initialize Configuration
```bash
moltbot-ha config init
```

The interactive setup will ask you:
- **Home Assistant URL**: Your HA instance URL (e.g., `http://192.168.1.100:8123`)
- **Token storage**: Environment variable (recommended) or config file

### 2. Set Token (if using environment variable)
```bash
export HA_TOKEN="your_long_lived_access_token"
```

**How to create a token:**
1. Open Home Assistant → Profile (bottom left icon)
2. Scroll down to "Long-Lived Access Tokens"
3. Click "Create Token", give it a name (e.g., "moltbot-ha")
4. Copy the token immediately (you can't see it again!)

### 3. Test Connection
```bash
moltbot-ha test
```

You should see:
```
✓ Connected to Home Assistant successfully
```

---

### Non-Interactive Setup

If you prefer to set everything via environment variables:

```bash
export HA_URL="http://192.168.1.100:8123"
export HA_TOKEN="your_token_here"
moltbot-ha config init --no-interactive
moltbot-ha test
```

---

## 📖 Usage

### Discovery

```bash
# List all entities
moltbot-ha list

# List by domain
moltbot-ha list light
moltbot-ha list switch
moltbot-ha list sensor

# Get entity state (JSON output)
moltbot-ha state light.kitchen
```

### Basic Actions

```bash
# Turn on/off
moltbot-ha on light.living_room
moltbot-ha off switch.fan

# Toggle
moltbot-ha toggle light.hallway
```

### Advanced Control

```bash
# Set attributes
moltbot-ha set light.bedroom brightness_pct=50
moltbot-ha set light.office brightness_pct=80 color_temp=300

# Call services
moltbot-ha call scene.turn_on entity_id=scene.movie_time
moltbot-ha call climate.set_temperature entity_id=climate.living_room temperature=21

# Generic service call with JSON
moltbot-ha call script.turn_on --json '{"entity_id": "script.bedtime", "variables": {"dim": true}}'
```

---

## 🛡️ Safety System

moltbot-ha implements a **3-level safety system** to prevent accidental or dangerous actions.

### Safety Levels

| Level | Behavior |
|-------|----------|
| 0 | No safety checks (⚠️ dangerous!) |
| 1 | Log actions only, no confirmations |
| 2 | Confirm all write operations |
| 3 | Confirm critical operations only (🏅 **recommended**) |

### Level 3 (Default): Critical Domains

By default, these domains require explicit `--force` confirmation:
- **lock**: Door locks
- **alarm_control_panel**: Security systems
- **cover**: Garage doors, blinds, shutters

### Confirmation Workflow

1. **Attempt critical action without --force:**
```bash
$ moltbot-ha on cover.garage
```

2. **Tool returns error:**
```
⚠️  CRITICAL ACTION REQUIRES CONFIRMATION

Action: turn_on on cover.garage

This is a critical operation that requires explicit user approval.
Ask the user to confirm, then retry with --force flag.

Example: moltbot-ha on cover.garage --force
```

3. **After user confirms, retry with --force:**
```bash
$ moltbot-ha on cover.garage --force
✓ cover.garage turned on
```

### Blocked Entities

Permanently block entities that should NEVER be automated:

```toml
# ~/.config/moltbot-ha/config.toml
[safety]
blocked_entities = [
    "switch.main_breaker",      # Never touch the main power!
    "lock.front_door",          # Keep front door manual-only
]
```

Blocked entities cannot be controlled even with `--force`.

### Allowlist

Restrict access to specific entities only:

```toml
[safety]
allowed_entities = [
    "light.*",                  # All lights
    "switch.office_*",          # Office switches only
    "scene.*",                  # All scenes
]
```

---

## ⚙️ Configuration

Full configuration file (`~/.config/moltbot-ha/config.toml`):

```toml
[server]
# Home Assistant URL (required)
url = "http://192.168.1.100:8123"

# Token (optional, prefer HA_TOKEN env var)
# token = "eyJ..."

[safety]
# Safety level: 0=disabled, 1=log-only, 2=confirm all, 3=confirm critical
level = 3

# Domains that require confirmation (level 3)
critical_domains = ["lock", "alarm_control_panel", "cover"]

# Entities that are always blocked (even with --force)
blocked_entities = []

# Entities that are allowed (empty = all allowed except blocked)
# Supports wildcards: "light.*", "switch.office_*"
allowed_entities = []

[logging]
# Enable action logging
enabled = true

# Log file path
path = "~/.config/moltbot-ha/actions.log"

# Log level: DEBUG, INFO, WARNING, ERROR
level = "INFO"
```

### Environment Variables

Environment variables override config file settings:

- `HA_URL`: Home Assistant URL
- `HA_TOKEN`: Long-lived access token (⭐ **recommended** for security)
- `HA_CTL_CONFIG`: Custom config file path

---

## 🐳 Docker / Moltbot Integration

If running inside Docker (e.g., Moltbot gateway):

### Installation in Container
```bash
docker exec -it moltbot-gateway uv tool install moltbot-ha
```

### Configuration
```bash
docker exec -it moltbot-gateway moltbot-ha config init
docker exec -it moltbot-gateway vi ~/.config/moltbot-ha/config.toml
```

### Set Token via Environment
Add to `docker-compose.yml`:
```yaml
environment:
  - HA_TOKEN=${HA_TOKEN}
```

Then in host `.env`:
```
HA_TOKEN=your_token_here
```

### Networking Tips

- **IP address** (recommended): `http://192.168.1.100:8123`
- **Tailscale**: `http://homeassistant.ts.net:8123`
- **Avoid mDNS** in Docker: `homeassistant.local` often doesn't work
- **Nabu Casa**: `https://xxxxx.ui.nabu.casa` (requires subscription)

---

## 🔍 Troubleshooting

### Connection Refused

**Symptom:**
```
Connection failed: Connection refused
```

**Solutions:**
- Verify Home Assistant is running
- Check URL in config matches your HA instance
- Ensure HA is reachable from the machine running moltbot-ha
- Check firewall settings (port 8123 must be open)
- If in Docker, use IP address instead of `homeassistant.local`

### 401 Unauthorized

**Symptom:**
```
[401] Authentication failed
```

**Solutions:**
- Verify `HA_TOKEN` environment variable is set correctly
- Ensure token is a **Long-Lived Access Token** (not session token)
- Check token hasn't been revoked in Home Assistant settings
- Regenerate token if necessary

### Entity Not Found

**Symptom:**
```
Entity not found: light.kitche
```

**Solutions:**
- Use `moltbot-ha list` to discover correct entity IDs
- Entity IDs are case-sensitive
- Check for typos (e.g., `kitche` vs `kitchen`)

### Blocked Entity

**Symptom:**
```
❌ Entity switch.main_breaker is BLOCKED in configuration
```

**Solution:**
- This is intentional! The entity is in your `blocked_entities` list
- Remove from config if you want to allow control
- This safety feature prevents accidental control of critical devices

---

## 📝 Examples

### Morning Routine Script
```bash
#!/bin/bash
# morning.sh

moltbot-ha on light.bedroom brightness_pct=30
moltbot-ha call cover.open_cover entity_id=cover.bedroom_blinds
moltbot-ha call climate.set_temperature entity_id=climate.bedroom temperature=21
moltbot-ha call scene.turn_on entity_id=scene.good_morning
```

### Check Temperature Sensors
```bash
#!/bin/bash
# check-temps.sh

echo "Living Room:"
moltbot-ha state sensor.temperature_living_room | jq -r '.state'

echo "Bedroom:"
moltbot-ha state sensor.temperature_bedroom | jq -r '.state'

echo "Outside:"
moltbot-ha state sensor.temperature_outside | jq -r '.state'
```

### Night Mode
```bash
#!/bin/bash
# night-mode.sh

moltbot-ha call scene.turn_on entity_id=scene.goodnight
moltbot-ha call cover.close_cover entity_id=cover.all_blinds
moltbot-ha call climate.set_temperature entity_id=climate.bedroom temperature=18
```

---

## 🤝 Contributing

Contributions welcome! Please:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit changes (`git commit -m 'Add amazing feature'`)
4. Push to branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

---

## 📄 License

MIT License - see [LICENSE](LICENSE) file for details.

---

## 🙏 Acknowledgments

- [Home Assistant](https://www.home-assistant.io/) for the amazing smart home platform
- [Moltbot](https://molt.bot/) for agent infrastructure
- [Typer](https://typer.tiangolo.com/) for CLI framework
- [Rich](https://rich.readthedocs.io/) for beautiful terminal output

---

## 🔗 Links

- [Home Assistant REST API Docs](https://developers.home-assistant.io/docs/api/rest/)
- [Moltbot Documentation](https://docs.molt.bot/)
- [ClawdHub](https://clawdhub.com/) (skill registry)

---

**Made with ❤️ for smart homes and AI agents**
