ESPHome 2026.1.4
Loading...
Searching...
No Matches
mqtt_climate.cpp
Go to the documentation of this file.
1#include "mqtt_climate.h"
2#include "esphome/core/log.h"
3
4#include "mqtt_const.h"
5
6#ifdef USE_MQTT
7#ifdef USE_CLIMATE
8
9namespace esphome::mqtt {
10
11static const char *const TAG = "mqtt.climate";
12
13using namespace esphome::climate;
14
16 // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
17 auto traits = this->device_->get_traits();
18 // current_temperature_topic
19 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE)) {
20 root[MQTT_CURRENT_TEMPERATURE_TOPIC] = this->get_current_temperature_state_topic();
21 }
22 // current_humidity_topic
23 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_HUMIDITY)) {
24 root[MQTT_CURRENT_HUMIDITY_TOPIC] = this->get_current_humidity_state_topic();
25 }
26 // mode_command_topic
27 root[MQTT_MODE_COMMAND_TOPIC] = this->get_mode_command_topic();
28 // mode_state_topic
29 root[MQTT_MODE_STATE_TOPIC] = this->get_mode_state_topic();
30 // modes
31 JsonArray modes = root[MQTT_MODES].to<JsonArray>();
32 // sort array for nice UI in HA
33 if (traits.supports_mode(CLIMATE_MODE_AUTO))
34 modes.add(ESPHOME_F("auto"));
35 modes.add(ESPHOME_F("off"));
36 if (traits.supports_mode(CLIMATE_MODE_COOL))
37 modes.add(ESPHOME_F("cool"));
38 if (traits.supports_mode(CLIMATE_MODE_HEAT))
39 modes.add(ESPHOME_F("heat"));
40 if (traits.supports_mode(CLIMATE_MODE_FAN_ONLY))
41 modes.add(ESPHOME_F("fan_only"));
42 if (traits.supports_mode(CLIMATE_MODE_DRY))
43 modes.add(ESPHOME_F("dry"));
44 if (traits.supports_mode(CLIMATE_MODE_HEAT_COOL))
45 modes.add(ESPHOME_F("heat_cool"));
46
49 // temperature_low_command_topic
50 root[MQTT_TEMPERATURE_LOW_COMMAND_TOPIC] = this->get_target_temperature_low_command_topic();
51 // temperature_low_state_topic
52 root[MQTT_TEMPERATURE_LOW_STATE_TOPIC] = this->get_target_temperature_low_state_topic();
53 // temperature_high_command_topic
54 root[MQTT_TEMPERATURE_HIGH_COMMAND_TOPIC] = this->get_target_temperature_high_command_topic();
55 // temperature_high_state_topic
56 root[MQTT_TEMPERATURE_HIGH_STATE_TOPIC] = this->get_target_temperature_high_state_topic();
57 } else {
58 // temperature_command_topic
59 root[MQTT_TEMPERATURE_COMMAND_TOPIC] = this->get_target_temperature_command_topic();
60 // temperature_state_topic
61 root[MQTT_TEMPERATURE_STATE_TOPIC] = this->get_target_temperature_state_topic();
62 }
63
64 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY)) {
65 // target_humidity_command_topic
66 root[MQTT_TARGET_HUMIDITY_COMMAND_TOPIC] = this->get_target_humidity_command_topic();
67 // target_humidity_state_topic
68 root[MQTT_TARGET_HUMIDITY_STATE_TOPIC] = this->get_target_humidity_state_topic();
69 }
70
71 // min_temp
72 root[MQTT_MIN_TEMP] = traits.get_visual_min_temperature();
73 // max_temp
74 root[MQTT_MAX_TEMP] = traits.get_visual_max_temperature();
75 // target_temp_step
76 root[MQTT_TARGET_TEMPERATURE_STEP] = roundf(traits.get_visual_target_temperature_step() * 10) * 0.1;
77 // current_temp_step
78 root[MQTT_CURRENT_TEMPERATURE_STEP] = roundf(traits.get_visual_current_temperature_step() * 10) * 0.1;
79 // temperature units are always coerced to Celsius internally
80 root[MQTT_TEMPERATURE_UNIT] = "C";
81
82 // min_humidity
83 root[MQTT_MIN_HUMIDITY] = traits.get_visual_min_humidity();
84 // max_humidity
85 root[MQTT_MAX_HUMIDITY] = traits.get_visual_max_humidity();
86
87 if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
88 // preset_mode_command_topic
89 root[MQTT_PRESET_MODE_COMMAND_TOPIC] = this->get_preset_command_topic();
90 // preset_mode_state_topic
91 root[MQTT_PRESET_MODE_STATE_TOPIC] = this->get_preset_state_topic();
92 // presets
93 JsonArray presets = root[ESPHOME_F("preset_modes")].to<JsonArray>();
94 if (traits.supports_preset(CLIMATE_PRESET_HOME))
95 presets.add(ESPHOME_F("home"));
96 if (traits.supports_preset(CLIMATE_PRESET_AWAY))
97 presets.add(ESPHOME_F("away"));
98 if (traits.supports_preset(CLIMATE_PRESET_BOOST))
99 presets.add(ESPHOME_F("boost"));
100 if (traits.supports_preset(CLIMATE_PRESET_COMFORT))
101 presets.add(ESPHOME_F("comfort"));
102 if (traits.supports_preset(CLIMATE_PRESET_ECO))
103 presets.add(ESPHOME_F("eco"));
104 if (traits.supports_preset(CLIMATE_PRESET_SLEEP))
105 presets.add(ESPHOME_F("sleep"));
106 if (traits.supports_preset(CLIMATE_PRESET_ACTIVITY))
107 presets.add(ESPHOME_F("activity"));
108 for (const auto &preset : traits.get_supported_custom_presets())
109 presets.add(preset);
110 }
111
112 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_ACTION)) {
113 // action_topic
114 root[MQTT_ACTION_TOPIC] = this->get_action_state_topic();
115 }
116
117 if (traits.get_supports_fan_modes()) {
118 // fan_mode_command_topic
119 root[MQTT_FAN_MODE_COMMAND_TOPIC] = this->get_fan_mode_command_topic();
120 // fan_mode_state_topic
121 root[MQTT_FAN_MODE_STATE_TOPIC] = this->get_fan_mode_state_topic();
122 // fan_modes
123 JsonArray fan_modes = root[ESPHOME_F("fan_modes")].to<JsonArray>();
124 if (traits.supports_fan_mode(CLIMATE_FAN_ON))
125 fan_modes.add(ESPHOME_F("on"));
126 if (traits.supports_fan_mode(CLIMATE_FAN_OFF))
127 fan_modes.add(ESPHOME_F("off"));
128 if (traits.supports_fan_mode(CLIMATE_FAN_AUTO))
129 fan_modes.add(ESPHOME_F("auto"));
130 if (traits.supports_fan_mode(CLIMATE_FAN_LOW))
131 fan_modes.add(ESPHOME_F("low"));
132 if (traits.supports_fan_mode(CLIMATE_FAN_MEDIUM))
133 fan_modes.add(ESPHOME_F("medium"));
134 if (traits.supports_fan_mode(CLIMATE_FAN_HIGH))
135 fan_modes.add(ESPHOME_F("high"));
136 if (traits.supports_fan_mode(CLIMATE_FAN_MIDDLE))
137 fan_modes.add(ESPHOME_F("middle"));
138 if (traits.supports_fan_mode(CLIMATE_FAN_FOCUS))
139 fan_modes.add(ESPHOME_F("focus"));
140 if (traits.supports_fan_mode(CLIMATE_FAN_DIFFUSE))
141 fan_modes.add(ESPHOME_F("diffuse"));
142 if (traits.supports_fan_mode(CLIMATE_FAN_QUIET))
143 fan_modes.add(ESPHOME_F("quiet"));
144 for (const auto &fan_mode : traits.get_supported_custom_fan_modes())
145 fan_modes.add(fan_mode);
146 }
147
148 if (traits.get_supports_swing_modes()) {
149 // swing_mode_command_topic
150 root[MQTT_SWING_MODE_COMMAND_TOPIC] = this->get_swing_mode_command_topic();
151 // swing_mode_state_topic
152 root[MQTT_SWING_MODE_STATE_TOPIC] = this->get_swing_mode_state_topic();
153 // swing_modes
154 JsonArray swing_modes = root[ESPHOME_F("swing_modes")].to<JsonArray>();
155 if (traits.supports_swing_mode(CLIMATE_SWING_OFF))
156 swing_modes.add(ESPHOME_F("off"));
157 if (traits.supports_swing_mode(CLIMATE_SWING_BOTH))
158 swing_modes.add(ESPHOME_F("both"));
159 if (traits.supports_swing_mode(CLIMATE_SWING_VERTICAL))
160 swing_modes.add(ESPHOME_F("vertical"));
161 if (traits.supports_swing_mode(CLIMATE_SWING_HORIZONTAL))
162 swing_modes.add(ESPHOME_F("horizontal"));
163 }
164
165 config.state_topic = false;
166 config.command_topic = false;
167 // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
168}
170 auto traits = this->device_->get_traits();
171 this->subscribe(this->get_mode_command_topic(), [this](const std::string &topic, const std::string &payload) {
172 auto call = this->device_->make_call();
173 call.set_mode(payload);
174 call.perform();
175 });
176
177 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
179 this->subscribe(this->get_target_temperature_low_command_topic(),
180 [this](const std::string &topic, const std::string &payload) {
181 auto val = parse_number<float>(payload);
182 if (!val.has_value()) {
183 ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
184 return;
185 }
186 auto call = this->device_->make_call();
188 call.perform();
189 });
190 this->subscribe(this->get_target_temperature_high_command_topic(),
191 [this](const std::string &topic, const std::string &payload) {
192 auto val = parse_number<float>(payload);
193 if (!val.has_value()) {
194 ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
195 return;
196 }
197 auto call = this->device_->make_call();
199 call.perform();
200 });
201 } else {
202 this->subscribe(this->get_target_temperature_command_topic(),
203 [this](const std::string &topic, const std::string &payload) {
204 auto val = parse_number<float>(payload);
205 if (!val.has_value()) {
206 ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
207 return;
208 }
209 auto call = this->device_->make_call();
211 call.perform();
212 });
213 }
214
215 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY)) {
216 this->subscribe(this->get_target_humidity_command_topic(),
217 [this](const std::string &topic, const std::string &payload) {
218 auto val = parse_number<float>(payload);
219 if (!val.has_value()) {
220 ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
221 return;
222 }
223 auto call = this->device_->make_call();
225 call.perform();
226 });
227 }
228
229 if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
230 this->subscribe(this->get_preset_command_topic(), [this](const std::string &topic, const std::string &payload) {
231 auto call = this->device_->make_call();
232 call.set_preset(payload);
233 call.perform();
234 });
235 }
236
237 if (traits.get_supports_fan_modes()) {
238 this->subscribe(this->get_fan_mode_command_topic(), [this](const std::string &topic, const std::string &payload) {
239 auto call = this->device_->make_call();
240 call.set_fan_mode(payload);
241 call.perform();
242 });
243 }
244
245 if (traits.get_supports_swing_modes()) {
246 this->subscribe(this->get_swing_mode_command_topic(), [this](const std::string &topic, const std::string &payload) {
247 auto call = this->device_->make_call();
248 call.set_swing_mode(payload);
249 call.perform();
250 });
251 }
252
253 this->device_->add_on_state_callback([this](Climate & /*unused*/) { this->publish_state_(); });
254}
258const EntityBase *MQTTClimateComponent::get_entity() const { return this->device_; }
259
261 auto traits = this->device_->get_traits();
262 // mode
263 const char *mode_s;
264 switch (this->device_->mode) {
265 case CLIMATE_MODE_OFF:
266 mode_s = "off";
267 break;
269 mode_s = "auto";
270 break;
272 mode_s = "cool";
273 break;
275 mode_s = "heat";
276 break;
278 mode_s = "fan_only";
279 break;
280 case CLIMATE_MODE_DRY:
281 mode_s = "dry";
282 break;
284 mode_s = "heat_cool";
285 break;
286 default:
287 mode_s = "unknown";
288 }
289 bool success = true;
290 if (!this->publish(this->get_mode_state_topic(), mode_s))
291 success = false;
292 int8_t target_accuracy = traits.get_target_temperature_accuracy_decimals();
293 int8_t current_accuracy = traits.get_current_temperature_accuracy_decimals();
294 char payload[VALUE_ACCURACY_MAX_LEN];
295 size_t len;
296 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE) &&
297 !std::isnan(this->device_->current_temperature)) {
298 len = value_accuracy_to_buf(payload, this->device_->current_temperature, current_accuracy);
299 if (!this->publish(this->get_current_temperature_state_topic(), payload, len))
300 success = false;
301 }
302 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
304 len = value_accuracy_to_buf(payload, this->device_->target_temperature_low, target_accuracy);
305 if (!this->publish(this->get_target_temperature_low_state_topic(), payload, len))
306 success = false;
307 len = value_accuracy_to_buf(payload, this->device_->target_temperature_high, target_accuracy);
308 if (!this->publish(this->get_target_temperature_high_state_topic(), payload, len))
309 success = false;
310 } else {
311 len = value_accuracy_to_buf(payload, this->device_->target_temperature, target_accuracy);
312 if (!this->publish(this->get_target_temperature_state_topic(), payload, len))
313 success = false;
314 }
315
316 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_HUMIDITY) &&
317 !std::isnan(this->device_->current_humidity)) {
319 if (!this->publish(this->get_current_humidity_state_topic(), payload, len))
320 success = false;
321 }
322 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY) &&
323 !std::isnan(this->device_->target_humidity)) {
324 len = value_accuracy_to_buf(payload, this->device_->target_humidity, 0);
325 if (!this->publish(this->get_target_humidity_state_topic(), payload, len))
326 success = false;
327 }
328
329 if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
330 std::string payload;
331 if (this->device_->preset.has_value()) {
332 switch (this->device_->preset.value()) {
334 payload = "none";
335 break;
337 payload = "home";
338 break;
340 payload = "away";
341 break;
343 payload = "boost";
344 break;
346 payload = "comfort";
347 break;
349 payload = "eco";
350 break;
352 payload = "sleep";
353 break;
355 payload = "activity";
356 break;
357 default:
358 payload = "unknown";
359 }
360 }
361 if (this->device_->has_custom_preset())
362 payload = this->device_->get_custom_preset().c_str();
363 if (!this->publish(this->get_preset_state_topic(), payload))
364 success = false;
365 }
366
367 if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_ACTION)) {
368 const char *payload;
369 switch (this->device_->action) {
371 payload = "off";
372 break;
374 payload = "cooling";
375 break;
377 payload = "heating";
378 break;
380 payload = "idle";
381 break;
383 payload = "drying";
384 break;
386 payload = "fan";
387 break;
388 default:
389 payload = "unknown";
390 }
391 if (!this->publish(this->get_action_state_topic(), payload))
392 success = false;
393 }
394
395 if (traits.get_supports_fan_modes()) {
396 std::string payload;
397 if (this->device_->fan_mode.has_value()) {
398 switch (this->device_->fan_mode.value()) {
399 case CLIMATE_FAN_ON:
400 payload = "on";
401 break;
402 case CLIMATE_FAN_OFF:
403 payload = "off";
404 break;
405 case CLIMATE_FAN_AUTO:
406 payload = "auto";
407 break;
408 case CLIMATE_FAN_LOW:
409 payload = "low";
410 break;
412 payload = "medium";
413 break;
414 case CLIMATE_FAN_HIGH:
415 payload = "high";
416 break;
418 payload = "middle";
419 break;
421 payload = "focus";
422 break;
424 payload = "diffuse";
425 break;
427 payload = "quiet";
428 break;
429 default:
430 payload = "unknown";
431 }
432 }
433 if (this->device_->has_custom_fan_mode())
434 payload = this->device_->get_custom_fan_mode().c_str();
435 if (!this->publish(this->get_fan_mode_state_topic(), payload))
436 success = false;
437 }
438
439 if (traits.get_supports_swing_modes()) {
440 const char *payload;
441 switch (this->device_->swing_mode) {
443 payload = "off";
444 break;
446 payload = "both";
447 break;
449 payload = "vertical";
450 break;
452 payload = "horizontal";
453 break;
454 default:
455 payload = "unknown";
456 }
457 if (!this->publish(this->get_swing_mode_state_topic(), payload))
458 success = false;
459 }
460
461 return success;
462}
463
464} // namespace esphome::mqtt
465
466#endif
467#endif // USE_MQTT
constexpr const char * c_str() const
Definition string_ref.h:73
ClimateCall & set_target_temperature(float target_temperature)
Set the target temperature of the climate device.
Definition climate.cpp:279
ClimateCall & set_swing_mode(ClimateSwingMode swing_mode)
Set the swing mode of the climate device.
Definition climate.cpp:263
ClimateCall & set_target_temperature_low(float target_temperature_low)
Set the low point target temperature of the climate device.
Definition climate.cpp:284
ClimateCall & set_preset(ClimatePreset preset)
Set the preset of the climate device.
Definition climate.cpp:225
ClimateCall & set_fan_mode(ClimateFanMode fan_mode)
Set the fan mode of the climate device.
Definition climate.cpp:187
ClimateCall & set_target_humidity(float target_humidity)
Set the target humidity of the climate device.
Definition climate.cpp:294
ClimateCall & set_target_temperature_high(float target_temperature_high)
Set the high point target temperature of the climate device.
Definition climate.cpp:289
ClimateCall & set_mode(ClimateMode mode)
Set the mode of the climate device.
Definition climate.cpp:171
ClimateDevice - This is the base class for all climate integrations.
Definition climate.h:182
ClimateMode mode
The active mode of the climate device.
Definition climate.h:262
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition climate.h:256
ClimateTraits get_traits()
Get the traits of this climate device with all overrides applied.
Definition climate.cpp:487
float target_temperature
The target temperature of the climate device.
Definition climate.h:243
float current_humidity
The current humidity of the climate device, as reported from the integration.
Definition climate.h:239
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition climate.h:268
float target_temperature_low
The minimum target temperature of the climate device, for climate devices with split target temperatu...
Definition climate.h:246
void add_on_state_callback(std::function< void(Climate &)> &&callback)
Add a callback for the climate device state, each time the state of the climate device is updated (us...
Definition climate.cpp:351
bool has_custom_preset() const
Check if a custom preset is currently active.
Definition climate.h:233
float current_temperature
The current temperature of the climate device, as reported from the integration.
Definition climate.h:236
ClimateAction action
The active state of the climate device.
Definition climate.h:265
ClimateCall make_call()
Make a climate device control call, this is used to control the climate device, see the ClimateCall d...
Definition climate.cpp:533
StringRef get_custom_preset() const
Get the active custom preset (read-only access). Returns StringRef.
Definition climate.h:274
bool has_custom_fan_mode() const
Check if a custom fan mode is currently active.
Definition climate.h:230
optional< ClimatePreset > preset
The active preset of the climate device.
Definition climate.h:259
float target_humidity
The target humidity of the climate device.
Definition climate.h:253
float target_temperature_high
The maximum target temperature of the climate device, for climate devices with split target temperatu...
Definition climate.h:248
StringRef get_custom_fan_mode() const
Get the active custom fan mode (read-only access). Returns StringRef.
Definition climate.h:271
int8_t get_target_temperature_accuracy_decimals() const
MQTTClimateComponent(climate::Climate *device)
state command command command command command command state state state MQTT_COMPONENT_CUSTOM_TOPIC(preset, command) protected bool publish_state_()
void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override
bool publish(const std::string &topic, const std::string &payload)
Send a MQTT message.
void subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos=0)
Subscribe to a MQTT topic.
bool has_value() const
Definition optional.h:92
value_type const & value() const
Definition optional.h:94
ClimateFanMode fan_mode
Definition climate.h:3
ClimatePreset preset
Definition climate.h:8
mopeka_std_values val[4]
@ CLIMATE_SUPPORTS_CURRENT_HUMIDITY
@ CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
@ CLIMATE_SUPPORTS_CURRENT_TEMPERATURE
@ CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE
@ CLIMATE_PRESET_NONE
No preset is active.
@ CLIMATE_PRESET_COMFORT
Device is in comfort preset.
@ CLIMATE_PRESET_AWAY
Device is in away preset.
@ CLIMATE_PRESET_BOOST
Device is in boost preset.
@ CLIMATE_PRESET_ACTIVITY
Device is reacting to activity (e.g., movement sensors)
@ CLIMATE_PRESET_SLEEP
Device is prepared for sleep.
@ CLIMATE_PRESET_HOME
Device is in home preset.
@ CLIMATE_PRESET_ECO
Device is running an energy-saving preset.
@ CLIMATE_SWING_OFF
The swing mode is set to Off.
@ CLIMATE_SWING_HORIZONTAL
The fan mode is set to Horizontal.
@ CLIMATE_SWING_VERTICAL
The fan mode is set to Vertical.
@ CLIMATE_SWING_BOTH
The fan mode is set to Both.
@ CLIMATE_MODE_DRY
The climate device is set to dry/humidity mode.
@ CLIMATE_MODE_FAN_ONLY
The climate device only has the fan enabled, no heating or cooling is taking place.
@ CLIMATE_MODE_HEAT
The climate device is set to heat to reach the target temperature.
@ CLIMATE_MODE_COOL
The climate device is set to cool to reach the target temperature.
@ CLIMATE_MODE_HEAT_COOL
The climate device is set to heat/cool to reach the target temperature.
@ CLIMATE_MODE_OFF
The climate device is off.
@ CLIMATE_MODE_AUTO
The climate device is adjusting the temperature dynamically.
@ CLIMATE_ACTION_OFF
The climate device is off (inactive or no power)
@ CLIMATE_ACTION_IDLE
The climate device is idle (monitoring climate but no action needed)
@ CLIMATE_ACTION_DRYING
The climate device is drying.
@ CLIMATE_ACTION_HEATING
The climate device is actively heating.
@ CLIMATE_ACTION_COOLING
The climate device is actively cooling.
@ CLIMATE_ACTION_FAN
The climate device is in fan only mode.
@ CLIMATE_FAN_MEDIUM
The fan mode is set to Medium.
@ CLIMATE_FAN_DIFFUSE
The fan mode is set to Diffuse.
@ CLIMATE_FAN_ON
The fan mode is set to On.
@ CLIMATE_FAN_AUTO
The fan mode is set to Auto.
@ CLIMATE_FAN_FOCUS
The fan mode is set to Focus.
@ CLIMATE_FAN_LOW
The fan mode is set to Low.
@ CLIMATE_FAN_MIDDLE
The fan mode is set to Middle.
@ CLIMATE_FAN_QUIET
The fan mode is set to Quiet.
@ CLIMATE_FAN_OFF
The fan mode is set to Off.
@ CLIMATE_FAN_HIGH
The fan mode is set to High.
MQTT_COMPONENT_TYPE(MQTTAlarmControlPanelComponent, "alarm_control_panel") const EntityBase *MQTTAlarmControlPanelComponent
size_t value_accuracy_to_buf(std::span< char, VALUE_ACCURACY_MAX_LEN > buf, float value, int8_t accuracy_decimals)
Format value with accuracy to buffer, returns chars written (excluding null)
Definition helpers.cpp:448
std::string size_t len
Definition helpers.h:595
optional< T > parse_number(const char *str)
Parse an unsigned decimal number from a null-terminated string.
Definition helpers.h:640
Simple Helper struct used for Home Assistant MQTT send_discovery().
bool command_topic
If the command topic should be included. Default to true.
bool state_topic
If the state topic should be included. Defaults to true.