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.
Files changed (40) hide show
  1. {pyhive_integration-1.0.8.dev3/pyhive_integration.egg-info → pyhive_integration-1.0.8.dev4}/PKG-INFO +1 -1
  2. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4/pyhive_integration.egg-info}/PKG-INFO +1 -1
  3. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/setup.py +1 -1
  4. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_async_api.py +7 -2
  5. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_auth_async.py +1 -1
  6. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/heating.py +7 -0
  7. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/hotwater.py +7 -0
  8. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/light.py +7 -0
  9. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/plug.py +7 -0
  10. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/sensor.py +7 -0
  11. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/session.py +27 -13
  12. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/LICENSE +0 -0
  13. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/MANIFEST.in +0 -0
  14. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/README.md +0 -0
  15. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/SOURCES.txt +0 -0
  16. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/dependency_links.txt +0 -0
  17. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/requires.txt +0 -0
  18. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyhive_integration.egg-info/top_level.txt +0 -0
  19. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/pyproject.toml +0 -0
  20. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/requirements.txt +0 -0
  21. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/requirements_test.txt +0 -0
  22. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/setup.cfg +0 -0
  23. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/__init__.py +0 -0
  24. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/action.py +0 -0
  25. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/alarm.py +0 -0
  26. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/__init__.py +0 -0
  27. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_api.py +0 -0
  28. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/api/hive_auth.py +0 -0
  29. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/camera.py +0 -0
  30. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/device_attributes.py +0 -0
  31. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/__init__.py +0 -0
  32. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/const.py +0 -0
  33. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/debugger.py +0 -0
  34. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hive_exceptions.py +0 -0
  35. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hive_helper.py +0 -0
  36. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/hivedataclasses.py +0 -0
  37. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/helper/map.py +0 -0
  38. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/hive.py +0 -0
  39. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/src/hub.py +0 -0
  40. {pyhive_integration-1.0.8.dev3 → pyhive_integration-1.0.8.dev4}/tests/test_hub.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyhive-integration
3
- Version: 1.0.8.dev3
3
+ Version: 1.0.8.dev4
4
4
  Summary: A Python library to interface with the Hive API
5
5
  Home-page: https://github.com/Pyhive/pyhiveapi
6
6
  Author: KJonline24
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyhive-integration
3
- Version: 1.0.8.dev3
3
+ Version: 1.0.8.dev4
4
4
  Summary: A Python library to interface with the Hive API
5
5
  Home-page: https://github.com/Pyhive/pyhiveapi
6
6
  Author: KJonline24
@@ -17,7 +17,7 @@ def requirements_from_file(filename="requirements.txt"):
17
17
 
18
18
 
19
19
  setup(
20
- version="1.0.8.dev3",
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("Token refresh completed successfully.")
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
- "Checking token expiry time ( Current: %s | Expiry: %s)",
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