Skip to content

Architecture

jv edited this page Jun 6, 2026 · 2 revisions

Architecture

src/
  main.tsx            App bootstrap: applyTheme(), installHaptics()
  App.tsx             Top-level shell: sidebar, header, views, detail flyout
  config.ts           Seed catalogs (sample scenes[]/persons[]/rooms[], HA_URL/TOKEN); replaceable from the UI
  settings.ts         App settings (localStorage) + applyTheme()
  types.ts            Shared layout / entity types

  hooks/
    useHomeAssistant.ts  WebSocket connection, entity state, callHA, history/forecast
    useLayout.ts         Loads/saves the layout (views, tiles, glance); export/import; startBlank/reset
    useArtworkColor.ts   Extracts a dominant color from now-playing artwork

  lib/
    layout.ts          viewRows() and layout helpers
    tileSize.ts        Tile span/size logic
    glance.ts          At-a-glance metric catalog + computeMetric()
    mediaDevices.ts    Media de-dup: friendlyName, deviceNameKey, group/dedupe (+ manual merges)
    persons.ts         resolvePersons(): auto-discover person.* (config names override)
    weather.ts         resolveWeatherId(): auto-discover/select the weather.* entity
    colorExtract.ts    Canvas-based dominant-color extraction
    viewTransition.ts  View Transitions API wrapper (shared-element morphs)
    haptics.ts         navigator.vibrate + delegated press listener
    entityInfo.ts      Per-domain display helpers

  components/          One component per surface (see Features)
  styles/theme.css     All styling + animations (single stylesheet)

vite-layout-plugin.ts  Dev/preview middleware: GET/POST/DELETE /layout (honors LAYOUT_FILE)
layouts.json           Persisted custom layout (on the add-on: /data/layouts.json)

Data flow

  • useHomeAssistant opens the WS connection, subscribes to entity states, and exposes entities, connected, error, callHA(domain, service, …), getForecast, and getHistory.
  • useLayout loads the editable layout from /layout (falls back to a default) and writes changes back via the Vite middleware to layouts.json (or /data/layouts.json on the add-on). It also exposes exportLayout() / importLayout().
  • App resolves the active view, renders its scenes + tiles, and owns the DetailPanel flyout (entity controls, camera, history, links, quick actions).

Layout persistence plumbing

  • vite-layout-plugin.ts serves GET/POST/DELETE /layout, reading/writing a JSON file. The file path honors the LAYOUT_FILE env var (the add-on points it at /data/layouts.json).
  • For Ingress, Vite uses base: './', a BASE_URL-relative /layout fetch, and preview.allowedHosts: true so assets and the persistence API work behind /api/hassio_ingress/<token>/.

Settings persistence

  • App settings (HA URL, token, theme, accent) save to localStorage per browser/device by default.
  • Dashboard layout saves server-side to layouts.json via the Vite middleware — shared across devices on the same host, and persisted to /data/layouts.json on the add-on.
  • Remember connection on this server (opt-in) also stores the URL + token server-side (connection.json, /data/connection.json on the add-on) so new devices with no local token adopt it on first load. Off by default; the file is gitignored and never committed. See Configuration.

Tech stack

  • React 19.1, TypeScript ~5.8 (strict), Vite 6
  • home-assistant-js-websocket for the HA connection
  • @dnd-kit/* for drag-and-drop editing
  • Material Design Icons (mdi-* classes)
  • Single stylesheet: src/styles/theme.css

Clone this wiki locally