How to create multiple phrases to send at random to TTS?

I have an automation that says “welcome home” when I unlock my front door. It’s cool but growing a bit stale. I’d like to create about 10 different phrases and have Home Assistant insert them at random into the TTS action when my door is unlocked. How would I go about doing that?

Here’s my automation:

- alias: Unlock Routine
  initial_state: true
  trigger:
    platform: mqtt
    topic: smartthings/Unlock Notifier/switch
    payload: 'on'
  action:
    - service: tts.google_say
      entity_id: media_player.living_room_home
      data:
        message: 'Welcome home Boss!'
5 Likes

Did you see the Alexa example? It might give you an idea how.

Giving Alexa Some Personality

In the examples above, we told Alexa to say OK when she successfully completed the task. This is effective but a little dull! We can again use templates to spice things up a little.

First create a file called alexa_confirm.yaml with something like the following in it (go on, be creative!):

      >
      {{ [
      "OK",
      "Sure",
      "If you insist",
      "Done",
      "No worries",
      "I can do that",
      "Leave it to me",
      "Consider it done",
      "As you wish",
      "By your command",
      "Affirmative",
      "Yes oh revered one",
      "I will",
      "As you decree, so shall it be",
      "No Problem"
      ] | random }} 

Then, wherever you would put some simple text for a response like OK, replace it with a reference to the file so that:

text: OK
becomes:

text: !include alexa_confirm.yaml

4 Likes

Awesome, I had not seen that but it’s exactly what I was looking for! Thanks

Ok so I set this up, however, it simply reads out the entire file… “Opening curly bracket, opening curly bracket, OK, Sure, If you insist, Done, random”

  >
  {{ [
  "OK",
  "Sure",
  "If you insist",
  "Done"
  ] | random }}

If I indent it a little more, it doesn’t say, “opening bracket, opening bracket”, but still reads the rest of the stuff all together.

    >
    {{ [
    "OK",
    "Sure",
    "If you insist",
    "Done"
    ] | random }}

Looks like I need some better formatting and that’s where I’m not sure what to do. Anyone have more info? I’m using this with Google Home if that makes any difference.

Try starting with it directly in the automation, this will ensure the format is correct and hopefully give you a clue. Then you can extract the working text template to a file for neatness later…

- alias: Unlock Routine
  initial_state: true
  trigger:
    platform: mqtt
    topic: smartthings/Unlock Notifier/switch
    payload: 'on'
  action:
    - service: tts.google_say
      entity_id: media_player.living_room_home
      data_template:
        message: {{ ["OK", "Sure", "If you insist", "Done"] | random }}

(I’m terrible with templates myself, so if there is an obvious error with it somebody else will have to point it out!!)

3 Likes

Thanks, that’s a great idea and immediately it identifies a problem:

2017-06-14 20:45:23 ERROR (MainThread) [homeassistant.bootstrap] Error loading /home/homeassistant/.homeassistant/configuration.yaml: while scanning for the next token
found character ‘|’ that cannot start any token
in “/home/homeassistant/.homeassistant/automations.yaml”, line 420, column 61

message: {{ ["OK", "Sure", "If you insist", "Done"] | random }}

Like I say I’m crap with templates, should it have single quotes around it…

message: '{{ ["OK", "Sure", "If you insist", "Done"] | random }}'

or perhaps the [ ] should be ( ) ?

Total guesswork I’m afraid until somebody more knowledgeable comes along…

1 Like

https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/announcements.yaml

Let me know if you come up with some good ones to add to my collection. :slight_smile:

7 Likes

Nice, that got me going in the right direction. I read up a little on templating and discovered that the real problem I was having we not using “data_template”. This structure got it working for me:

action:
    - service: tts.google_say
      entity_id: media_player.living_room_home
      data_template:
        message: >
          '{{ ["OK", "Sure", "If you insist", "Done"] | random }}'

Thanks for the help!

8 Likes

Wow, this is impressive but pretty advanced for me. My system works by identifying the key code punched in on a z-wave deadbolt, which comes in via MQTT from a SmartThings hub. It will take a good bit more knowledge to figure out how to implement your system but thanks for sharing, always nice to have something better to strive for!

2 Likes

NEAT ! I just started with TTS last week end I was looking how to give it more ‘personality’ this week-end. I will definitely try something like you !

My favorite:

"Welcome Home " ~ person + ". We have missed you. Or at least Molly did."

Guessing that Molly is the dog… hilarious!

I would love to have this Bugs Bunny clip played for random folks that open the door:

2 Likes

Molly is our cat. She occasionally plays guard dog though…

After we put our fake dog barks on snooze for 30 minutes. :slight_smile:

1 Like

Priceless. We need to make Molly the HA Mascot.

1 Like

Thanx for sharing the code! I am using Alexa and Google Home. Anyone who can point me into the right direction?

Hi all,
please help to debug this… I spent the whole last night debuging and at a loss what is wrong.
I am on 0.53 version of HA.
my configs are passing the checks and there are no errors loading HA.
‘People Greeting’ automation fails…
Underlying scripts work fine.

I pretty much now trying to make CCOSTAN’s code work on my HA.
My Sonos TTS script itself works and I tested it with some hardcoded values. ‘Dexter Pee Call’ script works perfectly. But my automation below, which calls simular script fails with the error: “trigger is undefined”

Btw, Dexter is my dog and what I am really building here is ability for him to communicate with us.
I already have AWS IOT button and a lambda function working, so when Dexer press the button attached to the door, it goes out via Lambda to an MQTT server and back to HA to either speak the request to go pee over Sonos or send a push notification to our phones if we are not home. The idea is to make his “pee call” dynamic and level of intensity of the message will depend on how many times he pressed the button… So that at first it will be like (depending on who is home): Daddy or mommy I want to go pee. and after a few times we ignore him, it will be more like: “I will pee on the floor now if you will not take me out…” I also plan to switch do Yandex TTS, because it allows for voice intonation. and I can make the voice more angry with later messages.

I looked at other threads where people had the same error and my syntax does not contain the errors that helped the other person. For example I am already using data_template and my yaml indents seem correct… But maybe not… Please help to spot what is wrong…

Here is the error:

Sep 13 08:22:29 HomeControl hass[2156]: 2017-09-13 08:22:29 INFO (MainThread) [homeassistant.core] Bus:Handling <Event logbook_entry[L]: entity_id=automation.people_greeting, message=has been triggered, domain=automation, name=People Greeting>
Sep 13 08:22:29 HomeControl hass[2156]: 2017-09-13 08:22:29 INFO (MainThread) [homeassistant.helpers.script] Script People Greeting: Executing step call service
Sep 13 08:22:29 HomeControl hass[2156]: 2017-09-13 08:22:29 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Sep 13 08:22:29 HomeControl hass[2156]: Traceback (most recent call last):
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/template.py", line 102, in async_render
Sep 13 08:22:29 HomeControl hass[2156]: return self._compiled.render(kwargs).strip()
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/jinja2/environment.py", line 1008, in render
Sep 13 08:22:29 HomeControl hass[2156]: return self.environment.handle_exception(exc_info, True)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/jinja2/environment.py", line 780, in handle_exception
Sep 13 08:22:29 HomeControl hass[2156]: reraise(exc_type, exc_value, tb)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/jinja2/_compat.py", line 37, in reraise
Sep 13 08:22:29 HomeControl hass[2156]: raise value.with_traceback(tb)
Sep 13 08:22:29 HomeControl hass[2156]: File "<template>", line 1, in top-level template code
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/jinja2/sandbox.py", line 385, in getattr
Sep 13 08:22:29 HomeControl hass[2156]: value = getattr(obj, attribute)
Sep 13 08:22:29 HomeControl hass[2156]: jinja2.exceptions.UndefinedError: 'trigger' is undefined
Sep 13 08:22:29 HomeControl hass[2156]: During handling of the above exception, another exception occurred:
Sep 13 08:22:29 HomeControl hass[2156]: Traceback (most recent call last):
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/lib/python3.4/asyncio/tasks.py", line 237, in _step
Sep 13 08:22:29 HomeControl hass[2156]: result = next(coro)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/components/automation/__init__.py", line 343, in async_trigger
Sep 13 08:22:29 HomeControl hass[2156]: yield from self._async_action(self.entity_id, variables)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/components/automation/__init__.py", line 433, in action
Sep 13 08:22:29 HomeControl hass[2156]: yield from script_obj.async_run(variables)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/script.py", line 151, in async_run
Sep 13 08:22:29 HomeControl hass[2156]: yield from self._async_call_service(action, variables)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/script.py", line 181, in _async_call_service
Sep 13 08:22:29 HomeControl hass[2156]: self.hass, action, True, variables, validate_config=False)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/service.py", line 74, in async_call_from_config
Sep 13 08:22:29 HomeControl hass[2156]: config[CONF_SERVICE_DATA_TEMPLATE]))
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/service.py", line 70, in _data_template_creator
Sep 13 08:22:29 HomeControl hass[2156]: for key, item in value.items()}
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/service.py", line 70, in <dictcomp>
Sep 13 08:22:29 HomeControl hass[2156]: for key, item in value.items()}
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/service.py", line 72, in _data_template_creator
Sep 13 08:22:29 HomeControl hass[2156]: return value.async_render(variables)
Sep 13 08:22:29 HomeControl hass[2156]: File "/usr/local/lib/python3.4/dist-packages/homeassistant/helpers/template.py", line 104, in async_render
Sep 13 08:22:29 HomeControl hass[2156]: raise TemplateError(err)
Sep 13 08:22:29 HomeControl hass[2156]: homeassistant.exceptions.TemplateError: UndefinedError: 'trigger' is undefined
Sep 13 08:22:29 HomeControl hass[2156]: 2017-09-13 08:22:29 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]: service_call_id=1973448880-89>
Sep 13

Here is my automation and scripts:

- alias: 'People Greeting'
  trigger:
    platform: state
    entity_id: device_tracker.dmitry
    from: 'not_home'
    to: 'home'
    for:
       minutes: 1
  action:
     service: script.arrive_greetings
     data_template:
        speech_message: >
           {% set person = trigger.entity_id.split('.')[1]|replace('_', ' ')%}
           {%- macro greeting_sentence(person) -%}
           {{ [
           "Welcome back home " ~ person,
           "Guess who is home?" ~ person +" is!",
           person + " is now in the house.",
           "Welcome Home " ~ person + ".  We have missed you. Or at least Dexter did.",
           "Our home is now complete, Rest your head and relax your feet! Welcome Back " ~ person,
           "Life is like a song, you’re back where you belong. Welcome home " ~ person,
           "Hey there " ~ person + " Welcome Home!",
           "Knock Knock. Who is There? "   ~ person +" is!",
           person ~ "! You are home!",
           "I know a secret! "  ~ person +" is home!"
           ] | random }}
           {%- endmacro -%}
           "{{greeting_sentence(person)}}"

And the script it calls below:
(note that dexter_pee_call script works perfectly. I used it to test… Dexter is my dog btw… )

arrive_greetings:
  alias: "Greetings on Arrival Home"
  sequence:
   - service: script.sonos_say
     data_template:
       sonos_entity: media_player.living_room
       volume: 0.4
       message: "{{ speech_message }}"
       delay: '00:00:03'

dexter_pee_call:
  alias: "Dexter Pee Action Script"
  sequence:
   - service: script.sonos_say
     data:
       sonos_entity: media_player.living_room
       volume: 0.4
       message: 'Daddy, I want to go pee'
       delay: '00:00:03'

sonos_say:
  alias: "Sonos TTS script"
  sequence:
   - service: media_player.sonos_snapshot
     data_template:
       entity_id: "{{ sonos_entity }}"
   - service: media_player.sonos_unjoin
     data_template:
       entity_id: "{{ sonos_entity }}"
   - service: media_player.volume_set
     data_template:
       entity_id: "{{ sonos_entity }}"
       volume_level: "{{ volume }}"
   - service: tts.google_say
     data_template:
       entity_id: "{{ sonos_entity }}"
       message: "{{ message }}"
   - delay: "{{ delay }}"
   - service: media_player.sonos_restore
     data_template:
       entity_id: "{{ sonos_entity }}"
1 Like

Try changing out the trigger variable and work backwards…

{% set person = “Dexter” %}

1 Like

Hi CCOSTAN,
I have done exactly that and it works.
{% set person = “Dexter” %}

This line:
{% set person = trigger.entity_id.split(’.’)[1]|replace(’_’, ’ ')%}
seem to be causing a problem.
Can you explain what it does? it seem to split the “device_tracker.dmitry” on the “.” into the array of
{‘device_tracker’,‘dmitry’) and you are taking array slot [1], which is "dmitry’
but then you replacing “underscore” with a "space " Why? There is not an underscore in device tracker id?
unless you are assuming that device tracker is owntracks something like “dima_dmitry” and you want to further split it on “_” ???

Anyhow, I tried to modify that code and removed spliting on “_” but it still fails with the same error.
Any ideas?

Also, what happens when multiple people arrive at the same time?

@CCOSTAN, this speech engine obviously took you a serious amount of time to build.

If i go and make a speech engine myself, what is the best way to start building it? This to prevent myself from finding out i did it all wrong halfway :stuck_out_tongue:

  • i’d like a buildup where a bunch of switches determine what phrases to use
  • the incoming request sets all the right states to the switches
  • all the different variations of messages are then triggered by just 1 action

atleast, that’s what i get from looking at your code

Thanks. For me it was about reusability of the code. Think about all the types of variables you will want to send to the engine. Who, What, where basically. and build an override for emergencies…

Mine is still a work in progress though…