Hi everyone,
I’ve created an app to control my lights based on motion detectors. Everything is working as intended except the timer restart does not work.
my motion_lights.py file:
import appdaemon.plugins.hass.hassapi as hass
######################################################################################
# App to turn on light when motion is detected, then turn off after a delay
# If one of the no_action_devices is on (PC, armed alarm system, AV Receiver, etc)
# a trigger of the motion sensor has no effect
# args:
#
# sensor: motion sensor to use as trigger
# light_entities: light to turn on/off, multiple lights separated by comma
# lux_sensor: when the lux of this sensor is above lux_threshold then light is not turned on
# lux_threshold: value above which light will not be turned on, default 100 lux
# timer_sec: time in seconds until light turns off when there's no motion, default 30 seconds
# no_action_entities: devices which will lead to no action on motion if they are on/armed
# day_state_entity: name of the input_select which shows time of day
# brightness_level: brightness level in % for different periods of day, default 75%
# Morgen Wochentag: 30
# Tag Wochentag: 70
# Nacht Wochentag:
# Morgen Wochenende:
# Tag Wochenende:
# Nacht Wochenende:
# light_color: color of light for different periods of day, e.g. orange, default white
# Morgen Wochentag: orange
# Tag Wochentag: white
# Nacht Wochentag:
# Morgen Wochenende:
# Tag Wochenende:
# Nacht Wochenende:
######################################################################################
class MotionLights(hass.Hass):
def initialize(self):
self.handle = None
if "brightness_level" in self.args:
self.brightness_map = self.args["brightness_level"]
if "light_color" in self.args:
self.color_map = self.args["light_color"]
if "timer_sec" in self.args:
self.delay = self.args["timer_sec"]
else:
self.delay = 30 # default delay
if "sensor" in self.args:
self.listen_state(self.motion, self.args["sensor"])
else:
self.log("No motion sensor specified, doing nothing!")
def motion(self, entity, attribute, old, new, kwargs):
if new == "on":
self.log("Bewegung erkannt")
if self.get_no_action_state() == False:
if self.get_light_status() == True:
self.log("Licht ist bereits an, Timer neustarten")
self.cancel_timer(self.handle)
self.handle = self.run_in(self.light_off, self.delay)
elif self.get_lux_status() == True:
self.log("Lichtstärke ist genug hoch, keine Aktion")
else:
self.turn_light_on()
def turn_light_on(self):
if "light_entities" in self.args:
entities = self.args["light_entities"].split(",")
for entity in entities:
self.turn_on(entity, brightness = self.get_brightness(), color_name = self.get_light_color())
self.handle = self.run_in(self.light_off, self.delay)
self.log("{} wurden eingeschaltet".format(self.args["light_entities"]))
def get_no_action_state(self):
no_action_state = False
if "no_action_entities" in self.args:
entities = self.args["no_action_entities"].split(",")
for entity in entities:
if self.get_state(entity) == "armed":
self.log("Einbrecher, keine Aktion um Alarmsystem nicht zu stören")
no_action_state = True
elif self.get_state(entity) == "on" or self.get_state(entity) == "home":
self.log("{} ist eingeschaltet, keine Aktion".format(entity))
no_action_state = True
return no_action_state
def get_light_status(self):
light_on = False
if "light_entities" in self.args:
entities = self.args["light_entities"].split(",")
for entity in entities:
if self.get_state(entity) == "on":
light_on = True
return light_on
def get_lux_status(self):
lux_above_threshold = False
if "lux_threshold" in self.args:
lux_threshold = self.args["lux_threshold"]
else:
lux_threshold = 100
if "lux_sensor" in self.args:
if float(self.get_state(self.args["lux_sensor"])) > float(lux_threshold):
lux_above_threshold = True
return lux_above_threshold
def get_brightness(self):
brightness_level = 75
state_of_day = self.get_state(self.args["day_state_entity"])
if "brightness_level" in self.args:
brightness_level = self.brightness_map[state_of_day]
brightness_level = self.pcnt_to_brightness(brightness_level)
return brightness_level
def pcnt_to_brightness(self, brightness_pcnt):
return 255 / 100 * int(brightness_pcnt)
def get_light_color(self):
light_color = "white"
state_of_day = self.get_state(self.args["day_state_entity"])
if "light_color" in self.args:
light_color = self.color_map[state_of_day]
return light_color
def light_off(self, kwargs):
if "light_entities" in self.args:
entities = self.args["light_entities"].split(",")
for entity in entities:
self.turn_off(entity)
self.log("{} wurden durch Timer ausgeschaltet".format(self.args["light_entities"]))
The delay for the timer is set to 900 seconds (15 min) in the configuration file.
Below is a log from when the problem occured.
2018-08-08 06:46:03.155651 INFO Ankleidezimmer Bewegung: Bewegung erkannt
2018-08-08 06:46:03.921477 INFO Ankleidezimmer Bewegung: light.ankleidezimmer wurden eingeschaltet
2018-08-08 07:01:46.546190 INFO Ankleidezimmer Bewegung: Bewegung erkannt
2018-08-08 07:01:46.546790 INFO Ankleidezimmer Bewegung: Licht ist bereits an, Timer neustarten
2018-08-08 07:02:00.379015 INFO Ankleidezimmer Bewegung: light.ankleidezimmer wurden durch Timer ausgeschaltet
As you can see the light was turned on by motion at 06:46. At 07:01 the app recognized that the light is already on so it should restart the timer, however a few seconds later at 07:02 (15 min after initial trigger) the light turns off but it should not because the timer should have been reset.
I have no clue what I’m doing wrong. Your help would be highly appreciated!