I have been trying for days to play with various things and try to get Home Assistant to check my calendar for entries and if there are entries, tell me about them with tts_speak. I have that part working - however, I would like to search for a specific text string in the calendar summary and filter found entries and tell me about those entries only. Currently, it is telling me about those entries and anything else in that same calendar. I have to admit, I am not entirely clear how to use the variable that is set up to filter those entries. I thought it was doing so on the calendar get.
Any help would be greatly appreciated. Here is the relevant code from the automation:
- action: calendar.get_events
data:
start_date_time: '{{ today_at() + timedelta(days=0) }}'
duration:
hours: 24
minutes: 0
seconds: 0
target:
entity_id: calendar.laughing_goblin
response_variable: agenda
- variables:
beer_ready: |
{{ agenda['calendar.laughing_goblin'].events | selectattr('summary', 'search', 'Check Tap', true) | list | count > 0 }}
- action: tts.cloud_say
data:
entity_id: media_player.jam_bedroom
message: >
{%- if r_count == people|count -%}
{{- 'Everyone' }}
{%- else %}
{%- set arriving = people | selectattr('ent', 'in', recent) | map(attribute='name') | list %}
{{-' and '.join(( arriving | join(', ')).rsplit(', ', 1))}}!
{%- endif %}
{# ===================================== Check Beer Kegs ========================================== #}
{% set list_length = agenda | count %} {% set nsa = namespace(i = 0) %}
{%- if (agenda['calendar.laughing_goblin'].events | selectattr('summary', 'search', 'Check Tap', true) | list | count > 0) %}
Stephen, you have kegs that should be ready to serve. Why not pour yourself a pint. Here's what's new on tap...
{% for item in agenda["calendar.laughing_goblin"]["events"] %}
{% if nsa.i < list_length %}
{{'Welcome home '}}, {{ item.description }}
{% set nsa.i = nsa.i + 1 %}
{% else %}
{{'Welcome home '}}, {{ item.description }},
{% endif %}
{% endfor %} {{ state_attr('input_select.mm_simple_cheers', 'options') | reject('in', [states('input_select.mm_simple_cheers'), 'My option value']) | list | random }}!
{% endif %}
Can you clarify what you want the message to be…? Currently it looks like it will say “Everyone” or speak the names of recently arrived people (though you have left out how people and recent are defined).
Then you have a part just for you, that has some issues:
That will always be 1, since you are only querying 1 calendar entity.
You check if there are any “Check Tap” events, but in the for loop…
… you iterate over all events without selecting just the “Check Tap” events.
Then you say “Welcome home” to every calendar event description (which I assume are the beer names)… but “description” isn’t a valid attribute, I think you meant “summary”.
- action: calendar.get_events
data:
start_date_time: '{{ today_at() }}'
duration:
hours: 24
minutes: 0
seconds: 0
target:
entity_id: calendar.laughing_goblin
response_variable: agenda
- variables:
events: |
{{ agenda['calendar.laughing_goblin'].events }}
check_tap_events: |
{{ events | selectattr('summary', 'search', 'Check Tap', true) | list }}
- action: tts.cloud_say
data:
entity_id: media_player.jam_bedroom
message: >
Welcome home,
{%- if r_count == people|count -%}
Everyone.
{%- else %}
{%- set arriving = people | selectattr('ent', 'in', recent) | map(attribute='name') | list %}
{{-' and '.join(( arriving | join(', ')).rsplit(', ', 1))}}!
{%- endif %}
{# ===================================== Check Beer Kegs ========================================== #}
{%- if check_tap_events | count > 0 %}
Stephen, you have kegs that should be ready to serve. Why not pour yourself a pint. Here's what's new on tap...
{%- set on_tap = check_tap_events | map(attribute='summary') | list %}
{{-' and '.join(( on_tap | join(', ')).rsplit(', ', 1))}}.
{{- state_attr('input_select.mm_simple_cheers', 'options') | reject('in', [states('input_select.mm_simple_cheers'), 'My option value']) | list | random }}!
{% endif %}
Note: I changed the script variables you had created to avoid having reuse agenda['calendar.laughing_goblin'].events and to select for the “Check Tap” events.
Thanks for your reply. Sorry, as I said - this thing confuses me. The “person/everyone” bit works fine. That is for presence detection & welcome home tts.
The part I am searching for is the “Check Tap” bit. There in fact could be up to 4 of them as I have 4 beer taps going at home. I want to search for calendar events on that day and if there are events with “Check Taps” in the summary, I want tts to tell me about those events. There are other events in the same calendar that I don’t need to be told about. Currently it tells me about all events on that day, and it is parsing info for the “description”. I’m not sure how to select just the “check taps” events. That’s exactly what I need.
I made adjustments on my end too, probably at the same time you were. It works properly now. I hadn’t realized that I had set the {{ welcome home }} at every calendar entry - that was a mistake. Anyhow, here is the working code:
- action: calendar.get_events
data:
start_date_time: '{{ today_at() }}'
duration:
hours: 24
minutes: 0
seconds: 0
target:
entity_id: calendar.laughing_goblin
response_variable: agenda
- variables:
events: |
{{ agenda['calendar.laughing_goblin'].events }}
check_tap_events: |
{{ events | selectattr('summary', 'search', 'Check Tap', true) | list }}
- action: tts.cloud_say
data:
entity_id: media_player.pixel_tablet_fully_kiosk
message: >
{%- if r_count == people|count -%}
{{- 'Everyone' }}
{%- else %}
{%- set arriving = people | selectattr('ent', 'in', recent) | map(attribute='name') | list %}
{{-' and '.join(( arriving | join(', ')).rsplit(', ', 1))}}!
{%- endif %}
{# ===================================== Check Beer Kegs ========================================== #}
{%- if check_tap_events | count > 0 %}
You have kegs that should be ready to serve. Why not pour yourself a pint. Here's what's new on tap...
{{ check_tap_events | map(attribute='description') | list | join(', ') }}
{{ state_attr('input_select.mm_simple_cheers', 'options') | reject('in', [states('input_select.mm_simple_cheers'), 'My option value']) | list | random }}!
{% endif %}
I want to thank you again for your help with this. I’ve been pulling my hair out for days trying to figure this out.
So my previous question is essentially solved. I do however have a follow up question. As it is directly related to this automation, i would rather not open a new ticket - to try and keep the info together.
So, what I would like to do is have one message when only one person is arriving, and a pluralized message if both of us are arriving. I sort of mocked it up, but it doesn’t really work. Obviously, it doesn’t need to list both parties if only one of us is arriving, but I didn’t know how to state that as a single entity.
- action: calendar.get_events
data:
start_date_time: '{{ today_at() }}'
duration:
hours: 24
minutes: 0
seconds: 0
target:
entity_id: calendar.laughing_goblin
response_variable: agenda
- variables:
time_span: 10 # Minutes after which person is no longer considered recently arrived
people:
- ent: 'person.stiofan'
name: 'Stephen'
- ent: 'person.guest'
name: |
{{ state_attr('person.guest', 'friendly_name') }}
recent: |
{{ people | map(attribute='ent')
| select('is_state', 'home') | expand
| selectattr('last_changed', 'gt', (now()-timedelta(minutes=time_span))) | list }}
r_count: "{{ recent|count }}"
events: |
{{ agenda['calendar.laughing_goblin'].events }}
check_tap_events: |
{{ events | selectattr('summary', 'search', 'Check Tap', true) | list }}
- action: tts.cloud_say
data:
entity_id: media_player.pixel_tablet_fully_kiosk
message: >
{# ===================================== Welcome Drinkers ========================================== #}
{%- if check_tap_events | count > 0 %}
{%- if r_count == people|count -%}
{%- set arriving = people | selectattr('ent', 'in', recent) | map(attribute='name') | list %}
{{-' and '.join(( arriving | join(', ')).rsplit(', ', 1))}}! There are kegs that should be ready to try. Why not pour yourselves a pint.
{%- else %}
{%- set arriving = people | selectattr('ent', 'in', recent) | map(attribute='name') | list %}
{{-' and '.join(( arriving | join(', ')).rsplit(', ', 1))}}! There are kegs that should be ready to taste. Why not pour yourself a pint.
{%- endif %}
{# ===================================== Check Beer Kegs ========================================== #}
Here's what's new on tap...
{{ check_tap_events | map(attribute='description') | list | join(', ') }}
{{ state_attr('input_select.mm_simple_cheers', 'options') | reject('in', [states('input_select.mm_simple_cheers'), 'My option value']) | list | random }}!
{% endif %}
It looks like you currently have an “everyone” clause by using {%- if r_count == people|count -%}
… Should that still speak all the people’s names or just a generic address like “Everyone”?
The name-joining template you are using should work fine to speak the name for a single person or multiple people.
...
message: >
{# ===================================== Welcome Drinkers ========================================== #}
{%- if check_tap_events | count > 0 %}
Welcome,
{%- if r_count == people|count -%}
{# Generic group label if everyone recently arrived #}
everyone!
{%- else %}
{# Individually name recent arrivals #}
{%- set arriving = people | selectattr('ent', 'in', recent) | map(attribute='name') | list %}
{{-' and '.join(( arriving | join(', ')).rsplit(', ', 1))}}!
{%- endif %}
There are kegs that should be ready to taste. Why not pour yourself a pint.
{# ===================================== Check Beer Kegs ========================================== #}
Here's what's new on tap...
{{ check_tap_events | map(attribute='description') | list | join(', ') }}
{{ state_attr('input_select.mm_simple_cheers', 'options')
| reject('in', [states('input_select.mm_simple_cheers'), 'My option value']) | list | random }}!
{% endif %}
Ideally, it would only say one of the names if one of us comes home, and both names if both of us do. The “everyone” is a orphan, it doesn’t really work anyhow. In testing I changed it to something else and it didn’t do anything anyway.
I’m gonna owe you a beer after all this.
The {%- if r_count == people|count -%} template doesn’t seem to work. I also tried {%- if r_count > 1 -%} to see if it would pluralize. It didn’t seem to do anything.
Sorry, i should have been clearer about the phrasing too. I was hoping that if there is only one of us, something like; “… pour yourself a pint…” and if more than one of us; “… pour yourselves some pints.”
Then you should be good without the first if clause, since your name-joining expression will handle that.
Ok, that’s definitely do-able:
...
message: >
{# ===================================== Welcome Drinkers ========================================== #}
{%- if check_tap_events | count > 0 %}
{%- set arriving = people | selectattr('ent', 'in', recent) | map(attribute='name') | list %}
Welcome, {{' and '.join(( arriving | join(', ')).rsplit(', ', 1))}}!
There are kegs that should be ready to taste.
Why not pour {{'yourself a pint' if arriving | count == 1 else 'yourselves some pints'}}.
{# ===================================== Check Beer Kegs ========================================== #}
Here's what's new on tap...
{{ check_tap_events | map(attribute='description') | list | join(', ') }}
{{ state_attr('input_select.mm_simple_cheers', 'options')
| reject('in', [states('input_select.mm_simple_cheers'), 'My option value']) | list | random }}!
{% endif %}