Help with a json array

I want to spice up my daily tts message announcing the drinking hour, but lack one piece of the puzzle. I’m trying to select a random message and language code from a json array as it just seems a bit more elegant than lots of if statements and input_select stuff, plus I’d like to learn more about json. Just a pointer to some pertinent docs would be great.

Edit: OK, I found how to create the array with
{% set value_json= … %}
and how to select with
’{{ value_json[states.sensor.message.state][‘code’] }}'
now if I just knew where to set the array…

- id: beer_oclock
  alias: Timely message
  trigger:
    platform: time
    at: '17:00:00'
  action:
    service: tts.google_say
    entity_id: media_player.kitchen_display
    data:
      message: Sore wa doko ka ni 5-jidesu
      language: ja



- platform: random
  name: "5pm Message"
  minimum: 1
  maximum: 18



{
  "1": { "language":"Chinese", "code":"zh", "message":"Xiànzài shì 5 diǎn zhōng" },
  "2": { "language":"Danish", "code":"da", "message":"Det er klokken fem et eller ndet sted" },
  "3": { "language":"Dutch", "code":"nl", "message":"Het is ergens rond vijf uur"  },
  "4": { "language":"English", "code":"en", "message":"It's 5 o'clock somewhere" },
  "5": { "language":"French", "code":"fr", "message":"Il est cinq heures quelque part" },
  "6": { "language":"German", "code":"de", "message":"Es ist fünf Uhr irgendwo" },
  "7": { "language":"Hindi", "code":"hi", "message":"abhee paanch baje hain" },
  "8": { "language":"Indonesian", "code":"id", "message":"Sekarang jam 5 suatu tempat" },
  "9": { "language":"Italian", "code":"it", "message":"Sono le cinque in punto" },
  "10": { "language":"Japanese", "code":"ja", "message":"Goji doko ka ni" },
  "11": { "language":"Korean", "code":"ko", "message":"eodinga 5 siya" },
  "12": { "language":"Norwegian", "code":"nb", "message":"Det er fem på et sted" },
  "13": { "language":"Polish", "code":"pl", "message":"Jest gdzieś 5-ta" },
  "14": { "language":"Portugese", "code":"pt", "message":"São cinco horas em algum lugar" },
  "15": { "language":"Spanish", "code":"es", "message":"Son las cinco en algún lugar" },
  "16": { "language":"Swedish", "code":"sv", "message":"Det är fem på någonstans" },
  "17": { "language":"Thai", "code":"th", "message":"5 Mong chêā xyū̀ thī̀h̄ịn s̄ạk h̄æ̀ng" },
  "18": { "language":"Turkish", "code":"tr", "message":"Saat 5 yönünde bir yerlerde" }
}

Put this into Home Assistant’s Template Editor and experiment with the final variable to get an idea of how it works. In this example, it will select the 5th language (French) and display the associated message.

{% set x = {
  "1": { "language":"Chinese", "code":"zh", "message":"Xiànzài shì 5 diǎn zhōng" },
  "2": { "language":"Danish", "code":"da", "message":"Det er klokken fem et eller ndet sted" },
  "3": { "language":"Dutch", "code":"nl", "message":"Het is ergens rond vijf uur"  },
  "4": { "language":"English", "code":"en", "message":"It's 5 o'clock somewhere" },
  "5": { "language":"French", "code":"fr", "message":"Il est cinq heures quelque part" },
  "6": { "language":"German", "code":"de", "message":"Es ist fünf Uhr irgendwo" },
  "7": { "language":"Hindi", "code":"hi", "message":"abhee paanch baje hain" },
  "8": { "language":"Indonesian", "code":"id", "message":"Sekarang jam 5 suatu tempat" },
  "9": { "language":"Italian", "code":"it", "message":"Sono le cinque in punto" },
  "10": { "language":"Japanese", "code":"ja", "message":"Goji doko ka ni" },
  "11": { "language":"Korean", "code":"ko", "message":"eodinga 5 siya" },
  "12": { "language":"Norwegian", "code":"nb", "message":"Det er fem på et sted" },
  "13": { "language":"Polish", "code":"pl", "message":"Jest gdzieś 5-ta" },
  "14": { "language":"Portugese", "code":"pt", "message":"São cinco horas em algum lugar" },
  "15": { "language":"Spanish", "code":"es", "message":"Son las cinco en algún lugar" },
  "16": { "language":"Swedish", "code":"sv", "message":"Det är fem på någonstans" },
  "17": { "language":"Thai", "code":"th", "message":"5 Mong chêā xyū̀ thī̀h̄ịn s̄ạk h̄æ̀ng" },
  "18": { "language":"Turkish", "code":"tr", "message":"Saat 5 yönünde bir yerlerde" }
} %}

{{x['5'].message}}

This works in the Editor, I just can’t figure out where/how to set the variable

{% set value_json= {
  "1": { "language":"Chinese", "code":"zh", "message":"Xiànzài shì 5 diǎn zhōng" },
  "2": { "language":"Danish", "code":"da", "message":"Det er klokken fem et eller ndet sted" },
  "3": { "language":"Dutch", "code":"nl", "message":"Het is ergens rond vijf uur"  },
  "4": { "language":"English", "code":"en", "message":"It's 5 o'clock somewhere" },
  "5": { "language":"French", "code":"fr", "message":"Il est cinq heures quelque part" },
  "6": { "language":"German", "code":"de", "message":"Es ist fünf Uhr irgendwo" },
  "7": { "language":"Hindi", "code":"hi", "message":"abhee paanch baje hain" },
  "8": { "language":"Indonesian", "code":"id", "message":"Sekarang jam 5 suatu tempat" },
  "9": { "language":"Italian", "code":"it", "message":"Sono le cinque in punto" },
  "10": { "language":"Japanese", "code":"ja", "message":"Goji doko ka ni" },
  "11": { "language":"Korean", "code":"ko", "message":"eodinga 5 siya" },
  "12": { "language":"Norwegian", "code":"nb", "message":"Det er fem på et sted" },
  "13": { "language":"Polish", "code":"pl", "message":"Jest gdzieś 5-ta" },
  "14": { "language":"Portugese", "code":"pt", "message":"São cinco horas em algum lugar" },
  "15": { "language":"Spanish", "code":"es", "message":"Son las cinco en algún lugar" },
  "16": { "language":"Swedish", "code":"sv", "message":"Det är fem på någonstans" },
  "17": { "language":"Thai", "code":"th", "message":"5 Mong chêā xyū̀ thī̀h̄ịn s̄ạk h̄æ̀ng" },
  "18": { "language":"Turkish", "code":"tr", "message":"Saat 5 yönünde bir yerlerde" }
} %}

'{{ value_json[states.sensor.message.state]['message'] }}'
'{{ value_json[states.sensor.message.state]['code'] }}'

I don’t think you’re going to like the answer:

  action:
    service: tts.google_say
    entity_id: media_player.kitchen_display
    data_template:
      message: >-
        {% set x = {<entire dictionary goes here>} %}
        {{ x[states.sensor.message.state]['message'] }}
      language: >-
        {% set x = {<entire dictionary goes here>} %}
        {{ x[states.sensor.message.state]['code'] }}

Haha. So much for elegant…

Ideally, there would a file where you could define global variables and macros for the Jinja2 template engine. You could put your language dictionary there and then refer it to from any template. However, it doesn’t work like that. The scope of a variable is currently limited to within the template where it’s defined (meaning the option’s template so that’s one template for message: and a separate one for the language: option).

Could I jam it in a sensor or pull it from a google speadsheet? I have lots of database experience but that’s some serious overkill. What would you do?

It would be cool if an automation or a script could have a top-level ‘template’ section to contain things at least global to the parent node.

automation:
  - alias: foo
    template: >
      {% set x = <that big dictionary> %}
    trigger: blah
    action: something using "x".

I like that idea but I have the feeling implementing it the automation component would be a non-trivial task. Nevertheless, if you post it as a Feature Request, I’d vote for it.

I’d duplicate it. It’s ugly but nobody sees the config file but me.

On second thought, not an exact duplicate. The dictionary for language: can be much smaller because it only needs code and not language or message. The dictionary for message doesn’t need code.

It’s a damn sight better looking than my Harmony-Dish channel selector with all the ifs, and I have 2 of them.

Here’s what I meant about reducing the size of the dictionary for language:

{% set x = {
  "1":"zh",
  "2":"da", 
  "3":"nl",
  "4":"en",
  "5":"fr",
  "6":"de",
  "7":"hi",
  "8":"id",
  "9":"it",
  "10":"ja",
  "11":"ko",
  "12":"nb",
  "13":"pl",
  "14":"pt",
  "15":"es",
  "16":"sv",
  "17":"th",
  "18":"tr"
} %}
{{ x[states.sensor.message.state] }}

I’m getting this when I manually kick off the automation from the states page:

Error on init TTS: Not supported language {% set value_json= {
  "1": { "language":"Chinese", "code":"zh", "message":"Xiànzài shì 5 diǎn zhōng" },
  "2": { "language":"Danish", "code":"da", "message":"Det er klokken fem et eller ndet sted" },
  "3": { "language":"Dutch", "code":"nl", "message":"Het is ergens rond vijf uur"  },
  "4": { "language":"English", "code":"en", "message":"It's 5 o'clock somewhere" },
  "5": { "language":"French", "code":"fr", "message":"Il est cinq heures quelque part" },
  "6": { "language":"German", "code":"de", "message":"Es ist fünf Uhr irgendwo" },
  "7": { "language":"Hindi", "code":"hi", "message":"abhee paanch baje hain" },
  "8": { "language":"Indonesian", "code":"id", "message":"Sekarang jam 5 suatu tempat" },
  "9": { "language":"Italian", "code":"it", "message":"Sono le cinque in punto" },
  "10": { "language":"Japanese", "code":"ja", "message":"Goji doko ka ni" },
  "11": { "language":"Korean", "code":"ko", "message":"eodinga 5 siya" },
  "12": { "language":"Norwegian", "code":"nb", "message":"Det er fem på et sted" },
  "13": { "language":"Polish", "code":"pl", "message":"Jest gdzieś 5-ta" },
  "14": { "language":"Portugese", "code":"pt", "message":"São cinco horas em algum lugar" },
  "15": { "language":"Spanish", "code":"es", "message":"Son las cinco en algún lugar" },
  "16": { "language":"Swedish", "code":"sv", "message":"Det är fem på någonstans" },
  "17": { "language":"Thai", "code":"th", "message":"5 Mong chêā xyū̀ thī̀h̄ịn s̄ạk h̄æ̀ng" },
  "18": { "language":"Turkish", "code":"tr", "message":"Saat 5 yönünde bir yerlerde" }
} %} {{ value_json[states.sensor.pm_message.state]['code'] }}

I’m getting the right data when I plug it all into the template editor.

EDIT: Forgot to change to data_template:

I’m not sure if it’s more “elegant” or not but you can try this:

sensor:
  - platform: time_date
    display_options:
      - time
      - date
      - date_time
      - time_date
  - platform: template
    sensors:
      five_oclock_message:
        friendly_name: "5 O'Clock Message"
        entity_id: sensor.time
       value_template: >
        {% set value_json = {
          "1": { "language":"Chinese", "code":"zh", "message":"Xiànzài shì 5 diǎn zhōng" },
          "2": { "language":"Danish", "code":"da", "message":"Det er klokken fem et eller ndet sted" },
          "3": { "language":"Dutch", "code":"nl", "message":"Het is ergens rond vijf uur"  },
          "4": { "language":"English", "code":"en", "message":"It's 5 o'clock somewhere" },
          "5": { "language":"French", "code":"fr", "message":"Il est cinq heures quelque part" },
          "6": { "language":"German", "code":"de", "message":"Es ist fünf Uhr irgendwo" },
          "7": { "language":"Hindi", "code":"hi", "message":"abhee paanch baje hain" },
          "8": { "language":"Indonesian", "code":"id", "message":"Sekarang jam 5 suatu tempat" },
          "9": { "language":"Italian", "code":"it", "message":"Sono le cinque in punto" },
          "10": { "language":"Japanese", "code":"ja", "message":"Goji doko ka ni" },
          "11": { "language":"Korean", "code":"ko", "message":"eodinga 5 siya" },
          "12": { "language":"Norwegian", "code":"nb", "message":"Det er fem på et sted" },
          "13": { "language":"Polish", "code":"pl", "message":"Jest gdzieś 5-ta" },
          "14": { "language":"Portugese", "code":"pt", "message":"São cinco horas em algum lugar" },
          "15": { "language":"Spanish", "code":"es", "message":"Son las cinco en algún lugar" },
          "16": { "language":"Swedish", "code":"sv", "message":"Det är fem på någonstans" },
          "17": { "language":"Thai", "code":"th", "message":"5 Mong chêā xyū̀ thī̀h̄ịn s̄ạk h̄æ̀ng" },
          "18": { "language":"Turkish", "code":"tr", "message":"Saat 5 yönünde bir yerlerde" }
          }
        %}
        {% set x = range(1,18) | random | string %}
        {{value_json[x] }}

That will create a sensor that contains each line from your code randomly changing every minute. You will also have to create the sensor.time (the first sensor above).

Then in your automation you can access the individual items using the following:

{{ states.sensor.five_oclock_message.state.split(',')[0].split(':')[1] }} # language
{{ states.sensor.five_oclock_message.state.split(',')[1].split(':')[1] }} # code
{{ states.sensor.five_oclock_message.state.split(',')[2].split(':')[1][:-1] }} # message

Again, I’m not sure that it helps much but it was a good exercise in creative templating for me. :wink:

Won’t entity_id: sensor.time make Home Assistant evaluate the template sensor every minute?

Seems like a lot of overhead for a sensor that’s used maybe once a day. At the very least, it ought to be excluded from being recorded in History!

Now that I’ve experimented with python_script … everything looks like a nail. :slight_smile:

The automation would be:

- id: beer_oclock
  alias: Timely message
  trigger:
    platform: time
    at: '17:00:00'
  action:
    service: python_script.random_msg
    data_template:
      entity_id: media_player.kitchen_display
      lang_id: {{range(1,18) | random | string}}

The python_script would be config/python_scripts/random_msg.py that accepts two variables (entity_id and lang_id) and its contents would be (… more to come tomorrow 'cuz it’s well past my bedtime) :slight_smile:

That’s true but it was just used as an example and for testing.

They can easily switch the “sensor.time” to “sensor.date” (which is also created by the time_date sensor platform in the code above) and then it will only update once a day at midnight.

I guess if elegance was really the top priority, node-red is how I would have gone. I have about half of my automations there. So many toys tools in the arsenal.

I honestly can’t wrap my head around this.

I have an entity with an attribute that looks like this
{{ state_attr('media_player.rotel_rsp_1570', 'input_icons') }} which gives this as a value:

{'HDMI': False, 
 'Coaxial': False,
 'Optical': False, 
 'A': True, 
 '1': False, 
 '2': False,
 '3': False, 
'4': False,
 '5': False}

Finding the value from the key ‘HDMI’ (‘False’)
{{ state_attr('media_player.rotel_rsp_1570', 'input_icons').HDMI }}

But how do I find the Key for the value ‘True’, which should be ‘A’?

Does this not work?

{{ state_attr('media_player.rotel_rsp_1570', 'input_icons').A }}

Yess. That works.
What I am trying to figure out is to find the ‘A’ (Key), when I search for ‘True’ (Value) (The array only gets one True).

Something like {{ state_attr(‘media_player.rotel_rsp_1570’, ‘input_icons’).[].‘True’ }} ?

 {%- set icons = state_attr('media_player.rotel_rsp_1570', 'input_icons') %}
 {% for key, value in icon.items() if value == true %}
   {{ key }}
 {% endfor -%}

Should there be a possibility of more than just one key having a value of true, then this will return only the first one:

 {%- set icons = state_attr('media_player.rotel_rsp_1570', 'input_icons') %}
 {% for key, value in icon.items() if value == true %}
   {% if loop.first %} {{ key }} {% endif %}
 {% endfor -%}

FWIW, I tried to do this without using a for-loop but my Jinja2 skills weren’t up to the task. Perhaps someone else can demonstrate how it can be done without a loop.

1 Like