mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 07:51:46 -05:00
Report an uncalibrated Shelly roller by its last direction (#180485)
This commit is contained in:
@@ -120,13 +120,33 @@ class BlockShellyCover(ShellyBlockAttributeEntity, CoverEntity):
|
||||
self.control_result: dict[str, Any] | None = None
|
||||
self._attr_name = None # Main device entity
|
||||
self._attr_unique_id: str = f"{coordinator.mac}-{block.description}"
|
||||
if self.coordinator.device.settings["rollers"][0]["positioning"]:
|
||||
self._positioning: bool = self.coordinator.device.settings["rollers"][0][
|
||||
"positioning"
|
||||
]
|
||||
# Without positioning the direction it last travelled in is all there is,
|
||||
# and that says nothing about where it stopped
|
||||
self._attr_assumed_state = not self._positioning
|
||||
if self._positioning:
|
||||
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
|
||||
|
||||
@property
|
||||
@override
|
||||
def is_closed(self) -> bool:
|
||||
def is_closed(self) -> bool | None:
|
||||
"""If cover is closed."""
|
||||
if not self._positioning:
|
||||
# An uncalibrated roller parks its position on 101, so the direction
|
||||
# it last travelled in is all there is to go on
|
||||
last_direction = self.coordinator.device.status["rollers"][0].get(
|
||||
"last_direction"
|
||||
)
|
||||
if self.control_result:
|
||||
last_direction = self.control_result.get(
|
||||
"last_direction", last_direction
|
||||
)
|
||||
if not last_direction:
|
||||
return None
|
||||
return cast(str, last_direction) == "close"
|
||||
|
||||
if self.control_result:
|
||||
return cast(bool, self.control_result["current_pos"] == 0)
|
||||
|
||||
@@ -134,8 +154,11 @@ class BlockShellyCover(ShellyBlockAttributeEntity, CoverEntity):
|
||||
|
||||
@property
|
||||
@override
|
||||
def current_cover_position(self) -> int:
|
||||
def current_cover_position(self) -> int | None:
|
||||
"""Position of the cover."""
|
||||
if not self._positioning:
|
||||
return None
|
||||
|
||||
if self.control_result:
|
||||
return cast(int, self.control_result["current_pos"])
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Tests for Shelly cover platform."""
|
||||
|
||||
from copy import deepcopy
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import AsyncMock, Mock
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
@@ -23,7 +23,13 @@ from homeassistant.components.cover import (
|
||||
CoverState,
|
||||
)
|
||||
from homeassistant.components.shelly.const import RPC_COVER_UPDATE_TIME_SEC
|
||||
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform
|
||||
from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE,
|
||||
ATTR_ENTITY_ID,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_registry import EntityRegistry
|
||||
|
||||
@@ -111,6 +117,83 @@ async def test_block_device_update(
|
||||
state = hass.states.get("cover.test_name")
|
||||
assert state
|
||||
assert state.state == CoverState.OPEN
|
||||
assert ATTR_ASSUMED_STATE not in state.attributes
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("last_direction", "expected_state"),
|
||||
[
|
||||
("close", CoverState.CLOSED),
|
||||
("open", CoverState.OPEN),
|
||||
# Nothing has moved since the device booted
|
||||
(None, STATE_UNKNOWN),
|
||||
],
|
||||
)
|
||||
async def test_block_device_roller_without_positioning(
|
||||
hass: HomeAssistant,
|
||||
mock_block_device: Mock,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
last_direction: str | None,
|
||||
expected_state: str,
|
||||
) -> None:
|
||||
"""Test an uncalibrated roller reports the direction it last travelled in."""
|
||||
settings = deepcopy(mock_block_device.settings)
|
||||
settings["rollers"][0]["positioning"] = False
|
||||
monkeypatch.setattr(mock_block_device, "settings", settings)
|
||||
|
||||
status = deepcopy(mock_block_device.status)
|
||||
# An uncalibrated roller parks its position on 101
|
||||
status["rollers"] = [{"current_pos": 101, "last_direction": last_direction}]
|
||||
monkeypatch.setattr(mock_block_device, "status", status)
|
||||
|
||||
await init_integration(hass, 1)
|
||||
|
||||
assert (state := hass.states.get("cover.test_name"))
|
||||
assert state.state == expected_state
|
||||
assert state.attributes.get(ATTR_CURRENT_POSITION) is None
|
||||
# Stopping mid travel leaves the direction saying more than it knows, so
|
||||
# both buttons stay available
|
||||
assert state.attributes[ATTR_ASSUMED_STATE] is True
|
||||
|
||||
|
||||
async def test_block_device_roller_without_positioning_stopped(
|
||||
hass: HomeAssistant,
|
||||
mock_block_device: Mock,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Test stopping an uncalibrated roller keeps it on its last direction."""
|
||||
settings = deepcopy(mock_block_device.settings)
|
||||
settings["rollers"][0]["positioning"] = False
|
||||
monkeypatch.setattr(mock_block_device, "settings", settings)
|
||||
|
||||
status = deepcopy(mock_block_device.status)
|
||||
status["rollers"] = [{"current_pos": 101, "last_direction": "close"}]
|
||||
monkeypatch.setattr(mock_block_device, "status", status)
|
||||
|
||||
# An uncalibrated roller answers a command with position 101 as well
|
||||
monkeypatch.setattr(
|
||||
mock_block_device.blocks[ROLLER_BLOCK_ID],
|
||||
"set_state",
|
||||
AsyncMock(
|
||||
side_effect=lambda go, roller_pos=0: {"current_pos": 101, "state": go}
|
||||
),
|
||||
)
|
||||
|
||||
await init_integration(hass, 1)
|
||||
|
||||
entity_id = "cover.test_name"
|
||||
assert (state := hass.states.get(entity_id))
|
||||
assert state.state == CoverState.CLOSED
|
||||
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_STOP_COVER,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert (state := hass.states.get(entity_id))
|
||||
assert state.state == CoverState.CLOSED
|
||||
|
||||
|
||||
async def test_block_device_no_roller_blocks(
|
||||
|
||||
Reference in New Issue
Block a user