-
Notifications
You must be signed in to change notification settings - Fork 6
/
presence.py
executable file
·216 lines (185 loc) · 7.51 KB
/
presence.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
"""Define automations for presence."""
from enum import Enum
from typing import Union
from appbase import AppBase
from constants import NOT_HOME, PERSON
from house_config import HOUSE, PERSONS
##############################################################################
# App to set input_selects for all persons in the house and the house itself
# based on presence status
##############################################################################
KEYS = "keys"
PRESENCE_STATE = "presence_state"
INPUT_SELECT = "input_select"
TARGET_STATE = "target_state"
class PresenceAutomation(AppBase):
"""Define a base feature for presence automations."""
class PresenceState(Enum):
"""Define an enum for person related presence states."""
home = "zu Hause"
just_arrived = "gerade angekommen"
just_left = "gerade gegangen"
away = "weg"
extended_away = "lange weg"
class HouseState(Enum):
"""Define an enum for house related presence states."""
someone = "Jemand ist zu Hause"
everyone = "Alle sind zu Hause"
noone = "Niemand ist zu Hause"
vacation = "Ferien"
def configure(self) -> None:
"""Configure."""
for person, attribute in PERSONS.items():
# get key topic for mqtt room device tracker
keys_topic = attribute.get("keys_topic")
# set initial state
if self.get_state(attribute[KEYS]) == NOT_HOME:
self.select_option(
attribute[PRESENCE_STATE], self.PresenceState.away.value
)
else:
self.select_option(
attribute[PRESENCE_STATE], self.PresenceState.home.value
)
# away/extented away to just arrived
self.listen_state(
self.set_presence_person,
attribute[KEYS],
old=NOT_HOME,
input_select=attribute[PRESENCE_STATE],
person=person,
key_topic=keys_topic,
target_state=self.PresenceState.just_arrived.value,
)
# home to just left
self.listen_state(
self.set_presence_person,
attribute[KEYS],
new=NOT_HOME,
input_select=attribute[PRESENCE_STATE],
person=person,
keys_topic=keys_topic,
target_state=self.PresenceState.just_left.value,
)
# just arrived to home
self.listen_state(
self.set_presence_person,
attribute[PRESENCE_STATE],
new=self.PresenceState.just_arrived.value,
duration=60 * 5,
input_select=attribute[PRESENCE_STATE],
person=person,
keys_topic=keys_topic,
target_state=self.PresenceState.home.value,
)
# just left to just arrived = home
self.listen_state(
self.set_presence_person,
attribute[PRESENCE_STATE],
old=self.PresenceState.just_left.value,
new=self.PresenceState.just_arrived.value,
input_select=attribute[PRESENCE_STATE],
person=person,
keys_topic=keys_topic,
target_state=self.PresenceState.home.value,
)
# just left to away
self.listen_state(
self.set_presence_person,
attribute[PRESENCE_STATE],
new=self.PresenceState.just_left.value,
duration=60 * 5,
input_select=attribute[PRESENCE_STATE],
person=person,
keys_topic=keys_topic,
target_state=self.PresenceState.away.value,
)
# away to extended away
self.listen_state(
self.set_presence_person,
attribute[PRESENCE_STATE],
new=self.PresenceState.away.value,
duration=60 * 60 * 24,
input_select=attribute[PRESENCE_STATE],
person=person,
keys_topic=keys_topic,
target_state=self.PresenceState.extended_away.value,
)
# listen state to trigger house state change
self.listen_state(self.set_presence_house, attribute[PRESENCE_STATE])
def set_presence_person(
self, entity: Union[str, dict], attribute: str, old: str, new: str, kwargs: dict
) -> None:
"""Set the presence input select for the
specified person based on the given state"""
old_state = self.get_state(kwargs[INPUT_SELECT])
self.select_option(kwargs[INPUT_SELECT], kwargs[TARGET_STATE])
if kwargs["keys_topic"] is not None:
if kwargs["target_state"] in [self.PresenceState.just_arrived.value, self.PresenceState.home.value]:
payload = "home"
else:
payload = "not_home"
self.mqtt.mqtt_publish(
kwargs["keys_topic"],
payload,
namespace="mqtt",
)
self.log(
f"{kwargs[PERSON]} war {old_state}, " f"ist jetzt {kwargs[TARGET_STATE]}"
)
def set_presence_house(
self, entity: Union[str, dict], attribute: str, old: str, new: str, kwargs: dict
) -> None:
"""Set the presence for the house."""
if self.everyone_home:
self.set_house_input_select(self.HouseState.everyone.value)
elif self.everyone_vacation:
self.set_house_input_select(self.HouseState.vacation.value)
elif self.noone_home:
self.set_house_input_select(self.HouseState.noone.value)
else:
self.set_house_input_select(self.HouseState.someone.value)
def set_house_input_select(self, new_state: str) -> None:
"""Set the presence input select for the house."""
old_state = self.house_presence_state
if not old_state == new_state:
self.select_option(HOUSE[PRESENCE_STATE], new_state)
self.log("Vorher: {}, Jetzt: {}".format(old_state, new_state))
def who_in_state(self, *presence_states: Enum) -> list:
"""Return list of person in given state."""
presence_state_list = [
presence_state.value for presence_state in presence_states
]
return [
person
for person, attribute in PERSONS.items()
if self.get_state(attribute[PRESENCE_STATE]) in presence_state_list
]
@property
def house_presence_state(self):
"""Return current state of the house presence."""
return self.get_state(HOUSE[PRESENCE_STATE])
@property
def everyone_home(self) -> bool:
"""Return true if everyone is home."""
return self.persons_home == list(PERSONS.keys())
@property
def someone_home(self) -> bool:
"""Return true if someone is home."""
return len(self.persons_home) != 0
@property
def noone_home(self) -> bool:
"""Return true if noone is home."""
return not self.persons_home
@property
def everyone_vacation(self):
"""Return true if everyone is on vacation."""
return self.who_in_state(self.PresenceState.extended_away) == list(
PERSONS.keys()
)
@property
def persons_home(self) -> list:
"""Return list of persons home."""
return self.who_in_state(
self.PresenceState.home, self.PresenceState.just_arrived
)