This commit is contained in:
monster
2018-12-30 14:13:57 +03:00
parent e311c31b88
commit 2033fe79e4
225 changed files with 6370 additions and 0 deletions
@@ -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