Initial work on a presence tracker. Inspired by @helto4real
This commit is contained in:
parent
3e61dcda71
commit
7305d719ee
79
appdaemon/apps/presence.py
Normal file
79
appdaemon/apps/presence.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
from entities import Entities
|
||||||
|
from timers import Timers
|
||||||
|
|
||||||
|
class Presence(Timers, Entities):
|
||||||
|
|
||||||
|
HOME = 'home'
|
||||||
|
AWAY = 'not_home'
|
||||||
|
ARRIVED = 'just_arrived'
|
||||||
|
LEFT = 'just_left'
|
||||||
|
TIMEOUT = 300
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
super().initialize()
|
||||||
|
|
||||||
|
attr = self.args.get('attributes', {})
|
||||||
|
|
||||||
|
self.register_entity('tracker', self.args['name'], managed=True, default="not_home", attributes=self.args.get('attributes',{}))
|
||||||
|
self.tracker = self.e['tracker']
|
||||||
|
if(self.tracker.state in [self.ARRIVED, self.LEFT]):
|
||||||
|
self.tracker.state = self.AWAY
|
||||||
|
|
||||||
|
self.devices = []
|
||||||
|
for i,d in enumerate(self.args['devices']):
|
||||||
|
name = f"device{i}"
|
||||||
|
self.register_entity(name, d);
|
||||||
|
self.e[name].listen(self.update, {"name": name})
|
||||||
|
self.devices.append(self.e[name])
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self, old=None, new=None, kwarg=None):
|
||||||
|
if not old or isinstance(old, str):
|
||||||
|
timeout = False
|
||||||
|
elif old is None:
|
||||||
|
timeout = False
|
||||||
|
else:
|
||||||
|
timeout = old.get('trigger', False)
|
||||||
|
new_state = self.is_home()
|
||||||
|
old_state = self.tracker.state
|
||||||
|
if new_state:
|
||||||
|
if old_state == self.AWAY:
|
||||||
|
self.run_in('timeout', self.update, self.TIMEOUT, trigger = "timeout")
|
||||||
|
state = self.ARRIVED
|
||||||
|
elif old_state == self.LEFT:
|
||||||
|
self.cancel_timer('timeout')
|
||||||
|
state = self.HOME
|
||||||
|
elif old_state == self.ARRIVED and timeout:
|
||||||
|
state = self.HOME
|
||||||
|
else:
|
||||||
|
state = old_state
|
||||||
|
else:
|
||||||
|
if old_state == self.HOME:
|
||||||
|
self.run_in('timeout', self.update, self.TIMEOUT, trigger = "timeout")
|
||||||
|
state = self.LEFT
|
||||||
|
elif old_state == self.ARRIVED:
|
||||||
|
self.cancel_timer('timeout')
|
||||||
|
state = self.AWAY
|
||||||
|
elif old_state == self.LEFT and timeout:
|
||||||
|
state = self.AWAY
|
||||||
|
else:
|
||||||
|
state = old_state
|
||||||
|
|
||||||
|
self.tracker.state = state
|
||||||
|
self.tracker.push()
|
||||||
|
|
||||||
|
def is_home(self):
|
||||||
|
for d in self.devices:
|
||||||
|
if d.domain == 'device_tracker':
|
||||||
|
if d.attr['source_type'] in ['router']:
|
||||||
|
if d.state == 'home':
|
||||||
|
return True
|
||||||
|
if d.domain == 'sensor':
|
||||||
|
if d.state != 'unknown' and int(d.state) > 0:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
37
appdaemon/apps/presence.yaml
Normal file
37
appdaemon/apps/presence.yaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
presence_thomas:
|
||||||
|
module: presence
|
||||||
|
class: Presence
|
||||||
|
global_dependencies:
|
||||||
|
- entities
|
||||||
|
- timers
|
||||||
|
dependencies:
|
||||||
|
- entity_manager
|
||||||
|
|
||||||
|
name: device_tracker.thomas_presence
|
||||||
|
attributes: {}
|
||||||
|
|
||||||
|
devices:
|
||||||
|
- device_tracker.thomas_iphone_beta
|
||||||
|
- device_tracker.thomas_iphone_2
|
||||||
|
- sensor.thomas_iphone_bt
|
||||||
|
- sensor.thomas_iphone_bt2
|
||||||
|
|
||||||
|
presence_anneli:
|
||||||
|
module: presence
|
||||||
|
class: Presence
|
||||||
|
global_depencencies:
|
||||||
|
- entities
|
||||||
|
- timers
|
||||||
|
dependencies:
|
||||||
|
- entity_manager
|
||||||
|
|
||||||
|
name: device_tracker.anneli_presence
|
||||||
|
attributes: {}
|
||||||
|
|
||||||
|
devices:
|
||||||
|
- device_tracker.anneli_lovn
|
||||||
|
- device_tracker.anneli_loven
|
||||||
|
- sensor.anneli_iphone_bt
|
||||||
|
- sensor.anneli_iphone_bt2
|
||||||
|
# - sensor.anneli_klocka_bt
|
||||||
|
# - sensor.anneli_klocka_bt2
|
@ -21,6 +21,43 @@ popup_cards:
|
|||||||
- type: history-graph
|
- type: history-graph
|
||||||
entities: *door_entities
|
entities: *door_entities
|
||||||
|
|
||||||
|
device_tracker.thomas_presence:
|
||||||
|
title: Thomas
|
||||||
|
large: true
|
||||||
|
card:
|
||||||
|
type: vertical-stack
|
||||||
|
cards:
|
||||||
|
- type: entities
|
||||||
|
entities: &thomas_entities
|
||||||
|
- device_tracker.thomas_iphone_beta
|
||||||
|
- device_tracker.thomas_iphone_2
|
||||||
|
- sensor.thomas_iphone_bt
|
||||||
|
- sensor.thomas_iphone_bt2
|
||||||
|
- type: history-graph
|
||||||
|
entities:
|
||||||
|
- device_tracker.thomas_presence
|
||||||
|
- type: history-graph
|
||||||
|
entities: *thomas_entities
|
||||||
|
|
||||||
|
device_tracker.anneli_presence:
|
||||||
|
title: Anneli
|
||||||
|
large: true
|
||||||
|
card:
|
||||||
|
type: vertical-stack
|
||||||
|
cards:
|
||||||
|
- type: entities
|
||||||
|
entities: &anneli_entities
|
||||||
|
- device_tracker.anneli_lovn
|
||||||
|
- device_tracker.anneli_loven
|
||||||
|
- sensor.anneli_iphone_bt
|
||||||
|
- sensor.anneli_iphone_bt2
|
||||||
|
- sensor.anneli_klocka_bt
|
||||||
|
- sensor.anneli_klocka_bt2
|
||||||
|
- type: history-graph
|
||||||
|
entities:
|
||||||
|
- device_tracker.anneli_presence
|
||||||
|
- type: history-graph
|
||||||
|
entities: *anneli_entities
|
||||||
cards:
|
cards:
|
||||||
- type: custom:layout-card
|
- type: custom:layout-card
|
||||||
layout: vertical
|
layout: vertical
|
||||||
@ -56,10 +93,22 @@ cards:
|
|||||||
- break
|
- break
|
||||||
- type: horizontal-stack
|
- type: horizontal-stack
|
||||||
cards:
|
cards:
|
||||||
- type: picture
|
- type: picture-entity
|
||||||
image: /local/images/thomas_clr.jpg
|
entity: device_tracker.thomas_presence
|
||||||
- type: picture
|
image: /local/images/thomas_bw.jpg
|
||||||
image: /local/images/anneli_clr.png
|
show_name: false
|
||||||
|
show_state: false
|
||||||
|
state_image:
|
||||||
|
"home": /local/images/thomas_clr.jpg
|
||||||
|
"just_arrived": /local/images/thomas_clr.jpg
|
||||||
|
- type: picture-entity
|
||||||
|
entity: device_tracker.anneli_presence
|
||||||
|
image: /local/images/anneli_bw.png
|
||||||
|
show_name: false
|
||||||
|
show_state: false
|
||||||
|
state_image:
|
||||||
|
"home": /local/images/anneli_clr.png
|
||||||
|
"just_arrived": /local/images/anneli_clr.png
|
||||||
- type: horizontal-stack
|
- type: horizontal-stack
|
||||||
cards:
|
cards:
|
||||||
- type: entity-button
|
- type: entity-button
|
||||||
|
37
packages/presence.yaml
Normal file
37
packages/presence.yaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
homeassistant:
|
||||||
|
customize:
|
||||||
|
package.node_anchors:
|
||||||
|
common: &common
|
||||||
|
package: 'security'
|
||||||
|
|
||||||
|
binary_sensor.home_occupied:
|
||||||
|
<<: *common
|
||||||
|
automation.adm_rescan_monitor_on_restart:
|
||||||
|
<<: *common
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: template
|
||||||
|
sensors:
|
||||||
|
home_occupied:
|
||||||
|
friendly_name: Anyone home
|
||||||
|
value_template: >-
|
||||||
|
{{ (is_state('device_tracker.thomas_presence', 'home') or
|
||||||
|
is_state('device_tracker.anneli_presence', 'home')) }}
|
||||||
|
|
||||||
|
device_tracker:
|
||||||
|
- platform: unifi
|
||||||
|
host: unifi
|
||||||
|
username: !secret unifi_username
|
||||||
|
password: !secret unifi_password
|
||||||
|
verify_ssl: false
|
||||||
|
ssid_filter: !secret unifi_ssids
|
||||||
|
|
||||||
|
automation:
|
||||||
|
- alias: ADM - Rescan monitor on restart
|
||||||
|
trigger:
|
||||||
|
platform: homeassistant
|
||||||
|
event: start
|
||||||
|
action:
|
||||||
|
- service: mqtt.publish
|
||||||
|
data:
|
||||||
|
topic: "monitor/scan/restart"
|
Loading…
x
Reference in New Issue
Block a user