Home Assistant¶
The smart-home hub. Everything below — integrations, UI, automations — runs inside the homeassistant container on the IoT Stack.
Voice Pipeline¶
Fully local Assist pipeline — no cloud dependency for voice control. Three Wyoming protocol containers (apps/iot.yml) feed into HA's built-in Assist:
- Whisper — STT via OpenAI Whisper (tiny-int8 model, ~75MB RAM)
- Piper — TTS via rhasspy/piper (en-US Amy low-quality voice by default)
- openWakeWord — wake-word ("Hey Jarvis") detection on-device
All three are configured in HA under Settings → Devices & Services → Wyoming Protocol. Pipeline wired together at Settings → Voice assistants.
Custom Integrations (HACS)¶
Third-party HA integrations installed via HACS (Home Assistant Community Store):
| Integration | Purpose |
|---|---|
| HACS | Package manager for community integrations, themes, and frontend cards |
| Spook 👻 | Unlocks hidden HA services, exposes set_state/find_entity, adds useful Repairs issues |
| Alexa Media Player | Amazon Alexa device control + TTS |
| Xiaomi Home | Xiaomi/Aqara device integration |
| Panasonic Comfort Cloud | Panasonic AC control |
HACS auth uses a GitHub OAuth token (device-code flow, one-time setup). Updates surface in Settings → HACS and as a persistent notification.
Frontend Cards (HACS)¶
Custom Lovelace cards installed via HACS → Frontend. All 19 auto-register in Settings → Dashboards → Resources as /hacsfiles/<repo>/…js.
Used by the default /lovelace (Mushroom/Bubble) dashboard:
| Card | Repo | Purpose |
|---|---|---|
| Mushroom | piitaya/lovelace-mushroom |
Minimal, phone-friendly entity cards (chips, person, light, climate, fan, media-player, template) |
| Bubble Card | Clooos/Bubble-Card |
Modern buttons, pop-ups, and animated tiles — used for the Quick Actions row |
Added for the /lovelace-md3 Material Design 3 dashboard:
| Card | Repo | Purpose |
|---|---|---|
| Streamline Card | brunosabot/streamline-card |
DRY card templates — every MD3 room, scene, and nav strip uses a streamline template |
| Navbar Card | joseluis9595/lovelace-navbar-card |
Bottom/side nav bar (Home · Rooms · Media · Climate · System · More popup) |
| Stack In Card | custom-cards/stack-in-card |
Grouped card backgrounds — used in room tiles to merge header + controls |
| Vertical Stack In Card | ofekashery/vertical-stack-in-card |
Vertical grouping variant |
| Big Slider Card | nicufarmache/lovelace-big-slider-card |
120 px brightness slider — used on Living Room + Prince's Room light pages |
| Button Card | custom-cards/button-card |
Full-control button primitive; dep of several MD3 pieces |
| Config Template Card | iantrich/config-template-card |
JS-evaluated dynamic card config (e.g. colour-by-value) |
| Custom Card Features | Nerwyn/custom-card-features |
Inline tile-feature plugins (dep of ElementZoom MD3 big sliders) |
| Calendar Card Pro | alexpfau/calendar-card-pro |
Compact calendar agenda card |
| Simple Swipe Card | nutteloost/simple-swipe-card |
Horizontal swipe carousel for subpages |
| Simple Tabs Card | agoberg85/home-assistant-simple-tabs |
In-page tabs (used for room subviews) |
| Apex Charts Card | RomRider/apexcharts-card |
Climate 24 h inside/outside temperature chart |
| Weather Card Extended | Thyraz/weather-forecast-extended |
Rich weather tile with 5-day forecast |
| Lunar Phase Card | ngocjohn/lunar-phase-card |
Moon phase + lunar data on Climate + System pages |
| Mediocre HA Media Player Cards | antontanderup/mediocre-hass-media-player-cards |
Prettier media player (Spotify / TV / Echoes) |
| Timer Bar Card | rianadon/timer-bar-card |
Progress-bar card for timers / scheduled jobs |
| Location Timeline Card | konewka17/timeline_card |
Recent location timeline (placeholder on System page) |
Dashboards¶
Three dashboards are registered in /config/.storage/lovelace_dashboards. Toggle between them from the sidebar:
| URL path | Title | Purpose | Entry in sidebar |
|---|---|---|---|
/lovelace |
Overview | Default — sectioned all-Mushroom layout, device-type grouped | "Overview" |
/lovelace-md3 |
MD3 | Material Design 3 phone-first dashboard (room-based, Hue-style scene swatches) | "MD3" |
/lovelace-legacy |
Home (Legacy) | Preserved snapshot of the pre-Feature 3 dashboard for rollback | "Home (Legacy)" |
The default at sign-in is whichever the user sets under Profile → Default Dashboard. Swap the default by updating show_in_sidebar / require_admin fields in the registry, or simply pick from the sidebar.
Overview dashboard (/lovelace)¶
The default dashboard (/lovelace) is a sectioned, all-Mushroom layout. Controls are inline (no collapsed sliders, no room pop-ups), organized by device type for consistency. Bubble Card is used only for the Quick Actions row.
- Chips header — weather, AC state/temp, live motion count, next dusk, unavailable-entity count (tap the unavailable chip to open HA's filtered entity list)
- People — Mushroom person card
- Lights —
mushroom-light-cardfor every light (Living Room strip, Prince's Room main + strip, Kitchen, Bathroom); brightness, color, and color-temp sliders are inline - Switches — Chandelier, Accent, Front Door (three main switches), PC plug, Refrigerator plug. Fridge is inverted: tap → more-info, hold → toggle, to prevent accidental shutoff
- Climate —
mushroom-climate-cardforclimate.main_acwith HVAC modes and temperature controls inline, a chips row for inside/outside temp + daily/cooling energy, then each option (AI ECO, Nanoe, ECONAVI, iAuto-X, Vertical Swing, Horizontal Swing, Smart Climate boolean, Target Temp slider) as its own Mushroom card - Air Purifier —
mushroom-fan-cardfor the Xiaomi Elite, chips for PM2.5 (color-coded), PM10, filter life, and fault state, plus four Mushroom toggle cards for Plasma / UV / Alarm / Child Lock - Media —
mushroom-media-player-cardfor Spotify and Living Room TV - Sensors — chips row for all contact sensors (Main Door, Prince's Room, Bathroom, Mama's Room, Alexa connectivity), template tiles for both vibration sensors (Main Window / Secondary Window) with battery, Aqara TVOC tile (temp · humidity · VOC, icon color follows air quality), and a 3rd Reality temp/humidity tile
- Quick Actions — Bubble Card buttons: All Lights Off, Movie Mode (scene), Sleep Mode (
script.sleep_mode)
The previous dashboard is preserved at /lovelace-legacy (sidebar entry "Home (Legacy)") for rollback.
MD3 dashboard (/lovelace-md3)¶
Material Design 3, phone-first, inspired by ElementZoom/Material-Design-3-Dynamic-Mobile-Dashboard. Tailored to the five rooms in this home.
Structure — nine views, navbar on every page:
- Home (
/lovelace-md3/overview) — chip row (presence · weather · in/out temp · lights-on · PM2.5), Weather Card Extended, Person + Someone Home, four quick-action scene tiles (All Off / Movie / Sleep / Bright), and a grid of five room tiles (Living Room, Prince's Room, Kitchen, Bathroom, Mama's Room) — each a Streamline Card template (md3_room_card) showing temp · humidity, primary light, climate, and a door/motion badge. - Rooms — all five rooms condensed onto one page with full Mushroom light/climate/fan controls plus windows + vacuums.
- Living Room — Big Slider for RGB strip, three switches (Chandelier / Accent / Front Door), climate card, Mediocre media player for TV.
- Prince's Room — Big Sliders for both RGB lights, air purifier card, PM2.5 / VOC / humidity chips, door state, two Echo media cards.
- Other Rooms — Kitchen / Bathroom / Mama's — lights plus motion + door sensors.
- Media — Spotify, TV, all three Echoes (Mediocre cards).
- Climate — Weather Card Extended, AC control, Apex Charts 24 h inside/outside temperature, PM2.5 / humidity / VOC chips, Lunar Phase.
- Scenes — Hue-style colour swatches for each of the three RGB lights (
light.h618e,light.yeelink_sg_…,light.prince_s_room_strip_light). Tap any swatch →script.md3_rgb_presetapplieswarm / daylight / candle / reading / red / orange / yellow / green / blue / purple. - System — unavailable-entity count, Lunar Phase, WiFi QR placeholder.
Shared plumbing (in packages/md3_dashboard.yaml):
input_boolean.md3_scene_*— relax, movie, bright, focus (used by navbar popups).sensor.lights_living_room_on_count,sensor.lights_princes_room_on_count,sensor.lights_all_on_count— rollups used in chips.sensor.windows_open_count,sensor.doors_open_count,sensor.motion_active_count,sensor.media_players_active_count,sensor.unavailable_entities_count.sensor.md3_outside_temp,sensor.md3_inside_temp— null-safefloat(0)-guarded wrappers so card templates never break when the source isunknown.
Scripts (appended to config/scripts.yaml):
md3_all_lights_off— all lights + the three main switches off.md3_scene_movie,md3_scene_sleep,md3_scene_bright,md3_scene_focus— one-shot scene applications.md3_rgb_preset— parameterised:fields: { entity, preset }, dispatches viachoose:on preset name.
Theme — themes/md3.yaml defines md3_dark (primary) and md3_light. The MD3 dashboard pins theme: md3_dark in its top-level config so it's scoped to that URL path (the other two dashboards keep the user's picked theme).
Streamline templates used: md3_navbar, md3_title, md3_action_chip, md3_room_card, md3_preset_swatch, md3_scene_tile, md3_battery_chip.
Editing workflow — the canonical source is config/md3-dashboard.yaml (kept in git ignore but easy to read). After edits, run python3 /config/md3_publish.py to JSON-serialise it into .storage/lovelace.lovelace-md3 and docker restart homeassistant. The dashboard's UI Raw Editor still works; however, UI edits won't round-trip back into md3-dashboard.yaml — export manually if that happens.
Helper script — sleep_mode¶
Defined in appdata/homeassistant/config/scripts.yaml:
- Turns off all lights (
light.turn_offonentity_id: all) - Turns off the three main switches (Chandelier, Accent, Front-door light)
- Sets
climate.main_actocoolat 24°C
Backup & rollback¶
Storage-mode dashboards live at appdata/homeassistant/config/.storage/lovelace.<url_path> (JSON) and the registry at .storage/lovelace_dashboards. Before any structural change, back up both to /srv/storage/backups/homeassistant/md3-YYYYMMDD-HHMMSS/ and restart HA with docker restart homeassistant. Swap back in by overwriting the file from a backup and restarting.
When rolling back specifically from /lovelace-md3: delete or rename .storage/lovelace.lovelace-md3, remove its entry from lovelace_dashboards, restart. The 17 HACS cards stay installed and cost ~4 MB of config/www/community/.
Automations & Scenes¶
All presence-aware automations run off a composite binary_sensor.someone_home instead of person.prynstag, because indoor GPS on sm_g736w is flaky and the HA Companion app reports "not home" too often.
Composite presence — binary_sensor.someone_home¶
Defined in appdata/homeassistant/config/templates.yaml. Logical OR across five signal classes; any of them being true keeps someone_home on:
| Signal class | Entities | Decays after |
|---|---|---|
| WiFi primary | binary_sensor.prynstag_home_wifi — sensor.sm_g736w_wi_fi_connection is one of PrivateWifi / PrivateWifi-5g |
Instant |
| VPN active | sensor.sm_g736w_network_type == 'vpn' — WireGuard is always-on at home only; cellular confirms "away" |
Instant |
| Phone interactive | binary_sensor.sm_g736w_interactive == 'on' (screen on = user using phone nearby) |
Instant |
| GPS fallback | person.prynstag == 'home' |
Instant |
| Motion | binary_sensor.prince_s_echo_motion, binary_sensor.kitchen_light_occupancy |
15 min |
| Door interaction | binary_sensor.main_door_sensor_contact last_changed |
5 min |
| Room doors currently open | Main / Prince's room / Bathroom / Mama's room contact sensors | Instant |
| Any light or main switch on | Living-room strip, Prince's main + strip, Kitchen, Bathroom, Chandelier, Accent, Front-door | Instant |
Flip-to-off requires ALL of: WiFi disconnected · not on VPN · phone screen off · GPS not home · no motion 15 min · main door untouched 5 min · every light + main-switch off · every door closed. This makes false-negatives (away when actually home) practically impossible, at the cost of occasional false-positives (home when actually away) — preferred tradeoff for an "any sign of life" gate.
Android Companion-App gotcha for SSID reads: Android treats WiFi SSID as location data. The app permission alone isn't enough — the system Location master toggle also has to be ON, because Google treats SSID as location data. If the toggle is off, the app sees sensor.sm_g736w_wi_fi_connection = '<unknown>' and bssid = 02:00:00:00:00:00 (Android's redacted stand-ins), regardless of what permissions the app has. This homelab keeps system Location OFF by preference, so the WiFi-SSID signal is effectively permanently off — presence detection relies on the VPN-active signal instead (WireGuard is always-on at home, absent when on cellular, so network_type == 'vpn' is a clean "at home" proxy). Also note the Companion-App entity ID is sensor.sm_g736w_wi_fi_connection (underscore between wi and fi), not wifi.
Pre-wake sensor — sensor.prewake_time¶
Template sensor that returns sensor.sm_g736w_next_alarm − 10 min as a device_class: timestamp. HA's time trigger accepts it as a dynamic at: target, so the morning routine fires 10 min before whatever alarm the phone has set for tomorrow — no YAML changes when wake-up time shifts.
Automations¶
All 13 in appdata/homeassistant/config/automations.yaml, mode single, IDs feat4_001–feat4_014 (005b removed per "no AC when away" rule).
| ID | Alias | Trigger | Guard | Action |
|---|---|---|---|---|
| 001 | Bathroom — motion light at night | Bathroom occupancy on / off for 2 min | sun below horizon (on); skip off if light on > 10 min (manual override) | Toggle light.bathroom_light |
| 002 | Kitchen — motion light at night | Kitchen occupancy on / off for 3 min | Same manual-override heuristic | Toggle light.kitchen_light |
| 003 | Front door — night alert | Main door contact on | Sun below horizon | Front-door switch on 5 min + Alexa announce |
| 004 | Window vibration while away — alert | Either vibration sensor on | someone_home == 'off' |
Critical mobile push (alarm_stream channel) + Alexa announce on three echoes + Discord (notify.discord_home) + physical alarm switch |
| 005 | AC pre-cool on arrival | someone_home off→on |
Outside temp > 30 °C and AC off | climate.set_temperature cool 25 °C |
| 006 | Auto-off AC when away | someone_home on→off for 15 min |
AC not already off | climate.turn_off |
| 007 | Smart air purifier — PM2.5 based | PM2.5 > 35 µg/m³; or PM2.5 < 12 for 10 min | someone_home == 'on' (gated on presence — no running the fan for an empty house) |
Fan 80 % / off |
| 008 | Sunset — apply evening scene | Sun event sunset |
someone_home == 'on' |
scene.turn_on scene.evening |
| 009 | Morning routine — ramp Prince's strip | 10 min before next phone alarm (sensor.prewake_time), fallback weekday 10:00 if no alarm set |
someone_home == 'on' |
Strip 1 % → 60 % with 5-min transition |
| 010 | Bedtime — run sleep mode | 23:00 daily, OR wireless charger docked after 20:00 (nightstand) | someone_home == 'on' + ringer mode normal (skip if user already DND/silent) |
script.sleep_mode |
| 011 | Air purifier — filter life warning | Filter level below 10 % | (monotonic sensor, fires once per transition) | Mobile push + Alexa announce |
| 012 | Low battery — daily digest at 09:00 | 09:00 daily | Any device_class: battery sensor below 15 % |
One mobile push with rendered list |
| 013 | Door-open ventilation — Prince's room | Prince's room contact on | Humidity > 75 % and someone_home == 'on' |
Fan 100 % for 15 min |
| 014 | Vacuum on weekday departure | Weekday 09:00 | someone_home == 'off' |
vacuum.start on S8 MaxV Ultra |
Guards use binary_sensor.someone_home throughout — never person.prynstag directly.
Scenes¶
Defined in appdata/homeassistant/config/scenes.yaml; applied with scene.turn_on (YAML scenes are delta-apply, so no snapshot/restore side effects):
| Scene | Entities |
|---|---|
| Movie | Living-room strip 15 % RGB [120,60,180], Accent on, Chandelier + Front-door off, TV on |
| Evening | Living-room strip 60 % warm amber [255,171,64], Accent on, Chandelier off |
| Bright | Chandelier + Accent on, Living-room strip 100 % at 4000 K |
Notes¶
- Don't-run-when-away rule. Appliances that consume power (AC, purifier) are all gated on
someone_home == 'on'. The original speculative pre-cool (feat4_005b,detected_activity→ walking/in_vehicle while away) was removed because it deliberately fired the AC while the house was empty — conflicts with the rule even with the 30-min retraction. - Air purifier runs 24/7 when home. Earlier draft had a 00:00–06:00 quiet window; dropped because the user isn't bothered by the fan noise while sleeping, and poor air overnight is worse than the noise.
- Discord alerts.
notify.discord_homeis a REST notify service defined inconfiguration.yamlthat POSTs to a Discord webhook (URL insecrets.yaml → discord_webhook_home). Currently used byfeat4_004(window vibration); add to other critical alerts as needed. - Legacy removed: the "Lights on when Door open" automation (accent switch on Prince's room door) was deleted — it wasn't actually wanted.
automations.yamlpreviously had atemplatetrigger onsensor.air_quality_temperature | floatthat threwValueError: could not convert string to float: 'unknown'whenever the Aqara sensor went offline — that automation (Smart AC - Idle when room is cooled) was removed. Smart-idle logic will be rebuilt on the new presence sensors.- The numeric-state variant (
Smart AC - Cool when room is hot) was kept — numeric-state triggers don't throw onunknownvalues, they simply don't fire. - Scenes are also individually invocable from Quick Actions on the dashboard once added as Bubble Card buttons.