1 """Support for MQTT climate devices."""
3 from __future__
import annotations
5 from abc
import ABC, abstractmethod
6 from collections.abc
import Callable
7 from functools
import partial
11 import voluptuous
as vol
16 ATTR_TARGET_TEMP_HIGH,
39 CONF_TEMPERATURE_UNIT,
54 from .
import subscription
55 from .config
import DEFAULT_RETAIN, MQTT_BASE_SCHEMA
59 CONF_CURRENT_HUMIDITY_TEMPLATE,
60 CONF_CURRENT_HUMIDITY_TOPIC,
61 CONF_CURRENT_TEMP_TEMPLATE,
62 CONF_CURRENT_TEMP_TOPIC,
63 CONF_MODE_COMMAND_TEMPLATE,
64 CONF_MODE_COMMAND_TOPIC,
66 CONF_MODE_STATE_TEMPLATE,
67 CONF_MODE_STATE_TOPIC,
68 CONF_POWER_COMMAND_TEMPLATE,
69 CONF_POWER_COMMAND_TOPIC,
72 CONF_TEMP_COMMAND_TEMPLATE,
73 CONF_TEMP_COMMAND_TOPIC,
77 CONF_TEMP_STATE_TEMPLATE,
78 CONF_TEMP_STATE_TOPIC,
82 from .entity
import MqttEntity, async_setup_entity_entry_helper
89 from .schemas
import MQTT_ENTITY_COMMON_SCHEMA
90 from .util
import valid_publish_topic, valid_subscribe_topic
92 _LOGGER = logging.getLogger(__name__)
96 DEFAULT_NAME =
"MQTT HVAC"
98 CONF_FAN_MODE_COMMAND_TEMPLATE =
"fan_mode_command_template"
99 CONF_FAN_MODE_COMMAND_TOPIC =
"fan_mode_command_topic"
100 CONF_FAN_MODE_LIST =
"fan_modes"
101 CONF_FAN_MODE_STATE_TEMPLATE =
"fan_mode_state_template"
102 CONF_FAN_MODE_STATE_TOPIC =
"fan_mode_state_topic"
104 CONF_HUMIDITY_COMMAND_TEMPLATE =
"target_humidity_command_template"
105 CONF_HUMIDITY_COMMAND_TOPIC =
"target_humidity_command_topic"
106 CONF_HUMIDITY_STATE_TEMPLATE =
"target_humidity_state_template"
107 CONF_HUMIDITY_STATE_TOPIC =
"target_humidity_state_topic"
108 CONF_HUMIDITY_MAX =
"max_humidity"
109 CONF_HUMIDITY_MIN =
"min_humidity"
111 CONF_PRESET_MODE_STATE_TOPIC =
"preset_mode_state_topic"
112 CONF_PRESET_MODE_COMMAND_TOPIC =
"preset_mode_command_topic"
113 CONF_PRESET_MODE_VALUE_TEMPLATE =
"preset_mode_value_template"
114 CONF_PRESET_MODE_COMMAND_TEMPLATE =
"preset_mode_command_template"
115 CONF_PRESET_MODES_LIST =
"preset_modes"
116 CONF_SWING_MODE_COMMAND_TEMPLATE =
"swing_mode_command_template"
117 CONF_SWING_MODE_COMMAND_TOPIC =
"swing_mode_command_topic"
118 CONF_SWING_MODE_LIST =
"swing_modes"
119 CONF_SWING_MODE_STATE_TEMPLATE =
"swing_mode_state_template"
120 CONF_SWING_MODE_STATE_TOPIC =
"swing_mode_state_topic"
121 CONF_TEMP_HIGH_COMMAND_TEMPLATE =
"temperature_high_command_template"
122 CONF_TEMP_HIGH_COMMAND_TOPIC =
"temperature_high_command_topic"
123 CONF_TEMP_HIGH_STATE_TEMPLATE =
"temperature_high_state_template"
124 CONF_TEMP_HIGH_STATE_TOPIC =
"temperature_high_state_topic"
125 CONF_TEMP_LOW_COMMAND_TEMPLATE =
"temperature_low_command_template"
126 CONF_TEMP_LOW_COMMAND_TOPIC =
"temperature_low_command_topic"
127 CONF_TEMP_LOW_STATE_TEMPLATE =
"temperature_low_state_template"
128 CONF_TEMP_LOW_STATE_TOPIC =
"temperature_low_state_topic"
129 CONF_TEMP_STEP =
"temp_step"
131 DEFAULT_INITIAL_TEMPERATURE = 21.0
133 MQTT_CLIMATE_ATTRIBUTES_BLOCKED = frozenset(
135 climate.ATTR_CURRENT_HUMIDITY,
136 climate.ATTR_CURRENT_TEMPERATURE,
137 climate.ATTR_FAN_MODE,
138 climate.ATTR_FAN_MODES,
139 climate.ATTR_HUMIDITY,
140 climate.ATTR_HVAC_ACTION,
141 climate.ATTR_HVAC_MODES,
142 climate.ATTR_MAX_HUMIDITY,
143 climate.ATTR_MAX_TEMP,
144 climate.ATTR_MIN_HUMIDITY,
145 climate.ATTR_MIN_TEMP,
146 climate.ATTR_PRESET_MODE,
147 climate.ATTR_PRESET_MODES,
148 climate.ATTR_SWING_MODE,
149 climate.ATTR_SWING_MODES,
150 climate.ATTR_TARGET_TEMP_HIGH,
151 climate.ATTR_TARGET_TEMP_LOW,
152 climate.ATTR_TARGET_TEMP_STEP,
153 climate.ATTR_TEMPERATURE,
157 VALUE_TEMPLATE_KEYS = (
158 CONF_CURRENT_HUMIDITY_TEMPLATE,
159 CONF_CURRENT_TEMP_TEMPLATE,
160 CONF_FAN_MODE_STATE_TEMPLATE,
161 CONF_HUMIDITY_STATE_TEMPLATE,
162 CONF_MODE_STATE_TEMPLATE,
163 CONF_ACTION_TEMPLATE,
164 CONF_PRESET_MODE_VALUE_TEMPLATE,
165 CONF_SWING_MODE_STATE_TEMPLATE,
166 CONF_TEMP_HIGH_STATE_TEMPLATE,
167 CONF_TEMP_LOW_STATE_TEMPLATE,
168 CONF_TEMP_STATE_TEMPLATE,
171 COMMAND_TEMPLATE_KEYS = {
172 CONF_FAN_MODE_COMMAND_TEMPLATE,
173 CONF_HUMIDITY_COMMAND_TEMPLATE,
174 CONF_MODE_COMMAND_TEMPLATE,
175 CONF_POWER_COMMAND_TEMPLATE,
176 CONF_PRESET_MODE_COMMAND_TEMPLATE,
177 CONF_SWING_MODE_COMMAND_TEMPLATE,
178 CONF_TEMP_COMMAND_TEMPLATE,
179 CONF_TEMP_HIGH_COMMAND_TEMPLATE,
180 CONF_TEMP_LOW_COMMAND_TEMPLATE,
186 CONF_CURRENT_HUMIDITY_TOPIC,
187 CONF_CURRENT_TEMP_TOPIC,
188 CONF_FAN_MODE_COMMAND_TOPIC,
189 CONF_FAN_MODE_STATE_TOPIC,
190 CONF_HUMIDITY_COMMAND_TOPIC,
191 CONF_HUMIDITY_STATE_TOPIC,
192 CONF_MODE_COMMAND_TOPIC,
193 CONF_MODE_STATE_TOPIC,
194 CONF_POWER_COMMAND_TOPIC,
195 CONF_PRESET_MODE_COMMAND_TOPIC,
196 CONF_PRESET_MODE_STATE_TOPIC,
197 CONF_SWING_MODE_COMMAND_TOPIC,
198 CONF_SWING_MODE_STATE_TOPIC,
199 CONF_TEMP_COMMAND_TOPIC,
200 CONF_TEMP_HIGH_COMMAND_TOPIC,
201 CONF_TEMP_HIGH_STATE_TOPIC,
202 CONF_TEMP_LOW_COMMAND_TOPIC,
203 CONF_TEMP_LOW_STATE_TOPIC,
204 CONF_TEMP_STATE_TOPIC,
209 """Validate that the preset mode reset payload is not one of the preset modes."""
210 if PRESET_NONE
in config[CONF_PRESET_MODES_LIST]:
211 raise vol.Invalid(
"preset_modes must not include preset mode 'none'")
216 """Validate a target_humidity range configuration, throws otherwise."""
217 if config[CONF_HUMIDITY_MIN] >= config[CONF_HUMIDITY_MAX]:
218 raise vol.Invalid(
"target_humidity_max must be > target_humidity_min")
219 if config[CONF_HUMIDITY_MAX] > 100:
220 raise vol.Invalid(
"max_humidity must be <= 100")
226 """Validate humidity state.
228 Ensure that if CONF_HUMIDITY_STATE_TOPIC is set then
229 CONF_HUMIDITY_COMMAND_TOPIC is also set.
232 CONF_HUMIDITY_STATE_TOPIC
in config
233 and CONF_HUMIDITY_COMMAND_TOPIC
not in config
236 f
"{CONF_HUMIDITY_STATE_TOPIC} cannot be used without"
237 f
" {CONF_HUMIDITY_COMMAND_TOPIC}"
243 _PLATFORM_SCHEMA_BASE = MQTT_BASE_SCHEMA.extend(
245 vol.Optional(CONF_CURRENT_HUMIDITY_TEMPLATE): cv.template,
246 vol.Optional(CONF_CURRENT_HUMIDITY_TOPIC): valid_subscribe_topic,
247 vol.Optional(CONF_CURRENT_TEMP_TEMPLATE): cv.template,
248 vol.Optional(CONF_CURRENT_TEMP_TOPIC): valid_subscribe_topic,
249 vol.Optional(CONF_FAN_MODE_COMMAND_TEMPLATE): cv.template,
250 vol.Optional(CONF_FAN_MODE_COMMAND_TOPIC): valid_publish_topic,
253 default=[FAN_AUTO, FAN_LOW, FAN_MEDIUM, FAN_HIGH],
255 vol.Optional(CONF_FAN_MODE_STATE_TEMPLATE): cv.template,
256 vol.Optional(CONF_FAN_MODE_STATE_TOPIC): valid_subscribe_topic,
257 vol.Optional(CONF_HUMIDITY_COMMAND_TEMPLATE): cv.template,
258 vol.Optional(CONF_HUMIDITY_COMMAND_TOPIC): valid_publish_topic,
260 CONF_HUMIDITY_MIN, default=DEFAULT_MIN_HUMIDITY
261 ): cv.positive_float,
263 CONF_HUMIDITY_MAX, default=DEFAULT_MAX_HUMIDITY
264 ): cv.positive_float,
265 vol.Optional(CONF_HUMIDITY_STATE_TEMPLATE): cv.template,
266 vol.Optional(CONF_HUMIDITY_STATE_TOPIC): valid_subscribe_topic,
267 vol.Optional(CONF_MODE_COMMAND_TEMPLATE): cv.template,
268 vol.Optional(CONF_MODE_COMMAND_TOPIC): valid_publish_topic,
280 vol.Optional(CONF_MODE_STATE_TEMPLATE): cv.template,
281 vol.Optional(CONF_MODE_STATE_TOPIC): valid_subscribe_topic,
282 vol.Optional(CONF_NAME): vol.Any(cv.string,
None),
283 vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
284 vol.Optional(CONF_PAYLOAD_ON, default=
"ON"): cv.string,
285 vol.Optional(CONF_PAYLOAD_OFF, default=
"OFF"): cv.string,
286 vol.Optional(CONF_POWER_COMMAND_TOPIC): valid_publish_topic,
287 vol.Optional(CONF_POWER_COMMAND_TEMPLATE): cv.template,
288 vol.Optional(CONF_PRECISION): vol.In(
289 [PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE]
291 vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
292 vol.Optional(CONF_ACTION_TEMPLATE): cv.template,
293 vol.Optional(CONF_ACTION_TOPIC): valid_subscribe_topic,
297 CONF_PRESET_MODE_COMMAND_TOPIC,
"preset_modes"
298 ): valid_publish_topic,
300 CONF_PRESET_MODES_LIST,
"preset_modes", default=[]
302 vol.Optional(CONF_PRESET_MODE_COMMAND_TEMPLATE): cv.template,
303 vol.Optional(CONF_PRESET_MODE_STATE_TOPIC): valid_subscribe_topic,
304 vol.Optional(CONF_PRESET_MODE_VALUE_TEMPLATE): cv.template,
305 vol.Optional(CONF_SWING_MODE_COMMAND_TEMPLATE): cv.template,
306 vol.Optional(CONF_SWING_MODE_COMMAND_TOPIC): valid_publish_topic,
308 CONF_SWING_MODE_LIST, default=[SWING_ON, SWING_OFF]
310 vol.Optional(CONF_SWING_MODE_STATE_TEMPLATE): cv.template,
311 vol.Optional(CONF_SWING_MODE_STATE_TOPIC): valid_subscribe_topic,
312 vol.Optional(CONF_TEMP_INITIAL): vol.All(vol.Coerce(float)),
313 vol.Optional(CONF_TEMP_MIN): vol.Coerce(float),
314 vol.Optional(CONF_TEMP_MAX): vol.Coerce(float),
315 vol.Optional(CONF_TEMP_STEP, default=1.0): vol.Coerce(float),
316 vol.Optional(CONF_TEMP_COMMAND_TEMPLATE): cv.template,
317 vol.Optional(CONF_TEMP_COMMAND_TOPIC): valid_publish_topic,
318 vol.Optional(CONF_TEMP_HIGH_COMMAND_TEMPLATE): cv.template,
319 vol.Optional(CONF_TEMP_HIGH_COMMAND_TOPIC): valid_publish_topic,
320 vol.Optional(CONF_TEMP_HIGH_STATE_TOPIC): valid_subscribe_topic,
321 vol.Optional(CONF_TEMP_HIGH_STATE_TEMPLATE): cv.template,
322 vol.Optional(CONF_TEMP_LOW_COMMAND_TEMPLATE): cv.template,
323 vol.Optional(CONF_TEMP_LOW_COMMAND_TOPIC): valid_publish_topic,
324 vol.Optional(CONF_TEMP_LOW_STATE_TEMPLATE): cv.template,
325 vol.Optional(CONF_TEMP_LOW_STATE_TOPIC): valid_subscribe_topic,
326 vol.Optional(CONF_TEMP_STATE_TEMPLATE): cv.template,
327 vol.Optional(CONF_TEMP_STATE_TOPIC): valid_subscribe_topic,
328 vol.Optional(CONF_TEMPERATURE_UNIT): cv.temperature_unit,
329 vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
331 ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
333 PLATFORM_SCHEMA_MODERN = vol.All(
334 _PLATFORM_SCHEMA_BASE,
335 valid_preset_mode_configuration,
336 valid_humidity_range_configuration,
337 valid_humidity_state_configuration,
340 _DISCOVERY_SCHEMA_BASE = _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA)
342 DISCOVERY_SCHEMA = vol.All(
343 _DISCOVERY_SCHEMA_BASE,
344 valid_preset_mode_configuration,
345 valid_humidity_range_configuration,
346 valid_humidity_state_configuration,
352 config_entry: ConfigEntry,
353 async_add_entities: AddEntitiesCallback,
355 """Set up MQTT climate through YAML and through MQTT discovery."""
363 PLATFORM_SCHEMA_MODERN,
368 """Helper entity class to control temperature.
370 MqttTemperatureControlEntity supports shared methods for
371 climate and water_heater platforms.
374 _attr_target_temperature_low: float |
None
375 _attr_target_temperature_high: float |
None
377 _feature_preset_mode: bool =
False
379 _topic: dict[str, Any]
381 _command_templates: dict[str, Callable[[PublishPayloadType], PublishPayloadType]]
382 _value_templates: dict[str, Callable[[ReceivePayloadType], ReceivePayloadType]]
385 self, msg: ReceiveMessage, template_name: str
386 ) -> ReceivePayloadType:
387 """Render a template by name."""
388 template = self._value_templates[template_name]
393 self, template_name: str, attr: str, msg: ReceiveMessage
395 """Handle climate attributes coming via MQTT."""
399 "Invalid empty payload for attribute %s, ignoring update",
403 if payload == PAYLOAD_NONE:
404 setattr(self, attr,
None)
407 setattr(self, attr,
float(payload))
409 _LOGGER.error(
"Could not parse %s from %s", template_name, payload)
415 """(Re)Subscribe to topics."""
417 CONF_CURRENT_TEMP_TOPIC,
420 CONF_CURRENT_TEMP_TEMPLATE,
421 "_attr_current_temperature",
423 {
"_attr_current_temperature"},
426 CONF_TEMP_STATE_TOPIC,
429 CONF_TEMP_STATE_TEMPLATE,
430 "_attr_target_temperature",
432 {
"_attr_target_temperature"},
435 CONF_TEMP_LOW_STATE_TOPIC,
438 CONF_TEMP_LOW_STATE_TEMPLATE,
439 "_attr_target_temperature_low",
441 {
"_attr_target_temperature_low"},
444 CONF_TEMP_HIGH_STATE_TOPIC,
447 CONF_TEMP_HIGH_STATE_TEMPLATE,
448 "_attr_target_temperature_high",
450 {
"_attr_target_temperature_high"},
454 """(Re)Subscribe to topics."""
455 subscription.async_subscribe_topics_internal(self.
hasshasshass, self.
_sub_state_sub_state)
457 async
def _publish(self, topic: str, payload: PublishPayloadType) ->
None:
458 if self._topic[topic]
is not None:
472 if self._optimistic
or self._topic[state_topic]
is None:
475 setattr(self, attr, temp)
477 payload = self._command_templates[cmnd_template](temp)
478 await self.
_publish_publish(cmnd_topic, payload)
483 """Set new target temperatures."""
485 kwargs.get(ATTR_TEMPERATURE),
486 CONF_TEMP_COMMAND_TOPIC,
487 CONF_TEMP_COMMAND_TEMPLATE,
488 CONF_TEMP_STATE_TOPIC,
489 "_attr_target_temperature",
493 kwargs.get(ATTR_TARGET_TEMP_LOW),
494 CONF_TEMP_LOW_COMMAND_TOPIC,
495 CONF_TEMP_LOW_COMMAND_TEMPLATE,
496 CONF_TEMP_LOW_STATE_TOPIC,
497 "_attr_target_temperature_low",
501 kwargs.get(ATTR_TARGET_TEMP_HIGH),
502 CONF_TEMP_HIGH_COMMAND_TOPIC,
503 CONF_TEMP_HIGH_COMMAND_TEMPLATE,
504 CONF_TEMP_HIGH_STATE_TOPIC,
505 "_attr_target_temperature_high",
514 """Representation of an MQTT climate device."""
516 _attr_fan_mode: str |
None =
None
517 _attr_hvac_mode: HVACMode |
None =
None
518 _attr_swing_mode: str |
None =
None
519 _default_name = DEFAULT_NAME
520 _entity_id_format = climate.ENTITY_ID_FORMAT
521 _attributes_extra_blocked = MQTT_CLIMATE_ATTRIBUTES_BLOCKED
522 _attr_target_temperature_low: float |
None =
None
523 _attr_target_temperature_high: float |
None =
None
524 _enable_turn_on_off_backwards_compatibility =
False
528 """Return the config schema."""
529 return DISCOVERY_SCHEMA
532 """(Re)Setup the entity."""
536 CONF_TEMPERATURE_UNIT, self.
hasshasshass.config.units.temperature_unit
538 if (min_temp := config.get(CONF_TEMP_MIN))
is not None:
540 if (max_temp := config.get(CONF_TEMP_MAX))
is not None:
544 if (precision := config.get(CONF_PRECISION))
is not None:
550 self.
_topic_topic = {key: config.get(key)
for key
in TOPIC_KEYS}
555 init_temp: float = config.get(
557 TemperatureConverter.convert(
558 DEFAULT_INITIAL_TEMPERATURE,
559 UnitOfTemperature.CELSIUS,
563 if self.
_topic_topic[CONF_TEMP_STATE_TOPIC]
is None or self.
_optimistic_optimistic:
565 if self.
_topic_topic[CONF_TEMP_LOW_STATE_TOPIC]
is None or self.
_optimistic_optimistic:
567 if self.
_topic_topic[CONF_TEMP_HIGH_STATE_TOPIC]
is None or self.
_optimistic_optimistic:
570 if self.
_topic_topic[CONF_FAN_MODE_STATE_TOPIC]
is None or self.
_optimistic_optimistic:
572 if self.
_topic_topic[CONF_SWING_MODE_STATE_TOPIC]
is None or self.
_optimistic_optimistic:
574 if self.
_topic_topic[CONF_MODE_STATE_TOPIC]
is None or self.
_optimistic_optimistic:
579 presets.extend(config[CONF_PRESET_MODES_LIST])
581 presets.insert(0, PRESET_NONE)
587 self.
_optimistic_optimistic
or CONF_PRESET_MODE_STATE_TOPIC
not in config
590 value_templates: dict[str, Template |
None] = {
591 key: config.get(CONF_VALUE_TEMPLATE)
for key
in VALUE_TEMPLATE_KEYS
593 value_templates.update(
594 {key: config[key]
for key
in VALUE_TEMPLATE_KEYS & config.keys()}
600 ).async_render_with_possible_json_value
601 for key, template
in value_templates.items()
606 for key
in COMMAND_TEMPLATE_KEYS
609 support = ClimateEntityFeature.TURN_ON | ClimateEntityFeature.TURN_OFF
610 if (self.
_topic_topic[CONF_TEMP_STATE_TOPIC]
is not None)
or (
611 self.
_topic_topic[CONF_TEMP_COMMAND_TOPIC]
is not None
613 support |= ClimateEntityFeature.TARGET_TEMPERATURE
615 if (self.
_topic_topic[CONF_TEMP_LOW_STATE_TOPIC]
is not None)
or (
616 self.
_topic_topic[CONF_TEMP_LOW_COMMAND_TOPIC]
is not None
618 support |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
620 if (self.
_topic_topic[CONF_TEMP_HIGH_STATE_TOPIC]
is not None)
or (
621 self.
_topic_topic[CONF_TEMP_HIGH_COMMAND_TOPIC]
is not None
623 support |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
625 if self.
_topic_topic[CONF_HUMIDITY_COMMAND_TOPIC]
is not None:
626 support |= ClimateEntityFeature.TARGET_HUMIDITY
628 if (self.
_topic_topic[CONF_FAN_MODE_STATE_TOPIC]
is not None)
or (
629 self.
_topic_topic[CONF_FAN_MODE_COMMAND_TOPIC]
is not None
631 support |= ClimateEntityFeature.FAN_MODE
633 if (self.
_topic_topic[CONF_SWING_MODE_STATE_TOPIC]
is not None)
or (
634 self.
_topic_topic[CONF_SWING_MODE_COMMAND_TOPIC]
is not None
636 support |= ClimateEntityFeature.SWING_MODE
639 support |= ClimateEntityFeature.PRESET_MODE
645 """Handle receiving action via MQTT."""
646 payload = self.
render_templaterender_template(msg, CONF_ACTION_TEMPLATE)
649 "Invalid %s action: %s, ignoring",
650 [e.value
for e
in HVACAction],
654 if payload == PAYLOAD_NONE:
661 "Invalid %s action: %s",
662 [e.value
for e
in HVACAction],
669 self, template_name: str, attr: str, mode_list: str, msg: ReceiveMessage
671 """Handle receiving listed mode via MQTT."""
674 if payload == PAYLOAD_NONE:
675 setattr(self, attr,
None)
676 elif payload
not in self.
_config_config[mode_list]:
677 _LOGGER.warning(
"Invalid %s mode: %s", mode_list, payload)
679 setattr(self, attr, payload)
683 """Handle receiving preset mode via MQTT."""
684 preset_mode = self.
render_templaterender_template(msg, CONF_PRESET_MODE_VALUE_TEMPLATE)
685 if preset_mode
in [PRESET_NONE, PAYLOAD_NONE]:
689 _LOGGER.debug(
"Ignoring empty preset_mode from '%s'", msg.topic)
693 "'%s' received on topic %s. '%s' is not a valid preset mode",
703 """(Re)Subscribe to topics."""
708 {
"_attr_hvac_action"},
711 CONF_CURRENT_HUMIDITY_TOPIC,
714 CONF_CURRENT_HUMIDITY_TEMPLATE,
715 "_attr_current_humidity",
717 {
"_attr_current_humidity"},
720 CONF_HUMIDITY_STATE_TOPIC,
723 CONF_HUMIDITY_STATE_TEMPLATE,
724 "_attr_target_humidity",
726 {
"_attr_target_humidity"},
729 CONF_MODE_STATE_TOPIC,
732 CONF_MODE_STATE_TEMPLATE,
739 CONF_FAN_MODE_STATE_TOPIC,
742 CONF_FAN_MODE_STATE_TEMPLATE,
749 CONF_SWING_MODE_STATE_TOPIC,
752 CONF_SWING_MODE_STATE_TEMPLATE,
754 CONF_SWING_MODE_LIST,
756 {
"_attr_swing_mode"},
759 CONF_PRESET_MODE_STATE_TOPIC,
761 {
"_attr_preset_mode"},
767 """Set new target temperatures."""
768 operation_mode: HVACMode |
None
769 if (operation_mode := kwargs.get(ATTR_HVAC_MODE))
is not None:
774 """Set new target humidity."""
778 CONF_HUMIDITY_COMMAND_TOPIC,
779 CONF_HUMIDITY_COMMAND_TEMPLATE,
780 CONF_HUMIDITY_STATE_TOPIC,
781 "_attr_target_humidity",
787 """Set new swing mode."""
788 payload = self.
_command_templates_command_templates[CONF_SWING_MODE_COMMAND_TEMPLATE](swing_mode)
789 await self.
_publish_publish(CONF_SWING_MODE_COMMAND_TOPIC, payload)
791 if self.
_optimistic_optimistic
or self.
_topic_topic[CONF_SWING_MODE_STATE_TOPIC]
is None:
796 """Set new target temperature."""
797 payload = self.
_command_templates_command_templates[CONF_FAN_MODE_COMMAND_TEMPLATE](fan_mode)
798 await self.
_publish_publish(CONF_FAN_MODE_COMMAND_TOPIC, payload)
800 if self.
_optimistic_optimistic
or self.
_topic_topic[CONF_FAN_MODE_STATE_TOPIC]
is None:
805 """Set new operation mode."""
806 payload = self.
_command_templates_command_templates[CONF_MODE_COMMAND_TEMPLATE](hvac_mode)
807 await self.
_publish_publish(CONF_MODE_COMMAND_TOPIC, payload)
809 if self.
_optimistic_optimistic
or self.
_topic_topic[CONF_MODE_STATE_TOPIC]
is None:
814 """Set a preset mode."""
815 mqtt_payload = self.
_command_templates_command_templates[CONF_PRESET_MODE_COMMAND_TEMPLATE](
819 CONF_PRESET_MODE_COMMAND_TOPIC,
828 """Turn the entity on."""
829 if CONF_POWER_COMMAND_TOPIC
in self.
_config_config:
830 mqtt_payload = self.
_command_templates_command_templates[CONF_POWER_COMMAND_TEMPLATE](
831 self.
_config_config[CONF_PAYLOAD_ON]
833 await self.
_publish_publish(CONF_POWER_COMMAND_TOPIC, mqtt_payload)
839 """Turn the entity off."""
840 if CONF_POWER_COMMAND_TOPIC
in self.
_config_config:
841 mqtt_payload = self.
_command_templates_command_templates[CONF_POWER_COMMAND_TEMPLATE](
842 self.
_config_config[CONF_PAYLOAD_OFF]
844 await self.
_publish_publish(CONF_POWER_COMMAND_TOPIC, mqtt_payload)
str temperature_unit(self)
None async_set_hvac_mode(self, HVACMode hvac_mode)
None async_set_humidity(self, float humidity)
None _prepare_subscribe_topics(self)
_attr_target_temperature_step
_attr_target_temperature_low
None async_set_preset_mode(self, str preset_mode)
None async_set_fan_mode(self, str fan_mode)
None async_set_swing_mode(self, str swing_mode)
_attr_target_temperature_high
VolSchemaType config_schema()
None async_set_hvac_mode(self, HVACMode hvac_mode)
None _handle_action_received(self, ReceiveMessage msg)
None async_set_temperature(self, **Any kwargs)
None async_turn_off(self)
None _handle_preset_mode_received(self, ReceiveMessage msg)
None _handle_mode_received(self, str template_name, str attr, str mode_list, ReceiveMessage msg)
None _setup_from_config(self, ConfigType config)
None async_set_temperature(self, **Any kwargs)
None _subscribe_topics(self)
None _publish(self, str topic, PublishPayloadType payload)
ReceivePayloadType render_template(self, ReceiveMessage msg, str template_name)
None handle_climate_attribute_received(self, str template_name, str attr, ReceiveMessage msg)
bool _set_climate_attribute(self, float|None temp, str cmnd_topic, str cmnd_template, str state_topic, str attr)
None prepare_subscribe_topics(self)
None async_publish_with_config(self, str topic, PublishPayloadType payload)
bool add_subscription(self, str state_topic_config_key, Callable[[ReceiveMessage], None] msg_callback, set[str]|None tracked_attributes, bool disable_encoding=False)
None async_write_ha_state(self)
ConfigType valid_humidity_state_configuration(ConfigType config)
ConfigType valid_preset_mode_configuration(ConfigType config)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
ConfigType valid_humidity_range_configuration(ConfigType config)
None async_setup_entity_entry_helper(HomeAssistant hass, ConfigEntry entry, type[MqttEntity]|None entity_class, str domain, AddEntitiesCallback async_add_entities, VolSchemaType discovery_schema, VolSchemaType platform_schema_modern, dict[str, type[MqttEntity]]|None schema_class_mapping=None)
bool template(HomeAssistant hass, Template value_template, TemplateVarsType variables=None)