Randomly choose a set of parameters for a service call?

So, I’m wrapping my head around this problem for some hours and still don’t know, if this is plainly impossible with HA or if I just didn’t understand, how to properly use data_template, value_template, json etc. in HA, respectively yaml.

The problem: Basically I want to define a list with items consisting of a sentence and its associated language, I want to randomly choose an item and pass it to Google TTS.

Choosing a random sentence from the list is easy with data_template:

- service: tts.google_say
  entity_id: media_player.livingroom
  data_template:
    message: '{{ ["Hello", "World"] | random }}'
    language: 'en'

But how to randomly chose a sentence together with the proper language? Obviously, the following example isn’t working as expected, as the values for both parameters are selected seperately, but I hope this makes it more clear, what I want to achieve:

- service: tts.google_say
  entity_id: media_player.livingroom
  data_template:
    message: '{{ ["Hello World", "Hallo Welt", "Bonjour monde"] | random }}'
    language: '{{ ["en", "de", "fr"] | random }}'

Besides, separate lists for sentences and languages would be hard to read and awful to edit if the lists get longer. So ideally it should be possible to have a sentence and it’s language defined in one line.

But how can I define a list consisting of items holding a sentence and its language, randomly choose an item and pass it to google_say?

Is it possible to set and use local variables in script sequences? Or is it possible to define lists as json strings, pass them to a script and parse them?

Or do you have any other ideas?

1 Like

I’m not sure if it would work, but try using the data template line as a json object. I’ve tried it in the past and I can’t remember if it worked.

- service: tts.google_say
  entity_id: media_player.livingroom
  data_template: >
    {% set m = ["Hello World", "Hallo Welt", "Bonjour monde"] %}
    {% set l = ["en", "de", "fr"] %}
    {% set i = range(m) | random %}
    { 'message':{{ m[i] }}, 'language':{{ l[i] }} }

Unfortunately this seems to be invalid syntax:

Invalid config for [script]: expected a dictionary for dictionary value @ data['script']['tts_test']['sequence'][0]['data_template']. Got '{% set m = ["Hello World", "Hallo Welt", "Bonjour monde"] %} {% set l = ["en", "de", "fr"] %} {% set i = range(m) | random %} { \'message\':{{ m[i] }}, \'language\':{{ l[i] }} }\n'. (See /config/configuration.yaml, line 93). Please check the docs at https://home-assistant.io/components/script/

I remember how it worked!

You have to use a mqtt intermediary sensor inbetween because it parses the dictionary as a json object when its read in.

basically you plop that data_template into a mqtt topic and then when the topic changes, have an automation that pushes the topic out. The topic should be read in as a json object so it will see the dictionary correctly.

Pain in the ass but it should work.

I’m presuming that what you want is a list of English phrases, a list of French phrases and a list of German phrases, and then to pass the correct language code based on which list?

If so I would do it like this

Create a random sensor to give you a number that is either 1, 2 or 3

action:
  service: tts.google_say
  entity_id: media_player.livingroom
  data_template:
    message: >
     {% if is_state('sensor.random' , '1') %} !include english.yaml
     {% elif is_state('sensor.random' , '2') %} !include french.yaml
     {% else %} !include german.yaml {% endif %} 
    language: >
      {% if is_state('sensor.random' , '1') %} en
      {% elif is_state('sensor.random' , '2') %} fr
      {% else %} de {% endif %}

And then put your lists in the appropriate includes. You might have to template it slightly differently (I can’t test this) but that’s the concept.

Hope this helps.

1 Like

Interesting, you are the component guru. Every week you show me something new

Just for better understanding your approach: this works in 99.9% of all cases, because the random sensor is always returning the same value for about 30 seconds, right?

Good question. It’s the 0.1% that will drive you nuts! :slight_smile: You could always add an input_number entity, and adjust your automation to save sensor.random to that input_number, then use the input_number in the templates.

The way I understand it all the templates in the ‘data_template’ bracket would be resolved at the same time, so the number would be the same for both even if it changed a millisecond later, but if you want to be certain @pnbruckner 's method would definitely work because it would only be relied on once.

So, yesterdayI finally had the time to solve this. As others may find it useful as well, I started a new topic for it in the Share your projects! category: (Random) multi language Google TTS messages

Thanks for your input, which was really useful to solve this at last.

1 Like