diff --git a/create-dashboard-file-api.py b/create-dashboard-file-api.py new file mode 100644 index 0000000..95ccec5 --- /dev/null +++ b/create-dashboard-file-api.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +"""Create dashboard by writing to Home Assistant config directory via file editor API""" +import urllib.request +import json +import sys + +TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI4NmM2ZGNlMTY2MWU0M2U5YjQ2MDI3MjMxYjE0NDFlMyIsImlhdCI6MTc2NzE3ODUyNiwiZXhwIjoyMDgyNTM4NTI2fQ.E8eShOsejwDYglixpgM_d_JYBlB1OVNhN7cHPnPiLOs" +HA_URL = "http://homeassistant.local:8123" + +DASHBOARD_YAML = """title: Kiosk Dashboard +path: dashboard-kiosk +icon: mdi:view-dashboard +panel: false +type: sidebar +cards: + - type: markdown + content: | + #
{{ now().strftime('%A, %B %d, %Y') }}
+ ##
{{ now().strftime('%I:%M %p') }}
+ - type: weather-forecast + entity: weather.forecast_home + name: Current Weather + show_forecast: true + forecast_type: daily + - type: entities + title: ๐ŸŒ… Sun Information + entities: + - entity: sun.sun + name: Sun Position + icon: mdi:weather-sunny + - entity: sensor.sun_next_rising + name: Sunrise + icon: mdi:weather-sunset-up + - entity: sensor.sun_next_setting + name: Sunset + icon: mdi:weather-sunset-down + - entity: sensor.sun_next_dawn + name: Dawn + icon: mdi:weather-sunset-up + - entity: sensor.sun_next_dusk + name: Dusk + icon: mdi:weather-sunset-down + - type: entities + title: ๐Ÿš† Public Transport + entities: + - entity: sensor.roslagsbanan_line_28_to_stockholms_ostra + name: To Stockholm ร–stra + icon: mdi:train + - entity: sensor.roslagsbanan_line_28_to_akersberga + name: To ร…kersberga + icon: mdi:train + - entity: sensor.sl_departure_sensor_9636_bravalavagen + name: SL Departure + icon: mdi:bus + - entity: sensor.next_departure_time + name: Next Departure + icon: mdi:clock-outline + - type: entities + title: ๐Ÿ“น Camera Status + entities: + - entity: binary_sensor.backyard_motion + name: Backyard Motion + icon: mdi:motion-sensor + - entity: binary_sensor.frontdoor_motion + name: Front Door Motion + icon: mdi:motion-sensor + - entity: binary_sensor.driveway_motion + name: Driveway Motion + icon: mdi:motion-sensor + - entity: binary_sensor.roofcam_motion + name: Roof Camera Motion + icon: mdi:motion-sensor + - type: entities + title: ๐Ÿ‘ฅ Occupancy Summary + entities: + - entity: sensor.backyard_person_count + name: Backyard People + icon: mdi:account-group + - entity: sensor.frontdoor_person_count + name: Front Door People + icon: mdi:account-group + - entity: sensor.driveway_person_count + name: Driveway People + icon: mdi:account-group + - entity: sensor.roofcam_person_count + name: Roof Camera People + icon: mdi:account-group + - type: entities + title: ๐ŸŒ Network Status + entities: + - entity: sensor.xe75_download_speed + name: Download Speed + icon: mdi:download + - entity: sensor.xe75_upload_speed + name: Upload Speed + icon: mdi:upload + - entity: sensor.external_ip + name: External IP + icon: mdi:ip-network + - entity: binary_sensor.xe75_wan_status + name: WAN Status + icon: mdi:router-wireless + - type: markdown + content: | +




+""" + +def write_file_via_api(file_path, content): + """Write file using Home Assistant file editor API""" + # Try file editor API endpoint + url = f"{HA_URL}/api/file_editor/write" + + data = { + "path": file_path, + "content": content + } + + req = urllib.request.Request(url, data=json.dumps(data).encode()) + req.add_header("Authorization", f"Bearer {TOKEN}") + req.add_header("Content-Type", "application/json") + + try: + with urllib.request.urlopen(req) as response: + result = json.loads(response.read().decode()) + if result.get("success"): + print(f"โœ“ Successfully wrote file: {file_path}") + return True + else: + print(f"โœ— Failed to write file: {result.get('error', 'Unknown error')}") + return False + except urllib.error.HTTPError as e: + error_msg = e.read().decode() + print(f"โœ— HTTP Error {e.code}: {error_msg[:200]}") + return False + except Exception as e: + print(f"โœ— Error: {e}") + return False + +def create_dashboard(): + """Create dashboard by writing to storage directory""" + + # Home Assistant stores dashboards in .storage/lovelace/ + # Try different possible paths + paths_to_try = [ + ".storage/lovelace/dashboard-kiosk.yaml", + "config/.storage/lovelace/dashboard-kiosk.yaml", + "dashboard-kiosk.yaml" + ] + + print("Attempting to create dashboard via file editor API...") + print() + + for path in paths_to_try: + print(f"Trying path: {path}") + if write_file_via_api(path, DASHBOARD_YAML): + print(f"\nโœ“ Dashboard created at: {path}") + print(f"Dashboard URL: {HA_URL}/dashboard-kiosk/0") + return True + print() + + # If file editor doesn't work, try creating via Lovelace storage format + print("Trying Lovelace storage format...") + storage_data = { + "title": "Kiosk Dashboard", + "icon": "mdi:view-dashboard", + "url_path": "dashboard-kiosk", + "require_admin": False, + "show_in_sidebar": True, + "config": { + "title": "Kiosk Dashboard", + "path": "dashboard-kiosk", + "icon": "mdi:view-dashboard", + "panel": False, + "type": "sidebar", + "cards": json.loads(json.dumps([ + {"type": "markdown", "content": "#
{{ now().strftime('%A, %B %d, %Y') }}
\n##
{{ now().strftime('%I:%M %p') }}
"}, + {"type": "weather-forecast", "entity": "weather.forecast_home", "name": "Current Weather", "show_forecast": True, "forecast_type": "daily"}, + # ... simplified for storage format + ])) + } + } + + storage_path = ".storage/lovelace.dashboards" + if write_file_via_api(storage_path, json.dumps(storage_data, indent=2)): + return True + + print("\n" + "="*60) + print("Could not create dashboard via API.") + print("Home Assistant dashboards must be created via the UI.") + print("="*60) + print("\nDashboard YAML is ready in: /home/kyle/scripts/dashboard-kiosk-final.yaml") + print("\nPlease create it manually:") + print("1. Settings > Dashboards > Add Dashboard") + print("2. Raw configuration editor > Paste YAML") + + return False + +if __name__ == '__main__': + create_dashboard()