mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Update whirlpool-sixth-sense to 0.19.1 (#139987)
This commit is contained in:
parent
2401d8900a
commit
82d5304b45
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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"]
|
||||
}
|
||||
|
@ -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:
|
||||
|
2
requirements_all.txt
generated
2
requirements_all.txt
generated
@ -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
|
||||
|
2
requirements_test_all.txt
generated
2
requirements_test_all.txt
generated
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
6
tests/components/whirlpool/const.py
Normal file
6
tests/components/whirlpool/const.py
Normal file
@ -0,0 +1,6 @@
|
||||
"""Constants for the Whirlpool Sixth Sense integration tests."""
|
||||
|
||||
MOCK_SAID1 = "said1"
|
||||
MOCK_SAID2 = "said2"
|
||||
MOCK_SAID3 = "said3"
|
||||
MOCK_SAID4 = "said4"
|
@ -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({
|
||||
|
@ -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:
|
||||
|
@ -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."""
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user