Created
September 18, 2022 22:45
-
-
Save haberda/8bc0296459fb5a434c1a6284aa938216 to your computer and use it in GitHub Desktop.
Appdaemon app to turn on lights when motion is detected
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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