diff --git a/homeassistant/components/whirlpool/__init__.py b/homeassistant/components/whirlpool/__init__.py index 6231324bb0d..cb073779379 100644 --- a/homeassistant/components/whirlpool/__init__.py +++ b/homeassistant/components/whirlpool/__init__.py @@ -1,6 +1,5 @@ """The Whirlpool Appliances integration.""" -from dataclasses import dataclass import logging from aiohttp import ClientError @@ -20,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) PLATFORMS = [Platform.CLIMATE, Platform.SENSOR] -type WhirlpoolConfigEntry = ConfigEntry[WhirlpoolData] +type WhirlpoolConfigEntry = ConfigEntry[AppliancesManager] async def async_setup_entry(hass: HomeAssistant, entry: WhirlpoolConfigEntry) -> bool: @@ -52,8 +51,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: WhirlpoolConfigEntry) -> if not await appliances_manager.fetch_appliances(): _LOGGER.error("Cannot fetch appliances") return False + await appliances_manager.connect() - entry.runtime_data = WhirlpoolData(appliances_manager, auth, backend_selector) + entry.runtime_data = appliances_manager await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True @@ -61,13 +61,5 @@ async def async_setup_entry(hass: HomeAssistant, entry: WhirlpoolConfigEntry) -> async def async_unload_entry(hass: HomeAssistant, entry: WhirlpoolConfigEntry) -> bool: """Unload a config entry.""" + await entry.runtime_data.disconnect() return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) - - -@dataclass -class WhirlpoolData: - """Whirlpool integaration shared data.""" - - appliances_manager: AppliancesManager - auth: Auth - backend_selector: BackendSelector diff --git a/homeassistant/components/whirlpool/climate.py b/homeassistant/components/whirlpool/climate.py index 6baf738e54e..84a2c0d52ca 100644 --- a/homeassistant/components/whirlpool/climate.py +++ b/homeassistant/components/whirlpool/climate.py @@ -5,10 +5,7 @@ from __future__ import annotations import logging from typing import Any -from aiohttp import ClientSession from whirlpool.aircon import Aircon, FanSpeed as AirconFanSpeed, Mode as AirconMode -from whirlpool.auth import Auth -from whirlpool.backendselector import BackendSelector from homeassistant.components.climate import ( ENTITY_ID_FORMAT, @@ -25,7 +22,6 @@ from homeassistant.components.climate import ( ) from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature from homeassistant.core import HomeAssistant -from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity import generate_entity_id from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback @@ -73,19 +69,8 @@ async def async_setup_entry( async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up entry.""" - whirlpool_data = config_entry.runtime_data - - aircons = [ - AirConEntity( - hass, - ac_data["SAID"], - ac_data["NAME"], - whirlpool_data.backend_selector, - whirlpool_data.auth, - async_get_clientsession(hass), - ) - for ac_data in whirlpool_data.appliances_manager.aircons - ] + appliances_manager = config_entry.runtime_data + aircons = [AirConEntity(hass, aircon) for aircon in appliances_manager.aircons] async_add_entities(aircons, True) @@ -110,36 +95,26 @@ class AirConEntity(ClimateEntity): _attr_target_temperature_step = SUPPORTED_TARGET_TEMPERATURE_STEP _attr_temperature_unit = UnitOfTemperature.CELSIUS - def __init__( - self, - hass: HomeAssistant, - said: str, - name: str | None, - backend_selector: BackendSelector, - auth: Auth, - session: ClientSession, - ) -> None: + def __init__(self, hass: HomeAssistant, aircon: Aircon) -> None: """Initialize the entity.""" - self._aircon = Aircon(backend_selector, auth, said, session) - self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, said, hass=hass) - self._attr_unique_id = said + self._aircon = aircon + self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, aircon.said, hass=hass) + self._attr_unique_id = aircon.said self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, said)}, - name=name if name is not None else said, + identifiers={(DOMAIN, aircon.said)}, + name=aircon.name if aircon.name is not None else aircon.said, manufacturer="Whirlpool", model="Sixth Sense", ) async def async_added_to_hass(self) -> None: - """Connect aircon to the cloud.""" + """Register updates callback.""" self._aircon.register_attr_callback(self.async_write_ha_state) - await self._aircon.connect() async def async_will_remove_from_hass(self) -> None: - """Close Whrilpool Appliance sockets before removing.""" + """Unregister updates callback.""" self._aircon.unregister_attr_callback(self.async_write_ha_state) - await self._aircon.disconnect() @property def available(self) -> bool: diff --git a/homeassistant/components/whirlpool/diagnostics.py b/homeassistant/components/whirlpool/diagnostics.py index 87d6ea827e2..09338396de4 100644 --- a/homeassistant/components/whirlpool/diagnostics.py +++ b/homeassistant/components/whirlpool/diagnostics.py @@ -4,6 +4,8 @@ from __future__ import annotations from typing import Any +from whirlpool.appliance import Appliance + from homeassistant.components.diagnostics import async_redact_data from homeassistant.core import HomeAssistant @@ -26,18 +28,25 @@ async def async_get_config_entry_diagnostics( ) -> dict[str, Any]: """Return diagnostics for a config entry.""" - whirlpool = config_entry.runtime_data + def get_appliance_diagnostics(appliance: Appliance) -> dict[str, Any]: + return { + "data_model": appliance.appliance_info.data_model, + "category": appliance.appliance_info.category, + "model_number": appliance.appliance_info.model_number, + } + + appliances_manager = config_entry.runtime_data diagnostics_data = { - "Washer_dryers": { - wd["NAME"]: dict(wd.items()) - for wd in whirlpool.appliances_manager.washer_dryers + "washer_dryers": { + wd.name: get_appliance_diagnostics(wd) + for wd in appliances_manager.washer_dryers }, "aircons": { - ac["NAME"]: dict(ac.items()) for ac in whirlpool.appliances_manager.aircons + ac.name: get_appliance_diagnostics(ac) for ac in appliances_manager.aircons }, "ovens": { - oven["NAME"]: dict(oven.items()) - for oven in whirlpool.appliances_manager.ovens + oven.name: get_appliance_diagnostics(oven) + for oven in appliances_manager.ovens }, } diff --git a/homeassistant/components/whirlpool/manifest.json b/homeassistant/components/whirlpool/manifest.json index 67901eea482..ace2e31791d 100644 --- a/homeassistant/components/whirlpool/manifest.json +++ b/homeassistant/components/whirlpool/manifest.json @@ -7,5 +7,5 @@ "integration_type": "hub", "iot_class": "cloud_push", "loggers": ["whirlpool"], - "requirements": ["whirlpool-sixth-sense==0.18.12"] + "requirements": ["whirlpool-sixth-sense==0.19.1"] } diff --git a/homeassistant/components/whirlpool/sensor.py b/homeassistant/components/whirlpool/sensor.py index f4811feb2c9..d0d13a128e2 100644 --- a/homeassistant/components/whirlpool/sensor.py +++ b/homeassistant/components/whirlpool/sensor.py @@ -16,7 +16,6 @@ from homeassistant.components.sensor import ( SensorEntityDescription, ) from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.typing import StateType @@ -134,37 +133,16 @@ async def async_setup_entry( config_entry: WhirlpoolConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: - """Config flow entry for Whrilpool Laundry.""" + """Config flow entry for Whirlpool sensors.""" entities: list = [] - whirlpool_data = config_entry.runtime_data - for appliance in whirlpool_data.appliances_manager.washer_dryers: - _wd = WasherDryer( - whirlpool_data.backend_selector, - whirlpool_data.auth, - appliance["SAID"], - async_get_clientsession(hass), - ) - await _wd.connect() - + appliances_manager = config_entry.runtime_data + for washer_dryer in appliances_manager.washer_dryers: entities.extend( - [ - WasherDryerClass( - appliance["SAID"], - appliance["NAME"], - description, - _wd, - ) - for description in SENSORS - ] + [WasherDryerClass(washer_dryer, description) for description in SENSORS] ) entities.extend( [ - WasherDryerTimeClass( - appliance["SAID"], - appliance["NAME"], - description, - _wd, - ) + WasherDryerTimeClass(washer_dryer, description) for description in SENSOR_TIMER ] ) @@ -178,34 +156,30 @@ class WasherDryerClass(SensorEntity): _attr_has_entity_name = True def __init__( - self, - said: str, - name: str, - description: WhirlpoolSensorEntityDescription, - washdry: WasherDryer, + self, washer_dryer: WasherDryer, description: WhirlpoolSensorEntityDescription ) -> None: """Initialize the washer sensor.""" - self._wd: WasherDryer = washdry + self._wd: WasherDryer = washer_dryer - if name == "dryer": + if washer_dryer.name == "dryer": self._attr_icon = ICON_D else: self._attr_icon = ICON_W self.entity_description: WhirlpoolSensorEntityDescription = description self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, said)}, - name=name.capitalize(), + identifiers={(DOMAIN, washer_dryer.said)}, + name=washer_dryer.name.capitalize(), manufacturer="Whirlpool", ) - self._attr_unique_id = f"{said}-{description.key}" + self._attr_unique_id = f"{washer_dryer.said}-{description.key}" async def async_added_to_hass(self) -> None: - """Connect washer/dryer to the cloud.""" + """Register updates callback.""" self._wd.register_attr_callback(self.async_write_ha_state) async def async_will_remove_from_hass(self) -> None: - """Close Whirlpool Appliance sockets before removing.""" + """Unregister updates callback.""" self._wd.unregister_attr_callback(self.async_write_ha_state) @property @@ -226,16 +200,12 @@ class WasherDryerTimeClass(RestoreSensor): _attr_has_entity_name = True def __init__( - self, - said: str, - name: str, - description: SensorEntityDescription, - washdry: WasherDryer, + self, washer_dryer: WasherDryer, description: SensorEntityDescription ) -> None: """Initialize the washer sensor.""" - self._wd: WasherDryer = washdry + self._wd: WasherDryer = washer_dryer - if name == "dryer": + if washer_dryer.name == "dryer": self._attr_icon = ICON_D else: self._attr_icon = ICON_W @@ -243,11 +213,11 @@ class WasherDryerTimeClass(RestoreSensor): self.entity_description: SensorEntityDescription = description self._running: bool | None = None self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, said)}, - name=name.capitalize(), + identifiers={(DOMAIN, washer_dryer.said)}, + name=washer_dryer.name.capitalize(), manufacturer="Whirlpool", ) - self._attr_unique_id = f"{said}-{description.key}" + self._attr_unique_id = f"{washer_dryer.said}-{description.key}" async def async_added_to_hass(self) -> None: """Connect washer/dryer to the cloud.""" @@ -259,7 +229,6 @@ class WasherDryerTimeClass(RestoreSensor): async def async_will_remove_from_hass(self) -> None: """Close Whrilpool Appliance sockets before removing.""" self._wd.unregister_attr_callback(self.update_from_latest_data) - await self._wd.disconnect() @property def available(self) -> bool: diff --git a/requirements_all.txt b/requirements_all.txt index a4d5f6c6914..22cbf6bf7cd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -3061,7 +3061,7 @@ webmin-xmlrpc==0.0.2 weheat==2025.2.26 # homeassistant.components.whirlpool -whirlpool-sixth-sense==0.18.12 +whirlpool-sixth-sense==0.19.1 # homeassistant.components.whois whois==0.9.27 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2d34851cecc..0e5dd85decd 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2465,7 +2465,7 @@ webmin-xmlrpc==0.0.2 weheat==2025.2.26 # homeassistant.components.whirlpool -whirlpool-sixth-sense==0.18.12 +whirlpool-sixth-sense==0.19.1 # homeassistant.components.whois whois==0.9.27 diff --git a/tests/components/whirlpool/__init__.py b/tests/components/whirlpool/__init__.py index ca00975941a..97d9b4d61d5 100644 --- a/tests/components/whirlpool/__init__.py +++ b/tests/components/whirlpool/__init__.py @@ -31,5 +31,4 @@ async def init_integration_with_entry( entry.add_to_hass(hass) await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() - return entry diff --git a/tests/components/whirlpool/conftest.py b/tests/components/whirlpool/conftest.py index c302922fe25..93881d3735a 100644 --- a/tests/components/whirlpool/conftest.py +++ b/tests/components/whirlpool/conftest.py @@ -8,10 +8,7 @@ import whirlpool import whirlpool.aircon from whirlpool.backendselector import Brand, Region -MOCK_SAID1 = "said1" -MOCK_SAID2 = "said2" -MOCK_SAID3 = "said3" -MOCK_SAID4 = "said4" +from .const import MOCK_SAID1, MOCK_SAID2, MOCK_SAID3, MOCK_SAID4 @pytest.fixture( @@ -36,7 +33,7 @@ def fixture_brand(request: pytest.FixtureRequest) -> tuple[str, Brand]: return request.param -@pytest.fixture(name="mock_auth_api") +@pytest.fixture(name="mock_auth_api", autouse=True) def fixture_mock_auth_api(): """Set up Auth fixture.""" with ( @@ -50,8 +47,10 @@ def fixture_mock_auth_api(): yield mock_auth -@pytest.fixture(name="mock_appliances_manager_api") -def fixture_mock_appliances_manager_api(): +@pytest.fixture(name="mock_appliances_manager_api", autouse=True) +def fixture_mock_appliances_manager_api( + mock_aircon1_api, mock_aircon2_api, mock_sensor1_api, mock_sensor2_api +): """Set up AppliancesManager fixture.""" with ( mock.patch( @@ -63,28 +62,15 @@ def fixture_mock_appliances_manager_api(): ), ): mock_appliances_manager.return_value.fetch_appliances = AsyncMock() + mock_appliances_manager.return_value.connect = AsyncMock() + mock_appliances_manager.return_value.disconnect = AsyncMock() mock_appliances_manager.return_value.aircons = [ - {"SAID": MOCK_SAID1, "NAME": "TestZone"}, - {"SAID": MOCK_SAID2, "NAME": "TestZone"}, + mock_aircon1_api, + mock_aircon2_api, ] mock_appliances_manager.return_value.washer_dryers = [ - {"SAID": MOCK_SAID3, "NAME": "washer"}, - {"SAID": MOCK_SAID4, "NAME": "dryer"}, - ] - yield mock_appliances_manager - - -@pytest.fixture(name="mock_appliances_manager_laundry_api") -def fixture_mock_appliances_manager_laundry_api(): - """Set up AppliancesManager fixture.""" - with mock.patch( - "homeassistant.components.whirlpool.AppliancesManager" - ) as mock_appliances_manager: - mock_appliances_manager.return_value.fetch_appliances = AsyncMock() - mock_appliances_manager.return_value.aircons = None - mock_appliances_manager.return_value.washer_dryers = [ - {"SAID": MOCK_SAID3, "NAME": "washer"}, - {"SAID": MOCK_SAID4, "NAME": "dryer"}, + mock_sensor1_api, + mock_sensor2_api, ] yield mock_appliances_manager @@ -107,9 +93,11 @@ def fixture_mock_backend_selector_api(): def get_aircon_mock(said): """Get a mock of an air conditioner.""" mock_aircon = mock.Mock(said=said) - mock_aircon.connect = AsyncMock() - mock_aircon.disconnect = AsyncMock() + mock_aircon.name = f"Aircon {said}" mock_aircon.register_attr_callback = MagicMock() + mock_aircon.appliance_info.data_model = "aircon_model" + mock_aircon.appliance_info.category = "aircon" + mock_aircon.appliance_info.model_number = "12345" mock_aircon.get_online.return_value = True mock_aircon.get_power_on.return_value = True mock_aircon.get_mode.return_value = whirlpool.aircon.Mode.Cool @@ -132,13 +120,13 @@ def get_aircon_mock(said): @pytest.fixture(name="mock_aircon1_api", autouse=False) -def fixture_mock_aircon1_api(mock_auth_api, mock_appliances_manager_api): +def fixture_mock_aircon1_api(): """Set up air conditioner API fixture.""" return get_aircon_mock(MOCK_SAID1) @pytest.fixture(name="mock_aircon2_api", autouse=False) -def fixture_mock_aircon2_api(mock_auth_api, mock_appliances_manager_api): +def fixture_mock_aircon2_api(): """Set up air conditioner API fixture.""" return get_aircon_mock(MOCK_SAID2) @@ -168,9 +156,11 @@ def side_effect_function(*args, **kwargs): def get_sensor_mock(said): """Get a mock of a sensor.""" mock_sensor = mock.Mock(said=said) - mock_sensor.connect = AsyncMock() - mock_sensor.disconnect = AsyncMock() + mock_sensor.name = f"WasherDryer {said}" mock_sensor.register_attr_callback = MagicMock() + mock_sensor.appliance_info.data_model = "washer_dryer_model" + mock_sensor.appliance_info.category = "washer_dryer" + mock_sensor.appliance_info.model_number = "12345" mock_sensor.get_online.return_value = True mock_sensor.get_machine_state.return_value = ( whirlpool.washerdryer.MachineState.Standby @@ -187,13 +177,13 @@ def get_sensor_mock(said): @pytest.fixture(name="mock_sensor1_api", autouse=False) -def fixture_mock_sensor1_api(mock_auth_api, mock_appliances_manager_laundry_api): +def fixture_mock_sensor1_api(): """Set up sensor API fixture.""" return get_sensor_mock(MOCK_SAID3) @pytest.fixture(name="mock_sensor2_api", autouse=False) -def fixture_mock_sensor2_api(mock_auth_api, mock_appliances_manager_laundry_api): +def fixture_mock_sensor2_api(): """Set up sensor API fixture.""" return get_sensor_mock(MOCK_SAID4) diff --git a/tests/components/whirlpool/const.py b/tests/components/whirlpool/const.py new file mode 100644 index 00000000000..04ea5c0645c --- /dev/null +++ b/tests/components/whirlpool/const.py @@ -0,0 +1,6 @@ +"""Constants for the Whirlpool Sixth Sense integration tests.""" + +MOCK_SAID1 = "said1" +MOCK_SAID2 = "said2" +MOCK_SAID3 = "said3" +MOCK_SAID4 = "said4" diff --git a/tests/components/whirlpool/snapshots/test_diagnostics.ambr b/tests/components/whirlpool/snapshots/test_diagnostics.ambr index ee8abe04bf1..7ffae8bc808 100644 --- a/tests/components/whirlpool/snapshots/test_diagnostics.ambr +++ b/tests/components/whirlpool/snapshots/test_diagnostics.ambr @@ -2,24 +2,32 @@ # name: test_entry_diagnostics dict({ 'appliances': dict({ - 'Washer_dryers': dict({ - 'dryer': dict({ - 'NAME': 'dryer', - 'SAID': '**REDACTED**', - }), - 'washer': dict({ - 'NAME': 'washer', - 'SAID': '**REDACTED**', - }), - }), 'aircons': dict({ - 'TestZone': dict({ - 'NAME': 'TestZone', - 'SAID': '**REDACTED**', + 'Aircon said1': dict({ + 'category': 'aircon', + 'data_model': 'aircon_model', + 'model_number': '12345', + }), + 'Aircon said2': dict({ + 'category': 'aircon', + 'data_model': 'aircon_model', + 'model_number': '12345', }), }), 'ovens': dict({ }), + 'washer_dryers': dict({ + 'WasherDryer said3': dict({ + 'category': 'washer_dryer', + 'data_model': 'washer_dryer_model', + 'model_number': '12345', + }), + 'WasherDryer said4': dict({ + 'category': 'washer_dryer', + 'data_model': 'washer_dryer_model', + 'model_number': '12345', + }), + }), }), 'config_entry': dict({ 'data': dict({ diff --git a/tests/components/whirlpool/test_climate.py b/tests/components/whirlpool/test_climate.py index cdae28f4432..0586d654f7f 100644 --- a/tests/components/whirlpool/test_climate.py +++ b/tests/components/whirlpool/test_climate.py @@ -68,6 +68,7 @@ async def test_no_appliances( ) -> None: """Test the setup of the climate entities when there are no appliances available.""" mock_appliances_manager_api.return_value.aircons = [] + mock_appliances_manager_api.return_value.washer_dryers = [] await init_integration(hass) assert len(hass.states.async_all()) == 0 @@ -75,16 +76,15 @@ async def test_no_appliances( async def test_static_attributes( hass: HomeAssistant, entity_registry: er.EntityRegistry, - mock_aircon1_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test static climate attributes.""" await init_integration(hass) - for entity_id in ("climate.said1", "climate.said2"): + for said in ("said1", "said2"): + entity_id = f"climate.{said}" entry = entity_registry.async_get(entity_id) assert entry - assert entry.unique_id == entity_id.split(".")[1] + assert entry.unique_id == said state = hass.states.get(entity_id) assert state is not None @@ -92,7 +92,7 @@ async def test_static_attributes( assert state.state == HVACMode.COOL attributes = state.attributes - assert attributes[ATTR_FRIENDLY_NAME] == "TestZone" + assert attributes[ATTR_FRIENDLY_NAME] == f"Aircon {said}" assert ( attributes[ATTR_SUPPORTED_FEATURES] @@ -123,7 +123,6 @@ async def test_static_attributes( async def test_dynamic_attributes( hass: HomeAssistant, - mock_aircon_api_instances: MagicMock, mock_aircon1_api: MagicMock, mock_aircon2_api: MagicMock, ) -> None: @@ -212,7 +211,6 @@ async def test_dynamic_attributes( async def test_service_calls( hass: HomeAssistant, - mock_aircon_api_instances: MagicMock, mock_aircon1_api: MagicMock, mock_aircon2_api: MagicMock, ) -> None: diff --git a/tests/components/whirlpool/test_diagnostics.py b/tests/components/whirlpool/test_diagnostics.py index 2a0b2e6fd18..192339156e1 100644 --- a/tests/components/whirlpool/test_diagnostics.py +++ b/tests/components/whirlpool/test_diagnostics.py @@ -1,7 +1,5 @@ """Test Blink diagnostics.""" -from unittest.mock import MagicMock - from syrupy import SnapshotAssertion from syrupy.filters import props @@ -19,9 +17,6 @@ async def test_entry_diagnostics( hass: HomeAssistant, hass_client: ClientSessionGenerator, snapshot: SnapshotAssertion, - mock_appliances_manager_api: MagicMock, - mock_aircon1_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test config entry diagnostics.""" diff --git a/tests/components/whirlpool/test_init.py b/tests/components/whirlpool/test_init.py index 8f082ff6294..5f04bf84b9e 100644 --- a/tests/components/whirlpool/test_init.py +++ b/tests/components/whirlpool/test_init.py @@ -21,7 +21,6 @@ async def test_setup( mock_backend_selector_api: MagicMock, region, brand, - mock_aircon_api_instances: MagicMock, ) -> None: """Test setup.""" entry = await init_integration(hass, region[0], brand[0]) @@ -33,7 +32,6 @@ async def test_setup( async def test_setup_region_fallback( hass: HomeAssistant, mock_backend_selector_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test setup when no region is available on the ConfigEntry. @@ -57,7 +55,6 @@ async def test_setup_brand_fallback( hass: HomeAssistant, region, mock_backend_selector_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test setup when no brand is available on the ConfigEntry. @@ -81,7 +78,6 @@ async def test_setup_brand_fallback( async def test_setup_http_exception( hass: HomeAssistant, mock_auth_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test setup with an http exception.""" mock_auth_api.return_value.do_auth = AsyncMock( @@ -95,7 +91,6 @@ async def test_setup_http_exception( async def test_setup_auth_failed( hass: HomeAssistant, mock_auth_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test setup with failed auth.""" mock_auth_api.return_value.do_auth = AsyncMock() @@ -108,7 +103,6 @@ async def test_setup_auth_failed( async def test_setup_auth_account_locked( hass: HomeAssistant, mock_auth_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test setup with failed auth due to account being locked.""" mock_auth_api.return_value.do_auth.side_effect = AccountLockedError @@ -120,7 +114,6 @@ async def test_setup_auth_account_locked( async def test_setup_fetch_appliances_failed( hass: HomeAssistant, mock_appliances_manager_api: MagicMock, - mock_aircon_api_instances: MagicMock, ) -> None: """Test setup with failed fetch_appliances.""" mock_appliances_manager_api.return_value.fetch_appliances.return_value = False @@ -129,11 +122,7 @@ async def test_setup_fetch_appliances_failed( assert entry.state is ConfigEntryState.SETUP_ERROR -async def test_unload_entry( - hass: HomeAssistant, - mock_aircon_api_instances: MagicMock, - mock_sensor_api_instances: MagicMock, -) -> None: +async def test_unload_entry(hass: HomeAssistant) -> None: """Test successful unload of entry.""" entry = await init_integration(hass) assert len(hass.config_entries.async_entries(DOMAIN)) == 1 diff --git a/tests/components/whirlpool/test_sensor.py b/tests/components/whirlpool/test_sensor.py index 548025e29bd..95fca331707 100644 --- a/tests/components/whirlpool/test_sensor.py +++ b/tests/components/whirlpool/test_sensor.py @@ -12,14 +12,13 @@ from homeassistant.helpers import entity_registry as er from homeassistant.util.dt import as_timestamp, utc_from_timestamp, utcnow from . import init_integration +from .const import MOCK_SAID3, MOCK_SAID4 from tests.common import async_fire_time_changed, mock_restore_cache_with_extra_data async def update_sensor_state( - hass: HomeAssistant, - entity_id: str, - mock_sensor_api_instance: MagicMock, + hass: HomeAssistant, entity_id: str, mock_sensor_api_instance: MagicMock ) -> State: """Simulate an update trigger from the API.""" @@ -46,10 +45,7 @@ def side_effect_function_open_door(*args, **kwargs): async def test_dryer_sensor_values( - hass: HomeAssistant, - mock_sensor_api_instances: MagicMock, - mock_sensor2_api: MagicMock, - entity_registry: er.EntityRegistry, + hass: HomeAssistant, mock_sensor2_api: MagicMock, entity_registry: er.EntityRegistry ) -> None: """Test the sensor value callbacks.""" hass.set_state(CoreState.not_running) @@ -58,14 +54,11 @@ async def test_dryer_sensor_values( hass, ( ( - State( - "sensor.washer_end_time", - "1", - ), + State(f"sensor.washerdryer_{MOCK_SAID3}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ( - State("sensor.dryer_end_time", "1"), + State(f"sensor.washerdryer_{MOCK_SAID4}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ), @@ -73,7 +66,7 @@ async def test_dryer_sensor_values( await init_integration(hass) - entity_id = "sensor.dryer_state" + entity_id = f"sensor.washerdryer_{MOCK_SAID4}_state" mock_instance = mock_sensor2_api entry = entity_registry.async_get(entity_id) assert entry @@ -83,7 +76,7 @@ async def test_dryer_sensor_values( state = await update_sensor_state(hass, entity_id, mock_instance) assert state is not None - state_id = f"{entity_id.split('_', maxsplit=1)[0]}_end_time" + state_id = f"sensor.washerdryer_{MOCK_SAID3}_end_time" state = hass.states.get(state_id) assert state.state == thetimestamp.isoformat() @@ -110,10 +103,7 @@ async def test_dryer_sensor_values( async def test_washer_sensor_values( - hass: HomeAssistant, - mock_sensor_api_instances: MagicMock, - mock_sensor1_api: MagicMock, - entity_registry: er.EntityRegistry, + hass: HomeAssistant, mock_sensor1_api: MagicMock, entity_registry: er.EntityRegistry ) -> None: """Test the sensor value callbacks.""" hass.set_state(CoreState.not_running) @@ -122,14 +112,11 @@ async def test_washer_sensor_values( hass, ( ( - State( - "sensor.washer_end_time", - "1", - ), + State(f"sensor.washerdryer_{MOCK_SAID3}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ( - State("sensor.dryer_end_time", "1"), + State(f"sensor.washerdryer_{MOCK_SAID4}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ), @@ -143,7 +130,7 @@ async def test_washer_sensor_values( ) await hass.async_block_till_done() - entity_id = "sensor.washer_state" + entity_id = f"sensor.washerdryer_{MOCK_SAID3}_state" mock_instance = mock_sensor1_api entry = entity_registry.async_get(entity_id) assert entry @@ -153,11 +140,11 @@ async def test_washer_sensor_values( state = await update_sensor_state(hass, entity_id, mock_instance) assert state is not None - state_id = f"{entity_id.split('_', maxsplit=1)[0]}_end_time" + state_id = f"sensor.washerdryer_{MOCK_SAID3}_end_time" state = hass.states.get(state_id) assert state.state == thetimestamp.isoformat() - state_id = f"{entity_id.split('_', maxsplit=1)[0]}_detergent_level" + state_id = f"sensor.washerdryer_{MOCK_SAID3}_detergent_level" entry = entity_registry.async_get(state_id) assert entry assert entry.disabled @@ -277,10 +264,7 @@ async def test_washer_sensor_values( assert state.state == "door_open" -async def test_restore_state( - hass: HomeAssistant, - mock_sensor_api_instances: MagicMock, -) -> None: +async def test_restore_state(hass: HomeAssistant) -> None: """Test sensor restore state.""" # Home assistant is not running yet hass.set_state(CoreState.not_running) @@ -289,14 +273,11 @@ async def test_restore_state( hass, ( ( - State( - "sensor.washer_end_time", - "1", - ), + State(f"sensor.washerdryer_{MOCK_SAID3}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ( - State("sensor.dryer_end_time", "1"), + State(f"sensor.washerdryer_{MOCK_SAID4}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ), @@ -305,20 +286,18 @@ async def test_restore_state( # create and add entry await init_integration(hass) # restore from cache - state = hass.states.get("sensor.washer_end_time") + state = hass.states.get(f"sensor.washerdryer_{MOCK_SAID3}_end_time") assert state.state == thetimestamp.isoformat() - state = hass.states.get("sensor.dryer_end_time") + state = hass.states.get(f"sensor.washerdryer_{MOCK_SAID4}_end_time") assert state.state == thetimestamp.isoformat() async def test_no_restore_state( - hass: HomeAssistant, - mock_sensor_api_instances: MagicMock, - mock_sensor1_api: MagicMock, + hass: HomeAssistant, mock_sensor1_api: MagicMock ) -> None: """Test sensor restore state with no restore.""" # create and add entry - entity_id = "sensor.washer_end_time" + entity_id = f"sensor.washerdryer_{MOCK_SAID3}_end_time" await init_integration(hass) # restore from cache state = hass.states.get(entity_id) @@ -330,11 +309,7 @@ async def test_no_restore_state( @pytest.mark.freeze_time("2022-11-30 00:00:00") -async def test_callback( - hass: HomeAssistant, - mock_sensor_api_instances: MagicMock, - mock_sensor1_api: MagicMock, -) -> None: +async def test_callback(hass: HomeAssistant, mock_sensor1_api: MagicMock) -> None: """Test callback timestamp callback function.""" hass.set_state(CoreState.not_running) thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, UTC) @@ -342,14 +317,11 @@ async def test_callback( hass, ( ( - State( - "sensor.washer_end_time", - "1", - ), + State(f"sensor.washerdryer_{MOCK_SAID3}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ( - State("sensor.dryer_end_time", "1"), + State(f"sensor.washerdryer_{MOCK_SAID4}_end_time", "1"), {"native_value": thetimestamp, "native_unit_of_measurement": None}, ), ), @@ -358,12 +330,12 @@ async def test_callback( # create and add entry await init_integration(hass) # restore from cache - state = hass.states.get("sensor.washer_end_time") + state = hass.states.get(f"sensor.washerdryer_{MOCK_SAID3}_end_time") assert state.state == thetimestamp.isoformat() callback = mock_sensor1_api.register_attr_callback.call_args_list[1][0][0] callback() - state = hass.states.get("sensor.washer_end_time") + state = hass.states.get(f"sensor.washerdryer_{MOCK_SAID3}_end_time") assert state.state == thetimestamp.isoformat() mock_sensor1_api.get_machine_state.return_value = MachineState.RunningMainCycle mock_sensor1_api.get_attribute.side_effect = None @@ -371,19 +343,19 @@ async def test_callback( callback() # Test new timestamp when machine starts a cycle. - state = hass.states.get("sensor.washer_end_time") + state = hass.states.get(f"sensor.washerdryer_{MOCK_SAID3}_end_time") time = state.state assert state.state != thetimestamp.isoformat() # Test no timestamp change for < 60 seconds time change. mock_sensor1_api.get_attribute.return_value = "65" callback() - state = hass.states.get("sensor.washer_end_time") + state = hass.states.get(f"sensor.washerdryer_{MOCK_SAID3}_end_time") assert state.state == time # Test timestamp change for > 60 seconds. mock_sensor1_api.get_attribute.return_value = "125" callback() - state = hass.states.get("sensor.washer_end_time") + state = hass.states.get(f"sensor.washerdryer_{MOCK_SAID3}_end_time") newtime = utc_from_timestamp(as_timestamp(time) + 65) assert state.state == newtime.isoformat()