Dynamic lists in Home assistant

One of the features currently missing in Home assistant is support for dynamic lists. For example, if you had a number of video files from a security camera which are stored in a directory and the videos are changing every day, how would you be able to show this in Home Assistant. The solution below is a little involved, but does work very well and can be adapted for your needs.

example of a dynamic list in Home Assistant

First, we need to create an ‘input select’ in the configuration.yaml file. We will only give it one static option at this point, which will just let us know if the list has been updated or not. When the list has been correctly updated this option will disappear from the list.

input_select:
  security_video_playlist:
    name: Security Video playlist
    options:
      - 'List not defined - run rest update command'  
    icon: mdi:video

Next, we need to create a sensor. This will store the filenames of the video files as attributes within a sensor. The sensor takes its information from a JSON formatted file within the same directory as the security videos. The folder is best placed in the homeassistant configuration/www directory as this directory is an already accessable resource in Home Assistant.

sensor:  
  platform: rest 
  name: Security video playlist
  json_attributes: 
    - path
    - files
   resource: https://XXXX.com/local/timelapse_recordings/json.txt
  value_template: "{{ value_json.path}}" 

To create the JSON formatted list of the directory contents I used this python script, which I found somewhere online and re-purposed to create a JSON list in the format I needed. You would need to create a cron job to run this script every 5 minutes, so that it maintains an up to date list of the directory contents. I have attached the python script and an example of the output it generates.

#!/usr/bin/env python

import os
import errno

def path_hierarchy(path):
    hierarchy = {
        'type': 'folder',
        'name': os.path.basename(path),
        'path': path,
    }

    try:
        hierarchy['files'] = [
            path_hierarchy(os.path.join(path, contents))
            for contents in os.listdir(path)
        ]
    except OSError as e:
        if e.errno != errno.ENOTDIR:
            raise
        hierarchy['type'] = 'file'

    return hierarchy

if __name__ == '__main__':
    import json
    import sys

    try:
        directory = sys.argv[1]
    except IndexError:
        directory = "."

    print(json.dumps(path_hierarchy(directory), indent=2, sort_keys=True))

We now have a method of creating a directory list, a sensor which will read the list and an ‘input select’ to hold the list options. But, we now need to tell Home Assistant to feed the sensor data into the ‘input select’. This is quite a complex statement which we need to insert into the configuration.yaml file. I will show the statement and then break down what it does.

rest_command:  
  populate_input_select_security_video_playlist:
    url: "https://XXXXXXX.com/api/services/input_select/set_options"
    method: POST
    headers:
      content-type: application/json
      x-ha-access: {your secure API key}
    content_type: application/json
    payload: >-
      {
        "entity_id": "input_select.security_video_playlist",
        "options": [
      {%- set files = states.sensor.security_video_playlist.attributes.files -%}
      {%- for item in files -%}
        "{{ item.name }}"{% if not loop.last %}, {% endif %}
      {%- endfor %}]
      }

The above rest command instructs Home Assistant to set the options for an input select, by reading the contents of the sensor. In the payload statement, we instruct Home Assistant to iterate through each JSON object under ‘files’ attribute and pull out the object called ‘name’. Each ‘name’, (which is a filename) will then be fed to the ‘input select’ as an option.

Finally, we need to create a simple automation to run the rest command often, so that the ‘input select’ is constantly updated (say every 5 minutes).

automation:
  alias: Populate input select for media players and update playlists 
  initial_state: True 
  trigger:
    - platform: homeassistant
      event: start
    - platform: time_pattern   
      minutes: '/5'
  action:
    - delay:
        seconds: 30
    - service: rest_command.populate_input_select_security_video_playlist 

I said it was a little convoluted, but if you absolutely do need a dynamic list of elements in your Home Assistant, this is one method I have found. As a way of finishing off, you might like to know how I play my security files in home assistant. I direct the chosen file to a local chromecast stick. So now I can play a video file to any chromecast in the house. The automation below shows how I achived this.

automation:
- alias: Play security video (last 24hrs)
  initial_state: True
  trigger:
    - platform: state
      entity_id: input_boolean.play_security_video
      to: 'on'
  action:
    - service_template: >
        {% if is_state('input_select.video_capable_players', 'off') %}
          media_player.turn_on
        {% else %}
          script.noop
        {% endif %}
      data_template:
        entity_id: '{{ states.input_select.default_tts_media_player.state }}'
    - service: media_player.play_media
      data_template:
        entity_id: '{{ states.input_select.video_capable_players.state }}'
        media_content_id: 'https://XXXXXXX.com/local/timelapse_recordings/{{ states.input_select.security_video_playlist.state }}'
        media_content_type: video
    - service: input_boolean.turn_off
      data:
        entity_id: input_boolean.play_security_video

And the final view in Home Assistant looks like this.

Leave a Reply

Your email address will not be published. Required fields are marked *