Random Choice in Automations and Scripts

I am suggesting a new Building Block for automation actions called “Random Choice.”

It would act similarly to the “Choose” action, however instead of setting conditions you would just add as many Options to the Random action as you want, and when triggered, HA would select one randomly to run.

Here is an example use case: For your morning alarm (or nighttime white noise), you have a list of possible sounds or songs you would like to play, but a random one each day. You can quickly add each song as an Option to the Random action and it would do the randomization for you.

Another example: You want to have your lights come on and off while you are away from home, but you do not want them to sequence in a pattern that can be recognized by a potential thief. Using the Random action to add different room lights to the action would pick different rooms randomly, more closely representing someone being home. (This is where a random timing trigger would also be useful)

Anyone else think this would be useful? Yes, I know you can do this in templates. I know you can also make a Random Helper and feed that number into the Choose action. But that is a lot of extra steps, and you have to change the random helper each time you want to add an additional Option to the automation.

Thanks!
Seth

You can already do this.
Jinja: {{ range(1, 51) | random }} or use a random sensor as trigger.

2 Likes

Please post an example of what the proposed Random Choice feature would look like in YAML format.

Here’s an example of pulling a random voice for Nabu-Casa speech from all the available US voices…
HA_Blueprints/Scripts/tts_All_Message_Script_Blueprint.yaml at c05d6fb431c1d84cb145c7d6dd5ffe5a60b1d9e2 · SirGoodenough/HA_Blueprints · GitHub.

Love that one.

I have one in there for Piper as well.

1 Like

Besides the technical aspect I think it’s worth pointing out that randomness isn’t psychologically straight forward: humans can struggle with this. There’s been studies to show that if you ask people to make up random sequences that they turn out not to be so random, yet we think it is. It’s also how you can detect certain kinds of financial fraud.

Very much simplified, there are different kinds of randomness and whether (for example) you want repetition or not can highly affect how you perceive randomness.

If you get the same result 10 times in a row many people will react with: “That’s not random!” It surely may be probabilisticly highly unlikely, but it may well still be random.

So, my point is: There isn’t a single solution for what constitutes “random”. It depends on the specific case. It’s an enormous field of study where not everything can be reduced to a coin flip.

In the case of sounds or music, initially shuffled playlists used simple uniform distributions, but this lead to certain tracks perceived to be played too often. Etc. Then some smart people came along and created the Knuth/Fisher-Yates shuffle and today it’s even more advanced using machine learning and such.

1 Like

Here’s an actual example

  random:
    - sequence:
      - service: google_generative_ai_conversation.generate_content
        metadata: {}
        data:
          prompt: >-
            Create a short announcement like a medieval herald for an angelic
            princess named Daphne who is just waking up. It should be glamorous
            and regal. The announcement should be about 50 words long
        response_variable: proclamation
        enabled: true
        alias: Gemeni Herald (Angelic)
      - service: tts.google_cloud_say
        metadata: {}
        data:
          cache: false
          entity_id: "{{ media_target }}"
          message: "{{ proclamation[\"text\"] }}"
          options:
            voice: en-IN-Neural2-D
            gender: female
            speed: 0.8
            pitch: -1
        alias: Google TTS from Gemini (Indian English)
    - sequence:
      - service: google_generative_ai_conversation.generate_content
        metadata: {}
        data:
          prompt: >-
            Create a short announcement like a medieval herald for an evil
            princess named Daphne who is just waking up. It should be
            threatening the audience and ominous. The announcement should be
            about 50 words long
        response_variable: proclamation
        enabled: true
        alias: Gemini Herald (Evil)
      - service: tts.google_cloud_say
        metadata: {}
        data:
          cache: false
          entity_id: "{{ media_target }}"
          message: "{{ proclamation[\"text\"] }}"
        alias: Google TTS from Gemini (Deep British Male)
    - sequence:
      - service: google_generative_ai_conversation.generate_content
        metadata: {}
        data:
          prompt: >-
            Create a short announcement like a medieval herald for an enchanted
            forest princess named Daphne who is just waking up. It should be
            magical and directed towards the animals in her kingdom. The
            announcement should be about 50 words long
        response_variable: proclamation
        enabled: true
        alias: Gemini Herald (Enchanted)
      - service: tts.google_cloud_say
        metadata: {}
        data:
          cache: false
          entity_id: "{{ media_target }}"
          message: "{{ proclamation[\"text\"] }}"
          options:
            voice: fr-FR-Polyglot-1
            gender: male
            speed: 0.95
            pitch: -1
        alias: Google TTS from Gemini (French Male)

And here’s a simplified example:

random:
  - sequence:
    - service: light.turn_on
      target: light.living_room
  - sequence:
    - service: light.turn_on
      target: light.dining_room
  - sequence:
    - service: light.turn_on
      target: light.bedroom
  - sequence:
    - service: light.turn_on
      target: light.porch

Thanks. As I said in the post, I know it can be done in templating. I’m suggesting it be added to the UI as an automation Building Block for ease of use, since HA is moving in that direction.

Effectively, it’s a list of actions and Home Assistant would randomly select one for execution. It replaces templating with duplication (entire actions are replicated with minor alterations).

For automating my home, I haven’t found a need for employing randomness except for one instance and I encountered the “perception of non-randomness” explained by parautenbach. It’s more evident when random choices are made over short intervals of time, such as when playing songs or displaying colors.

As a consequence, I had to shuffle the list first then iterate through it in sequence. After the last item in the list was used, the list was re-shuffled.

Personally, I wouldn’t have a use for this FR but I think it would make it easier to implement “random actions” for users (especially for anyone uncomfortable with templating). As long as they understand that, depending on their application, the end-result might not “feel” as random as they expected.

2 Likes
      - service: google_generative_ai_conversation.generate_content
        metadata: {}
        data:
          prompt: >-
            {{ ("Create a short announcement like a medieval herald for an angelic
            princess named Daphne who is just waking up. It should be glamorous
            and regal. The announcement should be about 50 words long",
            "Create a short announcement like a medieval herald for an evil
            princess named Daphne who is just waking up. It should be
            threatening the audience and ominous. The announcement should be
            about 50 words long",
            "Create a short announcement like a medieval herald for an enchanted
            forest princess named Daphne who is just waking up. It should be
            magical and directed towards the animals in her kingdom. The
            announcement should be about 50 words long") | random }}
        response_variable: proclamation
        enabled: true
        alias: Gemini Herald (Enchanted)
      - service: tts.google_cloud_say
        metadata: {}
        data:
          cache: false
          entity_id: "{{ media_target }}"
          message: "{{ proclamation[\"text\"] }}"
          options:
            voice: fr-FR-Polyglot-1
            gender: male
            speed: 0.95
            pitch: -1
        alias: Google TTS from Gemini (French Male)

How about that?

1 Like

In the first example of lordratner’s post, each prompt message has associated voice, gender, speed, and pitch parameters. To replicate that functionality, you would need to create a list of dictionary items, randomly select one of the dictionary items, then use the values of its prompt, voice, gender, etc keys in the service call.

I have a vague recollection of creating such an example for someone else. I’ll post a link if I find it.

1 Like

I found the post I was thinking of. The user had wanted to randomly pick one of several options in a choose statement. In other words, it’s very similar to the example you posted containing several sequences where one would be chosen at random.

Borrowing from that example, your “random choice of actions” would look like the following example. It’s structure is similar to what you had proposed.

Example: Random choice of actions
action:
  - variables:
      i: "{{ [1,2,3] | random }}"
  - choose:
      - conditions: "{{ i == 1 }}"
        sequence:
          - service: google_generative_ai_conversation.generate_content
            metadata: {}
            data:
              prompt: >-
                Create a short announcement like a medieval herald for an angelic
                princess named Daphne who is just waking up. It should be glamorous
                and regal. The announcement should be about 50 words long
            response_variable: proclamation
            enabled: true
            alias: Gemeni Herald (Angelic)
          - service: tts.google_cloud_say
            metadata: {}
            data:
              cache: false
              entity_id: "{{ media_target }}"
              message: "{{ proclamation[\"text\"] }}"
              options:
                voice: en-IN-Neural2-D
                gender: female
                speed: 0.8
                pitch: -1
            alias: Google TTS from Gemini (Indian English)
      - conditions: "{{ i == 2 }}"
        sequence:
          - service: google_generative_ai_conversation.generate_content
            metadata: {}
            data:
              prompt: >-
                Create a short announcement like a medieval herald for an evil
                princess named Daphne who is just waking up. It should be
                threatening the audience and ominous. The announcement should be
                about 50 words long
            response_variable: proclamation
            enabled: true
            alias: Gemini Herald (Evil)
          - service: tts.google_cloud_say
            metadata: {}
            data:
              cache: false
              entity_id: "{{ media_target }}"
              message: "{{ proclamation[\"text\"] }}"
            alias: Google TTS from Gemini (Deep British Male)
      - conditions: "{{ i == 3 }}"
        sequence:
          - service: google_generative_ai_conversation.generate_content
            metadata: {}
            data:
              prompt: >-
                Create a short announcement like a medieval herald for an enchanted
                forest princess named Daphne who is just waking up. It should be
                magical and directed towards the animals in her kingdom. The
                announcement should be about 50 words long
            response_variable: proclamation
            enabled: true
            alias: Gemini Herald (Enchanted)
          - service: tts.google_cloud_say
            metadata: {}
            data:
              cache: false
              entity_id: "{{ media_target }}"
              message: "{{ proclamation[\"text\"] }}"
              options:
                voice: fr-FR-Polyglot-1
                gender: male
                speed: 0.95
                pitch: -1
            alias: Google TTS from Gemini (French Male)

FWIW, my preference would be to separate the data from the service call by using variables.

action:
  - variables:
      phrases:
        - prompt: 'Something'
          voice: en-IN-Neural2-D
          gender: female
          speed: 0.8
          pitch: -1
        - prompt: 'Something else'
          voice: en-IN-Neural2-D
          gender: male
          speed: 0.75
          pitch: -1
        - prompt: 'Something else again'
          voice: fr-FR-Polyglot-1
          gender: male
          speed: 0.95
          pitch: -1
      phrase: "{{ phrases[[0,1,2] | random] }}"
  - service: google_generative_ai_conversation.generate_content
    data:
      prompt: "{{ phrase.prompt }}"
    response_variable: proclamation
  - service: tts.google_cloud_say
    data:
      cache: false
      entity_id: "{{ media_target }}"
      message: "{{ proclamation[\"text\"] }}"
      options:
        voice: "{{ phrase.voice }}"
        gender: "{{ phrase.gender }}"
        speed: "{{ phrase.speed }}"
        pitch: "{{ phrase.pitch }}"
1 Like

Thanks!

I wanna just say that I still think this would be a good addition as a Building Block specifically so this type of advanced templating is not necessary. But until then:

Is there a jinja function to count the number of entries in a variable? The goal is to change this line:

phrase: "{{ phrases([0,1,2] | random) }}"

into something that does not need to be updated each time a new option is added to the “phrases” variable. In python it would be the count() function. Not sure exactly how it would work since it seems the random function in jinja seems to need the options listed explicitly.

Either way, thanks, this’ll at least help me clean up the code.

-Seth

phrase: "{{ phrases[range(0, phrases | count) | random] }}"

NOTE

I corrected an error in my previous example.

This won’t work:

"{{ phrases([0,1,2] | random) }}"

This will:

"{{ phrases[[0,1,2] | random] }}"
1 Like

thanks for the assistance all.

Here’s my automation in case others want inspiration. sometimes AI gets rate limited so i have backup message.

- conditions:
    - condition: trigger
      id: create-ai
    - not: "{{ trigger.event.data.service_data.message == 'clear_notification' }}"
  sequence:
    - service: google_generative_ai_conversation.generate_content
      continue_on_error: true
      data:
        prompt: >-
          Briefly tell me that my {{ trigger.event.data.service_data.data.prompt }} 
          {{ [
            'in a country accent',
            'as samuel jackson',
            'as darth vader',
            'as yoda'
            'like a medieval herald'
            ] | random
          }}
      response_variable: generated_content
    - service: notify.family
      data:
        message: >-
          {% set ai_response = generated_content['text'] if (generated_content is defined) else trigger.event.data.service_data.data.backup %}

          {% if (trigger.event.data.service_data.message != 'False' and trigger.event.data.service_data.message != false) %}
            {{ ai_response }}

            {{ trigger.event.data.service_data.message }}
          {% else %}
            {{ ai_response }}
          {% endif %}
        title: "{{ trigger.event.data.service_data.title }}"
        data:
          tag: "{{ trigger.event.data.service_data.data.tag }}"