Bump whirlpool-sixth-sense to 2.0.3 (#180700)

This commit is contained in:
Abílio Costa
2026-09-08 13:26:21 +02:00
committed by GitHub
parent b4c8323be6
commit 290737cd45
10 changed files with 85 additions and 37 deletions
@@ -58,11 +58,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: WhirlpoolConfigEntry) ->
)
appliances_manager = AppliancesManager(backend_selector, auth, session)
if not await appliances_manager.fetch_appliances():
if not await appliances_manager.connect():
raise ConfigEntryNotReady(
translation_domain=DOMAIN, translation_key="appliances_fetch_failed"
translation_domain=DOMAIN, translation_key="cannot_connect"
)
await appliances_manager.connect()
entry.runtime_data = appliances_manager
@@ -66,7 +66,9 @@ async def authenticate(
if check_appliances_exist:
appliances_manager = AppliancesManager(backend_selector, auth, session)
await appliances_manager.fetch_appliances()
if not await appliances_manager.connect():
return "cannot_connect"
await appliances_manager.disconnect()
if (
not appliances_manager.aircons
@@ -28,7 +28,6 @@ async def async_get_config_entry_diagnostics(
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,
}
+1 -1
View File
@@ -48,7 +48,7 @@ class WhirlpoolEntity(Entity):
@callback
def _async_attr_callback(self) -> None:
_LOGGER.debug("Attribute update for entity %s", self.entity_id)
self._attr_available = self._appliance.get_online()
self._attr_available = self._appliance.get_online() or False
if not self._attr_available:
if not self._unavailable_logged:
@@ -8,5 +8,5 @@
"iot_class": "cloud_push",
"loggers": ["whirlpool"],
"quality_scale": "silver",
"requirements": ["whirlpool-sixth-sense==1.3.1"]
"requirements": ["whirlpool-sixth-sense==2.0.3"]
}
+1 -1
View File
@@ -3446,7 +3446,7 @@ webmin-xmlrpc==0.0.2
weheat==2026.9.3
# homeassistant.components.whirlpool
whirlpool-sixth-sense==1.3.1
whirlpool-sixth-sense==2.0.3
# homeassistant.components.whois
whoisdomain==2.20260806.3
+42 -16
View File
@@ -101,9 +101,7 @@ def get_aircon_mock(said):
"""Get a mock of an air conditioner."""
mock_aircon = Mock(spec=aircon.Aircon, said=said)
mock_aircon.name = f"Aircon {said}"
mock_aircon.appliance_info = Mock(
data_model="aircon_model", category="aircon", model_number="12345"
)
mock_aircon.appliance_info = Mock(category="aircon", model_number="12345")
mock_aircon.get_online.return_value = True
mock_aircon.get_power_on.return_value = True
mock_aircon.get_mode.return_value = aircon.Mode.Cool
@@ -113,6 +111,12 @@ def get_aircon_mock(said):
mock_aircon.get_current_humidity.return_value = 80
mock_aircon.get_humidity.return_value = 50
mock_aircon.get_h_louver_swing.return_value = True
mock_aircon.get_raw_data.return_value = {
"_id": said,
"attributes": {
"Cavity_OpSetHorzLouverSwing": {"value": "1", "updateTime": 1626517992782},
},
}
return mock_aircon
@@ -134,9 +138,7 @@ def mock_washer_api():
"""Get a mock of a washer."""
mock_washer = Mock(spec=washer.Washer, said="said_washer")
mock_washer.name = "Washer"
mock_washer.appliance_info = Mock(
data_model="washer", category="washer_dryer", model_number="12345"
)
mock_washer.appliance_info = Mock(category="washer_dryer", model_number="12345")
mock_washer.get_online.return_value = True
mock_washer.get_machine_state.return_value = washer.MachineState.RunningMainCycle
mock_washer.get_door_open.return_value = False
@@ -148,6 +150,12 @@ def mock_washer_api():
mock_washer.get_cycle_status_soaking.return_value = False
mock_washer.get_cycle_status_spinning.return_value = False
mock_washer.get_cycle_status_washing.return_value = False
mock_washer.get_raw_data.return_value = {
"_id": "WBR123456789",
"attributes": {
"Cavity_OpSetHorzLouverSwing": {"value": "1", "updateTime": 1626517992782},
},
}
return mock_washer
@@ -157,14 +165,18 @@ def mock_dryer_api():
"""Get a mock of a dryer."""
mock_dryer = mock.Mock(spec=dryer.Dryer, said="said_dryer")
mock_dryer.name = "Dryer"
mock_dryer.appliance_info = Mock(
data_model="dryer", category="washer_dryer", model_number="12345"
)
mock_dryer.appliance_info = Mock(category="washer_dryer", model_number="12345")
mock_dryer.get_online.return_value = True
mock_dryer.get_machine_state.return_value = dryer.MachineState.RunningMainCycle
mock_dryer.get_door_open.return_value = False
mock_dryer.get_time_remaining.return_value = 3540
mock_dryer.get_cycle_status_sensing.return_value = False
mock_dryer.get_raw_data.return_value = {
"_id": "WBR123456789",
"attributes": {
"Cavity_OpSetHorzLouverSwing": {"value": "1", "updateTime": 1626517992782},
},
}
return mock_dryer
@@ -173,9 +185,7 @@ def mock_oven_single_cavity_api():
"""Get a mock of a single cavity oven."""
mock_oven = Mock(spec=oven.Oven, said="said_oven_single")
mock_oven.name = "Single Cavity Oven"
mock_oven.appliance_info = Mock(
data_model="oven", category="oven", model_number="12345"
)
mock_oven.appliance_info = Mock(category="oven", model_number="12345")
mock_oven.get_cavity_state.return_value = oven.CavityState.Standby
mock_oven.get_cook_mode.return_value = oven.CookMode.Bake
mock_oven.get_online.return_value = True
@@ -185,6 +195,12 @@ def mock_oven_single_cavity_api():
mock_oven.get_light.return_value = True
mock_oven.get_temp.return_value = 180
mock_oven.get_target_temp.return_value = 200
mock_oven.get_raw_data.return_value = {
"_id": "WBR123456789",
"attributes": {
"Cavity_OpSetHorzLouverSwing": {"value": "1", "updateTime": 1626517992782},
},
}
return mock_oven
@@ -193,9 +209,7 @@ def mock_oven_dual_cavity_api():
"""Get a mock of a dual cavity oven."""
mock_oven = Mock(spec=oven.Oven, said="said_oven_dual")
mock_oven.name = "Dual Cavity Oven"
mock_oven.appliance_info = Mock(
data_model="oven", category="oven", model_number="12345"
)
mock_oven.appliance_info = Mock(category="oven", model_number="12345")
mock_oven.get_cavity_state.return_value = oven.CavityState.Standby
mock_oven.get_cook_mode.return_value = oven.CookMode.Bake
mock_oven.get_online.return_value = True
@@ -209,6 +223,12 @@ def mock_oven_dual_cavity_api():
mock_oven.get_light.side_effect = lambda cavity: cavity == oven.Cavity.Upper
mock_oven.get_temp.return_value = 180
mock_oven.get_target_temp.return_value = 200
mock_oven.get_raw_data.return_value = {
"_id": "WBR123456789",
"attributes": {
"Cavity_OpSetHorzLouverSwing": {"value": "1", "updateTime": 1626517992782},
},
}
return mock_oven
@@ -218,7 +238,13 @@ def mock_refrigerator_api():
mock_refrigerator = Mock(spec=refrigerator.Refrigerator, said="said_refrigerator")
mock_refrigerator.name = "Beer fridge"
mock_refrigerator.appliance_info = Mock(
data_model="refrigerator", category="refrigerator", model_number="12345"
category="refrigerator", model_number="12345"
)
mock_refrigerator.get_offset_temp.return_value = 0
mock_refrigerator.get_raw_data.return_value = {
"_id": "WBR123456789",
"attributes": {
"Cavity_OpSetHorzLouverSwing": {"value": "1", "updateTime": 1626517992782},
},
}
return mock_refrigerator
@@ -5,45 +5,38 @@
'aircons': dict({
'Aircon said1': dict({
'category': 'aircon',
'data_model': 'aircon_model',
'model_number': '12345',
}),
'Aircon said2': dict({
'category': 'aircon',
'data_model': 'aircon_model',
'model_number': '12345',
}),
}),
'dryers': dict({
'Dryer': dict({
'category': 'washer_dryer',
'data_model': 'dryer',
'model_number': '12345',
}),
}),
'ovens': dict({
'Dual Cavity Oven': dict({
'category': 'oven',
'data_model': 'oven',
'model_number': '12345',
}),
'Single Cavity Oven': dict({
'category': 'oven',
'data_model': 'oven',
'model_number': '12345',
}),
}),
'refrigerators': dict({
'Beer fridge': dict({
'category': 'refrigerator',
'data_model': 'refrigerator',
'model_number': '12345',
}),
}),
'washers': dict({
'Washer': dict({
'category': 'washer_dryer',
'data_model': 'washer',
'model_number': '12345',
}),
}),
+31 -1
View File
@@ -71,6 +71,7 @@ async def test_user_flow(
hass: HomeAssistant,
region: tuple[str, Region],
brand: tuple[str, Brand],
mock_appliances_manager_api: MagicMock,
mock_backend_selector_api: MagicMock,
mock_whirlpool_setup_entry: MagicMock,
) -> None:
@@ -87,6 +88,8 @@ async def test_user_flow(
)
assert_successful_user_flow(mock_whirlpool_setup_entry, result, region[0], brand[0])
mock_appliances_manager_api.return_value.connect.assert_awaited_once()
mock_appliances_manager_api.return_value.disconnect.assert_awaited_once()
mock_backend_selector_api.assert_called_once_with(brand[1], region[1])
@@ -109,7 +112,6 @@ async def test_user_flow_invalid_auth(
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": "invalid_auth"}
# Test that it succeeds if the authentication is valid
mock_auth_api.return_value.is_access_token_valid.return_value = True
result = await hass.config_entries.flow.async_configure(
result["flow_id"], CONFIG_INPUT | {CONF_REGION: region[0], CONF_BRAND: brand[0]}
@@ -161,6 +163,34 @@ async def test_user_flow_auth_error(
assert_successful_user_flow(mock_whirlpool_setup_entry, result, region[0], brand[0])
async def test_user_flow_connect_error(
hass: HomeAssistant,
region: tuple[str, Region],
brand: tuple[str, Brand],
mock_appliances_manager_api: MagicMock,
mock_whirlpool_setup_entry: MagicMock,
) -> None:
"""Test a failed connection in the flow initialized by the user."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
mock_appliances_manager_api.return_value.connect.return_value = False
result = await hass.config_entries.flow.async_configure(
result["flow_id"], CONFIG_INPUT | {CONF_REGION: region[0], CONF_BRAND: brand[0]}
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": "cannot_connect"}
# Test that it succeeds if the connection is successful
mock_appliances_manager_api.return_value.connect.return_value = True
result = await hass.config_entries.flow.async_configure(
result["flow_id"], CONFIG_INPUT | {CONF_REGION: region[0], CONF_BRAND: brand[0]}
)
assert_successful_user_flow(mock_whirlpool_setup_entry, result, region[0], brand[0])
async def test_already_configured(
hass: HomeAssistant, region: tuple[str, Region], brand: tuple[str, Brand]
) -> None:
+4 -5
View File
@@ -124,12 +124,11 @@ async def test_setup_auth_failed(
assert entry.state is ConfigEntryState.SETUP_ERROR
async def test_setup_fetch_appliances_failed(
hass: HomeAssistant,
mock_appliances_manager_api: MagicMock,
async def test_setup_connect_failed(
hass: HomeAssistant, mock_appliances_manager_api: MagicMock
) -> None:
"""Test setup with failed fetch_appliances."""
mock_appliances_manager_api.return_value.fetch_appliances.return_value = False
"""Test setup with failed connect call."""
mock_appliances_manager_api.return_value.connect = AsyncMock(return_value=False)
entry = await init_integration(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert entry.state is ConfigEntryState.SETUP_RETRY