pyhive-integration 1.0.8.dev3__tar.gz → 1.0.8.dev4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyhive_integration-1.0.8.dev3/pyhive_integration.egg-info → pyhive_integration-1.0.8.dev4}/PKG-INFO +1 -1
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4/pyhive_integration.egg-info}/PKG-INFO +1 -1
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/setup.py +1 -1
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_async_api.py +7 -2
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_auth_async.py +1 -1
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/heating.py +7 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/hotwater.py +7 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/light.py +7 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/plug.py +7 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/sensor.py +7 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/session.py +27 -13
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/LICENSE +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/MANIFEST.in +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/README.md +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/SOURCES.txt +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/dependency_links.txt +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/requires.txt +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/top_level.txt +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyproject.toml +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/requirements.txt +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/requirements_test.txt +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/setup.cfg +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/__init__.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/action.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/alarm.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/__init__.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_api.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_auth.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/camera.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/device_attributes.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/__init__.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/const.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/debugger.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hive_exceptions.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hive_helper.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hivedataclasses.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/map.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/hive.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/hub.py +0 -0
- {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/tests/test_hub.py +0 -0
|
@@ -17,7 +17,7 @@ def requirements_from_file(filename="requirements.txt"):
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
setup(
|
|
20
|
-
version="1.0.8.
|
|
20
|
+
version="1.0.8.dev4",
|
|
21
21
|
packages=["apyhiveapi", "apyhiveapi.api", "apyhiveapi.helper"],
|
|
22
22
|
package_dir={"apyhiveapi": "src"},
|
|
23
23
|
package_data={"data": ["*.json"]},
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"""Hive API Module."""
|
|
2
2
|
|
|
3
3
|
# pylint: skip-file
|
|
4
|
+
import asyncio
|
|
4
5
|
import json
|
|
5
6
|
import logging
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
8
9
|
import requests
|
|
9
10
|
import urllib3
|
|
10
|
-
from aiohttp import ClientResponse, ClientSession, web_exceptions
|
|
11
|
+
from aiohttp import ClientResponse, ClientSession, ClientTimeout, web_exceptions
|
|
11
12
|
from pyquery import PyQuery
|
|
12
13
|
|
|
13
14
|
from ..helper.const import HTTP_FORBIDDEN, HTTP_UNAUTHORIZED
|
|
@@ -82,8 +83,9 @@ class HiveApiAsync:
|
|
|
82
83
|
auth_token[-4:] if len(auth_token) >= 4 else auth_token,
|
|
83
84
|
)
|
|
84
85
|
|
|
86
|
+
timeout = ClientTimeout(total=10)
|
|
85
87
|
async with self.websession.request(
|
|
86
|
-
method, url, headers=headers, data=data
|
|
88
|
+
method, url, headers=headers, data=data, timeout=timeout
|
|
87
89
|
) as resp:
|
|
88
90
|
resp_body = await resp.text()
|
|
89
91
|
if str(resp.status).startswith("20"):
|
|
@@ -163,6 +165,9 @@ class HiveApiAsync:
|
|
|
163
165
|
resp = await self.request("get", url)
|
|
164
166
|
json_return.update({"original": resp.status})
|
|
165
167
|
json_return.update({"parsed": await resp.json(content_type=None)})
|
|
168
|
+
except asyncio.TimeoutError:
|
|
169
|
+
_LOGGER.warning("Hive API request timed out fetching all nodes.")
|
|
170
|
+
raise
|
|
166
171
|
except (OSError, RuntimeError, ZeroDivisionError):
|
|
167
172
|
await self.error()
|
|
168
173
|
|
|
@@ -625,7 +625,7 @@ class HiveAuthAsync:
|
|
|
625
625
|
_LOGGER.error("Token refresh failed: cannot reach Cognito endpoint.")
|
|
626
626
|
raise HiveApiError from err
|
|
627
627
|
|
|
628
|
-
_LOGGER.debug("
|
|
628
|
+
_LOGGER.debug("Cognito token refresh completed successfully.")
|
|
629
629
|
return result
|
|
630
630
|
|
|
631
631
|
async def forget_device(self, access_token, device_key):
|
|
@@ -495,6 +495,13 @@ class Climate(HiveHeating):
|
|
|
495
495
|
await self.session.helper.errorCheck(
|
|
496
496
|
device["device_id"], "ERROR", device["deviceData"]["online"]
|
|
497
497
|
)
|
|
498
|
+
cached = self.session.devices.get(device["hiveID"])
|
|
499
|
+
if cached is not None:
|
|
500
|
+
_LOGGER.debug(
|
|
501
|
+
"Returning cached state for offline climate %s.",
|
|
502
|
+
device["haName"],
|
|
503
|
+
)
|
|
504
|
+
return cached
|
|
498
505
|
return device
|
|
499
506
|
|
|
500
507
|
async def getScheduleNowNextLater(self, device: dict):
|
|
@@ -263,6 +263,13 @@ class WaterHeater(HiveHotwater):
|
|
|
263
263
|
await self.session.helper.errorCheck(
|
|
264
264
|
device["device_id"], "ERROR", device["deviceData"]["online"]
|
|
265
265
|
)
|
|
266
|
+
cached = self.session.devices.get(device["hiveID"])
|
|
267
|
+
if cached is not None:
|
|
268
|
+
_LOGGER.debug(
|
|
269
|
+
"Returning cached state for offline water heater %s.",
|
|
270
|
+
device["haName"],
|
|
271
|
+
)
|
|
272
|
+
return cached
|
|
266
273
|
return device
|
|
267
274
|
|
|
268
275
|
async def getScheduleNowNextLater(self, device: dict):
|
|
@@ -420,6 +420,13 @@ class Light(HiveLight):
|
|
|
420
420
|
await self.session.helper.errorCheck(
|
|
421
421
|
device["device_id"], "ERROR", device["deviceData"]["online"]
|
|
422
422
|
)
|
|
423
|
+
cached = self.session.devices.get(device["hiveID"])
|
|
424
|
+
if cached is not None:
|
|
425
|
+
_LOGGER.debug(
|
|
426
|
+
"Returning cached state for offline light %s.",
|
|
427
|
+
device["haName"],
|
|
428
|
+
)
|
|
429
|
+
return cached
|
|
423
430
|
return device
|
|
424
431
|
|
|
425
432
|
async def turnOn(self, device: dict, brightness: int, color_temp: int, color: list):
|
|
@@ -180,6 +180,13 @@ class Switch(HiveSmartPlug):
|
|
|
180
180
|
await self.session.helper.errorCheck(
|
|
181
181
|
device["device_id"], "ERROR", device["deviceData"]["online"]
|
|
182
182
|
)
|
|
183
|
+
cached = self.session.devices.get(device["hiveID"])
|
|
184
|
+
if cached is not None:
|
|
185
|
+
_LOGGER.debug(
|
|
186
|
+
"Returning cached state for offline switch %s.",
|
|
187
|
+
device["haName"],
|
|
188
|
+
)
|
|
189
|
+
return cached
|
|
183
190
|
return device
|
|
184
191
|
|
|
185
192
|
async def getSwitchState(self, device: dict):
|
|
@@ -152,4 +152,11 @@ class Sensor(HiveSensor):
|
|
|
152
152
|
await self.session.helper.errorCheck(
|
|
153
153
|
device["device_id"], "ERROR", device["deviceData"]["online"]
|
|
154
154
|
)
|
|
155
|
+
cached = self.session.devices.get(device["hiveID"])
|
|
156
|
+
if cached is not None:
|
|
157
|
+
_LOGGER.debug(
|
|
158
|
+
"Returning cached state for offline sensor %s.",
|
|
159
|
+
device["haName"],
|
|
160
|
+
)
|
|
161
|
+
return cached
|
|
155
162
|
return device
|
|
@@ -358,7 +358,7 @@ class HiveSession:
|
|
|
358
358
|
expiry_time = self.tokens.tokenCreated + (self.tokens.tokenExpiry * 0.95)
|
|
359
359
|
# Refresh at 95% of token lifetime to prevent expiration during API calls
|
|
360
360
|
_LOGGER.debug(
|
|
361
|
-
"
|
|
361
|
+
"Session token expiry time ( Current: %s | Expiry: %s)",
|
|
362
362
|
datetime.now(),
|
|
363
363
|
expiry_time,
|
|
364
364
|
)
|
|
@@ -372,7 +372,7 @@ class HiveSession:
|
|
|
372
372
|
return result
|
|
373
373
|
actual_expiry = self.tokens.tokenCreated + self.tokens.tokenExpiry
|
|
374
374
|
_LOGGER.debug(
|
|
375
|
-
"Token created: %s | Actual expiry: %s | "
|
|
375
|
+
"Session Token created: %s | Actual expiry: %s | "
|
|
376
376
|
"Early refresh (×0.95): %s | Now: %s",
|
|
377
377
|
self.tokens.tokenCreated,
|
|
378
378
|
actual_expiry,
|
|
@@ -385,11 +385,17 @@ class HiveSession:
|
|
|
385
385
|
)
|
|
386
386
|
|
|
387
387
|
if result and "AuthenticationResult" in result:
|
|
388
|
-
_LOGGER.debug("Token refresh successful.")
|
|
389
388
|
await self.updateTokens(result)
|
|
389
|
+
new_expiry = (
|
|
390
|
+
self.tokens.tokenCreated + self.tokens.tokenExpiry
|
|
391
|
+
)
|
|
392
|
+
_LOGGER.debug(
|
|
393
|
+
"Session Token refresh successful. New expiry: %s",
|
|
394
|
+
new_expiry,
|
|
395
|
+
)
|
|
390
396
|
except (HiveRefreshTokenExpired, HiveFailedToRefreshTokens) as exc:
|
|
391
397
|
_LOGGER.warning(
|
|
392
|
-
"Token refresh failed (%s), falling back to device login.",
|
|
398
|
+
"Session Token refresh failed (%s), falling back to device login.",
|
|
393
399
|
type(exc).__name__,
|
|
394
400
|
)
|
|
395
401
|
await self._retryDeviceLogin()
|
|
@@ -580,6 +586,12 @@ class HiveSession:
|
|
|
580
586
|
_LOGGER.error("Reauthentication required, propagating to caller.")
|
|
581
587
|
self.config.lastUpdate = datetime.now()
|
|
582
588
|
raise
|
|
589
|
+
except asyncio.TimeoutError:
|
|
590
|
+
_LOGGER.warning("Hive API request timed out — keeping cached device data.")
|
|
591
|
+
self.config.lastUpdate = (
|
|
592
|
+
datetime.now() - self.config.scanInterval + timedelta(seconds=30)
|
|
593
|
+
)
|
|
594
|
+
get_nodes_successful = False
|
|
583
595
|
except (
|
|
584
596
|
OSError,
|
|
585
597
|
RuntimeError,
|
|
@@ -682,15 +694,6 @@ class HiveSession:
|
|
|
682
694
|
a = self.data["actions"][action] # noqa: F841
|
|
683
695
|
eval("self." + ACTIONS)
|
|
684
696
|
|
|
685
|
-
_LOGGER.debug(
|
|
686
|
-
"Device discovery found: %d climate, %d light, %d switch, %d sensor, %d camera, %d alarm.",
|
|
687
|
-
len(self.deviceList["climate"]),
|
|
688
|
-
len(self.deviceList["light"]),
|
|
689
|
-
len(self.deviceList["switch"]),
|
|
690
|
-
len(self.deviceList["sensor"]),
|
|
691
|
-
len(self.deviceList["camera"]),
|
|
692
|
-
len(self.deviceList["alarm_control_panel"]),
|
|
693
|
-
)
|
|
694
697
|
hive_type = HIVE_TYPES["Heating"] + HIVE_TYPES["Switch"] + HIVE_TYPES["Light"]
|
|
695
698
|
for aProduct in self.data.products:
|
|
696
699
|
p = self.data.products[aProduct]
|
|
@@ -713,6 +716,17 @@ class HiveSession:
|
|
|
713
716
|
if self.data.products[aProduct]["type"] in hive_type:
|
|
714
717
|
self.config.mode.append(p["id"])
|
|
715
718
|
|
|
719
|
+
_LOGGER.debug(
|
|
720
|
+
"Device discovery found: %d parent, %d binary_sensor, %d climate, %d light, %d sensor, %d switch, %d water_heater",
|
|
721
|
+
len(self.deviceList.get("parent", [])),
|
|
722
|
+
len(self.deviceList.get("binary_sensor", [])),
|
|
723
|
+
len(self.deviceList.get("climate", [])),
|
|
724
|
+
len(self.deviceList.get("light", [])),
|
|
725
|
+
len(self.deviceList.get("sensor", [])),
|
|
726
|
+
len(self.deviceList.get("switch", [])),
|
|
727
|
+
len(self.deviceList.get("water_heater", [])),
|
|
728
|
+
)
|
|
729
|
+
|
|
716
730
|
return self.deviceList
|
|
717
731
|
|
|
718
732
|
@staticmethod
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hive_exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hivedataclasses.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|