diff --git a/homeassistant/components/shelly/climate.py b/homeassistant/components/shelly/climate.py index f8e157a6a5d..f1491acdd81 100644 --- a/homeassistant/components/shelly/climate.py +++ b/homeassistant/components/shelly/climate.py @@ -36,6 +36,7 @@ from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM from .const import ( BLU_TRV_TEMPERATURE_SETTINGS, + BLU_TRV_TIMEOUT, DOMAIN, LOGGER, NOT_CALIBRATED_ISSUE_ID, @@ -604,4 +605,5 @@ class RpcBluTrvClimate(ShellyRpcEntity, ClimateEntity): "method": "Trv.SetTarget", "params": {"id": 0, "target_C": target_temp}, }, + timeout=BLU_TRV_TIMEOUT, ) diff --git a/homeassistant/components/shelly/const.py b/homeassistant/components/shelly/const.py index f81ba5ca7f7..e78a6f1a59d 100644 --- a/homeassistant/components/shelly/const.py +++ b/homeassistant/components/shelly/const.py @@ -265,3 +265,6 @@ VIRTUAL_NUMBER_MODE_MAP = { API_WS_URL = "/api/shelly/ws" COMPONENT_ID_PATTERN = re.compile(r"[a-z\d]+:\d+") + +# value confirmed by Shelly team +BLU_TRV_TIMEOUT = 60 diff --git a/homeassistant/components/shelly/entity.py b/homeassistant/components/shelly/entity.py index 8c9044aeaff..001727c74b3 100644 --- a/homeassistant/components/shelly/entity.py +++ b/homeassistant/components/shelly/entity.py @@ -390,15 +390,20 @@ class ShellyRpcEntity(CoordinatorEntity[ShellyRpcCoordinator]): """Handle device update.""" self.async_write_ha_state() - async def call_rpc(self, method: str, params: Any) -> Any: + async def call_rpc( + self, method: str, params: Any, timeout: float | None = None + ) -> Any: """Call RPC method.""" LOGGER.debug( - "Call RPC for entity %s, method: %s, params: %s", + "Call RPC for entity %s, method: %s, params: %s, timeout: %s", self.name, method, params, + timeout, ) try: + if timeout: + return await self.coordinator.device.call_rpc(method, params, timeout) return await self.coordinator.device.call_rpc(method, params) except DeviceConnectionError as err: self.coordinator.last_update_success = False diff --git a/homeassistant/components/shelly/manifest.json b/homeassistant/components/shelly/manifest.json index cf5c59da5e3..e0d8c03ffc4 100644 --- a/homeassistant/components/shelly/manifest.json +++ b/homeassistant/components/shelly/manifest.json @@ -8,7 +8,7 @@ "integration_type": "device", "iot_class": "local_push", "loggers": ["aioshelly"], - "requirements": ["aioshelly==12.3.1"], + "requirements": ["aioshelly==12.3.2"], "zeroconf": [ { "type": "_http._tcp.local.", diff --git a/homeassistant/components/shelly/number.py b/homeassistant/components/shelly/number.py index fb61c885423..7140c79fbb6 100644 --- a/homeassistant/components/shelly/number.py +++ b/homeassistant/components/shelly/number.py @@ -25,7 +25,7 @@ from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH, DeviceIn from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_registry import RegistryEntry -from .const import CONF_SLEEP_PERIOD, LOGGER, VIRTUAL_NUMBER_MODE_MAP +from .const import BLU_TRV_TIMEOUT, CONF_SLEEP_PERIOD, LOGGER, VIRTUAL_NUMBER_MODE_MAP from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator from .entity import ( BlockEntityDescription, @@ -127,6 +127,17 @@ class RpcBluTrvNumber(RpcNumber): connections={(CONNECTION_BLUETOOTH, ble_addr)} ) + async def async_set_native_value(self, value: float) -> None: + """Change the value.""" + if TYPE_CHECKING: + assert isinstance(self._id, int) + + await self.call_rpc( + self.entity_description.method, + self.entity_description.method_params_fn(self._id, value), + timeout=BLU_TRV_TIMEOUT, + ) + NUMBERS: dict[tuple[str, str], BlockNumberDescription] = { ("device", "valvePos"): BlockNumberDescription( diff --git a/requirements_all.txt b/requirements_all.txt index 1a86e1b0560..11973ad3c2f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -368,7 +368,7 @@ aioruuvigateway==0.1.0 aiosenz==1.0.0 # homeassistant.components.shelly -aioshelly==12.3.1 +aioshelly==12.3.2 # homeassistant.components.skybell aioskybell==22.7.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9dcae1ea28a..7a3fd7857cb 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -350,7 +350,7 @@ aioruuvigateway==0.1.0 aiosenz==1.0.0 # homeassistant.components.shelly -aioshelly==12.3.1 +aioshelly==12.3.2 # homeassistant.components.skybell aioskybell==22.7.0 diff --git a/tests/components/shelly/test_climate.py b/tests/components/shelly/test_climate.py index 352bdcb0a7d..5ad298c15a1 100644 --- a/tests/components/shelly/test_climate.py +++ b/tests/components/shelly/test_climate.py @@ -26,7 +26,7 @@ from homeassistant.components.climate import ( HVACAction, HVACMode, ) -from homeassistant.components.shelly.const import DOMAIN +from homeassistant.components.shelly.const import BLU_TRV_TIMEOUT, DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState from homeassistant.const import ( @@ -804,6 +804,7 @@ async def test_blu_trv_climate_set_temperature( "method": "Trv.SetTarget", "params": {"id": 0, "target_C": 28.0}, }, + BLU_TRV_TIMEOUT, ) assert get_entity_attribute(hass, entity_id, ATTR_TEMPERATURE) == 28 diff --git a/tests/components/shelly/test_number.py b/tests/components/shelly/test_number.py index 2a64ab839ea..15ed098093b 100644 --- a/tests/components/shelly/test_number.py +++ b/tests/components/shelly/test_number.py @@ -18,7 +18,7 @@ from homeassistant.components.number import ( SERVICE_SET_VALUE, NumberMode, ) -from homeassistant.components.shelly.const import DOMAIN +from homeassistant.components.shelly.const import BLU_TRV_TIMEOUT, DOMAIN from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState from homeassistant.const import ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, STATE_UNKNOWN from homeassistant.core import HomeAssistant, State @@ -415,3 +415,39 @@ async def test_blu_trv_number_entity( entry = entity_registry.async_get(entity_id) assert entry == snapshot(name=f"{entity_id}-entry") + + +async def test_blu_trv_set_value( + hass: HomeAssistant, + mock_blu_trv: Mock, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test the set value action for BLU TRV number entity.""" + await init_integration(hass, 3, model=MODEL_BLU_GATEWAY_GEN3) + + entity_id = f"{NUMBER_DOMAIN}.trv_name_external_temperature" + + assert hass.states.get(entity_id).state == "15.2" + + monkeypatch.setitem(mock_blu_trv.status["blutrv:200"], "current_C", 22.2) + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: f"{NUMBER_DOMAIN}.trv_name_external_temperature", + ATTR_VALUE: 22.2, + }, + blocking=True, + ) + mock_blu_trv.mock_update() + mock_blu_trv.call_rpc.assert_called_once_with( + "BluTRV.Call", + { + "id": 200, + "method": "Trv.SetExternalTemperature", + "params": {"id": 0, "t_C": 22.2}, + }, + BLU_TRV_TIMEOUT, + ) + + assert hass.states.get(entity_id).state == "22.2"