Home Assistant (app layer)
Dashboards (Lovelace), the Great Room AV stack, and household automations on home.vino.network. Access/SSH/API/Z-Wave infra is owned by the fritzlab skill home-assistant (reference/home-assistant.md). Token: VINO_HA_TOKEN in ~/.env.
Config is version-controlled at **`dfritz/home-assistant`** (code.fritzlab.net; clone `~/code/git/code.fritzlab.net/dfritz/home-assistant`): a manual mirror of the safe parts of HAOS `/config` — YAML config + includes, blueprints, `custom_components/frame_art`, `www/` cards, and a `dashboards/` snapshot of the storage-mode Lovelace (export, not live-sync). Gitignored: `secrets.yaml`, `.storage/`, the DB, `*.pem`, logs, deps/venv. Externally-managed components stay in their own repos: celebright → `dfritz/celebright`, hdmi_matrix → `dfritz/haas-hdmi-matrix-custom-component`. No CI auto-deploy — sync via `rsync -e "ssh -6"` to/from `home-assistant.vino.network:/config/`.
## Nest thermostats
Matter Server 9.1.0 and the matter integration provide local control for three
Nest Learning Thermostat 4th gen nodes plus their bridged sensors. Primary devices
are Entryway Nest, Master Bedroom Nest, and Sport Court Nest; climates are
climate.entryway_nest, climate.master_bedroom_nest, and
climate.sport_court_nest. Thermostats carry Matter Nest + Matter HVAC labels;
child devices are <Location> Sensor Nest and unlabeled. All three are forced-air
heat_cool zones.
The cloud nest fallback integration is not configured. It requires a dedicated
Vino Web OAuth client in Google Cloud project home-assistant-471823 (redirect
https://my.home-assistant.io/redirect/oauth) and a separate Device Access project;
do not reuse Lodge OAuth credentials, Device Access project, or Pub/Sub subscription.
Target cloud naming is <Zone> Google Nest and climate.<zone>_google_nest, labels
Google Nest + HVAC.
Recovery backup pre-nest-normalization-2026-07-18 (a7b09a9b) contains HA
registry/dashboard state without the database.
## Editing dashboards (Lovelace)
Both dashboards (`Overview` url_path `lovelace`, `Map`) are **storage mode** (UI-managed), not YAML — no file to edit. Drive over the WS API:
- Read: `{"type":"lovelace/config"}` (no `url_path` = default `Overview`) → full config (`views[]`).
- Write: `{"type":"lovelace/config/save","config":}` — **whole-config read-modify-write**, not per-view. Always back up the fetched config first; a bad save replaces every view.
- Views use `subview: true` for the per-device remotes (reached by nav, not the top tab bar). Card commands: copy a *proven* button from a working view rather than guessing service/command strings.
- No HACS, no custom themes (`frontend/get_themes` empty). Custom Lovelace cards: drop the JS in `/config/www/` (root-owned → `ssh -6 … sudo tee`), register via `{"type":"lovelace/resources/create","res_type":"module","url":"/local/.js?v=N"}`. Served at `
https://home.vino.network/local/.js`. Browser caches resources — bump `?v=` and hard-refresh (mobile app: restart) to pick up changes.
## Great Room TV / AV topology
TV = **Samsung Frame** (`media_player.the_frame_tv` power+vol+source `['TV','HDMI']`; `remote.the_frame_tv` needs Samsung `KEY_*` codes — see ). WoL power-on MAC `C8:A6:EF:AE:E5:FA` via `script.turn_on_great_room_tv_2`.
Sources feed an HDMI matrix; select.hdmi_matrix_vino_network_output_1 (named "Great Room TV") = current TV input, ..._output_3 = speakers. Options incl. Roku-Ultra, Roku-3, FireTvStick, From-GR-AVR, Kiosk1/2.
Matrix-source audio is the Denon AVR, not the TV: zones media_player.great_room (+ media_player.kitchen), source HDMI Matrix; volume = media_player.great_room, and the TV's own speaker is set near-mute by the building block. TV-direct audio = the TV itself (the remote card's volume is context-aware — see ).
Source switching = script.set_mode_great_room_*:
movie → Roku Ultra (alias set-mode-great-room-roku-ultra), roku_3, fire_tv_stick, music, camera_scanner.
- Each sets both matrix outputs then runs
script.building_block_set_great_room_to_hdmi_matrix (TV→HDMI, AVR zones on, vol 0.55, ALL ZONE STEREO).
Source devices: Roku (remote.roku_ultra/roku_3, commands lowercase home/back/up/down/left/right/select/info); Fire TV (remote.fire_tv_stick, commands UPPERCASE HOME/BACK/UP/DOWN/LEFT/RIGHT/CENTER/INFO/MENU). App shortcuts via media_player.select_source (Roku Plex source = Plex - Free Movies & TV).
Great Room AVR = Denon AVR-X2700H. setup_error plus a timeout on
:8080/goform/Deviceinfo.xml is a wedged receiver network stack; the narrow repair
is Denon telnet command NSRBT, wait for Deviceinfo HTTP 200, then reload the
Great Room config entry. This preserves power/mute state and restores
media_player.great_room + media_player.kitchen.
## Virtual remotes (Lovelace subviews, Overview dashboard)
- `great-room-tv-remote` — **the main one.** A bespoke custom card `custom:great-room-remote-card`: plus-shaped D-pad, context-aware volume, source pills (set_mode scripts), apps/playback, power toggle. Fits an iPhone with no scrolling; details in .
- `roku-ultra-remote`, `roku-3-remote`, `fire-tv-stick-remote` — older stock single-device remotes (still present).
URL: https://home.vino.network/lovelace/great-room-tv-remote. Launcher: a "Great Room TV" navigate-button under the Virtual Remotes heading on the kitchen_greatroom view (subviews aren't in the tab bar, so they need a navigate-button entry point).
Source-of-truth: `dfritz/home-assistant` repo → `www/great-room-remote-card.js` (vanilla custom element, no build step). Deployed copy → HA `/config/www/great-room-remote-card.js`, resource `/local/great-room-remote-card.js?v=N`. Robust layout: plus-shaped CSS-grid D-pad (no abspos) with Back/Home/Info column beside it, wrapping grids, single delegated click handler. Fits an iPhone with no scroll (~630px, ≤660 budget); apps row collapses in TV mode.
**Control target is explicit + visible** (a "Controlling: X" line + a `[Follow source] | [TV]` toggle):
- *Follow source* (default): D-pad/transport/apps drive the device the matrix is on (Roku `select`/lowercase, Fire TV `CENTER`/UPPERCASE). Falls back to TV when the matrix state isn't a known source (e.g. `Viewport16`).
- *TV*: forces `remote.the_frame_tv`. One-tap fallback if a source device (asleep Roku → "Error communicating with Roku API") doesn't respond. **Samsung `samsungtv` integration needs `KEY_*` codes** (`KEY_UP/DOWN/LEFT/RIGHT/ENTER/RETURN/HOME/INFO`, `KEY_VOLUP/VOLDOWN`) — lowercase words return HTTP 200 but the TV silently ignores them (this is why the original lowercase remote never actually drove the TV).
- Tapping a source pill switches the matrix (`set_mode` script) and snaps target back to Follow source.
**Volume/mute are context-aware too** (per-profile `volume` entity): TV target → `media_player.the_frame_tv` (Samsung supports `volume_set`); source target → `media_player.great_room` (Denon AVR zone, the audio path for matrix sources). The slider uses a timestamp guard (not `activeElement`) so frequent `hass` updates don't snap the thumb back mid-drag on iOS. Frame TV can't launch apps via `select_source` (source_list only `['TV','HDMI']`), so apps only show for Roku/Fire. All entities/commands live in `DEFAULTS` (config-overridable).
**Deploy after edit:** `node --check` then `cat www/great-room-remote-card.js | ssh -6 home-assistant.vino.network 'sudo tee /config/www/great-room-remote-card.js'`, bump resource `?v=` (WS `lovelace/resources/update`, resource_id `7ee4fcac14ea4a3b9ef76c0625a89721`), hard-refresh.