Init
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: group.presence
|
||||
ha_panel: alarm_control_panel.ha_alarm
|
||||
constraint: input_boolean.presence_control
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,33 @@
|
||||
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):
|
||||
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'])
|
||||
|
||||
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')
|
||||
|
||||
def return_home_mode(self):
|
||||
self.log('return_home_mode')
|
||||
self.fire_event('return_home_mode')
|
||||
@@ -0,0 +1,9 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
alarm_panel_action:
|
||||
module: alarm_panel_action
|
||||
class: AlarmPanelAction
|
||||
ha_panel: alarm_control_panel.ha_alarm
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,32 @@
|
||||
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):
|
||||
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")
|
||||
|
||||
def away_mode(self, event_id, event_args, kwargs):
|
||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||
return
|
||||
for entity_id in self.args["away_entities"]:
|
||||
self.turn_off(entity_id)
|
||||
|
||||
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
|
||||
for entity_id in self.args["return_entities"]:
|
||||
self.turn_on(entity_id)
|
||||
@@ -0,0 +1,18 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
entities_action:
|
||||
module: entities_action
|
||||
class: EntitiesByPresence
|
||||
away_entities:
|
||||
- group.all_lights
|
||||
- switch.kitchen_mini_light
|
||||
- switch.plug_158d0001104a0c # телевизор
|
||||
- switch.plug_158d0001a68b18 # термопот
|
||||
return_entities:
|
||||
- light.yeelight_rgb_34ce008fe328
|
||||
- light.hall
|
||||
- switch.plug_158d0001104a0c # телевизор
|
||||
- switch.plug_158d0001a68b18 # термопот
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -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,91 @@
|
||||
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)
|
||||
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')
|
||||
else:
|
||||
self.create_sensor(sensor, 'off')
|
||||
|
||||
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 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,15 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
tags_presence:
|
||||
module: tags_presence
|
||||
class: TagsPresence
|
||||
tag_prefix: sensor.tag_
|
||||
sensor_prefix: sensor.presence_
|
||||
constraint_prefix: input_boolean.tag_
|
||||
rooms:
|
||||
- hall
|
||||
- balcony
|
||||
- kitchen
|
||||
global_dependencies:
|
||||
- globals
|
||||
@@ -0,0 +1,89 @@
|
||||
import appdaemon.plugins.hass.hassapi as hass
|
||||
|
||||
#
|
||||
# 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
|
||||
timer = None
|
||||
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(self.away_mode, "away_mode")
|
||||
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()
|
||||
if (len(powered_on) > 0):
|
||||
device_names = ""
|
||||
for device in powered_on:
|
||||
if device_names != '':
|
||||
device_names += ", "
|
||||
device_names += self.friendly_name(device)
|
||||
self.notify('В доме остались требующие воды устройства ({}), подача воды не будет отключена.'.format(device_names), name = self.args['notify'])
|
||||
self.cancel_current_timer()
|
||||
self.timer = self.run_every(self.wait_when_device_is_done, self.datetime(), 5*60)
|
||||
else:
|
||||
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) == 0):
|
||||
# self.turn_off(self.args['water_valve'])
|
||||
# for device in self.args['water_devices']:
|
||||
# self.turn_off(device)
|
||||
self.notify('Устройства требующие воды закончили свою работу.', name = self.args['notify'])
|
||||
self.cancel_current_timer()
|
||||
|
||||
def get_turned_on_devices(self):
|
||||
powered_on_devices = []
|
||||
devices = self.args['water_devices']
|
||||
for device in devices:
|
||||
state = self.get_state(device)
|
||||
attributes = self.get_state(device, attribute = "all")
|
||||
if 'attributes' in attributes:
|
||||
attributes = attributes['attributes']
|
||||
if 'load_power' not in attributes:
|
||||
continue
|
||||
load_power = attributes['load_power']
|
||||
self.log('{} load power is: {}'.format(device, load_power))
|
||||
if state == 'on' and load_power < self.standby_power_limit:
|
||||
continue
|
||||
powered_on_devices.append(device)
|
||||
return powered_on_devices
|
||||
|
||||
def cancel_current_timer(self):
|
||||
if self.timer != None:
|
||||
self.log('canceling timer')
|
||||
self.cancel_timer(self.timer)
|
||||
self.timer = None
|
||||
@@ -0,0 +1,14 @@
|
||||
#################################
|
||||
# HOME PRESENSE #
|
||||
#################################
|
||||
water_action:
|
||||
module: water_action
|
||||
class: WaterValveControl
|
||||
water_valve: switch.water_valve
|
||||
notify: telegram
|
||||
constraint: input_boolean.water_control
|
||||
water_devices:
|
||||
- switch.plug_158d0001a68c64 # Посудомойка
|
||||
- switch.plug_158d0001a4cfb4 # стиралка
|
||||
global_dependencies:
|
||||
- globals
|
||||
Reference in New Issue
Block a user