One Light on at a Time

Interesting, I wasn’t aware the entity selector let you just type in a comma-separated list of values anyway.

I think you actually can work with that then, you just have to adjust the automation a bit with some templates. So first, you have to stuff the value of that input into a variable so you an access it in templates by adding this to the top of the automation:

variables:
  light_list: !input light_list

Next you won’t be able to use a state trigger, you’ll have to use a template trigger like this:

trigger:
- platform: template
  value_template: >-
    {{ (light_list | regex_replace('\\s+', '')).split(',') | expand | selectattr('state', 'eq', 'on') | list | count > 0 }}

So what this will do is strip all whitespace out of the users entry, split the list by commas, expand it to get the actual entity data and then return true if there are one or more lights on. It’s also going to trigger any time any of the lights referenced in light_list are updated.

Now unfortunately using a template trigger means you won’t get access to trigger.entity_id so we’re going to have to use essentially the same template again. Fortunately though this is going to trigger as soon as a light has turned on. So any time this triggers we want to immediately turn off all lights except the last one turned on like this:

action:
- service: light.turn_off
  data:
    entity_id: >-
      {{ ((light_list | regex_replace('\\s+', '')).split(',') | expand | selectattr('state', 'eq', 'on') | sort(reverse=True, attribute="last_changed") | map(attribute="entity_id") | list)[1:] }}

This first part of this template should look familiar since its reconstructing the same list of which lights from the list are on. Then its sorting that list based on last_changed to ensure the one turned on last is first, turning the list back into an array of light IDs and then stripping the first one off the list (since that’s the one you want to keep on).

If you just turn your automation into this trigger and this action that alone will ensure there is never more then one light in the list on at any one time. The two hour delay bit is the final part, for that we’ll these final 3 actions:

- wait_template: >-
    {{ (light_list | regex_replace('\\s+', '')).split(',') | expand | selectattr('state', 'eq', 'on') | list | count != 1 }}
  timeout: 
    hours: 2
- condition: template
  value_template: "{{ not wait.completed }}"
- service: light.turn_off
  data:
    entity_id: >-
      {{ (light_list | regex_replace('\\s+', '')).split(',') | expand | selectattr('state', 'eq', 'on') | map(attribute="entity_id") | first }}

You’ll also want to change the mode to queued so the next iteration of this automation cannot start until the previous one has finished (but then will be started, we don’t want to drop them).

So what happens now is that this will wait until the number of lights on from the list is not exactly 1 (since it just made it exactly one in the previous step) or two hours have passed. It will then proceed in one of the following ways:

  1. All the lights are off, we’re good then, stop execution
  2. More then one light is on, don’t do anything since another instance of this automation is now queued, just exit and let it run
  3. The wait timed out because the light was left on for 2 hours. In that case proceed and turn that light off by finding the one on one from the list

Phew, that was a lot. I really wish there was a “select list of entities” selector. But in the meantime, seems like this would work pretty efficiently using a comma-separated list form of entry.

[EDIT] Tweaked the trigger template to trigger any time any light turns on, not just more then one. Realized it didn’t handle the situation where a light turned on and you wanted it to turn back off 2 hours later. Also FYI these templates work fine if a user does just enter one light and wants it to timeout after 2 hours.

1 Like

Not sure the juice is worth the squeeze; despite all that heavy-lifting, the user still has to enter multiple light entities from memory avoiding typos (OK, you can peek at the menu … :slight_smile:).

A multi-select Entity selector is sorely needed.

Yeah, doesn’t all that just do the same thing that my automation already accomplishes with way less work?

Sorry I think I misunderstood. I thought you were saying the list of comma-separated IDs did not work in the trigger state area. You’re right then, ignore me, sorry about that.

Yea absolutely. There’s a few I think are really needed:

  1. List of entities selector
  2. Service selector, like provide the name of a service of type notify, scene, script or any of the types of services where you end up with a lot of unique ones that are called with a common interface. Notify in particular is problematic since there is no associated entity and the calls vary slightly from integration to integration, hence why you see everything selecting a device of type mobile_app right now
  3. Dictionary selector, so users can provide a dictionary that can then be used in templates in service calls

#1 is the biggest though

EDIT: One I forgot, a device by service selector (kind of an alternative to #2 but somewhat different). Like I want you to select a device which has a specific known service like turn_on, turn_off, notify, etc., regardless of what type of device it is. That would even be useful for this blueprint too, for instance, you can’t use this blueprint if you have switch entities instead of light entities for your lights. Perhaps because they are table lamps controlled by smart plugs or are lights represented as switches since they don’t have any dimming options.

It should be pretty easy for me to change it to allow for switch and lights to turn off. Just have to change light.turn_off to homeassistant.turn_off and update the selector, and it should be good to go!

Technically you are correct. But I’ll point out your selector is for light so a user would not see switches in the dropdown. However since apparently users can enter any text they want in an entity selector you are correct in that if they put in a comma-separated list of switches and lights and you changed the action to homeassistant.turn_off it would all work. But of course at that point the selector just isn’t doing anything at all, might as well just change it to text and put all this in the description.

If we’re making a wish list for Santa, this bastardized usage of choose needs a proper replacement:

- service: whatever
  entity_id: !input user_supplied_entity
- choose:
  default: !input user_supplied_actions

Currently, that’s the only way to insert a user-supplied set of actions among some existing actions. Ideally, something like a standalone sequence option would be permitted.

- service: whatever
  entity_id: !input user_supplied_entity
- sequence: !input user_supplied_actions

In other words, the ability to assign that !input directive to something other than a lobotomized choose.

I was able to add switch to the selector, so it will show all lights and switches. Tested and it works. Maybe Santa will give us a multi-select option for Christmas!

2 Likes

Congratulations! Well done! :+1:

That’s undocumented and the first example of a multi-domain Entity selector that I’ve seen in this forum.

FWIW, I just tried it in one of my blueprints and it works as advertised.


EDIT

I’ve discovered at least one limitation. If you add a qualifier for any of the domains (I added device_class: motion for domain: binary_sensor) the multiple domains are reported as an error (duplicated domain keys).

1 Like

Bad news. It appears you have discovered a bug as opposed to an undocumented feature.

When I use the blueprint to create an automation, the moment the Entity selector displays multiple domains, an error message is posted to Logs complaining about duplicate domain keys.

The bug is that neither Check Configuration or Reload Automations detects the duplicated domain keys. They’re caught at runtime when the Entity selector is used (or at least that’s how it appears based on my tests).

That’s odd. I did a test using a light and a switch and it accepted it in the automation. More importantly, the automation worked as expected.

I think if you check Logs you will find that it’s not entirely happy with it.

It might appear to be functioning properly but under the hood there’s a ticking sound …

The moment I select a light using an Entity selector listing lights and switches, this gets logged:

I tried something slightly different:

      selector:
        entity:
          domain: light
        entity:
          domain: switch

This seems to work without errors.

Still produces the same warning message for me. I’ve narrowed it down to the moment the blueprint is opened to create an automation, the warning message is generated.

I should clarify that in my previous post I called it an error message but, to be more accurate, it’s a warning. Nevertheless, using the blueprint with this multi-domain syntax does generate warning messages.

In addition, the menu fails to produce a complete list of available entities. In other words, when I use this:

  input:
    first_entity:
      name: First Light
      description: Select a light.
      selector:
        entity:
          domain: light
        entity:
          domain: switch
      default: light.hallway_light

It shows me only two entities in the menu, one light and one switch. There’s only one switch available, so that’s fine, but there are many available lights.

I have a second Entity selector defined in the same blueprint:

    second_entity:
      name: Second Light
      description: Select a light.
      selector:
        entity:
          domain: light
      default: light.foyer_light
variables:

This one’s menu lists all available lights (and not just one like in the first selector).

Finally, if I define three domains for the first selector:

  input:
    first_entity:
      name: First Light
      description: Select a light.
      selector:
        entity:
          domain: light
        entity:
          domain: switch
        entity:
          domain: binary_sensor
      default: light.hallway_light

the resulting menu lists all four binary_sensors, only one light, and no switches. That’s different from the previous test but equally wrong.

Given that the generated menus are inconsistent, and warning messages are produced, I believe this is a bug, not an undocumented feature. There’s no way I would want to release a blueprint that leverages this bug because users are likely to encounter unusual selector behavior.

Wait a minute, isn’t the answer here just to use the target selector? It specifically allows you to select multiple entities of the same type.

@123 I just saw your conversation over in the Single user lights blueprint, this is the same situation isn’t it?

I think so. I failed to examine the other one closely and assumed it was tackling the ‘list of lights’ issue the same way as this one. However, I was wrong and the other one uses target constrained to the light domain.

If the same technique is employed here, the service call will need to be modified to accept target as opposed to entity_id.


EDIT

I recall experimenting with the Target Selector and could only constrain it to a single domain.

I also noticed that the author of this topic’s blueprint has chosen to use an Entity Selector with multiple domains, despite the fact it’s unreliable and logs warning messages. :man_shrugging:

Invalid use of multiple domains in an Entity Selector

I tried using the target selector, but while it appears to work, any automations created using it wouldn’t actually work. It would throw an error in the logs along the lines of:

2020-12-22 12:19:12 ERROR (MainThread) [homeassistant.components.automation] Blueprint Keep One Light on at a Time generated invalid automation with inputs OrderedDict([(‘light_list’, OrderedDict([(‘entity_id’, [‘light.basement_stairs’, ‘light.basement_storage’])]))]): Entity ID entity_id is an invalid entity id for dictionary value @ data[‘entity_id’]. Got None

Did you do this?

I tried, but can’t seem to figure out how to do that.