diff --git a/homeassistant/components/smartthings/cover.py b/homeassistant/components/smartthings/cover.py index d2d0dba6773..5d7e29c1312 100644 --- a/homeassistant/components/smartthings/cover.py +++ b/homeassistant/components/smartthings/cover.py @@ -62,7 +62,11 @@ def get_capabilities(capabilities: Sequence[str]) -> Sequence[str] | None: # Must have one of the min_required if any(capability in capabilities for capability in min_required): # Return all capabilities supported/consumed - return min_required + [Capability.battery, Capability.switch_level] + return min_required + [ + Capability.battery, + Capability.switch_level, + Capability.window_shade_level, + ] return None @@ -74,12 +78,16 @@ class SmartThingsCover(SmartThingsEntity, CoverEntity): """Initialize the cover class.""" super().__init__(device) self._device_class = None + self._current_cover_position = None self._state = None self._state_attrs = None self._attr_supported_features = ( CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE ) - if Capability.switch_level in device.capabilities: + if ( + Capability.switch_level in device.capabilities + or Capability.window_shade_level in device.capabilities + ): self._attr_supported_features |= CoverEntityFeature.SET_POSITION async def async_close_cover(self, **kwargs: Any) -> None: @@ -103,7 +111,12 @@ class SmartThingsCover(SmartThingsEntity, CoverEntity): if not self.supported_features & CoverEntityFeature.SET_POSITION: return # Do not set_status=True as device will report progress. - await self._device.set_level(kwargs[ATTR_POSITION], 0) + if Capability.window_shade_level in self._device.capabilities: + await self._device.set_window_shade_level( + kwargs[ATTR_POSITION], set_status=False + ) + else: + await self._device.set_level(kwargs[ATTR_POSITION], set_status=False) async def async_update(self) -> None: """Update the attrs of the cover.""" @@ -117,6 +130,11 @@ class SmartThingsCover(SmartThingsEntity, CoverEntity): self._device_class = CoverDeviceClass.GARAGE self._state = VALUE_TO_STATE.get(self._device.status.door) + if Capability.window_shade_level in self._device.capabilities: + self._current_cover_position = self._device.status.shade_level + elif Capability.switch_level in self._device.capabilities: + self._current_cover_position = self._device.status.level + self._state_attrs = {} battery = self._device.status.attributes[Attribute.battery].value if battery is not None: @@ -142,9 +160,7 @@ class SmartThingsCover(SmartThingsEntity, CoverEntity): @property def current_cover_position(self) -> int | None: """Return current position of cover.""" - if not self.supported_features & CoverEntityFeature.SET_POSITION: - return None - return self._device.status.level + return self._current_cover_position @property def device_class(self) -> CoverDeviceClass | None: diff --git a/homeassistant/components/smartthings/manifest.json b/homeassistant/components/smartthings/manifest.json index 29eb681dc4d..89e5071051c 100644 --- a/homeassistant/components/smartthings/manifest.json +++ b/homeassistant/components/smartthings/manifest.json @@ -30,5 +30,5 @@ "documentation": "https://www.home-assistant.io/integrations/smartthings", "iot_class": "cloud_push", "loggers": ["httpsig", "pysmartapp", "pysmartthings"], - "requirements": ["pysmartapp==0.3.3", "pysmartthings==0.7.6"] + "requirements": ["pysmartapp==0.3.5", "pysmartthings==0.7.8"] } diff --git a/requirements_all.txt b/requirements_all.txt index b1989ae25a0..9bf2a461a12 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2006,10 +2006,10 @@ pysma==0.7.3 pysmappee==0.2.29 # homeassistant.components.smartthings -pysmartapp==0.3.3 +pysmartapp==0.3.5 # homeassistant.components.smartthings -pysmartthings==0.7.6 +pysmartthings==0.7.8 # homeassistant.components.edl21 pysml==0.0.12 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 75b8fc80d06..1487828b246 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1492,10 +1492,10 @@ pysma==0.7.3 pysmappee==0.2.29 # homeassistant.components.smartthings -pysmartapp==0.3.3 +pysmartapp==0.3.5 # homeassistant.components.smartthings -pysmartthings==0.7.6 +pysmartthings==0.7.8 # homeassistant.components.edl21 pysml==0.0.12 diff --git a/tests/components/smartthings/test_cover.py b/tests/components/smartthings/test_cover.py index bdf3cc901a7..bf781c71c4e 100644 --- a/tests/components/smartthings/test_cover.py +++ b/tests/components/smartthings/test_cover.py @@ -113,8 +113,10 @@ async def test_close(hass: HomeAssistant, device_factory) -> None: assert state.state == STATE_CLOSING -async def test_set_cover_position(hass: HomeAssistant, device_factory) -> None: - """Test the cover sets to the specific position.""" +async def test_set_cover_position_switch_level( + hass: HomeAssistant, device_factory +) -> None: + """Test the cover sets to the specific position for legacy devices that use Capability.switch_level.""" # Arrange device = device_factory( "Shade", @@ -140,6 +142,37 @@ async def test_set_cover_position(hass: HomeAssistant, device_factory) -> None: assert device._api.post_device_command.call_count == 1 # type: ignore +async def test_set_cover_position(hass: HomeAssistant, device_factory) -> None: + """Test the cover sets to the specific position.""" + # Arrange + device = device_factory( + "Shade", + [Capability.window_shade, Capability.battery, Capability.window_shade_level], + { + Attribute.window_shade: "opening", + Attribute.battery: 95, + Attribute.shade_level: 10, + }, + ) + await setup_platform(hass, COVER_DOMAIN, devices=[device]) + # Act + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_SET_COVER_POSITION, + {ATTR_POSITION: 50, "entity_id": "all"}, + blocking=True, + ) + + state = hass.states.get("cover.shade") + # Result of call does not update state + assert state.state == STATE_OPENING + assert state.attributes[ATTR_BATTERY_LEVEL] == 95 + assert state.attributes[ATTR_CURRENT_POSITION] == 10 + # Ensure API called + + assert device._api.post_device_command.call_count == 1 # type: ignore + + async def test_set_cover_position_unsupported( hass: HomeAssistant, device_factory ) -> None: