1 """Support for water heater devices."""
3 from __future__
import annotations
5 from datetime
import timedelta
6 from enum
import IntFlag
9 from typing
import Any, final
11 from propcache
import cached_property
12 import voluptuous
as vol
29 DeprecatedConstantEnum,
30 all_with_deprecated_constants,
31 check_if_deprecated_constant,
32 dir_with_deprecated_constants,
41 from .const
import DOMAIN
43 DATA_COMPONENT: HassKey[EntityComponent[WaterHeaterEntity]] =
HassKey(DOMAIN)
44 ENTITY_ID_FORMAT = DOMAIN +
".{}"
45 PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA
46 PLATFORM_SCHEMA_BASE = cv.PLATFORM_SCHEMA_BASE
49 DEFAULT_MIN_TEMP = 110
50 DEFAULT_MAX_TEMP = 140
52 SERVICE_SET_AWAY_MODE =
"set_away_mode"
53 SERVICE_SET_TEMPERATURE =
"set_temperature"
54 SERVICE_SET_OPERATION_MODE =
"set_operation_mode"
57 STATE_ELECTRIC =
"electric"
58 STATE_PERFORMANCE =
"performance"
59 STATE_HIGH_DEMAND =
"high_demand"
60 STATE_HEAT_PUMP =
"heat_pump"
65 """Supported features of the fan entity."""
67 TARGET_TEMPERATURE = 1
76 WaterHeaterEntityFeature.TARGET_TEMPERATURE,
"2025.1"
79 WaterHeaterEntityFeature.OPERATION_MODE,
"2025.1"
82 WaterHeaterEntityFeature.AWAY_MODE,
"2025.1"
85 ATTR_MAX_TEMP =
"max_temp"
86 ATTR_MIN_TEMP =
"min_temp"
87 ATTR_AWAY_MODE =
"away_mode"
88 ATTR_OPERATION_MODE =
"operation_mode"
89 ATTR_OPERATION_LIST =
"operation_list"
90 ATTR_TARGET_TEMP_HIGH =
"target_temp_high"
91 ATTR_TARGET_TEMP_LOW =
"target_temp_low"
92 ATTR_CURRENT_TEMPERATURE =
"current_temperature"
94 CONVERTIBLE_ATTRIBUTE = [ATTR_TEMPERATURE]
96 _LOGGER = logging.getLogger(__name__)
98 SET_AWAY_MODE_SCHEMA: VolDictType = {
99 vol.Required(ATTR_AWAY_MODE): cv.boolean,
101 SET_TEMPERATURE_SCHEMA: VolDictType = {
102 vol.Required(ATTR_TEMPERATURE,
"temperature"): vol.Coerce(float),
103 vol.Optional(ATTR_OPERATION_MODE): cv.string,
105 SET_OPERATION_MODE_SCHEMA: VolDictType = {
106 vol.Required(ATTR_OPERATION_MODE): cv.string,
112 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
113 """Set up water_heater devices."""
114 component = hass.data[DATA_COMPONENT] = EntityComponent[WaterHeaterEntity](
115 _LOGGER, DOMAIN, hass, SCAN_INTERVAL
117 await component.async_setup(config)
119 component.async_register_entity_service(
120 SERVICE_TURN_ON,
None,
"async_turn_on", [WaterHeaterEntityFeature.ON_OFF]
122 component.async_register_entity_service(
123 SERVICE_TURN_OFF,
None,
"async_turn_off", [WaterHeaterEntityFeature.ON_OFF]
125 component.async_register_entity_service(
126 SERVICE_SET_AWAY_MODE, SET_AWAY_MODE_SCHEMA, async_service_away_mode
128 component.async_register_entity_service(
129 SERVICE_SET_TEMPERATURE, SET_TEMPERATURE_SCHEMA, async_service_temperature_set
131 component.async_register_entity_service(
132 SERVICE_SET_OPERATION_MODE,
133 SET_OPERATION_MODE_SCHEMA,
134 "async_handle_set_operation_mode",
141 """Set up a config entry."""
146 """Unload a config entry."""
151 """A class that describes water heater entities."""
154 CACHED_PROPERTIES_WITH_ATTR_ = {
158 "current_temperature",
159 "target_temperature",
160 "target_temperature_high",
161 "target_temperature_low",
167 """Base class for water heater entities."""
169 _entity_component_unrecorded_attributes = frozenset(
170 {ATTR_OPERATION_LIST, ATTR_MIN_TEMP, ATTR_MAX_TEMP}
173 entity_description: WaterHeaterEntityEntityDescription
174 _attr_current_operation: str |
None =
None
175 _attr_current_temperature: float |
None =
None
176 _attr_is_away_mode_on: bool |
None =
None
177 _attr_max_temp: float
178 _attr_min_temp: float
179 _attr_operation_list: list[str] |
None =
None
180 _attr_precision: float
181 _attr_state:
None =
None
183 _attr_target_temperature_high: float |
None =
None
184 _attr_target_temperature_low: float |
None =
None
185 _attr_target_temperature: float |
None =
None
186 _attr_temperature_unit: str
191 """Return the current state."""
196 """Return the precision of the system."""
197 if hasattr(self,
"_attr_precision"):
198 return self._attr_precision
199 if self.
hasshass.config.units.temperature_unit == UnitOfTemperature.CELSIUS:
200 return PRECISION_TENTHS
201 return PRECISION_WHOLE
205 """Return capability attributes."""
206 data: dict[str, Any] = {
207 ATTR_MIN_TEMP: show_temp(
210 ATTR_MAX_TEMP: show_temp(
223 """Return the optional state attributes."""
224 data: dict[str, Any] = {
225 ATTR_CURRENT_TEMPERATURE: show_temp(
231 ATTR_TEMPERATURE: show_temp(
237 ATTR_TARGET_TEMP_HIGH: show_temp(
243 ATTR_TARGET_TEMP_LOW: show_temp(
253 if WaterHeaterEntityFeature.OPERATION_MODE
in supported_features:
256 if WaterHeaterEntityFeature.AWAY_MODE
in supported_features:
258 data[ATTR_AWAY_MODE] = STATE_ON
if is_away
else STATE_OFF
264 """Return the unit of measurement used by the platform."""
265 return self._attr_temperature_unit
269 """Return current operation ie. eco, electric, performance, ..."""
270 return self._attr_current_operation
274 """Return the list of available operation modes."""
275 return self._attr_operation_list
279 """Return the current temperature."""
280 return self._attr_current_temperature
284 """Return the temperature we try to reach."""
285 return self._attr_target_temperature
289 """Return the highbound target temperature we try to reach."""
290 return self._attr_target_temperature_high
294 """Return the lowbound target temperature we try to reach."""
295 return self._attr_target_temperature_low
299 """Return true if away mode is on."""
300 return self._attr_is_away_mode_on
303 """Set new target temperature."""
304 raise NotImplementedError
307 """Set new target temperature."""
308 await self.
hasshass.async_add_executor_job(
313 """Turn the water heater on."""
314 raise NotImplementedError
317 """Turn the water heater on."""
318 await self.
hasshass.async_add_executor_job(ft.partial(self.
turn_onturn_on, **kwargs))
321 """Turn the water heater off."""
322 raise NotImplementedError
325 """Turn the water heater off."""
326 await self.
hasshass.async_add_executor_job(ft.partial(self.
turn_offturn_off, **kwargs))
329 """Set new target operation mode."""
330 raise NotImplementedError
333 """Set new target operation mode."""
338 """Handle a set target operation mode service call."""
341 translation_domain=DOMAIN,
342 translation_key=
"operation_list_not_defined",
343 translation_placeholders={
345 "operation_mode": operation_mode,
351 translation_domain=DOMAIN,
352 translation_key=
"not_valid_operation_mode",
353 translation_placeholders={
355 "operation_mode": operation_mode,
356 "operation_list": operation_list,
362 """Turn away mode on."""
363 raise NotImplementedError
366 """Turn away mode on."""
370 """Turn away mode off."""
371 raise NotImplementedError
374 """Turn away mode off."""
379 """Return the minimum temperature."""
380 if hasattr(self,
"_attr_min_temp"):
381 return self._attr_min_temp
382 return TemperatureConverter.convert(
383 DEFAULT_MIN_TEMP, UnitOfTemperature.FAHRENHEIT, self.
temperature_unittemperature_unit
388 """Return the maximum temperature."""
389 if hasattr(self,
"_attr_max_temp"):
390 return self._attr_max_temp
391 return TemperatureConverter.convert(
392 DEFAULT_MAX_TEMP, UnitOfTemperature.FAHRENHEIT, self.
temperature_unittemperature_unit
397 """Return the list of supported features."""
398 return self._attr_supported_features
402 """Return the supported features as WaterHeaterEntityFeature.
404 Remove this compatibility shim in 2025.1 or later.
407 if type(features)
is int:
415 entity: WaterHeaterEntity, service: ServiceCall
417 """Handle away mode service."""
418 if service.data[ATTR_AWAY_MODE]:
419 await entity.async_turn_away_mode_on()
421 await entity.async_turn_away_mode_off()
425 entity: WaterHeaterEntity, service: ServiceCall
427 """Handle set temperature service."""
431 for value, temp
in service.data.items():
432 if value
in CONVERTIBLE_ATTRIBUTE:
433 kwargs[value] = TemperatureConverter.convert(
434 temp, hass.config.units.temperature_unit, entity.temperature_unit
439 await entity.async_set_temperature(**kwargs)
443 __getattr__ = ft.partial(check_if_deprecated_constant, module_globals=globals())
444 __dir__ = ft.partial(
445 dir_with_deprecated_constants, module_globals_keys=[*globals().keys()]
None async_turn_off(self, **Any kwargs)
None turn_off(self, **Any kwargs)
dict[str, Any] capability_attributes(self)
None turn_away_mode_on(self)
float|None target_temperature_low(self)
None async_set_operation_mode(self, str operation_mode)
None turn_on(self, **Any kwargs)
None async_turn_on(self, **Any kwargs)
WaterHeaterEntityFeature supported_features_compat(self)
None async_turn_away_mode_on(self)
WaterHeaterEntityFeature supported_features(self)
None turn_away_mode_off(self)
float|None target_temperature_high(self)
None async_turn_away_mode_off(self)
float|None current_temperature(self)
None async_handle_set_operation_mode(self, str operation_mode)
dict[str, Any] state_attributes(self)
list[str]|None operation_list(self)
None set_temperature(self, **Any kwargs)
None set_operation_mode(self, str operation_mode)
str|None current_operation(self)
bool|None is_away_mode_on(self)
None async_set_temperature(self, **Any kwargs)
float|None target_temperature(self)
str temperature_unit(self)
None _report_deprecated_supported_features_values(self, IntFlag replacement)
int|None supported_features(self)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
None async_service_away_mode(WaterHeaterEntity entity, ServiceCall service)
bool async_setup(HomeAssistant hass, ConfigType config)
None async_service_temperature_set(WaterHeaterEntity entity, ServiceCall service)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
list[str] all_with_deprecated_constants(dict[str, Any] module_globals)