支持的功能:
- 支持光照度条件, 环境光足够亮就不开灯, 例如阳台灯
- 支持多个 sensor 共同触发, 例如卫生间可以放两个人体传感器, 玄关可以放一个门窗传感器+人体传感器
- 支持只关不开(厕所排气扇场景)或者只开不关(不知道为啥要这样, 你想到了告诉我)
- 支持延时关闭, 根据自身情况设定, 规避人体传感器不灵敏的问题
这个功能不适合经常有人呆着的地方, 比如书房, 卧室, 客厅.
hallway_motion_lights: | |
module: motion_lights | |
class: MotionLights | |
sensor_list: | |
- binary_sensor.door_window_sensor_158d0001191793 | |
- binary_sensor.motion_sensor_158d0001296340 | |
entity_on: group.hallway_lights | |
entity_off: group.hallway_lights | |
delay: 5 | |
inside_restroom_motion_lights: | |
module: motion_lights | |
class: MotionLights | |
sensor_list: | |
- binary_sensor.motion_sensor_158d0002231dad | |
- binary_sensor.motion_sensor_158d000224f8df | |
entity_on: switch.wall_switch_ln_left_158d00022a8a9d | |
entity_off: switch.wall_switch_ln_left_158d00022a8a9d | |
illumination_sensor: sensor.illumination_158d000224f8df | |
illumination_throttle: 300 | |
delay: 300 | |
outside_restroom_motion_lights: | |
module: motion_lights | |
class: MotionLights | |
sensor_list: | |
- binary_sensor.motion_sensor_158d000211a0c9 | |
entity_on: switch.wall_switch_ln_right_158d00022a83d4 | |
entity_off: switch.wall_switch_ln_right_158d00022a83d4 | |
delay: 180 | |
inside_restroom_fan: | |
module: motion_lights | |
class: MotionLights | |
delay: 120 | |
sensor_list: | |
- binary_sensor.motion_sensor_158d0002231dad | |
- binary_sensor.motion_sensor_158d000224f8df | |
entity_off: switch.wall_switch_ln_right_158d00022a8a9d | |
outside_restroom_fan: | |
module: motion_lights | |
class: MotionLights | |
delay: 120 | |
sensor_list: | |
- binary_sensor.motion_sensor_158d000211a0c9 | |
entity_off: switch.wall_switch_ln_left_158d00022a83d4 |
import appdaemon.plugins.hass.hassapi as hass | |
# | |
# App to turn lights on when motion detected then off again after a delay | |
# | |
# Use with constrints to activate only for the hours of darkness | |
# | |
# Args: | |
# | |
# sensor_list: binary_sensors to listen on, each sensor turn "on" will action on the switch | |
# entity_on : entity to turn on when any sensor of sensor_list turned on, can be a light, script, scene or anything else that can be turned on | |
# entity_off : entity to turn off when all sensor of sensor_list turned off , can be a light, script, scene or anything else that can be turned off | |
# delay: amount of time after turning on to turn off again. If not specified defaults to 60 seconds. | |
# illumination_sensor: illumination sensor to depends on | |
# illumination_throttle: turn on switch if illumination_sensor state is below this config value, default is 500 | |
# | |
# Release Notes | |
# | |
# Version 1.1: | |
# Add ability for other apps to cancel the timer | |
# | |
# Version 1.0: | |
# Initial Version | |
class MotionLights(hass.Hass): | |
def initialize(self): | |
self.handle = None | |
# Subscribe to sensors | |
for _sensor in self.args['sensor_list']: | |
self.listen_state(self.state_cb_sensor, _sensor) | |
if self.entity_off: | |
self.listen_state(self.state_cb_count_down_when_on, | |
self.entity_off) | |
self._start_turn_off_timer() | |
def state_cb_sensor(self, entity, attribute, old, new, kwargs): | |
if new == 'on': | |
if not self.can_turn_entity_on: | |
return | |
self.log("turn on entity %s because of sensor %s state %s" % | |
(self.entity_on, entity, new)) | |
self.turn_on(self.entity_on) | |
self._start_turn_off_timer() | |
if new == "off": | |
if not self.can_turn_entity_off: | |
return | |
self.log("%s turn %s" % (entity, new)) | |
self._start_turn_off_timer() | |
@property | |
def illumination_switch(self): | |
"""光照条件开关 | |
配置 illumination_sensor 后启用 | |
光照临界值 illumination_throttle 默认 500 | |
Returns: | |
Boolean -- True 时可以开灯 | |
""" | |
if self.illumination_sensor_state is None: | |
return True | |
self.log("illumination state %s, throttle %s" % | |
(self.illumination_sensor_state, self.illumination_throttle)) | |
return self.illumination_sensor_state < self.illumination_throttle | |
@property | |
def illumination_throttle(self): | |
"""光照阈值, 超过时不满足开灯条件.""" | |
return float(self.args.get('illumination_throttle', 500)) | |
@property | |
def illumination_sensor_state(self): | |
if 'illumination_sensor' in self.args: | |
illum_state = self.get_state(self.args['illumination_sensor']) | |
try: | |
return float(illum_state) | |
except ValueError: | |
return 0 | |
return None | |
@property | |
def delay(self): | |
if "delay" in self.args: | |
return self.args['delay'] | |
elif "delay_entity" in self.args: | |
return int(self.get_state(self.args["delay_entity"])) | |
return 30 | |
def state_cb_count_down_when_on(self, entity, attribute, old, new, kwargs): | |
if new == "on": | |
self.log("%s turn %s, start timer" % (entity, new)) | |
self._start_turn_off_timer() | |
def _start_turn_off_timer(self): | |
if not self.entity_off: | |
return | |
self.log("start count down %s seconds to turn off %s" % | |
(self.delay, self.entity_off)) | |
self.cancel() | |
self.handle = self.run_in(self._turn_off_entity, self.delay) | |
self.log("start timer %s" % self.handle) | |
def _turn_off_entity(self, kwargs): | |
if self.can_turn_entity_off: | |
self.log("Turning {} off".format(self.entity_off)) | |
self.turn_off(self.entity_off) | |
def _turn_on_entity(self): | |
if not self.entity_on: | |
return | |
if self.can_turn_entity_on: | |
self.turn_on(self.entity_on) | |
def cancel(self): | |
if self.handle is not None: | |
self.log("cancel timer %s" % self.handle) | |
self.cancel_timer(self.handle) | |
self.handle = None | |
@property | |
def entity_off(self): | |
return self.args.get("entity_off") | |
@property | |
def entity_on(self): | |
return self.args.get("entity_on") | |
@property | |
def can_turn_entity_off(self): | |
if not self.entity_off: | |
return False | |
if self.get_state(self.entity_off) == "off": | |
return False | |
all_sensor_is_off = all([ | |
self.get_state(entity_id) == "off" | |
for entity_id in self.args['sensor_list'] | |
]) | |
return all_sensor_is_off | |
@property | |
def can_turn_entity_on(self): | |
if not self.entity_on: | |
return False | |
if self.get_state(self.entity_on) == "on": | |
return False | |
return self.illumination_switch | |