Script to find all ungrouped items

Hi @finity, If you have the indentation levels right, it will not add the group unless there are two or more items in it (including the trigger for the script). However, there is currently nothing in the script to remove the group if it already exists.

If you have already dealt with everything in the view, and want to get rid of it, you might need to restart HA.

Love this, will hopefully integrate it so that the view appears when my maintenance mode is on, and disappears when it’s off.

Thanks for sharing :+1:

Hi @Mariusthvdb

in order to get groups that aren’t included anywhere, try this (I’m not actually on my HA system right now, but this should work, or at least be pretty close). I can verify it when I am done work if necessary.

Remove group from the domains_to_ignore variable or parameter

Change the block which is currently this

  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)

to

  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"):
      if (state.entity_id != target_group):
        groups.append(state.entity_id)
      if (("view" in state.entity_id.attributes) and (state.entity_id.attributes["view"] == false)):
        entity_ids.append(state.entity_id)

I will take a look at the group.set service (I wasn’t aware of it until just now, and also see there’s a group.remove). One thing I have found frustrating is because I am doing everything inside a function, a lot of objects aren’t automatically available (which is why I pass hass and logger into the function)

cool.

we can set the groups visibility and the view easily with the code I posted.

Ive filed a request to do so with a template, as is possible with group.set_visibility alone.

which is kind of cool, since one can then template that depending on a mode (in my settings a dev-mode… or not)

as it stands now, we have to hard code it. Works but less elegant.

Running the python script now creates the group as a view, as I have screenshot and posted.

We should be able to toggle the view. Instead of always setting to true, we should be able to enable/disable when we want it

see Allow for full templating support in Group.set

Ohh…that is unfortunate. I guess, we can have two separate actions

yes, that how I do it now:

scene_normal:
  alias: Call Normal scene
  sequence:
    - service: homeassistant.turn_off
      entity_id: group.philips_motion_sensor_switches
    - service: input_select.select_option
      data:
        entity_id: input_select.theme
        option: 'teal'
    - service: group.set
      data:
        object_id: developer
        view: false
        visible: false

scene_developer:
  alias: Call Developer scene
  sequence:
    - service: homeassistant.turn_off
      entity_id: group.philips_motion_sensor_switches
    - service: input_select.select_option
      data:
        entity_id: input_select.theme
        option: 'matrix'
    - service: group.set
      data:
        object_id: developer
        view: true
        visible: true

That’s perfect…dev mode on/off :slight_smile:

Okay, when I get home this evening, I will look at adding a couple more parameters (and maybe a bit of restructuring)

  1. show_as_view to control whether it is set as a view or not (default true)
  2. show_if_empty to control whether it is shown if there are no ungrouped items (I guess you guys want default false?)

I believe that should allow you guys to do what you’re looking to?

I haven’t tried Developer mode yet, but this way to toggle it is really cool. I’m learning a lot just from what you guys are sharing, thanks!

of course, I should have added this to my template switch:

switch:
  - platform: template
    switches:
      mode_developer:
        friendly_name: Developer mode switch
        value_template: >
          {{ is_state('input_select.mode', 'Developer') }}
        turn_on:
          - service: script.mode_developer_direct
          - service: homeassistant.turn_on
            entity_id: input_boolean.notify_developing

        turn_off:
          - service: script.mode_normal_direct
          - service: homeassistant.turn_off
            entity_id: input_boolean.notify_developing

Weirdly enough, when I run group.set with {"object_id": "catchall", "view":false, "visible":false}, instead of modifying group.catchall, it creates new group.catchall_2, group.catchall_3,…

besides a typo (had true instead of True for visible, attribs={“visible”:True, “view”:True, “friendly_name”: “Ungrouped Items”, “icon”: “mdi:magnify”}

all is fine here:

before:

33

click:

49

after:

14
32

changing Execute into Catch!

homeassistant:
  customize:
    script.catchall:
      action_name: 'Catch!'
      icon: mdi:baseball
      show_last_changed: true

After you have the group.catchall, can you run the group.set service from dev panel to see if it is removed/hidden?

I hope to do that by selecting the normal_mode again, or switching of my dev_mode switch. But here’s the dev tools:
09

and, unfortunately the group stays in view…
and, also unfortunately, I see a group.catchall_2… !
this is new, worked before.
maybe take the visibility and view out of the python.

Same here…something is not quite right there.

the script itself does work, I do it with my dev tools, and they show and hide on command. It is a predefined group though, which I simply have not grouped anywhere, so it shows up in the far right of the tab-bar, when made visible and a view by the script.

We should probably try to do the same with this Ungrouped catch_all group.

check, this works:

group:
  developer:
    name: Developer
    icon: mdi:developer-board
#    view: true
    entities:
      - switch.mode_developer
      - script.reload_frontend
      - script.reload_python
      - script.catchall
      - script.restart_ha
      - script.rc_reboot_iungo
      - script.sc_reboot_iungo
      - group.catchall # if made on the fly by python_script

group.developer is displayed as view in dev_mode (see previously posted switch, or input_select.mode).
it reveals the script for running the python script. (Ive removed the view: true in the python script)

running the script

script:
  catchall:
    alias: Catch all ungrouped
    sequence:
      - service: python_script.populate_catchall

creates the group.catchall, which is then displayed. Switching of dev-mode, takes it all out again :wink:

Cheers,
Marius

Hi guys,

here’s an updated version of the script.

I added three new parameters
show_as_view (whether to create it as a view or a group, defaults to True)
show_if_empty (whether to show the group or not depending on the number of items, defaults to False)
min_items_to_show (this controls the show_if_empty. It defaults to showing the group if at least one uncaught item was found).

I’ve also modified the script so that it doesn’t exclude Groups by default, so it will find groups that aren’t included anywhere (I found a few I’d forgotten about).

It also ignores Hidden items (alerts were causing me problems while testing, not sure how I will deal with this in the long run).

def scan_for_new_entities(hass, logger, data):
  ignore = data.get("domains_to_ignore","zone,automation,script,zwave")
  domains_to_ignore=ignore.split(",")
  target_group=data.get("target_group","group.catchall")
  show_as_view = data.get("show_as_view", True)
  show_if_empty = data.get("show_if_empty", False)
  min_items_to_show = data.get("min_items_to_show", 1)
  
  logger.info("ignoring {} domain(s)".format(len(domains_to_ignore)))
  logger.info("Targetting group {}".format(target_group))

  entity_ids=[]
  groups=[]
  
  for s in hass.states.all():
    state=hass.states.get(s.entity_id)
    domain = state.entity_id.split(".")[0]
    
    if (domain not in domains_to_ignore):
      if (domain != "group"):
        if (("hidden" not in state.attributes) or
             (state.attributes["hidden"] == False)):  
          entity_ids.append(state.entity_id)
      else:
        if (("view" not in state.attributes) or 
          (state.attributes["view"] == False)):
          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)))

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

  attrs={}
  attrs["view"]=show_as_view

  if (len(entity_ids)) > min_items_to_show or show_if_empty:
    attrs["visible"]=True
  else:
    attrs["visible"]=False

  attrs["friendly_name"]="Ungrouped Items"
  attrs["icon"]= "mdi:magnify"
  attrs["view"]=show_as_view
  attrs["order"] = high_order
  entity_ids.insert(0,"script.scan_for_new_devices")
  attrs["entity_id"]=entity_ids

  hass.states.set("group.catchall", "new", attrs)

scan_for_new_entities(hass, logger, data)
2 Likes