| entities_list_entitiesA | List entity states, optionally filtered by domain, with pagination and field selection. Reads live states via ha.get_states() over HTTP; when fields requests
area_id, device_id or labels, it also fetches the entity registry
over WebSocket and joins it by entity ID. Filtering by domain and
pagination (limit/offset) are applied client-side after the fetch. Use when: browsing or searching current entity states across the whole
installation or one domain.
Not for: raw registry fields such as disabled/hidden status — use
entities_list_entity_registry; a plain unfiltered state dump — use
ws_get_states.
Returns: list of dicts, one per entity, containing only the requested
fields.
Limits: limit/offset paginate the already-filtered list; no size cap
beyond that. |
| entities_get_entityA | Get the full state and attributes of a single entity. Calls ha.get_state(entity_id), a single HTTP GET to
/api/states/<entity_id>; the response includes state, attributes,
last_changed and last_updated as reported by Home Assistant. Use when: inspecting one entity's current value and attributes before or
after an action.
Not for: many entities at once — use entities_list_entities or
snapshot_get_snapshot.
Returns: dict with entity_id, state, attributes, last_changed,
last_updated, context. |
| entities_turn_onA | Turn on an entity, optionally with light-only color and brightness options. Calls <domain>.turn_on for the entity's domain over HTTP. If any of
brightness, color_temp, color_temp_kelvin or rgb_color is given
for a non-light entity, the service is not called at all — HA's own
turn_on for other domains (e.g. switch) rejects unknown fields, so
this checks the domain first. A given color_temp (mireds) is converted
to Kelvin (round(1_000_000 / mireds)) since HA's light.turn_on no
longer accepts mireds. Use when: turning on any entity, with or without light color/brightness.
Not for: a dedicated light color/brightness change without an on/off
intent — use services_set_light_color; an input_boolean-only helper —
helpers_set_input_boolean is the domain-specific equivalent.
Returns: the list of changed states from Home Assistant, or an error
dict.
Errors: {"error": "..."} when a light-only option is given for a
non-light domain. |
| entities_turn_offA | Turn off an entity by calling its domain's turn_off action. Calls <domain>.turn_off with {"entity_id": entity_id} over HTTP. Use when: turning off any controllable entity regardless of domain.
Not for: flipping state without knowing the target — use
entities_toggle.
Returns: the list of changed states from Home Assistant. |
| entities_toggleA | Toggle an entity between on and off by calling its domain's toggle action. Calls <domain>.toggle with {"entity_id": entity_id} over HTTP; the
resulting state depends on the entity's current state, so repeating this
call flips it back and forth. Use when: the desired end state is unknown or irrelevant, only "flip it".
Not for: a deterministic on/off — use entities_turn_on/entities_turn_off.
Returns: the list of changed states from Home Assistant. |
| entities_set_valueA | Set the numeric value of an input_number, number or climate entity. Dispatches to input_number.set_value, number.set_value or
climate.set_temperature depending on entity_id's domain; any other
domain raises ValueError before any HTTP call is made. Use when: writing a target number or temperature to one of these three
domains.
Not for: input_text, input_select, input_boolean or input_datetime — use
helpers_set_input_text, helpers_set_input_select,
helpers_set_input_boolean or helpers_set_input_datetime.
Returns: the list of changed states from Home Assistant.
Errors: raises ValueError for any domain other than input_number,
number or climate. |
| entities_select_optionA | Select an option on an input_select or select entity. Calls input_select.select_option for input_select.* entities, or
select.select_option for every other domain (in practice select.*). Use when: setting the current option of an input_select or select entity.
Not for: an input_select-only call site — helpers_set_input_select
does the same thing for that domain specifically.
Returns: the list of changed states from Home Assistant. |
| entities_update_entity_nameA | Rename an entity in the entity registry, replacing its current display name. Calls WS config/entity_registry/update with name=name; the previous
name is not returned or preserved anywhere by this call. Use when: correcting or customising an entity's display name.
Not for: reassigning area, or enabling/disabling — use
entities_assign_entity_to_area, entities_disable_entity,
entities_enable_entity.
Returns: the updated entity registry entry from Home Assistant. |
| entities_assign_entity_to_areaA | Assign an entity to an area, replacing its current area assignment. Calls WS config/entity_registry/update with area_id=area_id; any
previous area assignment is overwritten and not returned. Use when: moving an entity to a different area in the registry.
Not for: renaming it, or toggling exposure — use
entities_update_entity_name or entities_set_entity_exposure.
Returns: the updated entity registry entry from Home Assistant. |
| entities_disable_entityA | Disable an entity in the registry so Home Assistant stops creating its state. Calls WS config/entity_registry/update with disabled_by="user". Use when: retiring an entity without deleting its registry entry.
Not for: re-enabling it — use entities_enable_entity.
Returns: the updated entity registry entry from Home Assistant. |
| entities_enable_entityA | Re-enable a previously disabled entity in the registry. Calls WS config/entity_registry/update with disabled_by=None. Use when: restoring an entity disabled via entities_disable_entity.
Not for: disabling it — use entities_disable_entity.
Returns: the updated entity registry entry from Home Assistant. |
| entities_list_entity_registryA | Get the raw entity registry, including disabled and hidden entities. Calls WS config/entity_registry/list and filters client-side by
domain when given. Unlike entities_list_entities, this has no state
values, only registry metadata (area_id, device_id, disabled_by,
labels, ...). Use when: auditing registry metadata, including disabled/hidden entities
that carry no live state.
Not for: current state values — use entities_list_entities.
Returns: list of raw entity registry entry dicts from Home Assistant. |
| entities_bulk_controlA | Turn on, turn off or toggle many entities in one call, grouped by domain. Groups entity_ids by domain and issues one <domain>.<action> service
call per domain group (e.g. all light.* entities get a single
light.turn_on), instead of one call per entity. Use when: applying the same on/off/toggle action to many entities across
domains at once.
Not for: writing arbitrary states instead of calling a service — use
entities_bulk_set_state; controlling every entity of one domain in a
single area by area_id rather than an explicit entity_id list — use
areas_control_area.
Returns: dict mapping domain to the number of entities affected.
Errors: raises ValueError when action is not one of turn_on,
turn_off, toggle. |
| entities_bulk_set_stateA | Write states for many entities directly via the states API, one call per entity. Calls ha.set_state(entity_id, state, attributes) per item in
updates, which posts to /api/states/<entity_id>; this sets a virtual
state that a real device driver overwrites on its next update, unlike a
real service call. Use when: seeding or overriding state for testing, template sensors, or
entities with no backing device.
Not for: actually controlling a device — use entities_bulk_control.
Returns: list of per-update dicts ({entity_id, ok, error?, error_type?});
a missing entity_id/state or a failed write is reported per item, not
raised.
Errors: per-item {"ok": false, "error": "...", "error_type": "..."};
error_type is "validation" for a missing entity_id/state (no
write attempted), "http" for an httpx.HTTPError from the write call
(bad response or network failure talking to Home Assistant), or
"unexpected" for any other exception. An "unexpected" error is still
caught per item and does not abort the rest of the batch. |
| entities_set_entity_exposureA | Expose or hide one entity to one voice assistant. Calls WS homeassistant/expose_entity with a single-element
entity_ids/assistants list. Use when: changing exposure for one entity and one assistant.
Not for: many entities or assistants at once — use
entities_bulk_set_entity_exposure.
Returns: dict with entity_id, assistant, should_expose and the raw
WS result.
Errors: raises ValueError when assistant is not one of conversation,
cloud.alexa, cloud.google_assistant. |
| entities_get_entity_exposureA | Get exposure flags for one entity across all voice assistants. Home Assistant has no per-entity exposure query, so this fetches the
full exposure map via WS homeassistant/expose_entity/list and filters
it client-side; an entity absent from that map is reported as False
for every assistant. Use when: checking whether one entity is exposed, and to which
assistants.
Not for: the whole exposure map for one assistant — use
entities_list_exposed_entities.
Returns: dict with entity_id and exposure (assistant name -> bool for
conversation, cloud.alexa, cloud.google_assistant). |
| entities_list_exposed_entitiesA | List every entity currently exposed to one voice assistant. Home Assistant has no per-assistant exposure query, so this fetches the
full exposure map via WS homeassistant/expose_entity/list and filters
it client-side for the given assistant. Use when: auditing what one assistant can currently see.
Not for: exposure of one specific entity — use
entities_get_entity_exposure.
Returns: dict with assistant and exposed (list of entity IDs).
Errors: raises ValueError when assistant is not one of conversation,
cloud.alexa, cloud.google_assistant. |
| entities_bulk_set_entity_exposureA | Expose or hide many entities across one or more voice assistants in a single call. Calls WS homeassistant/expose_entity once with the full entity_ids
and assistants lists, which HA accepts natively, instead of one call
per entity/assistant pair. Returns immediately with an empty result when
entity_ids is empty. Use when: changing exposure for many entities and/or several assistants
at once.
Not for: a single entity and assistant — use
entities_set_entity_exposure.
Returns: dict with count, assistants, should_expose and the raw WS
result.
Errors: raises ValueError when assistants contains an identifier
outside conversation, cloud.alexa, cloud.google_assistant. |
| services_call_serviceA | Call any Home Assistant action by domain and service name over HTTP. Posts to /api/services/<domain>/<service> with data as the JSON
body; data holds both fields and targets (entity_id/area_id/
device_id). Effect depends entirely on the domain/service passed.
domain/service must match [A-Za-z0-9_]+ (ADR-0006 D3) or the call
is refused before any request is built. Refuses hassio.addon_stop/
app_stop/addon_stdin/app_stdin against nexus's own add-on
(self_protection.is_own_addon); addon_restart/app_restart stay
allowed. homeassistant.restart/stop, hassio.host_reboot/
host_shutdown/restore_full/restore_partial, update.install and
group.remove additionally require confirm=True (ADR-0006 D2) — a
human-in-the-loop checkpoint, not a security boundary; ignored for
every other service. Use when: no dedicated tool exists for the action needed.
Not for: an action returning response data (e.g.
weather.get_forecasts) — use ws_call_service, which refuses the
same eight guarded services outright (ADR-0006 D5) instead of
accepting confirm.
Returns: the list of states changed during the call.
Errors: {"error": "invalid_service_name"} for a malformed
domain/service; {"error": "self_addon_hassio_service_blocked", "message": ...} for the blocked hassio.* cases; {"error": "confirmation_required", "message": ..., "action": ...} for a guarded
service called without confirm=True. |
| services_list_servicesA | List all services Home Assistant currently has registered, optionally filtered by domain. Calls ha.list_services() (HTTP GET /api/services) and filters the
result client-side by domain when given. Use when: discovering which services and fields a domain supports before
calling services_call_service.
Returns: list of dicts, one per domain, each with its available services
and their fields. |
| services_fire_eventA | Fire an arbitrary Home Assistant event with an optional data payload. Posts to /api/events/<event_type> with event_data as the JSON body;
any automation or integration listening for event_type reacts to it,
so the effect depends entirely on what is registered to listen. Use when: triggering automations or integrations that listen for a
specific event type.
Returns: dict confirming the event was fired, as returned by Home
Assistant. |
| services_render_templateA | Render a Jinja2 template string once through HA's template engine over HTTP. Posts to /api/template with {"template": template} and returns the
rendered text. Use when: testing a template's output before saving it into an
automation, script or template sensor.
Not for: rendering through the WebSocket subscription transport — use
ws_render_template.
Returns: the rendered template as plain text. |
| services_reload_configA | Reload one domain's configuration from disk by calling its reload action. Calls <domain>.reload (e.g. automation.reload, input_boolean.reload)
over HTTP with no data. Use when: applying YAML changes for automations, scripts, scenes or
input helpers without restarting Home Assistant.
Not for: reloading every helper domain in one call — use
helpers_reload_helpers.
Returns: the list of states changed by the reload. |
| services_press_buttonA | Press a button entity, running whatever action it is configured to perform. Calls button.press with {"entity_id": entity_id} over HTTP. Use when: running a button entity's configured action, such as a
template button or a device's physical-button equivalent.
Returns: the list of states changed by the press. |
| services_set_cover_positionA | Set a cover/blind/shutter to a specific open position. Calls cover.set_cover_position with {"entity_id": entity_id, "position": position} over HTTP. Use when: moving a cover to a specific percentage rather than fully
open/closed.
Returns: the list of states changed by the call. |
| services_set_cover_tiltA | Set a cover's slat/tilt position independently of its open/closed position. Calls cover.set_cover_tilt_position with {"entity_id": entity_id, "tilt_position": tilt_position} over HTTP. Use when: adjusting slat angle on a cover that supports tilt.
Not for: the cover's overall open/closed position — use
services_set_cover_position.
Returns: the list of states changed by the call. |
| services_set_climate_modeA | Set a climate entity's heating/cooling mode. Calls climate.set_hvac_mode with {"entity_id": entity_id, "hvac_mode": hvac_mode} over HTTP. Use when: switching a thermostat between heat/cool/auto/off/fan_only/dry.
Not for: the target temperature — use entities_set_value.
Returns: the list of states changed by the call. |
| services_set_light_colorA | Set a light's color, color temperature and/or brightness in one call. Calls light.turn_on with only the given fields set (rgb_color,
color_temp_kelvin, brightness); a given color_temp (mireds) is
converted to Kelvin (round(1_000_000 / mireds)) first, since HA's
light.turn_on no longer accepts mireds. Use when: adjusting a light's color/brightness, whether it is currently
on or off — light.turn_on also turns it on.
Not for: a plain on/off/toggle with no color change — use
entities_turn_on, which supports the same brightness/color options for
lights alongside generic on/off for any domain.
Returns: the list of states changed by the call. |
| services_media_play_pauseA | Toggle a media player between playing and paused. Calls media_player.media_play_pause with {"entity_id": entity_id}
over HTTP; the resulting state depends on the player's current state. Use when: a simple play/pause toggle is enough, without checking current
state first.
Returns: the list of states changed by the call. |
| services_media_seekA | Seek a media player to an absolute playback position. Calls media_player.media_seek with {"entity_id": entity_id, "seek_position": position} over HTTP. Use when: jumping to a specific point in the currently playing media.
Returns: the list of states changed by the call. |
| services_set_volumeA | Set a media player's volume level. Calls media_player.volume_set with {"entity_id": entity_id, "volume_level": volume} over HTTP. Use when: setting an exact volume rather than stepping it up/down.
Returns: the list of states changed by the call. |
| services_send_notificationA | Send a notification through a Home Assistant notify service. Calls notify.<target> (or plain notify.notify when target is
omitted) with message and optional title; target may include the
domain (notify.xyz) or be a bare service name, but a dotted target
must name the notify domain itself (ADR-0006 D6) — otherwise it would
let any domain.service be reached under cover of a "notification".
Each call dispatches a new notification to whatever device or channel
that service delivers to, which can be outside the local network (e.g.
a phone push). Use when: pushing a message to a person or device through a configured
notify service.
Not for: an in-UI banner tracked by an ID — use
services_notify_persistent_create.
Returns: the list of states changed by the call (notify services
typically change none).
Errors: {"error": "invalid_notify_target", "message": ...} when a
dotted target names a domain other than notify; {"error": "invalid_service_name"} when the part after notify. is not itself a
bare [A-Za-z0-9_]+ service name (e.g. a second dot). |
| services_camera_snapshotA | Save a still snapshot from a camera entity to a file, overwriting any existing file at that path. Calls camera.snapshot with {"entity_id": entity_id, "filename": filename} over HTTP. filename must be inside the HA config directory
and allow-listed via allowlist_external_dirs, typically under
/config/www/snapshots/... so it can be served by HA. Use when: capturing a single still frame to a known path, e.g. for a
dashboard image or Lovelace card.
Not for: a video clip — use services_camera_record.
Returns: dict with entity_id, filename and the raw service call
result. |
| services_camera_recordA | Record a short clip from a camera entity to a file, overwriting any existing file at that path. Calls camera.record with {"entity_id": entity_id, "filename": filename, "duration": duration} over HTTP. Use when: capturing a short video clip rather than a single still frame.
Not for: a single still frame — use services_camera_snapshot.
Returns: dict with entity_id, filename, duration and the raw
service call result.
Limits: blocks for roughly duration seconds while HA records. |
| services_notify_persistent_createA | Create or replace a persistent notification banner in the Home Assistant UI. Calls persistent_notification.create with message, optional title
and notification_id. Giving the same notification_id again replaces
that notification's content in place; omitting it creates a new,
separately addressable notification each time. Use when: showing a UI banner that a person can dismiss, as opposed to a
push notification.
Not for: a push notification to a device — use
services_send_notification.
Returns: dict with notification_id and the raw service call result. |
| services_notify_persistent_dismissA | Dismiss one persistent notification by its ID. Calls persistent_notification.dismiss with {"notification_id": notification_id} over HTTP; dismissing an already-dismissed or unknown
ID is a no-op from this tool's perspective. Use when: clearing one specific UI banner.
Not for: clearing every banner — use
services_notify_persistent_dismiss_all.
Returns: dict with notification_id and the raw service call result. |
| services_notify_persistent_dismiss_allA | Dismiss every persistent notification currently shown in the Home Assistant UI. Calls persistent_notification.dismiss_all over HTTP with no data. Use when: clearing all UI banners at once.
Not for: clearing a single banner — use
services_notify_persistent_dismiss.
Returns: dict with the raw service call result. |
| automations_list_automationsA | List all automations with their current state. Reads ha.get_states() and keeps entries whose entity_id starts with
'automation.'. Returns: list[dict] {"entity_id", "state", "friendly_name", "last_triggered"} per automation. |
| automations_trigger_automationA | Run an automation's actions now, skipping its normal trigger. Calls the automation.trigger service with entity_id; Home Assistant
skips the automation's conditions by default (skip_condition=true),
so this can fire actions the automation's own conditions would
otherwise block. Use when: testing or forcing an automation's actions on demand.
Returns: list[dict], the raw automation.trigger service-call
response from Home Assistant. |
| automations_enable_automationA | Enable a disabled automation. Calls the automation.turn_on service with entity_id. Not for: running the automation's actions immediately — use
automations_trigger_automation.
Returns: list[dict], the raw automation.turn_on service-call response. |
| automations_disable_automationA | Disable an automation so it stops reacting to its triggers. Calls the automation.turn_off service with entity_id; the
automation's stored config is untouched, only its runtime state
changes. Returns: list[dict], the raw automation.turn_off service-call
response. |
| automations_reload_automationsA | Reload all automations from YAML. Calls the automation.reload service, which re-reads
automations.yaml/packages and re-applies enabled/disabled state; any
automations created only via automations_set_automation_config since
the last reload are included too, since that tool writes through the
same config store. Returns: list[dict], the raw automation.reload service-call
response. |
| automations_list_scriptsA | List all scripts with their current state. Reads ha.get_states() and keeps entries whose entity_id starts with
'script.'. Returns: list[dict] {"entity_id", "state", "friendly_name", "last_triggered"} per script. |
| automations_run_scriptA | Start a script and return immediately without waiting for it to finish. Calls the script.turn_on service with entity_id and, when given,
variables as the script's fields; the call returns as soon as Home
Assistant accepts it and does not return the script's response
variables. Not for: getting the script's result — this tool never returns it,
regardless of the script's own response_variable.
Returns: list[dict], the raw script.turn_on service-call response. |
| automations_reload_scriptsA | Reload all scripts from YAML. Calls the script.reload service, which re-reads scripts.yaml/packages
and re-registers script entities. Returns: list[dict], the raw script.reload service-call response. |
| automations_list_scenesA | List all scenes. Reads ha.get_states() and keeps entries whose entity_id starts with
'scene.'. Returns: list[dict] {"entity_id", "friendly_name"} per scene. |
| automations_activate_sceneA | Activate a scene, applying its stored entity states. Calls the scene.turn_on service with entity_id. Returns: list[dict], the raw scene.turn_on service-call response. |
| automations_reload_scenesA | Reload scenes from YAML. Calls the scene.reload service, which re-reads scenes.yaml and
re-registers scene entities from it; scenes saved via
automations_set_scene_config are included since that tool writes to
the same config store. Returns: list[dict], the raw scene.reload service-call response. |
| automations_get_scene_configA | Get a scene's stored config (member entities and their target states). Requests /api/config/scene/config/<id> over HTTP and returns the
parsed JSON, or None on a 404. Not for: the scene's current runtime state — use
automations_list_scenes or entities_get_entity for that.
Returns: dict with id, name and entities (mapping entity_id to
its target state dict), or None when no scene has that id. |
| automations_set_scene_configA | Create or overwrite a scene's stored config, then reload scenes. Posts {id, name, entities} to /api/config/scene/config/<id>,
replacing any existing config at that id, then calls the
scene.reload service so the change takes effect immediately. Not for: applying the scene's states right now — use
automations_activate_scene.
Returns: dict {"scene_id", "name", "entity_count", ...} merged with
HA's save response.
Errors: returns {"error": "entities must be a non-empty dict of {entity_id: state_dict}"} when entities is empty or not a dict.
Limits: no confirm parameter; an existing scene at scene_id is
replaced without a prompt. |
| automations_delete_sceneA | Delete a scene config, then reload scenes. Without confirm=True returns a safety prompt and touches nothing;
with confirm=True deletes /api/config/scene/config/<id> and calls
the scene.reload service. Returns: dict {"deleted": sid, ...} merged with HA's delete response,
or {"status": "not_found", "scene_id": sid} when no scene has that
id.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True.
Limits: requires confirm=True; deletion is immediate and permanent. |
| automations_get_automation_configA | Get the stored config of one automation (automations.yaml) as a dict. Requests /api/config/automation/config/<id> over HTTP and returns
the parsed JSON, or None on a 404 — including for automations defined
in packages/YAML without an id, since those have no config-id route. Not for: the automation's current runtime state — use
automations_list_automations or entities_get_entity for that.
Returns: dict with id, alias, trigger/triggers,
condition/conditions, action/actions and mode, or None when
no automation has that config id. |
| automations_set_automation_configA | Create or replace the automation whose config id is automation_id. Posts config to /api/config/automation/config/<id>, replacing the
whole stored config at that id (or creating a new automation if the id
is unused), then calls the automation.reload service. Not for: editing a single field without resending the rest of the
config — this tool always replaces the whole stored config.
Returns: dict {"status": "saved", "automation_id", "result"}.
Errors: returns {"error": "config must be a dict"} when config
isn't a dict, or {"error": "config must contain at least 'alias' or 'trigger'/'triggers'"} when both are missing.
Limits: no confirm parameter; an existing automation at
automation_id is replaced without a prompt. |
| automations_delete_automationA | Delete an automation by config id, then reload automations. Without confirm=True returns a safety prompt; with confirm=True
deletes /api/config/automation/config/<id> and calls the
automation.reload service. Returns: dict {"status": "deleted", "automation_id", "result"}.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True, or {"error": "not found", "automation_id": aid} when no automation has that config id.
Limits: requires confirm=True; deletion is immediate and permanent. |
| automations_get_script_configA | Get a script's stored YAML config as a dict. Requests /api/config/script/config/<id> over HTTP and returns the
parsed JSON, or None on a 404. Not for: the script's current runtime state — use
automations_list_scripts or entities_get_entity for that.
Returns: dict with the script's alias, sequence, fields and
mode, or None when no script has that id. |
| automations_set_script_configA | Create or overwrite a script's stored YAML config, then reload scripts. Posts config to /api/config/script/config/<id>, replacing the whole
stored config at that id (or creating a new script if the id is
unused), then calls the script.reload service. Not for: running the script — use automations_run_script.
Returns: dict {"status": "saved", "script_id", "result"}.
Errors: returns {"error": "config must be a dict"} when config
isn't a dict, or {"error": "config must contain at least 'alias' or 'sequence'"} when both are missing.
Limits: no confirm parameter; an existing script at script_id is
replaced without a prompt. |
| automations_delete_scriptA | Delete a script by id, then reload scripts. Without confirm=True returns a safety prompt; with confirm=True
deletes /api/config/script/config/<id> and calls the script.reload
service. Returns: dict {"status": "deleted", "script_id", "result"}.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True, or {"error": "not found", "script_id": sid} when no script has that id.
Limits: requires confirm=True; deletion is immediate and permanent. |
| automations_list_automation_tracesA | List trace summaries (recent runs) for an automation. Calls the trace/list WebSocket command for domain 'automation' and
automation_id. Returns: list[dict] of trace summaries (run_id, timestamps,
script_execution outcome) — no step-by-step detail; use
automations_get_automation_trace for one run's full detail.
Limits: blocks for the WebSocket round trip. |
| automations_get_automation_traceA | Get a full automation trace (steps, timing, condition results) for a specific run. Calls the trace/get WebSocket command for domain 'automation',
automation_id and run_id. Not for: finding which run_id to use — use
automations_list_automation_traces or
automations_get_last_automation_trace first.
Returns: dict with the full step-by-step trace for that run.
Limits: blocks for the WebSocket round trip. |
| automations_list_script_tracesA | List trace summaries (recent runs) for a script. Calls the trace/list WebSocket command for domain 'script' and
script_id. Returns: list[dict] of trace summaries (run_id, timestamps,
script_execution outcome) — no step-by-step detail; use
automations_get_script_trace for one run's full detail.
Limits: blocks for the WebSocket round trip. |
| automations_get_script_traceA | Get a full script trace (steps, timing, action results) for a specific run. Calls the trace/get WebSocket command for domain 'script',
script_id and run_id. Not for: finding which run_id to use — use
automations_list_script_traces or automations_get_last_script_trace
first.
Returns: dict with the full step-by-step trace for that run.
Limits: blocks for the WebSocket round trip. |
| automations_get_last_automation_traceA | Fetch the most recent trace for an automation in one call. Calls trace/list for automation_id, then picks a run_id (the most
recent overall, or with failed_only=True the most recent whose
script_execution isn't 'finished') and calls trace/get for it. Use when: debugging "why didn't this fire?" without first listing
traces and picking a run_id by hand.
Returns: dict with the full step-by-step trace for the picked run.
Errors: returns {"error": "no_traces"|"no_failed_traces", "automation_id": aid} when no matching run exists.
Limits: blocks for two sequential WebSocket round trips. |
| automations_get_last_script_traceA | Fetch the most recent (or most recent failed) trace for a script. Calls trace/list for script_id, then picks a run_id (the most
recent overall, or with failed_only=True the most recent whose
script_execution isn't 'finished') and calls trace/get for it. Use when: debugging why a script didn't behave as expected without
first listing traces and picking a run_id by hand.
Returns: dict with the full step-by-step trace for the picked run.
Errors: returns {"error": "no_traces"|"no_failed_traces", "script_id": sid} when no matching run exists.
Limits: blocks for two sequential WebSocket round trips. |
| automations_validate_best_practicesA | Validate automation YAML against static Home Assistant authoring rules. Parses yaml_content with plain yaml.safe_load (HA-only tags like
!input/!secret are NOT resolved and make parsing fail with a YAML
parse error, same as any other unknown tag) and runs fixed checks: a
state trigger without 'for:', a missing 'mode:', multiple triggers
without 'id:', a missing 'alias:'/'id:', the deprecated 'service:'
action key, 'restart' mode, and a missing 'description:'. Use when: linting automation YAML before saving it with
automations_set_automation_config.
Not for: checking that referenced entities/services actually exist —
use automations_validate_automation_references; blueprint content
with unresolved '!input'/'!secret' tags — extract them to plain YAML
first.
Returns: dict {valid_yaml, automations_checked, issues_total, warnings, infos, issues[], summary}; each issue is {automation, rule, severity, message} with severity 'warning' (should fix) or
'info' (good to know).
Errors: returns {"valid_yaml": False, "error": "YAML parse error: ...", "issues": []} for invalid YAML. |
| automations_validate_automation_referencesA | Cross-check entity IDs and services used in automation YAML against the live registry. Unlike automations_validate_best_practices (static), this calls
ha.get_states() and ha.list_services() to verify that every literal
entity_id value and every literal service:/action: string in
yaml_content exists. It only looks at literal values — it does NOT
resolve device_id, area_id, label_id, or any templated reference,
not just the ones containing '{{ ... }}' (which are explicitly skipped
and counted in template_refs_skipped). Use when: checking that an automation's references are real before
saving it with automations_set_automation_config.
Not for: YAML syntax or authoring-rule checks — use
automations_validate_best_practices.
Returns: dict {valid_yaml, automations_checked, entities_checked, services_checked, missing_entities[], missing_services[], template_refs_skipped, entities_check, services_check, errors[], summary}. entities_check/services_check are 'ok' or 'unavailable'.
Errors: returns {"valid_yaml": False, "error": "YAML parse error: ..."} for invalid YAML. When ha.get_states() or ha.list_services()
raises, the matching entities_check/services_check is 'unavailable'
and errors names which fetch failed; the corresponding missing_*
list stays empty rather than reporting a false "nothing missing" or a
false "everything is missing".
Limits: fetches the full live state list and full service list on
every call. |
| automations_list_groupsA | List all Home Assistant entity groups (group.* entities). Reads ha.get_states() and keeps entries whose entity_id starts with
'group.', with their members, icon and current state. Returns: list[dict] {"entity_id", "state", "friendly_name", "entity_ids", "icon", "all", "order"} per group. |
| automations_set_groupA | Create or update an old-style group.* entity at runtime. Calls the group.set service with object_id=group_id and whichever
of name/entities/icon/all/add_entities/remove_entities were
given. The group is NOT written to groups.yaml and disappears on
restart or automations_reload_groups-style YAML reload; for a
persistent group use a Group helper or add it to groups.yaml with the
files_write_config_file tools. Does not create light/switch/cover
group helpers. Not for: a group that survives a restart — define it in groups.yaml
instead (files_write_config_file) or create a Group helper.
Returns: dict {"status": "set", "group_id": "group.<id>"}.
Errors: returns {"error": "entities cannot be combined with add_entities/remove_entities — pass a full member list via entities, or incremental changes via add_entities/remove_entities, not both"} when
entities is given together with add_entities or remove_entities;
group.set is not called in that case.
Limits: entities replaces the whole member list and must not be
combined with add_entities/remove_entities in the same call. |
| automations_remove_groupA | Remove a group created with automations_set_group. Without confirm=True returns a safety prompt; with confirm=True
calls the group.remove service with object_id. Groups defined in
groups.yaml come back on the next restart or YAML reload — this only
removes the runtime entity. Returns: dict {"status": "removed", "group_id": "group.<id>"}.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True.
Limits: requires confirm=True; has no effect on a group defined in
groups.yaml beyond the next reload/restart. |
| areas_list_areasA | List all Home Assistant areas (rooms). Reads the area registry over WebSocket (config/area_registry/list) and
returns every entry exactly as Home Assistant reports it, unfiltered. Use when: you need area IDs and names before assigning entities, devices
or labels to an area.
Returns: list of area registry dicts (area_id, name, floor_id, icon,
aliases, picture). |
| areas_create_areaA | Create a new Home Assistant area (room). Calls WS config/area_registry/create with name; Home Assistant
assigns a new area_id and there is no way to request a specific one, so
calling this twice with the same name creates two distinct areas. Use when: you need a new area to assign devices, entities or labels to.
Not for: renaming or moving an existing area — no update tool exists
for areas in this namespace.
Returns: the created area registry dict (area_id, name, floor_id, icon,
aliases, picture). |
| areas_delete_areaA | Delete a Home Assistant area by its area_id. Calls WS config/area_registry/delete and returns Home Assistant's
result unchanged; the area disappears from the registry immediately. Use when: removing an area that is no longer used.
Returns: the raw WS deletion result.
Limits: irreversible — there is no restore tool for a deleted area. |
| areas_list_floorsA | List all floors defined in Home Assistant. Reads the floor registry over WebSocket (config/floor_registry/list)
and returns every entry exactly as Home Assistant reports it, unfiltered. Use when: grouping areas by floor, e.g. before building a floor-scoped
dashboard.
Returns: list of floor registry dicts as reported by Home Assistant. |
| areas_list_devicesA | List all devices in Home Assistant's device registry, unfiltered. Calls WS config/device_registry/list via ha_client and returns every
registry entry exactly as Home Assistant reports it, with every field
(unlike the slimmed projection other tools apply). Use when: you need the complete raw device registry, including fields
not exposed elsewhere.
Not for: a smaller per-field view — use devices_list_devices, which
projects each entry down to id/name/area_id/manufacturer/model/
entry_type plus config_entries/disabled_by; devices scoped to one area —
use devices_list_devices_in_area; fuzzy name-based search — use
search_search_devices.
Returns: list of full device registry dicts as returned by
config/device_registry/list. |
| areas_get_area_entitiesA | Get every entity registered in a given area, directly or via its device. Reads the entity and device registries over WebSocket, then keeps
entity-registry rows whose own area_id matches, or whose device_id
belongs to a device assigned to the area. Use when: you need the entity registry rows for one area, e.g. before
bulk-editing labels or categories.
Not for: current state values — use areas_get_area_states, or a
combined view — use snapshot_get_area_snapshot.
Returns: list of entity registry dicts (entity_id, device_id, area_id,
labels, …) belonging to the area.
Limits: an unknown area_id returns an empty list rather than an error. |
| areas_get_area_statesA | Get current states of every entity in a given area. Calls areas_get_area_entities for the area, then filters the full
state list (ha.get_states()) down to the entity_ids found in that call. Use when: you need live state values scoped to one area, e.g. before
deciding what to control.
Not for: registry rows without state values — use
areas_get_area_entities, or a combined view — use
snapshot_get_area_snapshot.
Returns: list of HA state objects (entity_id, state, attributes,
last_changed, last_updated) for entities in the area. |
| areas_control_areaA | Turn on, off or toggle every entity of one domain in an area. Calls service <domain>.<action> over HTTP with {"area_id": area_id}
as the target, so Home Assistant dispatches it to every entity of that
domain in the area. action must be one of turn_on/turn_off/toggle
(ADR-0006 D6) — an unchecked value here could reach an arbitrary
<domain>.<action> service under cover of "controlling an area". Use when: controlling a whole area by domain, e.g. all lights in a room.
Not for: controlling an explicit list of entity_ids across areas — use
entities_bulk_control.
Returns: list of state-change dicts as returned by the HA service call.
Errors: raises ValueError when action is not one of turn_on,
turn_off, toggle.
Limits: an invalid domain (no such domain, or the domain has no
matching service) fails with the underlying HTTP error from Home
Assistant. |
| history_get_state_historyA | Get an entity's recorded state history over the last N hours. Calls GET /api/history/period/<start> filtered to entity_id, where
start is now - hours; returns whatever the recorder database has
kept for that window. Use when: seeing how one entity's state changed over time, e.g. a
temperature trend.
Not for: human-readable event descriptions — use
history_get_logbook; this is raw, short-term state history, not the
recorder's long-term pre-aggregated sum/mean/min/max values — use
statistics_get_statistics for those, or statistics_list_statistic_ids
to discover which entities have them.
Returns: HA's raw history-period payload — a list of state-change
records for the entity.
Errors: raises httpx.HTTPStatusError if the HA API request fails.
Limits: only as far back as the recorder integration has retained data
for this entity. |
| history_get_logbookA | Get human-readable logbook entries from the last N hours. Calls GET /api/logbook/<start>, optionally filtered by entity_id,
where start is now - hours. Use when: a narrative of what happened (state changes, triggered
automations) is more useful than raw state-history records.
Not for: raw per-state timestamps and values for one entity — use
history_get_state_history.
Returns: HA's raw logbook payload — a list of {when, name, message, entity_id, ...}-shaped entries.
Errors: raises httpx.HTTPStatusError if the HA API request fails.
Limits: only as far back as the recorder integration has retained
logbook data. |
| history_get_error_logA | Fetch Home Assistant's error log as plain text. Prefers the raw log file via GET /api/error_log. That view only
exists when HA logs to a file — Supervisor installs ship with
duplicate_log_file: false, so it 404s there, in which case the
warning/error records held by the system_log integration are rendered
into log-file-like text instead. Use when: diagnosing recent warnings/errors across the whole instance.
Not for: one entity's history or logbook — use
history_get_state_history or history_get_logbook.
Returns: plain-text log content, from either source.
Errors: re-raises httpx.HTTPStatusError for any status other than 404
from /api/error_log. |
| history_get_system_infoA | Get Home Assistant's raw API liveness message. Calls GET /api/, which returns only a fixed liveness message (e.g.
{"message": "API running."}) — no version or system data despite the
tool's name. Use when: a plain proof that the HTTP API is answering is enough.
Not for: version/location/units/components — use
history_get_ha_config; for subsystem health — use
system_get_system_health; for Core/OS details — use
supervisor_get_core_info or supervisor_get_host_info; for a simple
reachable/unreachable boolean — use system_ping_ha.
Returns: {"message": "API running."} (HA's fixed liveness payload).
Errors: raises httpx.HTTPStatusError if the HA API request fails. |
| history_get_ha_configA | Get Home Assistant's current configuration. Calls GET /api/config for location, unit system, HA version and
loaded components. Use when: version, location, unit system or the loaded-components list
is needed.
Not for: the equivalent WebSocket command — use ws_get_config; for
subsystem health checks — use system_get_system_health.
Returns: HA's raw config payload (latitude, longitude,
unit_system, version, components, and related fields).
Errors: raises httpx.HTTPStatusError if the HA API request fails. |
| helpers_list_helpersA | List every helper entity across all helper domains, with its current state. Reads all states via ha.get_states() over HTTP and keeps only entities
whose domain is one of input_boolean, input_number, input_text,
input_select, input_datetime, input_button, counter, timer, schedule. Use when: browsing which helpers exist and their current values.
Not for: helpers of one specific domain filtered generically — use
entities_list_entities with domain set.
Returns: list of dicts with entity_id, state, attributes for each
matching helper entity. |
| helpers_set_input_booleanA | Set an input_boolean helper to true or false. Calls input_boolean.turn_on when value is true, otherwise
input_boolean.turn_off, over HTTP. Use when: setting a known boolean helper to a specific value.
Not for: any other domain's on/off state — use entities_turn_on/
entities_turn_off, which work generically across domains including
input_boolean.
Returns: the list of states changed by the call. |
| helpers_set_input_numberA | Set an input_number helper's numeric value. Calls input_number.set_value with {"entity_id": entity_id, "value": value} over HTTP. Use when: writing a specific number to an input_number helper.
Not for: a number/climate entity too — entities_set_value covers
input_number identically plus the number and climate domains.
Returns: the list of states changed by the call. |
| helpers_set_input_textA | Set an input_text helper's text value. Calls input_text.set_value with {"entity_id": entity_id, "value": value} over HTTP. Use when: writing a specific string to an input_text helper.
Returns: the list of states changed by the call. |
| helpers_set_input_selectA | Set an input_select helper to one of its configured options. Calls input_select.select_option with {"entity_id": entity_id, "option": option} over HTTP. Use when: setting a known input_select helper to a specific option.
Not for: the generic select/input_select dispatch that also handles
plain select entities — entities_select_option covers input_select
identically plus the select domain.
Returns: the list of states changed by the call. |
| helpers_set_input_datetimeA | Set an input_datetime helper's date, time or combined datetime value. Calls input_datetime.set_datetime over HTTP with whichever of date,
time, datetime are given; passing none of them still calls the
service with only entity_id. Use when: writing a specific date/time to an input_datetime helper.
Returns: the list of states changed by the call. |
| helpers_increment_counterA | Increment a counter helper by its configured step. Calls counter.increment with {"entity_id": entity_id} over HTTP;
repeating this call keeps increasing the counter's value. Use when: counting up an event occurrence.
Not for: setting the counter back to zero — use
helpers_reset_counter.
Returns: the list of states changed by the call. |
| helpers_reset_counterA | Reset a counter helper's value back to 0. Calls counter.reset with {"entity_id": entity_id} over HTTP; the
counter is runtime UI state, not stored configuration. Use when: clearing a counter back to its initial value.
Not for: increasing it by one — use helpers_increment_counter.
Returns: the list of states changed by the call. |
| helpers_start_timerA | Start a timer helper, optionally overriding its duration. Calls timer.start over HTTP with entity_id and duration when
given; calling this on an already-running timer restarts it with the
new duration. Use when: starting a countdown, e.g. for a reminder or process timeout.
Not for: stopping it early — use helpers_cancel_timer.
Returns: the list of states changed by the call. |
| helpers_cancel_timerA | Cancel a running timer helper. Calls timer.cancel with {"entity_id": entity_id} over HTTP. Use when: stopping a timer before it finishes.
Not for: starting one — use helpers_start_timer.
Returns: the list of states changed by the call. |
| helpers_reload_helpersA | Reload every helper domain's entities from configuration in one call. Calls <domain>.reload over HTTP for each of input_boolean,
input_number, input_text, input_select, input_datetime, counter, timer
in turn; a domain whose reload call raises is skipped but its error is
captured rather than silently dropped. Use when: applying YAML changes across several helper domains without
restarting Home Assistant.
Not for: reloading one specific domain — use services_reload_config.
Returns: {"reloaded": [...], "failed": {domain: message}} — combined
list of states changed across every domain that reloaded successfully,
plus a per-domain map of the error message for every domain whose
reload call raised.
Errors: a domain's failure never raises out of this call; instead its
exception message is recorded under failed[<domain>] so the caller can
tell which domain, if any, did not reload. |
| system_check_configA | Validate the current Home Assistant configuration without applying anything. Calls POST /api/config/core/check_config, the same YAML validation HA
runs internally before a restart; nothing is reloaded or restarted by
this call. Use when: verifying configuration.yaml and related files are valid
before calling system_restart_ha.
Not for: applying a change into the running instance — use
system_reload_all for a no-downtime reload or system_restart_ha for a
full restart.
Returns: HA's check payload, typically {"result": "valid"|"invalid", "errors": ...}.
Errors: raises httpx.HTTPStatusError if the HA API request itself
fails (e.g. HA unreachable). |
| system_restart_haA | Restart Home Assistant after an explicit confirmation. Calls the homeassistant.restart service, which causes roughly 30
seconds of downtime for the whole instance, including this add-on.
Without confirm=True nothing is restarted; the call only returns a
safety prompt describing how to confirm. Use when: a config change requires a full restart, e.g. after
system_check_config reports the config is valid.
Not for: a no-downtime reload — use system_reload_all; stopping HA
without restarting it — use system_stop_ha; restarting only Core under
Supervisor — use supervisor_restart_core.
Returns: the homeassistant.restart service-call result when confirmed,
otherwise a confirmation prompt.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false.
Limits: interrupts Home Assistant for about 30 seconds; requires
confirm=True. |
| system_stop_haA | Stop Home Assistant after an explicit confirmation. Calls the homeassistant.stop service. Unlike a restart, nothing brings
the instance back automatically — a manual restart is required. Without
confirm=True nothing is stopped; the call only returns a safety
prompt. Use when: HA needs to be taken fully offline, e.g. before host
maintenance.
Not for: a temporary interruption that comes back on its own — use
system_restart_ha.
Returns: the homeassistant.stop service-call result when confirmed,
otherwise a confirmation prompt.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false.
Limits: requires a manual restart to bring HA back online; requires
confirm=True. |
| system_reload_allA | Reload core Home Assistant configuration without restarting the instance. Calls the homeassistant.reload_all service, which HA fans out to every
component that supports a config reload (automations, scripts, scenes,
groups and more), re-reading their YAML from disk. Use when: YAML for automations/scripts/scenes/groups changed and a fast,
no-downtime reload is enough.
Not for: changes that require a full restart, e.g. new integrations or
structural configuration.yaml edits — use system_restart_ha; for one
integration only — use system_reload_integration.
Returns: {"status": "reload_all triggered"}; it does not wait for or
report individual component reload results. |
| system_create_backupA | Create a Home Assistant backup using whichever backup service the instance registers. On Supervisor installs backup.create does not exist, so this calls
backup.create_automatic instead, which creates a backup using the
automatic-backup settings configured in Settings -> System -> Backups;
when a retention count is configured there, those same settings prune
older automatic backups as a side effect of this call. On HA
Core/Container installs, where backup.create exists, that one is
called instead — no name, folder selection or password. Returns an
error if neither service is registered. Use when: HA already has the wanted automatic-backup settings configured
and a quick backup with no extra parameters is enough.
Not for: a named, partial, and/or password-protected backup on a
Supervisor install, or a backup that never deletes older ones — use
supervisor_create_backup.
Returns: the called service's result, or an error dict when neither
service is registered.
Errors: {"error": "Neither backup.create nor backup.create_automatic is registered on this Home Assistant instance."}.
Limits: on Supervisor installs, applies the instance's configured
retention count, which can delete older backups. |
| system_list_integrationsA | List every Home Assistant config entry, whatever its state. Calls the raw config_entries/get WebSocket command and returns it
unfiltered: every field HA stores per entry, in any state (loaded,
not_loaded, setup_error, disabled). On instances with many
integrations this can be a large payload. Use when: the raw config-entry objects, with every field, are needed.
Not for: a compact, easier-to-scan listing — use
system_get_all_integrations, which strips this down to
entry_id/domain/title/state/source.
Returns: list of raw config-entry dicts as returned by HA's WebSocket
API.
Errors: raises RuntimeError if the underlying WebSocket call fails
(e.g. auth or WS-level error).
Limits: no pagination or filtering; large HA instances get a large
response. |
| system_reload_integrationA | Reload a single integration's config entry without restarting Home Assistant. Calls the homeassistant.reload_config_entry service for the given
entry_id, which unloads and re-sets-up that one integration only. Use when: one integration needs to pick up new options or recover from a
transient setup error.
Not for: reloading every reloadable component at once — use
system_reload_all.
Returns: the homeassistant.reload_config_entry service-call result.
Errors: raises httpx.HTTPStatusError if entry_id does not exist or
the domain does not support config-entry reload. |
| system_ping_haA | Check whether the Home Assistant API is reachable over HTTP. Calls GET /api/ through ha.ping(), which catches any connection
error internally and reports plain reachability, not health or
subsystem status. Use when: confirming HA is up before other calls, quick liveness
probing.
Not for: the raw /api/ payload itself — use history_get_system_info;
for HA version/location/config use history_get_ha_config; for
subsystem health use system_get_system_health.
Returns: {"reachable": bool, "url": <configured HA_URL>}. |
| system_get_all_integrationsA | List every config entry as a compact summary of its key fields. Calls the same config_entries/get WebSocket command as
system_list_integrations and projects each entry down to entry_id,
domain, title, state and source; every state is included, so filter on
state yourself. Use when: scanning or filtering integrations by domain/state without the
full raw payload.
Not for: every field HA stores on the entry — use
system_list_integrations.
Returns: list of {entry_id, domain, title, state, source} dicts.
Errors: raises RuntimeError if the underlying WebSocket call fails
(e.g. auth or WS-level error). |
| system_get_system_healthA | Get Home Assistant's system-health report across its core subsystems. Runs the system_health/info WebSocket subscription to completion and
merges its initial/update/finish events into one dict, since HA exposes
system health only as a WebSocket stream, not over HTTP. Use when: checking recorder/websocket/cloud/network-style health checks
and basic system info (version, dev mode, virtualenv) in one call.
Not for: a plain liveness check — use system_ping_ha; for HA
version/location/config use history_get_ha_config.
Returns: dict keyed by integration domain, each with an info dict
mapping check name to value (or {"error": ...} for a failed check).
Errors: raises RuntimeError on WebSocket auth failure or a WS-level
error from system_health/info.
Limits: waits up to an internal 15-second timeout for the stream's
finish event; on timeout it returns whatever partial data arrived
instead of raising. |
| system_get_repairsA | List Home Assistant's active repair issues. Calls the repairs/list_issues WebSocket command and projects each
issue down to its id, domain, severity, breaks_in_ha_version,
learn-more URL, translation key, and ignored/is_fixable flags. Use when: surfacing deprecated config, broken integrations or required
migrations that need attention.
Not for: the full raw repair-issue payload with every field HA stores —
this always returns the projected subset above.
Returns: list of {issue_id, domain, severity, breaks_in_ha_version, learn_more_url, translation_key, ignored, is_fixable} dicts.
Errors: raises RuntimeError if the underlying WebSocket call fails
(e.g. auth or WS-level error). |
| system_get_updatesA | List Home Assistant's update.* entities, one per updatable component. Reads all HA states and filters to entities in the update domain
(core, add-ons, HACS repositories, custom components), extracts
installed/latest version and release info from their attributes, and
sorts pending updates first. Use when: checking what has an update available across the whole
instance in one call.
Not for: live Supervisor add-on state beyond this snapshot — use
supervisor_get_addon or supervisor_list_addons.
Returns: list of {entity_id, name, installed_version, latest_version, update_available, release_url, release_notes, skipped_version, in_progress, auto_update}, sorted with available updates first. |
| dashboards_list_dashboardsA | List every registered Lovelace dashboard. Calls lovelace/dashboards/list and returns the raw collection: each
entry has id, url_path, title, mode (storage or yaml), and
related flags. Use when: discovering a dashboard's url_path before calling
dashboards_get_dashboard_config or dashboards_screenshot.
Returns: list of dashboard dicts, unfiltered. The default dashboard is
not included — it has no url_path entry here. |
| dashboards_add_dashboard_resourceA | Register a custom JS or CSS resource that loads on every Lovelace dashboard page. Sends url/resource_type to lovelace/resources/create, which
stores a new resource entry with a server-generated id — repeating
this call registers a second, distinct resource rather than updating
one. The tool itself only stores the URL string; it never fetches
url — the browser loads it later, from /local/, /hacsfiles/, or
any external CDN the URL names. Use when: registering a custom card, theme, or script so it becomes
available on every dashboard.
Not for: changing an existing resource's URL/type — use
dashboards_update_dashboard_resource.
Returns: {"status": "added", "url": ..., "resource_type": ..., "result": ...} on success.
Errors: {"error": "resource_type must be 'module', 'js', or 'css'"}
when resource_type is anything else. |
| dashboards_remove_dashboard_resourceA | Remove a registered Lovelace resource by its numeric id. Requires confirm=True; without it, returns a confirmation prompt and
makes no change. With confirm=True, calls lovelace/resources/delete,
which drops the resource from every dashboard page that loaded it —
any custom card/theme it provided stops rendering until the resource
is re-added. Use when: removing a resource that is no longer needed (e.g. after
uninstalling a HACS frontend card).
Returns: {"status": "removed", "resource_id": ..., "result": ...} on
success.
Errors: {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false. |
| dashboards_update_dashboard_resourceA | Replace the URL and type of an existing Lovelace resource. Sends resource_id, url and resource_type to
lovelace/resources/update, replacing both fields of that resource
entry — the previous URL/type are not recoverable afterwards. Like
dashboards_add_dashboard_resource, this tool never fetches url
itself. Use when: repointing an existing resource entry at a new file or
changing its declared type.
Not for: registering a brand-new resource — use
dashboards_add_dashboard_resource.
Returns: {"status": "updated", "resource_id": ..., "url": ..., "resource_type": ..., "result": ...} on success.
Errors: {"error": "resource_type must be 'module', 'js', or 'css'"}
when resource_type is anything else. |
| dashboards_get_dashboard_configA | Get one Lovelace dashboard's config, or a read-only excerpt of one view. Calls lovelace/config for url_path as a dashboard; if that raises
config_not_found, re-fetches the default dashboard and returns the
matching view instead, since url_path may instead be that view's own
path. Use when: reading a dashboard's views/sections before editing it,
or inspecting one view without the surrounding dashboard.
Not for: passing the view-path result back into
dashboards_save_dashboard_config — that excerpt is not a full
dashboard config and would delete every other view.
Returns: the full dashboard dict (with views) for a dashboard
url_path; {"view": ..., "source": "default_dashboard_view", "path": ...} for a view path in the default dashboard.
Errors: raises RuntimeError when url_path matches neither a
dashboard nor a view in the default dashboard. |
| dashboards_save_dashboard_configA | Replace the entire config of one storage-mode Lovelace dashboard. Sends config as-is to lovelace/config/save, fully overwriting that
dashboard's stored views/sections with no validation, backup, or
undo — keep the previous config (e.g. from
dashboards_get_dashboard_config) if you need to restore it. Use when: writing back a dashboard object built or fetched in full.
Not for: a single card or section change — use
dashboards_add_card_to_section/dashboards_update_card_in_section/
dashboards_remove_card_from_section (sections views) or
dashboards_add_card_to_view (masonry/panel views), which read-modify-
write the config for you.
Returns: {"status": "saved", "url_path": ...}. |
| dashboards_get_dashboard_resourcesA | List every registered Lovelace resource (custom cards, CSS). Calls lovelace/resources and returns the raw collection: each entry
has id, type (module/js/css), and url. Use when: finding a resource's numeric id before calling
dashboards_update_dashboard_resource or
dashboards_remove_dashboard_resource.
Returns: list of resource dicts, unfiltered. |
| dashboards_add_card_to_viewA | Append a card to one view's cards list and save the whole dashboard. Reads the dashboard via dashboards_get_dashboard_config, appends
card_config to views[view_index]["cards"] (creating that key if
absent), and writes the whole dashboard back with
dashboards_save_dashboard_config — every other view and card is
round-tripped unchanged. Use when: adding a card to a masonry/panel view.
Not for: a type: sections view — there, cards in view.cards render
only in edit mode; use dashboards_add_card_to_section instead.
Returns: {"status": "saved", "url_path": ...} from the underlying
save.
Errors: raises ValueError when view_index is out of range for the
dashboard's view count. |
| dashboards_add_view_to_dashboardA | Append a new view to a dashboard and save the whole dashboard. Reads the dashboard via dashboards_get_dashboard_config, appends
view_config to its views list, and writes the whole dashboard back
with dashboards_save_dashboard_config — every existing view and card
is round-tripped unchanged. Use when: adding a whole new tab/view to a dashboard.
Not for: adding a card to an existing view — use
dashboards_add_card_to_view or dashboards_add_card_to_section.
Returns: {"status": "saved", "url_path": ...} from the underlying
save. |
| dashboards_get_view_sectionsA | List the sections of one type: sections view, with real indexes, headings and card counts. Resolves the view via _load_view (dashboard config or default-
dashboard view path), requires it to be a sections view, and reports
each section's position, a fallback-derived heading (its heading
card, or title), and card count. Use when: reading current section indexes before calling
dashboards_add_card_to_section / dashboards_update_card_in_section
/ dashboards_remove_card_from_section, or before re-sending
expected_config_hash to one of them after their previous call
changed it.
Returns: {status, url_path, view_index, view_title, view_path, sections: [{section_index, heading, card_count}, ...], config_hash} —
pass config_hash back as expected_config_hash to
dashboards_add_card_to_section / _update_card_in_section /
_remove_card_from_section / _add_section_to_view to detect a
dashboard change before your write lands.
Errors: raises ValueError when the view can't be resolved (bad
index/path) or is not a type: sections view. |
| dashboards_add_card_to_sectionA | Insert a card into one section of a type: sections view, leaving every other view intact. Resolves the view via _load_view, requires it to be a sections
view, inserts card_config into that section's cards list at
position (or the end), and saves the whole dashboard back. This is
the only way to make a card visible on a sections view —
dashboards_add_card_to_view writes to view.cards, which such a
view renders only in edit mode. When expected_config_hash is given,
it is checked against the dashboard's hash right after the read and
before any change, so a stale caller never overwrites the wrong
section. Use when: adding a card to a specific section of a sections view.
Pass expected_config_hash whenever section_index/position came
from an earlier read that might now be stale.
Not for: a masonry/panel view — use
dashboards_add_card_to_view.
Returns: {status: "added", url_path, view_index, view_title, section_index, card_index, cards_in_section, config_hash} —
config_hash is re-read from HA after the save (not the locally built
dict), ready to chain into the next call's expected_config_hash.
Errors: raises ValueError when card_config has no type key, the
view can't be resolved, isn't a sections view, or section_index is
out of range. Returns {"error": "config_changed", "expected_config_hash", "current_config_hash", "action"} without saving when
expected_config_hash doesn't match. |
| dashboards_update_card_in_sectionA | Change one existing card inside a section of a type: sections view. Resolves the view and target card via _load_view/_require_card,
then merges card_config's keys into the existing card (merge=True,
the default) or replaces it outright (merge=False), and saves the
whole dashboard back. The previous card is only recoverable via
card_before in this call's own response — storage itself keeps no
history. With expected_config_hash, the dashboard's hash is checked
right after the read and before any change, so a stale caller can't
edit the wrong card. Use when: tweaking or replacing one card already placed in a section.
Pass expected_config_hash when section_index/card_index came
from a read that might now be stale.
Not for: adding a new card — use
dashboards_add_card_to_section; removing one — use
dashboards_remove_card_from_section.
Returns: {status: "updated", url_path, view_index, view_title, section_index, card_index, card_before, card_after, config_hash} —
config_hash is re-read from HA after the save, for the next call's
expected_config_hash.
Errors: raises ValueError when card_config is empty, merge=False
lacks a type key, or the view/section/card can't be resolved.
Returns {"error": "config_changed", ...} without saving when
expected_config_hash doesn't match. |
| dashboards_remove_card_from_sectionA | Delete one card from a section of a type: sections view. Resolves the view and section via _load_view/_require_section,
pops the card at card_index from that section's cards list, and
saves the whole dashboard back. card_index is a position, not a
stable id — repeating this call with the same section_index/
card_index after a first successful removal deletes whatever card
has shifted into that position next, not a no-op, unless
expected_config_hash is also passed and now points at the pre-removal
hash, in which case the repeat is rejected with config_changed
instead of deleting the wrong card. Use when: removing a card that's no longer wanted on a sections view.
Pass expected_config_hash whenever section_index/card_index came
from an earlier read that might now be stale.
Returns: {status: "removed", url_path, view_index, view_title, section_index, card_index, removed_card, cards_in_section, config_hash} — removed_card can be passed back to
dashboards_add_card_to_section to restore it; config_hash is
re-read from HA after the save, ready to chain into the next call's
expected_config_hash.
Errors: raises ValueError when the view/section/card can't be
resolved (bad index/path). Returns {"error": "config_changed", "expected_config_hash", "current_config_hash", "action"} without
saving when expected_config_hash doesn't match. |
| dashboards_add_section_to_viewA | Insert a new section into a type: sections view. Resolves the view via _load_view, requires it to be a sections
view, defaults section_config to {"type": "grid", "cards": []}
when omitted, inserts it into that view's sections list at
position (or the end), and saves the whole dashboard back. When
expected_config_hash is given, it is checked against the dashboard's
hash right after the read and before any change. Use when: adding a whole new section (a card group with its own grid)
to a sections view, before populating it with
dashboards_add_card_to_section. Pass expected_config_hash whenever
position came from an earlier read that might now be stale.
Returns: {status: "added", url_path, view_index, view_title, section_index, sections_in_view, config_hash} — config_hash is
re-read from HA after the save, ready to chain into the next call's
expected_config_hash.
Errors: raises ValueError when section_config["cards"] isn't a
list, or the view can't be resolved/isn't a sections view. Returns
{"error": "config_changed", "expected_config_hash", "current_config_hash", "action"} without saving when
expected_config_hash doesn't match. |
| dashboards_screenshotA | Capture a PNG screenshot of one Lovelace dashboard view via the Puppet add-on engine. Resolves url_path to a concrete frontend route (see the parameter
description), rejects paths containing unsafe characters, then calls
the Puppet engine (discovered via Supervisor or
NEXUS_SCREENSHOT_ENGINE_URL) over HTTP with the resolved viewport/
zoom/wait parameters and returns its PNG response as base64. Deciding
between a dashboard route and a default-dashboard view path costs one
lovelace/dashboards/list call (skipped when url_path already
starts with lovelace). Reaches only a local/LAN add-on, not the
public internet. Use when: visually verifying a dashboard or view after editing it.
Returns: {url_path, engine, format: "png", width, height, image_base64, size_bytes} on success — url_path echoes the
resolved route, not the raw argument, and image_base64 can be large,
especially with full_page=True (fixed 4096px height).
Errors: {"error": "dashboard_list_unavailable" | "invalid_path" | "engine_not_available" | "engine_unreachable" | "engine_http_<code>" | "empty_response", "detail": ..., ...} when the dashboard list can't
be fetched, the path is unsafe, the Puppet engine isn't installed/
started, or the engine request itself fails.
Limits: 60-second engine timeout; full_page=True only approximates
full-scroll capture since the engine does not measure actual page
height, so it can crop tall pages or leave blank space on short ones. |
| files_read_config_fileA | Read one config file's raw text from the HA config directory. Resolves relative_path under HA_CONFIG_PATH via _safe_path (blocking
paths outside the directory, disallowed extensions, and secrets.yaml/
.storage) and returns its content as a UTF-8 string; nothing is parsed
or validated. Use when: reading the current text of a YAML/JSON/txt file before
editing it.
Not for: checking whether that text is valid YAML — pass it to
files_validate_yaml_content; discovering which files exist first —
use files_list_config_files.
Returns: str, the file's raw text (UTF-8).
Errors: raises FileNotFoundError when the file does not exist, and
raises PermissionError (from _safe_path) when relative_path
resolves outside the config directory, uses a disallowed extension, or
targets secrets.yaml/.storage. |
| files_write_config_fileA | Overwrite or create one config file under /config with new content. Resolves relative_path via _safe_path, YAML-checks content first
unless validate_yaml=False or the extension isn't .yaml/.yml, then
creates parent directories as needed and writes the file, replacing any
previous content at that path. Use when: no rollback point for the previous content is needed.
Not for: keeping a rollback point — use git_safe_write_with_checkpoint,
which commits the pre-write state first; ESPHome device YAML — use
esphome_write_config.
Returns: dict {"success": True, "path": ...} on success, or
{"success": False, "error": ...} when validate_yaml catches invalid
YAML before writing.
Errors: raises PermissionError (from _safe_path) for a path outside
the config directory, a disallowed extension, or secrets.yaml/.storage;
returns {"success": False, "error": ...} instead of raising for
invalid YAML.
Limits: no backup is taken — the previous content is permanently lost.
Does not reload Home Assistant. |
| files_list_config_filesA | Recursively list config files with allowed extensions under /config. Resolves subdirectory (default the config root) under HA_CONFIG_PATH,
recurses with Path.rglob('*'), and returns config-root-relative paths
for files whose extension is in .yaml/.yml/.json/.txt, skipping
secrets.yaml and .storage/. Use when: discovering which config files exist before reading or
writing one.
Not for: reading a file's content once you have its path — use
files_read_config_file.
Returns: list[str] of config-root-relative file paths.
Limits: output can be large for the /config root; a subdirectory that
resolves (after following symlinks) outside /config returns an empty
list instead of listing files outside the config directory. |
| files_validate_yaml_contentA | Check YAML syntax for a string without writing anything. Parses content with a Home-Assistant-tolerant YAML loader that
accepts !include*/!secret/!env_var/!input as opaque values, and reports
only whether parsing succeeded and the top-level type. Use when: checking a YAML snippet's syntax before calling
files_write_config_file or automations_set_automation_config.
Not for: full HA schema validation — use system_check_config; HA tags
here are accepted but not resolved, so only syntax is checked, not HA
schema validity.
Returns: dict {"valid": True, "type": ...} (top-level type name only,
not the parsed content) or {"valid": False, "error": ...}.
Errors: returns {"valid": False, "error": str(e)} for a YAML parse
error rather than raising. |
| files_delete_config_fileA | Permanently delete one config file under /config after an explicit confirmation. Without confirm=True returns a confirmation prompt and does not
resolve or touch relative_path at all. With confirm=True, resolves
relative_path via _safe_path and calls Path.unlink(); there is no
backup or trash in this tool — deletion is immediate and irreversible
from here alone. Use when: removing a YAML/JSON/txt file that HA no longer needs, once
that removal is confirmed.
Not for: keeping the ability to undo — commit the config to git first
(git_git_commit_all) or write through
git_safe_write_with_checkpoint so a rollback stays possible.
Returns: dict {"success": True, "deleted": ...} when confirmed,
otherwise a confirmation prompt.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; raises FileNotFoundError
when the file does not exist, and raises PermissionError (from
_safe_path) for a path outside the config directory, a disallowed
extension, or secrets.yaml/.storage.
Limits: requires confirm=True; the deletion runs immediately with no
undo once confirmed. |
| files_append_to_config_fileA | Append text to the end of an existing config file. Resolves relative_path via _safe_path, reads its current text,
appends content after a newline, YAML-checks the combined text only
when validate_yaml=True and the extension is .yaml/.yml, then writes
the combined text back. Use when: adding raw YAML/JSON/txt lines that already match the file's
existing list indentation.
Not for: automations — use automations_set_automation_config, which
edits by config id instead of a raw text append.
Returns: dict {"success": True, "path": ...} on success, or
{"success": False, "error": ...} when validate_yaml=True and the
combined text fails to parse.
Errors: raises FileNotFoundError when the file does not exist, and
raises PermissionError (from _safe_path) for a path outside the
config directory, a disallowed extension, or secrets.yaml/.storage.
Limits: validate_yaml defaults to False, so an invalid append is
written without warning unless explicitly checked. |
| git_git_init_configA | Initialize a git repository in the HA config directory. Creates a git repo at HA_CONFIG_PATH via git.Repo.init unless a .git/
directory already exists there, writes a default .gitignore
(secrets.yaml, .storage/, .db, home-assistant.log) when none exists,
and makes one initial commit adding that .gitignore. Use when: preparing /config before using any other git_* tool or
git_safe_write_with_checkpoint for the first time.
Returns: dict {"status": "initialized"|"already_initialized", "path": ...}. |
| git_git_statusA | Show git status of the HA config directory. Calls _repo() for the /config git repo and returns the active branch,
staged/modified/untracked file lists (repo.index.diff,
repo.untracked_files) and an overall dirty flag. Use when: checking what changed in /config before committing or
writing a file.
Returns: dict {"branch", "staged", "modified", "untracked", "is_dirty"}.
Errors: raises RuntimeError (from _repo()) when gitpython is not
installed or no git repo exists yet at HA_CONFIG_PATH — run
git_git_init_config first. |
| git_git_commit_allA | Stage and commit every change in the HA config directory. Calls _repo(), stages everything with git add -A, and commits
message unless nothing is dirty, in which case no commit is made. Use when: creating a checkpoint before a risky change to /config.
Not for: writing one file and checkpointing it in a single call — use
git_safe_write_with_checkpoint.
Returns: dict {"status": "committed", "sha", "message"}, or
{"status": "nothing_to_commit"} when the working tree is clean.
Errors: raises RuntimeError (from _repo()) when gitpython is not
installed or no git repo exists yet — run git_git_init_config first. |
| git_git_logA | List recent commits in the HA config git repository. Calls _repo() and returns up to limit commits from
repo.iter_commits, most recent first, with short SHA, message, author
name and ISO commit date. Use when: reviewing recent config changes before a rollback or diff.
Returns: list[dict] {"sha", "message", "author", "date"}.
Errors: raises RuntimeError (from _repo()) when gitpython is not
installed or no git repo exists yet — run git_git_init_config first.
Limits: limit caps the number of commits returned; no further
pagination is offered. |
| git_git_diffA | Show unstaged changes, or one commit's stat summary. Without sha, calls repo.git.diff() for the unified diff of unstaged
changes to tracked files in /config, excluding staged changes and
untracked new files (see git_git_status). With sha, calls git show --stat <sha> for the commit header and per-file changed-line counts,
not the actual patch. Use when: reviewing what changed before committing, or summarising one
past commit.
Returns: str, the raw diff or stat text.
Errors: raises RuntimeError (from _repo()) when no git repo exists;
raises an exception from gitpython when sha does not resolve to a
commit.
Limits: output is raw, unformatted text and can be large for big diffs. |
| git_git_rollback_fileA | Restore one file to its state at a specific commit. Refuses a relative_path that resolves outside /config
(_resolve_within_config) before running anything, and without
confirm=True returns a safety prompt instead of touching the file;
with confirm=True it calls repo.git.checkout(sha, '--', relative_path), replacing the file's on-disk content with the version
from sha and losing any uncommitted changes to that file. Use when: undoing an accidental edit to a single file.
Not for: resetting the whole config tree — use
git_git_rollback_to_commit.
Returns: dict {"status": "restored", "file", "to"} on success.
Errors: returns {"error": "invalid_path"|"path_outside_config", ...}
when relative_path escapes /config; returns {"error": "confirmation_required", ...} when confirm is not True; raises
RuntimeError (from _repo()) when no git repo exists.
Limits: requires confirm=True; uncommitted changes to the target
file are permanently lost once it runs. |
| git_git_rollback_to_commitA | Hard-reset the entire HA config directory to a previous commit. Without confirm=True returns a safety prompt naming the current head commit;
with confirm=True calls repo.git.reset('--hard', sha), which
discards every commit and uncommitted change made after sha. Use when: reverting /config entirely after a bad batch of changes, and
the target commit is already known.
Not for: restoring a single file — use git_git_rollback_file.
Returns: dict {"status": "reset", "to": sha} on success.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is not True; raises RuntimeError (from
_repo()) when no git repo exists.
Limits: requires confirm=True. WARNING: every commit and uncommitted
change made after sha is permanently and irreversibly lost. |
| git_git_create_branchA | Create a new git branch from the current commit and switch to it. Calls repo.create_head(branch_name) then branch.checkout();
uncommitted changes carry over onto the new branch, and live /config
files now follow it. Use when: starting an isolated set of changes without touching the
current branch's commit history.
Not for: switching to a branch that already exists — use
git_git_checkout_branch.
Returns: dict {"status": "created_and_checked_out", "branch": ...}.
Errors: raises an exception from gitpython when a branch named
branch_name already exists; raises RuntimeError (from _repo())
when no git repo exists. |
| git_git_checkout_branchA | Switch the HA config git repository to an existing branch. Calls repo.git.checkout(branch_name), which replaces every tracked
file under /config with that branch's committed version — the live
configuration Home Assistant reads from changes as soon as this
returns. Use when: switching between prepared configurations that are tracked
as branches.
Not for: creating a branch that does not exist yet — use
git_git_create_branch.
Returns: dict {"status": "switched", "branch": ...}.
Errors: raises an exception from gitpython when branch_name does not
exist, or when uncommitted local changes would conflict with the
target branch's files; raises RuntimeError (from _repo()) when no
git repo exists.
Limits: no confirm parameter; a conflicting uncommitted change blocks
the checkout rather than being silently discarded (plain git
behaviour), but a non-conflicting one carries over onto the new
branch. |
| git_git_list_branchesA | List all local branches in the HA config git repository. Calls _repo() and returns every local branch name from
repo.branches. Returns: list[str] of local branch names.
Errors: raises RuntimeError (from _repo()) when gitpython is not
installed or no git repo exists yet — run git_git_init_config first. |
| git_safe_write_with_checkpointA | Write one config file after committing a checkpoint of the prior state. Stages and commits every uncommitted change under /config as a
checkpoint commit (only when the tree is dirty), then calls the same
write_config_file logic files_write_config_file uses for
relative_path/content, and finally stages and commits that change
with commit_message (or a default message) if the write succeeded. Use when: overwriting a config file while keeping a git-based rollback
point, unlike a plain overwrite.
Not for: a write without a checkpoint — use
files_write_config_file; ESPHome device YAML — use
esphome_write_config.
Returns: dict — the underlying write result ({"success": True, "path": ...} or {"success": False, "error": ...}), plus git_sha/
git_message when the new-content commit was made.
Errors: raises RuntimeError (from _repo()) when no git repo exists
— run git_git_init_config first; returns {"success": False, "error": ...} unchanged when YAML validation fails, in which case the
checkpoint commit of the prior dirty state (if any) still happened, but
no new-content commit is made.
Limits: does not reload Home Assistant; same file-extension and
location limits as files_write_config_file. |
| ws_get_statesA | Get all entity states over the WebSocket API in one call. Sends get_states and waits up to timeout seconds for the matching
result message; this can be faster than the HTTP /api/states
endpoint on large installs since it avoids per-entity HTTP overhead. Use when: fetching every entity's state on a large installation.
Not for: a filtered or paginated state list — use
entities_list_entities.
Returns: the list of state dicts from HA's result.result.
Errors: raises RuntimeError when the WebSocket handshake or the
result message does not arrive within timeout, or when a result
message arrives but is not successful.
Limits: blocks for up to timeout seconds (default 10), including the
initial handshake. |
| ws_call_serviceA | Call a Home Assistant action over WebSocket and return its response data. Sends call_service with return_response=True always set, so actions
that support a response (e.g. weather.get_forecasts,
calendar.get_events) return it; actions without one (light.turn_on,
most control actions) fail with a validation error. domain/service
must match [A-Za-z0-9_]+ (ADR-0006 D3) or the call is refused first.
Refuses hassio.addon_stop/app_stop/addon_stdin/app_stdin against
nexus's own add-on (self_protection.is_own_addon); addon_restart/
app_restart stay allowed. Outright refuses the eight services
services_call_service gates behind confirm (ADR-0006 D5) — none
support a response (F1). Use when: the action's response payload is needed, not just the changed
states.
Not for: a plain control action, or one of the eight guarded services —
use services_call_service for both.
Returns: raw WS result: {success, result: {context, response}} on
success, or a failure dict from HA; {"success": False} if no result
message arrives.
Errors: raises RuntimeError on a handshake timeout; {"error": "invalid_service_name"} for a malformed domain/service; {"error": "self_addon_hassio_service_blocked", "message": ...} for a blocked
hassio.* case; {"error": "guarded_service_refused", "message": ..., "use": "services_call_service"} for a guarded service.
Limits: blocks for up to timeout seconds (default 10), including the
initial handshake. |
| ws_render_templateA | Render a Jinja2 template through HA's WebSocket render_template subscription. Sends render_template; HA acknowledges the subscription with a null
result, then streams the rendered value in a follow-up event. This
waits up to timeout seconds for that event and returns its result. Use when: the WebSocket transport itself is specifically required.
Not for: a one-shot render — use services_render_template, a plain
HTTP call with no subscription semantics.
Returns: the rendered template value from the event's result field.
Errors: raises RuntimeError when the template itself errors (e.g. an
undefined variable), when the WebSocket handshake does not complete
within timeout, or when no event arrives within timeout.
Limits: blocks for up to timeout seconds (default 10), including the
initial handshake. |
| ws_listen_state_changesA | Passively wait for and collect state_changed events for one entity. Subscribes to HA's state_changed event type, which has no server-side
per-entity filter, and counts only events matching entity_id toward
count, so unrelated entities' events do not displace the target's.
Returns early once count matching events arrive, or whatever arrived
once timeout elapses. Use when: waiting for a specific entity to change state, e.g. to confirm
an action took effect.
Not for: any entity's events — use ws_listen_events with
event_type='state_changed'; a one-shot trigger condition — use
ws_subscribe_trigger.
Returns: list of dicts with entity_id, old_state, new_state,
last_changed.
Errors: raises RuntimeError when the WebSocket handshake does not
complete within timeout.
Limits: blocks for up to timeout seconds, including the initial
handshake; collects at most count events. |
| ws_listen_eventsA | Passively wait for and collect events of one HA event type. Subscribes to event_type via subscribe_events and collects up to
count events, returning early once that many arrive or whatever
arrived once timeout elapses. Use when: observing any event type, e.g. integration or automation
events not tied to a single entity's state.
Not for: state changes on one specific entity — use
ws_listen_state_changes.
Returns: list of raw event payloads as HA sent them.
Errors: raises RuntimeError when the WebSocket handshake does not
complete within timeout.
Limits: blocks for up to timeout seconds, including the initial
handshake; collects at most count events. |
| ws_get_configA | Get Home Assistant's own configuration over WebSocket. Sends get_config and waits up to timeout seconds for the matching
result message. Use when: reading HA's location, unit system, version and component
list over the WebSocket transport.
Not for: the same data over HTTP — use history_get_ha_config.
Returns: HA's config dict from result.result (location, unit_system,
version, components, ...).
Errors: raises RuntimeError when the WebSocket handshake or the
result message does not arrive within timeout, or when a result
message arrives but is not successful.
Limits: blocks for up to timeout seconds (default 10), including the
initial handshake. |
| ws_subscribe_triggerA | Passively wait for a Home Assistant trigger definition to fire once. Sends subscribe_trigger with the given trigger and waits up to
timeout seconds for the matching event. Use when: waiting for a specific trigger condition (state, time, numeric
state, ...) rather than polling.
Not for: raw state_changed events on one entity — use
ws_listen_state_changes.
Returns: the trigger's event context dict when it fires, or None if
timeout elapses first.
Errors: raises RuntimeError when the WebSocket handshake does not
complete within timeout.
Limits: blocks for up to timeout seconds, including the initial
handshake. |
| blueprints_list_blueprintsA | List all installed blueprints for a domain over the WebSocket API. Calls the blueprint/list WebSocket command via ha._ws_call for the
given domain and returns Home Assistant's response unchanged; nothing
is read from disk directly here. Use when: enumerating what blueprints exist under
/config/blueprints/ before importing, substituting or deleting
one.
Returns: dict keyed by blueprint path, each value the blueprint's
metadata (name, description, domain, source_url) as returned by HA.
Limits: blocks for the WebSocket round trip; the default 10 second
response wait in ha._ws_call applies. |
| blueprints_import_blueprintA | Fetch a blueprint from a URL and validate it without saving it. Calls the blueprint/import WebSocket command, which has Home Assistant
download url and validate its YAML. This only downloads and
validates — it does NOT save anything to disk. Use when: previewing a blueprint (its metadata and validation errors)
before deciding to persist it.
Not for: persisting the fetched blueprint — pass its raw_data and
suggested_filename to blueprints_save_blueprint.
Returns: dict with suggested_filename, raw_data (the blueprint YAML
text), blueprint.metadata, validation_errors and exists (whether a
blueprint already sits at that path).
Limits: blocks for the WebSocket round trip plus the remote download
time; the default 10 second response wait in ha._ws_call applies. |
| blueprints_save_blueprintA | Save blueprint YAML to /config/blueprints//. Calls the blueprint/save WebSocket command with yaml_content as the
payload and overwrite mapped to HA's allow_override flag; with
overwrite=False (default) it does not replace an existing file at
path, and with overwrite=True it does, losing the previous content. Not for: fetching a blueprint from the internet first — use
blueprints_import_blueprint to get raw_data/suggested_filename.
Returns: Home Assistant's blueprint/save result (typically an empty
success payload).
Errors: Home Assistant raises a WebSocket error, surfaced by
ha._ws_call as a RuntimeError, when overwrite=False and a file
already exists at path.
Limits: blocks for the WebSocket round trip; the default 10 second
response wait in ha._ws_call applies. No confirm parameter — the
only overwrite guard is the overwrite flag itself. |
| blueprints_delete_blueprintA | Delete an installed blueprint by its relative path. Calls the blueprint/delete WebSocket command for domain/path; the
file under /config/blueprints// is removed and its content is
lost, with no backup taken by this tool. Not for: automations or scripts generated from this blueprint — they
keep running with their already-substituted config; use
automations_delete_automation or automations_delete_script for
those.
Returns: Home Assistant's blueprint/delete result (typically an empty
success payload).
Limits: blocks for the WebSocket round trip; the default 10 second
response wait in ha._ws_call applies. No confirm parameter guards
this deletion. |
| blueprints_substitute_blueprintA | Render a blueprint with given inputs into a plain automation or script. Calls the blueprint/substitute WebSocket command, which resolves
input against the blueprint's input: placeholders and returns the
resulting config; nothing is saved or reloaded by this tool. Use when: previewing the concrete triggers/conditions/actions a
blueprint would produce before saving it via
automations_set_automation_config or automations_set_script_config.
Returns: dict with the substituted automation/script YAML content as a
dict.
Limits: blocks for the WebSocket round trip; the default 10 second
response wait in ha._ws_call applies. |
| calendar_list_calendarsA | List every calendar.* entity known to HA. Calls GET /api/calendars over HTTP. Use when: discovering which entity_id to pass to
calendar_list_events/calendar_create_event/calendar_delete_event.
Not for: the events within a calendar — use calendar_list_events.
Returns: list of {"entity_id", "name"} dicts, or an empty list if the
response isn't a JSON list. |
| calendar_list_eventsA | List events on one calendar between start and end. Calls GET /api/calendars/{entity_id} over HTTP with start/end as
query parameters. Use when: reading a calendar's upcoming or past events for a known date
range.
Not for: listing the calendar entities themselves — use
calendar_list_calendars.
Returns: list of event dicts as returned by HA (fields include summary,
start, end, uid), or an empty list if the response isn't a JSON
list. |
| calendar_create_eventA | Create a new event on a calendar via the calendar.create_event service. Maps start/end to the service's start_date_time/end_date_time
fields. Calling this twice with identical arguments creates two
separate events, since HA assigns each a new uid. Use when: adding a new event to a calendar that supports creation (local
or CalDAV calendars).
Not for: removing an event — use calendar_delete_event.
Returns: {"entity_id", "summary", "start", "end", "result": ...} where
result is the service-call response. |
| calendar_delete_eventA | Delete a calendar event by its uid via WS calendar/event/delete. Only works for calendar platforms that declare
CalendarEntityFeature.DELETE_EVENT (e.g. local/CalDAV calendars);
read-only integrations such as Google Calendar reject it, and this
returns ok: False with HA's error instead of raising. Use when: removing an event or a recurring instance from a calendar
that supports deletion.
Not for: creating an event — use calendar_create_event; not for
read-only calendar integrations, which will fail here regardless of
arguments.
Returns: {"entity_id", "uid", "result": ..., "ok": True} on success.
Errors: {"entity_id", "uid", "ok": False, "error": str(e)} when the
platform rejects the deletion or the WS call otherwise raises. |
| todo_list_todo_listsA | List all todo.* entities currently registered in HA. Filters ha.get_states() for entity IDs starting with todo.. Use when: discovering which entity_id to pass to
todo_list_items/todo_add_item/todo_update_item/todo_remove_item.
Not for: the items within a list — use todo_list_items.
Returns: list of {"entity_id", "state", "friendly_name"} dicts, one
per todo.* entity. |
| todo_list_itemsA | List items on a todo list, optionally filtered by status. Calls WS todo/item/list and filters the returned items by status in
Python (HA's response shape for this command has varied between "items"
dicts and a bare list across versions, both are handled here). Use when: reading a todo list's current items.
Not for: listing the todo entities themselves — use
todo_list_todo_lists.
Returns: list of item dicts as returned by HA (fields include uid,
summary/item text, status). |
| todo_add_itemA | Add a new item to a todo list via the todo.add_item service. Sends due_date or due_datetime depending on whether due_date
contains a time component ('T' or a space). Calling this twice with the
same item text creates two separate items with distinct uids. Use when: adding a new entry to a todo list.
Not for: changing or completing an existing item — use
todo_update_item.
Returns: {"entity_id", "item", "result": ...} where result is the
service-call response. |
| todo_update_itemA | Update a todo item's text and/or status via the todo.update_item service. Maps item to the service's rename field. Only the fields you pass
(item/status) are sent, so whichever value is omitted is left
unchanged on HA's side. Use when: renaming an item or marking it needs_action/completed.
Not for: adding a new item — use todo_add_item; not for removing one
— use todo_remove_item.
Returns: {"entity_id", "uid", "result": ...} where result is the
service-call response. |
| todo_remove_itemA | Remove an item from a todo list by its uid via the todo.remove_item service. Use when: permanently deleting an item, e.g. after completing a task
you don't want to keep marked completed.
Not for: marking an item completed without deleting it — use
todo_update_item with status='completed'.
Returns: {"entity_id", "uid", "result": ...} where result is the
service-call response. |
| devices_list_devicesA | List all devices with a slimmed set of common fields. Calls WS config/device_registry/list and projects each entry down to
id, name_by_user, name, area_id, manufacturer, model, entry_type, plus
config_entries and disabled_by when present. Use when: you need the device registry without every raw field.
Not for: the full unfiltered registry — use areas_list_devices;
devices scoped to one area — use devices_list_devices_in_area; fuzzy
name-based search — use search_search_devices.
Returns: list of slimmed device dicts as described above. |
| devices_update_deviceA | Update fields on an existing device registry entry. Calls WS config/device_registry/update; only the parameters you pass
are sent, so omitted or null fields are left unchanged. Use when: renaming a device, moving it to another area, or enabling or
disabling it.
Returns: dict with device_id and result (the updated device,
slimmed like devices_list_devices).
Limits: area_id can only be set here, not cleared — there is no
parameter to remove an existing area assignment. |
| devices_remove_deviceA | Remove a device from one of its config entries. Calls WS config_entries/remove_device with both IDs; if the device
belongs to other config entries it keeps existing under those. Use when: detaching a device from one integration without touching its
other config entries.
Returns: dict with device_id, config_entry_id and the raw WS
result.
Limits: both device_id and config_entry_id are required — there is
no way to remove a device from every config entry in one call. |
| devices_list_devices_in_areaA | List devices currently assigned to one area. Calls WS config/device_registry/list and filters the slimmed device
list (see devices_list_devices) down to entries whose area_id
matches. Use when: you need only the devices in one area rather than the whole
registry.
Not for: the whole device registry — use devices_list_devices or
areas_list_devices; fuzzy name-based search — use
search_search_devices.
Returns: list of slimmed device dicts (see devices_list_devices) whose
area_id equals the given area_id.
Limits: devices without an area are never returned here. |
| supervisor_list_addonsA | List every installed add-on with its slug, name, state and version. Calls Supervisor's GET /addons and projects each entry down to slug,
name, state, version, version_latest and update_available. Use when: getting an overview of installed add-ons and which have
updates pending.
Not for: full add-on detail (options, ports, boot mode) — use
supervisor_get_addon.
Returns: {"addons": [{slug, name, state, version, version_latest, update_available}, ...]}.
Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing;
{"error": "HTTP <status>", "detail": ...} on a Supervisor API error. |
| supervisor_get_addonA | Get full Supervisor info for one add-on, with secret option values redacted. Calls GET /addons/<slug>/info: every field Supervisor stores for that
add-on (options schema, current options, ports, boot mode, version,
state and more), except options values are replaced with a fixed
placeholder wherever the schema marks a field a password, the key name
looks like a secret (password/pass/pwd, token, api_key,
secret, credential, private, key as a word/suffix), or the value
is a URL with inline credentials (scheme://user:pass@host) — covers
nexus's own API key and other add-ons' secrets/connection strings
alike, recursively through nested groups and lists. An empty/unset
value stays empty. Adds redacted_fields: {"path", "reason"} dicts. Use when: the full add-on record is needed, e.g. before editing its
options with supervisor_set_addon_options, which accepts the same
placeholder back for an unchanged secret field without overwriting it.
Not for: a quick overview across all add-ons — use
supervisor_list_addons.
Returns: Supervisor's add-on info payload with secret-looking options
values replaced by a placeholder, plus redacted_fields.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing; {"error": "HTTP <status>", "detail": ...} if the slug does not exist. |
| supervisor_install_addonA | Install an add-on from its slug. Calls POST /addons/<slug>/install. The add-on must already belong to a
repository Supervisor knows about; this does not add repositories.
Installing downloads the add-on's image, which reaches outside the HA
instance and its host. Use when: adding a new add-on that is already visible in an installed
repository.
Not for: starting/stopping an already-installed add-on — use
supervisor_start_addon/supervisor_stop_addon.
Returns: Supervisor's install-job result.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing;
{"error": "HTTP <status>", "detail": ...} if the slug is unknown.
Limits: downloads the add-on image over the network; can take a while
on a slow connection. |
| supervisor_uninstall_addonA | Uninstall an add-on and its persistent data after an explicit confirmation. Calls POST /addons/<slug>/uninstall. Refuses to run at all against
nexus's own add-on (its real slug, or the alias Supervisor resolves to
the caller itself — see self_protection.is_own_addon) — checked first,
with no Supervisor request made either way, before even the
confirmation gate: nexus removing itself is never the right tool for
that regardless of confirm. Otherwise, without confirm=True nothing
is removed; the call only returns an error asking for confirmation
(ADR-0003 D1). Use when: permanently removing an add-on that is no longer needed.
Not for: temporarily stopping it while keeping its data and config — use
supervisor_stop_addon.
Returns: Supervisor's uninstall-job result when confirmed.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "self_addon_uninstall_blocked", "message": ...} when
slug is nexus's own add-on; returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm
is false; {"error": "HTTP <status>", "detail": ...} on a Supervisor
API error.
Limits: WARNING: deletes the add-on's data with no separate backup step;
requires confirm=True. |
| supervisor_start_addonA | Start an installed, stopped add-on. Calls POST /addons/<slug>/start. Use when: bringing an installed add-on online after it was stopped.
Not for: installing a new add-on — use supervisor_install_addon; for
stopping it — use supervisor_stop_addon.
Returns: Supervisor's start-job result.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing;
{"error": "HTTP <status>", "detail": ...} if the slug is unknown or
already running. |
| supervisor_stop_addonA | Stop a running add-on. Calls POST /addons/<slug>/stop. The add-on — e.g. an MQTT broker other
integrations depend on — becomes unavailable until started again.
Refuses to run at all against nexus's own add-on (by its real slug or
the literal alias Supervisor resolves to the caller itself): nexus
stopping itself would cut off the very connection carrying this call,
with no guarantee the response ever comes back, and — unlike
supervisor_restart_addon — leaves nexus down until someone starts it
again some other way. Use when: taking one add-on offline without uninstalling it.
Not for: removing it entirely — use supervisor_uninstall_addon; for
bringing it back — use supervisor_start_addon; for a brief restart of
nexus itself — use supervisor_restart_addon instead, which is allowed.
Returns: Supervisor's stop-job result.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "self_addon_stop_blocked", "message": ...} when
slug is nexus's own add-on; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var
is missing; {"error": "HTTP <status>", "detail": ...} if the slug is
unknown.
Limits: interrupts the add-on's availability, and anything depending on
it, until it is started again. |
| supervisor_restart_addonA | Restart an add-on (stop, then start). Calls POST /addons/<slug>/restart. The add-on — which could be this
nexus add-on itself — is briefly unavailable during the restart. Use when: an add-on needs to pick up new options or recover from a
stuck state.
Not for: a one-way stop — use supervisor_stop_addon; for restarting
Core instead — use supervisor_restart_core.
Returns: Supervisor's restart-job result.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing;
{"error": "HTTP <status>", "detail": ...} if the slug is unknown.
Limits: briefly interrupts the add-on's availability. |
| supervisor_update_addonA | Update an add-on to its latest available version. Calls POST /addons/<slug>/update, which downloads and installs the new
version over the network; the previous version is only recoverable from
a backup taken beforehand. Use when: update_available is true for the add-on and the new version
should be applied.
Not for: reverting an update — restore a backup via
supervisor_restore_backup instead; there is no dedicated rollback
call.
Returns: Supervisor's update-job result.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing;
{"error": "HTTP <status>", "detail": ...} on a failed update.
Limits: downloads the new version over the network; no automatic
rollback on failure. |
| supervisor_get_addon_logsA | Get the most recent log lines from one add-on. Calls GET /addons/<slug>/logs, which returns plain text, and keeps
only the last lines lines. Use when: debugging one add-on's runtime behaviour.
Not for: the ESPHome add-on's per-device compile/upload logs — use
esphome_get_addon_logs if that distinction matters to the caller.
Returns: {"logs": "<joined log lines>"}.
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set or empty response"} when
the token is missing; {"error": "HTTP <status>", "detail": ...} on a
Supervisor API error. |
| supervisor_set_addon_optionsA | Replace an add-on's stored options with the given object. Calls POST /addons/<slug>/options as {"options": options}. Read
current values via supervisor_get_addon, modify them, and send the
full dict back — overwrites previous options entirely, so omitted
fields are lost. A value left as the placeholder for a secret field is
swapped for the real stored value first, so echoing it back unchanged
never overwrites the secret — a list containing it must keep every
item's order/count as read, or the call is refused rather than guessed.
Once a placeholder was resolved, a Supervisor error strips detail
(it can otherwise echo the rejected payload, secret included). Takes
effect after supervisor_restart_addon. Refuses to run against
nexus's own add-on — could otherwise lift its own restrictions. Use when: changing an add-on's configuration programmatically.
Not for: reading the current options first — use
supervisor_get_addon; for changing nexus's own configuration — use the
Home Assistant Supervisor UI instead.
Returns: Supervisor's options-update result.
Errors: {"error": "invalid_slug"} for a bad slug; self_addon_options_blocked for nexus's own add-on;
redaction_marker_list_length_mismatch on a placeholder list-length
mismatch; SUPERVISOR_TOKEN not set when the token is missing;
{"error": "HTTP <status>"} on a schema-validation or placeholder
read-back failure.
Limits: does not apply until the add-on is restarted. |
| supervisor_get_addon_statsA | Get an add-on's current runtime resource usage. Calls GET /addons/<slug>/stats for CPU, memory, network and disk I/O
figures at the moment of the call. Use when: checking whether an add-on is consuming unexpected resources.
Not for: historical usage over time — this returns only a snapshot.
Returns: Supervisor's raw stats payload (CPU percent, memory
usage/limit, network and block I/O counters).
Errors: {"error": "invalid_slug"} for a bad slug; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing;
{"error": "HTTP <status>", "detail": ...} if the add-on is not
running. |
| supervisor_get_supervisor_infoA | Get info about the Supervisor component itself. Calls GET /supervisor/info for its version, update channel and health
flag. Use when: checking the Supervisor's own version/channel/health, as
opposed to Core or the host.
Not for: Home Assistant Core details — use supervisor_get_core_info;
for the host OS — use supervisor_get_host_info.
Returns: Supervisor's raw info payload (version, channel, healthy,
and related fields).
Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing. |
| supervisor_get_core_infoA | Get info about the Home Assistant Core container. Calls GET /core/info for its version, CPU architecture and machine
type. Use when: checking Core's version/arch, as opposed to the Supervisor or
host.
Not for: HA's own location/units/component config — use
history_get_ha_config.
Returns: Supervisor's raw Core info payload (version, arch, machine).
Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing. |
| supervisor_get_host_infoA | Get info about the host operating system. Calls GET /host/info for Home Assistant OS version, hostname, kernel and related
host-level fields. Use when: checking the underlying OS/hardware, as opposed to Core or the
Supervisor.
Not for: Supervisor's own version — use
supervisor_get_supervisor_info.
Returns: Supervisor's raw host info payload (Home Assistant OS version, hostname,
kernel, and related fields).
Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing. |
| supervisor_restart_coreA | Restart Home Assistant Core through the Supervisor after an explicit confirmation. Calls POST /core/restart. WARNING: causes downtime for HA Core (and
everything depending on it) until it comes back up. Without
confirm=True nothing is restarted. Use when: Core needs restarting on a Supervisor install specifically.
Not for: the equivalent call via HA's own service — use
system_restart_ha; for rebooting the whole host — use
supervisor_restart_host.
Returns: Supervisor's restart-job result when confirmed.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the
token env var is missing.
Limits: requires confirm=True; interrupts Core until it restarts. |
| supervisor_restart_hostA | Reboot the whole host machine after an explicit confirmation. Calls POST /host/reboot. WARNING: Home Assistant, every add-on
(including this nexus add-on) and the host OS go offline for minutes.
Without confirm=True nothing is rebooted. Use when: a host-level change (e.g. a Home Assistant OS update) requires a full reboot.
Not for: restarting only Core — use supervisor_restart_core; for
restarting one add-on — use supervisor_restart_addon.
Returns: Supervisor's reboot-job result when confirmed.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the
token env var is missing.
Limits: requires confirm=True; takes the whole host, including this
add-on, offline for minutes — the call itself may not receive a reply. |
| supervisor_list_backupsA | List every backup Supervisor manages. Calls GET /backups for the full backup catalogue Supervisor tracks. Use when: finding a backup's slug before restoring or deleting it, or
checking whether a scheduled backup succeeded.
Not for: HA Core's own backup.create/backup.create_automatic backups
when they were not made through Supervisor — those may not appear here
under the same view.
Returns: Supervisor's raw backups payload.
Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing. |
| supervisor_create_backupA | Create a new Supervisor backup, full or partial. Calls POST /backups/new/full when neither addons nor folders is
given, otherwise POST /backups/new/partial with those slugs/folders.
Unlike system_create_backup, this never deletes older backups — it
only adds a new one. Use when: a named, partial and/or password-protected backup is needed on
a Supervisor install.
Not for: a quick backup using the instance's own automatic-backup
settings (which may prune old ones) — use system_create_backup.
Returns: Supervisor's backup-job result, including the new backup's
slug on success.
Errors: {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the token env var is missing;
{"error": "HTTP <status>", "detail": ...} on a timeout or failure —
check supervisor_list_backups before retrying.
Limits: a full backup can take minutes; on a timeout error, check
supervisor_list_backups before retrying rather than assuming failure. |
| supervisor_restore_backupA | Restore a full backup after an explicit confirmation. Calls POST /backups/<slug>/restore/full, which replaces the HA
configuration, every add-on with its data, and the backed-up folders
with the backup's contents; anything changed since the backup was taken
is lost. Core and this nexus add-on restart as part of the restore, so
the call may drop the connection before it can reply. Without
confirm=True nothing is restored. Use when: reverting to a known-good state after a failed update or
misconfiguration.
Not for: restoring only some add-ons/folders — Supervisor's partial
restore is not exposed by this tool.
Returns: Supervisor's restore-job result when confirmed; the reply may
never arrive because the add-on restarts mid-call.
Errors: {"error": "invalid_slug"} for a bad slug; returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "HTTP <status>", "detail": ...} if the slug or password is wrong.
Limits: WARNING: discards every change made since the backup; requires
confirm=True. |
| supervisor_delete_backupA | Permanently delete one backup after an explicit confirmation. Calls DELETE /backups/<slug>. Without confirm=True nothing is
deleted; the call only returns a confirmation prompt. There is no undo
once the backup file is gone — a backup is itself the undo mechanism
for every other change in this add-on. Use when: cleaning up a backup that is confirmed to be no longer
needed.
Not for: any situation where the backup might still be needed — there
is no recovery after this call, even with confirm=True.
Returns: Supervisor's delete result when confirmed, otherwise a
confirmation prompt.
Errors: {"error": "invalid_slug"} for a bad slug; returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; {"error": "SUPERVISOR_TOKEN not set — Nexus must run as HA add-on for Supervisor API"} when the
token env var is missing; {"error": "HTTP <status>", "detail": ...}
if the slug does not exist.
Limits: requires confirm=True; deletion is immediate and permanent
with no undo once confirmed. |
| hacs_list_hacs_repositoriesA | List HACS repositories known to this Home Assistant instance. Calls the hacs/repositories/list WebSocket command, optionally scoped
to one category. Use when: browsing or checking the state of repositories HACS already
knows about (installed or not).
Not for: repositories not yet added to HACS at all — use
hacs_add_custom_repository first.
Returns: list of HACS repository dicts as reported by HACS, or
{"error": ..., "hint": ...} if the WebSocket call fails.
Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when the WebSocket command fails,
e.g. because HACS is not installed. |
| hacs_get_hacs_repositoryA | Get details about a single HACS repository. Calls the hacs/repository/info WebSocket command for the given
repo_id, passed as its repository_id field. Use when: checking one repository's installed/available version or
metadata before installing or updating it.
Not for: browsing many repositories at once — use
hacs_list_hacs_repositories.
Returns: HACS's raw repository-info dict, or {"error": ..., "hint": ...} if the WebSocket call fails.
Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when repo_id is unknown or the
WebSocket command fails. |
| hacs_install_hacs_repositoryA | Install a HACS repository, optionally pinning a version. Calls the hacs/repository/download WebSocket command (HACS has no
separate "install" command — download installs when not yet
installed, or re-downloads in place when it is), which fetches the
repository's release from its source (typically GitHub) — an outbound
fetch beyond this HA instance and its host. Use when: adding a HACS-managed integration/plugin/theme that is already
known to HACS (via the default store or hacs_add_custom_repository).
Not for: adding a repository HACS does not know about yet — use
hacs_add_custom_repository first.
Returns: HACS's install result, or {"error": ..., "hint": ...} if the
WebSocket call fails.
Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when repo_id/version is
invalid or the WebSocket command fails.
Limits: downloads the release over the network; requires a restart of
the affected component for most categories. |
| hacs_uninstall_hacs_repositoryA | Uninstall a HACS repository. Calls the hacs/repository/remove WebSocket command (HACS has no
separate "uninstall" command), which removes the installed files for
repo_id; the integration/plugin/theme stops working until
reinstalled. Use when: removing a HACS-managed component that is no longer needed.
Not for: only skipping an update while keeping it installed — there is
no such option exposed here.
Returns: HACS's remove result, or {"error": ..., "hint": ...} if
the WebSocket call fails.
Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when repo_id is not installed or
the WebSocket command fails. |
| hacs_update_hacs_repositoryA | Update an installed HACS repository to its latest available version. HACS has no single "update" WebSocket command. This performs the three
calls HACS's own frontend makes for an update: hacs/repository/refresh
(re-fetches repository data; always returns {}, no version info),
then hacs/repository/info (reads the resulting available_version),
then hacs/repository/download with that version — which downloads and
installs the newest release over the network; the previous version is
only recoverable from a backup taken beforehand. Use when: pending_upgrade is set for the repository (see
hacs_list_hacs_critical_updates) and the new version should be
applied.
Not for: pinning a specific version instead of the latest — use
hacs_install_hacs_repository with version set.
Returns: HACS's download result, or {"error": ..., "hint": ...} if
any of the three WebSocket calls fails.
Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when the refresh or info call
fails (the download call is then never made); {"error": "HACS did not report an available_version for this repository", "raw": ...} when
info succeeds but has nothing to update to.
Limits: downloads the new release over the network; no automatic
rollback on failure; three sequential WebSocket round-trips instead of
one. |
| hacs_add_custom_repositoryA | Register a custom repository with HACS so it becomes installable. Calls the hacs/repositories/add WebSocket command (plural — distinct
from the singular hacs/repository/* commands used elsewhere in this
namespace) with url as its repository field and category. This
only registers the repository — it does not install it. Use when: a repository is not in HACS's default store and needs adding
before it can be installed.
Not for: installing an already-registered repository — use
hacs_install_hacs_repository.
Returns: HACS's add result, or {"error": ..., "hint": ...} if the
WebSocket call fails.
Errors: {"error": str(exception), "hint": "HACS may not be installed, or the WS command name has changed"} when url/category is invalid
or the WebSocket command fails. |
| hacs_list_hacs_critical_updatesA | List installed HACS repositories that have a pending upgrade available. Calls the same hacs/repositories/list WebSocket command as
hacs_list_hacs_repositories and filters to entries whose
pending_upgrade flag is set, despite this tool's name — HACS itself
has no separate "critical" severity here. Use when: finding what needs hacs_update_hacs_repository without
filtering the full list manually.
Not for: every repository regardless of upgrade state — use
hacs_list_hacs_repositories.
Returns: list of repository dicts with pending_upgrade truthy, or
{"error": ...} if the underlying call fails or returns an unexpected
shape.
Errors: {"error": str(exception), "hint": ...} when the WebSocket call
fails; {"error": "Unexpected HACS response shape", "raw": result} when
it succeeds but does not return a list. |
| energy_get_energy_prefsA | Return the full HA Energy Dashboard preferences. Calls the WebSocket endpoint energy/get_prefs and returns its payload
unchanged, including the configured energy_sources and
device_consumption lists. Use when: you need the current preferences before editing them with
energy_save_energy_prefs or one of the energy_add_*/
energy_remove_energy_source helpers.
Not for: adding or removing a single source without hand-building the
full list — use energy_add_grid_consumption, energy_add_grid_return,
energy_add_solar_source, energy_add_battery_source or
energy_remove_energy_source instead.
Returns: dict with energy_sources (list) and device_consumption
(list), exactly as HA stores them.
Errors: {"error": "..."} when the WebSocket call raises. |
| energy_save_energy_prefsA | Save Energy Dashboard preferences via WS energy/save_prefs. Each of energy_sources/device_consumption you pass replaces the
entire corresponding saved list — it is not merged with what's already
there. Use energy_add_grid_consumption, energy_add_grid_return,
energy_add_solar_source, energy_add_battery_source or
energy_remove_energy_source for incremental edits instead of
hand-building the full list. currency/energy_per_unit are kept only
for backward compatibility and are rejected: HA's currency lives in core
config (homeassistant.currency), not this WS schema, and
energy_per_unit does not exist in it at all. Use when: you already hold the full desired energy_sources/
device_consumption list, e.g. from energy_get_energy_prefs.
Not for: adding or removing one source — use the energy_add_*/
energy_remove_energy_source helpers, which read-modify-write for you.
Returns: {"status": "saved", "result": ..., "fields": [...]} on
success.
Errors: {"error": "no fields to save", ...} when both list parameters
are omitted; {"error": "currency and energy_per_unit are not fields of HA's energy/save_prefs WS schema...", ...} when either deprecated
parameter is passed; {"error": str(e), ...} when the WS call raises. |
| energy_get_energy_infoA | Return Energy Dashboard info such as cost sensors and currency. Calls the WebSocket endpoint energy/info and returns its payload
unchanged. Use when: you need metadata about the Energy Dashboard (available cost
sensor types, currency) rather than the source configuration itself.
Not for: the actual source/device list — use energy_get_energy_prefs.
Returns: dict as returned by HA's energy/info WS command.
Errors: {"error": str(e)} when the WS call raises. |
| energy_validate_energy_prefsA | Validate the currently saved Energy Dashboard configuration. Calls the WebSocket endpoint energy/validate, which checks the saved
energy_sources/device_consumption for issues (e.g. a statistic ID
that no longer exists) without changing anything. Use when: checking whether the current Energy Dashboard setup has
issues, e.g. after editing sources with energy_save_energy_prefs or
one of the energy_add_* helpers.
Not for: reading the configuration itself — use
energy_get_energy_prefs.
Returns: dict as returned by HA's energy/validate WS command, listing
any detected issues per source.
Errors: {"error": str(e)} when the WS call raises. |
| energy_add_grid_consumptionA | Add a grid consumption flow to the Energy Dashboard's grid source. Reads the current preferences via ha._ws_call("energy/get_prefs"),
appends stat_energy_from (and stat_cost if given) as a new
flow_from entry on the existing grid source, creating that grid
source first if none exists yet, then saves the updated list via WS
energy/save_prefs. Calling it twice with the same stat_energy_from
adds a second, duplicate flow entry. Use when: registering a grid-import sensor as an Energy Dashboard
consumption flow.
Not for: grid export/solar compensation — use
energy_add_grid_return; for a full source-list replacement use
energy_save_energy_prefs.
Returns: {"status": "added", "stat_energy_from": ..., "result": ...}.
Errors: {"error": str(e), "stat_energy_from": ...} when either WS call
raises. |
| energy_add_grid_returnA | Add a grid return (export) flow to the Energy Dashboard's grid source. Reads the current preferences via ha._ws_call("energy/get_prefs"),
appends stat_energy_to (and stat_compensation if given) as a new
flow_to entry on the existing grid source, creating that grid source
first if none exists yet, then saves via WS energy/save_prefs. Calling
it twice with the same stat_energy_to adds a second, duplicate entry. Use when: registering a solar-export or other grid-return sensor, e.g.
solar sold back to the grid.
Not for: grid import — use energy_add_grid_consumption; for a full
source-list replacement use energy_save_energy_prefs.
Returns: {"status": "added", "stat_energy_to": ..., "result": ...}.
Errors: {"error": str(e), "stat_energy_to": ...} when either WS call
raises. |
| energy_add_solar_sourceA | Add a solar production source to the Energy Dashboard. Reads the current preferences, appends a new {"type": "solar", ...}
entry to the energy_sources list, and saves it via WS
energy/save_prefs. Calling it twice with the same stat_energy_from
adds a second, duplicate source. Use when: registering a solar production sensor as a new Energy
Dashboard source.
Not for: an existing source's export flow — use
energy_add_grid_return; for a full source-list replacement use
energy_save_energy_prefs.
Returns: {"status": "added", "stat_energy_from": ..., "result": ...}.
Errors: {"error": str(e), "stat_energy_from": ...} when either WS call
raises. |
| energy_add_battery_sourceA | Add a battery source to the Energy Dashboard. Reads the current preferences, appends a new {"type": "battery", ...}
entry combining stat_energy_from (discharge) and stat_energy_to
(charge) to the energy_sources list, and saves it via WS
energy/save_prefs. Calling it twice with the same arguments adds a
second, duplicate source. Use when: registering a home battery's charge and discharge sensors as
one Energy Dashboard source.
Not for: grid or solar sources — use energy_add_grid_consumption/
energy_add_grid_return/energy_add_solar_source.
Returns: {"status": "added", "stat_energy_from": ..., "stat_energy_to": ..., "result": ...}.
Errors: {"error": str(e)} when either WS call raises. |
| energy_remove_energy_sourceA | Remove an energy source identified by its stat_energy_from. Reads the current preferences, drops any solar/battery/gas/water source
whose stat_energy_from matches, also strips matching flow_from
entries from the grid source, and saves the resulting list via WS
energy/save_prefs. This replaces the whole energy_sources list with
one that has the matching entries removed — anything else in the list
is preserved as-is. Use when: undoing an energy_add_solar_source/energy_add_battery_source/
energy_add_grid_consumption call, or dropping a source that no longer
exists.
Not for: replacing the whole source list at once — use
energy_save_energy_prefs.
Returns: {"status": "removed", "removed": <count>, "stat_energy_from": ..., "result": ...} on success, or {"status": "not_found", "stat_energy_from": ...} when nothing matched.
Errors: {"error": str(e), "stat_energy_from": ...} when either WS call
raises. |
| zones_list_zonesA | List all zone entities with their common location attributes. Reads all HA states and keeps zone.* entities, projecting each down
to entity_id, state, and any of latitude, longitude, radius,
friendly_name, passive and icon present in its attributes. Use when: you need every zone's location and radius, e.g. before
checking who is inside one.
Returns: list of slimmed zone dicts as described above. |
| zones_get_zoneA | Get one zone entity's full state and attributes. Prefixes entity_id with zone. if missing, then fetches it with
ha.get_state. Use when: you need every attribute of a single zone rather than the
slimmed list from zones_list_zones.
Returns: the full HA state object for the zone (entity_id, state,
attributes).
Errors: {"error": "<message>", "entity_id": ...} if the zone entity
does not exist. |
| zones_create_zoneA | Create a zone as a UI helper (storage collection), not a YAML zone. Calls WS zone/create with the given coordinates and radius; only
zones created this way can later be changed through
zones_update_zone or zones_delete_zone. zone.home (core config)
and YAML-defined zones live outside this storage collection and cannot
be created here. Use when: adding a new geofence zone without editing configuration.yaml.
Returns: dict with status, name, and the raw WS result.
Errors: on failure, returns {"error": "<message>", "hint": "...", "name": ...} instead of raising. |
| zones_update_zoneA | Update fields on an existing zone helper. Calls WS zone/update; only the parameters you pass are sent, so
omitted fields keep their current value. Only works for zones created
via zones_create_zone (UI helpers) — zone.home and YAML-defined
zones reject this WS command. Use when: adjusting a UI-helper zone's coordinates, radius or name.
Returns: dict with status, zone_id, and the raw WS result.
Errors: on failure (e.g. a YAML zone or zone.home), returns
{"error": "<message>", "hint": "...", "zone_id": ...} instead of
raising. |
| zones_delete_zoneA | Delete a zone helper. Calls WS zone/delete; accepts either the bare helper id or the full
zone.<id> entity_id. Only works for zones created via
zones_create_zone — zone.home and YAML-defined zones reject this WS
command. Use when: removing a UI-helper zone that is no longer needed.
Returns: dict with status, zone_id, and the raw WS result.
Errors: on failure, returns {"error": "<message>", "hint": "...", "zone_id": ...} instead of raising. |
| zones_reload_zonesA | Reload zones defined in configuration.yaml. Calls service zone.reload over HTTP, which makes Home Assistant
re-read YAML-defined zones without a full restart. Use when: you edited zone YAML and want the change applied, or after
zones_create_zone reports that YAML zones aren't supported.
Returns: dict with status and the raw service-call result.
Errors: on failure, returns {"error": "<message>"} instead of
raising. |
| zones_list_persons_in_zoneA | List person entities currently inside a given zone. Reads the zone's own persons attribute (maintained by Home
Assistant's zone component); falls back to matching each person's
state string against the zone only when that attribute is entirely
absent, which also special-cases zone.home (Home Assistant always
reports "home" there regardless of the zone's friendly_name). Use when: checking who is currently inside a specific zone.
Returns: list of dicts (entity_id, state, friendly_name, latitude,
longitude) for persons in the zone; empty list if the zone does not
exist. |
| zones_get_user_locationA | Get one person entity's current location. Prefixes person_entity_id with person. if missing, then reads its
state and location attributes. Use when: you need just one person's coordinates rather than scanning
a zone with zones_list_persons_in_zone.
Returns: dict with entity_id, state, latitude, longitude, gps_accuracy,
source.
Errors: {"error": "<message>", "entity_id": ...} if the person entity
does not exist. |
| labels_list_labelsA | List all labels defined in Home Assistant. Calls WS config/label_registry/list and returns the result unfiltered;
returns an empty list if the WS response is not a list. Use when: you need label IDs and names before filtering or assigning
them to entities or devices.
Returns: list of label registry dicts (label_id, name, icon, color,
description).
Errors: on a WS failure, returns [{"error": "<message>"}] instead of
raising. |
| labels_create_labelA | Create a new label. Calls WS config/label_registry/create with name and any of icon,
color and description you pass; Home Assistant assigns a new
label_id, so calling this twice with the same name creates two separate
labels. Use when: you need a new label to tag entities or devices with.
Returns: the created label registry dict (label_id, name, icon, color,
description).
Errors: on a WS failure, returns {"error": "<message>"} instead of
raising. |
| labels_update_labelA | Update fields on an existing label. Calls WS config/label_registry/update; only the parameters you pass
are sent, so omitted fields keep their current value. Use when: renaming a label or changing its icon, color or description.
Returns: the updated label registry dict.
Errors: on a WS failure, returns {"error": "<message>"} instead of
raising. |
| labels_delete_labelA | Delete a label from the label registry. Calls WS config/label_registry/delete with the given label_id and
returns Home Assistant's result unchanged. Use when: a label is no longer needed.
Returns: dict with label_id, the raw WS result, and ok (true on
success).
Errors: on a WS failure, returns {"label_id": ..., "ok": false, "error": "<message>"} instead of raising. |
| labels_assign_label_to_entityA | Assign a label to an entity, keeping its existing labels. Reads the entity's current labels list from the entity registry,
appends label_id if not already present, and writes the full list
back via WS config/entity_registry/update. Use when: tagging one entity with a label without disturbing labels
already on it.
Not for: removing a label — use labels_remove_label_from_entity.
Returns: dict with entity_id, the resulting labels list, the raw WS
result, and ok.
Errors: on a WS failure, returns {"entity_id": ..., "label_id": ..., "ok": false, "error": "<message>"}. |
| labels_remove_label_from_entityA | Remove a label from an entity, keeping its other labels. Reads the entity's current labels list from the entity registry,
drops label_id if present, and writes the remaining list back via WS
config/entity_registry/update. Use when: untagging one entity from a label without touching its other
labels.
Not for: deleting the label itself everywhere — use
labels_delete_label.
Returns: dict with entity_id, the resulting labels list, the raw WS
result, and ok.
Errors: on a WS failure, returns {"entity_id": ..., "label_id": ..., "ok": false, "error": "<message>"}. |
| labels_assign_label_to_deviceA | Assign a label to a device, keeping its existing labels. Reads the device's current labels list from the device registry,
appends label_id if not already present, and writes the full list
back via WS config/device_registry/update. Use when: tagging one device with a label without disturbing labels
already on it.
Not for: removing a label — use labels_remove_label_from_device.
Returns: dict with device_id, the resulting labels list, the raw WS
result, and ok.
Errors: on a WS failure, returns {"device_id": ..., "label_id": ..., "ok": false, "error": "<message>"}. |
| labels_remove_label_from_deviceA | Remove a label from a device, keeping its other labels. Reads the device's current labels list from the device registry,
drops label_id if present, and writes the remaining list back via WS
config/device_registry/update. Use when: untagging one device from a label without touching its other
labels.
Not for: deleting the label itself everywhere — use
labels_delete_label.
Returns: dict with device_id, the resulting labels list, the raw WS
result, and ok.
Errors: on a WS failure, returns {"device_id": ..., "label_id": ..., "ok": false, "error": "<message>"}. |
| labels_list_entities_with_labelA | List entities that currently have a given label assigned. Reads the entity registry over WebSocket and keeps rows whose labels
list contains label_id. Use when: finding everything tagged with one label, e.g. before a bulk
action.
Returns: list of entity registry dicts that have the label.
Errors: on a WS failure, returns [{"error": "<message>"}] instead of
raising. |
| labels_list_devices_with_labelA | List devices that currently have a given label assigned. Reads the device registry over WebSocket and keeps rows whose labels
list contains label_id. Use when: finding everything tagged with one label, e.g. before a bulk
action.
Returns: list of device registry dicts that have the label.
Errors: on a WS failure, returns [{"error": "<message>"}] instead of
raising. |
| labels_list_categoriesA | List categories defined for a given registry scope. Calls WS config/category_registry/list with scope and returns the
result unfiltered; returns an empty list if the WS response is not a
list. Use when: you need category IDs for one scope, e.g. before tagging
automations.
Returns: list of category registry dicts (category_id, name, icon) for
the given scope.
Errors: on a WS failure, returns [{"error": "<message>"}] instead of
raising. |
| labels_create_categoryA | Create a category within a registry scope. Calls WS config/category_registry/create with scope and name,
plus icon if given; Home Assistant assigns a new category_id, so
calling this twice with the same name creates two separate categories. Use when: you need a new category to group items within one scope, e.g.
automations.
Returns: the created category registry dict.
Errors: on a WS failure, returns {"error": "<message>"} instead of
raising. |
| labels_update_categoryA | Update fields on an existing category. Calls WS config/category_registry/update; only the parameters you
pass are sent, so omitted fields keep their current value. Use when: renaming a category or changing its icon within its scope.
Returns: the updated category registry dict.
Errors: on a WS failure, returns {"error": "<message>"} instead of
raising. |
| labels_delete_categoryA | Delete a category from a registry scope. Calls WS config/category_registry/delete with scope and
category_id and returns Home Assistant's result unchanged. Use when: a category is no longer needed within its scope.
Returns: dict with scope, category_id, the raw WS result, and
ok.
Errors: on a WS failure, returns {"scope": ..., "category_id": ..., "ok": false, "error": "<message>"}. |
| search_search_entitiesA | Fuzzy-rank entities by entity_id, friendly_name and device_id. Scores every entity against query with substring match (score 1.0)
or a sequence-similarity ratio, keeps only scores above 0, and returns
the top limit matches sorted descending. Use when: you don't know the exact entity_id and want a ranked guess
from a name fragment.
Returns: list of dicts (entity_id, friendly_name, state, device_id,
score) up to limit entries.
Limits: entities that score exactly 0 are dropped entirely, not just
deprioritised. |
| search_search_devicesA | Fuzzy-rank devices by name, name_by_user, manufacturer and model. Scores every device from the device registry against query, keeps
only scores above 0, and returns the top limit matches sorted
descending. Use when: you don't know a device's exact id and want a ranked guess
from a name fragment.
Not for: an exact, unranked device list — use devices_list_devices,
areas_list_devices or devices_list_devices_in_area.
Returns: list of dicts (id, name, name_by_user, manufacturer, model,
area_id, score) up to limit entries.
Limits: devices that score exactly 0 are dropped entirely; a WS
failure yields an empty list rather than an error. |
| search_search_areasA | Fuzzy-rank areas by name. Scores every area from the area registry against query, keeps only
scores above 0, and returns the top limit matches sorted descending. Use when: you don't know an area's exact id and want a ranked guess
from a name fragment.
Not for: an exact, unranked area list — use areas_list_areas.
Returns: list of dicts (area_id, name, floor_id, icon, score) up to
limit entries.
Limits: areas that score exactly 0 are dropped entirely; a WS failure
yields an empty list rather than an error. |
| search_deep_searchA | Fuzzy-search entities, devices and areas together in one ranked list. Scores states (tagging automation.* entities as kind 'automation',
others as 'entity'), devices and areas against query the same way as
the single-kind search tools, merges all matches, and returns the top
limit sorted descending. Use when: you don't know whether what you're looking for is an entity,
device or area.
Not for: results scoped to one kind — use search_search_entities,
search_search_devices or search_search_areas.
Returns: list of dicts tagged with kind ('entity'/'automation'/
'device'/'area'), each with kind-specific fields plus score, up to
limit entries. |
| search_find_relatedA | Return an entity's device, area, floor and sibling entities. Looks up entity_id in the entity registry, resolves its device
(falling back to the device's area if the entity itself has none) and
area/floor, then collects other entities on the same device and other
entities/devices in the same area. Use when: exploring what else is connected to one entity before
changing or troubleshooting it.
Returns: dict with entity_id, device_id, area_id, floor_id, device,
area, same_device_entities, same_area_entities.
Errors: {"entity_id": ..., "error": "entity not found in registry"}
if the entity isn't in the registry, or {"entity_id": ..., "error": "<message>"} on a WS failure. |
| search_find_unused_entitiesA | Heuristically list entities that look unused or orphaned. Flags entities whose state has been 'unavailable' or 'unknown' for
more than 7 days (or has no last_changed at all), plus any
entity-registry entries with no device_id — which normally means
helpers, automations and template entities, not proof of disuse. Use when: hunting for cleanup candidates, always reviewing each result
before deleting anything.
Returns: list of dicts (entity_id, state, last_changed, device_id,
reasons) — reasons explains which heuristic(s) matched.
Limits: purely heuristic; the 7-day unavailability threshold and a
missing device_id are weak signals, not confirmation that an entity is
truly unused. |
| search_find_orphan_devicesA | List devices with no entities associated with them in the entity registry. Compares every device's id against the set of device_id values
referenced by entity-registry entries and returns devices that no
entity points to. Use when: hunting for device-registry entries that may be safe to
remove, always reviewing each result first.
Returns: list of dicts (id, name, name_by_user, manufacturer, model,
area_id, config_entries) for devices with no referencing entity.
Limits: a WS failure on either registry silently yields an empty
underlying list rather than an error, which can under-report orphans. |
| integrations_list_flow_handlersA | List every integration domain that supports a config flow. Calls GET /api/config/config_entries/flow_handlers over HTTP for the
domains HA can set up through the UI-style flow (as opposed to
YAML-only integrations). Use when: checking whether a domain can be installed via
integrations_start_config_flow before attempting it.
Not for: domains already configured — use system_list_integrations.
Returns: list of domain strings, e.g. ["shelly", "hue", ...].
Errors: raises httpx.HTTPStatusError if the HA API request fails. |
| integrations_list_flows_in_progressA | List config flows that were started but not yet finished. Calls the config_entries/flow/progress WebSocket command. Use when: finding a flow_id left over from an earlier
integrations_start_config_flow call, e.g. one waiting on discovery.
Not for: flows already completed into a config entry — use
system_list_integrations.
Returns: list of in-progress flow dicts (flow_id, handler,
step_id, context, and related fields).
Errors: raises RuntimeError if the underlying WebSocket call fails
(e.g. auth or WS-level error). |
| integrations_start_config_flowA | Start a new config flow for an integration domain. Calls POST /api/config/config_entries/flow with {"handler": handler, "show_advanced_options": show_advanced_options}; HA has no
WebSocket command for this. Each call creates a new, distinct flow. Use when: beginning to set up a new integration through the same
step-by-step flow the HA UI uses.
Not for: editing an already-configured entry — use
integrations_start_options_flow.
Returns: the first step: {flow_id, step_id, data_schema, errors, ...}. Pass flow_id into integrations_submit_config_flow_step with
the user's answers.
Errors: raises httpx.HTTPStatusError if handler is not a valid
flow-handler domain. |
| integrations_submit_config_flow_stepA | Submit user input for the current step of a config flow. Calls POST /api/config/config_entries/flow/{flow_id} with
user_input. What this does depends entirely on the integration domain
driving the flow: it may just advance to the next form, or it may
validate credentials against the integration's own device/cloud service
and create or overwrite a real config entry that HA loads. HA does not
signal in advance which step is the last one, so any submitted step —
not only a visibly "final" one — can be the one that creates the entry. Use when: providing the values a config-flow step asked for.
Not for: reading the current step without submitting anything — use
integrations_get_config_flow; cancelling a flow before it finishes —
use integrations_abort_config_flow.
Returns: the next step (form), a step with errors, or the finished
config entry. The returned step's last_step field is True only
when the integration explicitly declares this is the final step, and
None otherwise — most integrations leave it None even on their
actual last step, so None does not mean more steps remain.
Errors: raises httpx.HTTPStatusError if flow_id is unknown or
expired.
Limits: the integration handling this domain may reach an external
device or cloud service while validating user_input; a config entry
can be created without warning on any step. |
| integrations_abort_config_flowA | Abort a config flow that has not been finished yet. Calls DELETE /api/config/config_entries/flow/{flow_id}. Nothing was
persisted by an unfinished flow, so this discards only the flow's
in-progress state, not a config entry. Use when: cancelling a setup that was started by mistake or is no
longer wanted.
Not for: removing a completed integration — use
integrations_remove_integration.
Returns: HA's abort response for the flow.
Errors: raises httpx.HTTPStatusError if flow_id is unknown or
already finished. |
| integrations_get_config_flowA | Get the current state of a config flow without advancing it. Calls GET /api/config/config_entries/flow/{flow_id}. Use when: checking a flow's current step/schema again, e.g. after
losing the earlier response.
Not for: providing the step's answers — use
integrations_submit_config_flow_step.
Returns: the flow's current step payload, same shape as
integrations_start_config_flow's result.
Errors: raises httpx.HTTPStatusError if flow_id is unknown or
expired. |
| integrations_remove_integrationA | Remove (uninstall) an integration's config entry after an explicit confirmation. Calls DELETE /api/config/config_entries/entry/{entry_id} — there is no
config_entries/remove WebSocket command. HA unloads the integration
and deletes its entry; any devices/entities it owned typically go with
it. Without confirm=True nothing is removed. Use when: an integration is no longer wanted and should be fully
uninstalled, not just disabled.
Not for: keeping the entry but pausing it — use
integrations_disable_integration.
Returns: HA's removal result when confirmed, otherwise a confirmation
prompt.
Errors: returns {"error": "confirmation_required", "message": ..., "action": ...} when confirm is false; raises
httpx.HTTPStatusError if entry_id does not exist.
Limits: requires confirm=True; deletes the entry and its
devices/entities with no separate backup step. |
| integrations_disable_integrationA | Disable an integration's config entry without removing it. Calls the config_entries/disable WebSocket command with
disabled_by="user". The entry and its devices/entities stay
registered but stop loading until re-enabled. Use when: pausing an integration temporarily while keeping its
configuration and registry entries intact.
Not for: permanently deleting the entry — use
integrations_remove_integration; to bring it back — use
integrations_enable_integration.
Returns: the config_entries/disable result.
Errors: raises RuntimeError if the underlying WebSocket call fails
(e.g. entry_id unknown). |
| integrations_enable_integrationA | Re-enable a previously disabled integration's config entry. Calls the config_entries/disable WebSocket command with
disabled_by=None, which HA treats as clearing the disabled state. Use when: bringing back an integration disabled via
integrations_disable_integration.
Not for: setting up a brand-new integration — use
integrations_start_config_flow.
Returns: the config_entries/disable result.
Errors: raises RuntimeError if the underlying WebSocket call fails
(e.g. entry_id unknown). |
| integrations_start_options_flowA | Start the options flow for an existing config entry. Calls POST /api/config/config_entries/options/flow, passing
entry_id as handler — HA's options-flow API reuses the config-flow
request shape and documents handler as "the entry_id" in this
context. Each call creates a new, distinct flow. Use when: changing an already-configured integration's settings through
its own options UI/schema.
Not for: configuring a brand-new integration — use
integrations_start_config_flow.
Returns: the first step: {flow_id, step_id, data_schema, errors, ...}. Pass flow_id into integrations_submit_options_flow_step.
Errors: raises httpx.HTTPStatusError if entry_id does not exist or
the integration has no options flow. |
| integrations_submit_options_flow_stepA | Submit a step of an options flow. Calls POST /api/config/config_entries/options/flow/{flow_id} with
user_input. What this does depends entirely on the integration
domain: an intermediate step just advances the form, while the step
that finishes the flow applies the new options to the existing config
entry, replacing its previous options. HA does not signal in advance
which step is the last one, so any submitted step — not only a
visibly "final" one — can be the one that overwrites the options. Use when: providing the values an options-flow step asked for.
Not for: reading the current step without submitting — there is no
separate "get options flow" tool; call
integrations_start_options_flow again to restart it; cancelling a
flow before it finishes — use integrations_abort_options_flow.
Returns: the next step (form), a step with errors, or the entry's
updated result. The returned step's last_step field is True only
when the integration explicitly declares this is the final step, and
None otherwise — most integrations leave it None even on their
actual last step, so None does not mean more steps remain.
Errors: raises httpx.HTTPStatusError if flow_id is unknown or
expired.
Limits: any submitted step, not only a visibly "final" one, may
overwrite the entry's previous options; the integration may reach an
external device or cloud service while validating the submitted
values. |
| integrations_abort_options_flowA | Abort an options flow that has not been finished yet. Calls DELETE /api/config/config_entries/options/flow/{flow_id}. The
entry's existing options are untouched, since nothing was applied by an
unfinished flow. Use when: cancelling an options edit started by mistake or no longer
wanted.
Not for: cancelling a new-integration setup flow instead — use
integrations_abort_config_flow.
Returns: HA's abort response for the flow.
Errors: raises httpx.HTTPStatusError if flow_id is unknown or
already finished. |
| integrations_update_integration_entryA | Update selected properties of an existing config entry. Calls the config_entries/update WebSocket command with only the
fields given here (title, pref_disable_new_entities,
pref_disable_polling) — omitted fields keep their previous stored
value, but any field that is given replaces the previous one, which is
then lost. Use when: renaming an integration's entry or changing its
entity-discovery/polling preferences without going through its options
flow.
Not for: settings specific to the integration itself (its actual
options schema) — use integrations_start_options_flow.
Returns: the config_entries/update result.
Errors: raises RuntimeError if the underlying WebSocket call fails
(e.g. entry_id unknown). |
| voice_list_pipelinesA | List all Assist pipelines plus the preferred pipeline id. Calls WS assist_pipeline/pipeline/list and returns its payload
unchanged. Use when: you need every configured pipeline, e.g. to pick one for
voice_set_preferred_pipeline or before editing one with
voice_update_pipeline.
Not for: a single pipeline's full detail — use voice_get_pipeline.
Returns: {"pipelines": [...], "preferred_pipeline": "<id>"}. |
| voice_get_pipelineA | Get a single Assist pipeline by id, or the preferred one if omitted. Calls WS assist_pipeline/pipeline/get, passing pipeline_id only when
given. Use when: you need one pipeline's full configuration (engines,
languages) rather than the whole list.
Not for: every pipeline at once — use voice_list_pipelines.
Returns: dict with the pipeline's engine/language fields, as returned by
HA. |
| voice_create_pipelineA | Create a new Assist pipeline via WS assist_pipeline/pipeline/create. Every parameter is forwarded as-is to HA; engine parameters are entity
IDs of the relevant provider (stt.*, tts.*, wake_word.*) rather
than free-form names. Calling this twice with the same name creates
two separate pipelines with distinct IDs, since HA assigns a new ID each
time. Use when: setting up a new voice pipeline with a specific combination of
conversation/STT/TTS/wake-word engines.
Not for: changing an existing pipeline — use voice_update_pipeline.
Returns: the created pipeline dict, as returned by HA (includes its new
id).
Limits: engine parameters must already be installed entity IDs; discover
them with voice_list_stt_engines, voice_list_tts_engines,
voice_list_wake_word_engines and voice_list_conversation_agents
first. |
| voice_update_pipelineA | Update an existing Assist pipeline's fields via WS assist_pipeline/pipeline/update. HA's WS API requires the full set of fields on every update call, so
this first fetches the current pipeline with WS
assist_pipeline/pipeline/get and fills in any parameter left as
None from that current state before sending the update — only the
parameters you actually pass are changed; the previous value of any
field you omit is lost from this call's perspective and replaced by
whatever assist_pipeline/pipeline/get returned for it. Use when: changing one or more fields of an existing pipeline.
Not for: creating a new pipeline — use voice_create_pipeline.
Returns: the updated pipeline dict, as returned by HA. |
| voice_delete_pipelineA | Delete an Assist pipeline via WS assist_pipeline/pipeline/delete. HA rejects deleting the pipeline currently marked preferred — call
voice_set_preferred_pipeline with a different id first in that case. Use when: permanently removing a pipeline that is no longer needed.
Not for: the preferred pipeline without switching preference first, and
not for temporarily disabling a pipeline (HA has no such state).
Returns: HA's WS response for assist_pipeline/pipeline/delete
(typically empty on success). |
| voice_set_preferred_pipelineA | Set the default Assist pipeline, used when no pipeline is specified. Calls WS assist_pipeline/pipeline/set_preferred. Use when: changing which pipeline Assist uses by default.
Not for: reading the current preference — use voice_list_pipelines,
whose response includes preferred_pipeline.
Returns: HA's WS response for assist_pipeline/pipeline/set_preferred
(typically empty on success). |
| voice_list_stt_enginesA | List installed speech-to-text engines as their stt.* entities. Filters ha.get_states() for entity IDs starting with stt.. Use when: discovering which STT engine entity ID to pass to
voice_create_pipeline/voice_update_pipeline.
Not for: TTS or wake-word engines — use voice_list_tts_engines/
voice_list_wake_word_engines.
Returns: list of {"entity_id", "state", "attributes"} for each stt.*
entity. |
| voice_list_tts_enginesA | List installed text-to-speech engines as their tts.* entities. Filters ha.get_states() for entity IDs starting with tts.. Use when: discovering which TTS engine entity ID to pass to
voice_create_pipeline/voice_update_pipeline.
Not for: STT or wake-word engines — use voice_list_stt_engines/
voice_list_wake_word_engines.
Returns: list of {"entity_id", "state", "attributes"} for each tts.*
entity. |
| voice_list_wake_word_enginesA | List installed wake-word detection engines as their wake_word.* entities. Filters ha.get_states() for entity IDs starting with wake_word.. Use when: discovering which wake-word entity ID to pass to
voice_create_pipeline/voice_update_pipeline.
Not for: STT or TTS engines — use voice_list_stt_engines/
voice_list_tts_engines.
Returns: list of {"entity_id", "state", "attributes"} for each
wake_word.* entity. |
| voice_list_conversation_agentsA | List conversation agents available for a pipeline's conversation step. Calls WS conversation/agent/list and returns its payload unchanged. Use when: discovering which conversation_engine value to pass to
voice_create_pipeline/voice_update_pipeline.
Not for: STT/TTS/wake-word engines — use voice_list_stt_engines/
voice_list_tts_engines/voice_list_wake_word_engines.
Returns: dict as returned by HA's conversation/agent/list WS command. |
| themes_list_themesA | List all Lovelace themes registered with the frontend. Calls WS frontend/get_themes and returns Home Assistant's response
unchanged. Use when: you need every theme's name plus which one is active before
switching or editing.
Returns: dict with themes (name to variable-map), default_theme,
and default_dark_theme. |
| themes_get_themeA | Get one theme's CSS variable map by name. Calls WS frontend/get_themes and looks up name in the result. Use when: inspecting a single theme's variables rather than the whole
registry from themes_list_themes.
Returns: dict with name and variables (the CSS variable map).
Errors: {"error": "Theme '<name>' not found", "available": [...]} if
the name isn't registered. |
| themes_set_active_themeA | Set the active Lovelace frontend theme. Calls service frontend.set_theme with name, and mode when it is
'light' or 'dark'; any other mode value is silently omitted from the
call. Use when: switching which theme the frontend displays.
Returns: the raw result of the frontend.set_theme service call.
Limits: mode values other than 'light'/'dark' are dropped rather than
rejected. |
| themes_reload_themesA | Reload theme files from the themes directory. Calls service frontend.reload_themes, making Home Assistant re-read
every YAML file under <config>/themes/. Use when: after themes_create_theme, themes_update_theme or
themes_delete_theme writes a file with reload=False, or after
editing a theme file outside nexus.
Returns: dict with status: 'reloaded'. |
| themes_create_themeA | Create a new Lovelace theme file. Writes themes/<name>.yaml as {<name>: variables}. The file is only
loaded by the frontend if configuration.yaml has frontend: themes: !include_dir_merge_named themes. Fails instead of overwriting unless
overwrite=True. Use when: adding a brand-new theme.
Not for: changing an existing theme in place — use
themes_update_theme.
Returns: dict with success, path, and reloaded (present when
reload=True).
Errors: {"success": false, "error": "Theme '<name>' already exists. Pass overwrite=True to replace."} when the file exists and
overwrite is false; {"success": false, "error": "invalid_theme_name", "detail": ...} when name contains '/' or a
backslash, starts with '.', or is blank.
Limits: name must not contain '/' or a backslash, start with '.', or
be blank. |
| themes_update_themeA | Update an existing Lovelace theme file. With merge=True (default), shallow-merges the given variables into
the existing top-level keys — a passed modes key replaces the whole
modes block rather than merging inside it; with merge=False,
replaces the entire variable set. Fails if the theme file doesn't
exist yet. Use when: changing some or all variables on a theme that already
exists.
Not for: a theme that doesn't exist yet — use themes_create_theme.
Returns: dict with success, path, merged, and reloaded (present
when reload=True).
Errors: {"success": false, "error": "Theme '<name>' not found at <path>"} when the file doesn't exist; {"success": false, "error": "invalid_theme_name", "detail": ...} when name contains '/' or a
backslash, starts with '.', or is blank. |
| themes_delete_themeA | Delete a theme file. Removes themes/<name>.yaml from disk if it exists. Use when: a theme is no longer needed.
Returns: dict with success and deleted (the removed path), plus
reloaded when reload=True.
Errors: {"success": false, "error": "Theme '<name>' not found at <path>"} when the file doesn't exist; {"success": false, "error": "invalid_theme_name", "detail": ...} when name contains '/' or a
backslash, starts with '.', or is blank. |
| themes_list_theme_filesA | List YAML theme files present on disk under themes/. Scans <config>/themes/ recursively for .yaml/.yml files,
returning their paths relative to the config directory; returns an
empty list if the directory doesn't exist yet. Use when: a theme exists on disk but isn't showing up in
themes_list_themes (not yet loaded).
Returns: list of file paths relative to the Home Assistant config
directory. |
| card_builder_list_cardsA | List every Card Builder card stored on this Home Assistant instance. Calls the card_builder/cards/list WebSocket command and returns the
raw collection: each entry carries id, name, description,
config (the DocumentData block tree), version, tags and
categories. Use when: discovering existing cards before reading one in full with
card_builder_get_card or editing one with card_builder_update_card.
Returns: list of card dicts, in storage order, unfiltered. |
| card_builder_get_cardA | Get one Card Builder card by id, including its full config. Fetches the whole card collection via card_builder/cards/list and
matches on id or the legacy card_id field client-side — there is no
dedicated get-by-id WebSocket command. Use when: inspecting or copying one card's config before calling
card_builder_update_card or card_builder_renderer_card_config.
Returns: the matching card dict (same shape as one entry from
card_builder_list_cards).
Errors: {"error": "not_found", "card_id": ...} when no card matches. |
| card_builder_create_cardA | Create a new Card Builder card from a DocumentData config. Sends config and the metadata fields to card_builder/cards/create,
which assigns a new id server-side (confirmed in upstream storage.py:
every create path generates a fresh uuid4) — repeating this call with
identical arguments creates a second, distinct card rather than
updating the first. Use when: saving a card built with card_builder_build_from_recipe or
card_builder_make_template_card's underlying recipe.
Not for: changing an existing card — use card_builder_update_card.
Returns: the created card dict, including its new id.
Limits: run card_builder_validate_config on config first; this tool
does not validate the block tree before sending it. |
| card_builder_update_cardA | Update fields of an existing Card Builder card. Sends only the parameters that are not omitted to
card_builder/cards/update; every omitted parameter's prior value in
storage is left untouched, but any parameter that is supplied
(including config) fully replaces the previous value for that field
with no way to recover it afterwards. Use when: renaming a card, editing its config, or retagging it.
Not for: creating a new card — use card_builder_create_card.
Returns: the updated card dict as returned by the WebSocket command. |
| card_builder_delete_cardA | Permanently delete one Card Builder card by id. Calls card_builder/cards/delete; Home Assistant's WebSocket handler
returns an empty payload on success. Any dashboard still referencing
this card_id via custom:card-builder-renderer-card will show a
broken/empty card afterwards — this tool does not check for or update
such references. Use when: removing a card that is no longer used on any dashboard.
Returns: {"status": "deleted", "card_id": ..., "result": ...} on
success.
Errors: on failure, returns {"status": "error", "card_id": ..., "error": <exception text>} instead of raising. |
| card_builder_list_style_presetsA | List every reusable Card Builder style preset. Calls card_builder/style_presets/list and returns the raw
collection: each entry has id, name, description, data (the
CSS-style configuration blob) and, if present, extends_preset_id. Use when: picking an existing preset to extend, or checking presets
before creating a new one with card_builder_create_style_preset.
Returns: list of style-preset dicts, unfiltered. |
| card_builder_create_style_presetA | Create a new reusable Card Builder style preset. Sends data and the metadata fields to card_builder/style_presets/create,
which assigns a new id server-side (confirmed in upstream storage.py:
every create path generates a fresh uuid4) — repeating this call
creates a second, distinct preset rather than updating the first. Use when: packaging a reusable set of style properties (e.g. a card
theme) to apply across multiple cards.
Not for: changing an existing preset — use
card_builder_update_style_preset.
Returns: the created style-preset dict, including its new id. |
| card_builder_update_style_presetA | Update fields of an existing Card Builder style preset. Sends only the parameters that are not omitted to
card_builder/style_presets/update; any parameter that is supplied
(including data) fully replaces the previous value for that field,
with no way to recover the prior value afterwards. Use when: adjusting an existing preset's style data or metadata.
Not for: creating a new preset — use
card_builder_create_style_preset.
Returns: the updated style-preset dict as returned by the WebSocket
command. |
| card_builder_delete_style_presetA | Permanently delete one Card Builder style preset by id. Calls card_builder/style_presets/delete. Any card whose style data
references this preset via extends_preset_id keeps that dangling id —
this tool does not check for or update such references. Use when: removing a preset that is no longer extended by any card or
other preset.
Returns: {"status": "deleted", "style_preset_id": ..., "result": ...}
on success.
Errors: on failure, returns {"status": "error", "style_preset_id": ..., "error": <exception text>} instead of raising. |
| card_builder_list_css_custom_propertiesA | List every registered CSS custom property (@property registration). Calls card_builder/css_custom_properties/list and returns the raw
collection: each entry has id, name, syntax (e.g. <color>),
initial_value and inherits. Use when: checking which custom properties already exist before
registering a new one with
card_builder_create_css_custom_property.
Returns: list of CSS-custom-property dicts, unfiltered. |
| card_builder_create_css_custom_propertyA | Register a new CSS custom property (@property) for use in card styles. Sends the four fields to card_builder/css_custom_properties/create,
which assigns a new id server-side (confirmed in upstream
storage.py: every create path generates a fresh uuid4) — repeating
this call registers a second, distinct property rather than updating
the first. Use when: defining an animatable/typed CSS variable (e.g. a themeable
accent color) that card styles can reference by name.
Returns: the created CSS-custom-property dict, including its new id. |
| card_builder_delete_css_custom_propertyA | Permanently delete one registered CSS custom property by id. Calls card_builder/css_custom_properties/delete. Any card style
still referencing this property's name keeps that reference — the
browser falls back to an unset CSS variable — this tool does not check
for or update such references. Use when: removing a custom property that is no longer used by any
card style.
Returns: {"status": "deleted", "custom_property_id": ..., "result": ...} on success.
Errors: on failure, returns {"status": "error", "custom_property_id": ..., "error": <exception text>} instead of raising. |
| card_builder_list_mediaA | List files and folders in the Card Builder media directory. Calls card_builder/media/list, scoped to www/card_builder/<path>. Use when: checking what's already uploaded before calling
card_builder_upload_media or card_builder_delete_media.
Returns: dict with the media-browser entries HA's WS handler returns
for that path (files and sub-folders). |
| card_builder_upload_mediaA | Upload base64-encoded bytes as a file in the Card Builder media directory. Decodes content_base64 and writes it under www/card_builder/<path>/ <filename> via card_builder/media/upload. filename must be a bare
name (no /, \, or ..) with an allowed extension — .png,
.jpg, .jpeg, .gif, .webp, .svg, .avif (case-insensitive). A
.svg filename gets its decoded content sanitized (script/handler/
unsafe-URL stripping, element-count cap) — see sanitize_svg. The
file becomes **public** under /local/ with **no authentication**,
same origin as the HA frontend. Upstream's _write_media_file writes
with no existence check, so uploading onto an existing filename/
path silently overwrites it, with no backup. Use when: the file bytes are already in memory (e.g. generated inline).
Not for: a file already on the HA config filesystem — use
card_builder_upload_media_from_path; a remote image — use
card_builder_upload_image_from_url; raw SVG you'd rather not
base64-encode — use card_builder_upload_svg.
Returns: {reference, path, url} — reference is the
cb-media://local/card_builder/<filename> URI for a block-image's
mediaReference prop.
Errors: {"error": "extension_not_allowed" | "invalid_base64" | "file_too_large" | "invalid_svg" | ...} (plus sanitize_svg errors)
when validation or sanitization rejects the input.
Limits: decoded content over _MAX_MEDIA_UPLOAD_BYTES (15 MiB) is
refused. |
| card_builder_upload_media_from_pathA | Read a local file under the HA config directory and upload it as Card Builder media. local_path must resolve (after following symlinks) under <config>/www
or <config>/media, and have an image/SVG extension — see
_ALLOWED_MEDIA_EXTENSIONS. Anything else (e.g. secrets.yaml,
/data/options.json, a sibling directory) is refused before the file is
read. .svg files are sanitized (script/event-handler/unsafe-URL
stripping) before upload — see sanitize_svg. The uploaded file
becomes public under Home Assistant's /local/ path with no
authentication. Upstream's _write_media_file writes with no
existence check, so uploading onto a path/filename that already
holds a file silently overwrites it, with no backup.
Use when: re-publishing a file that already exists on the config
filesystem (e.g. under www/) into the Card Builder media library.
Not for: bytes already in memory — use card_builder_upload_media; a
remote URL — use card_builder_upload_image_from_url.
Returns: {reference, path, url} on success, same shape as
card_builder_upload_media.
Errors: {"error": "invalid_path" | "path_not_allowed" | "extension_not_allowed" | "file_not_found" | "invalid_svg" | ...}
(plus the sanitize_svg errors) when the source path is outside the
allowed roots, has a disallowed extension, doesn't exist, or fails
sanitization. |
| card_builder_upload_svgA | Sanitize SVG markup and upload it to the Card Builder media directory. svg_content must start with <svg or <?xml. .svg is appended to
filename if missing; the result is stored under
www/card_builder/<path>/<filename>. svg_content is always
sanitized first: <script>, <style>, <foreignObject>, <iframe>,
<embed>, <object> and other non-presentation elements are stripped
with their subtree, along with every on*= handler and any
href/xlink:href pointing at javascript: or an external/
data:image/svg+xml URL — see sanitize_svg for the allowlist. This
matters because the file becomes public, unauthenticated, under
/local/, where an unsanitized SVG opened directly executes embedded
script as stored XSS into an admin session. _write_media_file writes
with no existence check, so uploading onto an existing path/
filename silently overwrites it, with no backup.
Use when: publishing generated or hand-written SVG markup as media.
Not for: an SVG file on disk — use
card_builder_upload_media_from_path; a remote SVG URL — use
card_builder_upload_image_from_url.
Returns: {reference, path, url} — reference is the
cb-media://local/card_builder/<filename> URI for a block-image's
mediaReference prop.
Errors: {"error": "not_svg" | "file_too_large" | "path_not_allowed" | "svg_too_complex"} on invalid, unsafe, or oversized input.
Limits: capped at _MAX_MEDIA_UPLOAD_BYTES (15 MiB), then
_SVG_MAX_ELEMENTS elements after parsing. |
| card_builder_upload_image_from_urlA | Download an image from an http(s) URL and upload it to the Card Builder media library. Only http/https schemes are accepted. The response must declare an
image/* Content-Type (covers image/svg+xml) and stay within
_MAX_URL_IMAGE_BYTES, else nothing is uploaded. image/svg+xml is
sanitized (see sanitize_svg) regardless of filename, since the
remote server controls the bytes. The file becomes public under
/local/ with no authentication, and an existing path/
filename is silently overwritten. The URL and every redirect hop are resolved and rejected on a
loopback, link-local, unspecified, multicast or other reserved
address (incl. ::ffff:127.0.0.1) — host_network: true means
127.0.0.1/localhost here can reach host services that trust it as
a local peer. Private LAN ranges stay allowed (e.g. a camera snapshot
on your own network). Use when: mirroring a remote image into the media library.
Not for: bytes already in memory — use card_builder_upload_media; a
file on disk — use card_builder_upload_media_from_path.
Returns: {reference, path, url}.
Errors: {"error": "scheme_not_allowed" | "target_not_allowed" | "dns_resolution_failed" | "too_many_redirects" | "content_type_not_allowed" | "file_too_large" | "download_failed" | "invalid_svg" | ...}.
Limits: 30-second timeout, _MAX_URL_IMAGE_BYTES (15 MiB) cap, up to
_MAX_URL_REDIRECTS (5) redirects, each re-validated. |
| card_builder_delete_mediaA | Permanently delete one file from the Card Builder media directory. Calls card_builder/media/delete with path relative to
www/card_builder/. Any card whose mediaReference points at this
file (e.g. via block-image or block-weather-background) will fail
to load it afterwards — this tool does not check for or update such
references. Use when: removing an uploaded image/SVG that no card uses anymore.
Returns: {"status": "deleted", "path": ..., "result": ...} on
success.
Errors: on failure, returns {"status": "error", "path": ..., "error": <exception text>} instead of raising. |
| card_builder_renderer_card_configA | Build the Lovelace card config dict that renders a Card Builder card. Pure computation — assembles
{"type": "custom:card-builder-renderer-card", "card_id": ...} plus
the optional slot_entities/slot_actions keys; makes no call to
Home Assistant. Use when: embedding an existing Card Builder card on a dashboard.
Not for: adding the resulting config to a dashboard — pass it as
card_config to dashboards_add_card_to_section (sections views) or
dashboards_add_card_to_view (masonry/panel views).
Returns: {"type": "custom:card-builder-renderer-card", "card_id": ..., "slot_entities": {...}, "slot_actions": {...}} — the latter two
keys are omitted when not provided. |
| card_builder_list_block_typesA | List every block type from the embedded Card Builder schema (BLOCK_TYPES). Reads the module-level BLOCK_TYPES constant synced from upstream Card
Builder (see card_builder_check_schema_sync); makes no call to Home
Assistant. Use when: discovering which block types exist before writing a recipe
for card_builder_build_from_recipe.
Not for: full prop details of one type — use
card_builder_get_block_schema.
Returns: list of {type, category, label, accepts_children, requires_entity, prop_count}, one entry per block type. |
| card_builder_get_block_schemaA | Get the full embedded schema for one Card Builder block type. Looks up block_type in the module-level BLOCK_TYPES constant and
adds its style targets from STYLE_TARGETS; makes no call to Home
Assistant. Use when: checking a block's exact prop names, types, defaults, enum
values, and supported entity domains before writing a recipe.
Returns: {type, category, label, accepts_children, requires_entity, props, notes, supported_domains, style_targets, ...} — the same
entry as in BLOCK_TYPES plus style_targets.
Errors: {"error": "unknown_block_type", "block_type": ..., "known": [...]} when block_type isn't in the embedded schema. |
| card_builder_list_button_toggle_featuresA | List the feature IDs accepted by block-button-toggle / block-select-menu. Reads the module-level FEATURE_DEFINITIONS constant; makes no call
to Home Assistant. Feature IDs are namespaced by domain — e.g.
climate_hvac_mode for an AC, cover_state for a blind, light_power
for a bulb. Use when: picking an explicit feature value for a
block-button-toggle/block-select-menu prop instead of the default
"auto", which lets Card Builder pick the first available feature for
the entity at runtime.
Returns: list of {domain, id, label} dicts. |
| card_builder_list_style_categoriesA | List CSS style categories with their property names and unit conventions. Reads the module-level STYLE_CATEGORIES constant; makes no call to
Home Assistant. Property names are camelCase (e.g.
flexDirection, backgroundColor) — anything else is silently
discarded by Card Builder's CSS resolver. Use when: looking up the exact property names/units for a style
category before hand-writing a styles/dz_styles blob.
Not for: ready-to-use presets — use
card_builder_list_style_snippets.
Returns: list of {category, properties, length_units, legacy_aliases, notes} dicts. |
| card_builder_list_style_targetsA | List the style targets (sub-components) one block type supports. Looks up block_type in STYLE_TARGETS (defaulting to the single
"block" target); makes no call to Home Assistant. Example:
block-entity-field-state has state and unit targets so you can
colour the number and the unit differently. Use when: styling a sub-component of a block (e.g. a slider's thumb)
rather than the whole block.
Returns: {block_type, targets} where targets is the list of valid
keys for that block's styles dict.
Errors: {"error": "unknown_block_type", "block_type": ...} when
block_type isn't in the embedded schema. |
| card_builder_list_style_snippetsA | List built-in Card Builder style snippets by name and style category. Reads the module-level STYLE_SNIPPETS constant; makes no call to
Home Assistant. Use when: browsing ready-made style presets (padding, flex layout,
typography scale) before composing them with
card_builder_build_styles.
Not for: the full property list per category — use
card_builder_list_style_categories; the full body of one snippet —
use card_builder_get_style_snippet.
Returns: list of {name, categories} dicts, where categories are
the style-category keys that snippet sets. |
| card_builder_get_style_snippetA | Fetch one built-in style snippet wrapped in the full target/container envelope. Looks up name in STYLE_SNIPPETS and wraps it as
{target: {containers: {container: <snippet>}}}; makes no call to
Home Assistant. Use when: assigning exactly one snippet to a block's styles without
composing several via card_builder_build_styles.
Returns: {<target>: {containers: {<container>: <snippet>}}} — ready
to assign to a block's styles directly.
Errors: {"error": "unknown_snippet", "name": ..., "known": [...]}
when name isn't a known snippet. |
| card_builder_build_stylesA | Compose a styles object from one or more built-in snippets plus optional overrides. Merges each named entry from STYLE_SNIPPETS in order, then extra,
at the property level — later entries override earlier ones for the
same category/property; makes no call to Home Assistant. Use when: assembling a block's styles/dz_styles from reusable
presets instead of hand-writing the full envelope.
Returns: {<target>: {containers: {<container>: {<category>: {<prop>: <value>, ...}, ...}}}}.
Errors: {"error": "unknown_snippet", "name": ..., "known": [...]}
when a name in snippet_names isn't a known snippet. |
| card_builder_check_schema_syncA | Compare the embedded block schema against upstream Card Builder's main branch on GitHub. Fetches custom_components/card_builder/manifest.json and
frontend/src/common/blocks/loader.ts from
raw.githubusercontent.com/{UPSTREAM_REPO}/main over HTTP and diffs
the upstream version/block list against this module's BLOCK_TYPES
and UPSTREAM_SCHEMA_SYNC constants. Reaches outside the HA instance
and its host. Use when: a recipe that used to work stops producing the expected
card — the upstream integration may have shipped a breaking schema
change.
Returns: {status: "ok"|"drift"|"fetch_failed", upstream_version, embedded_version, version_matches, missing_block_types, extra_embedded_block_types, advice, embedded_schema, ...}.
Errors: {"status": "fetch_failed", "error": <exception text>, "embedded": ...} when the manifest request itself fails (a timeout or
network error); a failed loader fetch instead sets loader_fetch_error
and still returns status.
Limits: two GitHub requests with a 10-second timeout each. |
| card_builder_recipe_guideA | Get the embedded how-to for building Card Builder cards programmatically. Returns the static _RECIPE_GUIDE_MD constant; makes no call to Home
Assistant. Use when: starting a card build and needing the DocumentData shape,
prop-wrapping rules, slots, or recipe shorthand before calling
card_builder_build_from_recipe.
Not for: UX/visual guidance — use card_builder_design_principles.
Returns: markdown text covering DocumentData layout, the block tree,
entity inheritance, slots, drop-zones, dashboard embedding, and the
recipe shorthand consumed by card_builder_build_from_recipe. |
| card_builder_design_principlesA | Get the embedded UX design playbook for Card Builder cards. Returns the static _DESIGN_PRINCIPLES_MD constant; makes no call to
Home Assistant. Use when: deciding hierarchy, state feedback, spacing, typography, or
layout choices for a card, before or after using
card_builder_recipe_guide for the mechanics.
Not for: HOW to build the block tree itself — use
card_builder_recipe_guide.
Returns: markdown text covering hierarchy, state feedback via binding,
spacing rhythm, typography scale, semantic colors, layout choice
(grid vs flow vs absolute), state badges, background images, empty
states, and anti-patterns that produce flat-feeling cards. |
| card_builder_list_design_patternsA | List curated UX design patterns, each pairing a recipe recommendation with the reasoning behind it. Reads the module-level DESIGN_PATTERNS constant; makes no call to
Home Assistant. Use when: browsing available design patterns before picking one by
hand, rather than letting card_builder_design_for_intent score them.
Returns: list of pattern dicts, each with name, intent_keywords,
domains, label, description, ux_notes,
recommended_template, anti_patterns. |
| card_builder_get_design_patternA | Get one curated design pattern by name, in full. Looks up name in the module-level DESIGN_PATTERNS constant; makes
no call to Home Assistant. Use when: reading the full rationale/anti-patterns for one pattern
already picked (e.g. via card_builder_design_for_intent).
Returns: same fields as one entry from
card_builder_list_design_patterns.
Errors: {"error": "unknown_pattern", "name": ..., "known": [...]}
when name isn't a known pattern. |
| card_builder_design_for_intentA | Score curated design patterns against a free-text intent and recommend the top match. Scores each entry in DESIGN_PATTERNS by domain match (weight 5) and
intent-keyword overlap (weight 1.5 per hit against intent.lower()),
then returns the top scorer plus up to three runners-up; makes no
call to Home Assistant. Use when: turning a user's free-text card request into a concrete
pattern/template recommendation.
Not for: the full pattern body — call
card_builder_get_design_pattern(name) on the recommendation; the
underlying design rules — call card_builder_design_principles.
Returns: {intent, domain, entity_id, recommendation, score, label, description, ux_notes, recommended_template, anti_patterns, next_steps, alternatives}, or {..., "recommendation": None, "note": ...} when nothing scores above zero. |
| card_builder_build_from_recipeA | Materialise a recipe shorthand into a full DocumentData (config) dict. Builds a canvas root wrapping one block-container, recursively
turns recipe["blocks"] into the block tree via _build_block_tree
(auto-inserting block-drop-zone children for layout blocks and
auto-wrapping raw prop scalars in {"value": ...}), and returns the
assembled {version, rootId, slots, blocks} dict. Pure computation —
makes no call to Home Assistant. Use when: turning a recipe (hand-written or from
card_builder_get_card_template) into the config to pass to
card_builder_create_card/card_builder_update_card.
Not for: hand-crafted low-level DocumentData — assemble that directly
instead; a template-driven one-shot creation — use
card_builder_make_template_card.
Returns: a dict ready to pass as config to card_builder_create_card.
Errors: raises ValueError when recipe["root_slot"] isn't defined in
recipe["slots"], when a block in recipe["blocks"] has an unknown or
internal type, or when a non-container block type is given
children.
Limits: run card_builder_validate_config on the result before
saving — this tool does not validate the produced tree itself. |
| card_builder_validate_configA | Run lightweight structural validation on a Card Builder config (DocumentData). Checks version, rootId presence, that every block has a known
type, that parent/child links are mutually consistent, that
entity-required blocks resolve an entity provider (inherited, slot, or
fixed) by walking up the tree, and that prop values use the
{value: ...}/{binding: ...} wrapper Card Builder requires. Pure
computation — makes no call to Home Assistant and does not check
against the live upstream schema (see
card_builder_check_schema_sync for that). Use when: sanity-checking a config before
card_builder_create_card/card_builder_update_card.
Returns: {ok: bool, errors: [...], warnings: [...], block_count, slot_count} — ok is false only when errors is non-empty;
warnings flags renamed/unwrapped/unknown props without failing. |
| card_builder_list_card_templatesA | List built-in Card Builder recipe templates (CARD_RECIPES). Reads the module-level CARD_RECIPES constant; makes no call to Home
Assistant. Use when: browsing available templates before previewing one with
card_builder_get_card_template or instantiating it with
card_builder_make_template_card.
Returns: list of {name, label, description, domains} dicts. |
| card_builder_get_card_templateA | Resolve one built-in template into a full DocumentData config, without saving anything. Calls the template's recipe function and, if it returned a recipe
shorthand rather than a full DocumentData, runs it through
card_builder_build_from_recipe. Makes no call to Home Assistant. Use when: inspecting or hand-editing a template's config before
calling card_builder_create_card yourself.
Not for: saving the card directly — use
card_builder_make_template_card to skip this step.
Returns: the full DocumentData config dict for the template.
Errors: {"error": "unknown_template", "name": ..., "known": [...]}
when name isn't a known template. |
| card_builder_make_template_cardA | Resolve a built-in template and save it as a new Card Builder card in one call. Resolves template the same way as card_builder_get_card_template,
then passes the config straight to card_builder_create_card — which
assigns a new id server-side, so repeating this call creates a second,
distinct card. Use when: turning a built-in template into a saved card without the
separate preview/create steps.
Not for: previewing the config first without saving — use
card_builder_get_card_template; a fully custom recipe — use
card_builder_build_from_recipe and card_builder_create_card
directly.
Returns: the created card dict, including its new id. Use that id
with card_builder_renderer_card_config(card_id, slot_entities= {<slot>: ...}) to place the card on a dashboard.
Errors: {"error": "unknown_template", "template": ..., "known": [...]} when template isn't a known template. |
| snapshot_get_snapshotA | Return a single filtered snapshot combining HA states, registries and config. Reads live states via ha.get_states() and, depending on include, the
area/floor/device/entity registries and config entries over HTTP in one
call, applies domains/area_id filtering and limit/offset
pagination to the states list, and returns one dict keyed by section
name. Every call in this path is a read; nothing here writes to HA. Use when: a client needs several registries and/or states together and
should not spend several round-trips assembling that context.
Not for: a single registry without filtering — use entities_list_entities
or ws_get_states for a plain state list, or areas_list_devices/
devices_list_devices for a plain device list.
Returns: dict keyed by requested section (states, areas, floors,
devices, entities, integrations, config), plus _meta (echoed
filters and per-section counts) and _states_total (pre-pagination
count) when states is included.
Errors: {"error": "unknown_include", "unknown": [...], "valid": [...]}
when include names a section outside the valid set.
Limits: limit/offset paginate only the states section; every other
section is always returned in full. |
| snapshot_get_area_snapshotA | Return states, devices and entities for one area in a single call. Convenience wrapper that calls snapshot_get_snapshot with
include=["states", "devices", "entities", "areas"] and area_id fixed
to the given area; it adds no filtering beyond summary. Use when: exploring or controlling everything in one physical area
without composing snapshot_get_snapshot's include/area_id
arguments by hand.
Not for: a snapshot spanning several areas or other sections — call
snapshot_get_snapshot directly; entity registry rows without state
values — use areas_get_area_entities; live state values without
registry context — use areas_get_area_states.
Returns: same dict shape as snapshot_get_snapshot with
include=["states", "devices", "entities", "areas"].
Limits: no pagination; every state/device/entity in the area is
returned. |
| esphome_list_devicesA | List ESPHome devices from YAML configs, the HA device registry and online status. Combines <name>.yaml files under /config/esphome/ with matching HA
device-registry entries (identified via ESPHome config entries,
identifiers domain, or manufacturer as a fallback). A device's
connected status comes from its own entities' states (entity registry
device_id match): any entity in a state other than "unavailable"
means connected, since ESPHome entities share one per-config-entry
availability flag (homeassistant/components/esphome/entity.py) —
not from a binary_sensor.*_api_connection_status entity, which is not
guaranteed to exist. Use when: getting an overview of every ESPHome device, whether or not it
currently has a matching HA device.
Not for: one device's entities — use esphome_get_device_entities.
Returns: {"yaml_configs": [...], "ha_devices": [...], "online": <int>, "offline": <int>}, where each ha_devices entry's connected is True,
False, or None (no known entities/states yet).
Errors: ha_devices becomes [{"error": str(e)}] if reading the HA
device registry raises; entity-registry/config-entry/state lookups are
silently skipped (treated as empty) on error instead of failing the
whole call. |
| esphome_get_configA | Read one ESPHome device's YAML config from /config/esphome/. Resolves name to <name>.yaml under _ESPHOME_DIR, rejecting path
separators/leading dots/paths that escape that directory. Use when: inspecting a device's current configuration before editing it
with esphome_write_config or one of the esphome_lvgl_* editors.
Not for: a device's HA entities — use esphome_get_device_entities.
Returns: {"name": <filename>, "content": <yaml text>}.
Errors: {"error": "Invalid device name: ..."} for a path-escaping
name; {"error": "Not found: ...", "esphome_dir": ...} when the file
doesn't exist. |
| esphome_write_configA | Write a full ESPHome device YAML config to /config/esphome/, overwriting any existing file. Validates YAML syntax first (HA custom tags !secret/!include/
!lambda/!extend/!remove pass through unchanged) and only writes if
that succeeds. This replaces the whole file — there is no merge with
the previous content and, unlike git_safe_write_with_checkpoint, no
checkpoint commit is made first, so the previous content is not
recoverable through this tool. Use when: saving a complete device config you already have in full,
e.g. after fetching and editing it with esphome_get_config.
Not for: a git-checkpointed config write — use
git_safe_write_with_checkpoint; for a generic /config file write use
files_write_config_file; for a single LVGL widget edit use
esphome_lvgl_add_widget/esphome_lvgl_delete_widget instead of
hand-editing the whole YAML text.
Returns: {"success": True, "name": ..., "path": ..., "bytes": ...} on
success; a remote external_components:/packages: source
(github:///gitlab:///codeberg:///git:///http(s)://, or a dict
with a url) adds "warning" (review before esphome_compile_device,
which fetches and runs it) and "external_sources": [...]; a config
with none, or only local (type: local, bare-path, !include) ones,
gets neither key.
Errors: {"success": False, "error": "YAML validation failed: ..."} for
invalid YAML; {"success": False, "error": "Invalid device name: ..."}
for a path-escaping name. |
| esphome_get_device_entitiesA | Get every HA entity belonging to one ESPHome device. Slugifies device_name (lowercase, spaces/dashes to underscores) and, if
a device-registry entry's own slugified name matches, matches entities by
that device's device_id (precise: immune to one device's slug being a
substring of another's). Falls back to matching entity registry entries
whose platform is "esphome" and whose entity_id contains the slug
when no device-registry entry matches (or that lookup fails). Use when: inspecting a specific device's exposed entities and their
current state.
Not for: the device list itself — use esphome_list_devices.
Returns: list of {"entity_id", "name", "domain", "state", "attributes", "disabled"} dicts.
Errors: [{"error": str(e)}] when reading the entity registry or
states raises. |
| esphome_compile_deviceA | Compile ESPHome firmware for a device via the dashboard's /compile WebSocket route. Blocks until the compile process exits (~60-180s). Compatible with the
"ESPHome Device Builder" add-on (esphome/device-builder): /compile
keeps the same spawn wire protocol as the old dashboard, now backed by
its firmware job queue. A first build for a platform fetches PlatformIO
packages from the internet before compiling. only_generate=True is
rejected outright (see Errors) — Device Builder ignores that field and
always runs a full build (ADR-0004 D4); it stays in the signature only
for input-shape compatibility. Use when: building firmware before esphome_upload_device.
Not for: checking config validity only — use esphome_validate_config,
which is faster and skips package downloads.
Returns: {"device", "action": "compile", "exit_code", "success", "log_tail", "log_lines"}.
Errors: {"error": "esphome_unsupported_option", ...} for
only_generate=True (no I/O); {"error": "Invalid device name: ..."}
for a path-escaping or blocked (e.g. 'secrets') name; otherwise one of
esphome_dashboard.DashboardError's stable codes —
esphome_unreachable/esphome_auth_required add diagnosis (see
esphome_ping_dashboard); timeout adds log_tail/log_lines/
job_may_still_be_running (always True — do not retry, check
esphome_get_addon_logs); esphome_command_failed adds
dashboard_error_code/details.
Limits: blocks up to timeout seconds; log_lines truncates the log. |
| esphome_validate_configA | Validate an ESPHome device's YAML config without compiling it. Uses the devices/validate command on Device Builder's newer
multiplexed /ws protocol (github.com/esphome/device-builder,
docs/API.md) — the legacy /validate route from the old ESPHome
dashboard no longer exists. Unlike esphome_compile_device, this never
builds firmware or fetches PlatformIO packages. If the dashboard needs
a username/password, this fails fast instead of hanging (no credential
wiring exists here). Use when: checking a config's validity quickly, e.g. before
esphome_compile_device.
Not for: a full firmware build — use esphome_compile_device; not for
LVGL-only structural checks — use esphome_lvgl_validate, which runs
without the dashboard.
Returns: {"device", "action": "validate", "success", "result", "log_tail", "log_lines"}.
Errors: {"error": "Invalid device name: ..."} for a path-escaping or
blocked (e.g. 'secrets') name; otherwise one of
esphome_dashboard.DashboardError's stable codes —
esphome_auth_required (credentials this tool cannot supply) and
esphome_unreachable add diagnosis (see esphome_ping_dashboard);
timeout adds log_tail/log_lines/job_may_still_be_running
(always False — validation enqueues no job); esphome_command_failed
adds dashboard_error_code/details. |
| esphome_upload_deviceA | Flash previously compiled firmware to an ESPHome device via the dashboard's /upload WebSocket route. Requires the device to already be built (esphome_compile_device) and,
for OTA, reachable with a matching OTA password. Without confirm=True
returns a confirmation prompt and performs no I/O (ADR-0004 D5) — this
overwrites the running firmware with no automatic rollback if broken.
Same "ESPHome Device Builder" (esphome/device-builder) spawn wire
protocol as esphome_compile_device, on /upload. Use when: deploying a compiled build to the device, once confirmed.
Not for: building the firmware — use esphome_compile_device first.
Returns: {"device", "action": "upload", "exit_code", "success", "log_tail", "log_lines"} on completion.
Errors: {"error": "confirmation_required", "message", "action"} when
confirm is false (checked first, before name is resolved);
{"error": "Invalid device name: ..."} for a path-escaping or blocked
(e.g. 'secrets') name; otherwise one of
esphome_dashboard.DashboardError's stable codes —
esphome_unreachable/esphome_auth_required add diagnosis (see
esphome_ping_dashboard); timeout adds log_tail/log_lines/
job_may_still_be_running (always True — do not retry, check
esphome_get_addon_logs); esphome_command_failed adds
dashboard_error_code/details.
Limits: requires confirm=True; blocks up to timeout seconds; no
rollback if the upload succeeds but firmware is broken. |
| esphome_clean_mqttA | Remove stale MQTT discovery entries for an ESPHome device, through HA's own MQTT integration. Skips with zero network calls when the config has no mqtt: section.
Otherwise resolves the node name (esphome.name, with substitutions:)
and mqtt.discovery_prefix (default "homeassistant"). With a matching
HA device, reads topics via WS mqtt/device/debug_info; otherwise
briefly mqtt/subscribes to {prefix}/+/{node_name}/# and collects
retained topics. Clears each topic via the mqtt.publish service,
payload="" and retain=True -- MQTT's own way to delete a retained
message. Never touches the ESPHome dashboard, which has no
MQTT-topic-clearing command. Use when: a removed/renamed device's old MQTT discovery entries still
linger in Home Assistant.
Not for: a config with no mqtt: section; firmware artifacts -- use
esphome_compile_device.
Returns: {"device", "action": "clean_mqtt", "skipped": True, "reason": ...} with no mqtt: section; otherwise {"success": <bool>, "method": "debug_info"|"wildcard_subscribe", "topics_cleared": [...], "count": <int>}, plus "errors": [...] on partial failures.
Errors: {"error": "..."} for an invalid/missing device file, an
unresolvable esphome.name/mqtt.discovery_prefix, or a WebSocket/
service-call failure.
Limits: the wildcard fallback only collects for min(timeout, 3)
seconds -- may miss a slow message or catch an unrelated topic. |
| esphome_get_addon_infoA | Get the ESPHome add-on's status, version and update availability via the Supervisor API. The add-on slug is discovered dynamically from the live /addons list
(see _discover_esphome_slug) rather than guessed from a fixed set of
hashes — the hash prefix in <hash>_esphome differs per add-on-store
repository/installation. Use when: checking whether the ESPHome add-on is installed, running,
and up to date.
Not for: log output — use esphome_get_addon_logs.
Returns: {"slug", "name", "state", "version", "version_latest", "update_available", "ingress_url"}.
Errors: {"error": "ESPHome add-on not found. Tried: [...]"} when no
matching add-on slug responds, or when SUPERVISOR_TOKEN is unset. |
| esphome_get_addon_logsA | Get the ESPHome add-on's recent log output. Fetches raw text logs via the Supervisor API and returns the last
lines lines. Shows compile errors, OTA status and device connection
events. The add-on slug is discovered dynamically — see
esphome_get_addon_info. Use when: diagnosing why esphome_compile_device/esphome_upload_device/
esphome_validate_config failed, or checking recent device activity.
Not for: any other add-on's logs — use
supervisor_get_addon_logs with its slug instead.
Returns: {"slug": ..., "logs": "<text>", "total_lines": <int>}.
Errors: {"error": "ESPHome add-on not found. Tried: [...]"} when no
matching slug responds; {"error": "HTTP <status>"} for a non-404 HTTP
error; {"error": str(e)} for any other failure. |
| esphome_ping_dashboardA | Check whether the ESPHome Device Builder dashboard responds. Resolves where the dashboard is (esphome_dashboard.DashboardLocator,
ADR-0004 D2) — an explicit ESPHOME_DASHBOARD_URL (mode "explicit")
if set, else in add-on mode the installed ESPHome add-on's own
site-ingress port, always dialled at http://127.0.0.1:<ingress_port>
(mode "supervisor_ingress") — then calls GET /ping there. A False
reachable here does not necessarily mean the add-on itself is down;
see diagnosis/advice for what to check next. Use when: diagnosing a connection failure from
esphome_compile_device/esphome_validate_config/esphome_upload_device,
or confirming the dashboard is reachable before calling one of them.
Not for: add-on version/update status — use esphome_get_addon_info.
Returns: {"reachable": True, "url": ..., "mode": "explicit"| "supervisor_ingress", "result": {...}} (the raw /ping JSON) on
success.
Errors: never raises. On failure: {"reachable": False, "error": <stable code>, "message": ...} — "esphome_not_configured" (neither
ESPHOME_DASHBOARD_URL nor the add-on's own info could be resolved) has
no url/mode; "esphome_unreachable"/"esphome_auth_required" add
url, mode and a diagnosis: {"mode", "dashboard_url", "slug", "addon_state", "ingress", "ingress_port", "advice"} built from the
ESPHome add-on's own GET /addons/<slug>/info (slug/addon_state/
ingress/ingress_port are None outside supervisor_ingress mode). |
| esphome_lvgl_list_devicesA | List ESPHome devices whose YAML config has an lvgl: section. Parses every device YAML under /config/esphome/ (tolerating parse
errors by skipping that device) and reports the ones with LVGL display
support. Use when: finding which devices have an LVGL screen before inspecting
or editing its pages/widgets.
Not for: page detail on one device — use esphome_lvgl_get_pages.
Returns: list of {"device", "pages": <count>, "page_ids": [...]}. |
| esphome_lvgl_get_pagesA | Get the LVGL pages configured on an ESPHome device. Parses the device's YAML and reads the lvgl: section's pages and
displays[0].default_page. Use when: getting page IDs, background colors and widget counts before
drilling into one page with esphome_lvgl_get_page_widgets.
Not for: the widgets on one specific page — use
esphome_lvgl_get_page_widgets.
Returns: {"device": ..., "default_page": ..., "pages": [{"id", "bg_color", "widget_count"}, ...]}.
Errors: {"error": "..."} when the file can't be found/parsed, or when
there is no lvgl: section in the device config. |
| esphome_lvgl_get_page_widgetsA | Get all LVGL widgets on one page of an ESPHome device. Parses the device's YAML and summarises each widget on the requested
page: type, ID, position and key properties. Lambda callback values are
shown as the literal string <lambda> (opaque here — use
esphome_get_config to see the full source). Use when: inspecting an existing page's widget tree before adding or
removing a widget.
Not for: page-level metadata only — use esphome_lvgl_get_pages.
Returns: {"device", "page", "widget_count", "widgets": [...]}.
Errors: {"error": "..."} when the file can't be found/parsed, when
there is no lvgl: section, or when page_id doesn't exist. |
| esphome_lvgl_get_stylesA | Get the LVGL theme and style definitions from an ESPHome device config. Parses the device's YAML and reads the lvgl: section's theme,
style_definitions and gradients keys. Use when: checking what theme/styles a device's LVGL UI currently uses
before referencing a style name in a new widget.
Not for: page/widget content — use esphome_lvgl_get_pages/
esphome_lvgl_get_page_widgets.
Returns: {"device", "theme", "style_definitions", "gradients"}.
Errors: {"error": "..."} when the file can't be found/parsed, or when
there is no lvgl: section in the device config. |
| esphome_lvgl_validateA | Validate an ESPHome device's LVGL structure client-side, without the dashboard. Checks for duplicate page/widget IDs and default_page references that
don't exist among the parsed pages. This is a structural check only —
it does not validate widget properties or ESPHome component
correctness. Use when: a quick local pre-check after editing LVGL pages/widgets,
before a full esphome_validate_config or esphome_compile_device.
Not for: full component/property validation — use
esphome_validate_config.
Returns: {"device", "valid": <bool>, "pages": <count>, "widgets": <count>, "issues": [...]}.
Errors: {"error": "...", "valid": False} when the file can't be
found/parsed, or when there is no lvgl: section in the device config. |
| esphome_lvgl_add_widgetA | Add an LVGL widget to a page on an ESPHome device and save the whole config. Appends {widget_type: properties} to the page's widgets list, then
rewrites the entire device YAML file via yaml.dump — comments, blank
lines and YAML anchors/aliases elsewhere in the file are NOT preserved.
A <file>.bak copy of the previous content is written first so the
original formatting can be recovered manually. Lambda callbacks
(on_click, on_value_changed) are not supported here — add them
manually via esphome_get_config/esphome_write_config. Calling this
twice with the same arguments adds two separate widgets. Use when: adding one widget to an existing LVGL page without
hand-editing the full YAML.
Not for: removing a widget — use esphome_lvgl_delete_widget; not for
lambda callbacks or other structural edits — use
esphome_get_config/esphome_write_config. After adding, run
esphome_lvgl_validate/esphome_validate_config, then
esphome_compile_device and esphome_upload_device to deploy.
Returns: {"success": True, "name": ..., "bytes": ..., "backup": ..., "added": <widget_type>, "to_page": <page_id>} on success.
Errors: {"error": "..."} when the file can't be found/parsed, when
there is no lvgl: section, when page_id doesn't exist, or when the
save itself fails ({"success": False, "error": ...}).
Limits: rewrites and overwrites the whole file; only the pre-write
content is recoverable, via the .bak copy. |
| esphome_lvgl_delete_widgetA | Delete an LVGL widget by id from a page on an ESPHome device and save the whole config. Removes the matching widget from the page's widgets list, then
rewrites the entire device YAML file via yaml.dump — comments, blank
lines and YAML anchors/aliases elsewhere in the file are NOT preserved.
A <file>.bak copy of the previous content is written first so the
original formatting can be recovered manually. Use when: removing one widget from an existing LVGL page.
Not for: adding a widget — use esphome_lvgl_add_widget. After
deleting, run esphome_lvgl_validate/esphome_validate_config, then
esphome_compile_device and esphome_upload_device to deploy.
Returns: {"success": True, "name": ..., "bytes": ..., "backup": ..., "deleted": <widget_id>, "from_page": <page_id>} on success.
Errors: {"error": "..."} when the file can't be found/parsed, when
there is no lvgl: section, when page_id/widget_id doesn't exist,
or when the save itself fails ({"success": False, "error": ...}).
Limits: rewrites and overwrites the whole file; only the pre-write
content is recoverable, via the .bak copy. |
| statistics_list_statistic_idsA | List recorder statistic IDs of the requested type. Calls WS recorder/list_statistic_ids and returns one entry per
statistic the recorder tracks, with its source and unit. Use when: discovering which entities have long-term statistics before
calling statistics_get_statistics or statistics_get_statistics_metadata.
Not for: raw short-term state history — use
history_get_state_history instead.
Returns: list of {"statistic_id", "name", "source", "unit", "has_sum", "has_mean"} dicts.
Errors: [{"error": "..."}] when statistic_type is not 'sum'/'mean',
when the WS response isn't a list, or when the WS call raises. |
| statistics_get_statisticsA | Get aggregated recorder statistics for one or more IDs over a time range. Calls WS recorder/statistics_during_period with start/end parsed
into UTC timestamps, converts each row's epoch start back to an ISO
string, and rounds numeric aggregates to 4 decimals. Use when: analysing energy/temperature/etc. trends over hours, days,
weeks or months using the recorder's pre-aggregated data.
Not for: raw short-term state changes between two points in time — use
history_get_state_history instead.
Returns: {"period", "start", "end", "types", "data": {statistic_id: [{"start": <iso>, "sum": ..., "mean": ..., ...}, ...]}}.
Errors: {"error": "..."} for an empty statistic_ids, an invalid
period/types value, an unparsable start/end, a non-dict WS
response, or when the WS call raises. |
| statistics_get_energy_statisticsA | Get sum statistics for every energy-related sensor over the last N days. Auto-discovers 'sum' statistic IDs via WS recorder/list_statistic_ids,
keeps only those whose unit is an energy/volume unit (kWh, MWh, Wh, m³,
ft³, L, gal — instantaneous power sensors in 'W' are excluded since a
'sum' statistic on a power sensor is not a meaningful energy value),
then fetches sum/change via WS recorder/statistics_during_period
for the requested window. This is a convenience wrapper around
statistics_get_statistics. Use when: a quick overview of overall energy consumption trends is
needed without first listing statistic IDs by hand.
Not for: a hand-picked set of statistic IDs or non-energy sensors — use
statistics_get_statistics directly.
Returns: {"days", "period", "statistic_count", "data": {statistic_id: {"unit": ..., "rows": [{"start": <date>, "change": ..., "sum": ...}, ...]}}}, or {"message": "..."} when no energy statistic IDs are
found.
Errors: {"error": "days must be between 1 and 365"} for an
out-of-range days; {"error": "..."} when either WS call raises or
returns an unexpected shape. |
| statistics_get_statistics_metadataA | Get metadata (unit, source, name) for specific recorder statistic IDs. Calls WS recorder/get_statistics_metadata and returns one entry per
requested ID. Use when: you already know the statistic IDs and only need their
unit/source/name, without their historical values.
Not for: the actual aggregated values — use statistics_get_statistics.
Returns: list of {"statistic_id", "name", "source", "unit", "has_sum", "has_mean"} dicts.
Errors: [{"error": "..."}] when the WS response isn't a list or the
WS call raises. |
| discover_tool_searchA | Fuzzy search the Nexus tool catalogue by name and description. Scores every mounted tool's name + description against query with a
BM25-lite ranking (term frequency/inverse document frequency plus a
small boost when a query word appears in the tool name itself) and
returns the top top_k matches. Use when: finding the right tool name before calling it, instead of
keeping the whole tool surface in working memory.
Not for: a single tool's full documentation once you have its name —
use discover_get_tool_doc.
Returns: list of {"name", "namespace", "summary", "score", "access"}
dicts, highest score first; empty list if nothing scores above zero.
access is "read", "write" or "destructive" (ADR-0002/0003
annotation class). |
| discover_list_namespacesA | List every mounted Nexus tool namespace with its tool count. Groups the current tool index by namespace (the mount prefix parsed
from server.py, e.g. "card_builder", "entities") and counts entries. Use when: getting an overview of which domains exist before narrowing a
discover_tool_search call with its namespace parameter.
Not for: the tools within one namespace — use discover_tool_search
with that namespace.
Returns: list of {"namespace", "count"}, most populated first. |
| discover_get_tool_docA | Get one tool's full description, parameter schema and MCP annotations. Looks the tool up by exact name in the current index and returns its
full (un-truncated) docstring alongside the same inputSchema and
annotations an MCP client sees from tools/list. Use when: reading a specific tool's full contract after finding its
name with discover_tool_search.
Not for: searching by keyword — use discover_tool_search.
Returns: {"name", "namespace", "description", "input_schema", "annotations", "access"}. input_schema is the tool's JSON-schema
parameter dict; annotations is the four MCP hints plus title as a
plain dict, or None for a tool whose module has not yet declared them.
access is "read", "write" or "destructive" (ADR-0002/0003
annotation class), computed fail-closed even when annotations is
None.
Errors: {"error": "not_found", "name": name} when no tool with that
exact name is in the index. |
| discover_refresh_indexA | Force-rebuild the in-memory tool search index. Drops the cached index and rebuilds it from _ROOT.list_tools(). Only
nexus's own in-process cache is affected — nothing in HA changes. Use when: tools were mounted or changed at runtime after the index was
first built (normally only relevant during development, since
server.py mounts every namespace once at startup).
Not for: routine searches — discover_tool_search/
discover_list_namespaces/discover_get_tool_doc already rebuild the
index lazily on first use.
Returns: {"status": "rebuilt", "tools": <count>}. |