Skip to content

Commit 55dab57

Browse files
authored
Merge pull request #841 from jfsimoneau/silence-flexd-reward
Update pre-commit hooks and fix flex d reward exception
2 parents 990066f + 316128f commit 55dab57

File tree

11 files changed

+163
-33
lines changed

11 files changed

+163
-33
lines changed

.github/workflows/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
pull_request:
99

1010
env:
11-
DEFAULT_PYTHON: 3.9
11+
DEFAULT_PYTHON: 3.13
1212

1313
jobs:
1414
pre-commit:

.pre-commit-config.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
repos:
33
- repo: https://github.com/PyCQA/bandit
4-
rev: '1.7.9'
4+
rev: '1.9.2'
55
hooks:
66
- id: bandit
77
args:
@@ -10,7 +10,7 @@ repos:
1010
- --configfile=.bandit.yaml
1111
files: ^custom_components/hilo/.+\.py$
1212
- repo: https://github.com/python/black
13-
rev: 22.3.0
13+
rev: 25.12.0
1414
hooks:
1515
- id: black
1616
args:
@@ -19,7 +19,7 @@ repos:
1919
language_version: python3
2020
files: ^custom_components/hilo/.+\.py$
2121
- repo: https://github.com/codespell-project/codespell
22-
rev: v1.16.0
22+
rev: v2.4.1
2323
hooks:
2424
- id: codespell
2525
args:
@@ -29,15 +29,15 @@ repos:
2929
- -L ba,hass,que,bord
3030
exclude_types: [json]
3131
- repo: https://github.com/PyCQA/flake8
32-
rev: 4.0.1
32+
rev: 7.3.0
3333
hooks:
3434
- id: flake8
3535
additional_dependencies:
3636
- flake8-docstrings==1.5.0
3737
- pydocstyle==5.0.1
3838
files: ^custom_components/hilo/.+\.py$
3939
- repo: https://github.com/pre-commit/mirrors-isort
40-
rev: v4.3.21
40+
rev: v5.10.1
4141
hooks:
4242
- id: isort
4343
additional_dependencies:
@@ -52,7 +52,7 @@ repos:
5252
# - types-python-dateutil==2.8.0
5353

5454
- repo: https://github.com/pre-commit/pre-commit-hooks
55-
rev: v2.4.0
55+
rev: v6.0.0
5656
hooks:
5757
- id: check-json
5858
# Exclude .devcontainer.json and .vscode since it uses JSONC
@@ -66,12 +66,12 @@ repos:
6666
# - id: pydocstyle
6767
# files: ^custom_components/hilo/.+\.py$
6868
- repo: https://github.com/gruntwork-io/pre-commit
69-
rev: v0.1.12
69+
rev: v0.1.30
7070
hooks:
7171
- id: shellcheck
7272
files: ^script/.+
7373
- repo: https://github.com/jorisroovers/gitlint
74-
rev: v0.17.0
74+
rev: v0.19.1
7575
hooks:
7676
- id: gitlint
7777
name: gitlint
@@ -80,7 +80,7 @@ repos:
8080
args: [--staged, --msg-filename]
8181
stages: [commit-msg]
8282
- repo: https://github.com/pre-commit/pre-commit-hooks
83-
rev: v4.1.0
83+
rev: v6.0.0
8484
hooks:
8585
- id: check-yaml
8686
- id: trailing-whitespace

custom_components/hilo/__init__.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
EVENT_HOMEASSISTANT_STOP,
2525
Platform,
2626
)
27-
from homeassistant.core import Context, Event, HomeAssistant, callback
27+
from homeassistant.core import Context, HomeAssistant, callback
2828
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
2929
from homeassistant.helpers import (
3030
config_entry_oauth2_flow,
@@ -114,8 +114,10 @@ def _async_standardize_config_entry(hass: HomeAssistant, entry: ConfigEntry) ->
114114
def _async_register_custom_device(
115115
hass: HomeAssistant, entry: ConfigEntry, device: HiloDevice
116116
) -> None:
117-
"""Register a custom device. This is used to register the
118-
Hilo gateway and the unknown source tracker."""
117+
"""Register a custom device.
118+
119+
This is used to register the Hilo gateway and the unknown source tracker.
120+
"""
119121
LOG.debug("Generating custom device %s", device)
120122
device_registry = dr.async_get(hass)
121123
device_registry.async_get_or_create(
@@ -196,12 +198,12 @@ async def handle_debug_event(event: Event):
196198

197199
async def async_reload_entry(_: HomeAssistant, updated_entry: ConfigEntry) -> None:
198200
"""Handle an options update.
201+
199202
This method will get called in two scenarios:
200203
1. When HiloOptionsFlowHandler is initiated
201204
2. When a new refresh token is saved to the config entry data
202205
We only want #1 to trigger an actual reload.
203206
"""
204-
nonlocal current_options
205207
updated_options = {**updated_entry.options}
206208
if updated_options == current_options:
207209
return
@@ -319,6 +321,7 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry, api: API) -> None:
319321
self._websocket_listeners = []
320322

321323
def validate_heartbeat(self, event: WebsocketEvent) -> None:
324+
"""Validate heartbeat messages from the websocket."""
322325
heartbeat_time = from_utc_timestamp(event.arguments[0]) # type: ignore
323326
if self._api.log_traces:
324327
LOG.debug("Heartbeat: %s", time_diff(heartbeat_time, event.timestamp))
@@ -519,15 +522,15 @@ async def on_websocket_event(self, event: WebsocketEvent) -> None:
519522

520523
@callback
521524
async def subscribe_to_location(self, inv_id: int) -> None:
522-
"""Sends the json payload to receive updates from the location."""
525+
"""Send the json payload to receive updates from the location."""
523526
LOG.debug("Subscribing to location %s", self.devices.location_id)
524527
await self._api.websocket_devices.async_invoke(
525528
[self.devices.location_id], "SubscribeToLocation", inv_id
526529
)
527530

528531
@callback
529532
async def subscribe_to_challenge(self, inv_id: int, event_id: int = 0) -> None:
530-
"""Sends the json payload to receive updates from the challenge."""
533+
"""Send the json payload to receive updates from the challenge."""
531534
LOG.debug("Subscribing to challenge : %s or %s", event_id, self.challenge_id)
532535
event_id = event_id or self.challenge_id
533536
LOG.debug("API URN is %s", self._api.urn)
@@ -571,7 +574,7 @@ async def subscribe_to_challenge(self, inv_id: int, event_id: int = 0) -> None:
571574

572575
@callback
573576
async def subscribe_to_challengelist(self, inv_id: int) -> None:
574-
"""Sends the json payload to receive updates from the challenge list."""
577+
"""Send the json payload to receive updates from the challenge list."""
575578
# TODO : Rename challegenge functions to Event, fallback on challenge for now
576579
LOG.debug(
577580
"Subscribing to challenge list at location %s", self.devices.location_id
@@ -595,7 +598,7 @@ async def subscribe_to_challengelist(self, inv_id: int) -> None:
595598
async def request_challenge_consumption_update(
596599
self, inv_id: int, event_id: int = 0
597600
) -> None:
598-
"""Sends the json payload to receive energy consumption updates from the challenge."""
601+
"""Send the json payload to receive energy consumption updates from the challenge."""
599602
event_id = event_id or self.challenge_id
600603

601604
# TODO: Remove fallback once split is complete
@@ -647,12 +650,14 @@ async def request_challenge_consumption_update(
647650

648651
@callback
649652
async def request_status_update(self) -> None:
653+
"""Request a status update from the device websocket."""
650654
await self._api.websocket_devices.send_status()
651655
for inv_id, inv_cb in self.invocations.items():
652656
await inv_cb(inv_id)
653657

654658
@callback
655659
async def request_status_update_challenge(self) -> None:
660+
"""Request a status update from the challenge websocket."""
656661
await self._api.websocket_challenges.send_status()
657662
for inv_id, inv_cb in self.invocations.items():
658663
await inv_cb(inv_id)
@@ -675,8 +680,8 @@ def _get_unknown_source_tracker(self) -> HiloDevice:
675680
}
676681

677682
async def get_event_details(self, event_id: int):
678-
"""Getting events from Hilo only when necessary.
679-
Otherwise, we hit the cache.
683+
"""Get events from Hilo only when necessary, otherwise, we hit the cache.
684+
680685
When preheat is started and our last update is before
681686
the preheat_start, we refresh. This should update the
682687
allowed_kWh, etc. values.
@@ -819,6 +824,7 @@ async def start_websocket_loop(self, websocket, id) -> None:
819824
)
820825

821826
async def cancel_task(self, task) -> None:
827+
"""Cancel a task."""
822828
LOG.debug("Cancelling task %s", task)
823829
if task:
824830
task.cancel()
@@ -843,7 +849,8 @@ async def cancel_websocket_loop(self, websocket, id) -> None:
843849
def should_websocket_reconnect(self) -> bool:
844850
"""Determine if a websocket should reconnect when the connection is lost.
845851
846-
Currently only used to disable websockets in the unit tests."""
852+
Currently only used to disable websockets in the unit tests.
853+
"""
847854
return self._should_websocket_reconnect
848855

849856
@should_websocket_reconnect.setter
@@ -852,14 +859,15 @@ def should_websocket_reconnect(self, value: bool) -> None:
852859
self._should_websocket_reconnect = value
853860

854861
async def async_update(self) -> None:
855-
"""Updates tarif periodically."""
862+
"""Update tarif periodically."""
856863
if self.generate_energy_meters or self.track_unknown_sources:
857864
self.check_tarif()
858865

859866
if self.track_unknown_sources:
860867
self.handle_unknown_power()
861868

862869
def find_meter(self, hass):
870+
"""Find the smart meter entity in Home Assistant."""
863871
entity_registry_dict = {}
864872

865873
registry = hass.data.get("entity_registry")
@@ -892,6 +900,7 @@ def find_meter(self, hass):
892900
return ", ".join(filtered_names) if filtered_names else ""
893901

894902
def set_state(self, entity, state, new_attrs={}, keep_state=False, force=False):
903+
"""Set the state of an entity."""
895904
params = f"{entity=} {state=} {new_attrs=} {keep_state=}"
896905
current = self._hass.states.get(entity)
897906
if not current:
@@ -913,20 +922,21 @@ def set_state(self, entity, state, new_attrs={}, keep_state=False, force=False):
913922

914923
@property
915924
def high_times(self):
925+
"""Check if the current time is within high tariff periods."""
916926
challenge_sensor = self._hass.states.get("sensor.defi_hilo")
917927
LOG.debug(
918928
"high_times check tarif challenge sensor is %s", challenge_sensor.state
919929
)
920930
return challenge_sensor.state == "reduction"
921931

922932
def check_season(self):
923-
"""This logic determines if we are using a winter or summer rate"""
933+
"""Determine if we are using a winter or summer rate."""
924934
current_month = datetime.now().month
925935
LOG.debug("check_season current month is %s", current_month)
926936
return current_month in [12, 1, 2, 3]
927937

928938
def check_tarif(self):
929-
"""Logic to determine which tarif to select depending on season and user-selected rate"""
939+
"""Determine which tarif to select depending on season and user-selected rate."""
930940
if self.generate_energy_meters:
931941
season = self.check_season()
932942
LOG.debug("check_tarif current season state is %s", season)
@@ -989,7 +999,7 @@ def check_tarif(self):
989999
self.set_tarif(entity, state.state, tarif)
9901000

9911001
def handle_unknown_power(self):
992-
"""Function that takes care of the unknown source meter"""
1002+
"""Take care of the unknown source meter."""
9931003
known_power = 0
9941004
smart_meter = self.find_meter(self._hass)
9951005
LOG.debug("Smart meter used currently is: %s", smart_meter)
@@ -1044,7 +1054,7 @@ def handle_unknown_power(self):
10441054

10451055
@callback
10461056
def fix_utility_sensor(self, entity, state):
1047-
"""not sure why this doesn't get created with a proper device_class"""
1057+
"""Not sure why this doesn't get created with a proper device_class."""
10481058
current_state = state.as_dict()
10491059
attrs = current_state.get("attributes", {})
10501060
if entity.startswith("select.") or entity.find("hilo_rate") > 0:
@@ -1075,6 +1085,7 @@ def fix_utility_sensor(self, entity, state):
10751085

10761086
@callback
10771087
def set_tarif(self, entity, current, new):
1088+
"""Set the tarif on the select entity if needed."""
10781089
if self.untarificated_devices and entity != f"select.{HILO_ENERGY_TOTAL}":
10791090
return
10801091
if entity.startswith("select.hilo_energy") and current != new:
@@ -1149,4 +1160,5 @@ def async_migrate_unique_id(
11491160

11501161
@callback
11511162
def handle_subscription_result(self, hilo_id: str) -> None:
1163+
"""Handle subscription result by notifying entities."""
11521164
async_dispatcher_send(self._hass, SIGNAL_UPDATE_ENTITY.format(hilo_id))

custom_components/hilo/climate.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Support for Hilo Climate entities."""
2+
13
from datetime import datetime, timedelta
24

35
from homeassistant.components.climate import ClimateEntity
@@ -23,6 +25,7 @@
2325

2426

2527
def validate_reduction_phase(events, tag):
28+
"""Validate if current time is within a challenge lock reduction phase."""
2629
if not events:
2730
return
2831
current = events[0]
@@ -44,6 +47,7 @@ def validate_reduction_phase(events, tag):
4447
async def async_setup_entry(
4548
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
4649
) -> None:
50+
"""Set up Hilo climate entities from a config entry."""
4751
hilo = hass.data[DOMAIN][entry.entry_id]
4852
entities = []
4953
for d in hilo.devices.all:
@@ -55,12 +59,15 @@ async def async_setup_entry(
5559

5660

5761
class HiloClimate(HiloEntity, ClimateEntity):
62+
"""Representation of a Hilo Climate entity."""
63+
5864
_attr_hvac_modes = [HVACMode.HEAT]
5965
_attr_temperature_unit: str = UnitOfTemperature.CELSIUS
6066
_attr_precision: float = PRECISION_TENTHS
6167
_attr_supported_features: int = ClimateEntityFeature.TARGET_TEMPERATURE
6268

6369
def __init__(self, hilo: Hilo, device):
70+
"""Initialize the climate entity."""
6471
super().__init__(hilo, device=device, name=device.name)
6572
old_unique_id = f"{slugify(device.name)}-climate"
6673
self._attr_unique_id = f"{slugify(device.identifier)}-climate"
@@ -74,38 +81,47 @@ def __init__(self, hilo: Hilo, device):
7481

7582
@property
7683
def current_temperature(self):
84+
"""Return the current temperature."""
7785
return self._device.current_temperature
7886

7987
@property
8088
def target_temperature(self):
89+
"""Return the target temperature."""
8190
return self._device.target_temperature
8291

8392
@property
8493
def max_temp(self):
94+
"""Return the maximum temperature."""
8595
return self._device.max_temp
8696

8797
@property
8898
def min_temp(self):
99+
"""Return the minimum temperature."""
89100
return self._device.min_temp
90101

91102
def set_hvac_mode(self, hvac_mode):
103+
"""Set hvac mode."""
92104
return
93105

94106
@property
95107
def hvac_mode(self):
108+
"""Return hvac mode."""
96109
return HVACMode.HEAT
97110

98111
@property
99112
def hvac_action(self):
113+
"""Return the current hvac action."""
100114
return self._device.hvac_action
101115

102116
@property
103117
def icon(self):
118+
"""Return the icon to use in the frontend, based on hvac_action."""
104119
if self._device.hvac_action == HVACAction.HEATING:
105120
return "mdi:radiator"
106121
return "mdi:radiator-disabled"
107122

108123
async def async_set_temperature(self, **kwargs):
124+
"""Set new target temperature."""
109125
if ATTR_TEMPERATURE in kwargs:
110126
if self._hilo.challenge_lock:
111127
challenge = self._hilo._hass.states.get("sensor.defi_hilo")

custom_components/hilo/config_flow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class HiloOptionsFlowHandler(config_entries.OptionsFlow):
154154
"""Handle a Hilo options flow."""
155155

156156
def __init__(self, config_entry: ConfigEntry) -> None:
157-
"""Initialize"""
157+
"""Initialize."""
158158
if AwesomeVersion(HAVERSION) < "2024.11.99":
159159
self.config_entry = config_entry
160160
else:

custom_components/hilo/const.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Hilo integration constants."""
2+
13
import logging
24

35
from homeassistant.components.utility_meter.const import DAILY

0 commit comments

Comments
 (0)