"""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()