python-hilo 2025.11.1__tar.gz → 2025.12.1__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 (21) hide show
  1. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/PKG-INFO +1 -1
  2. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/api.py +6 -4
  3. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/const.py +2 -1
  4. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/devices.py +2 -2
  5. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/event.py +7 -1
  6. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/graphql.py +4 -4
  7. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/websocket.py +4 -0
  8. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyproject.toml +1 -1
  9. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/LICENSE +0 -0
  10. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/README.md +0 -0
  11. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/__init__.py +0 -0
  12. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/device/__init__.py +0 -0
  13. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/device/climate.py +0 -0
  14. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/device/graphql_value_mapper.py +0 -0
  15. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/device/light.py +0 -0
  16. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/device/sensor.py +0 -0
  17. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/device/switch.py +0 -0
  18. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/exceptions.py +0 -0
  19. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/oauth2helper.py +0 -0
  20. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/util/__init__.py +0 -0
  21. {python_hilo-2025.11.1 → python_hilo-2025.12.1}/pyhilo/util/state.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hilo
3
- Version: 2025.11.1
3
+ Version: 2025.12.1
4
4
  Summary: A Python3, async interface to the Hilo API
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -12,6 +12,7 @@ from urllib import parse
12
12
  from aiohttp import ClientSession
13
13
  from aiohttp.client_exceptions import ClientResponseError
14
14
  import backoff
15
+ from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
15
16
 
16
17
  from pyhilo.const import (
17
18
  ANDROID_CLIENT_ENDPOINT,
@@ -66,7 +67,7 @@ class API:
66
67
  self,
67
68
  *,
68
69
  session: ClientSession,
69
- oauth_session,
70
+ oauth_session: OAuth2Session,
70
71
  request_retries: int = REQUEST_RETRY,
71
72
  log_traces: bool = False,
72
73
  ) -> None:
@@ -97,7 +98,7 @@ class API:
97
98
  cls,
98
99
  *,
99
100
  session: ClientSession,
100
- oauth_session,
101
+ oauth_session: OAuth2Session,
101
102
  request_retries: int = REQUEST_RETRY,
102
103
  log_traces: bool = False,
103
104
  ) -> API:
@@ -382,11 +383,12 @@ class API:
382
383
  # Create both websocket clients
383
384
  # ic-dev21 need to work on this as it can't lint as is, may need to
384
385
  # instantiate differently
385
- self.websocket_devices = WebsocketClient(self.websocket_manager.devicehub)
386
+ # TODO: fix type ignore after refactor
387
+ self.websocket_devices = WebsocketClient(self.websocket_manager.devicehub) # type: ignore
386
388
 
387
389
  # For backward compatibility during the transition to challengehub websocket
388
390
  self.websocket = self.websocket_devices
389
- self.websocket_challenges = WebsocketClient(self.websocket_manager.challengehub)
391
+ self.websocket_challenges = WebsocketClient(self.websocket_manager.challengehub) # type: ignore
390
392
 
391
393
  async def refresh_ws_token(self) -> None:
392
394
  """Refresh the websocket token."""
@@ -7,7 +7,7 @@ import aiohttp
7
7
  LOG: Final = logging.getLogger(__package__)
8
8
  DEFAULT_STATE_FILE: Final = "hilo_state.yaml"
9
9
  REQUEST_RETRY: Final = 9
10
- PYHILO_VERSION: Final = "2025.11.01"
10
+ PYHILO_VERSION: Final = "2025.12.01"
11
11
  # TODO: Find a way to keep previous line in sync with pyproject.toml automatically
12
12
 
13
13
  CONTENT_TYPE_FORM: Final = "application/x-www-form-urlencoded"
@@ -32,6 +32,7 @@ API_GD_SERVICE_ENDPOINT: Final = f"/GDService/{API_END}"
32
32
  API_NOTIFICATIONS_ENDPOINT: Final = "/Notifications"
33
33
  API_EVENTS_ENDPOINT: Final = "/Notifications"
34
34
  API_REGISTRATION_ENDPOINT: Final = f"{API_NOTIFICATIONS_ENDPOINT}/Registrations"
35
+ PLATFORM_HOST: Final = "platform.hiloenergie.com"
35
36
 
36
37
  API_REGISTRATION_HEADERS: Final = {
37
38
  "AppId": ANDROID_PKG_NAME,
@@ -55,7 +55,7 @@ class Devices:
55
55
  """Uses the dict from parse_values_received to map the values to devices."""
56
56
  updated_devices = []
57
57
  for reading in readings:
58
- device_identifier = reading.device_id
58
+ device_identifier: Union[int, str] = reading.device_id
59
59
  if device_identifier == 0:
60
60
  device_identifier = reading.hilo_id
61
61
  if device := self.find_device(device_identifier):
@@ -69,7 +69,7 @@ class Devices:
69
69
  )
70
70
  return updated_devices
71
71
 
72
- def find_device(self, device_identifier: int | str) -> HiloDevice:
72
+ def find_device(self, device_identifier: int | str) -> HiloDevice | None:
73
73
  """Makes sure the devices received have an identifier, this means some need to be hardcoded
74
74
  like the unknown power meter.
75
75
  """
@@ -27,7 +27,7 @@ class Event:
27
27
  def __init__(self, **event: dict[str, Any]):
28
28
  """Initialize."""
29
29
  self._convert_phases(cast(dict[str, Any], event.get("phases")))
30
- params: dict[str, Any] = event.get("parameters", {})
30
+ params: dict[str, Any] = event.get("parameters") or {}
31
31
  devices: list[dict[str, Any]] = params.get("devices", [])
32
32
  consumption: dict[str, Any] = event.get("consumption", {})
33
33
  allowed_wH: int = consumption.get("baselineWh", 0) or 0
@@ -71,6 +71,12 @@ class Event:
71
71
  self.used_kWh = round(used_wH / 1000, 2)
72
72
  self.last_update = datetime.now(timezone.utc).astimezone()
73
73
 
74
+ def update_allowed_wh(self, allowed_wH: float) -> None:
75
+ """This function is used to update the allowed_kWh attribute during a Hilo Challenge Event"""
76
+ LOG.debug("Updating allowed Wh: %s", allowed_wH)
77
+ self.allowed_kWh = round(allowed_wH / 1000, 2)
78
+ self.last_update = datetime.now(timezone.utc).astimezone()
79
+
74
80
  def should_check_for_allowed_wh(self) -> bool:
75
81
  """This function is used to authorize subscribing to a specific event in Hilo to receive the allowed_kWh
76
82
  that is made available in the pre_heat phase"""
@@ -8,7 +8,7 @@ from gql.transport.aiohttp import AIOHTTPTransport
8
8
  from gql.transport.websockets import WebsocketsTransport
9
9
 
10
10
  from pyhilo import API
11
- from pyhilo.const import LOG
11
+ from pyhilo.const import LOG, PLATFORM_HOST
12
12
  from pyhilo.device.graphql_value_mapper import GraphqlValueMapper
13
13
  from pyhilo.devices import Devices
14
14
 
@@ -534,7 +534,7 @@ class GraphQlHelper:
534
534
  """This functions calls the digital-twin and requests location id"""
535
535
  access_token = await self._get_access_token()
536
536
  transport = AIOHTTPTransport(
537
- url="https://platform.hiloenergie.com/api/digital-twin/v3/graphql",
537
+ url=f"https://{PLATFORM_HOST}/api/digital-twin/v3/graphql",
538
538
  headers={"Authorization": f"Bearer {access_token}"},
539
539
  )
540
540
  client = Client(transport=transport, fetch_schema_from_transport=True)
@@ -562,7 +562,7 @@ class GraphQlHelper:
562
562
  LOG.debug("subscribe_to_device_updated while true")
563
563
  access_token = await self._get_access_token()
564
564
  transport = WebsocketsTransport(
565
- url=f"wss://platform.hiloenergie.com/api/digital-twin/v3/graphql?access_token={access_token}",
565
+ url=f"wss://{PLATFORM_HOST}/api/digital-twin/v3/graphql?access_token={access_token}",
566
566
  ssl=ssl_context,
567
567
  )
568
568
  client = Client(transport=transport, fetch_schema_from_transport=True)
@@ -602,7 +602,7 @@ class GraphQlHelper:
602
602
  ) -> None:
603
603
  access_token = await self._get_access_token()
604
604
  transport = WebsocketsTransport(
605
- url=f"wss://platform.hiloenergie.com/api/digital-twin/v3/graphql?access_token={access_token}"
605
+ url=f"wss://{PLATFORM_HOST}/api/digital-twin/v3/graphql?access_token={access_token}"
606
606
  )
607
607
  client = Client(transport=transport, fetch_schema_from_transport=True)
608
608
  query = gql(self.SUBSCRIPTION_LOCATION_UPDATED)
@@ -310,6 +310,10 @@ class WebsocketClient:
310
310
  raise CannotConnectError(err) from err
311
311
 
312
312
  LOG.info(f"Connected to websocket server {self._api.endpoint}")
313
+
314
+ # Quick pause to prevent race condition
315
+ await asyncio.sleep(0.05)
316
+
313
317
  self._watchdog.trigger()
314
318
  for callback in self._connect_callbacks:
315
319
  schedule_callback(callback)
@@ -40,7 +40,7 @@ exclude = ".venv/.*"
40
40
 
41
41
  [tool.poetry]
42
42
  name = "python-hilo"
43
- version = "2025.11.1"
43
+ version = "2025.12.1"
44
44
  description = "A Python3, async interface to the Hilo API"
45
45
  readme = "README.md"
46
46
  authors = ["David Vallee Delisle <me@dvd.dev>"]
File without changes