ESPHome  2024.4.1
mqtt_backend_esp32.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP32
2 
3 #include <string>
4 #include "mqtt_backend_esp32.h"
5 #include "esphome/core/log.h"
6 #include "esphome/core/helpers.h"
7 
8 namespace esphome {
9 namespace mqtt {
10 
11 static const char *const TAG = "mqtt.idf";
12 
14 #if ESP_IDF_VERSION_MAJOR < 5
15  mqtt_cfg_.user_context = (void *) this;
16  mqtt_cfg_.buffer_size = MQTT_BUFFER_SIZE;
17 
18  mqtt_cfg_.host = this->host_.c_str();
19  mqtt_cfg_.port = this->port_;
20  mqtt_cfg_.keepalive = this->keep_alive_;
21  mqtt_cfg_.disable_clean_session = !this->clean_session_;
22 
23  if (!this->username_.empty()) {
24  mqtt_cfg_.username = this->username_.c_str();
25  if (!this->password_.empty()) {
26  mqtt_cfg_.password = this->password_.c_str();
27  }
28  }
29 
30  if (!this->lwt_topic_.empty()) {
31  mqtt_cfg_.lwt_topic = this->lwt_topic_.c_str();
32  this->mqtt_cfg_.lwt_qos = this->lwt_qos_;
33  this->mqtt_cfg_.lwt_retain = this->lwt_retain_;
34 
35  if (!this->lwt_message_.empty()) {
36  mqtt_cfg_.lwt_msg = this->lwt_message_.c_str();
37  mqtt_cfg_.lwt_msg_len = this->lwt_message_.size();
38  }
39  }
40 
41  if (!this->client_id_.empty()) {
42  mqtt_cfg_.client_id = this->client_id_.c_str();
43  }
44  if (ca_certificate_.has_value()) {
45  mqtt_cfg_.cert_pem = ca_certificate_.value().c_str();
46  mqtt_cfg_.skip_cert_common_name_check = skip_cert_cn_check_;
47  mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_SSL;
48 
49  if (this->cl_certificate_.has_value() && this->cl_key_.has_value()) {
50  mqtt_cfg_.client_cert_pem = this->cl_certificate_.value().c_str();
51  mqtt_cfg_.client_key_pem = this->cl_key_.value().c_str();
52  }
53  } else {
54  mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_TCP;
55  }
56 #else
57  mqtt_cfg_.broker.address.hostname = this->host_.c_str();
58  mqtt_cfg_.broker.address.port = this->port_;
59  mqtt_cfg_.session.keepalive = this->keep_alive_;
60  mqtt_cfg_.session.disable_clean_session = !this->clean_session_;
61 
62  if (!this->username_.empty()) {
63  mqtt_cfg_.credentials.username = this->username_.c_str();
64  if (!this->password_.empty()) {
65  mqtt_cfg_.credentials.authentication.password = this->password_.c_str();
66  }
67  }
68 
69  if (!this->lwt_topic_.empty()) {
70  mqtt_cfg_.session.last_will.topic = this->lwt_topic_.c_str();
71  this->mqtt_cfg_.session.last_will.qos = this->lwt_qos_;
72  this->mqtt_cfg_.session.last_will.retain = this->lwt_retain_;
73 
74  if (!this->lwt_message_.empty()) {
75  mqtt_cfg_.session.last_will.msg = this->lwt_message_.c_str();
76  mqtt_cfg_.session.last_will.msg_len = this->lwt_message_.size();
77  }
78  }
79 
80  if (!this->client_id_.empty()) {
81  mqtt_cfg_.credentials.client_id = this->client_id_.c_str();
82  }
83  if (ca_certificate_.has_value()) {
84  mqtt_cfg_.broker.verification.certificate = ca_certificate_.value().c_str();
85  mqtt_cfg_.broker.verification.skip_cert_common_name_check = skip_cert_cn_check_;
86  mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_SSL;
87 
88  if (this->cl_certificate_.has_value() && this->cl_key_.has_value()) {
89  mqtt_cfg_.credentials.authentication.certificate = this->cl_certificate_.value().c_str();
90  mqtt_cfg_.credentials.authentication.key = this->cl_key_.value().c_str();
91  }
92  } else {
93  mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_TCP;
94  }
95 #endif
96  auto *mqtt_client = esp_mqtt_client_init(&mqtt_cfg_);
97  if (mqtt_client) {
98  handler_.reset(mqtt_client);
99  is_initalized_ = true;
100  esp_mqtt_client_register_event(mqtt_client, MQTT_EVENT_ANY, mqtt_event_handler, this);
101  return true;
102  } else {
103  ESP_LOGE(TAG, "Failed to initialize IDF-MQTT");
104  return false;
105  }
106 }
107 
109  // process new events
110  // handle only 1 message per loop iteration
111  if (!mqtt_events_.empty()) {
112  auto &event = mqtt_events_.front();
113  mqtt_event_handler_(event);
114  mqtt_events_.pop();
115  }
116 }
117 
119  ESP_LOGV(TAG, "Event dispatched from event loop event_id=%d", event.event_id);
120  switch (event.event_id) {
121  case MQTT_EVENT_BEFORE_CONNECT:
122  ESP_LOGV(TAG, "MQTT_EVENT_BEFORE_CONNECT");
123  break;
124 
125  case MQTT_EVENT_CONNECTED:
126  ESP_LOGV(TAG, "MQTT_EVENT_CONNECTED");
127  this->is_connected_ = true;
128  this->on_connect_.call(event.session_present);
129  break;
130  case MQTT_EVENT_DISCONNECTED:
131  ESP_LOGV(TAG, "MQTT_EVENT_DISCONNECTED");
132  // TODO is there a way to get the disconnect reason?
133  this->is_connected_ = false;
135  break;
136 
137  case MQTT_EVENT_SUBSCRIBED:
138  ESP_LOGV(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event.msg_id);
139  // hardcode QoS to 0. QoS is not used in this context but required to mirror the AsyncMqtt interface
140  this->on_subscribe_.call((int) event.msg_id, 0);
141  break;
142  case MQTT_EVENT_UNSUBSCRIBED:
143  ESP_LOGV(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event.msg_id);
144  this->on_unsubscribe_.call((int) event.msg_id);
145  break;
146  case MQTT_EVENT_PUBLISHED:
147  ESP_LOGV(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event.msg_id);
148  this->on_publish_.call((int) event.msg_id);
149  break;
150  case MQTT_EVENT_DATA: {
151  static std::string topic;
152  if (event.topic.length() > 0) {
153  topic = event.topic;
154  }
155  ESP_LOGV(TAG, "MQTT_EVENT_DATA %s", topic.c_str());
156  this->on_message_.call(event.topic.length() > 0 ? topic.c_str() : nullptr, event.data.data(), event.data.size(),
157  event.current_data_offset, event.total_data_len);
158  } break;
159  case MQTT_EVENT_ERROR:
160  ESP_LOGE(TAG, "MQTT_EVENT_ERROR");
161  if (event.error_handle.error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
162  ESP_LOGE(TAG, "Last error code reported from esp-tls: 0x%x", event.error_handle.esp_tls_last_esp_err);
163  ESP_LOGE(TAG, "Last tls stack error number: 0x%x", event.error_handle.esp_tls_stack_err);
164  ESP_LOGE(TAG, "Last captured errno : %d (%s)", event.error_handle.esp_transport_sock_errno,
165  strerror(event.error_handle.esp_transport_sock_errno));
166  } else if (event.error_handle.error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {
167  ESP_LOGE(TAG, "Connection refused error: 0x%x", event.error_handle.connect_return_code);
168  } else {
169  ESP_LOGE(TAG, "Unknown error type: 0x%x", event.error_handle.error_type);
170  }
171  break;
172  default:
173  ESP_LOGV(TAG, "Other event id:%d", event.event_id);
174  break;
175  }
176 }
177 
179 void MQTTBackendESP32::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id,
180  void *event_data) {
181  MQTTBackendESP32 *instance = static_cast<MQTTBackendESP32 *>(handler_args);
182  // queue event to decouple processing
183  if (instance) {
184  auto event = *static_cast<esp_mqtt_event_t *>(event_data);
185  instance->mqtt_events_.push(Event(event));
186  }
187 }
188 
189 } // namespace mqtt
190 } // namespace esphome
191 #endif // USE_ESP32
value_type const & value() const
Definition: optional.h:89
CallbackManager< on_subscribe_callback_t > on_subscribe_
void mqtt_event_handler_(const Event &event)
optional< std::string > ca_certificate_
CallbackManager< on_unsubscribe_callback_t > on_unsubscribe_
bool has_value() const
Definition: optional.h:87
esp_mqtt_error_codes_t error_handle
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
static - Dispatch event to instance method
static const size_t MQTT_BUFFER_SIZE
CallbackManager< on_connect_callback_t > on_connect_
esp_mqtt_event_id_t event_id
CallbackManager< on_message_callback_t > on_message_
CallbackManager< on_publish_user_callback_t > on_publish_
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
uint8_t event_id
Definition: tt21100.cpp:15
CallbackManager< on_disconnect_callback_t > on_disconnect_
esp_mqtt_client_config_t mqtt_cfg_
optional< std::string > cl_certificate_
optional< std::string > cl_key_