Only offer Braava mop behavior where the robot reports it (#179349)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Brent Rector
2026-09-15 15:50:45 +02:00
committed by GitHub
co-authored by Claude
parent a4a2e9b488
commit 61a63b82d0
2 changed files with 49 additions and 1 deletions
@@ -352,6 +352,12 @@ class BraavaJet(IRobotVacuum):
for spray in BRAAVA_SPRAY_AMOUNT
]
# Combo models report a mop pad but not `rankOverlap`, which the mop
# behavior is derived from.
if self.vacuum_state.get("rankOverlap") is None:
self._attr_supported_features &= ~VacuumEntityFeature.FAN_SPEED
self._attr_fan_speed_list = []
@property
@override
def fan_speed(self) -> str:
+43 -1
View File
@@ -1,5 +1,6 @@
"""Tests for the Roomba vacuum platform."""
from typing import Any
from unittest.mock import AsyncMock, patch
import pytest
@@ -9,6 +10,7 @@ from homeassistant.components.vacuum import (
DOMAIN as VACUUM_DOMAIN,
SERVICE_SET_FAN_SPEED,
VacuumActivity,
VacuumEntityFeature,
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
@@ -68,6 +70,43 @@ async def test_vacuum_activity(
assert state.state == expected
@pytest.mark.parametrize(
("extra_state", "expect_fan_speed_support", "expected_fan_speed"),
[
# 67 is OVERLAP_STANDARD.
({"rankOverlap": 67}, True, "Standard-1"),
# Combo models report a mop pad but no rankOverlap.
({}, False, None),
],
)
async def test_braava_fan_speed_requires_rank_overlap(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_roomba: AsyncMock,
extra_state: dict[str, Any],
expect_fan_speed_support: bool,
expected_fan_speed: str | None,
) -> None:
"""Test that fan speed is only offered when it can be produced."""
reported = mock_roomba.master_state["state"]["reported"]
reported["detectedPad"] = "reusableWet"
# fan_speed reads the "disposable" key.
reported["padWetness"] = {"disposable": 1, "reusable": 1}
reported.pop("rankOverlap", None)
reported.update(extra_state)
with patch("homeassistant.components.roomba.PLATFORMS", [Platform.VACUUM]):
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state is not None
supported = VacuumEntityFeature(state.attributes["supported_features"])
assert bool(supported & VacuumEntityFeature.FAN_SPEED) is expect_fan_speed_support
assert state.attributes.get("fan_speed") == expected_fan_speed
@pytest.mark.parametrize(
("fan_speed", "translation_key"),
[
@@ -89,7 +128,10 @@ async def test_braava_set_fan_speed_invalid(
translation_key: str,
) -> None:
"""Test that invalid Braava fan speeds raise instead of being swallowed."""
mock_roomba.master_state["state"]["reported"]["detectedPad"] = "reusableWet"
reported = mock_roomba.master_state["state"]["reported"]
reported["detectedPad"] = "reusableWet"
# 67 is OVERLAP_STANDARD; without it the mop behavior is not offered at all.
reported["rankOverlap"] = 67
await _setup(hass, mock_config_entry)