From 079767eb03507e5a6c0452041e7aef9ad26a7922 Mon Sep 17 00:00:00 2001 From: Alexander Tihoniuk Date: Fri, 12 Jun 2026 18:15:13 +0300 Subject: [PATCH 1/3] ci(python-check): test against HA 2026.5/2026.6 on Python 3.14 The matrix still pinned HA 2024.2/2024.3 from upstream history, which the component no longer supports (DataUpdateCoordinator config_entry kwarg needs 2024.8+), so every commit failed CI regardless of its content. Test what the fork actually targets: 2026.5.4 (compat branch baseline) and latest 2026.6. Also bump checkout/setup-python actions off the deprecated node16 runtime. Co-Authored-By: Claude Fable 5 --- .github/workflows/python_check.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/python_check.yml b/.github/workflows/python_check.yml index 8438dcb..8d9ec37 100644 --- a/.github/workflows/python_check.yml +++ b/.github/workflows/python_check.yml @@ -14,19 +14,15 @@ jobs: fail-fast: false matrix: include: - - home-assistant: "2024.2.0" - python-version: "3.11" - - home-assistant: "2024.2.0" - python-version: "3.12" - - home-assistant: "2024.3.0" - python-version: "3.11" - - home-assistant: "2024.3.0" - python-version: "3.12" + - home-assistant: "2026.5.4" + python-version: "3.14" + - home-assistant: "2026.6.0" + python-version: "3.14" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 49ad6bb42fa47e14ccb1d09a256778d70581162b Mon Sep 17 00:00:00 2001 From: Alexander Tihoniuk Date: Fri, 12 Jun 2026 18:15:13 +0300 Subject: [PATCH 2/3] fix(types): satisfy mypy against HA 2026.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - config_flow: FlowResult → ConfigFlowResult (HA 2024.4+ flow typing) - climate: narrow _attr_hvac_mode before returning it from hvac_mode - binary_sensor: wrap is_on comparison in bool() (device.get returns Any) - drop now-unused voluptuous type: ignore comments (ships typed since 0.14) Co-Authored-By: Claude Fable 5 --- custom_components/hon/__init__.py | 2 +- custom_components/hon/binary_sensor.py | 5 ++-- custom_components/hon/climate.py | 35 ++++++++++++++++++-------- custom_components/hon/config_flow.py | 8 +++--- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/custom_components/hon/__init__.py b/custom_components/hon/__init__.py index 6c9b9fc..6c1e4cb 100644 --- a/custom_components/hon/__init__.py +++ b/custom_components/hon/__init__.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Any -import voluptuous as vol # type: ignore[import-untyped] +import voluptuous as vol from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_EMAIL, CONF_PASSWORD from homeassistant.helpers import config_validation as cv, aiohttp_client diff --git a/custom_components/hon/binary_sensor.py b/custom_components/hon/binary_sensor.py index fe8b6a4..f417709 100644 --- a/custom_components/hon/binary_sensor.py +++ b/custom_components/hon/binary_sensor.py @@ -428,13 +428,12 @@ class HonBinarySensorEntity(HonEntity, BinarySensorEntity): def is_on(self) -> bool: attr = self._device.get(self.entity_description.key, None) value = attr.value if hasattr(attr, "value") else attr - return value == self.entity_description.on_value - + return bool(value == self.entity_description.on_value) @callback def _handle_coordinator_update(self, update: bool = True) -> None: attr = self._device.get(self.entity_description.key, None) value = attr.value if hasattr(attr, "value") else attr - self._attr_native_value = (value == self.entity_description.on_value) + self._attr_native_value = value == self.entity_description.on_value if update: self.schedule_update_ha_state() diff --git a/custom_components/hon/climate.py b/custom_components/hon/climate.py index 16a44f2..e1b5682 100644 --- a/custom_components/hon/climate.py +++ b/custom_components/hon/climate.py @@ -188,11 +188,15 @@ async def async_set_temperature(self, **kwargs: Any) -> None: if "settings.machMode" in self._device.settings: current_mach = self._device.get("machMode") if current_mach is not None: - self._device.settings["settings.machMode"].value = str(int(current_mach)) + self._device.settings["settings.machMode"].value = str( + int(current_mach) + ) if "settings.onOffStatus" in self._device.settings: current_onoff = self._device.get("onOffStatus") if current_onoff is not None: - self._device.settings["settings.onOffStatus"].value = str(int(current_onoff)) + self._device.settings["settings.onOffStatus"].value = str( + int(current_onoff) + ) self._device.settings["settings.tempSel"].value = str(int(temperature)) await self._device.commands["settings"].send() @@ -211,12 +215,13 @@ def hvac_mode(self) -> HVACMode: mode = HON_HVAC_MODE[mach] - if mode == HVACMode.AUTO and getattr(self, "_attr_hvac_mode", None) not in ( - None, - HVACMode.OFF, - HVACMode.AUTO, + attr_mode: HVACMode | None = getattr(self, "_attr_hvac_mode", None) + if ( + mode == HVACMode.AUTO + and attr_mode is not None + and attr_mode not in (HVACMode.OFF, HVACMode.AUTO) ): - return self._attr_hvac_mode + return attr_mode return mode @@ -314,11 +319,15 @@ async def async_set_fan_mode(self, fan_mode: str) -> None: if "settings.machMode" in self._device.settings: current_mach = self._device.get("machMode") if current_mach is not None: - self._device.settings["settings.machMode"].value = str(int(current_mach)) + self._device.settings["settings.machMode"].value = str( + int(current_mach) + ) if "settings.onOffStatus" in self._device.settings: current_onoff = self._device.get("onOffStatus") if current_onoff is not None: - self._device.settings["settings.onOffStatus"].value = str(int(current_onoff)) + self._device.settings["settings.onOffStatus"].value = str( + int(current_onoff) + ) fan_modes: dict[str, str] = {} for mode in reversed(self._device.settings["settings.windSpeed"].values): @@ -345,11 +354,15 @@ async def async_set_swing_mode(self, swing_mode: str) -> None: if "settings.machMode" in self._device.settings: current_mach = self._device.get("machMode") if current_mach is not None: - self._device.settings["settings.machMode"].value = str(int(current_mach)) + self._device.settings["settings.machMode"].value = str( + int(current_mach) + ) if "settings.onOffStatus" in self._device.settings: current_onoff = self._device.get("onOffStatus") if current_onoff is not None: - self._device.settings["settings.onOffStatus"].value = str(int(current_onoff)) + self._device.settings["settings.onOffStatus"].value = str( + int(current_onoff) + ) horizontal = self._device.settings["settings.windDirectionHorizontal"] vertical = self._device.settings["settings.windDirectionVertical"] diff --git a/custom_components/hon/config_flow.py b/custom_components/hon/config_flow.py index cfaf8d7..d5ea36e 100644 --- a/custom_components/hon/config_flow.py +++ b/custom_components/hon/config_flow.py @@ -1,10 +1,10 @@ import logging from typing import Any -import voluptuous as vol # type: ignore[import-untyped] +import voluptuous as vol from homeassistant import config_entries +from homeassistant.config_entries import ConfigFlowResult from homeassistant.const import CONF_EMAIL, CONF_PASSWORD -from homeassistant.data_entry_flow import FlowResult from .const import DOMAIN @@ -21,7 +21,7 @@ def __init__(self) -> None: async def async_step_user( self, user_input: dict[str, Any] | None = None - ) -> FlowResult: + ) -> ConfigFlowResult: if user_input is None: return self.async_show_form( step_id="user", @@ -53,5 +53,5 @@ async def async_step_user( }, ) - async def async_step_import(self, user_input: dict[str, str]) -> FlowResult: + async def async_step_import(self, user_input: dict[str, str]) -> ConfigFlowResult: return await self.async_step_user(user_input) From 143d2a57af9aba612a30ffcb7ef783898f59a3a6 Mon Sep 17 00:00:00 2001 From: Alexander Tihoniuk Date: Fri, 12 Jun 2026 18:15:13 +0300 Subject: [PATCH 3/3] style: apply current black to button and check script Co-Authored-By: Claude Fable 5 --- custom_components/hon/button.py | 2 +- scripts/check.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/hon/button.py b/custom_components/hon/button.py index 8d99fbe..0fdafd2 100644 --- a/custom_components/hon/button.py +++ b/custom_components/hon/button.py @@ -103,7 +103,7 @@ async def async_press(self) -> None: persistent_notification.create( self._hass, f"````\n```\n{self._device.diagnose}\n```\n````", title ) - _LOGGER.info(self._device.diagnose.replace(" ", "\u200B ")) + _LOGGER.info(self._device.diagnose.replace(" ", "\u200b ")) class HonDataArchive(HonEntity, ButtonEntity): diff --git a/scripts/check.py b/scripts/check.py index 2045d71..bbd36e8 100755 --- a/scripts/check.py +++ b/scripts/check.py @@ -2,7 +2,6 @@ import sys from pathlib import Path - if __name__ == "__main__": sys.path.insert(0, str(Path(__file__).parent.parent))