Add create-dashboard-api.py
This commit is contained in:
205
create-dashboard-api.py
Normal file
205
create-dashboard-api.py
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/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": "# <center>{{ now().strftime('%A, %B %d, %Y') }}</center>\n## <center>{{ now().strftime('%I:%M %p') }}</center>"
|
||||
},
|
||||
# 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": "<br><br><br><br><br>"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 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()
|
||||
Reference in New Issue
Block a user