ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
mqtt_component.cpp
Go to the documentation of this file.
1#include "mqtt_component.h"
2
3#ifdef USE_MQTT
4
5#include <cmath>
6
9#include "esphome/core/log.h"
12
13#include "mqtt_const.h"
14
15namespace esphome::mqtt {
16
17ESPHOME_LOG_TAG(TAG, "mqtt.component");
18
19// Entity category MQTT strings indexed by EntityCategory enum: NONE(0) is skipped, CONFIG(1), DIAGNOSTIC(2)
20PROGMEM_STRING_TABLE(EntityCategoryMqttStrings, "", "config", "diagnostic");
21
22// Helper functions for building topic strings on stack
23inline char *append_str(char *p, const char *s, size_t len) {
24 memcpy(p, s, len);
25 return p + len;
26}
27
28inline char *append_char(char *p, char c) {
29 *p = c;
30 return p + 1;
31}
32
33// Max lengths for stack-based topic building.
34// These limits are enforced at Python config validation time in mqtt/__init__.py
35// using cv.Length() validators for topic_prefix and discovery_prefix.
36// MQTT_COMPONENT_TYPE_MAX_LEN, MQTT_SUFFIX_MAX_LEN, and MQTT_DEFAULT_TOPIC_MAX_LEN are in mqtt_component.h.
37// ESPHOME_DEVICE_NAME_MAX_LEN and OBJECT_ID_MAX_LEN are defined in entity_base.h.
38// This ensures the stack buffers below are always large enough.
39// MQTT_DISCOVERY_PREFIX_MAX_LEN and MQTT_DISCOVERY_TOPIC_MAX_LEN are defined in mqtt_component.h
40
41// Function implementation of LOG_MQTT_COMPONENT macro to reduce code size
42void log_mqtt_component(const char *tag, MQTTComponent *obj, bool state_topic, bool command_topic) {
43 ESP_LOGCONFIG(tag, "MQTT %s '%s':", obj->component_type(), LOG_STR_ARG(obj->get_entity()->get_log_name()));
44 char buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
45 if (state_topic) {
46 ESP_LOGCONFIG(tag, " State Topic: '%s'", obj->get_state_topic_to_(buf).c_str());
47 }
48 if (command_topic) {
49 ESP_LOGCONFIG(tag, " Command Topic: '%s'", obj->get_command_topic_to_(buf).c_str());
50 }
51}
52
53void MQTTComponent::set_qos(uint8_t qos) { this->qos_ = qos; }
54
55void MQTTComponent::set_subscribe_qos(uint8_t qos) { this->subscribe_qos_ = qos; }
56
57void MQTTComponent::set_retain(bool retain) { this->retain_ = retain; }
58
59StringRef MQTTComponent::get_discovery_topic_to_(std::span<char, MQTT_DISCOVERY_TOPIC_MAX_LEN> buf,
60 const MQTTDiscoveryInfo &discovery_info) const {
61 char sanitized_name[ESPHOME_DEVICE_NAME_MAX_LEN + 1];
62 str_sanitize_to(sanitized_name, App.get_name().c_str());
63 const char *comp_type = this->component_type();
64 char object_id_buf[OBJECT_ID_MAX_LEN];
65 StringRef object_id = this->get_default_object_id_to_(object_id_buf);
66
67 char *p = buf.data();
68
69 p = append_str(p, discovery_info.prefix.data(), discovery_info.prefix.size());
70 p = append_char(p, '/');
71 p = append_str(p, comp_type, strlen(comp_type));
72 p = append_char(p, '/');
73 p = append_str(p, sanitized_name, strlen(sanitized_name));
74 p = append_char(p, '/');
75 p = append_str(p, object_id.c_str(), object_id.size());
76 p = append_str(p, "/config", 7);
77 *p = '\0';
78
79 return StringRef(buf.data(), p - buf.data());
80}
81
82StringRef MQTTComponent::get_default_topic_for_to_(std::span<char, MQTT_DEFAULT_TOPIC_MAX_LEN> buf, const char *suffix,
83 size_t suffix_len) const {
84 const std::string &topic_prefix = global_mqtt_client->get_topic_prefix();
85 if (topic_prefix.empty()) {
86 return StringRef(); // Empty topic_prefix means no default topic
87 }
88
89 const char *comp_type = this->component_type();
90 char object_id_buf[OBJECT_ID_MAX_LEN];
91 StringRef object_id = this->get_default_object_id_to_(object_id_buf);
92
93 char *p = buf.data();
94
95 p = append_str(p, topic_prefix.data(), topic_prefix.size());
96 p = append_char(p, '/');
97 p = append_str(p, comp_type, strlen(comp_type));
98 p = append_char(p, '/');
99 p = append_str(p, object_id.c_str(), object_id.size());
100 p = append_char(p, '/');
101 p = append_str(p, suffix, suffix_len);
102 *p = '\0';
103
104 return StringRef(buf.data(), p - buf.data());
105}
106
107std::string MQTTComponent::get_default_topic_for_(const std::string &suffix) const {
108 char buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
109 StringRef ref = this->get_default_topic_for_to_(buf, suffix.data(), suffix.size());
110 return std::string(ref.c_str(), ref.size());
111}
112
113StringRef MQTTComponent::get_state_topic_to_(std::span<char, MQTT_DEFAULT_TOPIC_MAX_LEN> buf) const {
114 if (this->custom_state_topic_.has_value()) {
115 // Returns ref to existing data for static/value, uses buf only for lambda case
116 return this->custom_state_topic_.ref_or_copy_to(buf.data(), buf.size());
117 }
118 return this->get_default_topic_for_to_(buf, "state", 5);
119}
120
121StringRef MQTTComponent::get_command_topic_to_(std::span<char, MQTT_DEFAULT_TOPIC_MAX_LEN> buf) const {
122 if (this->custom_command_topic_.has_value()) {
123 // Returns ref to existing data for static/value, uses buf only for lambda case
124 return this->custom_command_topic_.ref_or_copy_to(buf.data(), buf.size());
125 }
126 return this->get_default_topic_for_to_(buf, "command", 7);
127}
128
130 if (this->custom_command_topic_.is_lambda()) {
131 char buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
133 }
135}
136
138 char buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
139 StringRef ref = this->get_state_topic_to_(buf);
140 return std::string(ref.c_str(), ref.size());
141}
142
144 char buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
146 return std::string(ref.c_str(), ref.size());
147}
148
149bool MQTTComponent::publish(const std::string &topic, const std::string &payload) {
150 return this->publish(topic.c_str(), payload.data(), payload.size());
151}
152
153bool MQTTComponent::publish(const std::string &topic, const char *payload, size_t payload_length) {
154 return this->publish(topic.c_str(), payload, payload_length);
155}
156
157bool MQTTComponent::publish(const char *topic, const char *payload, size_t payload_length) {
158 if (topic[0] == '\0')
159 return false;
160 return global_mqtt_client->publish(topic, payload, payload_length, this->qos_, this->retain_);
161}
162
163bool MQTTComponent::publish(const char *topic, const char *payload) {
164 return this->publish(topic, payload, strlen(payload));
165}
166
167#ifdef USE_ESP8266
168bool MQTTComponent::publish(const std::string &topic, ProgmemStr payload) {
169 return this->publish(topic.c_str(), payload);
170}
171
172bool MQTTComponent::publish(const char *topic, ProgmemStr payload) {
173 if (topic[0] == '\0')
174 return false;
175 // On ESP8266, ProgmemStr is __FlashStringHelper* - need to copy from flash
176 char buf[64];
177 strncpy_P(buf, reinterpret_cast<const char *>(payload), sizeof(buf) - 1);
178 buf[sizeof(buf) - 1] = '\0';
179 return global_mqtt_client->publish(topic, buf, strlen(buf), this->qos_, this->retain_);
180}
181#endif
182
183bool MQTTComponent::publish_float_(StringRef topic, float value, int8_t accuracy) {
184 if (global_mqtt_client->is_publish_nan_as_none() && std::isnan(value))
185 return this->publish(topic, "None", 4);
186 char buf[VALUE_ACCURACY_MAX_LEN];
187 size_t len = value_accuracy_to_buf(buf, value, accuracy);
188 return this->publish(topic, buf, len);
189}
190
191bool MQTTComponent::publish_json(const std::string &topic, const json::json_build_t &f) {
192 return this->publish_json(topic.c_str(), f);
193}
194
195bool MQTTComponent::publish_json(const char *topic, const json::json_build_t &f) {
196 if (topic[0] == '\0')
197 return false;
198 return global_mqtt_client->publish_json(topic, f, this->qos_, this->retain_);
199}
200
203
204 char discovery_topic_buf[MQTT_DISCOVERY_TOPIC_MAX_LEN];
205 StringRef discovery_topic = this->get_discovery_topic_to_(discovery_topic_buf, discovery_info);
206
207 if (discovery_info.clean) {
208 ESP_LOGV(TAG, "'%s': Cleaning discovery", LOG_STR_ARG(this->log_name_()));
209 return global_mqtt_client->publish(discovery_topic.c_str(), "", 0, this->qos_, true);
210 }
211
212 ESP_LOGV(TAG, "'%s': Sending discovery", LOG_STR_ARG(this->log_name_()));
213
214 // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
216 discovery_topic.c_str(),
217 [this](JsonObject root) {
218 SendDiscoveryConfig config;
219 config.state_topic = true;
220 config.command_topic = true;
221
222 this->send_discovery(root, config);
223 // Set subscription QoS (default is 0)
224 if (this->subscribe_qos_ != 0) {
225 root[MQTT_QOS] = this->subscribe_qos_;
226 }
227
228 // Fields from EntityBase
229 if (this->get_entity()->has_own_name()) {
230 root[MQTT_NAME] = json::linked(this->get_entity()->get_name_progmem());
231 } else {
232 root[MQTT_NAME] = StringRef();
233 }
234
235 if (this->is_disabled_by_default_())
236 root[MQTT_ENABLED_BY_DEFAULT] = false;
238 if (!icon.empty()) {
239 root[MQTT_ICON] = json::linked(icon);
240 }
242 if (!dc.empty()) {
243 root[MQTT_DEVICE_CLASS] = json::linked(dc);
244 }
245
246 const auto entity_category = this->get_entity()->get_entity_category();
247 if (entity_category != ENTITY_CATEGORY_NONE) {
248 root[MQTT_ENTITY_CATEGORY] = EntityCategoryMqttStrings::get_progmem_str(
249 static_cast<uint8_t>(entity_category), static_cast<uint8_t>(ENTITY_CATEGORY_CONFIG));
250 }
251
252 if (config.state_topic) {
253 char state_topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
254 root[MQTT_STATE_TOPIC] = this->get_state_topic_to_(state_topic_buf);
255 }
256 if (config.command_topic) {
257 char command_topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
258 root[MQTT_COMMAND_TOPIC] = this->get_command_topic_to_(command_topic_buf);
259 }
260 if (this->command_retain_)
261 root[MQTT_COMMAND_RETAIN] = true;
262
263 const Availability &avail =
264 this->availability_ == nullptr ? global_mqtt_client->get_availability() : *this->availability_;
265 if (!avail.topic.empty()) {
266 root[MQTT_AVAILABILITY_TOPIC] = avail.topic;
267 if (avail.payload_available != "online")
268 root[MQTT_PAYLOAD_AVAILABLE] = avail.payload_available;
269 if (avail.payload_not_available != "offline")
270 root[MQTT_PAYLOAD_NOT_AVAILABLE] = avail.payload_not_available;
271 }
272
274 char object_id_buf[OBJECT_ID_MAX_LEN];
275 StringRef object_id = this->get_default_object_id_to_(object_id_buf);
277 char name_buf[ENTITY_NAME_BUF_SIZE];
278 char friendly_name_hash[9];
279 buf_append_printf(friendly_name_hash, sizeof(friendly_name_hash), 0, "%08" PRIx32,
280 fnv1_hash(this->get_entity()->get_name_to(name_buf).c_str()));
281 // Format: mac-component_type-hash (e.g. "aabbccddeeff-sensor-12345678")
282 // MAC (12) + "-" (1) + domain (max 20) + "-" (1) + hash (8) + null (1) = 43
283 char unique_id[MAC_ADDRESS_BUFFER_SIZE + ESPHOME_DOMAIN_MAX_LEN + 11];
284 char mac_buf[MAC_ADDRESS_BUFFER_SIZE];
286 buf_append_printf(unique_id, sizeof(unique_id), 0, "%s-%s-%s", mac_buf, this->component_type(),
287 friendly_name_hash);
288 root[MQTT_UNIQUE_ID] = unique_id;
289 } else {
290 // default to almost-unique ID. It's a hack but the only way to get that
291 // gorgeous device registry view.
292 // "ESP" (3) + component_type (max 20) + object_id (max 128) + null
293 char unique_id_buf[3 + MQTT_COMPONENT_TYPE_MAX_LEN + OBJECT_ID_MAX_LEN + 1];
294 buf_append_printf(unique_id_buf, sizeof(unique_id_buf), 0, "ESP%s%s", this->component_type(),
295 object_id.c_str());
296 root[MQTT_UNIQUE_ID] = unique_id_buf;
297 }
298
299 const auto &node_name = App.get_name();
301 // node_name (max 31) + "_" (1) + object_id (max 128) + null
302 char object_id_full[ESPHOME_DEVICE_NAME_MAX_LEN + 1 + OBJECT_ID_MAX_LEN + 1];
303 buf_append_printf(object_id_full, sizeof(object_id_full), 0, "%s_%s", node_name.c_str(), object_id.c_str());
304 root[MQTT_OBJECT_ID] = object_id_full;
305 }
306
307 const auto &friendly_name_ref = App.get_friendly_name();
308 const auto &node_friendly_name = friendly_name_ref.empty() ? node_name : friendly_name_ref;
309 const char *node_area = App.get_area();
310
311 JsonObject device_info = root[MQTT_DEVICE].to<JsonObject>();
312 char mac[MAC_ADDRESS_BUFFER_SIZE];
314 device_info[MQTT_DEVICE_IDENTIFIERS] = mac;
315 device_info[MQTT_DEVICE_NAME] = node_friendly_name;
316#ifdef ESPHOME_PROJECT_NAME
317 device_info[MQTT_DEVICE_SW_VERSION] = ESPHOME_PROJECT_VERSION " (ESPHome " ESPHOME_VERSION ")";
318 const char *model = std::strchr(ESPHOME_PROJECT_NAME, '.');
319 device_info[MQTT_DEVICE_MODEL] = model == nullptr ? ESPHOME_BOARD : model + 1;
320 if (model == nullptr) {
321 device_info[MQTT_DEVICE_MANUFACTURER] = ESPHOME_PROJECT_NAME;
322 } else {
323 // Extract manufacturer (part before '.') using stack buffer to avoid heap allocation
324 // memcpy is used instead of strncpy since we know the exact length and strncpy
325 // would still require manual null-termination
326 char manufacturer[sizeof(ESPHOME_PROJECT_NAME)];
327 size_t len = model - ESPHOME_PROJECT_NAME;
328 memcpy(manufacturer, ESPHOME_PROJECT_NAME, len);
329 manufacturer[len] = '\0';
330 device_info[MQTT_DEVICE_MANUFACTURER] = manufacturer;
331 }
332#else
333 static const char ver_fmt[] PROGMEM = ESPHOME_VERSION " (config hash 0x%08" PRIx32 ")";
334 // Buffer sized for format string expansion: ~4 bytes net growth from format specifier to 8 hex digits, plus
335 // safety margin
336 char version_buf[sizeof(ver_fmt) + 8];
337 ESPHOME_snprintf_P(version_buf, sizeof(version_buf), ver_fmt, App.get_config_hash());
338 device_info[MQTT_DEVICE_SW_VERSION] = version_buf;
339 device_info[MQTT_DEVICE_MODEL] = ESPHOME_BOARD;
340#if defined(USE_ESP8266) || defined(USE_ESP32)
341 device_info[MQTT_DEVICE_MANUFACTURER] = "Espressif";
342#elif defined(USE_RP2)
343 device_info[MQTT_DEVICE_MANUFACTURER] = "Raspberry Pi";
344#elif defined(USE_BK72XX)
345 device_info[MQTT_DEVICE_MANUFACTURER] = "Beken";
346#elif defined(USE_RTL87XX)
347 device_info[MQTT_DEVICE_MANUFACTURER] = "Realtek";
348#elif defined(USE_HOST)
349 device_info[MQTT_DEVICE_MANUFACTURER] = "Host";
350#endif
351#endif
352 if (node_area[0] != '\0') {
353 device_info[MQTT_DEVICE_SUGGESTED_AREA] = node_area;
354 }
355
356 device_info[MQTT_DEVICE_CONNECTIONS][0][0] = "mac";
357 device_info[MQTT_DEVICE_CONNECTIONS][0][1] = mac;
358 },
359 this->qos_, discovery_info.retain);
360 // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
361}
362
363bool MQTTComponent::is_discovery_enabled() const {
364 return this->discovery_enabled_ && global_mqtt_client->is_discovery_enabled();
365}
366
367MQTTComponent::MQTTComponent() = default;
368
369float MQTTComponent::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
370void MQTTComponent::disable_discovery() { this->discovery_enabled_ = false; }
371void MQTTComponent::set_command_retain(bool command_retain) { this->command_retain_ = command_retain; }
372
373void MQTTComponent::set_availability(std::string topic, std::string payload_available,
374 std::string payload_not_available) {
375 this->availability_ = make_unique<Availability>();
376 this->availability_->topic = std::move(topic);
377 this->availability_->payload_available = std::move(payload_available);
378 this->availability_->payload_not_available = std::move(payload_not_available);
379}
380void MQTTComponent::disable_availability() { this->set_availability("", "", ""); }
381void MQTTComponent::call_setup() {
382 // Cache is_internal result once during setup - topics don't change after this
383 this->is_internal_ = this->compute_is_internal_();
384 if (this->is_internal_)
385 return;
386
387 this->setup();
388
390
391 if (!this->is_connected_())
392 return;
393
394 if (this->is_discovery_enabled()) {
395 if (!this->send_discovery_()) {
396 this->schedule_resend_state();
397 }
398 }
399 if (!this->send_initial_state()) {
400 this->schedule_resend_state();
401 }
402}
403
404void MQTTComponent::process_resend() {
405 // Called by MQTTClientComponent when connected to process pending resends
406 // Note: is_internal() check not needed - internal components are never registered
407 if (!this->resend_state_)
408 return;
409
410 this->resend_state_ = false;
411 if (this->is_discovery_enabled()) {
412 if (!this->send_discovery_()) {
413 this->schedule_resend_state();
414 }
415 }
416 if (!this->send_initial_state()) {
417 this->schedule_resend_state();
418 }
419}
420void MQTTComponent::schedule_resend_state() { this->resend_state_ = true; }
421bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); }
422
423// Pull these properties from EntityBase if not overridden
424#pragma GCC diagnostic push
425#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
426const StringRef &MQTTComponent::friendly_name_() const { return this->get_entity()->get_name(); }
427#pragma GCC diagnostic pop
428const LogString *MQTTComponent::log_name_() const { return this->get_entity()->get_log_name(); }
429StringRef MQTTComponent::get_default_object_id_to_(std::span<char, OBJECT_ID_MAX_LEN> buf) const {
430 return this->get_entity()->get_object_id_to(buf);
431}
432bool MQTTComponent::is_disabled_by_default_() const { return this->get_entity()->is_disabled_by_default(); }
433bool MQTTComponent::compute_is_internal_() {
434 if (this->custom_state_topic_.has_value()) {
435 // If the custom state_topic is empty, return true as it is internal and should not publish
436 // else, return false, as it is explicitly set to a topic, so it is not internal and should publish
437 // Using is_empty() avoids heap allocation for non-lambda cases
438 return this->custom_state_topic_.is_empty();
439 }
440
441 if (this->custom_command_topic_.has_value()) {
442 // If the custom command_topic is empty, return true as it is internal and should not publish
443 // else, return false, as it is explicitly set to a topic, so it is not internal and should publish
444 // Using is_empty() avoids heap allocation for non-lambda cases
445 return this->custom_command_topic_.is_empty();
446 }
447
448 // No custom topics have been set - check topic_prefix directly to avoid allocation
449 if (global_mqtt_client->get_topic_prefix().empty()) {
450 // If the default topic prefix is empty, then the component, by default, is internal and should not publish
451 return true;
452 }
453
454 // Use ESPHome's component internal state if topic_prefix is not empty with no custom state_topic or command_topic
455 return this->get_entity()->is_internal();
456}
457
458} // namespace esphome::mqtt
459
460#endif // USE_MQTT
const StringRef & get_name() const
Get the name of this Application set by pre_setup().
uint32_t get_config_hash()
Get the config hash as a 32-bit integer.
const StringRef & get_friendly_name() const
Get the friendly name of this Application set by pre_setup().
const char * get_area() const
Get the area of this Application set by pre_setup().
ProgmemStringRef get_device_class_progmem() const
The device class as stored (in flash on ESP8266), for consumers that read flash themselves.
ProgmemStringRef get_icon_progmem() const
The icon as stored (in flash on ESP8266), for consumers that read flash themselves.
const LogString * get_log_name() const
Get the name for a "%s" log argument (LOG_STR_ARG).
EntityCategory get_entity_category() const
A string that may live in flash (on ESP8266): pointer and length, with no byte-reading operations.
Definition string_ref.h:230
constexpr bool empty() const
Definition string_ref.h:240
StringRef is a reference to a string owned by something else.
Definition string_ref.h:31
constexpr const char * c_str() const
Definition string_ref.h:78
constexpr bool empty() const
Definition string_ref.h:81
constexpr size_type size() const
Definition string_ref.h:79
const std::string & get_topic_prefix() const
Get the topic prefix of this device, using default if necessary.
void register_mqtt_component(MQTTComponent *component)
bool publish(const MQTTMessage &message)
Publish a MQTTMessage.
const MQTTDiscoveryInfo & get_discovery_info() const
Get Home Assistant discovery info.
static MQTTTopicSource copy_topic(StringRef topic)
A heap copy of topic, owned by the one subscription it is passed to and freed when that is erased.
const Availability & get_availability()
bool publish_json(const std::string &topic, const json::json_build_t &f, uint8_t qos=0, bool retain=false)
Construct and send a JSON MQTT message.
MQTTComponent is the base class for all components that interact with MQTT to expose certain function...
StringRef get_command_topic_to_(std::span< char, MQTT_DEFAULT_TOPIC_MAX_LEN > buf) const
Get the MQTT command topic into a buffer (no heap allocation for non-lambda custom topics).
TemplatableValue< std::string > custom_state_topic_
TemplatableValue< std::string > custom_command_topic_
std::unique_ptr< Availability > availability_
StringRef get_discovery_topic_to_(std::span< char, MQTT_DISCOVERY_TOPIC_MAX_LEN > buf, const MQTTDiscoveryInfo &discovery_info) const
Helper method to get the discovery topic for this component into a buffer.
bool is_disabled_by_default_() const
Get whether the underlying Entity is disabled by default.
const LogString * log_name_() const
Entity name for a "%s" log argument.
MQTTTopicSource command_topic_source_() const
The command topic as a subscription source. A lambda topic is read once and copied,...
void set_qos(uint8_t qos)
Set QOS for state messages.
StringRef get_default_topic_for_to_(std::span< char, MQTT_DEFAULT_TOPIC_MAX_LEN > buf, const char *suffix, size_t suffix_len) const
Get this components state/command/... topic into a buffer.
bool publish(const std::string &topic, const std::string &payload)
Send a MQTT message.
bool send_discovery_()
Internal method to start sending discovery info, this will call send_discovery().
void set_subscribe_qos(uint8_t qos)
Set the QOS for subscribe messages (used in discovery).
bool publish_float_(StringRef topic, float value, int8_t accuracy)
Publish a float formatted to accuracy, or "None" for NaN when publish_nan_as_none is set.
bool publish_json(const std::string &topic, const json::json_build_t &f)
Construct and send a JSON MQTT message.
std::string get_default_topic_for_(const std::string &suffix) const
Get this components state/command/... topic (allocates std::string).
StringRef get_default_object_id_to_(std::span< char, OBJECT_ID_MAX_LEN > buf) const
Get the object ID for this MQTT component, writing to the provided buffer.
void set_retain(bool retain)
Set whether state message should be retained.
virtual const EntityBase * get_entity() const =0
Gets the Entity served by this MQTT component.
std::string get_state_topic_() const
Get the MQTT topic that new states will be shared to (allocates std::string).
MQTTTopicSource topic_source_() const
A topic built by one of this component's get_*_topic_to getters, rebuilt when needed.
StringRef get_state_topic_to_(std::span< char, MQTT_DEFAULT_TOPIC_MAX_LEN > buf) const
Get the MQTT state topic into a buffer (no heap allocation for non-lambda custom topics).
std::string get_command_topic_() const
Get the MQTT topic for listening to commands (allocates std::string).
virtual const char * component_type() const =0
Override this method to return the component type (e.g. "light", "sensor", ...)
StringRef ref
void setup()
PROGMEM_STRING_TABLE(AlarmControlPanelStateStrings, "DISARMED", "ARMED_HOME", "ARMED_AWAY", "ARMED_NIGHT", "ARMED_VACATION", "ARMED_CUSTOM_BYPASS", "PENDING", "ARMING", "DISARMING", "TRIGGERED", "UNKNOWN")
ESPHOME_LOG_TAG(TAG, "alarm_control_panel")
std::function< void(JsonObject)> json_build_t
Callback function typedef for building JsonObjects.
Definition json_util.h:164
JsonString linked(const char *s)
Definition json_util.h:24
constexpr ColorMode COLOR_MODE_LOOKUP[] PROGMEM
Definition color_mode.h:114
@ MQTT_DEVICE_NAME_OBJECT_ID_GENERATOR
@ MQTT_MAC_ADDRESS_UNIQUE_ID_GENERATOR
char * append_char(char *p, char c)
char * append_str(char *p, const char *s, size_t len)
MQTTClientComponent * global_mqtt_client
void log_mqtt_component(const char *tag, MQTTComponent *obj, bool state_topic, bool command_topic)
constexpr float AFTER_CONNECTION
For components that should be initialized after a data connection (API/MQTT) is connected.
Definition component.h:57
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:625
const void size_t len
Definition hal.h:68
if(written< 0)
Definition helpers.h:1264
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
Definition helpers.cpp:169
@ ENTITY_CATEGORY_NONE
Definition entity_base.h:58
@ ENTITY_CATEGORY_CONFIG
Definition entity_base.h:59
char * str_sanitize_to(char *buffer, size_t buffer_size, const char *str)
Sanitize a string to buffer, keeping only alphanumerics, dashes, and underscores.
Definition helpers.cpp:265
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Definition helpers.cpp:848
Application App
Global storage of Application pointer - only one Application can exist.
const __FlashStringHelper * ProgmemStr
Definition progmem.h:31
Simple data struct for Home Assistant component availability.
std::string topic
Empty means disabled.
Internal struct for MQTT Home Assistant discovery.
MQTTDiscoveryUniqueIdGenerator unique_id_generator
std::string prefix
The Home Assistant discovery prefix. Empty means disabled.
MQTTDiscoveryObjectIdGenerator object_id_generator
Where a subscription's topic comes from. The topic is rebuilt whenever it is needed,...
Definition mqtt_client.h:70