Home Assistant Skill
Control smart home devices via the Home Assistant REST API.
Setup
Set environment variables:
- HA_URL — Your Home Assistant URL (e.g., http://10.0.0.10:8123)
- HA_TOKEN — Long-lived access token (create in HA → Profile → Long-Lived Access Tokens)
Safety Rules
Always confirm with the user before performing these actions:
- Locks — locking or unlocking any lock
- Alarm panels — arming or disarming
- Garage doors — opening or closing (cover.* with device_class: garage)
- Security automations — disabling automations related to security or safety
- Covers — opening or closing covers that control physical access (gates, barriers)
Never act on security-sensitive devices without explicit user confirmation.
Entity Discovery
List all entities
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[].entity_id' | sort
List entities by domain
# Switches
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("switch.")) | "\(.entity_id): \(.state)"'
# Lights
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("light.")) | "\(.entity_id): \(.state)"'
# Sensors
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("sensor.")) | "\(.entity_id): \(.state) \(.attributes.unit_of_measurement // "")"'
Replace the domain prefix (switch., light., sensor., etc.) to discover entities
in any domain.
Get single entity state
curl -s "$HA_URL/api/states/ENTITY_ID" -H "Authorization: Bearer $HA_TOKEN"
Area & Floor Discovery
Use the template API to query areas, floors, and labels.
# List all areas
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{{ areas() }}"}'
# Entities in a specific area
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{{ area_entities(\"kitchen\") }}"}'
# Only lights in an area
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{{ area_entities(\"kitchen\") | select(\"match\", \"light.\") | list }}"}'
# Find which area an entity belongs to
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{{ area_name(\"light.kitchen\") }}"}'
# List all floors and their areas
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{% for floor in floors() %}{{ floor }}: {{ floor_areas(floor) }}\n{% endfor %}"}'
Switches
# Turn on
curl -s -X POST "$HA_URL/api/services/switch/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "switch.office_lamp"}'
# Turn off
curl -s -X POST "$HA_URL/api/services/switch/turn_off" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "switch.office_lamp"}'
# Toggle
curl -s -X POST "$HA_URL/api/services/switch/toggle" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "switch.office_lamp"}'
Lights
# Turn on with brightness
curl -s -X POST "$HA_URL/api/services/light/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "light.living_room", "brightness_pct": 80}'
# Turn on with color (RGB)
curl -s -X POST "$HA_URL/api/services/light/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "light.living_room", "rgb_color": [255, 150, 50]}'
# Turn on with color temperature (mireds)
curl -s -X POST "$HA_URL/api/services/light/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "light.living_room", "color_temp": 300}'
# Turn off
curl -s -X POST "$HA_URL/api/services/light/turn_off" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "light.living_room"}'
Scenes
curl -s -X POST "$HA_URL/api/services/scene/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "scene.movie_time"}'
Scripts
# List all scripts
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("script.")) | "\(.entity_id): \(.state)"'
# Run a script
curl -s -X POST "$HA_URL/api/services/script/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "script.bedtime_routine"}'
# Run a script with variables
curl -s -X POST "$HA_URL/api/services/script/bedtime_routine" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"variables": {"brightness": 20, "delay_minutes": 5}}'
Automations
# List all automations
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("automation.")) | "\(.entity_id): \(.state)"'
# Trigger an automation
curl -s -X POST "$HA_URL/api/services/automation/trigger" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "automation.morning_routine"}'
# Enable automation
curl -s -X POST "$HA_URL/api/services/automation/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "automation.morning_routine"}'
# Disable automation
curl -s -X POST "$HA_URL/api/services/automation/turn_off" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "automation.morning_routine"}'
Climate Control
# Get thermostat state
curl -s "$HA_URL/api/states/climate.thermostat" -H "Authorization: Bearer $HA_TOKEN" \
| jq '{state: .state, current_temp: .attributes.current_temperature, target_temp: .attributes.temperature}'
# Set temperature
curl -s -X POST "$HA_URL/api/services/climate/set_temperature" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "climate.thermostat", "temperature": 72}'
# Set HVAC mode (heat, cool, auto, off)
curl -s -X POST "$HA_URL/api/services/climate/set_hvac_mode" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "climate.thermostat", "hvac_mode": "auto"}'
Covers (Blinds, Garage Doors)
Safety: Confirm with the user before opening/closing garage doors or gates.
# Open
curl -s -X POST "$HA_URL/api/services/cover/open_cover" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "cover.garage_door"}'
# Close
curl -s -X POST "$HA_URL/api/services/cover/close_cover" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "cover.garage_door"}'
# Set position (0 = closed, 100 = open)
curl -s -X POST "$HA_URL/api/services/cover/set_cover_position" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "cover.blinds", "position": 50}'
Locks
Safety: Always confirm with the user before locking/unlocking.
# Lock
curl -s -X POST "$HA_URL/api/services/lock/lock" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "lock.front_door"}'
# Unlock
curl -s -X POST "$HA_URL/api/services/lock/unlock" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "lock.front_door"}'
Fans
# Turn on
curl -s -X POST "$HA_URL/api/services/fan/turn_on" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "fan.bedroom", "percentage": 50}'
# Turn off
curl -s -X POST "$HA_URL/api/services/fan/turn_off" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "fan.bedroom"}'
Media Players
# Play/pause
curl -s -X POST "$HA_URL/api/services/media_player/media_play_pause" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "media_player.living_room_tv"}'
# Set volume (0.0 to 1.0)
curl -s -X POST "$HA_URL/api/services/media_player/volume_set" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "media_player.living_room_tv", "volume_level": 0.5}'
Vacuum
# Start cleaning
curl -s -X POST "$HA_URL/api/services/vacuum/start" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "vacuum.robot"}'
# Return to dock
curl -s -X POST "$HA_URL/api/services/vacuum/return_to_base" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "vacuum.robot"}'
Alarm Control Panel
Safety: Always confirm with the user before arming/disarming.
# Arm (home mode)
curl -s -X POST "$HA_URL/api/services/alarm_control_panel/alarm_arm_home" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "alarm_control_panel.home"}'
# Disarm (requires code if configured)
curl -s -X POST "$HA_URL/api/services/alarm_control_panel/alarm_disarm" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "alarm_control_panel.home", "code": "1234"}'
Notifications
# List available notification targets
curl -s "$HA_URL/api/services" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.domain == "notify") | .services | keys[]' | sort
# Send a notification to a mobile device
curl -s -X POST "$HA_URL/api/services/notify/mobile_app_phone" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "Front door opened", "title": "Home Alert"}'
# Send to all devices (default notify service)
curl -s -X POST "$HA_URL/api/services/notify/notify" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "System alert", "title": "Home Assistant"}'
Replace mobile_app_phone with the actual service name from the list command.
Person & Presence
# Who is home?
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("person.")) | "\(.attributes.friendly_name // .entity_id): \(.state)"'
# Device tracker locations
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("device_tracker.")) | "\(.entity_id): \(.state)"'
States: home, not_home, or a zone name.
Weather
# Current weather
curl -s "$HA_URL/api/states/weather.home" -H "Authorization: Bearer $HA_TOKEN" \
| jq '{state: .state, temperature: .attributes.temperature, humidity: .attributes.humidity, wind_speed: .attributes.wind_speed}'
# Get forecast (daily)
curl -s -X POST "$HA_URL/api/services/weather/get_forecasts" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "weather.home", "type": "daily"}'
# Get forecast (hourly)
curl -s -X POST "$HA_URL/api/services/weather/get_forecasts" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "weather.home", "type": "hourly"}'
Input Helpers
# Toggle an input boolean
curl -s -X POST "$HA_URL/api/services/input_boolean/toggle" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "input_boolean.guest_mode"}'
# Set input number
curl -s -X POST "$HA_URL/api/services/input_number/set_value" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "input_number.target_temperature", "value": 72}'
# Set input select
curl -s -X POST "$HA_URL/api/services/input_select/select_option" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "input_select.house_mode", "option": "Away"}'
# Set input text
curl -s -X POST "$HA_URL/api/services/input_text/set_value" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "input_text.welcome_message", "value": "Welcome home!"}'
# Set input datetime
curl -s -X POST "$HA_URL/api/services/input_datetime/set_datetime" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "input_datetime.alarm_time", "time": "07:30:00"}'
Calendar
# List all calendars
curl -s "$HA_URL/api/calendars" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[].entity_id'
# Get upcoming events (next 7 days)
curl -s "$HA_URL/api/calendars/calendar.personal?start=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)&end=$(date -u -v+7d +%Y-%m-%dT%H:%M:%S.000Z)" \
-H "Authorization: Bearer $HA_TOKEN" \
| jq '[.[] | {summary: .summary, start: .start.dateTime, end: .end.dateTime}]'
Text-to-Speech
curl -s -X POST "$HA_URL/api/services/tts/speak" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "tts.google_en", "media_player_entity_id": "media_player.living_room_speaker", "message": "Dinner is ready"}'
Replace tts.google_en with your TTS entity and media_player.living_room_speaker with the target speaker.
Call Any Service
The general pattern for any HA service:
curl -s -X POST "$HA_URL/api/services/{domain}/{service}" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "domain.entity_name", ...}'
Batch operations
Control multiple entities in one call by passing an array of entity IDs:
# Turn off all living room lights at once
curl -s -X POST "$HA_URL/api/services/light/turn_off" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": ["light.living_room", "light.living_room_lamp", "light.living_room_ceiling"]}'
Error Handling
Check API connectivity
curl -s -o /dev/null -w "%{http_code}" "$HA_URL/api/" \
-H "Authorization: Bearer $HA_TOKEN"
# Expect: 200
Verify entity exists before acting
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"$HA_URL/api/states/light.nonexistent" \
-H "Authorization: Bearer $HA_TOKEN")
# 200 = exists, 404 = not found
HTTP status codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request (malformed JSON or invalid service data) |
| 401 | Unauthorized (bad or missing token) |
| 404 | Entity or endpoint not found |
| 405 | Method not allowed (wrong HTTP method) |
| 503 | Home Assistant is starting up or unavailable |
Response Format
Service calls return an array of state objects for affected entities:
[{"entity_id": "light.living_room", "state": "on", "attributes": {...}, "last_changed": "..."}]
- Successful call with no state change: returns
[](empty array) - State read (
/api/states/...): returns a single state object - Errors: returns
{"message": "..."}with an HTTP error code
Template Evaluation
The /api/template endpoint evaluates Jinja2 templates server-side. Useful for computed queries.
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "TEMPLATE_STRING"}'
Examples
# Count entities by domain
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{{ states.light | list | count }} lights"}'
# Get entity state in a template
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{{ states(\"light.living_room\") }}"}'
# List all entities that are "on"
curl -s -X POST "$HA_URL/api/template" \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "{{ states | selectattr(\"state\", \"eq\", \"on\") | map(attribute=\"entity_id\") | list }}"}'
Available template functions: states(), is_state(), state_attr(), areas(), area_entities(), area_name(), floors(), floor_areas(), labels(), label_entities(), devices(), device_entities(), now(), relative_time().
History & Logbook
Entity state history
# Last 24 hours for a specific entity
curl -s "$HA_URL/api/history/period?filter_entity_id=sensor.temperature" \
-H "Authorization: Bearer $HA_TOKEN" \
| jq '.[0] | [.[] | {state: .state, last_changed: .last_changed}]'
# Specific time range (ISO 8601)
curl -s "$HA_URL/api/history/period/2025-01-15T00:00:00Z?end_time=2025-01-15T23:59:59Z&filter_entity_id=sensor.temperature" \
-H "Authorization: Bearer $HA_TOKEN" \
| jq '.[0]'
Logbook
# Recent logbook entries
curl -s "$HA_URL/api/logbook" -H "Authorization: Bearer $HA_TOKEN" \
| jq '.[:10]'
# Logbook for a specific entity
curl -s "$HA_URL/api/logbook?entity=light.living_room" \
-H "Authorization: Bearer $HA_TOKEN" \
| jq '.[:10] | [.[] | {name: .name, message: .message, when: .when}]'
Dashboard Overview
Quick status of all active devices:
# All lights that are on
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("light.")) | select(.state == "on") | .entity_id'
# All open doors/windows (binary sensors)
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("binary_sensor.")) | select(.state == "on") | select(.attributes.device_class == "door" or .attributes.device_class == "window") | .entity_id'
# Temperature sensors
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("sensor.")) | select(.attributes.device_class == "temperature") | "\(.attributes.friendly_name // .entity_id): \(.state)\(.attributes.unit_of_measurement // "")"'
# Climate summary (all thermostats)
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("climate.")) | "\(.attributes.friendly_name // .entity_id): \(.state), current: \(.attributes.current_temperature)°, target: \(.attributes.temperature)°"'
# Lock status
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("lock.")) | "\(.attributes.friendly_name // .entity_id): \(.state)"'
# Who is home
curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \
| jq -r '.[] | select(.entity_id | startswith("person.")) | "\(.attributes.friendly_name // .entity_id): \(.state)"'
Entity Domains
| Domain | Examples |
|---|---|
switch.* |
Smart plugs, generic switches |
light.* |
Lights (Hue, LIFX, etc.) |
scene.* |
Pre-configured scenes |
script.* |
Reusable action sequences |
automation.* |
Automations |
climate.* |
Thermostats, AC units |
cover.* |
Blinds, garage doors, gates |
lock.* |
Smart locks |
fan.* |
Fans, ventilation |
media_player.* |
TVs, speakers, streaming devices |
vacuum.* |
Robot vacuums |
alarm_control_panel.* |
Security systems |
notify.* |
Notification targets |
person.* |
People / presence tracking |
device_tracker.* |
Device locations |
weather.* |
Weather conditions and forecasts |
calendar.* |
Calendar events |
tts.* |
Text-to-speech engines |
sensor.* |
Temperature, humidity, power, etc. |
binary_sensor.* |
Motion, door/window, presence |
input_boolean.* |
Virtual toggles |
input_number.* |
Numeric sliders |
input_select.* |
Dropdown selectors |
input_text.* |
Text inputs |
input_datetime.* |
Date/time inputs |
Notes
- API returns JSON by default
- Long-lived tokens don't expire — store securely
- Test entity IDs with the list command first
- For locks, alarms, and garage doors — always confirm actions with the user