Skip to content

Commit c3dc061

Browse files
authored
1.2.1 (#7)
* add debug timings * have keepalive perform full logout once per day * full relogin additional fix * make keepalive task wait for sync check task to sleep before lgging out * update changelog * bump version, bump aiohttp to >=3.9.3
1 parent 1664fb2 commit c3dc061

File tree

6 files changed

+610
-506
lines changed

6 files changed

+610
-506
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 1.2.1 (2024-02-07)
2+
3+
* add timing loggin for zone/site updates
4+
* do full logout once per day
5+
* have keepalive task wait for sync check task to sleep before logging out
6+
17
## 1.2.0 (2024-01-30)
28

39
* add exceptions and exception handling

poetry.lock

Lines changed: 553 additions & 498 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyadtpulse/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Constants for pyadtpulse."""
22

3-
__version__ = "1.2.0"
3+
__version__ = "1.2.1"
44

55
DEFAULT_API_HOST = "https://portal.adtpulse.com"
66
API_HOST_CA = "https://portal-ca.adtpulse.com" # Canada

pyadtpulse/pyadtpulse_async.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class PyADTPulseAsync:
6161
"_site",
6262
"_detailed_debug_logging",
6363
"_sync_check_exception",
64+
"_sync_check_sleeping",
6465
)
6566

6667
@typechecked
@@ -129,6 +130,7 @@ def __init__(
129130
pc_backoff = self._pulse_connection.get_login_backoff()
130131
self._sync_check_exception: Exception | None = PulseNotLoggedInError()
131132
pc_backoff.reset_backoff()
133+
self._sync_check_sleeping = asyncio.Event()
132134

133135
def __repr__(self) -> str:
134136
"""Object representation."""
@@ -138,12 +140,21 @@ def __repr__(self) -> str:
138140

139141
async def _update_sites(self, soup: BeautifulSoup) -> None:
140142
with self._pa_attribute_lock:
143+
start_time = 0.0
144+
if self._pulse_connection.detailed_debug_logging:
145+
start_time = time.time()
141146
if self._site is None:
142147
await self._initialize_sites(soup)
143148
if self._site is None:
144149
raise RuntimeError("pyadtpulse could not retrieve site")
145150
self._site.alarm_control_panel.update_alarm_from_soup(soup)
146151
self._site.update_zone_from_soup(soup)
152+
if self._pulse_connection.detailed_debug_logging:
153+
LOG.debug(
154+
"Updated site %s in %s seconds",
155+
self._site.id,
156+
time.time() - start_time,
157+
)
147158

148159
async def _initialize_sites(self, soup: BeautifulSoup) -> None:
149160
"""
@@ -159,7 +170,9 @@ async def _initialize_sites(self, soup: BeautifulSoup) -> None:
159170
single_premise = soup.find("span", {"id": "p_singlePremise"})
160171
if single_premise:
161172
site_name = single_premise.text
162-
173+
start_time = 0.0
174+
if self._pulse_connection.detailed_debug_logging:
175+
start_time = time.time()
163176
# FIXME: this code works, but it doesn't pass the linter
164177
signout_link = str(
165178
soup.find("a", {"class": "p_signoutlink"}).get("href") # type: ignore
@@ -180,6 +193,12 @@ async def _initialize_sites(self, soup: BeautifulSoup) -> None:
180193
new_site.gateway.is_online = False
181194
new_site.update_zone_from_soup(soup)
182195
self._site = new_site
196+
if self._pulse_connection.detailed_debug_logging:
197+
LOG.debug(
198+
"Initialized site %s in %s seconds",
199+
self._site.id,
200+
time.time() - start_time,
201+
)
183202
return
184203
else:
185204
LOG.warning(
@@ -241,6 +260,7 @@ def should_relogin(relogin_interval: int) -> bool:
241260
> randint(int(0.75 * relogin_interval), relogin_interval)
242261
)
243262

263+
next_full_logout_time = time.time() + 24 * 60 * 60
244264
response: str | None
245265
task_name: str = self._get_task_name(self._timeout_task, KEEPALIVE_TASK_NAME)
246266
LOG.debug("creating %s", task_name)
@@ -257,8 +277,24 @@ def should_relogin(relogin_interval: int) -> bool:
257277
if not self._pulse_connection.is_connected:
258278
LOG.debug("%s: Skipping relogin because not connected", task_name)
259279
continue
260-
elif should_relogin(relogin_interval):
261-
await self._pulse_connection.quick_logout()
280+
if should_relogin(relogin_interval):
281+
msg = "quick"
282+
if time.time() > next_full_logout_time:
283+
msg = "full"
284+
with self._pa_attribute_lock:
285+
if self._sync_task:
286+
if self._detailed_debug_logging:
287+
LOG.debug(
288+
"%s: waiting for sync check task to sleep",
289+
task_name,
290+
)
291+
await self._sync_check_sleeping.wait()
292+
if msg == "full":
293+
next_full_logout_time = time.time() + 24 * 60 * 60
294+
await self.async_logout()
295+
else:
296+
await self._pulse_connection.quick_logout()
297+
LOG.debug("%s: performing %s logout", task_name, msg)
262298
try:
263299
await self._login_looped(task_name)
264300
except (PulseAuthenticationError, PulseMFARequiredError) as ex:
@@ -458,14 +494,15 @@ async def shutdown_task(ex: Exception):
458494

459495
while True:
460496
try:
497+
self._sync_check_sleeping.set()
461498
if not have_updates and not self.site.gateway.is_online:
462499
# gateway going back online will trigger a sync check of 1-0-0
463500
await self.site.gateway.backoff.wait_for_backoff()
464501
else:
465502
await asyncio.sleep(
466503
self.site.gateway.poll_interval if not have_updates else 0.0
467504
)
468-
505+
self._sync_check_sleeping.clear()
469506
try:
470507
code, response_text, url = await perform_sync_check_query()
471508
except (

pyadtpulse/site.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,9 @@ def update_zone_from_soup(self, soup: BeautifulSoup) -> None:
312312
Raises:
313313
PulseGatewayOffline: If the gateway is offline.
314314
"""
315-
315+
start_time = 0.0
316+
if self._pulse_connection.detailed_debug_logging:
317+
start_time = time()
316318
# parse ADT's convulated html to get sensor status
317319
with self._site_lock:
318320
orb_status = soup.find("canvas", {"id": "ic_orb"})
@@ -402,8 +404,12 @@ def update_zone_from_soup(self, soup: BeautifulSoup) -> None:
402404
status,
403405
last_update,
404406
)
407+
405408
self._last_updated = int(time())
406409

410+
if self._pulse_connection.detailed_debug_logging:
411+
LOG.debug("Updated zones in %f seconds", time() - start_time)
412+
407413
async def _async_update_zones(self) -> list[ADTPulseFlattendZone] | None:
408414
"""Update zones asynchronously.
409415

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "pyadtpulse"
3-
version = "1.2.0"
3+
version = "1.2.1"
44
description = "Python interface for ADT Pulse security systems"
55
authors = ["Ryan Snodgrass"]
66
maintainers = ["Robert Lippmann"]
@@ -16,7 +16,7 @@ classifiers = [
1616

1717
[tool.poetry.dependencies]
1818
python = "^3.11"
19-
aiohttp = "3.9.1"
19+
aiohttp = "^3.9.3"
2020
beautifulsoup4 = "^4.12.2"
2121
uvloop = "^0.19.0"
2222
bs4 = "^0.0.1"

0 commit comments

Comments
 (0)