Using templates for input_select.set_options (populating options within an input selector)

My man. Thank you!

hello, thanks for sharing this solution. at every restart of Hassio I start an automation that populates my input_select, but unfortunately doing so I lose the current selection, do you know if there is a way to keep the previous setting on reboot?

can you please tell me what this HTTP password? I keep getting the following error.

Login attempt or request with invalid authentication from 127.0.0.1

update: solution is here

1 Like

Sorry - I only just found your post now, haven’t logged in for a while. Yeah since HA has has long lived tokens, I use them religiously now :slight_smile: that’s the way to go

This string helped me a lot - thanks gents. I still can’t get this to work. Goal is to dynamically update input_select… Gives me a perfectly formatted array in the developer tools template.

rest_command:
  populate_input_select_options:
    url: "http://192.168.1.100:8123/api/services/input_select/set_options"
    method: POST
    headers:
      x-ha-access: !secret http_password
      content-type: application/json
    payload: >-
      {
        "entity_id": "input_select.meat_type"
        "options": [
      {%- for state in states.variable if state_attr(state.entity_id, 'meat_type')==states['input_select.meat_type'].state -%}
        "{{state_attr(state.entity_id, 'meat_cut')}}"
      {%- if not loop.last %}, {%-endif-%}
      {%- endfor -%}]
      }

Help much appreciated. Dave

It’s giving you a string that only looks like an array.

The output of any template is a string.

Hi Dave,

A few suggestions:

1: Paste your rest_command config into the template area with the HASS UI, then paste the resulting payload here or at the jsonlint site to test if it’s actually valid json

2: it looks like you are using an HTTP password, try creating long life tokens instead. (The ‘bearer: ####’ examples from above)

3: call the rest command a few times then check the main log. It should tell you what is going wrong.

Hi everybody,

Im newbie with HA but i like it :wink:

I would like too populate an input_select depending of the value of a first input_select.

input_select:
  who_cooks:
    name: Who cooks today
    options:
      - Select
      - Paulus
      - Anne Therese
    initial: Select
    icon: mdi:panda
  living_room_preset:
    options:
      - Visitors
      - Visitors with kids
      - Home Alone

automation:
  - alias: change select
    trigger:
      platform: state
      entity_id: input_select.who_cooks
    action:
      service: input_select.set_options
      data:
        entity_id: input_select.living_room_preset
        options: >
          {% if trigger.to_state.state == 'Paulus' %}
            ["Item A", "Item B", "Item C"]
          {% elif trigger.to_state.state == 'radio' %}
            ["19", "20", "21"]
          {% endif %}

I understand that template returns string, also i would like use the workaroud.set_options to populate the second input_select.
BUT i need the values are in a list written by me for some temperature value.

If 1st input == ‘Comfort’ , the second input populates with temperature number 19, 20, 21…

Like


automation:
  - alias: change input_select_Second
    trigger:
      platform: state
      entity_id: input_select.first
    action:
      service: input_select.set_options
      data_template:
        entity_id: input_select.second
        options: >
          {% if trigger.to_state.state == 'Comfort' %}
            ["20", "20.5", "21", "21.5", "22"]
          {% elif trigger.to_state.state == 'Eco' %}
            ["14", "14.5", "15", "15.5"]
          {% endif %}

Can you help me please ?
Thanks

With 0.117 and the new native types for templates, you should be able to use the automation as you have written.
Just make sure you have

homeassistant:
    legacy_templates: false

in your configuration.yaml

Thanks @Olen

I know but it is in beta and i dont want to risk modify the other template that i use.

It’s why i would like to do this with the rest_command :wink:

Generally beta doesnt like me :wink:

The chances of anything breaking are pretty slim, especially if you have just started using ha, and your templates are reasonably standard. And if they do, it is pretty easy to fix.

I have hundreds of automations, scripts and sensors using templates built over several years, and nothing serious broke here.
Not using something that works well and will be default in the next release or so is imho just causing yourself more trouble at a later date.

Hi @Olen

He i cant wait and i do the modification. :slight_smile:
It works like a charm yeah !!

But i want testing the rest solution for populating.
What add in configuration for testing the api? Please

Thanks for thé job for all admins of ha

I know this thread is old, and my reply doesn’t exactly address the original question, but I have solved a similar problem that someone might find useful.

The use case is: maintain a dropdown in the front end containing a (relatively short) list of movies available for my Kodi media player. The list must be able to be updated dynamically. My solution uses pyscript modules to glue everything together (https://github.com/custom-components/pyscript).

The dropdown is defined as an input_select in yaml, with a static dummy option:

kodi_movies:
  name: Kodi Movies
  options:
    - "Select"

Next is a script to set or update the actual list - the key service is kodi.call_method:

kodi_get_all_movies:
  alias: Kodi Get All Movies
  sequence:
  - condition: state
    entity_id: media_player.shield_tv
    state: 'off'
  - service: input_boolean.turn_off
    data:
      entity_id: input_boolean.kodi_specific_movie
  - service: media_player.turn_on
    data:
      entity_id: media_player.shield_tv
  - delay: 00:00:03
  - service: androidtv.adb_command
    data:
      entity_id: media_player.shield_tv
      command: "am start -a android.intent.action.MAIN -c android.intent.category.LEANBACK_LAUNCHER -n 'org.xbmc.kodi/.Splash'"
  - delay: 00:00:02
  - service: kodi.call_method
    data:
      entity_id: media_player.kodi
      method: VideoLibrary.GetMovies
  - delay: 00:00:02
  - service: remote.send_command
    entity_id: remote.harmony_hub
    data:
      command: 'Home'
      device: NVIDIA Shield TV
  - delay: 00:00:02
  - service: media_player.turn_off
    data:
      entity_id: media_player.shield_tv

This drives an automation to process the response, which is a list of 2 dictionaries (“limit” describes the number of entries, “movies” contains all the movies and movie IDs). I am just using the movie title at the moment, then calling Kodi again to get the ID when I play it. I might try to save the IDs at this point, but I think that would get a bit messy:

- alias: Kodi All Movies Result
  id: kodi_all_movies_result
  trigger:
    - platform: event
      event_type: kodi_call_method_result
      event_data:
        result_ok: true
        input:
          method: VideoLibrary.GetMovies
  condition:
    - condition: state
      entity_id: input_boolean.kodi_specific_movie
      state: 'off'
  action:
    - service: pyscript.populate_all_movies
      data:
        entity: input_select.kodi_movies
        result: "{{ trigger.event.data.result }}"

Finally, here is the pyscript module called by the above automation:

#!/usr/bin/python3

# Populate the given input select from the result of a Kodi all movies query.

import sys

# File I/O is done in a called module - ensure the path includes it. Note that this only needs to be added
# to one file ... pyscript picks it up when loading the files.
if "/config/pyscript_modules" not in sys.path:
    sys.path.append("/config/pyscript_modules")

import file_ops


# This runs as a service, and is normally run from an automation.
@service
def populate_all_movies(entity=None, result=None):
    log.debug(f"got entity {entity}, result {result}")

    # Inputs are required. They are defined as optional so we can just log an error instead of encountering
    # an exception.
    if entity is None or result is None:
        log.error("entity and result are both required, exiting")

    # Domain must be input_select.
    elif not entity.startswith("input_select."):
        log.error("input entity must be domain input_select, exiting")

    # All seems well.
    else:
        # List of all movies
        movies = result['movies']
        all_movies = []
        for movie in movies:
            all_movies.append(movie['label'])
        all_movies.sort()
        log.debug(f"movie list {all_movies}")

        # Populate the input select.
        input_select.set_options(entity_id=entity, options=all_movies)

        # Write the list to a file so we can restore the input select after a restart.
        task.executor(file_ops.write_movie_file, all_movies)

Well, I said “finally” but not really. Note the last instruction above. When HA restarts, the input_select reverts back to its initial, static, value. So the write_movie_file() above persists the movie list using a native Python module. Note that when pyscript calls native Python, using task.executor(), the native Python module must exist in a different directory, python_modules in my case. At the top of the above file is a bit of code to modify the Python search path to include this directory. This is covered in the pyscript doc, but I struggled with it a bit. Here is the file containing write_movie_file(), as well as read_movie_file(), to be described in a bit:

#!/usr/bin/python3

# This native Python module is called by pyscript modules to perform file operations.

import os
import pickle

# Constants
MOVIE_BACKUP_FILE = "/config/all_movies_backup"


# Write the movie list to a file.
def write_movie_file(all_movies):
    with open(MOVIE_BACKUP_FILE, "wb") as outfile:
        pickle.dump(all_movies, outfile)


# Read and return the movie list.
def read_movie_file():
    with open(MOVIE_BACKUP_FILE, "rb") as infile:
        return pickle.load(infile)

To fully restore the input_select we need not only the movie list, but the selected option as well. For my use this is the movie to be shown for my “feature presentation” mode (work in progress), so I don’t want to lose it over a restart. This requires an input_text (not shown since it just has a name), and an automation to set the text when a movie is selected from the dropdown in the front end:

- alias: Save Feature Movie Name
  id: save_feature_movie_name
  trigger:
    - platform: state
      entity_id: input_select.kodi_movies
  condition:
    - condition: template
      value_template: "{{ ( trigger.to_state.state ) != ( 'Select' ) }}"
  action:
    - service: input_text.set_value
      data_template:
        entity_id: input_text.current_feature
        value: "{{ ( trigger.to_state.state ) }}"

Here is the restart automation to restore the input_select:

- alias: Restore Movie List On Start
  id: restore_movie_list_on_start
  trigger:
    - platform: homeassistant
      event: start
  action:
    - service: pyscript.restore_all_movies
      data:
        entity: input_select.kodi_movies
    - service: input_select.select_option
      data:
        entity_id: input_select.kodi_movies
        option: "{{ states('input_text.current_feature') }}"

And the pyscript module:

#!/usr/bin/python3

# Restore the given input select from the previously saved list of all movies.

import file_ops


# This runs as a service, and is normally run from an automation.
@service
def restore_all_movies(entity=None):
    log.debug(f"got entity {entity}")

    # Input entity is required. It is defined as optional so we can just log an error instead of encountering
    # an exception.
    if entity is None:
        log.error("entity is required, exiting")

    # Domain must be input_select.
    elif not entity.startswith("input_select."):
        log.error("input entity must be domain input_select, exiting")

    # All seems well.
    else:

        # Read the backup file.
        try:
            all_movies = task.executor(file_ops.read_movie_file)
        except FileNotFoundError:
            log.error(f"saved movie file not found, exiting")
            sys.exit(f"file not found")
        except pickle.UnpicklingError:
            log.error(f"saved movie file not usable, exiting")
            sys.exit(f"file not usable")

        log.debug(f"movie list {all_movies}")

        # Populate the input select.
        input_select.set_options(entity_id=entity, options=all_movies)

Apologies for the massively long reply :slight_smile:

Hey it’s always great when someone takes the time to post their solution. There is nearly always something to be learned from the ingenuity of others. Thanks!

I thought I might share the direction I have gone since this thread… so when I need something reflected into HASS based on a scripted payload, I push it straight to HASS from the code.

Here is some old BASH code I really need to convert to Python. The services function allows me to update most things editable. The sensors thing has been really valuable too.


hassApi='https://mypersonal.dns.com/api/'

# where I keep my long lived access tokens
# the directory business is so I can use these functions from within the HASS docker,
# or from my server 
if [ -f /config/llat.txt ]; then
    source /config/llat.txt
elif [ -f /volume1/docker/hass/llat.txt ]; then
    source /volume1/docker/hass/llat.txt
fi


function callHASSservice {
    domain=$1
    service=$2
    json=$3
    _service='services/'
    serviceurl=$hassApi$_service
    url="$serviceurl$domain/$service"
    post=$(curl -s -X POST -H "Authorization: Bearer $llat" -H "Content-Type: application/json" -d "$json" $url)
    echo $post
}

 
function callHASSsensor {
    # I use a state-on, pause then state-off so that I can more easily control when automations trigger.. probably uneccessary
    stateon=$1
    json=$2
    sensor=$3
    stateoff=$4
    _sensor='states/sensor.'
    status='{"state":"'$stateon'","attributes":'$json'}'
    sensorurl=$hassApi$_sensor$sensor
    send=$(curl -X POST -s -H "Authorization: Bearer $llat" -H "Content-Type: application/json" -d "$status" $sensorurl)
    if [ ! -z $4 ]; then
		sleep 3
		status='{"state":"'$stateoff'","attributes":'$json'}'
		send=$(curl -s -X POST -H "Authorization: Bearer $llat" -H "Content-Type: application/json" -d "$status" $sensorurl)
		echo $send
	fi
}

This works !!!

action:
      - service: input_select.set_options
        target:
          entity_id: input_select.di_zhi
        data:
          options: >
                    {% set zonelist = namespace(numbers=[]) %} {%- for zone in states.zone -%} {%- set zonelist.numbers = zonelist.numbers + [zone.entity_id.replace('zone.','') ]  -%}   {%- endfor -%}  {{zonelist.numbers}}  


If you simply want to create a list of each zone’s object_id (the object_id in zone.office is office) then you can do that, without using a for-loop, like this:

action:
  - service: input_select.set_options
    target:
      entity_id: input_select.di_zhi
    data:
      options: "{{ states.zone | map(attribute='object_id') | list }}"
3 Likes

I decided to try out the new native types support for templates (beta) feature .

I was able to populate the list of my favorite Sonos stations in an input_select helper with this code:

service: input_select.set_options
target:
  entity_id: input_select.sonos_favorites
data_template:
  options: >
    [{%- for key, value in state_attr('sensor.sonos_favorites', 'items').items() -%}
      "{{ value }}", 
    {%- endfor %}]
1 Like
service: input_select.set_options
target:
  entity_id: input_select.sonos_favorites
data:
  options:  >
    {{ state_attr('sensor.sonos_favorites', 'items').values() | list }}
6 Likes

@123 Thank you, thank you, thank you! I think this is the best post I’ve found so far on my HA journey?

I’ve been phaffing around with loops, tests and various input helpers to convert a string into a list and to find it can be done by piping into “list”. My dozen+ lines of template which nearly worked now all in one simple and concise line.

Bloody Perfect!

I’m trying to populate a “selection B” based on a “selection A”. From what I understand this should be doable. I’m admittedly autodidact leaving big blanks in my understanding of HA and yaml.

Specifically, I’m trying to on the basis of the initial choice of type of inverter (1 phase ot 3 phase) make a drop down list for choosing between only models related to the type. But no matter what I end up with the complete list. I’ve been around alot reading and testing but must admit I can’t get this to work. Here is the basic code I’m building from, just så you get the idea.

input_select:
  inverter_1_phases:
    name: "Inverter #1 Phases"
    options:
      - Select
      - 1 Phase
      - 3 Phase
  inverter_1_models:
    name: "Inverter #1 Models"
    options:
      - Select
      - SUN2000 2 KTL-L1
      - SUN2000 3 KTL-L1
      - SUN2000 3.68 KTL-L1
      - SUN2000 4 KTL-L1
      - SUN2000 4.6 KTL-L1
      - SUN2000 5 KTL-L1
      - SUN2000 6 KTL-L1
      - SUN2000 3 KTL-M1
      - SUN2000 4 KTL-M1
      - SUN2000 5 KTL-M1
      - SUN2000 6 KTL-M1
      - SUN2000 8 KTL-M1
      - SUN2000 10 KTL-M1

automation:
  - alias: "Inverter #1 Model"
    trigger:
      platform: state
      entity_id: input_select.inverter_1_phases
    action:
      service: input_select.set_options
      data:
        entity_id: input_select.inverter_1_models
        options: >
          {% if trigger.to_state.state == '1 Phase' %}
            [
              "Select",
              "SUN2000 2 KTL-L1",
              "SUN2000 3 KTL-L1",
              "SUN2000 3.68 KTL-L1",
              "SUN2000 4 KTL-L1",
              "SUN2000 4.6 KTL-L1",
              "SUN2000 5 KTL-L1",
              "SUN2000 6 KTL-L1"
            ]
          {% elif trigger.to_state.state == '3 Phase' %}
            [
              "Select",
              "SUN2000 3 KTL-M1",
              "SUN2000 4 KTL-M1",
              "SUN2000 5 KTL-M1",
              "SUN2000 6 KTL-M1",
              "SUN2000 8 KTL-M1",
              "SUN2000 10 KTL-M1"
            ]
          {% else %}
            {{ 'Select No of Phases' }}
          {% endif %}