first commit
This commit is contained in:
@@ -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,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,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,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,94 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
|
||||
#
|
||||
# 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
|
||||
if self.get_state(self.args['control_entity']) == 'off':
|
||||
self.turn_on(self.args['control_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
|
||||
if self.door_state_changed == False:
|
||||
self.log('Motion is detected inside and door is still closed - dont turn off the light')
|
||||
return
|
||||
if self.get_state(self.args['control_entity']) == 'on':
|
||||
self.turn_off(self.args['control_entity'])
|
||||
self.log("Light off.")
|
||||
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
|
||||
@@ -0,0 +1,13 @@
|
||||
#################################
|
||||
# LIGHT CONTROL #
|
||||
#################################
|
||||
light_control_bath:
|
||||
module: lightcontrol_bath
|
||||
class: LightControlBath
|
||||
sensor: binary_sensor.motion_sensor_bath
|
||||
door_sensor: binary_sensor.door_window_sensor_bath
|
||||
control_entity: switch.light_bath
|
||||
timeout: 240
|
||||
constraint: input_boolean.bath_light_control
|
||||
global_dependencies:
|
||||
- globals
|
||||
Reference in New Issue
Block a user