Just tested it. You are correct. It defaults to that you have in the py file and if you pass things when you run the service it overrides that and replaces the ignore list with the one you supplied. Perfect. Thanks again!
Loved the script.
I’m trying (without success, how can I add filter for specific string in “friendly name” attribute.
For example, all the entities in those domains that contains the words “first_floor”.
It is possible?
"""Turn off devices that are on unless ignored."""
ignore = data.get("friendly_name_ignore").split(",")
domains = ['light','fan']
device = []
for domain in domains:
for entity_id in hass.states.entity_ids(domain):
state = hass.states.get(entity_id)
if state.state == 'on':
for name in ignore:
if name not in state.name and state.entity_id not in device:
device.append(state.entity_id)
if device:
data = { "entity_id" : device }
hass.services.call('homeassistant', 'turn_off', data)
Thanks for that.
Actually I’m trying to choose entities based on friendly name, not ignore them…
Also, It’s possible to set only part of the friendly name? for example, turn off all entities that are on and contains the string “first_floor” (so “light.bathroom_first_floor” will turn off, but “light.bathroom_second_floor” will stay on).
just remove the first not in the if ignore line and it will do what you want. But it’s looking at the whole string not just the first part.
It’s the critical part. I must search in part of the string, not all of it.
It’s not have to be in Python. Template script is good for me also.
If you can help me with that I will really appreciate it.
I am using the following code to build a comma sep, list of entities. i also enclude a “dummy” entity just to make sure the list is not empty.
This seems to have broken to present as a comma separated list for the homeassistant.turn_XXX call, but it works fine for the light.turn_XXX and switch.turn_XXX calls…
Presenting as a regular list works fine.
I still don’t think you understand me. It’s searching part of the string. But it’s searching the whole string for part of a string. Which is what you are asking for.
OK.
Just tested it. I’m getting this error in the log:
Error executing script: 'in <string>' requires string as left operand, not list
For me this is working the only caveat is that I have to do it domain by domain (light, switch, fan, climate, media_player, etc) but it won’t throw any errors when all devices from a domain are off as I pass a have a dummy device when the array is empty:
- service: light.turn_off
data_template:
entity_id: >
{%- set device = dict(states.light|groupby("state"))["on"] %}
{%- for device in device %}{%- if loop.first %}{% else %}, {% endif %}{{ device.entity_id | lower }}{%- if loop.last %}{% endif %}{%- endfor %}{%- if device|length < 1 %}{{'light.dummy'}}{% endif %}
Also I have a version of it where I can set which entities to exclude:
- service: switch.turn_off
data_template:
entity_id: >
{% set exclude_entities = [
'switch.tv',
'switch.mibox',
'switch.speakerslr',
'switch.wake_on_lan',
'switch.mediaplayer',
'switch.keeptvon',
'switch.aircooler',
'switch.plug_158d0002167b64',
'switch.plug_158d000117b73d',
'switch.omv_tranmission_switch',
'switch.washing_machine',
'switch.camera'
] %}
{%- set device = dict(states.switch|rejectattr('entity_id','in',exclude_entities)|groupby("state"))["on"] %}
{%- for device in device %}{%- if loop.first %}{% else %}, {% endif %}{{ device.entity_id | lower }}{%- if loop.last %}{% endif %}{%- endfor %}{%- if device|length == 0 %}{{'switch.dummy'}}{% endif %}
This is thanks to a few threads
I found the answer right here in the forum, I just merged whatever I found around across several posts.
Sorry to bring back such an old topic, but this seems to be exactly what I’m trying to do. I’m a newbie, and really haven’t grasped this code yet. (also, not real coding experience).
I’m looking to turn off only lights that are on in part of a switch group or light group. I’ve tried running the following code under scripts, as action in an automation and as a python script and cannot get it to work. Hopefully someone can point me in the right direction.
service: homeasisstant.turn_off
data_template:
entity_id: >
{% set group_id = 'switch.basement_lights_group' %}
{% set on_states = ['on'] %}
{{ states | selectattr('entity_id','in', state_attr(group_id, 'entity_id')) | selectattr('state','in',on_states) | map(attribute='entity_id') | join(', ') }}
This is the error message I get.
Message malformed: template value is None for dictionary value @ data[‘sequence’][0][‘data_template’]
service: switch.turn_off
target:
entity_id: >
{{ expand(state_attr('switch.basement_lights_group', 'entity_id'))
| selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }}
-
Your switch group named
switch.basement_lights_group
has an attribute calledentity_id
. -
That attribute lists all of the switch group’s members.
-
The template uses
expand
to get each member’s information. -
It uses
selectattr
to select only the members whosestate
ison
. -
It uses
map
to reduce the information for each member just to itsentity_id
. -
It reports the result as a list.
Thanks for the quick response and detailed explanation. . I tested your updated code and it does work and it’s very quick. My goal is to take this code and use it in a service where I pass switch or light and the group to control the lights. Thanks again.
If you intend to use it in a manner where the group might be either a switch
or light
group then the service call should be homeassistant.turn_off
.