updating configuration
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
|
||||
#
|
||||
# Listen for presence sensor change state and change alarm control panel state.
|
||||
#
|
||||
# Args:
|
||||
# sensor - home presence 'sensor'
|
||||
# ha_panel - alarm control panel entity (to arm and disarm).
|
||||
# constraint - (optional, input_boolen), if turned off - alarm panel will be not armed\disarmed.
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class AlarmPanelBySensor(hass.Hass):
|
||||
def initialize(self):
|
||||
if "sensor" not in self.args or "ha_panel" not in self.args:
|
||||
self.error("Please provide sensor and ha_panel in config!")
|
||||
return
|
||||
self.listen_state(self.sensor_trigger, self.args['sensor'])
|
||||
self.listen_event(self.ha_event, "ha_started")
|
||||
|
||||
def ha_event(self, event_name, data, kwargs):
|
||||
self.log('Starting up!')
|
||||
state = self.get_state(self.args['sensor'])
|
||||
self.log('Updating alarm_control_panel state: {}'.format(state))
|
||||
if state == "off":
|
||||
self.away_mode()
|
||||
|
||||
def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||
self.log("{} turned {}".format(entity, new))
|
||||
if new == "off" and old == "on":
|
||||
self.away_mode()
|
||||
if new == "on" and old == "off":
|
||||
self.return_home_mode()
|
||||
|
||||
def away_mode(self):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
self.call_service("alarm_control_panel/alarm_arm_away", entity_id = self.args['ha_panel'])
|
||||
|
||||
def return_home_mode(self):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
self.call_service("alarm_control_panel/alarm_disarm", entity_id = self.args['ha_panel'])
|
||||
@@ -0,0 +1,11 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
alarm_panel:
|
||||
module: alarm_panel
|
||||
class: AlarmPanelBySensor
|
||||
sensor: sensor.presence_home
|
||||
ha_panel: alarm_control_panel.ha_alarm
|
||||
constraint: input_boolean.presence_control
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,77 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
|
||||
#
|
||||
# Listen for Alarm panel state change and fire an events ('away_mode' and 'return_home_mode')
|
||||
#
|
||||
# Args:
|
||||
# ha_panel - alarm control panel entity.
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class AlarmPanelAction(hass.Hass):
|
||||
extended_timeout = 5*60
|
||||
timers = []
|
||||
|
||||
def initialize(self):
|
||||
if "ha_panel" not in self.args:
|
||||
self.error("Please provide ha_panel in config!")
|
||||
return
|
||||
self.listen_state(self.ha_panel_trigger, self.args['ha_panel'])
|
||||
extended_timeout = self.args.get('extended_timeout', self.extended_timeout)
|
||||
self.log('extended_timeout: {}'.format(self.extended_timeout))
|
||||
|
||||
def ha_panel_trigger(self, entity, attribute, old, new, kwargs):
|
||||
# не срабатываем на triggered.
|
||||
if new == "armed_away" and old != "triggered":
|
||||
self.away_mode()
|
||||
if new == "disarmed" and old == "armed_away":
|
||||
self.return_home_mode()
|
||||
|
||||
def away_mode(self):
|
||||
self.log('away_mode')
|
||||
self.fire_event('away_mode')
|
||||
|
||||
if 'presence_extended' in self.args:
|
||||
self.fire_event('presence_extended_just_left')
|
||||
self.set_mode('Just Left')
|
||||
self.cancel_current_timer()
|
||||
self.timers.append(self.run_in(self.run_in_set_mode, self.extended_timeout, mode='Away'))
|
||||
|
||||
|
||||
def return_home_mode(self):
|
||||
self.log('return_home_mode')
|
||||
self.fire_event('return_home_mode')
|
||||
if 'presence_extended' in self.args:
|
||||
self.set_mode('Just Arrived')
|
||||
self.fire_event('presence_extended_just_arrived')
|
||||
self.cancel_current_timer()
|
||||
self.timers.append(self.run_in(self.run_in_set_mode, self.extended_timeout, mode='Home'))
|
||||
|
||||
|
||||
def set_mode(self, mode):
|
||||
if 'presence_extended' not in self.args:
|
||||
return
|
||||
entity_id = self.args['presence_extended']
|
||||
self.log('setting mode direct: {}={}'.format(entity_id, mode))
|
||||
self.call_service("input_select/select_option", entity_id = entity_id, option = mode)
|
||||
|
||||
|
||||
def run_in_set_mode(self, kwargs):
|
||||
if not 'mode' in kwargs:
|
||||
return
|
||||
mode = kwargs['mode']
|
||||
entity_id = self.args['presence_extended']
|
||||
event = 'presence_extended_{}'.format(mode.lower())
|
||||
self.log('firing event: {}'.format(event))
|
||||
self.fire_event(event)
|
||||
|
||||
self.log('setting mode by timer: {}={}'.format(entity_id, mode))
|
||||
self.call_service("input_select/select_option", entity_id = entity_id, option = mode)
|
||||
|
||||
def cancel_current_timer(self):
|
||||
for timer in self.timers:
|
||||
self.log('canceling timer')
|
||||
self.cancel_timer(timer)
|
||||
self.timers = []
|
||||
@@ -0,0 +1,11 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
alarm_panel_action:
|
||||
module: alarm_panel_action
|
||||
class: AlarmPanelAction
|
||||
ha_panel: alarm_control_panel.ha_alarm
|
||||
presence_extended: input_select.presence_extended
|
||||
extended_timeout: 300
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,80 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
|
||||
#
|
||||
# Light control by presence events
|
||||
# Listen for presence events and change light state
|
||||
#
|
||||
# Args:
|
||||
# entities - entities to turn on and off when presence is changed.
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class EntitiesByPresence(hass.Hass):
|
||||
mode = None
|
||||
def initialize(self):
|
||||
if 'away_entities' not in self.args or 'return_entities' not in self.args:
|
||||
self.error("Please provide away_entities and return_entities in config!")
|
||||
return
|
||||
self.listen_event(self.away_mode, "away_mode")
|
||||
self.listen_event(self.return_home_mode, "return_home_mode")
|
||||
self.determine_current_mode()
|
||||
self.set_thermostat_by_mode(None)
|
||||
self.timer = self.run_every(self.set_thermostat_by_mode, 'now', 5*60)
|
||||
|
||||
def determine_current_mode(self):
|
||||
state = self.get_state('input_select.presence_extended')
|
||||
if state == 'Home' or state == 'Just Arrived':
|
||||
self.mode = 'home'
|
||||
else:
|
||||
self.mode = 'away'
|
||||
|
||||
def away_mode(self, event_id, event_args, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
self.mode = 'away'
|
||||
for entity_id in self.args["away_entities"]:
|
||||
self.turn_off_custom(entity_id)
|
||||
self.set_thermostat_by_mode(None)
|
||||
|
||||
def return_home_mode(self, event_id, event_args, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
self.mode = 'home'
|
||||
entities = self.args["return_entities"]
|
||||
if entities == None:
|
||||
entities=[]
|
||||
for entity_id in entities:
|
||||
self.turn_on_custom(entity_id)
|
||||
self.set_thermostat_by_mode(None)
|
||||
|
||||
def set_thermostat_by_mode(self, kwargs):
|
||||
if "thremostats" not in self.args:
|
||||
return
|
||||
preset = 'away'
|
||||
if self.mode == 'home':
|
||||
preset = 'manual'
|
||||
for entity_id in self.args["thremostats"]:
|
||||
state = self.get_state(entity_id, 'preset_mode')
|
||||
if state != preset:
|
||||
self.log('Set thermostat ({}), current state = {}, set mode to {}'.format(entity_id, state, preset))
|
||||
self.call_service("climate/set_preset_mode", entity_id=entity_id, preset_mode = preset)
|
||||
|
||||
def turn_on_custom(self, entity_id):
|
||||
if 'cover.' in entity_id:
|
||||
self.call_service("cover/open_cover", entity_id=entity_id)
|
||||
return
|
||||
if 'climate.' in entity_id:
|
||||
self.call_service("climate/turn_on", entity_id=entity_id)
|
||||
return
|
||||
self.turn_on(entity_id)
|
||||
|
||||
def turn_off_custom(self, entity_id):
|
||||
if 'cover.' in entity_id:
|
||||
self.call_service("cover/close_cover", entity_id=entity_id)
|
||||
return
|
||||
if 'climate.' in entity_id:
|
||||
self.call_service("climate/turn_off", entity_id=entity_id)
|
||||
return
|
||||
self.turn_off(entity_id)
|
||||
@@ -0,0 +1,82 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
entities_action:
|
||||
module: entities_action
|
||||
class: EntitiesByPresence
|
||||
away_entities:
|
||||
# air conditioners
|
||||
- climate.ac_bedroom
|
||||
- climate.ac_childroom
|
||||
- climate.ac_kitchen
|
||||
- climate.ac_mainroom
|
||||
|
||||
# din rail lights
|
||||
- light.light_mainroom_mainlamp
|
||||
- light.light_mainroom_spotlights
|
||||
- light.light_mainroom_pc_spotlight
|
||||
# balcony
|
||||
- light.light_balcony_spotlight
|
||||
# bedroom
|
||||
- light.light_bedroom_spotlights
|
||||
- light.light_bedroom_nightlight_left
|
||||
- light.light_bedroom_nightlight_right
|
||||
- light.light_bedroom_pc_spotlight
|
||||
- light.light_bedroom_mainlight
|
||||
- light.light_bedroom_pc_nightlight
|
||||
# bath
|
||||
- light.light_bath
|
||||
- light.light_bath_shelf
|
||||
# shower
|
||||
- light.light_shower_main_spotlights
|
||||
- light.light_shower_shower_spotlights
|
||||
- light.light_shower_shelf_light
|
||||
# hall
|
||||
- light.light_hall_long
|
||||
# childroom
|
||||
- light.light_childroom_main
|
||||
- light.light_childroom_spotlights
|
||||
- light.light_childroom_bed
|
||||
# kitchen
|
||||
- light.light_kitchen_spotlights
|
||||
- light.light_kitchen_table_lamp
|
||||
- light.light_kitchen_bar_lamp
|
||||
- light.light_kitchen_set
|
||||
|
||||
# ventilation
|
||||
- fan.ventilation_shower
|
||||
- fan.ventilation_bath
|
||||
|
||||
# bedside lamps
|
||||
- light.danil_bedside_lamp_rgbww_light
|
||||
- light.svetlana_bedside_lamp_rgbww_light
|
||||
|
||||
# mirrors and heaters
|
||||
- switch.shower_mirror
|
||||
- switch.switch_mirror_shower_heater
|
||||
- switch.light_bath_mirror
|
||||
- switch.switch_mirror_bath_heater
|
||||
|
||||
# media
|
||||
- media_player.bedroom_tv
|
||||
- media_player.kitchen_tv
|
||||
- media_player.mainroom_tv
|
||||
|
||||
# alice
|
||||
- media_player.yandex_station_m00r46000m53db
|
||||
- media_player.yandex_station_m00fhe2003seqr
|
||||
- media_player.yandex_station_ly00000000000008674600007209d3f5
|
||||
- media_player.yandex_station_ff98f029ab48468d28c557be
|
||||
- media_player.yandex_station_u003jc100phn9k
|
||||
return_entities:
|
||||
# - light.light_kitchen_set
|
||||
|
||||
thremostats:
|
||||
- climate.radiator_childroom
|
||||
- climate.radiator_mainroom
|
||||
- climate.radiator_kitchen
|
||||
- climate.radiator_bedroom
|
||||
- climate.radiator_bedroom_balcony
|
||||
global_dependencies:
|
||||
- globals
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
purifier_timer:
|
||||
module: purifier
|
||||
class: Purifier
|
||||
on_time: "06:45:00"
|
||||
off_time: "23:00:00"
|
||||
entity: fan.xiaomi_miio_device
|
||||
ha_panel: alarm_control_panel.ha_alarm
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,107 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
import datetime
|
||||
|
||||
#
|
||||
# Purifier controller
|
||||
# Turn on and off purifier by light sensor and timers
|
||||
#
|
||||
# Args:
|
||||
#
|
||||
# None
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class Purifier(hass.Hass):
|
||||
away_fan_speed = 8 #1-14
|
||||
listen_event_handle_list = []
|
||||
mode = 'auto'
|
||||
|
||||
def initialize(self):
|
||||
if not globals.check_args(self, ["on_time", "off_time"]):
|
||||
return
|
||||
on_time = self.parse_time(self.args["on_time"])
|
||||
off_time = self.parse_time(self.args["off_time"])
|
||||
|
||||
self.on_timer = self.run_daily(self.day_mode_timer_event, on_time)
|
||||
self.off_timer = self.run_daily(self.night_mode_timer_event, off_time)
|
||||
|
||||
self.listen_event_handle_list.append(self.listen_event(self.away_mode_event, "away_mode"))
|
||||
self.listen_event_handle_list.append(self.listen_event(self.return_home_mode_event, "return_home_mode"))
|
||||
self.listen_event_handle_list.append(self.listen_state(self.state_change, self.args['entity'], attribute='illuminance'))
|
||||
|
||||
def state_change(self, entity, attribute, old, new, kwargs):
|
||||
presence_state = self.get_state(self.args['ha_panel'])
|
||||
if presence_state != "disarmed":
|
||||
# self.log('Nobody home, ignoring illuminance changes.')
|
||||
return
|
||||
self.log("{} changed from {} to {}".format(attribute, old, new))
|
||||
if old > 0 and new == 0 and self.time_is_between(self.datetime(), self.args["on_time"], self.args["off_time"]):
|
||||
self.night_mode()
|
||||
elif old == 0 and new > 0 and self.time_is_between(self.datetime(), self.args["on_time"], self.args["off_time"]):
|
||||
self.auto_mode()
|
||||
#self.auto_mode()
|
||||
|
||||
def return_home_mode_event(self, event_id, event_args, kwargs):
|
||||
self.auto_mode()
|
||||
|
||||
def away_mode_event(self, event_id, event_args, kwargs):
|
||||
self.away_mode()
|
||||
|
||||
def night_mode_timer_event(self, kwargs):
|
||||
self.night_mode()
|
||||
|
||||
def day_mode_timer_event(self, kwargs):
|
||||
self.auto_mode()
|
||||
|
||||
|
||||
def away_mode(self):
|
||||
self.mode='away'
|
||||
self.log('Set purifier mode to favorite, speed: {}'.format(self.away_fan_speed))
|
||||
if 'entity' in self.args:
|
||||
self.call_service("fan/set_speed", entity_id = self.args['entity'], speed='favorite')
|
||||
self.call_service("fan/xiaomi_miio_set_favorite_level", entity_id = self.args['entity'], level=self.away_fan_speed)
|
||||
self.call_service("fan/xiaomi_miio_set_led_on", entity_id = self.args['entity'])
|
||||
# self.call_service("fan/xiaomi_miio_set_buzzer_on", entity_id = self.args['entity'])
|
||||
|
||||
def auto_mode(self):
|
||||
self.mode='auto'
|
||||
self.log('Set purifier mode to auto.')
|
||||
if 'entity' in self.args:
|
||||
self.call_service("fan/set_speed", entity_id = self.args['entity'], speed='auto')
|
||||
self.call_service("fan/xiaomi_miio_set_led_on", entity_id = self.args['entity'])
|
||||
# self.call_service("fan/xiaomi_miio_set_buzzer_on", entity_id = self.args['entity'])
|
||||
|
||||
def night_mode(self):
|
||||
self.mode='night'
|
||||
self.log('Set purifier mode to silent.')
|
||||
if 'entity' in self.args:
|
||||
self.call_service("fan/xiaomi_miio_set_buzzer_off", entity_id = self.args['entity'])
|
||||
self.call_service("fan/set_speed", entity_id = self.args['entity'], speed='silent')
|
||||
self.call_service("fan/xiaomi_miio_set_led_off", entity_id = self.args['entity'])
|
||||
|
||||
|
||||
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,51 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import globals
|
||||
|
||||
#
|
||||
# Home and away report
|
||||
# Send report about home state after presence_actions was done.
|
||||
#
|
||||
# Args:
|
||||
# entity - group of entities to send state report
|
||||
# notify - notify entity to send message
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class ReportByPresence(hass.Hass):
|
||||
report_delay = 15
|
||||
def initialize(self):
|
||||
if 'entity' not in self.args or 'notify' not in self.args:
|
||||
self.error("Please provide entity and notify in config!")
|
||||
return
|
||||
self.listen_event(self.away_mode, "away_mode")
|
||||
self.listen_event(self.return_home_mode, "return_home_mode")
|
||||
|
||||
def away_mode(self, event_id, event_args, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
#wait 15 seconds before all devices will change thair states.
|
||||
self.run_in(self.send_report, self.report_delay)
|
||||
|
||||
def return_home_mode(self, event_id, event_args, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
self.notify("Добро пожаловать домой!", name = self.args['notify'])
|
||||
|
||||
############# AWAY REPORT ##########################
|
||||
def send_report(self, kwargs):
|
||||
any = False
|
||||
message = ""
|
||||
entities = globals.get_group_entities(self, self.args['entity'])
|
||||
for entity in entities:
|
||||
state = self.get_state(entity)
|
||||
if state == "on":
|
||||
any = True
|
||||
message += '{} ({}) = {}\n'.format(self.friendly_name(entity), entity, self.get_state(entity))
|
||||
if any:
|
||||
message = "В доме остались работать следующие устройства:\n" + message
|
||||
self.notify(message, name = self.args['notify'])
|
||||
else:
|
||||
self.notify("Все устройства в доме выключены.", name = self.args['notify'])
|
||||
@@ -0,0 +1,10 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
report_action:
|
||||
module: report_action
|
||||
class: ReportByPresence
|
||||
entity: group.report_entities
|
||||
notify: telegram
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,136 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
|
||||
#
|
||||
# Tags counter
|
||||
# This app count 'at home' BLE tags and set home presence state.
|
||||
# tag names must start from 'tag_'. Room presence sensors will be generated.
|
||||
#
|
||||
# Args:
|
||||
# tag_prefix = tag prefix to search (in my case 'sensor.tag_')
|
||||
# sensor_prefix = sensor prefix for room presence sensor (ex: if prefix 'sensor.presence_', than sensor name will be 'sensor.presence_hall')
|
||||
# rooms = rooms list, where tags will be discovered (sensor will be created for each room)
|
||||
# constraint_prefix (input_boolean) = constraint for tag (ex: input_boolean.tag_monster)
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
class TagsPresence(hass.Hass):
|
||||
tags = []
|
||||
constraint_list = []
|
||||
tag_by_room_cache = {}
|
||||
def initialize(self):
|
||||
if 'tag_prefix' not in self.args or 'sensor_prefix' not in self.args or 'rooms' not in self.args or 'constraint_prefix' not in self.args:
|
||||
self.error("Please provide tag_prefix, sensor_prefix, constraint_prefix and rooms in config!")
|
||||
return
|
||||
self.listen_tags()
|
||||
# self.listen_event(self.ha_event, "plugin_started")
|
||||
self.refresh_presence_state()
|
||||
|
||||
# def ha_event(self, event_name, data, kwargs):
|
||||
# self.run_in(self.refresh_presence_state_timer, 10)
|
||||
|
||||
def refresh_presence_state_timer(self, kwargs):
|
||||
self.refresh_presence_state()
|
||||
|
||||
def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||
self.refresh_presence_state()
|
||||
|
||||
def constraint_trigger(self, entity, attribute, old, new, kwargs):
|
||||
self.refresh_presence_state()
|
||||
|
||||
def listen_tags(self):
|
||||
self.fill_tags_and_constraints()
|
||||
for tag in self.tags:
|
||||
self.listen_state(self.sensor_trigger, tag)
|
||||
for constraint in self.constraint_list:
|
||||
self.listen_state(self.constraint_trigger, constraint)
|
||||
|
||||
def refresh_presence_state(self):
|
||||
tags_by_room = self.get_tags_state_by_room(self.tags, self.constraint_list)
|
||||
tags_by_person = self.get_tags_state_by_person(self.tags, self.constraint_list)
|
||||
homePresence = 'off'
|
||||
for room in self.args['rooms']:
|
||||
sensor = '{}{}'.format(self.args['sensor_prefix'],room)
|
||||
if room in tags_by_room and len(tags_by_room[room]) > 0:
|
||||
self.create_sensor(sensor, 'on')
|
||||
homePresence = 'on'
|
||||
else:
|
||||
self.create_sensor(sensor, 'off')
|
||||
|
||||
for person in tags_by_person:
|
||||
if len(tags_by_person[person])>0 and tags_by_person[person] != 'not home':
|
||||
attr = self.get_state(person, attribute='all').get('attributes', None)
|
||||
# self.log(attr)
|
||||
# attr['state'] = tags_by_person[person][0]
|
||||
|
||||
# disable set person state
|
||||
# self.set_state(person, state = tags_by_person[person][0], attributes = attr)
|
||||
|
||||
homeSensor = '{}{}'.format(self.args['sensor_prefix'],'home')
|
||||
self.create_sensor(homeSensor, homePresence)
|
||||
|
||||
def get_tags_state_by_room(self, tags, constraint_list):
|
||||
tags_by_room = {}
|
||||
for tag in tags:
|
||||
constraint = '{}{}'.format(self.args['constraint_prefix'],tag.replace(self.args['tag_prefix'],''))
|
||||
if constraint in constraint_list and not self.constrain_input_boolean(constraint):
|
||||
continue
|
||||
room = self.get_state(tag)
|
||||
if room not in tags_by_room:
|
||||
tags_by_room[room] = []
|
||||
tags_by_room[room].append(tag)
|
||||
return tags_by_room
|
||||
|
||||
def get_tags_state_by_person(self, tags, constraint_list):
|
||||
tags_by_person = {}
|
||||
for tag in tags:
|
||||
constraint = '{}{}'.format(self.args['constraint_prefix'],tag.replace(self.args['tag_prefix'],''))
|
||||
if constraint in constraint_list and not self.constrain_input_boolean(constraint):
|
||||
continue
|
||||
tagName = tag.replace(self.args['tag_prefix'],'')
|
||||
if '_' in tagName:
|
||||
tagName = tagName.split('_')[0]
|
||||
person = '{}{}'.format(self.args['person_prefix'], tagName)
|
||||
person_state = self.get_state(person)
|
||||
if person_state != None:
|
||||
# self.log('{}: {}'.format(person, person_state))
|
||||
if person not in tags_by_person:
|
||||
tags_by_person[person] = []
|
||||
tags_by_person[person].append(self.get_state(tag))
|
||||
return tags_by_person
|
||||
|
||||
# if person_state in self.get_state('person'):
|
||||
# self.log('{} found'.format(person))
|
||||
# else:
|
||||
# self.log('{} not found'.format(person))
|
||||
|
||||
# self.log('{}: {}'.format(person, person_state))
|
||||
# tag_state = self.get_state(tag)
|
||||
# if room not in tags_by_room:
|
||||
# tags_by_room[room] = []
|
||||
# tags_by_room[room].append(tag)
|
||||
# return tags_by_room
|
||||
|
||||
def fill_tags_and_constraints(self):
|
||||
self.tags = []
|
||||
self.constraint_list = []
|
||||
devices = self.get_state()
|
||||
for tag in devices:
|
||||
if not tag.startswith(self.args['tag_prefix']):
|
||||
continue
|
||||
self.tags.append(tag)
|
||||
|
||||
constraint = '{}{}'.format(self.args['constraint_prefix'],tag.replace(self.args['tag_prefix'],''))
|
||||
if constraint in devices and constraint not in self.constraint_list:
|
||||
self.constraint_list.append(constraint)
|
||||
|
||||
def create_sensor(self, entity_id, state, attributes = None):
|
||||
current_state = self.get_state(entity_id)
|
||||
if (current_state == state):
|
||||
return
|
||||
# self.log('Updating {} state ({}->{})'.format(entity_id, current_state, state))
|
||||
if attributes == None:
|
||||
attributes = {}
|
||||
attributes['description'] = 'Created and updated from appdaemon (tags_presence)'
|
||||
self.set_state(entity_id, state = state, attributes = attributes)
|
||||
@@ -0,0 +1,16 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
tags_presence:
|
||||
module: tags_presence
|
||||
class: TagsPresence
|
||||
tag_prefix: sensor.tag_
|
||||
sensor_prefix: sensor.presence_
|
||||
constraint_prefix: input_boolean.tag_
|
||||
person_prefix: person.
|
||||
rooms:
|
||||
- kladovka
|
||||
- bedroom
|
||||
- mainroom
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,107 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
import datetime
|
||||
|
||||
#
|
||||
# Water control application.
|
||||
# Controls water valve when all leave and no water needed devices is working.
|
||||
#
|
||||
# Args:
|
||||
# water_valve = water valve entity
|
||||
# notify - notify entity to send message
|
||||
# constraint (optional) = input_boolean to enable\disable this automation
|
||||
#
|
||||
# Release Notes
|
||||
#
|
||||
# Version 1.0:
|
||||
# Initial Version
|
||||
|
||||
class WaterValveControl(hass.Hass):
|
||||
standby_power_limit = 15
|
||||
current_wait_cycle = 0
|
||||
wait_cycles = 2
|
||||
timer = None
|
||||
listen_event_handle_list = []
|
||||
timers = []
|
||||
|
||||
def initialize(self):
|
||||
if 'water_valve' not in self.args or 'water_devices' not in self.args or 'notify' not in self.args:
|
||||
self.error("Please provide water_valve, water_devices and notify in config!")
|
||||
return
|
||||
|
||||
self.listen_event_handle_list.append(self.listen_event(self.away_mode, "away_mode"))
|
||||
self.listen_event_handle_list.append(self.listen_event(self.return_home_mode, "return_home_mode"))
|
||||
self.log(self.get_turned_on_devices())
|
||||
|
||||
def return_home_mode(self, event_id, event_args, kwargs):
|
||||
self.timer = None
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
self.turn_on(self.args['water_valve'])
|
||||
for device in self.args['water_devices']:
|
||||
self.turn_on(device)
|
||||
self.cancel_current_timer()
|
||||
|
||||
def away_mode(self, event_id, event_args, kwargs):
|
||||
self.timer = None
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
powered_on = self.get_turned_on_devices()
|
||||
self.log('away entities: {}'.format(powered_on))
|
||||
if (len(powered_on) > 0):
|
||||
device_names = ""
|
||||
for device in powered_on:
|
||||
if device_names != '':
|
||||
device_names += ", "
|
||||
name = self.friendly_name(device)
|
||||
if name is None:
|
||||
name = device
|
||||
device_names += name
|
||||
self.notify('В доме остались требующие воды устройства ({}), подача воды не будет отключена.'.format(device_names), name = self.args['notify'])
|
||||
self.cancel_current_timer()
|
||||
self.timers.append(self.run_every(self.wait_when_device_is_done, self.datetime()+datetime.timedelta(seconds=5), 5*60))
|
||||
else:
|
||||
self.notify('Отключаю подачу воды.', name = self.args['notify'])
|
||||
self.turn_off(self.args['water_valve'])
|
||||
# for device in self.args['water_devices']:
|
||||
# self.turn_off(device)
|
||||
|
||||
def wait_when_device_is_done(self, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
powered_on = self.get_turned_on_devices()
|
||||
self.log('still powered on: {}'.format(powered_on))
|
||||
if len(powered_on) == 1:
|
||||
self.current_wait_cycle = 0
|
||||
elif len(powered_on) == 0 and self.current_wait_cycle<self.wait_cycles:
|
||||
self.log("Current wait cycle: {}".format(self.current_wait_cycle))
|
||||
self.current_wait_cycle = self.current_wait_cycle+1
|
||||
elif len(powered_on) == 0 and self.current_wait_cycle>=self.wait_cycles:
|
||||
self.current_wait_cycle = 0
|
||||
self.notify('Устройства требующие воды закончили свою работу, отключаю подачу воды.', name = self.args['notify'])
|
||||
self.turn_off_water_devices()
|
||||
self.cancel_current_timer()
|
||||
|
||||
def turn_off_water_devices(self):
|
||||
self.log("Turning off water devices.")
|
||||
self.turn_off(self.args['water_valve'])
|
||||
for device in self.args['water_devices']:
|
||||
if 'switch' in device:
|
||||
self.log('switching off: {}'.format(device))
|
||||
self.turn_off(device)
|
||||
|
||||
def get_turned_on_devices(self):
|
||||
powered_on_devices = []
|
||||
devices = self.args['water_devices']
|
||||
for device in devices:
|
||||
state = self.get_state(device)
|
||||
self.log('{} state: {}'.format(device, state))
|
||||
if state == 'off' or state == None:
|
||||
continue
|
||||
powered_on_devices.append(device)
|
||||
return powered_on_devices
|
||||
|
||||
def cancel_current_timer(self):
|
||||
for timer in self.timers:
|
||||
self.log('canceling timer')
|
||||
self.cancel_timer(timer)
|
||||
self.timers = []
|
||||
@@ -0,0 +1,14 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
water_action:
|
||||
module: water_action
|
||||
class: WaterValveControl
|
||||
water_valve: switch.watercontrol_valves
|
||||
notify: telegram
|
||||
constraint: input_boolean.water_control
|
||||
water_devices:
|
||||
- binary_sensor.washer_running # стиралка
|
||||
- binary_sensor.hc_dishwasher_running # посудомойка
|
||||
global_dependencies:
|
||||
- globals
|
||||
Reference in New Issue
Block a user