用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Rotoslider/Choom --skill home-assistant命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | home-assistant |
| description | Controls smart home devices and reads sensor data via Home Assistant |
| version | 1.0.0 |
| author | system |
| tools | ["ha_get_state","ha_list_entities","ha_call_service","ha_get_history","ha_get_logbook","ha_get_home_status","ha_get_camera_snapshot","ha_fire_event","ha_render_template","ha_list_services"] |
| dependencies | [] |
Home Assistant entities follow the format domain.name but names are often non-obvious.
CRITICAL: NEVER guess entity IDs. Always use ha_list_entities first to discover actual IDs, or use ha_get_home_status to get all readings at once. Entity IDs frequently don't match what you'd expect (e.g. bathroom temperature might be sensor.temperature, not sensor.bathroom_temperature).
Common domains:
sensor — numeric readings (temperature, humidity, power)binary_sensor — on/off states (motion, door, window)light — controllable lights (supports brightness, color)switch — on/off switchesclimate — thermostats / HVACfan — fans with speed controlcover — garage doors, blinds, shuttersentity_id)| Domain | Service | Use |
|---|---|---|
| light | turn_on | Turn on (optional: brightness 0-255, color_name, rgb_color) |
| light | turn_off | Turn off |
| light | toggle | Toggle on/off |
| switch | turn_on | Turn on |
| switch | turn_off | Turn off |
| climate | set_temperature | Set target temp (service_data: {temperature: 72}) |
| climate | set_hvac_mode | Set mode (heat, cool, auto, off) |
| fan | turn_on | Turn on (optional: percentage) |
| cover | open_cover | Open garage door / blinds |
| cover | close_cover | Close garage door / blinds |
entity_id)| Domain | Service | Example service_data |
|---|---|---|
| notify | mobile_app_ | {"message": "motion detected", "title": "Alert"} |
| notify | persistent_notification | {"message": "...", "title": "..."} |
| tts | speak | {"entity_id": "tts.<provider>", "media_player_entity_id": "media_player.living_room", "message": "hello"} — entity_id is the TTS service entity (tts.*), NOT the speaker. Find providers with ha_list_entities(domain="tts"). If you only have media_player.play_media, use that instead. |
| scene | turn_on | Pass entity_id: "scene.movie_time" to activate |
| scene | create | {"scene_id": "guest_mode", "entities": {"light.kitchen": {"state": "on", "brightness": 180}}} |
| script | turn_on | entity_id: "script.bedtime", or omit entity_id and pass {"variables": {...}} for parameterized scripts |
| automation | trigger | entity_id: "automation.morning_routine" |
| homeassistant | reload_config_entry | For reloading an integration |
HA has two kinds of entities involved in voice output:
tts.*) — the engine that converts text to audio. Examples: tts.chatterbox, tts.piper, tts.google_translate_en_com, tts.openai_tts. Discover with ha_list_entities(domain="tts"). On this system, prefer tts.chatterbox — it's the configured/tuned provider. Only fall back to another if chatterbox isn't present.media_player.*) — where the audio plays. Home Assistant Voice PE devices may register as media_player.home_assistant_voice_<id> and/or assist_satellite.* — check both domains.To speak on a speaker:
ha_call_service(
domain: "tts", service: "speak",
service_data: {
"entity_id": "tts.piper", # TTS provider
"media_player_entity_id": "media_player.living_room", # speaker
"message": "Dinner is ready"
}
)
If TTS isn't configured, fall back to media_player.play_media with a URL, or use notify.mobile_app_<device> to send a push instead.
target param)ha_call_service(domain: "light", service: "turn_off", target: {"area_id": "kitchen"})
ha_call_service(domain: "light", service: "turn_on", target: {"entity_id": ["light.a", "light.b"]}, service_data: {"brightness": 128})
ha_get_state — fast, cachedha_list_entities — discover what's available; area filter uses HA's real area registry (device→area inheritance respected), falls back to friendly-name matchingha_call_service — lights, scenes, scripts, TTS, notify, automation triggering, etc.ha_get_history — min/max/avg over time (numeric sensors) or state changes (non-numeric)ha_get_logbook — timestamped state changes (location history, door events, etc.)ha_get_home_status — snapshot of all active devicesha_get_camera_snapshot — fetches JPEG to workspaceha_render_template — one call answers what would take 20 ha_get_statesha_fire_event — emit custom events that automations can listen forha_render_template)When a question would take many ha_get_state calls, use one template instead:
# "Which motion sensors are active right now?"
template: "{{ states | selectattr('attributes.device_class','equalto','motion') | selectattr('state','equalto','on') | map(attribute='entity_id') | list | tojson }}"
# "Are all the downstairs lights off?"
template: "{{ area_entities('downstairs') | select('match','^light\\.') | map('states') | select('equalto','on') | list | length == 0 }}"
# "What's the average temperature across all thermostats?"
template: "{{ states.climate | map(attribute='attributes.current_temperature') | select('number') | sum / states.climate | list | length }}"
# "Is anyone home?" (person domain)
template: "{{ states.person | selectattr('state','equalto','home') | map(attribute='attributes.friendly_name') | list | tojson }}"
Return values that are JSON-parseable are auto-parsed; otherwise raw string is returned.
To grab a still frame from an HA camera (Reolink, generic MJPEG, etc.), use ha_get_camera_snapshot — one tool, one call:
ha_get_camera_snapshot(entity_id: "camera.garage")
It authenticates with HA, fetches the JPEG, saves it to selfies_{your_slug}/{entity}_{timestamp}.jpg, and returns the path. Do NOT use ha_call_service with camera.snapshot — that writes into HA's container filesystem and the file is unreachable from your workspace.
Save location rules: the default (selfies_{your_slug}/) is almost always correct. Only override save_path when you have a clear reason to share the snapshot with another Choom — in that case use choom_commons/. NEVER save snapshots to sibling_journal/ — that folder is text-only and append-only (you can't delete entries). If you try, the tool will redirect to your personal folder and warn you.
Once saved, the returned path works everywhere:
analyze_image(image_path: "<path>", prompt: "...")send_notification(message: "...", file_paths: ["<path>"]) — images display inline in Signal.file_created event; chat UI renders the image inline.Use ha_list_entities with domain: "camera" first if you don't know the entity_id.
This is the #1 place Chooms hallucinate service names (camera.available_ptz_presets, ptz.list_presets, onvif.ptz_preset — none of these exist). Actual PTZ control in HA depends on the camera's integration. Two common patterns:
select.<camera>_ptz_preset entities. List options with ha_get_state(entity_id="select.<camera>_ptz_preset") — attributes.options is the preset names. Move to one via:
ha_call_service(domain="select", service="select_option",
entity_id="select.<camera>_ptz_preset",
service_data={"option": "<preset name>"})
button.<camera>_preset_<name> entity. Press with ha_call_service(domain="button", service="press", entity_id="button.<preset>").Discovery workflow when you're unsure what services/entities a device exposes:
ha_list_entities() with no filter, grep the result for the camera name — look for select.*, button.*, or integration-specific entities (e.g. reolink.*) related to the camera.ha_list_services(domain="<integration>") (e.g. domain: "reolink", domain: "onvif") for integration-specific PTZ services.ha_list_services(domain: "camera") to see what the camera.* domain actually supports — almost never has native PTZ.attributes.pan / attributes.tilt but no preset entities, the integration only supports live PTZ streaming, not preset recall — report that to the user instead of guessing.Never call camera.*_ptz_*, ptz.*, or onvif.ptz_* services without first confirming they exist via ha_list_services. If HA returns 400: Bad Request, the most common cause is a non-existent service name — discovery, not retry.
Case sensitivity & settling: select.select_option is case-sensitive on the option value — but the handler auto-corrects common case mismatches ("driveway" → "Driveway") by looking up attributes.options on the entity. When the target looks like a PTZ preset (entity_id contains "ptz" or "preset"), the handler also waits ~6 seconds after the service call so the camera has time to physically move before you take a snapshot. Don't take a snapshot immediately yourself — just wait for ha_call_service to return, then call ha_get_camera_snapshot.
The preset select reads back as "unknown" — that is NORMAL, not a failure: Reolink (and most ONVIF) PTZ preset selects are write-only. Selecting an option commands the camera to move, but HA never reads the active preset back, so ha_get_state on the select entity (and the HOME ENVIRONMENT summary) shows unknown even when the camera is sitting exactly where you sent it. When your select.select_option call returns success: true with moved_to: "<preset>", the move worked — the camera went where you sent it. Do NOT re-select the preset, and do NOT call ha_get_state afterward to "confirm" the position (it will always say unknown and send you in a loop). Trust the success result; to see the view, call ha_get_camera_snapshot.
ha_list_entities or ha_get_home_status first to find actual IDsha_get_state returns a 404 error, the entity_id is wrong — use ha_list_entities to find the correct oneunavailable or unknown — do not interpret these as readings