mirror of
https://github.com/espressif/esp-mqtt.git
synced 2025-09-25 06:31:34 +02:00
Merge branch 'move_idf_history' into 'master'
Moves idf history to esp-mqtt Closes DOC-2797, IDF-3859, IDFGH-4986, and IDF-1027 See merge request espressif/esp-mqtt!247
This commit is contained in:
@@ -69,7 +69,7 @@ build_and_host_test:
|
||||
script:
|
||||
# Replace the IDF's default esp-mqtt with this version
|
||||
- rm -rf $IDF_PATH/components/mqtt/esp-mqtt && cp -r $MQTT_PATH $IDF_PATH/components/mqtt/
|
||||
- cd $IDF_PATH/components/mqtt/esp-mqtt/host_test
|
||||
- cd $IDF_PATH/components/mqtt/esp-mqtt/test/host
|
||||
- idf.py build
|
||||
- build/host_mqtt_client_test.elf
|
||||
|
||||
|
208
docs/en/index.rst
Normal file
208
docs/en/index.rst
Normal file
@@ -0,0 +1,208 @@
|
||||
ESP-MQTT
|
||||
========
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP-MQTT is an implementation of `MQTT <https://mqtt.org/>`__ protocol client, which is a lightweight publish/subscribe messaging protocol. Now ESP-MQTT supports `MQTT v5.0 <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html>`__.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Support MQTT over TCP, SSL with Mbed TLS, MQTT over WebSocket, and MQTT over WebSocket Secure
|
||||
* Easy to setup with URI
|
||||
* Multiple instances (multiple clients in one application)
|
||||
* Support subscribing, publishing, authentication, last will messages, keep alive pings, and all 3 Quality of Service (QoS) levels (it should be a fully functional client)
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- :example:`protocols/mqtt/tcp` demonstrates how to implement MQTT communication over TCP (default port 1883).
|
||||
|
||||
- :example:`protocols/mqtt/ssl` demonstrates how to use SSL transport to implement MQTT communication over TLS (default port 8883).
|
||||
|
||||
- :example:`protocols/mqtt/ssl_ds` demonstrates how to use digital signature peripheral for authentication to implement MQTT communication over TLS (default port 8883).
|
||||
|
||||
- :example:`protocols/mqtt/ssl_mutual_auth` demonstrates how to use certificates for authentication to implement MQTT communication (default port 8883).
|
||||
|
||||
- :example:`protocols/mqtt/ssl_psk` demonstrates how to use pre-shared keys for authentication to implement MQTT communication over TLS (default port 8883).
|
||||
|
||||
- :example:`protocols/mqtt/ws` demonstrates how to implement MQTT communication over WebSocket (default port 80).
|
||||
|
||||
- :example:`protocols/mqtt/wss` demonstrates how to implement MQTT communication over WebSocket Secure (default port 443).
|
||||
|
||||
- :example:`protocols/mqtt5` demonstrates how to use ESP-MQTT library to connect to broker with MQTT v5.0.
|
||||
|
||||
- :example:`protocols/mqtt/custom_outbox` demonstrates how to customize the outbox in the ESP-MQTT library.
|
||||
|
||||
MQTT Message Retransmission
|
||||
---------------------------
|
||||
|
||||
A new MQTT message can be created by calling :cpp:func:`esp_mqtt_client_publish <esp_mqtt_client_publish()>` or its non-blocking counterpart :cpp:func:`esp_mqtt_client_enqueue <esp_mqtt_client_enqueue()>`.
|
||||
|
||||
Messages with QoS 0 are sent only once. QoS 1 and 2 behave differently since the protocol requires additional steps to complete the process.
|
||||
|
||||
The ESP-MQTT library opts to always retransmit unacknowledged QoS 1 and 2 publish messages to prevent data loss in faulty connections, even though the MQTT specification requires the re-transmission only on reconnect with Clean Session flag been set to 0 (set :cpp:member:`disable_clean_session <esp_mqtt_client_config_t::session_t::disable_clean_session>` to true for this behavior).
|
||||
|
||||
QoS 1 and 2 messages that may need retransmission are always enqueued, but first transmission try occurs immediately if :cpp:func:`esp_mqtt_client_publish <esp_mqtt_client_publish>` is used. A transmission retry for unacknowledged messages will occur after :cpp:member:`message_retransmit_timeout <esp_mqtt_client_config_t::session_t::message_retransmit_timeout>`. After :ref:`CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS` messages will expire and be deleted. If :ref:`CONFIG_MQTT_REPORT_DELETED_MESSAGES` is set, an event will be sent to notify the user.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The configuration is made by setting fields in :cpp:class:`esp_mqtt_client_config_t` struct. The configuration struct has the following sub structs to configure different aspects of the client operation.
|
||||
|
||||
* :cpp:class:`esp_mqtt_client_config_t::broker_t` - Allow to set address and security verification.
|
||||
* :cpp:class:`esp_mqtt_client_config_t::credentials_t` - Client credentials for authentication.
|
||||
* :cpp:class:`esp_mqtt_client_config_t::session_t` - Configuration for MQTT session aspects.
|
||||
* :cpp:class:`esp_mqtt_client_config_t::network_t` - Networking related configuration.
|
||||
* :cpp:class:`esp_mqtt_client_config_t::task_t` - Allow to configure FreeRTOS task.
|
||||
* :cpp:class:`esp_mqtt_client_config_t::buffer_t` - Buffer size for input and output.
|
||||
|
||||
In the following sections, the most common aspects are detailed.
|
||||
|
||||
Broker
|
||||
^^^^^^^^^^^
|
||||
|
||||
===========
|
||||
Address
|
||||
===========
|
||||
|
||||
Broker address can be set by usage of :cpp:class:`address <esp_mqtt_client_config_t::broker_t::address_t>` struct. The configuration can be made by usage of :cpp:member:`uri <esp_mqtt_client_config_t::broker_t::address_t::uri>` field or the combination of :cpp:member:`hostname <esp_mqtt_client_config_t::broker_t::address_t::hostname>`, :cpp:member:`transport <esp_mqtt_client_config_t::broker_t::address_t::transport>` and :cpp:member:`port <esp_mqtt_client_config_t::broker_t::address_t::port>`. Optionally, :cpp:member:`path <esp_mqtt_client_config_t::broker_t::address_t::path>` could be set, this field is useful in WebSocket connections.
|
||||
|
||||
The :cpp:member:`uri <esp_mqtt_client_config_t::broker_t::address_t::uri>` field is used in the format ``scheme://hostname:port/path``.
|
||||
|
||||
- Currently support ``mqtt``, ``mqtts``, ``ws``, ``wss`` schemes
|
||||
- MQTT over TCP samples:
|
||||
|
||||
- ``mqtt://mqtt.eclipseprojects.io``: MQTT over TCP, default port 1883
|
||||
- ``mqtt://mqtt.eclipseprojects.io:1884``: MQTT over TCP, port 1884
|
||||
- ``mqtt://username:password@mqtt.eclipseprojects.io:1884``: MQTT over TCP,
|
||||
port 1884, with username and password
|
||||
|
||||
- MQTT over SSL samples:
|
||||
|
||||
- ``mqtts://mqtt.eclipseprojects.io``: MQTT over SSL, port 8883
|
||||
- ``mqtts://mqtt.eclipseprojects.io:8884``: MQTT over SSL, port 8884
|
||||
|
||||
- MQTT over WebSocket samples:
|
||||
|
||||
- ``ws://mqtt.eclipseprojects.io:80/mqtt``
|
||||
|
||||
- MQTT over WebSocket Secure samples:
|
||||
|
||||
- ``wss://mqtt.eclipseprojects.io:443/mqtt``
|
||||
|
||||
- Minimal configurations:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = "mqtt://mqtt.eclipseprojects.io",
|
||||
};
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
|
||||
esp_mqtt_client_start(client);
|
||||
|
||||
.. note::
|
||||
|
||||
By default MQTT client uses event loop library to post related MQTT events (connected, subscribed, published, etc.).
|
||||
|
||||
============
|
||||
Verification
|
||||
============
|
||||
|
||||
For secure connections with TLS used, and to guarantee Broker's identity, the :cpp:class:`verification <esp_mqtt_client_config_t::broker_t::verification_t>` struct must be set.
|
||||
The broker certificate may be set in PEM or DER format. To select DER, the equivalent :cpp:member:`certificate_len <esp_mqtt_client_config_t::broker_t::verification_t::certificate_len>` field must be set. Otherwise, a null-terminated string in PEM format should be provided to :cpp:member:`certificate <esp_mqtt_client_config_t::broker_t::verification_t::certificate>` field.
|
||||
|
||||
- Get certificate from server, example: ``mqtt.eclipseprojects.io``
|
||||
.. code::
|
||||
|
||||
openssl s_client -showcerts -connect mqtt.eclipseprojects.io:8883 < /dev/null \
|
||||
2> /dev/null | openssl x509 -outform PEM > mqtt_eclipse_org.pem
|
||||
|
||||
- Check the sample application: :example:`protocols/mqtt/ssl`
|
||||
- Configuration:
|
||||
|
||||
.. code:: c
|
||||
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker = {
|
||||
.address.uri = "mqtts://mqtt.eclipseprojects.io:8883",
|
||||
.verification.certificate = (const char *)mqtt_eclipse_org_pem_start,
|
||||
},
|
||||
};
|
||||
|
||||
For details about other fields, please check the `API Reference`_ and :ref:`esp_tls_server_verification`.
|
||||
|
||||
Client Credentials
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
All client related credentials are under the :cpp:class:`credentials <esp_mqtt_client_config_t::credentials_t>` field.
|
||||
|
||||
* :cpp:member:`username <esp_mqtt_client_config_t::credentials_t::username>`: pointer to the username used for connecting to the broker, can also be set by URI
|
||||
* :cpp:member:`client_id <esp_mqtt_client_config_t::credentials_t::client_id>`: pointer to the client ID, defaults to ``ESP32_%CHIPID%`` where ``%CHIPID%`` are the last 3 bytes of MAC address in hex format
|
||||
|
||||
==============
|
||||
Authentication
|
||||
==============
|
||||
|
||||
It is possible to set authentication parameters through the :cpp:class:`authentication <esp_mqtt_client_config_t::credentials_t::authentication_t>` field. The client supports the following authentication methods:
|
||||
|
||||
* :cpp:member:`password <esp_mqtt_client_config_t::credentials_t::authentication_t::password>`: use a password by setting
|
||||
* :cpp:member:`certificate <esp_mqtt_client_config_t::credentials_t::authentication_t::certificate>` and :cpp:member:`key <esp_mqtt_client_config_t::credentials_t::authentication_t::key>`: mutual authentication with TLS, and both can be provided in PEM or DER format
|
||||
* :cpp:member:`use_secure_element <esp_mqtt_client_config_t::credentials_t::authentication_t::use_secure_element>`: use secure element (ATECC608A) interfaced to ESP32 series
|
||||
* :cpp:member:`ds_data <esp_mqtt_client_config_t::credentials_t::authentication_t::ds_data>`: use Digital Signature Peripheral available in some Espressif devices
|
||||
|
||||
Session
|
||||
^^^^^^^^^^^
|
||||
|
||||
For MQTT session-related configurations, :cpp:class:`session <esp_mqtt_client_config_t::session_t>` fields should be used.
|
||||
|
||||
=======================
|
||||
Last Will and Testament
|
||||
=======================
|
||||
|
||||
MQTT allows for a last will and testament (LWT) message to notify other clients when a client ungracefully disconnects. This is configured by the following fields in the :cpp:class:`last_will <esp_mqtt_client_config_t::session_t::last_will_t>` struct.
|
||||
|
||||
* :cpp:member:`topic <esp_mqtt_client_config_t::session_t::last_will_t::topic>`: pointer to the LWT message topic
|
||||
* :cpp:member:`msg <esp_mqtt_client_config_t::session_t::last_will_t::msg>`: pointer to the LWT message
|
||||
* :cpp:member:`msg_len <esp_mqtt_client_config_t::session_t::last_will_t::msg_len>`: length of the LWT message, required if :cpp:member:`msg <esp_mqtt_client_config_t::session_t::last_will_t::msg>` is not null-terminated
|
||||
* :cpp:member:`qos <esp_mqtt_client_config_t::session_t::last_will_t::qos>`: quality of service for the LWT message
|
||||
* :cpp:member:`retain <esp_mqtt_client_config_t::session_t::last_will_t::retain>`: specifies the retain flag of the LWT message
|
||||
|
||||
Change Settings in Project Configuration Menu
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The settings for MQTT can be found using :code:`idf.py menuconfig`, under ``Component config`` > ``ESP-MQTT Configuration``.
|
||||
|
||||
The following settings are available:
|
||||
|
||||
- :ref:`CONFIG_MQTT_PROTOCOL_311`: enable 3.1.1 version of MQTT protocol
|
||||
|
||||
- :ref:`CONFIG_MQTT_TRANSPORT_SSL` and :ref:`CONFIG_MQTT_TRANSPORT_WEBSOCKET`: enable specific MQTT transport layer, such as SSL, WEBSOCKET, and WEBSOCKET_SECURE
|
||||
|
||||
- :ref:`CONFIG_MQTT_CUSTOM_OUTBOX`: disable default implementation of mqtt_outbox, so a specific implementation can be supplied
|
||||
|
||||
|
||||
Events
|
||||
------
|
||||
The following events may be posted by the MQTT client:
|
||||
|
||||
* ``MQTT_EVENT_BEFORE_CONNECT``: The client is initialized and about to start connecting to the broker.
|
||||
* ``MQTT_EVENT_CONNECTED``: The client has successfully established a connection to the broker. The client is now ready to send and receive data.
|
||||
* ``MQTT_EVENT_DISCONNECTED``: The client has aborted the connection due to being unable to read or write data, e.g., because the server is unavailable.
|
||||
* ``MQTT_EVENT_SUBSCRIBED``: The broker has acknowledged the client's subscribe request. The event data contains the message ID of the subscribe message.
|
||||
* ``MQTT_EVENT_UNSUBSCRIBED``: The broker has acknowledged the client's unsubscribe request. The event data contains the message ID of the unsubscribe message.
|
||||
* ``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 <esp_mqtt_event_t::current_data_offset>` and :cpp:member:`total_data_len <esp_mqtt_event_t::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 <esp_mqtt_error_codes_t>` in the event data contains :cpp:type:`error_type <esp_mqtt_error_type_t>` that can be used to identify the error. The type of error determines which parts of the :cpp:type:`error_handle <esp_mqtt_error_codes_t>` struct is filled.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/mqtt_client.inc
|
||||
.. include-build-file:: inc/mqtt5_client.inc
|
208
docs/zh_CN/index.rst
Normal file
208
docs/zh_CN/index.rst
Normal file
@@ -0,0 +1,208 @@
|
||||
ESP-MQTT
|
||||
========
|
||||
|
||||
:link_to_translation:`en:[English]`
|
||||
|
||||
概述
|
||||
--------
|
||||
|
||||
ESP-MQTT 是 `MQTT <https://mqtt.org/>`__ 协议客户端的实现,MQTT 是一种基于发布/订阅模式的轻量级消息传输协议。ESP-MQTT 当前支持 `MQTT v5.0 <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html>`__。
|
||||
|
||||
|
||||
特性
|
||||
--------
|
||||
|
||||
* 支持基于 TCP 的 MQTT、基于 Mbed TLS 的 SSL、基于 WebSocket 的 MQTT 以及基于 WebSocket Secure 的 MQTT
|
||||
* 通过 URI 简化配置流程
|
||||
* 多个实例(一个应用程序中有多个客户端)
|
||||
* 支持订阅、发布、认证、遗嘱消息、保持连接心跳机制以及 3 个服务质量 (QoS) 级别(组成全功能客户端)
|
||||
|
||||
|
||||
应用示例
|
||||
-------------------
|
||||
|
||||
- :example:`protocols/mqtt/tcp` 演示了如何通过 TCP 实现 MQTT 通信(默认端口 1883)。
|
||||
|
||||
- :example:`protocols/mqtt/ssl` 演示了如何使用 SSL 传输来实现基于 TLS 的 MQTT 通信(默认端口 8883)。
|
||||
|
||||
- :example:`protocols/mqtt/ssl_ds` 演示了如何使用数字签名外设进行身份验证,以实现基于 TLS 的 MQTT 通信(默认端口 8883)。
|
||||
|
||||
- :example:`protocols/mqtt/ssl_mutual_auth` 演示了如何使用证书进行身份验证实现 MQTT 通信(默认端口 8883)。
|
||||
|
||||
- :example:`protocols/mqtt/ssl_psk` 演示了如何使用预共享密钥进行身份验证,以实现基于 TLS 的 MQTT 通信(默认端口 8883)。
|
||||
|
||||
- :example:`protocols/mqtt/ws` 演示了如何通过 WebSocket 实现 MQTT 通信(默认端口 80)。
|
||||
|
||||
- :example:`protocols/mqtt/wss` 演示了如何通过 WebSocket Secure 实现 MQTT 通信(默认端口 443)。
|
||||
|
||||
- :example:`protocols/mqtt5` 演示了如何使用 ESP-MQTT 库通过 MQTT v5.0 连接到代理。
|
||||
|
||||
- :example:`protocols/mqtt/custom_outbox` 演示了如何自定义 ESP-MQTT 库中的 outbox。
|
||||
|
||||
MQTT 消息重传
|
||||
--------------------------
|
||||
|
||||
调用 :cpp:func:`esp_mqtt_client_publish <esp_mqtt_client_publish()>` 或其非阻塞形式 :cpp:func:`esp_mqtt_client_enqueue <esp_mqtt_client_enqueue()>`,可以创建新的 MQTT 消息。
|
||||
|
||||
QoS 0 的消息将只发送一次,QoS 1 和 2 具有不同行为,因为协议需要执行额外步骤来完成该过程。
|
||||
|
||||
ESP-MQTT 库将始终重新传输未确认的 QoS 1 和 2 发布消息,以避免连接错误导致信息丢失,虽然 MQTT 规范要求仅在重新连接且 Clean Session 标志设置为 0 时重新传输(针对此行为,将 :cpp:member:`disable_clean_session <esp_mqtt_client_config_t::session_t::disable_clean_session>` 设置为 true)。
|
||||
|
||||
可能需要重传的 QoS 1 和 2 消息总是处于排队状态,但若使用 :cpp:func:`esp_mqtt_client_publish <esp_mqtt_client_publish>` 则会立即进行第一次传输尝试。未确认消息的重传将在 :cpp:member:`message_retransmit_timeout <esp_mqtt_client_config_t::session_t::message_retransmit_timeout>` 之后进行。在 :ref:`CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS` 之后,消息会过期并被删除。如已设置 :ref:`CONFIG_MQTT_REPORT_DELETED_MESSAGES`,则会发送事件来通知用户。
|
||||
|
||||
配置
|
||||
-------------
|
||||
|
||||
通过设置 :cpp:class:`esp_mqtt_client_config_t` 结构体中的字段来进行配置。配置结构体包含以下子结构体,用于配置客户端的多种操作。
|
||||
|
||||
* :cpp:class:`esp_mqtt_client_config_t::broker_t` - 允许设置地址和安全验证。
|
||||
* :cpp:class:`esp_mqtt_client_config_t::credentials_t` - 用于身份验证的客户端凭据。
|
||||
* :cpp:class:`esp_mqtt_client_config_t::session_t` - MQTT 会话相关配置。
|
||||
* :cpp:class:`esp_mqtt_client_config_t::network_t` - 网络相关配置。
|
||||
* :cpp:class:`esp_mqtt_client_config_t::task_t` - 允许配置 FreeRTOS 任务。
|
||||
* :cpp:class:`esp_mqtt_client_config_t::buffer_t` - 输入输出的缓冲区大小。
|
||||
|
||||
下文将详细介绍不同配置。
|
||||
|
||||
服务器
|
||||
^^^^^^^^^^^^
|
||||
|
||||
===========
|
||||
地址
|
||||
===========
|
||||
|
||||
通过 :cpp:class:`address <esp_mqtt_client_config_t::broker_t::address_t>` 结构体的 :cpp:member:`uri <esp_mqtt_client_config_t::broker_t::address_t::uri>` 字段或者 :cpp:member:`hostname <esp_mqtt_client_config_t::broker_t::address_t::hostname>`、:cpp:member:`transport <esp_mqtt_client_config_t::broker_t::address_t::transport>` 以及 :cpp:member:`port <esp_mqtt_client_config_t::broker_t::address_t::port>` 的组合,可以设置服务器地址。也可以选择设置 :cpp:member:`path <esp_mqtt_client_config_t::broker_t::address_t::path>`,该字段对 WebSocket 连接而言非常有用。
|
||||
|
||||
使用 :cpp:member:`uri <esp_mqtt_client_config_t::broker_t::address_t::uri>` 字段的格式为 ``scheme://hostname:port/path``。
|
||||
|
||||
- 当前支持 ``mqtt``、``mqtts``、``ws`` 和 ``wss`` 协议
|
||||
- 基于 TCP 的 MQTT 示例:
|
||||
|
||||
- ``mqtt://mqtt.eclipseprojects.io``:基于 TCP 的 MQTT,默认端口 1883
|
||||
- ``mqtt://mqtt.eclipseprojects.io:1884``:基于 TCP 的 MQTT,端口 1884
|
||||
- ``mqtt://username:password@mqtt.eclipseprojects.io:1884``:基于 TCP 的 MQTT,
|
||||
端口 1884,带有用户名和密码
|
||||
|
||||
- 基于 SSL 的 MQTT 示例:
|
||||
|
||||
- ``mqtts://mqtt.eclipseprojects.io``:基于 SSL 的 MQTT,端口 8883
|
||||
- ``mqtts://mqtt.eclipseprojects.io:8884``:基于 SSL 的 MQTT,端口 8884
|
||||
|
||||
- 基于 WebSocket 的 MQTT 示例:
|
||||
|
||||
- ``ws://mqtt.eclipseprojects.io:80/mqtt``
|
||||
|
||||
- 基于 WebSocket Secure 的 MQTT 示例:
|
||||
|
||||
- ``wss://mqtt.eclipseprojects.io:443/mqtt``
|
||||
|
||||
- 最简配置:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = "mqtt://mqtt.eclipseprojects.io",
|
||||
};
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
|
||||
esp_mqtt_client_start(client);
|
||||
|
||||
.. note::
|
||||
|
||||
默认情况下,MQTT 客户端使用事件循环库来发布相关 MQTT 事件(已连接、已订阅、已发布等)。
|
||||
|
||||
=============
|
||||
验证
|
||||
=============
|
||||
|
||||
为验证服务器身份,对于使用 TLS 的安全链接,必须设置 :cpp:class:`verification <esp_mqtt_client_config_t::broker_t::verification_t>` 结构体。
|
||||
服务器证书可设置为 PEM 或 DER 格式。如要选择 DER 格式,必须设置等效 :cpp:member:`certificate_len <esp_mqtt_client_config_t::broker_t::verification_t::certificate_len>` 字段,否则应在 :cpp:member:`certificate <esp_mqtt_client_config_t::broker_t::verification_t::certificate>` 字段传入以空字符结尾的 PEM 格式字符串。
|
||||
|
||||
- 从服务器获取证书,例如:``mqtt.eclipseprojects.io``
|
||||
.. code::
|
||||
|
||||
openssl s_client -showcerts -connect mqtt.eclipseprojects.io:8883 < /dev/null \
|
||||
2> /dev/null | openssl x509 -outform PEM > mqtt_eclipse_org.pem
|
||||
|
||||
- 检查示例应用程序::example:`protocols/mqtt/ssl`
|
||||
- 配置:
|
||||
|
||||
.. code:: c
|
||||
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker = {
|
||||
.address.uri = "mqtts://mqtt.eclipseprojects.io:8883",
|
||||
.verification.certificate = (const char *)mqtt_eclipse_org_pem_start,
|
||||
},
|
||||
};
|
||||
|
||||
了解其他字段的详细信息,请查看 `API 参考`_ 以及 :ref:`esp_tls_server_verification`。
|
||||
|
||||
客户端凭据
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:cpp:class:`credentials <esp_mqtt_client_config_t::credentials_t>` 字段下包含所有客户端相关凭据。
|
||||
|
||||
* :cpp:member:`username <esp_mqtt_client_config_t::credentials_t::username>`:指向用于连接服务器用户名的指针,也可通过 URI 设置
|
||||
* :cpp:member:`client_id <esp_mqtt_client_config_t::credentials_t::client_id>`:指向客户端 ID 的指针,默认为 ``ESP32_%CHIPID%``,其中 ``%CHIPID%`` 是十六进制 MAC 地址的最后 3 个字节
|
||||
|
||||
===============
|
||||
认证
|
||||
===============
|
||||
|
||||
可以通过 :cpp:class:`authentication <esp_mqtt_client_config_t::credentials_t::authentication_t>` 字段设置认证参数。客户端支持以下认证方式:
|
||||
|
||||
* :cpp:member:`password <esp_mqtt_client_config_t::credentials_t::authentication_t::password>`:使用密码
|
||||
* * :cpp:member:`certificate <esp_mqtt_client_config_t::credentials_t::authentication_t::certificate>` 和 :cpp:member:`key <esp_mqtt_client_config_t::credentials_t::authentication_t::key>`:进行双向 TLS 身份验证,PEM 或 DER 格式均可
|
||||
* :cpp:member:`use_secure_element <esp_mqtt_client_config_t::credentials_t::authentication_t::use_secure_element>`:使用 ESP32 系列中的安全元素 (ATECC608A)
|
||||
* :cpp:member:`ds_data <esp_mqtt_client_config_t::credentials_t::authentication_t::ds_data>`:使用某些乐鑫设备的数字签名外设
|
||||
|
||||
会话
|
||||
^^^^^^^^^^^^
|
||||
|
||||
使用 :cpp:class:`session <esp_mqtt_client_config_t::session_t>` 字段进行 MQTT 会话相关配置。
|
||||
|
||||
========================
|
||||
遗嘱消息 (LWT)
|
||||
========================
|
||||
|
||||
通过设置 :cpp:class:`last_will <esp_mqtt_client_config_t::session_t::last_will_t>` 结构体的以下字段,MQTT 会在一个客户端意外断开连接时通过遗嘱消息通知其他客户端。
|
||||
|
||||
* :cpp:member:`topic <esp_mqtt_client_config_t::session_t::last_will_t::topic>`:指向 LWT 消息主题的指针
|
||||
* :cpp:member:`msg <esp_mqtt_client_config_t::session_t::last_will_t::msg>`:指向 LWT 消息的指针
|
||||
* :cpp:member:`msg_len <esp_mqtt_client_config_t::session_t::last_will_t::msg_len>`:LWT 消息的长度,:cpp:member:`msg <esp_mqtt_client_config_t::session_t::last_will_t::msg>` 不以空字符结尾时需要该字段
|
||||
* :cpp:member:`qos <esp_mqtt_client_config_t::session_t::last_will_t::qos>`:LWT 消息的服务质量
|
||||
* :cpp:member:`retain <esp_mqtt_client_config_t::session_t::last_will_t::retain>`:指定 LWT 消息的保留标志
|
||||
|
||||
在项目配置菜单中设置 MQTT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
通过 :code:`idf.py menuconfig`,可以在 ``Component config`` > ``ESP-MQTT Configuration`` 中找到 MQTT 设置。
|
||||
|
||||
相关设置如下:
|
||||
|
||||
- :ref:`CONFIG_MQTT_PROTOCOL_311`:启用 MQTT 协议 3.1.1 版本
|
||||
|
||||
- :ref:`CONFIG_MQTT_TRANSPORT_SSL` 和 :ref:`CONFIG_MQTT_TRANSPORT_WEBSOCKET`:启用特定 MQTT 传输层,例如 SSL、WEBSOCKET 和 WEBSOCKET_SECURE
|
||||
|
||||
- :ref:`CONFIG_MQTT_CUSTOM_OUTBOX`:禁用 mqtt_outbox 默认实现,因此可以提供特定实现
|
||||
|
||||
|
||||
事件
|
||||
------------
|
||||
MQTT 客户端可能会发布以下事件:
|
||||
|
||||
* ``MQTT_EVENT_BEFORE_CONNECT``:客户端已初始化并即将开始连接至服务器。
|
||||
* ``MQTT_EVENT_CONNECTED``:客户端已成功连接至服务器。客户端已准备好收发数据。
|
||||
* ``MQTT_EVENT_DISCONNECTED``:由于无法读取或写入数据,例如因为服务器无法使用,客户端已终止连接。
|
||||
* ``MQTT_EVENT_SUBSCRIBED``:服务器已确认客户端的订阅请求。事件数据将包含订阅消息的消息 ID。
|
||||
* ``MQTT_EVENT_UNSUBSCRIBED``:服务器已确认客户端的退订请求。事件数据将包含退订消息的消息 ID。
|
||||
* ``MQTT_EVENT_PUBLISHED``:服务器已确认客户端的发布消息。消息将仅针对 QoS 级别 1 和 2 发布,因为级别 0 不会进行确认。事件数据将包含发布消息的消息 ID。
|
||||
* ``MQTT_EVENT_DATA``:客户端已收到发布消息。事件数据包含:消息 ID、发布消息所属主题名称、收到的数据及其长度。对于超出内部缓冲区的数据,将发布多个 ``MQTT_EVENT_DATA``,并更新事件数据的 :cpp:member:`current_data_offset <esp_mqtt_event_t::current_data_offset>` 和 :cpp:member:`total_data_len<esp_mqtt_event_t::total_data_len>` 以跟踪碎片化消息。
|
||||
* ``MQTT_EVENT_ERROR``:客户端遇到错误。使用事件数据 :cpp:type:`error_handle <esp_mqtt_error_codes_t>` 字段中的 :cpp:type:`error_type <esp_mqtt_error_type_t>`,可以发现错误。错误类型决定 :cpp:type:`error_handle <esp_mqtt_error_codes_t>` 结构体的哪些部分会被填充。
|
||||
|
||||
API 参考
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/mqtt_client.inc
|
||||
.. include-build-file:: inc/mqtt5_client.inc
|
20
examples/custom_outbox/CMakeLists.txt
Normal file
20
examples/custom_outbox/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_tcp_custom_outbox)
|
||||
|
||||
# Add custom outbox implementation to mqtt component
|
||||
idf_component_get_property(mqtt mqtt COMPONENT_LIB)
|
||||
target_sources(${mqtt} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/main/custom_outbox.cpp)
|
||||
|
||||
# Our C++ needs an extra dependency to mqtt component, so we add it to mqtt component.
|
||||
# This is needed because we are adding another source to the mqtt component and the build
|
||||
# system needs to be aware of it to be able to compile and link the mqtt component.
|
||||
# First we get our dependency
|
||||
idf_component_get_property(pthread pthread COMPONENT_LIB)
|
||||
# And them we link the components
|
||||
target_link_libraries(${mqtt} ${pthread})
|
100
examples/custom_outbox/README.md
Normal file
100
examples/custom_outbox/README.md
Normal file
@@ -0,0 +1,100 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT custom outbox sample application
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example is a slightly modified version of the tcp example to show how to configure a custom outbox.
|
||||
This example connects to the broker URI selected using `idf.py menuconfig` (using mqtt tcp transport) and as a demonstration subscribes/unsubscribes and send a message on certain topic.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes))
|
||||
|
||||
Note: If the URI equals `FROM_STDIN` then the broker address is read from stdin upon application startup (used for testing)
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
|
||||
## Necessary changes to customize the outbox
|
||||
|
||||
To customize the outbox the first step is to enable it in the menuconfig option.
|
||||
|
||||
With this option enabled, the default implementation isn't defined and the function definition needs to be added to mqtt component.
|
||||
Any extra dependencies needed by the new sources also need to be added to the mqtt component. Refer to the example CMakeLists.txt file
|
||||
for the details on how to do it.
|
||||
|
||||
## The custom outbox in the example
|
||||
|
||||
For the sake of this example the customized outbox implements the same functionalits of the regular but using C++ as a language.
|
||||
|
||||
The implementation uses [C++ Polymorphic memory resources]() to control memory allocations and limit the usage of the memory.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
Note that the mandatory configurations for this example, mqtt custom outbox and C++ exceptions are automatically added by the `sdkconfig.defaults` file.
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (4635) example_common: Connected to example_netif_sta
|
||||
I (4645) example_common: - IPv4 address: 192.168.33.206,
|
||||
I (4645) example_common: - IPv6 address: fe80:0000:0000:0000:7e9e:bdff:fecf:00c0, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (4655) Monotonic: Monotonic: 400 bytes allocated, 400 total bytes in use
|
||||
I (4665) Monotonic: Monotonic: 1000 bytes allocated, 1400 total bytes in use
|
||||
I (4675) Monotonic: Monotonic: 128 bytes allocated, 1528 total bytes in use
|
||||
I (4685) Pool: Pool: 32 bytes allocated, 32 total bytes in use
|
||||
I (4685) Monotonic: Monotonic: 7688 bytes allocated, 9216 total bytes in use
|
||||
I (4695) Monotonic: Monotonic: 128 bytes allocated, 9344 total bytes in use
|
||||
I (4705) Pool: Pool: 480 bytes allocated, 512 total bytes in use
|
||||
I (4715) Monotonic: Monotonic: 992 bytes allocated, 10336 total bytes in use
|
||||
I (4715) Monotonic: Monotonic: 128 bytes allocated, 10464 total bytes in use
|
||||
I (4725) Pool: Pool: 23 bytes allocated, 535 total bytes in use
|
||||
I (4735) MQTT_EXAMPLE: Enqueued msg_id=14345
|
||||
I (4735) Pool: Pool: 29 bytes allocated, 564 total bytes in use
|
||||
I (4745) MQTT_EXAMPLE: Enqueued msg_id=3507
|
||||
I (4745) MQTT_EXAMPLE: Other event id:7
|
||||
I (4755) main_task: Returned from app_main()
|
||||
I (5085) MQTT_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (5085) Pool: Pool: 23 bytes allocated, 587 total bytes in use
|
||||
I (5085) MQTT_EXAMPLE: sent publish successful, msg_id=47425
|
||||
I (5085) Pool: Pool: 18 bytes allocated, 605 total bytes in use
|
||||
I (5095) MQTT_EXAMPLE: sent subscribe successful, msg_id=60709
|
||||
I (5105) Pool: Pool: 18 bytes allocated, 623 total bytes in use
|
||||
I (5105) MQTT_EXAMPLE: sent subscribe successful, msg_id=33273
|
||||
I (5395) Pool: Pool: 23 bytes deallocated, 623 total bytes in use
|
||||
I (5395) MQTT_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=47425
|
||||
I (6005) Pool: Pool: 18 bytes deallocated, 623 total bytes in use
|
||||
I (6005) MQTT_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=60709
|
||||
I (6005) MQTT_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (6015) Pool: Pool: 18 bytes deallocated, 623 total bytes in use
|
||||
I (6015) MQTT_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=33273
|
||||
I (6025) MQTT_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (6035) MQTT_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos1
|
||||
DATA=data_3
|
||||
I (6315) MQTT_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos1
|
||||
DATA=data_3
|
||||
I (6315) Pool: Pool: 23 bytes deallocated, 623 total bytes in use
|
||||
I (6315) MQTT_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=14345
|
||||
I (6615) MQTT_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
4
examples/custom_outbox/main/CMakeLists.txt
Normal file
4
examples/custom_outbox/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES mqtt nvs_flash esp_netif
|
||||
)
|
13
examples/custom_outbox/main/Kconfig.projbuild
Normal file
13
examples/custom_outbox/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,13 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URL
|
||||
string "Broker URL"
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL of the broker to connect to
|
||||
|
||||
config BROKER_URL_FROM_STDIN
|
||||
bool
|
||||
default y if BROKER_URL = "FROM_STDIN"
|
||||
|
||||
endmenu
|
173
examples/custom_outbox/main/app_main.c
Normal file
173
examples/custom_outbox/main/app_main.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* MQTT (over TCP) Example with custom outbox
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static const char *TAG = "MQTT_EXAMPLE";
|
||||
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0) {
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_BROKER_URL,
|
||||
};
|
||||
#if CONFIG_BROKER_URL_FROM_STDIN
|
||||
char line[128];
|
||||
|
||||
if (strcmp(mqtt_cfg.broker.address.uri, "FROM_STDIN") == 0) {
|
||||
int count = 0;
|
||||
printf("Please enter url of mqtt broker\n");
|
||||
while (count < 128) {
|
||||
int c = fgetc(stdin);
|
||||
if (c == '\n') {
|
||||
line[count] = '\0';
|
||||
break;
|
||||
} else if (c > 0 && c < 127) {
|
||||
line[count] = c;
|
||||
++count;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
mqtt_cfg.broker.address.uri = line;
|
||||
printf("Broker url: %s\n", line);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");
|
||||
abort();
|
||||
}
|
||||
#endif /* CONFIG_BROKER_URL_FROM_STDIN */
|
||||
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
|
||||
/*Let's enqueue a few messages to the outbox to see the allocations*/
|
||||
int msg_id;
|
||||
msg_id = esp_mqtt_client_enqueue(client, "/topic/qos1", "data_3", 0, 1, 0, true);
|
||||
ESP_LOGI(TAG, "Enqueued msg_id=%d", msg_id);
|
||||
msg_id = esp_mqtt_client_enqueue(client, "/topic/qos2", "QoS2 message", 0, 2, 0, true);
|
||||
ESP_LOGI(TAG, "Enqueued msg_id=%d", msg_id);
|
||||
|
||||
/* Now we start the client and it's possible to see the memory usage for the operations in the outbox. */
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("custom_outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
393
examples/custom_outbox/main/custom_outbox.cpp
Normal file
393
examples/custom_outbox/main/custom_outbox.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <deque>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory_resource>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_outbox.h"
|
||||
|
||||
constexpr auto TAG = "custom_outbox";
|
||||
|
||||
/*
|
||||
* The trace resource class is created here as an example on how to build a custom memory resource
|
||||
* The class is only needed to show where we are allocating from and to track allocations and deallocations.
|
||||
*/
|
||||
class trace_resource : public std::pmr::memory_resource {
|
||||
public:
|
||||
explicit trace_resource(std::string resource_name, std::pmr::memory_resource *upstream_resource = std::pmr::get_default_resource()) : upstream{upstream_resource}, name{std::move(resource_name)} {}
|
||||
[[nodiscard]] std::string_view get_name() const noexcept
|
||||
{
|
||||
return std::string_view(name);
|
||||
}
|
||||
[[nodiscard]] auto upstream_resource() const
|
||||
{
|
||||
return upstream;
|
||||
}
|
||||
private:
|
||||
void *do_allocate(std::size_t bytes, std::size_t alignment) override
|
||||
{
|
||||
auto *allocated = upstream->allocate(bytes, alignment);
|
||||
allocated_total += bytes;
|
||||
ESP_LOGI(name.c_str(), "%s: %zu bytes allocated, %zu total bytes in use", name.c_str(), bytes, allocated_total);
|
||||
return allocated;
|
||||
}
|
||||
void do_deallocate(void *ptr, std::size_t bytes, std::size_t alignment) override
|
||||
{
|
||||
upstream->deallocate(ptr, bytes, alignment);
|
||||
ESP_LOGI(name.c_str(), "%s: %zu bytes deallocated, %zu total bytes in use", name.c_str(), bytes, allocated_total);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool do_is_equal(const std::pmr::memory_resource &other) const noexcept override
|
||||
{
|
||||
return this == &other;
|
||||
}
|
||||
size_t allocated_total{};
|
||||
std::pmr::memory_resource *upstream;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct outbox_item {
|
||||
/* Defining the allocator_type to let compiler know that our type is allocator aware,
|
||||
* This way the allocator used for the outbox is propagated to the messages*/
|
||||
using allocator_type = std::pmr::polymorphic_allocator<>;
|
||||
|
||||
/* Few strong types to diferetiate parameters*/
|
||||
enum class id_t : int {};
|
||||
enum class type_t : int {};
|
||||
enum class qos_t : int {};
|
||||
|
||||
/* Allocator aware constructors */
|
||||
outbox_item(
|
||||
std::pmr::vector<uint8_t> message,
|
||||
id_t msg_id,
|
||||
type_t msg_type,
|
||||
qos_t msg_qos,
|
||||
outbox_tick_t tick,
|
||||
pending_state_t pending_state,
|
||||
allocator_type alloc = {}
|
||||
) : message(std::move(message), alloc), id(msg_id), type(msg_type), qos(msg_qos), tick(tick), pending_state(pending_state) {}
|
||||
|
||||
/*Copy and move constructors have an extra allocator parameter, for copy default and allocator aware are the same.*/
|
||||
outbox_item(const outbox_item &other, allocator_type alloc = {}) : message(other.message, alloc), id(other.id), type(other.type), qos(other.qos), tick(other.tick), pending_state(other.pending_state) {}
|
||||
outbox_item(outbox_item &&other, allocator_type alloc) noexcept : message(std::move(other.message), alloc), id(other.id), type(other.type), qos(other.qos), tick(other.tick), pending_state(other.pending_state)
|
||||
{}
|
||||
|
||||
outbox_item(const outbox_item &) = default;
|
||||
outbox_item(outbox_item &&other) = default;
|
||||
outbox_item &operator=(const outbox_item &rhs) = default;
|
||||
outbox_item &operator=(outbox_item &&other) = default;
|
||||
~outbox_item() = default;
|
||||
|
||||
/* Getters to support outbox operation */
|
||||
[[nodiscard]] auto state() const noexcept
|
||||
{
|
||||
return pending_state;
|
||||
}
|
||||
|
||||
[[nodiscard]] allocator_type get_allocator() const
|
||||
{
|
||||
return message.get_allocator();
|
||||
}
|
||||
|
||||
void set(pending_state state) noexcept
|
||||
{
|
||||
pending_state = state;
|
||||
}
|
||||
|
||||
void set(outbox_tick_t n_tick) noexcept
|
||||
{
|
||||
tick = n_tick;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_id() const noexcept
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_type() const noexcept
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_tick() const noexcept
|
||||
{
|
||||
return tick;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_data(size_t *len, uint16_t *msg_id, int *msg_type, int *msg_qos)
|
||||
{
|
||||
*len = message.size();
|
||||
*msg_id = static_cast<uint16_t>(id);
|
||||
*msg_type = static_cast<int>(type);
|
||||
*msg_qos = static_cast<int>(qos);
|
||||
return message.data();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const noexcept
|
||||
{
|
||||
return message.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::pmr::vector<uint8_t> message;
|
||||
id_t id;
|
||||
type_t type;
|
||||
qos_t qos;
|
||||
outbox_tick_t tick;
|
||||
pending_state_t pending_state;
|
||||
};
|
||||
|
||||
/*
|
||||
* For the outbox_t we let the special member functions as default and
|
||||
* we don't extend the allocator aware versions for the sake of the simplicity, since the operations are not needed in the usage.
|
||||
*/
|
||||
struct outbox_t {
|
||||
using allocator_type = std::pmr::polymorphic_allocator<>;
|
||||
explicit outbox_t(allocator_type alloc = {}) : queue(alloc) {}
|
||||
|
||||
outbox_item_handle_t get(outbox_item::id_t msg_id)
|
||||
{
|
||||
if (auto item = std::ranges::find_if(queue, [msg_id](auto & item) {
|
||||
return item.get_id() == msg_id;
|
||||
});
|
||||
item != std::end(queue)) {
|
||||
return &(*item);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int delete_expired(outbox_tick_t current_tick, outbox_tick_t timeout)
|
||||
{
|
||||
return std::erase_if(queue, [current_tick, timeout, this](const outbox_item & item) {
|
||||
if (current_tick - item.get_tick() > timeout) {
|
||||
total_size -= item.get_size();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
outbox_item::id_t delete_single_expired(outbox_tick_t current_tick, outbox_tick_t timeout)
|
||||
{
|
||||
if (auto erase = std::ranges::find_if(queue, [current_tick, timeout](auto & item) {
|
||||
return (current_tick - item.get_tick() > timeout);
|
||||
}); erase != std::end(queue)) {
|
||||
auto msg_id = erase->get_id();
|
||||
total_size -= erase->get_size();
|
||||
queue.erase(erase);
|
||||
return msg_id;
|
||||
}
|
||||
return outbox_item::id_t{-1};
|
||||
}
|
||||
|
||||
auto erase(outbox_item_handle_t to_erase)
|
||||
{
|
||||
return erase_if([to_erase](auto & item) {
|
||||
return &item == to_erase;
|
||||
});
|
||||
}
|
||||
|
||||
auto erase(outbox_item::id_t msg_id, outbox_item::type_t msg_type)
|
||||
{
|
||||
return erase_if([msg_id, msg_type](auto & item) {
|
||||
return (item.get_id() == msg_id && (item.get_type() == msg_type));
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] auto size() const noexcept
|
||||
{
|
||||
return total_size;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
outbox_item_handle_t enqueue(outbox_message_handle_t message, outbox_tick_t tick) noexcept
|
||||
{
|
||||
try {
|
||||
auto &item =
|
||||
queue.emplace_back(std::pmr::vector<uint8_t> {message->data, message->data + message->len},
|
||||
outbox_item::id_t{message->msg_id},
|
||||
outbox_item::type_t{message->msg_type},
|
||||
outbox_item::qos_t{message->msg_qos},
|
||||
tick,
|
||||
QUEUED
|
||||
);
|
||||
total_size += item.get_size();
|
||||
ESP_LOGD(TAG, "ENQUEUE msgid=%d, msg_type=%d, len=%d, size=%" PRIu64, message->msg_id, message->msg_type, message->len + message->remaining_len, outbox_get_size(this));
|
||||
return &item;
|
||||
} catch (const std::exception &e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
outbox_item_handle_t dequeue(pending_state_t state, outbox_tick_t *tick)
|
||||
{
|
||||
if (auto item = std::ranges::find_if(queue, [state](auto & item) {
|
||||
return item.state() == state;
|
||||
});
|
||||
item != std::end(queue)) {
|
||||
if (tick != nullptr) {
|
||||
*tick = item->get_tick();
|
||||
}
|
||||
return &(*item);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
[[nodiscard]] allocator_type get_allocator() const
|
||||
{
|
||||
return queue.get_allocator();
|
||||
}
|
||||
private:
|
||||
[[nodiscard]] esp_err_t erase_if(std::predicate<outbox_item &> auto &&predicate)
|
||||
{
|
||||
if (auto to_erase = std::ranges::find_if(queue, predicate); to_erase != std::end(queue)) {
|
||||
total_size -= to_erase->get_size();
|
||||
queue.erase(to_erase);
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
std::size_t total_size{};
|
||||
std::pmr::deque<outbox_item> queue ;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
outbox_handle_t outbox_init()
|
||||
{
|
||||
/* First we create a fixed size memory buffer to be used. */
|
||||
static constexpr auto work_memory_size = 16 * 1024;
|
||||
static std::array<std::byte, work_memory_size> resource_buffer{};
|
||||
try {
|
||||
/*
|
||||
* Since the outbox is managed by a C API we can't rely on C++ automatic cleanup and smart pointers but, on production code it would be better to add the
|
||||
* memory resources to outbox_t, applying RAII principles, and make only outbox_item allocator aware. For the sake of the example we are keeping them
|
||||
* separated to explictly show the relations.
|
||||
* First we create the monotonic buffer and add null_memory_resource as upstream. This way if our working memory is exausted an exception is thrown.
|
||||
*/
|
||||
auto *monotonic_resource = new std::pmr::monotonic_buffer_resource{resource_buffer.data(), resource_buffer.size(), std::pmr::null_memory_resource()};
|
||||
/*Here we add our custom trace wrapper type to trace allocations and deallocations*/
|
||||
auto *trace_monotonic = new trace_resource("Monotonic", monotonic_resource);
|
||||
|
||||
/* We compose monotonic buffer with pool resource, since the monotonic deallocate is a no-op and we need to remove messages to not go out of memory.*/
|
||||
auto *pool_resource = new std::pmr::unsynchronized_pool_resource{trace_monotonic};
|
||||
auto *trace_pool = new trace_resource("Pool", pool_resource);
|
||||
/* Our outbox class is created using the trace_pool as memory resource */
|
||||
auto *outbox = new outbox_t{trace_pool};
|
||||
return outbox;
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGD(TAG, "Not enough memory to construct the outbox, review the resource_buffer size");
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, outbox_tick_t tick)
|
||||
{
|
||||
return outbox->enqueue(message, tick);
|
||||
}
|
||||
|
||||
outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id)
|
||||
{
|
||||
return outbox->get(outbox_item::id_t{msg_id});
|
||||
}
|
||||
|
||||
outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, outbox_tick_t *tick)
|
||||
{
|
||||
return outbox->dequeue(pending, tick);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos)
|
||||
{
|
||||
if (item == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return item->get_data(len, msg_id, msg_type, qos);
|
||||
}
|
||||
|
||||
esp_err_t outbox_delete_item(outbox_handle_t outbox, outbox_item_handle_t item_to_delete)
|
||||
{
|
||||
return outbox->erase(item_to_delete);
|
||||
|
||||
}
|
||||
|
||||
esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type)
|
||||
{
|
||||
return outbox->erase(outbox_item::id_t{msg_id}, outbox_item::type_t{msg_type});
|
||||
}
|
||||
|
||||
int outbox_delete_single_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout)
|
||||
{
|
||||
return static_cast<int>(outbox->delete_single_expired(current_tick, timeout));
|
||||
}
|
||||
|
||||
int outbox_delete_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout)
|
||||
{
|
||||
return outbox->delete_expired(current_tick, timeout);
|
||||
}
|
||||
|
||||
esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending)
|
||||
{
|
||||
if (auto *item = outbox->get(outbox_item::id_t{msg_id}); item != nullptr) {
|
||||
item->set(pending);
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
pending_state_t outbox_item_get_pending(outbox_item_handle_t item)
|
||||
{
|
||||
if (item != nullptr) {
|
||||
return item->state();
|
||||
}
|
||||
return QUEUED;
|
||||
}
|
||||
|
||||
esp_err_t outbox_set_tick(outbox_handle_t outbox, int msg_id, outbox_tick_t tick)
|
||||
{
|
||||
if (auto *item = outbox->get(outbox_item::id_t{msg_id}); item != nullptr) {
|
||||
item->set(tick);
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
uint64_t outbox_get_size(outbox_handle_t outbox)
|
||||
{
|
||||
return outbox->size();
|
||||
}
|
||||
|
||||
void outbox_delete_all_items(outbox_handle_t outbox)
|
||||
{
|
||||
outbox->clear();
|
||||
}
|
||||
|
||||
void outbox_destroy(outbox_handle_t outbox)
|
||||
{
|
||||
auto *trace_pool = static_cast<trace_resource *>(outbox->get_allocator().resource());
|
||||
auto *pool_resource = static_cast<std::pmr::unsynchronized_pool_resource *>(trace_pool->upstream_resource());
|
||||
auto *trace_monotonic = static_cast<trace_resource *>(pool_resource->upstream_resource());
|
||||
auto *monotonic_resource = static_cast<std::pmr::monotonic_buffer_resource *>(trace_monotonic->upstream_resource());
|
||||
|
||||
delete monotonic_resource;
|
||||
delete trace_monotonic;
|
||||
delete pool_resource;
|
||||
delete trace_pool;
|
||||
delete outbox;
|
||||
}
|
3
examples/custom_outbox/main/idf_component.yml
Normal file
3
examples/custom_outbox/main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
1
examples/custom_outbox/sdkconfig.ci.esp32c6
Normal file
1
examples/custom_outbox/sdkconfig.ci.esp32c6
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
3
examples/custom_outbox/sdkconfig.defaults
Normal file
3
examples/custom_outbox/sdkconfig.defaults
Normal file
@@ -0,0 +1,3 @@
|
||||
CONFIG_MQTT_CUSTOM_OUTBOX=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
9
examples/mqtt5/CMakeLists.txt
Normal file
9
examples/mqtt5/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt5)
|
78
examples/mqtt5/README.md
Normal file
78
examples/mqtt5/README.md
Normal file
@@ -0,0 +1,78 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT sample application
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example connects to the broker URI selected using `idf.py menuconfig` (using mqtt tcp transport) and as a demonstration subscribes/unsubscribes and send a message on certain topic.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes))
|
||||
|
||||
Note: If the URI equals `FROM_STDIN` then the broker address is read from stdin upon application startup (used for testing)
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker with MQTT version 5.
|
||||
|
||||
The more details about MQTT v5, please refer to [official website](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html)
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
* MQTT v5 protocol (`CONFIG_MQTT_PROTOCOL_5`) under "ESP-MQTT Configurations" menu is enabled by `sdkconfig.defaults`.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (5119) esp_netif_handlers: example_connect: sta ip: 192.168.3.143, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (5119) example_connect: Got IPv4 event: Interface "example_connect: sta" address: 192.168.3.143
|
||||
I (5619) example_connect: Got IPv6 event: Interface "example_connect: sta" address: fe80:0000:0000:0000:c64f:33ff:fe24:6645, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (5619) example_connect: Connected to example_connect: sta
|
||||
I (5629) example_connect: - IPv4 address: 192.168.3.143
|
||||
I (5629) example_connect: - IPv6 address: fe80:0000:0000:0000:c64f:33ff:fe24:6645, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (5649) MQTT5_EXAMPLE: Other event id:7
|
||||
W (6299) wifi:<ba-add>idx:0 (ifx:0, 34:29:12:43:c5:40), tid:7, ssn:0, winSize:64
|
||||
I (7439) MQTT5_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (7439) MQTT5_EXAMPLE: sent publish successful, msg_id=53118
|
||||
I (7439) MQTT5_EXAMPLE: sent subscribe successful, msg_id=41391
|
||||
I (7439) MQTT5_EXAMPLE: sent subscribe successful, msg_id=13695
|
||||
I (7449) MQTT5_EXAMPLE: sent unsubscribe successful, msg_id=55594
|
||||
I (7649) mqtt5_client: MQTT_MSG_TYPE_PUBACK return code is -1
|
||||
I (7649) MQTT5_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=53118
|
||||
I (8039) mqtt5_client: MQTT_MSG_TYPE_SUBACK return code is 0
|
||||
I (8049) MQTT5_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=41391
|
||||
I (8049) MQTT5_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (8059) mqtt5_client: MQTT_MSG_TYPE_SUBACK return code is 2
|
||||
I (8059) MQTT5_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=13695
|
||||
I (8069) MQTT5_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (8079) MQTT5_EXAMPLE: MQTT_EVENT_DATA
|
||||
I (8079) MQTT5_EXAMPLE: key is board, value is esp32
|
||||
I (8079) MQTT5_EXAMPLE: key is u, value is user
|
||||
I (8089) MQTT5_EXAMPLE: key is p, value is password
|
||||
I (8089) MQTT5_EXAMPLE: payload_format_indicator is 1
|
||||
I (8099) MQTT5_EXAMPLE: response_topic is /topic/test/response
|
||||
I (8109) MQTT5_EXAMPLE: correlation_data is 123456
|
||||
I (8109) MQTT5_EXAMPLE: content_type is
|
||||
I (8119) MQTT5_EXAMPLE: TOPIC=/topic/qos1
|
||||
I (8119) MQTT5_EXAMPLE: DATA=data_3
|
||||
I (8129) mqtt5_client: MQTT_MSG_TYPE_UNSUBACK return code is 0
|
||||
I (8129) MQTT5_EXAMPLE: MQTT_EVENT_UNSUBSCRIBED, msg_id=55594
|
||||
I (8139) mqtt_client: Client asked to disconnect
|
||||
I (9159) MQTT5_EXAMPLE: MQTT_EVENT_DISCONNECTED
|
||||
```
|
3
examples/mqtt5/main/CMakeLists.txt
Normal file
3
examples/mqtt5/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt nvs_flash esp_netif
|
||||
INCLUDE_DIRS ".")
|
13
examples/mqtt5/main/Kconfig.projbuild
Normal file
13
examples/mqtt5/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,13 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URL
|
||||
string "Broker URL"
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL of the broker to connect to
|
||||
|
||||
config BROKER_URL_FROM_STDIN
|
||||
bool
|
||||
default y if BROKER_URL = "FROM_STDIN"
|
||||
|
||||
endmenu
|
290
examples/mqtt5/main/app_main.c
Normal file
290
examples/mqtt5/main/app_main.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static const char *TAG = "mqtt5_example";
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0) {
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_mqtt5_user_property_item_t user_property_arr[] = {
|
||||
{"board", "esp32"},
|
||||
{"u", "user"},
|
||||
{"p", "password"}
|
||||
};
|
||||
|
||||
#define USE_PROPERTY_ARR_SIZE sizeof(user_property_arr)/sizeof(esp_mqtt5_user_property_item_t)
|
||||
|
||||
static esp_mqtt5_publish_property_config_t publish_property = {
|
||||
.payload_format_indicator = 1,
|
||||
.message_expiry_interval = 1000,
|
||||
.topic_alias = 0,
|
||||
.response_topic = "/topic/test/response",
|
||||
.correlation_data = "123456",
|
||||
.correlation_data_len = 6,
|
||||
};
|
||||
|
||||
static esp_mqtt5_subscribe_property_config_t subscribe_property = {
|
||||
.subscribe_id = 25555,
|
||||
.no_local_flag = false,
|
||||
.retain_as_published_flag = false,
|
||||
.retain_handle = 0,
|
||||
.is_share_subscribe = true,
|
||||
.share_name = "group1",
|
||||
};
|
||||
|
||||
static esp_mqtt5_subscribe_property_config_t subscribe1_property = {
|
||||
.subscribe_id = 25555,
|
||||
.no_local_flag = true,
|
||||
.retain_as_published_flag = false,
|
||||
.retain_handle = 0,
|
||||
};
|
||||
|
||||
static esp_mqtt5_unsubscribe_property_config_t unsubscribe_property = {
|
||||
.is_share_subscribe = true,
|
||||
.share_name = "group1",
|
||||
};
|
||||
|
||||
static esp_mqtt5_disconnect_property_config_t disconnect_property = {
|
||||
.session_expiry_interval = 60,
|
||||
.disconnect_reason = 0,
|
||||
};
|
||||
|
||||
static void print_user_property(mqtt5_user_property_handle_t user_property)
|
||||
{
|
||||
if (user_property) {
|
||||
uint8_t count = esp_mqtt5_client_get_user_property_count(user_property);
|
||||
if (count) {
|
||||
esp_mqtt5_user_property_item_t *item = malloc(count * sizeof(esp_mqtt5_user_property_item_t));
|
||||
if (esp_mqtt5_client_get_user_property(user_property, item, &count) == ESP_OK) {
|
||||
for (int i = 0; i < count; i ++) {
|
||||
esp_mqtt5_user_property_item_t *t = &item[i];
|
||||
ESP_LOGI(TAG, "key is %s, value is %s", t->key, t->value);
|
||||
free((char *)t->key);
|
||||
free((char *)t->value);
|
||||
}
|
||||
}
|
||||
free(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt5_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
|
||||
ESP_LOGD(TAG, "free heap size is %" PRIu32 ", minimum %" PRIu32, esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
print_user_property(event->property->user_property);
|
||||
esp_mqtt5_client_set_user_property(&publish_property.user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
|
||||
esp_mqtt5_client_set_publish_property(client, &publish_property);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 1);
|
||||
esp_mqtt5_client_delete_user_property(publish_property.user_property);
|
||||
publish_property.user_property = NULL;
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
|
||||
esp_mqtt5_client_set_user_property(&subscribe_property.user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
|
||||
esp_mqtt5_client_set_subscribe_property(client, &subscribe_property);
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
esp_mqtt5_client_delete_user_property(subscribe_property.user_property);
|
||||
subscribe_property.user_property = NULL;
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
esp_mqtt5_client_set_user_property(&subscribe1_property.user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
|
||||
esp_mqtt5_client_set_subscribe_property(client, &subscribe1_property);
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 2);
|
||||
esp_mqtt5_client_delete_user_property(subscribe1_property.user_property);
|
||||
subscribe1_property.user_property = NULL;
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
esp_mqtt5_client_set_user_property(&unsubscribe_property.user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
|
||||
esp_mqtt5_client_set_unsubscribe_property(client, &unsubscribe_property);
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos0");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
esp_mqtt5_client_delete_user_property(unsubscribe_property.user_property);
|
||||
unsubscribe_property.user_property = NULL;
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
print_user_property(event->property->user_property);
|
||||
break;
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, reason code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
print_user_property(event->property->user_property);
|
||||
esp_mqtt5_client_set_publish_property(client, &publish_property);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
print_user_property(event->property->user_property);
|
||||
esp_mqtt5_client_set_user_property(&disconnect_property.user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
|
||||
esp_mqtt5_client_set_disconnect_property(client, &disconnect_property);
|
||||
esp_mqtt5_client_delete_user_property(disconnect_property.user_property);
|
||||
disconnect_property.user_property = NULL;
|
||||
esp_mqtt_client_disconnect(client);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
print_user_property(event->property->user_property);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
print_user_property(event->property->user_property);
|
||||
ESP_LOGI(TAG, "payload_format_indicator is %d", event->property->payload_format_indicator);
|
||||
ESP_LOGI(TAG, "response_topic is %.*s", event->property->response_topic_len, event->property->response_topic);
|
||||
ESP_LOGI(TAG, "correlation_data is %.*s", event->property->correlation_data_len, event->property->correlation_data);
|
||||
ESP_LOGI(TAG, "content_type is %.*s", event->property->content_type_len, event->property->content_type);
|
||||
ESP_LOGI(TAG, "TOPIC=%.*s", event->topic_len, event->topic);
|
||||
ESP_LOGI(TAG, "DATA=%.*s", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
print_user_property(event->property->user_property);
|
||||
ESP_LOGI(TAG, "MQTT5 return code is %d", event->error_handle->connect_return_code);
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt5_app_start(void)
|
||||
{
|
||||
esp_mqtt5_connection_property_config_t connect_property = {
|
||||
.session_expiry_interval = 10,
|
||||
.maximum_packet_size = 1024,
|
||||
.receive_maximum = 65535,
|
||||
.topic_alias_maximum = 2,
|
||||
.request_resp_info = true,
|
||||
.request_problem_info = true,
|
||||
.will_delay_interval = 10,
|
||||
.payload_format_indicator = true,
|
||||
.message_expiry_interval = 10,
|
||||
.response_topic = "/test/response",
|
||||
.correlation_data = "123456",
|
||||
.correlation_data_len = 6,
|
||||
};
|
||||
|
||||
esp_mqtt_client_config_t mqtt5_cfg = {
|
||||
.broker.address.uri = CONFIG_BROKER_URL,
|
||||
.session.protocol_ver = MQTT_PROTOCOL_V_5,
|
||||
.network.disable_auto_reconnect = true,
|
||||
.credentials.username = "123",
|
||||
.credentials.authentication.password = "456",
|
||||
.session.last_will.topic = "/topic/will",
|
||||
.session.last_will.msg = "i will leave",
|
||||
.session.last_will.msg_len = 12,
|
||||
.session.last_will.qos = 1,
|
||||
.session.last_will.retain = true,
|
||||
};
|
||||
|
||||
#if CONFIG_BROKER_URL_FROM_STDIN
|
||||
char line[128];
|
||||
|
||||
if (strcmp(mqtt5_cfg.uri, "FROM_STDIN") == 0) {
|
||||
int count = 0;
|
||||
printf("Please enter url of mqtt broker\n");
|
||||
while (count < 128) {
|
||||
int c = fgetc(stdin);
|
||||
if (c == '\n') {
|
||||
line[count] = '\0';
|
||||
break;
|
||||
} else if (c > 0 && c < 127) {
|
||||
line[count] = c;
|
||||
++count;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
mqtt5_cfg.broker.address.uri = line;
|
||||
printf("Broker url: %s\n", line);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");
|
||||
abort();
|
||||
}
|
||||
#endif /* CONFIG_BROKER_URL_FROM_STDIN */
|
||||
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);
|
||||
|
||||
/* Set connection properties and user properties */
|
||||
esp_mqtt5_client_set_user_property(&connect_property.user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
|
||||
esp_mqtt5_client_set_user_property(&connect_property.will_user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
|
||||
esp_mqtt5_client_set_connect_property(client, &connect_property);
|
||||
|
||||
/* If you call esp_mqtt5_client_set_user_property to set user properties, DO NOT forget to delete them.
|
||||
* esp_mqtt5_client_set_connect_property will malloc buffer to store the user_property and you can delete it after
|
||||
*/
|
||||
esp_mqtt5_client_delete_user_property(connect_property.user_property);
|
||||
esp_mqtt5_client_delete_user_property(connect_property.will_user_property);
|
||||
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt5_app_start();
|
||||
}
|
3
examples/mqtt5/main/idf_component.yml
Normal file
3
examples/mqtt5/main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
65
examples/mqtt5/pytest_mqtt5.py
Normal file
65
examples/mqtt5/pytest_mqtt5.py
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.ethernet
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_examples_protocol_mqtt5(dut: Dut) -> None:
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
2. connect to mqtt://mqtt.eclipseprojects.io
|
||||
3. check connection success
|
||||
"""
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'mqtt5.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('mqtt5_bin_size : {}KB'.format(bin_size // 1024))
|
||||
# check if connected or not
|
||||
dut.expect_exact('MQTT_EVENT_CONNECTED', timeout=30)
|
||||
# check log
|
||||
res = dut.expect(r'sent publish successful, msg_id=(\d+)[^\d]')
|
||||
msgid_pub1 = res.group(1).decode('utf8')
|
||||
res = dut.expect(r'sent subscribe successful, msg_id=(\d+)[^\d]')
|
||||
msgid_sub1 = res.group(1).decode('utf8')
|
||||
res = dut.expect(r'sent subscribe successful, msg_id=(\d+)[^\d]')
|
||||
msgid_sub2 = res.group(1).decode('utf8')
|
||||
res = dut.expect(r'sent unsubscribe successful, msg_id=(\d+)[^\d]')
|
||||
msgid_unsub = res.group(1).decode('utf8')
|
||||
res = dut.expect(r'MQTT_EVENT_PUBLISHED, msg_id=(\d+)[^\d]')
|
||||
msgid_pubd = res.group(1).decode('utf8')
|
||||
assert msgid_pubd == msgid_pub1
|
||||
|
||||
res = dut.expect(r'MQTT_EVENT_SUBSCRIBED, msg_id=(\d+)[^\d]')
|
||||
msgid_subd = res.group(1).decode('utf8')
|
||||
assert msgid_subd == msgid_sub1
|
||||
|
||||
dut.expect_exact('sent publish successful, msg_id=0')
|
||||
res = dut.expect(r'MQTT_EVENT_SUBSCRIBED, msg_id=(\d+)[^\d]')
|
||||
msgid_subd = res.group(1).decode('utf8')
|
||||
assert msgid_subd == msgid_sub2
|
||||
|
||||
dut.expect_exact('sent publish successful, msg_id=0')
|
||||
dut.expect_exact('MQTT_EVENT_DATA')
|
||||
dut.expect_exact('key is board, value is esp32')
|
||||
dut.expect_exact('key is u, value is user')
|
||||
dut.expect_exact('key is p, value is password')
|
||||
dut.expect_exact('payload_format_indicator is 1')
|
||||
dut.expect_exact('response_topic is /topic/test/response')
|
||||
dut.expect_exact('correlation_data is 123456')
|
||||
dut.expect_exact('TOPIC=/topic/qos1')
|
||||
dut.expect_exact('DATA=data_3')
|
||||
res = dut.expect(r'MQTT_EVENT_UNSUBSCRIBED, msg_id=(\d+)[^\d]')
|
||||
msgid_unsubd = res.group(1).decode('utf8')
|
||||
assert msgid_unsubd == msgid_unsub
|
||||
|
||||
dut.expect_exact('MQTT_EVENT_DISCONNECTED')
|
||||
logging.info('MQTT5 pytest pass')
|
10
examples/mqtt5/sdkconfig.ci
Normal file
10
examples/mqtt5/sdkconfig.ci
Normal file
@@ -0,0 +1,10 @@
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_MQTT_PROTOCOL_5=y
|
||||
CONFIG_BROKER_URL="mqtt://${EXAMPLE_MQTTV5_BROKER_TCP}"
|
1
examples/mqtt5/sdkconfig.defaults
Normal file
1
examples/mqtt5/sdkconfig.defaults
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_MQTT_PROTOCOL_5=y
|
11
examples/ssl/CMakeLists.txt
Normal file
11
examples/ssl/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_ssl)
|
||||
|
||||
target_add_binary_data(${PROJECT_NAME}.elf "main/mqtt_eclipseprojects_io.pem" TEXT)
|
70
examples/ssl/README.md
Normal file
70
examples/ssl/README.md
Normal file
@@ -0,0 +1,70 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT SSL Sample application
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example connects to the broker mqtt.eclipseprojects.io using ssl transport and as a demonstration subscribes/unsubscribes and send a message on certain topic.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes))
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
PEM certificate for this example could be extracted from an openssl `s_client` command connecting to mqtt.eclipseprojects.io.
|
||||
In case a host operating system has `openssl` and `sed` packages installed, one could execute the following command to download and save the root certificate to a file (Note for Windows users: Both Linux like environment or Windows native packages may be used).
|
||||
```
|
||||
echo "" | openssl s_client -showcerts -connect mqtt.eclipseprojects.io:8883 | sed -n "1,/Root/d; /BEGIN/,/END/p" | openssl x509 -outform PEM >mqtt_eclipse_org.pem
|
||||
```
|
||||
Please note that this is not a general command for downloading a root certificate for an arbitrary host;
|
||||
this command works with mqtt.eclipseprojects.io as the site provides root certificate in the chain, which then could be extracted
|
||||
with text operation.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
|
||||
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
|
||||
I (4164) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (4174) MQTTS_EXAMPLE: sent publish successful, msg_id=41464
|
||||
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=17886
|
||||
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=42970
|
||||
I (4184) MQTTS_EXAMPLE: sent unsubscribe successful, msg_id=50241
|
||||
I (4314) MQTTS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
|
||||
I (4484) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
|
||||
I (4484) MQTTS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4684) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
|
||||
I (4684) MQTTS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (4884) MQTTS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (5194) MQTTS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
||||
|
3
examples/ssl/main/CMakeLists.txt
Normal file
3
examples/ssl/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt esp_partition nvs_flash esp_netif app_update
|
||||
INCLUDE_DIRS ".")
|
26
examples/ssl/main/Kconfig.projbuild
Normal file
26
examples/ssl/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,26 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URI
|
||||
string "Broker URL"
|
||||
default "mqtts://mqtt.eclipseprojects.io:8883"
|
||||
help
|
||||
URL of an mqtt broker which this example connects to.
|
||||
|
||||
config BROKER_CERTIFICATE_OVERRIDE
|
||||
string "Broker certificate override"
|
||||
default ""
|
||||
help
|
||||
Please leave empty if broker certificate included from a textfile; otherwise fill in a base64 part of PEM
|
||||
format certificate
|
||||
|
||||
config BROKER_CERTIFICATE_OVERRIDDEN
|
||||
bool
|
||||
default y if BROKER_CERTIFICATE_OVERRIDE != ""
|
||||
|
||||
config BROKER_BIN_SIZE_TO_SEND
|
||||
# This option is not visible and is used only to set parameters for example tests
|
||||
# Here we configure the data size to send and to be expected in the python script
|
||||
int
|
||||
default 20000
|
||||
|
||||
endmenu
|
165
examples/ssl/main/app_main.c
Normal file
165
examples/ssl/main/app_main.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/* MQTT over SSL Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_partition.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_tls.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include <sys/param.h>
|
||||
|
||||
static const char *TAG = "mqtts_example";
|
||||
|
||||
|
||||
#if CONFIG_BROKER_CERTIFICATE_OVERRIDDEN == 1
|
||||
static const uint8_t mqtt_eclipseprojects_io_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
|
||||
#else
|
||||
extern const uint8_t mqtt_eclipseprojects_io_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start");
|
||||
#endif
|
||||
extern const uint8_t mqtt_eclipseprojects_io_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end");
|
||||
|
||||
//
|
||||
// Note: this function is for testing purposes only publishing part of the active partition
|
||||
// (to be checked against the original binary)
|
||||
//
|
||||
static void send_binary(esp_mqtt_client_handle_t client)
|
||||
{
|
||||
esp_partition_mmap_handle_t out_handle;
|
||||
const void *binary_address;
|
||||
const esp_partition_t *partition = esp_ota_get_running_partition();
|
||||
esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &binary_address, &out_handle);
|
||||
// sending only the configured portion of the partition (if it's less than the partition size)
|
||||
int binary_size = MIN(CONFIG_BROKER_BIN_SIZE_TO_SEND, partition->size);
|
||||
int msg_id = esp_mqtt_client_publish(client, "/topic/binary", binary_address, binary_size, 0, 0);
|
||||
ESP_LOGI(TAG, "binary sent with msg_id=%d", msg_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, return code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
if (strncmp(event->data, "send binary please", event->data_len) == 0) {
|
||||
ESP_LOGI(TAG, "Sending the binary");
|
||||
send_binary(client);
|
||||
}
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
ESP_LOGI(TAG, "Last error code reported from esp-tls: 0x%x", event->error_handle->esp_tls_last_esp_err);
|
||||
ESP_LOGI(TAG, "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err);
|
||||
ESP_LOGI(TAG, "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno,
|
||||
strerror(event->error_handle->esp_transport_sock_errno));
|
||||
} else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {
|
||||
ESP_LOGI(TAG, "Connection refused error: 0x%x", event->error_handle->connect_return_code);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker = {
|
||||
.address.uri = CONFIG_BROKER_URI,
|
||||
.verification.certificate = (const char *)mqtt_eclipseprojects_io_pem_start
|
||||
},
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
3
examples/ssl/main/idf_component.yml
Normal file
3
examples/ssl/main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
30
examples/ssl/main/mqtt_eclipseprojects_io.pem
Normal file
30
examples/ssl/main/mqtt_eclipseprojects_io.pem
Normal file
@@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
|
||||
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
|
||||
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
|
||||
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
|
||||
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
|
||||
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
|
||||
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
|
||||
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
|
||||
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
|
||||
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
|
||||
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
|
||||
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
|
||||
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
|
||||
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
|
||||
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
|
||||
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
|
||||
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
|
||||
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
|
||||
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
|
||||
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
|
||||
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
|
||||
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
|
||||
nLRbwHOoq7hHwg==
|
||||
-----END CERTIFICATE-----
|
135
examples/ssl/pytest_mqtt_ssl.py
Normal file
135
examples/ssl/pytest_mqtt_ssl.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import ssl
|
||||
import sys
|
||||
from threading import Event
|
||||
from threading import Thread
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import pexpect
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
event_client_connected = Event()
|
||||
event_stop_client = Event()
|
||||
event_client_received_correct = Event()
|
||||
event_client_received_binary = Event()
|
||||
message_log = ''
|
||||
|
||||
|
||||
# The callback for when the client receives a CONNACK response from the server.
|
||||
def on_connect(client, userdata, flags, rc): # type: (mqtt.Client, str, bool, str) -> None
|
||||
_ = (userdata, flags)
|
||||
print('Connected with result code ' + str(rc))
|
||||
event_client_connected.set()
|
||||
client.subscribe('/topic/qos0')
|
||||
|
||||
|
||||
def mqtt_client_task(client): # type: (mqtt.Client) -> None
|
||||
while not event_stop_client.is_set():
|
||||
client.loop()
|
||||
|
||||
|
||||
# The callback for when a PUBLISH message is received from the server.
|
||||
def on_message(client, userdata, msg): # type: (mqtt.Client, tuple, mqtt.client.MQTTMessage) -> None
|
||||
global message_log
|
||||
global event_client_received_correct
|
||||
global event_client_received_binary
|
||||
if msg.topic == '/topic/binary':
|
||||
binary, bin_size = userdata
|
||||
print('Receiving binary from esp and comparing with {}, size {}...'.format(binary, bin_size))
|
||||
with open(binary, 'rb') as f:
|
||||
bin = f.read()
|
||||
if bin[:bin_size] == msg.payload[:bin_size]:
|
||||
print('...matches!')
|
||||
event_client_received_binary.set()
|
||||
return
|
||||
recv_binary = binary + '.received'
|
||||
with open(recv_binary, 'w', encoding='utf-8') as fw:
|
||||
fw.write(msg.payload)
|
||||
raise ValueError(
|
||||
'Received binary (saved as: {}) does not match the original file: {}'.format(recv_binary, binary)
|
||||
)
|
||||
|
||||
payload = msg.payload.decode()
|
||||
if not event_client_received_correct.is_set() and payload == 'data':
|
||||
client.subscribe('/topic/binary')
|
||||
client.publish('/topic/qos0', 'send binary please')
|
||||
if msg.topic == '/topic/qos0' and payload == 'data':
|
||||
event_client_received_correct.set()
|
||||
message_log += 'Received data:' + msg.topic + ' ' + payload + '\n'
|
||||
|
||||
|
||||
@pytest.mark.ethernet
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_examples_protocol_mqtt_ssl(dut): # type: (Dut) -> None
|
||||
broker_url = ''
|
||||
broker_port = 0
|
||||
"""
|
||||
steps:
|
||||
1. join AP and connects to ssl broker
|
||||
2. Test connects a client to the same broker
|
||||
3. Test evaluates python client received correct qos0 message
|
||||
4. Test ESP32 client received correct qos0 message
|
||||
5. Test python client receives binary data from running partition and compares it with the binary
|
||||
"""
|
||||
binary_file = os.path.join(dut.app.binary_path, 'mqtt_ssl.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('[Performance][mqtt_ssl_bin_size]: %s KB', bin_size // 1024)
|
||||
|
||||
# Look for host:port in sdkconfig
|
||||
try:
|
||||
value = re.search(r'\:\/\/([^:]+)\:([0-9]+)', dut.app.sdkconfig.get('BROKER_URI'))
|
||||
assert value is not None
|
||||
broker_url = value.group(1)
|
||||
broker_port = int(value.group(2))
|
||||
bin_size = min(int(dut.app.sdkconfig.get('BROKER_BIN_SIZE_TO_SEND')), bin_size)
|
||||
except Exception:
|
||||
print('ENV_TEST_FAILURE: Cannot find broker url in sdkconfig')
|
||||
raise
|
||||
client = None
|
||||
# 1. Test connects to a broker
|
||||
try:
|
||||
client = mqtt.Client()
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
client.user_data_set((binary_file, bin_size))
|
||||
client.tls_set(None, None, None, cert_reqs=ssl.CERT_NONE, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
|
||||
client.tls_insecure_set(True)
|
||||
print('Connecting...')
|
||||
client.connect(broker_url, broker_port, 60)
|
||||
except Exception:
|
||||
print(
|
||||
'ENV_TEST_FAILURE: Unexpected error while connecting to broker {}: {}:'.format(
|
||||
broker_url, sys.exc_info()[0]
|
||||
)
|
||||
)
|
||||
raise
|
||||
# Starting a py-client in a separate thread
|
||||
thread1 = Thread(target=mqtt_client_task, args=(client,))
|
||||
thread1.start()
|
||||
try:
|
||||
print('Connecting py-client to broker {}:{}...'.format(broker_url, broker_port))
|
||||
if not event_client_connected.wait(timeout=30):
|
||||
raise ValueError('ENV_TEST_FAILURE: Test script cannot connect to broker: {}'.format(broker_url))
|
||||
try:
|
||||
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[0]
|
||||
print('Connected to AP with IP: {}'.format(ip_address))
|
||||
except pexpect.TIMEOUT:
|
||||
print('ENV_TEST_FAILURE: Cannot connect to AP')
|
||||
raise
|
||||
print('Checking py-client received msg published from esp...')
|
||||
if not event_client_received_correct.wait(timeout=30):
|
||||
raise ValueError('Wrong data received, msg log: {}'.format(message_log))
|
||||
print('Checking esp-client received msg published from py-client...')
|
||||
dut.expect(r'DATA=send binary please', timeout=30)
|
||||
print('Receiving binary data from running partition...')
|
||||
if not event_client_received_binary.wait(timeout=30):
|
||||
raise ValueError('Binary not received within timeout')
|
||||
finally:
|
||||
event_stop_client.set()
|
||||
thread1.join()
|
22
examples/ssl/sdkconfig.ci
Normal file
22
examples/ssl/sdkconfig.ci
Normal file
@@ -0,0 +1,22 @@
|
||||
CONFIG_BROKER_URI="mqtts://${EXAMPLE_MQTT_BROKER_SSL}"
|
||||
CONFIG_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}"
|
||||
CONFIG_MQTT_USE_CUSTOM_CONFIG=y
|
||||
CONFIG_MQTT_TCP_DEFAULT_PORT=1883
|
||||
CONFIG_MQTT_SSL_DEFAULT_PORT=8883
|
||||
CONFIG_MQTT_WS_DEFAULT_PORT=80
|
||||
CONFIG_MQTT_WSS_DEFAULT_PORT=443
|
||||
CONFIG_MQTT_BUFFER_SIZE=16384
|
||||
CONFIG_MQTT_TASK_STACK_SIZE=6144
|
||||
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
|
||||
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
|
||||
CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_LWIP_CHECK_THREAD_SAFETY=y
|
18
examples/ssl_ds/CMakeLists.txt
Normal file
18
examples/ssl_ds/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_ssl_ds)
|
||||
|
||||
# Flash the custom partition named `esp_secure_cert`.
|
||||
set(partition esp_secure_cert)
|
||||
idf_build_get_property(project_dir PROJECT_DIR)
|
||||
set(image_file ${project_dir}/esp_secure_cert_data/${partition}.bin)
|
||||
partition_table_get_partition_info(offset "--partition-name ${partition}" "offset")
|
||||
esptool_py_flash_target_image(flash "${partition}" "${offset}" "${image_file}")
|
||||
|
||||
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/mosquitto.org.crt" TEXT)
|
105
examples/ssl_ds/README.md
Normal file
105
examples/ssl_ds/README.md
Normal file
@@ -0,0 +1,105 @@
|
||||
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT SSL Mutual Authentication with Digital Signature
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
Espressif's ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6, ESP32-H2 and ESP32-P4 MCU have a built-in Digital Signature (DS) Peripheral, which provides hardware acceleration for RSA signature. More details can be found at [Digital Signature with ESP-TLS](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/protocols/esp_tls.html#digital-signature-with-esp-tls).
|
||||
|
||||
This example connects to the broker test.mosquitto.org using ssl transport with client certificate(RSA) and as a demonstration subscribes/unsubscribes and sends a message on certain topic.The RSA signature operation required in the ssl connection is performed with help of the Digital Signature (DS) peripheral.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please visit http://test.mosquitto.org)
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any of the supported ESP32 family board (which has a built-in DS peripheral), the only required interface is WiFi/Ethernet and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
#### 1) Selecting the target
|
||||
|
||||
Please select the supported target with the following command:
|
||||
```
|
||||
idf.py set-target /* target */
|
||||
```
|
||||
More details can be found at [Selecting the target](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#selecting-the-target).
|
||||
|
||||
#### 2) Generate your client key and certificate
|
||||
|
||||
Navigate to the main directory
|
||||
|
||||
```
|
||||
cd main
|
||||
```
|
||||
|
||||
Generate a client key and a CSR. When you are generating the CSR, do not use the default values. At a minimum, the CSR must include the Country, Organisation and Common Name fields.
|
||||
|
||||
```
|
||||
openssl genrsa -out client.key
|
||||
openssl req -out client.csr -key client.key -new
|
||||
```
|
||||
|
||||
Paste the generated CSR in the [Mosquitto test certificate signer](https://test.mosquitto.org/ssl/index.php), click Submit and downloaded the `client.crt`. This `client.crt` file shall be used as the device certificate.
|
||||
|
||||
#### 3) Configure the DS peripheral
|
||||
|
||||
* i) Install the [esp_secure_cert configuration utility](https://github.com/espressif/esp_secure_cert_mgr/tree/main/tools#esp_secure_cert-configuration-tool) with following command:
|
||||
```
|
||||
pip install esp-secure-cert-tool
|
||||
```
|
||||
* ii) The DS peripheral can be configured by executing the following command:
|
||||
|
||||
```
|
||||
configure_esp_secure_cert.py -p /* Serial port */ --device-cert /* Device cert */ --private-key /* RSA priv key */ --target_chip /* target chip */ --configure_ds --skip_flash
|
||||
```
|
||||
This command shall generate a partition named `esp_secure_cert.bin` in the `esp_secure_cert_data` directory. This partition would be aumatically detected by the build system and flashed at appropriate offset when `idf.py flash` command is used. For this process, the command must be executed in the current folder only.
|
||||
|
||||
In the command USB COM port is nothing but the serial port to which the ESP chip is connected. see
|
||||
[check serial port](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/establish-serial-connection.html#check-port-on-windows) for more details.
|
||||
RSA private key is nothing but the client private key ( RSA ) generated in Step 2.
|
||||
|
||||
> Note: More details about the `esp-secure-cert-tool` utility can be found [here](https://github.com/espressif/esp_secure_cert_mgr/tree/main/tools).
|
||||
|
||||
#### 4) Connection configuration
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
|
||||
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
|
||||
I (4164) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (4174) MQTTS_EXAMPLE: sent publish successful, msg_id=41464
|
||||
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=17886
|
||||
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=42970
|
||||
I (4184) MQTTS_EXAMPLE: sent unsubscribe successful, msg_id=50241
|
||||
I (4314) MQTTS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
|
||||
I (4484) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
|
||||
I (4484) MQTTS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4684) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
|
||||
I (4684) MQTTS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (4884) MQTTS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (5194) MQTTS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
3
examples/ssl_ds/main/CMakeLists.txt
Normal file
3
examples/ssl_ds/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt esp_netif
|
||||
INCLUDE_DIRS ".")
|
156
examples/ssl_ds/main/app_main.c
Normal file
156
examples/ssl_ds/main/app_main.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/* MQTT Mutual Authentication Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "rsa_sign_alt.h"
|
||||
#include "esp_secure_cert_read.h"
|
||||
|
||||
static const char *TAG = "mqtts_example";
|
||||
|
||||
extern const uint8_t server_cert_pem_start[] asm("_binary_mosquitto_org_crt_start");
|
||||
extern const uint8_t server_cert_pem_end[] asm("_binary_mosquitto_org_crt_end");
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
// your_context_t *context = event->context;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, return code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
/* The context is used by the DS peripheral, should not be freed */
|
||||
esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();
|
||||
if (ds_data == NULL) {
|
||||
ESP_LOGE(TAG, "Error in reading DS data from NVS");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
char *device_cert = NULL;
|
||||
esp_err_t ret;
|
||||
uint32_t len;
|
||||
ret = esp_secure_cert_get_device_cert(&device_cert, &len);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to obtain the device certificate");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker = {
|
||||
.address.uri = "mqtts://test.mosquitto.org:8884",
|
||||
.verification.certificate = (const char *)server_cert_pem_start,
|
||||
},
|
||||
.credentials = {
|
||||
.authentication = {
|
||||
.certificate = (const char *)device_cert,
|
||||
.key = NULL,
|
||||
.ds_data = (void *)ds_data
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
5
examples/ssl_ds/main/idf_component.yml
Normal file
5
examples/ssl_ds/main/idf_component.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_secure_cert_mgr: "^2.0.2"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
25
examples/ssl_ds/main/mosquitto.org.crt
Normal file
25
examples/ssl_ds/main/mosquitto.org.crt
Normal file
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL
|
||||
BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG
|
||||
A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU
|
||||
BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv
|
||||
by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE
|
||||
BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES
|
||||
MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp
|
||||
dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg
|
||||
UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW
|
||||
Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA
|
||||
s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH
|
||||
3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo
|
||||
E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV
|
||||
6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
|
||||
BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC
|
||||
6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf
|
||||
+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK
|
||||
sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839
|
||||
LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE
|
||||
m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=
|
||||
-----END CERTIFICATE-----
|
||||
---
|
6
examples/ssl_ds/partitions.csv
Normal file
6
examples/ssl_ds/partitions.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
esp_secure_cert,0x3F,,,0x2000,
|
||||
nvs,data,nvs,,24K,
|
||||
phy_init,data,phy,,4K,
|
||||
factory,app,factory,0x20000,1M,
|
|
7
examples/ssl_ds/sdkconfig.defaults
Normal file
7
examples/ssl_ds/sdkconfig.defaults
Normal file
@@ -0,0 +1,7 @@
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
# Setting partition table offset to 0xC000 would make the address of
|
||||
# `esp_secure_cert` partition as 0xD000 (comes next in the sequence).
|
||||
# Modules that are programmed with Espressif Secure Pre Provisioining service
|
||||
# uses this offset for `esp_secure_cert` and hence this change aligns this example
|
||||
# to work on those modules.
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0xC000
|
2
examples/ssl_ds/sdkconfig.defaults.esp32h2
Normal file
2
examples/ssl_ds/sdkconfig.defaults.esp32h2
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
13
examples/ssl_mutual_auth/CMakeLists.txt
Normal file
13
examples/ssl_mutual_auth/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_ssl_mutual_auth)
|
||||
|
||||
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/client.crt" TEXT)
|
||||
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/client.key" TEXT)
|
||||
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/mosquitto.org.crt" TEXT)
|
82
examples/ssl_mutual_auth/README.md
Normal file
82
examples/ssl_mutual_auth/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT SSL Sample application (mutual authentication)
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example connects to the broker test.mosquitto.org using ssl transport with client certificate and as a demonstration subscribes/unsubscribes and send a message on certain topic.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please visit http://test.mosquitto.org)
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
* Generate your client keys and certificate
|
||||
|
||||
Navigate to the main directory
|
||||
|
||||
```
|
||||
cd main
|
||||
```
|
||||
|
||||
Generate a client key and a CSR. When you are generating the CSR, do not use the default values. At a minimum, the CSR must include the Country, Organisation and Common Name fields.
|
||||
|
||||
```
|
||||
openssl genrsa -out client.key
|
||||
openssl req -out client.csr -key client.key -new
|
||||
```
|
||||
|
||||
Paste the generated CSR in the [Mosquitto test certificate signer](https://test.mosquitto.org/ssl/index.php), click Submit and copy the downloaded `client.crt` in the `main` directory.
|
||||
|
||||
Please note, that the supplied files `client.crt` and `client.key` in the `main` directory are only placeholders for your client certificate and key (i.e. the example "as is" would compile but would not connect to the broker)
|
||||
|
||||
The server certificate `mosquitto.org.crt` can be downloaded in pem format from [mosquitto.org.crt](https://test.mosquitto.org/ssl/mosquitto.org.crt).
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
|
||||
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
|
||||
I (4164) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (4174) MQTTS_EXAMPLE: sent publish successful, msg_id=41464
|
||||
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=17886
|
||||
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=42970
|
||||
I (4184) MQTTS_EXAMPLE: sent unsubscribe successful, msg_id=50241
|
||||
I (4314) MQTTS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
|
||||
I (4484) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
|
||||
I (4484) MQTTS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4684) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
|
||||
I (4684) MQTTS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (4884) MQTTS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (5194) MQTTS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
||||
|
3
examples/ssl_mutual_auth/main/CMakeLists.txt
Normal file
3
examples/ssl_mutual_auth/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt esp_wifi nvs_flash
|
||||
INCLUDE_DIRS ".")
|
155
examples/ssl_mutual_auth/main/app_main.c
Normal file
155
examples/ssl_mutual_auth/main/app_main.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/* MQTT Mutual Authentication Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static const char *TAG = "mqtts_example";
|
||||
|
||||
extern const uint8_t client_cert_pem_start[] asm("_binary_client_crt_start");
|
||||
extern const uint8_t client_cert_pem_end[] asm("_binary_client_crt_end");
|
||||
extern const uint8_t client_key_pem_start[] asm("_binary_client_key_start");
|
||||
extern const uint8_t client_key_pem_end[] asm("_binary_client_key_end");
|
||||
extern const uint8_t server_cert_pem_start[] asm("_binary_mosquitto_org_crt_start");
|
||||
extern const uint8_t server_cert_pem_end[] asm("_binary_mosquitto_org_crt_end");
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0) {
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, return code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = "mqtts://test.mosquitto.org:8884",
|
||||
.broker.verification.certificate = (const char *)server_cert_pem_start,
|
||||
.credentials = {
|
||||
.authentication = {
|
||||
.certificate = (const char *)client_cert_pem_start,
|
||||
.key = (const char *)client_key_pem_start,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
1
examples/ssl_mutual_auth/main/client.crt
Normal file
1
examples/ssl_mutual_auth/main/client.crt
Normal file
@@ -0,0 +1 @@
|
||||
Please paste your client certificate here (follow instructions in README.md)
|
1
examples/ssl_mutual_auth/main/client.key
Normal file
1
examples/ssl_mutual_auth/main/client.key
Normal file
@@ -0,0 +1 @@
|
||||
Please paste here your client key (follow instructions in README.md)
|
3
examples/ssl_mutual_auth/main/idf_component.yml
Normal file
3
examples/ssl_mutual_auth/main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
24
examples/ssl_mutual_auth/main/mosquitto.org.crt
Normal file
24
examples/ssl_mutual_auth/main/mosquitto.org.crt
Normal file
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL
|
||||
BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG
|
||||
A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU
|
||||
BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv
|
||||
by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE
|
||||
BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES
|
||||
MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp
|
||||
dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg
|
||||
UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW
|
||||
Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA
|
||||
s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH
|
||||
3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo
|
||||
E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV
|
||||
6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
|
||||
BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC
|
||||
6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf
|
||||
+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK
|
||||
sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839
|
||||
LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE
|
||||
m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=
|
||||
-----END CERTIFICATE-----
|
9
examples/ssl_psk/CMakeLists.txt
Normal file
9
examples/ssl_psk/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_ssl_psk)
|
78
examples/ssl_psk/README.md
Normal file
78
examples/ssl_psk/README.md
Normal file
@@ -0,0 +1,78 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT SSL example with PSK verification
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example connects to a local broker configured to PSK authentication
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi (or ethernet) to connect to a MQTT
|
||||
broker with preconfigured PSK verification method.
|
||||
|
||||
#### Mosquitto settings
|
||||
In case of using mosquitto broker, here is how to enable PSK authentication in `mosquitto.config`,
|
||||
```
|
||||
psk_hint hint
|
||||
psk_file path_to_your_psk_file
|
||||
allow_anonymous true
|
||||
```
|
||||
Note: Last line enables anonymous mode, as this example does not use mqtt username and password.
|
||||
|
||||
PSK file then has to contain pairs of hints and keys, as shown below:
|
||||
```
|
||||
hint:BAD123
|
||||
```
|
||||
|
||||
Important note: Keys are stored as text hexadecimal values in PSK file, while the example code stores key as plain binary
|
||||
as required by MQTT API. (See the example source for details: `"BAD123" -> 0xBA, 0xD1, 0x23`)
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Run `idf.py menuconfig`
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (2160) example_connect: Ethernet Link Up
|
||||
I (4650) example_connect: Connected to Ethernet
|
||||
I (4650) example_connect: IPv4 address: 192.168.0.1
|
||||
I (4650) MQTTS_EXAMPLE: [APP] Free memory: 244792 bytes
|
||||
I (4660) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
D (4670) MQTT_CLIENT: MQTT client_id=ESP32_c6B4F8
|
||||
D (4680) MQTT_CLIENT: Core selection disabled
|
||||
I (4680) MQTTS_EXAMPLE: Other event id:7
|
||||
D (4680) esp-tls: host:192.168.0.2: strlen 13
|
||||
D (4700) esp-tls: ssl psk authentication
|
||||
D (4700) esp-tls: handshake in progress...
|
||||
D (4720) MQTT_CLIENT: Transport connected to mqtts://192.168.0.2:8883
|
||||
I (4720) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
|
||||
D (4720) MQTT_CLIENT: mqtt_message_receive: first byte: 0x20
|
||||
D (4730) MQTT_CLIENT: mqtt_message_receive: read "remaining length" byte: 0x2
|
||||
D (4730) MQTT_CLIENT: mqtt_message_receive: total message length: 4 (already read: 2)
|
||||
D (4740) MQTT_CLIENT: mqtt_message_receive: read_len=2
|
||||
D (4750) MQTT_CLIENT: mqtt_message_receive: transport_read():4 4
|
||||
D (4750) MQTT_CLIENT: Connected
|
||||
I (4760) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
D (4760) MQTT_CLIENT: mqtt_enqueue id: 4837, type=8 successful
|
||||
D (4770) OUTBOX: ENQUEUE msgid=4837, msg_type=8, len=18, size=18
|
||||
D (4770) MQTT_CLIENT: Sent subscribe topic=/topic/qos0, id: 4837, type=8 successful
|
||||
I (4780) MQTTS_EXAMPLE: sent subscribe successful, msg_id=4837
|
||||
D (4790) MQTT_CLIENT: mqtt_enqueue id: 58982, type=8 successful
|
||||
D (4790) OUTBOX: ENQUEUE msgid=58982, msg_type=8, len=18, size=36
|
||||
D (4800) MQTT_CLIENT: Sent subscribe topic=/topic/qos1, id: 58982, type=8 successful
|
||||
I (4810) MQTTS_EXAMPLE: sent subscribe successful, msg_id=58982
|
||||
```
|
||||
|
3
examples/ssl_psk/main/CMakeLists.txt
Normal file
3
examples/ssl_psk/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt esp_wifi nvs_flash
|
||||
INCLUDE_DIRS ".")
|
151
examples/ssl_psk/main/app_main.c
Normal file
151
examples/ssl_psk/main/app_main.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/* MQTT over SSL Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_tls.h"
|
||||
|
||||
/*
|
||||
* Add here URI of mqtt broker which supports PSK authentication
|
||||
*/
|
||||
#define EXAMPLE_BROKER_URI "mqtts://192.168.0.2"
|
||||
|
||||
static const char *TAG = "mqtts_example";
|
||||
|
||||
/*
|
||||
* Define psk key and hint as defined in mqtt broker
|
||||
* example for mosquitto server, content of psk_file:
|
||||
* hint:BAD123
|
||||
*
|
||||
*/
|
||||
static const uint8_t s_key[] = { 0xBA, 0xD1, 0x23 };
|
||||
|
||||
static const psk_hint_key_t psk_hint_key = {
|
||||
.key = s_key,
|
||||
.key_size = sizeof(s_key),
|
||||
.hint = "hint"
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, return code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = EXAMPLE_BROKER_URI,
|
||||
.broker.verification.psk_hint_key = &psk_hint_key,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
3
examples/ssl_psk/main/idf_component.yml
Normal file
3
examples/ssl_psk/main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
1
examples/ssl_psk/sdkconfig.defaults
Normal file
1
examples/ssl_psk/sdkconfig.defaults
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_ESP_TLS_PSK_VERIFICATION=y
|
9
examples/tcp/CMakeLists.txt
Normal file
9
examples/tcp/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_tcp)
|
375
examples/tcp/README.md
Normal file
375
examples/tcp/README.md
Normal file
@@ -0,0 +1,375 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT sample application
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example connects to the broker URI selected using `idf.py menuconfig` (using mqtt tcp transport) and as a demonstration subscribes/unsubscribes and send a message on certain topic.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes))
|
||||
|
||||
Note: If the URI equals `FROM_STDIN` then the broker address is read from stdin upon application startup (used for testing)
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
|
||||
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
|
||||
I (4164) MQTT_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (4174) MQTT_EXAMPLE: sent publish successful, msg_id=41464
|
||||
I (4174) MQTT_EXAMPLE: sent subscribe successful, msg_id=17886
|
||||
I (4174) MQTT_EXAMPLE: sent subscribe successful, msg_id=42970
|
||||
I (4184) MQTT_EXAMPLE: sent unsubscribe successful, msg_id=50241
|
||||
I (4314) MQTT_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
|
||||
I (4484) MQTT_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
|
||||
I (4484) MQTT_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4684) MQTT_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
|
||||
I (4684) MQTT_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (4884) MQTT_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (5194) MQTT_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
||||
|
||||
## Using Wi-Fi connection with ESP32P4
|
||||
|
||||
It is possible to use Wi-Fi connection on targets that do not support native Wi-Fi peripheral. This example demonstrates using `esp_wifi_remote` on ESP32P4 in the test configuration defined as `sdkconfig.ci.p4_wifi`. This configuration requires another ESP target with native Wi-Fi support physically connected to the ESP32-P4.
|
||||
|
||||
This uses [esp_hosted](https://components.espressif.com/components/espressif/esp_hosted) project by default, please refer to its documentation for more details.
|
||||
Note, that `esp_hosted` library currently transmits Wi-Fi credentials in plain text. In case this is a concern, please choose the `eppp` option in `esp_wifi_remote` configuration menu (`CONFIG_ESP_WIFI_REMOTE_LIBRARY_EPPP=y`) and setup master-slave verification (please see [eppp: Configure master-slave verification](#eppp)).
|
||||
|
||||
### esp-hosted: Configure the slave project
|
||||
|
||||
You first need to build and flash the slave project. It's possible to perform this action directly from the host project, these commands can be used to set the slave target device (for example ESP32C6), build and flash the slave project. You will have to hold the RST button to keep the host device (ESP32-P4) in reset while flashing the slave device.
|
||||
```
|
||||
idf.py -C managed_components/espressif__esp_hosted/slave/ -B build_slave set-target esp32c6
|
||||
idf.py -C managed_components/espressif__esp_hosted/slave/ -B build_slave build flash monitor
|
||||
```
|
||||
|
||||
### esp-hosted: Example Output of the slave device
|
||||
|
||||
```
|
||||
I (348) cpu_start: Unicore app
|
||||
I (357) cpu_start: Pro cpu start user code
|
||||
I (357) cpu_start: cpu freq: 160000000 Hz
|
||||
I (357) app_init: Application information:
|
||||
I (360) app_init: Project name: network_adapter
|
||||
I (365) app_init: App version: qa-test-full-master-esp32c5-202
|
||||
I (372) app_init: Compile time: Aug 30 2024 08:10:15
|
||||
I (378) app_init: ELF file SHA256: 6220fafe8...
|
||||
I (383) app_init: ESP-IDF: v5.4-dev-2600-g1157a27964c-dirt
|
||||
I (390) efuse_init: Min chip rev: v0.0
|
||||
I (395) efuse_init: Max chip rev: v0.99
|
||||
I (400) efuse_init: Chip rev: v0.1
|
||||
I (405) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (412) heap_init: At 4082FCD0 len 0004C940 (306 KiB): RAM
|
||||
I (418) heap_init: At 4087C610 len 00002F54 (11 KiB): RAM
|
||||
I (424) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM
|
||||
I (432) spi_flash: detected chip: generic
|
||||
I (435) spi_flash: flash io: dio
|
||||
I (440) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (447) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (454) coexist: coex firmware version: 8da3f50af
|
||||
I (481) coexist: coexist rom version 5b8dcfa
|
||||
I (481) main_task: Started on CPU0
|
||||
I (481) main_task: Calling app_main()
|
||||
I (482) fg_mcu_slave: *********************************************************************
|
||||
I (491) fg_mcu_slave: ESP-Hosted-MCU Slave FW version :: 0.0.6
|
||||
I (501) fg_mcu_slave: Transport used :: SDIO only
|
||||
I (510) fg_mcu_slave: *********************************************************************
|
||||
I (519) fg_mcu_slave: Supported features are:
|
||||
I (524) fg_mcu_slave: - WLAN over SDIO
|
||||
I (528) h_bt: - BT/BLE
|
||||
I (531) h_bt: - HCI Over SDIO
|
||||
I (535) h_bt: - BLE only
|
||||
I (539) fg_mcu_slave: capabilities: 0xd
|
||||
I (543) fg_mcu_slave: Supported extended features are:
|
||||
I (549) h_bt: - BT/BLE (extended)
|
||||
I (553) fg_mcu_slave: extended capabilities: 0x0
|
||||
I (563) h_bt: ESP Bluetooth MAC addr: 40:4c:ca:5b:a0:8a
|
||||
I (564) BLE_INIT: Using main XTAL as clock source
|
||||
I (574) BLE_INIT: ble controller commit:[7491a85]
|
||||
I (575) BLE_INIT: Bluetooth MAC: 40:4c:ca:5b:a0:8a
|
||||
I (581) phy_init: phy_version 310,dde1ba9,Jun 4 2024,16:38:11
|
||||
I (641) phy: libbtbb version: 04952fd, Jun 4 2024, 16:38:26
|
||||
I (642) SDIO_SLAVE: Using SDIO interface
|
||||
I (642) SDIO_SLAVE: sdio_init: sending mode: SDIO_SLAVE_SEND_STREAM
|
||||
I (648) SDIO_SLAVE: sdio_init: ESP32-C6 SDIO RxQ[20] timing[0]
|
||||
|
||||
I (1155) fg_mcu_slave: Start Data Path
|
||||
I (1165) fg_mcu_slave: Initial set up done
|
||||
I (1165) slave_ctrl: event ESPInit
|
||||
```
|
||||
|
||||
### esp_hosted: Example Output of the master device (ESP32-P4)
|
||||
|
||||
```
|
||||
I (1833) sdio_wrapper: Function 0 Blocksize: 512
|
||||
I (1843) sdio_wrapper: Function 1 Blocksize: 512
|
||||
I (1843) H_SDIO_DRV: SDIO Host operating in STREAMING MODE
|
||||
I (1853) H_SDIO_DRV: generate slave intr
|
||||
I (1863) transport: Received INIT event from ESP32 peripheral
|
||||
I (1873) transport: EVENT: 12
|
||||
I (1873) transport: EVENT: 11
|
||||
I (1873) transport: capabilities: 0xd
|
||||
I (1873) transport: Features supported are:
|
||||
I (1883) transport: * WLAN
|
||||
I (1883) transport: - HCI over SDIO
|
||||
I (1893) transport: - BLE only
|
||||
I (1893) transport: EVENT: 13
|
||||
I (1893) transport: ESP board type is : 13
|
||||
|
||||
I (1903) transport: Base transport is set-up
|
||||
|
||||
I (1903) transport: Slave chip Id[12]
|
||||
I (1913) hci_stub_drv: Host BT Support: Disabled
|
||||
I (1913) H_SDIO_DRV: Received INIT event
|
||||
I (1923) rpc_evt: EVENT: ESP INIT
|
||||
|
||||
I (1923) rpc_wrap: Received Slave ESP Init
|
||||
I (2703) rpc_core: <-- RPC_Req [0x116], uid 1
|
||||
I (2823) rpc_rsp: --> RPC_Resp [0x216], uid 1
|
||||
I (2823) rpc_core: <-- RPC_Req [0x139], uid 2
|
||||
I (2833) rpc_rsp: --> RPC_Resp [0x239], uid 2
|
||||
I (2833) rpc_core: <-- RPC_Req [0x104], uid 3
|
||||
I (2843) rpc_rsp: --> RPC_Resp [0x204], uid 3
|
||||
I (2843) rpc_core: <-- RPC_Req [0x118], uid 4
|
||||
I (2933) rpc_rsp: --> RPC_Resp [0x218], uid 4
|
||||
I (2933) example_connect: Connecting to Cermakowifi...
|
||||
I (2933) rpc_core: <-- RPC_Req [0x11c], uid 5
|
||||
I (2943) rpc_evt: Event [0x2b] received
|
||||
I (2943) rpc_evt: Event [0x2] received
|
||||
I (2953) rpc_evt: EVT rcvd: Wi-Fi Start
|
||||
I (2953) rpc_core: <-- RPC_Req [0x101], uid 6
|
||||
I (2973) rpc_rsp: --> RPC_Resp [0x21c], uid 5
|
||||
I (2973) H_API: esp_wifi_remote_connect
|
||||
I (2973) rpc_core: <-- RPC_Req [0x11a], uid 7
|
||||
I (2983) rpc_rsp: --> RPC_Resp [0x201], uid 6
|
||||
I (3003) rpc_rsp: --> RPC_Resp [0x21a], uid 7
|
||||
I (3003) example_connect: Waiting for IP(s)
|
||||
I (5723) rpc_evt: Event [0x2b] received
|
||||
I (5943) esp_wifi_remote: esp_wifi_internal_reg_rxcb: sta: 0x400309fe
|
||||
0x400309fe: wifi_sta_receive at /home/david/esp/idf/components/esp_wifi/src/wifi_netif.c:38
|
||||
|
||||
I (7573) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:424c:caff:fe5b:a088, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (9943) esp_netif_handlers: example_netif_sta ip: 192.168.0.29, mask: 255.255.255.0, gw: 192.168.0.1
|
||||
I (9943) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.0.29
|
||||
I (9943) example_common: Connected to example_netif_sta
|
||||
I (9953) example_common: - IPv4 address: 192.168.0.29,
|
||||
I (9963) example_common: - IPv6 address: fe80:0000:0000:0000:424c:caff:fe5b:a088, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (9973) mqtt_example: Other event id:7
|
||||
I (9973) main_task: Returned from app_main()
|
||||
I (10253) mqtt_example: MQTT_EVENT_CONNECTED
|
||||
I (10253) mqtt_example: sent publish successful, msg_id=45053
|
||||
I (10253) mqtt_example: sent subscribe successful, msg_id=34643
|
||||
I (10263) mqtt_example: sent subscribe successful, msg_id=2358
|
||||
I (10263) mqtt_example: sent unsubscribe successful, msg_id=57769
|
||||
I (10453) mqtt_example: MQTT_EVENT_PUBLISHED, msg_id=45053
|
||||
I (10603) mqtt_example: MQTT_EVENT_SUBSCRIBED, msg_id=34643
|
||||
I (10603) mqtt_example: sent publish successful, msg_id=0
|
||||
I (10603) mqtt_example: MQTT_EVENT_SUBSCRIBED, msg_id=2358
|
||||
I (10613) mqtt_example: sent publish successful, msg_id=0
|
||||
I (10613) mqtt_example: MQTT_EVENT_UNSUBSCRIBED, msg_id=57769
|
||||
I (10713) mqtt_example: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (10863) mqtt_example: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
||||
|
||||
### <a name="eppp"></a>eppp: Configure master-slave verification
|
||||
|
||||
In order to secure the physical connection between the ESP32-P4 (master) and the slave device, it is necessary to set certificates and keys for each side.
|
||||
To bootstrap this step, you can use one-time generated self-signed RSA keys and certificates running:
|
||||
```
|
||||
./managed_components/espressif__esp_wifi_remote/examples/test_certs/generate_test_certs.sh espressif.local
|
||||
```
|
||||
|
||||
#### eppp: Configure the slave project
|
||||
|
||||
It is recommended to create a new project from `esp_wifi_remote` component's example with
|
||||
```
|
||||
idf.py create-project-from-example "espressif/esp_wifi_remote:server"
|
||||
```
|
||||
but you can also build and flash the slave project directly from the `managed_components` directory using:
|
||||
```
|
||||
idf.py -C managed_components/espressif__esp_wifi_remote/examples/server/ -B build_slave
|
||||
```
|
||||
|
||||
Please follow these steps to setup the slave application:
|
||||
* `idf.py set-target` -- choose the slave target (must support Wi-Fi)
|
||||
* `idf.py menuconfig` -- configure the physical connection and verification details:
|
||||
- `CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA` -- CA for verifying ESP32-P4 application
|
||||
- `CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT` -- slave's certificate
|
||||
- `CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY` -- slave's private key
|
||||
* `idf.py build flash monitor`
|
||||
|
||||
#### eppp: Configure the master project (ESP32-P4)
|
||||
|
||||
similarly to the slave project, we have to configure
|
||||
* the physical connection
|
||||
* the verification
|
||||
- `CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA` -- CA for verifying the slave application
|
||||
- `CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT` -- our own certificate
|
||||
- `CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY` -- our own private key
|
||||
|
||||
After project configuration, you build and flash the board with
|
||||
```
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
### eppp: Example Output of the slave device
|
||||
|
||||
```
|
||||
I (7982) main_task: Returned from app_main()
|
||||
I (8242) rpc_server: Received header id 2
|
||||
I (8242) pp: pp rom version: 5b8dcfa
|
||||
I (8242) net80211: net80211 rom version: 5b8dcfa
|
||||
I (8252) wifi:wifi driver task: 4082be8c, prio:23, stack:6656, core=0
|
||||
I (8252) wifi:wifi firmware version: feaf82d
|
||||
I (8252) wifi:wifi certification version: v7.0
|
||||
I (8252) wifi:config NVS flash: enabled
|
||||
I (8262) wifi:config nano formatting: disabled
|
||||
I (8262) wifi:mac_version:HAL_MAC_ESP32AX_761,ut_version:N, band:0x1
|
||||
I (8272) wifi:Init data frame dynamic rx buffer num: 32
|
||||
I (8272) wifi:Init static rx mgmt buffer num: 5
|
||||
I (8282) wifi:Init management short buffer num: 32
|
||||
I (8282) wifi:Init dynamic tx buffer num: 32
|
||||
I (8292) wifi:Init static tx FG buffer num: 2
|
||||
I (8292) wifi:Init static rx buffer size: 1700 (rxctrl:92, csi:512)
|
||||
I (8302) wifi:Init static rx buffer num: 10
|
||||
I (8302) wifi:Init dynamic rx buffer num: 32
|
||||
I (8302) wifi_init: rx ba win: 6
|
||||
I (8312) wifi_init: accept mbox: 6
|
||||
I (8312) wifi_init: tcpip mbox: 32
|
||||
I (8322) wifi_init: udp mbox: 6
|
||||
I (8322) wifi_init: tcp mbox: 6
|
||||
I (8322) wifi_init: tcp tx win: 5760
|
||||
I (8332) wifi_init: tcp rx win: 5760
|
||||
I (8332) wifi_init: tcp mss: 1440
|
||||
I (8342) wifi_init: WiFi IRAM OP enabled
|
||||
I (8342) wifi_init: WiFi RX IRAM OP enabled
|
||||
I (8352) wifi_init: WiFi SLP IRAM OP enabled
|
||||
I (8362) rpc_server: Received header id 11
|
||||
I (8362) rpc_server: Received header id 4
|
||||
I (8372) rpc_server: Received header id 6
|
||||
I (8372) phy_init: phy_version 270,339aa07,Apr 3 2024,16:36:11
|
||||
I (8492) wifi:enable tsf
|
||||
I (8492) rpc_server: Received WIFI event 41
|
||||
I (8502) rpc_server: Received WIFI event 2
|
||||
I (8732) rpc_server: Received header id 10
|
||||
I (8742) rpc_server: Received header id 5
|
||||
I (8752) rpc_server: Received header id 8
|
||||
I (11452) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1, snd_ch_cfg:0x0
|
||||
I (11452) wifi:(connect)dot11_authmode:0x3, pairwise_cipher:0x3, group_cipher:0x1
|
||||
I (11452) wifi:state: init -> auth (0xb0)
|
||||
I (11462) rpc_server: Received WIFI event 41
|
||||
I (11462) wifi:state: auth -> assoc (0x0)
|
||||
I (11472) wifi:(assoc)RESP, Extended Capabilities length:8, operating_mode_notification:0
|
||||
I (11472) wifi:(assoc)RESP, Extended Capabilities, MBSSID:0, TWT Responder:0, OBSS Narrow Bandwidth RU In OFDMA Tolerance:0
|
||||
I (11482) wifi:Extended Capabilities length:8, operating_mode_notification:1
|
||||
I (11492) wifi:state: assoc -> run (0x10)
|
||||
I (11492) wifi:(trc)phytype:CBW20-SGI, snr:50, maxRate:144, highestRateIdx:0
|
||||
W (11502) wifi:(trc)band:2G, phymode:3, highestRateIdx:0, lowestRateIdx:11, dataSchedTableSize:14
|
||||
I (11512) wifi:(trc)band:2G, rate(S-MCS7, rateIdx:0), ampdu(rate:S-MCS7, schedIdx(0, stop:8)), snr:50, ampduState:wait operational
|
||||
I (11522) wifi:ifidx:0, rssi:-45, nf:-95, phytype(0x3, CBW20-SGI), phymode(0x3, 11bgn), max_rate:144, he:0, vht:0, ht:1
|
||||
I (11532) wifi:(ht)max.RxAMPDULenExponent:3(65535 bytes), MMSS:6(8 us)
|
||||
W (11542) wifi:<ba-add>idx:0, ifx:0, tid:0, TAHI:0x1002cb4, TALO:0x1b942980, (ssn:0, win:64, cur_ssn:0), CONF:0xc0000005
|
||||
I (11572) wifi:connected with Cermakowifi, aid = 2, channel 6, BW20, bssid = 80:29:94:1b:b4:2c
|
||||
I (11572) wifi:cipher(pairwise:0x3, group:0x1), pmf:0, security:WPA2-PSK, phy:11bgn, rssi:-45
|
||||
I (11582) wifi:pm start, type: 1, twt_start:0
|
||||
|
||||
I (11582) wifi:pm start, type:1, aid:0x2, trans-BSSID:80:29:94:1b:b4:2c, BSSID[5]:0x2c, mbssid(max-indicator:0, index:0), he:0
|
||||
I (11592) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
|
||||
I (11602) wifi:set rx beacon pti, rx_bcn_pti: 10, bcn_timeout: 25000, mt_pti: 10, mt_time: 10000
|
||||
I (11612) wifi:[ADDBA]TX addba request, tid:0, dialogtoken:1, bufsize:64, A-MSDU:0(not supported), policy:1(IMR), ssn:0(0x0)
|
||||
I (11622) wifi:[ADDBA]TX addba request, tid:7, dialogtoken:2, bufsize:64, A-MSDU:0(not supported), policy:1(IMR), ssn:0(0x20)
|
||||
I (11632) wifi:[ADDBA]TX addba request, tid:5, dialogtoken:3, bufsize:64, A-MSDU:0(not supported), policy:1(IMR), ssn:0(0x0)
|
||||
I (11642) wifi:[ADDBA]RX addba response, status:0, tid:7/tb:0(0x1), bufsize:64, batimeout:0, txa_wnd:64
|
||||
I (11652) wifi:[ADDBA]RX addba response, status:0, tid:5/tb:0(0x1), bufsize:64, batimeout:0, txa_wnd:64
|
||||
I (11662) wifi:[ADDBA]RX addba response, status:0, tid:0/tb:1(0x1), bufsize:64, batimeout:0, txa_wnd:64
|
||||
I (11672) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (11682) rpc_server: Received WIFI event 4
|
||||
I (15682) esp_netif_handlers: sta ip: 192.168.0.33, mask: 255.255.255.0, gw: 192.168.0.1
|
||||
I (15682) rpc_server: Received IP event 0
|
||||
I (15682) rpc_server: Main DNS:185.162.24.55
|
||||
I (15682) rpc_server: IP address:192.168.0.33
|
||||
```
|
||||
|
||||
### eppp: Example Output of the master device (ESP32-P4)
|
||||
|
||||
```
|
||||
I (445) example_connect: Start example_connect.
|
||||
I (455) uart: queue free spaces: 16
|
||||
I (455) eppp_link: Waiting for IP address 0
|
||||
I (3195) esp-netif_lwip-ppp: Connected
|
||||
I (3195) eppp_link: Got IPv4 event: Interface "pppos_client(EPPP0)" address: 192.168.11.2
|
||||
I (3195) esp-netif_lwip-ppp: Connected
|
||||
I (3195) eppp_link: Connected! 0
|
||||
I (5475) example_connect: Waiting for IP(s)
|
||||
I (8405) esp_wifi_remote: esp_wifi_internal_reg_rxcb: sta: 0x4001c68a
|
||||
I (9445) example_connect: Got IPv6 event: Interface "pppos_client" address: fe80:0000:0000:0000:5632:04ff:fe08:5054, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (12415) rpc_client: Main DNS:185.162.24.55
|
||||
I (12415) esp_netif_handlers: pppos_client ip: 192.168.11.2, mask: 255.255.255.255, gw: 192.168.11.1
|
||||
I (12415) rpc_client: EPPP IP:192.168.11.1
|
||||
I (12415) example_connect: Got IPv4 event: Interface "pppos_client" address: 192.168.11.2
|
||||
I (12425) rpc_client: WIFI IP:192.168.0.33
|
||||
I (12435) example_common: Connected to pppos_client
|
||||
I (12445) rpc_client: WIFI GW:192.168.0.1
|
||||
I (12455) example_common: - IPv6 address: fe80:0000:0000:0000:5632:04ff:fe08:5054, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (12455) rpc_client: WIFI mask:255.255.255.0
|
||||
I (12465) example_common: Connected to pppos_client
|
||||
I (12475) example_common: - IPv4 address: 192.168.11.2,
|
||||
I (12475) example_common: - IPv6 address: fe80:0000:0000:0000:5c3b:1291:05ca:6dc8, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (12495) mqtt_example: Other event id:7
|
||||
I (12495) main_task: Returned from app_main()
|
||||
I (12905) mqtt_example: MQTT_EVENT_CONNECTED
|
||||
I (12905) mqtt_example: sent publish successful, msg_id=36013
|
||||
I (12905) mqtt_example: sent subscribe successful, msg_id=44233
|
||||
I (12905) mqtt_example: sent subscribe successful, msg_id=36633
|
||||
I (12915) mqtt_example: sent unsubscribe successful, msg_id=15480
|
||||
I (13115) mqtt_example: MQTT_EVENT_PUBLISHED, msg_id=36013
|
||||
I (13415) mqtt_example: MQTT_EVENT_SUBSCRIBED, msg_id=44233
|
||||
I (13415) mqtt_example: sent publish successful, msg_id=0
|
||||
I (13415) mqtt_example: MQTT_EVENT_SUBSCRIBED, msg_id=36633
|
||||
I (13415) mqtt_example: sent publish successful, msg_id=0
|
||||
I (13425) mqtt_example: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos1
|
||||
DATA=data_3
|
||||
I (13435) mqtt_example: MQTT_EVENT_UNSUBSCRIBED, msg_id=15480
|
||||
I (13615) mqtt_example: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (13925) mqtt_example: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
```
|
3
examples/tcp/main/CMakeLists.txt
Normal file
3
examples/tcp/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt nvs_flash esp_netif
|
||||
INCLUDE_DIRS ".")
|
13
examples/tcp/main/Kconfig.projbuild
Normal file
13
examples/tcp/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,13 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URL
|
||||
string "Broker URL"
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL of the broker to connect to
|
||||
|
||||
config BROKER_URL_FROM_STDIN
|
||||
bool
|
||||
default y if BROKER_URL = "FROM_STDIN"
|
||||
|
||||
endmenu
|
162
examples/tcp/main/app_main.c
Normal file
162
examples/tcp/main/app_main.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/* MQTT (over TCP) Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static const char *TAG = "mqtt_example";
|
||||
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0) {
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, return code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_BROKER_URL,
|
||||
};
|
||||
#if CONFIG_BROKER_URL_FROM_STDIN
|
||||
char line[128];
|
||||
|
||||
if (strcmp(mqtt_cfg.broker.address.uri, "FROM_STDIN") == 0) {
|
||||
int count = 0;
|
||||
printf("Please enter url of mqtt broker\n");
|
||||
while (count < 128) {
|
||||
int c = fgetc(stdin);
|
||||
if (c == '\n') {
|
||||
line[count] = '\0';
|
||||
break;
|
||||
} else if (c > 0 && c < 127) {
|
||||
line[count] = c;
|
||||
++count;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
mqtt_cfg.broker.address.uri = line;
|
||||
printf("Broker url: %s\n", line);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");
|
||||
abort();
|
||||
}
|
||||
#endif /* CONFIG_BROKER_URL_FROM_STDIN */
|
||||
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
7
examples/tcp/main/idf_component.yml
Normal file
7
examples/tcp/main/idf_component.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
espressif/esp_wifi_remote:
|
||||
version: ">=0.10,<2.0"
|
||||
rules:
|
||||
- if: "target in [esp32p4, esp32h2]"
|
97
examples/tcp/pytest_mqtt_tcp.py
Normal file
97
examples/tcp/pytest_mqtt_tcp.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from common_test_methods import get_host_ip4_by_dest_ip
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
msgid = -1
|
||||
|
||||
|
||||
def mqqt_server_sketch(my_ip, port): # type: (str, str) -> None
|
||||
global msgid
|
||||
print('Starting the server on {}'.format(my_ip))
|
||||
s = None
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(60)
|
||||
s.bind((my_ip, port))
|
||||
s.listen(1)
|
||||
q, addr = s.accept()
|
||||
q.settimeout(30)
|
||||
print('connection accepted')
|
||||
except Exception:
|
||||
print(
|
||||
'Local server on {}:{} listening/accepting failure: {}'
|
||||
'Possibly check permissions or firewall settings'
|
||||
'to accept connections on this address'.format(my_ip, port, sys.exc_info()[0])
|
||||
)
|
||||
raise
|
||||
data = q.recv(1024)
|
||||
# check if received initial empty message
|
||||
print('received from client {!r}'.format(data))
|
||||
data = bytearray([0x20, 0x02, 0x00, 0x00])
|
||||
q.send(data)
|
||||
# try to receive qos1
|
||||
data = q.recv(1024)
|
||||
msgid = struct.unpack('>H', data[15:17])[0]
|
||||
print('received from client {!r}, msgid: {}'.format(data, msgid))
|
||||
data = bytearray([0x40, 0x02, data[15], data[16]])
|
||||
q.send(data)
|
||||
time.sleep(5)
|
||||
s.close()
|
||||
print('server closed')
|
||||
|
||||
|
||||
@pytest.mark.ethernet
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_examples_protocol_mqtt_qos1(dut: Dut) -> None:
|
||||
global msgid
|
||||
"""
|
||||
steps: (QoS1: Happy flow)
|
||||
1. start the broker broker (with correctly sending ACK)
|
||||
2. DUT client connects to a broker and publishes qos1 message
|
||||
3. Test evaluates that qos1 message is queued and removed from queued after ACK received
|
||||
4. Test the broker received the same message id evaluated in step 3
|
||||
"""
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'mqtt_tcp.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('[Performance][mqtt_tcp_bin_size]: %s KB', bin_size // 1024)
|
||||
# waiting for getting the IP address
|
||||
try:
|
||||
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)', timeout=30).group(1).decode()
|
||||
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
|
||||
except pexpect.TIMEOUT:
|
||||
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
|
||||
|
||||
# 2. start mqtt broker sketch
|
||||
host_ip = get_host_ip4_by_dest_ip(ip_address)
|
||||
thread1 = Thread(target=mqqt_server_sketch, args=(host_ip, 1883))
|
||||
thread1.start()
|
||||
|
||||
data_write = 'mqtt://' + host_ip
|
||||
print('writing to device: {}'.format(data_write))
|
||||
dut.write(data_write)
|
||||
thread1.join()
|
||||
print('Message id received from server: {}'.format(msgid))
|
||||
# 3. check the message id was enqueued and then deleted
|
||||
msgid_enqueued = dut.expect(b'outbox: ENQUEUE msgid=([0-9]+)', timeout=30).group(1).decode()
|
||||
msgid_deleted = dut.expect(b'outbox: DELETED msgid=([0-9]+)', timeout=30).group(1).decode()
|
||||
# 4. check the msgid of received data are the same as that of enqueued and deleted from outbox
|
||||
if msgid_enqueued == str(msgid) and msgid_deleted == str(msgid):
|
||||
print('PASS: Received correct msg id')
|
||||
else:
|
||||
print('Failure!')
|
||||
raise ValueError(
|
||||
'Mismatch of msgid: received: {}, enqueued {}, deleted {}'.format(msgid, msgid_enqueued, msgid_deleted)
|
||||
)
|
13
examples/tcp/sdkconfig.ci
Normal file
13
examples/tcp/sdkconfig.ci
Normal file
@@ -0,0 +1,13 @@
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_BROKER_URL="FROM_STDIN"
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_LWIP_TCPIP_CORE_LOCKING=y
|
||||
CONFIG_LWIP_CHECK_THREAD_SAFETY=y
|
5
examples/tcp/sdkconfig.ci.p4_eppp
Normal file
5
examples/tcp/sdkconfig.ci.p4_eppp
Normal file
@@ -0,0 +1,5 @@
|
||||
CONFIG_IDF_TARGET="esp32p4"
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=y
|
||||
CONFIG_ESP_WIFI_REMOTE_LIBRARY_EPPP=y
|
||||
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN=17
|
||||
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN=16
|
3
examples/tcp/sdkconfig.ci.p4_wifi
Normal file
3
examples/tcp/sdkconfig.ci.p4_wifi
Normal file
@@ -0,0 +1,3 @@
|
||||
CONFIG_IDF_TARGET="esp32p4"
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=y
|
||||
CONFIG_ESP_WIFI_REMOTE_LIBRARY_HOSTED=y
|
3
examples/tcp/sdkconfig.ci.ppp_connect
Normal file
3
examples/tcp/sdkconfig.ci.ppp_connect
Normal file
@@ -0,0 +1,3 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_PPP=y
|
||||
CONFIG_EXAMPLE_CONNECT_PPP_DEVICE_UART=y
|
9
examples/ws/CMakeLists.txt
Normal file
9
examples/ws/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_websocket)
|
61
examples/ws/README.md
Normal file
61
examples/ws/README.md
Normal file
@@ -0,0 +1,61 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT MQTT over Websocket
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example connects to the broker mqtt.eclipseprojects.io over web sockets as a demonstration subscribes/unsubscribes and send a message on certain topic.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes))
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
|
||||
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
|
||||
I (4164) MQTTWS_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (4174) MQTTWS_EXAMPLE: sent publish successful, msg_id=41464
|
||||
I (4174) MQTTWS_EXAMPLE: sent subscribe successful, msg_id=17886
|
||||
I (4174) MQTTWS_EXAMPLE: sent subscribe successful, msg_id=42970
|
||||
I (4184) MQTTWS_EXAMPLE: sent unsubscribe successful, msg_id=50241
|
||||
I (4314) MQTTWS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
|
||||
I (4484) MQTTWS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
|
||||
I (4484) MQTTWS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4684) MQTTWS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
|
||||
I (4684) MQTTWS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (4884) MQTTWS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (5194) MQTTWS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
||||
|
3
examples/ws/main/CMakeLists.txt
Normal file
3
examples/ws/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt esp_wifi nvs_flash
|
||||
INCLUDE_DIRS ".")
|
9
examples/ws/main/Kconfig.projbuild
Normal file
9
examples/ws/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,9 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URI
|
||||
string "Broker URL"
|
||||
default "ws://mqtt.eclipseprojects.io:80/mqtt"
|
||||
help
|
||||
URL of an mqtt broker which this example connects to.
|
||||
|
||||
endmenu
|
144
examples/ws/main/app_main.c
Normal file
144
examples/ws/main/app_main.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/* MQTT over Websockets Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static const char *TAG = "mqttws_example";
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0) {
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, return code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_BROKER_URI,
|
||||
};
|
||||
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_ws", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
3
examples/ws/main/idf_component.yml
Normal file
3
examples/ws/main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
108
examples/ws/pytest_mqtt_ws_example.py
Normal file
108
examples/ws/pytest_mqtt_ws_example.py
Normal file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from threading import Event
|
||||
from threading import Thread
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
event_client_connected = Event()
|
||||
event_stop_client = Event()
|
||||
event_client_received_correct = Event()
|
||||
message_log = ''
|
||||
|
||||
|
||||
# The callback for when the client receives a CONNACK response from the server.
|
||||
def on_connect(client, userdata, flags, rc): # type: (mqtt.Client, tuple, bool, str) -> None
|
||||
_ = (userdata, flags)
|
||||
print('Connected with result code ' + str(rc))
|
||||
event_client_connected.set()
|
||||
client.subscribe('/topic/qos0')
|
||||
|
||||
|
||||
def mqtt_client_task(client): # type: (mqtt.Client) -> None
|
||||
while not event_stop_client.is_set():
|
||||
client.loop()
|
||||
|
||||
|
||||
# The callback for when a PUBLISH message is received from the server.
|
||||
def on_message(client, userdata, msg): # type: (mqtt.Client, tuple, mqtt.client.MQTTMessage) -> None
|
||||
_ = userdata
|
||||
global message_log
|
||||
payload = msg.payload.decode()
|
||||
if not event_client_received_correct.is_set() and payload == 'data':
|
||||
client.publish('/topic/qos0', 'data_to_esp32')
|
||||
if msg.topic == '/topic/qos0' and payload == 'data':
|
||||
event_client_received_correct.set()
|
||||
message_log += 'Received data:' + msg.topic + ' ' + payload + '\n'
|
||||
|
||||
|
||||
@pytest.mark.ethernet
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_examples_protocol_mqtt_ws(dut): # type: (Dut) -> None
|
||||
broker_url = ''
|
||||
broker_port = 0
|
||||
"""
|
||||
steps: |
|
||||
1. join AP and connects to ws broker
|
||||
2. Test connects a client to the same broker
|
||||
3. Test evaluates it received correct qos0 message
|
||||
4. Test ESP32 client received correct qos0 message
|
||||
"""
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'mqtt_websocket.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('[Performance][mqtt_websocket_bin_size]: %s KB', bin_size // 1024)
|
||||
# Look for host:port in sdkconfig
|
||||
try:
|
||||
value = re.search(r'\:\/\/([^:]+)\:([0-9]+)', dut.app.sdkconfig.get('BROKER_URI'))
|
||||
assert value is not None
|
||||
broker_url = value.group(1)
|
||||
broker_port = int(value.group(2))
|
||||
except Exception:
|
||||
print('ENV_TEST_FAILURE: Cannot find broker url in sdkconfig')
|
||||
raise
|
||||
client = None
|
||||
# 1. Test connects to a broker
|
||||
try:
|
||||
client = mqtt.Client(transport='websockets')
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
print('Connecting...')
|
||||
client.connect(broker_url, broker_port, 60)
|
||||
except Exception:
|
||||
print(
|
||||
'ENV_TEST_FAILURE: Unexpected error while connecting to broker {}: {}:'.format(
|
||||
broker_url, sys.exc_info()[0]
|
||||
)
|
||||
)
|
||||
raise
|
||||
# Starting a py-client in a separate thread
|
||||
thread1 = Thread(target=mqtt_client_task, args=(client,))
|
||||
thread1.start()
|
||||
try:
|
||||
print('Connecting py-client to broker {}:{}...'.format(broker_url, broker_port))
|
||||
if not event_client_connected.wait(timeout=30):
|
||||
raise ValueError('ENV_TEST_FAILURE: Test script cannot connect to broker: {}'.format(broker_url))
|
||||
try:
|
||||
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[0]
|
||||
print('Connected to AP with IP: {}'.format(ip_address))
|
||||
except Dut.ExpectTimeout:
|
||||
print('ENV_TEST_FAILURE: Cannot connect to AP')
|
||||
raise
|
||||
print('Checking py-client received msg published from esp...')
|
||||
if not event_client_received_correct.wait(timeout=30):
|
||||
raise ValueError('Wrong data received, msg log: {}'.format(message_log))
|
||||
print('Checking esp-client received msg published from py-client...')
|
||||
dut.expect(r'DATA=data_to_esp32', timeout=30)
|
||||
finally:
|
||||
event_stop_client.set()
|
||||
thread1.join()
|
11
examples/ws/sdkconfig.ci
Normal file
11
examples/ws/sdkconfig.ci
Normal file
@@ -0,0 +1,11 @@
|
||||
CONFIG_BROKER_URI="ws://${EXAMPLE_MQTT_BROKER_WS}/ws"
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_LWIP_CHECK_THREAD_SAFETY=y
|
11
examples/wss/CMakeLists.txt
Normal file
11
examples/wss/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(mqtt_websocket_secure)
|
||||
|
||||
target_add_binary_data(${PROJECT_NAME}.elf "main/mqtt_eclipseprojects_io.pem" TEXT)
|
73
examples/wss/README.md
Normal file
73
examples/wss/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT MQTT over WSS Sample application
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example connects to the broker mqtt.eclipseprojects.io over secure websockets and as a demonstration subscribes/unsubscribes and send a message on certain topic.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes))
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
Note how to create a PEM certificate for mqtt.eclipseprojects.io:
|
||||
|
||||
PEM certificate for this example could be extracted from an openssl `s_client` command connecting to mqtt.eclipseprojects.io.
|
||||
In case a host operating system has `openssl` and `sed` packages installed, one could execute the following command to download and save the root certificate to a file (Note for Windows users: Both Linux like environment or Windows native packages may be used).
|
||||
```
|
||||
echo "" | openssl s_client -showcerts -connect mqtt.eclipseprojects.io:443 | sed -n "1,/Root/d; /BEGIN/,/END/p" | openssl x509 -outform PEM >mqtt_eclipse_org.pem
|
||||
```
|
||||
Please note that this is not a general command for downloading a root certificate for an arbitrary host;
|
||||
this command works with mqtt.eclipseprojects.io as the site provides root certificate in the chain, which then could be extracted
|
||||
with text operation.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
|
||||
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
|
||||
I (4164) MQTTWSS_EXAMPLE: MQTT_EVENT_CONNECTED
|
||||
I (4174) MQTTWSS_EXAMPLE: sent publish successful, msg_id=41464
|
||||
I (4174) MQTTWSS_EXAMPLE: sent subscribe successful, msg_id=17886
|
||||
I (4174) MQTTWSS_EXAMPLE: sent subscribe successful, msg_id=42970
|
||||
I (4184) MQTTWSS_EXAMPLE: sent unsubscribe successful, msg_id=50241
|
||||
I (4314) MQTTWSS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
|
||||
I (4484) MQTTWSS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
|
||||
I (4484) MQTTWSS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4684) MQTTWSS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
|
||||
I (4684) MQTTWSS_EXAMPLE: sent publish successful, msg_id=0
|
||||
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (4884) MQTTWSS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
|
||||
I (5194) MQTTWSS_EXAMPLE: MQTT_EVENT_DATA
|
||||
TOPIC=/topic/qos0
|
||||
DATA=data
|
||||
```
|
||||
|
||||
|
||||
|
3
examples/wss/main/CMakeLists.txt
Normal file
3
examples/wss/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
PRIV_REQUIRES mqtt esp_wifi nvs_flash
|
||||
INCLUDE_DIRS ".")
|
20
examples/wss/main/Kconfig.projbuild
Normal file
20
examples/wss/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,20 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URI
|
||||
string "Broker URL"
|
||||
default "wss://mqtt.eclipseprojects.io:443/mqtt"
|
||||
help
|
||||
URL of an mqtt broker which this example connects to.
|
||||
|
||||
config BROKER_CERTIFICATE_OVERRIDE
|
||||
string "Server certificate override"
|
||||
default ""
|
||||
help
|
||||
Please leave empty if server certificate included from a textfile; otherwise fill in a base64 part of PEM
|
||||
format certificate
|
||||
|
||||
config BROKER_CERTIFICATE_OVERRIDDEN
|
||||
bool
|
||||
default y if BROKER_CERTIFICATE_OVERRIDE != ""
|
||||
|
||||
endmenu
|
135
examples/wss/main/app_main.c
Normal file
135
examples/wss/main/app_main.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/* MQTT over Secure Websockets Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static const char *TAG = "mqttwss_example";
|
||||
|
||||
|
||||
#if CONFIG_BROKER_CERTIFICATE_OVERRIDDEN == 1
|
||||
static const uint8_t mqtt_eclipseprojects_io_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
|
||||
#else
|
||||
extern const uint8_t mqtt_eclipseprojects_io_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start");
|
||||
#endif
|
||||
extern const uint8_t mqtt_eclipseprojects_io_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end");
|
||||
|
||||
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
|
||||
{
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
// your_context_t *context = event->context;
|
||||
switch (event->event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, return code=0x%02x ", event->msg_id, (uint8_t)*event->data);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
/* The argument passed to esp_mqtt_client_register_event can de accessed as handler_args*/
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
|
||||
mqtt_event_handler_cb(event_data);
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_BROKER_URI,
|
||||
.broker.verification.certificate = (const char *)mqtt_eclipseprojects_io_pem_start,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
3
examples/wss/main/idf_component.yml
Normal file
3
examples/wss/main/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
30
examples/wss/main/mqtt_eclipseprojects_io.pem
Normal file
30
examples/wss/main/mqtt_eclipseprojects_io.pem
Normal file
@@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
|
||||
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
|
||||
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
|
||||
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
|
||||
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
|
||||
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
|
||||
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
|
||||
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
|
||||
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
|
||||
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
|
||||
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
|
||||
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
|
||||
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
|
||||
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
|
||||
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
|
||||
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
|
||||
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
|
||||
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
|
||||
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
|
||||
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
|
||||
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
|
||||
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
|
||||
nLRbwHOoq7hHwg==
|
||||
-----END CERTIFICATE-----
|
111
examples/wss/pytest_mqtt_wss_example.py
Normal file
111
examples/wss/pytest_mqtt_wss_example.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import ssl
|
||||
import sys
|
||||
from threading import Event
|
||||
from threading import Thread
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import pexpect
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
event_client_connected = Event()
|
||||
event_stop_client = Event()
|
||||
event_client_received_correct = Event()
|
||||
message_log = ''
|
||||
|
||||
|
||||
# The callback for when the client receives a CONNACK response from the server.
|
||||
def on_connect(client, userdata, flags, rc): # type: (mqtt.Client, tuple, bool, str) -> None
|
||||
_ = (userdata, flags)
|
||||
print('Connected with result code ' + str(rc))
|
||||
event_client_connected.set()
|
||||
client.subscribe('/topic/qos0')
|
||||
|
||||
|
||||
def mqtt_client_task(client): # type: (mqtt.Client) -> None
|
||||
while not event_stop_client.is_set():
|
||||
client.loop()
|
||||
|
||||
|
||||
# The callback for when a PUBLISH message is received from the server.
|
||||
def on_message(client, userdata, msg): # type: (mqtt.Client, tuple, mqtt.client.MQTTMessage) -> None
|
||||
_ = userdata
|
||||
global message_log
|
||||
payload = msg.payload.decode()
|
||||
if not event_client_received_correct.is_set() and payload == 'data':
|
||||
client.publish('/topic/qos0', 'data_to_esp32')
|
||||
if msg.topic == '/topic/qos0' and payload == 'data':
|
||||
event_client_received_correct.set()
|
||||
message_log += 'Received data:' + msg.topic + ' ' + payload + '\n'
|
||||
|
||||
|
||||
@pytest.mark.ethernet
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_examples_protocol_mqtt_wss(dut): # type: (Dut) -> None
|
||||
broker_url = ''
|
||||
broker_port = 0
|
||||
"""
|
||||
steps: |
|
||||
1. join AP and connects to wss broker
|
||||
2. Test connects a client to the same broker
|
||||
3. Test evaluates it received correct qos0 message
|
||||
4. Test ESP32 client received correct qos0 message
|
||||
"""
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'mqtt_websocket_secure.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('[Performance][mqtt_websocket_secure_bin_size]: %s KB', bin_size // 1024)
|
||||
# Look for host:port in sdkconfig
|
||||
try:
|
||||
value = re.search(r'\:\/\/([^:]+)\:([0-9]+)', dut.app.sdkconfig.get('BROKER_URI'))
|
||||
assert value is not None
|
||||
broker_url = value.group(1)
|
||||
broker_port = int(value.group(2))
|
||||
except Exception:
|
||||
print('ENV_TEST_FAILURE: Cannot find broker url in sdkconfig')
|
||||
raise
|
||||
client = None
|
||||
# 1. Test connects to a broker
|
||||
try:
|
||||
client = mqtt.Client(transport='websockets')
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
client.tls_set(None, None, None, cert_reqs=ssl.CERT_NONE, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
|
||||
print('Connecting...')
|
||||
client.connect(broker_url, broker_port, 60)
|
||||
except Exception:
|
||||
print(
|
||||
'ENV_TEST_FAILURE: Unexpected error while connecting to broker {}: {}:'.format(
|
||||
broker_url, sys.exc_info()[0]
|
||||
)
|
||||
)
|
||||
raise
|
||||
# Starting a py-client in a separate thread
|
||||
thread1 = Thread(target=mqtt_client_task, args=(client,))
|
||||
thread1.start()
|
||||
try:
|
||||
print('Connecting py-client to broker {}:{}...'.format(broker_url, broker_port))
|
||||
if not event_client_connected.wait(timeout=30):
|
||||
raise ValueError('ENV_TEST_FAILURE: Test script cannot connect to broker: {}'.format(broker_url))
|
||||
try:
|
||||
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[0]
|
||||
print('Connected to AP with IP: {}'.format(ip_address))
|
||||
except pexpect.TIMEOUT:
|
||||
print('ENV_TEST_FAILURE: Cannot connect to AP')
|
||||
raise
|
||||
print('Checking py-client received msg published from esp...')
|
||||
if not event_client_received_correct.wait(timeout=30):
|
||||
raise ValueError('Wrong data received, msg log: {}'.format(message_log))
|
||||
print('Checking esp-client received msg published from py-client...')
|
||||
dut.expect(r'DATA=data_to_esp32', timeout=30)
|
||||
finally:
|
||||
event_stop_client.set()
|
||||
thread1.join()
|
13
examples/wss/sdkconfig.ci
Normal file
13
examples/wss/sdkconfig.ci
Normal file
@@ -0,0 +1,13 @@
|
||||
CONFIG_BROKER_URI="wss://${EXAMPLE_MQTT_BROKER_WSS}/ws"
|
||||
CONFIG_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}"
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_LWIP_TCPIP_CORE_LOCKING=y
|
||||
CONFIG_LWIP_CHECK_THREAD_SAFETY=y
|
19
test/.build-test-rules.yml
Normal file
19
test/.build-test-rules.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/mqtt/test_apps:
|
||||
disable:
|
||||
- if: IDF_TARGET not in ["esp32", "esp32c3"]
|
||||
reason: component test apps, needn't build all targets (chosen two, one for each architecture)
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
temporary: false
|
||||
reason: Only esp32 target has ethernet runners
|
||||
depends_components:
|
||||
- mqtt
|
||||
- tcp_transport
|
||||
- app_update
|
||||
- esp_eth
|
||||
- esp_netif
|
||||
- esp_event
|
||||
depends_filepatterns:
|
||||
- components/mqtt/test_apps/common/**/*
|
10
test/apps/build_test/CMakeLists.txt
Normal file
10
test/apps/build_test/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mqtt_tcp)
|
6
test/apps/build_test/README.md
Normal file
6
test/apps/build_test/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Build only test for C++
|
||||
|
||||
This test app ensures that calling all mqtt-client API could be called from C++
|
3
test/apps/build_test/main/CMakeLists.txt
Normal file
3
test/apps/build_test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "mqtt_app.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
101
test/apps/build_test/main/mqtt_app.cpp
Normal file
101
test/apps/build_test/main/mqtt_app.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Build only example to check mqtt client API from C++
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
static const char *TAG = "mqtt_example";
|
||||
|
||||
|
||||
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
|
||||
{
|
||||
switch (event->event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
|
||||
mqtt_event_handler_cb((esp_mqtt_event_handle_t)event_data);
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
esp_mqtt_client_config_t mqtt_cfg = { };
|
||||
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, client);
|
||||
esp_mqtt_client_start(client);
|
||||
esp_mqtt_set_config(client, &mqtt_cfg);
|
||||
int msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "mqtt api returned %d", msg_id);
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "mqtt api returned %d", msg_id);
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "mqtt api returned %d", msg_id);
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "mqtt api returned %d", msg_id);
|
||||
esp_err_t err = esp_mqtt_client_set_uri(client, "mqtt://localhost:1883");
|
||||
ESP_LOGI(TAG, "mqtt api returned %d", err);
|
||||
err = esp_mqtt_client_reconnect(client);
|
||||
err = esp_mqtt_client_disconnect(client);
|
||||
err = esp_mqtt_client_stop(client);
|
||||
err = esp_mqtt_client_destroy(client);
|
||||
}
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_tcp", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_ssl", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
mqtt_app_start();
|
||||
}
|
4
test/apps/common/CMakeLists.txt
Normal file
4
test/apps/common/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
idf_component_register(SRCS test_mqtt_connection.c
|
||||
INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/include
|
||||
PRIV_REQUIRES unity esp_event esp_netif esp_eth)
|
18
test/apps/common/include/test_mqtt_connection.h
Normal file
18
test/apps/common/include/test_mqtt_connection.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
/**
|
||||
* Connection test fixture setup, so we expect the broker is available
|
||||
* on network
|
||||
*/
|
||||
void connect_test_fixture_setup(void);
|
||||
|
||||
/**
|
||||
* Cleans up the connection
|
||||
*/
|
||||
void connect_test_fixture_teardown(void);
|
144
test/apps/common/test_mqtt_connection.c
Normal file
144
test/apps/common/test_mqtt_connection.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
#if SOC_EMAC_SUPPORTED
|
||||
#define ETH_START_BIT BIT(0)
|
||||
#define ETH_STOP_BIT BIT(1)
|
||||
#define ETH_CONNECT_BIT BIT(2)
|
||||
#define ETH_GOT_IP_BIT BIT(3)
|
||||
#define ETH_STOP_TIMEOUT_MS (10000)
|
||||
#define ETH_GET_IP_TIMEOUT_MS (60000)
|
||||
|
||||
|
||||
static const char *TAG = "esp32_eth_test_fixture";
|
||||
static EventGroupHandle_t s_eth_event_group = NULL;
|
||||
static esp_netif_t *s_eth_netif = NULL;
|
||||
static esp_eth_mac_t *s_mac = NULL;
|
||||
static esp_eth_phy_t *s_phy = NULL;
|
||||
static esp_eth_handle_t s_eth_handle = NULL;
|
||||
static esp_eth_netif_glue_handle_t s_eth_glue = NULL;
|
||||
|
||||
|
||||
/** Event handler for Ethernet events */
|
||||
static void eth_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
xEventGroupSetBits(eth_event_group, ETH_CONNECT_BIT);
|
||||
ESP_LOGI(TAG, "Ethernet Link Up");
|
||||
break;
|
||||
case ETHERNET_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Down");
|
||||
break;
|
||||
case ETHERNET_EVENT_START:
|
||||
xEventGroupSetBits(eth_event_group, ETH_START_BIT);
|
||||
ESP_LOGI(TAG, "Ethernet Started");
|
||||
break;
|
||||
case ETHERNET_EVENT_STOP:
|
||||
xEventGroupSetBits(eth_event_group, ETH_STOP_BIT);
|
||||
ESP_LOGI(TAG, "Ethernet Stopped");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Event handler for IP_EVENT_ETH_GOT_IP */
|
||||
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
ESP_LOGI(TAG, "Ethernet Got IP Address");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
|
||||
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
|
||||
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
xEventGroupSetBits(eth_event_group, ETH_GOT_IP_BIT);
|
||||
}
|
||||
|
||||
static esp_err_t test_uninstall_driver(esp_eth_handle_t eth_hdl, uint32_t ms_to_wait)
|
||||
{
|
||||
int i = 0;
|
||||
ms_to_wait += 100;
|
||||
for (i = 0; i < ms_to_wait / 100; i++) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
if (esp_eth_driver_uninstall(eth_hdl) == ESP_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < ms_to_wait / 10) {
|
||||
return ESP_OK;
|
||||
} else {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void connect_test_fixture_setup(void)
|
||||
{
|
||||
EventBits_t bits;
|
||||
s_eth_event_group = xEventGroupCreate();
|
||||
TEST_ASSERT(s_eth_event_group != NULL);
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
// create TCP/IP netif
|
||||
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
|
||||
s_eth_netif = esp_netif_new(&netif_cfg);
|
||||
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
|
||||
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
s_phy = esp_eth_phy_new_ip101(&phy_config);
|
||||
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
|
||||
|
||||
// install Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_driver_install(ð_config, &s_eth_handle));
|
||||
// combine driver with netif
|
||||
s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
|
||||
TEST_ESP_OK(esp_netif_attach(s_eth_netif, s_eth_glue));
|
||||
// register user defined event handlers
|
||||
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, s_eth_event_group));
|
||||
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, s_eth_event_group));
|
||||
// start Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_start(s_eth_handle));
|
||||
/* wait for IP lease */
|
||||
bits = xEventGroupWaitBits(s_eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT);
|
||||
}
|
||||
|
||||
void connect_test_fixture_teardown(void)
|
||||
{
|
||||
EventBits_t bits;
|
||||
// stop Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_stop(s_eth_handle));
|
||||
/* wait for connection stop */
|
||||
bits = xEventGroupWaitBits(s_eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
|
||||
TEST_ESP_OK(esp_eth_del_netif_glue(s_eth_glue));
|
||||
/* driver should be uninstalled within 2 seconds */
|
||||
TEST_ESP_OK(test_uninstall_driver(s_eth_handle, 2000));
|
||||
TEST_ESP_OK(s_phy->del(s_phy));
|
||||
TEST_ESP_OK(s_mac->del(s_mac));
|
||||
TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));
|
||||
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
|
||||
esp_netif_destroy(s_eth_netif);
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
vEventGroupDelete(s_eth_event_group);
|
||||
}
|
||||
#endif // SOC_EMAC_SUPPORTED
|
9
test/apps/mqtt/CMakeLists.txt
Normal file
9
test/apps/mqtt/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
#This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
|
||||
"../common")
|
||||
|
||||
set(COMPONENTS main)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp_mqtt_client_test)
|
2
test/apps/mqtt/README.md
Normal file
2
test/apps/mqtt/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- |
|
8
test/apps/mqtt/main/CMakeLists.txt
Normal file
8
test/apps/mqtt/main/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
set(srcs test_mqtt_client_broker.c test_mqtt.c)
|
||||
|
||||
if(CONFIG_MQTT_PROTOCOL_5)
|
||||
list(APPEND srcs test_mqtt5_client_broker.c test_mqtt5.c)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common)
|
14
test/apps/mqtt/main/Kconfig.projbuild
Normal file
14
test/apps/mqtt/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,14 @@
|
||||
menu "ESP-MQTT Unit Test Config"
|
||||
|
||||
config MQTT_TEST_BROKER_URI
|
||||
string "URI of the test broker"
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL of an mqtt broker which this test connects to.
|
||||
|
||||
config MQTT5_TEST_BROKER_URI
|
||||
string "URI of the test broker"
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL of an mqtt broker which this test connects to.
|
||||
endmenu
|
122
test/apps/mqtt/main/test_mqtt.c
Normal file
122
test/apps/mqtt/main/test_mqtt.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*
|
||||
* This test code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, this
|
||||
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include "unity_fixture.h"
|
||||
#include "unity_fixture_extras.h"
|
||||
#include "test_utils.h"
|
||||
#include "memory_checks.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "test_mqtt_client_broker.h"
|
||||
#include "test_mqtt_connection.h"
|
||||
#include "esp_partition.h"
|
||||
|
||||
TEST_GROUP(mqtt);
|
||||
|
||||
TEST_SETUP(mqtt){
|
||||
test_utils_record_free_mem();
|
||||
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
|
||||
}
|
||||
|
||||
TEST_TEAR_DOWN(mqtt){
|
||||
test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL),
|
||||
test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL));
|
||||
}
|
||||
|
||||
TEST(mqtt, init_with_invalid_url)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = "INVALID",
|
||||
};
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
TEST_ASSERT_EQUAL(NULL, client );
|
||||
}
|
||||
|
||||
TEST(mqtt, init_and_deinit)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
// no connection takes place, but the uri has to be valid for init() to succeed
|
||||
.broker.address.uri = "mqtts://localhost:8883",
|
||||
};
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, client );
|
||||
esp_mqtt_client_destroy(client);
|
||||
}
|
||||
|
||||
static const char* this_bin_addr(void)
|
||||
{
|
||||
esp_partition_mmap_handle_t out_handle;
|
||||
const void *binary_address;
|
||||
const esp_partition_t* partition = esp_ota_get_running_partition();
|
||||
esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &binary_address, &out_handle);
|
||||
return binary_address;
|
||||
}
|
||||
|
||||
TEST(mqtt, enqueue_and_destroy_outbox)
|
||||
{
|
||||
const char * bin_addr = this_bin_addr();
|
||||
|
||||
// Reseting leak detection since this_bin_addr adds to allocated memory.
|
||||
test_utils_record_free_mem();
|
||||
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
|
||||
const int messages = 20;
|
||||
const int size = 2000;
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
// no connection takes place, but the uri has to be valid for init() to succeed
|
||||
.broker.address.uri = "mqtts://localhost:8883",
|
||||
};
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, client );
|
||||
int bytes_before = esp_get_free_heap_size();
|
||||
for (int i=0; i<messages; ++i) {
|
||||
esp_mqtt_client_publish(client, "test", bin_addr, size, 1, 0);
|
||||
}
|
||||
int bytes_after = esp_get_free_heap_size();
|
||||
// check that outbox allocated all messages on heap
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(messages*size, bytes_before - bytes_after);
|
||||
|
||||
esp_mqtt_client_destroy(client);
|
||||
}
|
||||
|
||||
#if SOC_EMAC_SUPPORTED
|
||||
/**
|
||||
* This test cases uses ethernet kit, so build and use it only if EMAC supported
|
||||
*/
|
||||
TEST(mqtt, broker_tests)
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
connect_test_fixture_setup();
|
||||
|
||||
RUN_MQTT_BROKER_TEST(mqtt_connect_disconnect);
|
||||
RUN_MQTT_BROKER_TEST(mqtt_subscribe_publish);
|
||||
RUN_MQTT_BROKER_TEST(mqtt_lwt_clean_disconnect);
|
||||
RUN_MQTT_BROKER_TEST(mqtt_subscribe_payload);
|
||||
|
||||
connect_test_fixture_teardown();
|
||||
}
|
||||
#endif // SOC_EMAC_SUPPORTED
|
||||
|
||||
|
||||
TEST_GROUP_RUNNER(mqtt) {
|
||||
RUN_TEST_CASE(mqtt, init_with_invalid_url);
|
||||
RUN_TEST_CASE(mqtt, init_and_deinit);
|
||||
RUN_TEST_CASE(mqtt, enqueue_and_destroy_outbox);
|
||||
|
||||
#if SOC_EMAC_SUPPORTED
|
||||
RUN_TEST_CASE(mqtt, broker_tests);
|
||||
#endif // SOC_EMAC_SUPPORTED
|
||||
}
|
||||
|
||||
void app_main(void){
|
||||
UNITY_MAIN(mqtt);
|
||||
}
|
227
test/apps/mqtt/main/test_mqtt_client_broker.c
Normal file
227
test/apps/mqtt/main/test_mqtt_client_broker.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_mac.h"
|
||||
|
||||
#define WAIT_FOR_EVENT(event) \
|
||||
TEST_ASSERT_TRUE(xEventGroupWaitBits(s_event_group, event, pdTRUE, pdTRUE, pdMS_TO_TICKS(COMMON_OPERATION_TIMEOUT)) & event);
|
||||
|
||||
#define TEST_ASSERT_TRUE(condition) TEST_ASSERT_TRUE_LINE(condition, __LINE__)
|
||||
#define TEST_ASSERT_TRUE_LINE(condition, line) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
ESP_LOGE("test_mqtt_client_broker.c", \
|
||||
"Assertion failed in line %d", line); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
static const int COMMON_OPERATION_TIMEOUT = 10000;
|
||||
static const int CONNECT_BIT = BIT0;
|
||||
static const int DISCONNECT_BIT = BIT1;
|
||||
static const int DATA_BIT = BIT2;
|
||||
|
||||
static EventGroupHandle_t s_event_group;
|
||||
|
||||
static char* append_mac(const char* string)
|
||||
{
|
||||
uint8_t mac[6];
|
||||
char *id_string = NULL;
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
asprintf(&id_string, "%s_%02x%02X%02X", string, mac[3], mac[4], mac[5]);
|
||||
return id_string;
|
||||
}
|
||||
|
||||
static void mqtt_data_handler_qos(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_id == MQTT_EVENT_DATA) {
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
int * qos = handler_args;
|
||||
*qos = event->qos;
|
||||
xEventGroupSetBits(s_event_group, DATA_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_data_handler_lwt(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_id == MQTT_EVENT_DATA) {
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
ESP_LOGI("mqtt-lwt", "MQTT_EVENT_DATA");
|
||||
ESP_LOGI("mqtt-lwt", "TOPIC=%.*s", event->topic_len, event->topic);
|
||||
ESP_LOGI("mqtt-lwt", "DATA=%.*s", event->data_len, event->data);
|
||||
if (strncmp(event->data, "no-lwt", event->data_len) == 0) {
|
||||
// no lwt, just to indicate the test has finished
|
||||
xEventGroupSetBits(s_event_group, DATA_BIT);
|
||||
} else {
|
||||
// count up any potential lwt message
|
||||
int * count = handler_args;
|
||||
*count = *count + 1;
|
||||
ESP_LOGE("mqtt-lwt", "count=%d", *count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_data_handler_subscribe(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_id == MQTT_EVENT_SUBSCRIBED) {
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
ESP_LOGI("mqtt-subscribe", "MQTT_EVENT_SUBSCRIBED, data size=%d", event->data_len);
|
||||
int * sub_payload = handler_args;
|
||||
if (event->data_len == 1) {
|
||||
ESP_LOGI("mqtt-subscribe", "DATA=%d", *(uint8_t*)event->data);
|
||||
*sub_payload = *(uint8_t*)event->data;
|
||||
}
|
||||
xEventGroupSetBits(s_event_group, DATA_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
xEventGroupSetBits(s_event_group, CONNECT_BIT);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
xEventGroupSetBits(s_event_group, DISCONNECT_BIT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool mqtt_connect_disconnect(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
|
||||
.network.disable_auto_reconnect = true,
|
||||
};
|
||||
s_event_group = xEventGroupCreate();
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
TEST_ASSERT_TRUE(NULL != client );
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
esp_mqtt_client_disconnect(client);
|
||||
WAIT_FOR_EVENT(DISCONNECT_BIT);
|
||||
esp_mqtt_client_reconnect(client);
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
esp_mqtt_client_destroy(client);
|
||||
vEventGroupDelete(s_event_group);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mqtt_subscribe_publish(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
|
||||
};
|
||||
char* topic = append_mac("topic");
|
||||
TEST_ASSERT_TRUE(NULL != topic);
|
||||
s_event_group = xEventGroupCreate();
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
TEST_ASSERT_TRUE(NULL != client );
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
int qos = -1;
|
||||
esp_mqtt_client_register_event(client, MQTT_EVENT_DATA, mqtt_data_handler_qos, &qos);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 2) != -1);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client, topic, "message", 0, 2, 0) != -1);
|
||||
WAIT_FOR_EVENT(DATA_BIT);
|
||||
TEST_ASSERT_TRUE(qos == 2);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client, topic, "message", 0, 1, 0) != -1);
|
||||
WAIT_FOR_EVENT(DATA_BIT);
|
||||
TEST_ASSERT_TRUE(qos == 1);
|
||||
esp_mqtt_client_destroy(client);
|
||||
vEventGroupDelete(s_event_group);
|
||||
free(topic);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mqtt_lwt_clean_disconnect(void)
|
||||
{
|
||||
char* lwt = append_mac("lwt");
|
||||
TEST_ASSERT_TRUE(lwt);
|
||||
const esp_mqtt_client_config_t mqtt_cfg1 = {
|
||||
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
|
||||
.credentials.set_null_client_id = true,
|
||||
.session.last_will.topic = lwt,
|
||||
.session.last_will.msg = "lwt_msg"
|
||||
};
|
||||
const esp_mqtt_client_config_t mqtt_cfg2 = {
|
||||
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
|
||||
.credentials.set_null_client_id = true,
|
||||
.session.last_will.topic = lwt,
|
||||
.session.last_will.msg = "lwt_msg"
|
||||
};
|
||||
s_event_group = xEventGroupCreate();
|
||||
|
||||
esp_mqtt_client_handle_t client1 = esp_mqtt_client_init(&mqtt_cfg1);
|
||||
esp_mqtt_client_handle_t client2 = esp_mqtt_client_init(&mqtt_cfg2);
|
||||
TEST_ASSERT_TRUE(NULL != client1 && NULL != client2 );
|
||||
esp_mqtt_client_register_event(client1, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_register_event(client2, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_start(client1) == ESP_OK);
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_start(client2) == ESP_OK);
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
int counter = 0;
|
||||
esp_mqtt_client_register_event(client1, MQTT_EVENT_DATA, mqtt_data_handler_lwt, &counter);
|
||||
esp_mqtt_client_register_event(client2, MQTT_EVENT_DATA, mqtt_data_handler_lwt, &counter);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client1, lwt, 0) != -1);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client2, lwt, 0) != -1);
|
||||
esp_mqtt_client_disconnect(client1);
|
||||
WAIT_FOR_EVENT(DISCONNECT_BIT);
|
||||
esp_mqtt_client_reconnect(client1);
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client1, lwt, 0) != -1);
|
||||
esp_mqtt_client_stop(client2);
|
||||
esp_mqtt_client_start(client2);
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client2, lwt, 0) != -1);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client1, lwt, "no-lwt", 0, 0, 0) != -1);
|
||||
WAIT_FOR_EVENT(DATA_BIT);
|
||||
TEST_ASSERT_TRUE(counter == 0);
|
||||
esp_mqtt_client_destroy(client1);
|
||||
esp_mqtt_client_destroy(client2);
|
||||
vEventGroupDelete(s_event_group);
|
||||
free(lwt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mqtt_subscribe_payload(void)
|
||||
{
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
|
||||
.network.disable_auto_reconnect = true,
|
||||
};
|
||||
char* topic = append_mac("topic");
|
||||
TEST_ASSERT_TRUE(NULL != topic);
|
||||
s_event_group = xEventGroupCreate();
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
TEST_ASSERT_TRUE(NULL != client );
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
|
||||
WAIT_FOR_EVENT(CONNECT_BIT);
|
||||
int qos_payload = -1;
|
||||
esp_mqtt_client_register_event(client, MQTT_EVENT_SUBSCRIBED, mqtt_data_handler_subscribe, &qos_payload);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 2) != -1);
|
||||
WAIT_FOR_EVENT(DATA_BIT);
|
||||
TEST_ASSERT_TRUE(qos_payload == 2);
|
||||
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 0) != -1);
|
||||
WAIT_FOR_EVENT(DATA_BIT);
|
||||
TEST_ASSERT_TRUE(qos_payload == 0);
|
||||
esp_mqtt_client_destroy(client);
|
||||
vEventGroupDelete(s_event_group);
|
||||
free(topic);
|
||||
return true;
|
||||
}
|
50
test/apps/mqtt/main/test_mqtt_client_broker.h
Normal file
50
test/apps/mqtt/main/test_mqtt_client_broker.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include "esp_log.h"
|
||||
|
||||
/**
|
||||
* @brief MQTT client-broker tests are not implemented as separate test cases
|
||||
* due to time consuming connection setup/teardown.
|
||||
* This utility macro is used to run functional cases as MQTT tests
|
||||
* and evaluate as separate assertions in one "mqtt broker tests" test case.
|
||||
*/
|
||||
#define RUN_MQTT_BROKER_TEST(test_name) \
|
||||
do { \
|
||||
ESP_LOGI("mqtt_test", "Running test:" #test_name "()"); \
|
||||
TEST_ASSERT_TRUE_MESSAGE(test_name(), "Mqtt test failed: " #test_name "() "); \
|
||||
ESP_LOGI("mqtt_test", "Test:" #test_name "() passed "); \
|
||||
} while(0)
|
||||
|
||||
|
||||
/**
|
||||
* @brief This module contains mqtt test cases interacting the client with a (real) broker
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief The client subscribes and publishes on the same topic
|
||||
* and verifies the received published qos in the event
|
||||
*/
|
||||
bool mqtt_subscribe_publish(void);
|
||||
|
||||
/**
|
||||
* @brief The client connects, disconnects and reconnects.
|
||||
* Tests basic client state transitions
|
||||
*/
|
||||
bool mqtt_connect_disconnect(void);
|
||||
|
||||
/**
|
||||
* @brief Two clients with defined lwt connect and subscribe to lwt topic.
|
||||
* This test verifies that no lwt is send when each of the client disconnects.
|
||||
* (we expect a clean disconnection, so no last-will being sent)
|
||||
*/
|
||||
bool mqtt_lwt_clean_disconnect(void);
|
||||
|
||||
/**
|
||||
* @brief The client subscribes to a topic with certain qos
|
||||
* and verifies the qos in SUBACK message from the broker.
|
||||
*/
|
||||
bool mqtt_subscribe_payload(void);
|
11
test/apps/mqtt/pytest_mqtt_ut.py
Normal file
11
test/apps/mqtt/pytest_mqtt_ut.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.ethernet
|
||||
@idf_parametrize('target', ['esp32'], indirect=['target'])
|
||||
def test_mqtt_client(dut: Dut) -> None:
|
||||
dut.expect_unity_test_output()
|
4
test/apps/mqtt/sdkconfig.ci.default
Normal file
4
test/apps/mqtt/sdkconfig.ci.default
Normal file
@@ -0,0 +1,4 @@
|
||||
CONFIG_MQTT_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
|
||||
CONFIG_MQTT5_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
3
test/apps/mqtt/sdkconfig.defaults
Normal file
3
test/apps/mqtt/sdkconfig.defaults
Normal file
@@ -0,0 +1,3 @@
|
||||
# General options for additional checks
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
9
test/apps/mqtt5/CMakeLists.txt
Normal file
9
test/apps/mqtt5/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
#This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
|
||||
"../common")
|
||||
|
||||
set(COMPONENTS main)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp_mqtt5_client_test)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user