updating configuration

This commit is contained in:
Your Name
2026-03-10 07:08:59 +00:00
commit 9498a076ee
238 changed files with 18119 additions and 0 deletions
@@ -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