ESPHome  2023.3.1
mqtt_backend_idf.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP_IDF
2 
3 #include <string>
4 #include "mqtt_backend_idf.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  mqtt_cfg_.user_context = (void *) this;
15  mqtt_cfg_.buffer_size = MQTT_BUFFER_SIZE;
16 
17  mqtt_cfg_.host = this->host_.c_str();
18  mqtt_cfg_.port = this->port_;
19  mqtt_cfg_.keepalive = this->keep_alive_;
20  mqtt_cfg_.disable_clean_session = !this->clean_session_;
21 
22  if (!this->username_.empty()) {
23  mqtt_cfg_.username = this->username_.c_str();
24  if (!this->password_.empty()) {
25  mqtt_cfg_.password = this->password_.c_str();
26  }
27  }
28 
29  if (!this->lwt_topic_.empty()) {
30  mqtt_cfg_.lwt_topic = this->lwt_topic_.c_str();
31  this->mqtt_cfg_.lwt_qos = this->lwt_qos_;
32  this->mqtt_cfg_.lwt_retain = this->lwt_retain_;
33 
34  if (!this->lwt_message_.empty()) {
35  mqtt_cfg_.lwt_msg = this->lwt_message_.c_str();
36  mqtt_cfg_.lwt_msg_len = this->lwt_message_.size();
37  }
38  }
39 
40  if (!this->client_id_.empty()) {
41  mqtt_cfg_.client_id = this->client_id_.c_str();
42  }
43  if (ca_certificate_.has_value()) {
44  mqtt_cfg_.cert_pem = ca_certificate_.value().c_str();
45  mqtt_cfg_.skip_cert_common_name_check = skip_cert_cn_check_;
46  mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_SSL;
47  } else {
48  mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_TCP;
49  }
50  auto *mqtt_client = esp_mqtt_client_init(&mqtt_cfg_);
51  if (mqtt_client) {
52  handler_.reset(mqtt_client);
53  is_initalized_ = true;
54  esp_mqtt_client_register_event(mqtt_client, MQTT_EVENT_ANY, mqtt_event_handler, this);
55  return true;
56  } else {
57  ESP_LOGE(TAG, "Failed to initialize IDF-MQTT");
58  return false;
59  }
60 }
61 
63  // process new events
64  // handle only 1 message per loop iteration
65  if (!mqtt_events_.empty()) {
66  auto &event = mqtt_events_.front();
67  mqtt_event_handler_(event);
68  mqtt_events_.pop();
69  }
70 }
71 
73  ESP_LOGV(TAG, "Event dispatched from event loop event_id=%d", event.event_id);
74  switch (event.event_id) {
75  case MQTT_EVENT_BEFORE_CONNECT:
76  ESP_LOGV(TAG, "MQTT_EVENT_BEFORE_CONNECT");
77  break;
78 
79  case MQTT_EVENT_CONNECTED:
80  ESP_LOGV(TAG, "MQTT_EVENT_CONNECTED");
81  // TODO session present check
82  this->is_connected_ = true;
83  this->on_connect_.call(!mqtt_cfg_.disable_clean_session);
84  break;
85  case MQTT_EVENT_DISCONNECTED:
86  ESP_LOGV(TAG, "MQTT_EVENT_DISCONNECTED");
87  // TODO is there a way to get the disconnect reason?
88  this->is_connected_ = false;
90  break;
91 
92  case MQTT_EVENT_SUBSCRIBED:
93  ESP_LOGV(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event.msg_id);
94  // hardcode QoS to 0. QoS is not used in this context but required to mirror the AsyncMqtt interface
95  this->on_subscribe_.call((int) event.msg_id, 0);
96  break;
97  case MQTT_EVENT_UNSUBSCRIBED:
98  ESP_LOGV(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event.msg_id);
99  this->on_unsubscribe_.call((int) event.msg_id);
100  break;
101  case MQTT_EVENT_PUBLISHED:
102  ESP_LOGV(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event.msg_id);
103  this->on_publish_.call((int) event.msg_id);
104  break;
105  case MQTT_EVENT_DATA: {
106  static std::string topic;
107  if (event.topic.length() > 0) {
108  topic = event.topic;
109  }
110  ESP_LOGV(TAG, "MQTT_EVENT_DATA %s", topic.c_str());
111  this->on_message_.call(event.topic.length() > 0 ? topic.c_str() : nullptr, event.data.data(), event.data.size(),
112  event.current_data_offset, event.total_data_len);
113  } break;
114  case MQTT_EVENT_ERROR:
115  ESP_LOGE(TAG, "MQTT_EVENT_ERROR");
116  if (event.error_handle.error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
117  ESP_LOGE(TAG, "Last error code reported from esp-tls: 0x%x", event.error_handle.esp_tls_last_esp_err);
118  ESP_LOGE(TAG, "Last tls stack error number: 0x%x", event.error_handle.esp_tls_stack_err);
119  ESP_LOGE(TAG, "Last captured errno : %d (%s)", event.error_handle.esp_transport_sock_errno,
120  strerror(event.error_handle.esp_transport_sock_errno));
121  } else if (event.error_handle.error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {
122  ESP_LOGE(TAG, "Connection refused error: 0x%x", event.error_handle.connect_return_code);
123  } else {
124  ESP_LOGE(TAG, "Unknown error type: 0x%x", event.error_handle.error_type);
125  }
126  break;
127  default:
128  ESP_LOGV(TAG, "Other event id:%d", event.event_id);
129  break;
130  }
131 }
132 
134 void MQTTBackendIDF::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
135  MQTTBackendIDF *instance = static_cast<MQTTBackendIDF *>(handler_args);
136  // queue event to decouple processing
137  if (instance) {
138  auto event = *static_cast<esp_mqtt_event_t *>(event_data);
139  instance->mqtt_events_.push(Event(event));
140  }
141 }
142 
143 } // namespace mqtt
144 } // namespace esphome
145 #endif // USE_ESP_IDF
value_type const & value() const
Definition: optional.h:89
CallbackManager< on_subscribe_callback_t > on_subscribe_
std::queue< Event > mqtt_events_
bool has_value() const
Definition: optional.h:87
CallbackManager< on_unsubscribe_callback_t > on_unsubscribe_
optional< std::string > ca_certificate_
esp_mqtt_error_codes_t error_handle
CallbackManager< on_publish_user_callback_t > on_publish_
CallbackManager< on_message_callback_t > on_message_
CallbackManager< on_connect_callback_t > on_connect_
void mqtt_event_handler_(const Event &event)
esp_mqtt_event_id_t event_id
esp_mqtt_client_config_t mqtt_cfg_
Definition: a4988.cpp:4
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
CallbackManager< on_disconnect_callback_t > on_disconnect_
static const size_t MQTT_BUFFER_SIZE