From d059d3b24e8b3d746d1bac5f03de07e223b867aa Mon Sep 17 00:00:00 2001 From: matt_ed Date: Wed, 4 Mar 2026 22:45:50 -0800 Subject: [PATCH] entities script --- ha_entities.csv | 206 ++++++++++++++++++++++++++++++++++ scripts/update_ha_entities.py | 175 +++++++++++++++++++++++++++++ 2 files changed, 381 insertions(+) create mode 100644 ha_entities.csv create mode 100644 scripts/update_ha_entities.py diff --git a/ha_entities.csv b/ha_entities.csv new file mode 100644 index 0000000..4eeb999 --- /dev/null +++ b/ha_entities.csv @@ -0,0 +1,206 @@ +entity_id,domain,friendly_name,device_class,description +binary_sensor.entertainment_area_1,binary_sensor,Entertainment area 1,running,Entertainment area 1 +binary_sensor.moonlight_beach_battery,binary_sensor,Moonlight beach Battery,battery,Moonlight beach Battery +binary_sensor.moonlight_beach_interior_battery,binary_sensor,Moonlight beach Interior battery,battery,Moonlight beach Interior battery +binary_sensor.moonlight_beach_soil_monitor_battery_2,binary_sensor,Moonlight beach Soil monitor battery 2,battery,Moonlight beach Soil monitor battery 2 +binary_sensor.moonlight_beach_soil_monitor_battery_3,binary_sensor,Moonlight beach Soil monitor battery 3,battery,Moonlight beach Soil monitor battery 3 +binary_sensor.tp_link_smart_plug_f048_cloud_connection,binary_sensor,TP-LINK_Smart Plug_F048 Cloud connection,connectivity,TP-LINK_Smart Plug_F048 Cloud connection +binary_sensor.vent_fan_cloud_connection,binary_sensor,Vent Fan Cloud connection,connectivity,Vent Fan Cloud connection +binary_sensor.vent_fan_overheated,binary_sensor,Vent Fan Overheated,problem,Vent Fan Overheated +binary_sensor.vent_fan_overloaded,binary_sensor,Vent Fan Overloaded,problem,Vent Fan Overloaded +binary_sensor.walkway_lights_cloud_connection,binary_sensor,Walkway Lights Cloud connection,connectivity,Walkway Lights Cloud connection +binary_sensor.walkway_lights_overheated,binary_sensor,Walkway Lights Overheated,problem,Walkway Lights Overheated +binary_sensor.walkway_lights_overloaded,binary_sensor,Walkway Lights Overloaded,problem,Walkway Lights Overloaded +camera.192_168_1_153,camera,Front Door,,Front Door +camera.192_168_1_153_2,camera,192_168_1_153,,192_168_1_153 +camera.192_168_1_153_3,camera,192_168_1_153,,192_168_1_153 +conversation.home_assistant,conversation,Home Assistant,,Home Assistant +device_tracker.pixel_10_pro,device_tracker,Pixel 10 Pro,,Pixel 10 Pro +device_tracker.wall_tablet,device_tracker,wall panel,,wall panel +event.backup_automatic_backup,event,Backup Automatic backup,,Backup Automatic backup +light.a_st_staircase,light,A St. Staircase,,A St. Staircase +light.bedtime_lights,light,Bedtime Lights,,Bedtime Lights +light.blue_lamp,light,Blue Lamp,,Blue Lamp +light.brown_lamp,light,Brown Lamp,,Brown Lamp +light.christmas_lights,light,Christmas Lights,,Christmas Lights +light.dining_room,light,Dining Room,,Dining Room +light.hue_color_lamp_3,light,Hue color lamp 3,,Hue color lamp 3 +light.hue_color_lamp_4,light,Hue color lamp 4,,Hue color lamp 4 +light.hue_smart_plug_1,light,Hue smart plug 1,,Hue smart plug 1 +light.hue_white_lamp_1,light,Hue white lamp 1,,Hue white lamp 1 +light.hue_white_lamp_2,light,Hue white lamp 2,,Hue white lamp 2 +light.janet_s_desk,light,Janet's Desk,,Janet's Desk +light.janet_s_lamp,light,Janet's Lamp,,Janet's Lamp +light.landing_chandelier,light,Landing Chandelier,,Landing Chandelier +light.living_room,light,Living Room,,Living Room +light.main_room,light,Main Room,,Main Room +light.matt_s_lamp,light,Matt's Lamp,,Matt's Lamp +light.office,light,Office,,Office +light.outdoor_stairway,light,Outdoor Stairway,,Outdoor Stairway +light.reading_corner,light,Reading Corner,,Reading Corner +light.south_bedroom,light,South Bedroom,,South Bedroom +light.south_desk,light,South Desk,,South Desk +light.staircase,light,Staircase,,Staircase +light.tv,light,TV,,TV +light.tv_room,light,TV Room,,TV Room +light.upstairs_bedroom,light,Upstairs Bedroom,,Upstairs Bedroom +light.upstairs_landing,light,Upstairs Landing,,Upstairs Landing +light.upstairs_landing_zone,light,Upstairs Landing Zone,,Upstairs Landing Zone +media_player.all_speakers,media_player,All Speakers,speaker,All Speakers +media_player.basement_monitor,media_player,Basement Monitor,,Basement Monitor +media_player.gym_tv,media_player,Gym TV,,Gym TV +media_player.home_group,media_player,Home group,speaker,Home group +media_player.main_room_speaker,media_player,Main Room speaker,speaker,Main Room speaker +media_player.sony_xbr_65x90ch,media_player,SONY XBR-65X90CH,,SONY XBR-65X90CH +number.vent_fan_power_protection,number,Vent Fan Power protection,,Vent Fan Power protection +number.vent_fan_turn_off_in,number,Vent Fan Turn off in,,Vent Fan Turn off in +number.walkway_lights_power_protection,number,Walkway Lights Power protection,,Walkway Lights Power protection +number.walkway_lights_turn_off_in,number,Walkway Lights Turn off in,,Walkway Lights Turn off in +person.matthew_edwards,person,Matthew Edwards,,Matthew Edwards +person.wall_tablet,person,Wall Tablet,,Wall Tablet +scene.a_st_staircase_emerald_isle,scene,A St. Staircase Emerald isle,,A St. Staircase Emerald isle +scene.a_st_staircase_midsummer_sun,scene,A St. Staircase Midsummer sun,,A St. Staircase Midsummer sun +scene.bedtime_lights_arctic_aurora,scene,Bedtime Lights Arctic aurora,,Bedtime Lights Arctic aurora +scene.bedtime_lights_bright,scene,Bedtime Lights Bright,,Bedtime Lights Bright +scene.bedtime_lights_concentrate,scene,Bedtime Lights Concentrate,,Bedtime Lights Concentrate +scene.bedtime_lights_dimmed,scene,Bedtime Lights Dimmed,,Bedtime Lights Dimmed +scene.bedtime_lights_energize,scene,Bedtime Lights Energize,,Bedtime Lights Energize +scene.bedtime_lights_galaxy,scene,Bedtime Lights Galaxy,,Bedtime Lights Galaxy +scene.bedtime_lights_nightlight,scene,Bedtime Lights Nightlight,,Bedtime Lights Nightlight +scene.bedtime_lights_read,scene,Bedtime Lights Read,,Bedtime Lights Read +scene.bedtime_lights_relax,scene,Bedtime Lights Relax,,Bedtime Lights Relax +scene.bedtime_lights_savanna_sunset,scene,Bedtime Lights Savanna sunset,,Bedtime Lights Savanna sunset +scene.bedtime_lights_spring_blossom,scene,Bedtime Lights Spring blossom,,Bedtime Lights Spring blossom +scene.bedtime_lights_tropical_twilight,scene,Bedtime Lights Tropical twilight,,Bedtime Lights Tropical twilight +scene.bedtime_lights_warm_embrace,scene,Bedtime Lights Warm embrace,,Bedtime Lights Warm embrace +scene.dining_room_bright,scene,Dining Room Bright,,Dining Room Bright +scene.dining_room_dimmed,scene,Dining Room Dimmed,,Dining Room Dimmed +scene.dining_room_nightlight,scene,Dining Room Nightlight,,Dining Room Nightlight +scene.living_room_bright,scene,Living Room Bright,,Living Room Bright +scene.living_room_dimmed,scene,Living Room Dimmed,,Living Room Dimmed +scene.living_room_nightlight,scene,Living Room Nightlight,,Living Room Nightlight +scene.main_room_bright,scene,Main Room Bright,,Main Room Bright +scene.main_room_dimmed,scene,Main Room Dimmed,,Main Room Dimmed +scene.main_room_nightlight,scene,Main Room Nightlight,,Main Room Nightlight +scene.office_night_time,scene,Office Night time,,Office Night time +scene.south_bedroom_bright,scene,South Bedroom Bright,,South Bedroom Bright +scene.south_bedroom_dimmed,scene,South Bedroom Dimmed,,South Bedroom Dimmed +scene.south_bedroom_nightlight,scene,South Bedroom Nightlight,,South Bedroom Nightlight +scene.tv_blue_lagoon,scene,TV Blue lagoon,,TV Blue lagoon +scene.tv_palm_beach,scene,TV Palm Beach,,TV Palm Beach +scene.tv_room_arctic_aurora,scene,TV Room Arctic aurora,,TV Room Arctic aurora +scene.tv_room_bright,scene,TV Room Bright,,TV Room Bright +scene.tv_room_concentrate,scene,TV Room Concentrate,,TV Room Concentrate +scene.tv_room_dimmed,scene,TV Room Dimmed,,TV Room Dimmed +scene.tv_room_energize,scene,TV Room Energize,,TV Room Energize +scene.tv_room_nightlight,scene,TV Room Nightlight,,TV Room Nightlight +scene.tv_room_palm_beach,scene,TV Room Palm Beach,,TV Room Palm Beach +scene.tv_room_read,scene,TV Room Read,,TV Room Read +scene.tv_room_relax,scene,TV Room Relax,,TV Room Relax +scene.tv_room_savanna_sunset,scene,TV Room Savanna sunset,,TV Room Savanna sunset +scene.tv_room_spring_blossom,scene,TV Room Spring blossom,,TV Room Spring blossom +scene.tv_room_taylor,scene,TV Room Taylor,,TV Room Taylor +scene.tv_room_tropical_twilight,scene,TV Room Tropical twilight,,TV Room Tropical twilight +scene.upstairs_bedroom_arctic_aurora,scene,Upstairs Bedroom Arctic aurora,,Upstairs Bedroom Arctic aurora +scene.upstairs_bedroom_bright,scene,Upstairs Bedroom Bright,,Upstairs Bedroom Bright +scene.upstairs_bedroom_concentrate,scene,Upstairs Bedroom Concentrate,,Upstairs Bedroom Concentrate +scene.upstairs_bedroom_dimmed,scene,Upstairs Bedroom Dimmed,,Upstairs Bedroom Dimmed +scene.upstairs_bedroom_energize,scene,Upstairs Bedroom Energize,,Upstairs Bedroom Energize +scene.upstairs_bedroom_nightlight,scene,Upstairs Bedroom Nightlight,,Upstairs Bedroom Nightlight +scene.upstairs_bedroom_read,scene,Upstairs Bedroom Read,,Upstairs Bedroom Read +scene.upstairs_bedroom_relax,scene,Upstairs Bedroom Relax,,Upstairs Bedroom Relax +scene.upstairs_bedroom_savanna_sunset,scene,Upstairs Bedroom Savanna sunset,,Upstairs Bedroom Savanna sunset +scene.upstairs_bedroom_spring_blossom,scene,Upstairs Bedroom Spring blossom,,Upstairs Bedroom Spring blossom +scene.upstairs_bedroom_tropical_twilight,scene,Upstairs Bedroom Tropical twilight,,Upstairs Bedroom Tropical twilight +scene.upstairs_bedroom_tropical_twilight_2,scene,Upstairs Bedroom Tropical twilight 2,,Upstairs Bedroom Tropical twilight 2 +scene.upstairs_landing_bright,scene,Upstairs Landing Bright,,Upstairs Landing Bright +scene.upstairs_landing_dimmed,scene,Upstairs Landing Dimmed,,Upstairs Landing Dimmed +scene.upstairs_landing_nightlight,scene,Upstairs Landing Nightlight,,Upstairs Landing Nightlight +scene.upstairs_landing_zone_bright,scene,Upstairs Landing Zone Bright,,Upstairs Landing Zone Bright +scene.upstairs_landing_zone_dimmed,scene,Upstairs Landing Zone Dimmed,,Upstairs Landing Zone Dimmed +scene.upstairs_landing_zone_nightlight,scene,Upstairs Landing Zone Nightlight,,Upstairs Landing Zone Nightlight +sensor.backup_backup_manager_state,sensor,Backup Backup Manager state,enum,Backup Backup Manager state +sensor.backup_last_attempted_automatic_backup,sensor,Backup Last attempted automatic backup,timestamp,Backup Last attempted automatic backup +sensor.backup_last_successful_automatic_backup,sensor,Backup Last successful automatic backup,timestamp,Backup Last successful automatic backup +sensor.backup_next_scheduled_automatic_backup,sensor,Backup Next scheduled automatic backup,timestamp,Backup Next scheduled automatic backup +sensor.moonlight_beach_absolute_pressure,sensor,Moonlight beach Absolute pressure,pressure,Moonlight beach Absolute pressure +sensor.moonlight_beach_daily_rain,sensor,Moonlight beach Daily rain,precipitation,Moonlight beach Daily rain +sensor.moonlight_beach_dew_point,sensor,Moonlight beach Dew point,temperature,Moonlight beach Dew point +sensor.moonlight_beach_event_rain,sensor,Moonlight beach Event rain,precipitation,Moonlight beach Event rain +sensor.moonlight_beach_feels_like,sensor,Moonlight beach Feels like,temperature,Moonlight beach Feels like +sensor.moonlight_beach_humidity,sensor,Moonlight beach Humidity,humidity,Moonlight beach Humidity +sensor.moonlight_beach_humidity_indoor,sensor,Moonlight beach Humidity indoor,humidity,Moonlight beach Humidity indoor +sensor.moonlight_beach_inside_temperature,sensor,Moonlight beach Inside temperature,temperature,Moonlight beach Inside temperature +sensor.moonlight_beach_last_rain,sensor,Moonlight beach Last rain,timestamp,Moonlight beach Last rain +sensor.moonlight_beach_max_gust,sensor,Moonlight beach Max gust,wind_speed,Moonlight beach Max gust +sensor.moonlight_beach_monthly_rain,sensor,Moonlight beach Monthly rain,precipitation,Moonlight beach Monthly rain +sensor.moonlight_beach_precipitation_intensity,sensor,Rain Rate,precipitation_intensity,Rain Rate +sensor.moonlight_beach_relative_pressure,sensor,Moonlight beach Relative pressure,pressure,Moonlight beach Relative pressure +sensor.moonlight_beach_soil_humidity_2,sensor,Moonlight beach Soil humidity 2,humidity,Moonlight beach Soil humidity 2 +sensor.moonlight_beach_soil_humidity_3,sensor,Moonlight beach Soil humidity 3,humidity,Moonlight beach Soil humidity 3 +sensor.moonlight_beach_temperature,sensor,Outside Temp,temperature,Outside Temp +sensor.moonlight_beach_weekly_rain,sensor,Moonlight beach Weekly rain,precipitation,Moonlight beach Weekly rain +sensor.moonlight_beach_wind_direction,sensor,Moonlight beach Wind direction,wind_direction,Moonlight beach Wind direction +sensor.moonlight_beach_wind_direction_average_10_minutes,sensor,Moonlight beach Wind direction average 10 minutes,wind_direction,Moonlight beach Wind direction average 10 minutes +sensor.moonlight_beach_wind_gust,sensor,Moonlight beach Wind gust,wind_speed,Moonlight beach Wind gust +sensor.moonlight_beach_wind_speed,sensor,Wind Speed,wind_speed,Wind Speed +sensor.moonlight_beach_yearly_rain,sensor,Moonlight beach Yearly rain,precipitation,Moonlight beach Yearly rain +sensor.pixel_10_pro_battery_level,sensor,Pixel 10 Pro Battery level,battery,Pixel 10 Pro Battery level +sensor.pixel_10_pro_battery_state,sensor,Pixel 10 Pro Battery state,enum,Pixel 10 Pro Battery state +sensor.pixel_10_pro_charger_type,sensor,Pixel 10 Pro Charger type,enum,Pixel 10 Pro Charger type +sensor.sun_next_dawn,sensor,Sun Next dawn,timestamp,Sun Next dawn +sensor.sun_next_dusk,sensor,Sun Next dusk,timestamp,Sun Next dusk +sensor.sun_next_midnight,sensor,Sun Next midnight,timestamp,Sun Next midnight +sensor.sun_next_noon,sensor,Sun Next noon,timestamp,Sun Next noon +sensor.sun_next_rising,sensor,Sun Next rising,timestamp,Sun Next rising +sensor.sun_next_setting,sensor,Sun Next setting,timestamp,Sun Next setting +sensor.vent_fan_auto_off_at,sensor,Vent Fan Auto-off at,timestamp,Vent Fan Auto-off at +sensor.vent_fan_current,sensor,Vent Fan Current,current,Vent Fan Current +sensor.vent_fan_current_consumption,sensor,Vent Fan Current consumption,power,Vent Fan Current consumption +sensor.vent_fan_signal_level,sensor,Vent Fan Signal level,,Vent Fan Signal level +sensor.vent_fan_this_month_s_consumption,sensor,Vent Fan This month's consumption,energy,Vent Fan This month's consumption +sensor.vent_fan_today_s_consumption,sensor,Vent Fan Today's consumption,energy,Vent Fan Today's consumption +sensor.vent_fan_voltage,sensor,Vent Fan Voltage,voltage,Vent Fan Voltage +sensor.walkway_lights_auto_off_at,sensor,Walkway Lights Auto-off at,timestamp,Walkway Lights Auto-off at +sensor.walkway_lights_current,sensor,Walkway Lights Current,current,Walkway Lights Current +sensor.walkway_lights_current_consumption,sensor,Walkway Lights Current consumption,power,Walkway Lights Current consumption +sensor.walkway_lights_signal_level,sensor,Walkway Lights Signal level,,Walkway Lights Signal level +sensor.walkway_lights_this_month_s_consumption,sensor,Walkway Lights This month's consumption,energy,Walkway Lights This month's consumption +sensor.walkway_lights_today_s_consumption,sensor,Walkway Lights Today's consumption,energy,Walkway Lights Today's consumption +sensor.walkway_lights_voltage,sensor,Walkway Lights Voltage,voltage,Walkway Lights Voltage +sensor.wall_panel_battery_level,sensor,wall panel Battery level,battery,wall panel Battery level +sensor.wall_panel_battery_state,sensor,wall panel Battery state,enum,wall panel Battery state +sensor.wall_panel_charger_type,sensor,wall panel Charger type,enum,wall panel Charger type +sun.sun,sun,Sun,,Sun +switch.automation_all_off_at_latest_230a,switch,Automation: All Off At Latest 230a,switch,Automation: All Off At Latest 230a +switch.automation_bedtime_lights_on,switch,Automation: Bedtime Lights On,switch,Automation: Bedtime Lights On +switch.automation_cool_bedtime_lights,switch,Automation: Cool Bedtime Lights,switch,Automation: Cool Bedtime Lights +switch.automation_dim_main_room,switch,Automation: Dim Main Room,switch,Automation: Dim Main Room +switch.automation_main_room_lights,switch,Automation: Main Room Lights,switch,Automation: Main Room Lights +switch.automation_none,switch,Automation: None,switch,Automation: None +switch.automation_random_off_away,switch,Automation: Random Off - Away,switch,Automation: Random Off - Away +switch.automation_turn_off_stair_lights,switch,Automation: Turn Off Stair Lights,switch,Automation: Turn Off Stair Lights +switch.automation_upstairs_bedroom_off_midnight,switch,Automation: Upstairs Bedroom Off Midnight,switch,Automation: Upstairs Bedroom Off Midnight +switch.tp_link_smart_plug_f048,switch,TP-LINK_Smart Plug_F048,,TP-LINK_Smart Plug_F048 +switch.tp_link_smart_plug_f048_fountain,switch,TP-LINK_Smart Plug_F048 Fountain,,TP-LINK_Smart Plug_F048 Fountain +switch.tp_link_smart_plug_f048_led,switch,TP-LINK_Smart Plug_F048 LED,,TP-LINK_Smart Plug_F048 LED +switch.tp_link_smart_plug_f048_outdoor_hanging_lights,switch,TP-LINK_Smart Plug_F048 Outdoor Hanging Lights,,TP-LINK_Smart Plug_F048 Outdoor Hanging Lights +switch.vent_fan,switch,Vent Fan,,Vent Fan +switch.vent_fan_auto_off_enabled,switch,Vent Fan Auto-off enabled,,Vent Fan Auto-off enabled +switch.vent_fan_auto_update_enabled,switch,Vent Fan Auto-update enabled,,Vent Fan Auto-update enabled +switch.vent_fan_led,switch,Vent Fan LED,,Vent Fan LED +switch.walkway_lights,switch,Walkway Lights,,Walkway Lights +switch.walkway_lights_auto_off_enabled,switch,Walkway Lights Auto-off enabled,,Walkway Lights Auto-off enabled +switch.walkway_lights_auto_update_enabled,switch,Walkway Lights Auto-update enabled,,Walkway Lights Auto-update enabled +switch.walkway_lights_led,switch,Walkway Lights LED,,Walkway Lights LED +todo.shopping_list,todo,Shopping List,,Shopping List +tts.google_translate_en_com,tts,Google Translate en com,,Google Translate en com +update.arp_scan_device_tracker_update,update,ARP-Scan Device Tracker update,,ARP-Scan Device Tracker update +update.get_hacs_update,update,Get HACS Update,,Get HACS Update +update.hacs_update,update,HACS update,,HACS update +update.home_assistant_core_update,update,Home Assistant Core Update,,Home Assistant Core Update +update.home_assistant_operating_system_update,update,Home Assistant Operating System Update,,Home Assistant Operating System Update +update.home_assistant_supervisor_update,update,Home Assistant Supervisor Update,,Home Assistant Supervisor Update +update.netalertx_full_access_update,update,NetAlertX Full Access Update,,NetAlertX Full Access Update +weather.forecast_home,weather,Forecast Home,,Forecast Home +zone.home,zone,Home,,Home diff --git a/scripts/update_ha_entities.py b/scripts/update_ha_entities.py new file mode 100644 index 0000000..ec90c05 --- /dev/null +++ b/scripts/update_ha_entities.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +""" +Update ha_entities.csv with all entities from Home Assistant. + +Reads HA URL and token from public/config.json (or HA_URL / HA_TOKEN env vars). +Fetches GET /api/states, then writes entity_id, domain, friendly_name, +device_class, and a suggested description to the CSV. + +Usage: + python scripts/update_ha_entities.py [--config path] [--output path] +""" + +import argparse +import csv +import json +import os +import re +import sys +from pathlib import Path +from urllib.request import Request, urlopen +from urllib.error import URLError, HTTPError + +# Default paths relative to project root +PROJECT_ROOT = Path(__file__).resolve().parent.parent +DEFAULT_CONFIG = PROJECT_ROOT / "public" / "config.json" +DEFAULT_OUTPUT = PROJECT_ROOT / "ha_entities.csv" + +# Domain -> human label for generating descriptions +DOMAIN_LABELS = { + "light": "Light", + "switch": "Switch", + "sensor": "Sensor", + "binary_sensor": "Binary sensor", + "climate": "Climate", + "cover": "Cover", + "fan": "Fan", + "lock": "Lock", + "media_player": "Media player", + "camera": "Camera", + "automation": "Automation", + "script": "Script", + "scene": "Scene", + "input_boolean": "Input boolean", + "input_number": "Input number", + "input_text": "Input text", + "input_datetime": "Input datetime", + "input_select": "Input select", + "device_tracker": "Device tracker", + "person": "Person", + "zone": "Zone", + "sun": "Sun", + "weather": "Weather", + "update": "Update", + "button": "Button", + "number": "Number", + "select": "Select", + "vacuum": "Vacuum", + "humidifier": "Humidifier", + "water_heater": "Water heater", + "calendar": "Calendar", + "timer": "Timer", + "counter": "Counter", +} + + +def humanize_id(object_id: str) -> str: + """Turn entity object_id into readable text (e.g. living_room -> Living room).""" + return re.sub(r"[_.]+", " ", object_id).strip().title() + + +def suggested_description(entity: dict) -> str: + """Build a short description for the entity.""" + attrs = entity.get("attributes") or {} + friendly = attrs.get("friendly_name") or attrs.get("name") + if friendly: + return str(friendly).strip() + domain = (entity.get("entity_id") or "").split(".", 1)[0] + object_id = (entity.get("entity_id") or "").split(".", 1)[-1] + label = DOMAIN_LABELS.get(domain, domain.replace("_", " ").title()) + return f"{label}: {humanize_id(object_id)}" + + +def load_config(config_path: Path) -> tuple[str, str]: + """Return (ha_url, ha_token). Prefer env HA_URL, HA_TOKEN over config file.""" + url = os.environ.get("HA_URL") + token = os.environ.get("HA_TOKEN") + if url and token: + return url.rstrip("/"), token + if not config_path.is_file(): + raise SystemExit( + f"Config not found: {config_path}. Set HA_URL and HA_TOKEN or create config." + ) + with open(config_path, encoding="utf-8") as f: + data = json.load(f) + settings = data.get("settings") or {} + url = settings.get("haUrl") or os.environ.get("HA_URL") + token = settings.get("haToken") or os.environ.get("HA_TOKEN") + if not url or not token: + raise SystemExit("Missing haUrl or haToken in config (or HA_URL/HA_TOKEN env).") + return url.rstrip("/"), token + + +def fetch_states(ha_url: str, ha_token: str) -> list[dict]: + """GET /api/states and return list of state objects.""" + req = Request( + f"{ha_url}/api/states", + headers={"Authorization": f"Bearer {ha_token}"}, + method="GET", + ) + try: + with urlopen(req, timeout=30) as resp: + return json.load(resp) + except HTTPError as e: + raise SystemExit(f"Home Assistant API error: {e.code} {e.reason}") + except URLError as e: + raise SystemExit(f"Cannot reach Home Assistant: {e.reason}") + + +def main() -> None: + parser = argparse.ArgumentParser(description="Update ha_entities.csv from Home Assistant.") + parser.add_argument( + "--config", + type=Path, + default=DEFAULT_CONFIG, + help="Path to config.json (default: public/config.json)", + ) + parser.add_argument( + "--output", + "-o", + type=Path, + default=DEFAULT_OUTPUT, + help="Output CSV path (default: ha_entities.csv)", + ) + args = parser.parse_args() + + ha_url, ha_token = load_config(args.config) + states = fetch_states(ha_url, ha_token) + + rows = [] + for entity in states: + eid = entity.get("entity_id") or "" + if not eid: + continue + domain = eid.split(".", 1)[0] + attrs = entity.get("attributes") or {} + friendly_name = (attrs.get("friendly_name") or attrs.get("name") or "").strip() + device_class = (attrs.get("device_class") or "").strip() + description = suggested_description(entity) + rows.append( + { + "entity_id": eid, + "domain": domain, + "friendly_name": friendly_name, + "device_class": device_class, + "description": description, + } + ) + + rows.sort(key=lambda r: (r["domain"], r["entity_id"])) + + args.output.parent.mkdir(parents=True, exist_ok=True) + with open(args.output, "w", newline="", encoding="utf-8") as f: + w = csv.DictWriter( + f, + fieldnames=["entity_id", "domain", "friendly_name", "device_class", "description"], + quoting=csv.QUOTE_MINIMAL, + ) + w.writeheader() + w.writerows(rows) + + print(f"Wrote {len(rows)} entities to {args.output}", file=sys.stderr) + + +if __name__ == "__main__": + main()