Template to display loaded components on HA instance?

added a dedicated Lovelace bit to the script, which doesn’t use the formatting codes (Markdown card doesn’t handle these at all, so looks a bit silly) One can use markdown code in the card definition, but there’s not much use with this card.

Lovelace output:

05

btw @petro,

I’ve used your template for the template card, made it multiline and use state_attr(), but the list isn’t using the \n after each component.

this is perfect (so I know the cards first use in my setup works…):
50

but then this shows:

56

using this code:

  - type: custom:card-templater
    card:
      content_template: >-
        {{ "<details>\n" + state_attr('sensor.mqtt_hub_config','components') | sort | join('\n') + "\n</details>" }}
      title_template: >
        {{state_attr('sensor.mqtt_hub_config','components')|length}} Components Loaded
      type: markdown
    entities:
      - sensor.mqtt_hub_config

entering that exact details template in dev-template show the correct format:

would that be a card issue, or a template issue…

anyways here’s the adapted python_script for use in lovelace and a markdown card:

##############################################################################################################
# python script to show the loaded components on a  Hassio instance, and order them alphabetically, grouping
# components that have sub components (attributes)
# this script gets its data from the rest_sensor:
#   - platform: rest
#     name: Mqtt hub config
#     resource: !secret resource_mqtt_hub_config
#     authentication: basic
#     value_template: >
#       {{ value_json.version }}
#     json_attributes:
#       - components
#       - unit_system
#       - config_dir
#     headers:
#       Content-Type: application/json
#       Authorization: !secret api_bearer_token
#       User-Agent: Home Assistant REST sensor
#
# use in Lovelace:
#  - type: custom:useful-markdown-card
#    content: >
#       [[ sensor.mqtt_hub_loaded_components.attributes.text_lovelace ]]
##########################################################################################
# Codes for text_colors declared in 
# Custom card: /custom_ui/state-card-value_only.html
# changed to use below customizing options:
##########################################################################################
#
#      case "*": return "bold";
#      case "/": return "italic";
#      case "!": return "red";
#      case "+": return "green";
#      case "=": return "yellow";
#      case "%": return "grey";
#      case "$": return "brown";
#      case "#": return "blue";
#      default:  return "normal";
#
# https://community.home-assistant.io/t/template-to-display-loaded-components-on-ha-instance/114402/59
# @123 and @apop pointed to the rest sensor, and made that availabe in Lovelace
# @petro had a great hand in creating the script
# thanks for joining in on a great HA community!
# @mariusthvdb 20190504
##############################################################################################################

components = hass.states.get('sensor.mqtt_hub_config').attributes['components']
cnt = len(components)
components.sort()

# Make a dictionary of all main domains, add each sub domain to the main domain list.
compdict = {}
for component in components:
    if component.count('.') == 0 and component not in compdict:
        compdict[component] = []
    if component.count('.') == 1:
        domain, subdomain = component.split('.')
        compdict[domain].append(subdomain)
        
# Make the dictionary into a flat list of strings.
complist = []
complistLovelace = []
for key, value in compdict.items():
    if value:
        value.sort()
        # Adding a domain & series of sub domains
        complist.append('!- {}: \n /--> {}'.format(key, ', '.join(value)))
        complistLovelace.append('- {}: \n --> {}'.format(key, ', '.join(value)))
    else:
        complist.append('+- {}'.format(key))
        complistLovelace.append('- {}'.format(key))

# join each component with a carriage return
complist = '\n'.join(complist)
complistLovelace = '\n'.join(complistLovelace)

text = '*========== {} Loaded Components ========\n' \
       '{}'.format(cnt, complist)

textLovelace = '========== {} Loaded Components ========\n' \
       '{}'.format(cnt, complistLovelace)

#text = text + complist

hass.states.set('sensor.mqtt_hub_loaded_components', cnt, {
        'custom_ui_state_card': 'state-card-value_only',
        'text': text,
        'text_lovelace': textLovelace
    })

##############################################################################################################
# first attempt, simply creating an unordered list of components
# components = hass.states.get('sensor.hassio_main_config').attributes['components']
# count = len(components)
# components.sort()
# list = ', '.join(components)
# 
# text = '*========== {} Loaded Components ========\n' \
#         '+{}' \
#           .format(count,
#                   list)
# 
# 
# hass.states.set('sensor.hassio_main_components', count, {
#         'custom_ui_state_card': 'state-card-value_only',
#         'text': text
#     })

inspired by this, Id like to get back to my efforts trying to show the list of domains in a same way: get it to be populated on an attribute ‘text’ of a sensor set in Python, and overcome the 255 max character that way.

Normally I read the states for doing that of an existing sensor, as in the above script. But I can’t do that right now since the sensor isn’t created because of the 255 character limit.

this is the template in regular jinja I am after, which can’t be done because the list is too long:

  {%- for d in states | groupby('domain') %}
   {% if loop.first %}{{loop.length}} Domains:
   {% endif %}- {{ d[0] }}
 {%- endfor %}

How can I set that in python directly, to go on with that and do something like this:

domains = hass.states.get(states|groupby('domain'))   ##<---- of course this is nonsense but just to show you what I am after
cnt = len(domains)
domains.sort()


domainlist = []

for d in domains:
        domainlist.append('- {}'.format(d))

# join each component with a carriage return
domainlist = '\n'.join(domainlist)

text = '*========== {} Loaded Domains ========\n' \
       '{}'.format(cnt, domainlist)


hass.states.set('sensor.hassio_main_domains', cnt, {
        'custom_ui_state_card': 'state-card-value_only',
        'text': text
    })

Id appreciate an extra eye here, thanks!

@petro, forgot to tag you here, sorry for that. If you could spare another moment, Id appreciate the effort very much.

This might work

domains = [ s.domain for s in hass.states.all() ]
domains = list(dict.fromkeys(domains))
cnt = len(domains)
domains.sort()


domainlist = []

for d in domains:
        domainlist.append('- {}'.format(d))

# join each component with a carriage return
domainlist = '\n'.join(domainlist)

text = '*========== {} Loaded Domains ========\n' \
       '{}'.format(cnt, domainlist)


hass.states.set('sensor.hassio_main_domains', cnt, {
        'custom_ui_state_card': 'state-card-value_only',
        'text': text
    })

thanks! almost I hope.

the second line throws an error, but when leaving that out, I get a respons for all states ordered by domain:

which is 90% of the goal.

Only need to set the 2nd line, which throws this error:

Error executing script: name 'list' is not defined
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "domains_in_use.py", line 10, in <module>
NameError: name 'list' is not defined

nm the line 10, which is caused because I have some commenting on the first few lines. it s about domains = list(dict.fromkeys(domains))

jesus… I really hate that python environment. It has nothing in it. So freaking limited.

Try this:

domains = []
for s in hass.states.all():
    res = str(s.domain)
    if res not in domains:
        domains.append(res)
cnt = len(domains)
domains.sort()


domainlist = []

for d in domains:
        domainlist.append('- {}'.format(d))

# join each component with a carriage return
domainlist = '\n'.join(domainlist)

text = '*========== {} Loaded Domains ========\n' \
       '{}'.format(cnt, domainlist)


hass.states.set('sensor.hassio_main_domains', cnt, {
        'custom_ui_state_card': 'state-card-value_only',
        'text': text
    })

I know you do… :wink:

this doesn’t error out, but the result remains the same:

Not sure what to tell you. That’s the only way we can filter inside this environment. If that if statement is not working, nothing can be done.

I made a change, if that doesn’t work then you are SOL.

it DOES…!

Perrfect, thank you so very much. Trying to learn here, could please in human language explain what your doing, (maybe why the other didn’t work) and why this script finds items not being in the domains, while the jinja template simply groups all domains with the same name and shows only that unique domain?

Ive done some searching on groupby in Python, saw a few tries, but your solution seems a different approach?

Well that’s good to know. That means domain is not a string it’s an object. Still doens’t make sense why str() would work and list() wouldn’t.

Apologies if this has already been explained in this thread but I couldn’t find it. I’d like to try this python_script but I’m not sure how it’s used by the system. Is it executed by an automation at startup? Is the sensor (sensor.hassio_main_domains) created by the script or should it be predefined (and how)?

This python script can indeed be fired at startup, by an automation. I do it by means of a script, which I show in the frontend. Have the script and the sensor in a group, and it shows when fired (and when the sensor is created).

script:

  set_sensor_domains_in_use:
    alias: 'Set sensor domains in use'
    sequence:
      service: python_script.domains_in_use

before running the script:

29

after:


note this is regular HA, Lovelace shows the yellow bar for an non existing entity or a markdown matching error when trying to load the text attributes, which hasn’t been set yet. Probably one can create a conditional card to mitigate that.

note 2: one needs the custom-ui-state-card for regular HA to show this as text only

using a comma to separate the list, simply change to:

for d in domains:
        domainlist.append('{}, '.format(d))

# join each component with a carriage return
domainlist = ''.join(domainlist)

25

Using my test system, I executed the python_script manually (from the Services page) and it successfully generated sensor.domains (I renamed the sensor within the python_script) containing a text attribute with 15 domains.

  • In the States page, the presentation of the list of domains is as shown above (each domain on a separate line).
  • In Lovelace’s UI, the more-info box ignores the newline characters and shows the list of domains all in one paragraph (but that’s not important to me).

so that’s complete succes then? cool.
I always use the text attribute to set, because ever since I started with that custom-ui-card it seemed the most appropriate attribute name. Could be anything of course if you don’t need/want the card.

using the markdown card on Lovelace:

  - type: custom:useful-markdown-card
    content: >
       [[ sensor.mqtt_hub_loaded_components.attributes.text_lovelace ]]

of course change the name.

I believe if you use <br /> as your separator it should add a carriage return if you want it.

since this is a bit old, I posted here List of all 'domains', 'entities', on a related but reversed quest, and would appreciate your thoughts on the matter… sorry for bumping this, didnt want to tag anyone though. thanks for having a look