diff --git a/docs/en/index.rst b/docs/en/index.rst index 5d22e4e..72cba9a 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -334,6 +334,7 @@ The following events may be posted by the MQTT client: * ``MQTT_EVENT_PUBLISHED``: The broker has acknowledged the client's publish message. This is only posted for QoS level 1 and 2, as level 0 does not use acknowledgements. The event data contains the message ID of the publish message. * ``MQTT_EVENT_DATA``: The client has received a publish message. The event data contains: message ID, name of the topic it was published to, received data and its length. For data that exceeds the internal buffer, multiple ``MQTT_EVENT_DATA`` events are posted and :cpp:member:`current_data_offset ` and :cpp:member:`total_data_len ` from event data updated to keep track of the fragmented message. * ``MQTT_EVENT_ERROR``: The client has encountered an error. The field :cpp:type:`error_handle ` in the event data contains :cpp:type:`error_type ` that can be used to identify the error. The type of error determines which parts of the :cpp:type:`error_handle ` struct is filled. +* ``MQTT_EVENT_KEEPALIVE``: The client sent a keepalive ``PINGREQ`` or received a ``PINGRESP``. :cpp:member:`data ` points to one byte of type :cpp:type:`esp_mqtt_keepalive_kind_t` (``MQTT_KEEPALIVE_PINGREQ`` or ``MQTT_KEEPALIVE_PINGRESP``) and :cpp:member:`data_len ` is 1. Keepalive timeout and failure to send ``PINGREQ`` still produce ``MQTT_EVENT_DISCONNECTED`` (and ``MQTT_EVENT_ERROR`` when a transport write fails); they do not post this event. Relation between errors and disconnections in MQTT client ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/index.rst b/docs/zh_CN/index.rst index 279eb58..b4b5ce0 100644 --- a/docs/zh_CN/index.rst +++ b/docs/zh_CN/index.rst @@ -232,6 +232,7 @@ MQTT 客户端可能会发布以下事件: * ``MQTT_EVENT_PUBLISHED``:服务器已确认客户端的发布消息。消息将仅针对 QoS 级别 1 和 2 发布,因为级别 0 不会进行确认。事件数据将包含发布消息的消息 ID。 * ``MQTT_EVENT_DATA``:客户端已收到发布消息。事件数据包含:消息 ID、发布消息所属主题名称、收到的数据及其长度。对于超出内部缓冲区的数据,将发布多个 ``MQTT_EVENT_DATA``,并更新事件数据的 :cpp:member:`current_data_offset ` 和 :cpp:member:`total_data_len` 以跟踪碎片化消息。 * ``MQTT_EVENT_ERROR``:客户端遇到错误。使用事件数据 :cpp:type:`error_handle ` 字段中的 :cpp:type:`error_type `,可以发现错误。错误类型决定 :cpp:type:`error_handle ` 结构体的哪些部分会被填充。 +* ``MQTT_EVENT_KEEPALIVE``:客户端已发送 keepalive ``PINGREQ`` 或已收到 ``PINGRESP``。:cpp:member:`data ` 指向一个 :cpp:type:`esp_mqtt_keepalive_kind_t` 字节(``MQTT_KEEPALIVE_PINGREQ`` 或 ``MQTT_KEEPALIVE_PINGRESP``),:cpp:member:`data_len ` 为 1。Keepalive 超时以及发送 ``PINGREQ`` 失败仍会发布 ``MQTT_EVENT_DISCONNECTED``(传输写入失败时还会发布 ``MQTT_EVENT_ERROR``),不会发布本事件。 API 参考 ------------- diff --git a/include/mqtt_client.h b/include/mqtt_client.h index a1e2d1f..4ab12e3 100644 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -97,8 +97,23 @@ typedef enum esp_mqtt_event_id_t { All fields from the esp_mqtt_event_t type could be used to pass an additional context data to the handler. */ + MQTT_EVENT_KEEPALIVE, /*!< Keepalive PINGREQ sent or PINGRESP received. + Additional context: + - data pointer to one byte, an :cpp:type:`esp_mqtt_keepalive_kind_t` + - data_len always 1 + The pointer remains valid for the duration of the event handler. + */ } esp_mqtt_event_id_t; +/** + * Kind of keepalive traffic reported in :cpp:enumerator:`MQTT_EVENT_KEEPALIVE`. + * Encoded as a single byte in :cpp:member:`esp_mqtt_event_t::data`. + */ +typedef enum { + MQTT_KEEPALIVE_PINGREQ = 0, /*!< Client sent a PINGREQ */ + MQTT_KEEPALIVE_PINGRESP = 1, /*!< Client received a PINGRESP */ +} esp_mqtt_keepalive_kind_t; + /** * *MQTT* connection error codes propagated via ERROR event */ diff --git a/mqtt_client.c b/mqtt_client.c index 3289e22..b9a4496 100644 --- a/mqtt_client.c +++ b/mqtt_client.c @@ -37,6 +37,7 @@ static const int DISCONNECT_BIT = (1 << 2); static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client); +static void esp_mqtt_dispatch_keepalive_event(esp_mqtt_client_handle_t client, esp_mqtt_keepalive_kind_t kind); static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms); static void esp_mqtt_abort_connection(esp_mqtt_client_handle_t client); static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client); @@ -818,6 +819,7 @@ static esp_err_t process_keepalive(esp_mqtt_client_handle_t client) } client->wait_for_ping_resp = true; + esp_mqtt_dispatch_keepalive_event(client, MQTT_KEEPALIVE_PINGREQ); return ESP_OK; } } @@ -1275,6 +1277,15 @@ esp_err_t esp_mqtt_dispatch_custom_event(esp_mqtt_client_handle_t client, esp_mq return ret; } +static void esp_mqtt_dispatch_keepalive_event(esp_mqtt_client_handle_t client, esp_mqtt_keepalive_kind_t kind) +{ + char data = (char)kind; + client->event.event_id = MQTT_EVENT_KEEPALIVE; + client->event.data_len = 1; + client->event.data = &data; + esp_mqtt_dispatch_event(client); +} + static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) { client->event.client = client; @@ -1830,6 +1841,7 @@ static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) * [MQTT-3.1.2-23] */ client->keepalive_tick = platform_tick_get_ms(); + esp_mqtt_dispatch_keepalive_event(client, MQTT_KEEPALIVE_PINGRESP); break; case MQTT_MSG_TYPE_DISCONNECT: diff --git a/test/apps/mqtt_conformance/main/mqtt_conformance.cpp b/test/apps/mqtt_conformance/main/mqtt_conformance.cpp index 5e98b47..d8778a1 100644 --- a/test/apps/mqtt_conformance/main/mqtt_conformance.cpp +++ b/test/apps/mqtt_conformance/main/mqtt_conformance.cpp @@ -193,6 +193,17 @@ void conformance_mqtt_event_handler(void *, esp_event_base_t, int32_t event_id, break; + case MQTT_EVENT_KEEPALIVE: + if (event->data && event->data_len == 1) { + const auto kind = static_cast( + static_cast(event->data[0])); + ESP_LOGI(TAG, "MQTT_EVENT_KEEPALIVE kind=%d", static_cast(kind)); + } else { + ESP_LOGI(TAG, "MQTT_EVENT_KEEPALIVE"); + } + + break; + default: ESP_LOGI(TAG, "Other event id:%d", event->event_id); break;