#!/usr/bin/env python3 """Create dashboard in Home Assistant via API""" import urllib.request import json import sys TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI4NmM2ZGNlMTY2MWU0M2U5YjQ2MDI3MjMxYjE0NDFlMyIsImlhdCI6MTc2NzE3ODUyNiwiZXhwIjoyMDgyNTM4NTI2fQ.E8eShOsejwDYglixpgM_d_JYBlB1OVNhN7cHPnPiLOs" HA_URL = "http://homeassistant.local:8123" def create_dashboard(): """Create the kiosk dashboard via API""" # Dashboard configuration (simplified - no card-mod for now) dashboard_config = { "title": "Kiosk Dashboard", "icon": "mdi:view-dashboard", "path": "dashboard-kiosk", "panel": False, "type": "sidebar", "cards": [ # Header with Date { "type": "markdown", "content": "#
{{ now().strftime('%A, %B %d, %Y') }}
\n##
{{ now().strftime('%I:%M %p') }}
" }, # Current Weather { "type": "weather-forecast", "entity": "weather.forecast_home", "name": "Current Weather", "show_forecast": True, "forecast_type": "daily" }, # Sun Information { "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"} ] }, # Public Transport { "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"} ] }, # Camera Motion Status { "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"} ] }, # Occupancy Summary { "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"} ] }, # Network Status { "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"} ] }, # Spacer for scrolling { "type": "markdown", "content": "




" } ] } # Try to get existing dashboards first url = f"{HA_URL}/api/lovelace/dashboards" req = urllib.request.Request(url) req.add_header("Authorization", f"Bearer {TOKEN}") req.add_header("Content-Type", "application/json") try: with urllib.request.urlopen(req) as response: dashboards = json.loads(response.read().decode()) print(f"Found {len(dashboards)} existing dashboards") # Check if dashboard already exists for dash in dashboards: if dash.get("url_path") == "dashboard-kiosk": print("Dashboard 'dashboard-kiosk' already exists!") print(f"Updating existing dashboard...") dashboard_id = dash.get("id") break else: dashboard_id = None except Exception as e: print(f"Could not get dashboards list: {e}") dashboard_id = None # Try to create/update via Lovelace config endpoint # Home Assistant stores dashboards in YAML, but we can try the API url = f"{HA_URL}/api/lovelace/config" req = urllib.request.Request(url) req.add_header("Authorization", f"Bearer {TOKEN}") req.add_header("Content-Type", "application/json") # Convert dashboard config to YAML string format # Home Assistant expects YAML for dashboard configs import re # Create YAML-like structure yaml_lines = [ "title: Kiosk Dashboard", "path: dashboard-kiosk", "icon: mdi:view-dashboard", "panel: false", "type: sidebar", "cards:" ] for card in dashboard_config["cards"]: yaml_lines.append(f" - type: {card['type']}") if "content" in card: # Handle multiline content content = card["content"].replace("\n", "\\n") yaml_lines.append(f" content: |") for line in card["content"].split("\n"): yaml_lines.append(f" {line}") if "entity" in card: yaml_lines.append(f" entity: {card['entity']}") if "name" in card: yaml_lines.append(f" name: {card['name']}") if "title" in card: yaml_lines.append(f" title: {card['title']}") if "entities" in card: yaml_lines.append(" entities:") for ent in card["entities"]: yaml_lines.append(f" - entity: {ent['entity']}") if "name" in ent: yaml_lines.append(f" name: {ent['name']}") if "icon" in ent: yaml_lines.append(f" icon: {ent['icon']}") if "show_forecast" in card: yaml_lines.append(f" show_forecast: {card['show_forecast']}") if "forecast_type" in card: yaml_lines.append(f" forecast_type: {card['forecast_type']}") yaml_content = "\n".join(yaml_lines) print("\n" + "="*60) print("Dashboard YAML Configuration:") print("="*60) print(yaml_content) print("="*60) # Try to save via API - Home Assistant may require manual creation # But we can try the config endpoint try: # Get current config req_get = urllib.request.Request(f"{HA_URL}/api/lovelace/config") req_get.add_header("Authorization", f"Bearer {TOKEN}") with urllib.request.urlopen(req_get) as response: current_config = response.read().decode() print("\nCurrent Lovelace config retrieved") except Exception as e: print(f"\nNote: Could not retrieve current config: {e}") print("\n✓ Dashboard configuration ready!") print(f"\nDashboard will be available at: {HA_URL}/dashboard-kiosk/0") print("\nNote: Home Assistant dashboards are typically created via the UI.") print("However, the configuration is ready above. You may need to:") print(" 1. Go to Settings > Dashboards > Add Dashboard") print(" 2. Use 'Raw configuration editor'") print(" 3. Paste the YAML above") return True if __name__ == '__main__': print("Creating Kiosk Dashboard in Home Assistant...") print(f"Home Assistant URL: {HA_URL}") print() create_dashboard()