Browse all 86 MCP tools across 24 categories.
Get Home Assistant add-ons - list installed, available, or get details for one. This tool retrieves add-on information based on the parameters: - slug provided: Returns detailed info for a single add-on (ingress, ports, options, state) - source='installed' (default): Lists currently installed add-ons - source='available': Lists add-ons available in the add-on store **Note:** This tool only works with Home Assistant OS or Supervised installations. **SINGLE ADD-ON (slug provided):** Returns comprehensive details including ingress entry, ports, options, state, and (when the add-on exposes one) a top-level ``log_level`` reflecting the current Supervisor option — useful for confirming ha_manage_addon log_level changes. Useful for discovering what APIs an add-on exposes before calling ha_manage_addon. **INSTALLED ADD-ONS (source='installed'):** Returns add-ons with version, state (started/stopped), and update availability. - include_stats: Optionally include CPU/memory usage statistics **AVAILABLE ADD-ONS (source='available'):** Returns add-ons from official and custom repositories that can be installed. - repository: Filter by repository slug (e.g., 'core', 'community') - query: Search by name or description (case-insensitive) **Example Usage:** - List installed add-ons: ha_get_addon() - Get Node-RED details: ha_get_addon(slug="a0d7b954_nodered") - List with resource usage: ha_get_addon(include_stats=True) - List available add-ons: ha_get_addon(source="available") - Search for MQTT: ha_get_addon(source="available", query="mqtt")
source - (Annotated[str | None, Field(description="Add-on source: 'installed' (default) for currently installed add-ons, 'available' for add-ons in the store that can be installed.", default=None)])
= null slug - (Annotated[str | None, Field(description="Add-on slug for detailed info (e.g., 'a0d7b954_nodered'). Omit to list all add-ons.", default=None)])
= null include_stats - (Annotated[bool, Field(description="Include CPU/memory usage statistics (only for source='installed')", default=False)])
= false repository - (Annotated[str | None, Field(description="Filter by repository slug, e.g., 'core', 'community' (only for source='available')", default=None)])
= null query - (Annotated[str | None, Field(description="Search filter for add-on names/descriptions (only for source='available')", default=None)])
= null Manage a Home Assistant add-on — update its configuration or call its internal API. Two mutually exclusive operating modes: **Config mode** (when any of options/network/boot/auto_update/watchdog is provided): Updates the add-on's Supervisor configuration via POST /addons/{slug}/options. All config parameters are optional; only provided fields are updated — current values are fetched and merged automatically (including one level of nested dicts). **Proxy mode** (when path is provided): Sends requests directly to the add-on container's own web API via HTTP or WebSocket. Use ha_get_addon(slug="...") to discover available ports and endpoints. **Response shaping (proxy mode):** - WebSocket streams can be noisy (ESPHome /validate often emits hundreds of config-dump lines). By default, `summarize=True` collapses long runs of non-signal messages into short elision markers; INFO/WARNING/ERROR/exit lines always pass through. Pagination via `message_offset` / `message_limit` works on the raw collected list before summarize runs. - `python_transform` applies a sandboxed Python expression as a final post-processing step in both HTTP and WebSocket modes. The variable `response` is bound to: * WebSocket: `list[dict | str]` — parsed JSON messages are dicts, undecodable frames stay as ANSI-stripped strings. Elision markers appear as `{"elided": N, "note": "..."}` dicts when summarize ran. * HTTP: `dict | list | str` — whichever the content-type produced. Transforms may mutate in place (response.append(...), del response[k]) or reassign (response = [...]). This is post-processing only — it does NOT provide optimistic-locking or write-back semantics. **WARNING:** Setting boot="auto"/"manual" will fail for add-ons whose Supervisor metadata locks the boot mode. The Supervisor returns an error in this case. **NOTE:** This tool only works with Home Assistant OS or Supervised installations. **Examples:** - Set add-on option: ha_manage_addon(slug="...", options={"log_level": "debug"}) Note: only the fields you provide are updated — current values are fetched first and merged automatically. Fields not in the add-on's schema are ignored with a warning. - Disable auto-update: ha_manage_addon(slug="...", auto_update=False) - Change host port: ha_manage_addon(slug="...", network={"5800/tcp": 8082}) - Set boot mode: ha_manage_addon(slug="...", boot="manual") - Call HTTP API: ha_manage_addon(slug="...", path="/api/events") - Direct port: ha_manage_addon(slug="...", path="/flows", port=1880) - WebSocket: ha_manage_addon(slug="...", path="/validate", port=6052, websocket=True, body={"type": "spawn", "configuration": "device.yaml"}) - Quick WS health check (50 msgs, raw): ha_manage_addon(slug="...", path="/logs", websocket=True, message_limit=50, summarize=False) - Filter WS errors only: ha_manage_addon(slug="...", path="/validate", websocket=True, python_transform="response = [m for m in response if 'ERROR' in str(m) or 'WARN' in str(m)]") - HTTP subset: ha_manage_addon(slug="...", path="/flows", python_transform="response = [f['id'] for f in response]")
slug required - (Annotated[str, Field(description="Add-on slug (e.g., 'a0d7b954_nodered', 'ccab4aaf_frigate'). Use ha_get_addon() to find installed add-on slugs.")]) path - (Annotated[str | None, Field(description="Proxy mode: API path relative to the add-on root (e.g., '/flows', '/api/events', '/api/stats'). Required for proxy mode; mutually exclusive with config parameters.", default=None)])
= null method - (Annotated[str, Field(description='Proxy mode only. HTTP method: GET, POST, PUT, DELETE, PATCH. Defaults to GET.', default='GET')])
= "GET" body - (Annotated[dict[str, Any] | str | None, Field(description='Proxy mode only. Request body for POST/PUT/PATCH. Pass a JSON object or JSON string.', default=None)])
= null debug - (Annotated[bool, Field(description='Proxy mode only. Include diagnostic info (request URL, headers sent, response headers). Default: false.', default=False)])
= false port - (Annotated[int | None, Field(description="Proxy mode only. Connect to this port instead of the Ingress port. Use ha_get_addon(slug='...') to find available ports.", default=None)])
= null offset - (Annotated[int, Field(description='Proxy mode only. HTTP: skip this many items in a JSON array response. Default: 0.', default=0)])
= 0 limit - (Annotated[int | None, Field(description='Proxy mode only. HTTP: return at most this many items from a JSON array response.', default=None)])
= null websocket - (Annotated[bool, Field(description="Proxy mode only. Use WebSocket instead of HTTP. For streaming endpoints (e.g., ESPHome /compile, /validate). Sends 'body' as initial message, collects responses. Default: false.", default=False)])
= false wait_for_close - (Annotated[bool, Field(description='Proxy mode only. WebSocket: True: wait for server to close (for compile/validate). False: return after first response batch (for quick commands). Default: true.', default=True)])
= true message_limit - (Annotated[int | None, Field(description='Proxy mode only. WebSocket: cap on messages collected from the wire, bounded by an internal safety ceiling. None = collect up to the ceiling. Lower to save tokens on noisy streams (e.g., message_limit=50 for a quick health check).', default=None)])
= null message_offset - (Annotated[int, Field(description='Proxy mode only. WebSocket: drop this many messages from the start of the collected list before returning. Useful for paginating past known-noisy headers. Default: 0.', default=0)])
= 0 summarize - (Annotated[bool, Field(description='Proxy mode only. WebSocket: when True (default), collapse runs of non-signal messages (typically YAML config dumps) into short elision markers. Set to False to return the raw stream.', default=True)])
= true python_transform - (Annotated[str | None, Field(description="Proxy mode only. Sandboxed Python expression that post-processes the response. Variable `response` is exposed — a list[dict | str] for WebSocket (parsed JSON or raw text), or dict/list/str for HTTP (parsed body). Supports in-place mutation (response.append(...)) or reassignment (response = [...]). Example: response = [m for m in response if 'ERROR' in str(m)]. Post-processing only — does not provide optimistic-locking write semantics.", default=None)])
= null options - (Annotated[dict[str, Any] | None, Field(description="Config mode: Add-on configuration values (the 'Configuration' tab in the UI).", default=None)])
= null network - (Annotated[dict[str, Any] | None, Field(description="Config mode: Host port mappings (e.g., {'5800/tcp': 8081}).", default=None)])
= null boot - (Annotated[str | None, Field(description="Config mode: Boot strategy — 'auto' (start with HA) or 'manual'.", default=None)])
= null auto_update - (Annotated[bool | None, Field(description='Config mode: Enable or disable automatic updates for this add-on.', default=None)])
= null watchdog - (Annotated[bool | None, Field(description='Config mode: Enable or disable Supervisor watchdog (auto-restart on crash).', default=None)])
= null List all Home Assistant areas (rooms). Returns area ID, name, icon, floor assignment, aliases, and picture URL.
List all Home Assistant floors. Returns floor ID, name, icon, level (0=ground, 1=first, -1=basement), and aliases.
Delete a Home Assistant area. Entities and devices in the area are not deleted, just unassigned. May break automations referencing this area.
area_id required - (Annotated[str, Field(description='Area ID to delete (use ha_config_list_areas to find IDs)')]) Delete a Home Assistant floor. Areas on this floor are not deleted, just unassigned. May break automations referencing this floor.
floor_id required - (Annotated[str, Field(description='Floor ID to delete (use ha_config_list_floors to find IDs)')]) Create or update a Home Assistant area (room). Areas organize entities by physical location for room-based control. Create: provide name only. Update: provide area_id (from ha_config_list_areas) plus any fields to change. EXAMPLES: ha_config_set_area(name="Kitchen") ha_config_set_area(name="Living Room", icon="mdi:sofa") ha_config_set_area(area_id="kitchen", name="Kitchen Renamed", floor_id="ground_floor")
name - (Annotated[str | None, Field(description="Name for the area (required for create, optional for update, e.g., 'Living Room', 'Kitchen')", default=None)])
= null area_id - (Annotated[str | None, Field(description='Area ID to update (omit to create new area, use ha_config_list_areas to find IDs)', default=None)])
= null floor_id - (Annotated[str | None, Field(description='Floor ID to assign this area to (use ha_config_list_floors to find IDs, empty string to remove)', default=None)])
= null icon - (Annotated[str | None, Field(description="Material Design Icon (e.g., 'mdi:sofa', 'mdi:bed', empty string to remove)", default=None)])
= null aliases - (Annotated[str | list[str] | None, Field(description="Alternative names for voice assistant recognition (e.g., ['lounge', 'family room'], empty list to clear)", default=None)])
= null picture - (Annotated[str | None, Field(description='URL to a picture representing the area (empty string to remove)', default=None)])
= null Create or update a Home Assistant floor. Provide name only to create a new floor. Provide floor_id to update existing. Floors organize areas into vertical levels for building-wide control.
name - (Annotated[str | None, Field(description="Name for the floor (required for create, optional for update, e.g., 'Ground Floor', 'Basement')", default=None)])
= null floor_id - (Annotated[str | None, Field(description='Floor ID to update (omit to create new floor, use ha_config_list_floors to find IDs)', default=None)])
= null level - (Annotated[int | None, Field(description='Numeric level for ordering (0=ground, 1=first, -1=basement, etc.)', default=None)])
= null icon - (Annotated[str | None, Field(description="Material Design Icon (e.g., 'mdi:home-floor-1', 'mdi:home-floor-b', empty string to remove)", default=None)])
= null aliases - (Annotated[str | list[str] | None, Field(description="Alternative names for voice assistant recognition (e.g., ['downstairs', 'main level'], empty list to clear)", default=None)])
= null List floors sorted by level ascending, each with their assigned areas nested, plus areas without a floor. Do not use for flat listings — ha_config_list_areas and ha_config_list_floors cover those. Use for location-based reasoning where floor-to-area relationships matter, such as "which rooms are on the ground floor" or operations scoped to a level. Floors with level=None sort alongside level 0 (ground floor). Areas without a floor assignment appear in unassigned_areas; areas whose floor_id points to a non-existent floor appear in orphaned_areas — a topology snapshot may diverge from individual list calls if the registries change between reads.
Retrieve Home Assistant automation configuration. Returns the complete configuration including triggers, conditions, actions, and mode settings. EXAMPLES: - Get automation: ha_config_get_automation("automation.morning_routine") - Get by unique_id: ha_config_get_automation("my_unique_automation_id") For comprehensive automation documentation, use ha_get_skill_home_assistant_best_practices.
identifier required - (Annotated[str, Field(description="Automation entity_id (e.g., 'automation.morning_routine') or unique_id")]) Delete a Home Assistant automation. EXAMPLES: - Delete automation: ha_config_remove_automation("automation.old_automation") - Delete by unique_id: ha_config_remove_automation("my_unique_id") **WARNING:** Deleting an automation removes it permanently from your Home Assistant configuration.
identifier required - (Annotated[str, Field(description="Automation entity_id (e.g., 'automation.old_automation') or unique_id to delete")]) wait - (Annotated[bool | str, Field(description='Wait for automation to be fully removed before returning. Default: True.', default=True)])
= true Create or update a Home Assistant automation. Supports two modes: full config replacement OR Python transformation. WHEN TO USE WHICH MODE: - python_transform: RECOMMENDED for edits to existing automations. Surgical updates. - config: Use for creating new automations or full restructures. IMPORTANT: python_transform requires 'identifier' and 'config_hash' from ha_config_get_automation(). PYTHON TRANSFORM EXAMPLES: - Update action: python_transform="config['action'][0]['data']['brightness'] = 255" - Add trigger: python_transform="config['trigger'].append({'platform': 'state', 'entity_id': 'binary_sensor.motion', 'to': 'on'})" - Remove last action: python_transform="config['action'].pop()" Creates a new automation (if identifier omitted) or updates existing automation with provided configuration. AUTOMATION TYPES: 1. Regular Automations - Define triggers and actions directly 2. Blueprint Automations - Use pre-built templates with customizable inputs REQUIRED FIELDS (Regular Automations): - alias: Human-readable automation name - trigger: List of trigger conditions (time, state, event, etc.) - action: List of actions to execute REQUIRED FIELDS (Blueprint Automations): - alias: Human-readable automation name - use_blueprint: Blueprint configuration - path: Blueprint file path (e.g., "motion_light.yaml") - input: Dictionary of input values for the blueprint OPTIONAL CONFIG FIELDS (Regular Automations): - description: Detailed description of the user's intent (RECOMMENDED: helps safely modify implementation later) - category: Category ID for organization (use ha_config_get_category to list, ha_config_set_category to create) - condition: Additional conditions that must be met - mode: 'single' (default), 'restart', 'queued', 'parallel' - max: Maximum concurrent executions (for queued/parallel modes) - initial_state: Whether automation starts enabled (true/false) - variables: Variables for use in automation BASIC EXAMPLES: Simple time-based automation: ha_config_set_automation(config={ "alias": "Morning Lights", "description": "Turn on bedroom lights at 7 AM to help wake up", "trigger": [{"platform": "time", "at": "07:00:00"}], "action": [{"service": "light.turn_on", "target": {"area_id": "bedroom"}}] }) Motion-activated lighting with condition: ha_config_set_automation(config={ "alias": "Motion Light", "trigger": [{"platform": "state", "entity_id": "binary_sensor.motion", "to": "on"}], "condition": [{"condition": "sun", "after": "sunset"}], "action": [ {"service": "light.turn_on", "target": {"entity_id": "light.hallway"}}, {"delay": {"minutes": 5}}, {"service": "light.turn_off", "target": {"entity_id": "light.hallway"}} ], "mode": "restart" }) Update existing automation: ha_config_set_automation( identifier="automation.morning_routine", config={ "alias": "Updated Morning Routine", "trigger": [{"platform": "time", "at": "06:30:00"}], "action": [ {"service": "light.turn_on", "target": {"area_id": "bedroom"}}, {"service": "climate.set_temperature", "target": {"entity_id": "climate.bedroom"}, "data": {"temperature": 22}} ] } ) BLUEPRINT AUTOMATION EXAMPLES: Create automation from blueprint: ha_config_set_automation(config={ "alias": "Motion Light Kitchen", "use_blueprint": { "path": "homeassistant/motion_light.yaml", "input": { "motion_entity": "binary_sensor.kitchen_motion", "light_target": {"entity_id": "light.kitchen"}, "no_motion_wait": 120 } } }) Update blueprint automation inputs: ha_config_set_automation( identifier="automation.motion_light_kitchen", config={ "alias": "Motion Light Kitchen", "use_blueprint": { "path": "homeassistant/motion_light.yaml", "input": { "motion_entity": "binary_sensor.kitchen_motion", "light_target": {"entity_id": "light.kitchen"}, "no_motion_wait": 300 } } } ) PREFER NATIVE SOLUTIONS OVER TEMPLATES: Before using template triggers/conditions/actions, check if a native option exists: - Use `condition: state` with `state: [list]` instead of template for multiple states - Use `condition: state` with `attribute:` instead of template for attribute checks - Use `condition: numeric_state` instead of template for number comparisons - Use `wait_for_trigger` instead of `wait_template` when waiting for state changes - Use `choose` action instead of template-based service names TRIGGER TYPES: time, time_pattern, sun, state, numeric_state, event, device, zone, template, and more CONDITION TYPES: state, numeric_state, time, sun, template, device, zone, and more ACTION TYPES: service calls, delays, wait_for_trigger, wait_template, if/then/else, choose, repeat, parallel For comprehensive automation documentation with all trigger/condition/action types and advanced examples: - Use: ha_get_skill_home_assistant_best_practices - Or visit: https://www.home-assistant.io/docs/automation/ TROUBLESHOOTING: - Use ha_get_state() to verify entity_ids exist - Use ha_search_entities() to find correct entity_ids - Use ha_eval_template() to test Jinja2 templates before using in automations - Use ha_search_entities(domain_filter='automation') to find existing automations
config - (Annotated[str | dict[str, Any] | None, Field(description="Complete automation configuration with required fields: 'alias', 'trigger', 'action'. Optional: 'description', 'condition', 'mode', 'max', 'initial_state', 'variables'. Mutually exclusive with python_transform.", default=None)])
= null identifier - (Annotated[str | None, Field(description='Automation entity_id or unique_id for updates. Required for python_transform. Omit to create new automation with generated unique_id.', default=None)])
= null python_transform - (Annotated[str | None, Field(description='Python expression to transform existing automation config. Mutually exclusive with config. Requires identifier and config_hash for validation. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config[\'action\'][0][\'data\'][\'brightness\'] = 255" Pattern: python_transform="for a in config[\'action\']: if a.get(\'alias\') == \'My Step\': a[\'data\'][\'value\'] = 100" \n\n' + get_security_documentation())])
= null config_hash - (Annotated[str | None, Field(description='Config hash from ha_config_get_automation for optimistic locking. REQUIRED for python_transform (validates automation unchanged). Optional for config updates (validates before full replacement if provided).')])
= null category - (Annotated[str | None, Field(description="Category ID to assign to this automation. Use ha_config_get_category(scope='automation') to list available categories, or ha_config_set_category() to create one.", default=None)])
= null wait - (Annotated[bool | str, Field(description='Wait for automation to be queryable before returning. Default: True. Set to False for bulk operations.', default=True)])
= true Get blueprint information - list all blueprints or get details for a specific one. Without a path: Lists all installed blueprints for the specified domain. With a path: Retrieves full blueprint configuration including inputs, triggers, conditions, and actions. EXAMPLES: - List all automation blueprints: ha_get_blueprint(domain="automation") - List script blueprints: ha_get_blueprint(domain="script") - Get specific blueprint: ha_get_blueprint(path="homeassistant/motion_light.yaml", domain="automation") RETURNS (when listing): - List of blueprints with path, name, and domain information - Count of blueprints found RETURNS (when getting specific blueprint): - Blueprint metadata (name, description, author, source_url) - Input definitions with selectors and defaults - Blueprint configuration (triggers, conditions, actions for automations; sequence for scripts)
path - (Annotated[str | None, Field(description="Blueprint path to get details for (e.g., 'homeassistant/motion_light.yaml'). If omitted, lists all blueprints in the domain.", default=None)])
= null domain - (Annotated[str, Field(description="Blueprint domain: 'automation' or 'script'", default='automation')])
= "automation" Import a blueprint from a URL. Imports a blueprint from GitHub, Home Assistant Community forums, or any direct URL to a blueprint YAML file. EXAMPLES: - Import from GitHub: ha_import_blueprint("https://github.com/user/repo/blob/main/blueprint.yaml") - Import from HA Community: ha_import_blueprint("https://community.home-assistant.io/t/motion-light/123456") - Import direct YAML: ha_import_blueprint("https://example.com/my-blueprint.yaml") SUPPORTED SOURCES: - GitHub repository URLs (will be converted to raw URLs) - Home Assistant Community forum posts with blueprint code - Direct URLs to YAML blueprint files RETURNS: - Import result with the blueprint path where it was saved - Blueprint metadata (name, domain, description) - Error details if import fails
url required - (Annotated[str, Field(description='URL to import blueprint from (GitHub, Home Assistant Community, or direct YAML URL)')]) Retrieve calendar events from a calendar entity. Retrieves calendar events within a specified time range. **Parameters:** - entity_id: Calendar entity ID (e.g., 'calendar.family') - start: Start datetime in ISO format (default: now) - end: End datetime in ISO format (default: 7 days from start) - max_results: Maximum number of events to return (default: 20) **Example Usage:** ```python # Get events for the next week events = ha_config_get_calendar_events("calendar.family") # Get events for a specific date range events = ha_config_get_calendar_events( "calendar.work", start="2024-01-01T00:00:00", end="2024-01-31T23:59:59" ) ``` **Note:** To find calendar entities, use ha_search_entities(query='calendar', domain_filter='calendar') **Returns:** - List of calendar events with summary, start, end, description, location
entity_id required - (Annotated[str, Field(description="Calendar entity ID (e.g., 'calendar.family')")]) start - (Annotated[str | None, Field(description='Start datetime in ISO format (default: now)', default=None)])
= null end - (Annotated[str | None, Field(description='End datetime in ISO format (default: 7 days from start)', default=None)])
= null max_results - (Annotated[int, Field(description='Maximum number of events to return', default=20)])
= 20 Delete an event from a calendar. Deletes a calendar event using the calendar.delete_event service. **Parameters:** - entity_id: Calendar entity ID (e.g., 'calendar.family') - uid: Unique identifier of the event to delete - recurrence_id: Optional recurrence ID for recurring events - recurrence_range: Optional recurrence range ('THIS_AND_FUTURE' to delete this and future occurrences) **Example Usage:** ```python # Delete a single event result = ha_config_remove_calendar_event( "calendar.family", uid="event-12345" ) # Delete a recurring event instance and future occurrences result = ha_config_remove_calendar_event( "calendar.work", uid="recurring-event-67890", recurrence_id="20240115T100000", recurrence_range="THIS_AND_FUTURE" ) ``` **Note:** To get the event UID, first use ha_config_get_calendar_events() to list events. The UID is returned in each event's data. **Returns:** - Success status and deletion confirmation
entity_id required - (Annotated[str, Field(description="Calendar entity ID (e.g., 'calendar.family')")]) uid required - (Annotated[str, Field(description='Unique identifier of the event to delete')]) recurrence_id - (Annotated[str | None, Field(description='Optional recurrence ID for recurring events', default=None)])
= null recurrence_range - (Annotated[str | None, Field(description="Optional recurrence range ('THIS_AND_FUTURE' to delete this and future occurrences)", default=None)])
= null Create a new event in a calendar. Creates a calendar event using the calendar.create_event service. **Parameters:** - entity_id: Calendar entity ID (e.g., 'calendar.family') - summary: Event title/summary - start: Event start datetime in ISO format - end: Event end datetime in ISO format - description: Optional event description - location: Optional event location **Example Usage:** ```python # Create a simple event result = ha_config_set_calendar_event( "calendar.family", summary="Doctor appointment", start="2024-01-15T14:00:00", end="2024-01-15T15:00:00" ) # Create an event with details result = ha_config_set_calendar_event( "calendar.work", summary="Team meeting", start="2024-01-16T10:00:00", end="2024-01-16T11:00:00", description="Weekly sync meeting", location="Conference Room A" ) ``` **Returns:** - Success status and event details
entity_id required - (Annotated[str, Field(description="Calendar entity ID (e.g., 'calendar.family')")]) summary required - (Annotated[str, Field(description='Event title/summary')]) start required - (Annotated[str, Field(description='Event start datetime in ISO format')]) end required - (Annotated[str, Field(description='Event end datetime in ISO format')]) description - (Annotated[str | None, Field(description='Optional event description', default=None)])
= null location - (Annotated[str | None, Field(description='Optional event location', default=None)])
= null Retrieve a snapshot image from a Home Assistant camera entity. This tool fetches the current camera image and returns it directly for visual analysis. Use this when you need to see what a camera is currently viewing. **Parameters:** - entity_id: Camera entity ID (e.g., 'camera.front_door', 'camera.living_room') - width: Optional width to resize the image (reduces token usage for large images) - height: Optional height to resize the image **Use Cases:** - Security checks: "Is someone at the front door?" - Pet monitoring: "Is my dog still on the couch?" - Delivery verification: "Did my package get delivered?" - Visual confirmation: "Did the garage door actually close?" - Incident investigation: "What triggered the motion sensor?" **Example Usage:** ```python # Get current snapshot from front door camera ha_get_camera_image(entity_id="camera.front_door") # Get resized image to reduce token usage ha_get_camera_image(entity_id="camera.backyard", width=640, height=480) ``` **Notes:** - Only cameras exposed to Home Assistant are accessible - The existing HA authentication/authorization applies - Images are returned in their native format (JPEG, PNG, or GIF) - Use width/height parameters for large high-resolution cameras to reduce token usage when full resolution is not needed **Related Services:** - camera.snapshot: Save snapshot to file on HA server - camera.turn_on/turn_off: Control camera power - camera.enable_motion_detection: Enable motion detection
entity_id required - (str) width - (int | None)
= null height - (int | None)
= null Delete a storage-mode dashboard completely. WARNING: This permanently deletes the dashboard and all its configuration. Cannot be undone. Does not work on YAML-mode dashboards. Accepts either the URL path or the internal dashboard ID. HA internal IDs may differ from url_path (e.g. hyphens → underscores); the tool resolves either form to the actual registry ID before deletion. EXAMPLES: - Delete dashboard: ha_config_delete_dashboard("mobile-dashboard") Note: The default dashboard cannot be deleted via this method.
url_path required - (Annotated[str, Field(description="Dashboard URL path or internal ID to delete (e.g., 'my-dashboard' or 'my_dashboard'). Both forms are accepted.")]) Delete a dashboard resource. Removes a resource from Home Assistant. The resource will no longer be loaded on dashboards. WARNING: Deleting a resource used by custom cards in your dashboards will cause those cards to fail to load. EXAMPLES: ha_config_delete_dashboard_resource(resource_id="abc123") Note: Use ha_config_list_dashboard_resources() to find resource IDs before deleting. Ensure no dashboards depend on the resource.
resource_id required - (Annotated[str, Field(description='Resource ID to delete. Get from ha_config_list_dashboard_resources()')]) Get dashboard info - list all dashboards, get config, or search for cards. MODE 1 — List: list_only=True Lists all storage-mode dashboards with metadata (url_path, title, icon). MODE 2 — Search: any of entity_id / card_type / heading provided Finds cards, badges, and header cards matching the criteria. Returns matches with jq_path for use with ha_config_set_dashboard(python_transform=...). Multiple criteria are AND-ed. Always fetches fresh config (force=True). Strategy dashboards are not searchable (no explicit cards). MODE 3 — Get: Active when list_only=False and no search parameters are provided. Returns the full Lovelace dashboard config, defaulting to the main dashboard if url_path is omitted. EXAMPLES: - List all dashboards: ha_config_get_dashboard(list_only=True) - Get default dashboard: ha_config_get_dashboard(url_path="default") - Get custom dashboard: ha_config_get_dashboard(url_path="lovelace-mobile") - Force reload: ha_config_get_dashboard(url_path="lovelace-home", force_reload=True) - Find cards by entity: ha_config_get_dashboard(url_path="my-dash", entity_id="light.living_room") - Find by wildcard: ha_config_get_dashboard(url_path="my-dash", entity_id="sensor.temperature_*") - Find by type: ha_config_get_dashboard(url_path="my-dash", card_type="tile") - Find heading: ha_config_get_dashboard(url_path="my-dash", heading="Climate", card_type="heading") SEARCH WORKFLOW EXAMPLE: 1. find = ha_config_get_dashboard(url_path="my-dash", entity_id="light.bedroom") 2. ha_config_set_dashboard( url_path="my-dash", config_hash=find["config_hash"], python_transform=f'config{find["matches"][0]["jq_path"]}["icon"] = "mdi:lamp"' ) Note: YAML-mode dashboards (defined in configuration.yaml) are not included in list.
url_path - (Annotated[str | None, Field(description="Dashboard URL path (e.g., 'lovelace-home'). Use 'default' for default dashboard. If omitted with list_only=True, lists all dashboards.")])
= null list_only - (Annotated[bool, Field(description='If True, list all dashboards instead of getting config. When True, url_path is ignored.')])
= false force_reload - (Annotated[bool, Field(description='Force reload from storage (bypass cache). Not applicable in search mode (search always uses force=True for fresh results).')])
= false entity_id - (Annotated[str | None, Field(description="Find cards by entity ID. Supports wildcards, e.g. 'sensor.temperature_*'. Matches cards with this entity in 'entity' or 'entities' field, view-level badges, and header cards. When provided, activates search mode (returns matches, not full config).")])
= null card_type - (Annotated[str | None, Field(description="Find cards by type, e.g. 'tile', 'button', 'heading'. When provided, activates search mode.")])
= null heading - (Annotated[str | None, Field(description='Find cards by heading/title text (case-insensitive partial match). When provided, activates search mode.')])
= null include_config - (Annotated[bool, Field(description="In search mode: include each matched card's own configuration object in results (increases output size). Does not affect whether the full dashboard config is returned — search mode always returns matches only, not the full dashboard. Ignored outside search mode.")])
= false List all Lovelace dashboard resources (custom cards, themes, CSS/JS). Returns all registered resources. For inline resources (created with ha_config_set_dashboard_resource(content=...)), shows a preview of the content instead of the full encoded URL to save tokens. Args: include_content: If True, includes full decoded content for inline resources in "_content" field. Default False (150-char preview only). Resource types: - module: ES6 JavaScript modules (modern custom cards) - js: Legacy JavaScript files - css: CSS stylesheets Each resource has a unique ID for update/delete operations. EXAMPLES: - List all resources: ha_config_list_dashboard_resources() - List with full content: ha_config_list_dashboard_resources(include_content=True) Note: Requires advanced mode to be enabled in Home Assistant for resource management through the UI, but API access works regardless.
include_content - (Annotated[bool, Field(description='Include full decoded content for inline resources. Default False to save tokens (shows 150-char preview instead).')])
= false Create or update a Home Assistant dashboard. Creates a new dashboard or updates an existing one with the provided configuration. Supports two modes: full config replacement OR Python transformation. Use 'default' or 'lovelace' to target the built-in default dashboard. New dashboards require a hyphenated url_path (e.g., 'my-dashboard'). WHEN TO USE WHICH MODE: - python_transform: RECOMMENDED for edits. Surgical/pattern-based updates, works on all platforms. - config: New dashboards only, or full restructure. Replaces everything. IMPORTANT: After delete/add operations, indices shift! Subsequent python_transform calls must use fresh config_hash from ha_config_get_dashboard() to get updated structure. Chain multiple ops in ONE expression when possible. TIP: Use ha_config_get_dashboard(entity_id=...) to get the path for any card. PYTHON TRANSFORM EXAMPLES (RECOMMENDED): - Update card icon: 'config["views"][0]["cards"][0]["icon"] = "mdi:thermometer"' - Add card: 'config["views"][0]["cards"].append({"type": "button", "entity": "light.bedroom"})' - Delete card: 'del config["views"][0]["cards"][2]' - Pattern-based update: 'for card in config["views"][0]["cards"]: if "light" in card.get("entity", ""): card["icon"] = "mdi:lightbulb"' - Multi-operation: 'config["views"][0]["cards"][0]["icon"] = "mdi:a"; config["views"][0]["cards"][1]["icon"] = "mdi:b"' MODERN DASHBOARD BEST PRACTICES (2024+): - Use "sections" view type (default) with grid-based layouts - Use "tile" cards as primary card type (replaces legacy entity/light/climate cards) - Use "grid" cards for multi-column layouts within sections - Create multiple views with navigation paths (avoid single-view endless scrolling) - Use "area" cards with navigation for hierarchical organization DISCOVERING ENTITY IDs FOR DASHBOARDS: Do NOT guess entity IDs - use these tools to find exact entity IDs: 1. ha_get_overview(include_entity_id=True) - Get all entities organized by domain/area 2. ha_search_entities(query, domain_filter, area_filter) - Find specific entities 3. ha_deep_search(query) - Comprehensive search across entities, areas, automations If unsure about entity IDs, ALWAYS use one of these tools first. DASHBOARD DOCUMENTATION (via MCP skills): - skill://home-assistant-best-practices/references/dashboard-guide.md — comprehensive guide - skill://home-assistant-best-practices/references/dashboard-cards.md — card types list - ha_get_skill_home_assistant_best_practices — guidance on card types and configuration EXAMPLES: Create empty dashboard: ha_config_set_dashboard( url_path="mobile-dashboard", title="Mobile View", icon="mdi:cellphone" ) Create dashboard with modern sections view: ha_config_set_dashboard( url_path="home-dashboard", title="Home Overview", config={ "views": [{ "title": "Home", "type": "sections", "sections": [{ "title": "Climate", "cards": [{ "type": "tile", "entity": "climate.living_room", "features": [{"type": "target-temperature"}] }] }] }] } ) Create strategy-based dashboard (auto-generated): ha_config_set_dashboard( url_path="my-home", title="My Home", config={ "strategy": { "type": "home", "favorite_entities": ["light.bedroom"] } } ) Note: Strategy dashboards cannot be converted to custom dashboards via this tool. Use the "Take Control" feature in the Home Assistant interface to convert them. Update existing dashboard config: ha_config_set_dashboard( url_path="existing-dashboard", config={ "views": [{ "title": "Updated View", "type": "sections", "sections": [{ "cards": [{"type": "markdown", "content": "Updated!"}] }] }] } ) Note: When updating an existing dashboard, title/icon/require_admin/show_in_sidebar are also updated if explicitly provided alongside (or instead of) a config change.
url_path required - (Annotated[str, Field(description="Dashboard URL path (e.g., 'my-dashboard'). Use 'default' or 'lovelace' for the default dashboard. New dashboards must use a hyphenated path.")]) config - (Annotated[str | dict[str, Any] | None, Field(description='Dashboard configuration with views and cards. Can be dict or JSON string. Omit or set to None to create dashboard without initial config. Mutually exclusive with python_transform.')])
= null python_transform - (Annotated[str | None, Field(description='Python expression to transform existing dashboard config. Mutually exclusive with config. Requires config_hash for validation. See PYTHON TRANSFORM SECURITY below for allowed operations. Examples: Simple: python_transform="config[\'views\'][0][\'cards\'][0][\'icon\'] = \'mdi:lamp\'" Pattern: python_transform="for card in config[\'views\'][0][\'cards\']: if \'light\' in card.get(\'entity\', \'\'): card[\'icon\'] = \'mdi:lightbulb\'" Multi-op: python_transform="config[\'views\'][0][\'cards\'][0][\'icon\'] = \'mdi:lamp\'; del config[\'views\'][0][\'cards\'][2]" \n\n' + get_security_documentation())])
= null config_hash - (Annotated[str | None, Field(description='Config hash from ha_config_get_dashboard for optimistic locking. REQUIRED for python_transform (validates dashboard unchanged). Optional for config (validates before full replacement if provided).')])
= null title - (Annotated[str | None, Field(description='Dashboard display name shown in sidebar')])
= null icon - (Annotated[str | None, Field(description="MDI icon name (e.g., 'mdi:home', 'mdi:cellphone'). Defaults to 'mdi:view-dashboard'")])
= null require_admin - (Annotated[bool | None, Field(description='Restrict dashboard to admin users only. For existing dashboards, only updated when explicitly provided.')])
= null show_in_sidebar - (Annotated[bool | None, Field(description='Show dashboard in sidebar navigation. For existing dashboards, only updated when explicitly provided.')])
= null Create or update a dashboard resource (inline code or external URL). Provide exactly one of: - content: Inline JavaScript or CSS code (embedded in URL, no file storage needed) - url: External resource URL (/local/, /hacsfiles/, or https://...) INLINE MODE (content=): - Custom card code written inline - CSS styling for dashboards - Small utility modules (<24KB) - URLs are deterministic (same content = same URL) - Supports 'module' and 'css' types only (not 'js') URL MODE (url=): - Files in /config/www/ directory (/local/...) - HACS-installed cards (/hacsfiles/...) - External CDN resources (https://...) - Supports all types: 'module', 'js', 'css' RESOURCE TYPES: - module: ES6 JavaScript modules (recommended for custom cards) - js: Legacy JavaScript files (older custom cards, url mode only) - css: CSS stylesheets (themes, global styles) EXAMPLES: Inline custom card: ha_config_set_dashboard_resource( content=""" class MyCard extends HTMLElement { setConfig(config) { this.config = config; } set hass(hass) { this.innerHTML = `<ha-card>Hello ${hass.states[this.config.entity]?.state}</ha-card>`; } } customElements.define('my-card', MyCard); """, resource_type="module" ) Add custom card from www/ directory: ha_config_set_dashboard_resource( url="/local/my-custom-card.js", resource_type="module" ) Add HACS card (after installing via ha_hacs_download): ha_config_set_dashboard_resource( url="/hacsfiles/lovelace-mushroom/mushroom.js", resource_type="module" ) Update existing resource: ha_config_set_dashboard_resource( url="/local/my-card-v2.js", resource_type="module", resource_id="abc123" ) Note: After adding a resource, clear browser cache or hard refresh (Ctrl+Shift+R) to load changes.
content - (Annotated[str | None, Field(description="JavaScript or CSS code to host inline (max ~24KB). The code is embedded in the URL via Cloudflare Worker - no file storage needed. Mutually exclusive with url. Supports 'module' and 'css' types only.")])
= null url - (Annotated[str | None, Field(description='URL of the resource. Can be: /local/file.js (www/ directory), /hacsfiles/component/file.js (HACS), https://cdn.example.com/card.js (external). Mutually exclusive with content.')])
= null resource_type - (Annotated[Literal['module', 'js', 'css'], Field(description="Resource type: 'module' for ES6 modules (modern cards, default), 'js' for legacy JavaScript (url mode only), 'css' for stylesheets")])
= "module" resource_id - (Annotated[str | None, Field(description='Resource ID to update. If omitted, creates a new resource. Get IDs from ha_config_list_dashboard_resources()')])
= null Get device information with pagination, including Zigbee (ZHA/Z2M) and Z-Wave JS devices. Without device_id/entity_id: Lists devices with optional filters and pagination. With device_id or entity_id: Returns full detail for that specific device. **List devices (paginated):** - First page: ha_get_device() - Next page: ha_get_device(offset=50) - By area: ha_get_device(area_id="living_room") - By integration: ha_get_device(integration="zigbee2mqtt") - Full details in list: ha_get_device(detail_level="full", limit=10) **Single device lookup (always full detail):** - By device_id: ha_get_device(device_id="abc123") - By entity_id: ha_get_device(entity_id="light.living_room") **Zigbee:** integration="zha" or "zigbee2mqtt". Returns ieee_address, radio metrics. **Z-Wave:** integration="zwave_js". Returns node_id, node_status.
device_id - (Annotated[str | None, Field(description='Device ID to retrieve details for. If omitted, lists devices.', default=None)])
= null entity_id - (Annotated[str | None, Field(description="Entity ID to find the associated device for (e.g., 'light.living_room')", default=None)])
= null integration - (Annotated[str | None, Field(description="Filter devices by integration: 'zha', 'zigbee2mqtt', 'zwave_js', 'mqtt', 'hue', etc.", default=None)])
= null area_id - (Annotated[str | None, Field(description="Filter devices by area ID (e.g., 'living_room')", default=None)])
= null manufacturer - (Annotated[str | None, Field(description="Filter devices by manufacturer name (e.g., 'Philips')", default=None)])
= null limit - (Annotated[int | str, Field(default=50, description='Max devices to return per page in list mode (default: 50)')])
= 50 offset - (Annotated[int | str, Field(default=0, description='Number of devices to skip for pagination (default: 0)')])
= 0 detail_level - (Annotated[Literal['summary', 'full'], Field(default='summary', description="'summary': basic device info and protocol identifiers (default for list mode). 'full': include entities and all integration details. Single device lookups always return full detail.")])
= "summary" Remove an orphaned device from the Home Assistant device registry. WARNING: This removes the device entry from the registry. - Use only for orphaned devices that are no longer connected - Active devices will typically be re-added by their integration - Associated entities may also be removed This uses the config entry removal which is the safe way to remove devices. If the device has multiple config entries, they must all be removed. EXAMPLES: - Remove orphaned device: ha_remove_device("abc123def456") NOTE: For most use cases, consider disabling the device instead: ha_update_device(device_id="abc123", disabled_by="user")
device_id required - (Annotated[str, Field(description='Device ID to remove from the registry')]) Update device properties such as name, area, disabled state, or labels. IMPORTANT: Renaming a device does NOT rename its entities! Device and entity names are independent. To rename entities, use ha_set_entity(new_entity_id=...). Common workflow for full rename: 1. ha_update_device(device_id="abc", name="Living Room Sensor") # Rename device 2. ha_set_entity("sensor.old", new_entity_id="sensor.living_room") # Rename entities separately PARAMETERS: - name: Sets the user-defined display name (name_by_user) - area_id: Assigns device to an area/room. Use '' to remove from area. - disabled_by: Set to 'user' to disable, or empty to enable - labels: List of labels (replaces existing labels) EXAMPLES: - Rename device: ha_update_device("abc123", name="Living Room Hub") - Move to area: ha_update_device("abc123", area_id="living_room") - Disable device: ha_update_device("abc123", disabled_by="user") - Enable device: ha_update_device("abc123", disabled_by="") - Add labels: ha_update_device("abc123", labels=["important", "sensor"])
device_id required - (Annotated[str, Field(description='Device ID to update')]) name - (Annotated[str | None, Field(description='New display name for the device (sets name_by_user)', default=None)])
= null area_id - (Annotated[str | None, Field(description="Area/room ID to assign the device to. Use empty string '' to unassign.", default=None)])
= null disabled_by - (Annotated[str | None, Field(description="Set to 'user' to disable, or None/empty string to enable", default=None)])
= null labels - (Annotated[str | list[str] | None, Field(description='Labels to assign to the device (replaces existing labels)', default=None)])
= null Manage the Home Assistant Energy Dashboard preferences. The Energy Dashboard configuration (grid/solar/battery/gas sources, individual device consumption sensors, cost tariffs, water) is stored in ``.storage/energy`` and not otherwise reachable via REST, services, or helper flows — this tool is the only way for agents to inspect or modify it. WHEN TO USE: - mode='get' / 'set': inspect or replace the full Energy Dashboard config. Use 'set' for bulk edits or anything touching multiple top-level keys at once. - mode='add_device' / 'remove_device': add or remove a single device-consumption entry. The tool performs a fresh read-modify-write internally; the caller does NOT manage config_hash. Use ``water=True`` to target the water meter list instead of electricity. - mode='add_source': append a single entry to ``energy_sources`` (grid, solar, battery, or gas). Same atomic read-modify-write semantics. WHEN NOT TO USE: - To create the underlying statistics themselves — they must already exist as HA entities before being referenced here; create them via the relevant integration's config flow first. CAVEATS: - ``energy/save_prefs`` has per-key FULL-REPLACE semantics. Passing ``{"device_consumption": [<one entry>]}`` deletes every other device the user had configured — silently, with no error. mode='set' requires a fresh ``config_hash`` for optimistic locking; convenience modes hide this entirely. - ``config_hash`` accepts both a single ``str`` (full-blob lock) and a ``dict[_PrefsKey, str]`` keyed by top-level keys (per-key lock, taken from the ``config_hash_per_key`` field of the mode='get' response). The per-key form lets an agent submit only the top- level key it wants to change — set-equality between ``config`` keys and dict keys is enforced, and any key outside the canonical set (typo, etc.) on either side is rejected with ``VALIDATION_FAILED`` rather than silently dropped (so an empty submission cannot succeed as a no-op). A per-key submission still fully replaces that key's value as the save endpoint requires. Mismatch on any locked key returns ``RESOURCE_LOCKED`` with the offending keys in the response's top-level ``mismatched_keys`` (``create_error_response`` flattens the ``context`` dict onto the response root). - ``dry_run=True`` skips the hash check entirely for both forms; the per-key form is therefore silently accepted on dry runs even if its keys would mismatch the current state. - A local shape check runs before every write; malformed payloads are rejected with a ``shape_errors`` list. - After a successful write, the tool calls ``energy/validate`` and returns any residual issues as ``post_save_validation_errors`` in the response. These reflect semantic problems (missing stats, unit mismatches) that shape checks can't catch; the save persists regardless — correct the config and write again if needed. - The underlying save endpoint is admin-only. Non-admin tokens will receive an authorization error from Home Assistant. - Convenience modes are NOT idempotent: 'add_device' on an existing ``stat_consumption`` returns RESOURCE_ALREADY_EXISTS; 'remove_device' on a missing entry returns RESOURCE_NOT_FOUND. 'add_source' rejects duplicates by ``(type, stat_energy_from)`` for solar/battery/gas (RESOURCE_ALREADY_EXISTS); grid entries are appended without a duplicate check (multiple grid variants are legitimate, and grid has no single canonical uniqueness key) — the caller is responsible for de-duplicating grid sources. - Convenience modes do NOT bypass the local shape check on dry_run: ``dry_run=True`` still raises ``RESOURCE_ALREADY_EXISTS`` (duplicate add_device / add_source), ``RESOURCE_NOT_FOUND`` (missing remove_device), or ``VALIDATION_FAILED`` (post-mutator shape error) when the proposed mutation is not applicable. The mutator and shape check both run before the dry-run short-circuit.
mode required - (Annotated[Literal['get', 'set', 'add_device', 'remove_device', 'add_source'], Field(description="Operation mode. Primitives: 'get' reads the current prefs; 'set' writes a full prefs payload (per-top-level-key full-replace). Convenience modes: 'add_device' / 'remove_device' / 'add_source' perform a single read-modify-write atomically — no config_hash from the caller, the tool fetches it fresh internally.")]) config - (Annotated[dict[str, Any] | None, Field(description="Full prefs payload for mode='set'. Must contain the top-level keys you intend to replace: 'energy_sources', 'device_consumption', 'device_consumption_water'. Any top-level key present in this payload REPLACES the existing list entirely; any omitted key is preserved. Call with mode='get' first, mutate the returned config, then pass the whole object back. Ignored by convenience modes.", default=None)])
= null config_hash - (Annotated[str | dict[_PrefsKey, str] | None, Field(description="Hash from a previous mode='get' call. REQUIRED for mode='set' unless dry_run=True. Two forms: str (full-blob lock) or dict (per-key lock, taken from the config_hash_per_key field of mode='get'). See the tool docstring for fail-closed semantics. Ignored by convenience modes.", default=None)])
= null dry_run - (Annotated[bool, Field(description="If True, no write is performed. For mode='set': runs a local shape check on the proposed config AND calls the server's energy/validate against the CURRENT persisted state (Home Assistant's validate endpoint cannot validate an unsubmitted payload). For convenience modes: simulates the mutation against a fresh read and reports what would change without writing — but still raises RESOURCE_ALREADY_EXISTS (duplicate add_device, or duplicate add_source for solar/battery/gas), RESOURCE_NOT_FOUND (missing remove_device), or VALIDATION_FAILED (post-mutator shape error) when the proposed mutation is not applicable. Default False.", default=False)])
= false stat_consumption - (Annotated[str | None, Field(description="Statistic entity_id for mode='add_device' / 'remove_device' (e.g. 'sensor.fridge_energy'). Required for those modes; ignored otherwise.", default=None)])
= null name - (Annotated[str | None, Field(description="Optional display name for mode='add_device'. Only used when adding a new device entry; ignored otherwise.", default=None)])
= null included_in_stat - (Annotated[str | None, Field(description="Optional 'parent' statistic for mode='add_device'. Set this to a statistic that already INCLUDES this device's consumption (e.g., a whole-home or circuit-level meter that this device feeds into). The Energy Dashboard will subtract this device's reading from the parent so the parent's contribution is not double-counted. Ignored otherwise.", default=None)])
= null water - (Annotated[bool, Field(description="If True, mode='add_device' / 'remove_device' targets 'device_consumption_water' instead of 'device_consumption'. Default False.", default=False)])
= false source - (Annotated[dict[str, Any] | None, Field(description="Single energy_sources entry for mode='add_source'. Must contain 'type' (one of grid|solar|battery|gas) and the type-specific required fields (e.g. solar/battery/gas require 'stat_energy_from'). Note: HA Core's voluptuous schema for grid sources requires the full field set (cost_adjustment_day, stat_energy_to, stat_cost, entity_energy_price, number_energy_price, entity_energy_price_export, number_energy_price_export, stat_compensation) — the local shape check is narrower, so a minimal {'type': 'grid'} passes locally but surfaces in post_save_validation_errors after writing. Pass the unused fields as None to satisfy the server. Required for mode='add_source'; ignored otherwise.", default=None)])
= null Get entity registry information for one or more entities. Returns detailed entity registry metadata including area assignment, custom name/icon, enabled/hidden state, aliases, labels, and more. RELATED TOOLS: - ha_set_entity(): Modify entity properties (area, name, icon, enabled, hidden, aliases) - ha_get_state(): Get current state/attributes (on/off, temperature, etc.) - ha_search_entities(): Find entities by name, domain, or area EXAMPLES: - Single entity: ha_get_entity("sensor.temperature") - Multiple entities: ha_get_entity(["light.living_room", "switch.porch"]) RESPONSE FIELDS: - entity_id: Full entity identifier - name: Custom display name (null if using original_name) - original_name: Default name from integration - icon: Custom icon (null if using default) - area_id: Assigned area/room ID (null if unassigned) - disabled_by: Why disabled (null=enabled, "user"/"integration"/etc) - hidden_by: Why hidden (null=visible, "user"/"integration"/etc) - enabled: Boolean shorthand (True if disabled_by is null) - hidden: Boolean shorthand (True if hidden_by is not null) - aliases: Voice assistant aliases - labels: Assigned label IDs - categories: Category assignments (dict mapping scope to category_id) - platform: Integration platform (e.g., "hue", "zwave_js") - device_id: Associated device ID (null if standalone) - unique_id: Integration's unique identifier
entity_id required - (Annotated[str | list[str], Field(description="Entity ID or list of entity IDs to retrieve (e.g., 'sensor.temperature' or ['light.living_room', 'switch.porch'])")]) Get entity exposure settings - list all or get settings for a specific entity. Without an entity_id: Lists all entities and their exposure status to voice assistants (Alexa, Google Assistant, Assist). With an entity_id: Returns which voice assistants the specific entity is exposed to. EXAMPLES: - List all exposures: ha_get_entity_exposure() - Filter by assistant: ha_get_entity_exposure(assistant="cloud.alexa") - Get specific entity: ha_get_entity_exposure(entity_id="light.living_room") RETURNS (when listing): - exposed_entities: Dict mapping entity_ids to their exposure status - summary: Count of entities exposed to each assistant RETURNS (when getting specific entity): - exposed_to: Dict of assistant -> True/False for each assistant - is_exposed_anywhere: True if exposed to at least one assistant
entity_id - (Annotated[str | None, Field(description='Entity ID to check exposure settings for. If omitted, lists all entities with exposure settings.', default=None)])
= null assistant - (Annotated[str | None, Field(description="Filter by assistant: 'conversation', 'cloud.alexa', or 'cloud.google_assistant'. If not specified, returns all.", default=None)])
= null Remove an entity from the Home Assistant entity registry. Permanently removes the entity registration from Home Assistant. The entity will no longer appear in the UI or be available to automations. WARNING: This permanently removes the entity registration. - Use only for orphaned or stale entity entries - If the underlying device or integration is still active, the entity may be re-added automatically on the next HA restart or reload - This action cannot be undone without restoring from backup EXAMPLES: - Remove orphaned sensor: ha_remove_entity("sensor.old_temperature") - Remove stale helper entry: ha_remove_entity("input_boolean.deleted_helper") NOTE: For most use cases, consider disabling instead: ha_set_entity(entity_id="sensor.old", enabled=False) RELATED TOOLS: - ha_search_entities: Find entities to verify the entity_id before removing - ha_get_entity: Check entity details before removal
entity_id required - (Annotated[str, Field(description="Entity ID to remove from the entity registry (e.g., 'sensor.old_temperature'). This permanently removes the entity registration.")]) Update entity properties in the entity registry. Allows modifying entity metadata such as area assignment, display name, icon, enabled/disabled state, visibility, aliases, labels, voice assistant exposure, and entity_id rename in a single call. BULK OPERATIONS: When entity_id is a list, only labels, expose_to, and categories parameters are supported. Other parameters (area_id, name, icon, enabled, hidden, aliases, new_entity_id, new_device_name) require single entity. LABEL OPERATIONS: - label_operation="set" (default): Replace all labels with the provided list. Use [] to clear. - label_operation="add": Add labels to existing ones without removing any. - label_operation="remove": Remove specified labels from the entity. ENTITY ID RENAME: Use new_entity_id to change an entity's ID (e.g., sensor.old -> sensor.new). Domain must match. Voice exposure settings are preserved automatically. WARNING: Renaming an entity_id does NOT update references in automations, scripts, templates, or dashboards. All consumers of the old entity_id must be updated manually — HA does not propagate the rename automatically. Rename limitations: - Entity history is preserved (HA 2022.4+) - Entities without unique IDs cannot be renamed - Entities disabled by their integration cannot be renamed DEVICE RENAME: Use new_device_name to rename the associated device. Can be combined with new_entity_id to rename both in one call. The device is looked up automatically. Use ha_search_entities() or ha_get_device() to find entity IDs. Use ha_config_get_label() to find available label IDs. EXAMPLES: Single entity: - Assign to area: ha_set_entity("sensor.temp", area_id="living_room") - Rename display name: ha_set_entity("sensor.temp", name="Living Room Temperature") - Rename entity_id: ha_set_entity("light.old_name", new_entity_id="light.new_name") - Rename entity and device: ha_set_entity("light.old", new_entity_id="light.new", new_device_name="New Lamp") - Rename entity_id with friendly name: ha_set_entity("sensor.old", new_entity_id="sensor.new", name="New Name") - Set labels: ha_set_entity("light.lamp", labels=["outdoor", "smart"]) - Add labels: ha_set_entity("light.lamp", labels=["new_label"], label_operation="add") - Remove labels: ha_set_entity("light.lamp", labels=["old_label"], label_operation="remove") - Clear labels: ha_set_entity("light.lamp", labels=[]) - Expose to Alexa: ha_set_entity("light.lamp", expose_to={"cloud.alexa": True}) Bulk operations: - Set labels on multiple: ha_set_entity(["light.a", "light.b"], labels=["outdoor"]) - Add labels to multiple: ha_set_entity(["light.a", "light.b"], labels=["new"], label_operation="add") - Expose multiple to Alexa: ha_set_entity(["light.a", "light.b"], expose_to={"cloud.alexa": True}) ENABLED/DISABLED WARNING: Setting enabled=False performs a **registry-level disable** — the entity is completely removed from the Home Assistant state machine and hidden from the UI. It will NOT appear in state queries, dashboards, or automations until re-enabled AND the integration is reloaded. This is NOT the same as "turning off" an entity. For automations and scripts, enabled=False is blocked. Use these instead: - ha_call_service("automation", "turn_off", entity_id="automation.xxx") - ha_call_service("script", "turn_off", entity_id="script.xxx")
entity_id required - (Annotated[str | list[str], Field(description='Entity ID or list of entity IDs to update. Bulk operations (list) only support labels and expose_to parameters.')]) area_id - (Annotated[str | None, Field(description="Area/room ID to assign the entity to. Use empty string '' to unassign from current area. Single entity only.", default=None)])
= null name - (Annotated[str | None, Field(description="Display name for the entity. Use empty string '' to remove custom name and revert to default. Single entity only.", default=None)])
= null icon - (Annotated[str | None, Field(description="Icon for the entity (e.g., 'mdi:thermometer'). Use empty string '' to remove custom icon. Single entity only.", default=None)])
= null enabled - (Annotated[bool | str | None, Field(description='True to enable the entity, False to disable it. Single entity only. WARNING: Setting enabled=False is a registry-level disable — it completely removes the entity from the state machine and hides it from the UI. A reload or restart is required to restore it after re-enabling. NOT allowed for automation or script entities — use automation.turn_off / script.turn_off via ha_call_service() instead.', default=None)])
= null hidden - (Annotated[bool | str | None, Field(description='True to hide the entity from UI, False to show it. Single entity only.', default=None)])
= null aliases - (Annotated[str | list[str] | None, Field(description='List of voice assistant aliases for the entity (replaces existing aliases). Single entity only.', default=None)])
= null categories - (Annotated[str | dict[str, str | None] | None, Field(description='Category assignment as a dict mapping scope to category_id. Example: {"automation": "category_id_here"}. Use null value to clear: {"automation": null}. Single entity only.', default=None)])
= null labels - (Annotated[str | list[str] | None, Field(description='List of label IDs for the entity. Behavior depends on label_operation parameter. Supports bulk operations.', default=None)])
= null label_operation - (Annotated[Literal['set', 'add', 'remove'], Field(description="How to apply labels: 'set' replaces all labels, 'add' adds to existing, 'remove' removes specified labels.", default='set')])
= "set" expose_to - (Annotated[str | dict[str, bool] | None, Field(description='Control voice assistant exposure. Pass a dict mapping assistant IDs to booleans. Valid assistants: \'conversation\' (Assist), \'cloud.alexa\', \'cloud.google_assistant\'. Example: {"conversation": true, "cloud.alexa": false}. Supports bulk operations.', default=None)])
= null new_entity_id - (Annotated[str | None, Field(description="New entity ID to rename to (e.g., 'light.new_name'). Domain must match the original. Single entity only.", default=None)])
= null new_device_name - (Annotated[str | None, Field(description='New display name for the associated device. If provided, both entity and device are updated in one operation. Single entity only.', default=None)])
= null Delete a file from allowed directories in the Home Assistant config. Permanently removes a file from the allowed directories. This action cannot be undone. **Allowed Delete Directories:** - `www/` - Web assets - `themes/` - Theme files - `custom_templates/` - Template files **Security:** - Only the directories above allow deletions - Configuration files cannot be deleted - Path traversal (../) is blocked - Requires confirm=True to prevent accidents **Returns:** - success: Whether the operation succeeded - path: The file path that was deleted - message: Confirmation message **Example:** ```python # Delete an old CSS file result = ha_delete_file( path="www/deprecated-style.css", confirm=True ) ```
path required - (Annotated[str, Field(description="Relative path from config directory. Must be in www/, themes/, or custom_templates/. Example: 'www/old-file.css'")]) confirm - (Annotated[bool | str, Field(default=False, description='Must be True to confirm deletion. This is a safety measure to prevent accidental deletions.')])
= false List files in a directory within the Home Assistant config directory. Lists files in allowed directories (www/, themes/, custom_templates/) with optional glob pattern filtering. Returns file names, sizes, and modification times. **Allowed Directories:** - `www/` - Web assets (CSS, JS, images for dashboards) - `themes/` - Theme files - `custom_templates/` - Jinja2 template files **Security:** Only directories in the allowed list can be accessed. Path traversal attempts (../) are blocked. **Returns:** - success: Whether the operation succeeded - path: The directory path that was listed - files: List of file info objects with name, size, is_dir, modified - count: Number of files found **Example:** ```python # List all CSS files in www/ result = ha_list_files(path="www/", pattern="*.css") ```
path required - (Annotated[str, Field(description="Relative directory path from config directory. Allowed paths: www/, themes/, custom_templates/. Example: 'www/' or 'themes/my_theme'")]) pattern - (Annotated[str | None, Field(default=None, description="Optional glob pattern to filter files. Example: '*.css', '*.yaml', '*.js'")])
= null Read a file from the Home Assistant config directory. Reads files from allowed paths within the config directory. Some files have special handling: - `secrets.yaml`: Values are masked for security - `home-assistant.log`: Limited to tail (last N lines) by default **Allowed Read Paths:** - `configuration.yaml`, `automations.yaml`, `scripts.yaml`, `scenes.yaml` - `secrets.yaml` (values masked) - `packages/*.yaml` - `home-assistant.log` (tail only) - `www/**`, `themes/**`, `custom_templates/**` - `custom_components/**/*.py` (read-only) **Security:** - Path traversal (../) is blocked - Only allowed paths can be read - Sensitive data in secrets.yaml is masked **Returns:** - success: Whether the operation succeeded - content: The file content (may be truncated for logs) - size: File size in bytes - modified: Last modification timestamp - path: The file path that was read **Example:** ```python # Read configuration result = ha_read_file(path="configuration.yaml") # Read last 100 lines of log result = ha_read_file(path="home-assistant.log", tail_lines=100) ```
path required - (Annotated[str, Field(description="Relative path from config directory. Examples: 'configuration.yaml', 'www/custom.css', 'home-assistant.log'")]) tail_lines - (Annotated[int | str | None, Field(default=None, description='For log files, return only the last N lines. Recommended for home-assistant.log to avoid large responses. Default: None (return full file, or last 1000 lines for logs)')])
= null Write a file to allowed directories in the Home Assistant config. Creates or updates files in restricted directories only. This is useful for: - Creating custom CSS/JS for dashboards - Adding theme files - Creating Jinja2 templates **Allowed Write Directories:** - `www/` - Web assets for dashboards - `themes/` - Theme YAML files - `custom_templates/` - Jinja2 template files **Security:** - Only the directories above allow writes - Configuration files (configuration.yaml, etc.) cannot be written - Path traversal (../) is blocked **Returns:** - success: Whether the operation succeeded - path: The file path that was written - size: Size of the written file in bytes - created: Whether this was a new file (vs overwrite) **Example:** ```python # Create a custom CSS file result = ha_write_file( path="www/custom-dashboard.css", content=".card { background: #333; }", overwrite=True ) # Create a theme file result = ha_write_file( path="themes/dark_blue.yaml", content="Dark Blue:\n primary-color: '#1a237e'", overwrite=False ) ```
path required - (Annotated[str, Field(description="Relative path from config directory. Must be in www/, themes/, or custom_templates/. Example: 'www/custom.css', 'themes/my_theme.yaml'")]) content required - (Annotated[str, Field(description='The content to write to the file.')]) overwrite - (Annotated[bool | str, Field(default=False, description='Whether to overwrite if file exists. Default is False to prevent accidental overwrites.')])
= false create_dirs - (Annotated[bool | str, Field(default=True, description="Whether to create parent directories if they don't exist. Default is True.")])
= true List all Home Assistant entity groups with their member entities. Returns all groups created via group.set service or YAML configuration, including: - Entity ID (group.xxx) - Friendly name - State (on/off based on member states) - Member entities - Icon (if set) - All mode (if all entities must be on) EXAMPLES: - List all groups: ha_config_list_groups() **NOTE:** This returns old-style groups (created via group.set or YAML). Platform-specific groups (light groups, cover groups) are separate entities.
Remove a service-based Home Assistant entity group via the group.remove service. **When NOT to use:** for groups created through `ha_config_set_helper(helper_type="group", ...)`, use `ha_delete_helpers_integrations`. Those config-entry-backed groups are not reachable via the group.remove service. **When to use:** removing groups created with `ha_config_set_group` or defined in YAML via `group:` configuration. Config-entry-backed deletion tools cannot find these. EXAMPLES: - Remove group: ha_config_remove_group("living_room_lights") Use ha_config_list_groups() to find existing groups. **WARNING:** - Removing a group used in automations may cause those automations to fail. - Groups defined in YAML can be removed at runtime but will reappear after restart. - This only removes old-style groups, not platform-specific groups.
object_id required - (Annotated[str, Field(description="Group identifier without 'group.' prefix (e.g., 'living_room_lights')")]) wait - (Annotated[bool | str, Field(description='Wait for group to be fully removed before returning. Default: True.', default=True)])
= true Create or update a service-based Home Assistant entity group via the group.set service. **When NOT to use:** for typical "combine these entities into one controllable group" requests, prefer `ha_config_set_helper(helper_type="group", ...)`. Config-entry-backed groups are registered in the entity registry, so `ha_set_entity` can assign them to areas and they are deletable via `ha_delete_helpers_integrations`. **When to use:** compatibility with existing groups already configured via group.set or YAML, or the rare case where entity-registry membership is explicitly unwanted. Groups created here are only removable via `ha_config_remove_group` — `ha_delete_helpers_integrations` will not find them. **For NEW groups:** Provide object_id and entities (required). **For EXISTING groups:** Provide object_id and any fields to update. EXAMPLES: - Create group: ha_config_set_group("bedroom_lights", entities=["light.lamp", "light.ceiling"]) - Create with name: ha_config_set_group("sensors", entities=["sensor.temp"], name="All Sensors") - Update name: ha_config_set_group("lights", name="Living Room Lights") - Add entities: ha_config_set_group("lights", add_entities=["light.extra"]) - Remove entities: ha_config_set_group("lights", remove_entities=["light.old"]) - Replace all entities: ha_config_set_group("lights", entities=["light.new1", "light.new2"]) **NOTE:** entities, add_entities, and remove_entities are mutually exclusive.
object_id required - (Annotated[str, Field(description="Group identifier without 'group.' prefix (e.g., 'living_room_lights')")]) entities - (Annotated[list[str] | None, Field(description='List of entity IDs for the group. Required when creating new group. When updating, replaces all entities (mutually exclusive with add_entities/remove_entities).', default=None)])
= null name - (Annotated[str | None, Field(description='Friendly display name for the group', default=None)])
= null icon - (Annotated[str | None, Field(description="Material Design Icon (e.g., 'mdi:lightbulb-group')", default=None)])
= null all_on - (Annotated[bool | None, Field(description='If True, all entities must be on for group to be on (default: False)', default=None)])
= null add_entities - (Annotated[list[str] | None, Field(description='Add these entities to an existing group (mutually exclusive with entities)', default=None)])
= null remove_entities - (Annotated[list[str] | None, Field(description='Remove these entities from an existing group (mutually exclusive with entities)', default=None)])
= null wait - (Annotated[bool | str, Field(description='Wait for group to be queryable before returning. Default: True. Set to False for bulk operations.', default=True)])
= true Add a custom GitHub repository to HACS. Allows adding custom repositories that are not in the default HACS store. This is useful for: - Adding custom integrations from GitHub - Installing custom Lovelace cards - Adding custom themes - Installing beta/development versions **Requirements:** - Repository must be a valid GitHub repository - Repository must follow HACS structure guidelines - Category must match the repository type **Examples:** ```python # Add custom integration ha_hacs_add_repository("owner/custom-integration", category="integration") # Add custom card ha_hacs_add_repository("owner/custom-card", category="lovelace") # Add custom theme ha_hacs_add_repository("owner/custom-theme", category="theme") ``` Args: repository: GitHub repository in format "owner/repo" category: Repository category (integration, lovelace, theme, appdaemon, python_script) Returns: Success status and repository ID if added successfully.
repository required - (str) category required - (Annotated[Literal['integration', 'lovelace', 'theme', 'appdaemon', 'python_script'], Field(description='Repository category (required)')]) Download and install a HACS repository. This installs a repository from HACS to your Home Assistant instance. For integrations, a restart of Home Assistant may be required after installation. **Prerequisites:** - The repository must already be in HACS (either from the default store or added via `ha_hacs_add_repository`) - Use `ha_hacs_search()` to find the repository ID **Examples:** ```python # Install latest version of a repository ha_hacs_download("441028036") # Install specific version ha_hacs_download("441028036", version="v2.0.0") # Install by GitHub path (will look up the numeric ID) ha_hacs_download("piitaya/lovelace-mushroom", version="v4.0.0") ``` **Note:** For integrations, you may need to restart Home Assistant after installation. For Lovelace cards, clear your browser cache to see the new card. Args: repository_id: Repository numeric ID or GitHub path (e.g., "441028036" or "owner/repo") version: Specific version to install (optional, defaults to latest) Returns: Success status and installation details.
repository_id required - (str) version - (Annotated[str | None, Field(default=None, description="Specific version to install (e.g., 'v1.2.3'). If not specified, installs the latest version.")])
= null Get detailed repository information including README and documentation. Returns comprehensive information about a HACS repository: - Basic info (name, description, category, authors) - Installation status and versions - README content (useful for configuration examples) - Available releases and versions - GitHub stats (stars, issues) - Configuration examples (if available) **Use Cases:** - Get card configuration examples: `ha_hacs_repository_info("441028036")` - Check integration setup instructions - Find theme customization options **Note:** The repository_id is the numeric ID from HACS, not the GitHub path. Use `ha_hacs_search()` to find the numeric ID. Args: repository_id: Repository numeric ID (e.g., "441028036") or GitHub path (e.g., "dvd-dev/hilo") Returns: Detailed repository information or error if not found.
repository_id required - (str) Search HACS store for repositories, or list installed repositories. **Search mode** (default): Searches by keyword across name, description, and authors. **Browse mode** (no query, `installed_only=False`): Returns all HACS store repos sorted alphabetically, paginated by `max_results` and `offset`. **Installed mode** (`installed_only=True`): Lists installed repos (no query needed). **DASHBOARD TIP:** Use `installed_only=True, category="lovelace"` to discover installed custom cards for use with `ha_config_set_dashboard()`. **Examples:** - Find custom cards: `ha_hacs_search("mushroom", category="lovelace")` - Find integrations: `ha_hacs_search("nest", category="integration")` - List installed: `ha_hacs_search(installed_only=True)` - Installed by category: `ha_hacs_search(installed_only=True, category="lovelace")` Args: query: Search query (repository name, description, author). Empty string with installed_only=True lists all installed repos. category: Filter by category (optional) installed_only: Only return installed repositories (default: False) max_results: Maximum results to return (default: 10, max: 100) offset: Number of results to skip for pagination (default: 0)
query - (str)
= "" category - (Annotated[Literal['integration', 'lovelace', 'theme', 'appdaemon', 'python_script'] | None, Field(default=None, description='Filter by category (optional)')])
= null installed_only - (Annotated[bool | str, Field(default=False, description='Only return installed repositories (default: False)')])
= false max_results - (Annotated[int | str, Field(default=10, description='Maximum number of results to return (default: 10, max: 100)')])
= 10 offset - (Annotated[int | str, Field(default=0, description='Number of results to skip for pagination (default: 0)')])
= 0 List all Home Assistant helpers of a specific type with their configurations. Returns complete configuration for all helpers of the specified type including: - ID, name, icon - Type-specific settings (min/max for input_number, options for input_select, etc.) - Area and label assignments SUPPORTED HELPER TYPES: - input_button: Virtual buttons for triggering automations - input_boolean: Toggle switches/checkboxes - input_select: Dropdown selection lists - input_number: Numeric sliders/input boxes - input_text: Text input fields - input_datetime: Date/time pickers - counter: Counters with increment/decrement/reset - timer: Countdown timers with start/pause/cancel - schedule: Weekly schedules with time ranges (on/off per day) - zone: Geographical zones for presence detection - person: Person entities linked to device trackers - tag: NFC/QR tags for automation triggers EXAMPLES: - List all number helpers: ha_config_list_helpers("input_number") - List all counters: ha_config_list_helpers("counter") - List all zones: ha_config_list_helpers("zone") - List all persons: ha_config_list_helpers("person") - List all tags: ha_config_list_helpers("tag") **NOTE:** This only returns storage-based helpers (created via UI/API), not YAML-defined helpers. For detailed helper documentation, use ha_get_skill_home_assistant_best_practices.
helper_type required - (Annotated[Literal['input_button', 'input_boolean', 'input_select', 'input_number', 'input_text', 'input_datetime', 'counter', 'timer', 'schedule', 'zone', 'person', 'tag'], Field(description='Type of helper entity to list')]) Create or update Home Assistant helper entities (27 types, unified interface). Creates new helper if helper_id is omitted, updates existing if helper_id is provided. SIMPLE types (structured params, WebSocket API): input_boolean, input_button, input_select, input_number, input_text, input_datetime, counter, timer, schedule, zone, person, tag. FLOW types (pass `config` dict, Config Entry Flow API): template, group, utility_meter, derivative, min_max, threshold, integration, statistics, trend, random, filter, tod, generic_thermostat, switch_as_x, generic_hygrostat. Note: `tod` is the purpose-built "is-current-time-in-range" indicator (supports cross-midnight ranges, unlike `schedule`). For flow-type updates, pass the existing entry_id as `helper_id`. Options flows reject the `name` key on update — to rename a flow helper, delete and recreate. EXAMPLES (menu-based types + tod, where first-call payload is non-obvious): - template sensor: ha_config_set_helper(helper_type="template", name="Room Temp", config={"next_step_id": "sensor", "state": "{{ states('sensor.x')|float }}", "unit_of_measurement": "°C"}) - group (light): ha_config_set_helper(helper_type="group", name="Kitchen Lights", config={"group_type": "light", "entities": ["light.a", "light.b"]}) - tod (time-of-day indicator, cross-midnight OK): ha_config_set_helper(helper_type="tod", name="Quiet Hours", config={"after_time": "22:00:00", "before_time": "07:00:00"}) For complex schemas and per-type parameter details, use ha_get_helper_schema.
helper_type required - (Annotated[Literal['counter', 'derivative', 'filter', 'generic_hygrostat', 'generic_thermostat', 'group', 'input_boolean', 'input_button', 'input_datetime', 'input_number', 'input_select', 'input_text', 'integration', 'min_max', 'person', 'random', 'schedule', 'statistics', 'switch_as_x', 'tag', 'template', 'threshold', 'timer', 'tod', 'trend', 'utility_meter', 'zone'], Field(description='Type of helper entity to create or update')]) name - (Annotated[str | None, Field(description="Display name for the helper. Required on create; optional on update (pass helper_id to skip). For flow-based helper types on update (template, group, utility_meter, ...), this is typically ignored — options flows don't expose renaming. Rename a flow helper by deleting and recreating instead.", default=None)])
= null helper_id - (Annotated[str | None, Field(description="Helper ID for updates (e.g., 'my_button' or 'input_button.my_button'). If not provided, creates a new helper.", default=None)])
= null icon - (Annotated[str | None, Field(description="Material Design Icon (e.g., 'mdi:bell', 'mdi:toggle-switch')", default=None)])
= null area_id - (Annotated[str | None, Field(description='Area/room ID to assign the helper to', default=None)])
= null labels - (Annotated[str | list[str] | None, Field(description='Labels to categorize the helper', default=None)])
= null min_value - (Annotated[float | None, Field(description='Minimum value (input_number/counter) or minimum length (input_text)', default=None)])
= null max_value - (Annotated[float | None, Field(description='Maximum value (input_number/counter) or maximum length (input_text)', default=None)])
= null step - (Annotated[float | None, Field(description='Step/increment value for input_number or counter', default=None)])
= null unit_of_measurement - (Annotated[str | None, Field(description="Unit of measurement for input_number (e.g., '°C', '%', 'W')", default=None)])
= null options - (Annotated[str | list[str] | None, Field(description='List of options for input_select (required for input_select)', default=None)])
= null initial - (Annotated[str | int | None, Field(description='Initial value for the helper (input_select, input_text, input_boolean, input_datetime, counter)', default=None)])
= null mode - (Annotated[str | None, Field(description="Display mode: 'box'/'slider' for input_number, 'text'/'password' for input_text", default=None)])
= null has_date - (Annotated[bool | None, Field(description='Include date component for input_datetime', default=None)])
= null has_time - (Annotated[bool | None, Field(description='Include time component for input_datetime', default=None)])
= null restore - (Annotated[bool | None, Field(description='Restore state after restart (counter, timer). Defaults to True for counter, False for timer', default=None)])
= null duration - (Annotated[str | None, Field(description="Default duration for timer in format 'HH:MM:SS' or seconds (e.g., '0:05:00' for 5 minutes)", default=None)])
= null monday - (Annotated[list[dict[str, Any]] | None, Field(description="Schedule time ranges for Monday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes (e.g. {'from': '07:00', 'to': '22:00', 'data': {'mode': 'comfort'}})", default=None)])
= null tuesday - (Annotated[list[dict[str, Any]] | None, Field(description="Schedule time ranges for Tuesday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes.", default=None)])
= null wednesday - (Annotated[list[dict[str, Any]] | None, Field(description="Schedule time ranges for Wednesday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes.", default=None)])
= null thursday - (Annotated[list[dict[str, Any]] | None, Field(description="Schedule time ranges for Thursday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes.", default=None)])
= null friday - (Annotated[list[dict[str, Any]] | None, Field(description="Schedule time ranges for Friday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes.", default=None)])
= null saturday - (Annotated[list[dict[str, Any]] | None, Field(description="Schedule time ranges for Saturday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes.", default=None)])
= null sunday - (Annotated[list[dict[str, Any]] | None, Field(description="Schedule time ranges for Sunday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes.", default=None)])
= null latitude - (Annotated[float | None, Field(description='Latitude for zone (required for zone)', default=None)])
= null longitude - (Annotated[float | None, Field(description='Longitude for zone (required for zone)', default=None)])
= null radius - (Annotated[float | None, Field(description='Radius in meters for zone (default: 100)', default=None)])
= null passive - (Annotated[bool | None, Field(description="Passive zone (won't trigger state changes for person entities)", default=None)])
= null user_id - (Annotated[str | None, Field(description='User ID to link to person entity', default=None)])
= null device_trackers - (Annotated[list[str] | None, Field(description='List of device_tracker entity IDs for person', default=None)])
= null picture - (Annotated[str | None, Field(description='Picture URL for person entity', default=None)])
= null tag_id - (Annotated[str | None, Field(description='Tag ID for tag (auto-generated if not provided)', default=None)])
= null description - (Annotated[str | None, Field(description='Description for tag', default=None)])
= null category - (Annotated[str | None, Field(description="Category ID to assign to this helper. Use ha_config_get_category(scope='helpers') to list available categories, or ha_config_set_category() to create one.", default=None)])
= null config - (Annotated[str | dict | None, Field(description='Config dict for flow-based helper types (template, group, utility_meter, derivative, min_max, threshold, integration, statistics, trend, random, filter, tod, generic_thermostat, switch_as_x, generic_hygrostat). Accepts JSON string or dict. Ignored for simple helper types. Use ha_get_helper_schema(helper_type) to discover required fields.', default=None)])
= null wait - (Annotated[bool | str, Field(description='Wait for helper entity to be queryable before returning. Default: True. Set to False for bulk operations.', default=True)])
= true Delete a Home Assistant helper or integration config entry. Combines simple-helper websocket deletion and config-entry deletion under one entry point with three routing paths driven by helper_type. WHEN NOT TO USE: - Removing only an entity (without deleting its underlying helper or config entry) — use `ha_remove_entity` instead. - YAML-configured helpers — they have no storage backend. Edit the YAML file and reload the relevant integration. SUPPORTED HELPER TYPES: - SIMPLE (12, websocket-delete): input_button, input_boolean, input_select, input_number, input_text, input_datetime, counter, timer, schedule, zone, person, tag. - FLOW (15, config-entry-delete via entity lookup): template, group, utility_meter, derivative, min_max, threshold, integration, statistics, trend, random, filter, tod, generic_thermostat, switch_as_x, generic_hygrostat. ROUTING: - SIMPLE helper_type + bare helper_id or entity_id → websocket delete. - FLOW helper_type + entity_id → resolve entity_id to config_entry_id via entity_registry, then delete the config entry. All sub-entities (e.g. utility_meter tariffs) are removed together. - helper_type=None + entry_id → direct config entry delete (any integration). EXAMPLES: - Delete SIMPLE button: ha_delete_helpers_integrations( target="my_button", helper_type="input_button", confirm=True ) - Delete FLOW utility_meter (any sub-entity works): ha_delete_helpers_integrations( target="sensor.energy_peak", helper_type="utility_meter", confirm=True, ) - Delete any integration by entry_id: ha_delete_helpers_integrations( target="01HXYZ...", confirm=True ) **WARNING:** Deleting a helper or integration that is referenced by automations, scripts, or other integrations may cause those to fail. Use ha_search_entities() / ha_get_integration() to verify before deletion. Cannot be undone.
target required - (Annotated[str, Field(description="What to delete. One of: (a) bare helper_id for SIMPLE helpers (requires helper_type), e.g. 'my_button'; (b) full entity_id (requires helper_type), e.g. 'input_button.my_button' or 'sensor.my_meter'; (c) config entry_id for any integration (helper_type=None), e.g. value from ha_get_integration().")]) helper_type - (Annotated[HelperTypeLiteral | None, Field(description='Helper type. Required when target is a helper_id (bare) or entity_id. Set to None when target is a config entry_id to delete any integration.', default=None)])
= null confirm - (Annotated[bool | str, Field(description="Must be True to confirm deletion. Accepts bool or string ('true'/'false'/'1'/'0'/'yes'/'no'/'on'/'off', case-insensitive) for transport ergonomics.", default=False)])
= false wait - (Annotated[bool | str, Field(description="Wait for entity removal. Default: True. Ignored when helper_type=None (no entity poll, require_restart returned). Accepts bool or string ('true'/'false'/'1'/'0'/'yes'/'no'/'on'/'off', case-insensitive).", default=True)])
= true Get configuration schema for a helper type. Returns the form fields and their types needed to create this helper. Use before ha_config_set_helper to understand required config. Two-call workflow for menu-based helpers (template, group): # Step 1 — discover sub-types: ha_get_helper_schema("template") → {flow_type: "menu", menu_options: ["sensor", "binary_sensor", ...]} # Step 2 — inspect form fields for a sub-type: ha_get_helper_schema("template", menu_option="sensor") → {flow_type: "form", menu_option: "sensor", data_schema: [{name: "state", ...}, ...]} For form-based helpers (min_max, utility_meter, etc.), omit menu_option.
helper_type required - (Annotated[SUPPORTED_HELPERS, Field(description='Helper type')]) menu_option - (Annotated[str | None, Field(description="For menu-based helpers: the sub-type to inspect (e.g. 'sensor' or 'binary_sensor' for template). Omit to see available menu options first.", default=None)])
= null Retrieve execution traces for automations and scripts to debug issues. Traces show what happened during automation/script runs: - What triggered the automation - Which conditions passed or failed - What actions were executed - Any errors that occurred - Variable values during execution USAGE MODES: 1. List recent traces (omit run_id): ha_get_automation_traces("automation.motion_light") Returns a summary of recent execution runs with timestamps, triggers, and status. 2. Get detailed trace (provide run_id): ha_get_automation_traces("automation.motion_light", run_id="1705312800.123456") Returns full execution details including trigger info, condition results, action trace with timing, and context variables. 3. Get detailed trace with logbook (provide run_id and detailed=True): ha_get_automation_traces("automation.motion_light", run_id="1705312800.123456", detailed=True) Returns the formatted trace plus logbook entries and context metadata. Useful when the standard trace summary doesn't reveal enough for debugging. Note: script-style action paths (sequence/, numeric) are always matched regardless of this flag. 4. Get full variables without deduplication (provide run_id and deduplicate=False): ha_get_automation_traces("automation.motion_light", run_id="1705312800.123456", deduplicate=False) Returns the formatted trace with full variables at every action step. DEBUGGING EXAMPLES: Automation not triggering: - Check if traces exist (automation may not be triggered) - Look at trigger info to see what event was received Automation runs but conditions fail: - Get detailed trace to see condition_results - Each condition shows whether it passed (true) or failed (false) Unexpected behavior in actions: - Get detailed trace to see action_trace - Shows each action step with result and any errors - For 'choose' actions, shows which branch was taken Template debugging: - Detailed trace shows evaluated template values in context - Trigger variables available under trigger_variables NOTES: - Traces are stored for a limited time by Home Assistant - Works for both automations and scripts (use full entity_id) - The 'state' field shows: 'stopped' (completed), 'running', or error state
automation_id required - (Annotated[str, Field(description="Automation or script entity_id (e.g., 'automation.motion_light' or 'script.morning_routine')")]) run_id - (Annotated[str | None, Field(description='Specific trace run_id to retrieve detailed trace. Omit to list recent traces.', default=None)])
= null limit - (Annotated[int, Field(description='Maximum number of traces to return when listing (default: 10, max: 50)', default=10, ge=1, le=50)])
= 10 deduplicate - (Annotated[bool, Field(description='Deduplicate variables across action steps (default: True). Set to False to include full variables at every step.', default=True)])
= true detailed - (Annotated[bool, Field(description='Include extra diagnostic data: logbook entries and context metadata (default: False). Use when standard trace lacks detail for debugging.', default=False)])
= false sections - (Annotated[str | None, Field(description="Comma-separated list of trace sections to return. Valid values: trigger, conditions, actions, config, error, logbook, context. Omit to return all sections. Example: 'actions' or 'trigger,conditions'.", default=None)])
= null Retrieve historical data from Home Assistant's recorder. **Sources:** - "history" (default): Raw state changes, ~10 day retention, full resolution - "statistics": Pre-aggregated data, permanent retention, requires state_class **Shared params:** entity_ids, start_time, end_time, limit, offset **History params:** minimal_response, significant_changes_only **Statistics params:** period, statistic_types **Default time range:** 24h for history, 30 days for statistics **Use ha_get_history (default) when:** - Troubleshooting why a value changed ("Why was my bedroom cold last night?") - Checking event sequences ("Did my garage door open while I was away?") - Analyzing recent patterns ("What time does motion usually trigger?") **Use ha_get_history(source="statistics") when:** - Tracking long-term trends beyond 10 days ("Energy use this month vs last month?") - Computing period averages ("Average living room temperature over 6 months?") - Entities must have state_class (measurement, total, total_increasing) **WARNING:** limit and offset apply per entity (not globally across all entities). All data is fetched from HA before slicing; limit/offset are client-side. With multiple entity_ids, offset must be 0 — use a single entity_id for offset > 0. Use has_more and next_offset from the response to paginate. **Example -- history (default):** ```python ha_get_history(entity_ids="sensor.bedroom_temperature", start_time="24h") ha_get_history(entity_ids=["sensor.temperature", "sensor.humidity"], start_time="7d", limit=500) ha_get_history(entity_ids="sensor.temperature", start_time="7d", limit=100, offset=100) ``` **Example -- statistics:** ```python ha_get_history(source="statistics", entity_ids="sensor.total_energy_kwh", start_time="30d", period="day") ha_get_history(source="statistics", entity_ids="sensor.living_room_temperature", start_time="6m", period="month", statistic_types=["mean", "min", "max"]) ha_get_history(source="statistics", entity_ids="sensor.energy_kwh", start_time="30d", period="5minute", limit=100, offset=200) ```
entity_ids required - (Annotated[str | list[str], Field(description='Entity ID(s) to query. Can be a single ID, comma-separated string, or JSON array.')]) source - (Annotated[Literal['history', 'statistics'], Field(description='Data source: "history" (default) for raw state changes (~10 day retention), or "statistics" for pre-aggregated long-term data (permanent, requires state_class).', default='history')])
= "history" start_time - (Annotated[str | None, Field(description="Start time: ISO datetime or relative (e.g., '24h', '7d', '30d'). Default: 24h ago for history, 30d ago for statistics", default=None)])
= null end_time - (Annotated[str | None, Field(description='End time: ISO datetime. Default: now', default=None)])
= null minimal_response - (Annotated[bool, Field(description='Return only states/timestamps without attributes. Default: true. Ignored when source="statistics"', default=True)])
= true significant_changes_only - (Annotated[bool, Field(description='Filter to significant state changes only. Default: true. Ignored when source="statistics"', default=True)])
= true limit - (Annotated[int | str | None, Field(description='Max entries per entity. Default: 100, Max: 1000. For source="history": state changes. For source="statistics": aggregated rows. With multiple entity_ids, offset must be 0 and total rows returned can reach limit × len(entity_ids).', default=None)])
= null offset - (Annotated[int | str | None, Field(description='Number of entries to skip per entity for pagination. Default: 0. Offset > 0 requires a single entity_id. Use with limit and has_more/next_offset in the response.', default=None)])
= null period - (Annotated[str, Field(description='Aggregation period: "5minute", "hour", "day", "week", "month", "year". Default: "day". Ignored when source="history"', default='day')])
= "day" statistic_types - (Annotated[str | list[str] | None, Field(description='Statistics types: "mean", "min", "max", "sum", "state", "change". Default: all. Ignored when source="history"', default=None)])
= null Get Home Assistant logs from various sources. **Sources:** - "logbook" (default): Entity state change history with pagination - "system": Structured system log entries (errors, warnings) via system_log/list - "error_log": Raw home-assistant.log text - "supervisor": Add-on container logs (requires slug parameter) - "logger": Effective log level per integration via logger/log_info (confirms logger.set_level changes took effect) **Shared params:** limit, search (keyword filter on entries/lines; matches integration domain for source='logger') **Logbook params:** hours_back, entity_id, end_time, offset, compact (default True — strips attribute dicts to save context) **System/error_log params:** level (ERROR, WARNING, INFO, DEBUG) **Supervisor params:** slug (add-on slug, e.g. "core_mosquitto")
source - (Literal['logbook', 'system', 'error_log', 'supervisor', 'logger'])
= "logbook" limit - (int | str | None)
= null search - (str | None)
= null hours_back - (int | str)
= 1 entity_id - (str | None)
= null end_time - (str | None)
= null offset - (int | str)
= 0 compact - (bool | str)
= true level - (str | None)
= null slug - (str | None)
= null Get integration (config entry) information with pagination. Without an entry_id: Lists all configured integrations with optional filters. With an entry_id: Returns detailed information including full options/configuration. EXAMPLES: - List all integrations: ha_get_integration() - Paginate: ha_get_integration(offset=50) - Search: ha_get_integration(query="zigbee") - Get specific entry: ha_get_integration(entry_id="abc123") - Get entry with editable fields: ha_get_integration(entry_id="abc123", include_schema=True) - List template entries: ha_get_integration(domain="template") STATES: 'loaded', 'setup_error', 'setup_retry', 'not_loaded', 'failed_unload', 'migration_error'. Each entry carries: - ``log_level``: the canonical Python logger level name (``DEBUG``/``INFO``/``WARNING``/``ERROR``/``CRITICAL``) when the integration has a ``logger.set_level`` override, or ``"DEFAULT"`` (uppercase sentinel) when no override is set. - ``log_level_raw``: the original numeric level (e.g. ``10`` for DEBUG) when HA returned an int, ``None`` otherwise (no override set, or HA provided a level name as a string). This is distinct from the add-on side, where ``ha_get_addon`` returns Supervisor's lowercase ``"default"`` literal — do not cross-compare.
entry_id - (Annotated[str | None, Field(description='Config entry ID to get details for. If omitted, lists all integrations.', default=None)])
= null query - (Annotated[str | None, Field(description='When listing, search by domain or title. Uses exact substring matching by default; set exact_match=False for fuzzy.', default=None)])
= null domain - (Annotated[str | None, Field(description="Filter by integration domain (e.g. 'template', 'group'). When set, includes the full options/configuration for each entry.", default=None)])
= null include_options - (Annotated[bool | str, Field(description='Include the options object for each entry. Automatically enabled when domain filter is set. Useful for auditing template definitions and helper configurations.', default=False)])
= false include_schema - (Annotated[bool | str, Field(description='When entry_id is set, also return the options flow schema (available fields and their types). Use before ha_config_set_helper to understand what can be updated. Only applies when supports_options=true.', default=False)])
= false exact_match - (Annotated[bool | str, Field(description='Use exact substring matching for query filter (default: True). Set to False for fuzzy matching when the query may contain typos.', default=True)])
= true limit - (Annotated[int | str, Field(default=50, description='Max entries to return per page in list mode (default: 50)')])
= 50 offset - (Annotated[int | str, Field(default=0, description='Number of entries to skip for pagination (default: 0)')])
= 0 Enable/disable integration (config entry). Use ha_get_integration() to find entry IDs.
entry_id required - (Annotated[str, Field(description='Config entry ID')]) enabled required - (Annotated[bool | str, Field(description='True to enable, False to disable')]) Get category info - list all categories for a scope or get a specific one by ID. Without a category_id: Lists all Home Assistant categories for the given scope. With a category_id: Returns configuration for that specific category. Categories are domain-scoped organizational groups for automations, scripts, scenes, and helpers. CATEGORY PROPERTIES: - ID (category_id), Name - Icon (optional) EXAMPLES: - List automation categories: ha_config_get_category("automation") - List script categories: ha_config_get_category("script") - List helper categories: ha_config_get_category("helpers") - Get specific category: ha_config_get_category("automation", category_id="my_category_id") Use ha_config_set_category() to create or update categories. Use ha_set_entity(categories={"automation": "category_id"}) to assign categories to entities.
scope required - (Annotated[str, Field(description="Domain scope for categories (e.g., 'automation', 'script', 'scene', 'helpers').")]) category_id - (Annotated[str | None, Field(description='ID of the category to retrieve. If omitted, lists all categories for the scope.', default=None)])
= null Get label info - list all labels or get a specific one by ID. Without a label_id: Lists all Home Assistant labels with their configurations. With a label_id: Returns configuration for that specific label. LABEL PROPERTIES: - ID (label_id), Name - Color (optional), Icon (optional), Description (optional) EXAMPLES: - List all labels: ha_config_get_label() - Get specific label: ha_config_get_label("my_label_id") Use ha_config_set_label() to create or update labels. Use ha_set_entity(labels=["label1", "label2"]) to assign labels to entities.
label_id - (Annotated[str | None, Field(description='ID of the label to retrieve. If omitted, lists all labels.', default=None)])
= null Delete a Home Assistant category. Removes the category from the category registry for the given scope (e.g., 'automation', 'script', 'scene', 'helpers'). This will also remove the category assignment from all entities in that scope. EXAMPLES: - Delete category: ha_config_remove_category("automation", "my_category_id") Use ha_config_get_category() to find category IDs. **WARNING:** Deleting a category will remove it from all assigned entities. This action cannot be undone.
scope required - (Annotated[str, Field(description="Domain scope for the category (e.g., 'automation', 'script', 'scene', 'helpers').")]) category_id required - (Annotated[str, Field(description='ID of the category to delete')]) Delete a Home Assistant label. Removes the label from the label registry. This will also remove the label from all entities, devices, and areas that have it assigned. EXAMPLES: - Delete label: ha_config_remove_label("my_label_id") Use ha_config_get_label() to find label IDs. **WARNING:** Deleting a label will remove it from all assigned entities. This action cannot be undone.
label_id required - (Annotated[str, Field(description='ID of the label to delete')]) Create or update a Home Assistant category. Creates a new category if category_id is not provided, or updates an existing category if category_id is provided. Categories are domain-scoped organizational groups for automations, scripts, scenes, and helpers. Unlike labels (which are cross-domain), categories are specific to a single domain scope. EXAMPLES: - Create automation category: ha_config_set_category("Lighting", scope="automation") - Create with icon: ha_config_set_category("Security", scope="automation", icon="mdi:shield") - Update category: ha_config_set_category("Updated Name", scope="automation", category_id="my_category_id") After creating a category, use ha_set_entity(categories={"automation": "category_id"}) to assign it.
name required - (Annotated[str, Field(description='Display name for the category')]) scope required - (Annotated[str, Field(description="Domain scope for the category (e.g., 'automation', 'script', 'scene', 'helpers').")]) category_id - (Annotated[str | None, Field(description='Category ID for updates. If not provided, creates a new category.', default=None)])
= null icon - (Annotated[str | None, Field(description="Material Design Icon (e.g., 'mdi:tag', 'mdi:label')", default=None)])
= null Create or update a Home Assistant label. Creates a new label if label_id is not provided, or updates an existing label if label_id is provided. Labels are a flexible tagging system that can be applied to entities, devices, and areas for organization and automation purposes. EXAMPLES: - Create simple label: ha_config_set_label("Critical") - Create colored label: ha_config_set_label("Outdoor", color="green") - Create label with icon: ha_config_set_label("Battery Powered", icon="mdi:battery") - Create full label: ha_config_set_label("Security", color="red", icon="mdi:shield", description="Security-related devices") - Update label: ha_config_set_label("Updated Name", label_id="my_label_id", color="blue") After creating a label, use ha_set_entity(labels=["label_id"]) to assign it to entities.
name required - (Annotated[str, Field(description='Display name for the label')]) label_id - (Annotated[str | None, Field(description='Label ID for updates. If not provided, creates a new label.', default=None)])
= null color - (Annotated[str | None, Field(description="Color for the label (e.g., 'red', 'blue', 'green', or hex like '#FF5733')", default=None)])
= null icon - (Annotated[str | None, Field(description="Material Design Icon (e.g., 'mdi:tag', 'mdi:label')", default=None)])
= null description - (Annotated[str | None, Field(description="Description of the label's purpose", default=None)])
= null Retrieve Home Assistant script configuration. Returns the complete configuration for a script, including sequence, mode, fields, and other settings. EXAMPLES: - Get script: ha_config_get_script("morning_routine") - Get script: ha_config_get_script("backup_script") For detailed script configuration help, use ha_get_skill_home_assistant_best_practices.
script_id required - (Annotated[str, Field(description="Script identifier (e.g., 'morning_routine')")]) Delete a Home Assistant script. EXAMPLES: - Delete script: ha_config_remove_script("old_script") - Delete script: ha_config_remove_script("temporary_script") **IMPORTANT LIMITATION:** This tool can only delete scripts created via the Home Assistant UI. Scripts defined in YAML configuration files (scripts.yaml or configuration.yaml) cannot be deleted through the API and will return a 405 Method Not Allowed error. To remove YAML-defined scripts, you must edit the configuration file directly. **WARNING:** Deleting a script that is used by automations may cause those automations to fail.
script_id required - (Annotated[str, Field(description="Script identifier to delete (e.g., 'old_script')")]) wait - (Annotated[bool | str, Field(description='Wait for script to be fully removed before returning. Default: True.', default=True)])
= true Create or update a Home Assistant script. Supports two modes: full config replacement OR Python transformation. WHEN TO USE WHICH MODE: - python_transform: RECOMMENDED for edits to existing scripts. Surgical updates. - config: Use for creating new scripts or full restructures. IMPORTANT: python_transform requires 'config_hash' from ha_config_get_script(). PYTHON TRANSFORM EXAMPLES: - Update step: python_transform="config['sequence'][0]['data']['message'] = 'Hello'" - Add step: python_transform="config['sequence'].append({'delay': {'seconds': 5}})" - Remove last step: python_transform="config['sequence'].pop()" Creates a new script or updates an existing one with the provided configuration. Supports both regular scripts (with sequence) and blueprint-based scripts. Required config fields (choose one): - sequence: List of actions to execute (for regular scripts) - use_blueprint: Blueprint configuration (for blueprint-based scripts) Optional config fields: - alias: Display name (defaults to script_id) - description: Script description - icon: Icon to display - mode: Execution mode ('single', 'restart', 'queued', 'parallel') - max: Maximum concurrent executions (for queued/parallel modes) - fields: Input parameters for the script SCRIPTS vs AUTOMATIONS: Scripts use 'sequence', NOT 'trigger' or 'action'. If you need trigger-based execution, use ha_config_set_automation instead. EXAMPLES: Create basic delay script: ha_config_set_script(script_id="wait_script", config={ "sequence": [{"delay": {"seconds": 5}}], "alias": "Wait 5 Seconds", "description": "Simple delay script" }) Create service call script: ha_config_set_script(script_id="blink_light", config={ "sequence": [ {"service": "light.turn_on", "target": {"entity_id": "light.living_room"}}, {"delay": {"seconds": 2}}, {"service": "light.turn_off", "target": {"entity_id": "light.living_room"}} ], "alias": "Light Blink", "mode": "single" }) Create script with parameters: ha_config_set_script(script_id="backup_script", config={ "alias": "Backup with Reference", "description": "Create backup with optional reference parameter", "fields": { "reference": { "name": "Reference", "description": "Optional reference for backup identification", "selector": {"text": None} } }, "sequence": [ { "action": "hassio.backup_partial", "data": { "compressed": False, "homeassistant": True, "homeassistant_exclude_database": True, "name": "Backup_{{ reference | default('auto') }}_{{ now().strftime('%Y%m%d_%H%M%S') }}" } } ] }) Update script: ha_config_set_script(script_id="morning_routine", config={ "sequence": [ {"service": "light.turn_on", "target": {"area_id": "bedroom"}}, {"service": "climate.set_temperature", "target": {"entity_id": "climate.bedroom"}, "data": {"temperature": 22}} ], "alias": "Updated Morning Routine" }) Create blueprint-based script: ha_config_set_script(script_id="notification_script", config={ "alias": "My Notification Script", "use_blueprint": { "path": "notification_script.yaml", "input": { "message": "Hello World", "title": "Test Notification" } } }) Update blueprint script inputs: ha_config_set_script(script_id="notification_script", config={ "alias": "My Notification Script", "use_blueprint": { "path": "notification_script.yaml", "input": { "message": "Updated message", "title": "Updated Title" } } }) PREFER NATIVE ACTIONS OVER TEMPLATES: Before using template-based logic in scripts, check if native actions exist: - Use `choose` action instead of template-based service names - Use `if/then/else` action instead of template conditions - Use `repeat` action with `for_each` instead of template loops - Use `wait_for_trigger` instead of `wait_template` when waiting for state changes - Use native action variables instead of complex template calculations For detailed script configuration help, use ha_get_skill_home_assistant_best_practices. Note: Scripts use Home Assistant's action syntax. Check the documentation for advanced features like conditions, variables, parallel execution, and service call options.
script_id required - (Annotated[str, Field(description="Script identifier (e.g., 'morning_routine')")]) config - (Annotated[str | dict[str, Any] | None, Field(description="Script configuration dictionary. Must include EITHER 'sequence' (for regular scripts) OR 'use_blueprint' (for blueprint-based scripts). Optional fields: 'alias', 'description', 'icon', 'mode', 'max', 'fields'. Mutually exclusive with python_transform.", default=None)])
= null python_transform - (Annotated[str | None, Field(description='Python expression to transform existing script config. Mutually exclusive with config. Requires config_hash for validation. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config[\'sequence\'][0][\'data\'][\'message\'] = \'Hello\'" Pattern: python_transform="for step in config[\'sequence\']: if step.get(\'alias\') == \'My Step\': step[\'data\'][\'value\'] = 100" \n\n' + get_security_documentation())])
= null config_hash - (Annotated[str | None, Field(description='Config hash from ha_config_get_script for optimistic locking. REQUIRED for python_transform (validates script unchanged). Optional for config updates (validates before full replacement if provided).')])
= null category - (Annotated[str | None, Field(description="Category ID to assign to this script. Use ha_config_get_category(scope='script') to list available categories, or ha_config_set_category() to create one.", default=None)])
= null wait - (Annotated[bool | str, Field(description='Wait for script to be queryable before returning. Default: True. Set to False for bulk operations.', default=True)])
= true Search inside automation, script, helper, and dashboard *configurations* — not for finding entity IDs. Use this when you need to find automations/scripts by what they *do* (e.g., which automations call a specific service, reference a particular entity, or contain a certain action). For finding entity IDs by name, use ha_search_entities instead. Searches within configuration definitions including triggers, actions, sequences, and other config fields. Also searches dashboard configurations (cards, badges, views) when search_types includes 'dashboard'. **NOTE:** Dashboards and badges are NOT searched by default. Add 'dashboard' to search_types to include them. Args: query: Search query (exact substring by default, or fuzzy with exact_match=False) search_types: Types to search (default: ["automation", "script", "helper"]) limit: Maximum total results to return (default: 5) exact_match: Use exact substring matching (default: True) Examples: - Find automations referencing an entity: ha_deep_search("sensor.temperature") - Find with fuzzy matching: ha_deep_search("motion", exact_match=False) - Search dashboards for entity refs: ha_deep_search("sensor.temperature", search_types=["dashboard"]) - Search everything: ha_deep_search("light.bedroom", search_types=["automation","script","helper","dashboard"])
query required - (str) search_types - (Annotated[str | list[str] | None, Field(default=None, description="Types to search: 'automation', 'script', 'helper', 'dashboard'. Pass as list or JSON array string. Default: automation, script, helper.")])
= null limit - (Annotated[int | str, Field(default=5, description='Maximum total results to return (default: 5)')])
= 5 offset - (Annotated[int | str, Field(default=0, description='Number of results to skip for pagination (default: 0)')])
= 0 include_config - (Annotated[bool | str, Field(default=False, description='Include full config in results. Default: False (returns summary only). Use ha_config_get_automation/ha_config_get_script for individual configs.')])
= false exact_match - (Annotated[bool | str, Field(default=True, description='Use exact substring matching (default: True). Set to False for fuzzy matching when the query may contain typos or when searching with approximate terms.')])
= true Get AI-friendly system overview with intelligent categorization. Returns comprehensive system information at the requested detail level, including Home Assistant base_url, version, location, timezone, entity overview, and active persistent notifications (if any). Use 'minimal' (default) for most queries. Domain counts and states_summary are always complete regardless of entity pagination. Standard/full modes paginate entities (default 200 per page) — use offset to fetch more. Use 'domains' filter to narrow scope.
detail_level - (Annotated[Literal['minimal', 'standard', 'full'], Field(default='minimal', description="'minimal': 10 entities/domain, top-5 states (default); 'standard': 200 entities/page, top-10 states (use offset for more); 'full': 200 entities/page + entity_id + state + full states. Use 'domains', 'limit', or max_entities_per_domain to control size")])
= "minimal" domains - (Annotated[str | list[str] | None, Field(default=None, description="Filter to specific domains (e.g. 'light,sensor' or ['light','sensor']). None = all domains. Useful to avoid context window overload.")])
= null limit - (Annotated[int | str | None, Field(default=None, description='Max total entities across all domains (default: unlimited for minimal, 200 for standard/full). Counts and states always complete. Use with offset for pagination.')])
= null offset - (Annotated[int | str, Field(default=0, description='Number of entities to skip for pagination (default: 0)')])
= 0 max_entities_per_domain - (Annotated[int | None, Field(default=None, description='Override default entity cap per domain (minimal=10, standard/full=unlimited). 0 = no limit on entities or states.')])
= null include_state - (Annotated[bool | str | None, Field(default=None, description='Include state field for entities (None = auto based on level). Full defaults to True.')])
= null include_entity_id - (Annotated[bool | str | None, Field(default=None, description='Include entity_id field for entities (None = auto based on level). Full defaults to True.')])
= null include_notifications - (Annotated[bool | str | None, Field(default=True, description='Include active persistent notifications (default: True). Set False to skip.')])
= true Get current status, state, and attributes of one or more entities (lights, switches, sensors, climate, covers, locks, fans, etc.). SINGLE ENTITY: Pass a string entity_id. Returns the entity's full state and attributes. MULTIPLE ENTITIES: Pass a list of entity IDs (max 100). Efficiently retrieves states using parallel requests. Duplicates are automatically deduplicated. Returns success=True if at least one entity state was retrieved. Check 'error_count' for any failed lookups in partial-success scenarios. EXAMPLES: - Single: ha_get_state("light.kitchen") - Multiple: ha_get_state(["light.kitchen", "light.living_room", "sensor.temperature"])
entity_id required - (Annotated[str | list[str], Field(description="Entity ID or list of entity IDs to retrieve state for (e.g., 'light.kitchen' or ['light.kitchen', 'sensor.temperature'])")]) Find or list entities (lights, sensors, switches, etc.) by name, domain, or area. When NOT to use: for searching inside automation, script, helper, or dashboard *configurations* (e.g. which automations call a service or reference an entity), use `ha_deep_search`. To enumerate all entities of a domain, omit `query` and pass `domain_filter`. For example, `ha_search_entities(domain_filter="calendar")` lists all calendars. At least one of `query`, `domain_filter`, or `area_filter` must be set.
query - (Annotated[str | None, Field(default=None, description='Entity name to search for (fuzzy or exact match). Omit to list entities; `domain_filter` or `area_filter` must be set in that mode.')])
= null domain_filter - (Annotated[str | None, Field(default=None, description="Limit to a single domain (e.g. 'light', 'sensor', 'calendar').")])
= null area_filter - (Annotated[str | None, Field(default=None, description='Limit to entities in a specific area (area ID or name).')])
= null limit - (int)
= 10 offset - (Annotated[int | str, Field(default=0, description='Number of results to skip for pagination (default: 0)')])
= 0 group_by_domain - (bool | str)
= false exact_match - (Annotated[bool | str, Field(default=True, description='Use exact substring matching (default: True). Set to False for fuzzy matching when the query may contain typos or approximate terms.')])
= true Control multiple devices with bulk operation support and WebSocket tracking.
operations required - (str | list[dict[str, Any]]) parallel - (bool | str)
= true Execute Home Assistant services to control entities and trigger automations. This is the universal tool for controlling all Home Assistant entities. Services follow the pattern domain.service (e.g., light.turn_on, climate.set_temperature). **Basic Usage:** ```python # Turn on a light ha_call_service("light", "turn_on", entity_id="light.living_room") # Set temperature with parameters ha_call_service("climate", "set_temperature", entity_id="climate.thermostat", data={"temperature": 22}) # Trigger automation ha_call_service("automation", "trigger", entity_id="automation.morning_routine") # Universal controls work with any entity ha_call_service("homeassistant", "toggle", entity_id="switch.porch_light") ``` **Parameters:** - **domain**: Service domain (light, climate, automation, etc.) - **service**: Service name (turn_on, set_temperature, trigger, etc.) - **entity_id**: Optional target entity. For some services (e.g., light.turn_off), omitting this targets all entities in the domain - **data**: Optional dict of service-specific parameters - **return_response**: Set to True for services that return data - **wait**: Wait for the entity state to change after the service call (default: True). Only applies to state-changing services on a single entity. Set to False for fire-and-forget calls, bulk operations, or services without observable state changes. **For detailed service documentation, use ha_get_skill_home_assistant_best_practices.** Common patterns: Use ha_get_state() to check current values before making changes. Use ha_search_entities() to find correct entity IDs.
domain required - (str) service required - (str) entity_id - (str | None)
= null data - (str | dict[str, Any] | None)
= null return_response - (bool | str)
= false wait - (bool | str)
= true Check status of one or more device operations with real-time WebSocket verification. Pass a single operation_id string to check one operation, or a list of IDs to check multiple operations at once (bulk status). The timeout_seconds parameter applies to single-operation checks only. Bulk checks poll each operation individually with a short internal timeout. Use this to track operations initiated by ha_bulk_control or ha_call_service. For current entity states, use ha_get_state instead.
operation_id required - (Annotated[str | list[str], Field(description='Single operation ID or list of operation IDs to check. Use a single string for one operation, or a list for bulk status checks.')]) timeout_seconds - (int)
= 10 List available Home Assistant services with optional pagination and detail control. Discovers services/actions that can be called via ha_call_service. Use domain or query filters to narrow results. Defaults to summary mode (name + description only) to keep responses compact. Args: domain: Filter by domain (e.g., 'light', 'switch', 'climate'). query: Search in service names and descriptions. limit: Max services per page (default: 50). offset: Pagination offset (default: 0). detail_level: 'summary' (default) returns name/description only; 'full' includes parameter field schemas. Examples: # Browse first page of all services (compact) ha_list_services() # List all light services with full parameter details ha_list_services(domain="light", detail_level="full") # Search for temperature-related services ha_list_services(query="temperature") # Paginate through all services ha_list_services(offset=50)
domain - (str | None)
= null query - (str | None)
= null limit - (Annotated[int | str, Field(default=50, description='Max services to return per page (default: 50)')])
= 50 offset - (Annotated[int | str, Field(default=0, description='Number of services to skip for pagination (default: 0)')])
= 0 detail_level - (Annotated[Literal['summary', 'full'], Field(default='summary', description="'summary': service name + description only (default). 'full': include parameter field schemas.")])
= "summary" Create a fast Home Assistant backup (local only).
name - (Annotated[str | None, Field(description="Backup name (auto-generated if not provided, e.g., 'MCP_Backup_2025-10-05_04:30')", default=None)])
= null Restore Home Assistant from a backup (LAST RESORT - use with extreme caution). **⚠️ WARNING - DESTRUCTIVE OPERATION ⚠️** **This tool restarts Home Assistant and restores configuration to a previous state.** **IMPORTANT CONSIDERATIONS:** 1. **Try undo operations first** - Often you can just reverse what you did: - Deleted automation? Recreate it with ha_config_set_automation - Modified script? Use ha_config_set_script to fix it - Most config changes can be rolled back without using restore 2. **Safety mechanism:** A NEW backup is automatically created BEFORE restore - This allows you to rollback the restore if needed - You can restore from this pre-restore backup if something goes wrong 3. **What gets restored:** - Home Assistant configuration (automations, scripts, etc.) - Add-ons (if they were in the backup) - Optional: Database - historical sensor data, statistics, state history (set restore_database=true) 4. **Side effects:** - Home Assistant will RESTART during restore - Any changes made after the backup was created will be LOST - Temporary disconnection from all integrations during restart **Recommended workflow:** 1. Try to undo your changes manually first 2. If you must restore, use the most recent backup 3. Set restore_database=false unless you need historical data 4. Expect a restart and temporary downtime **Example Usage:** - Restore config only: ha_backup_restore("dd7550ed") - Full restore with DB: ha_backup_restore("dd7550ed", restore_database=true) **Returns:** Restore job status
backup_id required - (Annotated[str, Field(description="Backup ID to restore (e.g., 'dd7550ed' from backup list or ha_backup_create result)")]) restore_database - (Annotated[bool, Field(description='Restore database (default: false for config-only restore)', default=False)])
= false Check Home Assistant configuration for errors. Validates configuration files without applying changes. Always run this before ha_restart() to ensure configuration is valid.
Update raw YAML configuration in configuration.yaml or packages/*.yaml (LAST RESORT). **WARNING:** Destructive, disabled by default. Dedicated tools exist for almost every use case and should be preferred: - Template sensors (state-based or trigger-based) -> ha_config_set_helper(helper_type='template') - Automations -> ha_config_set_automation - Scripts -> ha_config_set_script - Scenes -> ha_config_set_scene - All 27 helper types (input_*, counter, timer, schedule, zone, person, tag, group, min_max, threshold, derivative, statistics, utility_meter, trend, filter, switch_as_x, etc.) -> ha_config_set_helper Intended for YAML-only integrations with no config-flow or API equivalent (command_line, rest, shell_command, notify platforms). Check ``post_action`` in the response: most keys need a full HA restart; template, mqtt, and group support reload. Preserves YAML comments and HA tags (``!include``, ``!secret``) on round-trip; ``replace`` swaps the subtree as-is. For detailed routing guidance, use ha_get_skill_home_assistant_best_practices.
yaml_path required - (Annotated[str, Field(description="Top-level YAML key to modify. Only a narrow allowlist of YAML-only integration keys is accepted (e.g., 'command_line', 'rest', 'shell_command', 'notify'). Not for template sensors (use ha_config_set_helper), automations, scripts, scenes, or input_* helpers — those have dedicated tools.")]) action required - (Annotated[str, Field(description="Action to perform: 'add' (insert/merge content under key), 'replace' (overwrite key with new content), or 'remove' (delete the key entirely).")]) content - (Annotated[str | None, Field(default=None, description="YAML content for the value under yaml_path. Required for 'add' and 'replace' actions. Must be valid YAML.")])
= null file - (Annotated[str, Field(default='configuration.yaml', description="Relative path to the YAML config file. Defaults to 'configuration.yaml'. Also supports 'packages/*.yaml'.")])
= "configuration.yaml" backup - (Annotated[bool | str, Field(default=True, description='Create a backup before editing. Defaults to True. Backups are saved to www/yaml_backups/.')])
= true Get Home Assistant system health, including Zigbee (ZHA) and Z-Wave JS network diagnostics. Returns health check results from integrations, system resources, and connectivity. Available information varies by installation type and loaded integrations. **Parameters:** - include: Optional comma-separated list of additional data to include. - "repairs": Repair items from Settings > System > Repairs - "zha_network": ZHA Zigbee devices with radio signal summary (name, LQI, RSSI) - "zha_network_full": ZHA Zigbee devices with all device details (can be large on 100+ device networks; prefer "zha_network" for summary) - "zwave_network": Z-Wave JS network status and node summary (status, security, routing) - Example: include="repairs,zha_network,zwave_network"
include - (str | None)
= null Get update information -- list all updates or get details for a specific one. Without an entity_id: Lists all available updates across the system including Home Assistant Core, add-ons, device firmware, HACS, and OS updates. With an entity_id: Returns detailed information about a specific update including version info, category, and release notes (if available). With include_release_notes=True (Core updates only): Also fetches HA release blog posts for every monthly version between installed and latest. Returns structured breaking changes and installed integration domains for cross-referencing. EXAMPLES: - List all updates: ha_get_updates() - List including skipped: ha_get_updates(include_skipped=True) - Get specific update: ha_get_updates(entity_id="update.home_assistant_core_update") - Pre-update analysis: ha_get_updates(entity_id="update.home_assistant_core_update", include_release_notes=True) RETURNS (when listing): - updates_available: Count of available updates - updates: List of update entities with version info - categories: Updates grouped by category (core, addons, devices, hacs, os) RETURNS (when getting specific update): - Update details including installed/latest versions - Release notes (fetched from WebSocket API or GitHub) - Category and installation status RETURNS (with include_release_notes=True, Core only): - breaking_changes.entries[]: Each has integration, description, version - multi_version_release_notes[]: Full text per version {version, content, source_url} - installed_integrations: Your integration domains for cross-referencing
entity_id - (Annotated[str | None, Field(description="Update entity ID to get details for (e.g., 'update.home_assistant_core_update'). If omitted, lists all available updates.", default=None)])
= null include_skipped - (Annotated[bool | str, Field(description='When listing all updates, include updates that have been skipped (default: False)', default=False)])
= false include_release_notes - (Annotated[bool | str, Field(description='When getting a Core update entity, fetch multi-version release notes and breaking changes for all versions between installed and latest (default: False). Adds breaking_changes, multi_version_release_notes, and installed_integrations to the response.', default=False)])
= false Reload Home Assistant configuration without full restart. This tool reloads specific configuration components, allowing changes to take effect without restarting the entire Home Assistant instance. This is much faster than a full restart. **Parameters:** - target: What to reload. Options: - "all": Reload all reloadable components - "automations": Reload automation configurations - "scripts": Reload script configurations - "scenes": Reload scene configurations - "groups": Reload group configurations - "input_booleans": Reload input_boolean helpers - "input_numbers": Reload input_number helpers - "input_texts": Reload input_text helpers - "input_selects": Reload input_select helpers - "input_datetimes": Reload input_datetime helpers - "input_buttons": Reload input_button helpers - "timers": Reload timer helpers - "counters": Reload counter helpers - "templates": Reload template sensors/entities - "persons": Reload person configurations - "zones": Reload zone configurations - "core": Reload core configuration (customize, packages) - "themes": Reload frontend themes **Example Usage:** ```python # Reload just automations after editing ha_reload_core(target="automations") # Reload all configurations ha_reload_core(target="all") # Reload input helpers after adding new ones ha_reload_core(target="input_booleans") ``` **When to Use:** - After editing automation/script YAML files - After adding new input helpers via YAML - After modifying customize.yaml - After theme changes
target - (str)
= "all" Restart Home Assistant. **WARNING: This will restart the entire Home Assistant instance!** All automations will be temporarily unavailable during restart. The restart typically takes 1-5 minutes depending on your setup. **Parameters:** - confirm: Must be set to True to confirm the restart. This is a safety measure to prevent accidental restarts. **Best Practices:** 1. Always run ha_check_config() first to ensure configuration is valid 2. Notify users before restarting (if applicable) 3. Schedule restarts during low-activity periods **Example Usage:** ```python # Always check config first config = ha_check_config() if config["result"] == "valid": # Restart with confirmation result = ha_restart(confirm=True) ``` **Alternative:** For configuration changes, consider using ha_reload_core() instead, which reloads specific components without a full restart.
confirm - (bool | str)
= false Get todo lists or items - list all todo lists or get items from a specific list. Without an entity_id: Lists all todo list entities in Home Assistant. With an entity_id: Gets items from that specific todo list, optionally filtered by status. **LISTING TODO LISTS (entity_id omitted):** Returns all entities in the 'todo' domain, including shopping lists and any other todo-type integrations. Each todo list includes: - entity_id: The unique identifier (e.g., 'todo.shopping_list') - friendly_name: Human-readable name - state: Number of incomplete items or current status **GETTING TODO ITEMS (entity_id provided):** Retrieves items from the specified todo list. Status filter values: - needs_action: Items that still need to be done - completed: Items that have been marked as done - None (default): Returns all items regardless of status Item properties: - uid: Unique identifier for the item - summary: The item text/description - status: Current status (needs_action or completed) - description: Optional detailed description - due: Optional due date (if supported) EXAMPLES: - List all todo lists: ha_get_todo() - Get all items: ha_get_todo("todo.shopping_list") - Get incomplete items: ha_get_todo("todo.shopping_list", status="needs_action") - Get completed items: ha_get_todo("todo.shopping_list", status="completed") USE CASES: - "What todo lists do I have?" - "Show me my shopping list" - "What's on my todo list?" - "Show completed items"
entity_id - (Annotated[str | None, Field(description="Todo list entity ID (e.g., 'todo.shopping_list'). If omitted, lists all todo list entities.", default=None)])
= null status - (Annotated[Literal['needs_action', 'completed'] | None, Field(description="Filter items by status: 'needs_action' for incomplete, 'completed' for done. Only applies when entity_id is provided.", default=None)])
= null Remove an item from a Home Assistant todo list. Permanently deletes an item from the specified todo list. IDENTIFYING ITEMS: - Use the item's UID (from ha_get_todo) - Or use the exact item summary/name text EXAMPLES: - Remove by name: ha_remove_todo_item("todo.shopping_list", "Buy milk") - Remove by UID: ha_remove_todo_item("todo.shopping_list", "abc123-uid") USE CASES: - "Remove milk from my shopping list" - "Delete the eggs item" - "Clear 'call mom' from my todo" WARNING: This permanently removes the item. To mark as completed instead, use ha_set_todo_item() with status="completed".
entity_id required - (Annotated[str, Field(description="Todo list entity ID (e.g., 'todo.shopping_list')")]) item required - (Annotated[str, Field(description='Item to remove - can be the item UID or the exact item summary/name')]) Create or update a todo item in Home Assistant. WITHOUT item parameter (create mode): Creates a new item. summary is required. WITH item parameter (update mode): Updates an existing item identified by UID or exact name. At least one update field (rename, status, description, due_date, due_datetime) is required. EXAMPLES: - Add item: ha_set_todo_item("todo.shopping_list", summary="Buy milk") - Add with description: ha_set_todo_item("todo.shopping_list", summary="Buy milk", description="2% organic") - Add with due date: ha_set_todo_item("todo.tasks", summary="Pay bills", due_date="2024-12-31") - Complete item: ha_set_todo_item("todo.shopping_list", item="Buy milk", status="completed") - Rename item: ha_set_todo_item("todo.tasks", item="Old task", rename="New task name") - Update due date: ha_set_todo_item("todo.tasks", item="Pay bills", due_date="2024-12-31") - Reopen item: ha_set_todo_item("todo.tasks", item="Task to redo", status="needs_action") NOTE: Not all todo integrations support all features (description, due dates). The Shopping List integration only supports summary.
entity_id required - (Annotated[str, Field(description="Todo list entity ID (e.g., 'todo.shopping_list')")]) summary - (Annotated[str | None, Field(description="Item text/name. Required when creating a new item. Ignored in update mode — use 'rename' to change the item name.", default=None)])
= null item - (Annotated[str | None, Field(description='Existing item to update - can be the item UID or the exact item summary/name. When provided, operates in update mode. When omitted, creates a new item.', default=None)])
= null status - (Annotated[Literal['needs_action', 'completed'] | None, Field(description="Item status: 'completed' to mark done, 'needs_action' to mark incomplete. Only used in update mode.", default=None)])
= null description - (Annotated[str | None, Field(description='Detailed description for the item', default=None)])
= null due_date - (Annotated[str | None, Field(description="Due date in YYYY-MM-DD format (e.g., '2024-12-25')", default=None)])
= null due_datetime - (Annotated[str | None, Field(description="Due datetime in ISO format (e.g., '2024-12-25T14:00:00'). Overrides due_date if both provided.", default=None)])
= null rename - (Annotated[str | None, Field(description='New name/summary for an existing item. Only used in update mode.', default=None)])
= null Evaluate Jinja2 templates using Home Assistant's template engine. This tool allows testing and debugging of Jinja2 template expressions that are commonly used in Home Assistant automations, scripts, and configurations. It provides real-time evaluation with access to all Home Assistant states, functions, and template variables. **Parameters:** - template: The Jinja2 template string to evaluate - timeout: Maximum evaluation time in seconds (default: 3) - report_errors: Whether to return detailed error information (default: True) **Common Template Functions:** **State Access:** ```jinja2 {{ states('sensor.temperature') }} # Get entity state value {{ states.sensor.temperature.state }} # Alternative syntax {{ state_attr('light.bedroom', 'brightness') }} # Get entity attribute {{ is_state('light.living_room', 'on') }} # Check if entity has specific state ``` **Numeric Operations:** ```jinja2 {{ states('sensor.temperature') | float(0) }} # Convert to float with default {{ states('sensor.humidity') | int }} # Convert to integer {{ (states('sensor.temp') | float + 5) | round(1) }} # Math operations ``` **Time and Date:** ```jinja2 {{ now() }} # Current datetime {{ now().strftime('%H:%M:%S') }} # Format current time {{ as_timestamp(now()) }} # Convert to Unix timestamp {{ now().hour }} # Current hour (0-23) {{ now().weekday() }} # Day of week (0=Monday) ``` **Conditional Logic:** ```jinja2 {{ 'Day' if now().hour < 18 else 'Night' }} # Ternary operator {% if is_state('sun.sun', 'above_horizon') %} It's daytime {% else %} It's nighttime {% endif %} ``` **Lists and Loops:** ```jinja2 {% for entity in states.light %} {{ entity.entity_id }}: {{ entity.state }} {% endfor %} {{ states.light | selectattr('state', 'eq', 'on') | list | count }} # Count on lights ``` **String Operations:** ```jinja2 {{ states('sensor.weather') | title }} # Title case {{ 'Hello ' + states('input_text.name') }} # String concatenation {{ states('sensor.data') | regex_replace('pattern', 'replacement') }} ``` **Device and Area Functions:** ```jinja2 {{ device_entities('device_id_here') }} # Get entities for device {{ area_entities('living_room') }} # Get entities in area {{ device_id('light.bedroom') }} # Get device ID for entity ``` **Common Use Cases:** **Automation Conditions:** ```jinja2 # Check if it's a workday and after 7 AM {{ is_state('binary_sensor.workday', 'on') and now().hour >= 7 }} # Temperature-based condition {{ states('sensor.outdoor_temp') | float < 0 }} ``` **Dynamic Service Data:** ```jinja2 # Dynamic brightness based on time {{ 255 if now().hour < 22 else 50 }} # Message with current values "Temperature is {{ states('sensor.temp') }}°C, humidity {{ states('sensor.humidity') }}%" ``` **Examples:** **Test basic state access:** ```python ha_eval_template("{{ states('light.living_room') }}") ``` **Test conditional logic:** ```python ha_eval_template("{{ 'Day' if now().hour < 18 else 'Night' }}") ``` **Test mathematical operations:** ```python ha_eval_template("{{ (states('sensor.temperature') | float + 5) | round(1) }}") ``` **Test complex automation condition:** ```python ha_eval_template("{{ is_state('binary_sensor.workday', 'on') and now().hour >= 7 and states('sensor.temperature') | float > 20 }}") ``` **Test entity counting:** ```python ha_eval_template("{{ states.light | selectattr('state', 'eq', 'on') | list | count }}") ``` **IMPORTANT NOTES:** - Templates have access to all current Home Assistant states and attributes - Use this tool to test templates before using them in automations or scripts - Template evaluation respects Home Assistant's security model and timeouts - Complex templates may affect Home Assistant performance - keep them efficient - Use default values (e.g., `| float(0)`) to handle missing or invalid states **For template documentation:** https://www.home-assistant.io/docs/configuration/templating/
template required - (str) timeout - (int)
= 3 report_errors - (bool | str)
= true Install the ha_mcp_tools custom component via HACS. This tool installs the ha_mcp_tools custom component which provides advanced services not available through standard Home Assistant APIs: **Available Services (after installation):** - `ha_mcp_tools.list_files`: List files in allowed directories (www/, themes/) - More services coming soon: file write, backup cleanup, event buffer, etc. **Installation Process:** 1. Checks if HACS is available 2. Checks if ha_mcp_tools is already installed 3. Adds the repository to HACS if not present 4. Downloads and installs the component 5. Optionally restarts Home Assistant **Note:** A restart is required for the integration to load and become available. Set `restart=True` to automatically restart, or manually restart later. Args: restart: Whether to restart Home Assistant after installation (default: False) Returns: Installation status and next steps.
restart - (Annotated[bool, Field(default=False, description='Whether to restart Home Assistant after installation (required for integration to load)')])
= false Collect diagnostic information for filing issue reports or feedback. This tool generates templates for TWO types of reports: 1. **Runtime Bug Report** - For ha-mcp errors, failures, unexpected behavior 2. **Agent Behavior Feedback** - For AI agent inefficiency, wrong tool usage **IMPORTANT FOR AI AGENTS:** You MUST analyze the conversation context to determine which template to present: 🐛 **Present RUNTIME BUG template if:** - User reports an error, failure, or unexpected behavior - A tool returned an error or incorrect result - Something is broken or not working in ha-mcp 🤖 **Present AGENT BEHAVIOR template if:** - User mentions YOU (the agent) used the wrong tool - User suggests a more efficient workflow - User reports YOUR inefficiency or mistakes - User says you should have done something differently **If unclear which type, ASK the user:** "Are you reporting a bug in ha-mcp, or providing feedback on how I used the tools?" **WHEN TO USE THIS TOOL:** - "I want to file a bug/issue/report" - "This isn't working" - "You should have used [other tool]" - "That was inefficient" **OUTPUT:** Returns both templates plus diagnostic data. Key fields: - `runtime_bug_template`, `agent_behavior_template` — pick based on context - `recent_logs`, `startup_logs` — captured ha-mcp tool/server log entries - `addon_logs` — addon container stdout/stderr (HA add-on installs only; empty string otherwise) - `suggested_title`, `duplicate_check_urls`, `anonymization_guide`
tool_call_count - (Annotated[int, Field(default=10, ge=1, le=16, description='Number of tool calls made since the issue started. This determines how many log entries to include. Count how many ha_* tools were called from when the issue began. Default: 10. Max: 16 (limited by 200-entry log buffer: 16*4*3=192)')])
= 10 Get zone information - list all zones or get details for a specific one. Without a zone_id: Lists all Home Assistant zones with their coordinates and radius. With a zone_id: Returns detailed configuration for a specific zone. ZONE PROPERTIES: - ID, name, icon - Latitude, longitude, radius - Passive mode setting EXAMPLES: - List all zones: ha_get_zone() - Get specific zone: ha_get_zone(zone_id="abc123") **NOTE:** This returns storage-based zones (created via UI/API), not YAML-defined zones. The 'home' zone is typically defined in YAML and may not appear in this list.
zone_id - (Annotated[str | None, Field(description='Zone ID to get details for (from ha_get_zone() list). If omitted, lists all zones.', default=None)])
= null Remove a Home Assistant zone. EXAMPLES: - Remove zone: ha_remove_zone("abc123") **WARNING:** Removing a zone used in automations may cause those automations to fail. Use ha_get_zone() to find the zone_id for the zone you want to remove. **NOTE:** The 'home' zone cannot be removed as it is typically defined in configuration.yaml.
zone_id required - (Annotated[str, Field(description='Zone ID to remove (use ha_get_zone to find IDs)')]) Create or update a Home Assistant zone. Omit zone_id to create a new zone (name, latitude, longitude required). Provide zone_id to update an existing zone (only specified fields change). EXAMPLES: - Create: ha_set_zone(name="Office", latitude=40.7128, longitude=-74.0060, radius=150, icon="mdi:briefcase") - Update name: ha_set_zone(zone_id="abc123", name="New Office") - Update radius: ha_set_zone(zone_id="abc123", radius=200) - Update location: ha_set_zone(zone_id="abc123", latitude=40.7128, longitude=-74.0060) Note: The 'home' zone is typically defined in YAML and cannot be modified via this API.
name - (Annotated[str | None, Field(description='Display name for the zone (required for create)', default=None)])
= null latitude - (Annotated[float | None, Field(description='Latitude coordinate of the zone center (required for create)', default=None)])
= null longitude - (Annotated[float | None, Field(description='Longitude coordinate of the zone center (required for create)', default=None)])
= null zone_id - (Annotated[str | None, Field(description='Zone ID to update (omit to create new zone, use ha_get_zone to find IDs)', default=None)])
= null radius - (Annotated[float | None, Field(description='Radius of the zone in meters (must be > 0, defaults to 100 on create)', default=None)])
= null icon - (Annotated[str | None, Field(description="Material Design Icon (e.g., 'mdi:briefcase', 'mdi:school')", default=None)])
= null passive - (Annotated[bool | None, Field(description='Passive mode - if True, zone will not trigger enter/exit automations (defaults to False on create)', default=None)])
= null