Initial backup 2026-02-17
This commit is contained in:
7
skills/home-assistant/.clawhub/origin.json
Normal file
7
skills/home-assistant/.clawhub/origin.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "home-assistant",
|
||||
"installedVersion": "1.0.0",
|
||||
"installedAt": 1770184115989
|
||||
}
|
||||
2
skills/home-assistant/.env
Normal file
2
skills/home-assistant/.env
Normal file
@@ -0,0 +1,2 @@
|
||||
HA_URL=http://homeassistant.kangaroo-eel.ts.net:8123
|
||||
HA_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1NzczNWY1OWE4NGM0NzBmOTVlNmI5Y2Y3NzRjYTBjNyIsImlhdCI6MTcyNzk3MTQ0OCwiZXhwIjoyMDQzMzMxNDQ4fQ.P9LZCJz7O0kMVZRlbrGjOcr2YguQv7N8Us6-QT4GoAA
|
||||
175
skills/home-assistant/SKILL.md
Normal file
175
skills/home-assistant/SKILL.md
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
name: home-assistant
|
||||
description: Control Home Assistant smart home devices, run automations, and receive webhook events. Use when controlling lights, switches, climate, scenes, scripts, or any HA entity. Supports bidirectional communication via REST API (outbound) and webhooks (inbound triggers from HA automations).
|
||||
metadata: {"clawdbot":{"emoji":"🏠","requires":{"bins":["jq","curl"]}}}
|
||||
---
|
||||
|
||||
# Home Assistant
|
||||
|
||||
Control your smart home via Home Assistant's REST API and webhooks.
|
||||
|
||||
## Setup
|
||||
|
||||
### Option 1: Config File (Recommended)
|
||||
|
||||
Create `~/.config/home-assistant/config.json`:
|
||||
```json
|
||||
{
|
||||
"url": "https://your-ha-instance.duckdns.org",
|
||||
"token": "your-long-lived-access-token"
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2: Environment Variables
|
||||
|
||||
```bash
|
||||
export HA_URL="http://homeassistant.local:8123"
|
||||
export HA_TOKEN="your-long-lived-access-token"
|
||||
```
|
||||
|
||||
### Getting a Long-Lived Access Token
|
||||
|
||||
1. Open Home Assistant → Profile (bottom left)
|
||||
2. Scroll to "Long-Lived Access Tokens"
|
||||
3. Click "Create Token", name it (e.g., "Clawdbot")
|
||||
4. Copy the token immediately (shown only once)
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### List Entities
|
||||
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $HA_TOKEN" "$HA_URL/api/states" | jq '.[].entity_id'
|
||||
```
|
||||
|
||||
### Get Entity State
|
||||
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer $HA_TOKEN" "$HA_URL/api/states/light.living_room"
|
||||
```
|
||||
|
||||
### Control Devices
|
||||
|
||||
```bash
|
||||
# Turn on
|
||||
curl -X POST -H "Authorization: Bearer $HA_TOKEN" -H "Content-Type: application/json" \
|
||||
"$HA_URL/api/services/light/turn_on" -d '{"entity_id": "light.living_room"}'
|
||||
|
||||
# Turn off
|
||||
curl -X POST -H "Authorization: Bearer $HA_TOKEN" -H "Content-Type: application/json" \
|
||||
"$HA_URL/api/services/light/turn_off" -d '{"entity_id": "light.living_room"}'
|
||||
|
||||
# Set brightness (0-255)
|
||||
curl -X POST -H "Authorization: Bearer $HA_TOKEN" -H "Content-Type: application/json" \
|
||||
"$HA_URL/api/services/light/turn_on" -d '{"entity_id": "light.living_room", "brightness": 128}'
|
||||
```
|
||||
|
||||
### Run Scripts & Automations
|
||||
|
||||
```bash
|
||||
# Trigger script
|
||||
curl -X POST -H "Authorization: Bearer $HA_TOKEN" "$HA_URL/api/services/script/turn_on" \
|
||||
-H "Content-Type: application/json" -d '{"entity_id": "script.goodnight"}'
|
||||
|
||||
# Trigger automation
|
||||
curl -X POST -H "Authorization: Bearer $HA_TOKEN" "$HA_URL/api/services/automation/trigger" \
|
||||
-H "Content-Type: application/json" -d '{"entity_id": "automation.motion_lights"}'
|
||||
```
|
||||
|
||||
### Activate Scenes
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Authorization: Bearer $HA_TOKEN" "$HA_URL/api/services/scene/turn_on" \
|
||||
-H "Content-Type: application/json" -d '{"entity_id": "scene.movie_night"}'
|
||||
```
|
||||
|
||||
## Common Services
|
||||
|
||||
| Domain | Service | Example entity_id |
|
||||
|--------|---------|-------------------|
|
||||
| `light` | `turn_on`, `turn_off`, `toggle` | `light.kitchen` |
|
||||
| `switch` | `turn_on`, `turn_off`, `toggle` | `switch.fan` |
|
||||
| `climate` | `set_temperature`, `set_hvac_mode` | `climate.thermostat` |
|
||||
| `cover` | `open_cover`, `close_cover`, `stop_cover` | `cover.garage` |
|
||||
| `media_player` | `play_media`, `media_pause`, `volume_set` | `media_player.tv` |
|
||||
| `scene` | `turn_on` | `scene.relax` |
|
||||
| `script` | `turn_on` | `script.welcome_home` |
|
||||
| `automation` | `trigger`, `turn_on`, `turn_off` | `automation.sunrise` |
|
||||
|
||||
## Inbound Webhooks (HA → Clawdbot)
|
||||
|
||||
To receive events from Home Assistant automations:
|
||||
|
||||
### 1. Create HA Automation with Webhook Action
|
||||
|
||||
```yaml
|
||||
# In HA automation
|
||||
action:
|
||||
- service: rest_command.notify_clawdbot
|
||||
data:
|
||||
event: motion_detected
|
||||
area: living_room
|
||||
```
|
||||
|
||||
### 2. Define REST Command in HA
|
||||
|
||||
```yaml
|
||||
# configuration.yaml
|
||||
rest_command:
|
||||
notify_clawdbot:
|
||||
url: "https://your-clawdbot-url/webhook/home-assistant"
|
||||
method: POST
|
||||
headers:
|
||||
Authorization: "Bearer {{ webhook_secret }}"
|
||||
Content-Type: "application/json"
|
||||
payload: '{"event": "{{ event }}", "area": "{{ area }}"}'
|
||||
```
|
||||
|
||||
### 3. Handle in Clawdbot
|
||||
|
||||
Clawdbot receives the webhook and can notify you or take action based on the event.
|
||||
|
||||
## CLI Wrapper
|
||||
|
||||
The `scripts/ha.sh` CLI provides easy access to all HA functions:
|
||||
|
||||
```bash
|
||||
# Test connection
|
||||
ha.sh info
|
||||
|
||||
# List entities
|
||||
ha.sh list all # all entities
|
||||
ha.sh list lights # just lights
|
||||
ha.sh list switch # just switches
|
||||
|
||||
# Search entities
|
||||
ha.sh search kitchen # find entities by name
|
||||
|
||||
# Get/set state
|
||||
ha.sh state light.living_room
|
||||
ha.sh states light.living_room # full details with attributes
|
||||
ha.sh on light.living_room
|
||||
ha.sh on light.living_room 200 # with brightness (0-255)
|
||||
ha.sh off light.living_room
|
||||
ha.sh toggle switch.fan
|
||||
|
||||
# Scenes & scripts
|
||||
ha.sh scene movie_night
|
||||
ha.sh script goodnight
|
||||
|
||||
# Climate
|
||||
ha.sh climate climate.thermostat 22
|
||||
|
||||
# Call any service
|
||||
ha.sh call light turn_on '{"entity_id":"light.room","brightness":200}'
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **401 Unauthorized**: Token expired or invalid. Generate a new one.
|
||||
- **Connection refused**: Check HA_URL, ensure HA is running and accessible.
|
||||
- **Entity not found**: List entities to find the correct entity_id.
|
||||
|
||||
## API Reference
|
||||
|
||||
For advanced usage, see [references/api.md](references/api.md).
|
||||
175
skills/home-assistant/references/api.md
Normal file
175
skills/home-assistant/references/api.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# Home Assistant REST API Reference
|
||||
|
||||
## Authentication
|
||||
|
||||
All requests require the `Authorization` header:
|
||||
|
||||
```
|
||||
Authorization: Bearer <long-lived-access-token>
|
||||
```
|
||||
|
||||
## Base Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/api/` | GET | API status and HA version |
|
||||
| `/api/config` | GET | Current configuration |
|
||||
| `/api/states` | GET | All entity states |
|
||||
| `/api/states/<entity_id>` | GET | Single entity state |
|
||||
| `/api/states/<entity_id>` | POST | Set entity state |
|
||||
| `/api/services` | GET | Available services |
|
||||
| `/api/services/<domain>/<service>` | POST | Call a service |
|
||||
| `/api/events` | GET | Available events |
|
||||
| `/api/events/<event_type>` | POST | Fire an event |
|
||||
| `/api/history/period/<timestamp>` | GET | State history |
|
||||
| `/api/logbook/<timestamp>` | GET | Logbook entries |
|
||||
|
||||
## Common Services
|
||||
|
||||
### Lights
|
||||
|
||||
```bash
|
||||
# Turn on with options
|
||||
POST /api/services/light/turn_on
|
||||
{
|
||||
"entity_id": "light.living_room",
|
||||
"brightness": 255, # 0-255
|
||||
"color_temp": 370, # Mireds (153-500 typically)
|
||||
"rgb_color": [255, 0, 0], # RGB array
|
||||
"transition": 2 # Seconds
|
||||
}
|
||||
|
||||
# Turn off
|
||||
POST /api/services/light/turn_off
|
||||
{"entity_id": "light.living_room"}
|
||||
```
|
||||
|
||||
### Climate
|
||||
|
||||
```bash
|
||||
# Set temperature
|
||||
POST /api/services/climate/set_temperature
|
||||
{
|
||||
"entity_id": "climate.thermostat",
|
||||
"temperature": 22,
|
||||
"hvac_mode": "heat" # heat, cool, auto, off
|
||||
}
|
||||
|
||||
# Set preset
|
||||
POST /api/services/climate/set_preset_mode
|
||||
{
|
||||
"entity_id": "climate.thermostat",
|
||||
"preset_mode": "away"
|
||||
}
|
||||
```
|
||||
|
||||
### Media Player
|
||||
|
||||
```bash
|
||||
# Play/pause
|
||||
POST /api/services/media_player/media_play_pause
|
||||
{"entity_id": "media_player.tv"}
|
||||
|
||||
# Set volume (0.0-1.0)
|
||||
POST /api/services/media_player/volume_set
|
||||
{"entity_id": "media_player.tv", "volume_level": 0.5}
|
||||
|
||||
# Play media
|
||||
POST /api/services/media_player/play_media
|
||||
{
|
||||
"entity_id": "media_player.tv",
|
||||
"media_content_type": "music",
|
||||
"media_content_id": "spotify:playlist:xyz"
|
||||
}
|
||||
```
|
||||
|
||||
### Cover (Blinds/Garage)
|
||||
|
||||
```bash
|
||||
POST /api/services/cover/open_cover
|
||||
{"entity_id": "cover.garage"}
|
||||
|
||||
POST /api/services/cover/close_cover
|
||||
{"entity_id": "cover.garage"}
|
||||
|
||||
POST /api/services/cover/set_cover_position
|
||||
{"entity_id": "cover.blinds", "position": 50} # 0=closed, 100=open
|
||||
```
|
||||
|
||||
### Notifications
|
||||
|
||||
```bash
|
||||
POST /api/services/notify/mobile_app_phone
|
||||
{
|
||||
"message": "Motion detected!",
|
||||
"title": "Security Alert",
|
||||
"data": {
|
||||
"image": "/local/camera_snapshot.jpg"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Entity State Object
|
||||
|
||||
```json
|
||||
{
|
||||
"entity_id": "light.living_room",
|
||||
"state": "on",
|
||||
"attributes": {
|
||||
"brightness": 255,
|
||||
"color_temp": 370,
|
||||
"friendly_name": "Living Room Light",
|
||||
"supported_features": 63
|
||||
},
|
||||
"last_changed": "2024-01-15T10:30:00+00:00",
|
||||
"last_updated": "2024-01-15T10:30:00+00:00"
|
||||
}
|
||||
```
|
||||
|
||||
## Webhooks (Inbound to HA)
|
||||
|
||||
Trigger automations via webhook:
|
||||
|
||||
```bash
|
||||
POST /api/webhook/<webhook_id>
|
||||
{"custom": "data"}
|
||||
```
|
||||
|
||||
Create webhook trigger in automation:
|
||||
|
||||
```yaml
|
||||
automation:
|
||||
trigger:
|
||||
- platform: webhook
|
||||
webhook_id: my_webhook_id
|
||||
allowed_methods:
|
||||
- POST
|
||||
```
|
||||
|
||||
## WebSocket API
|
||||
|
||||
For real-time updates, use the WebSocket API at `ws://ha-url/api/websocket`.
|
||||
|
||||
Connection flow:
|
||||
1. Connect to WebSocket
|
||||
2. Receive `auth_required`
|
||||
3. Send `{"type": "auth", "access_token": "TOKEN"}`
|
||||
4. Receive `auth_ok`
|
||||
5. Subscribe to events: `{"id": 1, "type": "subscribe_events", "event_type": "state_changed"}`
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 400 | Bad request (invalid JSON or missing fields) |
|
||||
| 401 | Unauthorized (invalid/missing token) |
|
||||
| 404 | Entity or service not found |
|
||||
| 405 | Method not allowed |
|
||||
|
||||
## Rate Limits
|
||||
|
||||
Home Assistant doesn't enforce strict rate limits, but avoid:
|
||||
- Polling faster than every 1 second
|
||||
- Bulk updates without batching
|
||||
|
||||
Use WebSocket for real-time state tracking instead of polling.
|
||||
172
skills/home-assistant/scripts/ha.sh
Normal file
172
skills/home-assistant/scripts/ha.sh
Normal file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env bash
|
||||
# Home Assistant CLI wrapper
|
||||
# Usage: ha.sh <command> [args...]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CONFIG_FILE="${HA_CONFIG:-$HOME/.config/home-assistant/config.json}"
|
||||
|
||||
# Load config
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
HA_URL="${HA_URL:-$(jq -r '.url // empty' "$CONFIG_FILE")}"
|
||||
HA_TOKEN="${HA_TOKEN:-$(jq -r '.token // empty' "$CONFIG_FILE")}"
|
||||
fi
|
||||
|
||||
: "${HA_URL:?Set HA_URL or configure $CONFIG_FILE}"
|
||||
: "${HA_TOKEN:?Set HA_TOKEN or configure $CONFIG_FILE}"
|
||||
|
||||
cmd="${1:-help}"
|
||||
shift || true
|
||||
|
||||
api() {
|
||||
curl -s -H "Authorization: Bearer $HA_TOKEN" -H "Content-Type: application/json" "$@"
|
||||
}
|
||||
|
||||
case "$cmd" in
|
||||
state|get)
|
||||
# Get entity state: ha.sh state light.living_room
|
||||
entity="${1:?Usage: ha.sh state <entity_id>}"
|
||||
api "$HA_URL/api/states/$entity" | jq -r '.state // "unknown"'
|
||||
;;
|
||||
|
||||
states)
|
||||
# Get full entity state with attributes
|
||||
entity="${1:?Usage: ha.sh states <entity_id>}"
|
||||
api "$HA_URL/api/states/$entity" | jq
|
||||
;;
|
||||
|
||||
on|turn_on)
|
||||
# Turn on entity: ha.sh on light.living_room [brightness]
|
||||
entity="${1:?Usage: ha.sh on <entity_id> [brightness]}"
|
||||
domain="${entity%%.*}"
|
||||
brightness="${2:-}"
|
||||
if [[ -n "$brightness" ]]; then
|
||||
api -X POST "$HA_URL/api/services/$domain/turn_on" \
|
||||
-d "{\"entity_id\": \"$entity\", \"brightness\": $brightness}"
|
||||
else
|
||||
api -X POST "$HA_URL/api/services/$domain/turn_on" \
|
||||
-d "{\"entity_id\": \"$entity\"}"
|
||||
fi
|
||||
echo "✓ $entity turned on"
|
||||
;;
|
||||
|
||||
off|turn_off)
|
||||
# Turn off entity: ha.sh off light.living_room
|
||||
entity="${1:?Usage: ha.sh off <entity_id>}"
|
||||
domain="${entity%%.*}"
|
||||
api -X POST "$HA_URL/api/services/$domain/turn_off" \
|
||||
-d "{\"entity_id\": \"$entity\"}" >/dev/null
|
||||
echo "✓ $entity turned off"
|
||||
;;
|
||||
|
||||
toggle)
|
||||
# Toggle entity: ha.sh toggle switch.fan
|
||||
entity="${1:?Usage: ha.sh toggle <entity_id>}"
|
||||
domain="${entity%%.*}"
|
||||
api -X POST "$HA_URL/api/services/$domain/toggle" \
|
||||
-d "{\"entity_id\": \"$entity\"}" >/dev/null
|
||||
echo "✓ $entity toggled"
|
||||
;;
|
||||
|
||||
scene)
|
||||
# Activate scene: ha.sh scene movie_night
|
||||
scene="${1:?Usage: ha.sh scene <scene_name>}"
|
||||
[[ "$scene" == scene.* ]] || scene="scene.$scene"
|
||||
api -X POST "$HA_URL/api/services/scene/turn_on" \
|
||||
-d "{\"entity_id\": \"$scene\"}" >/dev/null
|
||||
echo "✓ Scene $scene activated"
|
||||
;;
|
||||
|
||||
script)
|
||||
# Run script: ha.sh script goodnight
|
||||
script="${1:?Usage: ha.sh script <script_name>}"
|
||||
[[ "$script" == script.* ]] || script="script.$script"
|
||||
api -X POST "$HA_URL/api/services/script/turn_on" \
|
||||
-d "{\"entity_id\": \"$script\"}" >/dev/null
|
||||
echo "✓ Script $script executed"
|
||||
;;
|
||||
|
||||
automation|trigger)
|
||||
# Trigger automation: ha.sh automation motion_lights
|
||||
auto="${1:?Usage: ha.sh automation <automation_name>}"
|
||||
[[ "$auto" == automation.* ]] || auto="automation.$auto"
|
||||
api -X POST "$HA_URL/api/services/automation/trigger" \
|
||||
-d "{\"entity_id\": \"$auto\"}" >/dev/null
|
||||
echo "✓ Automation $auto triggered"
|
||||
;;
|
||||
|
||||
climate|temp)
|
||||
# Set temperature: ha.sh climate climate.thermostat 22
|
||||
entity="${1:?Usage: ha.sh climate <entity_id> <temperature>}"
|
||||
temp="${2:?Usage: ha.sh climate <entity_id> <temperature>}"
|
||||
api -X POST "$HA_URL/api/services/climate/set_temperature" \
|
||||
-d "{\"entity_id\": \"$entity\", \"temperature\": $temp}" >/dev/null
|
||||
echo "✓ $entity set to ${temp}°"
|
||||
;;
|
||||
|
||||
list)
|
||||
# List entities by domain: ha.sh list lights / ha.sh list all
|
||||
filter="${1:-all}"
|
||||
if [[ "$filter" == "all" ]]; then
|
||||
api "$HA_URL/api/states" | jq -r '.[].entity_id' | sort
|
||||
else
|
||||
# Normalize: "lights" -> "light", "switches" -> "switch"
|
||||
filter="${filter%s}"
|
||||
api "$HA_URL/api/states" | jq -r --arg d "$filter" \
|
||||
'.[] | select(.entity_id | startswith($d + ".")) | .entity_id' | sort
|
||||
fi
|
||||
;;
|
||||
|
||||
search)
|
||||
# Search entities: ha.sh search kitchen
|
||||
pattern="${1:?Usage: ha.sh search <pattern>}"
|
||||
api "$HA_URL/api/states" | jq -r --arg p "$pattern" \
|
||||
'.[] | select(.entity_id | test($p; "i")) | "\(.entity_id): \(.state)"'
|
||||
;;
|
||||
|
||||
call)
|
||||
# Call any service: ha.sh call light turn_on '{"entity_id":"light.room","brightness":200}'
|
||||
domain="${1:?Usage: ha.sh call <domain> <service> [json_data]}"
|
||||
service="${2:?Usage: ha.sh call <domain> <service> [json_data]}"
|
||||
data="${3:-{}}"
|
||||
api -X POST "$HA_URL/api/services/$domain/$service" -d "$data"
|
||||
;;
|
||||
|
||||
info)
|
||||
# Get HA instance info
|
||||
api "$HA_URL/api/" | jq
|
||||
;;
|
||||
|
||||
help|*)
|
||||
cat <<EOF
|
||||
Home Assistant CLI
|
||||
|
||||
Usage: ha.sh <command> [args...]
|
||||
|
||||
Commands:
|
||||
state <entity> Get entity state
|
||||
states <entity> Get full entity state with attributes
|
||||
on <entity> [brightness] Turn on (optional brightness 0-255)
|
||||
off <entity> Turn off
|
||||
toggle <entity> Toggle on/off
|
||||
scene <name> Activate scene
|
||||
script <name> Run script
|
||||
automation <name> Trigger automation
|
||||
climate <entity> <temp> Set temperature
|
||||
list [domain] List entities (lights, switches, all)
|
||||
search <pattern> Search entities by name
|
||||
call <domain> <svc> [json] Call any service
|
||||
info Get HA instance info
|
||||
|
||||
Environment:
|
||||
HA_URL Home Assistant URL (required)
|
||||
HA_TOKEN Long-lived access token (required)
|
||||
|
||||
Examples:
|
||||
ha.sh on light.living_room 200
|
||||
ha.sh scene movie_night
|
||||
ha.sh list lights
|
||||
ha.sh search kitchen
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user