Skip to content

Commit bdb0489

Browse files
authored
Merge pull request #825 from dvd-dev/split_CH_Flex
Séparation Crédit Hivernal et Flex D avec leur messages websocket associés. Ajout fonction debug websocket.
2 parents 84cbb14 + 410c25a commit bdb0489

3 files changed

Lines changed: 137 additions & 32 deletions

File tree

custom_components/hilo/__init__.py

Lines changed: 118 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
)
4848
from pyhilo.graphql import GraphQlHelper
4949
from pyhilo.util import from_utc_timestamp, time_diff
50-
from pyhilo.websocket import WebsocketEvent
50+
from pyhilo.websocket import WebsocketEvent, websocket_event_from_payload
5151

5252
from .config_flow import STEP_OPTION_SCHEMA, HiloFlowHandler
5353
from .const import (
@@ -180,6 +180,20 @@ async def async_setup_entry( # noqa: C901
180180
hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
181181
)
182182

183+
async def handle_debug_event(event: Event):
184+
"""Handle an event."""
185+
LOG.debug("HILO_DEBUG: Event received: %s", event)
186+
log_traces = current_options.get(CONF_LOG_TRACES)
187+
LOG.debug("HILO_DEBUG: log_traces is %s", log_traces)
188+
websocket_event = websocket_event_from_payload(event.data)
189+
LOG.debug("HILO_DEBUG: Websocket event parsed: %s", websocket_event)
190+
await hilo.on_websocket_event(websocket_event)
191+
192+
log_traces = current_options.get(CONF_LOG_TRACES)
193+
if log_traces:
194+
LOG.debug("HILO_DEBUG: log_traces is %s", log_traces)
195+
hass.bus.async_listen("hilo_debug", handle_debug_event)
196+
183197
async def async_reload_entry(_: HomeAssistant, updated_entry: ConfigEntry) -> None:
184198
"""Handle an options update.
185199
This method will get called in two scenarios:
@@ -317,36 +331,48 @@ def register_websocket_listener(self, listener):
317331
async def _handle_websocket_message(self, event):
318332
"""Process websocket messages and notify listeners."""
319333

334+
# TODO: ic-dev21: This needs to be cleaned up and optimized
320335
LOG.debug("Received websocket message type: %s", event)
321336
target = event.target
322337
LOG.debug("handle_websocket_message_target %s", target)
323338
msg_data = event
324339
LOG.debug("handle_websocket_message_ msg_data %s", msg_data)
325340

326-
if target == "ChallengeListInitialValuesReceived":
341+
if target in [
342+
"ChallengeListInitialValuesReceived",
343+
"EventListInitialValuesReceived",
344+
]:
327345
msg_type = "challenge_list_initial"
328-
elif target == "ChallengeAdded":
346+
elif target in ["ChallengeAdded", "EventAdded"]:
329347
msg_type = "challenge_added"
330348
elif target == "ChallengeDetailsUpdated":
331349
msg_type = "challenge_details_update"
332350
elif target == "ChallengeConsumptionUpdatedValuesReceived":
333351
msg_type = "challenge_details_update"
334-
elif target == "ChallengeDetailsUpdatedValuesReceived":
352+
elif target in [
353+
"ChallengeDetailsUpdatedValuesReceived",
354+
"EventCHDetailsUpdatedValuesReceived",
355+
"EventFlexDetailsUpdatedValuesReceived",
356+
]:
335357
msg_type = "challenge_details_update"
336-
elif target == "ChallengeDetailsInitialValuesReceived":
358+
elif target in [
359+
"ChallengeDetailsInitialValuesReceived",
360+
"EventCHDetailsInitialValuesReceived",
361+
"EventFlexDetailsInitialValuesReceived",
362+
]:
337363
msg_type = "challenge_details_update"
338-
elif target == "ChallengeListUpdatedValuesReceived":
364+
elif target in [
365+
"ChallengeListUpdatedValuesReceived",
366+
"EventListUpdatedValuesReceived",
367+
]:
339368
msg_type = "challenge_details_update"
340-
elif target == "EventCHConsumptionUpdatedValuesReceived":
369+
elif target in [
370+
"EventCHConsumptionUpdatedValuesReceived",
371+
"EventFlexConsumptionUpdatedValuesReceived",
372+
]:
341373
LOG.debug("%s message received", target)
342374
LOG.debug("%s data: %s", target, msg_data)
343375
return
344-
elif target == "EventCHDetailsUpdatedValuesReceived":
345-
msg_type = "challenge_details_update"
346-
elif target == "EventFlexDetailsUpdatedValuesReceived":
347-
msg_type = "challenge_details_update"
348-
elif target == "EventListUpdatedValuesReceived":
349-
msg_type = "challenge_details_update"
350376

351377
# ic-dev21 Notify listeners
352378
for listener in self._websocket_listeners:
@@ -478,13 +504,11 @@ async def on_websocket_event(self, event: WebsocketEvent) -> None:
478504
elif event.target == "Heartbeat":
479505
self.validate_heartbeat(event)
480506

481-
elif "Challenge" in event.target:
507+
elif "Challenge" in event.target or "Event" in event.target:
508+
LOG.debug("HILO_DEBUG: Handling challenge/event websocket event: %s", event)
482509
await self._handle_challenge_events(event)
483510
await self._handle_websocket_message(event)
484511

485-
elif "Event" in event.target:
486-
await self._handle_websocket_message(event)
487-
488512
elif "Device" in event.target or event.target == "GatewayValuesReceived":
489513
await self._handle_device_events(event)
490514

@@ -504,36 +528,72 @@ async def subscribe_to_challenge(self, inv_id: int, event_id: int = 0) -> None:
504528
"""Sends the json payload to receive updates from the challenge."""
505529
LOG.debug("Subscribing to challenge : %s or %s", event_id, self.challenge_id)
506530
event_id = event_id or self.challenge_id
507-
508-
LOG.debug(
509-
"Subscribing to challenge %s at location %s",
510-
event_id,
511-
self.devices.location_id,
512-
)
531+
LOG.debug("API URN is %s", self._api.urn)
532+
# Get plan name to connect to the correct challenge hub list
533+
tarif_config = self.hq_plan_name
534+
LOG.debug("Event list needed is %s", tarif_config)
535+
536+
# TODO: This is a fallback but will eventually need to be removed, I expect it to create
537+
# websocket disconnects once the split is complete.
538+
LOG.warning("Not using plan name %s, falling back to default", tarif_config)
513539
await self._api.websocket_challenges.async_invoke(
514540
[{"locationId": self.devices.location_id, "eventId": event_id}],
515541
"SubscribeToChallenge",
516542
inv_id,
517543
)
518544

545+
# Subscribe to the correct challenge hub
546+
if tarif_config == "rate d":
547+
await self._api.websocket_challenges.async_invoke(
548+
[{"locationHiloId": self._api.urn, "eventId": event_id}],
549+
"SubscribeToEventCH",
550+
inv_id,
551+
)
552+
553+
elif tarif_config == "flex d":
554+
await self._api.websocket_challenges.async_invoke(
555+
[{"locationHiloId": self._api.urn, "eventId": event_id}],
556+
"SubscribeToEventFlex",
557+
inv_id,
558+
)
559+
else:
560+
LOG.warning("Unknown plan name %s, falling back to default", tarif_config)
561+
await self._api.websocket_challenges.async_invoke(
562+
[{"locationId": self.devices.location_id, "eventId": event_id}],
563+
"SubscribeToChallenge",
564+
inv_id,
565+
)
566+
519567
@callback
520568
async def subscribe_to_challengelist(self, inv_id: int) -> None:
521569
"""Sends the json payload to receive updates from the challenge list."""
570+
# TODO : Rename challegenge functions to Event, fallback on challenge for now
522571
LOG.debug(
523572
"Subscribing to challenge list at location %s", self.devices.location_id
524573
)
574+
LOG.debug("API URN is %s", self._api.urn)
575+
525576
await self._api.websocket_challenges.async_invoke(
526577
[{"locationId": self.devices.location_id}],
527578
"SubscribeToChallengeList",
528579
inv_id,
529580
)
530581

582+
LOG.debug("Subscribing to event list at location %s", self.devices.location_id)
583+
await self._api.websocket_challenges.async_invoke(
584+
[{"locationHiloId": self._api.urn}],
585+
"SubscribeToEventList",
586+
inv_id,
587+
)
588+
531589
@callback
532590
async def request_challenge_consumption_update(
533591
self, inv_id: int, event_id: int = 0
534592
) -> None:
535593
"""Sends the json payload to receive energy consumption updates from the challenge."""
536594
event_id = event_id or self.challenge_id
595+
596+
# TODO: Remove fallback once split is complete
537597
LOG.debug(
538598
"Requesting challenge %s consumption update at location %s",
539599
event_id,
@@ -545,6 +605,41 @@ async def request_challenge_consumption_update(
545605
inv_id,
546606
)
547607

608+
# Get plan name to request the correct consumption update
609+
tarif_config = self.hq_plan_name
610+
LOG.debug("API URN is %s", self._api.urn)
611+
if tarif_config == "rate d":
612+
LOG.debug(
613+
"Requesting event CH consumption update at location %s",
614+
self.devices.location_id,
615+
)
616+
await self._api.websocket_challenges.async_invoke(
617+
[{"locationHiloId": self._api.urn, "eventId": event_id}],
618+
"RequestEventCHConsumptionUpdate",
619+
inv_id,
620+
)
621+
elif tarif_config == "flex d":
622+
LOG.debug(
623+
"Requesting event Flex consumption update at location %s",
624+
self.devices.location_id,
625+
)
626+
await self._api.websocket_challenges.async_invoke(
627+
[{"locationHiloId": self._api.urn, "eventId": event_id}],
628+
"RequestEventFlexConsumptionUpdate",
629+
inv_id,
630+
)
631+
else:
632+
LOG.debug(
633+
"Requesting challenge %s consumption update at location %s",
634+
event_id,
635+
self.devices.location_id,
636+
)
637+
await self._api.websocket_challenges.async_invoke(
638+
[{"locationId": self.devices.location_id, "eventId": event_id}],
639+
"RequestChallengeConsumptionUpdate",
640+
inv_id,
641+
)
642+
548643
@callback
549644
async def request_status_update(self) -> None:
550645
await self._api.websocket_devices.send_status()

custom_components/hilo/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
"documentation": "https://github.com/dvd-dev/hilo",
1212
"iot_class": "cloud_push",
1313
"issue_tracker": "https://github.com/dvd-dev/hilo/issues",
14-
"requirements": ["python-hilo>=2025.12.3"],
15-
"version": "2025.12.4"
14+
"requirements": ["python-hilo>=2025.12.5"],
15+
"version": "2025.12.5"
1616
}

custom_components/hilo/sensor.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,8 @@ def process_wifi(strength: int) -> str:
9292

9393

9494
def validate_tariff_list(tariff_config):
95-
tariff_list = TARIFF_LIST
96-
for tariff in TARIFF_LIST:
97-
if not tariff_config.get(tariff, 0):
98-
tariff_list.remove(tariff)
99-
return tariff_list
95+
"""Validate the tariff list from the configuration."""
96+
return TARIFF_LIST
10097

10198

10299
def generate_entities_from_device(device, hilo, scan_interval):
@@ -717,6 +714,17 @@ async def handle_challenge_details_update(self, challenge):
717714
async def _async_update(self):
718715
seasons = await self._hilo._api.get_seasons(self._hilo.devices.location_id)
719716
self._events_to_poll = dict()
717+
seasons = sorted(seasons, key=lambda x: x["season"], reverse=True)
718+
719+
# Re-add the totalReward that was present in the legacy API
720+
for season_data in seasons:
721+
total = sum(
722+
event["reward"]
723+
for event in season_data["events"]
724+
if not event.get("isPreseasonEvent")
725+
)
726+
season_data["totalReward"] = total
727+
720728
if seasons:
721729
current_history = await self._load_history()
722730
new_history = []
@@ -950,6 +958,8 @@ async def handle_challenge_details_update(self, challenge):
950958
elif used_wH is not None and used_wH > 0:
951959
current_event = self._events[event_id]
952960
current_event.update_wh(used_wH)
961+
if baselinewH > 0:
962+
current_event.update_allowed_wh(baselinewH)
953963
# For non consumption updates, we need an event id
954964
elif event_has_id:
955965
current_event = self._events[event_id]
@@ -1005,7 +1015,7 @@ def icon(self):
10051015
@property
10061016
def should_poll(self):
10071017
"""No need to poll with websockets. Polling to update allowed_wh in pre_heat phrase and consumption in reduction phase"""
1008-
return self.state in ["reduction", "pre_heat"]
1018+
return self.state in ["recovery", "reduction", "pre_heat"]
10091019

10101020
@property
10111021
def extra_state_attributes(self):
@@ -1022,7 +1032,7 @@ async def _async_update(self):
10221032
if event.should_check_for_allowed_wh():
10231033
LOG.debug("ASYNC UPDATE SUB: EVENT: %s", event_id)
10241034
await self._hilo.subscribe_to_challenge(1, event_id)
1025-
await self._hilo.request_challenge_details_update(1, event_id)
1035+
await self._hilo.request_challenge_consumption_update(1, event_id)
10261036
elif self.state == "reduction":
10271037
LOG.debug("ASYNC UPDATE: EVENT: %s", event_id)
10281038
await self._hilo.request_challenge_consumption_update(1, event_id)

0 commit comments

Comments
 (0)