mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Remove deprecated aux heat from Climate Entity component (#145151)
This commit is contained in:
parent
b16d4dd94b
commit
010b4f6b15
@ -18,23 +18,20 @@ from homeassistant.const import (
|
|||||||
SERVICE_TOGGLE,
|
SERVICE_TOGGLE,
|
||||||
SERVICE_TURN_OFF,
|
SERVICE_TURN_OFF,
|
||||||
SERVICE_TURN_ON,
|
SERVICE_TURN_ON,
|
||||||
STATE_OFF,
|
|
||||||
STATE_ON,
|
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||||
from homeassistant.exceptions import ServiceValidationError
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import config_validation as cv, issue_registry as ir
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity, EntityDescription
|
from homeassistant.helpers.entity import Entity, EntityDescription
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.temperature import display_temp as show_temp
|
from homeassistant.helpers.temperature import display_temp as show_temp
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.loader import async_get_issue_tracker, async_suggest_report_issue
|
from homeassistant.loader import async_suggest_report_issue
|
||||||
from homeassistant.util.hass_dict import HassKey
|
from homeassistant.util.hass_dict import HassKey
|
||||||
from homeassistant.util.unit_conversion import TemperatureConverter
|
from homeassistant.util.unit_conversion import TemperatureConverter
|
||||||
|
|
||||||
from .const import ( # noqa: F401
|
from .const import ( # noqa: F401
|
||||||
ATTR_AUX_HEAT,
|
|
||||||
ATTR_CURRENT_HUMIDITY,
|
ATTR_CURRENT_HUMIDITY,
|
||||||
ATTR_CURRENT_TEMPERATURE,
|
ATTR_CURRENT_TEMPERATURE,
|
||||||
ATTR_FAN_MODE,
|
ATTR_FAN_MODE,
|
||||||
@ -77,7 +74,6 @@ from .const import ( # noqa: F401
|
|||||||
PRESET_HOME,
|
PRESET_HOME,
|
||||||
PRESET_NONE,
|
PRESET_NONE,
|
||||||
PRESET_SLEEP,
|
PRESET_SLEEP,
|
||||||
SERVICE_SET_AUX_HEAT,
|
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
SERVICE_SET_HUMIDITY,
|
SERVICE_SET_HUMIDITY,
|
||||||
SERVICE_SET_HVAC_MODE,
|
SERVICE_SET_HVAC_MODE,
|
||||||
@ -168,12 +164,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
"async_handle_set_preset_mode_service",
|
"async_handle_set_preset_mode_service",
|
||||||
[ClimateEntityFeature.PRESET_MODE],
|
[ClimateEntityFeature.PRESET_MODE],
|
||||||
)
|
)
|
||||||
component.async_register_entity_service(
|
|
||||||
SERVICE_SET_AUX_HEAT,
|
|
||||||
{vol.Required(ATTR_AUX_HEAT): cv.boolean},
|
|
||||||
async_service_aux_heat,
|
|
||||||
[ClimateEntityFeature.AUX_HEAT],
|
|
||||||
)
|
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
SET_TEMPERATURE_SCHEMA,
|
SET_TEMPERATURE_SCHEMA,
|
||||||
@ -239,7 +229,6 @@ CACHED_PROPERTIES_WITH_ATTR_ = {
|
|||||||
"target_temperature_low",
|
"target_temperature_low",
|
||||||
"preset_mode",
|
"preset_mode",
|
||||||
"preset_modes",
|
"preset_modes",
|
||||||
"is_aux_heat",
|
|
||||||
"fan_mode",
|
"fan_mode",
|
||||||
"fan_modes",
|
"fan_modes",
|
||||||
"swing_mode",
|
"swing_mode",
|
||||||
@ -279,7 +268,6 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
_attr_hvac_action: HVACAction | None = None
|
_attr_hvac_action: HVACAction | None = None
|
||||||
_attr_hvac_mode: HVACMode | None
|
_attr_hvac_mode: HVACMode | None
|
||||||
_attr_hvac_modes: list[HVACMode]
|
_attr_hvac_modes: list[HVACMode]
|
||||||
_attr_is_aux_heat: bool | None
|
|
||||||
_attr_max_humidity: float = DEFAULT_MAX_HUMIDITY
|
_attr_max_humidity: float = DEFAULT_MAX_HUMIDITY
|
||||||
_attr_max_temp: float
|
_attr_max_temp: float
|
||||||
_attr_min_humidity: float = DEFAULT_MIN_HUMIDITY
|
_attr_min_humidity: float = DEFAULT_MIN_HUMIDITY
|
||||||
@ -299,52 +287,6 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
_attr_target_temperature: float | None = None
|
_attr_target_temperature: float | None = None
|
||||||
_attr_temperature_unit: str
|
_attr_temperature_unit: str
|
||||||
|
|
||||||
__climate_reported_legacy_aux = False
|
|
||||||
|
|
||||||
def _report_legacy_aux(self) -> None:
|
|
||||||
"""Log warning and create an issue if the entity implements legacy auxiliary heater."""
|
|
||||||
|
|
||||||
report_issue = async_suggest_report_issue(
|
|
||||||
self.hass,
|
|
||||||
integration_domain=self.platform.platform_name,
|
|
||||||
module=type(self).__module__,
|
|
||||||
)
|
|
||||||
_LOGGER.warning(
|
|
||||||
(
|
|
||||||
"%s::%s implements the `is_aux_heat` property or uses the auxiliary "
|
|
||||||
"heater methods in a subclass of ClimateEntity which is "
|
|
||||||
"deprecated and will be unsupported from Home Assistant 2025.4."
|
|
||||||
" Please %s"
|
|
||||||
),
|
|
||||||
self.platform.platform_name,
|
|
||||||
self.__class__.__name__,
|
|
||||||
report_issue,
|
|
||||||
)
|
|
||||||
|
|
||||||
translation_placeholders = {"platform": self.platform.platform_name}
|
|
||||||
translation_key = "deprecated_climate_aux_no_url"
|
|
||||||
issue_tracker = async_get_issue_tracker(
|
|
||||||
self.hass,
|
|
||||||
integration_domain=self.platform.platform_name,
|
|
||||||
module=type(self).__module__,
|
|
||||||
)
|
|
||||||
if issue_tracker:
|
|
||||||
translation_placeholders["issue_tracker"] = issue_tracker
|
|
||||||
translation_key = "deprecated_climate_aux_url_custom"
|
|
||||||
ir.async_create_issue(
|
|
||||||
self.hass,
|
|
||||||
DOMAIN,
|
|
||||||
f"deprecated_climate_aux_{self.platform.platform_name}",
|
|
||||||
breaks_in_ha_version="2025.4.0",
|
|
||||||
is_fixable=False,
|
|
||||||
is_persistent=False,
|
|
||||||
issue_domain=self.platform.platform_name,
|
|
||||||
severity=ir.IssueSeverity.WARNING,
|
|
||||||
translation_key=translation_key,
|
|
||||||
translation_placeholders=translation_placeholders,
|
|
||||||
)
|
|
||||||
self.__climate_reported_legacy_aux = True
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@property
|
@property
|
||||||
def state(self) -> str | None:
|
def state(self) -> str | None:
|
||||||
@ -453,14 +395,6 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
if ClimateEntityFeature.SWING_HORIZONTAL_MODE in supported_features:
|
if ClimateEntityFeature.SWING_HORIZONTAL_MODE in supported_features:
|
||||||
data[ATTR_SWING_HORIZONTAL_MODE] = self.swing_horizontal_mode
|
data[ATTR_SWING_HORIZONTAL_MODE] = self.swing_horizontal_mode
|
||||||
|
|
||||||
if ClimateEntityFeature.AUX_HEAT in supported_features:
|
|
||||||
data[ATTR_AUX_HEAT] = STATE_ON if self.is_aux_heat else STATE_OFF
|
|
||||||
if (
|
|
||||||
self.__climate_reported_legacy_aux is False
|
|
||||||
and "custom_components" in type(self).__module__
|
|
||||||
):
|
|
||||||
self._report_legacy_aux()
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -540,14 +474,6 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
"""
|
"""
|
||||||
return self._attr_preset_modes
|
return self._attr_preset_modes
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def is_aux_heat(self) -> bool | None:
|
|
||||||
"""Return true if aux heater.
|
|
||||||
|
|
||||||
Requires ClimateEntityFeature.AUX_HEAT.
|
|
||||||
"""
|
|
||||||
return self._attr_is_aux_heat
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def fan_mode(self) -> str | None:
|
def fan_mode(self) -> str | None:
|
||||||
"""Return the fan setting.
|
"""Return the fan setting.
|
||||||
@ -732,22 +658,6 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
"""Set new preset mode."""
|
"""Set new preset mode."""
|
||||||
await self.hass.async_add_executor_job(self.set_preset_mode, preset_mode)
|
await self.hass.async_add_executor_job(self.set_preset_mode, preset_mode)
|
||||||
|
|
||||||
def turn_aux_heat_on(self) -> None:
|
|
||||||
"""Turn auxiliary heater on."""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
async def async_turn_aux_heat_on(self) -> None:
|
|
||||||
"""Turn auxiliary heater on."""
|
|
||||||
await self.hass.async_add_executor_job(self.turn_aux_heat_on)
|
|
||||||
|
|
||||||
def turn_aux_heat_off(self) -> None:
|
|
||||||
"""Turn auxiliary heater off."""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
async def async_turn_aux_heat_off(self) -> None:
|
|
||||||
"""Turn auxiliary heater off."""
|
|
||||||
await self.hass.async_add_executor_job(self.turn_aux_heat_off)
|
|
||||||
|
|
||||||
def turn_on(self) -> None:
|
def turn_on(self) -> None:
|
||||||
"""Turn the entity on."""
|
"""Turn the entity on."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@ -845,16 +755,6 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
return self._attr_max_humidity
|
return self._attr_max_humidity
|
||||||
|
|
||||||
|
|
||||||
async def async_service_aux_heat(
|
|
||||||
entity: ClimateEntity, service_call: ServiceCall
|
|
||||||
) -> None:
|
|
||||||
"""Handle aux heat service."""
|
|
||||||
if service_call.data[ATTR_AUX_HEAT]:
|
|
||||||
await entity.async_turn_aux_heat_on()
|
|
||||||
else:
|
|
||||||
await entity.async_turn_aux_heat_off()
|
|
||||||
|
|
||||||
|
|
||||||
async def async_service_humidity_set(
|
async def async_service_humidity_set(
|
||||||
entity: ClimateEntity, service_call: ServiceCall
|
entity: ClimateEntity, service_call: ServiceCall
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -96,7 +96,6 @@ class HVACAction(StrEnum):
|
|||||||
CURRENT_HVAC_ACTIONS = [cls.value for cls in HVACAction]
|
CURRENT_HVAC_ACTIONS = [cls.value for cls in HVACAction]
|
||||||
|
|
||||||
|
|
||||||
ATTR_AUX_HEAT = "aux_heat"
|
|
||||||
ATTR_CURRENT_HUMIDITY = "current_humidity"
|
ATTR_CURRENT_HUMIDITY = "current_humidity"
|
||||||
ATTR_CURRENT_TEMPERATURE = "current_temperature"
|
ATTR_CURRENT_TEMPERATURE = "current_temperature"
|
||||||
ATTR_FAN_MODES = "fan_modes"
|
ATTR_FAN_MODES = "fan_modes"
|
||||||
@ -128,7 +127,6 @@ DOMAIN = "climate"
|
|||||||
|
|
||||||
INTENT_SET_TEMPERATURE = "HassClimateSetTemperature"
|
INTENT_SET_TEMPERATURE = "HassClimateSetTemperature"
|
||||||
|
|
||||||
SERVICE_SET_AUX_HEAT = "set_aux_heat"
|
|
||||||
SERVICE_SET_FAN_MODE = "set_fan_mode"
|
SERVICE_SET_FAN_MODE = "set_fan_mode"
|
||||||
SERVICE_SET_PRESET_MODE = "set_preset_mode"
|
SERVICE_SET_PRESET_MODE = "set_preset_mode"
|
||||||
SERVICE_SET_HUMIDITY = "set_humidity"
|
SERVICE_SET_HUMIDITY = "set_humidity"
|
||||||
@ -147,7 +145,6 @@ class ClimateEntityFeature(IntFlag):
|
|||||||
FAN_MODE = 8
|
FAN_MODE = 8
|
||||||
PRESET_MODE = 16
|
PRESET_MODE = 16
|
||||||
SWING_MODE = 32
|
SWING_MODE = 32
|
||||||
AUX_HEAT = 64
|
|
||||||
TURN_OFF = 128
|
TURN_OFF = 128
|
||||||
TURN_ON = 256
|
TURN_ON = 256
|
||||||
SWING_HORIZONTAL_MODE = 512
|
SWING_HORIZONTAL_MODE = 512
|
||||||
|
@ -1,17 +1,5 @@
|
|||||||
# Describes the format for available climate services
|
# Describes the format for available climate services
|
||||||
|
|
||||||
set_aux_heat:
|
|
||||||
target:
|
|
||||||
entity:
|
|
||||||
domain: climate
|
|
||||||
supported_features:
|
|
||||||
- climate.ClimateEntityFeature.AUX_HEAT
|
|
||||||
fields:
|
|
||||||
aux_heat:
|
|
||||||
required: true
|
|
||||||
selector:
|
|
||||||
boolean:
|
|
||||||
|
|
||||||
set_preset_mode:
|
set_preset_mode:
|
||||||
target:
|
target:
|
||||||
entity:
|
entity:
|
||||||
|
@ -12,7 +12,6 @@ from homeassistant.helpers.significant_change import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
ATTR_AUX_HEAT,
|
|
||||||
ATTR_CURRENT_HUMIDITY,
|
ATTR_CURRENT_HUMIDITY,
|
||||||
ATTR_CURRENT_TEMPERATURE,
|
ATTR_CURRENT_TEMPERATURE,
|
||||||
ATTR_FAN_MODE,
|
ATTR_FAN_MODE,
|
||||||
@ -27,7 +26,6 @@ from . import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
SIGNIFICANT_ATTRIBUTES: set[str] = {
|
SIGNIFICANT_ATTRIBUTES: set[str] = {
|
||||||
ATTR_AUX_HEAT,
|
|
||||||
ATTR_CURRENT_HUMIDITY,
|
ATTR_CURRENT_HUMIDITY,
|
||||||
ATTR_CURRENT_TEMPERATURE,
|
ATTR_CURRENT_TEMPERATURE,
|
||||||
ATTR_FAN_MODE,
|
ATTR_FAN_MODE,
|
||||||
@ -67,7 +65,6 @@ def async_check_significant_change(
|
|||||||
|
|
||||||
for attr_name in changed_attrs:
|
for attr_name in changed_attrs:
|
||||||
if attr_name in [
|
if attr_name in [
|
||||||
ATTR_AUX_HEAT,
|
|
||||||
ATTR_FAN_MODE,
|
ATTR_FAN_MODE,
|
||||||
ATTR_HVAC_ACTION,
|
ATTR_HVAC_ACTION,
|
||||||
ATTR_PRESET_MODE,
|
ATTR_PRESET_MODE,
|
||||||
|
@ -36,9 +36,6 @@
|
|||||||
"fan_only": "Fan only"
|
"fan_only": "Fan only"
|
||||||
},
|
},
|
||||||
"state_attributes": {
|
"state_attributes": {
|
||||||
"aux_heat": {
|
|
||||||
"name": "Aux heat"
|
|
||||||
},
|
|
||||||
"current_humidity": {
|
"current_humidity": {
|
||||||
"name": "Current humidity"
|
"name": "Current humidity"
|
||||||
},
|
},
|
||||||
@ -149,16 +146,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"set_aux_heat": {
|
|
||||||
"name": "Turn on/off auxiliary heater",
|
|
||||||
"description": "Turns auxiliary heater on/off.",
|
|
||||||
"fields": {
|
|
||||||
"aux_heat": {
|
|
||||||
"name": "Auxiliary heating",
|
|
||||||
"description": "New value of auxiliary heater."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"set_preset_mode": {
|
"set_preset_mode": {
|
||||||
"name": "Set preset mode",
|
"name": "Set preset mode",
|
||||||
"description": "Sets preset mode.",
|
"description": "Sets preset mode.",
|
||||||
@ -267,16 +254,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"issues": {
|
|
||||||
"deprecated_climate_aux_url_custom": {
|
|
||||||
"title": "The {platform} custom integration is using deprecated climate auxiliary heater",
|
|
||||||
"description": "The custom integration `{platform}` implements the `is_aux_heat` property or uses the auxiliary heater methods in a subclass of ClimateEntity.\n\nPlease create a bug report at {issue_tracker}.\n\nOnce an updated version of `{platform}` is available, install it and restart Home Assistant to fix this issue."
|
|
||||||
},
|
|
||||||
"deprecated_climate_aux_no_url": {
|
|
||||||
"title": "[%key:component::climate::issues::deprecated_climate_aux_url_custom::title%]",
|
|
||||||
"description": "The custom integration `{platform}` implements the `is_aux_heat` property or uses the auxiliary heater methods in a subclass of ClimateEntity.\n\nPlease report it to the author of the {platform} integration.\n\nOnce an updated version of `{platform}` is available, install it and restart Home Assistant to fix this issue."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exceptions": {
|
"exceptions": {
|
||||||
"not_valid_preset_mode": {
|
"not_valid_preset_mode": {
|
||||||
"message": "Preset mode {mode} is not valid. Valid preset modes are: {modes}."
|
"message": "Preset mode {mode} is not valid. Valid preset modes are: {modes}."
|
||||||
|
@ -53,7 +53,6 @@ SUPPORT_FLAGS_THERMOSTAT = (
|
|||||||
ClimateEntityFeature.TARGET_TEMPERATURE
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||||
| ClimateEntityFeature.FAN_MODE
|
| ClimateEntityFeature.FAN_MODE
|
||||||
| ClimateEntityFeature.AUX_HEAT
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ components. Instead call the service directly.
|
|||||||
|
|
||||||
from homeassistant.components.climate import (
|
from homeassistant.components.climate import (
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
ATTR_AUX_HEAT,
|
|
||||||
ATTR_FAN_MODE,
|
ATTR_FAN_MODE,
|
||||||
ATTR_HUMIDITY,
|
ATTR_HUMIDITY,
|
||||||
ATTR_HVAC_MODE,
|
ATTR_HVAC_MODE,
|
||||||
@ -16,7 +15,6 @@ from homeassistant.components.climate import (
|
|||||||
ATTR_TARGET_TEMP_HIGH,
|
ATTR_TARGET_TEMP_HIGH,
|
||||||
ATTR_TARGET_TEMP_LOW,
|
ATTR_TARGET_TEMP_LOW,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_AUX_HEAT,
|
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
SERVICE_SET_HUMIDITY,
|
SERVICE_SET_HUMIDITY,
|
||||||
SERVICE_SET_HVAC_MODE,
|
SERVICE_SET_HVAC_MODE,
|
||||||
@ -62,31 +60,6 @@ def set_preset_mode(
|
|||||||
hass.services.call(DOMAIN, SERVICE_SET_PRESET_MODE, data)
|
hass.services.call(DOMAIN, SERVICE_SET_PRESET_MODE, data)
|
||||||
|
|
||||||
|
|
||||||
async def async_set_aux_heat(
|
|
||||||
hass: HomeAssistant, aux_heat: bool, entity_id: str = ENTITY_MATCH_ALL
|
|
||||||
) -> None:
|
|
||||||
"""Turn all or specified climate devices auxiliary heater on."""
|
|
||||||
data = {ATTR_AUX_HEAT: aux_heat}
|
|
||||||
|
|
||||||
if entity_id:
|
|
||||||
data[ATTR_ENTITY_ID] = entity_id
|
|
||||||
|
|
||||||
await hass.services.async_call(DOMAIN, SERVICE_SET_AUX_HEAT, data, blocking=True)
|
|
||||||
|
|
||||||
|
|
||||||
@bind_hass
|
|
||||||
def set_aux_heat(
|
|
||||||
hass: HomeAssistant, aux_heat: bool, entity_id: str = ENTITY_MATCH_ALL
|
|
||||||
) -> None:
|
|
||||||
"""Turn all or specified climate devices auxiliary heater on."""
|
|
||||||
data = {ATTR_AUX_HEAT: aux_heat}
|
|
||||||
|
|
||||||
if entity_id:
|
|
||||||
data[ATTR_ENTITY_ID] = entity_id
|
|
||||||
|
|
||||||
hass.services.call(DOMAIN, SERVICE_SET_AUX_HEAT, data)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_set_temperature(
|
async def async_set_temperature(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
temperature: float | None = None,
|
temperature: float | None = None,
|
||||||
|
@ -37,21 +37,14 @@ from homeassistant.components.climate.const import (
|
|||||||
SWING_HORIZONTAL_ON,
|
SWING_HORIZONTAL_ON,
|
||||||
ClimateEntityFeature,
|
ClimateEntityFeature,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
|
||||||
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, UnitOfTemperature
|
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, UnitOfTemperature
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ServiceValidationError
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import issue_registry as ir
|
|
||||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
MockConfigEntry,
|
MockConfigEntry,
|
||||||
MockEntity,
|
MockEntity,
|
||||||
MockModule,
|
|
||||||
MockPlatform,
|
|
||||||
async_mock_service,
|
async_mock_service,
|
||||||
mock_integration,
|
|
||||||
mock_platform,
|
|
||||||
setup_test_component_platform,
|
setup_test_component_platform,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -500,255 +493,6 @@ async def test_sync_toggle(hass: HomeAssistant) -> None:
|
|||||||
assert climate.toggle.called
|
assert climate.toggle.called
|
||||||
|
|
||||||
|
|
||||||
ISSUE_TRACKER = "https://blablabla.com"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
(
|
|
||||||
"manifest_extra",
|
|
||||||
"translation_key",
|
|
||||||
"translation_placeholders_extra",
|
|
||||||
"report",
|
|
||||||
"module",
|
|
||||||
),
|
|
||||||
[
|
|
||||||
(
|
|
||||||
{},
|
|
||||||
"deprecated_climate_aux_no_url",
|
|
||||||
{},
|
|
||||||
"report it to the author of the 'test' custom integration",
|
|
||||||
"custom_components.test.climate",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
{"issue_tracker": ISSUE_TRACKER},
|
|
||||||
"deprecated_climate_aux_url_custom",
|
|
||||||
{"issue_tracker": ISSUE_TRACKER},
|
|
||||||
"create a bug report at https://blablabla.com",
|
|
||||||
"custom_components.test.climate",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_issue_aux_property_deprecated(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
config_flow_fixture: None,
|
|
||||||
manifest_extra: dict[str, str],
|
|
||||||
translation_key: str,
|
|
||||||
translation_placeholders_extra: dict[str, str],
|
|
||||||
report: str,
|
|
||||||
module: str,
|
|
||||||
issue_registry: ir.IssueRegistry,
|
|
||||||
) -> None:
|
|
||||||
"""Test the issue is raised on deprecated auxiliary heater attributes."""
|
|
||||||
|
|
||||||
class MockClimateEntityWithAux(MockClimateEntity):
|
|
||||||
"""Mock climate class with mocked aux heater."""
|
|
||||||
|
|
||||||
_attr_supported_features = (
|
|
||||||
ClimateEntityFeature.AUX_HEAT | ClimateEntityFeature.TARGET_TEMPERATURE
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_aux_heat(self) -> bool | None:
|
|
||||||
"""Return true if aux heater.
|
|
||||||
|
|
||||||
Requires ClimateEntityFeature.AUX_HEAT.
|
|
||||||
"""
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def async_turn_aux_heat_on(self) -> None:
|
|
||||||
"""Turn auxiliary heater on."""
|
|
||||||
await self.hass.async_add_executor_job(self.turn_aux_heat_on)
|
|
||||||
|
|
||||||
async def async_turn_aux_heat_off(self) -> None:
|
|
||||||
"""Turn auxiliary heater off."""
|
|
||||||
await self.hass.async_add_executor_job(self.turn_aux_heat_off)
|
|
||||||
|
|
||||||
# Fake the module is custom component or built in
|
|
||||||
MockClimateEntityWithAux.__module__ = module
|
|
||||||
|
|
||||||
climate_entity = MockClimateEntityWithAux(
|
|
||||||
name="Testing",
|
|
||||||
entity_id="climate.testing",
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_setup_entry_init(
|
|
||||||
hass: HomeAssistant, config_entry: ConfigEntry
|
|
||||||
) -> bool:
|
|
||||||
"""Set up test config entry."""
|
|
||||||
await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN])
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def async_setup_entry_climate_platform(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
config_entry: ConfigEntry,
|
|
||||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
||||||
) -> None:
|
|
||||||
"""Set up test weather platform via config entry."""
|
|
||||||
async_add_entities([climate_entity])
|
|
||||||
|
|
||||||
mock_integration(
|
|
||||||
hass,
|
|
||||||
MockModule(
|
|
||||||
"test",
|
|
||||||
async_setup_entry=async_setup_entry_init,
|
|
||||||
partial_manifest=manifest_extra,
|
|
||||||
),
|
|
||||||
built_in=False,
|
|
||||||
)
|
|
||||||
mock_platform(
|
|
||||||
hass,
|
|
||||||
"test.climate",
|
|
||||||
MockPlatform(async_setup_entry=async_setup_entry_climate_platform),
|
|
||||||
)
|
|
||||||
|
|
||||||
config_entry = MockConfigEntry(domain="test")
|
|
||||||
config_entry.add_to_hass(hass)
|
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert climate_entity.state == HVACMode.HEAT
|
|
||||||
|
|
||||||
issue = issue_registry.async_get_issue("climate", "deprecated_climate_aux_test")
|
|
||||||
assert issue
|
|
||||||
assert issue.issue_domain == "test"
|
|
||||||
assert issue.issue_id == "deprecated_climate_aux_test"
|
|
||||||
assert issue.translation_key == translation_key
|
|
||||||
assert (
|
|
||||||
issue.translation_placeholders
|
|
||||||
== {"platform": "test"} | translation_placeholders_extra
|
|
||||||
)
|
|
||||||
|
|
||||||
assert (
|
|
||||||
"test::MockClimateEntityWithAux implements the `is_aux_heat` property or uses "
|
|
||||||
"the auxiliary heater methods in a subclass of ClimateEntity which is deprecated "
|
|
||||||
f"and will be unsupported from Home Assistant 2025.4. Please {report}"
|
|
||||||
) in caplog.text
|
|
||||||
|
|
||||||
# Assert we only log warning once
|
|
||||||
caplog.clear()
|
|
||||||
await hass.services.async_call(
|
|
||||||
DOMAIN,
|
|
||||||
SERVICE_SET_TEMPERATURE,
|
|
||||||
{
|
|
||||||
"entity_id": "climate.test",
|
|
||||||
"temperature": "25",
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert ("implements the `is_aux_heat` property") not in caplog.text
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
(
|
|
||||||
"manifest_extra",
|
|
||||||
"translation_key",
|
|
||||||
"translation_placeholders_extra",
|
|
||||||
"report",
|
|
||||||
"module",
|
|
||||||
),
|
|
||||||
[
|
|
||||||
(
|
|
||||||
{"issue_tracker": ISSUE_TRACKER},
|
|
||||||
"deprecated_climate_aux_url",
|
|
||||||
{"issue_tracker": ISSUE_TRACKER},
|
|
||||||
"create a bug report at https://blablabla.com",
|
|
||||||
"homeassistant.components.test.climate",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_no_issue_aux_property_deprecated_for_core(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
register_test_integration: MockConfigEntry,
|
|
||||||
manifest_extra: dict[str, str],
|
|
||||||
translation_key: str,
|
|
||||||
translation_placeholders_extra: dict[str, str],
|
|
||||||
report: str,
|
|
||||||
module: str,
|
|
||||||
issue_registry: ir.IssueRegistry,
|
|
||||||
) -> None:
|
|
||||||
"""Test the no issue on deprecated auxiliary heater attributes for core integrations."""
|
|
||||||
|
|
||||||
class MockClimateEntityWithAux(MockClimateEntity):
|
|
||||||
"""Mock climate class with mocked aux heater."""
|
|
||||||
|
|
||||||
_attr_supported_features = ClimateEntityFeature.AUX_HEAT
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_aux_heat(self) -> bool | None:
|
|
||||||
"""Return true if aux heater.
|
|
||||||
|
|
||||||
Requires ClimateEntityFeature.AUX_HEAT.
|
|
||||||
"""
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def async_turn_aux_heat_on(self) -> None:
|
|
||||||
"""Turn auxiliary heater on."""
|
|
||||||
await self.hass.async_add_executor_job(self.turn_aux_heat_on)
|
|
||||||
|
|
||||||
async def async_turn_aux_heat_off(self) -> None:
|
|
||||||
"""Turn auxiliary heater off."""
|
|
||||||
await self.hass.async_add_executor_job(self.turn_aux_heat_off)
|
|
||||||
|
|
||||||
# Fake the module is custom component or built in
|
|
||||||
MockClimateEntityWithAux.__module__ = module
|
|
||||||
|
|
||||||
climate_entity = MockClimateEntityWithAux(
|
|
||||||
name="Testing",
|
|
||||||
entity_id="climate.testing",
|
|
||||||
)
|
|
||||||
|
|
||||||
setup_test_component_platform(
|
|
||||||
hass, DOMAIN, entities=[climate_entity], from_config_entry=True
|
|
||||||
)
|
|
||||||
await hass.config_entries.async_setup(register_test_integration.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert climate_entity.state == HVACMode.HEAT
|
|
||||||
|
|
||||||
issue = issue_registry.async_get_issue("climate", "deprecated_climate_aux_test")
|
|
||||||
assert not issue
|
|
||||||
|
|
||||||
assert (
|
|
||||||
"test::MockClimateEntityWithAux implements the `is_aux_heat` property or uses "
|
|
||||||
"the auxiliary heater methods in a subclass of ClimateEntity which is deprecated "
|
|
||||||
f"and will be unsupported from Home Assistant 2024.10. Please {report}"
|
|
||||||
) not in caplog.text
|
|
||||||
|
|
||||||
|
|
||||||
async def test_no_issue_no_aux_property(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
register_test_integration: MockConfigEntry,
|
|
||||||
issue_registry: ir.IssueRegistry,
|
|
||||||
) -> None:
|
|
||||||
"""Test the issue is raised on deprecated auxiliary heater attributes."""
|
|
||||||
|
|
||||||
climate_entity = MockClimateEntity(
|
|
||||||
name="Testing",
|
|
||||||
entity_id="climate.testing",
|
|
||||||
)
|
|
||||||
|
|
||||||
setup_test_component_platform(
|
|
||||||
hass, DOMAIN, entities=[climate_entity], from_config_entry=True
|
|
||||||
)
|
|
||||||
assert await hass.config_entries.async_setup(register_test_integration.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert climate_entity.state == HVACMode.HEAT
|
|
||||||
|
|
||||||
assert len(issue_registry.issues) == 0
|
|
||||||
|
|
||||||
assert (
|
|
||||||
"test::MockClimateEntityWithAux implements the `is_aux_heat` property or uses "
|
|
||||||
"the auxiliary heater methods in a subclass of ClimateEntity which is deprecated "
|
|
||||||
"and will be unsupported from Home Assistant 2024.10."
|
|
||||||
) not in caplog.text
|
|
||||||
|
|
||||||
|
|
||||||
async def test_humidity_validation(
|
async def test_humidity_validation(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
register_test_integration: MockConfigEntry,
|
register_test_integration: MockConfigEntry,
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.climate import (
|
from homeassistant.components.climate import (
|
||||||
ATTR_AUX_HEAT,
|
|
||||||
ATTR_CURRENT_HUMIDITY,
|
ATTR_CURRENT_HUMIDITY,
|
||||||
ATTR_CURRENT_TEMPERATURE,
|
ATTR_CURRENT_TEMPERATURE,
|
||||||
ATTR_FAN_MODE,
|
ATTR_FAN_MODE,
|
||||||
@ -37,8 +36,6 @@ async def test_significant_state_change(hass: HomeAssistant) -> None:
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("unit_system", "old_attrs", "new_attrs", "expected_result"),
|
("unit_system", "old_attrs", "new_attrs", "expected_result"),
|
||||||
[
|
[
|
||||||
(METRIC, {ATTR_AUX_HEAT: "old_value"}, {ATTR_AUX_HEAT: "old_value"}, False),
|
|
||||||
(METRIC, {ATTR_AUX_HEAT: "old_value"}, {ATTR_AUX_HEAT: "new_value"}, True),
|
|
||||||
(METRIC, {ATTR_FAN_MODE: "old_value"}, {ATTR_FAN_MODE: "old_value"}, False),
|
(METRIC, {ATTR_FAN_MODE: "old_value"}, {ATTR_FAN_MODE: "old_value"}, False),
|
||||||
(METRIC, {ATTR_FAN_MODE: "old_value"}, {ATTR_FAN_MODE: "new_value"}, True),
|
(METRIC, {ATTR_FAN_MODE: "old_value"}, {ATTR_FAN_MODE: "new_value"}, True),
|
||||||
(
|
(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user