Files
home-automation/apps/ui/main.py

127 lines
3.6 KiB
Python

"""UI main entry point."""
import logging
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from apps.ui.api_client import fetch_devices, fetch_layout
logger = logging.getLogger(__name__)
# Initialize FastAPI app
app = FastAPI(
title="Home Automation UI",
description="User interface for home automation system",
version="0.1.0"
)
# Setup Jinja2 templates
templates_dir = Path(__file__).parent / "templates"
templates = Jinja2Templates(directory=str(templates_dir))
# Setup static files
static_dir = Path(__file__).parent / "static"
static_dir.mkdir(exist_ok=True)
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
@app.get("/", response_class=HTMLResponse)
async def index(request: Request) -> HTMLResponse:
"""Redirect to dashboard.
Args:
request: The FastAPI request object
Returns:
HTMLResponse: Rendered dashboard
"""
return await dashboard(request)
@app.get("/dashboard", response_class=HTMLResponse)
async def dashboard(request: Request) -> HTMLResponse:
"""Render the dashboard with rooms and devices.
Args:
request: The FastAPI request object
Returns:
HTMLResponse: Rendered dashboard template
"""
try:
# Load layout from API
layout_data = fetch_layout()
# Fetch devices from API (now includes features)
api_devices = fetch_devices()
# Create device lookup by device_id
device_map = {d["device_id"]: d for d in api_devices}
# Build rooms with merged device data
rooms = []
for room in layout_data.get("rooms", []):
devices = []
for tile in room.get("devices", []):
# Merge tile data with API device data
device_data = {
"device_id": tile["device_id"],
"title": tile["title"],
"icon": tile["icon"],
"rank": tile["rank"],
}
# Add type, name, and features from API if available
if tile["device_id"] in device_map:
api_device = device_map[tile["device_id"]]
device_data["type"] = api_device.get("type")
device_data["name"] = api_device.get("name")
device_data["features"] = api_device.get("features", {})
else:
device_data["features"] = {}
devices.append(device_data)
# Sort devices by rank (ascending)
devices.sort(key=lambda d: d["rank"])
rooms.append({
"name": room["name"],
"devices": devices
})
logger.info(f"Rendering dashboard with {len(rooms)} rooms")
return templates.TemplateResponse("dashboard.html", {
"request": request,
"rooms": rooms
})
except Exception as e:
logger.error(f"Error rendering dashboard: {e}", exc_info=True)
# Fallback to empty dashboard
return templates.TemplateResponse("dashboard.html", {
"request": request,
"rooms": []
})
def main() -> None:
"""Run the UI application with uvicorn."""
import uvicorn
uvicorn.run(
"apps.ui.main:app",
host="0.0.0.0",
port=8002,
reload=True
)
if __name__ == "__main__":
main()