200 lines
6.6 KiB
Python
200 lines
6.6 KiB
Python
#!/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: |
|
|
# <center>{{ now().strftime('%A, %B %d, %Y') }}</center>
|
|
## <center>{{ now().strftime('%I:%M %p') }}</center>
|
|
- 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: |
|
|
<br><br><br><br><br>
|
|
"""
|
|
|
|
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": "# <center>{{ now().strftime('%A, %B %d, %Y') }}</center>\n## <center>{{ now().strftime('%I:%M %p') }}</center>"},
|
|
{"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()
|