Only turn off lights when there is no current motions (2 attempts both failed miserably)

Evening All

I have tried to put together a script to turn off all lights in rooms that have no motion and have failed miserably twice:

Attempt One:

'1538598508744':
  alias: NoMotionLightOff
  sequence:
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001d5403a', 'off') %} 
         light.hallway
       {% elif is_state('binary_sensor.motion_sensor_158d0001d694b2', 'off') %} 
         light.landing
       {% elif is_state('binary_sensor.motion_sensor_158d0001a90d90', 'off') and is_state(''binary_sensor.motion_sensor_158d0001b1956a', 'off') %} 
         light.kitchen      
       {% elif is_state('binary_sensor.motion_sensor_158d0001a90d90', 'off') and is_state(''binary_sensor.motion_sensor_158d0001b1956a', 'off') %} 
         light.cupboard  
       {% elif is_state('binary_sensor.motion_sensor_158d0001e7a5a7', 'off') %} 
         light.bedroom_light
       {% elif is_state('binary_sensor.motion_sensor_158d0001b19555', 'off') %} 
         light.childone_light       
       {% elif is_state('binary_sensor.motion_sensor_158d0001e19504', 'off') %} 
         light.childtwo_light
       {% elif is_state('binary_sensor.motion_sensor_158d0001d90b5d', 'off') %} 
         light.porch_light
       {% elif is_state('binary_sensor.motion_sensor_158d0001e5eae8', 'off') %} 
         light.livingroom
       {% else %}
         none
       {% endif %}

Attempt Two:

'1538598508744':
  alias: NoMotionLightOff
  sequence:
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001d5403a', 'off') %} 
         light.hallway
       {% else %}
         none
       {% endif %}
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001d694b2', 'off') %} 
         light.landing
       {% else %}
         none
       {% endif %}
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001a90d90', 'off') and is_state(''binary_sensor.motion_sensor_158d0001b1956a', 'off') %} 
         light.kitchen
       {% else %}
         none
       {% endif %}      
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001a90d90', 'off') and is_state(''binary_sensor.motion_sensor_158d0001b1956a', 'off') %} 
         light.cupboard
       {% else %}
         none
       {% endif %}  
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001e7a5a7', 'off') %} 
         light.bedroom_light
       {% else %}
         none
       {% endif %}
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001b19555', 'off') %} 
         light.childone_light
       {% else %}
         none
       {% endif %}       
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001e19504', 'off') %} 
         light.childtwo_light
       {% else %}
         none
       {% endif %}
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001d90b5d', 'off') %} 
         light.porch_light
       {% else %}
         none
       {% endif %}
  - service: light.turn_off
    data_template:
      entity_id: >
       {% if is_state('binary_sensor.motion_sensor_158d0001e5eae8', 'off') %} 
         light.livingroom
       {% else %}
         none
       {% endif %}

Perhaps I should be going from the other angle of using a service template instead?

The most difficult part of this is when there are no lights to turn off. In that case you can’t really call the light.turn_off service with an empty list of light entity_id’s. So you’d have to add a condition step first, which would end up doing most of the same work as the step that actually generates the list of entity_id’s to turn off.

The easiest way to do this is actually via a python_script instead of a “regular” YAML script. E.g.:

entities = []

if hass.states.get('binary_sensor.motion_sensor_158d0001d5403a').state == 'off':
    entities.append('light.hallway')
if hass.states.get('binary_sensor.motion_sensor_158d0001d694b2').state == 'off':
    entities.append('light.landing')
if (hass.states.get('binary_sensor.motion_sensor_158d0001a90d90').state == 'off' and
        hass.states.get('binary_sensor.motion_sensor_158d0001b1956a').state == 'off'):
    entities.append('light.kitchen')

# Add more like above for additional sensors & lights here...

if entities:
    hass.services.call('light', 'turn_off', {'entity_id': entities})

EDIT: Corrected mistake @Knottyboy discovered; i.e., append .state to each get() call.

I have done something similar but my approach was different (maybe this gives you an idea)

  1. I have defined a light timer (e.g. 2min)
  2. Whenever there is a motion i reset the light timer
  3. When the light timer expires I switch off the light

I did this in Node-Red so I can’t help you with the automation script, sorry.

@pnbruckner , as always thank you for you help. However it doesn’t seem to work for me

All I can dig from the log is this:

2018-10-04 08:30:49 DEBUG (MainThread) [homeassistant.components.websocket_api] WS 1864391504: Received {'type': 'call_service', 'domain': 'python_script', 'service': 'lightsoff', 'service_data': {}, 'id': 35}
2018-10-04 08:30:49 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: domain=python_script, service=lightsoff, service_data=, service_call_id=fbf5d808213c4ac3ac8aea78ba2f3a17>
2018-10-04 08:30:49 INFO (SyncWorker_14) [homeassistant.components.python_script] Executing lightsoff.py: {}
2018-10-04 08:30:49 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]: service_call_id=fbf5d808213c4ac3ac8aea78ba2f3a17>

This is what I have (also double checked binary sensors and light names):

entities = []

if hass.states.get('binary_sensor.motion_sensor_158d0001d5403a') == 'off':
    entities.append('light.hallway')
if hass.states.get('binary_sensor.motion_sensor_158d0001d694b2') == 'off':
    entities.append('light.landing')
if (hass.states.get('binary_sensor.motion_sensor_158d0001a90d90') == 'off' and
        hass.states.get('binary_sensor.motion_sensor_158d0001b1956a') == 'off'):
    entities.append('light.kitchen')
if hass.states.get('binary_sensor.motion_sensor_158d0001e7a5a7') == 'off':
    entities.append('light.bedroom_light')
if hass.states.get('binary_sensor.motion_sensor_158d0001b19555') == 'off':
    entities.append('light.childone_light')
if hass.states.get('binary_sensor.motion_sensor_158d0001e19504') == 'off':
    entities.append('light.childtwo_light')	
if hass.states.get('binary_sensor.motion_sensor_158d0001d90b5d') == 'off':
    entities.append('light.porch_light')
if hass.states.get('binary_sensor.motion_sensor_158d0001e5eae8') == 'off':
    entities.append('light.livingroom')	

if entities:
    hass.services.call('light', 'turn_off', {'entity_id': entities})

Edit:

I’ve also tried reducing it to just the one light and it still doesn’t work:

entities = []

if hass.states.get('binary_sensor.motion_sensor_158d0001e5eae8') == 'off':
    entities.append('light.livingroom')	

if entities:
    hass.services.call('light', 'turn_off', {'entity_id': entities})

Edit 2:

I have the day off work and was determined to get this done. It’s missing .state at the end of hass.states.get(). It was pulling through all the values associated with the motion sensor (last motion, on/off ect).

Thanks for this man, but I have something similar implemented. This is to run off the back of a button press. My wife likes to leave lights on in rooms she’s not in (to be fair after some moaning she has cut down). I have a button on the side of our bed and it would be nice to turn off all lights where there is no motion (if the kids are up I don’t want to turn their lights off).

Also when I do use the timer to turn them off it’s difficult for rooms like the living room (sitting still on the sofa).

For those who want to know the end result it was this:

entities = (
     ('light.hallway', hass.states.get('binary_sensor.motion_sensor_158d0001d5403a').state),
	 ('light.livingroom', hass.states.get('binary_sensor.motion_sensor_158d0001e5eae8').state),
	 ('light.landing', hass.states.get('binary_sensor.motion_sensor_158d0001d694b2').state),
	 ('light.kitchen', hass.states.get('binary_sensor.motion_sensor_158d0001a90d90').state),
	 ('light.cupboard', hass.states.get('binary_sensor.motion_sensor_158d0001a90d90').state),
	 ('light.bedroom_light', hass.states.get('binary_sensor.motion_sensor_158d0001e7a5a7').state),
	 ('light.childone_light', hass.states.get('binary_sensor.motion_sensor_158d0001b19555').state),
	 ('light.childtwo_light', hass.states.get('binary_sensor.motion_sensor_158d0001e19504').state),
	 ('light.porch_light', hass.states.get('binary_sensor.motion_sensor_158d0001d90b5d').state),
	 ('light.livingroom', hass.states.get('binary_sensor.motion_sensor_158d0001e5eae8').state),
)

for lightv, onoffv in entities:
    if onoffv == 'off':
      	 hass.services.call('light', 'turn_off', {'entity_id': '{}'.format(lightv)})

You may have noticed earlier in the thread I had two sensors for kitchen, I’ll be creating a template binary sensory to replace motion_sensor_158d0001a90d90 with.

Thanks to @pnbruckner for his help.

Glad to help, and sorry for the mistake in my original suggestion. (I’m going to go back and edit it so people who come across this topic later don’t get misled by it if they don’t read the rest of the posts.)

FWIW, the way you have it now is a bit inefficient. It’s calling the service for every light that needs to be turned off. It’s much more efficient to do that with a list of light entities, like in my original suggestion – which would have worked if .state had been appended to each of the get() calls (as you discovered.) Actually you can still do that with your implementation, by changing the last part to:

entity_ids = []
for lightv, onoffv in entities:
    if onoffv == 'off':
        entity_ids.append(lightv)
hass.services.call('light', 'turn_off', {'entity_id': entity_ids})

I’m 99.44% sure this will work. :slight_smile:

EDIT: Well, after I fixed a typo!!

wouldn’t it be much easier to create templates and service_templates if you’d named your binary_sensors differently;

binary_sensor.motion_sensor_hallway
binary_sensor.motion_sensor_livingroom
etc
etc

would be easier to debug too… :wink:

you then could filter out the last part of the binary into a variable
{% set s = ‘binary_sensor.motion_sensor_livingroom’.split(’.’)[-1].split(’_’)[-1] %}

and use that in the service_template and entity_id template?
Or wouldn’t that help is this case.

I’m still learning but thank you I’ll update it.

lol! I just noticed there’s a typo!! I’ll fix it…