Script to find all ungrouped items

Hi all,

One thing that irritated me when I set up my own tabs, is that there was no way to catch all the other entities in the system that haven’t been grouped yet.

I’ve been working on this for a short while, and wanted to post it to get some feedback. I’m new to HA, and haven’t done anything in Python for years. Currently, this works on my system, but that is no guarantee it will work on anyone else’s system.

python_scripts/populate_catchall_group.py

ignore = data.get("domains_to_ignore","zone,group,automation,script,zwave")
domains_to_ignore=ignore.split(",")
target_group=data.get("target_group","group.catchall")

logger.info("ignoring {} domain(s)".format(len(domains_to_ignore)))
logger.info("Targetting group {}".format(target_group))

def scan_for_new_entities(hass, logger, domains_to_ignore, target_group):
  entity_ids=[]
  groups=[]
  catchall=hass.states.get(target_group)

  if (catchall is None):
    logger.error("Target group {} doesn't exist".format(target_group))
    return
  
  for state in hass.states.all():
    domain = state.entity_id.split(".")[0]
    if (domain not in domains_to_ignore):
      entity_ids.append(state.entity_id)
    if (domain == "group") and (state.entity_id != target_group):
      groups.append(state.entity_id)
    

  logger.info("==== Entity count ====")
  logger.info("{0} entities".format(len(entity_ids)))
  logger.info("{0} groups".format(len(groups)))

  for groupname in groups:
    group = hass.states.get(groupname)
    for a in group.attributes["entity_id"]:
      if a in entity_ids:
        entity_ids.remove(a)

  attrs={}
  for a in catchall.attributes:
    if a != "entity_id":
      attrs[a] = catchall.attributes[a]

  entity_ids.insert(0,"script.scan_for_new_devices")
  attrs["entity_id"]=entity_ids
  hass.states.set("group.catchall", catchall.state, attrs)

scan_for_new_entities(hass, logger, domains_to_ignore, target_group)

In order for this to run on startup, I added a automation trigger

- alias: Get Ungrouped Entities On Start
  hide_entity: true
  trigger:
    platform: homeassistant
    event: start
  action:
    service: python_script.populate_catchall_group
    data:
      domains_to_ignore: "zone,group,automation,script,zwave"
      target_group: "group.catchall"

There is also a regular script that calls the python script.

If the “catchall” group (or whatever you call it) is defined as a view, you actually end up with the sensor badges displayed across the top :smile:

Any feedback? questions? Is this something really basic you had all figured out yourselves already? :slight_smile:

19 Likes

Excellent!!

We should find a way to define the group if it does not exist. Also, we need a way to be able to add/remove the group/views dynamically.

What does it actually do?

It adds all the entities that are not defined in a group/view to a group.

Sounds interesting - where to write the code?

The way it’s written at the moment, you would need to first create a group in your groups.yaml (or configuration.yaml) file (here’s how mine looks)

catchall:
  name: Catch All group
  view: yes
  icon: mdi:magnify
  entities:
    - light.doesnt_exist

You would then copy the first big block, and save that in a file in the python_scripts folder under your HA folder (you might need to create the folder).

You can then call the python script from the developer tools - services tab. You might need to restart HA first.

I modified

  if (catchall is None):
    logger.error("Target group {} doesn't exist".format(target_group))
    return

to

  if (catchall is None):
    hass.states.set("group.catchall","Unknown")

so that group will be created if it does not exist.

I used this block to create the group with some attributes I wanted it to have.

  if (catchall is None):
    attribs={"view":True, "friendly_name": "Ungrouped Items", "icon": "mdi:magnify"}
    hass.states.set(target_group, "", attribs)
    catchall=hass.states.get(target_group)

And another change further down to catch the high order from the groups so that I could be sure this went to the end.

Nice. Now, we need a way to toggle the visibility of the group on demand.

That would be an interesting challenge, but I don’t see the need for it.

I have a script added to the view so that I can re-populate it on demand,

Is it okay?

What should be now :slight_smile:

The problem is that the view remains after it is added. It will be nice to be able to remove it after we are done with it.

Hi @Abeksis, it looks as if you haven’t run the script yet.

If you go to the Services section of the Developer Tools area, you should see the script listed in the top drop-down.

Exactly what it will be called will depend on the filename you gave it. Because I saved the file under the name “populate_catchall_group.py” the script shows up in the dropdown as “python_script.populate_catchall_group”. You don’t need to provide any service data, and can just click the Call Service button.

If you don’t see the option in the dropdown, you might need to restart homeassistant (I don’t think the reload scripts option loads python scripts).

@Arsaboo, I suppose you could add a couple of lines of code to set the hidden attribute to true if len(entity_ids) is 1, and false if it’s >1.

You would then need to add an easier way to re-run the script. This is why I’m not interested in doing this part myself. I don’t mind having the extra page hanging around. I’m already using Icons for all my views, so have lots of space :slight_smile:

I just realized that if you haven’t defined your own default view, there might not be anything to show up there.

And to point out another thing that might need to be done is to add “python_script:” to your configuration.yaml file if it’s not already there.

I had a long post asking why I wasn’t seeing the service then realized I hadn’t added the above entry.

It’s working now.

But one other question that I can’t figure out is where does the script create the actual group.catchall? If I’d need to possibly edit it or delete it or whatever I’d like to know where it’s created.

I’ve got my config split into folders and I’ve looked in all the suspected places but I can’t find where it is.

Hi @finity, I could be wrong on this, but I think it’s a temporary group lasting until the system gets rebooted.

When I disable the automation that runs the script on startup, and restart HA then the group doesn’t exist until I manually run the script

I think you’re right.

I just restarted my HA and the group was gone. I haven’t implemented the automation to regenerate it at startup yet.

Thanks for this. It’s something I’ve wanted in HA since I split my groups up into different views. It’s kind of easy to add something then forget about adding it to a group somewhere.

One other thing I just thought of…

Is it possible for the script to run at every startup via the automation but if there are no ungrouped items the catchall group doesn’t get created?

That way if there is nothing ungrouped you wouldn’t have the extra tab. Then if there was something new that is ungrouped it would be more likely to get your attention than if it was always there.

I have a file named scripts.yaml where all the codes of the scripts are located. Should your code name be? The truth I tried to add but it does not fit me in terms of lines.