diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 38d8e89269a..b0a9c5a4c5a 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -933,6 +933,44 @@ async def async_service_temperature_set( entity: ClimateEntity, service_call: ServiceCall ) -> None: """Handle set temperature service.""" + if ( + ATTR_TEMPERATURE in service_call.data + and not entity.supported_features & ClimateEntityFeature.TARGET_TEMPERATURE + ): + report_issue = async_suggest_report_issue( + entity.hass, + integration_domain=entity.platform.platform_name, + module=type(entity).__module__, + ) + _LOGGER.warning( + ( + "%s::%s set_temperature action was used with temperature but the entity does not " + "implement the ClimateEntityFeature.TARGET_TEMPERATURE feature. Please %s" + ), + entity.platform.platform_name, + entity.__class__.__name__, + report_issue, + ) + if ( + ATTR_TARGET_TEMP_LOW in service_call.data + and not entity.supported_features + & ClimateEntityFeature.TARGET_TEMPERATURE_RANGE + ): + report_issue = async_suggest_report_issue( + entity.hass, + integration_domain=entity.platform.platform_name, + module=type(entity).__module__, + ) + _LOGGER.warning( + ( + "%s::%s set_temperature action was used with target_temp_low but the entity does not " + "implement the ClimateEntityFeature.TARGET_TEMPERATURE_RANGE feature. Please %s" + ), + entity.platform.platform_name, + entity.__class__.__name__, + report_issue, + ) + hass = entity.hass kwargs = {} min_temp = entity.min_temp diff --git a/tests/components/climate/test_init.py b/tests/components/climate/test_init.py index 6342313d1da..b3f26dc775f 100644 --- a/tests/components/climate/test_init.py +++ b/tests/components/climate/test_init.py @@ -110,6 +110,9 @@ class MockClimateEntity(MockEntity, ClimateEntity): _attr_swing_mode = "auto" _attr_swing_modes = ["auto", "off"] _attr_temperature_unit = UnitOfTemperature.CELSIUS + _attr_target_temperature = 20 + _attr_target_temperature_high = 25 + _attr_target_temperature_low = 15 @property def hvac_mode(self) -> HVACMode: @@ -143,6 +146,14 @@ class MockClimateEntity(MockEntity, ClimateEntity): """Set new target hvac mode.""" self._attr_hvac_mode = hvac_mode + def set_temperature(self, **kwargs: Any) -> None: + """Set new target temperature.""" + if ATTR_TEMPERATURE in kwargs: + self._attr_target_temperature = kwargs[ATTR_TEMPERATURE] + if ATTR_TARGET_TEMP_HIGH in kwargs: + self._attr_target_temperature_high = kwargs[ATTR_TARGET_TEMP_HIGH] + self._attr_target_temperature_low = kwargs[ATTR_TARGET_TEMP_LOW] + class MockClimateEntityTestMethods(MockClimateEntity): """Mock Climate device.""" @@ -242,6 +253,73 @@ def test_deprecated_current_constants( ) +async def test_temperature_features_is_valid( + hass: HomeAssistant, + register_test_integration: MockConfigEntry, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test correct features for setting temperature.""" + + class MockClimateTempEntity(MockClimateEntity): + @property + def supported_features(self) -> int: + """Return supported features.""" + return ClimateEntityFeature.TARGET_TEMPERATURE_RANGE + + class MockClimateTempRangeEntity(MockClimateEntity): + @property + def supported_features(self) -> int: + """Return supported features.""" + return ClimateEntityFeature.TARGET_TEMPERATURE + + climate_temp_entity = MockClimateTempEntity( + name="test", entity_id="climate.test_temp" + ) + climate_temp_range_entity = MockClimateTempRangeEntity( + name="test", entity_id="climate.test_range" + ) + + setup_test_component_platform( + hass, + DOMAIN, + entities=[climate_temp_entity, climate_temp_range_entity], + from_config_entry=True, + ) + await hass.config_entries.async_setup(register_test_integration.entry_id) + await hass.async_block_till_done() + + await hass.services.async_call( + DOMAIN, + SERVICE_SET_TEMPERATURE, + { + "entity_id": "climate.test_temp", + "temperature": 20, + }, + blocking=True, + ) + assert ( + "MockClimateTempEntity set_temperature action was used " + "with temperature but the entity does not " + "implement the ClimateEntityFeature.TARGET_TEMPERATURE feature. Please" + ) in caplog.text + + await hass.services.async_call( + DOMAIN, + SERVICE_SET_TEMPERATURE, + { + "entity_id": "climate.test_range", + "target_temp_low": 20, + "target_temp_high": 25, + }, + blocking=True, + ) + assert ( + "MockClimateTempRangeEntity set_temperature action was used with " + "target_temp_low but the entity does not " + "implement the ClimateEntityFeature.TARGET_TEMPERATURE_RANGE feature. Please" + ) in caplog.text + + async def test_mode_validation( hass: HomeAssistant, register_test_integration: MockConfigEntry,