🏠 Prožívání · Audio a TTS

Audio které tě nepřeruší ráno

Tři reproduktory, čtyři režimy, jeden orchestrátor. TTS jde přes Google Cast s tvrdým limitem 200 znaků na utterance — proto se ranní briefing rozdělí do dvou fází. Sleep guard ticho v noci. Prev_playing guard, aby se po TTS nepustila radiostanice z minulé rutiny do prázdné koupelny.

3Reproduktory
200Char TTS limit
2Briefing fáze
100TTS priorita

Co to dělá

Audio které ví, kdy mlčet

Tři reproduktory v bytě — kuchyně, koupelna, ložnice. Všechny Google Cast, všechny řízené přes sh_audio_brain_v2 (dispatcher) a sh_tts_orchestrator_v1 (řečí). Centrální audio_request proměnná — kdokoli může požádat o radio nebo TTS, brain rozhodne, který speaker a v jakém pořadí.

Google Cast má hard limit 200 znaků na jedno utterance. Delší text se useká uprostřed věty, user slyší „...možná už ti t". Proto je v sayTTS defenzivní truncation a ranní briefing je rozdělený do dvou fází — první ve 3:15 (čas, počasí, svátek, do 150 znaků), druhý o 15 min později (BTC, PM2.5, vlhkost, vtipný komentář, do 170 znaků).

Audio má prioritu 100 v priority engine — když TTS běží, světla (priorita 60) ani jiné automatizace ho nepřebijí. Po dokončení TTS se priority uvolní a může se resumovat předchozí radio (jen když prev_playing='yes' — guard po bathroom misroute bug).

Audio stránka v dashboardu — speakers, current mode, volume, briefing replay
Audio stránka v dashboardu — 3 speakers + Nest Hub Max, aktuální mode (TTS / radio / scene), volume controls

Denní provoz

Jak audio reaguje přes den

Většinu dne je ticho. Akce jsou rituální — ráno briefing, večer možná comfort suggest.

  1. 03:15

    Briefing fáze 1

    15 min před budíkem. Pozdrav, čas, datum, počasí dnes, svátek dne. Limit 150 znaků. Kuchyňský speaker (kde se ráno chystá káva). Po dokončení se spustí 15min countdown na fázi 2.

  2. 03:30

    Briefing fáze 2

    BTC kurz, PM2.5 venku a uvnitř, vlhkost, vtipný komentář od Gemini. Limit 170 znaků. Stejný speaker. Cíl: dokončit ranní informace dřív než odejdu do auta v 03:45.

  3. Den

    Idle, čekání

    sh_audio_request='idle'. Žádné automatické audio přes den. Speakers fungují jako TTS recipients pro alerty, jinak ticho. AI coordinator monitoruje situation, zatím nic nespouští.

  4. Večer

    Comfort suggest (možná)

    AI coordinator může vyhodnotit „evening + idle scene" → comfort_suggest. TTS přečte návrh: „Chceš spustit relax scénu?". Dispatch radio jen pokud user explicitně přijme přes Cube nebo Voice (ne timeout fallback).

  5. Noc

    Sleep silent

    sh_spim='yes' → priority engine zablokne TTS. Critical alerty (zaplavení, požár) jdou přes vlastní safety bypass. Komfortní hlášky čekají na probuzení.

Scény

Pět akcí, pět rolí

Většina je triggrovaná systémem, ne user inputem.

Ranní briefing

Dvě fáze, 15 min apart. Limit 150/170 chars. TV mute před, unmute po. Speaker = kuchyně (kde se chystá káva). Gemini generuje, sayTTS truncuje na 200 max.

Comfort suggest

AI coordinator vyhodnotí level 4 situation večer → suggest. Bez user accept (cube/voice) NE auto-execute — to byl bathroom misroute bug.

Bathroom radio

Motion v koupelně + TOD ráno → spustí radio (Italia Classic Hits, Sanremo feed). Stop při motion_off + 30s timeout. Resume guard kontroluje prev_playing='yes'.

Sleep silent

Sleep state → priority deny pro TTS. Critical alerts (gas, water leak) mají safety bypass. Briefing 03:15 jede normálně (sleep state už unset).

Resume after TTS

Když před TTS hrálo radio (prev_playing='yes', prev_mode='radio_*'), po dokončení TTS se obnoví. Bez prev_playing guardu by se resumovalo i když nic nehrálo.

Hardware

Co reálně mluví a hraje

Tři Google Cast koncové body + Homey jako orchestrátor.

Speaker kuchyně

Google Cast · Wi-Fi · TTS + radio

Hlavní speaker pro ranní briefing. Kuchyně je centrem rituálu — káva, chystání, rozhodnutí dne. TTS recipient pro většinu hlášek. Radio backup pro bathroom když koupelnový padne.

Speaker koupelna

Google Cast · Wi-Fi · ranní radio

Italian Classic Hits ráno při sprchování. Motion-trigger, motion_off + 30s stop. Po bathroom misroute bug 25.4. doplněn prev_playing guard, aby se radio nezapnulo z prázdna.

Speaker ložnice

Google Cast · Wi-Fi · evening

Lehčí použití — večerní hudba před spaním, alerty když user v ložnici. Sleep guard chrání před nočními TTS. Speaker variable sh_tts_speaker='ložnice' historicky, real cast jde do kuchyně.

Nest Hub Max ložnice

Google Cast · Wi-Fi · vizuál + audio

Sekundární výstup pro vizuální alerty — Nest Hub Max v ložnici. TV mute pipeline před TTS / unmute po (přes Android TV remote capabilities).

Voice intent Plánováno

Local LLM · Whisper · HA voice

Hlasové ovládání lokálně — Whisper STT + lokální LLM nebo HA Voice. Aktuálně user_intent přes Cubo + buttons. Voice je další iterace, závisí na LLM host (RPi5 nebo NAS).

Pro tech-savvy

Co se děje pod kapotou

Orchestrator, dispatcher, priority engine, prev_playing guard.

200 char Cast limit + briefing split

Google Cast SDK má hard limit 200 znaků na utterance. Překročí → cast stream padá nebo truncates uprostřed věty. NENÍ to bug, je to safety net v sh_gemini_brain_v1::sayTTS():

if (cleaned.length > 200) {
  cleaned = cleaned.substring(0, 200);
  logMsg('GOOGLE CAST: message truncated to 200 chars');
}

Briefing split do dvou fází:

  • briefing (3:15) — pozdrav, čas, datum, počasí, svátek (max 150 chars)
  • briefing2 (+15 min) — BTC, PM2.5, vlhkost, vtipný komentář (max 170 chars)

Orchestrace přes flow „SH – Morning – Briefing 2" s 15 min delay. Pending var: sh_morning_briefing2_pending_ts.

Audio brain + TTS orchestrator
  • sh_tts_orchestrator_v1 — vystaví TTS request, počká na completion, emituje tts_completed event. Drží sh_priority_active='tts' po dobu řeči.
  • sh_audio_brain_v2 — dispatcher pro non-TTS audio (radio, music, ambient). Čte sh_audio_request, rozhoduje speaker dle aktivní zóny a TOD. Emituje audio_dispatch event.
  • sh_tts_resume_exec_v1 — po TTS dokončení rozhodne, jestli resumovat předchozí audio. Guarduje na prev_playing='yes' (po bathroom misroute fix v1.8).
Priority engine (TTS=100, light=60)

Centrální arbitr. Každý request má prioritu, vyhraje vyšší. Když TTS aktivní (priority 100), light request (60) odložen. Tabulka:

  • 100 — TTS (briefing, alerts, voice response)
  • 80 — Critical alerts (water leak, gas, fire)
  • 60 — Light request
  • 50 — Audio comfort (radio, music)
  • 30 — Background ambient

Stuck recovery: když active='tts' > 1 min bez forward progress, brain guardian resetuje na none/idle.

Prev_playing guard (post bathroom misroute)

Bug 25.4. noc: po comfort_suggest TTS, ~46 s později bathroom radio sám spustil. Root cause: sh_tts_resume_exec_v1 fallback if (target === 'idle' && currentMode === 'radio_bathroom') resumoval bez ověření, že před TTS skutečně něco hrálo.

sh_audio_current_mode bylo zaseklé na radio_bathroom z ranní rutiny. Resume podmínka byla splněná i když speaker už dávno mlčel.

Fix v1.8: přidán guard if (sh_audio_prev_playing !== 'yes') return skip. Resume jen když před TTS reálně hrálo radio.

TV mute / unmute pipeline

Před každým TTS:

  1. Read TV state (Android TV remote, IP 192.168.1.245)
  2. Pokud volume > 0 → setCapability volume_mute = true, ulož original volume
  3. Spustí TTS
  4. Po tts_completed: setCap volume_mute = false, restore volume

Bez tohoto by TTS hlas konkuroval s TV soundu — ranní zprávy + briefing nebylo slyšet. Capability volume_mute je toggle, není potřeba čekat na driver ack.