updating configuration
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
import datetime
|
||||
|
||||
class ChildDoorNotifier(hass.Hass):
|
||||
isLocked = False
|
||||
|
||||
def initialize(self):
|
||||
if not globals.check_args(self,['entities', 'sensor']):
|
||||
return
|
||||
|
||||
self.listen_event_handle_list = []
|
||||
self.listen_event_handle_list.append(self.listen_state(self.state_change, self.args['sensor'])) #, attribute='action'
|
||||
|
||||
def state_change(self, entity, attribute, old, new, kwargs):
|
||||
self.log('state = {}'.format(new))
|
||||
if new == "on":
|
||||
self.log('open')
|
||||
for i in range(1, 7):
|
||||
self.run_in(self.switch_light, i)
|
||||
|
||||
def switch_light(self, kwargs):
|
||||
for entity in self.args['entities']:
|
||||
self.toggle(entity)
|
||||
@@ -0,0 +1,14 @@
|
||||
#################################
|
||||
# Door Notifier #
|
||||
#################################
|
||||
child_door_notifier:
|
||||
module: child_door_notifier
|
||||
class: ChildDoorNotifier
|
||||
sensor: binary_sensor.door_childroom_contact
|
||||
entities:
|
||||
- light.svetlana_bedside_lamp_rgbww_light
|
||||
- light.danil_bedside_lamp_rgbww_light
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import datetime
|
||||
|
||||
#
|
||||
# App to control balcony room light based on lux and door sensor
|
||||
#
|
||||
# Args:
|
||||
# door_sensor: door contact sensor
|
||||
# lux_sensor: xiaomi lux sensor
|
||||
# light: light entity_id
|
||||
# lux_min: min lux value to turn light on
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class BalconyLightControl(hass.Hass):
|
||||
def initialize(self):
|
||||
self.door_sensor = self.args.get("door_sensor", "binary_sensor.door_balcony_contact")
|
||||
self.light = self.args.get("light", "light.light_balcony_spotlight")
|
||||
self.lux_sensor = self.args.get("lux_sensor", "sensor.brightness_balcony_illuminance")
|
||||
self.lux_min = self.args.get("lux_min", 100)
|
||||
|
||||
self.log("Initializing balcony light control application")
|
||||
self.log(f"Door sensor: {self.door_sensor}")
|
||||
self.log(f"Lux sensor: {self.lux_sensor}")
|
||||
self.log(f"Lux min: {self.lux_min}")
|
||||
self.log(f"Light: {self.light}")
|
||||
|
||||
# Listen for presence events
|
||||
self.listen_state(self.state_change, self.args['door_sensor'])
|
||||
self.log("Presence event handler registered")
|
||||
|
||||
def state_change(self, entity, attribute, old, new, kwargs):
|
||||
self.log(f"door entity: {entity}, attribute: {attribute}, old: {old}, new: {new}")
|
||||
lux = int(self.get_state(self.lux_sensor))
|
||||
if new == "on":
|
||||
self.log("Door is open, lux: {}, lux_min: {}".format(lux, self.lux_min))
|
||||
if lux < self.lux_min:
|
||||
self.turn_on(self.light)
|
||||
else:
|
||||
self.log("high lux value, skip turn light on")
|
||||
elif new == "off":
|
||||
self.log("Door is closed, lux: {}, lux_min: {}".format(lux, self.lux_min))
|
||||
self.turn_off(self.light)
|
||||
@@ -0,0 +1,7 @@
|
||||
light_balcony:
|
||||
module: light_balcony
|
||||
class: BalconyLightControl
|
||||
light: light.light_balcony_spotlight
|
||||
door_sensor: binary_sensor.door_balcony_contact
|
||||
lux_sensor: sensor.brightness_balcony_illuminance
|
||||
lux_min: 150
|
||||
@@ -0,0 +1,36 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import datetime
|
||||
|
||||
#
|
||||
# App to control main room light based on Aqara FP1 presence sensor
|
||||
#
|
||||
# Args:
|
||||
# presence_sensor: presence sensor entity_id (default: sensor.presence_aqara_mainroom_presence_event)
|
||||
# light: light entity_id (default: light.light_mainroom_pc_spotlight)
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class MainRoomLightControl(hass.Hass):
|
||||
def initialize(self):
|
||||
self.presence_sensor = self.args.get("presence_sensor", "sensor.presence_aqara_mainroom_presence_event")
|
||||
self.light = self.args.get("light", "light.light_mainroom_pc_spotlight")
|
||||
|
||||
self.log("Initializing light control application")
|
||||
self.log(f"Presence sensor: {self.presence_sensor}")
|
||||
self.log(f"Light: {self.light}")
|
||||
|
||||
# Listen for presence events
|
||||
self.listen_state(self.state_change, self.args['presence_sensor'])
|
||||
self.log("Presence event handler registered")
|
||||
|
||||
def state_change(self, entity, attribute, old, new, kwargs):
|
||||
self.log(f"entity: {entity}, attribute: {attribute}, old: {old}, new: {new}")
|
||||
if new == "away":
|
||||
self.log("Status 'away' - turning off light")
|
||||
self.turn_off(self.light)
|
||||
else:
|
||||
self.log("Presence detected - turning on light")
|
||||
self.turn_on(self.light)
|
||||
@@ -0,0 +1,5 @@
|
||||
light_mainroom:
|
||||
module: light_mainroom
|
||||
class: MainRoomLightControl
|
||||
presence_sensor: sensor.presence_aqara_mainroom_presence_event11
|
||||
light: light.light_mainroom_pc_spotlight
|
||||
@@ -0,0 +1,29 @@
|
||||
#################################
|
||||
# LIGHT BUTTONS #
|
||||
#################################
|
||||
# light_button_bath:
|
||||
# module: lightbutton
|
||||
# class: LightButton
|
||||
# sensor: binary_sensor.wall_switch_bath
|
||||
# entities: light.bath
|
||||
# # control_input: input_boolean.bath_light_control
|
||||
# global_dependencies:
|
||||
# - globals
|
||||
|
||||
light_button_main:
|
||||
module: lightbutton
|
||||
class: LightButton
|
||||
sensor: sensor.bed_button
|
||||
entities: light.yeelight_color1_34ce008fe328,light.yeelight_color1_286c071065c7,light.yeelight_mono1_34ce0087ff33,light.yeelight_mono1_f0b4290e5444,light.yeelight_mono1_f0b429a8f6df,light.yeelight_mono1_286c07f12bed,light.yeelight_mono1_f0b429a8d936,light.lamp1
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
light_button_hall:
|
||||
module: lightbutton
|
||||
class: LightButton
|
||||
sensor: sensor.0x00158d000183a5fe_action
|
||||
entities: switch.plug_light_hall
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
import datetime
|
||||
|
||||
class LightButton(hass.Hass):
|
||||
isLocked = False
|
||||
|
||||
def initialize(self):
|
||||
if not globals.check_args(self,['entities', 'sensor']):
|
||||
return
|
||||
|
||||
self.listen_event_handle_list = []
|
||||
self.listen_event_handle_list.append(self.listen_event(self.event_detected, "xiaomi_aqara.click"))
|
||||
self.listen_event_handle_list.append(self.listen_state(self.state_change, self.args['sensor'])) #, attribute='action'
|
||||
|
||||
def state_change(self, entity, attribute, old, new, kwargs):
|
||||
if new == "single":
|
||||
self.log('button_click')
|
||||
self.make_action_by_mode("off")
|
||||
if new == "double":
|
||||
self.log('button_dblclick')
|
||||
self.make_action_by_mode("on")
|
||||
|
||||
def event_detected(self, event_name, data, kwargs):
|
||||
if data["entity_id"] != self.args["sensor"] or self.isLocked:
|
||||
return
|
||||
self.isLocked = True
|
||||
if data["click_type"] == "single":
|
||||
self.log('button_click')
|
||||
self.make_action_by_mode("off")
|
||||
if data["click_type"] == "double":
|
||||
self.log('button_dblclick')
|
||||
self.make_action_by_mode("on")
|
||||
|
||||
self.run_in(self.clear_lock, 1)
|
||||
|
||||
def clear_lock(self, kwargs):
|
||||
self.isLocked = False
|
||||
|
||||
def make_action_by_mode(self, state):
|
||||
states = self.fill_states()
|
||||
control_entity = self.args.get('control_input', None)
|
||||
if (control_entity != None):
|
||||
entity_id = next(iter(states))
|
||||
state = self.get_state(entity_id)
|
||||
self.set_state(entity_id, self.invert_state(state))
|
||||
self.set_state(control_entity, state)
|
||||
return
|
||||
|
||||
if len(self.args["entities"]) > 1:
|
||||
self.toggle_next_with_state(state, states)
|
||||
|
||||
def toggle_next_with_state(self, state, states):
|
||||
for entity_id in states:
|
||||
entity_state = states[entity_id]
|
||||
if (entity_state == state):
|
||||
self.set_state(entity_id, self.invert_state(state))
|
||||
self.log('toggling {}'.format(entity_id))
|
||||
return
|
||||
|
||||
for entity_id in states:
|
||||
self.log('toggling {}'.format(entity_id))
|
||||
self.toggle(entity_id)
|
||||
|
||||
def set_state(self, entity_id, state):
|
||||
if (state == "off"):
|
||||
self.log('turn_off {}'.format(entity_id))
|
||||
self.set_off(entity_id)
|
||||
if (state == "on"):
|
||||
self.log('turn_on {}'.format(entity_id))
|
||||
self.set_on(entity_id)
|
||||
|
||||
#light
|
||||
def set_on(self, entity_id):
|
||||
brightness = 1 #night mode
|
||||
if self.time_is_between(self.datetime(), '07:00:00', '23:00:00'):
|
||||
brightness=255 #day mode
|
||||
|
||||
if entity_id.startswith("light") and 'color' in entity_id:
|
||||
self.call_service("homeassistant/turn_on", entity_id = entity_id, transition = 1, brightness = brightness, color_temp=204)
|
||||
elif entity_id.startswith("light"):
|
||||
self.call_service("homeassistant/turn_on", entity_id = entity_id, transition = 1, brightness = brightness)
|
||||
else:
|
||||
self.turn_on(entity_id)
|
||||
|
||||
def set_off(self, entity_id):
|
||||
if entity_id.startswith("light"):
|
||||
self.call_service("homeassistant/turn_off", entity_id = entity_id, transition = 1)
|
||||
else:
|
||||
self.turn_off(entity_id)
|
||||
|
||||
|
||||
def invert_state(self, state):
|
||||
if (state == "off"):
|
||||
return "on"
|
||||
return "off"
|
||||
|
||||
def fill_states(self):
|
||||
states = {}
|
||||
for entity_id in self.split_device_list(self.args["entities"]):
|
||||
state = self.get_state(entity_id)
|
||||
if (state == None):
|
||||
self.log("Warning! Device {} not found (state: {}).".format(entity_id, state))
|
||||
continue
|
||||
states[entity_id] = state
|
||||
return states
|
||||
|
||||
def terminate(self):
|
||||
if self.listen_event_handle_list != None:
|
||||
for listen_event_handle in self.listen_event_handle_list:
|
||||
self.cancel_listen_event(listen_event_handle)
|
||||
|
||||
def time_is_between(
|
||||
hass, target_dt: datetime, start_time: str,
|
||||
end_time: str) -> bool:
|
||||
"""Generalization of AppDaemon's now_is_between method."""
|
||||
start_time_dt = hass.parse_time(start_time) # type: datetime
|
||||
end_time_dt = hass.parse_time(end_time) # type: datetime
|
||||
start_dt = target_dt.replace(
|
||||
hour=start_time_dt.hour,
|
||||
minute=start_time_dt.minute,
|
||||
second=start_time_dt.second)
|
||||
end_dt = target_dt.replace(
|
||||
hour=end_time_dt.hour,
|
||||
minute=end_time_dt.minute,
|
||||
second=end_time_dt.second)
|
||||
|
||||
if end_dt < start_dt:
|
||||
# Spans midnight
|
||||
if target_dt < start_dt and target_dt < end_dt:
|
||||
target_dt = target_dt + timedelta(days=1)
|
||||
end_dt = end_dt + timedelta(days=1)
|
||||
return start_dt <= target_dt <= end_dt
|
||||
@@ -0,0 +1,25 @@
|
||||
light_control_hall:
|
||||
module: lightcontrol
|
||||
class: LightControl
|
||||
sensor: binary_sensor.motion_sensor_hall
|
||||
control_entity: switch.plug_light_hall
|
||||
control_night_entity: light.gateway
|
||||
timeout: 240
|
||||
constraint: input_boolean.hall_light_control
|
||||
ha_panel: alarm_control_panel.ha_alarm
|
||||
vacuum: vacuum.xiaomi_vacuum_cleaner
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
light_control_kitchen:
|
||||
module: lightcontrol
|
||||
class: LightControl
|
||||
sensor: group.kitchen_motion_sensors
|
||||
control_entity: switch.light_kitchen
|
||||
timeout: 600
|
||||
constraint: input_boolean.kitchen_light_control
|
||||
ha_panel: alarm_control_panel.ha_alarm
|
||||
vacuum: vacuum.xiaomi_vacuum_cleaner
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
import datetime
|
||||
|
||||
#
|
||||
# This app will use motion sensors to turn on and off control_entity for 'timeout' time.
|
||||
# It work with xiaomi motion sensors.
|
||||
# main algorithm: when sensor turns on - turn on the light; when sensor is off - set timer for 'timeout';
|
||||
# if sensor goes on - turn off the timer; when timer was hit - turn off the light.
|
||||
#
|
||||
# Args:
|
||||
#
|
||||
# sensor = motion sensor to use (will work with other sensor types too)
|
||||
# timeout = timeout after sensor will turned off (keep in mind that xiaomi motion sensor has own timeout!)
|
||||
# control_entity = entity, that will be controlled (example: group of light bulbs)
|
||||
# constraint = you can define constraint (input_boolean), that will turn on and off this app.
|
||||
# after_sundown (optionally) - whether to only trigger after sundown. example: True
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class LightControl(hass.Hass):
|
||||
timer = None
|
||||
def initialize(self):
|
||||
if not globals.check_args(self, ["sensor", "timeout", "control_entity"]):
|
||||
return
|
||||
self.listen_event_handle_list = []
|
||||
self.listen_event_handle_list.append(self.listen_state(self.sensor_trigger, self.args['sensor']))
|
||||
|
||||
def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
if 'after_sundown' in self.args and self.args['after_sundown'] and not self.sun_down():
|
||||
# self.log('Sun is up, and we will turn it only after sundown.')
|
||||
return
|
||||
|
||||
vacuum_state = "docked"
|
||||
ha_panel_state = ""
|
||||
if "vacuum" in self.args:
|
||||
vacuum_state = self.get_state(self.args["vacuum"])
|
||||
if "ha_panel" in self.args:
|
||||
ha_panel_state = self.get_state(self.args["ha_panel"])
|
||||
#Если работает пылесос и сработал датчик движения
|
||||
if ha_panel_state == "armed_away" and vacuum_state == 'cleaning':
|
||||
self.log('Motion sensor is triggered, but vacuum is cleaning.')
|
||||
return
|
||||
|
||||
#sensor is off
|
||||
if new == 'off' and old == 'on':
|
||||
self.log('Sensor is off - running timer for {}s.'.format(self.args['timeout']))
|
||||
self.run_timer()
|
||||
#sensor is on
|
||||
if new == 'on' and old == 'off':
|
||||
#turnin on control entity and wait while sensor will be off, than run timer.
|
||||
self.control_entity_on()
|
||||
self.stop_timer()
|
||||
|
||||
|
||||
def terminate(self):
|
||||
if self.listen_event_handle_list != None:
|
||||
for listen_event_handle in self.listen_event_handle_list:
|
||||
self.cancel_listen_event(listen_event_handle)
|
||||
|
||||
############ TIMER ########################
|
||||
def run_timer(self):
|
||||
if self.timer != None:
|
||||
self.stop_timer()
|
||||
self.timer = self.run_in(self.control_entity_off, self.args['timeout'])
|
||||
|
||||
def control_entity_on(self):
|
||||
#if 'constraint' is off - we dont need to do anything
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
entity = self.args['control_entity']
|
||||
if not self.time_is_between(self.datetime(), '07:00:00', '23:00:00') and 'control_night_entity' in self.args:
|
||||
entity=self.args['control_night_entity'] #day mode
|
||||
|
||||
if self.get_state(entity) == 'off':
|
||||
self.turn_on(entity)
|
||||
self.log("Light on ({}).".format(entity))
|
||||
|
||||
def control_entity_off(self, kwargs):
|
||||
#if 'constraint' is off - we dont need to do anything
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
entity = self.args['control_entity']
|
||||
if not self.time_is_between(self.datetime(), '07:00:00', '23:00:00') and 'control_night_entity' in self.args:
|
||||
entity=self.args['control_night_entity'] #day mode
|
||||
|
||||
if self.get_state(entity) == 'on':
|
||||
self.turn_off(entity)
|
||||
self.log("Light off.")
|
||||
self.stop_timer()
|
||||
|
||||
def stop_timer(self):
|
||||
if (self.timer == None):
|
||||
return
|
||||
self.log('stopping timer.')
|
||||
self.cancel_timer(self.timer)
|
||||
self.timer = None
|
||||
|
||||
def time_is_between(
|
||||
hass, target_dt: datetime, start_time: str,
|
||||
end_time: str) -> bool:
|
||||
"""Generalization of AppDaemon's now_is_between method."""
|
||||
start_time_dt = hass.parse_time(start_time) # type: datetime
|
||||
end_time_dt = hass.parse_time(end_time) # type: datetime
|
||||
start_dt = target_dt.replace(
|
||||
hour=start_time_dt.hour,
|
||||
minute=start_time_dt.minute,
|
||||
second=start_time_dt.second)
|
||||
end_dt = target_dt.replace(
|
||||
hour=end_time_dt.hour,
|
||||
minute=end_time_dt.minute,
|
||||
second=end_time_dt.second)
|
||||
|
||||
if end_dt < start_dt:
|
||||
# Spans midnight
|
||||
if target_dt < start_dt and target_dt < end_dt:
|
||||
target_dt = target_dt + timedelta(days=1)
|
||||
end_dt = end_dt + timedelta(days=1)
|
||||
return start_dt <= target_dt <= end_dt
|
||||
@@ -0,0 +1,136 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
import datetime
|
||||
import time
|
||||
|
||||
#
|
||||
# This app will use motion sensors to turn on and off control_entity for 'timeout' time.
|
||||
# It work with xiaomi motion sensors.
|
||||
# main algorithm: when sensor turns on - turn on the light; when sensor is off - set timer for 'timeout';
|
||||
# if sensor goes on - turn off the timer; when timer was hit - turn off the light.
|
||||
#
|
||||
# Args:
|
||||
#
|
||||
# sensor = motion sensor to use (will work with other sensor types too)
|
||||
# timeout = timeout after sensor will turned off (keep in mind that xiaomi motion sensor has own timeout!)
|
||||
# control_entity = entity, that will be controlled (example: group of light bulbs)
|
||||
# constraint = you can define constraint (input_boolean), that will turn on and off this app.
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class LightControlBath(hass.Hass):
|
||||
timer = None
|
||||
door_state_changed = None
|
||||
def initialize(self):
|
||||
if "sensor" not in self.args or 'door_sensor' not in self.args or "timeout" not in self.args or "control_entity" not in self.args:
|
||||
self.error("Please provide sensor, door_sensor, control_entity and timeout in config!")
|
||||
return
|
||||
self.listen_state(self.sensor_trigger, self.args['sensor'])
|
||||
self.listen_state(self.door_sensor_trigger, self.args['door_sensor'])
|
||||
|
||||
def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||
#sensor is off
|
||||
if new == 'off' and old == 'on':
|
||||
self.log('door_state_changed:{}'.format(self.door_state_changed))
|
||||
if self.door_state_changed == False:
|
||||
return
|
||||
self.log('Sensor is off - running timer for {}s.'.format(self.args['timeout']))
|
||||
self.run_timer()
|
||||
#sensor is on
|
||||
|
||||
if new == 'on' and old == 'off':
|
||||
#turnin on control entity and wait while sensor will be off, than run timer.
|
||||
self.control_entity_on()
|
||||
self.stop_timer()
|
||||
door_state = self.get_state(self.args['door_sensor'])
|
||||
if door_state == "off":
|
||||
self.door_state_changed = False
|
||||
else :
|
||||
self.door_state_changed = None
|
||||
|
||||
|
||||
def door_sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||
#door is open
|
||||
sensor_state = self.get_state(self.args['sensor'])
|
||||
if new == 'on' and old == 'off' and sensor_state == 'off':
|
||||
self.log('door is opened now, runnig the timer')
|
||||
if self.timer == None:
|
||||
self.run_timer()
|
||||
if self.door_state_changed == False:
|
||||
self.door_state_changed = True
|
||||
self.log('door_state_changed:{}'.format(self.door_state_changed))
|
||||
|
||||
############ TIMER ########################
|
||||
def control_entity_on(self):
|
||||
#if 'constraint' is off - we dont need to do anything
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
entity = self.args['control_entity']
|
||||
if not self.time_is_between(self.datetime(), '07:00:00', '23:00:00') and 'control_night_entity' in self.args:
|
||||
entity=self.args['control_night_entity'] #day mode
|
||||
|
||||
if self.get_state(entity) == 'off':
|
||||
self.turn_on(entity)
|
||||
self.log("Light on.")
|
||||
if 'control_mini_light_entity' in self.args:
|
||||
self.turn_on(self.args['control_mini_light_entity'])
|
||||
|
||||
def control_entity_off(self, kwargs):
|
||||
#if 'constraint' is off - we dont need to do anything
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
if self.door_state_changed == False:
|
||||
self.log('Motion is detected inside and door is still closed - dont turn off the light')
|
||||
return
|
||||
|
||||
is_night = False
|
||||
entity = self.args['control_entity']
|
||||
if not self.time_is_between(self.datetime(), '07:00:00', '23:00:00') and 'control_night_entity' in self.args:
|
||||
entity=self.args['control_night_entity'] #day mode
|
||||
is_night = True
|
||||
|
||||
if self.get_state(entity) == 'on':
|
||||
self.turn_off(entity)
|
||||
self.log("Light off.")
|
||||
if 'control_mini_light_entity' in self.args:
|
||||
self.turn_off(self.args['control_mini_light_entity'])
|
||||
if not is_night and 'control_night_entity' in self.args:
|
||||
self.turn_off(self.args['control_night_entity'])
|
||||
self.stop_timer()
|
||||
|
||||
def run_timer(self):
|
||||
if self.timer != None:
|
||||
self.stop_timer()
|
||||
self.timer = self.run_in(self.control_entity_off, self.args['timeout'])
|
||||
|
||||
def stop_timer(self):
|
||||
if (self.timer == None):
|
||||
return
|
||||
self.log('stopping timer.')
|
||||
self.cancel_timer(self.timer)
|
||||
self.timer = None
|
||||
|
||||
def time_is_between(
|
||||
hass, target_dt: datetime, start_time: str,
|
||||
end_time: str) -> bool:
|
||||
"""Generalization of AppDaemon's now_is_between method."""
|
||||
start_time_dt = hass.parse_time(start_time) # type: datetime
|
||||
end_time_dt = hass.parse_time(end_time) # type: datetime
|
||||
start_dt = target_dt.replace(
|
||||
hour=start_time_dt.hour,
|
||||
minute=start_time_dt.minute,
|
||||
second=start_time_dt.second)
|
||||
end_dt = target_dt.replace(
|
||||
hour=end_time_dt.hour,
|
||||
minute=end_time_dt.minute,
|
||||
second=end_time_dt.second)
|
||||
|
||||
if end_dt < start_dt:
|
||||
# Spans midnight
|
||||
if target_dt < start_dt and target_dt < end_dt:
|
||||
target_dt = target_dt + timedelta(days=1)
|
||||
end_dt = end_dt + timedelta(days=1)
|
||||
return start_dt <= target_dt <= end_dt
|
||||
@@ -0,0 +1,39 @@
|
||||
#################################
|
||||
# LIGHT CONTROL #
|
||||
#################################
|
||||
light_control_bath:
|
||||
module: lightcontrol_bath
|
||||
class: LightControlBath
|
||||
sensor: binary_sensor.motion_bath
|
||||
door_sensor: binary_sensor.door_bath_contact
|
||||
control_entity: switch.light_bath
|
||||
control_night_entity: switch.light_bath_mirror
|
||||
control_mini_light_entity: light.light_bath_shelf
|
||||
timeout: 240
|
||||
constraint: input_boolean.bath_light_control
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
light_control_shower:
|
||||
module: lightcontrol_bath
|
||||
class: LightControlBath
|
||||
sensor: binary_sensor.motion_shower_center_occupancy
|
||||
door_sensor: binary_sensor.door_shower_contact
|
||||
control_entity: switch.light_shower_main_spotlights
|
||||
control_night_entity: switch.shower_mirror
|
||||
control_mini_light_entity: light.light_shower_shelf_light
|
||||
timeout: 240
|
||||
constraint: input_boolean.shower_light_control
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
light_control_shower_shower:
|
||||
module: lightcontrol_bath
|
||||
class: LightControlBath
|
||||
sensor: binary_sensor.motion_shower_shower_occupancy
|
||||
door_sensor: binary_sensor.door_shower_contact
|
||||
control_entity: switch.light_shower_shower_spotlights
|
||||
timeout: 360
|
||||
constraint: input_boolean.shower_light_control
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,131 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
import datetime
|
||||
import time
|
||||
|
||||
#
|
||||
# This app will use motion sensors to turn on and off control_entity for 'timeout' time.
|
||||
# It work with xiaomi motion sensors.
|
||||
# main algorithm: when sensor turns on - turn on the light; when sensor is off - set timer for 'timeout';
|
||||
# if sensor goes on - turn off the timer; when timer was hit - turn off the light.
|
||||
#
|
||||
# Args:
|
||||
#
|
||||
# sensor = motion sensor to use (will work with other sensor types too)
|
||||
# timeout = timeout after sensor will turned off (keep in mind that xiaomi motion sensor has own timeout!)
|
||||
# control_entity = entity, that will be controlled (example: group of light bulbs)
|
||||
# constraint = you can define constraint (input_boolean), that will turn on and off this app.
|
||||
# after_sundown (optionally) - whether to only trigger after sundown. example: True
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class LightControlHall(hass.Hass):
|
||||
timer = None
|
||||
turn_on_by_door = None
|
||||
def initialize(self):
|
||||
if not globals.check_args(self, ["motion_sensors", "door_sensors", "timeout", "control_entity"]):
|
||||
return
|
||||
self.listen_event_handle_list = []
|
||||
for sensor in self.args['door_sensors']:
|
||||
self.listen_event_handle_list.append(self.listen_state(self.sensor_trigger, sensor))
|
||||
|
||||
for sensor in self.args['motion_sensors']:
|
||||
self.listen_event_handle_list.append(self.listen_state(self.motion_trigger, sensor))
|
||||
|
||||
for event in self.args['events']:
|
||||
self.listen_event(self.event_trigger, event)
|
||||
|
||||
|
||||
def motion_trigger(self, entity, attribute, old, new, kwargs):
|
||||
#sensor is off
|
||||
if new == 'off' and old == 'on' and self.turn_on_by_door != None:
|
||||
self.log('Sensor is off - running timer for {}s.'.format(self.args['timeout']))
|
||||
self.run_timer()
|
||||
|
||||
#sensor is on
|
||||
if new == 'on' and old == 'off':
|
||||
self.stop_timer()
|
||||
|
||||
def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
|
||||
#sensor is on
|
||||
if new == 'on' and old == 'off':
|
||||
#turnin on control entity and wait while sensor will be off, than run timer.
|
||||
self.control_entity_on()
|
||||
self.turn_on_by_door = True
|
||||
self.stop_timer()
|
||||
|
||||
def event_trigger(self, event_name, data, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
#turnin on control entity and wait while sensor will be off, than run timer.
|
||||
self.control_entity_on()
|
||||
self.turn_on_by_door = True
|
||||
self.stop_timer()
|
||||
self.run_timer()
|
||||
|
||||
def terminate(self):
|
||||
if self.listen_event_handle_list != None:
|
||||
for listen_event_handle in self.listen_event_handle_list:
|
||||
self.cancel_listen_event(listen_event_handle)
|
||||
|
||||
############ TIMER ########################
|
||||
def run_timer(self):
|
||||
if self.timer != None:
|
||||
self.stop_timer()
|
||||
self.timer = self.run_in(self.control_entity_off, self.args['timeout'])
|
||||
|
||||
def control_entity_on(self):
|
||||
#if 'constraint' is off - we dont need to do anything
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
|
||||
entity = self.args['control_entity']
|
||||
state = self.get_state(entity)
|
||||
|
||||
self.turn_on(entity)
|
||||
self.log("Light on ({}).".format(entity))
|
||||
|
||||
def control_entity_off(self, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
self.turn_on_by_door = None
|
||||
|
||||
entity = self.args['control_entity']
|
||||
state = self.get_state(entity)
|
||||
self.turn_off(entity)
|
||||
self.log("Light off.")
|
||||
self.stop_timer()
|
||||
|
||||
def stop_timer(self):
|
||||
if (self.timer == None):
|
||||
return
|
||||
self.log('stopping timer.')
|
||||
self.cancel_timer(self.timer)
|
||||
self.timer = None
|
||||
|
||||
def time_is_between(
|
||||
hass, target_dt: datetime, start_time: str,
|
||||
end_time: str) -> bool:
|
||||
"""Generalization of AppDaemon's now_is_between method."""
|
||||
start_time_dt = hass.parse_time(start_time) # type: datetime
|
||||
end_time_dt = hass.parse_time(end_time) # type: datetime
|
||||
start_dt = target_dt.replace(
|
||||
hour=start_time_dt.hour,
|
||||
minute=start_time_dt.minute,
|
||||
second=start_time_dt.second)
|
||||
end_dt = target_dt.replace(
|
||||
hour=end_time_dt.hour,
|
||||
minute=end_time_dt.minute,
|
||||
second=end_time_dt.second)
|
||||
|
||||
if end_dt < start_dt:
|
||||
# Spans midnight
|
||||
if target_dt < start_dt and target_dt < end_dt:
|
||||
target_dt = target_dt + timedelta(days=1)
|
||||
end_dt = end_dt + timedelta(days=1)
|
||||
return start_dt <= target_dt <= end_dt
|
||||
@@ -0,0 +1,18 @@
|
||||
light_control_hall:
|
||||
module: lightcontrol_hall
|
||||
class: LightControlHall
|
||||
motion_sensors:
|
||||
- binary_sensor.motion_hall_1_occupancy
|
||||
- binary_sensor.motion_hall_2_occupancy
|
||||
door_sensors:
|
||||
- binary_sensor.door_locker_hall_right_contact
|
||||
- binary_sensor.door_locker_hall_left_contact
|
||||
- binary_sensor.door_locker2_hall_left_contact
|
||||
- binary_sensor.door_locker2_hall_right_contact
|
||||
events:
|
||||
- door_opened
|
||||
control_entity: light.light_hall_long
|
||||
timeout: 120
|
||||
constraint: input_boolean.locker_light_control
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,149 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
import datetime
|
||||
import time
|
||||
|
||||
#
|
||||
# This app will use motion sensors to turn on and off control_entity for 'timeout' time.
|
||||
# It work with xiaomi motion sensors.
|
||||
# main algorithm: when sensor turns on - turn on the light; when sensor is off - set timer for 'timeout';
|
||||
# if sensor goes on - turn off the timer; when timer was hit - turn off the light.
|
||||
#
|
||||
# Args:
|
||||
#
|
||||
# sensor = motion sensor to use (will work with other sensor types too)
|
||||
# timeout = timeout after sensor will turned off (keep in mind that xiaomi motion sensor has own timeout!)
|
||||
# control_entity = entity, that will be controlled (example: group of light bulbs)
|
||||
# constraint = you can define constraint (input_boolean), that will turn on and off this app.
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class LightControlKitchenset(hass.Hass):
|
||||
timer = None
|
||||
def initialize(self):
|
||||
if "sensors" not in self.args or "timeout" not in self.args or "control_entity" not in self.args:
|
||||
self.error("Please provide sensor, control_entity and timeout in config!")
|
||||
return
|
||||
for sensor in self.args['sensors']:
|
||||
self.listen_state(self.sensor_trigger, sensor)
|
||||
if 'night_sensors' in self.args:
|
||||
for sensor in self.args['night_sensors']:
|
||||
self.listen_state(self.sensor_night_trigger, sensor)
|
||||
|
||||
def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||
#sensor is on
|
||||
if new == 'on' and old == 'off':
|
||||
#turnin on control entity and wait while sensor will be off, than run timer.
|
||||
self.log('motion detected: {}'.format(entity))
|
||||
self.control_entity_on()
|
||||
self.stop_timer()
|
||||
|
||||
#sensor is off
|
||||
if new == 'off' and old == 'on':
|
||||
self.log('motion stop detected:{}'.format(entity))
|
||||
state = self.get_motion_state()
|
||||
if state == 'off':
|
||||
self.run_timer()
|
||||
|
||||
def sensor_night_trigger(self, entity, attribute, old, new, kwargs):
|
||||
door_state = 'on'
|
||||
if 'door_sensors' in self.args:
|
||||
for door in self.args['door_sensors']:
|
||||
door_state = self.get_state(door)
|
||||
self.log('door_state: {}'.format(door_state))
|
||||
if door_state == 'off':
|
||||
door_state = 'off'
|
||||
|
||||
if new == 'on' and old == 'off' and door_state == 'on':
|
||||
if self.is_night():
|
||||
self.log('night motion detected: {}'.format(entity))
|
||||
self.control_entity_on()
|
||||
self.stop_timer()
|
||||
|
||||
if new == 'off' and old == 'on':
|
||||
self.log('night motion stop detected:{}'.format(entity))
|
||||
state = self.get_motion_state()
|
||||
if state == 'off':
|
||||
self.run_timer()
|
||||
|
||||
############ SENSOR GROUP ########################
|
||||
def get_motion_state(self):
|
||||
sensors = self.args['sensors']
|
||||
night_sensors = []
|
||||
if 'night_sensors' in self.args and self.is_night():
|
||||
night_sensors = self.args['night_sensors']
|
||||
all_sensors = sensors + night_sensors
|
||||
|
||||
self.log('all sensors: {}'.format(all_sensors))
|
||||
for sensor in all_sensors:
|
||||
state = self.get_state(sensor)
|
||||
if state == 'on':
|
||||
return 'on'
|
||||
return 'off'
|
||||
|
||||
def is_night(self):
|
||||
return not self.time_is_between(self.datetime(), '07:00:00', '23:00:00')
|
||||
|
||||
############ TIMER ########################
|
||||
def control_entity_on(self):
|
||||
#if 'constraint' is off - we dont need to do anything
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
entity = self.args['control_entity']
|
||||
if self.get_state(entity) == 'off':
|
||||
self.turn_on(entity)
|
||||
self.log("Light on.")
|
||||
|
||||
def control_entity_off(self, kwargs):
|
||||
#if 'constraint' is off - we dont need to do anything
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
|
||||
entity = self.args['control_entity']
|
||||
|
||||
if self.get_state(entity) == 'on':
|
||||
self.turn_off(entity)
|
||||
self.log("Light off.")
|
||||
self.stop_timer()
|
||||
|
||||
def run_timer(self):
|
||||
if self.timer != None:
|
||||
self.stop_timer()
|
||||
|
||||
timeout = self.args['timeout']
|
||||
if 'night_timeout' in self.args and self.is_night():
|
||||
timeout = self.args['night_timeout']
|
||||
self.log('Sensor is off - running timer for {}s'.format(timeout))
|
||||
self.timer = self.run_in(self.control_entity_off, timeout)
|
||||
|
||||
def stop_timer(self):
|
||||
if (self.timer == None):
|
||||
return
|
||||
self.log('stopping timer.')
|
||||
self.cancel_timer(self.timer)
|
||||
self.timer = None
|
||||
|
||||
def time_is_between(
|
||||
hass, target_dt: datetime, start_time: str,
|
||||
end_time: str) -> bool:
|
||||
"""Generalization of AppDaemon's now_is_between method."""
|
||||
start_time_dt = hass.parse_time(start_time) # type: datetime
|
||||
end_time_dt = hass.parse_time(end_time) # type: datetime
|
||||
start_dt = target_dt.replace(
|
||||
hour=start_time_dt.hour,
|
||||
minute=start_time_dt.minute,
|
||||
second=start_time_dt.second)
|
||||
end_dt = target_dt.replace(
|
||||
hour=end_time_dt.hour,
|
||||
minute=end_time_dt.minute,
|
||||
second=end_time_dt.second)
|
||||
|
||||
if end_dt < start_dt:
|
||||
# Spans midnight
|
||||
if target_dt < start_dt and target_dt < end_dt:
|
||||
target_dt = target_dt + timedelta(days=1)
|
||||
end_dt = end_dt + timedelta(days=1)
|
||||
return start_dt <= target_dt <= end_dt
|
||||
@@ -0,0 +1,20 @@
|
||||
#################################
|
||||
# LIGHT CONTROL #
|
||||
#################################
|
||||
light_control_kitchenset:
|
||||
module: lightcontrol_kitchenset
|
||||
class: LightControlKitchenset
|
||||
constraint: input_boolean.kitchenset_light_control
|
||||
sensors:
|
||||
- binary_sensor.motion_kitchenset_left_occupancy
|
||||
- binary_sensor.motion_kitchenset_right_occupancy
|
||||
night_sensors:
|
||||
- binary_sensor.motion_hall_1_occupancy
|
||||
- binary_sensor.motion_hall_2_occupancy
|
||||
door_sensors:
|
||||
- binary_sensor.door_kitchen_contact
|
||||
control_entity: switch.light_kitchen_set
|
||||
timeout: 900 #1200 - 20 mins
|
||||
night_timeout: 300 #300 - 5 min
|
||||
global_dependencies:
|
||||
- globals
|
||||
Reference in New Issue
Block a user