-
-
Save yougotborked/878998f50c7a7ad4d5d2e62b16bcb45e to your computer and use it in GitHub Desktop.
Send a greetings TTS message using tts.google_say service after opening the door, considering who arrived in the configured minutes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| blueprint: | |
| name: TTS on Door Opening with Recent Arrivals (rev B2) | |
| description: > | |
| Speaks a greeting via TTS when a door opens **and** one or more selected | |
| people have arrived home within the last N minutes. (Fix: robust list typing.) | |
| domain: automation | |
| input: | |
| door_sensor: | |
| name: Door sensor | |
| selector: | |
| entity: | |
| domain: binary_sensor | |
| device_class: | |
| - door | |
| - opening | |
| persons: | |
| name: Persons to watch | |
| selector: | |
| entity: | |
| domain: person | |
| multiple: true | |
| minutes: | |
| name: Minutes window | |
| default: 5 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 60 | |
| step: 1 | |
| unit_of_measurement: min | |
| mode: slider | |
| settle_seconds: | |
| name: Debounce after door opens (sec) | |
| default: 3 | |
| selector: | |
| number: | |
| min: 0 | |
| max: 30 | |
| step: 1 | |
| unit_of_measurement: s | |
| mode: slider | |
| message_single: | |
| name: Message (single person) | |
| description: Use <person> to insert the person name | |
| default: "Welcome home <person>!" | |
| selector: | |
| text: | |
| multiline: true | |
| message_multiple: | |
| name: Message (multiple people) | |
| description: Use <persons> to insert names (comma-and logic built in) | |
| default: "Welcome home <persons>!" | |
| selector: | |
| text: | |
| multiline: true | |
| persons_concat: | |
| name: Two-name joiner | |
| default: " and " | |
| selector: | |
| text: | |
| media_player: | |
| name: Media player | |
| selector: | |
| entity: | |
| domain: media_player | |
| tts_device: | |
| name: TTS entity | |
| description: The TTS entity that renders speech (e.g., tts.piper, tts.cloud) | |
| selector: | |
| entity: | |
| domain: tts | |
| volume_level: | |
| name: Temporary volume (optional) | |
| default: null | |
| selector: | |
| number: | |
| min: 0 | |
| max: 1 | |
| step: 0.01 | |
| mode: slider | |
| pre_actions: | |
| name: Pre-actions | |
| default: [] | |
| selector: | |
| action: {} | |
| post_actions: | |
| name: Post-actions | |
| default: [] | |
| selector: | |
| action: {} | |
| quiet_start: | |
| name: Quiet hours start (optional) | |
| selector: | |
| time: | |
| quiet_end: | |
| name: Quiet hours end (optional) | |
| selector: | |
| time: | |
| max_every_minutes: | |
| name: Max announcement frequency | |
| description: Minimum minutes between announcements; 0 disables the guard | |
| default: 2 | |
| selector: | |
| number: | |
| min: 0 | |
| max: 120 | |
| step: 1 | |
| unit_of_measurement: min | |
| mode: slider | |
| source_url: https://gist.github.com/yougotborked/878998f50c7a7ad4d5d2e62b16bcb45e | |
| variables: | |
| persons_list: !input persons | |
| minutes_window: !input minutes | |
| settle_seconds: !input settle_seconds | |
| concat_str: !input persons_concat | |
| tts_device: !input tts_device | |
| media_player: !input media_player | |
| volume_level: !input volume_level | |
| quiet_start: !input quiet_start | |
| quiet_end: !input quiet_end | |
| max_every_minutes: !input max_every_minutes | |
| # seconds math | |
| window_seconds: "{{ (minutes_window | int(0)) * 60 }}" | |
| max_every_seconds: "{{ (max_every_minutes | int(0)) * 60 }}" | |
| # Build JSON list, then parse to a real list | |
| recent_arrivals_json: > | |
| {%- set now_ts = as_timestamp(now()) -%} | |
| {%- set win = window_seconds | int(0) -%} | |
| {%- set names = [] -%} | |
| {%- for p in expand(persons_list) | |
| if p is not none and p.state == 'home' -%} | |
| {%- set last = as_timestamp(p.last_changed) -%} | |
| {%- if last is number and (now_ts - last) <= win -%} | |
| {%- set _ = names.append(p.name) -%} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {{ names | tojson }} | |
| recent_arrivals: "{{ recent_arrivals_json | from_json }}" | |
| # Render nice names list with Oxford comma & custom 2-name joiner | |
| persons_rendered: > | |
| {%- set lst = recent_arrivals -%} | |
| {%- if lst | length == 0 -%}{% elif lst | length == 1 -%} | |
| {{ lst[0] }} | |
| {%- elif lst | length == 2 -%} | |
| {{ lst | join(concat_str) }} | |
| {%- else -%} | |
| {{ lst[:-1] | join(', ') ~ ', and ' ~ lst[-1] }} | |
| {%- endif -%} | |
| message_single: !input message_single | |
| message_multiple: !input message_multiple | |
| tts_message: > | |
| {%- if recent_arrivals | length > 1 -%} | |
| {{ message_multiple.replace('<persons>', persons_rendered) }} | |
| {%- elif recent_arrivals | length == 1 -%} | |
| {{ message_single.replace('<person>', persons_rendered) }} | |
| {%- else -%}{%- endif -%} | |
| # Quiet-hours suppression (boolean) | |
| is_quiet: > | |
| {%- set qs = quiet_start -%} | |
| {%- set qe = quiet_end -%} | |
| {%- set has = (qs is not none) and (qe is not none) and (qs|string) and (qe|string) -%} | |
| {%- if has -%} | |
| {%- set start = today_at(qs) -%} | |
| {%- set end = today_at(qe) -%} | |
| {%- if end <= start -%} | |
| {{ (now() >= start) or (now() < end) }} | |
| {%- else -%} | |
| {{ (start <= now()) and (now() < end) }} | |
| {%- endif -%} | |
| {%- else -%}false{%- endif -%} | |
| # Throttle using this automation's own last_triggered | |
| last_fired_ok: > | |
| {%- set guard = max_every_seconds | int(0) -%} | |
| {%- if guard <= 0 -%}true | |
| {%- else -%} | |
| {%- set lt = this.attributes.last_triggered -%} | |
| {%- if lt is not none -%} | |
| {{ (as_timestamp(now()) - as_timestamp(lt)) >= guard }} | |
| {%- else -%}true{%- endif -%} | |
| {%- endif -%} | |
| trigger: | |
| - platform: state | |
| entity_id: !input door_sensor | |
| to: 'on' | |
| - platform: state | |
| entity_id: !input door_sensor | |
| to: 'open' | |
| condition: [] | |
| action: | |
| - if: | |
| - condition: template | |
| value_template: "{{ not is_quiet }}" | |
| - condition: template | |
| value_template: "{{ last_fired_ok }}" | |
| then: | |
| - delay: | |
| seconds: "{{ settle_seconds | int(0) }}" | |
| - service: logbook.log | |
| data: | |
| name: "Arrival TTS" | |
| message: > | |
| Window: {{ minutes_window }} min ({{ window_seconds }} s), | |
| Recent: {{ recent_arrivals }}, | |
| Persons: {{ persons_list }}, | |
| Quiet(start/end): {{ is_quiet }} ({{ quiet_start }}–{{ quiet_end }}), | |
| LastFiredOK: {{ last_fired_ok }} | |
| - condition: template | |
| value_template: "{{ (recent_arrivals | length) > 0 and (tts_message | trim) != '' }}" | |
| - choose: [] | |
| default: !input pre_actions | |
| - variables: | |
| __orig_vol: > | |
| {{ state_attr(media_player, 'volume_level') if (volume_level is number) else none }} | |
| - choose: | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ volume_level is number }}" | |
| sequence: | |
| - service: media_player.volume_set | |
| target: | |
| entity_id: "{{ media_player }}" | |
| data: | |
| volume_level: "{{ volume_level }}" | |
| default: [] | |
| - service: tts.speak | |
| target: | |
| entity_id: "{{ tts_device }}" | |
| data: | |
| media_player_entity_id: "{{ media_player }}" | |
| message: "{{ tts_message }}" | |
| - choose: | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ __orig_vol is number }}" | |
| sequence: | |
| - service: media_player.volume_set | |
| target: | |
| entity_id: "{{ media_player }}" | |
| data: | |
| volume_level: "{{ __orig_vol }}" | |
| default: [] | |
| - choose: [] | |
| default: !input post_actions | |
| mode: single |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment