diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index a3af9f863ea..9e0659048b0 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -20,5 +20,5 @@ "documentation": "https://www.home-assistant.io/integrations/frontend", "integration_type": "system", "quality_scale": "internal", - "requirements": ["home-assistant-frontend==20230411.0"] + "requirements": ["home-assistant-frontend==20230411.1"] } diff --git a/homeassistant/components/homewizard/button.py b/homeassistant/components/homewizard/button.py index 6a245a00420..665406499e1 100644 --- a/homeassistant/components/homewizard/button.py +++ b/homeassistant/components/homewizard/button.py @@ -1,4 +1,5 @@ """Support for HomeWizard buttons.""" + from homeassistant.components.button import ButtonEntity from homeassistant.config_entries import ConfigEntry from homeassistant.const import EntityCategory @@ -16,7 +17,7 @@ async def async_setup_entry( ) -> None: """Set up the Identify button.""" coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] - if coordinator.data.features.has_identify: + if coordinator.supports_identify(): async_add_entities([HomeWizardIdentifyButton(coordinator, entry)]) diff --git a/homeassistant/components/homewizard/const.py b/homeassistant/components/homewizard/const.py index 34c83626f86..ff065592283 100644 --- a/homeassistant/components/homewizard/const.py +++ b/homeassistant/components/homewizard/const.py @@ -4,7 +4,6 @@ from __future__ import annotations from dataclasses import dataclass from datetime import timedelta -from homewizard_energy.features import Features from homewizard_energy.models import Data, Device, State, System from homeassistant.const import Platform @@ -30,6 +29,5 @@ class DeviceResponseEntry: device: Device data: Data - features: Features - state: State | None + state: State | None = None system: System | None = None diff --git a/homeassistant/components/homewizard/coordinator.py b/homeassistant/components/homewizard/coordinator.py index 2da618eeb27..533af445c84 100644 --- a/homeassistant/components/homewizard/coordinator.py +++ b/homeassistant/components/homewizard/coordinator.py @@ -4,7 +4,9 @@ from __future__ import annotations import logging from homewizard_energy import HomeWizardEnergy +from homewizard_energy.const import SUPPORTS_IDENTIFY, SUPPORTS_STATE, SUPPORTS_SYSTEM from homewizard_energy.errors import DisabledError, RequestError +from homewizard_energy.models import Device from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -39,11 +41,12 @@ class HWEnergyDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceResponseEntry] data = DeviceResponseEntry( device=await self.api.device(), data=await self.api.data(), - features=await self.api.features(), - state=await self.api.state(), ) - if data.features.has_system: + if self.supports_state(data.device): + data.state = await self.api.state() + + if self.supports_system(data.device): data.system = await self.api.system() except RequestError as ex: @@ -61,4 +64,27 @@ class HWEnergyDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceResponseEntry] self.api_disabled = False + self.data = data return data + + def supports_state(self, device: Device | None = None) -> bool: + """Return True if the device supports state.""" + + if device is None: + device = self.data.device + + return device.product_type in SUPPORTS_STATE + + def supports_system(self, device: Device | None = None) -> bool: + """Return True if the device supports system.""" + if device is None: + device = self.data.device + + return device.product_type in SUPPORTS_SYSTEM + + def supports_identify(self, device: Device | None = None) -> bool: + """Return True if the device supports identify.""" + if device is None: + device = self.data.device + + return device.product_type in SUPPORTS_IDENTIFY diff --git a/homeassistant/components/homewizard/manifest.json b/homeassistant/components/homewizard/manifest.json index e05b34dbcd6..b1bbd8d0945 100644 --- a/homeassistant/components/homewizard/manifest.json +++ b/homeassistant/components/homewizard/manifest.json @@ -8,6 +8,6 @@ "iot_class": "local_polling", "loggers": ["homewizard_energy"], "quality_scale": "platinum", - "requirements": ["python-homewizard-energy==1.8.0"], + "requirements": ["python-homewizard-energy==2.0.1"], "zeroconf": ["_hwenergy._tcp.local."] } diff --git a/homeassistant/components/homewizard/number.py b/homeassistant/components/homewizard/number.py index 8d00234f976..0451aed9739 100644 --- a/homeassistant/components/homewizard/number.py +++ b/homeassistant/components/homewizard/number.py @@ -20,7 +20,7 @@ async def async_setup_entry( ) -> None: """Set up numbers for device.""" coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] - if coordinator.data.state: + if coordinator.supports_state(): async_add_entities([HWEnergyNumberEntity(coordinator, entry)]) diff --git a/homeassistant/components/homewizard/switch.py b/homeassistant/components/homewizard/switch.py index f6a9ed2b05f..1edb9e1e605 100644 --- a/homeassistant/components/homewizard/switch.py +++ b/homeassistant/components/homewizard/switch.py @@ -27,7 +27,7 @@ from .helpers import homewizard_exception_handler class HomeWizardEntityDescriptionMixin: """Mixin values for HomeWizard entities.""" - create_fn: Callable[[DeviceResponseEntry], bool] + create_fn: Callable[[HWEnergyDeviceUpdateCoordinator], bool] available_fn: Callable[[DeviceResponseEntry], bool] is_on_fn: Callable[[DeviceResponseEntry], bool | None] set_fn: Callable[[HomeWizardEnergy, bool], Awaitable[Any]] @@ -46,7 +46,7 @@ SWITCHES = [ HomeWizardSwitchEntityDescription( key="power_on", device_class=SwitchDeviceClass.OUTLET, - create_fn=lambda data: data.state is not None, + create_fn=lambda coordinator: coordinator.supports_state(), available_fn=lambda data: data.state is not None and not data.state.switch_lock, is_on_fn=lambda data: data.state.power_on if data.state else None, set_fn=lambda api, active: api.state_set(power_on=active), @@ -57,7 +57,7 @@ SWITCHES = [ entity_category=EntityCategory.CONFIG, icon="mdi:lock", icon_off="mdi:lock-open", - create_fn=lambda data: data.state is not None, + create_fn=lambda coordinator: coordinator.supports_state(), available_fn=lambda data: data.state is not None, is_on_fn=lambda data: data.state.switch_lock if data.state else None, set_fn=lambda api, active: api.state_set(switch_lock=active), @@ -68,7 +68,7 @@ SWITCHES = [ entity_category=EntityCategory.CONFIG, icon="mdi:cloud", icon_off="mdi:cloud-off-outline", - create_fn=lambda data: data.system is not None, + create_fn=lambda coordinator: coordinator.supports_system(), available_fn=lambda data: data.system is not None, is_on_fn=lambda data: data.system.cloud_enabled if data.system else None, set_fn=lambda api, active: api.system_set(cloud_enabled=active), @@ -91,7 +91,7 @@ async def async_setup_entry( entry=entry, ) for description in SWITCHES - if description.available_fn(coordinator.data) + if description.create_fn(coordinator) ) diff --git a/homeassistant/components/lifx/manifest.json b/homeassistant/components/lifx/manifest.json index 65f4e7ecefa..7f715a0d49b 100644 --- a/homeassistant/components/lifx/manifest.json +++ b/homeassistant/components/lifx/manifest.json @@ -41,7 +41,7 @@ "loggers": ["aiolifx", "aiolifx_effects", "bitstring"], "quality_scale": "platinum", "requirements": [ - "aiolifx==0.8.9", + "aiolifx==0.8.10", "aiolifx_effects==0.3.2", "aiolifx_themes==0.4.5" ] diff --git a/homeassistant/const.py b/homeassistant/const.py index 1944bf7e998..845445d6b07 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -8,7 +8,7 @@ from .backports.enum import StrEnum APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2023 MINOR_VERSION: Final = 4 -PATCH_VERSION: Final = "3" +PATCH_VERSION: Final = "4" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 10, 0) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 24732608eee..63564979ae3 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -25,7 +25,7 @@ ha-av==10.0.0 hass-nabucasa==0.63.1 hassil==1.0.6 home-assistant-bluetooth==1.9.3 -home-assistant-frontend==20230411.0 +home-assistant-frontend==20230411.1 home-assistant-intents==2023.3.29 httpx==0.23.3 ifaddr==0.1.7 diff --git a/pyproject.toml b/pyproject.toml index 7226e594c83..ea02d089a30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2023.4.3" +version = "2023.4.4" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst" diff --git a/requirements_all.txt b/requirements_all.txt index a91461b180b..9c2fa18abdf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -193,7 +193,7 @@ aiokafka==0.7.2 aiokef==0.2.16 # homeassistant.components.lifx -aiolifx==0.8.9 +aiolifx==0.8.10 # homeassistant.components.lifx aiolifx_effects==0.3.2 @@ -907,7 +907,7 @@ hole==0.8.0 holidays==0.21.13 # homeassistant.components.frontend -home-assistant-frontend==20230411.0 +home-assistant-frontend==20230411.1 # homeassistant.components.conversation home-assistant-intents==2023.3.29 @@ -2054,7 +2054,7 @@ python-gc100==1.0.3a0 python-gitlab==1.6.0 # homeassistant.components.homewizard -python-homewizard-energy==1.8.0 +python-homewizard-energy==2.0.1 # homeassistant.components.hp_ilo python-hpilo==4.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 740086d187f..914f5a37256 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -177,7 +177,7 @@ aioimaplib==1.0.1 aiokafka==0.7.2 # homeassistant.components.lifx -aiolifx==0.8.9 +aiolifx==0.8.10 # homeassistant.components.lifx aiolifx_effects==0.3.2 @@ -693,7 +693,7 @@ hole==0.8.0 holidays==0.21.13 # homeassistant.components.frontend -home-assistant-frontend==20230411.0 +home-assistant-frontend==20230411.1 # homeassistant.components.conversation home-assistant-intents==2023.3.29 @@ -1477,7 +1477,7 @@ python-ecobee-api==0.2.14 python-fullykiosk==0.0.12 # homeassistant.components.homewizard -python-homewizard-energy==1.8.0 +python-homewizard-energy==2.0.1 # homeassistant.components.izone python-izone==1.2.9 diff --git a/tests/components/homewizard/conftest.py b/tests/components/homewizard/conftest.py index b1bfb1190dc..4cfec96cb8f 100644 --- a/tests/components/homewizard/conftest.py +++ b/tests/components/homewizard/conftest.py @@ -3,7 +3,6 @@ from collections.abc import Generator import json from unittest.mock import AsyncMock, MagicMock, patch -from homewizard_energy.features import Features from homewizard_energy.models import Data, Device, State, System import pytest @@ -44,7 +43,6 @@ def mock_homewizardenergy(): "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", ) as device: client = device.return_value - client.features = AsyncMock(return_value=Features("HWE-SKT", "3.01")) client.device = AsyncMock( side_effect=lambda: Device.from_dict( json.loads(load_fixture("homewizard/device.json")) diff --git a/tests/components/homewizard/fixtures/device.json b/tests/components/homewizard/fixtures/device.json index 493daa12b94..2e5be55c68e 100644 --- a/tests/components/homewizard/fixtures/device.json +++ b/tests/components/homewizard/fixtures/device.json @@ -1,5 +1,5 @@ { - "product_type": "HWE-P1", + "product_type": "HWE-SKT", "product_name": "P1 Meter", "serial": "3c39e7aabbcc", "firmware_version": "2.11", diff --git a/tests/components/homewizard/generator.py b/tests/components/homewizard/generator.py index f9bdea74fb4..6eb945334fd 100644 --- a/tests/components/homewizard/generator.py +++ b/tests/components/homewizard/generator.py @@ -2,7 +2,6 @@ from unittest.mock import AsyncMock -from homewizard_energy.features import Features from homewizard_energy.models import Data, Device @@ -29,9 +28,6 @@ def get_mock_device( mock_device.data = AsyncMock(return_value=Data.from_dict({})) mock_device.state = AsyncMock(return_value=None) mock_device.system = AsyncMock(return_value=None) - mock_device.features = AsyncMock( - return_value=Features(product_type, firmware_version) - ) mock_device.close = AsyncMock() diff --git a/tests/components/homewizard/test_button.py b/tests/components/homewizard/test_button.py index bc6584e903b..d8b8b5030b6 100644 --- a/tests/components/homewizard/test_button.py +++ b/tests/components/homewizard/test_button.py @@ -18,7 +18,7 @@ async def test_identify_button_entity_not_loaded_when_not_available( ) -> None: """Does not load button when device has no support for it.""" - api = get_mock_device(product_type="HWE-P1") + api = get_mock_device(product_type="SDM230-WIFI") with patch( "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", diff --git a/tests/components/homewizard/test_diagnostics.py b/tests/components/homewizard/test_diagnostics.py index df5f5576158..64e8b0c6dfd 100644 --- a/tests/components/homewizard/test_diagnostics.py +++ b/tests/components/homewizard/test_diagnostics.py @@ -21,7 +21,7 @@ async def test_diagnostics( "data": { "device": { "product_name": "P1 Meter", - "product_type": "HWE-P1", + "product_type": "HWE-SKT", "serial": REDACTED, "api_version": "v1", "firmware_version": "2.11", diff --git a/tests/components/homewizard/test_number.py b/tests/components/homewizard/test_number.py index f78a9cdbab5..aa4ab01cfc6 100644 --- a/tests/components/homewizard/test_number.py +++ b/tests/components/homewizard/test_number.py @@ -44,7 +44,7 @@ async def test_number_loads_entities( ) -> None: """Test entity does load number when brightness is available.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock(return_value=State.from_dict({"brightness": 255})) with patch( @@ -81,7 +81,7 @@ async def test_brightness_level_set( ) -> None: """Test entity turns sets light level.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock(return_value=State.from_dict({"brightness": 255})) def state_set(brightness): @@ -157,7 +157,7 @@ async def test_brightness_level_set_catches_requesterror( ) -> None: """Test entity raises HomeAssistantError when RequestError was raised.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock(return_value=State.from_dict({"brightness": 255})) api.state_set = AsyncMock(side_effect=RequestError()) @@ -193,7 +193,7 @@ async def test_brightness_level_set_catches_disablederror( ) -> None: """Test entity raises HomeAssistantError when DisabledError was raised.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock(return_value=State.from_dict({"brightness": 255})) api.state_set = AsyncMock(side_effect=DisabledError()) @@ -229,7 +229,7 @@ async def test_brightness_level_set_catches_invalid_value( ) -> None: """Test entity raises ValueError when value was invalid.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock(return_value=State.from_dict({"brightness": 255})) def state_set(brightness): diff --git a/tests/components/homewizard/test_switch.py b/tests/components/homewizard/test_switch.py index 5dc91a3dc99..f55550ee825 100644 --- a/tests/components/homewizard/test_switch.py +++ b/tests/components/homewizard/test_switch.py @@ -54,7 +54,7 @@ async def test_switch_loads_entities( ) -> None: """Test entity loads smr version.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock( return_value=State.from_dict({"power_on": False, "switch_lock": False}) ) @@ -109,7 +109,7 @@ async def test_switch_power_on_off( ) -> None: """Test entity turns switch on and off.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock( return_value=State.from_dict({"power_on": False, "switch_lock": False}) ) @@ -164,7 +164,7 @@ async def test_switch_lock_power_on_off( ) -> None: """Test entity turns switch on and off.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock( return_value=State.from_dict({"power_on": False, "switch_lock": False}) ) @@ -228,7 +228,7 @@ async def test_switch_lock_sets_power_on_unavailable( ) -> None: """Test entity turns switch on and off.""" - api = get_mock_device() + api = get_mock_device(product_type="HWE-SKT") api.state = AsyncMock( return_value=State.from_dict({"power_on": True, "switch_lock": False}) )