Skip to content

Instantly share code, notes, and snippets.

@haberda
Created September 18, 2022 22:45
Show Gist options
  • Save haberda/8bc0296459fb5a434c1a6284aa938216 to your computer and use it in GitHub Desktop.
Save haberda/8bc0296459fb5a434c1a6284aa938216 to your computer and use it in GitHub Desktop.
Appdaemon app to turn on lights when motion is detected
import hassapi as hass
#
# App to turn lights on when motion detected then off again after a delay
#
# Use with constraints to activate only for the hours of darkness
#
# Args:
#
# sensor: binary sensor to use as trigger
# entity_on : entity to turn on when detecting motion, can be a light, script, scene or anything else that can be turned on
# entity_off : entity to turn off when detecting motion, can be a light, script or anything else that can be turned off. Can also be a scene which will be turned on
# delay: amount of time after turning on to turn off again. If not specified defaults to 60 seconds.
#
# Release Notes
#
# Version 2.0:
# Added ability for multiple lights, multiple sensors, light service data, and contraint options
#
# Version 1.1:
# Add ability for other apps to cancel the timer
#
# Version 1.0:
# Initial Version
class motion_lights(hass.Hass):
def initialize(self):
self.sensor = self.args.get('sensor',None)
self.lights = self.args.get('entity_id', [])
self.on_time = self.args.get('on_time', 'sunset')
self.off_time = self.args.get('off_time', 'sunrise')
self.constraint = self.args.get('constraint', [])
self.service_data = self.args.get('data', {"entity_id": None})
self.service_data['entity_id'] = self.lights
self.off_service_data = self.args.get('off_data', {"entity_id": None})
self.off_service_data['entity_id'] = self.lights
self.handle = None
if isinstance(self.sensor, str):
self.sensor = self.sensor.split(',')
# Check some Params
# Subscribe to sensors/lights and off time
if self.sensor is not None and self.lights is not None:
for sensor in self.sensor:
self.listen_state(self.motion, sensor)
for light in self.lights:
self.listen_state(self.light_off_cancel_timer, light)
self.run_daily (self.light_off,self.parse_time(self.off_time))
else:
self.log("No sensor specified, doing nothing")
return
def motion(self, entity, attribute, old, new, kwargs):
check = self.constraint_check()
if new == 'on' and self.now_is_between(self.on_time,self.off_time) and not check:
self.call_service("light/turn_on", **self.service_data)
self.cancel_timer(self.handle)
elif new == 'off' and self.now_is_between(self.on_time,self.off_time) and not check:
self.cancel_timer(self.handle)
sensor_on = False
for sensor in self.sensor:
if self.get_state(sensor) == 'on':
sensor_on = True
if not sensor_on:
self.handle = self.run_in(self.light_off, int(self.args.get('delay',60)))
def light_off_cancel_timer(self, entity, attribute, old, new, kwargs):
if new == 'off':
light_on = False
for light in self.lights:
if self.get_state(light) == 'on':
light_on = True
if not light_on:
self.cancel_timer(self.handle)
def light_off(self, kwargs):
check = self.constraint_check()
if not check:
self.call_service("light/turn_off", **self.off_service_data)
def constraint_check (self):
value = False
if self.constraint is not None:
condition_states = ['on', 'Home', 'home', 'True', 'true']
for entity in self.constraint:
if len(entity.split(',')) > 1:
if entity.split(',')[1] == self.get_state(entity.split(',')[0]):
value = True
elif self.get_state(entity) in condition_states:
value = True
return value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment