ClothesCast can publish the rendered forecast sentence to your MQTT broker after each scheduled twice-daily refresh, so Home Assistant (or any other MQTT-aware consumer) can speak it on a trigger of your choice — a wardrobe door opening, a bathroom humidity spike after a shower, a fixed time of day, or any other automation you wire up.
This is the “single source of truth lives in the app” path: your tuned clothes rules and the rain / calendar / evening-event heuristics all stay in ClothesCast, and Home Assistant is just the dumb plumbing that reads a string and speaks it.
The bridge is off by default. Turning it on relaxes the “insight prose never leaves the device” guarantee documented in PRIVACY.md — but only to a broker you configure yourself; no developer-operated service ever sees the payload.
homeassistant.local) manually.1883 plain / 8883 TLS — the toggle
swaps the port for you when you flip TLS.Topic prefix defaults to clothescast/default. Today’s forecast
publishes to <prefix>/today/text; tonight’s to <prefix>/tonight/text.
The outfit image, the TTS audio, and a combined card-plus-announcement
MP4 (when published) land on <prefix>/<period>/image,
<prefix>/<period>/audio, and <prefix>/<period>/video respectively.
Each fully-successful publish is also mirrored to <prefix>/now/<kind> —
<prefix>/now/text, <prefix>/now/image, <prefix>/now/audio,
<prefix>/now/video, and <prefix>/now/timestamp — so a consumer can
subscribe to a single “latest” topic without having to switch on today
vs tonight. Whichever period most recently published is what now
reflects.
Trigger your automations on <prefix>/now/timestamp. The now
set updates as an atomic bundle, and now/timestamp (epoch
milliseconds, as a string) is written last of all — only after
now/image, now/audio, now/video, and now/text have each
settled. So a change on now/timestamp is the single signal that the
whole bundle is in place: trigger on it and read the sibling now/*
topics, and you’ll never pick up a now/image / now/audio /
now/video / now/text left over from a different forecast. It also
doubles as a dedupe key — every topic is retained, so a consumer
that reconnects (HA restart, network blip) is re-delivered the last
bundle on connect; remembering the last now/timestamp you acted on
lets you skip re-announcing it rather than replaying a stale clip at
reboot.
Modalities absent from the current delivery (e.g. an outfit render
failed, or you’re on device TTS so no audio bytes exist) clear their
now/* slot with an empty retained payload — MQTT’s convention for
“delete the retained message” — so you never read a stale
image/audio/video left over from a previous bundle. now/text is held
back if any of now/image / now/audio / now/video fails, and
now/timestamp is held back if now/text fails, so a now/timestamp
update always implies a fully coherent bundle settled successfully. If
any period publish in the bundle fails outright, the entire now
mirror is skipped — the previous fully-successful now set stays
intact rather than being half-overwritten. MQTT itself has no
transactional primitive across topics, so a fresh-reconnect consumer
reading the retained now/* topics during a partial-failure window may
briefly observe a mismatch; triggering on now/timestamp — the last
write — and gating reads on its updates sidesteps this.
The next scheduled refresh (07:00 by default for today, 19:00 for tonight — configurable in Settings → Schedule) will publish a retained MQTT message to each topic.
If you don’t already have an MQTT broker, install the Mosquitto broker add-on inside Home Assistant (Settings → Add-ons → Add-on Store → Mosquitto broker → Install → Start). You don’t need to touch the Configuration tab — Log Destinations and Log Types can stay on their defaults.
The Mosquitto HA add-on uses Home Assistant’s own user system for MQTT authentication by default, so you create the MQTT account the same way as any other HA user:
ClothesCast. Username: clothescast.1883 (or flip TLS for 8883), tick
the username field and paste the password, save.Don’t reuse your own HA user for this. A dedicated account makes the publisher’s traffic easy to spot in MQTT logs and makes the access revocable in one click if you ever want to turn the bridge off permanently.
By default the Mosquitto add-on grants every authenticated HA user
full access to every topic. For a personal LAN-only setup that’s
fine. If you’d rather lock the clothescast user down to only the
topics ClothesCast actually writes:
/share/mosquitto/acl.conf (via the File Editor
add-on, the Studio Code Server add-on, or SSH) with:
user clothescast
topic write clothescast/default/#
That grants write-only access on the topic prefix and nothing else. Adjust the topic if you customised the prefix in the ClothesCast Smart Home settings.
customize:
active: true
folder: mosquitto
Save.
Home Assistant’s MQTT integration itself reads via the broker’s own internal connection (a separate, privileged client), so the ACL above only constrains the ClothesCast publisher — it doesn’t break HA’s ability to subscribe to the topic for the automation that speaks the forecast.
If you’re running a standalone Mosquitto outside Home Assistant instead of the HA add-on, the user creation step uses
mosquitto_passwd -c /etc/mosquitto/passwd clothescastand the same ACL file syntax inmosquitto.conf(acl_file /etc/mosquitto/acl). HA-side YAML for reading the sensor is identical.
Add the following to configuration.yaml (or anywhere your
mqtt: block lives):
mqtt:
sensor:
- name: "Clothescast today"
unique_id: clothescast_today
state_topic: "clothescast/default/today/text"
value_template: ""
- name: "Clothescast tonight"
unique_id: clothescast_tonight
state_topic: "clothescast/default/tonight/text"
value_template: ""
# Single "latest" sensor — mirrors whichever period last published, so
# an automation can speak the most recent forecast without branching
# on today vs tonight.
- name: "Clothescast now"
unique_id: clothescast_now
state_topic: "clothescast/default/now/text"
value_template: ""
# Commit marker — epoch-millis written *last* once the whole `now`
# bundle is in place. Trigger your automations on a state change of
# this sensor (not on the prose sensor) when you want them to fire on
# each new forecast: by the time it changes, now/text, now/image,
# now/audio, and now/video are all settled and coherent.
- name: "Clothescast now updated"
unique_id: clothescast_now_updated
state_topic: "clothescast/default/now/timestamp"
device_class: timestamp
# Topic carries epoch milliseconds; the timestamp device_class wants a
# timezone-aware datetime, which as_datetime() returns (UTC) for a
# numeric unix timestamp in seconds.
value_template: ""
Restart Home Assistant or reload MQTT entries; the sensors should populate within seconds of the next ClothesCast refresh (or instantly, if you’ve already done one — retained messages are delivered to new subscribers on connect).
To fire an automation each time a fresh forecast lands, trigger on the commit marker rather than the prose sensor:
triggers:
- trigger: state
entity_id: sensor.clothescast_now_updated
This guarantees every now/* topic is already in place when the
automation runs, and — because the marker only advances on a genuinely
new bundle — it won’t re-fire when HA reconnects and re-reads the
retained set.
Alongside the prose sensor, ClothesCast publishes a PNG outfit card to
<prefix>/<period>/image (e.g. clothescast/default/today/image). The
card is 800 × 480 px (Nest Hub 7” native resolution) and shows:
HA’s camera.mqtt integration turns the retained binary payload into a
camera.* entity; a one-line automation then pushes it to the Nest Hub
display via media_player.play_media.
The result: at your morning alarm time the Hub shows the outfit picture alongside the spoken briefing — “T-shirt and shorts” on screen while the voice reads the full forecast.
configuration.yamlAdd under your existing mqtt: block (no platform: mqtt line — that
is implied when the entry sits under mqtt:):
mqtt:
camera:
- name: "Clothescast today outfit"
topic: "clothescast/default/today/image"
- name: "Clothescast tonight outfit"
topic: "clothescast/default/tonight/image"
Reload MQTT (Developer Tools → YAML → Reload MQTT) or restart HA so
the entities appear as camera.clothescast_today_outfit and
camera.clothescast_tonight_outfit.
Then find each entity’s access token in Developer Tools → States →
search camera.clothescast → open Details. Copy the access_token
value — you’ll need it in the automation below.
alias: Show outfit on kitchen Hub at 07:01
description: ""
mode: single
triggers:
- trigger: time
at: "07:01:00"
conditions: []
actions:
- action: media_player.play_media
target:
entity_id: media_player.kitchen_hub
data:
media_content_id: "http://192.168.x.x:8123/api/camera_proxy/camera.clothescast_today_outfit?token=<access_token>"
media_content_type: image/jpeg
Replace media_player.kitchen_hub with your actual Nest Hub entity ID
(find it under Settings → Devices & Services → Google Cast),
192.168.x.x with your HA instance’s local IP address, and
<access_token> with the token you copied from the entity details.
Use the IP address, not homeassistant.local. mDNS does not
resolve across VLANs or subnets, so the Hub will fail to fetch the
image if you use a hostname. The IP address works regardless of network
topology as long as the Hub can reach your HA instance on port 8123.
The access token is long-lived and stable across refreshes — unlike the
entity_picture session token it does not rotate on each payload
change, so you only need to paste it once. You can combine this action
with Option A/B/C below in a single automation so the Hub shows the
picture and speaks the forecast — either at the same moment, or
serially (speak first, then show the picture). See “Chaining the
spoken forecast and the outfit image” further down for the YAML
shape.
Note on external URLs. If your Nest Hub cannot reach your HA instance’s local IP directly, use HA’s external URL (
https://your-ha.duckdns.org) instead. The camera proxy path and access token are the same either way.
For a Nest Hub, the tidiest result is one media item that shows the
outfit card and plays the spoken briefing over it, with no parallel
TTS + image dance. ClothesCast publishes exactly that to
<prefix>/<period>/video (mirrored to <prefix>/now/video): an MP4
with the 800 × 480 outfit card as a static video frame and the Gemini
TTS audio as the audio track. Hand it to a Cast receiver and the card
fills the screen while the forecast plays.
This is published only when both an outfit image and Gemini TTS audio exist for the delivery (Gemini engine selected, audio not suppressed by “don’t speak at home”); otherwise the slot is cleared with an empty retained payload like any other absent modality.
Like the audio clip, media_player.play_media needs an HTTP URL and HA
won’t read an MQTT binary payload into the media player directly — so
the MP4 has to land somewhere HA serves over HTTP (e.g.
config/www/clothescast_now.mp4, fetchable at
http://<ha-ip>:8123/local/clothescast_now.mp4). Use the same
write-to-file recipe as the audio clip below (Node-RED mqtt in →
file, or a shell_command running mosquitto_sub), pointed at
clothescast/default/now/video, then cast it:
triggers:
- trigger: state
entity_id: sensor.clothescast_now_updated
actions:
- action: media_player.play_media
target:
entity_id: media_player.kitchen_hub
data:
media_content_id: "http://192.168.x.x:8123/local/clothescast_now.mp4"
media_content_type: video/mp4
The card disappears when the clip ends. A Cast receiver returns to its idle / photo screen once the MP4 finishes, so the card stays up only for the length of the announcement. Keeping it up longer is a known follow-up (a configurable post-speech hold baked into the clip).
When the Gemini TTS engine is selected (Settings → Voice → Gemini),
ClothesCast publishes the synthesised audio as a WAV clip to
<prefix>/<period>/audio (e.g. clothescast/default/today/audio).
The payload is signed 16-bit mono PCM at the sample rate Gemini
returned, wrapped in a canonical 44-byte RIFF/WAVE header — playable
as-is by ffmpeg, browsers, and media_player.play_media when handed
via an HTTP fetch (HA doesn’t read MQTT binary payloads directly into
the media player). It’s exactly the bytes the phone speaks, so any
“speak it on the Hub” automation built around the prose sensor or one
of the TTS options below stays in lockstep with the phone.
Two things to know before you wire anything up:
The simplest way to make the Hub actually speak is still options A /
B / C below: trigger an automation on the now/timestamp commit marker
(the sensor.clothescast_now_updated sensor above) and let HA’s TTS
service synthesise — that path is already paved end to end. Triggering
on the commit marker rather than the prose sensor guarantees the audio
and image are already in place when the automation runs. The audio topic is here for setups that already prefer a fixed
voice clip over re-synthesising in HA (e.g. music_assistant.play_announcement
→ media URL flows), and for users who want to capture the rendered
briefing for their own pipelines.
media_player.play_media needs an HTTP URL, and HA won’t read an MQTT
binary payload into the media player directly — so the WAV has to land
on disk somewhere HA serves over HTTP. HA exposes the config/www/
directory at /local/, so a file written to
config/www/clothescast_now.wav is fetchable at
http://<ha-ip>:8123/local/clothescast_now.wav.
The Node-RED add-on is the least-fiddly way to do that write — it holds an always-on subscription and dumps the raw bytes in three nodes:
mqtt in — topic clothescast/default/now/audio, Output set
to a Buffer (not “a parsed JSON object” or “a String”). The payload
is binary WAV; decoding it as a string corrupts it.switch — drop the empty retained “clear” payloads. Add one rule,
msg.payload → length (or a function node returning the message
only when msg.payload.length > 0). Without this guard a clear
message (see the empty-retained-payload note near the top of this
doc) truncates clothescast_now.wav to zero bytes the moment a
period publishes with no audio.file (write) — filename /config/www/clothescast_now.wav,
action overwrite file, “add newline to each payload” off. Wire
mqtt in → switch → file.Create config/www/ first if it doesn’t already exist (HA only
auto-creates it in some installs). After the next ClothesCast refresh —
or immediately, since the audio topic is retained — the file appears and
is served at http://<ha-ip>:8123/local/clothescast_now.wav.
Then play it from any automation:
- action: media_player.play_media
target:
entity_id: media_player.kitchen_hub
data:
media_content_id: "http://192.168.x.x:8123/local/clothescast_now.wav"
media_content_type: music
Use the IP address, not homeassistant.local, for the same cross-VLAN
mDNS reason as the outfit-image automation above. music is the most
broadly accepted media_content_type for a raw audio URL on Cast
targets; audio/x-wav also works on most.
No-Node-RED alternative. A shell_command wrapping
mosquitto_sub -C 1 -t clothescast/default/now/audio > /config/www/clothescast_now.wav
does the same write, but it re-subscribes on every call and you have to
guard the empty-payload clears yourself (a zero-byte capture overwrites
the good clip). Node-RED’s persistent subscription plus the switch
guard handle both cleanly, which is why it’s the recommended path.
As of mid-2026, getting Google Home / Nest devices to actually speak arbitrary text on demand is genuinely fiddly — Google has been actively churning the Cast pipeline and several “obvious” paths are flaky on Nest Minis specifically. Three options below; quick comparison first.
| A. notify.google_assistant_sdk | B. tts.speak → MA media_player |
C. tts.cloud_say / tts.google_translate_say | |
|---|---|---|---|
| Setup cost | Google Cloud project + OAuth in HA | One add-on install | Nabu Casa sub (cloud_say) or none (google_translate_say) |
| Preamble before the text | Yes — Google’s broadcast service prepends “There’s a message, it says…” / “Here’s a message for X: …” with no flag to suppress | No | No |
| Targets a specific speaker | Yes — if HA language is bare “English” (en-US). Other “English (XX)” entries fall back to broadcast-to-all. | Yes — always, via media_player.* entity ID; no locale dependency |
Yes — always, via entity_id: media_player.* |
| Target value format | Bare room name from Google Home (Master Bathroom) |
HA entity ID (media_player.master_bathroom_display) |
HA entity ID (media_player.master_bathroom_display) |
| Voice quality | Google Assistant voice (good) | Cast TTS — either Google Translate (free) or Nabu Casa (good) | Same as Music Assistant uses, just without the player-state restoration |
| Reliability on Nest Mini | Best (sidesteps Cast pipe entirely) | OK — wraps Cast with state-restoration, masks some flakiness | Worst on Nest Mini specifically as of early 2026 |
| Reliability on Nest Hub | Good | Good — Hubs tolerate Cast TTS better than Minis do | OK |
| State restoration (resumes previous playback) | N/A — broadcast doesn’t take over playback | Yes | No |
Rough decision tree:
tts.cloud_say working on your hardware and don’t
want to install Music Assistant: Option C.Three options in detail:
The YAML below is in the UI-editor format Home Assistant 2024.10+
uses: top-level alias: / triggers: / actions:, with trigger:
inside each trigger item and action: inside each action item. Paste
directly into Settings → Automations → New automation → Edit in YAML.
If you maintain configuration.yaml by hand, wrap each example in
automation: and convert triggers: / trigger: / actions: /
action: to the old plural-less form yourself.
notify.google_assistant_sdkUses Google’s own broadcast pipeline — the same backend as a spoken
“Hey Google, broadcast …” — rather than pushing audio over Cast.
Because it sidesteps Cast TTS entirely, it tends to work where
tts.cloud_say and the Music Assistant TTS-via-announce path
currently fail.
Setup needs a Google Cloud project with OAuth credentials added to Home Assistant (one-time setup, documented in the google_assistant_sdk integration page).
alias: Speak forecast when wardrobe opens
description: ""
mode: single
triggers:
- trigger: state
entity_id: binary_sensor.wardrobe_door
to: "on"
conditions: []
actions:
- action: notify.google_assistant_sdk
data:
message: ""
target:
- Master Bathroom
Two caveats specific to this path:
A Google broadcast preamble is baked into the service (“There’s a message, it says…”, or for a targeted broadcast something like “Here’s a message for Master Bathroom: …”) and there is no flag to suppress it. If you want the speaker to just speak the forecast with no preamble, use Option B below.
The target: field is the room name as it appears in Google
Home, on its own. Just Master Bathroom — not the combined
“Master Bathroom Display - Master Bathroom” string Google Home
shows in its device listing, and not the device name on its own.
Targeting only routes when HA’s interface language resolves to
English (US). Settings → System → General → Language: “English”
(no country suffix) resolves to en-US under the hood — that’s the
one that works, and matches what most installs default to.
“English (United Kingdom)” is a distinct option in HA’s language
picker — if you’ve explicitly chosen that one, the integration
silently appends the target string to the broadcast text instead
of routing, and you’ll hear “to master bathroom” spoken out loud
followed by the forecast going to every speaker.
(HA’s Country field on the Home Information page is separate metadata — sun position, currency, etc. — and doesn’t affect the SDK locale.)
If you’ve intentionally picked “English (United Kingdom)” for date
/ number formatting and want to keep it, use Option B below; it
routes via media_player.* entities and is locale-independent.
tts.speak → Music Assistant media_playerPlays HA TTS through a Music Assistant-owned media_player.* entity.
MA exposes the player’s MEDIA_ANNOUNCE capability, so HA’s tts.speak
routes through MA’s announcement queue automatically — you get state
restoration (whatever was playing before the announcement resumes
after) without naming an MA-specific service. No “There’s a message,
it says…” preamble; targeting is by HA entity ID so it’s
locale-independent.
The price of admission is the Music Assistant Server add-on
(Settings → Add-ons → Add-on Store → Music Assistant → Install →
Start) plus the Music Assistant core HA integration
(Settings → Devices & Services → Add Integration → Music Assistant —
auto-detects a Server running on the same HA instance). Once both are
up, MA auto-discovers your Cast devices and exposes them as
media_player.* entities. You’ll also need at least one TTS engine
configured — tts.home_assistant_cloud if you have Nabu Casa,
otherwise the free Google Translate integration (Settings →
Devices & Services → Add Integration → Google Translate text-to-speech).
It generates a per-language tts.* entity (e.g. tts.google_en_com),
which is what you’ll target in the example below.
alias: Speak forecast when wardrobe opens
description: ""
mode: single
triggers:
- trigger: state
entity_id: binary_sensor.wardrobe_door
to: "on"
conditions: []
actions:
- action: tts.speak
target:
entity_id: tts.home_assistant_cloud
data:
media_player_entity_id: media_player.master_bathroom_display
message: ""
tts.home_assistant_cloud is the canonical entity for Nabu Casa
TTS. If you’re using a different TTS engine, replace the
target.entity_id with whatever tts.* entity HA created for it —
the Google Translate integration, for instance, generates a
per-language entity like tts.google_en_com, not a bare
tts.google_translate; find the actual ID in Developer Tools →
States → search tts..
The media_player_entity_id here is the MA-owned entity for that
speaker (it appears under HA’s Music Assistant integration after
discovery completes). Pointing at it is what triggers MA’s
announcement-queue / state-restoration behaviour; pointing the same
field at the raw Cast media_player.* entity instead works too,
that’s Option C below, but skips the state-restoration wrapper.
Note on legacy
mass.announce. Older guides (including earlier revisions of this one) usemass.announcewithmessage:+target_player:. That was the HACS-era custom integration’s service and is no longer available in the Music Assistant core integration as of 2025 — swap in thetts.speakshape above.
Still rides the Cast pipe under the hood, so subject to the early-2026 “Nest Mini intermittently silent” reports — but Music Assistant’s player-state handling masks a lot of the flakiness, and Nest Hubs (with displays) generally behave better on the Cast path than the smaller Minis do.
tts.cloud_say → media_player.* CastThe classic, simplest setup — but currently the least reliable on Nest Mini specifically. Listed for completeness; not recommended as the first thing to try. If it works on your hardware, great; if it doesn’t, jump to Option A or B.
alias: Speak forecast when wardrobe opens
description: ""
mode: single
triggers:
- trigger: state
entity_id: binary_sensor.wardrobe_door
to: "on"
conditions: []
actions:
- action: tts.cloud_say
data:
entity_id: media_player.master_bathroom_display
message: ""
(tts.google_translate_say is the free alternative if you don’t have
Nabu Casa — same shape, robot-Google-Translate voice.)
Two automations side by side work fine, but a single automation is easier to keep in sync (one trigger time, one entity to retarget when you move the Hub). Two patterns, depending on whether you want them at the same moment or one after the other.
Both examples below use the Option A (notify.google_assistant_sdk)
shape, since that’s the path verified end-to-end on this project’s
own setup. The picker below the serial example covers what to swap
in if you’re on Option B or C instead. Each TTS service expects a
different data: shape — target: for Option A,
media_player_entity_id: for B, entity_id: for C — so don’t
hot-swap the service inside an example; copy the YAML for the
service you’re actually using from the option section above and
slot it into the chaining shape.
Parallel — speak and show together. Drop both actions in the same
actions: list with no wait between them. Cast pipes the TTS to the
speaker channel and play_media to the display channel; on a Nest
Hub they don’t collide:
alias: ClothesCast on kitchen Hub at 07:01 (parallel)
mode: single
triggers:
- trigger: time
at: "07:01:00"
actions:
- action: notify.google_assistant_sdk
data:
message: ""
target:
- Kitchen
- action: media_player.play_media
target:
entity_id: media_player.kitchen_hub
data:
media_content_id: "http://192.168.x.x:8123/api/camera_proxy/camera.clothescast_today_outfit?token=<access_token>"
media_content_type: image/jpeg
Serial — speak first, then show. Cast’s media_player.play_media
with image/jpeg interrupts whatever’s currently rendering, including
in-flight TTS, so for the serial pattern you wait for the speech to
finish before pushing the picture. A fixed delay: sized to your
longest spoken briefing is the simplest reliable wait, and works
regardless of which TTS service you’ve picked — see the picker
under the example for the small B/C swap-in note (and why a
state-based wait isn’t recommended even when the player exposes
state).
alias: ClothesCast on kitchen Hub at 07:01 (serial)
mode: single
triggers:
- trigger: time
at: "07:01:00"
actions:
# 1. Speak the forecast.
- action: notify.google_assistant_sdk
data:
message: ""
target:
- Kitchen
# 2. Wait for the spoken clip to finish before swapping the display.
# Pad a few seconds past your longest briefing — the SDK includes
# a "There's a message…" preamble, so allow for that too.
- delay: "00:00:18"
# 3. Push the outfit picture.
- action: media_player.play_media
target:
entity_id: media_player.kitchen_hub
data:
media_content_id: "http://192.168.x.x:8123/api/camera_proxy/camera.clothescast_today_outfit?token=<access_token>"
media_content_type: image/jpeg
Picker — swapping in Option B or C. Replace the step-1 action
with the Option B or Option C YAML from those sections. The fixed
delay: in step 2 stays as-is — it works for any TTS service that
takes roughly a known time to speak.
Edge case — speaker was already playing music (Option B specifically). Music Assistant restores the prior playback after the announcement finishes, so if the Hub was playing music when the automation fired, the image step at the end of the serial recipe will fire while MA is back to playing music and interrupt it. This applies regardless of wait mechanism (fixed
delay:or state-based) because the restored playback happens before the delay even runs out. If your setup can have the Hub playing music at trigger time, gate the automation withcondition: state … idleon the player up front, or pause the player before step 1.
If you’re tempted to swap the delay: for a state-based wait on
media_player.* instead, don’t, at least not without testing it
end-to-end on your specific setup. Options B and C do expose
playing → idle transitions on the player, but the obvious
two-stage wait_template (wait for non-idle, then wait for idle)
has two failure modes specific to the state-based approach:
- Slow TTS start. If the TTS service takes more than the initial wait’s timeout to actually start playing, the first
wait_templatetimes out withcontinue_on_timeout: true, the second one then seesidle(because TTS hasn’t started yet) and trips immediately, and the image fires just as the spoken clip finally arrives. You’d need await.completedcheck to abort cleanly when the start wait times out.- Variable briefing length saves at most a few seconds. A fixed
delay:is conservative by design; the state-based wait only saves you the slack you padded into the delay. Rarely worth the complexity for a once-a-day automation.
(The “already playing” edge case above isn’t on this list because it’s not specific to wait_template — it’s an MA-restoration property that applies to any wait shape.)
What’s verified. The Option A (
notify.google_assistant_sdk) path above is the one this project’s author runs day-to-day. The Option B and C variants follow current HA service shapes but haven’t been tested end-to-end on this setup — if you wire one up and find a wrinkle, a PR-fix is welcome.
mosquitto_sub -h <broker-host> -u <user> -P <pass> -t 'clothescast/default/#' -v
Then trigger a refresh from the ClothesCast Today screen. The
payload should appear within ~5 seconds of the
Insight delivered for … log line.
See PRIVACY.md for the full data-handling boundary. Quickly: the bridge is off by default, and turning it on sends the rendered forecast sentence to your own broker — not to a developer-operated service. The payload is the same string you see in the notification, including any calendar-event tie-in clause if you have the calendar tie-in enabled.