Skip to content

Instantly share code, notes, and snippets.

@crhan
Last active September 19, 2018 14:40
Show Gist options
  • Save crhan/a75c289d6dab373f3204cc51a9fa5c75 to your computer and use it in GitHub Desktop.
Save crhan/a75c289d6dab373f3204cc51a9fa5c75 to your computer and use it in GitHub Desktop.
MotionLights for HomeAssistant

支持的功能:

  1. 支持光照度条件, 环境光足够亮就不开灯, 例如阳台灯
  2. 支持多个 sensor 共同触发, 例如卫生间可以放两个人体传感器, 玄关可以放一个门窗传感器+人体传感器
  3. 支持只关不开(厕所排气扇场景)或者只开不关(不知道为啥要这样, 你想到了告诉我)
  4. 支持延时关闭, 根据自身情况设定, 规避人体传感器不灵敏的问题

这个功能不适合经常有人呆着的地方, 比如书房, 卧室, 客厅.

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment