From f6ee315d69d453174239c431ceae5449332545d0 Mon Sep 17 00:00:00 2001 From: Alexander Bobkov Date: Sat, 4 Oct 2025 23:55:02 -0400 Subject: [PATCH] . --- ESP32-IDF_Temperture-Node-v2/build/config.env | 2 +- .../build/kconfigs.in | 4 +- .../build/local_components_list.temp.yml | 213 -- .../espressif__mqtt/.build-test-rules.yml | 106 + .../espressif__mqtt/.component_hash | 1 + .../espressif__mqtt/.editorconfig | 34 + .../espressif__mqtt/.gitignore | 112 + .../espressif__mqtt/.gitlab/ci/build.yml | 27 + .../espressif__mqtt/.gitlab/ci/deploy.yml | 29 + .../espressif__mqtt/.gitlab/ci/docs.yml | 82 + .../.gitlab/ci/ignore_build_warnings.txt | 5 + .../espressif__mqtt/.gitlab/ci/test.yml | 50 + .../espressif__mqtt/.gitlab/ci/utils.sh | 26 + .../espressif__mqtt/.idf_build_apps.toml | 18 + .../espressif__mqtt/.idf_ci.toml | 21 + .../espressif__mqtt/.travis.yml | 65 + .../espressif__mqtt/CHECKSUMS.json | 1 + .../espressif__mqtt/CMakeLists.txt | 14 + .../espressif__mqtt/Kconfig | 190 ++ .../espressif__mqtt/LICENSE | 202 ++ .../espressif__mqtt/README.md | 52 + .../espressif__mqtt/docs/Doxyfile | 57 + .../espressif__mqtt/docs/conf_common.py | 39 + .../docs/doxygen-known-warnings.txt | 2 + .../espressif__mqtt/docs/en/conf.py | 27 + .../espressif__mqtt/docs/en/index.rst | 208 ++ .../docs/sphinx-known-warnings.txt | 37 + .../espressif__mqtt/docs/zh_CN/conf.py | 27 + .../espressif__mqtt/docs/zh_CN/index.rst | 208 ++ .../examples/custom_outbox/CMakeLists.txt | 20 + .../examples/custom_outbox/README.md | 100 + .../custom_outbox/main/CMakeLists.txt | 4 + .../custom_outbox/main/Kconfig.projbuild | 13 + .../examples/custom_outbox/main/app_main.c | 173 ++ .../custom_outbox/main/custom_outbox.cpp | 393 +++ .../custom_outbox/main/idf_component.yml | 5 + .../custom_outbox/sdkconfig.ci.esp32c6 | 1 + .../examples/custom_outbox/sdkconfig.defaults | 3 + .../examples/mqtt5/CMakeLists.txt | 9 + .../espressif__mqtt/examples/mqtt5/README.md | 78 + .../examples/mqtt5/main/CMakeLists.txt | 3 + .../examples/mqtt5/main/Kconfig.projbuild | 13 + .../examples/mqtt5/main/app_main.c | 290 ++ .../examples/mqtt5/main/idf_component.yml | 5 + .../examples/mqtt5/pytest_mqtt5.py | 65 + .../examples/mqtt5/sdkconfig.ci | 10 + .../examples/mqtt5/sdkconfig.defaults | 1 + .../examples/ssl/CMakeLists.txt | 11 + .../espressif__mqtt/examples/ssl/README.md | 70 + .../examples/ssl/main/CMakeLists.txt | 3 + .../examples/ssl/main/Kconfig.projbuild | 26 + .../examples/ssl/main/app_main.c | 165 ++ .../examples/ssl/main/idf_component.yml | 5 + .../ssl/main/mqtt_eclipseprojects_io.pem | 30 + .../examples/ssl/pytest_mqtt_ssl.py | 135 + .../espressif__mqtt/examples/ssl/sdkconfig.ci | 22 + .../examples/ssl_ds/CMakeLists.txt | 18 + .../espressif__mqtt/examples/ssl_ds/README.md | 105 + .../examples/ssl_ds/main/CMakeLists.txt | 3 + .../examples/ssl_ds/main/app_main.c | 156 ++ .../examples/ssl_ds/main/idf_component.yml | 6 + .../examples/ssl_ds/main/mosquitto.org.crt | 25 + .../examples/ssl_ds/partitions.csv | 6 + .../examples/ssl_ds/sdkconfig.defaults | 7 + .../ssl_ds/sdkconfig.defaults.esp32h2 | 2 + .../examples/ssl_mutual_auth/CMakeLists.txt | 13 + .../examples/ssl_mutual_auth/README.md | 82 + .../ssl_mutual_auth/main/CMakeLists.txt | 3 + .../examples/ssl_mutual_auth/main/app_main.c | 155 ++ .../examples/ssl_mutual_auth/main/client.crt | 1 + .../examples/ssl_mutual_auth/main/client.key | 1 + .../ssl_mutual_auth/main/idf_component.yml | 5 + .../ssl_mutual_auth/main/mosquitto.org.crt | 24 + .../ssl_mutual_auth/sdkconfig.defaults | 1 + .../sdkconfig.defaults.esp32c5 | 1 + .../sdkconfig.defaults.esp32c6 | 1 + .../sdkconfig.defaults.esp32c61 | 1 + .../examples/ssl_psk/CMakeLists.txt | 9 + .../examples/ssl_psk/README.md | 78 + .../examples/ssl_psk/main/CMakeLists.txt | 3 + .../examples/ssl_psk/main/app_main.c | 151 ++ .../examples/ssl_psk/main/idf_component.yml | 5 + .../examples/ssl_psk/sdkconfig.defaults | 1 + .../ssl_psk/sdkconfig.defaults.esp32c5 | 1 + .../ssl_psk/sdkconfig.defaults.esp32c6 | 1 + .../ssl_psk/sdkconfig.defaults.esp32c61 | 1 + .../examples/tcp/CMakeLists.txt | 9 + .../espressif__mqtt/examples/tcp/README.md | 375 +++ .../examples/tcp/main/CMakeLists.txt | 3 + .../examples/tcp/main/Kconfig.projbuild | 13 + .../examples/tcp/main/app_main.c | 162 ++ .../examples/tcp/main/idf_component.yml | 13 + .../examples/tcp/pytest_mqtt_tcp.py | 97 + .../espressif__mqtt/examples/tcp/sdkconfig.ci | 13 + .../examples/tcp/sdkconfig.ci.p4_eppp | 5 + .../examples/tcp/sdkconfig.ci.p4_wifi | 3 + .../examples/tcp/sdkconfig.ci.ppp_connect | 3 + .../examples/ws/CMakeLists.txt | 9 + .../espressif__mqtt/examples/ws/README.md | 61 + .../examples/ws/main/CMakeLists.txt | 3 + .../examples/ws/main/Kconfig.projbuild | 9 + .../examples/ws/main/app_main.c | 144 + .../examples/ws/main/idf_component.yml | 5 + .../examples/ws/pytest_mqtt_ws_example.py | 108 + .../espressif__mqtt/examples/ws/sdkconfig.ci | 11 + .../examples/wss/CMakeLists.txt | 11 + .../espressif__mqtt/examples/wss/README.md | 73 + .../examples/wss/main/CMakeLists.txt | 3 + .../examples/wss/main/Kconfig.projbuild | 20 + .../examples/wss/main/app_main.c | 135 + .../examples/wss/main/idf_component.yml | 5 + .../wss/main/mqtt_eclipseprojects_io.pem | 30 + .../examples/wss/pytest_mqtt_wss_example.py | 111 + .../espressif__mqtt/examples/wss/sdkconfig.ci | 13 + .../espressif__mqtt/idf_component.yml | 18 + .../espressif__mqtt/include/mqtt5_client.h | 286 ++ .../espressif__mqtt/include/mqtt_client.h | 704 +++++ .../include/mqtt_supported_features.h | 83 + .../lib/include/mqtt5_client_priv.h | 56 + .../espressif__mqtt/lib/include/mqtt5_msg.h | 142 + .../lib/include/mqtt_client_priv.h | 150 ++ .../espressif__mqtt/lib/include/mqtt_config.h | 118 + .../espressif__mqtt/lib/include/mqtt_msg.h | 152 ++ .../espressif__mqtt/lib/include/mqtt_outbox.h | 64 + .../espressif__mqtt/lib/include/platform.h | 14 + .../lib/include/platform_esp32_idf.h | 29 + .../espressif__mqtt/lib/mqtt5_msg.c | 1047 ++++++++ .../espressif__mqtt/lib/mqtt_msg.c | 637 +++++ .../espressif__mqtt/lib/mqtt_outbox.c | 225 ++ .../espressif__mqtt/lib/platform_esp32_idf.c | 48 + .../espressif__mqtt/mqtt5_client.c | 768 ++++++ .../espressif__mqtt/mqtt_client.c | 2392 +++++++++++++++++ .../espressif__mqtt/pytest.ini | 28 + .../espressif__mqtt/static-analysis-rules.yml | 9 + .../test/apps/common/CMakeLists.txt | 4 + .../common/include/test_mqtt_connection.h | 18 + .../test/apps/common/test_mqtt_connection.c | 144 + .../test/apps/mqtt/CMakeLists.txt | 16 + .../espressif__mqtt/test/apps/mqtt/README.md | 2 + .../test/apps/mqtt/main/CMakeLists.txt | 8 + .../test/apps/mqtt/main/Kconfig.projbuild | 14 + .../test/apps/mqtt/main/idf_component.yml | 5 + .../test/apps/mqtt/main/test_mqtt.c | 122 + .../apps/mqtt/main/test_mqtt_client_broker.c | 227 ++ .../apps/mqtt/main/test_mqtt_client_broker.h | 50 + .../test/apps/mqtt/pytest_mqtt_ut.py | 11 + .../test/apps/mqtt/sdkconfig.ci.default | 4 + .../test/apps/mqtt/sdkconfig.defaults | 3 + .../test/apps/mqtt5/CMakeLists.txt | 16 + .../espressif__mqtt/test/apps/mqtt5/README.md | 2 + .../test/apps/mqtt5/main/CMakeLists.txt | 4 + .../test/apps/mqtt5/main/Kconfig.projbuild | 14 + .../test/apps/mqtt5/main/idf_component.yml | 4 + .../test/apps/mqtt5/main/test_mqtt5.c | 172 ++ .../mqtt5/main/test_mqtt5_client_broker.c | 285 ++ .../mqtt5/main/test_mqtt5_client_broker.h | 51 + .../test/apps/mqtt5/pytest_mqtt5_ut.py | 11 + .../test/apps/mqtt5/sdkconfig.ci.default | 4 + .../test/apps/mqtt5/sdkconfig.defaults | 4 + .../apps/publish_connect_test/CMakeLists.txt | 16 + .../test/apps/publish_connect_test/README.md | 25 + .../test/apps/publish_connect_test/ca.crt | 19 + .../test/apps/publish_connect_test/ca.der | Bin 0 -> 797 bytes .../test/apps/publish_connect_test/ca.key | 28 + .../apps/publish_connect_test/client_inv.crt | 19 + .../publish_connect_test/client_no_pwd.key | 28 + .../apps/publish_connect_test/client_pwd.crt | 18 + .../apps/publish_connect_test/client_pwd.key | 30 + .../publish_connect_test/main/CMakeLists.txt | 4 + .../main/Kconfig.projbuild | 94 + .../publish_connect_test/main/connect_test.c | 197 ++ .../main/idf_component.yml | 11 + .../main/mqtt_eclipseprojects_io.pem | 30 + .../main/publish_connect_test.c | 334 +++ .../main/publish_connect_test.h | 59 + .../publish_connect_test/main/publish_test.c | 229 ++ .../publish_connect_test/pytest_mqtt_app.py | 276 ++ .../pytest_mqtt_publish_app.py | 335 +++ .../publish_connect_test/sdkconfig.ci.default | 20 + .../sdkconfig.ci.local_broker | 13 + .../test/apps/publish_connect_test/server.key | 27 + .../espressif__mqtt/test/host/CMakeLists.txt | 17 + .../espressif__mqtt/test/host/README.md | 30 + .../test/host/main/CMakeLists.txt | 21 + .../espressif__mqtt/test/host/main/Kconfig | 9 + .../test/host/main/idf_component.yml | 9 + .../test/host/main/test_mqtt_client.cpp | 171 ++ .../test/host/mocks/include/sys/queue.h | 71 + .../test/host/sdkconfig.ci.coverage | 1 + .../test/host/sdkconfig.defaults | 6 + 190 files changed, 15921 insertions(+), 216 deletions(-) delete mode 100644 ESP32-IDF_Temperture-Node-v2/build/local_components_list.temp.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.build-test-rules.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.component_hash create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.editorconfig create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitignore create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/build.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/deploy.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/docs.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/ignore_build_warnings.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/test.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/utils.sh create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_build_apps.toml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_ci.toml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.travis.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CHECKSUMS.json create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/Kconfig create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/LICENSE create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/Doxyfile create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/conf_common.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/doxygen-known-warnings.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/conf.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/index.rst create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/sphinx-known-warnings.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/conf.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/index.rst create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/custom_outbox.cpp create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.ci.esp32c6 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.defaults create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/pytest_mqtt5.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.ci create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.defaults create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/mqtt_eclipseprojects_io.pem create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/pytest_mqtt_ssl.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/sdkconfig.ci create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/mosquitto.org.crt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/partitions.csv create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults.esp32h2 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.crt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.key create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/mosquitto.org.crt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c5 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c6 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c61 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c5 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c6 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c61 create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/pytest_mqtt_tcp.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_eppp create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_wifi create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.ppp_connect create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/pytest_mqtt_ws_example.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/sdkconfig.ci create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/app_main.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/mqtt_eclipseprojects_io.pem create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/pytest_mqtt_wss_example.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/sdkconfig.ci create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt5_client.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_client.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_supported_features.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_client_priv.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_msg.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_client_priv.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_config.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_msg.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_outbox.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform_esp32_idf.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt5_msg.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_msg.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_outbox.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/platform_esp32_idf.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt5_client.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt_client.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/pytest.ini create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/static-analysis-rules.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/include/test_mqtt_connection.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/test_mqtt_connection.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt_client_broker.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt_client_broker.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/pytest_mqtt_ut.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.ci.default create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.defaults create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/pytest_mqtt5_ut.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.ci.default create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.defaults create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.crt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.der create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.key create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/client_inv.crt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/client_no_pwd.key create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/client_pwd.crt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/client_pwd.key create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/Kconfig.projbuild create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/connect_test.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/mqtt_eclipseprojects_io.pem create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/publish_connect_test.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/publish_connect_test.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/main/publish_test.c create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/pytest_mqtt_app.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/pytest_mqtt_publish_app.py create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/sdkconfig.ci.default create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/sdkconfig.ci.local_broker create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/server.key create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/README.md create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/main/CMakeLists.txt create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/main/Kconfig create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/main/idf_component.yml create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/main/test_mqtt_client.cpp create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/mocks/include/sys/queue.h create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/sdkconfig.ci.coverage create mode 100644 ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/host/sdkconfig.defaults diff --git a/ESP32-IDF_Temperture-Node-v2/build/config.env b/ESP32-IDF_Temperture-Node-v2/build/config.env index 18b4c1640..737549384 100644 --- a/ESP32-IDF_Temperture-Node-v2/build/config.env +++ b/ESP32-IDF_Temperture-Node-v2/build/config.env @@ -1,5 +1,5 @@ { - "COMPONENT_KCONFIGS": "/home/abobkov/esp/v5.4.1/esp-idf/components/app_trace/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/bt/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/console/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/driver/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/efuse/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp-tls/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_adc/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_coex/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_common/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_ana_cmpr/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_cam/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_dac/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_gpio/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_gptimer/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_i2c/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_i2s/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_isp/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_jpeg/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_ledc/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_mcpwm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_parlio/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_pcnt/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_rmt/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_sdm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_spi/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_touch_sens/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_tsens/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_uart/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_usb_serial_jtag/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_eth/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_event/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_gdbstub/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hid/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_http_client/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_http_server/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_https_ota/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_https_server/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hw_support/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_lcd/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_mm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_netif/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_partition/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_phy/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_pm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_psram/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_ringbuf/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_security/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_system/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_timer/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_wifi/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/espcoredump/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/fatfs/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/freertos/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/hal/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/heap/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/ieee802154/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/log/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/lwip/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/mbedtls/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/mqtt/esp-mqtt/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/newlib/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_flash/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_sec_provider/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/openthread/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/protocomm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/pthread/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/soc/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/spi_flash/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/spiffs/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/tcp_transport/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/ulp/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/unity/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/usb/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/vfs/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/wear_levelling/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/wifi_provisioning/Kconfig;/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__cmake_utilities/Kconfig;/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__i2c_bus/Kconfig", + "COMPONENT_KCONFIGS": "/home/abobkov/esp/v5.4.1/esp-idf/components/app_trace/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/bt/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/console/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/driver/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/efuse/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp-tls/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_adc/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_coex/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_common/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_ana_cmpr/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_cam/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_dac/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_gpio/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_gptimer/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_i2c/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_i2s/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_isp/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_jpeg/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_ledc/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_mcpwm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_parlio/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_pcnt/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_rmt/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_sdm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_spi/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_touch_sens/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_tsens/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_uart/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_usb_serial_jtag/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_eth/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_event/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_gdbstub/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hid/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_http_client/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_http_server/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_https_ota/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_https_server/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hw_support/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_lcd/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_mm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_netif/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_partition/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_phy/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_pm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_psram/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_ringbuf/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_security/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_system/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_timer/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_wifi/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/espcoredump/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/fatfs/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/freertos/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/hal/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/heap/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/ieee802154/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/log/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/lwip/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/mbedtls/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/newlib/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_flash/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_sec_provider/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/openthread/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/protocomm/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/pthread/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/soc/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/spi_flash/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/spiffs/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/tcp_transport/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/ulp/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/unity/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/usb/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/vfs/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/wear_levelling/Kconfig;/home/abobkov/esp/v5.4.1/esp-idf/components/wifi_provisioning/Kconfig;/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__cmake_utilities/Kconfig;/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__i2c_bus/Kconfig;/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/Kconfig", "COMPONENT_KCONFIGS_PROJBUILD": "/home/abobkov/esp/v5.4.1/esp-idf/components/bootloader/Kconfig.projbuild;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_app_format/Kconfig.projbuild;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_rom/Kconfig.projbuild;/home/abobkov/esp/v5.4.1/esp-idf/components/esptool_py/Kconfig.projbuild;/home/abobkov/esp/v5.4.1/esp-idf/components/partition_table/Kconfig.projbuild", "COMPONENT_SDKCONFIG_RENAMES": "/home/abobkov/esp/v5.4.1/esp-idf/components/app_trace/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/bootloader/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/bt/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/driver/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_coex/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_event/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_gdbstub/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_https_ota/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hw_support/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hw_support/sdkconfig.rename.esp32;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_phy/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_pm/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_system/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_system/sdkconfig.rename.esp32;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_timer/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esp_wifi/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/espcoredump/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/esptool_py/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/freertos/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/hal/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/lwip/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/newlib/sdkconfig.rename.esp32;/home/abobkov/esp/v5.4.1/esp-idf/components/pthread/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/spi_flash/sdkconfig.rename;/home/abobkov/esp/v5.4.1/esp-idf/components/ulp/sdkconfig.rename.esp32;/home/abobkov/esp/v5.4.1/esp-idf/components/vfs/sdkconfig.rename", "IDF_TARGET": "esp32", diff --git a/ESP32-IDF_Temperture-Node-v2/build/kconfigs.in b/ESP32-IDF_Temperture-Node-v2/build/kconfigs.in index 3a9e7678e..19d293bbc 100644 --- a/ESP32-IDF_Temperture-Node-v2/build/kconfigs.in +++ b/ESP32-IDF_Temperture-Node-v2/build/kconfigs.in @@ -57,7 +57,6 @@ source "/home/abobkov/esp/v5.4.1/esp-idf/components/ieee802154/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/log/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/lwip/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/mbedtls/Kconfig" -source "/home/abobkov/esp/v5.4.1/esp-idf/components/mqtt/esp-mqtt/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/newlib/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_flash/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_sec_provider/Kconfig" @@ -75,4 +74,5 @@ source "/home/abobkov/esp/v5.4.1/esp-idf/components/vfs/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/wear_levelling/Kconfig" source "/home/abobkov/esp/v5.4.1/esp-idf/components/wifi_provisioning/Kconfig" source "/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__cmake_utilities/Kconfig" -source "/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__i2c_bus/Kconfig" \ No newline at end of file +source "/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__i2c_bus/Kconfig" +source "/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/Kconfig" \ No newline at end of file diff --git a/ESP32-IDF_Temperture-Node-v2/build/local_components_list.temp.yml b/ESP32-IDF_Temperture-Node-v2/build/local_components_list.temp.yml deleted file mode 100644 index 9af522fcb..000000000 --- a/ESP32-IDF_Temperture-Node-v2/build/local_components_list.temp.yml +++ /dev/null @@ -1,213 +0,0 @@ -components: - - name: "app_trace" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/app_trace" - - name: "app_update" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/app_update" - - name: "bootloader" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/bootloader" - - name: "bootloader_support" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/bootloader_support" - - name: "bt" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/bt" - - name: "cmock" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/cmock" - - name: "console" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/console" - - name: "cxx" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/cxx" - - name: "driver" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/driver" - - name: "efuse" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/efuse" - - name: "esp-tls" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp-tls" - - name: "esp_adc" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_adc" - - name: "esp_app_format" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_app_format" - - name: "esp_bootloader_format" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_bootloader_format" - - name: "esp_coex" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_coex" - - name: "esp_common" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_common" - - name: "esp_driver_ana_cmpr" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_ana_cmpr" - - name: "esp_driver_cam" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_cam" - - name: "esp_driver_dac" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_dac" - - name: "esp_driver_gpio" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_gpio" - - name: "esp_driver_gptimer" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_gptimer" - - name: "esp_driver_i2c" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_i2c" - - name: "esp_driver_i2s" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_i2s" - - name: "esp_driver_isp" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_isp" - - name: "esp_driver_jpeg" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_jpeg" - - name: "esp_driver_ledc" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_ledc" - - name: "esp_driver_mcpwm" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_mcpwm" - - name: "esp_driver_parlio" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_parlio" - - name: "esp_driver_pcnt" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_pcnt" - - name: "esp_driver_ppa" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_ppa" - - name: "esp_driver_rmt" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_rmt" - - name: "esp_driver_sdio" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_sdio" - - name: "esp_driver_sdm" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_sdm" - - name: "esp_driver_sdmmc" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_sdmmc" - - name: "esp_driver_sdspi" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_sdspi" - - name: "esp_driver_spi" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_spi" - - name: "esp_driver_touch_sens" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_touch_sens" - - name: "esp_driver_tsens" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_tsens" - - name: "esp_driver_uart" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_uart" - - name: "esp_driver_usb_serial_jtag" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_driver_usb_serial_jtag" - - name: "esp_eth" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_eth" - - name: "esp_event" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_event" - - name: "esp_gdbstub" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_gdbstub" - - name: "esp_hid" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hid" - - name: "esp_http_client" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_http_client" - - name: "esp_http_server" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_http_server" - - name: "esp_https_ota" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_https_ota" - - name: "esp_https_server" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_https_server" - - name: "esp_hw_support" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_hw_support" - - name: "esp_lcd" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_lcd" - - name: "esp_local_ctrl" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_local_ctrl" - - name: "esp_mm" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_mm" - - name: "esp_netif" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_netif" - - name: "esp_netif_stack" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_netif_stack" - - name: "esp_partition" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_partition" - - name: "esp_phy" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_phy" - - name: "esp_pm" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_pm" - - name: "esp_psram" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_psram" - - name: "esp_ringbuf" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_ringbuf" - - name: "esp_rom" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_rom" - - name: "esp_security" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_security" - - name: "esp_system" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_system" - - name: "esp_timer" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_timer" - - name: "esp_vfs_console" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_vfs_console" - - name: "esp_wifi" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esp_wifi" - - name: "espcoredump" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/espcoredump" - - name: "esptool_py" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/esptool_py" - - name: "fatfs" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/fatfs" - - name: "freertos" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/freertos" - - name: "hal" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/hal" - - name: "heap" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/heap" - - name: "http_parser" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/http_parser" - - name: "idf_test" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/idf_test" - - name: "ieee802154" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/ieee802154" - - name: "json" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/json" - - name: "linux" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/linux" - - name: "log" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/log" - - name: "lwip" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/lwip" - - name: "mbedtls" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/mbedtls" - - name: "mqtt" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/mqtt" - - name: "newlib" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/newlib" - - name: "nvs_flash" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_flash" - - name: "nvs_sec_provider" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/nvs_sec_provider" - - name: "openthread" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/openthread" - - name: "partition_table" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/partition_table" - - name: "perfmon" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/perfmon" - - name: "protobuf-c" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/protobuf-c" - - name: "protocomm" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/protocomm" - - name: "pthread" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/pthread" - - name: "riscv" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/riscv" - - name: "rt" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/rt" - - name: "sdmmc" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/sdmmc" - - name: "soc" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/soc" - - name: "spi_flash" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/spi_flash" - - name: "spiffs" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/spiffs" - - name: "tcp_transport" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/tcp_transport" - - name: "touch_element" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/touch_element" - - name: "ulp" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/ulp" - - name: "unity" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/unity" - - name: "usb" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/usb" - - name: "vfs" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/vfs" - - name: "wear_levelling" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/wear_levelling" - - name: "wifi_provisioning" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/wifi_provisioning" - - name: "wpa_supplicant" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/wpa_supplicant" - - name: "xtensa" - path: "/home/abobkov/esp/v5.4.1/esp-idf/components/xtensa" - - name: "main" - path: "/home/abobkov/MyProjects/ESP-Nodes/ESP32-IDF_Temperture-Node-v2/main" diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.build-test-rules.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.build-test-rules.yml new file mode 100644 index 000000000..a1929adca --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.build-test-rules.yml @@ -0,0 +1,106 @@ +# ESP-MQTT Build Test Rules +# Consolidated manifest covering all examples and test apps + +.default_rules: &default_rules + disable: + - if: IDF_TARGET in ["esp32h21", "esp32h4"] + temporary: true + reason: not supported yet + - if: IDF_TARGET in ["esp32p4", "esp32h2"] and IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR == 3 + temporary: true + reason: esp32p4/esp32h2 example dependencies require IDF versions other than 5.3 + disable_test: + - if: IDF_TARGET not in ["esp32"] + reason: Tests run only on ESP32 with ethernet runners + +# Basic TCP MQTT example +examples/tcp: + <<: *default_rules + +# SSL/TLS MQTT example +examples/ssl: + <<: *default_rules + disable_test: + - if: IDF_TARGET == IDF_TARGET + reason: CN verification enabled, tests disabled during server migration + +# WebSocket MQTT example +examples/ws: + <<: *default_rules + +# WebSocket Secure MQTT example +examples/wss: + <<: *default_rules + disable_test: + - if: IDF_TARGET == IDF_TARGET + reason: CN verification enabled, tests disabled during server migration + +# MQTT 5.0 protocol example +examples/mqtt5: + <<: *default_rules + +# SSL with mutual authentication +examples/ssl_mutual_auth: + <<: *default_rules + disable_test: + - if: IDF_TARGET == IDF_TARGET + reason: Advanced feature demonstration, only build + +# SSL with pre-shared keys +examples/ssl_psk: + <<: *default_rules + disable_test: + - if: IDF_TARGET == IDF_TARGET + reason: Advanced feature demonstration, only build + +# SSL with Digital Signature peripheral +examples/ssl_ds: + <<: *default_rules + disable: + - if: SOC_DIG_SIGN_SUPPORTED != 1 + reason: DS not present + disable_test: + - if: IDF_TARGET == IDF_TARGET + reason: Advanced feature demonstration, only build + +# Custom outbox implementation example +examples/custom_outbox: + <<: *default_rules + disable_test: + - if: IDF_TARGET == IDF_TARGET + reason: Advanced feature demonstration, only build + +test/apps: + disable: + - if: IDF_TARGET not in ["esp32"] + reason: Test apps build only for esp32 + disable_test: + - if: IDF_TARGET != "esp32" + temporary: false + reason: Only esp32 target has ethernet runners for integration tests + +# C++ compatibility build test +test/apps/build_test: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3"] + reason: C++ compatibility build test + disable_test: + - if: IDF_TARGET != IDF_TARGET + temporary: false + reason: Build only test + +# Publish/Connect integration test +test/apps/publish_connect_test: + enable: + - if: IDF_TARGET in ["esp32"] + reason: Integration test for publish/connect functionality + disable_test: + - if: IDF_TARGET != "esp32" + temporary: false + reason: Only esp32 target has ethernet runners for integration tests + +# Host tests (unit tests with mocks) +test/host: + enable: + - if: IDF_TARGET in ["linux"] + reason: Host-based unit tests with mocked ESP-IDF components diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.component_hash b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.component_hash new file mode 100644 index 000000000..81dacc210 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.component_hash @@ -0,0 +1 @@ +ffdad5659706b4dc14bc63f8eb73ef765efa015bf7e9adf71c813d52a2dc9342 \ No newline at end of file diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.editorconfig b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.editorconfig new file mode 100644 index 000000000..15977c64e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.editorconfig @@ -0,0 +1,34 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[{*.md,*.rst}] +trim_trailing_whitespace = false + +[{Makefile,*.mk,*.bat}] +indent_style = tab +indent_size = 2 + +[*/freertos/**] +indent_style = tab +indent_size = 4 + +[{*/freertos/**.S,**/FreeRTOSConfig.h}] +indent_style = space +indent_size = 4 + +[*.pem] +insert_final_newline = false + +[*.py] +max_line_length = 119 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitignore b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitignore new file mode 100644 index 000000000..119e9fa75 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitignore @@ -0,0 +1,112 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su + +# ESP-IDF Build System +build/ +sdkconfig +sdkconfig.old +dependencies.lock +managed_components/ + +# ESP-IDF build directories (but not source directories like build_test) +**/build/ +**/build_esp32*/ +**/build_esp32c*/ +**/build_esp32s*/ +**/build_esp32h*/ +**/build_esp32p*/ +**/build_linux*/ + +# Examples and test app builds +examples/**/build/ +examples/**/build_esp32*/ +examples/**/build_esp32c*/ +examples/**/build_esp32s*/ +examples/**/build_esp32h*/ +examples/**/build_esp32p*/ +examples/**/sdkconfig +examples/**/sdkconfig.old +examples/**/dependencies.lock +examples/**/managed_components/ + +# Test application builds (specific build directories, not source) +test/apps/**/build/ +test/apps/**/build_esp32*/ +test/apps/**/build_esp32c*/ +test/apps/**/build_esp32s*/ +test/apps/**/build_esp32h*/ +test/apps/**/build_esp32p*/ +test/apps/**/sdkconfig +test/apps/**/sdkconfig.old +test/apps/**/dependencies.lock +test/apps/**/managed_components/ + +# Host test builds +test/host/build/ +test/host/sdkconfig +test/host/sdkconfig.old +test/host/dependencies.lock +test/host/managed_components/ + +# idf-ci generated files +app_info_*.txt +size_info_*.txt +compile_commands.json +*.log + +# Python cache and environments +__pycache__/ +*.pyc +*.pyo +.venv/ +.cache/ + +# Coverage and test results +**/coverage.xml +**/coverage.html +**/junit.xml +**/pytest_*.xml +**/test_results_*.xml + +# Documentation builds +docs/_build/ +docs/build/ + +# Distribution/packaging +dist/ +build/ +*.egg-info/ + +# CI/CD artifacts +build_child_pipeline.yml diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/build.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/build.yml new file mode 100644 index 000000000..84e536a17 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/build.yml @@ -0,0 +1,27 @@ +# Note: No need to run build and test on master branch since we use FastForward merge strategy and so each merge request +# is tested and then merged onto top of master branch. + +.build_template: + stage: build + tags: + - build + - internet + script: + - pip install -U 'idf-ci<1' + - idf-ci build run + +build_idf_v5.3: + extends: .build_template + image: espressif/idf:release-v5.3 + +build_idf_v5.4: + extends: .build_template + image: espressif/idf:release-v5.4 + +build_idf_v5.5: + extends: .build_template + image: espressif/idf:release-v5.5 + +build_idf_latest: + extends: .build_template + image: espressif/idf:latest diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/deploy.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/deploy.yml new file mode 100644 index 000000000..38920d139 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/deploy.yml @@ -0,0 +1,29 @@ +push_master_to_github: + stage: deploy + image: ${CI_DOCKER_REGISTRY}/esp32-ci-env + tags: + - build + only: + refs: + - master + - idf + when: on_success + variables: + GIT_STRATEGY: clone + script: + - source ${CI_PROJECT_DIR}/.gitlab/ci/utils.sh + - add_github_remote "$GH_PUSH_KEY" "$GH_PUSH_REPO" + - git push github HEAD:${CI_COMMIT_REF_NAME} + +upload_to_component_manager: + stage: deploy + image: python:3.10-alpine + tags: + - deploy + rules: + - if: '$CI_COMMIT_BRANCH == "master"' + script: + - pip install idf-component-manager + - export IDF_COMPONENT_API_TOKEN=${MQTT_COMPONENT_API_KEY} + - export COMP_VERSION=$(grep 'version:' idf_component.yml | head -n 1 | awk '{print $2}' | tr -d '"') + - compote component upload --namespace=espressif --name=mqtt --allow-existing --version=${COMP_VERSION} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/docs.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/docs.yml new file mode 100644 index 000000000..5402d094e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/docs.yml @@ -0,0 +1,82 @@ +variables: + # System environment + ESP_DOCS_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env-v5.4:1-1" + ESP_DOCS_PATH: "$CI_PROJECT_DIR" + +docs_build: + stage: build + image: $ESP_DOCS_ENV_IMAGE + tags: + - build_docs + variables: + # Set Python buffering for better CI output + PYTHONUNBUFFERED: 1 + TYPE: "preview" + DOCS_BUILD_DIR: "${CI_PROJECT_DIR}/docs/_build/" + artifacts: + when: always + paths: + - docs/_build/*/*/*.txt + - docs/_build/*/*/html/* + expire_in: 4 days + before_script: + # Install ESP-IDF documentation build tool + - pip install -U pip + - pip install esp-docs linuxdoc + script: + - cd docs + - build-docs -t esp32 -l en + +.deploy_docs_template: + image: $ESP_DOCS_ENV_IMAGE + variables: + DOCS_BUILD_DIR: "${CI_PROJECT_DIR}/docs/_build/" + PYTHONUNBUFFERED: 1 + # ensure all tags are fetched, need to know the latest/stable tag for the docs + GIT_STRATEGY: clone + GIT_DEPTH: 0 + stage: test_deploy + tags: + - brew + - amd64 + script: + - source ${CI_PROJECT_DIR}/.gitlab/ci/utils.sh + # ensure all tags are fetched, need to know the latest/stable tag for the docs + - add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER + - export GIT_VER=$(git describe --always ${PIPELINE_COMMIT_SHA} --) + - pip install esp-docs + - deploy-docs + +deploy_docs_preview: + extends: + - .deploy_docs_template + except: + refs: + - master + needs: + - docs_build + variables: + TYPE: "preview" + DOCS_BUILD_DIR: "${CI_PROJECT_DIR}/docs/_build/" + DOCS_DEPLOY_PRIVATEKEY: "$DOCS_PREVIEW_PRIVATEKEY" + DOCS_DEPLOY_SERVER: "$DOCS_PREVIEW_SERVER" + DOCS_DEPLOY_SERVER_USER: "$DOCS_PREVIEW_SERVER_USER" + DOCS_DEPLOY_PATH: "$DOCS_PREVIEW_PATH" + DOCS_DEPLOY_URL_BASE: "$DOCS_PREVIEW_URL_BASE" + +deploy_docs_prod: + extends: + - .deploy_docs_template + stage: deploy + only: + refs: + - master + needs: + - docs_build + variables: + TYPE: "production" + DOCS_DEPLOY_PRIVATEKEY: "$DOCS_PROD_PRIVATEKEY" + DOCS_DEPLOY_SERVER: "$DOCS_PROD_SERVER" + DOCS_DEPLOY_SERVER_USER: "$DOCS_PROD_SERVER_USER" + DOCS_DEPLOY_PATH: "$DOCS_PROD_PATH" + DOCS_DEPLOY_URL_BASE: "$DOCS_PROD_URL_BASE" diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/ignore_build_warnings.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/ignore_build_warnings.txt new file mode 100644 index 000000000..302920da0 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/ignore_build_warnings.txt @@ -0,0 +1,5 @@ +Warning: Deprecated: Option '--flash_size' is deprecated. Use '--flash-size' instead. +Warning: Deprecated: Option '--flash_mode' is deprecated. Use '--flash-mode' instead. +Warning: Deprecated: Option '--flash_freq' is deprecated. Use '--flash-freq' instead. +Warning: Deprecated: Command 'sign_data' is deprecated. Use 'sign-data' instead. +Warning: Deprecated: Command 'extract_public_key' is deprecated. Use 'extract-public-key' instead. diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/test.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/test.yml new file mode 100644 index 000000000..86725ab46 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/test.yml @@ -0,0 +1,50 @@ +.add_gh_key_remote: &add_gh_key_remote | + curl -sSL ${CIT_LOADER_URL} | sh + source citools/import_functions + cit_add_ssh_key "${GH_PUSH_KEY}" + git remote remove github || true + git remote add github ${GH_PUSH_REPO} + +host_tests: + image: espressif/idf:latest + stage: test + tags: [build] + timeout: 1h + variables: + GIT_DEPTH: 1 + needs: [] + artifacts: + paths: + - "**/coverage.xml" + - "**/coverage.html" + expire_in: 1 week + when: always + reports: + junit: "**/junit.xml" + coverage_report: + coverage_format: cobertura + path: "**/coverage.xml" + before_script: + - pip install -U gcovr 'idf-ci<1' + script: + - idf-ci build run -t linux -p test/host + - cd test/host + - ./build_linux_coverage/host_mqtt_client_test.elf -r junit -o junit.xml + - cd ../.. + - gcovr --gcov-ignore-parse-errors -g -k -r . --html coverage.html -x coverage.xml + +check_remotes_sync: + stage: test_deploy + image: espressif/idf:latest + tags: + - build + - internet + needs: [] + except: + - master + - idf + script: + - *add_gh_key_remote + - git fetch --depth=1 origin master + - git fetch --depth=1 github master + - test "$(git rev-parse origin/master)" == "$(git rev-parse github/master)" diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/utils.sh b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/utils.sh new file mode 100644 index 000000000..2676b0918 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.gitlab/ci/utils.sh @@ -0,0 +1,26 @@ +function add_ssh_keys() { + local key_string="${1}" + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo -n "${key_string}" >~/.ssh/id_rsa_base64 + base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 >~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa +} +function add_doc_server_ssh_keys() { + local key_string="${1}" + local server_url="${2}" + local server_user="${3}" + add_ssh_keys "${key_string}" + echo -e "Host ${server_url}\n\tStrictHostKeyChecking no\n\tUser ${server_user}\n" >>~/.ssh/config +} + +function add_github_remote() { + local key_string="${1}" + local remote_url="${2}" + add_ssh_keys "${key_string}" + if ! grep -q "Host github.com" ~/.ssh/config 2>/dev/null; then + printf "Host github.com\n\tStrictHostKeyChecking no\n" >>~/.ssh/config + fi + git remote remove github || true + git remote add github "${remote_url}" +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_build_apps.toml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_build_apps.toml new file mode 100644 index 000000000..3117396e3 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_build_apps.toml @@ -0,0 +1,18 @@ +# check the latest documentation at +# https://docs.espressif.com/projects/idf-build-apps/en/latest/references/config_file.html + +config_rules = ['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'] + +recursive = true +check_warnings = true +keep_going = true + +build_dir = "build_@t_@w" +build_log_filename = "build.log" +size_json_filename = "size.json" + +collect_app_info_filename = "app_info_@p.txt" + +check_manifest_rules = true +manifest_filepatterns = ['**/.build-test-rules.yml'] +ignore_warning_files = ['.gitlab/ci/ignore_build_warnings.txt'] diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_ci.toml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_ci.toml new file mode 100644 index 000000000..993c081e2 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.idf_ci.toml @@ -0,0 +1,21 @@ +# ESP-MQTT idf-ci Configuration +[gitlab.artifacts] +build_job_filepatterns = [ + "**/build*/partition_table/*.bin", + "**/build*/bootloader/*.bin", + "**/build*/bootloader/*.map", + "**/build*/bootloader/*.elf", + "**/build*/config/sdkconfig.json", + "**/build*/*.map", + "**/build*/*.bin", + "**/build*/*.elf", + "**/build*/flasher_args.json", +] + +test_job_filepatterns = [ + "**/test_logs", + "**/XUNIT_RESULT_*.xml", +] + +[gitlab.build_pipeline] +runs_per_job = 15 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.travis.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.travis.yml new file mode 100644 index 000000000..4affec10d --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/.travis.yml @@ -0,0 +1,65 @@ +sudo: false +language: bash +os: + - linux + +addons: + apt: + packages: + - gperf + - python + - python-serial + +before_install: + # Save path to the git respository + - PROJECT_PATH=$(pwd) + # Have to checkout a temp branch for later in tree reference + - git checkout -b temporary_ref_branch + - CI_COMMIT_SHA=$(git rev-parse HEAD) + # Test building with latest (stable == v3.3 for now) IDF + - LTS_IDF=release/v3.3 + +install: + # Install ESP32 toochain following steps as desribed + # in http://esp-idf.readthedocs.io/en/latest/linux-setup.html + # + # Get required packages - already done above, see addons: apt: packages: + # - sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial + # Prepare directory for the toolchain + - mkdir -p ~/esp + - cd ~/esp + # Download binary toolchain for the ESP32 + - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz + - tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz + # Get ESP-IDF from github (non-recursive to save time, later we update submodules for different versions) + - git clone https://github.com/espressif/esp-idf.git + # Set the path to ESP-IDF directory + - export IDF_PATH=~/esp/esp-idf + - python -m pip install --user -r $IDF_PATH/requirements.txt + # Setup build tool: xtensa-esp32-elf and idf.py + - export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin:$IDF_PATH/tools + +script: + # Legacy build with IDF < 3.2 + - cd $IDF_PATH + - git checkout v3.1 && git submodule update --init --recursive + - cd $PROJECT_PATH + - ./ci/modify_for_legacy_idf.sh ${LTS_IDF} || true + - cd $PROJECT_PATH/examples/tcp + - make defconfig + - make -j4 + # Build with v3.3 (LTS) IDF + - cd $IDF_PATH + - git checkout ${LTS_IDF} && git submodule update --init --recursive + - cd $IDF_PATH/components/mqtt/esp-mqtt + - git remote add local $PROJECT_PATH/.git + - git fetch local + - git reset --hard $CI_COMMIT_SHA + - cd $IDF_PATH/examples/protocols/mqtt/tcp + - idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/ssl + - idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/ws + - idf.py build + - cd $IDF_PATH/examples/protocols/mqtt/wss + - idf.py build \ No newline at end of file diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CHECKSUMS.json b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CHECKSUMS.json new file mode 100644 index 000000000..00493c9b3 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CHECKSUMS.json @@ -0,0 +1 @@ +{"version":"1.0","algorithm":"sha256","created_at":"2025-09-17T12:32:25.834794+00:00","files":[{"path":".build-test-rules.yml","size":3148,"hash":"5d65aecb48c2d6945a9d84b6ef63dab95687248ba0d5c96cde4264304da32790"},{"path":".editorconfig","size":595,"hash":"0592d873d53552677f17072f27cd86c519ba07b9ae09c50e12fd4897d0462e16"},{"path":".gitignore","size":1724,"hash":"1a31ebe938735595df33adf681fd3416428e958a82daf6ebd90e6c077cc16d90"},{"path":".idf_build_apps.toml","size":543,"hash":"0b2142700fd70a0682050577d0448cd690aee239417989bd54db16eefb6c4612"},{"path":".idf_ci.toml","size":485,"hash":"43b096498c023040f9d2ccc00a05e4d4eed3c890d36853e532caf780bd37291e"},{"path":".travis.yml","size":2196,"hash":"95750cb0110692f20f5df9e63a5c59fa985fd862d83a2cf109471f07debd4a26"},{"path":"CMakeLists.txt","size":622,"hash":"b6bd1b528700e2ff567ccba36a7692c34a8fcdce86a51a3481c2ea5be2514d62"},{"path":"Kconfig","size":6648,"hash":"4584e68452c6d1c02a935d7c9a988b6caa7e4976ca8e3dbb62ae2e9e1bc89135"},{"path":"LICENSE","size":11339,"hash":"20ed622a5f1a273258b415097609f6a236fb2f23f8c593c63e29e6cc77de0032"},{"path":"README.md","size":2097,"hash":"388922ed982a05c6e2b17eb9c583b7e73393bb66f52d8670b4e15674c8e690d5"},{"path":"coverage.html","size":15598,"hash":"fe96cfbbb16636d99a48aebcfa090cfb4dd249b80728d52e4795707eef203ff9"},{"path":"coverage.xml","size":383,"hash":"29f272a3fd2cf98fcfef1a5a83fa0fd06f6182708b3423fe8c92ff7227b640f9"},{"path":"idf_component.yml","size":587,"hash":"de5eb67afef8fd3f7f0cc769a83e3f133ac9b892c9135e8b69b131c3b6e47b9e"},{"path":"mqtt5_client.c","size":33116,"hash":"05973d1bd85e7844d6b21df80489e4ca63a4596338f995e30230c6c0d5cb23df"},{"path":"mqtt_client.c","size":99989,"hash":"4b24720b34c2bd44b0857a5251f5392663225c618595229540b35f1529663a9a"},{"path":"pytest.ini","size":708,"hash":"eb1e46050a53c5cc8a36306416977051cc96d095d558116310ec14099d14d50c"},{"path":"static-analysis-rules.yml","size":152,"hash":"5388e0824a15876b022b4b0efc09b17b9f25b0afa8f31e9520b0f4a0a02cc0b5"},{"path":"docs/Doxyfile","size":1617,"hash":"54bea31a8741fb1670aad8e1280c5162d56b4fd02823796c9c3fa1cb6a19dd4e"},{"path":"docs/conf_common.py","size":1005,"hash":"ec735c12fc953d84f1c0650f5675a285bf009ae5edd296df0d5b35f2ab53b4e3"},{"path":"docs/doxygen-known-warnings.txt","size":104,"hash":"2d963560507e50f94c3b1f6c058a0bc594eb5f2e329d826dfe9fc2dfe299bf68"},{"path":"docs/sphinx-known-warnings.txt","size":3209,"hash":"414485def9bc11d6c45c89624b1a2157fd24d4b13de715be43171631cad99414"},{"path":"include/mqtt5_client.h","size":14938,"hash":"8d2fc142e3e5a7ce7c1d2bac655df8722245bdd081cfe11f8e9d1824784584ec"},{"path":"include/mqtt_client.h","size":32426,"hash":"6b05afe12c80f9a77127f776c2ed787a67e22cba3be7ad66358efe470b221bd5"},{"path":"include/mqtt_supported_features.h","size":2648,"hash":"49f5d5b95c5d284083569c4cc7cc72df60410230d836d760ea6cf1b0a7961d4f"},{"path":"lib/mqtt5_msg.c","size":49594,"hash":"615bf5574776c65cd0496c99e1f6c3c31fe344da9aefbc7e3a77958f87e8c8cd"},{"path":"lib/mqtt_msg.c","size":20083,"hash":"f536a71cb75bcf054f997bda520c3a2f804daa29831ed18277fb3d8f9fe00087"},{"path":"lib/mqtt_outbox.c","size":6749,"hash":"14e8db1fae7006ed4647646d0086b7a91919260b4bb6f64f57cdc23a6840af9f"},{"path":"lib/platform_esp32_idf.c","size":1130,"hash":"31cff57ddebb2544feae66ff0488daf19af38cd28831f225d4775c2c8a33f7e4"},{"path":"test/host/CMakeLists.txt","size":666,"hash":"a75bf83c46f4cc0e1e7aea1cd748ccfbb32bf9216a262127ca977a2bfdcd7fd7"},{"path":"test/host/README.md","size":502,"hash":"5ac037b59086239896a5fafb491b55d4d025255e60ad9f5983cf17d6531d6e46"},{"path":"test/host/sdkconfig.ci.coverage","size":22,"hash":"3af786d60d341eebc0905750dddacc0639c623663ed638792c46f957a4baf3c7"},{"path":"test/host/sdkconfig.defaults","size":211,"hash":"1b722f26c279027f3a08001a389fc6ef41bf87e629e8e9f60c28936ac1d4f775"},{"path":"test/host/main/CMakeLists.txt","size":1083,"hash":"583d2601e09d238f698b9b43d78314cdbafddb7095de6db6ad04abd0778fcfef"},{"path":"test/host/main/Kconfig","size":177,"hash":"2b316639175c9ec220b7ae785765493e30f867f76c1dbb9617d5fa388c5815db"},{"path":"test/host/main/idf_component.yml","size":203,"hash":"b9385d15c2ac8400f5c857d224006e84c60da59e5188c232f5ee460cc09ccc70"},{"path":"test/host/main/test_mqtt_client.cpp","size":6752,"hash":"1dfb612ea88e6b36921572020fae116bde68de753ae890b9ff37e75db73582d3"},{"path":"test/host/mocks/include/sys/queue.h","size":2220,"hash":"24e7bd0df69cfb30e7460af398134075fa56bfadfbefa81a5bbaa0c9e012cc70"},{"path":"test/apps/common/CMakeLists.txt","size":188,"hash":"0f3d32701ae15c094170b549400f1d61450ac1e1395916fcb3622cc05e70fb21"},{"path":"test/apps/common/test_mqtt_connection.c","size":5352,"hash":"658463962b9866114ea5bdff6551522ee842445525426e283098f4d43b99b8a6"},{"path":"test/apps/mqtt/CMakeLists.txt","size":519,"hash":"fcfa074033b1b6f094832972f40a413a7e0293ccc0043d52d498bcdba6e02889"},{"path":"test/apps/mqtt/README.md","size":82,"hash":"05a6bd555a813916fb24460b83a691b94fc4bf09871b510a3c3493822037b36a"},{"path":"test/apps/mqtt/pytest_mqtt_ut.py","size":378,"hash":"1911a45931f086b5f39c6c0d6ab9fd158fc40a238cd1a2c3466db6b17764fb51"},{"path":"test/apps/mqtt/sdkconfig.ci.default","size":184,"hash":"be57ca92d356bfd36397babac94d690e5ba2e14ce7c83dae9360457a6d4ef959"},{"path":"test/apps/mqtt/sdkconfig.defaults","size":95,"hash":"b9002ecbf28b4125fef5770511c85b2f9ee04f14fbdd8110a5f5a03d6f9e4490"},{"path":"test/apps/mqtt5/CMakeLists.txt","size":520,"hash":"d87dbc309f001e8607f1da0fd746d4906783688dd8363f36e807c977063f73fa"},{"path":"test/apps/mqtt5/README.md","size":82,"hash":"05a6bd555a813916fb24460b83a691b94fc4bf09871b510a3c3493822037b36a"},{"path":"test/apps/mqtt5/pytest_mqtt5_ut.py","size":379,"hash":"c21608c95cc874c1673052689624a208e24a7a4a9393c898bd3d91581a60e7da"},{"path":"test/apps/mqtt5/sdkconfig.ci.default","size":184,"hash":"be57ca92d356bfd36397babac94d690e5ba2e14ce7c83dae9360457a6d4ef959"},{"path":"test/apps/mqtt5/sdkconfig.defaults","size":120,"hash":"cf7a6b828fa9bc5b7cb4900df31f5b560f61d3d487aa0783b00c747375b6bca1"},{"path":"test/apps/publish_connect_test/CMakeLists.txt","size":835,"hash":"be324b6b124e586144f8207bd2abc35b130632c78c617a61662a1051cbc6e3e9"},{"path":"test/apps/publish_connect_test/README.md","size":1238,"hash":"395413b6b9f47663959df3c3a34da8c67e8e84d2b3a83680c8dfd8464abed83d"},{"path":"test/apps/publish_connect_test/ca.crt","size":1135,"hash":"ddccb46bfeae064b591ea3d09ec16a68d57c78348a3557935f63ff0e9dfba826"},{"path":"test/apps/publish_connect_test/ca.der","size":797,"hash":"da8d302d190589b28a378ba41934db584aa45f2a1546348b3f7536a56d5b646c"},{"path":"test/apps/publish_connect_test/ca.key","size":1708,"hash":"54157361c60b97ce743fb8f875466311fd0e1f873224f16ef611bb8339cd638d"},{"path":"test/apps/publish_connect_test/client_inv.crt","size":1099,"hash":"8208370061d0d89d18e0f87b85c8d0879ff4fef46e4c99b32c84b116be905efb"},{"path":"test/apps/publish_connect_test/client_no_pwd.key","size":1704,"hash":"1d1df8ff79d756700952d4c4d16d8b5f9dc2a00069304cdabec79534a8ae09b0"},{"path":"test/apps/publish_connect_test/client_pwd.crt","size":1086,"hash":"f3b3ae6596c5bd59cb349921ffda34e086e3a259c8554f76b709e8992149d18e"},{"path":"test/apps/publish_connect_test/client_pwd.key","size":1886,"hash":"1eb44d11023b9af728a6e0f234754de14e29de176ba4fb6415f6edc59fa4732c"},{"path":"test/apps/publish_connect_test/pytest_mqtt_app.py","size":11374,"hash":"88db6ab27d5e17a317225ff53d41488dade5fdb82d5e1b0800074f4b3d9c9e25"},{"path":"test/apps/publish_connect_test/pytest_mqtt_publish_app.py","size":15180,"hash":"08f4daeb2923fcab3008202aaac5197de39d8044d190fad92337247b5d514306"},{"path":"test/apps/publish_connect_test/sdkconfig.ci.default","size":866,"hash":"114c1e7efde7ddf1b83ec97093614db699fe57d73e80c5d663c5838d68bd2b96"},{"path":"test/apps/publish_connect_test/sdkconfig.ci.local_broker","size":473,"hash":"d5a8fc690149ecdd65ad7d02e0bcfe999ffbe9ba42aa54aa198966d385166dc8"},{"path":"test/apps/publish_connect_test/server.key","size":1675,"hash":"e567ff3810f9440dcddb6fc14e2bf93a236f9413d8863f0ae8d3baf6796c7ac8"},{"path":"test/apps/publish_connect_test/main/CMakeLists.txt","size":250,"hash":"c8642ab0e5df5c8d2f128f027a5e54c25a9e28788acbb61e828f77b2cc1d72f3"},{"path":"test/apps/publish_connect_test/main/Kconfig.projbuild","size":2698,"hash":"ff7fbe8020c57bf0ad72cd15bb2930d38780d9e5ae1bf81a0204ae438f46aaad"},{"path":"test/apps/publish_connect_test/main/connect_test.c","size":7886,"hash":"da47055a1de5755b502ab22718d7fb2c9110e19d6cbafd313f9c27893f650998"},{"path":"test/apps/publish_connect_test/main/idf_component.yml","size":300,"hash":"f04be606ccd04822c07464a2f438b272e420ff2adc638094e963161e66b77af1"},{"path":"test/apps/publish_connect_test/main/mqtt_eclipseprojects_io.pem","size":1826,"hash":"177e1b8fc43b722b393f4200ff4d92e32deeffbb76fef5ee68d8f49c88cf9d32"},{"path":"test/apps/publish_connect_test/main/publish_connect_test.c","size":11287,"hash":"5802889ae473dae42f40c2d03a6c6877e115bfbb8146069b33f068866346389e"},{"path":"test/apps/publish_connect_test/main/publish_connect_test.h","size":1556,"hash":"b6860ff0f99d2d44e82e0465fc0d831fc59c7a8735ed18a1ea7a34d00aff2de7"},{"path":"test/apps/publish_connect_test/main/publish_test.c","size":9524,"hash":"cc447a94bb44325e1a88c5b6a2339e06ab192b7c5f85d1c913bf33226b8e55e4"},{"path":"test/apps/mqtt5/main/CMakeLists.txt","size":184,"hash":"f662a4161c94c83a80cdfc49752ce14a9fccc0f39199f073f7ede5bdfcc996bf"},{"path":"test/apps/mqtt5/main/Kconfig.projbuild","size":438,"hash":"c9ee0b12c2a4cc3860a5849e07bc6d56e392d3138023683e0b17f31c83f4a18e"},{"path":"test/apps/mqtt5/main/idf_component.yml","size":81,"hash":"01bec0cacc38aefd5f5b032321b51cf2678669e60f7cfe7c28d0e57ebb409e28"},{"path":"test/apps/mqtt5/main/test_mqtt5.c","size":5917,"hash":"f47ee72395036d275e501348862606868ae3e67d216075c077b1d1ba8cea7841"},{"path":"test/apps/mqtt5/main/test_mqtt5_client_broker.c","size":11590,"hash":"2846d59012da765713e4e9cccbea4f14408561acda9f62cc5a49ef52ef0d0433"},{"path":"test/apps/mqtt5/main/test_mqtt5_client_broker.h","size":1653,"hash":"b22dd1e5fc7c9aa86fd287b77328b0e50b4ef51fcc3dcb4a6b716224543012ca"},{"path":"test/apps/mqtt/main/CMakeLists.txt","size":280,"hash":"bf563d3e2058962f6258fd4e797f7833d5c392f2c497989a3f00d6aa5b6d567a"},{"path":"test/apps/mqtt/main/Kconfig.projbuild","size":438,"hash":"c9ee0b12c2a4cc3860a5849e07bc6d56e392d3138023683e0b17f31c83f4a18e"},{"path":"test/apps/mqtt/main/idf_component.yml","size":93,"hash":"f381001de37b61491ceb74caf5e8e753cbd3971fcf8fcdbc45e280b45ce183f1"},{"path":"test/apps/mqtt/main/test_mqtt.c","size":3893,"hash":"89282cbea9c052f6ff15dd198a0f94ba9373e3d947773d1299a6482925724f19"},{"path":"test/apps/mqtt/main/test_mqtt_client_broker.c","size":8839,"hash":"2b1f18d47b921c38d4ef13ab8bf89529ded91563aa5d3bea4b590bab7e6fd3a0"},{"path":"test/apps/mqtt/main/test_mqtt_client_broker.h","size":1641,"hash":"a37f3a5f84b2edf5b94673d98f7eaa11a8f6b51c0028ff476d0720e59d2ad94e"},{"path":"test/apps/common/include/test_mqtt_connection.h","size":373,"hash":"6af9cce1f3ea9d7010d227a18e4aa94e0a97d0780897b87d745d4b93a6d7d5c0"},{"path":"lib/include/mqtt5_client_priv.h","size":2405,"hash":"6c7b225be69b9cb6c14416b4ac153d6aa5544c00e3918da0bf96f8c4bee1ed58"},{"path":"lib/include/mqtt5_msg.h","size":6180,"hash":"86c50af4687528e27e940bbaf80d6247969a8bb52fa03e360f1817ceb975518f"},{"path":"lib/include/mqtt_client_priv.h","size":3891,"hash":"ee8f464f6cbf77a83468126bf22d91833b9c2b8985ba5860381acb99a655c565"},{"path":"lib/include/mqtt_config.h","size":3107,"hash":"1237445252e445f5fae23b2c9171ce101445667be9b8de1d87c4e34702eac948"},{"path":"lib/include/mqtt_msg.h","size":5746,"hash":"40be3eca3c6cd60ffe22d43ae5be0ac0d1a52b2e2152d95ece75b708e1ca245e"},{"path":"lib/include/mqtt_outbox.h","size":2197,"hash":"4eacd0383171e881053ed256147017adc24de2754130462367ff332ff03fd2fa"},{"path":"lib/include/platform.h","size":296,"hash":"54ebf11150b6ff7e0d0d075f779e9a78e49d74fa594251af4d04c1579d351c7b"},{"path":"lib/include/platform_esp32_idf.h","size":1057,"hash":"9ff4b5254413f07096edba16d836238baedefd8f06130f1b41f68c1aef77dfbb"},{"path":"examples/custom_outbox/CMakeLists.txt","size":1001,"hash":"b872815f45c40599c68de1a3325b4ece8be444ac36328bf89bcaab66f3b1732d"},{"path":"examples/custom_outbox/README.md","size":5184,"hash":"009c36deaa1e4fdfa6b33bd39f15a844bd8128d17f90971f1400d6adfade84a7"},{"path":"examples/custom_outbox/sdkconfig.ci.esp32c6","size":42,"hash":"6653345afbb8d5c69f9bf91a74b562dd46c294a1c010a588b352e0ee57ddf1c1"},{"path":"examples/custom_outbox/sdkconfig.defaults","size":97,"hash":"c232fdd54ac529504969b8ddcc5a3b35aff8d434ba96390a11838e2db0eaee91"},{"path":"examples/mqtt5/CMakeLists.txt","size":370,"hash":"f7f6a6fead2c0465dac0c76a9eb81821d2e16b6f1c1f8719b70b8ab3f6ca66aa"},{"path":"examples/mqtt5/README.md","size":4220,"hash":"c9dda1a58b8daac04d79e754dc9202f1a841b906104e8f456d3d64e90f826748"},{"path":"examples/mqtt5/pytest_mqtt5.py","size":2536,"hash":"ed760f8e537c9dda9e361337bd748e844bdaf709c47f4ee64a62a45c39c9c211"},{"path":"examples/mqtt5/sdkconfig.ci","size":342,"hash":"c63d1df38e0d67b266b5eda9ea1565815bc37e58e0ebfa456a8f44eda590af5e"},{"path":"examples/mqtt5/sdkconfig.defaults","size":25,"hash":"f7c2090e8fc46c205de9aadd0559955e4b60813a0b746db7f36c6744b1de28c7"},{"path":"examples/ssl/CMakeLists.txt","size":458,"hash":"09b4628767c43f54599616a3125810811ffce4dc0dab9b499bd447015d510acb"},{"path":"examples/ssl/README.md","size":3564,"hash":"a7b5817b1f1d105c45d7382b1d3d86b022fc36c337a41b6e00515715dd675653"},{"path":"examples/ssl/pytest_mqtt_ssl.py","size":5518,"hash":"3c0d93f5794477502692e7d5d197ecd663a1231809eab8d6b81ac035830b45cb"},{"path":"examples/ssl/sdkconfig.ci","size":799,"hash":"29b0688a821085bccda1492e36bcbf856d3a6f447a1e0f35d4bd57a5d2d99f17"},{"path":"examples/ssl_ds/CMakeLists.txt","size":824,"hash":"770efd0ba7cbac114c3d7a104b737abfef48ee31708a32931797c7dbba06736a"},{"path":"examples/ssl_ds/README.md","size":5530,"hash":"b9957d1f8687d4a8c84f87c7b0ac2ccce0bcb4042ac04c7182f2c80115cf99eb"},{"path":"examples/ssl_ds/partitions.csv","size":177,"hash":"24f1257782a2df023bc65260364b5c9d2bf51bd6adbb77e4eb1132356c676d68"},{"path":"examples/ssl_ds/sdkconfig.defaults","size":398,"hash":"ad76f67287d9cf78466129ac6fc3866528c186691b034981dba96dd2bc0d0577"},{"path":"examples/ssl_ds/sdkconfig.defaults.esp32h2","size":64,"hash":"3aff995924e7aef20d4c61e143a1865f38eb4d1924014bb1364020db2bb3853a"},{"path":"examples/ssl_mutual_auth/CMakeLists.txt","size":612,"hash":"5455aecbfc4a7ecfa3ce1afe696e1708c48c48bbdf054794a0edff97385298e3"},{"path":"examples/ssl_mutual_auth/README.md","size":3680,"hash":"e26fc8c401a2ebb86e45e2a743fdee238edcdfb028e8b65660c661fbda556016"},{"path":"examples/ssl_mutual_auth/sdkconfig.defaults","size":61,"hash":"5765b89fbc38d2773ee9cf5ba18ba9dc11b36d35140496e4814a79e2664566fc"},{"path":"examples/ssl_mutual_auth/sdkconfig.defaults.esp32c5","size":42,"hash":"6653345afbb8d5c69f9bf91a74b562dd46c294a1c010a588b352e0ee57ddf1c1"},{"path":"examples/ssl_mutual_auth/sdkconfig.defaults.esp32c6","size":42,"hash":"6653345afbb8d5c69f9bf91a74b562dd46c294a1c010a588b352e0ee57ddf1c1"},{"path":"examples/ssl_mutual_auth/sdkconfig.defaults.esp32c61","size":42,"hash":"6653345afbb8d5c69f9bf91a74b562dd46c294a1c010a588b352e0ee57ddf1c1"},{"path":"examples/ssl_psk/CMakeLists.txt","size":377,"hash":"125efcc26092f44c25d4999057e9b30af2869fdfd49d9c7c9b9ebd797c8836a0"},{"path":"examples/ssl_psk/README.md","size":3434,"hash":"195de8fee9bfd710d1515ba3b788db16dd6daa72c794ff6a26fa143ff4579636"},{"path":"examples/ssl_psk/sdkconfig.defaults","size":34,"hash":"821e05eaf372af317ef78a85f7eeb4ede94542ae3a27361971d15ebf80d9ce9a"},{"path":"examples/ssl_psk/sdkconfig.defaults.esp32c5","size":42,"hash":"6653345afbb8d5c69f9bf91a74b562dd46c294a1c010a588b352e0ee57ddf1c1"},{"path":"examples/ssl_psk/sdkconfig.defaults.esp32c6","size":42,"hash":"6653345afbb8d5c69f9bf91a74b562dd46c294a1c010a588b352e0ee57ddf1c1"},{"path":"examples/ssl_psk/sdkconfig.defaults.esp32c61","size":42,"hash":"6653345afbb8d5c69f9bf91a74b562dd46c294a1c010a588b352e0ee57ddf1c1"},{"path":"examples/tcp/CMakeLists.txt","size":373,"hash":"f63ad62560d2405c09beac72021cf3a2075673e422862823d5b49c72953a2116"},{"path":"examples/tcp/README.md","size":19224,"hash":"20d2e8b51d2c5196d08a3381d7d411b3debdd631d350b07d3473f6f906afbdcf"},{"path":"examples/tcp/pytest_mqtt_tcp.py","size":3642,"hash":"bb406e775a1d51f7b4cd158e7221c52c0f6b93a1b65863b1aa7a25e95f606447"},{"path":"examples/tcp/sdkconfig.ci","size":422,"hash":"54f668b27cb3ad19c10ed2e2ded73f12f009e86ebace337a2d31426632e8fc8f"},{"path":"examples/tcp/sdkconfig.ci.p4_eppp","size":182,"hash":"dfaf1bb40a2ad6c4fcc5e45713b30a26af7f9f3febefe2a6118d8108baba2094"},{"path":"examples/tcp/sdkconfig.ci.p4_wifi","size":98,"hash":"4b89fef2f2d4145b7d1c3a9ab843e584d7f4f00ae53c8dca903f895ce5fbc448"},{"path":"examples/tcp/sdkconfig.ci.ppp_connect","size":100,"hash":"977baff7c71bbdd5387b68d38a95d79177d2727e01ec2644750af0cf8c59b019"},{"path":"examples/ws/CMakeLists.txt","size":379,"hash":"b3a041e7ea1618c6e7c4842c0492e37ddec0f8c69773bd5be761768877b14841"},{"path":"examples/ws/README.md","size":2750,"hash":"f75c38abe84e96e7a8bcbc4d926cade57d80b7f45cb1a7d0ad12616283d9f5af"},{"path":"examples/ws/pytest_mqtt_ws_example.py","size":4107,"hash":"0e9aa67e88d84191a9015f07a2e05b98d900f1fc894da5fa95d767a974791d74"},{"path":"examples/ws/sdkconfig.ci","size":379,"hash":"465e344f384925435796a053f7c0d7704bbd81c00d7cafec08b3273dc85348b4"},{"path":"examples/wss/CMakeLists.txt","size":471,"hash":"2573e473265321aa836966d9300e961ca13ae8b29535274e4c7abdaeb622397d"},{"path":"examples/wss/README.md","size":3668,"hash":"abf6ca09a712fd3fa3cafa1ecc9944208ce0f35ef68625213c48af0469ca4c64"},{"path":"examples/wss/pytest_mqtt_wss_example.py","size":4261,"hash":"384fa7430531bc2d82e8b30a6301566b786c414362cd4293cb466d8c97b26feb"},{"path":"examples/wss/sdkconfig.ci","size":486,"hash":"1f7bb5d15ca76fe2170cdf14d40081fe078ce48938826899fa50975b35c43a94"},{"path":"examples/wss/main/CMakeLists.txt","size":137,"hash":"a5c4a973356fb78f8750946fb88d88da48555428d8a4b64fbe4f237f47ede634"},{"path":"examples/wss/main/Kconfig.projbuild","size":601,"hash":"076928b4213427f8afc3a36f91ded021695817ea96b4d51d7c6e3d96984da1e9"},{"path":"examples/wss/main/app_main.c","size":5012,"hash":"51d9625834ce5d699a90b2d17a9961ef3ce5686f865263a0a60f8dc12cf0a0e0"},{"path":"examples/wss/main/idf_component.yml","size":151,"hash":"c0f5b42698e8774ad57951b73c5d5f69197975a29b8cc4added119730ca77530"},{"path":"examples/wss/main/mqtt_eclipseprojects_io.pem","size":1826,"hash":"177e1b8fc43b722b393f4200ff4d92e32deeffbb76fef5ee68d8f49c88cf9d32"},{"path":"examples/ws/main/CMakeLists.txt","size":137,"hash":"a5c4a973356fb78f8750946fb88d88da48555428d8a4b64fbe4f237f47ede634"},{"path":"examples/ws/main/Kconfig.projbuild","size":223,"hash":"17ab4dca8eca03919cc925f16c3427afe59a62799b36acfa45c57a72a0181968"},{"path":"examples/ws/main/app_main.c","size":5473,"hash":"6960b1c551b79b7d0cab7614402931edba2ed6797fe784179d240da3c589dde7"},{"path":"examples/ws/main/idf_component.yml","size":151,"hash":"c0f5b42698e8774ad57951b73c5d5f69197975a29b8cc4added119730ca77530"},{"path":"examples/tcp/main/CMakeLists.txt","size":138,"hash":"616803f5a7096a312dd0e6c8174c707754b99a3aa93f51be3c8caa43dcc03662"},{"path":"examples/tcp/main/Kconfig.projbuild","size":289,"hash":"3c9a63b6def6d2a7709d61a6471824a0c5a23bf3c0e081b1003a420d7c4c0277"},{"path":"examples/tcp/main/app_main.c","size":6025,"hash":"4f7e16a458ced882106524aca47678be51451241392ac532644316193b8335e1"},{"path":"examples/tcp/main/idf_component.yml","size":350,"hash":"fbbeb42b0c08542897d2641801e5d39f6b7ff17cb4c3c91dcca1244cdedef7fd"},{"path":"examples/ssl_psk/main/CMakeLists.txt","size":137,"hash":"a5c4a973356fb78f8750946fb88d88da48555428d8a4b64fbe4f237f47ede634"},{"path":"examples/ssl_psk/main/app_main.c","size":5302,"hash":"cade7b6ce79f5128cb052a51d4f6e43fc1aba1f85623e0022cd9b63c6f280ae2"},{"path":"examples/ssl_psk/main/idf_component.yml","size":151,"hash":"c0f5b42698e8774ad57951b73c5d5f69197975a29b8cc4added119730ca77530"},{"path":"examples/ssl_mutual_auth/main/CMakeLists.txt","size":137,"hash":"a5c4a973356fb78f8750946fb88d88da48555428d8a4b64fbe4f237f47ede634"},{"path":"examples/ssl_mutual_auth/main/app_main.c","size":6024,"hash":"29320351a92255ec4acaf47ced0b3dee58b16a8207da790b6f736685447e0516"},{"path":"examples/ssl_mutual_auth/main/client.crt","size":77,"hash":"25fad8bcc56d47c66a23431921b91d44d2b9366f6949b5efc578f2af5ecc3ff4"},{"path":"examples/ssl_mutual_auth/main/client.key","size":69,"hash":"b8f709f7213eee2e73a2db7d41cc8eea79fed1fa3ccd0302b4303bf2f7bef443"},{"path":"examples/ssl_mutual_auth/main/idf_component.yml","size":151,"hash":"c0f5b42698e8774ad57951b73c5d5f69197975a29b8cc4added119730ca77530"},{"path":"examples/ssl_mutual_auth/main/mosquitto.org.crt","size":1452,"hash":"45612492b0690dc1f16b97c2df2d1649fababcc1bf52ca0c12935dbda00ad7e6"},{"path":"examples/ssl_ds/main/CMakeLists.txt","size":128,"hash":"7a64b2072f11c6455560ac42e585504339d9c26ddd5531df296ccd67e17c62bd"},{"path":"examples/ssl_ds/main/app_main.c","size":5586,"hash":"e9be245f7bf2ddf7684a714f2222782554f9d401eaede49fab173ff54db04536"},{"path":"examples/ssl_ds/main/idf_component.yml","size":191,"hash":"86ad970e52663aba7d977db6a5aacf92a72b4b3aa2ebffd60b862a9dfb8d2c94"},{"path":"examples/ssl_ds/main/mosquitto.org.crt","size":1456,"hash":"0ceb5dcc23f6216941d0ca68bbf3c9356c32dd2acd9149c60460fbf48fb2dc3b"},{"path":"examples/ssl/main/CMakeLists.txt","size":163,"hash":"719fa26a6a472355f326c90b4d950b11a4e2fd3c9eb8decae8d0d9f44c2c1958"},{"path":"examples/ssl/main/Kconfig.projbuild","size":849,"hash":"9a02eb5733e5ffe87e9415073372e9a618561a2443d66c92a14b39ae6545a206"},{"path":"examples/ssl/main/app_main.c","size":6900,"hash":"80cf5ad0fab1ee37145dd1c7a0be40c28ad317a2ea632cecbda0023caab06f17"},{"path":"examples/ssl/main/idf_component.yml","size":151,"hash":"c0f5b42698e8774ad57951b73c5d5f69197975a29b8cc4added119730ca77530"},{"path":"examples/ssl/main/mqtt_eclipseprojects_io.pem","size":1826,"hash":"177e1b8fc43b722b393f4200ff4d92e32deeffbb76fef5ee68d8f49c88cf9d32"},{"path":"examples/mqtt5/main/CMakeLists.txt","size":138,"hash":"616803f5a7096a312dd0e6c8174c707754b99a3aa93f51be3c8caa43dcc03662"},{"path":"examples/mqtt5/main/Kconfig.projbuild","size":289,"hash":"3c9a63b6def6d2a7709d61a6471824a0c5a23bf3c0e081b1003a420d7c4c0277"},{"path":"examples/mqtt5/main/app_main.c","size":12375,"hash":"f459e7027e6b763917e7cdc04d33c9ee7c1229d927f74f2f08a2337e7c611180"},{"path":"examples/mqtt5/main/idf_component.yml","size":151,"hash":"c0f5b42698e8774ad57951b73c5d5f69197975a29b8cc4added119730ca77530"},{"path":"examples/custom_outbox/main/CMakeLists.txt","size":159,"hash":"6da8fcc6003d843f2aedab6adf2c0273e5d4b3421e77be8c95636250911674b7"},{"path":"examples/custom_outbox/main/Kconfig.projbuild","size":289,"hash":"3c9a63b6def6d2a7709d61a6471824a0c5a23bf3c0e081b1003a420d7c4c0277"},{"path":"examples/custom_outbox/main/app_main.c","size":6448,"hash":"9a7e6802f5b680cb3b5a76976e1e115fa8e7ac269711479094f6d48becd9742a"},{"path":"examples/custom_outbox/main/custom_outbox.cpp","size":13353,"hash":"a32a650d9cb60cf88e4c5ab1415fcbb657459362e375417e5adcd702cb5de8a2"},{"path":"examples/custom_outbox/main/idf_component.yml","size":151,"hash":"c0f5b42698e8774ad57951b73c5d5f69197975a29b8cc4added119730ca77530"},{"path":"docs/en/conf.py","size":783,"hash":"6021c0a8b65c5d26585dab132f77149a2bb3e69fb9cab0d31a29a8869e9d0fd9"},{"path":"docs/en/index.rst","size":12597,"hash":"385b3ede3568af22a8a0dc905269cf54b2463a952de5bf7af6f13b453a5c32b0"},{"path":"docs/zh_CN/conf.py","size":786,"hash":"bf9fd2b51606aab8f9bafa68466a351fc1f6685e534b98acc55b52b048208ef4"},{"path":"docs/zh_CN/index.rst","size":11756,"hash":"f41eced579b912d51e59810c4cd28529a32946a4702863b1f011d9cfb9cd8102"},{"path":"docs/_build/en/esp32/IDF_TARGET-substitutions.txt","size":660,"hash":"a4d3e89430802cbb6838a4a6afb18919a8a5c8756d49a2a879513b729f6a3b1f"},{"path":"docs/_build/en/esp32/doxygen-warning-log-sanitized.txt","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"docs/_build/en/esp32/doxygen-warning-log.txt","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"docs/_build/en/esp32/sphinx-warning-log-sanitized.txt","size":3209,"hash":"414485def9bc11d6c45c89624b1a2157fd24d4b13de715be43171631cad99414"},{"path":"docs/_build/en/esp32/sphinx-warning-log.txt","size":4229,"hash":"6c1420326f5f52873268c18b78a8472611960c87ae74825fb772a5eddcc6baf0"},{"path":"docs/_build/en/esp32/html/.buildinfo","size":230,"hash":"0c8530e50a587a0b93464e3aadcf61cc38097f9f47c537def22f5fbb8cb7798f"},{"path":"docs/_build/en/esp32/html/genindex.html","size":49699,"hash":"8788be942d08dbb5fa15b0b2b7a3c6386518d8307bc38bff595414ecb7f330a2"},{"path":"docs/_build/en/esp32/html/index.html","size":331840,"hash":"cb91443d6375be67d93bde2f06a051e1a400367827abb72dbbb103880b2995d6"},{"path":"docs/_build/en/esp32/html/objects.inv","size":11285,"hash":"c47787bdf475a0a2c5f4fafc9b0cdd77ec0afe4ab750d7d410a790ebefe0f9a6"},{"path":"docs/_build/en/esp32/html/search.html","size":5484,"hash":"25414e97c45b868865f7aeb0083c8f8b1af9f81f52c5dd6b81acce9427483da0"},{"path":"docs/_build/en/esp32/html/searchindex.js","size":97481,"hash":"600ff49591e598a95af34ba2a615900d183d1829b2f7692c6f05e27ee7800170"},{"path":"docs/_build/en/esp32/html/_sources/index.rst.txt","size":12597,"hash":"385b3ede3568af22a8a0dc905269cf54b2463a952de5bf7af6f13b453a5c32b0"},{"path":"docs/_build/en/esp32/html/_static/DejaVuSans.ttf","size":720856,"hash":"4a2438171a9144a2c698a36a64b10116c4c9db9112cd12361296f9eb0bd8cbed"},{"path":"docs/_build/en/esp32/html/_static/NotoSansSC-Regular.otf","size":8665020,"hash":"9cfd9daa651014e66cb9816c8b8995c3f95bc25d315dfd697c520652f28687db"},{"path":"docs/_build/en/esp32/html/_static/_sphinx_javascript_frameworks_compat.js","size":4289,"hash":"480a2c7377252c14a11bca4d3a49dfa16ea540a998fa637fae0189aee1b89113"},{"path":"docs/_build/en/esp32/html/_static/basic.css","size":15059,"hash":"b2fe2bbe6f4ee4946c1e39e760feda90658531622978f8fb8e162746be3bd37c"},{"path":"docs/_build/en/esp32/html/_static/check-solid.svg","size":313,"hash":"edfc4de8b5af9662c19d74d0ef059deb00283f6b1ae21dfcc8e052d5617a1c7f"},{"path":"docs/_build/en/esp32/html/_static/clipboard.min.js","size":9031,"hash":"261ffa06f381039cf7d18984d1364c59f3c2b9b60b1fa05d5f9c8c152e4d5be5"},{"path":"docs/_build/en/esp32/html/_static/copy-button.svg","size":411,"hash":"8cf972ac6d0873154c8245eab96a509026ee132f03bf68ec79fdfe3fa7b03a05"},{"path":"docs/_build/en/esp32/html/_static/copybutton.css","size":2010,"hash":"5695e324fd258ce13f353545d543b75a28724a77a5b256fca338126210547d26"},{"path":"docs/_build/en/esp32/html/_static/copybutton.js","size":7479,"hash":"d9a85b63a47b50a2ec0336640175215d581dda5ee3f59259bc54e4b7fe83c6d6"},{"path":"docs/_build/en/esp32/html/_static/copybutton_funcs.js","size":2198,"hash":"858bf2ca435bc8029b7c0684c68d5d4990598d8afb4175bdac77eb2a963d05ec"},{"path":"docs/_build/en/esp32/html/_static/doctools.js","size":4472,"hash":"3d62b81f63b0418a39a8f5a323203d88ddafc8c5226f86d311970025d86d7b6c"},{"path":"docs/_build/en/esp32/html/_static/documentation_options.js","size":421,"hash":"e44fc9a43f54b703e99bfe35d445bd6806ff9b2928725985c4205060b32cb82f"},{"path":"docs/_build/en/esp32/html/_static/espressif-logo.svg","size":3956,"hash":"e0deb0b2e6f60753551ebaf3f77236a85765573f33bcd91adb2d078c8bffc845"},{"path":"docs/_build/en/esp32/html/_static/espressif2.pdf","size":67271,"hash":"db83d4e439de89ec7d405fc6089124c9367bfd1d38bd4f2de5582efb6b1bf85d"},{"path":"docs/_build/en/esp32/html/_static/file.png","size":286,"hash":"5c4bc9a16aebf38c4b950f59b8e501ca36495328cb9eb622218bce9064a35e3e"},{"path":"docs/_build/en/esp32/html/_static/jquery.js","size":89501,"hash":"ff1523fb7389539c84c65aba19260648793bb4f5e29329d2ee8804bc37a3fe6e"},{"path":"docs/_build/en/esp32/html/_static/language_data.js","size":4758,"hash":"95b1d44e1ba5a3155d89f8427a3b2c981158f956bf48b9cdf0030265e8b7a609"},{"path":"docs/_build/en/esp32/html/_static/minus.png","size":90,"hash":"47e7fc50db3699f1ca41ce9a2ffa202c00c5d1d5180c55f62ba859b1bd6cc008"},{"path":"docs/_build/en/esp32/html/_static/plus.png","size":90,"hash":"54115199b96a130cba02147c47c0deb43dcc9b9f08b5162bba8642b34980ac63"},{"path":"docs/_build/en/esp32/html/_static/pygments.css","size":4929,"hash":"1accd27ffdaa3456771214dbc2f4d841d9ebe9324da2b23ac0333d35756f25e5"},{"path":"docs/_build/en/esp32/html/_static/searchtools.js","size":18215,"hash":"5b9facbcb36e5e15e409e2db42439fb8cbc1e43275e337a645bb3c76c3191b93"},{"path":"docs/_build/en/esp32/html/_static/sphinx_highlight.js","size":4712,"hash":"0a20464b65797522de18421a7db1a0851a26aae6dd06b7109d442236313c27ee"},{"path":"docs/_build/en/esp32/html/_static/theme_overrides.css","size":1151,"hash":"baa7330647b71de6f9234d63d3ab13aa41e07eb8f908e0191fc1655d9669a921"},{"path":"docs/_build/en/esp32/html/_static/css/badge_only.css","size":3229,"hash":"3ebb8a7c4ab074330ec0c24a9bcb32b6ced1c5eb45be7ef34b79193864337865"},{"path":"docs/_build/en/esp32/html/_static/css/theme.css","size":135452,"hash":"27839b5c27d745332b2d76a84dd0a7e669a3ce2ee065fb299f7531925c6d899b"},{"path":"docs/_build/en/esp32/html/_static/js/badge_only.js","size":934,"hash":"f784a162bf0ecdd9d8c289e6bc7c4b67afcc85583804b9ee10e20a3e7fcb64eb"},{"path":"docs/_build/en/esp32/html/_static/js/html5shiv-printshiv.min.js","size":4370,"hash":"b42a7e949a6e21d66b30fbbb4a22deafd9e0ccabc04f0fa2907fc6252fdf165f"},{"path":"docs/_build/en/esp32/html/_static/js/html5shiv.min.js","size":2734,"hash":"f6e0283561ddb33b140e14977ffad57163aa28f7e2e7ff15e51e1475b6657b60"},{"path":"docs/_build/en/esp32/html/_static/js/theme.js","size":26617,"hash":"e740bbf6fce2838609cc1fa0ee7615dcff117f183c0f4abc8e9773700af4b878"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/Roboto-Slab-Bold.woff","size":87624,"hash":"9fec87cadbe2413b255f1ec577573a83f1ca2e1c37aa023dbebcd3a7b864636a"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/Roboto-Slab-Bold.woff2","size":67312,"hash":"1a0c024dd1a267c52d5575469ffe8570d1e84164de7d393cf3414bafd17d7a0c"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/Roboto-Slab-Regular.woff","size":86288,"hash":"9f32630e2c0c5135bf1e86e36cb65b3932e4410644235bc2bd995e9c7f6ff117"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/Roboto-Slab-Regular.woff2","size":66444,"hash":"874e42222856d7af03b3f438d21d923a4280d47fe67c48510e2174a1579795ef"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/fontawesome-webfont.eot","size":165742,"hash":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/fontawesome-webfont.svg","size":444379,"hash":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/fontawesome-webfont.ttf","size":165548,"hash":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/fontawesome-webfont.woff","size":98024,"hash":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/fontawesome-webfont.woff2","size":77160,"hash":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-bold-italic.woff","size":323344,"hash":"980c8592e5488df256192c999e92db8fd302db8cd8909b7fa266a684e37e45f8"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-bold-italic.woff2","size":193308,"hash":"c0916a33340d063f7b05679e08031e729d1888444706f04804705da5966d895d"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-bold.woff","size":309728,"hash":"0e56b17d142eb366c8007031d14e34da48c70b4a9d9a0ca492e696a7bae45e1e"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-bold.woff2","size":184912,"hash":"ae88fc0d7a961832f809527d30bd3983a6866d42f66a56ade23f543681594db6"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-normal-italic.woff","size":328412,"hash":"26318a1467a5e5caf10b04cfa942d079632560cd7a29cec565fd1dc9f7ec5081"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-normal-italic.woff2","size":195704,"hash":"4465765f2f6eddcdad34ffd7cab559e56bc0e75e45e192f85e9562b0771481dc"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-normal.woff","size":309192,"hash":"5b9025dda4d7688e3311b0c17eddc501133b807def33effaef6593843cf5416e"},{"path":"docs/_build/en/esp32/html/_static/css/fonts/lato-normal.woff2","size":182708,"hash":"983b0caf336e8542214fc17019a4fc5e0360864b92806ca14d55c1fc1c2c5a0f"},{"path":".gitlab/ci/build.yml","size":663,"hash":"9a40bf33d42c916f0707294e97e7b754983f1516d77724dc57387945582ff091"},{"path":".gitlab/ci/deploy.yml","size":926,"hash":"8cc0ac9f2a8c9131b7491145e578d2cbd96185a74805e2ebb193e733b4fe45c7"},{"path":".gitlab/ci/docs.yml","size":2482,"hash":"7cf6686cdb78dc0a364bdd9548e21997db4234404d92cf3e49f45588cc8b87c2"},{"path":".gitlab/ci/ignore_build_warnings.txt","size":438,"hash":"0de186cccca179e476bd8078d45979831eb69f53ff7d1c2e0460f4deba39ac36"},{"path":".gitlab/ci/test.yml","size":1407,"hash":"afff3a9d2400dd49a0d1871825e667e21e64c1e5b6881f250a71db75bd962a01"},{"path":".gitlab/ci/utils.sh","size":822,"hash":"e681ea308d973609dac626a781f75f92426a6f5103cdc972f48992ec619e3fd5"}]} \ No newline at end of file diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CMakeLists.txt new file mode 100644 index 000000000..8f86e9d25 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/CMakeLists.txt @@ -0,0 +1,14 @@ +set(srcs mqtt_client.c lib/mqtt_msg.c lib/mqtt_outbox.c lib/platform_esp32_idf.c) + +if(CONFIG_MQTT_PROTOCOL_5) + list(APPEND srcs lib/mqtt5_msg.c mqtt5_client.c) +endif() + +list(TRANSFORM srcs PREPEND ${CMAKE_CURRENT_LIST_DIR}/) +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/include + PRIV_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/lib/include + REQUIRES esp_event tcp_transport + PRIV_REQUIRES esp_timer http_parser esp_hw_support heap + KCONFIG ${CMAKE_CURRENT_LIST_DIR}/Kconfig + ) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/Kconfig b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/Kconfig new file mode 100644 index 000000000..d438858b9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/Kconfig @@ -0,0 +1,190 @@ +menu "ESP-MQTT Configurations" + + config MQTT_PROTOCOL_311 + bool "Enable MQTT protocol 3.1.1" + default y + help + If not, this library will use MQTT protocol 3.1 + + config MQTT_PROTOCOL_5 + bool "Enable MQTT protocol 5.0" + default n + help + If not, this library will not support MQTT 5.0 + + config MQTT_TRANSPORT_SSL + bool "Enable MQTT over SSL" + default y + help + Enable MQTT transport over SSL with mbedtls + + config MQTT_TRANSPORT_WEBSOCKET + bool "Enable MQTT over Websocket" + default y + depends on WS_TRANSPORT + help + Enable MQTT transport over Websocket. + + config MQTT_TRANSPORT_WEBSOCKET_SECURE + bool "Enable MQTT over Websocket Secure" + default y + depends on MQTT_TRANSPORT_WEBSOCKET + depends on MQTT_TRANSPORT_SSL + help + Enable MQTT transport over Websocket Secure. + + config MQTT_MSG_ID_INCREMENTAL + bool "Use Incremental Message Id" + default n + help + Set this to true for the message id (2.3.1 Packet Identifier) to be generated + as an incremental number rather then a random value (used by default) + + config MQTT_SKIP_PUBLISH_IF_DISCONNECTED + bool "Skip publish if disconnected" + default n + help + Set this to true to avoid publishing (enqueueing messages) if the client is disconnected. + The MQTT client tries to publish all messages by default, even in the disconnected state + (where the qos1 and qos2 packets are stored in the internal outbox to be published later) + The MQTT_SKIP_PUBLISH_IF_DISCONNECTED option allows applications to override this behaviour + and not enqueue publish packets in the disconnected state. + + config MQTT_REPORT_DELETED_MESSAGES + bool "Report deleted messages" + default n + help + Set this to true to post events for all messages which were deleted from the outbox + before being correctly sent and confirmed. + + config MQTT_USE_CUSTOM_CONFIG + bool "MQTT Using custom configurations" + default n + help + Custom MQTT configurations. + + config MQTT_TCP_DEFAULT_PORT + int "Default MQTT over TCP port" + default 1883 + depends on MQTT_USE_CUSTOM_CONFIG + help + Default MQTT over TCP port + + config MQTT_SSL_DEFAULT_PORT + int "Default MQTT over SSL port" + default 8883 + depends on MQTT_USE_CUSTOM_CONFIG + depends on MQTT_TRANSPORT_SSL + help + Default MQTT over SSL port + + config MQTT_WS_DEFAULT_PORT + int "Default MQTT over Websocket port" + default 80 + depends on MQTT_USE_CUSTOM_CONFIG + depends on MQTT_TRANSPORT_WEBSOCKET + help + Default MQTT over Websocket port + + config MQTT_WSS_DEFAULT_PORT + int "Default MQTT over Websocket Secure port" + default 443 + depends on MQTT_USE_CUSTOM_CONFIG + depends on MQTT_TRANSPORT_WEBSOCKET + depends on MQTT_TRANSPORT_WEBSOCKET_SECURE + help + Default MQTT over Websocket Secure port + + config MQTT_BUFFER_SIZE + int "Default MQTT Buffer Size" + default 1024 + depends on MQTT_USE_CUSTOM_CONFIG + help + This buffer size using for both transmit and receive + + config MQTT_TASK_STACK_SIZE + int "MQTT task stack size" + default 6144 + depends on MQTT_USE_CUSTOM_CONFIG + help + MQTT task stack size + + config MQTT_DISABLE_API_LOCKS + bool "Disable API locks" + default n + depends on MQTT_USE_CUSTOM_CONFIG + help + Default config employs API locks to protect internal structures. It is possible to disable + these locks if the user code doesn't access MQTT API from multiple concurrent tasks + + config MQTT_TASK_PRIORITY + int "MQTT task priority" + default 5 + depends on MQTT_USE_CUSTOM_CONFIG + help + MQTT task priority. Higher number denotes higher priority. + + config MQTT_POLL_READ_TIMEOUT_MS + int "MQTT transport poll read timeut" + default 1000 + depends on MQTT_USE_CUSTOM_CONFIG + help + Timeout when polling underlying transport for read. + + config MQTT_EVENT_QUEUE_SIZE + int "Number of queued events." + default 1 + depends on MQTT_USE_CUSTOM_CONFIG + help + A value higher than 1 enables multiple queued events. + + config MQTT_TASK_CORE_SELECTION_ENABLED + bool "Enable MQTT task core selection" + help + This will enable core selection + + choice MQTT_TASK_CORE_SELECTION + depends on MQTT_TASK_CORE_SELECTION_ENABLED + prompt "Core to use ?" + config MQTT_USE_CORE_0 + bool "Core 0" + config MQTT_USE_CORE_1 + bool "Core 1" + endchoice + + config MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY + bool "Use external memory for outbox data" + default n + depends on MQTT_USE_CUSTOM_CONFIG + help + Set to true to use external memory for outbox data. + + config MQTT_CUSTOM_OUTBOX + bool "Enable custom outbox implementation" + default n + help + Set to true if a specific implementation of message outbox is needed (e.g. persistent outbox in NVM or + similar). + Note: Implementation of the custom outbox must be added to the mqtt component. These CMake commands + could be used to append the custom implementation to lib-mqtt sources: + idf_component_get_property(mqtt mqtt COMPONENT_LIB) + set_property(TARGET ${mqtt} PROPERTY SOURCES ${PROJECT_DIR}/custom_outbox.c APPEND) + + config MQTT_OUTBOX_EXPIRED_TIMEOUT_MS + int "Outbox message expired timeout[ms]" + default 30000 + depends on MQTT_USE_CUSTOM_CONFIG + help + Messages which stays in the outbox longer than this value before being published will be discarded. + + config MQTT_TOPIC_PRESENT_ALL_DATA_EVENTS + bool "Enable publish topic in all data events" + default n + depends on MQTT_USE_CUSTOM_CONFIG + help + Set to true to have publish topic in all data events. This changes the behaviour + when the message is bigger than the receive buffer size. The first event of the sequence + always have the topic. + Note: This will allocate memory to store the topic only in case of messge bigger than the buffer size. + +endmenu diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/LICENSE b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/LICENSE new file mode 100644 index 000000000..a623b53ff --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 Tuan PM + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/README.md new file mode 100644 index 000000000..f46f80bd5 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/README.md @@ -0,0 +1,52 @@ +# ESP32 MQTT Library + +![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/espressif/esp-mqtt/test-examples.yml?branch=master) +![License](https://img.shields.io/github/license/espressif/esp-mqtt) +![GitHub contributors](https://img.shields.io/github/contributors/espressif/esp-mqtt) + +## Features + +- Based on: +- Support MQTT over TCP, SSL with mbedtls, MQTT over Websocket, MQTT over Websocket Secure +- Easy to setup with URI +- Multiple instances (Multiple clients in one application) +- Support subscribing, publishing, authentication, will messages, keep alive pings and all 3 QoS levels (it should be a fully functional client). +- Support for MQTT 3.1.1 and 5.0 + +## How to use + +ESP-MQTT is available through the [ESP-IDF Component Manager](https://components.espressif.com/) and ships as a standard [ESP-IDF](https://github.com/espressif/esp-idf) component. + +- To add it via the Component Manager (recommended), declare the dependency in your project's `idf_component.yml`, for example: + + ```yaml + dependencies: + espressif/mqtt: "*" + ``` + + Replace `*` with the version constraint you want to track, or run `idf.py add-dependency espressif/mqtt`. +- For local development, clone this repository as `mqtt` so the component name matches: + + ```bash + git clone https://github.com/espressif/esp-mqtt.git mqtt + ``` + +## Documentation + +- Documentation of ESP-MQTT API: + +## License + +- Apache License 2.0 +- MQTT package origin: [Stephen Robinson - contiki-mqtt](https://github.com/esar/contiki-mqtt) +- Additional contributions by [@tuanpmt](https://twitter.com/tuanpmt) + +## Older IDF versions + +For [ESP-IDF](https://github.com/espressif/esp-idf) versions prior to IDFv3.2, please clone as a component of [ESP-IDF](https://github.com/espressif/esp-idf): + +``` +git submodule add https://github.com/espressif/esp-mqtt.git components/espmqtt +``` + +and checkout the [ESP-MQTT_FOR_IDF_3.1](https://github.com/espressif/esp-mqtt/tree/ESP-MQTT_FOR_IDF_3.1) tag diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/Doxyfile b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/Doxyfile new file mode 100644 index 000000000..35dabbc4a --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/Doxyfile @@ -0,0 +1,57 @@ +# This is Doxygen configuration file +# +# Doxygen provides over 260 configuration statements +# To make this file easier to follow, +# it contains only statements that are non-default +# +# NOTE: +# It is recommended not to change defaults unless specifically required +# Test any changes how they affect generated documentation +# Make sure that correct warnings are generated to flag issues with documented code +# +# For the complete list of configuration statements see: +# http://doxygen.nl/manual/config.html + + +PROJECT_NAME = "ESP-MQTT Programming Guide" + +## The 'INPUT' statement below is used as input by script 'gen-df-input.py' +## to automatically generate API reference list files heder_file.inc +## These files are placed in '_inc' directory +## and used to include in API reference documentation + +INPUT = \ + $(PROJECT_PATH)/include/mqtt_client.h \ + $(PROJECT_PATH)/include/mqtt5_client.h \ + $(PROJECT_PATH)/include/mqtt_supported_features.h + +## Get warnings for functions that have no documentation for their parameters or return value +## +WARN_NO_PARAMDOC = YES + +## Enable preprocessing and remove __attribute__(...) expressions from the INPUT files +## +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +PREDEFINED = \ + $(ENV_DOXYGEN_DEFINES) \ + +## Do not complain about not having dot +## +HAVE_DOT = NO + +## Generate XML that is required for Breathe +## +GENERATE_XML = YES +XML_OUTPUT = xml + +GENERATE_HTML = NO +HAVE_DOT = NO +GENERATE_LATEX = NO +GENERATE_MAN = YES +GENERATE_RTF = NO + +## Skip distracting progress messages +## +QUIET = YES diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/conf_common.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/conf_common.py new file mode 100644 index 000000000..7e21f2976 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/conf_common.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# +# Common (non-language-specific) configuration for Sphinx +# + +# type: ignore +# pylint: disable=wildcard-import +# pylint: disable=undefined-variable + +from __future__ import print_function, unicode_literals + +from esp_docs.conf_docs import * # noqa: F403,F401 + +# IDF_PATH validation removed - not needed for standalone component docs +# Only required when using ESP-IDF extensions that depend on IDF environment + + +extensions += ['sphinx_copybutton', + # Needed as a trigger for running doxygen + 'esp_docs.esp_extensions.dummy_build_system', + 'esp_docs.esp_extensions.run_doxygen' + ] + +# link roles config +github_repo = 'espressif/esp-mqtt' + +# context used by sphinx_idf_theme +html_context['github_user'] = 'espressif' +html_context['github_repo'] = 'esp-mqtt' + +# Extra options required by sphinx_idf_theme +project_slug = 'esp-mqtt' +versions_url = './_static/mqtt_docs_versions.js' + +idf_targets = [ 'esp32' ] +languages = ['en'] + + + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/doxygen-known-warnings.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/doxygen-known-warnings.txt new file mode 100644 index 000000000..1ad7d8a06 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/doxygen-known-warnings.txt @@ -0,0 +1,2 @@ +# Known doxygen warnings for ESP-MQTT documentation build +# Currently no known doxygen warnings expected \ No newline at end of file diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/conf.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/conf.py new file mode 100644 index 000000000..be95ec82c --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/conf.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# English Language RTD & Sphinx config file +# +# Uses ../conf_common.py for most non-language-specific settings. + +# Importing conf_common adds all the non-language-specific +# parts to this conf module +try: + from conf_common import * # noqa: F403,F401 +except ImportError: + import os + import sys + sys.path.insert(0, os.path.abspath('../')) + from conf_common import * # noqa: F403,F401 + +import datetime + +current_year = datetime.datetime.now().year + +# General information about the project. +project = u'ESP-MQTT Programming Guide' +copyright = u'2019 - {}, Espressif Systems (Shanghai) Co., Ltd'.format(current_year) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +language = 'en' diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/index.rst b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/index.rst new file mode 100644 index 000000000..52e1a916b --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/en/index.rst @@ -0,0 +1,208 @@ +ESP-MQTT +======== + +:link_to_translation:`zh_CN:[中文]` + +Overview +-------- + +ESP-MQTT is an implementation of `MQTT `__ protocol client, which is a lightweight publish/subscribe messaging protocol. Now ESP-MQTT supports `MQTT v5.0 `__. + + +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:`tcp` demonstrates how to implement MQTT communication over TCP (default port 1883). + + - :example:`ssl` demonstrates how to use SSL transport to implement MQTT communication over TLS (default port 8883). + + - :example:`ssl_ds` demonstrates how to use digital signature peripheral for authentication to implement MQTT communication over TLS (default port 8883). + + - :example:`ssl_mutual_auth` demonstrates how to use certificates for authentication to implement MQTT communication (default port 8883). + + - :example:`ssl_psk` demonstrates how to use pre-shared keys for authentication to implement MQTT communication over TLS (default port 8883). + + - :example:`ws` demonstrates how to implement MQTT communication over WebSocket (default port 80). + + - :example:`wss` demonstrates how to implement MQTT communication over WebSocket Secure (default port 443). + + - :example:`mqtt5` demonstrates how to use ESP-MQTT library to connect to broker with MQTT v5.0. + + - :example:`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 ` or its non-blocking counterpart :cpp:func:`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 ` 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 ` is used. A transmission retry for unacknowledged messages will occur after :cpp:member:`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 ` struct. The configuration can be made by usage of :cpp:member:`uri ` field or the combination of :cpp:member:`hostname `, :cpp:member:`transport ` and :cpp:member:`port `. Optionally, :cpp:member:`path ` could be set, this field is useful in WebSocket connections. + +The :cpp:member:`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 ` struct must be set. +The broker certificate may be set in PEM or DER format. To select DER, the equivalent :cpp:member:`certificate_len ` field must be set. Otherwise, a null-terminated string in PEM format should be provided to :cpp:member:`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:`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 ` field. + + * :cpp:member:`username `: pointer to the username used for connecting to the broker, can also be set by URI + * :cpp:member:`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 ` field. The client supports the following authentication methods: + + * :cpp:member:`password `: use a password by setting + * :cpp:member:`certificate ` and :cpp:member:`key `: mutual authentication with TLS, and both can be provided in PEM or DER format + * :cpp:member:`use_secure_element `: use secure element (ATECC608A) interfaced to ESP32 series + * :cpp:member:`ds_data `: use Digital Signature Peripheral available in some Espressif devices + +Session +^^^^^^^^^^^ + +For MQTT session-related configurations, :cpp:class:`session ` 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 ` struct. + + * :cpp:member:`topic `: pointer to the LWT message topic + * :cpp:member:`msg `: pointer to the LWT message + * :cpp:member:`msg_len `: length of the LWT message, required if :cpp:member:`msg ` is not null-terminated + * :cpp:member:`qos `: quality of service for the LWT message + * :cpp:member:`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 ` and :cpp:member:`total_data_len ` from event data updated to keep track of the fragmented message. +* ``MQTT_EVENT_ERROR``: The client has encountered an error. The field :cpp:type:`error_handle ` in the event data contains :cpp:type:`error_type ` that can be used to identify the error. The type of error determines which parts of the :cpp:type:`error_handle ` struct is filled. + +API Reference +------------- + +.. include-build-file:: inc/mqtt_client.inc +.. include-build-file:: inc/mqtt5_client.inc diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/sphinx-known-warnings.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/sphinx-known-warnings.txt new file mode 100644 index 000000000..cff318d32 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/sphinx-known-warnings.txt @@ -0,0 +1,37 @@ +mqtt_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:type:: struct esp_mqtt_event_t esp_mqtt_event_t'. +mqtt_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:type:: struct esp_mqtt_client_config_t esp_mqtt_client_config_t'. +mqtt_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enum:: esp_mqtt_event_id_t'. +mqtt_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enum:: esp_mqtt_connect_return_code_t'. +mqtt_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enum:: esp_mqtt_error_type_t'. +mqtt_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enum:: esp_mqtt_transport_t'. +mqtt_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enum:: esp_mqtt_protocol_ver_t'. +mqtt5_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enumerator:: __attribute__'. +index.rst:line: CRITICAL: Duplicate ID: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +index.rst:line: WARNING: Duplicate explicit target name: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +mqtt5_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enumerator:: __attribute__'. +index.rst:line: CRITICAL: Duplicate ID: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +index.rst:line: WARNING: Duplicate explicit target name: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +mqtt5_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enumerator:: __attribute__'. +index.rst:line: CRITICAL: Duplicate ID: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +index.rst:line: WARNING: Duplicate explicit target name: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +mqtt5_client.inc:line: WARNING: Duplicate C++ declaration, also defined at index:line. +Declaration is '.. cpp:enumerator:: __attribute__'. +index.rst:line: CRITICAL: Duplicate ID: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +index.rst:line: WARNING: Duplicate explicit target name: "mqtt5__client_8h_1a4504a6557b6b27d66613101e758693f4a8c1dfc1ccf00a08192611433ee7f17b4". +index.rst:line: WARNING: undefined label: 'config_mqtt_outbox_expired_timeout_ms' +index.rst:line: WARNING: undefined label: 'config_mqtt_report_deleted_messages' +index.rst:line: WARNING: undefined label: 'esp_tls_server_verification' +index.rst:line: WARNING: undefined label: 'config_mqtt_protocol_311' +index.rst:line: WARNING: undefined label: 'config_mqtt_transport_ssl' +index.rst:line: WARNING: undefined label: 'config_mqtt_transport_websocket' +index.rst:line: WARNING: undefined label: 'config_mqtt_custom_outbox' diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/conf.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/conf.py new file mode 100644 index 000000000..0eadade5c --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/conf.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# English Language RTD & Sphinx config file +# +# Uses ../conf_common.py for most non-language-specific settings. + +# Importing conf_common adds all the non-language-specific +# parts to this conf module +try: + from conf_common import * # noqa: F403,F401 +except ImportError: + import os + import sys + sys.path.insert(0, os.path.abspath('../')) + from conf_common import * # noqa: F403,F401 + +import datetime + +current_year = datetime.datetime.now().year + +# General information about the project. +project = u'ESP-MQTT Programming Guide' +copyright = u'2019 - {}, Espressif Systems (Shanghai) Co., Ltd'.format(current_year) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +language = 'zh_CN' diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/index.rst b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/index.rst new file mode 100644 index 000000000..eca9217c2 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/docs/zh_CN/index.rst @@ -0,0 +1,208 @@ +ESP-MQTT +======== + +:link_to_translation:`en:[English]` + +概述 +-------- + +ESP-MQTT 是 `MQTT `__ 协议客户端的实现,MQTT 是一种基于发布/订阅模式的轻量级消息传输协议。ESP-MQTT 当前支持 `MQTT v5.0 `__。 + + +特性 +-------- + + * 支持基于 TCP 的 MQTT、基于 Mbed TLS 的 SSL、基于 WebSocket 的 MQTT 以及基于 WebSocket Secure 的 MQTT + * 通过 URI 简化配置流程 + * 多个实例(一个应用程序中有多个客户端) + * 支持订阅、发布、认证、遗嘱消息、保持连接心跳机制以及 3 个服务质量 (QoS) 级别(组成全功能客户端) + + +应用示例 +------------------- + + - :example:`tcp` 演示了如何通过 TCP 实现 MQTT 通信(默认端口 1883)。 + + - :example:`ssl` 演示了如何使用 SSL 传输来实现基于 TLS 的 MQTT 通信(默认端口 8883)。 + + - :example:`ssl_ds` 演示了如何使用数字签名外设进行身份验证,以实现基于 TLS 的 MQTT 通信(默认端口 8883)。 + + - :example:`ssl_mutual_auth` 演示了如何使用证书进行身份验证实现 MQTT 通信(默认端口 8883)。 + + - :example:`ssl_psk` 演示了如何使用预共享密钥进行身份验证,以实现基于 TLS 的 MQTT 通信(默认端口 8883)。 + + - :example:`ws` 演示了如何通过 WebSocket 实现 MQTT 通信(默认端口 80)。 + + - :example:`wss` 演示了如何通过 WebSocket Secure 实现 MQTT 通信(默认端口 443)。 + + - :example:`mqtt5` 演示了如何使用 ESP-MQTT 库通过 MQTT v5.0 连接到代理。 + + - :example:`custom_outbox` 演示了如何自定义 ESP-MQTT 库中的 outbox。 + +MQTT 消息重传 +-------------------------- + +调用 :cpp:func:`esp_mqtt_client_publish ` 或其非阻塞形式 :cpp:func:`esp_mqtt_client_enqueue `,可以创建新的 MQTT 消息。 + +QoS 0 的消息将只发送一次,QoS 1 和 2 具有不同行为,因为协议需要执行额外步骤来完成该过程。 + +ESP-MQTT 库将始终重新传输未确认的 QoS 1 和 2 发布消息,以避免连接错误导致信息丢失,虽然 MQTT 规范要求仅在重新连接且 Clean Session 标志设置为 0 时重新传输(针对此行为,将 :cpp:member:`disable_clean_session ` 设置为 true)。 + +可能需要重传的 QoS 1 和 2 消息总是处于排队状态,但若使用 :cpp:func:`esp_mqtt_client_publish ` 则会立即进行第一次传输尝试。未确认消息的重传将在 :cpp:member:`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 ` 结构体的 :cpp:member:`uri ` 字段或者 :cpp:member:`hostname `、:cpp:member:`transport ` 以及 :cpp:member:`port ` 的组合,可以设置服务器地址。也可以选择设置 :cpp:member:`path `,该字段对 WebSocket 连接而言非常有用。 + +使用 :cpp:member:`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 ` 结构体。 +服务器证书可设置为 PEM 或 DER 格式。如要选择 DER 格式,必须设置等效 :cpp:member:`certificate_len ` 字段,否则应在 :cpp:member:`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:`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 ` 字段下包含所有客户端相关凭据。 + + * :cpp:member:`username `:指向用于连接服务器用户名的指针,也可通过 URI 设置 + * :cpp:member:`client_id `:指向客户端 ID 的指针,默认为 ``ESP32_%CHIPID%``,其中 ``%CHIPID%`` 是十六进制 MAC 地址的最后 3 个字节 + +=============== +认证 +=============== + +可以通过 :cpp:class:`authentication ` 字段设置认证参数。客户端支持以下认证方式: + + * :cpp:member:`password `:使用密码 + * * :cpp:member:`certificate ` 和 :cpp:member:`key `:进行双向 TLS 身份验证,PEM 或 DER 格式均可 + * :cpp:member:`use_secure_element `:使用 ESP32 系列中的安全元素 (ATECC608A) + * :cpp:member:`ds_data `:使用某些乐鑫设备的数字签名外设 + +会话 +^^^^^^^^^^^^ + +使用 :cpp:class:`session ` 字段进行 MQTT 会话相关配置。 + +======================== +遗嘱消息 (LWT) +======================== + +通过设置 :cpp:class:`last_will ` 结构体的以下字段,MQTT 会在一个客户端意外断开连接时通过遗嘱消息通知其他客户端。 + + * :cpp:member:`topic `:指向 LWT 消息主题的指针 + * :cpp:member:`msg `:指向 LWT 消息的指针 + * :cpp:member:`msg_len `:LWT 消息的长度,:cpp:member:`msg ` 不以空字符结尾时需要该字段 + * :cpp:member:`qos `:LWT 消息的服务质量 + * :cpp:member:`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 ` 和 :cpp:member:`total_data_len` 以跟踪碎片化消息。 +* ``MQTT_EVENT_ERROR``:客户端遇到错误。使用事件数据 :cpp:type:`error_handle ` 字段中的 :cpp:type:`error_type `,可以发现错误。错误类型决定 :cpp:type:`error_handle ` 结构体的哪些部分会被填充。 + +API 参考 +------------- + +.. include-build-file:: inc/mqtt_client.inc +.. include-build-file:: inc/mqtt5_client.inc diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/CMakeLists.txt new file mode 100644 index 000000000..746ab1cb3 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/CMakeLists.txt @@ -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}) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/README.md new file mode 100644 index 000000000..5b64bcdba --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/README.md @@ -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 +``` diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/CMakeLists.txt new file mode 100644 index 000000000..7423b6078 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS "." + PRIV_REQUIRES mqtt nvs_flash esp_netif + ) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/Kconfig.projbuild new file mode 100644 index 000000000..c11539fb8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/app_main.c new file mode 100644 index 000000000..b30bc46aa --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/app_main.c @@ -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 +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/custom_outbox.cpp b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/custom_outbox.cpp new file mode 100644 index 000000000..2db9d7e49 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/custom_outbox.cpp @@ -0,0 +1,393 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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(id); + *msg_type = static_cast(type); + *msg_qos = static_cast(qos); + return message.data(); + } + + [[nodiscard]] auto get_size() const noexcept + { + return message.size(); + } + +private: + std::pmr::vector 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 {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 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 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 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(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(outbox->get_allocator().resource()); + auto *pool_resource = static_cast(trace_pool->upstream_resource()); + auto *trace_monotonic = static_cast(pool_resource->upstream_resource()); + auto *monotonic_resource = static_cast(trace_monotonic->upstream_resource()); + + delete monotonic_resource; + delete trace_monotonic; + delete pool_resource; + delete trace_pool; + delete outbox; +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/idf_component.yml new file mode 100644 index 000000000..808c17483 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.ci.esp32c6 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.ci.esp32c6 new file mode 100644 index 000000000..1686559de --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.ci.esp32c6 @@ -0,0 +1 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.defaults b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.defaults new file mode 100644 index 000000000..11f90ceac --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/custom_outbox/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_MQTT_CUSTOM_OUTBOX=y +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/CMakeLists.txt new file mode 100644 index 000000000..fe8bdc9cd --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/README.md new file mode 100644 index 000000000..3e6c9c225 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/README.md @@ -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: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 +``` diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/CMakeLists.txt new file mode 100644 index 000000000..3bf739cf8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt nvs_flash esp_netif + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/Kconfig.projbuild new file mode 100644 index 000000000..c11539fb8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/app_main.c new file mode 100644 index 000000000..e82fd70a9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/app_main.c @@ -0,0 +1,290 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/idf_component.yml new file mode 100644 index 000000000..808c17483 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/pytest_mqtt5.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/pytest_mqtt5.py new file mode 100644 index 000000000..dc7063e95 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/pytest_mqtt5.py @@ -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') diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.ci b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.ci new file mode 100644 index 000000000..f4a0a7e40 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.ci @@ -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}" diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.defaults b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.defaults new file mode 100644 index 000000000..db60a2ab3 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/mqtt5/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_MQTT_PROTOCOL_5=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/CMakeLists.txt new file mode 100644 index 000000000..e41e1b8e4 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/README.md new file mode 100644 index 000000000..0407edad9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/README.md @@ -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 +``` + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/CMakeLists.txt new file mode 100644 index 000000000..d6ca62dc1 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt esp_partition nvs_flash esp_netif app_update + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/Kconfig.projbuild new file mode 100644 index 000000000..5e9357d1a --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/app_main.c new file mode 100644 index 000000000..ed5e04f1f --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/app_main.c @@ -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 +#include +#include +#include +#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 + +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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/idf_component.yml new file mode 100644 index 000000000..808c17483 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/mqtt_eclipseprojects_io.pem b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/mqtt_eclipseprojects_io.pem new file mode 100644 index 000000000..43b222a60 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/main/mqtt_eclipseprojects_io.pem @@ -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----- diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/pytest_mqtt_ssl.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/pytest_mqtt_ssl.py new file mode 100644 index 000000000..c34cea6e5 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/pytest_mqtt_ssl.py @@ -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() diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/sdkconfig.ci b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/sdkconfig.ci new file mode 100644 index 000000000..e8d4a52f6 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl/sdkconfig.ci @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/CMakeLists.txt new file mode 100644 index 000000000..acf7743cb --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/README.md new file mode 100644 index 000000000..f89d1726e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/README.md @@ -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 +``` diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/CMakeLists.txt new file mode 100644 index 000000000..055d4c563 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt esp_netif + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/app_main.c new file mode 100644 index 000000000..7b54cfbf8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/app_main.c @@ -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 +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/idf_component.yml new file mode 100644 index 000000000..1a3b32d7e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/idf_component.yml @@ -0,0 +1,6 @@ +dependencies: + espressif/esp_secure_cert_mgr: ^2.0.2 + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/mosquitto.org.crt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/mosquitto.org.crt new file mode 100644 index 000000000..8a3d44f57 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/main/mosquitto.org.crt @@ -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----- +--- diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/partitions.csv b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/partitions.csv new file mode 100644 index 000000000..1423949dc --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/partitions.csv @@ -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,1500K, diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults new file mode 100644 index 000000000..94e282f1d --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults.esp32h2 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults.esp32h2 new file mode 100644 index 000000000..dcbc3a5a7 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_ds/sdkconfig.defaults.esp32h2 @@ -0,0 +1,2 @@ +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_CONNECT_ETHERNET=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/CMakeLists.txt new file mode 100644 index 000000000..67ec43b37 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/README.md new file mode 100644 index 000000000..4750ff1ff --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/README.md @@ -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 +``` + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/CMakeLists.txt new file mode 100644 index 000000000..31650f39d --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt esp_wifi nvs_flash + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/app_main.c new file mode 100644 index 000000000..90ba71c51 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/app_main.c @@ -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 +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.crt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.crt new file mode 100644 index 000000000..7a3074b90 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.crt @@ -0,0 +1 @@ +Please paste your client certificate here (follow instructions in README.md) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.key b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.key new file mode 100644 index 000000000..a956f850c --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/client.key @@ -0,0 +1 @@ +Please paste here your client key (follow instructions in README.md) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/idf_component.yml new file mode 100644 index 000000000..808c17483 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/mosquitto.org.crt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/mosquitto.org.crt new file mode 100644 index 000000000..e76dbd855 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/main/mosquitto.org.crt @@ -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----- diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults new file mode 100644 index 000000000..99d317837 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults @@ -0,0 +1 @@ +# Empty file to trigger idf-ci to use esp32c6 specific file. diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c5 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c5 new file mode 100644 index 000000000..1686559de --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c5 @@ -0,0 +1 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c6 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c6 new file mode 100644 index 000000000..1686559de --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c6 @@ -0,0 +1 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c61 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c61 new file mode 100644 index 000000000..1686559de --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_mutual_auth/sdkconfig.defaults.esp32c61 @@ -0,0 +1 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/CMakeLists.txt new file mode 100644 index 000000000..d30f79616 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/README.md new file mode 100644 index 000000000..d5dbb1b48 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/README.md @@ -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 +``` + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/CMakeLists.txt new file mode 100644 index 000000000..31650f39d --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt esp_wifi nvs_flash + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/app_main.c new file mode 100644 index 000000000..ee9e81859 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/app_main.c @@ -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 +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/idf_component.yml new file mode 100644 index 000000000..808c17483 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults new file mode 100644 index 000000000..1df83e8f3 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_TLS_PSK_VERIFICATION=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c5 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c5 new file mode 100644 index 000000000..1686559de --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c5 @@ -0,0 +1 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c6 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c6 new file mode 100644 index 000000000..1686559de --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c6 @@ -0,0 +1 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c61 b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c61 new file mode 100644 index 000000000..1686559de --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ssl_psk/sdkconfig.defaults.esp32c61 @@ -0,0 +1 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/CMakeLists.txt new file mode 100644 index 000000000..d6f01d8da --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/README.md new file mode 100644 index 000000000..cb9f2cca0 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/README.md @@ -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 +``` + +### 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: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 +``` diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/CMakeLists.txt new file mode 100644 index 000000000..3bf739cf8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt nvs_flash esp_netif + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/Kconfig.projbuild new file mode 100644 index 000000000..c11539fb8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/app_main.c new file mode 100644 index 000000000..396aca669 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/app_main.c @@ -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 +#include +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/idf_component.yml new file mode 100644 index 000000000..7c166832e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/main/idf_component.yml @@ -0,0 +1,13 @@ +dependencies: + espressif/esp_hosted: + rules: + - if: target in [esp32p4, esp32h2] + version: 2.5.1 + espressif/esp_wifi_remote: + rules: + - if: target in [esp32p4, esp32h2] + version: '>=0.10,<2.0' + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/pytest_mqtt_tcp.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/pytest_mqtt_tcp.py new file mode 100644 index 000000000..f8deb23ff --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/pytest_mqtt_tcp.py @@ -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) + ) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci new file mode 100644 index 000000000..acf084a9e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_eppp b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_eppp new file mode 100644 index 000000000..8d423df47 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_eppp @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_wifi b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_wifi new file mode 100644 index 000000000..a2ea93a35 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.p4_wifi @@ -0,0 +1,3 @@ +CONFIG_IDF_TARGET="esp32p4" +CONFIG_EXAMPLE_CONNECT_WIFI=y +CONFIG_ESP_WIFI_REMOTE_LIBRARY_HOSTED=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.ppp_connect b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.ppp_connect new file mode 100644 index 000000000..7366a909e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/tcp/sdkconfig.ci.ppp_connect @@ -0,0 +1,3 @@ +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_CONNECT_PPP=y +CONFIG_EXAMPLE_CONNECT_PPP_DEVICE_UART=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/CMakeLists.txt new file mode 100644 index 000000000..bc5e2f109 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/README.md new file mode 100644 index 000000000..5d1724fd3 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/README.md @@ -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 +``` + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/CMakeLists.txt new file mode 100644 index 000000000..31650f39d --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt esp_wifi nvs_flash + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/Kconfig.projbuild new file mode 100644 index 000000000..e547a5156 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/app_main.c new file mode 100644 index 000000000..f518fdfac --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/app_main.c @@ -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 +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/idf_component.yml new file mode 100644 index 000000000..808c17483 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/pytest_mqtt_ws_example.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/pytest_mqtt_ws_example.py new file mode 100644 index 000000000..3ad6bd742 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/pytest_mqtt_ws_example.py @@ -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() diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/sdkconfig.ci b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/sdkconfig.ci new file mode 100644 index 000000000..eebcafdea --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/ws/sdkconfig.ci @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/CMakeLists.txt new file mode 100644 index 000000000..e62d88e13 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/README.md new file mode 100644 index 000000000..b401d3191 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/README.md @@ -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 +``` + + + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/CMakeLists.txt new file mode 100644 index 000000000..31650f39d --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "app_main.c" + PRIV_REQUIRES mqtt esp_wifi nvs_flash + INCLUDE_DIRS ".") diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/Kconfig.projbuild new file mode 100644 index 000000000..b6d1f593d --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/app_main.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/app_main.c new file mode 100644 index 000000000..3de96c0b9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/app_main.c @@ -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 +#include +#include +#include +#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(); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/idf_component.yml new file mode 100644 index 000000000..808c17483 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: '*' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/mqtt_eclipseprojects_io.pem b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/mqtt_eclipseprojects_io.pem new file mode 100644 index 000000000..43b222a60 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/main/mqtt_eclipseprojects_io.pem @@ -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----- diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/pytest_mqtt_wss_example.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/pytest_mqtt_wss_example.py new file mode 100644 index 000000000..cb4a22e37 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/pytest_mqtt_wss_example.py @@ -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() diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/sdkconfig.ci b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/sdkconfig.ci new file mode 100644 index 000000000..c8e8ef94a --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/examples/wss/sdkconfig.ci @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/idf_component.yml new file mode 100644 index 000000000..9bcfaee62 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/idf_component.yml @@ -0,0 +1,18 @@ +dependencies: + idf: + version: '>=5.3' +description: ESP-MQTT - A robust MQTT client library for ESP32 microcontrollers supporting + MQTT 3.1.1 and 5.0 protocols with multiple transport layers +documentation: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/mqtt.html +issues: https://github.com/espressif/esp-mqtt/issues +license: Apache-2.0 +maintainers: +- Espressif Systems +repository: https://github.com/espressif/esp-mqtt +tags: +- mqtt +- mqtt5 +- protocol +- networking +url: https://github.com/espressif/esp-mqtt +version: 1.0.0 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt5_client.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt5_client.h new file mode 100644 index 000000000..25254c410 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt5_client.h @@ -0,0 +1,286 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MQTT5_CLIENT_H_ +#define _MQTT5_CLIENT_H_ + +#include "mqtt_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct esp_mqtt_client *esp_mqtt5_client_handle_t; + +/** + * MQTT5 protocol error reason code, more details refer to MQTT5 protocol document section 2.4 + */ +typedef enum mqtt5_error_reason_code_t { + MQTT5_UNSPECIFIED_ERROR = 0x80, + MQTT5_MALFORMED_PACKET = 0x81, + MQTT5_PROTOCOL_ERROR = 0x82, + MQTT5_IMPLEMENT_SPECIFIC_ERROR = 0x83, + MQTT5_UNSUPPORTED_PROTOCOL_VER = 0x84, + MQTT5_INVAILD_CLIENT_ID __attribute__((deprecated)) = 0x85, + MQTT5_INVALID_CLIENT_ID = 0x85, + MQTT5_BAD_USERNAME_OR_PWD = 0x86, + MQTT5_NOT_AUTHORIZED = 0x87, + MQTT5_SERVER_UNAVAILABLE = 0x88, + MQTT5_SERVER_BUSY = 0x89, + MQTT5_BANNED = 0x8A, + MQTT5_SERVER_SHUTTING_DOWN = 0x8B, + MQTT5_BAD_AUTH_METHOD = 0x8C, + MQTT5_KEEP_ALIVE_TIMEOUT = 0x8D, + MQTT5_SESSION_TAKEN_OVER = 0x8E, + MQTT5_TOPIC_FILTER_INVAILD __attribute__((deprecated)) = 0x8F, + MQTT5_TOPIC_FILTER_INVALID = 0x8F, + MQTT5_TOPIC_NAME_INVAILD __attribute__((deprecated)) = 0x90, + MQTT5_TOPIC_NAME_INVALID = 0x90, + MQTT5_PACKET_IDENTIFIER_IN_USE = 0x91, + MQTT5_PACKET_IDENTIFIER_NOT_FOUND = 0x92, + MQTT5_RECEIVE_MAXIMUM_EXCEEDED = 0x93, + MQTT5_TOPIC_ALIAS_INVAILD __attribute__((deprecated)) = 0x94, + MQTT5_TOPIC_ALIAS_INVALID = 0x94, + MQTT5_PACKET_TOO_LARGE = 0x95, + MQTT5_MESSAGE_RATE_TOO_HIGH = 0x96, + MQTT5_QUOTA_EXCEEDED = 0x97, + MQTT5_ADMINISTRATIVE_ACTION = 0x98, + MQTT5_PAYLOAD_FORMAT_INVAILD __attribute__((deprecated)) = 0x99, + MQTT5_PAYLOAD_FORMAT_INVALID = 0x99, + MQTT5_RETAIN_NOT_SUPPORT = 0x9A, + MQTT5_QOS_NOT_SUPPORT = 0x9B, + MQTT5_USE_ANOTHER_SERVER = 0x9C, + MQTT5_SERVER_MOVED = 0x9D, + MQTT5_SHARED_SUBSCR_NOT_SUPPORTED = 0x9E, + MQTT5_CONNECTION_RATE_EXCEEDED = 0x9F, + MQTT5_MAXIMUM_CONNECT_TIME = 0xA0, + MQTT5_SUBSCRIBE_IDENTIFIER_NOT_SUPPORT = 0xA1, + MQTT5_WILDCARD_SUBSCRIBE_NOT_SUPPORT = 0xA2, +} esp_mqtt5_error_reason_code_t; + +/** + * MQTT5 user property handle + */ +typedef struct mqtt5_user_property_list_t *mqtt5_user_property_handle_t; + +/** + * MQTT5 protocol connect properties and will properties configuration, more details refer to MQTT5 protocol document section 3.1.2.11 and 3.3.2.3 + */ +typedef struct { + uint32_t session_expiry_interval; /*!< The interval time of session expiry */ + uint32_t maximum_packet_size; /*!< The maximum packet size that we can receive */ + uint16_t receive_maximum; /*!< The maximum pakcket count that we process concurrently */ + uint16_t topic_alias_maximum; /*!< The maximum topic alias that we support */ + bool request_resp_info; /*!< This value to request Server to return Response information */ + bool request_problem_info; /*!< This value to indicate whether the reason string or user properties are sent in case of failures */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ + uint32_t will_delay_interval; /*!< The time interval that server delays publishing will message */ + uint32_t message_expiry_interval; /*!< The time interval that message expiry */ + bool payload_format_indicator; /*!< This value is to indicator will message payload format */ + const char *content_type; /*!< This value is to indicator will message content type, use a MIME content type string */ + const char *response_topic; /*!< Topic name for a response message */ + const char *correlation_data; /*!< Binary data for receiver to match the response message */ + uint16_t correlation_data_len; /*!< The length of correlation data */ + mqtt5_user_property_handle_t will_user_property; /*!< The handle for will message user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_connection_property_config_t; + +/** + * MQTT5 protocol publish properties configuration, more details refer to MQTT5 protocol document section 3.3.2.3 + */ +typedef struct { + bool payload_format_indicator; /*!< This value is to indicator publish message payload format */ + uint32_t message_expiry_interval; /*!< The time interval that message expiry */ + uint16_t topic_alias; /*!< An interger value to identify the topic instead of using topic name string */ + const char *response_topic; /*!< Topic name for a response message */ + const char *correlation_data; /*!< Binary data for receiver to match the response message */ + uint16_t correlation_data_len; /*!< The length of correlation data */ + const char *content_type; /*!< This value is to indicator publish message content type, use a MIME content type string */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_publish_property_config_t; + +/** + * MQTT5 protocol subscribe properties configuration, more details refer to MQTT5 protocol document section 3.8.2.1 + */ +typedef struct { + uint16_t subscribe_id; /*!< A variable byte represents the identifier of the subscription */ + bool no_local_flag; /*!< Subscription Option to allow that server publish message that client sent */ + bool retain_as_published_flag; /*!< Subscription Option to keep the retain flag as published option */ + uint8_t retain_handle; /*!< Subscription Option to handle retain option */ + bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ + const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_subscribe_property_config_t; + +/** + * MQTT5 protocol unsubscribe properties configuration, more details refer to MQTT5 protocol document section 3.10.2.1 + */ +typedef struct { + bool is_share_subscribe; /*!< Whether subscribe is a shared subscription */ + const char *share_name; /*!< The name of shared subscription which is a part of $share/{share_name}/{topic} */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_unsubscribe_property_config_t; + +/** + * MQTT5 protocol disconnect properties configuration, more details refer to MQTT5 protocol document section 3.14.2.2 + */ +typedef struct { + uint32_t session_expiry_interval; /*!< The interval time of session expiry */ + uint8_t disconnect_reason; /*!< The reason that connection disconnet, refer to mqtt5_error_reason_code */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_set_user_property to set it */ +} esp_mqtt5_disconnect_property_config_t; + +/** + * MQTT5 protocol for event properties + */ +typedef struct { + bool payload_format_indicator; /*!< Payload format of the message */ + char *response_topic; /*!< Response topic of the message */ + int response_topic_len; /*!< Response topic length of the message */ + char *correlation_data; /*!< Correlation data of the message */ + uint16_t correlation_data_len; /*!< Correlation data length of the message */ + char *content_type; /*!< Content type of the message */ + int content_type_len; /*!< Content type length of the message */ + uint16_t subscribe_id; /*!< Subscription identifier of the message */ + mqtt5_user_property_handle_t user_property; /*!< The handle for user property, call function esp_mqtt5_client_delete_user_property to free the memory */ +} esp_mqtt5_event_property_t; + +/** + * MQTT5 protocol for user property + */ +typedef struct { + const char *key; /*!< Item key name */ + const char *value; /*!< Item value string */ +} esp_mqtt5_user_property_item_t; + +/** + * @brief Set MQTT5 client connect property configuration + * + * @param client mqtt client handle + * @param connect_property connect property + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL on fail + * ESP_OK on success + */ +esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_connection_property_config_t *connect_property); + +/** + * @brief Set MQTT5 client publish property configuration + * + * This API will not store the publish property, it is one-time configuration. + * Before call `esp_mqtt_client_publish` to publish data, call this API to set publish property if have + * + * @param client mqtt client handle + * @param property publish property + * + * @return ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL on fail + * ESP_OK on success + */ +esp_err_t esp_mqtt5_client_set_publish_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_publish_property_config_t *property); + +/** + * @brief Set MQTT5 client subscribe property configuration + * + * This API will not store the subscribe property, it is one-time configuration. + * Before call `esp_mqtt_client_subscribe` to subscribe topic, call this API to set subscribe property if have + * + * @param client mqtt client handle + * @param property subscribe property + * + * @return ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL on fail + * ESP_OK on success + */ +esp_err_t esp_mqtt5_client_set_subscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_subscribe_property_config_t *property); + +/** + * @brief Set MQTT5 client unsubscribe property configuration + * + * This API will not store the unsubscribe property, it is one-time configuration. + * Before call `esp_mqtt_client_unsubscribe` to unsubscribe topic, call this API to set unsubscribe property if have + * + * @param client mqtt client handle + * @param property unsubscribe property + * + * @return ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL on fail + * ESP_OK on success + */ +esp_err_t esp_mqtt5_client_set_unsubscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_unsubscribe_property_config_t *property); + +/** + * @brief Set MQTT5 client disconnect property configuration + * + * This API will not store the disconnect property, it is one-time configuration. + * Before call `esp_mqtt_client_disconnect` to disconnect connection, call this API to set disconnect property if have + * + * @param client mqtt client handle + * @param property disconnect property + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL on fail + * ESP_OK on success + */ +esp_err_t esp_mqtt5_client_set_disconnect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_disconnect_property_config_t *property); + +/** + * @brief Set MQTT5 client user property configuration + * + * This API will allocate memory for user_property, please DO NOT forget `call esp_mqtt5_client_delete_user_property` + * after you use it. + * Before publish data, subscribe topic, unsubscribe, etc, call this API to set user property if have + * + * @param user_property user_property handle + * @param item array of user property data (eg. {{"var","val"},{"other","2"}}) + * @param item_num number of items in user property data + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_FAIL on fail + * ESP_OK on success + */ +esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property, esp_mqtt5_user_property_item_t item[], uint8_t item_num); + +/** + * @brief Get MQTT5 client user property + * + * @param user_property user_property handle + * @param item point that store user property data + * @param item_num number of items in user property data + * + * This API can use with `esp_mqtt5_client_get_user_property_count` to get list count of user property. + * And malloc number of count item array memory to store the user property data. + * Please DO NOT forget the item memory, key and value point in item memory when get user property data successfully. + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_FAIL on fail + * ESP_OK on success + */ +esp_err_t esp_mqtt5_client_get_user_property(mqtt5_user_property_handle_t user_property, esp_mqtt5_user_property_item_t *item, uint8_t *item_num); + +/** + * @brief Get MQTT5 client user property list count + * + * @param user_property user_property handle + * @return user property list count + */ +uint8_t esp_mqtt5_client_get_user_property_count(mqtt5_user_property_handle_t user_property); + +/** + * @brief Free the user property list + * + * @param user_property user_property handle + * + * This API will free the memory in user property list and free user_property itself + */ +void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property); +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_client.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_client.h new file mode 100644 index 000000000..4627585bc --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_client.h @@ -0,0 +1,704 @@ +/* + * This file is subject to the terms and conditions defined in + * file 'LICENSE', which is part of this source code package. + * Tuan PM + */ + +#ifndef _MQTT_CLIENT_H_ +#define _MQTT_CLIENT_H_ + +#include +#include +#include +#include "esp_err.h" +#include "esp_event.h" +#include "esp_transport.h" +#ifdef CONFIG_MQTT_PROTOCOL_5 +#include "mqtt5_client.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ESP_EVENT_DECLARE_BASE +// Define event loop types if macros not available +typedef void *esp_event_loop_handle_t; +typedef void *esp_event_handler_t; +#endif + +typedef struct esp_mqtt_client *esp_mqtt_client_handle_t; + +#define MQTT_OVER_TCP_SCHEME "mqtt" +#define MQTT_OVER_SSL_SCHEME "mqtts" +#define MQTT_OVER_WS_SCHEME "ws" +#define MQTT_OVER_WSS_SCHEME "wss" + +/** + * @brief *MQTT* event types. + * + * User event handler receives context data in `esp_mqtt_event_t` structure with + * - client - *MQTT* client handle + * - various other data depending on event type + * + */ +typedef enum esp_mqtt_event_id_t { + MQTT_EVENT_ANY = -1, + MQTT_EVENT_ERROR = + 0, /*!< on error event, additional context: connection return code, error + handle from esp_tls (if supported) */ + MQTT_EVENT_CONNECTED, /*!< connected event, additional context: + session_present flag */ + MQTT_EVENT_DISCONNECTED, /*!< disconnected event */ + MQTT_EVENT_SUBSCRIBED, /*!< subscribed event, additional context: + - msg_id message id + - error_handle `error_type` in case subscribing failed + - data pointer to broker response, check for errors. + - data_len length of the data for this + event + */ + MQTT_EVENT_UNSUBSCRIBED, /*!< unsubscribed event, additional context: msg_id */ + MQTT_EVENT_PUBLISHED, /*!< published event, additional context: msg_id */ + MQTT_EVENT_DATA, /*!< data event, additional context: + - msg_id message id + - topic pointer to the received topic + - topic_len length of the topic + - data pointer to the received data + - data_len length of the data for this event + - current_data_offset offset of the current data for + this event + - total_data_len total length of the data received + - retain retain flag of the message + - qos QoS level of the message + - dup dup flag of the message + Note: Multiple MQTT_EVENT_DATA could be fired for one + message, if it is longer than internal buffer. In that + case only first event contains topic pointer and length, + other contain data only with current data length and + current data offset updating. + */ + MQTT_EVENT_BEFORE_CONNECT, /*!< The event occurs before connecting */ + MQTT_EVENT_DELETED, /*!< Notification on delete of one message from the + internal outbox, if the message couldn't have been sent + or acknowledged before expiring defined in + OUTBOX_EXPIRED_TIMEOUT_MS. (events are not posted upon + deletion of successfully acknowledged messages) + - This event id is posted only if + MQTT_REPORT_DELETED_MESSAGES==1 + - Additional context: msg_id (id of the deleted + message, always 0 for QoS = 0 messages). + */ + MQTT_USER_EVENT, /*!< Custom event used to queue tasks into mqtt event handler + All fields from the esp_mqtt_event_t type could be used to pass + an additional context data to the handler. + */ +} esp_mqtt_event_id_t; + +/** + * *MQTT* connection error codes propagated via ERROR event + */ +typedef enum esp_mqtt_connect_return_code_t { + MQTT_CONNECTION_ACCEPTED = 0, /*!< Connection accepted */ + MQTT_CONNECTION_REFUSE_PROTOCOL, /*!< *MQTT* connection refused reason: Wrong + protocol */ + MQTT_CONNECTION_REFUSE_ID_REJECTED, /*!< *MQTT* connection refused reason: ID + rejected */ + MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE, /*!< *MQTT* connection refused + reason: Server unavailable */ + MQTT_CONNECTION_REFUSE_BAD_USERNAME, /*!< *MQTT* connection refused reason: + Wrong user */ + MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED /*!< *MQTT* connection refused reason: + Wrong username or password */ +} esp_mqtt_connect_return_code_t; + +/** + * *MQTT* connection error codes propagated via ERROR event + */ +typedef enum esp_mqtt_error_type_t { + MQTT_ERROR_TYPE_NONE = 0, + MQTT_ERROR_TYPE_TCP_TRANSPORT, + MQTT_ERROR_TYPE_CONNECTION_REFUSED, + MQTT_ERROR_TYPE_SUBSCRIBE_FAILED +} esp_mqtt_error_type_t; + +/** + * MQTT_ERROR_TYPE_TCP_TRANSPORT error type hold all sorts of transport layer + * errors, including ESP-TLS error, but in the past only the errors from + * MQTT_ERROR_TYPE_ESP_TLS layer were reported, so the ESP-TLS error type is + * re-defined here for backward compatibility + */ +#define MQTT_ERROR_TYPE_ESP_TLS MQTT_ERROR_TYPE_TCP_TRANSPORT + +typedef enum esp_mqtt_transport_t { + MQTT_TRANSPORT_UNKNOWN = 0x0, + MQTT_TRANSPORT_OVER_TCP, /*!< *MQTT* over TCP, using scheme: ``MQTT`` */ + MQTT_TRANSPORT_OVER_SSL, /*!< *MQTT* over SSL, using scheme: ``MQTTS`` */ + MQTT_TRANSPORT_OVER_WS, /*!< *MQTT* over Websocket, using scheme:: ``ws`` */ + MQTT_TRANSPORT_OVER_WSS /*!< *MQTT* over Websocket Secure, using scheme: + ``wss`` */ +} esp_mqtt_transport_t; + +/** + * *MQTT* protocol version used for connection + */ +typedef enum esp_mqtt_protocol_ver_t { + MQTT_PROTOCOL_UNDEFINED = 0, + MQTT_PROTOCOL_V_3_1, + MQTT_PROTOCOL_V_3_1_1, + MQTT_PROTOCOL_V_5, +} esp_mqtt_protocol_ver_t; + +/** + * @brief *MQTT* error code structure to be passed as a contextual information + * into ERROR event + * + * Important: This structure extends `esp_tls_last_error` error structure and is + * backward compatible with it (so might be down-casted and treated as + * `esp_tls_last_error` error, but recommended to update applications if used + * this way previously) + * + * Use this structure directly checking error_type first and then appropriate + * error code depending on the source of the error: + * + * | error_type | related member variables | note | + * | MQTT_ERROR_TYPE_TCP_TRANSPORT | esp_tls_last_esp_err, esp_tls_stack_err, + * esp_tls_cert_verify_flags, sock_errno | Error reported from + * tcp_transport/esp-tls | | MQTT_ERROR_TYPE_CONNECTION_REFUSED | + * connect_return_code | Internal error reported from *MQTT* broker on + * connection | + */ +typedef struct esp_mqtt_error_codes { + /* compatible portion of the struct corresponding to struct esp_tls_last_error + */ + esp_err_t esp_tls_last_esp_err; /*!< last esp_err code reported from esp-tls + component */ + int esp_tls_stack_err; /*!< tls specific error code reported from underlying + tls stack */ + int esp_tls_cert_verify_flags; /*!< tls flags reported from underlying tls + stack during certificate verification */ + /* esp-mqtt specific structure extension */ + esp_mqtt_error_type_t + error_type; /*!< error type referring to the source of the error */ + esp_mqtt_connect_return_code_t + connect_return_code; /*!< connection refused error code reported from + *MQTT* broker on connection */ +#ifdef CONFIG_MQTT_PROTOCOL_5 + esp_mqtt5_error_reason_code_t + disconnect_return_code; /*!< disconnection reason code reported from + *MQTT* broker on disconnection */ +#endif + /* tcp_transport extension */ + int esp_transport_sock_errno; /*!< errno from the underlying socket */ + +} esp_mqtt_error_codes_t; + +/** + * *MQTT* event configuration structure + */ +typedef struct esp_mqtt_event_t { + esp_mqtt_event_id_t event_id; /*!< *MQTT* event type */ + esp_mqtt_client_handle_t client; /*!< *MQTT* client handle for this event */ + char *data; /*!< Data associated with this event */ + int data_len; /*!< Length of the data for this event */ + int total_data_len; /*!< Total length of the data (longer data are supplied + with multiple events) */ + int current_data_offset; /*!< Actual offset for the data associated with this + event */ + char *topic; /*!< Topic associated with this event */ + int topic_len; /*!< Length of the topic for this event associated with this + event */ + int msg_id; /*!< *MQTT* messaged id of message */ + int session_present; /*!< *MQTT* session_present flag for connection event */ + esp_mqtt_error_codes_t + *error_handle; /*!< esp-mqtt error handle including esp-tls errors as well + as internal *MQTT* errors */ + bool retain; /*!< Retained flag of the message associated with this event */ + int qos; /*!< QoS of the messages associated with this event */ + bool dup; /*!< dup flag of the message associated with this event */ + esp_mqtt_protocol_ver_t protocol_ver; /*!< MQTT protocol version used for connection, defaults to value from menuconfig*/ +#ifdef CONFIG_MQTT_PROTOCOL_5 + esp_mqtt5_event_property_t *property; /*!< MQTT 5 property associated with this event */ +#endif + +} esp_mqtt_event_t; + +typedef esp_mqtt_event_t *esp_mqtt_event_handle_t; + +/** + * *MQTT* client configuration structure + * + * - Default values can be set via menuconfig + * - All certificates and key data could be passed in PEM or DER format. PEM format must have a terminating NULL + * character and the related len field set to 0. DER format requires a related len field set to the correct length. + */ +typedef struct esp_mqtt_client_config_t { + /** + * Broker related configuration + */ + struct broker_t { + /** + * Broker address + * + * - uri have precedence over other fields + * - If uri isn't set at least hostname, transport and port should. + */ + struct address_t { + const char *uri; /*!< Complete *MQTT* broker URI */ + const char *hostname; /*!< Hostname, to set ipv4 pass it as string) */ + esp_mqtt_transport_t transport; /*!< Selects transport*/ + const char *path; /*!< Path in the URI*/ + uint32_t port; /*!< *MQTT* server port */ + } address; /*!< Broker address configuration */ + /** + * Broker identity verification + * + * If fields are not set broker's identity isn't verified. it's recommended + * to set the options in this struct for security reasons. + */ + struct verification_t { + bool use_global_ca_store; /*!< Use a global ca_store, look esp-tls + documentation for details. */ + esp_err_t (*crt_bundle_attach)(void *conf); /*!< Pointer to ESP x509 Certificate Bundle attach function for + the usage of certificate bundles. Client only attach the bundle, the clean up must be done by the user. */ + const char *certificate; /*!< Certificate data, default is NULL. It's not copied nor freed by the client, user needs to clean up.*/ + size_t certificate_len; /*!< Length of the buffer pointed to by certificate. */ + const struct psk_key_hint *psk_hint_key; /*!< Pointer to PSK struct defined in esp_tls.h to enable PSK + authentication (as alternative to certificate verification). + PSK is enabled only if there are no other ways to + verify broker. It's not copied nor freed by the client, user needs to clean up.*/ + bool skip_cert_common_name_check; /*!< Skip any validation of server certificate CN field, this reduces the + security of TLS and makes the *MQTT* client susceptible to MITM attacks */ + const char **alpn_protos; /*!< NULL-terminated list of supported application protocols to be used for ALPN.*/ + const char *common_name; /*!< Pointer to the string containing server certificate common name. + If non-NULL, server certificate CN must match this name, + If NULL, server certificate CN must match hostname. + This is ignored if skip_cert_common_name_check=true. + It's not copied nor freed by the client, user needs to clean up.*/ + const int *ciphersuites_list; /*!< Pointer to a zero-terminated array of IANA identifiers of TLS cipher suites. + Please ensure the validity of the list, and note that it is not copied or freed by the client. */ + } verification; /*!< Security verification of the broker */ + } broker; /*!< Broker address and security verification */ + /** + * Client related credentials for authentication. + */ + struct credentials_t { + const char *username; /*!< *MQTT* username */ + const char *client_id; /*!< Set *MQTT* client identifier. Ignored if set_null_client_id == true If NULL set + the default client id. Default client id is ``ESP32_%CHIPID%`` where `%CHIPID%` are + last 3 bytes of MAC address in hex format */ + bool set_null_client_id; /*!< Selects a NULL client id */ + /** + * Client authentication + * + * Fields related to client authentication by broker + * + * For mutual authentication using TLS, user could select certificate and key, + * secure element or digital signature peripheral if available. + * + */ + struct authentication_t { + const char *password; /*!< *MQTT* password */ + const char *certificate; /*!< Certificate for ssl mutual authentication, not required if mutual + authentication is not needed. Must be provided with `key`. It's not copied nor freed by the client, user needs to clean up.*/ + size_t certificate_len; /*!< Length of the buffer pointed to by certificate.*/ + const char *key; /*!< Private key for SSL mutual authentication, not required if mutual authentication + is not needed. If it is not NULL, also `certificate` has to be provided. It's not copied nor freed by the client, user needs to clean up.*/ + size_t key_len; /*!< Length of the buffer pointed to by key.*/ + const char *key_password; /*!< Client key decryption password, not PEM nor DER, if provided + `key_password_len` must be correctly set.*/ + int key_password_len; /*!< Length of the password pointed to by `key_password` */ + bool use_secure_element; /*!< Enable secure element, available in ESP32-ROOM-32SE, for SSL connection */ + void *ds_data; /*!< Carrier of handle for digital signature parameters, digital signature peripheral is + available in some Espressif devices. It's not copied nor freed by the client, user needs to clean up.*/ + bool use_ecdsa_peripheral; /*!< Enable ECDSA peripheral, available in some Espressif devices. */ + uint8_t ecdsa_key_efuse_blk; /*!< ECDSA key block number from efuse, available in some Espressif devices. */ + } authentication; /*!< Client authentication */ + } credentials; /*!< User credentials for broker */ + /** + * *MQTT* Session related configuration + */ + struct session_t { + /** + * Last Will and Testament message configuration. + */ + struct last_will_t { + const char *topic; /*!< LWT (Last Will and Testament) message topic */ + const char *msg; /*!< LWT message, may be NULL terminated*/ + int msg_len; /*!< LWT message length, if msg isn't NULL terminated must have the correct length */ + int qos; /*!< LWT message QoS */ + int retain; /*!< LWT retained message flag */ + } last_will; /*!< Last will configuration */ + bool disable_clean_session; /*!< *MQTT* clean session, default clean_session is true */ + int keepalive; /*!< *MQTT* keepalive, default is 120 seconds + When configuring this value, keep in mind that the client attempts + to communicate with the broker at half the interval that is actually set. + This conservative approach allows for more attempts before the broker's timeout occurs */ + bool disable_keepalive; /*!< Set `disable_keepalive=true` to turn off keep-alive mechanism, keepalive is active + by default. Note: setting the config value `keepalive` to `0` doesn't disable + keepalive feature, but uses a default keepalive period */ + esp_mqtt_protocol_ver_t protocol_ver; /*!< *MQTT* protocol version used for connection.*/ + int message_retransmit_timeout; /*!< timeout for retransmitting of failed packet */ + } session; /*!< *MQTT* session configuration. */ + /** + * Network related configuration + */ + struct network_t { + int reconnect_timeout_ms; /*!< Reconnect to the broker after this value in miliseconds if auto reconnect is not + disabled (defaults to 10s) */ + int timeout_ms; /*!< Abort network operation if it is not completed after this value, in milliseconds + (defaults to 10s). */ + int refresh_connection_after_ms; /*!< Refresh connection after this value (in milliseconds) */ + bool disable_auto_reconnect; /*!< Client will reconnect to server (when errors/disconnect). Set + `disable_auto_reconnect=true` to disable */ + esp_transport_keep_alive_t tcp_keep_alive_cfg; /*!< Transport keep-alive config*/ + esp_transport_handle_t transport; /*!< Custom transport handle to use, leave it NULL to allow MQTT client create or recreate its own. Warning: The transport should be valid during the client lifetime and is destroyed when esp_mqtt_client_destroy is called. */ + struct ifreq * if_name; /*!< The name of interface for data to go through. Use the default interface without setting */ + } network; /*!< Network configuration */ + /** + * Client task configuration + */ + struct task_t { + int priority; /*!< *MQTT* task priority*/ + int stack_size; /*!< *MQTT* task stack size*/ + } task; /*!< FreeRTOS task configuration.*/ + /** + * Client buffer size configuration + * + * Client have two buffers for input and output respectivelly. + */ + struct buffer_t { + int size; /*!< size of *MQTT* send/receive buffer*/ + int out_size; /*!< size of *MQTT* output buffer. If not defined, defaults to the size defined by + ``buffer_size`` */ + } buffer; /*!< Buffer size configuration.*/ + + /** + * Client outbox configuration options. + */ + struct outbox_config_t { + uint64_t limit; /*!< Size limit for the outbox in bytes.*/ + } outbox; /*!< Outbox configuration. */ +} esp_mqtt_client_config_t; + +/** + * Topic definition struct + */ +typedef struct topic_t { + const char *filter; /*!< Topic filter to subscribe */ + int qos; /*!< Max QoS level of the subscription */ +} esp_mqtt_topic_t; + +/** + * @brief Creates *MQTT* client handle based on the configuration + * + * @param config *MQTT* configuration structure + * + * @return mqtt_client_handle if successfully created, NULL on error + */ +esp_mqtt_client_handle_t +esp_mqtt_client_init(const esp_mqtt_client_config_t *config); + +/** + * @brief Sets *MQTT* connection URI. This API is usually used to overrides the + * URI configured in esp_mqtt_client_init + * + * @param client *MQTT* client handle + * @param uri + * + * @return ESP_FAIL if URI parse error, ESP_OK on success + */ +esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, + const char *uri); + +/** + * @brief Starts *MQTT* client with already created client handle + * + * @param client *MQTT* client handle + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL on other error + */ +esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client); + +/** + * @brief This api is typically used to force reconnection upon a specific event + * + * @param client *MQTT* client handle + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL if client is in invalid state + */ +esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client); + +/** + * @brief This api is typically used to force disconnection from the broker + * + * @param client *MQTT* client handle + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG on wrong initialization + */ +esp_err_t esp_mqtt_client_disconnect(esp_mqtt_client_handle_t client); + +/** + * @brief Stops *MQTT* client tasks + * + * * Notes: + * - Cannot be called from the *MQTT* event handler + * + * @param client *MQTT* client handle + * + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG on wrong initialization + * ESP_FAIL if client is in invalid state + */ +esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client); + +#ifdef __cplusplus + +#define esp_mqtt_client_subscribe esp_mqtt_client_subscribe_single + +#else +/** + * @brief Convenience macro to select subscribe function to use. + * + * Notes: + * - Usage of `esp_mqtt_client_subscribe_single` is the same as previous + * esp_mqtt_client_subscribe, refer to it for details. + * + * @param client_handle *MQTT* client handle + * @param topic_type Needs to be char* for single subscription or `esp_mqtt_topic_t` for multiple topics + * @param qos_or_size It's either a qos when subscribing to a single topic or the size of the subscription array when subscribing to multiple topics. + * + * @return message_id of the subscribe message on success + * -1 on failure + * -2 in case of full outbox. + */ +#define esp_mqtt_client_subscribe(client_handle, topic_type, qos_or_size) _Generic((topic_type), \ + char *: esp_mqtt_client_subscribe_single, \ + const char *: esp_mqtt_client_subscribe_single, \ + esp_mqtt_topic_t*: esp_mqtt_client_subscribe_multiple \ + )(client_handle, topic_type, qos_or_size) + +#endif /* __cplusplus*/ +/** + * @brief Subscribe the client to defined topic with defined qos + * + * Notes: + * - Client must be connected to send subscribe message + * - This API is could be executed from a user task or + * from a *MQTT* event callback i.e. internal *MQTT* task + * (API is protected by internal mutex, so it might block + * if a longer data receive operation is in progress. + * - `esp_mqtt_client_subscribe` could be used to call this function. + * + * @param client *MQTT* client handle + * @param topic topic filter to subscribe + * @param qos Max qos level of the subscription + * + * @return message_id of the subscribe message on success + * -1 on failure + * -2 in case of full outbox. + */ +int esp_mqtt_client_subscribe_single(esp_mqtt_client_handle_t client, + const char *topic, int qos); +/** + * @brief Subscribe the client to a list of defined topics with defined qos + * + * Notes: + * - Client must be connected to send subscribe message + * - This API is could be executed from a user task or + * from a *MQTT* event callback i.e. internal *MQTT* task + * (API is protected by internal mutex, so it might block + * if a longer data receive operation is in progress. + * - `esp_mqtt_client_subscribe` could be used to call this function. + * + * @param client *MQTT* client handle + * @param topic_list List of topics to subscribe + * @param size size of topic_list + * + * @return message_id of the subscribe message on success + * -1 on failure + * -2 in case of full outbox. + */ +int esp_mqtt_client_subscribe_multiple(esp_mqtt_client_handle_t client, + const esp_mqtt_topic_t *topic_list, int size); + +/** + * @brief Unsubscribe the client from defined topic + * + * Notes: + * - Client must be connected to send unsubscribe message + * - It is thread safe, please refer to `esp_mqtt_client_subscribe_single` for details + * + * @param client *MQTT* client handle + * @param topic + * + * @return message_id of the subscribe message on success + * -1 on failure + */ +int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, + const char *topic); + +/** + * @brief Client to send a publish message to the broker + * + * Notes: + * - This API might block for several seconds, either due to network timeout + * (10s) or if publishing payloads longer than internal buffer (due to message + * fragmentation) + * - Client doesn't have to be connected for this API to work, enqueueing the + * messages with qos>1 (returning -1 for all the qos=0 messages if + * disconnected). If MQTT_SKIP_PUBLISH_IF_DISCONNECTED is enabled, this API will + * not attempt to publish when the client is not connected and will always + * return -1. + * - It is thread safe, please refer to `esp_mqtt_client_subscribe` for details + * + * @param client *MQTT* client handle + * @param topic topic string + * @param data payload string (set to NULL, sending empty payload message) + * @param len data length, if set to 0, length is calculated from payload + * string + * @param qos QoS of publish message + * @param retain retain flag + * + * @return message_id of the publish message (for QoS 0 message_id will always + * be zero) on success. -1 on failure, -2 in case of full outbox. + */ +int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, + const char *data, int len, int qos, int retain); + +/** + * @brief Enqueue a message to the outbox, to be sent later. Typically used for + * messages with qos>0, but could be also used for qos=0 messages if store=true. + * + * This API generates and stores the publish message into the internal outbox + * and the actual sending to the network is performed in the mqtt-task context + * (in contrast to the esp_mqtt_client_publish() which sends the publish message + * immediately in the user task's context). Thus, it could be used as a non + * blocking version of esp_mqtt_client_publish(). + * + * @param client *MQTT* client handle + * @param topic topic string + * @param data payload string (set to NULL, sending empty payload message) + * @param len data length, if set to 0, length is calculated from payload + * string + * @param qos QoS of publish message + * @param retain retain flag + * @param store if true, all messages are enqueued; otherwise only QoS 1 and + * QoS 2 are enqueued + * + * @return message_id if queued successfully, -1 on failure, -2 in case of full outbox. + */ +int esp_mqtt_client_enqueue(esp_mqtt_client_handle_t client, const char *topic, + const char *data, int len, int qos, int retain, + bool store); + +/** + * @brief Destroys the client handle + * + * Notes: + * - Cannot be called from the *MQTT* event handler + * + * @param client *MQTT* client handle + * + * @return ESP_OK + * ESP_ERR_INVALID_ARG on wrong initialization + */ +esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client); + +/** + * @brief Set configuration structure, typically used when updating the config + * (i.e. on "before_connect" event + * + * Notes: + * - When calling this function make sure to have all the intendend configurations + * set, otherwise default values are set. + * @param client *MQTT* client handle + * + * @param config *MQTT* configuration structure + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_ERR_INVALID_ARG if conflicts on transport configuration. + * ESP_OK on success + */ +esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, + const esp_mqtt_client_config_t *config); + +/** + * @brief Registers *MQTT* event + * + * @param client *MQTT* client handle + * @param event event type + * @param event_handler handler callback + * @param event_handler_arg handlers context + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_ERR_INVALID_ARG on wrong initialization + * ESP_OK on success + */ +esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, + esp_mqtt_event_id_t event, + esp_event_handler_t event_handler, + void *event_handler_arg); + +/** + * @brief Unregisters mqtt event + * + * @param client mqtt client handle + * @param event event ID + * @param event_handler handler to unregister + * + * @return ESP_ERR_NO_MEM if failed to allocate + * ESP_ERR_INVALID_ARG on invalid event ID + * ESP_OK on success + */ +esp_err_t esp_mqtt_client_unregister_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler); + +/** + * @brief Get outbox size + * + * @param client *MQTT* client handle + * @return outbox size + * 0 on wrong initialization + */ +int esp_mqtt_client_get_outbox_size(esp_mqtt_client_handle_t client); + +/** + * @brief Dispatch user event to the mqtt internal event loop + * + * @param client *MQTT* client handle + * @param event *MQTT* event handle structure + * @return ESP_OK on success + * ESP_ERR_TIMEOUT if the event couldn't be queued (ref also CONFIG_MQTT_EVENT_QUEUE_SIZE) + */ +esp_err_t esp_mqtt_dispatch_custom_event(esp_mqtt_client_handle_t client, esp_mqtt_event_t *event); + +/** + * @brief Get a transport from the scheme + * + * Allows extra settings to be made on the selected transport, + * for convenience the scheme used by the mqtt client are defined as + * MQTT_OVER_TCP_SCHEME, MQTT_OVER_SSL_SCHEME, MQTT_OVER_WS_SCHEME and MQTT_OVER_WSS_SCHEME + * If the transport_scheme is NULL and the client was set with a custom transport the custom transport will be returned. + * + * Notes: + * - This function should be called only on MQTT_EVENT_BEFORE_CONNECT. + * - The intetion is to provide a way to set different configurations than the ones available from client config. + * - If esp_mqtt_client_destroy is called the returned pointer will be invalidated. + * - All the required settings should be made in the MQTT_EVENT_BEFORE_CONNECT event handler + * + * @param client *MQTT* client handle + * @param transport_scheme Transport handle to search for. + * @return the transport handle + * NULL in case of error + * +*/ +esp_transport_handle_t esp_mqtt_client_get_transport(esp_mqtt_client_handle_t client, char *transport_scheme); +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_supported_features.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_supported_features.h new file mode 100644 index 000000000..6036e5f90 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/include/mqtt_supported_features.h @@ -0,0 +1,83 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _MQTT_SUPPORTED_FEATURES_H_ +#define _MQTT_SUPPORTED_FEATURES_H_ + +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#endif + +/** + * @brief This header defines supported features of IDF which mqtt module + * could use depending on specific version of ESP-IDF. + * In case "esp_idf_version.h" were not found, all additional + * features would be disabled + */ + +#ifdef ESP_IDF_VERSION + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(3, 3, 0) +// Features supported from 3.3 +#define MQTT_SUPPORTED_FEATURE_EVENT_LOOP +#define MQTT_SUPPORTED_FEATURE_SKIP_CRT_CMN_NAME_CHECK +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) +// Features supported in 4.0 +#define MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL +#define MQTT_SUPPORTED_FEATURE_TRANSPORT_ERR_REPORTING +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0) +// Features supported in 4.1 +#define MQTT_SUPPORTED_FEATURE_PSK_AUTHENTICATION +#define MQTT_SUPPORTED_FEATURE_DER_CERTIFICATES +#define MQTT_SUPPORTED_FEATURE_ALPN +#define MQTT_SUPPORTED_FEATURE_CLIENT_KEY_PASSWORD +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) +// Features supported in 4.2 +#define MQTT_SUPPORTED_FEATURE_SECURE_ELEMENT +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) +// Features supported in 4.3 +#define MQTT_SUPPORTED_FEATURE_DIGITAL_SIGNATURE +#define MQTT_SUPPORTED_FEATURE_TRANSPORT_SOCK_ERRNO_REPORTING +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) +// Features supported in 4.4 +#define MQTT_SUPPORTED_FEATURE_CERTIFICATE_BUNDLE +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) +// Features supported in 5.1.0 +#define MQTT_SUPPORTED_FEATURE_CRT_CMN_NAME +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) +// Features supported in 5.2.0 +#define MQTT_SUPPORTED_FEATURE_ECDSA_PERIPHERAL +#endif + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0) +// Features supported in 5.5.0 +#define MQTT_SUPPORTED_FEATURE_CIPHERSUITES_LIST +#endif + +#endif /* ESP_IDF_VERSION */ +#endif // _MQTT_SUPPORTED_FEATURES_H_ diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_client_priv.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_client_priv.h new file mode 100644 index 000000000..1b5f04bec --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_client_priv.h @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MQTT5_CLIENT_PRIV_H_ +#define _MQTT5_CLIENT_PRIV_H_ + +#include "mqtt5_client.h" +#include "mqtt_client_priv.h" +#include "mqtt5_msg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mqtt5_topic_alias { + char *topic; + uint16_t topic_len; + uint16_t topic_alias; + STAILQ_ENTRY(mqtt5_topic_alias) next; +} mqtt5_topic_alias_t; +STAILQ_HEAD(mqtt5_topic_alias_list_t, mqtt5_topic_alias); +typedef struct mqtt5_topic_alias_list_t *mqtt5_topic_alias_handle_t; +typedef struct mqtt5_topic_alias *mqtt5_topic_alias_item_t; + +typedef struct { + esp_mqtt5_connection_property_storage_t connect_property_info; + esp_mqtt5_connection_will_property_storage_t will_property_info; + esp_mqtt5_connection_server_resp_property_t server_resp_property_info; + esp_mqtt5_disconnect_property_config_t disconnect_property_info; + const esp_mqtt5_publish_property_config_t *publish_property_info; + const esp_mqtt5_subscribe_property_config_t *subscribe_property_info; + const esp_mqtt5_unsubscribe_property_config_t *unsubscribe_property_info; + mqtt5_topic_alias_handle_t peer_topic_alias; +} mqtt5_config_storage_t; + +void esp_mqtt5_increment_packet_counter(esp_mqtt5_client_handle_t client); +void esp_mqtt5_decrement_packet_counter(esp_mqtt5_client_handle_t client); +void esp_mqtt5_parse_pubcomp(esp_mqtt5_client_handle_t client); +void esp_mqtt5_parse_puback(esp_mqtt5_client_handle_t client); +void esp_mqtt5_parse_unsuback(esp_mqtt5_client_handle_t client); +void esp_mqtt5_parse_suback(esp_mqtt5_client_handle_t client); +void esp_mqtt5_parse_disconnect(esp_mqtt5_client_handle_t client, int *disconnect_rsp_code); +esp_err_t esp_mqtt5_parse_connack(esp_mqtt5_client_handle_t client, int *connect_rsp_code); +void esp_mqtt5_client_destory(esp_mqtt5_client_handle_t client); +esp_err_t esp_mqtt5_client_publish_check(esp_mqtt5_client_handle_t client, int qos, int retain); +esp_err_t esp_mqtt5_client_subscribe_check(esp_mqtt5_client_handle_t client, int qos); +esp_err_t esp_mqtt5_create_default_config(esp_mqtt5_client_handle_t client); +esp_err_t esp_mqtt5_get_publish_data(esp_mqtt5_client_handle_t client, uint8_t *msg_buf, size_t msg_read_len, char **msg_topic, size_t *msg_topic_len, char **msg_data, size_t *msg_data_len); +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif \ No newline at end of file diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_msg.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_msg.h new file mode 100644 index 000000000..6c2a036c8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt5_msg.h @@ -0,0 +1,142 @@ +#ifndef MQTT5_MSG_H +#define MQTT5_MSG_H +#include +#include +#include "sys/queue.h" +#include "mqtt_config.h" +#include "mqtt_msg.h" +#include "mqtt_client.h" +#ifdef __cplusplus +extern "C" { +#endif + +enum mqtt_properties_type { + MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR = 0x01, + MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL = 0x02, + MQTT5_PROPERTY_CONTENT_TYPE = 0x03, + MQTT5_PROPERTY_RESPONSE_TOPIC = 0x08, + MQTT5_PROPERTY_CORRELATION_DATA = 0x09, + MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER = 0x0B, + MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL = 0x11, + MQTT5_PROPERTY_ASSIGNED_CLIENT_IDENTIFIER = 0x12, + MQTT5_PROPERTY_SERVER_KEEP_ALIVE = 0x13, + MQTT5_PROPERTY_AUTHENTICATION_METHOD = 0x15, + MQTT5_PROPERTY_AUTHENTICATION_DATA = 0x16, + MQTT5_PROPERTY_REQUEST_PROBLEM_INFO = 0x17, + MQTT5_PROPERTY_WILL_DELAY_INTERVAL = 0x18, + MQTT5_PROPERTY_REQUEST_RESP_INFO = 0x19, + MQTT5_PROPERTY_RESP_INFO = 0x1A, + MQTT5_PROPERTY_SERVER_REFERENCE = 0x1C, + MQTT5_PROPERTY_REASON_STRING = 0x1F, + MQTT5_PROPERTY_RECEIVE_MAXIMUM = 0x21, + MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM = 0x22, + MQTT5_PROPERTY_TOPIC_ALIAS = 0x23, + MQTT5_PROPERTY_MAXIMUM_QOS = 0x24, + MQTT5_PROPERTY_RETAIN_AVAILABLE = 0x25, + MQTT5_PROPERTY_USER_PROPERTY = 0x26, + MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE = 0x27, + MQTT5_PROPERTY_WILDCARD_SUBSCR_AVAILABLE = 0x28, + MQTT5_PROPERTY_SUBSCR_IDENTIFIER_AVAILABLE = 0x29, + MQTT5_PROPERTY_SHARED_SUBSCR_AVAILABLE = 0x2A, +}; + +typedef struct mqtt5_user_property { + char *key; + char *value; + STAILQ_ENTRY(mqtt5_user_property) next; +} mqtt5_user_property_t; +STAILQ_HEAD(mqtt5_user_property_list_t, mqtt5_user_property); +typedef struct mqtt5_user_property *mqtt5_user_property_item_t; + +typedef struct { + uint32_t maximum_packet_size; + uint16_t receive_maximum; + uint16_t topic_alias_maximum; + uint8_t max_qos; + bool retain_available; + bool wildcard_subscribe_available; + bool subscribe_identifiers_available; + bool shared_subscribe_available; + char *response_info; +} esp_mqtt5_connection_server_resp_property_t; + +typedef struct { + bool payload_format_indicator; + uint32_t message_expiry_interval; + uint16_t topic_alias; + char *response_topic; + int response_topic_len; + char *correlation_data; + uint16_t correlation_data_len; + char *content_type; + int content_type_len; + uint16_t subscribe_id; +} esp_mqtt5_publish_resp_property_t; + +typedef struct { + uint32_t session_expiry_interval; + uint32_t maximum_packet_size; + uint16_t receive_maximum; + uint16_t topic_alias_maximum; + bool request_resp_info; + bool request_problem_info; + mqtt5_user_property_handle_t user_property; +} esp_mqtt5_connection_property_storage_t; + +typedef struct { + uint32_t will_delay_interval; + uint32_t message_expiry_interval; + bool payload_format_indicator; + char *content_type; + char *response_topic; + char *correlation_data; + uint16_t correlation_data_len; + mqtt5_user_property_handle_t user_property; +} esp_mqtt5_connection_will_property_storage_t; + +#define mqtt5_get_type mqtt_get_type + +#define mqtt5_get_dup mqtt_get_dup + +#define mqtt5_set_dup mqtt_set_dup + +#define mqtt5_get_qos mqtt_get_qos + +#define mqtt5_get_retain mqtt_get_retain + +#define mqtt5_msg_init mqtt_msg_init + +#define mqtt5_get_total_length mqtt_get_total_length + +#define mqtt5_has_valid_msg_hdr mqtt_has_valid_msg_hdr + +#define mqtt5_msg_pingreq mqtt_msg_pingreq + +#define mqtt5_msg_pingresp mqtt_msg_pingresp + +#define mqtt5_get_unsuback_data mqtt5_get_suback_data + +#define mqtt5_get_pubcomp_data mqtt5_get_puback_data + +uint16_t mqtt5_get_id(uint8_t *buffer, size_t length); +char *mqtt5_get_publish_property_payload(uint8_t *buffer, size_t buffer_length, char **msg_topic, size_t *msg_topic_len, esp_mqtt5_publish_resp_property_t *resp_property, uint16_t *property_len, size_t *payload_len, mqtt5_user_property_handle_t *user_property); +char *mqtt5_get_suback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property); +char *mqtt5_get_puback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property); +mqtt_message_t *mqtt5_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info, esp_mqtt5_connection_property_storage_t *property, esp_mqtt5_connection_will_property_storage_t *will_property); +mqtt_message_t *mqtt5_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id, const esp_mqtt5_publish_property_config_t *property, const char *resp_info); +esp_err_t mqtt5_msg_parse_connack_property(uint8_t *buffer, size_t buffer_len, mqtt_connect_info_t *connection_info, esp_mqtt5_connection_property_storage_t *connection_property, esp_mqtt5_connection_server_resp_property_t *resp_property, int *reason_code, uint8_t *ack_flag, mqtt5_user_property_handle_t *user_property); +int mqtt5_msg_get_reason_code(uint8_t *buffer, size_t length); +mqtt_message_t *mqtt5_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t *topic, int size, uint16_t *message_id, const esp_mqtt5_subscribe_property_config_t *property); +mqtt_message_t *mqtt5_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id, const esp_mqtt5_unsubscribe_property_config_t *property); +mqtt_message_t *mqtt5_msg_disconnect(mqtt_connection_t *connection, esp_mqtt5_disconnect_property_config_t *disconnect_property_info); +mqtt_message_t *mqtt5_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt5_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt5_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt5_msg_puback(mqtt_connection_t *connection, uint16_t message_id); + +#ifdef __cplusplus +} +#endif + +#endif /* MQTT5_MSG_H */ + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_client_priv.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_client_priv.h new file mode 100644 index 000000000..c1ed03884 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_client_priv.h @@ -0,0 +1,150 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MQTT_CLIENT_PRIV_H_ +#define _MQTT_CLIENT_PRIV_H_ + +#include +#include +#include +#include +#include "esp_err.h" +#include "platform.h" + +#include "esp_event.h" +#include "mqtt_client.h" +#include "mqtt_msg.h" +#ifdef MQTT_PROTOCOL_5 +#include "mqtt5_client_priv.h" +#endif +#include "esp_transport.h" +#include "esp_transport_tcp.h" +#include "esp_transport_ssl.h" +#include "esp_transport_ws.h" +#include "esp_log.h" +#include "mqtt_outbox.h" +#include "freertos/event_groups.h" +#include +#include + +#include "mqtt_supported_features.h" + +/* using uri parser */ +#include "http_parser.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_LIBC_NEWLIB_NANO_FORMAT +#define NEWLIB_NANO_COMPAT_FORMAT PRIu32 +#define NEWLIB_NANO_COMPAT_CAST(size_t_var) (uint32_t)size_t_var +#else +#define NEWLIB_NANO_COMPAT_FORMAT "zu" +#define NEWLIB_NANO_COMPAT_CAST(size_t_var) size_t_var +#endif + +#ifdef MQTT_DISABLE_API_LOCKS +# define MQTT_API_LOCK(c) +# define MQTT_API_UNLOCK(c) +#else +# define MQTT_API_LOCK(c) xSemaphoreTakeRecursive(c->api_lock, portMAX_DELAY) +# define MQTT_API_UNLOCK(c) xSemaphoreGiveRecursive(c->api_lock) +#endif /* MQTT_USE_API_LOCKS */ + +typedef struct mqtt_state { + uint8_t *in_buffer; + int in_buffer_length; + size_t message_length; + size_t in_buffer_read_len; + mqtt_connection_t connection; + uint16_t pending_msg_id; + int pending_msg_type; + int pending_publish_qos; +} mqtt_state_t; + +typedef struct { + esp_event_loop_handle_t event_loop_handle; + int task_stack; + int task_prio; + char *uri; + char *host; + char *path; + char *scheme; + int port; + bool auto_reconnect; + int network_timeout_ms; + int refresh_connection_after_ms; + int reconnect_timeout_ms; + char **alpn_protos; + int num_alpn_protos; + char *clientkey_password; + int clientkey_password_len; + bool use_global_ca_store; + esp_err_t ((*crt_bundle_attach)(void *conf)); + const int *ciphersuites_list; + const char *cacert_buf; + size_t cacert_bytes; + const char *clientcert_buf; + size_t clientcert_bytes; + const char *clientkey_buf; + size_t clientkey_bytes; + const struct psk_key_hint *psk_hint_key; + bool skip_cert_common_name_check; + const char *common_name; + bool use_secure_element; + void *ds_data; + bool use_ecdsa_peripheral; + uint8_t ecdsa_key_efuse_blk; + int message_retransmit_timeout; + uint64_t outbox_limit; + esp_transport_handle_t transport; + struct ifreq * if_name; + esp_transport_keep_alive_t tcp_keep_alive_cfg; +} mqtt_config_storage_t; + +typedef enum { + MQTT_STATE_INIT = 0, + MQTT_STATE_DISCONNECTED, + MQTT_STATE_CONNECTED, + MQTT_STATE_WAIT_RECONNECT, +} mqtt_client_state_t; + +struct esp_mqtt_client { + esp_transport_list_handle_t transport_list; + esp_transport_handle_t transport; + mqtt_config_storage_t *config; + mqtt_state_t mqtt_state; + _Atomic mqtt_client_state_t state; + uint64_t refresh_connection_tick; + int64_t keepalive_tick; + uint64_t reconnect_tick; +#ifdef MQTT_PROTOCOL_5 + mqtt5_config_storage_t *mqtt5_config; + uint16_t send_publish_packet_count; // This is for MQTT v5.0 flow control +#endif + int wait_timeout_ms; + int auto_reconnect; + esp_mqtt_event_t event; + bool run; + bool wait_for_ping_resp; + outbox_handle_t outbox; + EventGroupHandle_t status_bits; + SemaphoreHandle_t api_lock; + TaskHandle_t task_handle; +#if MQTT_EVENT_QUEUE_SIZE > 1 + atomic_int queued_events; +#endif +}; + +bool esp_mqtt_set_if_config(char const *const new_config, char **old_config); +void esp_mqtt_destroy_config(esp_mqtt_client_handle_t client); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_config.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_config.h new file mode 100644 index 000000000..d96e2ad41 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_config.h @@ -0,0 +1,118 @@ +/* + * This file is subject to the terms and conditions defined in + * file 'LICENSE', which is part of this source code package. + * Tuan PM + */ +#ifndef _MQTT_CONFIG_H_ +#define _MQTT_CONFIG_H_ + +#include "sdkconfig.h" + +#ifdef CONFIG_MQTT_PROTOCOL_311 +#define MQTT_PROTOCOL_311 +#endif + +#ifdef CONFIG_MQTT_PROTOCOL_5 +#define MQTT_PROTOCOL_5 +#endif + +#define MQTT_RECON_DEFAULT_MS (10*1000) + +#ifdef CONFIG_MQTT_POLL_READ_TIMEOUT_MS +#define MQTT_POLL_READ_TIMEOUT_MS CONFIG_MQTT_POLL_READ_TIMEOUT_MS +#else +#define MQTT_POLL_READ_TIMEOUT_MS (1000) +#endif + +#define MQTT_MSG_ID_INCREMENTAL CONFIG_MQTT_MSG_ID_INCREMENTAL + +#define MQTT_SKIP_PUBLISH_IF_DISCONNECTED CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED + +#define MQTT_REPORT_DELETED_MESSAGES CONFIG_MQTT_REPORT_DELETED_MESSAGES + +#if CONFIG_MQTT_BUFFER_SIZE +#define MQTT_BUFFER_SIZE_BYTE CONFIG_MQTT_BUFFER_SIZE +#else +#define MQTT_BUFFER_SIZE_BYTE 1024 +#endif + +#if CONFIG_MQTT_TASK_PRIORITY +#define MQTT_TASK_PRIORITY CONFIG_MQTT_TASK_PRIORITY +#else +#define MQTT_TASK_PRIORITY 5 +#endif + +#if CONFIG_MQTT_TASK_STACK_SIZE +#define MQTT_TASK_STACK CONFIG_MQTT_TASK_STACK_SIZE +#else +#define MQTT_TASK_STACK (6*1024) +#endif + +#define MQTT_KEEPALIVE_TICK (120) +#define MQTT_NETWORK_TIMEOUT_MS (10000) + +#ifdef CONFIG_MQTT_TCP_DEFAULT_PORT +#define MQTT_TCP_DEFAULT_PORT CONFIG_MQTT_TCP_DEFAULT_PORT +#else +#define MQTT_TCP_DEFAULT_PORT 1883 +#endif + +#ifdef CONFIG_MQTT_SSL_DEFAULT_PORT +#define MQTT_SSL_DEFAULT_PORT CONFIG_MQTT_SSL_DEFAULT_PORT +#else +#define MQTT_SSL_DEFAULT_PORT 8883 +#endif + +#ifdef CONFIG_MQTT_WS_DEFAULT_PORT +#define MQTT_WS_DEFAULT_PORT CONFIG_MQTT_WS_DEFAULT_PORT +#else +#define MQTT_WS_DEFAULT_PORT 80 +#endif + +#ifdef CONFIG_MQTT_WSS_DEFAULT_PORT +#define MQTT_WSS_DEFAULT_PORT CONFIG_MQTT_WSS_DEFAULT_PORT +#else +#define MQTT_WSS_DEFAULT_PORT 443 +#endif + +#define MQTT_CORE_SELECTION_ENABLED CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED + +#ifdef CONFIG_MQTT_DISABLE_API_LOCKS +#define MQTT_DISABLE_API_LOCKS CONFIG_MQTT_DISABLE_API_LOCKS +#endif + +#ifdef CONFIG_MQTT_USE_CORE_0 +#define MQTT_TASK_CORE 0 +#else +#ifdef CONFIG_MQTT_USE_CORE_1 +#define MQTT_TASK_CORE 1 +#else +#define MQTT_TASK_CORE 0 +#endif +#endif + +#ifdef CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS +#define OUTBOX_EXPIRED_TIMEOUT_MS CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS +#else +#define OUTBOX_EXPIRED_TIMEOUT_MS (30*1000) +#endif + +#define MQTT_ENABLE_SSL CONFIG_MQTT_TRANSPORT_SSL +#define MQTT_ENABLE_WS CONFIG_MQTT_TRANSPORT_WEBSOCKET +#define MQTT_ENABLE_WSS CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE +#define MQTT_DEFAULT_RETRANSMIT_TIMEOUT_MS 1000 + +#ifdef CONFIG_MQTT_EVENT_QUEUE_SIZE +#define MQTT_EVENT_QUEUE_SIZE CONFIG_MQTT_EVENT_QUEUE_SIZE +#else +#define MQTT_EVENT_QUEUE_SIZE 1 +#endif + +#ifdef CONFIG_MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY +#define MQTT_OUTBOX_MEMORY MALLOC_CAP_SPIRAM +#else +#define MQTT_OUTBOX_MEMORY MALLOC_CAP_DEFAULT +#endif + +#define OUTBOX_MAX_SIZE (4*1024) +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_msg.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_msg.h new file mode 100644 index 000000000..f09590dc9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_msg.h @@ -0,0 +1,152 @@ +#ifndef MQTT_MSG_H +#define MQTT_MSG_H +#include +#include + +#include "mqtt_config.h" +#include "mqtt_client.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* +* Copyright (c) 2014, Stephen Robinson +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ +/* 7 6 5 4 3 2 1 0 */ +/*| --- Message Type---- | DUP Flag | QoS Level | Retain | */ +/* Remaining Length */ + + +enum mqtt_message_type { + MQTT_MSG_TYPE_CONNECT = 1, + MQTT_MSG_TYPE_CONNACK = 2, + MQTT_MSG_TYPE_PUBLISH = 3, + MQTT_MSG_TYPE_PUBACK = 4, + MQTT_MSG_TYPE_PUBREC = 5, + MQTT_MSG_TYPE_PUBREL = 6, + MQTT_MSG_TYPE_PUBCOMP = 7, + MQTT_MSG_TYPE_SUBSCRIBE = 8, + MQTT_MSG_TYPE_SUBACK = 9, + MQTT_MSG_TYPE_UNSUBSCRIBE = 10, + MQTT_MSG_TYPE_UNSUBACK = 11, + MQTT_MSG_TYPE_PINGREQ = 12, + MQTT_MSG_TYPE_PINGRESP = 13, + MQTT_MSG_TYPE_DISCONNECT = 14 +}; + +typedef struct mqtt_message { + uint8_t *data; + size_t length; + size_t fragmented_msg_total_length; /*!< total len of fragmented messages (zero for all other messages) */ + size_t fragmented_msg_data_offset; /*!< data offset of fragmented messages (zero for all other messages) */ +} mqtt_message_t; + +typedef struct mqtt_connect_info { + char *client_id; + char *username; + char *password; + char *will_topic; + char *will_message; + int64_t keepalive; /*!< keepalive=0 -> keepalive is disabled */ + int will_length; + int will_qos; + int will_retain; + int clean_session; + esp_mqtt_protocol_ver_t protocol_ver; +} mqtt_connect_info_t; + +typedef struct mqtt_connection { + mqtt_message_t outbound_message; +#if MQTT_MSG_ID_INCREMENTAL + uint16_t last_message_id; /*!< last used id if incremental message id configured */ +#endif + uint8_t *buffer; + size_t buffer_length; + mqtt_connect_info_t information; + +} mqtt_connection_t; + +static inline int mqtt_get_type(const uint8_t *buffer) +{ + return (buffer[0] & 0xf0) >> 4; +} +static inline int mqtt_get_connect_session_present(const uint8_t *buffer) +{ + return buffer[2] & 0x01; +} +static inline int mqtt_get_connect_return_code(const uint8_t *buffer) +{ + return buffer[3]; +} +static inline int mqtt_get_dup(const uint8_t *buffer) +{ + return (buffer[0] & 0x08) >> 3; +} +static inline void mqtt_set_dup(uint8_t *buffer) +{ + buffer[0] |= 0x08; +} +static inline int mqtt_get_qos(const uint8_t *buffer) +{ + return (buffer[0] & 0x06) >> 1; +} +static inline int mqtt_get_retain(const uint8_t *buffer) +{ + return (buffer[0] & 0x01); +} + +bool mqtt_header_complete(uint8_t *buffer, size_t buffer_length); +size_t mqtt_get_total_length(const uint8_t *buffer, size_t length, int *fixed_size_len); +char *mqtt_get_publish_topic(uint8_t *buffer, size_t *length); +char *mqtt_get_publish_data(uint8_t *buffer, size_t *length); +char *mqtt_get_suback_data(uint8_t *buffer, size_t *length); +uint16_t mqtt_get_id(uint8_t *buffer, size_t length); +int mqtt_has_valid_msg_hdr(uint8_t *buffer, size_t length); + +esp_err_t mqtt_msg_buffer_init(mqtt_connection_t *connection, int buffer_size); +void mqtt_msg_buffer_destroy(mqtt_connection_t *connection); + +mqtt_message_t *mqtt_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info); +mqtt_message_t *mqtt_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id); +mqtt_message_t *mqtt_msg_puback(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id); +mqtt_message_t *mqtt_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t topic_list[], int size, uint16_t *message_id) __attribute__((nonnull)); +mqtt_message_t *mqtt_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id); +mqtt_message_t *mqtt_msg_pingreq(mqtt_connection_t *connection); +mqtt_message_t *mqtt_msg_pingresp(mqtt_connection_t *connection); +mqtt_message_t *mqtt_msg_disconnect(mqtt_connection_t *connection); +#ifdef __cplusplus +} +#endif + +#endif /* MQTT_MSG_H */ + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_outbox.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_outbox.h new file mode 100644 index 000000000..241b33525 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/mqtt_outbox.h @@ -0,0 +1,64 @@ +/* + * This file is subject to the terms and conditions defined in + * file 'LICENSE', which is part of this source code package. + * Tuan PM + */ +#ifndef _MQTT_OUTOBX_H_ +#define _MQTT_OUTOBX_H_ +#include "platform.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct outbox_item; + +typedef struct outbox_t *outbox_handle_t; +typedef struct outbox_item *outbox_item_handle_t; +typedef struct outbox_message *outbox_message_handle_t; +typedef long long outbox_tick_t; + +typedef struct outbox_message { + uint8_t *data; + int len; + int msg_id; + int msg_qos; + int msg_type; + uint8_t *remaining_data; + int remaining_len; +} outbox_message_t; + +typedef enum pending_state { + QUEUED, + TRANSMITTED, + ACKNOWLEDGED, + CONFIRMED +} pending_state_t; + +outbox_handle_t outbox_init(void); +outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, outbox_tick_t tick); +outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, outbox_tick_t *tick); +outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id); +uint8_t *outbox_item_get_data(outbox_item_handle_t item, size_t *len, uint16_t *msg_id, int *msg_type, int *qos); +esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type); +esp_err_t outbox_delete_item(outbox_handle_t outbox, outbox_item_handle_t item); +int outbox_delete_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout); +/** + * @brief Deletes single expired message returning it's message id + * + * @return msg id of the deleted message, -1 if no expired message in the outbox + */ +int outbox_delete_single_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout); + +esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending); +pending_state_t outbox_item_get_pending(outbox_item_handle_t item); +esp_err_t outbox_set_tick(outbox_handle_t outbox, int msg_id, outbox_tick_t tick); +uint64_t outbox_get_size(outbox_handle_t outbox); +void outbox_destroy(outbox_handle_t outbox); +void outbox_delete_all_items(outbox_handle_t outbox); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform.h new file mode 100644 index 000000000..b3358b9fe --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform.h @@ -0,0 +1,14 @@ +/* + * This file is subject to the terms and conditions defined in + * file 'LICENSE', which is part of this source code package. + * Tuan PM + */ +#ifndef _PLATFORM_H__ +#define _PLATFORM_H__ + +//Support ESP32 +#ifdef ESP_PLATFORM +#include "platform_esp32_idf.h" +#endif + +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform_esp32_idf.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform_esp32_idf.h new file mode 100644 index 000000000..98f5fe14f --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/include/platform_esp32_idf.h @@ -0,0 +1,29 @@ +/* + * This file is subject to the terms and conditions defined in + * file 'LICENSE', which is part of this source code package. + * Tuan PM + */ +#ifndef _ESP_PLATFORM_H__ +#define _ESP_PLATFORM_H__ + +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" + +#include +#include + +char *platform_create_id_string(void); +int platform_random(int max); +uint64_t platform_tick_get_ms(void); + +#define ESP_MEM_CHECK(TAG, a, action) if (!(a)) { \ + ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Memory exhausted"); \ + action; \ + } + +#define ESP_OK_CHECK(TAG, a, action) if ((a) != ESP_OK) { \ + ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Failed"); \ + action; \ + } + +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt5_msg.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt5_msg.c new file mode 100644 index 000000000..32ff92950 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt5_msg.c @@ -0,0 +1,1047 @@ +#include +#include "mqtt5_msg.h" +#include "mqtt_client.h" +#include "mqtt_config.h" +#include "platform.h" +#include "esp_log.h" + +#define MQTT5_MAX_FIXED_HEADER_SIZE 5 + +static const char *TAG = "mqtt5_msg"; + +#define APPEND_CHECK(a, ret) if(a == -1) { \ + ESP_LOGE(TAG,"%s(%d) fail",__FUNCTION__, __LINE__); \ + return (ret); \ + } +#define MQTT5_SHARED_SUB "$share/%s/%s" +#define MQTT5_CONVERT_ONE_BYTE_TO_FOUR(i, a, b, c, d) i = (a << 24); \ + i |= (b << 16); \ + i |= (c << 8); \ + i |= d; + +#define MQTT5_CONVERT_ONE_BYTE_TO_TWO(i, a, b) i = (a << 8); \ + i |= b; + +#define MQTT5_CONVERT_TWO_BYTE(i, a) i = (a >> 8) & 0xff; \ + i = a & 0xff; + +enum mqtt5_connect_flag { + MQTT5_CONNECT_FLAG_USERNAME = 1 << 7, + MQTT5_CONNECT_FLAG_PASSWORD = 1 << 6, + MQTT5_CONNECT_FLAG_WILL_RETAIN = 1 << 5, + MQTT5_CONNECT_FLAG_WILL = 1 << 2, + MQTT5_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 +}; + +static void generate_variable_len(size_t len, uint8_t *len_bytes, uint8_t *encoded_lens) +{ + uint8_t bytes = 0; + do { + uint8_t i = len % 128; + len /= 128; + if (len > 0) { + i |= 0x80; + } + encoded_lens[bytes ++] = i; + } while (len > 0); + *len_bytes = bytes; +} + +static size_t get_variable_len(uint8_t *buffer, size_t offset, size_t buffer_length, uint8_t *len_bytes) +{ + *len_bytes = 0; + size_t len = 0, i = 0; + for (i = offset; i < buffer_length; i ++) { + len += (buffer[i] & 0x7f) << (7 * (i - offset)); + if ((buffer[i] & 0x80) == 0) { + i ++; + break; + } + } + *len_bytes = i - offset; + return len; +} + +static int update_property_len_value(mqtt_connection_t *connection, size_t property_len, int property_offset) +{ + uint8_t encoded_lens[4] = {0}, len_bytes = 0; + size_t len = property_len, message_offset = property_offset + property_len; + generate_variable_len(len, &len_bytes, encoded_lens); + int offset = len_bytes - 1; + + connection->outbound_message.length += offset; + if (connection->outbound_message.length > connection->buffer_length) { + return -1; + } + + if (offset > 0) { + for (int i = 0; i < property_len; i ++) { + connection->buffer[message_offset + offset] = connection->buffer[message_offset]; + message_offset --; + } + } + + for (int i = 0; i < len_bytes; i ++) { + connection->buffer[property_offset ++] = encoded_lens[i]; + } + return offset; +} + +static int append_property(mqtt_connection_t *connection, uint8_t property_type, uint8_t len_occupy, const char *data, size_t data_len) +{ + if ((connection->outbound_message.length + len_occupy + (data ? data_len : 0) + (property_type ? 1 : 0)) > connection->buffer_length) { + return -1; + } + + size_t origin_message_len = connection->outbound_message.length; + if (property_type) { + connection->buffer[connection->outbound_message.length ++] = property_type; + } + + if (len_occupy == 0) { + uint8_t encoded_lens[4] = {0}, len_bytes = 0; + generate_variable_len(data_len, &len_bytes, encoded_lens); + for (int j = 0; j < len_bytes; j ++) { + connection->buffer[connection->outbound_message.length ++] = encoded_lens[j]; + } + } else { + for (int i = 1; i <= len_occupy; i ++) { + connection->buffer[connection->outbound_message.length ++] = (data_len >> (8 * (len_occupy - i))) & 0xff; + } + } + + if (data) { + memcpy(connection->buffer + connection->outbound_message.length, data, data_len); + connection->outbound_message.length += data_len; + } + + return connection->outbound_message.length - origin_message_len; +} + +static uint16_t append_message_id(mqtt_connection_t *connection, uint16_t message_id) +{ + // If message_id is zero then we should assign one, otherwise + // we'll use the one supplied by the caller + while (message_id == 0) { +#if MQTT_MSG_ID_INCREMENTAL + message_id = ++ connection->last_message_id; +#else + message_id = platform_random(65535); +#endif + } + + if (connection->outbound_message.length + 2 > connection->buffer_length) { + return 0; + } + + MQTT5_CONVERT_TWO_BYTE(connection->buffer[connection->outbound_message.length ++], message_id) + + return message_id; +} + +static int init_message(mqtt_connection_t *connection) +{ + connection->outbound_message.length = MQTT5_MAX_FIXED_HEADER_SIZE; + return MQTT5_MAX_FIXED_HEADER_SIZE; +} + +static mqtt_message_t *fail_message(mqtt_connection_t *connection) +{ + connection->outbound_message.data = connection->buffer; + connection->outbound_message.length = 0; + return &connection->outbound_message; +} + +static mqtt_message_t *fini_message(mqtt_connection_t *connection, int type, int dup, int qos, int retain) +{ + int message_length = connection->outbound_message.length - MQTT5_MAX_FIXED_HEADER_SIZE; + int total_length = message_length; + uint8_t encoded_lens[4] = {0}, len_bytes = 0; + // Check if we have fragmented message and update total_len + if (connection->outbound_message.fragmented_msg_total_length) { + total_length = connection->outbound_message.fragmented_msg_total_length - MQTT5_MAX_FIXED_HEADER_SIZE; + } + + // Encode MQTT message length + generate_variable_len(total_length, &len_bytes, encoded_lens); + + // Sanity check for MQTT header + if (len_bytes + 1 > MQTT5_MAX_FIXED_HEADER_SIZE) { + return fail_message(connection); + } + + // Save the header bytes + connection->outbound_message.length = message_length + len_bytes + 1; // msg len + encoded_size len + type (1 byte) + int offs = MQTT5_MAX_FIXED_HEADER_SIZE - 1 - len_bytes; + connection->outbound_message.data = connection->buffer + offs; + connection->outbound_message.fragmented_msg_data_offset -= offs; + // type byte + connection->buffer[offs ++] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + // length bytes + for (int j = 0; j < len_bytes; j ++) { + connection->buffer[offs ++] = encoded_lens[j]; + } + + return &connection->outbound_message; +} + +static esp_err_t mqtt5_msg_set_user_property(mqtt5_user_property_handle_t *user_property, char *key, size_t key_len, char *value, size_t value_len) +{ + if (!*user_property) { + *user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + ESP_MEM_CHECK(TAG, *user_property, return ESP_FAIL); + STAILQ_INIT(*user_property); + } + + mqtt5_user_property_item_t user_property_item = calloc(1, sizeof(mqtt5_user_property_t)); + ESP_MEM_CHECK(TAG, user_property_item, return ESP_FAIL;); + user_property_item->key = calloc(1, key_len + 1); + ESP_MEM_CHECK(TAG, user_property_item->key, { + free(user_property_item); + return ESP_FAIL; + }); + memcpy(user_property_item->key, key, key_len); + user_property_item->key[key_len] = '\0'; + + user_property_item->value = calloc(1, value_len + 1); + ESP_MEM_CHECK(TAG, user_property_item->value, { + free(user_property_item->key); + free(user_property_item); + return ESP_FAIL; + }); + memcpy(user_property_item->value, value, value_len); + user_property_item->value[value_len] = '\0'; + + STAILQ_INSERT_TAIL(*user_property, user_property_item, next); + return ESP_OK; +} + +static mqtt5_user_property_handle_t mqtt5_msg_get_user_property(uint8_t *buffer, size_t buffer_length) +{ + mqtt5_user_property_handle_t user_porperty = NULL; + uint8_t *property = buffer; + uint16_t property_offset = 0, len = 0; + while (property_offset < buffer_length) { + uint8_t property_id = property[property_offset ++]; + switch (property_id) { + case MQTT5_PROPERTY_REASON_STRING: //only print now + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_REASON_STRING %.*s", len, &property[property_offset]); + property_offset += len; + continue; + case MQTT5_PROPERTY_USER_PROPERTY: { + uint8_t *key = NULL, *value = NULL; + size_t key_len = 0, value_len = 0; + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + key = &property[property_offset]; + key_len = len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY key: %.*s", key_len, (char *)key); + property_offset += len; + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + value = &property[property_offset]; + value_len = len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY value: %.*s", value_len, (char *)value); + property_offset += len; + if (mqtt5_msg_set_user_property(&user_porperty, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { + ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); + goto err; + } + continue; + } + default: + ESP_LOGW(TAG, "Unknow property id 0x%02x", property_id); + goto err; + } + } + return user_porperty; +err: + esp_mqtt5_client_delete_user_property(user_porperty); + return NULL; +} + +uint16_t mqtt5_get_id(uint8_t *buffer, size_t length) +{ + int topiclen = 0; + uint8_t len_bytes = 0; + size_t offset = 1; + size_t totlen = get_variable_len(buffer, offset, length, &len_bytes); + offset += len_bytes; + totlen += offset; + + if (offset + 2 > length) { + return 0; + } + + switch (mqtt5_get_type(buffer)) { + case MQTT_MSG_TYPE_PUBLISH: { + MQTT5_CONVERT_ONE_BYTE_TO_TWO(topiclen, buffer[offset++], buffer[offset++]) + offset += topiclen; + if (offset + 2 > length) { + return 0; + } + if (mqtt_get_qos(buffer) == 0) { + return 0; + } + return (buffer[offset] << 8) | buffer[offset + 1]; + } + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_SUBSCRIBE: + case MQTT_MSG_TYPE_UNSUBSCRIBE: { + return (buffer[offset] << 8) | buffer[offset + 1]; + } + default: + return 0; + } +} + +char *mqtt5_get_publish_property_payload(uint8_t *buffer, size_t buffer_length, char **msg_topic, size_t *msg_topic_len, esp_mqtt5_publish_resp_property_t *resp_property, uint16_t *property_len, size_t *payload_len, mqtt5_user_property_handle_t *user_property) +{ + *user_property = NULL; + uint8_t len_bytes = 0; + size_t offset = 1; + size_t totlen = get_variable_len(buffer, offset, buffer_length, &len_bytes); + offset += len_bytes; + totlen += offset; + + size_t topic_len = buffer[offset ++] << 8; + topic_len |= buffer[offset ++] & 0xff; + *msg_topic = (char *)(buffer + offset); + *msg_topic_len = topic_len; + offset += topic_len; + + if (offset >= buffer_length) { + return NULL; + } + + if (mqtt5_get_qos(buffer) > 0) { + if (offset + 2 >= buffer_length) { + return NULL; + } + offset += 2; // skip the message id + } + + *property_len = get_variable_len(buffer, offset, buffer_length, &len_bytes); + offset += len_bytes; + + uint16_t len = 0, property_offset = 0; + uint8_t *property = (buffer + offset); + while (property_offset < *property_len) { + uint8_t property_id = property[property_offset ++]; + switch (property_id) { + case MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR: + resp_property->payload_format_indicator = property[property_offset ++]; + ESP_LOGD(TAG, "MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR %d", resp_property->payload_format_indicator); + continue; + case MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL: + MQTT5_CONVERT_ONE_BYTE_TO_FOUR(resp_property->message_expiry_interval, property[property_offset ++], property[property_offset ++], property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL %"PRIu32, resp_property->message_expiry_interval); + continue; + case MQTT5_PROPERTY_TOPIC_ALIAS: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->topic_alias, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_TOPIC_ALIAS %d", resp_property->topic_alias); + continue; + case MQTT5_PROPERTY_RESPONSE_TOPIC: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->response_topic_len, property[property_offset ++], property[property_offset ++]) + resp_property->response_topic = (char *)(property + property_offset); + property_offset += resp_property->response_topic_len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_RESPONSE_TOPIC %.*s", resp_property->response_topic_len, resp_property->response_topic); + continue; + case MQTT5_PROPERTY_CORRELATION_DATA: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->correlation_data_len, property[property_offset ++], property[property_offset ++]) + resp_property->correlation_data = (char *)(property + property_offset); + property_offset += resp_property->correlation_data_len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_CORRELATION_DATA length %d", resp_property->correlation_data_len); + continue; + case MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER: + resp_property->subscribe_id = get_variable_len(property, property_offset, buffer_length, &len_bytes); + property_offset += len_bytes; + ESP_LOGD(TAG, "MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER %d", resp_property->subscribe_id); + continue; + case MQTT5_PROPERTY_CONTENT_TYPE: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->content_type_len, property[property_offset ++], property[property_offset ++]) + resp_property->content_type = (char *)(property + property_offset); + property_offset += resp_property->content_type_len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_CONTENT_TYPE %.*s", resp_property->content_type_len, resp_property->content_type); + continue; + case MQTT5_PROPERTY_USER_PROPERTY: { + uint8_t *key = NULL, *value = NULL; + size_t key_len = 0, value_len = 0; + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + key = &property[property_offset]; + key_len = len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY key: %.*s", key_len, (char *)key); + property_offset += len; + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + value = &property[property_offset]; + value_len = len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY value: %.*s", value_len, (char *)value); + property_offset += len; + if (mqtt5_msg_set_user_property(user_property, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { + esp_mqtt5_client_delete_user_property(*user_property); + *user_property = NULL; + ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); + return NULL; + } + continue; + } + case MQTT5_PROPERTY_REASON_STRING: //only print now + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_REASON_STRING %.*s", len, &property[property_offset]); + property_offset += len; + continue; + default: + ESP_LOGW(TAG, "Unknow publish property id 0x%02x", property_id); + return NULL; + } + } + + offset += property_offset; + if (totlen <= buffer_length) { + *payload_len = totlen - offset; + } else { + *payload_len = buffer_length - offset; + } + return (char *)(buffer + offset); +} + +char *mqtt5_get_suback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property) +{ + uint8_t len_bytes = 0; + size_t offset = 1; + size_t totlen = get_variable_len(buffer, offset, *length, &len_bytes); + offset += len_bytes; + totlen += offset; + + if (totlen > *length) { + goto err; + } + offset += 2; // skip the message id + if (offset < totlen) { + size_t property_len = get_variable_len(buffer, offset, totlen, &len_bytes); + offset += len_bytes; + *user_property = mqtt5_msg_get_user_property(buffer + offset, property_len); + offset += property_len; + if (offset < totlen) { + *length = totlen - offset; + return (char *)(buffer + offset); + } + } +err: + *user_property = NULL; + *length = 0; + return NULL; +} + +char *mqtt5_get_puback_data(uint8_t *buffer, size_t *length, mqtt5_user_property_handle_t *user_property) +{ + uint8_t len_bytes = 0; + size_t offset = 1; + size_t totlen = get_variable_len(buffer, offset, *length, &len_bytes); + offset += len_bytes; + totlen += offset; + + offset += 2; // skip the message id + if (offset < totlen) { + *length = 1; + char *data = (char *)(buffer + offset); + offset ++; + if (offset < totlen) { + size_t property_len = get_variable_len(buffer, offset, totlen, &len_bytes); + offset += len_bytes; + *user_property = mqtt5_msg_get_user_property(buffer + offset, property_len); + } + return data; + } else { + *length = 0; + return NULL; + } +} + +mqtt_message_t *mqtt5_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info, esp_mqtt5_connection_property_storage_t *property, esp_mqtt5_connection_will_property_storage_t *will_property) +{ + init_message(connection); + connection->buffer[connection->outbound_message.length ++] = 0; // Variable header length MSB + /* Defaults to protocol version 5 values */ + connection->buffer[connection->outbound_message.length ++] = 4; // Variable header length LSB + memcpy(&connection->buffer[connection->outbound_message.length], "MQTT", 4); // Protocol name + connection->outbound_message.length += 4; + connection->buffer[connection->outbound_message.length ++] = 5; // Protocol version + + int flags_offset = connection->outbound_message.length; + connection->buffer[connection->outbound_message.length ++] = 0; // Flags + MQTT5_CONVERT_TWO_BYTE(connection->buffer[connection->outbound_message.length ++], info->keepalive) // Keep-alive + + if (info->clean_session) { + connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_CLEAN_SESSION; + } + + //Add properties + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + if (property->session_expiry_interval) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL, 4, NULL, property->session_expiry_interval), fail_message(connection)); + } + if (property->maximum_packet_size) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE, 4, NULL, property->maximum_packet_size), fail_message(connection)); + } + if (property->receive_maximum) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_RECEIVE_MAXIMUM, 2, NULL, property->receive_maximum), fail_message(connection)); + } + if (property->topic_alias_maximum) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM, 2, NULL, property->topic_alias_maximum), fail_message(connection)); + } + if (property->request_resp_info) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_REQUEST_RESP_INFO, 1, NULL, 1), fail_message(connection)); + } + if (property->request_problem_info) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_REQUEST_PROBLEM_INFO, 1, NULL, 1), fail_message(connection)); + } + if (property->user_property) { + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, property->user_property, next) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); + APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); + } + } + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + + if (info->client_id != NULL && info->client_id[0] != '\0') { + APPEND_CHECK(append_property(connection, 0, 2, info->client_id, strlen(info->client_id)), fail_message(connection)); + } else { + APPEND_CHECK(append_property(connection, 0, 2, NULL, 0), fail_message(connection)); + } + + //Add will properties + if (info->will_topic != NULL && info->will_topic[0] != '\0') { + properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + if (will_property->will_delay_interval) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_WILL_DELAY_INTERVAL, 4, NULL, will_property->will_delay_interval), fail_message(connection)); + } + if (will_property->payload_format_indicator) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR, 1, NULL, 1), fail_message(connection)); + } + if (will_property->message_expiry_interval) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL, 4, NULL, will_property->message_expiry_interval), fail_message(connection)); + } + if (will_property->content_type) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CONTENT_TYPE, 2, will_property->content_type, strlen(will_property->content_type)), fail_message(connection)); + } + if (will_property->response_topic) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_RESPONSE_TOPIC, 2, will_property->response_topic, strlen(will_property->response_topic)), fail_message(connection)); + } + if (will_property->correlation_data && will_property->correlation_data_len) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CORRELATION_DATA, 2, will_property->correlation_data, will_property->correlation_data_len), fail_message(connection)); + } + if (will_property->user_property) { + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, will_property->user_property, next) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); + APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); + } + } + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + + APPEND_CHECK(append_property(connection, 0, 2, info->will_topic, strlen(info->will_topic)), fail_message(connection)); + APPEND_CHECK(append_property(connection, 0, 2, info->will_message, info->will_length), fail_message(connection)); + + connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_WILL; + if (info->will_retain) { + connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_WILL_RETAIN; + } + connection->buffer[flags_offset] |= (info->will_qos & 3) << 3; + } + + if (info->username != NULL && info->username[0] != '\0') { + APPEND_CHECK(append_property(connection, 0, 2, info->username, strlen(info->username)), fail_message(connection)); + connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_USERNAME; + } + + if (info->password != NULL && info->password[0] != '\0') { + if (info->username == NULL || info->username[0] == '\0') { + /* In case if password is set without username, we need to set a zero length username. + * (otherwise we violate: MQTT-3.1.2-22: If the User Name Flag is set to 0 then the Password Flag MUST be set to 0.) + */ + APPEND_CHECK(append_property(connection, 0, 2, NULL, 0), fail_message(connection)); + connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_USERNAME; + } + APPEND_CHECK(append_property(connection, 0, 2, info->password, strlen(info->password)), fail_message(connection)); + connection->buffer[flags_offset] |= MQTT5_CONNECT_FLAG_PASSWORD; + } + + return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); +} + +esp_err_t mqtt5_msg_parse_connack_property(uint8_t *buffer, size_t buffer_len, mqtt_connect_info_t *connection_info, esp_mqtt5_connection_property_storage_t *connection_property, esp_mqtt5_connection_server_resp_property_t *resp_property, int *reason_code, uint8_t *ack_flag, mqtt5_user_property_handle_t *user_property) +{ + *reason_code = 0; + *user_property = NULL; + uint8_t len_bytes = 0; + size_t offset = 1; + size_t totlen = get_variable_len(buffer, offset, buffer_len, &len_bytes); + offset += len_bytes; + totlen += offset; + + if (totlen > buffer_len) { + ESP_LOGE(TAG, "Total length %d is over read len %d", totlen, buffer_len); + return ESP_FAIL; + } + + *ack_flag = buffer[offset ++]; //acknowledge flags + *reason_code = buffer[offset ++]; //reason code + size_t property_len = get_variable_len(buffer, offset, buffer_len, &len_bytes); + offset += len_bytes; + uint16_t property_offset = 0, len = 0; + uint8_t *property = (buffer + offset); + while (property_offset < property_len) { + uint8_t property_id = property[property_offset ++]; + switch (property_id) { + case MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL: + MQTT5_CONVERT_ONE_BYTE_TO_FOUR(connection_property->session_expiry_interval, property[property_offset ++], property[property_offset ++], property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL %"PRIu32, connection_property->session_expiry_interval); + continue; + case MQTT5_PROPERTY_RECEIVE_MAXIMUM: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->receive_maximum, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_RECEIVE_MAXIMUM %d", resp_property->receive_maximum); + continue; + case MQTT5_PROPERTY_MAXIMUM_QOS: + resp_property->max_qos = property[property_offset ++]; + ESP_LOGD(TAG, "MQTT5_PROPERTY_MAXIMUM_QOS %d", resp_property->max_qos); + continue; + case MQTT5_PROPERTY_RETAIN_AVAILABLE: + resp_property->retain_available = property[property_offset ++]; + ESP_LOGD(TAG, "MQTT5_PROPERTY_RETAIN_AVAILABLE %d", resp_property->retain_available); + continue; + case MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE: + MQTT5_CONVERT_ONE_BYTE_TO_FOUR(resp_property->maximum_packet_size, property[property_offset ++], property[property_offset ++], property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_MAXIMUM_PACKET_SIZE %"PRIu32, resp_property->maximum_packet_size); + continue; + case MQTT5_PROPERTY_ASSIGNED_CLIENT_IDENTIFIER: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + if (connection_info->client_id) { + free(connection_info->client_id); + } + connection_info->client_id = calloc(1, len + 1); + if (!connection_info->client_id) { + ESP_LOGE(TAG, "Failed to calloc %d data", len); + return ESP_FAIL; + } + memcpy(connection_info->client_id, &property[property_offset], len); + connection_info->client_id[len] = '\0'; + property_offset += len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_ASSIGNED_CLIENT_IDENTIFIER %s", connection_info->client_id); + continue; + case MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(resp_property->topic_alias_maximum, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_TOPIC_ALIAS_MAXIMIM %d", resp_property->topic_alias_maximum); + continue; + case MQTT5_PROPERTY_REASON_STRING: //only print now + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_REASON_STRING %.*s", len, &property[property_offset]); + property_offset += len; + continue; + case MQTT5_PROPERTY_USER_PROPERTY: { + uint8_t *key = NULL, *value = NULL; + size_t key_len = 0, value_len = 0; + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + key = &property[property_offset]; + key_len = len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY key: %.*s", key_len, (char *)key); + property_offset += len; + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + value = &property[property_offset]; + value_len = len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_USER_PROPERTY value: %.*s", value_len, (char *)value); + property_offset += len; + if (mqtt5_msg_set_user_property(user_property, (char *)key, key_len, (char *)value, value_len) != ESP_OK) { + esp_mqtt5_client_delete_user_property(*user_property); + *user_property = NULL; + ESP_LOGE(TAG, "mqtt5_msg_set_user_property fail"); + return ESP_FAIL; + } + continue; + } + case MQTT5_PROPERTY_WILDCARD_SUBSCR_AVAILABLE: + resp_property->wildcard_subscribe_available = property[property_offset++]; + ESP_LOGD(TAG, "MQTT5_PROPERTY_WILDCARD_SUBSCR_AVAILABLE %d", resp_property->wildcard_subscribe_available); + continue; + case MQTT5_PROPERTY_SUBSCR_IDENTIFIER_AVAILABLE: + resp_property->subscribe_identifiers_available = property[property_offset++]; + ESP_LOGD(TAG, "MQTT5_PROPERTY_SUBSCR_IDENTIFIER_AVAILABLE %d", resp_property->subscribe_identifiers_available); + continue; + case MQTT5_PROPERTY_SHARED_SUBSCR_AVAILABLE: + resp_property->shared_subscribe_available = property[property_offset++]; + ESP_LOGD(TAG, "MQTT5_PROPERTY_SHARED_SUBSCR_AVAILABLE %d", resp_property->shared_subscribe_available); + continue; + case MQTT5_PROPERTY_SERVER_KEEP_ALIVE: + MQTT5_CONVERT_ONE_BYTE_TO_TWO(connection_info->keepalive, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_SERVER_KEEP_ALIVE %lld", connection_info->keepalive); + continue; + case MQTT5_PROPERTY_RESP_INFO: + if (resp_property->response_info) { + free(resp_property->response_info); + } + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + resp_property->response_info = calloc(1, len + 1); + if (!resp_property->response_info) { + ESP_LOGE(TAG, "Failed to calloc %d data", len); + return ESP_FAIL; + } + memcpy(resp_property->response_info, &property[property_offset], len); + resp_property->response_info[len] = '\0'; + property_offset += len; + ESP_LOGD(TAG, "MQTT5_PROPERTY_RESP_INFO %s", resp_property->response_info); + continue; + case MQTT5_PROPERTY_SERVER_REFERENCE: //only print now + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_SERVER_REFERENCE %.*s", len, &property[property_offset]); + property_offset += len; + continue; + case MQTT5_PROPERTY_AUTHENTICATION_METHOD: //only print now + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_AUTHENTICATION_METHOD %.*s", len, &property[property_offset]); + property_offset += len; + continue; + case MQTT5_PROPERTY_AUTHENTICATION_DATA: //only print now + MQTT5_CONVERT_ONE_BYTE_TO_TWO(len, property[property_offset ++], property[property_offset ++]) + ESP_LOGD(TAG, "MQTT5_PROPERTY_AUTHENTICATION_DATA length %d", len); + property_offset += len; + continue; + default: + ESP_LOGW(TAG, "Unknow connack property id 0x%02x", property_id); + return ESP_FAIL; + } + } + return ESP_OK; +} + +mqtt_message_t *mqtt5_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id, const esp_mqtt5_publish_property_config_t *property, const char *resp_info) +{ + init_message(connection); + + if ((topic == NULL || topic[0] == '\0') && (!property || !property->topic_alias)){ + ESP_LOGE(TAG, "Message must have a topic filter or a topic alias set"); + return fail_message(connection); + } + int topic_len = (topic == NULL || topic[0] == '\0') ? 0 : strlen(topic); + APPEND_CHECK(append_property(connection, 0, 2, topic, topic_len), fail_message(connection)); + + if (data == NULL && data_length > 0) { + return fail_message(connection); + } + + if (qos > 0) { + if ((*message_id = append_message_id(connection, 0)) == 0) { + return fail_message(connection); + } + } else { + *message_id = 0; + } + + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + + if (property) { + if (property->payload_format_indicator) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_PAYLOAD_FORMAT_INDICATOR, 1, NULL, 1), fail_message(connection)); + } + if (property->message_expiry_interval) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_MESSAGE_EXPIRY_INTERVAL, 4, NULL, property->message_expiry_interval), fail_message(connection)); + } + if (property->topic_alias) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_TOPIC_ALIAS, 2, NULL, property->topic_alias), fail_message(connection)); + } + if (property->response_topic) { + if (resp_info && strlen(resp_info)) { + uint16_t response_topic_size = strlen(property->response_topic) + strlen(resp_info) + 1; + char *response_topic = calloc(1, response_topic_size); + if (!response_topic) { + ESP_LOGE(TAG, "Failed to calloc %d memory", response_topic_size); + return fail_message(connection); + } + snprintf(response_topic, response_topic_size, "%s/%s", property->response_topic, resp_info); + if (append_property(connection, MQTT5_PROPERTY_RESPONSE_TOPIC, 2, response_topic, response_topic_size) == -1) { + ESP_LOGE(TAG, "%s(%d) fail", __FUNCTION__, __LINE__); + free(response_topic); + return fail_message(connection); + } + free(response_topic); + } else { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_RESPONSE_TOPIC, 2, property->response_topic, strlen(property->response_topic)), fail_message(connection)); + } + } + if (property->correlation_data && property->correlation_data_len) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CORRELATION_DATA, 2, property->correlation_data, property->correlation_data_len), fail_message(connection)); + } + if (property->user_property) { + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, property->user_property, next) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); + APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); + } + } + if (property->content_type) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_CONTENT_TYPE, 2, property->content_type, strlen(property->content_type)), fail_message(connection)); + } + } + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + + if (connection->outbound_message.length + data_length > connection->buffer_length) { + // Not enough size in buffer -> fragment this message + connection->outbound_message.fragmented_msg_data_offset = connection->outbound_message.length; + memcpy(connection->buffer + connection->outbound_message.length, data, connection->buffer_length - connection->outbound_message.length); + connection->outbound_message.length = connection->buffer_length; + connection->outbound_message.fragmented_msg_total_length = data_length + connection->outbound_message.fragmented_msg_data_offset; + } else { + if (data != NULL) { + memcpy(connection->buffer + connection->outbound_message.length, data, data_length); + connection->outbound_message.length += data_length; + } + connection->outbound_message.fragmented_msg_total_length = 0; + } + return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); +} + +int mqtt5_msg_get_reason_code(uint8_t *buffer, size_t length) +{ + uint8_t len_bytes = 0; + size_t offset = 1; // Message type + size_t variable_len = get_variable_len(buffer, offset, length, &len_bytes); + offset += len_bytes; + + switch (mqtt5_get_type(buffer)) { + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_PUBCOMP: + if(variable_len == 2) { + return 0; + } + offset += 2; //skip the message id + if (offset >= length) { + ESP_LOGE(TAG, "Invalid control packet, reason code is absent"); + return -1; + } + return buffer[offset]; + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: { + offset += 2; //skip the message id + if (offset >= length) { + return -1; + } + size_t property_len = get_variable_len(buffer, offset, length, &len_bytes); + offset = offset + len_bytes + property_len; + if (offset >= length) { + ESP_LOGE(TAG, "Invalid control packet, reason code is absent"); + return -1; + } + return buffer[offset]; + } + case MQTT_MSG_TYPE_DISCONNECT: + if (offset >= length) { + return -1; + } else { + return buffer[offset]; + } + default: + break; + } + return -1; +} + +mqtt_message_t *mqtt5_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t *topic_list, int size, uint16_t *message_id, const esp_mqtt5_subscribe_property_config_t *property) +{ + init_message(connection); + + if ((*message_id = append_message_id(connection, 0)) == 0) { + return fail_message(connection); + } + + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + + if (property) { + if (property->subscribe_id) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_SUBSCRIBE_IDENTIFIER, 0, NULL, property->subscribe_id), fail_message(connection)); + } + if (property->user_property) { + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, property->user_property, next) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); + APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); + } + } + } + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + + for (int topic_number = 0; topic_number < size; ++topic_number) { + if (topic_list[topic_number].filter[0] == '\0') { + return fail_message(connection); + } + if (property && property->is_share_subscribe) { + uint16_t shared_topic_size = strlen(topic_list[topic_number].filter) + strlen(MQTT5_SHARED_SUB) + strlen(property->share_name); + char *shared_topic = calloc(1, shared_topic_size); + if (!shared_topic) { + ESP_LOGE(TAG, "Failed to calloc %d memory", shared_topic_size); + fail_message(connection); + } + snprintf(shared_topic, shared_topic_size, MQTT5_SHARED_SUB, property->share_name, topic_list[topic_number].filter); + if (append_property(connection, 0, 2, shared_topic, strlen(shared_topic)) == -1) { + ESP_LOGE(TAG, "%s(%d) fail", __FUNCTION__, __LINE__); + free(shared_topic); + return fail_message(connection); + } + free(shared_topic); + } else { + APPEND_CHECK(append_property(connection, 0, 2, topic_list[topic_number].filter, strlen(topic_list[topic_number].filter)), fail_message(connection)); + } + + if (connection->outbound_message.length + 1 > connection->buffer_length) { + return fail_message(connection); + } + connection->buffer[connection->outbound_message.length] = 0; + if (property) { + if (property->retain_handle > 0 && property->retain_handle < 3) { + connection->buffer[connection->outbound_message.length] |= (property->retain_handle & 3) << 4; + } + if (property->no_local_flag) { + connection->buffer[connection->outbound_message.length] |= (property->no_local_flag << 2); + } + if (property->retain_as_published_flag) { + connection->buffer[connection->outbound_message.length] |= (property->retain_as_published_flag << 3); + } + } + connection->buffer[connection->outbound_message.length] |= (topic_list[topic_number].qos & 3); + connection->outbound_message.length ++; + } + return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t *mqtt5_msg_disconnect(mqtt_connection_t *connection, esp_mqtt5_disconnect_property_config_t *disconnect_property_info) +{ + init_message(connection); + int reason_offset = connection->outbound_message.length; + connection->buffer[connection->outbound_message.length ++] = 0; + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + if (disconnect_property_info) { + if (disconnect_property_info->session_expiry_interval) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_SESSION_EXPIRY_INTERVAL, 4, NULL, disconnect_property_info->session_expiry_interval), fail_message(connection)); + } + if (disconnect_property_info->user_property) { + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, disconnect_property_info->user_property, next) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); + APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); + } + } + if (disconnect_property_info->disconnect_reason) { + connection->buffer[reason_offset] = disconnect_property_info->disconnect_reason; + } + } + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); +} + +mqtt_message_t *mqtt5_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id, const esp_mqtt5_unsubscribe_property_config_t *property) +{ + init_message(connection); + + if (topic == NULL || topic[0] == '\0') { + return fail_message(connection); + } + + if ((*message_id = append_message_id(connection, 0)) == 0) { + return fail_message(connection); + } + + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + if (property) { + if (property->user_property) { + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, property->user_property, next) { + APPEND_CHECK(append_property(connection, MQTT5_PROPERTY_USER_PROPERTY, 2, item->key, strlen(item->key)), fail_message(connection)); + APPEND_CHECK(append_property(connection, 0, 2, item->value, strlen(item->value)), fail_message(connection)); + } + } + } + + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + if (property && property->is_share_subscribe) { + uint16_t shared_topic_size = strlen(topic) + strlen(MQTT5_SHARED_SUB) + strlen(property->share_name); + char *shared_topic = calloc(1, shared_topic_size); + if (!shared_topic) { + ESP_LOGE(TAG, "Failed to calloc %d memory", shared_topic_size); + fail_message(connection); + } + snprintf(shared_topic, shared_topic_size, MQTT5_SHARED_SUB, property->share_name, topic); + if (append_property(connection, 0, 2, shared_topic, strlen(shared_topic)) == -1) { + ESP_LOGE(TAG, "%s(%d) fail", __FUNCTION__, __LINE__); + free(shared_topic); + return fail_message(connection); + } + free(shared_topic); + } else { + APPEND_CHECK(append_property(connection, 0, 2, topic, strlen(topic)), fail_message(connection)); + } + + return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t *mqtt5_msg_puback(mqtt_connection_t *connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + connection->buffer[connection->outbound_message.length ++] = 0; // Regard it is success + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); +} + +mqtt_message_t *mqtt5_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + connection->buffer[connection->outbound_message.length ++] = 0; // Regard it is success + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); +} + +mqtt_message_t *mqtt5_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + connection->buffer[connection->outbound_message.length ++] = 0; // Regard it is success + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); +} + +mqtt_message_t *mqtt5_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id) +{ + init_message(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + connection->buffer[connection->outbound_message.length ++] = 0; // Regard it is success + int properties_offset = connection->outbound_message.length; + connection->outbound_message.length ++; + APPEND_CHECK(update_property_len_value(connection, connection->outbound_message.length - properties_offset - 1, properties_offset), fail_message(connection)); + return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_msg.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_msg.c new file mode 100644 index 000000000..582fc92d8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_msg.c @@ -0,0 +1,637 @@ +/* +* Copyright (c) 2014, Stephen Robinson +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ +#include +#include "mqtt_client.h" +#include "mqtt_msg.h" +#include "mqtt_config.h" +#include "platform.h" + +#define MQTT_MAX_FIXED_HEADER_SIZE 5 +#define MQTT_3_1_VARIABLE_HEADER_SIZE 12 +#define MQTT_3_1_1_VARIABLE_HEADER_SIZE 10 + +enum mqtt_connect_flag { + MQTT_CONNECT_FLAG_USERNAME = 1 << 7, + MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, + MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, + MQTT_CONNECT_FLAG_WILL = 1 << 2, + MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 +}; + +static int append_string(mqtt_connection_t *connection, const char *string, int len) +{ + if (connection->outbound_message.length + len + 2 > connection->buffer_length) { + return -1; + } + + connection->buffer[connection->outbound_message.length++] = len >> 8; + connection->buffer[connection->outbound_message.length++] = len & 0xff; + memcpy(connection->buffer + connection->outbound_message.length, string, len); + connection->outbound_message.length += len; + + return len + 2; +} + +static uint16_t append_message_id(mqtt_connection_t *connection, uint16_t message_id) +{ + // If message_id is zero then we should assign one, otherwise + // we'll use the one supplied by the caller + while (message_id == 0) { +#if MQTT_MSG_ID_INCREMENTAL + message_id = ++connection->last_message_id; +#else + message_id = platform_random(65535); +#endif + } + + if (connection->outbound_message.length + 2 > connection->buffer_length) { + return 0; + } + + connection->buffer[connection->outbound_message.length++] = message_id >> 8; + connection->buffer[connection->outbound_message.length++] = message_id & 0xff; + + return message_id; +} + +static int set_message_header_size(mqtt_connection_t *connection) +{ + connection->outbound_message.length = MQTT_MAX_FIXED_HEADER_SIZE; + return MQTT_MAX_FIXED_HEADER_SIZE; +} + +static mqtt_message_t *fail_message(mqtt_connection_t *connection) +{ + connection->outbound_message.data = connection->buffer; + connection->outbound_message.length = 0; + return &connection->outbound_message; +} + +static mqtt_message_t *fini_message(mqtt_connection_t *connection, int type, int dup, int qos, int retain) +{ + int message_length = connection->outbound_message.length - MQTT_MAX_FIXED_HEADER_SIZE; + int total_length = message_length; + int encoded_length = 0; + uint8_t encoded_lens[4] = {0}; + // Check if we have fragmented message and update total_len + if (connection->outbound_message.fragmented_msg_total_length) { + total_length = connection->outbound_message.fragmented_msg_total_length - MQTT_MAX_FIXED_HEADER_SIZE; + } + + // Encode MQTT message length + int len_bytes = 0; // size of encoded message length + do { + encoded_length = total_length % 128; + total_length /= 128; + if (total_length > 0) { + encoded_length |= 0x80; + } + encoded_lens[len_bytes] = encoded_length; + len_bytes++; + } while (total_length > 0); + + // Sanity check for MQTT header + if (len_bytes + 1 > MQTT_MAX_FIXED_HEADER_SIZE) { + return fail_message(connection); + } + + // Save the header bytes + connection->outbound_message.length = message_length + len_bytes + 1; // msg len + encoded_size len + type (1 byte) + int offs = MQTT_MAX_FIXED_HEADER_SIZE - 1 - len_bytes; + connection->outbound_message.data = connection->buffer + offs; + connection->outbound_message.fragmented_msg_data_offset -= offs; + // type byte + connection->buffer[offs++] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + // length bytes + for (int j = 0; j < len_bytes; j++) { + connection->buffer[offs++] = encoded_lens[j]; + } + + return &connection->outbound_message; +} + +size_t mqtt_get_total_length(const uint8_t *buffer, size_t length, int *fixed_size_len) +{ + int i; + size_t totlen = 0; + + for (i = 1; i < length; ++i) { + totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); + if ((buffer[i] & 0x80) == 0) { + ++i; + break; + } + } + totlen += i; + if (fixed_size_len) { + *fixed_size_len = i; + } + + return totlen; +} + +bool mqtt_header_complete(uint8_t *buffer, size_t buffer_length) +{ + uint16_t i; + uint16_t topiclen; + + for (i = 1; i < MQTT_MAX_FIXED_HEADER_SIZE; ++i) { + if (i >= buffer_length) { + return false; + } + if ((buffer[i] & 0x80) == 0) { + ++i; + break; + } + } + // i is now the length of the fixed header + + if (i + 2 >= buffer_length) { + return false; + } + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + i += topiclen; + + if (mqtt_get_qos(buffer) > 0) { + i += 2; + } + // i is now the length of the fixed + variable header + return buffer_length >= i; +} + +char *mqtt_get_publish_topic(uint8_t *buffer, size_t *length) +{ + int i; + int topiclen; + + for (i = 1; i < *length; ++i) { + if ((buffer[i] & 0x80) == 0) { + ++i; + break; + } + } + + if (i + 2 >= *length) { + return NULL; + } + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if (i + topiclen > *length) { + return NULL; + } + + *length = topiclen; + return (char *)(buffer + i); +} + +char *mqtt_get_publish_data(uint8_t *buffer, size_t *length) +{ + int i; + int totlen = 0; + int topiclen; + int blength = *length; + *length = 0; + + for (i = 1; i < blength; ++i) { + totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); + if ((buffer[i] & 0x80) == 0) { + ++i; + break; + } + } + totlen += i; + + if (i + 2 >= blength) { + return NULL; + } + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if (i + topiclen >= blength) { + return NULL; + } + + i += topiclen; + + if (mqtt_get_qos(buffer) > 0) { + if (i + 2 >= blength) { + return NULL; + } + i += 2; + } + + if (totlen < i) { + return NULL; + } + + if (totlen <= blength) { + *length = totlen - i; + } else { + *length = blength - i; + } + return (char *)(buffer + i); +} + +char *mqtt_get_suback_data(uint8_t *buffer, size_t *length) +{ + // SUBACK payload length = total length - (fixed header (2 bytes) + variable header (2 bytes)) + // This requires the remaining length to be encoded in 1 byte. + if (*length > 4) { + *length -= 4; + return (char *)(buffer + 4); + } + *length = 0; + return NULL; +} + +uint16_t mqtt_get_id(uint8_t *buffer, size_t length) +{ + if (length < 1) { + return 0; + } + + switch (mqtt_get_type(buffer)) { + case MQTT_MSG_TYPE_PUBLISH: { + int i; + int topiclen; + + for (i = 1; i < length; ++i) { + if ((buffer[i] & 0x80) == 0) { + ++i; + break; + } + } + + if (i + 2 >= length) { + return 0; + } + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if (i + topiclen > length) { + return 0; + } + i += topiclen; + + if (mqtt_get_qos(buffer) > 0) { + if (i + 2 > length) { + return 0; + } + //i += 2; + } else { + return 0; + } + + return (buffer[i] << 8) | buffer[i + 1]; + } + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_SUBSCRIBE: + case MQTT_MSG_TYPE_UNSUBSCRIBE: { + // This requires the remaining length to be encoded in 1 byte, + // which it should be. + if (length >= 4 && (buffer[1] & 0x80) == 0) { + return (buffer[2] << 8) | buffer[3]; + } else { + return 0; + } + } + + default: + return 0; + } +} + +mqtt_message_t *mqtt_msg_connect(mqtt_connection_t *connection, mqtt_connect_info_t *info) +{ + + set_message_header_size(connection); + + int header_len; + if (info->protocol_ver == MQTT_PROTOCOL_V_3_1) { + header_len = MQTT_3_1_VARIABLE_HEADER_SIZE; + } else { + header_len = MQTT_3_1_1_VARIABLE_HEADER_SIZE; + } + + if (connection->outbound_message.length + header_len > connection->buffer_length) { + return fail_message(connection); + } + char *variable_header = (char *)(connection->buffer + connection->outbound_message.length); + connection->outbound_message.length += header_len; + + int header_idx = 0; + variable_header[header_idx++] = 0; // Variable header length MSB + + if (info->protocol_ver == MQTT_PROTOCOL_V_3_1) { + variable_header[header_idx++] = 6; // Variable header length LSB + memcpy(&variable_header[header_idx], "MQIsdp", 6); // Protocol name + header_idx = header_idx + 6; + variable_header[header_idx++] = 3; // Protocol version + } else { + /* Defaults to protocol version 3.1.1 values */ + variable_header[header_idx++] = 4; // Variable header length LSB + memcpy(&variable_header[header_idx], "MQTT", 4); // Protocol name + header_idx = header_idx + 4; + variable_header[header_idx++] = 4; // Protocol version + } + + int flags_offset = header_idx; + variable_header[header_idx++] = 0; // Flags + variable_header[header_idx++] = info->keepalive >> 8; // Keep-alive MSB + variable_header[header_idx] = info->keepalive & 0xff; // Keep-alive LSB + + if (info->clean_session) { + variable_header[flags_offset] |= MQTT_CONNECT_FLAG_CLEAN_SESSION; + } + + if (info->client_id != NULL && info->client_id[0] != '\0') { + if (append_string(connection, info->client_id, strlen(info->client_id)) < 0) { + return fail_message(connection); + } + } else { + if (append_string(connection, "", 0) < 0) { + return fail_message(connection); + } + } + + if (info->will_topic != NULL && info->will_topic[0] != '\0') { + if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) { + return fail_message(connection); + } + + if (append_string(connection, info->will_message, info->will_length) < 0) { + return fail_message(connection); + } + + variable_header[flags_offset] |= MQTT_CONNECT_FLAG_WILL; + if (info->will_retain) { + variable_header[flags_offset] |= MQTT_CONNECT_FLAG_WILL_RETAIN; + } + variable_header[flags_offset] |= (info->will_qos & 3) << 3; + } + + if (info->username != NULL && info->username[0] != '\0') { + if (append_string(connection, info->username, strlen(info->username)) < 0) { + return fail_message(connection); + } + + variable_header[flags_offset] |= MQTT_CONNECT_FLAG_USERNAME; + } + + if (info->password != NULL && info->password[0] != '\0') { + if (info->username == NULL || info->username[0] == '\0') { + /* In case if password is set without username, we need to set a zero length username. + * (otherwise we violate: MQTT-3.1.2-22: If the User Name Flag is set to 0 then the Password Flag MUST be set to 0.) + */ + if (append_string(connection, "", 0) < 0) { + return fail_message(connection); + } + + variable_header[flags_offset] |= MQTT_CONNECT_FLAG_USERNAME; + } + + if (append_string(connection, info->password, strlen(info->password)) < 0) { + return fail_message(connection); + } + + variable_header[flags_offset] |= MQTT_CONNECT_FLAG_PASSWORD; + } + + return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); +} + +mqtt_message_t *mqtt_msg_publish(mqtt_connection_t *connection, const char *topic, const char *data, int data_length, int qos, int retain, uint16_t *message_id) +{ + set_message_header_size(connection); + + if (topic == NULL || topic[0] == '\0') { + return fail_message(connection); + } + + if (append_string(connection, topic, strlen(topic)) < 0) { + return fail_message(connection); + } + + if (data == NULL && data_length > 0) { + return fail_message(connection); + } + + if (qos > 0) { + if ((*message_id = append_message_id(connection, 0)) == 0) { + return fail_message(connection); + } + } else { + *message_id = 0; + } + + if (data != NULL) { + if (connection->outbound_message.length + data_length > connection->buffer_length) { + // Not enough size in buffer -> fragment this message + connection->outbound_message.fragmented_msg_data_offset = connection->outbound_message.length; + memcpy(connection->buffer + connection->outbound_message.length, data, connection->buffer_length - connection->outbound_message.length); + connection->outbound_message.length = connection->buffer_length; + connection->outbound_message.fragmented_msg_total_length = data_length + connection->outbound_message.fragmented_msg_data_offset; + } else { + memcpy(connection->buffer + connection->outbound_message.length, data, data_length); + connection->outbound_message.length += data_length; + connection->outbound_message.fragmented_msg_total_length = 0; + } + } + return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); +} + +mqtt_message_t *mqtt_msg_puback(mqtt_connection_t *connection, uint16_t message_id) +{ + set_message_header_size(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); +} + +mqtt_message_t *mqtt_msg_pubrec(mqtt_connection_t *connection, uint16_t message_id) +{ + set_message_header_size(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); +} + +mqtt_message_t *mqtt_msg_pubrel(mqtt_connection_t *connection, uint16_t message_id) +{ + set_message_header_size(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); +} + +mqtt_message_t *mqtt_msg_pubcomp(mqtt_connection_t *connection, uint16_t message_id) +{ + set_message_header_size(connection); + if (append_message_id(connection, message_id) == 0) { + return fail_message(connection); + } + return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); +} + +mqtt_message_t *mqtt_msg_subscribe(mqtt_connection_t *connection, const esp_mqtt_topic_t topic_list[], int size, uint16_t *message_id) +{ + set_message_header_size(connection); + + if ((*message_id = append_message_id(connection, 0)) == 0) { + return fail_message(connection); + } + + for (int topic_number = 0; topic_number < size; ++topic_number) { + if (topic_list[topic_number].filter[0] == '\0') { + return fail_message(connection); + } + + if (append_string(connection, topic_list[topic_number].filter, strlen(topic_list[topic_number].filter)) < 0) { + return fail_message(connection); + } + + if (connection->outbound_message.length + 1 > connection->buffer_length) { + return fail_message(connection); + } + connection->buffer[connection->outbound_message.length] = topic_list[topic_number].qos; + connection->outbound_message.length ++; + } + + return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t *mqtt_msg_unsubscribe(mqtt_connection_t *connection, const char *topic, uint16_t *message_id) +{ + set_message_header_size(connection); + + if (topic == NULL || topic[0] == '\0') { + return fail_message(connection); + } + + if ((*message_id = append_message_id(connection, 0)) == 0) { + return fail_message(connection); + } + + if (append_string(connection, topic, strlen(topic)) < 0) { + return fail_message(connection); + } + + return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t *mqtt_msg_pingreq(mqtt_connection_t *connection) +{ + set_message_header_size(connection); + return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); +} + +mqtt_message_t *mqtt_msg_pingresp(mqtt_connection_t *connection) +{ + set_message_header_size(connection); + return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); +} + +mqtt_message_t *mqtt_msg_disconnect(mqtt_connection_t *connection) +{ + set_message_header_size(connection); + return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); +} + +/* + * check flags: [MQTT-2.2.2-1], [MQTT-2.2.2-2] + * returns 0 if flags are invalid, otherwise returns 1 + */ +int mqtt_has_valid_msg_hdr(uint8_t *buffer, size_t length) +{ + int qos, dup; + + if (length < 1) { + return 0; + } + switch (mqtt_get_type(buffer)) { + case MQTT_MSG_TYPE_CONNECT: + case MQTT_MSG_TYPE_CONNACK: + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_PINGREQ: + case MQTT_MSG_TYPE_PINGRESP: + case MQTT_MSG_TYPE_DISCONNECT: + return (buffer[0] & 0x0f) == 0; /* all flag bits are 0 */ + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_SUBSCRIBE: + case MQTT_MSG_TYPE_UNSUBSCRIBE: + return (buffer[0] & 0x0f) == 0x02; /* only bit 1 is set */ + case MQTT_MSG_TYPE_PUBLISH: + qos = mqtt_get_qos(buffer); + dup = mqtt_get_dup(buffer); + /* + * there is no qos=3 [MQTT-3.3.1-4] + * dup flag must be set to 0 for all qos=0 messages [MQTT-3.3.1-2] + */ + return (qos < 3) && ((qos > 0) || (dup == 0)); + default: + return 0; + } +} + +esp_err_t mqtt_msg_buffer_init(mqtt_connection_t *connection, int buffer_size) +{ + memset(&connection->outbound_message, 0, sizeof(mqtt_message_t)); + connection->buffer = (uint8_t *)calloc(buffer_size, sizeof(uint8_t)); + if (!connection->buffer) { + return ESP_ERR_NO_MEM; + } + connection->buffer_length = buffer_size; + return ESP_OK; +} + +void mqtt_msg_buffer_destroy(mqtt_connection_t *connection) +{ + if (connection) { + free(connection->buffer); + } +} + + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_outbox.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_outbox.c new file mode 100644 index 000000000..6e63b198e --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/mqtt_outbox.c @@ -0,0 +1,225 @@ +#include "mqtt_outbox.h" +#include +#include +#include +#include "mqtt_config.h" +#include "sys/queue.h" +#include "esp_heap_caps.h" +#include "esp_log.h" + +#ifndef CONFIG_MQTT_CUSTOM_OUTBOX +static const char *TAG = "outbox"; + +typedef struct outbox_item { + char *buffer; + int len; + int msg_id; + int msg_type; + int msg_qos; + outbox_tick_t tick; + pending_state_t pending; + STAILQ_ENTRY(outbox_item) next; +} outbox_item_t; + +STAILQ_HEAD(outbox_list_t, outbox_item); + +struct outbox_t { + _Atomic uint64_t size; + struct outbox_list_t *list; +}; + +outbox_handle_t outbox_init(void) +{ + outbox_handle_t outbox = calloc(1, sizeof(struct outbox_t)); + ESP_MEM_CHECK(TAG, outbox, return NULL); + outbox->list = calloc(1, sizeof(struct outbox_list_t)); + ESP_MEM_CHECK(TAG, outbox->list, {free(outbox); return NULL;}); + outbox->size = 0; + STAILQ_INIT(outbox->list); + return outbox; +} + +outbox_item_handle_t outbox_enqueue(outbox_handle_t outbox, outbox_message_handle_t message, outbox_tick_t tick) +{ + outbox_item_handle_t item = calloc(1, sizeof(outbox_item_t)); + ESP_MEM_CHECK(TAG, item, return NULL); + item->msg_id = message->msg_id; + item->msg_type = message->msg_type; + item->msg_qos = message->msg_qos; + item->tick = tick; + item->len = message->len + message->remaining_len; + item->pending = QUEUED; + item->buffer = heap_caps_malloc(message->len + message->remaining_len, MQTT_OUTBOX_MEMORY); + ESP_MEM_CHECK(TAG, item->buffer, { + free(item); + return NULL; + }); + memcpy(item->buffer, message->data, message->len); + if (message->remaining_data) { + memcpy(item->buffer + message->len, message->remaining_data, message->remaining_len); + } + STAILQ_INSERT_TAIL(outbox->list, item, next); + outbox->size += item->len; + 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(outbox)); + return item; +} + +outbox_item_handle_t outbox_get(outbox_handle_t outbox, int msg_id) +{ + outbox_item_handle_t item; + STAILQ_FOREACH(item, outbox->list, next) { + if (item->msg_id == msg_id) { + return item; + } + } + return NULL; +} + +outbox_item_handle_t outbox_dequeue(outbox_handle_t outbox, pending_state_t pending, outbox_tick_t *tick) +{ + outbox_item_handle_t item; + STAILQ_FOREACH(item, outbox->list, next) { + if (item->pending == pending) { + if (tick) { + *tick = item->tick; + } + return item; + } + } + return NULL; +} + +esp_err_t outbox_delete_item(outbox_handle_t outbox, outbox_item_handle_t item_to_delete) +{ + outbox_item_handle_t item; + STAILQ_FOREACH(item, outbox->list, next) { + if (item == item_to_delete) { + STAILQ_REMOVE(outbox->list, item, outbox_item, next); + outbox->size -= item->len; + ESP_LOGD(TAG, "DELETE_ITEM msgid=%d, msg_type=%d, remain size=%"PRIu64, item_to_delete->msg_id, item_to_delete->msg_type, outbox_get_size(outbox)); + free(item->buffer); + free(item); + return ESP_OK; + } + } + return ESP_FAIL; +} + +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) { + *len = item->len; + *msg_id = item->msg_id; + *msg_type = item->msg_type; + *qos = item->msg_qos; + return (uint8_t *)item->buffer; + } + return NULL; +} + +esp_err_t outbox_delete(outbox_handle_t outbox, int msg_id, int msg_type) +{ + outbox_item_handle_t item, tmp; + STAILQ_FOREACH_SAFE(item, outbox->list, next, tmp) { + if (item->msg_id == msg_id && (0xFF & (item->msg_type)) == msg_type) { + STAILQ_REMOVE(outbox->list, item, outbox_item, next); + outbox->size -= item->len; + ESP_LOGD(TAG, "DELETE msgid=%d, msg_type=%d, remain size=%"PRIu64, msg_id, msg_type, outbox_get_size(outbox)); + free(item->buffer); + free(item); + return ESP_OK; + } + + } + return ESP_FAIL; +} + +esp_err_t outbox_set_pending(outbox_handle_t outbox, int msg_id, pending_state_t pending) +{ + outbox_item_handle_t item = outbox_get(outbox, msg_id); + if (item) { + item->pending = pending; + return ESP_OK; + } + return ESP_FAIL; +} + +pending_state_t outbox_item_get_pending(outbox_item_handle_t item) +{ + if (item) { + return item->pending; + } + return QUEUED; +} + +esp_err_t outbox_set_tick(outbox_handle_t outbox, int msg_id, outbox_tick_t tick) +{ + outbox_item_handle_t item = outbox_get(outbox, msg_id); + if (item) { + item->tick = tick; + return ESP_OK; + } + return ESP_FAIL; +} + +int outbox_delete_single_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout) +{ + int msg_id = -1; + outbox_item_handle_t item; + STAILQ_FOREACH(item, outbox->list, next) { + if (current_tick - item->tick > timeout) { + STAILQ_REMOVE(outbox->list, item, outbox_item, next); + free(item->buffer); + outbox->size -= item->len; + msg_id = item->msg_id; + free(item); + ESP_LOGD(TAG, "DELETE_SINGLE_EXPIRED msgid=%d, remain size=%"PRIu64, msg_id, outbox_get_size(outbox)); + return msg_id; + } + + } + return msg_id; +} + +int outbox_delete_expired(outbox_handle_t outbox, outbox_tick_t current_tick, outbox_tick_t timeout) +{ + int deleted_items = 0; + outbox_item_handle_t item, tmp; + STAILQ_FOREACH_SAFE(item, outbox->list, next, tmp) { + if (current_tick - item->tick > timeout) { + STAILQ_REMOVE(outbox->list, item, outbox_item, next); + free(item->buffer); + outbox->size -= item->len; + ESP_LOGD(TAG, "DELETE_EXPIRED msgid=%d, remain size=%"PRIu64, item->msg_id, outbox_get_size(outbox)); + free(item); + deleted_items ++; + } + + } + return deleted_items; +} + +uint64_t outbox_get_size(outbox_handle_t outbox) +{ + return outbox->size; +} + +void outbox_delete_all_items(outbox_handle_t outbox) +{ + outbox_item_handle_t item, tmp; + STAILQ_FOREACH_SAFE(item, outbox->list, next, tmp) { + STAILQ_REMOVE(outbox->list, item, outbox_item, next); + outbox->size -= item->len; + ESP_LOGD(TAG, "DELETE_ALL_ITEMS msgid=%d, msg_type=%d, remain size=%"PRIu64, item->msg_id, item->msg_type, outbox_get_size(outbox)); + free(item->buffer); + free(item); + } +} +void outbox_destroy(outbox_handle_t outbox) +{ + outbox_delete_all_items(outbox); + free(outbox->list); + free(outbox); +} + +#endif /* CONFIG_MQTT_CUSTOM_OUTBOX */ diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/platform_esp32_idf.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/platform_esp32_idf.c new file mode 100644 index 000000000..a84e6fbf6 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/lib/platform_esp32_idf.c @@ -0,0 +1,48 @@ +#include "platform.h" + +#ifdef ESP_PLATFORM +#include "esp_log.h" +#include "esp_mac.h" +#include "soc/soc_caps.h" +#include "esp_timer.h" +#include "esp_random.h" +#include +#include + +static const char *TAG = "platform"; + +#define MAX_ID_STRING (32) + +#if defined SOC_WIFI_SUPPORTED +#define MAC_TYPE ESP_MAC_WIFI_STA +#elif defined SOC_EMAC_SUPPORTED +#define MAC_TYPE ESP_MAC_ETH +#elif defined SOC_IEEE802154_SUPPORTED +#define MAC_TYPE ESP_MAC_IEEE802154 +#endif +char *platform_create_id_string(void) +{ + char *id_string = calloc(1, MAX_ID_STRING); + ESP_MEM_CHECK(TAG, id_string, return NULL); + #ifndef MAC_TYPE + ESP_LOGW(TAG, "Soc doesn't provide MAC, client could be disconnected in case of device with same name in the broker."); + sprintf(id_string, "esp_mqtt_client_id"); + #else + uint8_t mac[6]; + esp_read_mac(mac, MAC_TYPE); + sprintf(id_string, "ESP32_%02x%02X%02X", mac[3], mac[4], mac[5]); + #endif + return id_string; +} + +int platform_random(int max) +{ + return esp_random() % max; +} + +uint64_t platform_tick_get_ms(void) +{ + return esp_timer_get_time()/(int64_t)1000; +} + +#endif diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt5_client.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt5_client.c new file mode 100644 index 000000000..060dfed55 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt5_client.c @@ -0,0 +1,768 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mqtt_client_priv.h" +#include "esp_log.h" +#include + +static const char *TAG = "mqtt5_client"; + +static void esp_mqtt5_print_error_code(esp_mqtt5_client_handle_t client, int code); +static esp_err_t esp_mqtt5_client_update_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, char *topic, size_t topic_len); +static char *esp_mqtt5_client_get_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, size_t *topic_length); +static void esp_mqtt5_client_delete_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle); +static esp_err_t esp_mqtt5_user_property_copy(mqtt5_user_property_handle_t user_property_new, const mqtt5_user_property_handle_t user_property_old); + +void esp_mqtt5_increment_packet_counter(esp_mqtt5_client_handle_t client) +{ + bool msg_dup = mqtt5_get_dup(client->mqtt_state.connection.outbound_message.data); + if (msg_dup == false) { + client->send_publish_packet_count ++; + ESP_LOGD(TAG, "Sent (%d) qos > 0 publish packet without ack", client->send_publish_packet_count); + } +} + +void esp_mqtt5_decrement_packet_counter(esp_mqtt5_client_handle_t client) +{ + if (client->send_publish_packet_count > 0) { + client->send_publish_packet_count --; + ESP_LOGD(TAG, "Receive (%d) qos > 0 publish packet with ack", client->send_publish_packet_count); + } +} + +void esp_mqtt5_parse_pubcomp(esp_mqtt5_client_handle_t client) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + ESP_LOGD(TAG, "MQTT_MSG_TYPE_PUBCOMP return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); + size_t msg_data_len = client->mqtt_state.in_buffer_read_len; + client->event.data = mqtt5_get_pubcomp_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property); + client->event.data_len = msg_data_len; + client->event.total_data_len = msg_data_len; + client->event.current_data_offset = 0; + } +} + +void esp_mqtt5_parse_puback(esp_mqtt5_client_handle_t client) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + ESP_LOGD(TAG, "MQTT_MSG_TYPE_PUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); + size_t msg_data_len = client->mqtt_state.in_buffer_read_len; + client->event.data = mqtt5_get_puback_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property); + client->event.data_len = msg_data_len; + client->event.total_data_len = msg_data_len; + client->event.current_data_offset = 0; + } +} + +void esp_mqtt5_parse_unsuback(esp_mqtt5_client_handle_t client) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + ESP_LOGD(TAG, "MQTT_MSG_TYPE_UNSUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); + size_t msg_data_len = client->mqtt_state.in_buffer_read_len; + client->event.data = mqtt5_get_unsuback_data(client->mqtt_state.in_buffer, &msg_data_len, &client->event.property->user_property); + client->event.data_len = msg_data_len; + client->event.total_data_len = msg_data_len; + client->event.current_data_offset = 0; + } +} + +void esp_mqtt5_parse_suback(esp_mqtt5_client_handle_t client) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + ESP_LOGD(TAG, "MQTT_MSG_TYPE_SUBACK return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); + } +} + +void esp_mqtt5_parse_disconnect(esp_mqtt5_client_handle_t client, int *disconnect_rsp_code) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + *disconnect_rsp_code = mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len); + ESP_LOGD(TAG, "MQTT_MSG_TYPE_DISCONNECT return code is %d", *disconnect_rsp_code); + } +} + +esp_err_t esp_mqtt5_parse_connack(esp_mqtt5_client_handle_t client, int *connect_rsp_code) +{ + size_t len = client->mqtt_state.in_buffer_read_len; + client->mqtt_state.in_buffer_read_len = 0; + uint8_t ack_flag = 0; + if (mqtt5_msg_parse_connack_property(client->mqtt_state.in_buffer, len, &client->mqtt_state. + connection.information, &client->mqtt5_config->connect_property_info, &client->mqtt5_config->server_resp_property_info, connect_rsp_code, &ack_flag, &client->event.property->user_property) != ESP_OK) { + ESP_LOGE(TAG, "Failed to parse CONNACK packet"); + return ESP_FAIL; + } + if (*connect_rsp_code == MQTT_CONNECTION_ACCEPTED) { + ESP_LOGD(TAG, "Connected"); + client->event.session_present = ack_flag & 0x01; + return ESP_OK; + } + esp_mqtt5_print_error_code(client, *connect_rsp_code); + return ESP_FAIL; +} + +esp_err_t esp_mqtt5_get_publish_data(esp_mqtt5_client_handle_t client, uint8_t *msg_buf, size_t msg_read_len, char **msg_topic, size_t *msg_topic_len, char **msg_data, size_t *msg_data_len) +{ + // get property + uint16_t property_len = 0; + esp_mqtt5_publish_resp_property_t property = {0}; + *msg_data = mqtt5_get_publish_property_payload(msg_buf, msg_read_len, msg_topic, msg_topic_len, &property, &property_len, msg_data_len, &client->event.property->user_property); + if (*msg_data == NULL) { + ESP_LOGE(TAG, "%s: mqtt5_get_publish_property_payload() failed", __func__); + return ESP_FAIL; + } + + if (property.topic_alias > client->mqtt5_config->connect_property_info.topic_alias_maximum) { + ESP_LOGE(TAG, "%s: Broker response topic alias %d is over the max topic alias %d", __func__, property.topic_alias, client->mqtt5_config->connect_property_info.topic_alias_maximum); + return ESP_FAIL; + } + + if (property.topic_alias) { + if (*msg_topic_len == 0) { + *msg_topic = esp_mqtt5_client_get_topic_alias(client->mqtt5_config->peer_topic_alias, property.topic_alias, msg_topic_len); + if (!*msg_topic) { + ESP_LOGE(TAG, "%s: esp_mqtt5_client_get_topic_alias() failed", __func__); + return ESP_FAIL; + } + } else { + if (esp_mqtt5_client_update_topic_alias(client->mqtt5_config->peer_topic_alias, property.topic_alias, *msg_topic, *msg_topic_len) != ESP_OK) { + ESP_LOGE(TAG, "%s: esp_mqtt5_client_update_topic_alias() failed", __func__); + return ESP_FAIL; + } + } + } + + client->event.property->payload_format_indicator = property.payload_format_indicator; + client->event.property->response_topic = property.response_topic; + client->event.property->response_topic_len = property.response_topic_len; + client->event.property->correlation_data = property.correlation_data; + client->event.property->correlation_data_len = property.correlation_data_len; + client->event.property->content_type = property.content_type; + client->event.property->content_type_len = property.content_type_len; + client->event.property->subscribe_id = property.subscribe_id; + return ESP_OK; +} + +esp_err_t esp_mqtt5_create_default_config(esp_mqtt5_client_handle_t client) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + client->event.property = calloc(1, sizeof(esp_mqtt5_event_property_t)); + ESP_MEM_CHECK(TAG, client->event.property, return ESP_FAIL) + client->mqtt5_config = calloc(1, sizeof(mqtt5_config_storage_t)); + ESP_MEM_CHECK(TAG, client->mqtt5_config, return ESP_FAIL) + client->mqtt5_config->server_resp_property_info.max_qos = 2; + client->mqtt5_config->server_resp_property_info.retain_available = true; + client->mqtt5_config->server_resp_property_info.wildcard_subscribe_available = true; + client->mqtt5_config->server_resp_property_info.subscribe_identifiers_available = true; + client->mqtt5_config->server_resp_property_info.shared_subscribe_available = true; + client->mqtt5_config->server_resp_property_info.receive_maximum = 65535; + } + return ESP_OK; +} + +static void esp_mqtt5_print_error_code(esp_mqtt5_client_handle_t client, int code) +{ + switch (code) { + case MQTT5_UNSPECIFIED_ERROR: + ESP_LOGW(TAG, "Unspecified error"); + break; + case MQTT5_MALFORMED_PACKET: + ESP_LOGW(TAG, "Malformed Packet"); + break; + case MQTT5_PROTOCOL_ERROR: + ESP_LOGW(TAG, "Protocol Error"); + break; + case MQTT5_IMPLEMENT_SPECIFIC_ERROR: + ESP_LOGW(TAG, "Implementation specific error"); + break; + case MQTT5_UNSUPPORTED_PROTOCOL_VER: + ESP_LOGW(TAG, "Unsupported Protocol Version"); + break; + case MQTT5_INVALID_CLIENT_ID: + ESP_LOGW(TAG, "Client Identifier not valid"); + break; + case MQTT5_BAD_USERNAME_OR_PWD: + ESP_LOGW(TAG, "Bad User Name or Password"); + break; + case MQTT5_NOT_AUTHORIZED: + ESP_LOGW(TAG, "Not authorized"); + break; + case MQTT5_SERVER_UNAVAILABLE: + ESP_LOGW(TAG, "Server unavailable"); + break; + case MQTT5_SERVER_BUSY: + ESP_LOGW(TAG, "Server busy"); + break; + case MQTT5_BANNED: + ESP_LOGW(TAG, "Banned"); + break; + case MQTT5_SERVER_SHUTTING_DOWN: + ESP_LOGW(TAG, "Server shutting down"); + break; + case MQTT5_BAD_AUTH_METHOD: + ESP_LOGW(TAG, "Bad authentication method"); + break; + case MQTT5_KEEP_ALIVE_TIMEOUT: + ESP_LOGW(TAG, "Keep Alive timeout"); + break; + case MQTT5_SESSION_TAKEN_OVER: + ESP_LOGW(TAG, "Session taken over"); + break; + case MQTT5_TOPIC_FILTER_INVALID: + ESP_LOGW(TAG, "Topic Filter invalid"); + break; + case MQTT5_TOPIC_NAME_INVALID: + ESP_LOGW(TAG, "Topic Name invalid"); + break; + case MQTT5_PACKET_IDENTIFIER_IN_USE: + ESP_LOGW(TAG, "Packet Identifier in use"); + break; + case MQTT5_PACKET_IDENTIFIER_NOT_FOUND: + ESP_LOGW(TAG, "Packet Identifier not found"); + break; + case MQTT5_RECEIVE_MAXIMUM_EXCEEDED: + ESP_LOGW(TAG, "Receive Maximum exceeded"); + break; + case MQTT5_TOPIC_ALIAS_INVALID: + ESP_LOGW(TAG, "Topic Alias invalid"); + break; + case MQTT5_PACKET_TOO_LARGE: + ESP_LOGW(TAG, "Packet too large"); + break; + case MQTT5_MESSAGE_RATE_TOO_HIGH: + ESP_LOGW(TAG, "Message rate too high"); + break; + case MQTT5_QUOTA_EXCEEDED: + ESP_LOGW(TAG, "Quota exceeded"); + break; + case MQTT5_ADMINISTRATIVE_ACTION: + ESP_LOGW(TAG, "Administrative action"); + break; + case MQTT5_PAYLOAD_FORMAT_INVALID: + ESP_LOGW(TAG, "Payload format invalid"); + break; + case MQTT5_RETAIN_NOT_SUPPORT: + ESP_LOGW(TAG, "Retain not supported"); + break; + case MQTT5_QOS_NOT_SUPPORT: + ESP_LOGW(TAG, "QoS not supported"); + break; + case MQTT5_USE_ANOTHER_SERVER: + ESP_LOGW(TAG, "Use another server"); + break; + case MQTT5_SERVER_MOVED: + ESP_LOGW(TAG, "Server moved"); + break; + case MQTT5_SHARED_SUBSCR_NOT_SUPPORTED: + ESP_LOGW(TAG, "Shared Subscriptions not supported"); + break; + case MQTT5_CONNECTION_RATE_EXCEEDED: + ESP_LOGW(TAG, "Connection rate exceeded"); + break; + case MQTT5_MAXIMUM_CONNECT_TIME: + ESP_LOGW(TAG, "Maximum connect time"); + break; + case MQTT5_SUBSCRIBE_IDENTIFIER_NOT_SUPPORT: + ESP_LOGW(TAG, "Subscription Identifiers not supported"); + break; + case MQTT5_WILDCARD_SUBSCRIBE_NOT_SUPPORT: + ESP_LOGW(TAG, "Wildcard Subscriptions not supported"); + break; + default: + ESP_LOGW(TAG, "Connection refused, Unknow reason"); + break; + } +} + +esp_err_t esp_mqtt5_client_subscribe_check(esp_mqtt5_client_handle_t client, int qos) +{ + /* Check Server support QoS level */ + if (client->mqtt5_config->server_resp_property_info.max_qos < qos) { + ESP_LOGE(TAG, "Server only support max QoS level %d", client->mqtt5_config->server_resp_property_info.max_qos); + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t esp_mqtt5_client_publish_check(esp_mqtt5_client_handle_t client, int qos, int retain) +{ + /* Check Server support QoS level */ + if (client->mqtt5_config->server_resp_property_info.max_qos < qos) { + ESP_LOGE(TAG, "Server only support max QoS level %d", client->mqtt5_config->server_resp_property_info.max_qos); + return ESP_FAIL; + } + + /* Check Server support RETAIN */ + if (!client->mqtt5_config->server_resp_property_info.retain_available && retain) { + ESP_LOGE(TAG, "Server not support retain"); + return ESP_FAIL; + } + + /* Flow control to check PUBLISH(No PUBACK or PUBCOMP received) packet sent count(Only record QoS1 and QoS2)*/ + if (client->send_publish_packet_count > client->mqtt5_config->server_resp_property_info.receive_maximum) { + ESP_LOGE(TAG, "Client send more than %d QoS1 and QoS2 PUBLISH packet without no ack", client->mqtt5_config->server_resp_property_info.receive_maximum); + return ESP_FAIL; + } + + return ESP_OK; +} + +void esp_mqtt5_client_destory(esp_mqtt5_client_handle_t client) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + if (client->mqtt5_config) { + free(client->mqtt5_config->will_property_info.content_type); + free(client->mqtt5_config->will_property_info.response_topic); + free(client->mqtt5_config->will_property_info.correlation_data); + free(client->mqtt5_config->server_resp_property_info.response_info); + esp_mqtt5_client_delete_topic_alias(client->mqtt5_config->peer_topic_alias); + esp_mqtt5_client_delete_user_property(client->mqtt5_config->connect_property_info.user_property); + esp_mqtt5_client_delete_user_property(client->mqtt5_config->will_property_info.user_property); + esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property); + free(client->mqtt5_config); + } + free(client->event.property); + } +} + +static void esp_mqtt5_client_delete_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle) +{ + if (topic_alias_handle) { + mqtt5_topic_alias_item_t item, tmp; + STAILQ_FOREACH_SAFE(item, topic_alias_handle, next, tmp) { + STAILQ_REMOVE(topic_alias_handle, item, mqtt5_topic_alias, next); + free(item->topic); + free(item); + } + free(topic_alias_handle); + } +} + +static esp_err_t esp_mqtt5_client_update_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, char *topic, size_t topic_len) +{ + mqtt5_topic_alias_item_t item; + bool found = false; + STAILQ_FOREACH(item, topic_alias_handle, next) { + if (item->topic_alias == topic_alias) { + found = true; + break; + } + } + if (found) { + if ((item->topic_len != topic_len) || strncmp(topic, item->topic, topic_len)) { + free(item->topic); + item->topic = calloc(1, topic_len); + ESP_MEM_CHECK(TAG, item->topic, return ESP_FAIL); + memcpy(item->topic, topic, topic_len); + item->topic_len = topic_len; + } + } else { + item = calloc(1, sizeof(mqtt5_topic_alias_t)); + ESP_MEM_CHECK(TAG, item, return ESP_FAIL); + item->topic_alias = topic_alias; + item->topic_len = topic_len; + item->topic = calloc(1, topic_len); + ESP_MEM_CHECK(TAG, item->topic, { + free(item); + return ESP_FAIL; + }); + memcpy(item->topic, topic, topic_len); + STAILQ_INSERT_TAIL(topic_alias_handle, item, next); + } + return ESP_OK; +} + +static char *esp_mqtt5_client_get_topic_alias(mqtt5_topic_alias_handle_t topic_alias_handle, uint16_t topic_alias, size_t *topic_length) +{ + mqtt5_topic_alias_item_t item; + STAILQ_FOREACH(item, topic_alias_handle, next) { + if (item->topic_alias == topic_alias) { + *topic_length = item->topic_len; + return item->topic; + } + } + *topic_length = 0; + return NULL; +} + +static esp_err_t esp_mqtt5_user_property_copy(mqtt5_user_property_handle_t user_property_new, const mqtt5_user_property_handle_t user_property_old) +{ + if (!user_property_new || !user_property_old) { + ESP_LOGE(TAG, "Input is NULL"); + return ESP_FAIL; + } + + mqtt5_user_property_item_t old_item, new_item; + STAILQ_FOREACH(old_item, user_property_old, next) { + new_item = calloc(1, sizeof(mqtt5_user_property_t)); + ESP_MEM_CHECK(TAG, new_item, return ESP_FAIL); + new_item->key = strdup(old_item->key); + ESP_MEM_CHECK(TAG, new_item->key, { + free(new_item); + return ESP_FAIL; + }); + new_item->value = strdup(old_item->value); + ESP_MEM_CHECK(TAG, new_item->value, { + free(new_item->key); + free(new_item); + return ESP_FAIL; + }); + STAILQ_INSERT_TAIL(user_property_new, new_item, next); + } + return ESP_OK; +} + +esp_err_t esp_mqtt5_client_set_publish_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_publish_property_config_t *property) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + MQTT_API_LOCK(client); + + /* Check protocol version */ + if (client->mqtt_state.connection.information.protocol_ver != MQTT_PROTOCOL_V_5) { + ESP_LOGE(TAG, "MQTT protocol version is not v5"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + /* Check topic alias less than server maximum topic alias */ + if (property->topic_alias > client->mqtt5_config->server_resp_property_info.topic_alias_maximum) { + ESP_LOGE(TAG, "Topic alias %d is bigger than server support %d", property->topic_alias, client->mqtt5_config->server_resp_property_info.topic_alias_maximum); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + client->mqtt5_config->publish_property_info = property; + MQTT_API_UNLOCK(client); + return ESP_OK; +} + +esp_err_t esp_mqtt5_client_set_subscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_subscribe_property_config_t *property) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + if (property->retain_handle > 2) { + ESP_LOGE(TAG, "retain_handle only support 0, 1, 2"); + return -1; + } + MQTT_API_LOCK(client); + + /* Check protocol version */ + if (client->mqtt_state.connection.information.protocol_ver != MQTT_PROTOCOL_V_5) { + ESP_LOGE(TAG, "MQTT protocol version is not v5"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + if (property->is_share_subscribe) { + if (property->no_local_flag) { + // MQTT-3.8.3-4 not allow that No Local bit to 1 on a Shared Subscription + ESP_LOGE(TAG, "Protocol error that no local flag set on shared subscription"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + if (!client->mqtt5_config->server_resp_property_info.shared_subscribe_available) { + ESP_LOGE(TAG, "MQTT broker not support shared subscribe"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + if (!property->share_name || !strlen(property->share_name)) { + ESP_LOGE(TAG, "Share name can't be empty for shared subscribe"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + } + client->mqtt5_config->subscribe_property_info = property; + MQTT_API_UNLOCK(client); + return ESP_OK; +} + +esp_err_t esp_mqtt5_client_set_unsubscribe_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_unsubscribe_property_config_t *property) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + MQTT_API_LOCK(client); + + /* Check protocol version */ + if (client->mqtt_state.connection.information.protocol_ver != MQTT_PROTOCOL_V_5) { + ESP_LOGE(TAG, "MQTT protocol version is not v5"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + if (property->is_share_subscribe) { + if (!client->mqtt5_config->server_resp_property_info.shared_subscribe_available) { + ESP_LOGE(TAG, "MQTT broker not support shared subscribe"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + if (!property->share_name || !strlen(property->share_name)) { + ESP_LOGE(TAG, "Share name can't be empty for shared subscribe"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + } + client->mqtt5_config->unsubscribe_property_info = property; + MQTT_API_UNLOCK(client); + return ESP_OK; +} + +esp_err_t esp_mqtt5_client_set_disconnect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_disconnect_property_config_t *property) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + MQTT_API_LOCK(client); + + /* Check protocol version */ + if (client->mqtt_state.connection.information.protocol_ver != MQTT_PROTOCOL_V_5) { + ESP_LOGE(TAG, "MQTT protocol version is not v5"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + if (property) { + if (property->session_expiry_interval) { + client->mqtt5_config->disconnect_property_info.session_expiry_interval = property->session_expiry_interval; + } + if (property->disconnect_reason) { + client->mqtt5_config->disconnect_property_info.disconnect_reason = property->disconnect_reason; + } + if (property->user_property) { + esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property); + client->mqtt5_config->disconnect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + ESP_MEM_CHECK(TAG, client->mqtt5_config->disconnect_property_info.user_property, { + MQTT_API_UNLOCK(client); + return ESP_ERR_NO_MEM; + }); + STAILQ_INIT(client->mqtt5_config->disconnect_property_info.user_property); + if (esp_mqtt5_user_property_copy(client->mqtt5_config->disconnect_property_info.user_property, property->user_property) != ESP_OK) { + ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail"); + free(client->mqtt5_config->disconnect_property_info.user_property); + client->mqtt5_config->disconnect_property_info.user_property = NULL; + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + } + } + + MQTT_API_UNLOCK(client); + return ESP_OK; +} + +esp_err_t esp_mqtt5_client_set_connect_property(esp_mqtt5_client_handle_t client, const esp_mqtt5_connection_property_config_t *connect_property) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + MQTT_API_LOCK(client); + + /* Check protocol version */ + if (client->mqtt_state.connection.information.protocol_ver != MQTT_PROTOCOL_V_5) { + ESP_LOGE(TAG, "MQTT protocol version is not v5"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + if (connect_property) { + if (connect_property->session_expiry_interval) { + client->mqtt5_config->connect_property_info.session_expiry_interval = connect_property->session_expiry_interval; + } + if (connect_property->maximum_packet_size) { + if (connect_property->maximum_packet_size > client->mqtt_state.in_buffer_length) { + ESP_LOGW(TAG, "Connect maximum_packet_size property is over buffer_size(%d), Please first change it", client->mqtt_state.in_buffer_length); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } else { + client->mqtt5_config->connect_property_info.maximum_packet_size = connect_property->maximum_packet_size; + } + } else { + client->mqtt5_config->connect_property_info.maximum_packet_size = client->mqtt_state.in_buffer_length; + } + if (connect_property->receive_maximum) { + client->mqtt5_config->connect_property_info.receive_maximum = connect_property->receive_maximum; + } + if (connect_property->topic_alias_maximum) { + client->mqtt5_config->connect_property_info.topic_alias_maximum = connect_property->topic_alias_maximum; + if (!client->mqtt5_config->peer_topic_alias) { + client->mqtt5_config->peer_topic_alias = calloc(1, sizeof(struct mqtt5_topic_alias_list_t)); + ESP_MEM_CHECK(TAG, client->mqtt5_config->peer_topic_alias, goto _mqtt_set_config_failed); + STAILQ_INIT(client->mqtt5_config->peer_topic_alias); + } + } + if (connect_property->request_resp_info) { + client->mqtt5_config->connect_property_info.request_resp_info = connect_property->request_resp_info; + } + if (connect_property->request_problem_info) { + client->mqtt5_config->connect_property_info.request_problem_info = connect_property->request_problem_info; + } + if (connect_property->user_property) { + esp_mqtt5_client_delete_user_property(client->mqtt5_config->connect_property_info.user_property); + client->mqtt5_config->connect_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + ESP_MEM_CHECK(TAG, client->mqtt5_config->connect_property_info.user_property, goto _mqtt_set_config_failed); + STAILQ_INIT(client->mqtt5_config->connect_property_info.user_property); + if (esp_mqtt5_user_property_copy(client->mqtt5_config->connect_property_info.user_property, connect_property->user_property) != ESP_OK) { + ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail"); + goto _mqtt_set_config_failed; + } + } + if (connect_property->payload_format_indicator) { + client->mqtt5_config->will_property_info.payload_format_indicator = connect_property->payload_format_indicator; + } + if (connect_property->will_delay_interval) { + client->mqtt5_config->will_property_info.will_delay_interval = connect_property->will_delay_interval; + } + if (connect_property->message_expiry_interval) { + client->mqtt5_config->will_property_info.message_expiry_interval = connect_property->message_expiry_interval; + } + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(connect_property->content_type, &client->mqtt5_config->will_property_info.content_type), goto _mqtt_set_config_failed); + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(connect_property->response_topic, &client->mqtt5_config->will_property_info.response_topic), goto _mqtt_set_config_failed); + if (connect_property->correlation_data && connect_property->correlation_data_len) { + free(client->mqtt5_config->will_property_info.correlation_data); + client->mqtt5_config->will_property_info.correlation_data = malloc(connect_property->correlation_data_len); + ESP_MEM_CHECK(TAG, client->mqtt5_config->will_property_info.correlation_data, goto _mqtt_set_config_failed); + memcpy(client->mqtt5_config->will_property_info.correlation_data, connect_property->correlation_data, connect_property->correlation_data_len); + client->mqtt5_config->will_property_info.correlation_data_len = connect_property->correlation_data_len; + } + if (connect_property->will_user_property) { + esp_mqtt5_client_delete_user_property(client->mqtt5_config->will_property_info.user_property); + client->mqtt5_config->will_property_info.user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + ESP_MEM_CHECK(TAG, client->mqtt5_config->will_property_info.user_property, goto _mqtt_set_config_failed); + STAILQ_INIT(client->mqtt5_config->will_property_info.user_property); + if (esp_mqtt5_user_property_copy(client->mqtt5_config->will_property_info.user_property, connect_property->will_user_property) != ESP_OK) { + ESP_LOGE(TAG, "esp_mqtt5_user_property_copy fail"); + goto _mqtt_set_config_failed; + } + } + } + MQTT_API_UNLOCK(client); + return ESP_OK; +_mqtt_set_config_failed: + esp_mqtt_destroy_config(client); + MQTT_API_UNLOCK(client); + return ESP_ERR_NO_MEM; +} + +esp_err_t esp_mqtt5_client_set_user_property(mqtt5_user_property_handle_t *user_property, esp_mqtt5_user_property_item_t item[], uint8_t item_num) +{ + if (!item_num || !item) { + ESP_LOGE(TAG, "Input value is NULL"); + return ESP_FAIL; + } + + if (!*user_property) { + *user_property = calloc(1, sizeof(struct mqtt5_user_property_list_t)); + ESP_MEM_CHECK(TAG, *user_property, return ESP_ERR_NO_MEM); + STAILQ_INIT(*user_property); + } + + for (int i = 0; i < item_num; i ++) { + if (item[i].key && item[i].value) { + mqtt5_user_property_item_t user_property_item = calloc(1, sizeof(mqtt5_user_property_t)); + ESP_MEM_CHECK(TAG, user_property_item, goto err); + size_t key_len = strlen(item[i].key); + size_t value_len = strlen(item[i].value); + + user_property_item->key = calloc(1, key_len + 1); + ESP_MEM_CHECK(TAG, user_property_item->key, { + free(user_property_item); + goto err; + }); + memcpy(user_property_item->key, item[i].key, key_len); + user_property_item->key[key_len] = '\0'; + + user_property_item->value = calloc(1, value_len + 1); + ESP_MEM_CHECK(TAG, user_property_item->value, { + free(user_property_item->key); + free(user_property_item); + goto err; + }); + memcpy(user_property_item->value, item[i].value, value_len); + user_property_item->value[value_len] = '\0'; + + STAILQ_INSERT_TAIL(*user_property, user_property_item, next); + } + } + return ESP_OK; +err: + esp_mqtt5_client_delete_user_property(*user_property); + *user_property = NULL; + return ESP_ERR_NO_MEM; +} + +esp_err_t esp_mqtt5_client_get_user_property(mqtt5_user_property_handle_t user_property, esp_mqtt5_user_property_item_t *item, uint8_t *item_num) +{ + int i = 0, j = 0; + if (user_property && item && *item_num) { + mqtt5_user_property_item_t user_property_item; + uint8_t num = *item_num; + STAILQ_FOREACH(user_property_item, user_property, next) { + if (i < num) { + size_t item_key_len = strlen(user_property_item->key); + size_t item_value_len = strlen(user_property_item->value); + char *key = calloc(1, item_key_len + 1); + ESP_MEM_CHECK(TAG, key, goto err); + memcpy(key, user_property_item->key, item_key_len); + key[item_key_len] = '\0'; + char *value = calloc(1, item_value_len + 1); + ESP_MEM_CHECK(TAG, value, { + free(key); + goto err; + }); + memcpy(value, user_property_item->value, item_value_len); + value[item_value_len] = '\0'; + item[i].key = key; + item[i].value = value; + i ++; + } else { + break; + } + } + *item_num = i; + return ESP_OK; + } else { + ESP_LOGE(TAG, "Input value is NULL or item_num is 0"); + return ESP_FAIL; + } +err: + for (j = 0; j < i; j ++) { + if (item[j].key) { + free((char *)item[j].key); + } + if (item[j].value) { + free((char *)item[j].value); + } + } + return ESP_ERR_NO_MEM; +} + +uint8_t esp_mqtt5_client_get_user_property_count(mqtt5_user_property_handle_t user_property) +{ + uint8_t count = 0; + if (user_property) { + mqtt5_user_property_item_t item; + STAILQ_FOREACH(item, user_property, next) { + count ++; + } + } + return count; +} + +void esp_mqtt5_client_delete_user_property(mqtt5_user_property_handle_t user_property) +{ + if (user_property) { + mqtt5_user_property_item_t item, tmp; + STAILQ_FOREACH_SAFE(item, user_property, next, tmp) { + STAILQ_REMOVE(user_property, item, mqtt5_user_property, next); + free(item->key); + free(item->value); + free(item); + } + } + free(user_property); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt_client.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt_client.c new file mode 100644 index 000000000..dd0ca7f21 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/mqtt_client.c @@ -0,0 +1,2392 @@ +#include +#include +#include +#include "esp_err.h" +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "esp_transport.h" +#include "mqtt_client.h" +#include "mqtt_client_priv.h" +#include "mqtt_msg.h" +#include "mqtt_outbox.h" + +_Static_assert(sizeof(uint64_t) == sizeof(outbox_tick_t), "mqtt-client tick type size different from outbox tick type"); +#ifdef ESP_EVENT_ANY_ID +_Static_assert(MQTT_EVENT_ANY == ESP_EVENT_ANY_ID, "mqtt-client event enum does not match the global EVENT_ANY_ID"); +#endif + +static const char *TAG = "mqtt_client"; + +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP +/** + * @brief Define of MQTT Event base + * + */ +ESP_EVENT_DEFINE_BASE(MQTT_EVENTS); +#endif + +const static int STOPPED_BIT = (1 << 0); +const static int RECONNECT_BIT = (1 << 1); +const static int DISCONNECT_BIT = (1 << 2); + +static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client); +static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client); +static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms); +static void esp_mqtt_abort_connection(esp_mqtt_client_handle_t client); +static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client); +static char *create_string(const char *ptr, int len); +static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_timeout_ms); +static void esp_mqtt_client_dispatch_transport_error(esp_mqtt_client_handle_t client); +static esp_err_t send_disconnect_msg(esp_mqtt_client_handle_t client); + +/** + * @brief Processes error reported from transport layer (considering the message read status) + * + * @param err: Error reported from TCP transport + * @param client: MQTT client handle + * @param mid_message: True if the error occured when reading incomplete message + * + * @return - 0 on Timeout + * - -1 on Timeout with incomplete message + * - -2 on Error or EOF + */ +static int esp_mqtt_handle_transport_read_error(int err, esp_mqtt_client_handle_t client, bool mid_message) +{ + if (err == ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT) { + if (mid_message) { + // No error message, because we could've read with timeout 0 (caller will decide) + return -1; + } + // Not an error, continue + ESP_LOGV(TAG, "%s: transport_read(): call timed out before data was ready!", __func__); + return 0; + } + + if (err == ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN) { + ESP_LOGE(TAG, "%s: transport_read(): EOF", __func__); + } + + ESP_LOGE(TAG, "%s: transport_read() error: errno=%d", __func__, errno); + esp_mqtt_client_dispatch_transport_error(client); + return -2; +} + +#if MQTT_ENABLE_SSL +enum esp_mqtt_ssl_cert_key_api { + MQTT_SSL_DATA_API_CA_CERT, + MQTT_SSL_DATA_API_CLIENT_CERT, + MQTT_SSL_DATA_API_CLIENT_KEY, + MQTT_SSL_DATA_API_MAX, +}; + +static esp_err_t esp_mqtt_set_cert_key_data(esp_transport_handle_t ssl, enum esp_mqtt_ssl_cert_key_api what, const char *cert_key_data, int cert_key_len) +{ + char *data = (char *)cert_key_data; + int ssl_transport_api_id = what; + int len = cert_key_len; + + if (!data) { + return ESP_OK; + } + + if (len == 0) { + // if length not specified, expect 0-terminated PEM string + // and the original transport_api_id (by convention after the last api_id in the enum) + ssl_transport_api_id += MQTT_SSL_DATA_API_MAX; + len = strlen(data); + } +#ifndef MQTT_SUPPORTED_FEATURE_DER_CERTIFICATES + else { + ESP_LOGE(TAG, "Explicit cert-/key-len is not available in IDF version %s", IDF_VER); + return ESP_ERR_NOT_SUPPORTED; + } +#endif + + // option to force the cert/key config to null (i.e. skip validation) when existing config updates + if (0 == strcmp(data, "NULL")) { + data = NULL; + len = 0; + } + + switch (ssl_transport_api_id) { +#ifdef MQTT_SUPPORTED_FEATURE_DER_CERTIFICATES + case MQTT_SSL_DATA_API_CA_CERT: + esp_transport_ssl_set_cert_data_der(ssl, data, len); + break; + case MQTT_SSL_DATA_API_CLIENT_CERT: + esp_transport_ssl_set_client_cert_data_der(ssl, data, len); + break; + case MQTT_SSL_DATA_API_CLIENT_KEY: + esp_transport_ssl_set_client_key_data_der(ssl, data, len); + break; +#endif + case MQTT_SSL_DATA_API_CA_CERT + MQTT_SSL_DATA_API_MAX: + esp_transport_ssl_set_cert_data(ssl, data, len); + break; + case MQTT_SSL_DATA_API_CLIENT_CERT + MQTT_SSL_DATA_API_MAX: + esp_transport_ssl_set_client_cert_data(ssl, data, len); + break; + case MQTT_SSL_DATA_API_CLIENT_KEY + MQTT_SSL_DATA_API_MAX: + esp_transport_ssl_set_client_key_data(ssl, data, len); + break; + default: + return ESP_ERR_INVALID_ARG; + } + return ESP_OK; +} + +static esp_err_t esp_mqtt_set_ssl_transport_properties(esp_transport_list_handle_t transport_list, mqtt_config_storage_t *cfg) +{ + esp_transport_handle_t ssl = esp_transport_list_get_transport(transport_list, MQTT_OVER_SSL_SCHEME); + + if (cfg->use_global_ca_store == true) { + esp_transport_ssl_enable_global_ca_store(ssl); + } else if (cfg->crt_bundle_attach != NULL) { +#ifdef MQTT_SUPPORTED_FEATURE_CERTIFICATE_BUNDLE +#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE + esp_transport_ssl_crt_bundle_attach(ssl, cfg->crt_bundle_attach); +#else + ESP_LOGE(TAG, "Certificate bundle is not enabled for mbedTLS in menuconfig"); + goto esp_mqtt_set_transport_failed; +#endif /* CONFIG_MBEDTLS_CERTIFICATE_BUNDLE */ +#else + ESP_LOGE(TAG, "Certificate bundle feature is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif /* MQTT_SUPPORTED_FEATURE_CERTIFICATE_BUNDLE */ + } else { + ESP_OK_CHECK(TAG, esp_mqtt_set_cert_key_data(ssl, MQTT_SSL_DATA_API_CA_CERT, cfg->cacert_buf, cfg->cacert_bytes), + goto esp_mqtt_set_transport_failed); + + } + if(cfg->ciphersuites_list) + { +#if defined(MQTT_SUPPORTED_FEATURE_CIPHERSUITES_LIST) + esp_transport_ssl_set_ciphersuites_list(ssl,cfg->ciphersuites_list); +#else + ESP_LOGE(TAG, "Cipher suites list feature is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif /* MQTT_SUPPORTED_FEATURE_CIPHERSUITES_LIST */ + } + + if (cfg->psk_hint_key) { +#if defined(MQTT_SUPPORTED_FEATURE_PSK_AUTHENTICATION) && MQTT_ENABLE_SSL +#ifdef CONFIG_ESP_TLS_PSK_VERIFICATION + esp_transport_ssl_set_psk_key_hint(ssl, cfg->psk_hint_key); +#else + ESP_LOGE(TAG, "PSK authentication configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option"); + goto esp_mqtt_set_transport_failed; +#endif +#else + ESP_LOGE(TAG, "PSK authentication is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif + } + + if (cfg->alpn_protos) { +#if defined(MQTT_SUPPORTED_FEATURE_ALPN) && MQTT_ENABLE_SSL +#if defined(CONFIG_MBEDTLS_SSL_ALPN) || defined(CONFIG_WOLFSSL_HAVE_ALPN) + esp_transport_ssl_set_alpn_protocol(ssl, (const char **)cfg->alpn_protos); +#else + ESP_LOGE(TAG, "APLN configured but not enabled in menuconfig: Please enable MBEDTLS_SSL_ALPN or WOLFSSL_HAVE_ALPN option"); + goto esp_mqtt_set_transport_failed; +#endif +#else + ESP_LOGE(TAG, "APLN is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif + } + + + if (cfg->skip_cert_common_name_check) { +#if defined(MQTT_SUPPORTED_FEATURE_SKIP_CRT_CMN_NAME_CHECK) && MQTT_ENABLE_SSL + esp_transport_ssl_skip_common_name_check(ssl); +#else + ESP_LOGE(TAG, "Skip certificate common name check is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif + } + + if (cfg->common_name) { +#if defined(MQTT_SUPPORTED_FEATURE_CRT_CMN_NAME) && MQTT_ENABLE_SSL + esp_transport_ssl_set_common_name(ssl, cfg->common_name); +#else + ESP_LOGE(TAG, "Setting expected certificate common name is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif + } + + if (cfg->use_secure_element) { +#ifdef MQTT_SUPPORTED_FEATURE_SECURE_ELEMENT +#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT + esp_transport_ssl_use_secure_element(ssl); +#else + ESP_LOGE(TAG, "Secure element not enabled for esp-tls in menuconfig"); + goto esp_mqtt_set_transport_failed; +#endif /* CONFIG_ESP_TLS_USE_SECURE_ELEMENT */ +#else + ESP_LOGE(TAG, "Secure element feature is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif /* MQTT_SUPPORTED_FEATURE_SECURE_ELEMENT */ + } + + if (cfg->ds_data != NULL) { +#ifdef MQTT_SUPPORTED_FEATURE_DIGITAL_SIGNATURE +#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL + esp_transport_ssl_set_ds_data(ssl, cfg->ds_data); +#else + ESP_LOGE(TAG, "Digital Signature not enabled for esp-tls in menuconfig"); + goto esp_mqtt_set_transport_failed; +#endif /* CONFIG_ESP_TLS_USE_DS_PERIPHERAL */ +#else + ESP_LOGE(TAG, "Digital Signature feature is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif + } + + if (cfg->use_ecdsa_peripheral) { +#ifdef MQTT_SUPPORTED_FEATURE_ECDSA_PERIPHERAL +#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN + esp_transport_ssl_set_client_key_ecdsa_peripheral(ssl, cfg->ecdsa_key_efuse_blk); +#else + ESP_LOGE(TAG, "ECDSA peripheral not enabled for esp-tls in menuconfig"); + goto esp_mqtt_set_transport_failed; +#endif /* CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN */ +#else + ESP_LOGE(TAG, "ECDSA peripheral feature is not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif /* MQTT_SUPPORTED_FEATURE_ECDSA_PERIPHERAL */ + } + + ESP_OK_CHECK(TAG, esp_mqtt_set_cert_key_data(ssl, MQTT_SSL_DATA_API_CLIENT_CERT, cfg->clientcert_buf, cfg->clientcert_bytes), + goto esp_mqtt_set_transport_failed); + ESP_OK_CHECK(TAG, esp_mqtt_set_cert_key_data(ssl, MQTT_SSL_DATA_API_CLIENT_KEY, cfg->clientkey_buf, cfg->clientkey_bytes), + goto esp_mqtt_set_transport_failed); + + if (cfg->clientkey_password && cfg->clientkey_password_len) { +#if defined(MQTT_SUPPORTED_FEATURE_CLIENT_KEY_PASSWORD) && MQTT_ENABLE_SSL + esp_transport_ssl_set_client_key_password(ssl, + cfg->clientkey_password, + cfg->clientkey_password_len); +#else + ESP_LOGE(TAG, "Password protected keys are not available in IDF version %s", IDF_VER); + goto esp_mqtt_set_transport_failed; +#endif + } + + + return ESP_OK; + +esp_mqtt_set_transport_failed: + return ESP_FAIL; +} +#endif // MQTT_ENABLE_SSL + +/* Checks if the user supplied config values are internally consistent */ +static esp_err_t esp_mqtt_check_cfg_conflict(const mqtt_config_storage_t *cfg, const esp_mqtt_client_config_t *user_cfg) +{ + if (cfg == NULL || user_cfg == NULL) { + ESP_LOGE(TAG, "Invalid configuration"); + return ESP_ERR_INVALID_ARG; + } + esp_err_t ret = ESP_OK; + + bool ssl_cfg_enabled = cfg->use_global_ca_store || cfg->cacert_buf || cfg->clientcert_buf || cfg->psk_hint_key || cfg->alpn_protos; + bool is_ssl_scheme = false; + if (cfg->scheme) { + is_ssl_scheme = (strncasecmp(cfg->scheme, MQTT_OVER_SSL_SCHEME, sizeof(MQTT_OVER_SSL_SCHEME)) == 0) || (strncasecmp(cfg->scheme, MQTT_OVER_WSS_SCHEME, sizeof(MQTT_OVER_WSS_SCHEME)) == 0); + } + + if (!is_ssl_scheme && ssl_cfg_enabled) { + if (cfg->uri) { + ESP_LOGW(TAG, "SSL related configs set, but the URI scheme specifies a non-SSL scheme, scheme = %s", cfg->scheme); + } else { + ESP_LOGW(TAG, "SSL related configs set, but the transport protocol is a non-SSL scheme, transport = %d", user_cfg->broker.address.transport); + } + ret = ESP_ERR_INVALID_ARG; + } + + if (cfg->uri && user_cfg->broker.address.transport) { + ESP_LOGW(TAG, "Transport config set, but overridden by scheme from URI: transport = %d, uri scheme = %s", user_cfg->broker.address.transport, cfg->scheme); + ret = ESP_ERR_INVALID_ARG; + } + + return ret; +} + +bool esp_mqtt_set_if_config(char const *const new_config, char **old_config) +{ + if (new_config) { + free(*old_config); + *old_config = strdup(new_config); + if (*old_config == NULL) { + return false; + } + } + return true; +} + +static esp_err_t esp_mqtt_client_create_transport(esp_mqtt_client_handle_t client) +{ + esp_err_t ret = ESP_OK; + if (client->transport_list) { + esp_transport_list_destroy(client->transport_list); + client->transport_list = NULL; + } + if (client->config->scheme) { + client->transport_list = esp_transport_list_init(); + ESP_MEM_CHECK(TAG, client->transport_list, return ESP_ERR_NO_MEM); + + if ((strncasecmp(client->config->scheme, MQTT_OVER_TCP_SCHEME, sizeof(MQTT_OVER_TCP_SCHEME)) == 0) || (strncasecmp(client->config->scheme, MQTT_OVER_WS_SCHEME, sizeof(MQTT_OVER_WS_SCHEME)) == 0)) { + esp_transport_handle_t tcp = esp_transport_tcp_init(); + ESP_MEM_CHECK(TAG, tcp, return ESP_ERR_NO_MEM); + esp_transport_set_default_port(tcp, MQTT_TCP_DEFAULT_PORT); + if (client->config->if_name) { + esp_transport_tcp_set_interface_name(tcp, client->config->if_name); + } + esp_transport_list_add(client->transport_list, tcp, MQTT_OVER_TCP_SCHEME); + if (strncasecmp(client->config->scheme, MQTT_OVER_WS_SCHEME, sizeof(MQTT_OVER_WS_SCHEME)) == 0) { +#if MQTT_ENABLE_WS + esp_transport_handle_t ws = esp_transport_ws_init(tcp); + ESP_MEM_CHECK(TAG, ws, return ESP_ERR_NO_MEM); + esp_transport_set_default_port(ws, MQTT_WS_DEFAULT_PORT); + if (client->config->path) { + esp_transport_ws_set_path(ws, client->config->path); + } +#ifdef MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL + esp_transport_ws_set_subprotocol(ws, MQTT_OVER_TCP_SCHEME); +#endif + esp_transport_list_add(client->transport_list, ws, MQTT_OVER_WS_SCHEME); +#else + ESP_LOGE(TAG, "Please enable MQTT_ENABLE_WS to use %s", client->config->scheme); + ret = ESP_FAIL; +#endif + } + } else if ((strncasecmp(client->config->scheme, MQTT_OVER_SSL_SCHEME, sizeof(MQTT_OVER_SSL_SCHEME)) == 0) || (strncasecmp(client->config->scheme, MQTT_OVER_WSS_SCHEME, sizeof(MQTT_OVER_WSS_SCHEME)) == 0)) { +#if MQTT_ENABLE_SSL + esp_transport_handle_t ssl = esp_transport_ssl_init(); + ESP_MEM_CHECK(TAG, ssl, return ESP_ERR_NO_MEM); + esp_transport_set_default_port(ssl, MQTT_SSL_DEFAULT_PORT); + if (client->config->if_name) { + esp_transport_ssl_set_interface_name(ssl, client->config->if_name); + } + esp_transport_list_add(client->transport_list, ssl, MQTT_OVER_SSL_SCHEME); + if (strncasecmp(client->config->scheme, MQTT_OVER_WSS_SCHEME, sizeof(MQTT_OVER_WSS_SCHEME)) == 0) { +#if MQTT_ENABLE_WS + esp_transport_handle_t wss = esp_transport_ws_init(ssl); + ESP_MEM_CHECK(TAG, wss, return ESP_ERR_NO_MEM); + esp_transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); + if (client->config->path) { + esp_transport_ws_set_path(wss, client->config->path); + } +#ifdef MQTT_SUPPORTED_FEATURE_WS_SUBPROTOCOL + esp_transport_ws_set_subprotocol(wss, MQTT_OVER_TCP_SCHEME); +#endif + esp_transport_list_add(client->transport_list, wss, MQTT_OVER_WSS_SCHEME); +#else + ESP_LOGE(TAG, "Please enable MQTT_ENABLE_WS to use %s", client->config->scheme); + ret = ESP_FAIL; +#endif + } +#else + ESP_LOGE(TAG, "Please enable MQTT_ENABLE_SSL to use %s", client->config->scheme); + ret = ESP_FAIL; +#endif + } else { + ESP_LOGE(TAG, "Not support this mqtt scheme %s", client->config->scheme); + ret = ESP_FAIL; + } + } else { + ESP_LOGE(TAG, "No scheme found"); + ret = ESP_FAIL; + } + return ret; +} + +esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_client_config_t *config) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + MQTT_API_LOCK(client); + //Copy user configurations to client context + esp_err_t err = ESP_OK; + if (!client->config) { + client->config = calloc(1, sizeof(mqtt_config_storage_t)); + ESP_MEM_CHECK(TAG, client->config, { + MQTT_API_UNLOCK(client); + return ESP_ERR_NO_MEM; + }); + } + + mqtt_msg_buffer_destroy(&client->mqtt_state.connection); + int buffer_size = config->buffer.size; + if (buffer_size <= 0) { + buffer_size = MQTT_BUFFER_SIZE_BYTE; + } + + // use separate value for output buffer size if configured + int out_buffer_size = config->buffer.out_size > 0 ? config->buffer.out_size : buffer_size; + if (mqtt_msg_buffer_init(&client->mqtt_state.connection, out_buffer_size) != ESP_OK) { + goto _mqtt_set_config_failed; + } + + free(client->mqtt_state.in_buffer); + client->mqtt_state.in_buffer = (uint8_t *)malloc(buffer_size); + ESP_MEM_CHECK(TAG, client->mqtt_state.in_buffer, goto _mqtt_set_config_failed); + client->mqtt_state.in_buffer_length = buffer_size; + + client->config->message_retransmit_timeout = config->session.message_retransmit_timeout; + if (config->session.message_retransmit_timeout <= 0) { + client->config->message_retransmit_timeout = MQTT_DEFAULT_RETRANSMIT_TIMEOUT_MS; + } + + client->config->task_prio = config->task.priority; + if (client->config->task_prio <= 0) { + client->config->task_prio = MQTT_TASK_PRIORITY; + } + + client->config->task_stack = config->task.stack_size; + if (client->config->task_stack <= 0) { + client->config->task_stack = MQTT_TASK_STACK; + } + + if (config->broker.address.port) { + client->config->port = config->broker.address.port; + } + + if (config->network.tcp_keep_alive_cfg.keep_alive_enable) { + client->config->tcp_keep_alive_cfg = config->network.tcp_keep_alive_cfg; + } + + err = ESP_ERR_NO_MEM; + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->broker.address.hostname, &client->config->host), goto _mqtt_set_config_failed); + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->broker.address.path, &client->config->path), goto _mqtt_set_config_failed); + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->credentials.username, &client->mqtt_state.connection.information.username), goto _mqtt_set_config_failed); + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->credentials.authentication.password, &client->mqtt_state.connection.information.password), goto _mqtt_set_config_failed); + + if (!config->credentials.set_null_client_id) { + if (config->credentials.client_id) { + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->credentials.client_id, &client->mqtt_state.connection.information.client_id), goto _mqtt_set_config_failed); + } else if (client->mqtt_state.connection.information.client_id == NULL) { + client->mqtt_state.connection.information.client_id = platform_create_id_string(); + } + ESP_MEM_CHECK(TAG, client->mqtt_state.connection.information.client_id, goto _mqtt_set_config_failed); + ESP_LOGD(TAG, "MQTT client_id=%s", client->mqtt_state.connection.information.client_id); + } + + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->broker.address.uri, &client->config->uri), goto _mqtt_set_config_failed); + ESP_MEM_CHECK(TAG, esp_mqtt_set_if_config(config->session.last_will.topic, &client->mqtt_state.connection.information.will_topic), goto _mqtt_set_config_failed); + + if (config->session.last_will.msg_len && config->session.last_will.msg) { + free(client->mqtt_state.connection.information.will_message); + client->mqtt_state.connection.information.will_message = malloc(config->session.last_will.msg_len); + ESP_MEM_CHECK(TAG, client->mqtt_state.connection.information.will_message, goto _mqtt_set_config_failed); + memcpy(client->mqtt_state.connection.information.will_message, config->session.last_will.msg, config->session.last_will.msg_len); + client->mqtt_state.connection.information.will_length = config->session.last_will.msg_len; + } else if (config->session.last_will.msg) { + free(client->mqtt_state.connection.information.will_message); + client->mqtt_state.connection.information.will_message = strdup(config->session.last_will.msg); + ESP_MEM_CHECK(TAG, client->mqtt_state.connection.information.will_message, goto _mqtt_set_config_failed); + client->mqtt_state.connection.information.will_length = strlen(config->session.last_will.msg); + } + if (config->session.last_will.qos) { + client->mqtt_state.connection.information.will_qos = config->session.last_will.qos; + } + if (config->session.last_will.retain) { + client->mqtt_state.connection.information.will_retain = config->session.last_will.retain; + } + + if (config->session.disable_clean_session == client->mqtt_state.connection.information.clean_session) { + client->mqtt_state.connection.information.clean_session = !config->session.disable_clean_session; + if (!client->mqtt_state.connection.information.clean_session && config->credentials.set_null_client_id) { + ESP_LOGE(TAG, "Clean Session flag must be true if client has a null id"); + } + } + if (config->session.keepalive) { + client->mqtt_state.connection.information.keepalive = config->session.keepalive; + } + if (client->mqtt_state.connection.information.keepalive == 0) { + client->mqtt_state.connection.information.keepalive = MQTT_KEEPALIVE_TICK; + } + if (config->session.disable_keepalive) { + // internal `keepalive` value (in connect_info) is in line with 3.1.2.10 Keep Alive from mqtt spec: + // * keepalive=0: Keep alive mechanism disabled (server not to disconnect the client on its inactivity) + // * period in seconds to send a Control packet if inactive + client->mqtt_state.connection.information.keepalive = 0; + } + + if (config->session.protocol_ver) { + client->mqtt_state.connection.information.protocol_ver = config->session.protocol_ver; + } + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_UNDEFINED) { +#ifdef MQTT_PROTOCOL_311 + client->mqtt_state.connection.information.protocol_ver = MQTT_PROTOCOL_V_3_1_1; +#else + client->mqtt_state.connection.information.protocol_ver = MQTT_PROTOCOL_V_3_1; +#endif + } else if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifndef MQTT_PROTOCOL_5 + ESP_LOGE(TAG, "Please first enable MQTT_PROTOCOL_5 feature in menuconfig"); + goto _mqtt_set_config_failed; +#endif + } + + client->config->network_timeout_ms = config->network.timeout_ms; + if (client->config->network_timeout_ms <= 0) { + client->config->network_timeout_ms = MQTT_NETWORK_TIMEOUT_MS; + } + + if (config->network.refresh_connection_after_ms) { + client->config->refresh_connection_after_ms = config->network.refresh_connection_after_ms; + } + + client->config->auto_reconnect = true; + if (config->network.disable_auto_reconnect == client->config->auto_reconnect) { + client->config->auto_reconnect = !config->network.disable_auto_reconnect; + } + + if (config->network.reconnect_timeout_ms) { + client->config->reconnect_timeout_ms = config->network.reconnect_timeout_ms; + } else { + client->config->reconnect_timeout_ms = MQTT_RECON_DEFAULT_MS; + } + + client->config->transport = config->network.transport; + + if (config->network.if_name) { + client->config->if_name = calloc(1, sizeof(struct ifreq) + 1); + ESP_MEM_CHECK(TAG, client->config->if_name, goto _mqtt_set_config_failed); + memcpy(client->config->if_name, config->network.if_name, sizeof(struct ifreq)); + } + + if (config->broker.verification.alpn_protos) { + for (int i = 0; i < client->config->num_alpn_protos; i++) { + free(client->config->alpn_protos[i]); + } + free(client->config->alpn_protos); + client->config->num_alpn_protos = 0; + + const char **p; + + for (p = config->broker.verification.alpn_protos; *p != NULL; p++ ) { + client->config->num_alpn_protos++; + } + // mbedTLS expects the list to be null-terminated + client->config->alpn_protos = calloc(client->config->num_alpn_protos + 1, sizeof(*config->broker.verification.alpn_protos)); + ESP_MEM_CHECK(TAG, client->config->alpn_protos, goto _mqtt_set_config_failed); + + for (int i = 0; i < client->config->num_alpn_protos; i++) { + client->config->alpn_protos[i] = strdup(config->broker.verification.alpn_protos[i]); + ESP_MEM_CHECK(TAG, client->config->alpn_protos[i], goto _mqtt_set_config_failed); + } + } + + // configure ssl related parameters + client->config->use_global_ca_store = config->broker.verification.use_global_ca_store; + client->config->cacert_buf = config->broker.verification.certificate; + client->config->cacert_bytes = config->broker.verification.certificate_len; + client->config->psk_hint_key = config->broker.verification.psk_hint_key; + client->config->crt_bundle_attach = config->broker.verification.crt_bundle_attach; + client->config->ciphersuites_list = config->broker.verification.ciphersuites_list; + client->config->clientcert_buf = config->credentials.authentication.certificate; + client->config->clientcert_bytes = config->credentials.authentication.certificate_len; + client->config->clientkey_buf = config->credentials.authentication.key; + client->config->clientkey_bytes = config->credentials.authentication.key_len; + client->config->skip_cert_common_name_check = config->broker.verification.skip_cert_common_name_check; + client->config->common_name = config->broker.verification.common_name; + client->config->use_secure_element = config->credentials.authentication.use_secure_element; + client->config->ds_data = config->credentials.authentication.ds_data; + client->config->use_ecdsa_peripheral = config->credentials.authentication.use_ecdsa_peripheral; + client->config->ecdsa_key_efuse_blk = config->credentials.authentication.ecdsa_key_efuse_blk; + + if (config->credentials.authentication.key_password && config->credentials.authentication.key_password_len) { + client->config->clientkey_password_len = config->credentials.authentication.key_password_len; + client->config->clientkey_password = malloc(client->config->clientkey_password_len); + ESP_MEM_CHECK(TAG, client->config->clientkey_password, goto _mqtt_set_config_failed); + memcpy(client->config->clientkey_password, config->credentials.authentication.key_password, client->config->clientkey_password_len); + } + + if (config->broker.address.transport) { + free(client->config->scheme); + client->config->scheme = NULL; + if (config->broker.address.transport == MQTT_TRANSPORT_OVER_TCP) { + client->config->scheme = create_string(MQTT_OVER_TCP_SCHEME, strlen(MQTT_OVER_TCP_SCHEME)); + ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); + } +#if MQTT_ENABLE_WS + else if (config->broker.address.transport == MQTT_TRANSPORT_OVER_WS) { + client->config->scheme = create_string(MQTT_OVER_WS_SCHEME, strlen(MQTT_OVER_WS_SCHEME)); + ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); + } +#endif +#if MQTT_ENABLE_SSL + else if (config->broker.address.transport == MQTT_TRANSPORT_OVER_SSL) { + client->config->scheme = create_string(MQTT_OVER_SSL_SCHEME, strlen(MQTT_OVER_SSL_SCHEME)); + ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); + } +#endif +#if MQTT_ENABLE_WSS + else if (config->broker.address.transport == MQTT_TRANSPORT_OVER_WSS) { + client->config->scheme = create_string(MQTT_OVER_WSS_SCHEME, strlen(MQTT_OVER_WSS_SCHEME)); + ESP_MEM_CHECK(TAG, client->config->scheme, goto _mqtt_set_config_failed); + } +#endif + } + + // Set uri at the end of config to override separately configured uri elements + if (config->broker.address.uri) { + if (esp_mqtt_client_set_uri(client, client->config->uri) != ESP_OK) { + err = ESP_FAIL; + goto _mqtt_set_config_failed; + } + } + client->config->outbox_limit = config->outbox.limit; + esp_err_t config_has_conflict = esp_mqtt_check_cfg_conflict(client->config, config); + + MQTT_API_UNLOCK(client); + + return config_has_conflict; +_mqtt_set_config_failed: + esp_mqtt_destroy_config(client); + MQTT_API_UNLOCK(client); + return err; +} + +void esp_mqtt_destroy_config(esp_mqtt_client_handle_t client) +{ + if (client->config == NULL) { + return; + } + free(client->mqtt_state.in_buffer); + mqtt_msg_buffer_destroy(&client->mqtt_state.connection); + free(client->config->host); + free(client->config->uri); + free(client->config->path); + free(client->config->scheme); + for (int i = 0; i < client->config->num_alpn_protos; i++) { + free(client->config->alpn_protos[i]); + } + free(client->config->alpn_protos); + free(client->config->clientkey_password); + free(client->config->if_name); + free(client->mqtt_state.connection.information.will_topic); + free(client->mqtt_state.connection.information.will_message); + free(client->mqtt_state.connection.information.client_id); + free(client->mqtt_state.connection.information.username); + free(client->mqtt_state.connection.information.password); +#ifdef MQTT_PROTOCOL_5 + esp_mqtt5_client_destory(client); +#endif + memset(&client->mqtt_state.connection.information, 0, sizeof(mqtt_connect_info_t)); +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP + if (client->config->event_loop_handle) { + esp_event_loop_delete(client->config->event_loop_handle); + } +#endif + esp_transport_destroy(client->config->transport); + memset(client->config, 0, sizeof(mqtt_config_storage_t)); + free(client->config); + client->config = NULL; +} + +static inline bool has_timed_out(uint64_t last_tick, uint64_t timeout) +{ + uint64_t next = last_tick + timeout; + return (int64_t)(next - platform_tick_get_ms()) <= 0; +} + +static esp_err_t process_keepalive(esp_mqtt_client_handle_t client) +{ + if (client->mqtt_state.connection.information.keepalive > 0) { + const uint64_t keepalive_ms = client->mqtt_state.connection.information.keepalive * 1000; + + if (client->wait_for_ping_resp == true ) { + if (has_timed_out(client->keepalive_tick, keepalive_ms)) { + ESP_LOGE(TAG, "No PING_RESP, disconnected"); + esp_mqtt_abort_connection(client); + client->wait_for_ping_resp = false; + return ESP_FAIL; + } + return ESP_OK; + } + + if (has_timed_out(client->keepalive_tick, keepalive_ms / 2)) { + if (esp_mqtt_client_ping(client) == ESP_FAIL) { + ESP_LOGE(TAG, "Can't send ping, disconnected"); + esp_mqtt_abort_connection(client); + return ESP_FAIL; + } + client->wait_for_ping_resp = true; + return ESP_OK; + } + } + return ESP_OK; +} + +static inline esp_err_t esp_mqtt_write(esp_mqtt_client_handle_t client) +{ + int wlen = 0, widx = 0, len = client->mqtt_state.connection.outbound_message.length; + while (len > 0) { + wlen = esp_transport_write(client->transport, + (char *)client->mqtt_state.connection.outbound_message.data + widx, + len, + client->config->network_timeout_ms); + if (wlen < 0) { + ESP_LOGE(TAG, "Writing failed: errno=%d", errno); + esp_mqtt_client_dispatch_transport_error(client); + return ESP_FAIL; + } + + if (wlen == 0) { + ESP_LOGE(TAG, "Writing didn't complete in specified timeout: errno=%d", errno); + return ESP_ERR_TIMEOUT; + } + widx += wlen; + len -= wlen; + } + return ESP_OK; +} + +static esp_err_t esp_mqtt_connect(esp_mqtt_client_handle_t client, int timeout_ms) +{ + int read_len, connect_rsp_code = 0; + client->wait_for_ping_resp = false; + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + mqtt5_msg_connect(&client->mqtt_state.connection, + &client->mqtt_state.connection.information, &client->mqtt5_config->connect_property_info, &client->mqtt5_config->will_property_info); +#endif + } else { + mqtt_msg_connect(&client->mqtt_state.connection, + &client->mqtt_state.connection.information); + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Connect message cannot be created"); + return ESP_FAIL; + } + + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.connection.outbound_message.data); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + client->mqtt_state.pending_msg_id = mqtt5_get_id(client->mqtt_state.connection.outbound_message.data, + client->mqtt_state.connection.outbound_message.length); +#endif + } else { + client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.connection.outbound_message.data, + client->mqtt_state.connection.outbound_message.length); + } + ESP_LOGD(TAG, "Sending MQTT CONNECT message, type: %d, id: %04X", + client->mqtt_state.pending_msg_type, + client->mqtt_state.pending_msg_id); + + if (esp_mqtt_write(client) != ESP_OK) { + return ESP_FAIL; + } + + client->mqtt_state.in_buffer_read_len = 0; + client->mqtt_state.message_length = 0; + + /* wait configured network timeout for broker connection response */ + uint64_t connack_recv_started = platform_tick_get_ms(); + do { + read_len = mqtt_message_receive(client, client->config->network_timeout_ms); + } while (read_len == 0 && platform_tick_get_ms() - connack_recv_started < client->config->network_timeout_ms); + + if (read_len <= 0) { + ESP_LOGE(TAG, "%s: mqtt_message_receive() returned %d", __func__, read_len); + return ESP_FAIL; + } + + if (mqtt_get_type(client->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK) { + ESP_LOGE(TAG, "Invalid MSG_TYPE response: %d, read_len: %d", mqtt_get_type(client->mqtt_state.in_buffer), read_len); + return ESP_FAIL; + } + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + if (esp_mqtt5_parse_connack(client, &connect_rsp_code) == ESP_OK) { + client->send_publish_packet_count = 0; + return ESP_OK; + } +#endif + } else { + client->mqtt_state.in_buffer_read_len = 0; + connect_rsp_code = mqtt_get_connect_return_code(client->mqtt_state.in_buffer); + if (connect_rsp_code == MQTT_CONNECTION_ACCEPTED) { + ESP_LOGD(TAG, "Connected"); + return ESP_OK; + } + switch (connect_rsp_code) { + case MQTT_CONNECTION_REFUSE_PROTOCOL: + ESP_LOGW(TAG, "Connection refused, bad protocol"); + break; + case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE: + ESP_LOGW(TAG, "Connection refused, server unavailable"); + break; + case MQTT_CONNECTION_REFUSE_BAD_USERNAME: + ESP_LOGW(TAG, "Connection refused, bad username or password"); + break; + case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED: + ESP_LOGW(TAG, "Connection refused, not authorized"); + break; + default: + ESP_LOGW(TAG, "Connection refused, Unknow reason"); + break; + } + } + /* propagate event with connection refused error */ + client->event.event_id = MQTT_EVENT_ERROR; + client->event.error_handle->error_type = MQTT_ERROR_TYPE_CONNECTION_REFUSED; + client->event.error_handle->connect_return_code = connect_rsp_code; + client->event.error_handle->esp_tls_stack_err = 0; + client->event.error_handle->esp_tls_last_esp_err = 0; + client->event.error_handle->esp_tls_cert_verify_flags = 0; + esp_mqtt_dispatch_event_with_msgid(client); + + return ESP_FAIL; +} + +static void esp_mqtt_abort_connection(esp_mqtt_client_handle_t client) +{ + MQTT_API_LOCK(client); + esp_transport_close(client->transport); + client->wait_timeout_ms = client->config->reconnect_timeout_ms; + client->reconnect_tick = platform_tick_get_ms(); + client->state = MQTT_STATE_WAIT_RECONNECT; + ESP_LOGD(TAG, "Reconnect after %d ms", client->wait_timeout_ms); + client->event.event_id = MQTT_EVENT_DISCONNECTED; + client->wait_for_ping_resp = false; + esp_mqtt_dispatch_event_with_msgid(client); + MQTT_API_UNLOCK(client); +} + +static bool create_client_data(esp_mqtt_client_handle_t client) +{ + client->event.error_handle = calloc(1, sizeof(esp_mqtt_error_codes_t)); + ESP_MEM_CHECK(TAG, client->event.error_handle, return false) + + client->api_lock = xSemaphoreCreateRecursiveMutex(); + ESP_MEM_CHECK(TAG, client->api_lock, return false); + + client->outbox = outbox_init(); + ESP_MEM_CHECK(TAG, client->outbox, return false); + client->status_bits = xEventGroupCreate(); + ESP_MEM_CHECK(TAG, client->status_bits, return false); + + return true; +} + +esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config) +{ + esp_mqtt_client_handle_t client = heap_caps_calloc(1, sizeof(struct esp_mqtt_client), +#if MQTT_EVENT_QUEUE_SIZE > 1 + // if supporting multiple queued events, we keep track of them + // using atomic variable, so need to make sure it won't get allocated in PSRAM + MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); +#else + MALLOC_CAP_DEFAULT); +#endif + ESP_MEM_CHECK(TAG, client, return NULL); + if (!create_client_data(client)) { + goto _mqtt_init_failed; + } + + if (esp_mqtt_set_config(client, config) != ESP_OK) { + goto _mqtt_init_failed; + } +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP + esp_event_loop_args_t no_task_loop = { + .queue_size = MQTT_EVENT_QUEUE_SIZE, + .task_name = NULL, + }; + esp_event_loop_create(&no_task_loop, &client->config->event_loop_handle); +#if MQTT_EVENT_QUEUE_SIZE > 1 + atomic_init(&client->queued_events, 0); +#endif +#endif + + client->keepalive_tick = platform_tick_get_ms(); + client->reconnect_tick = platform_tick_get_ms(); + client->refresh_connection_tick = platform_tick_get_ms(); + client->wait_for_ping_resp = false; +#ifdef MQTT_PROTOCOL_5 + if (esp_mqtt5_create_default_config(client) != ESP_OK) { + goto _mqtt_init_failed; + } +#endif + return client; +_mqtt_init_failed: + esp_mqtt_client_destroy(client); + return NULL; +} + +esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (client->run) { + esp_mqtt_client_stop(client); + } + esp_mqtt_destroy_config(client); + if (client->transport_list) { + esp_transport_list_destroy(client->transport_list); + } + if (client->outbox) { + outbox_destroy(client->outbox); + } + if (client->status_bits) { + vEventGroupDelete(client->status_bits); + } + if (client->api_lock) { + vSemaphoreDelete(client->api_lock); + } + free(client->event.error_handle); + free(client); + return ESP_OK; +} + +static char *create_string(const char *ptr, int len) +{ + char *ret; + if (len <= 0) { + return NULL; + } + ret = calloc(1, len + 1); + ESP_MEM_CHECK(TAG, ret, return NULL); + memcpy(ret, ptr, len); + return ret; +} + +esp_err_t esp_mqtt_client_set_uri(esp_mqtt_client_handle_t client, const char *uri) +{ + struct http_parser_url puri; + http_parser_url_init(&puri); + int parser_status = http_parser_parse_url(uri, strlen(uri), 0, &puri); + if (parser_status != 0) { + ESP_LOGE(TAG, "Error parse uri = %s", uri); + return ESP_FAIL; + } + + // This API could be also executed when client is active (need to protect config fields) + MQTT_API_LOCK(client); + // set uri overrides actual scheme, host, path if configured previously +// False-positive leak detection. TODO: GCC-366 +#pragma GCC diagnostic push // TODO: IDF-10105 +#if __clang__ +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" + free(client->config->scheme); + free(client->config->host); + free(client->config->path); + + client->config->scheme = create_string(uri + puri.field_data[UF_SCHEMA].off, puri.field_data[UF_SCHEMA].len); + client->config->host = create_string(uri + puri.field_data[UF_HOST].off, puri.field_data[UF_HOST].len); + client->config->path = NULL; +#pragma GCC diagnostic pop + + if (puri.field_data[UF_PATH].len || puri.field_data[UF_QUERY].len) { + int asprintf_ret_value; + if (puri.field_data[UF_QUERY].len == 0) { + asprintf_ret_value = asprintf(&client->config->path, + "%.*s", + puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off); + } else if (puri.field_data[UF_PATH].len == 0) { + asprintf_ret_value = asprintf(&client->config->path, + "/?%.*s", + puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off); + } else { + asprintf_ret_value = asprintf(&client->config->path, + "%.*s?%.*s", + puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off, + puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off); + } + + if (asprintf_ret_value == -1) { + ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Memory exhausted"); + MQTT_API_UNLOCK(client); + return ESP_ERR_NO_MEM; + } + } + + if (puri.field_data[UF_PORT].len) { + client->config->port = strtol((const char *)(uri + puri.field_data[UF_PORT].off), NULL, 10); + } + + char *user_info = create_string(uri + puri.field_data[UF_USERINFO].off, puri.field_data[UF_USERINFO].len); + if (user_info) { + char *pass = strchr(user_info, ':'); + if (pass) { + pass[0] = 0; //terminal username + pass ++; + client->mqtt_state.connection.information.password = strdup(pass); + } + client->mqtt_state.connection.information.username = strdup(user_info); + + free(user_info); + } + + MQTT_API_UNLOCK(client); + return ESP_OK; +} + + +static esp_err_t esp_mqtt_dispatch_event_with_msgid(esp_mqtt_client_handle_t client) +{ + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + client->event.msg_id = mqtt5_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); +#endif + } else { + client->event.msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); + } + return esp_mqtt_dispatch_event(client); +} + +esp_err_t esp_mqtt_dispatch_custom_event(esp_mqtt_client_handle_t client, esp_mqtt_event_t *event) +{ + esp_err_t ret = esp_event_post_to(client->config->event_loop_handle, MQTT_EVENTS, MQTT_USER_EVENT, event, sizeof(*event), 0); +#if MQTT_EVENT_QUEUE_SIZE > 1 + if (ret == ESP_OK) { + atomic_fetch_add(&client->queued_events, 1); + } +#endif + return ret; +} + +static esp_err_t esp_mqtt_dispatch_event(esp_mqtt_client_handle_t client) +{ + client->event.client = client; + client->event.protocol_ver = client->mqtt_state.connection.information.protocol_ver; + esp_err_t ret = ESP_FAIL; + +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP + esp_event_post_to(client->config->event_loop_handle, MQTT_EVENTS, client->event.event_id, &client->event, sizeof(client->event), portMAX_DELAY); + ret = esp_event_loop_run(client->config->event_loop_handle, 0); +#else + return ESP_FAIL; +#endif + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + esp_mqtt5_client_delete_user_property(client->event.property->user_property); + client->event.property->user_property = NULL; +#endif + } + return ret; +} + +static esp_err_t deliver_publish(esp_mqtt_client_handle_t client) +{ + uint8_t *msg_buf = client->mqtt_state.in_buffer; + size_t msg_read_len = client->mqtt_state.in_buffer_read_len; + size_t msg_total_len = client->mqtt_state.message_length; + size_t msg_topic_len = msg_read_len; + size_t msg_data_len = msg_read_len; + size_t msg_data_offset = 0; + size_t saved_msg_topic_len = 0; + char *saved_msg_topic = NULL; + char *msg_topic = NULL; + char *msg_data = NULL; + + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + if (esp_mqtt5_get_publish_data(client, msg_buf, msg_read_len, &msg_topic, &msg_topic_len, &msg_data, &msg_data_len) != ESP_OK) { + ESP_LOGE(TAG, "%s: esp_mqtt5_get_publish_data() failed", __func__); + return ESP_FAIL; + } +#endif + } else { + msg_topic = mqtt_get_publish_topic(msg_buf, &msg_topic_len); + if (msg_topic == NULL) { + ESP_LOGE(TAG, "%s: mqtt_get_publish_topic() failed", __func__); + return ESP_FAIL; + } + ESP_LOGD(TAG, "%s: msg_topic_len=%"NEWLIB_NANO_COMPAT_FORMAT, __func__, NEWLIB_NANO_COMPAT_CAST(msg_topic_len)); + + // get payload + msg_data = mqtt_get_publish_data(msg_buf, &msg_data_len); + if (msg_data_len > 0 && msg_data == NULL) { + ESP_LOGE(TAG, "%s: mqtt_get_publish_data() failed", __func__); + return ESP_FAIL; + } + } + + client->event.retain = mqtt_get_retain(msg_buf); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + client->event.msg_id = mqtt5_get_id(msg_buf, msg_read_len); +#endif + } else { + client->event.msg_id = mqtt_get_id(msg_buf, msg_read_len); + } + client->event.qos = mqtt_get_qos(msg_buf); + client->event.dup = mqtt_get_dup(msg_buf); + client->event.total_data_len = msg_data_len + msg_total_len - msg_read_len; + + bool send_event = true; + while (send_event) { + ESP_LOGD(TAG, "Get data len= %"NEWLIB_NANO_COMPAT_FORMAT", topic len=%"NEWLIB_NANO_COMPAT_FORMAT", total_data: %d offset: %"NEWLIB_NANO_COMPAT_FORMAT, + NEWLIB_NANO_COMPAT_CAST(msg_data_len), NEWLIB_NANO_COMPAT_CAST(msg_topic_len), + client->event.total_data_len, NEWLIB_NANO_COMPAT_CAST(msg_data_offset)); + client->event.event_id = MQTT_EVENT_DATA; + client->event.data = msg_data_len > 0 ? msg_data : NULL; + client->event.data_len = msg_data_len; + client->event.current_data_offset = msg_data_offset; + client->event.topic = msg_topic; + client->event.topic_len = msg_topic_len; + esp_mqtt_dispatch_event(client); + send_event = false; + + if (msg_read_len < msg_total_len) { + send_event = true; + #ifdef CONFIG_MQTT_TOPIC_PRESENT_ALL_DATA_EVENTS + if (!saved_msg_topic) { + saved_msg_topic = strndup(msg_topic, msg_topic_len); + ESP_MEM_CHECK(TAG, saved_msg_topic, return ESP_ERR_NO_MEM); + saved_msg_topic_len = msg_topic_len; + } + #endif + size_t buf_len = client->mqtt_state.in_buffer_length; + + msg_data = (char *)client->mqtt_state.in_buffer; + msg_topic = saved_msg_topic; + msg_topic_len = saved_msg_topic_len; + msg_data_offset += msg_data_len; + int ret = esp_transport_read(client->transport, (char *)client->mqtt_state.in_buffer, + msg_total_len - msg_read_len > buf_len ? buf_len : msg_total_len - msg_read_len, + client->config->network_timeout_ms); + if (ret <= 0) { + return esp_mqtt_handle_transport_read_error(ret, client, false) == 0 ? ESP_OK : ESP_FAIL; + } + + msg_data_len = ret; + msg_read_len += msg_data_len; + } + } + free(saved_msg_topic); + return ESP_OK; +} + +static esp_err_t deliver_suback(esp_mqtt_client_handle_t client) +{ + uint8_t *msg_buf = client->mqtt_state.in_buffer; + size_t msg_data_len = client->mqtt_state.in_buffer_read_len; + char *msg_data = NULL; + + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + msg_data = mqtt5_get_suback_data(msg_buf, &msg_data_len, &client->event.property->user_property); +#else + // SUBACK Using MQTT5 received but MQTT5 is disabled, This is unlikely to happen. + return ESP_FAIL; +#endif + } else { + msg_data = mqtt_get_suback_data(msg_buf, &msg_data_len); + } + if (msg_data_len <= 0) { + ESP_LOGE(TAG, "Failed to acquire suback data"); + return ESP_FAIL; + } + client->event.error_handle->esp_tls_stack_err = 0; + client->event.error_handle->esp_tls_last_esp_err = 0; + client->event.error_handle->esp_tls_cert_verify_flags = 0; + client->event.error_handle->error_type = MQTT_ERROR_TYPE_NONE; + client->event.error_handle->connect_return_code = MQTT_CONNECTION_ACCEPTED; + // post data event + for (int topic = 0; topic < msg_data_len; ++topic) { + if ((uint8_t)msg_data[topic] >= 0x80) { + client->event.error_handle->error_type = MQTT_ERROR_TYPE_SUBSCRIBE_FAILED; + break; + } + } + client->event.data_len = msg_data_len; + client->event.total_data_len = msg_data_len; + client->event.event_id = MQTT_EVENT_SUBSCRIBED; + client->event.data = msg_data; + client->event.current_data_offset = 0; + esp_mqtt_dispatch_event_with_msgid(client); + + return ESP_OK; +} + +// Deletes the initial message in MQTT communication protocol +// Return false when message is not found, making the received counterpart invalid. +static bool remove_initiator_message(esp_mqtt_client_handle_t client, int msg_type, int msg_id) +{ + if (outbox_delete(client->outbox, msg_id, msg_type) == ESP_OK) { + ESP_LOGD(TAG, "Removed pending_id=%d", msg_id); + return true; + } + + ESP_LOGD(TAG, "Failed to remove pending_id=%d", msg_id); + return false; +} + +static outbox_item_handle_t mqtt_enqueue(esp_mqtt_client_handle_t client, uint8_t *remaining_data, int remaining_len) +{ + ESP_LOGD(TAG, "mqtt_enqueue id: %d, type=%d successful", + client->mqtt_state.pending_msg_id, client->mqtt_state.pending_msg_type); + outbox_message_t msg = { 0 }; + msg.data = client->mqtt_state.connection.outbound_message.data; + msg.len = client->mqtt_state.connection.outbound_message.length; + msg.msg_id = client->mqtt_state.pending_msg_id; + msg.msg_type = client->mqtt_state.pending_msg_type; + msg.msg_qos = client->mqtt_state.pending_publish_qos; + msg.remaining_data = remaining_data; + msg.remaining_len = remaining_len; + //Copy to queue buffer + return outbox_enqueue(client->outbox, &msg, platform_tick_get_ms()); +} + + +/* + * Returns: + * -2 in case of failure or EOF (clean connection closure) + * -1 timeout while in-the-middle of the messge + * 0 if no message has been received + * 1 if a message has been received and placed to client->mqtt_state: + * message length: client->mqtt_state.message_length + * message content: client->mqtt_state.in_buffer + * + */ +static int mqtt_message_receive(esp_mqtt_client_handle_t client, int read_poll_timeout_ms) +{ + int read_len, total_len, fixed_header_len; + uint8_t *buf = client->mqtt_state.in_buffer + client->mqtt_state.in_buffer_read_len; + esp_transport_handle_t t = client->transport; + + client->mqtt_state.message_length = 0; + if (client->mqtt_state.in_buffer_read_len == 0) { + /* + * Read first byte of the mqtt packet fixed header, it contains packet + * type and flags. + */ + read_len = esp_transport_read(t, (char *)buf, 1, read_poll_timeout_ms); + if (read_len <= 0) { + return esp_mqtt_handle_transport_read_error(read_len, client, false); + } + ESP_LOGD(TAG, "%s: first byte: 0x%x", __func__, *buf); + /* + * Verify the flags and act according to MQTT protocol: close connection + * if the flags are set incorrectly. + */ + if (!mqtt_has_valid_msg_hdr(buf, read_len)) { + ESP_LOGE(TAG, "%s: received a message with an invalid header=0x%x", __func__, *buf); + goto err; + } + buf++; + client->mqtt_state.in_buffer_read_len++; + } + if ((client->mqtt_state.in_buffer_read_len == 1) || + ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80))) { + do { + /* + * Read the "remaining length" part of mqtt packet fixed header. It + * starts at second byte and spans up to 4 bytes, but we accept here + * only up to 2 bytes of remaining length, i.e. messages with + * maximal remaining length value = 16383 (maximal total message + * size of 16386 bytes). + */ + read_len = esp_transport_read(t, (char *)buf, 1, read_poll_timeout_ms); + if (read_len <= 0) { + return esp_mqtt_handle_transport_read_error(read_len, client, true); + } + ESP_LOGD(TAG, "%s: read \"remaining length\" byte: 0x%x", __func__, *buf); + buf++; + client->mqtt_state.in_buffer_read_len++; + } while ((client->mqtt_state.in_buffer_read_len < 6) && (*(buf - 1) & 0x80)); + } + total_len = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len, &fixed_header_len); + ESP_LOGD(TAG, "%s: total message length: %d (already read: %"NEWLIB_NANO_COMPAT_FORMAT")", __func__, total_len, NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.in_buffer_read_len)); + client->mqtt_state.message_length = total_len; + if (client->mqtt_state.in_buffer_length < total_len) { + if (mqtt_get_type(client->mqtt_state.in_buffer) == MQTT_MSG_TYPE_PUBLISH) { + /* + * In case larger publish messages, we only need to read full topic, data can be split to multiple data event. + * Evaluate and correct total_len to read only publish message header, so data can be read separately + */ + if (client->mqtt_state.in_buffer_read_len < fixed_header_len + 2) { + /* read next 2 bytes - topic length to get minimum portion of publish packet */ + read_len = esp_transport_read(t, (char *)buf, client->mqtt_state.in_buffer_read_len - fixed_header_len + 2, read_poll_timeout_ms); + ESP_LOGD(TAG, "%s: read_len=%d", __func__, read_len); + if (read_len <= 0) { + return esp_mqtt_handle_transport_read_error(read_len, client, true); + } + client->mqtt_state.in_buffer_read_len += read_len; + buf += read_len; + if (client->mqtt_state.in_buffer_read_len < fixed_header_len + 2) { + ESP_LOGD(TAG, "%s: transport_read(): message reading left in progress :: total message length: %d (already read: %"NEWLIB_NANO_COMPAT_FORMAT")", + __func__, total_len, NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.in_buffer_read_len)); + return 0; + } + } + int topic_len = client->mqtt_state.in_buffer[fixed_header_len] << 8; + topic_len |= client->mqtt_state.in_buffer[fixed_header_len + 1]; + total_len = fixed_header_len + topic_len + (mqtt_get_qos(client->mqtt_state.in_buffer) > 0 ? 2 : 0); + ESP_LOGD(TAG, "%s: total len modified to %d as message longer than input buffer", __func__, total_len); + if (client->mqtt_state.in_buffer_length < total_len) { + ESP_LOGE(TAG, "%s: message is too big, insufficient buffer size", __func__); + goto err; + } else { + total_len = client->mqtt_state.in_buffer_length; + } + /* free to continue with reading */ + } else { + ESP_LOGE(TAG, "%s: message is too big, insufficient buffer size", __func__); + goto err; + } + } + if (client->mqtt_state.in_buffer_read_len < total_len) { + /* read the rest of the mqtt message */ + read_len = esp_transport_read(t, (char *)buf, total_len - client->mqtt_state.in_buffer_read_len, read_poll_timeout_ms); + ESP_LOGD(TAG, "%s: read_len=%d", __func__, read_len); + if (read_len <= 0) { + return esp_mqtt_handle_transport_read_error(read_len, client, true); + } + client->mqtt_state.in_buffer_read_len += read_len; + if (client->mqtt_state.in_buffer_read_len < total_len) { + ESP_LOGD(TAG, "%s: transport_read(): message reading left in progress :: total message length: %d (already read: %"NEWLIB_NANO_COMPAT_FORMAT")", + __func__, total_len, NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.in_buffer_read_len)); + return 0; + } + } + ESP_LOGV(TAG, "%s: transport_read():%"NEWLIB_NANO_COMPAT_FORMAT" %"NEWLIB_NANO_COMPAT_FORMAT, __func__, + NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.in_buffer_read_len), NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.message_length)); + return 1; +err: + esp_mqtt_client_dispatch_transport_error(client); + return -2; +} + +static esp_err_t mqtt_process_receive(esp_mqtt_client_handle_t client) +{ + uint8_t msg_type = 0, msg_qos = 0; + uint16_t msg_id = 0; + size_t previous_in_buffer_read_len = client->mqtt_state.in_buffer_read_len; + + /* non-blocking receive in order not to block other tasks */ + int recv = mqtt_message_receive(client, 0); + if (recv == 0) { // Timeout + return ESP_OK; + } + if (recv == -1) { // Mid-message timeout + if (previous_in_buffer_read_len == client->mqtt_state.in_buffer_read_len) { + // Report error only if didn't receive anything since previous iteration + ESP_LOGE(TAG, "%s: Network timeout while reading MQTT message", __func__); + return ESP_FAIL; + } + return ESP_OK; // Treat as standard timeout (keep reading the message) + } + if (recv < 0) { // Other error + ESP_LOGE(TAG, "%s: mqtt_message_receive() returned %d", __func__, recv); + return ESP_FAIL; + } + int read_len = client->mqtt_state.message_length; + + // If the message was valid, get the type, quality of service and id of the message + msg_type = mqtt_get_type(client->mqtt_state.in_buffer); + msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + msg_id = mqtt5_get_id(client->mqtt_state.in_buffer, read_len); +#endif + } else { + msg_id = mqtt_get_id(client->mqtt_state.in_buffer, read_len); + } + + ESP_LOGD(TAG, "msg_type=%d, msg_id=%d", msg_type, msg_id); + + switch (msg_type) { + case MQTT_MSG_TYPE_SUBACK: + if (remove_initiator_message(client, MQTT_MSG_TYPE_SUBSCRIBE, msg_id)) { +#ifdef MQTT_PROTOCOL_5 + esp_mqtt5_parse_suback(client); +#endif + ESP_LOGD(TAG, "deliver_suback, message_length_read=%"NEWLIB_NANO_COMPAT_FORMAT", message_length=%"NEWLIB_NANO_COMPAT_FORMAT, + NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.in_buffer_read_len), NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.message_length)); + if (deliver_suback(client) != ESP_OK) { + ESP_LOGE(TAG, "Failed to deliver suback message id=%d", msg_id); + return ESP_FAIL; + } + } + break; + case MQTT_MSG_TYPE_UNSUBACK: + if (remove_initiator_message(client, MQTT_MSG_TYPE_UNSUBSCRIBE, msg_id)) { +#ifdef MQTT_PROTOCOL_5 + esp_mqtt5_parse_unsuback(client); +#endif + ESP_LOGD(TAG, "UnSubscribe successful"); + client->event.event_id = MQTT_EVENT_UNSUBSCRIBED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PUBLISH: + ESP_LOGD(TAG, "deliver_publish, message_length_read=%"NEWLIB_NANO_COMPAT_FORMAT", message_length=%"NEWLIB_NANO_COMPAT_FORMAT, NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.in_buffer_read_len), NEWLIB_NANO_COMPAT_CAST(client->mqtt_state.message_length)); + if (deliver_publish(client) != ESP_OK) { + ESP_LOGE(TAG, "Failed to deliver publish message id=%d", msg_id); + return ESP_FAIL; + } + if (msg_qos == 1 || msg_qos == 2) { + if (msg_qos == 1) { + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + mqtt5_msg_puback(&client->mqtt_state.connection, msg_id); +#endif + } else { + mqtt_msg_puback(&client->mqtt_state.connection, msg_id); + } + } else if (msg_qos == 2) { + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + mqtt5_msg_pubrec(&client->mqtt_state.connection, msg_id); +#endif + } else { + mqtt_msg_pubrec(&client->mqtt_state.connection, msg_id); + } + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Publish response message PUBACK or PUBREC cannot be created"); + return ESP_FAIL; + } + + ESP_LOGD(TAG, "Queue response QoS: %d", msg_qos); + + if (esp_mqtt_write(client) != ESP_OK) { + ESP_LOGE(TAG, "Error write qos msg repsonse, qos = %d", msg_qos); + return ESP_FAIL; + } + } + break; + case MQTT_MSG_TYPE_PUBACK: +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + esp_mqtt5_decrement_packet_counter(client); + } +#endif + if (remove_initiator_message(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish"); +#ifdef MQTT_PROTOCOL_5 + esp_mqtt5_parse_puback(client); +#endif + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PUBREC: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREC"); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBREC return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); + mqtt5_msg_pubrel(&client->mqtt_state.connection, msg_id); +#endif + } else { + mqtt_msg_pubrel(&client->mqtt_state.connection, msg_id); + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Publish response message PUBREL cannot be created"); + return ESP_FAIL; + } + + outbox_set_pending(client->outbox, msg_id, ACKNOWLEDGED); + esp_mqtt_write(client); + break; + case MQTT_MSG_TYPE_PUBREL: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBREL"); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBREL return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); + mqtt5_msg_pubcomp(&client->mqtt_state.connection, msg_id); +#endif + } else { + mqtt_msg_pubcomp(&client->mqtt_state.connection, msg_id); + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Publish response message PUBCOMP cannot be created"); + return ESP_FAIL; + } + + esp_mqtt_write(client); + break; + case MQTT_MSG_TYPE_PUBCOMP: + ESP_LOGD(TAG, "received MQTT_MSG_TYPE_PUBCOMP"); +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + esp_mqtt5_decrement_packet_counter(client); + } +#endif + if (remove_initiator_message(client, MQTT_MSG_TYPE_PUBLISH, msg_id)) { + ESP_LOGD(TAG, "Receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish"); +#ifdef MQTT_PROTOCOL_5 + esp_mqtt5_parse_pubcomp(client); +#endif + client->event.event_id = MQTT_EVENT_PUBLISHED; + esp_mqtt_dispatch_event_with_msgid(client); + } + break; + case MQTT_MSG_TYPE_PINGRESP: + ESP_LOGD(TAG, "MQTT_MSG_TYPE_PINGRESP"); + client->wait_for_ping_resp = false; + /* It is the responsibility of the Client to ensure that the interval between Control Packets + * being sent does not exceed the Keep Alive value. In the absence of sending any other Control + * Packets, the Client MUST send a PINGREQ Packet [MQTT-3.1.2-23]. + * [MQTT-3.1.2-23] + */ + client->keepalive_tick = platform_tick_get_ms(); + break; + case MQTT_MSG_TYPE_DISCONNECT: + ESP_LOGD(TAG, "MQTT_MSG_TYPE_DISCONNECT"); +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + int disconnect_rsp_code; + esp_mqtt5_parse_disconnect(client, &disconnect_rsp_code); + client->event.event_id = MQTT_EVENT_DISCONNECTED; + client->event.error_handle->disconnect_return_code = disconnect_rsp_code; + esp_mqtt_dispatch_event_with_msgid(client); + } +#endif + break; + } + + client->mqtt_state.in_buffer_read_len = 0; + return ESP_OK; +} + +static esp_err_t mqtt_resend_queued(esp_mqtt_client_handle_t client, outbox_item_handle_t item) +{ + // decode queued data + client->mqtt_state.connection.outbound_message.data = outbox_item_get_data(item, &client->mqtt_state.connection.outbound_message.length, &client->mqtt_state.pending_msg_id, + &client->mqtt_state.pending_msg_type, &client->mqtt_state.pending_publish_qos); + // set duplicate flag for QoS-1 and QoS-2 messages + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_publish_qos > 0 && (outbox_item_get_pending(item) == TRANSMITTED)) { + mqtt_set_dup(client->mqtt_state.connection.outbound_message.data); + ESP_LOGD(TAG, "Sending Duplicated QoS%d message with id=%d", client->mqtt_state.pending_publish_qos, client->mqtt_state.pending_msg_id); + } + + // try to resend the data + if (esp_mqtt_write(client) != ESP_OK) { + ESP_LOGE(TAG, "Error to resend data "); + esp_mqtt_abort_connection(client); + return ESP_FAIL; + } + + return ESP_OK; +} + +static esp_err_t mqtt_resend_pubrel(esp_mqtt_client_handle_t client, outbox_item_handle_t item) +{ + client->mqtt_state.connection.outbound_message.data = outbox_item_get_data(item, &client->mqtt_state.connection.outbound_message.length, &client->mqtt_state.pending_msg_id, + &client->mqtt_state.pending_msg_type, &client->mqtt_state.pending_publish_qos); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + ESP_LOGI(TAG, "MQTT_MSG_TYPE_PUBREC return code is %d", mqtt5_msg_get_reason_code(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_read_len)); + mqtt5_msg_pubrel(&client->mqtt_state.connection, client->mqtt_state.pending_msg_id); +#endif + } else { + mqtt_msg_pubrel(&client->mqtt_state.connection, client->mqtt_state.pending_msg_id); + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Publish response message PUBREL cannot be created"); + return ESP_FAIL; + } + + if (esp_mqtt_write(client) != ESP_OK) { + ESP_LOGE(TAG, "Error to resend data "); + esp_mqtt_abort_connection(client); + return ESP_FAIL; + } + + return ESP_OK; +} + +static void mqtt_delete_expired_messages(esp_mqtt_client_handle_t client) +{ + // Delete message after OUTBOX_EXPIRED_TIMEOUT_MS milliseconds +#if MQTT_REPORT_DELETED_MESSAGES + // also report the deleted items as MQTT_EVENT_DELETED events if enabled + int msg_id = 0; + while ((msg_id = outbox_delete_single_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS)) >= 0) { + client->event.event_id = MQTT_EVENT_DELETED; + client->event.msg_id = msg_id; + if (esp_mqtt_dispatch_event(client) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post event on deleting message id=%d", msg_id); + } + } +#else + outbox_delete_expired(client->outbox, platform_tick_get_ms(), OUTBOX_EXPIRED_TIMEOUT_MS); +#endif +} + +/** + * @brief When using multiple queued item, we'd like to reduce the poll timeout to proceed with event loop exacution + */ +static inline int max_poll_timeout(esp_mqtt_client_handle_t client, int max_timeout) +{ + return +#if MQTT_EVENT_QUEUE_SIZE > 1 + atomic_load(&client->queued_events) > 0 ? 10 : max_timeout; +#else + max_timeout; +#endif +} + +static inline void run_event_loop(esp_mqtt_client_handle_t client) +{ +#if MQTT_EVENT_QUEUE_SIZE > 1 + if (atomic_load(&client->queued_events) > 0) { + atomic_fetch_sub(&client->queued_events, 1); +#else + { +#endif + esp_err_t ret = esp_event_loop_run(client->config->event_loop_handle, 0); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error in running event_loop %d", ret); + } + } +} + +static void esp_mqtt_task(void *pv) +{ + esp_mqtt_client_handle_t client = (esp_mqtt_client_handle_t) pv; + uint64_t last_retransmit = 0; + outbox_tick_t msg_tick = 0; + client->run = true; + + client->state = MQTT_STATE_INIT; + xEventGroupClearBits(client->status_bits, STOPPED_BIT); + while (client->run) { + MQTT_API_LOCK(client); + run_event_loop(client); + // delete long pending messages + mqtt_delete_expired_messages(client); + mqtt_client_state_t state = client->state; + switch (state) { + case MQTT_STATE_DISCONNECTED: + break; + case MQTT_STATE_INIT: + xEventGroupClearBits(client->status_bits, RECONNECT_BIT | DISCONNECT_BIT); + + client->transport = client->config->transport; + if (!client->transport) { + + if (esp_mqtt_client_create_transport(client) != ESP_OK) { + ESP_LOGE(TAG, "Failed to create transport list"); + client->run = false; + break; + } + //get transport by scheme + client->transport = esp_transport_list_get_transport(client->transport_list, client->config->scheme); + + if (client->transport == NULL) { + ESP_LOGE(TAG, "There are no transports valid, stop mqtt client, config scheme = %s", client->config->scheme); + client->run = false; + break; + } + } + //default port + if (client->config->port == 0) { + client->config->port = esp_transport_get_default_port(client->transport); + } + +#if MQTT_ENABLE_SSL + esp_mqtt_set_ssl_transport_properties(client->transport_list, client->config); +#endif + + if(client->config->tcp_keep_alive_cfg.keep_alive_enable) { + esp_transport_tcp_set_keep_alive(client->transport, &client->config->tcp_keep_alive_cfg); + } + + client->event.event_id = MQTT_EVENT_BEFORE_CONNECT; + esp_mqtt_dispatch_event_with_msgid(client); + + if (esp_transport_connect(client->transport, + client->config->host, + client->config->port, + client->config->network_timeout_ms) < 0) { + ESP_LOGE(TAG, "Error transport connect"); + esp_mqtt_client_dispatch_transport_error(client); + esp_mqtt_abort_connection(client); + break; + } + ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); + if (esp_mqtt_connect(client, client->config->network_timeout_ms) != ESP_OK) { + ESP_LOGE(TAG, "MQTT connect failed"); + esp_mqtt_abort_connection(client); + break; + } + client->event.event_id = MQTT_EVENT_CONNECTED; + if (client->mqtt_state.connection.information.protocol_ver != MQTT_PROTOCOL_V_5) { + client->event.session_present = mqtt_get_connect_session_present(client->mqtt_state.in_buffer); + } + client->state = MQTT_STATE_CONNECTED; + esp_mqtt_dispatch_event_with_msgid(client); + client->refresh_connection_tick = platform_tick_get_ms(); + client->keepalive_tick = platform_tick_get_ms(); + + break; + case MQTT_STATE_CONNECTED: + // check for disconnection request + if (xEventGroupWaitBits(client->status_bits, DISCONNECT_BIT, true, true, 0) & DISCONNECT_BIT) { + send_disconnect_msg(client); // ignore error, if clean disconnect fails, just abort the connection + esp_mqtt_abort_connection(client); + break; + } + // receive and process data + if (mqtt_process_receive(client) == ESP_FAIL) { + esp_mqtt_abort_connection(client); + break; + } + + if (last_retransmit == 0) { + // connected for first time, set last_retransmit to now, avoid retransmit + last_retransmit = platform_tick_get_ms(); + } + + + // resend all non-transmitted messages first + outbox_item_handle_t item = outbox_dequeue(client->outbox, QUEUED, NULL); + if (item) { + if (mqtt_resend_queued(client, item) == ESP_OK) { + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_publish_qos == 0) { + // delete all qos0 publish messages once we process them + if (outbox_delete_item(client->outbox, item) != ESP_OK) { + ESP_LOGE(TAG, "Failed to remove queued qos0 message from the outbox"); + } + } + if (client->mqtt_state.pending_publish_qos > 0) { + outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + esp_mqtt5_increment_packet_counter(client); + } +#endif + } + } + // resend other "transmitted" messages after 1s + } else if (has_timed_out(last_retransmit, client->config->message_retransmit_timeout)) { + last_retransmit = platform_tick_get_ms(); + item = outbox_dequeue(client->outbox, TRANSMITTED, &msg_tick); + if (item && (last_retransmit - msg_tick > client->config->message_retransmit_timeout)) { + if (mqtt_resend_queued(client, item) == ESP_OK) { +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + esp_mqtt5_increment_packet_counter(client); + } +#endif + } + } + item = outbox_dequeue(client->outbox, ACKNOWLEDGED, &msg_tick); + if (item && (last_retransmit - msg_tick > client->config->message_retransmit_timeout)) { + if (mqtt_resend_pubrel(client, item) == ESP_OK) { +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + esp_mqtt5_increment_packet_counter(client); + } +#endif + } + } + } + + if (process_keepalive(client) != ESP_OK) { + break; + } + + if (client->config->refresh_connection_after_ms && + has_timed_out(client->refresh_connection_tick, client->config->refresh_connection_after_ms)) { + ESP_LOGD(TAG, "Refreshing the connection..."); + esp_mqtt_abort_connection(client); + client->state = MQTT_STATE_INIT; + } + + break; + case MQTT_STATE_WAIT_RECONNECT: + + if (!client->config->auto_reconnect && xEventGroupGetBits(client->status_bits)&RECONNECT_BIT) { + xEventGroupClearBits(client->status_bits, RECONNECT_BIT); + client->state = MQTT_STATE_INIT; + client->wait_timeout_ms = MQTT_RECON_DEFAULT_MS; + ESP_LOGD(TAG, "Reconnecting per user request..."); + break; + } else if (client->config->auto_reconnect && + platform_tick_get_ms() - client->reconnect_tick > client->wait_timeout_ms) { + client->state = MQTT_STATE_INIT; + client->reconnect_tick = platform_tick_get_ms(); + ESP_LOGD(TAG, "Reconnecting..."); + break; + } + MQTT_API_UNLOCK(client); + xEventGroupWaitBits(client->status_bits, RECONNECT_BIT, false, true, + max_poll_timeout(client, client->wait_timeout_ms / 2 / portTICK_PERIOD_MS)); + // continue the while loop instead of break, as the mutex is unlocked + continue; + default: + ESP_LOGE(TAG, "MQTT client error, client is in an unrecoverable state."); + break; + } + MQTT_API_UNLOCK(client); + if (MQTT_STATE_CONNECTED == client->state) { + if (esp_transport_poll_read(client->transport, max_poll_timeout(client, MQTT_POLL_READ_TIMEOUT_MS)) < 0) { + ESP_LOGE(TAG, "Poll read error: %d, aborting connection", errno); + esp_mqtt_abort_connection(client); + } + } + + } + esp_transport_close(client->transport); + outbox_delete_all_items(client->outbox); + client->state = MQTT_STATE_DISCONNECTED; + xEventGroupSetBits(client->status_bits, STOPPED_BIT); + + vTaskDelete(NULL); +} + +esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + MQTT_API_LOCK(client); + if (client->state != MQTT_STATE_INIT && client->state != MQTT_STATE_DISCONNECTED) { + ESP_LOGE(TAG, "Client has started"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } + esp_err_t err = ESP_OK; +#if MQTT_CORE_SELECTION_ENABLED + ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE); + if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle, MQTT_TASK_CORE) != pdTRUE) { + ESP_LOGE(TAG, "Error create mqtt task"); + err = ESP_FAIL; + } +#else + ESP_LOGD(TAG, "Core selection disabled"); + if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) { + ESP_LOGE(TAG, "Error create mqtt task"); + err = ESP_FAIL; + } +#endif + MQTT_API_UNLOCK(client); + return err; +} + +esp_err_t esp_mqtt_client_disconnect(esp_mqtt_client_handle_t client) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + ESP_LOGI(TAG, "Client asked to disconnect"); + xEventGroupSetBits(client->status_bits, DISCONNECT_BIT); + return ESP_OK; +} + +esp_err_t esp_mqtt_client_reconnect(esp_mqtt_client_handle_t client) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + ESP_LOGI(TAG, "Client force reconnect requested"); + if (client->state != MQTT_STATE_WAIT_RECONNECT) { + ESP_LOGD(TAG, "The client is not waiting for reconnection. Ignore the request"); + return ESP_FAIL; + } + client->wait_timeout_ms = 0; + xEventGroupSetBits(client->status_bits, RECONNECT_BIT); + return ESP_OK; +} + +static esp_err_t send_disconnect_msg(esp_mqtt_client_handle_t client) +{ + // Notify the broker we are disconnecting + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + mqtt5_msg_disconnect(&client->mqtt_state.connection, &client->mqtt5_config->disconnect_property_info); + if (client->mqtt_state.connection.outbound_message.length) { + esp_mqtt5_client_delete_user_property(client->mqtt5_config->disconnect_property_info.user_property); + client->mqtt5_config->disconnect_property_info.user_property = NULL; + memset(&client->mqtt5_config->disconnect_property_info, 0, sizeof(esp_mqtt5_disconnect_property_config_t)); + } +#endif + } else { + mqtt_msg_disconnect(&client->mqtt_state.connection); + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Disconnect message cannot be created"); + return ESP_FAIL; + } + if (esp_mqtt_write(client) != ESP_OK) { + ESP_LOGE(TAG, "Error sending disconnect message"); + } + return ESP_OK; +} + +esp_err_t esp_mqtt_client_stop(esp_mqtt_client_handle_t client) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return ESP_ERR_INVALID_ARG; + } + MQTT_API_LOCK(client); + if (client->run) { + /* A running client cannot be stopped from the MQTT task/event handler */ + TaskHandle_t running_task = xTaskGetCurrentTaskHandle(); + if (running_task == client->task_handle) { + MQTT_API_UNLOCK(client); + ESP_LOGE(TAG, "Client cannot be stopped from MQTT task"); + return ESP_FAIL; + } + + // Only send the disconnect message if the client is connected + if (client->state == MQTT_STATE_CONNECTED) { + send_disconnect_msg(client); + } + + client->run = false; + client->state = MQTT_STATE_DISCONNECTED; + MQTT_API_UNLOCK(client); + xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); + return ESP_OK; + } else { + ESP_LOGW(TAG, "Client asked to stop, but was not started"); + MQTT_API_UNLOCK(client); + return ESP_FAIL; + } +} + +static esp_err_t esp_mqtt_client_ping(esp_mqtt_client_handle_t client) +{ + mqtt_msg_pingreq(&client->mqtt_state.connection); + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Ping message cannot be created"); + return ESP_FAIL; + } + + if (esp_mqtt_write(client) != ESP_OK) { + ESP_LOGE(TAG, "Error sending ping"); + return ESP_FAIL; + } + ESP_LOGD(TAG, "Sent PING successful"); + return ESP_OK; +} + +int esp_mqtt_client_subscribe_multiple(esp_mqtt_client_handle_t client, + const esp_mqtt_topic_t *topic_list, int size) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return -1; + } + + if (client->config->outbox_limit > 0 && outbox_get_size(client->outbox) > client->config->outbox_limit) { + return -2; + } + + if (client->state != MQTT_STATE_CONNECTED) { + ESP_LOGE(TAG, "Client has not connected"); + return -1; + } + + MQTT_API_LOCK(client); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + int max_qos = topic_list[0].qos; + for (int topic_number = 0; topic_number < size; ++topic_number) { + if (topic_list[topic_number].qos > max_qos) { + max_qos = topic_list[topic_number].qos; + } + } + if (esp_mqtt5_client_subscribe_check(client, max_qos) != ESP_OK) { + ESP_LOGI(TAG, "MQTT5 subscribe check fail: QoS %d not accepted by broker ", max_qos); + MQTT_API_UNLOCK(client); + return -1; + } + mqtt5_msg_subscribe(&client->mqtt_state.connection, + topic_list, size, + &client->mqtt_state.pending_msg_id, client->mqtt5_config->subscribe_property_info); + if (client->mqtt_state.connection.outbound_message.length) { + client->mqtt5_config->subscribe_property_info = NULL; + } +#endif + } else { + mqtt_msg_subscribe(&client->mqtt_state.connection, + topic_list, size, + &client->mqtt_state.pending_msg_id); + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Subscribe message cannot be created"); + MQTT_API_UNLOCK(client); + return -1; + } + + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.connection.outbound_message.data); + //move pending msg to outbox (if have) + if (!mqtt_enqueue(client, NULL, 0)) { + MQTT_API_UNLOCK(client); + return -1; + } + outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED);// handle error + + if (esp_mqtt_write(client) != ESP_OK) { + ESP_LOGE(TAG, "Error to send subscribe message, first topic: %s, qos: %d", topic_list[0].filter, topic_list[0].qos); + MQTT_API_UNLOCK(client); + return -1; + } + + ESP_LOGD(TAG, "Sent subscribe, first topic=%s, id: %d", topic_list[0].filter, client->mqtt_state.pending_msg_id); + + int pending_msg_id = client->mqtt_state.pending_msg_id; + MQTT_API_UNLOCK(client); + return pending_msg_id; + +} +int esp_mqtt_client_subscribe_single(esp_mqtt_client_handle_t client, const char *topic, int qos) +{ + esp_mqtt_topic_t user_topic = {.filter = topic, .qos = qos}; + return esp_mqtt_client_subscribe_multiple(client, &user_topic, 1); +} + +int esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return -1; + } + if (client->state != MQTT_STATE_CONNECTED) { + ESP_LOGE(TAG, "Client has not connected"); + return -1; + } + MQTT_API_LOCK(client); + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + mqtt5_msg_unsubscribe(&client->mqtt_state.connection, + topic, + &client->mqtt_state.pending_msg_id, client->mqtt5_config->unsubscribe_property_info); + if (client->mqtt_state.connection.outbound_message.length) { + client->mqtt5_config->unsubscribe_property_info = NULL; + } +#endif + } else { + mqtt_msg_unsubscribe(&client->mqtt_state.connection, + topic, + &client->mqtt_state.pending_msg_id); + } + if (client->mqtt_state.connection.outbound_message.length == 0) { + MQTT_API_UNLOCK(client); + ESP_LOGE(TAG, "Unubscribe message cannot be created"); + return -1; + } + ESP_LOGD(TAG, "unsubscribe, topic\"%s\", id: %d", topic, client->mqtt_state.pending_msg_id); + + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.connection.outbound_message.data); + if (!mqtt_enqueue(client, NULL, 0)) { + MQTT_API_UNLOCK(client); + return -1; + } + outbox_set_pending(client->outbox, client->mqtt_state.pending_msg_id, TRANSMITTED); //handle error + + if (esp_mqtt_write(client) != ESP_OK) { + ESP_LOGE(TAG, "Error to unsubscribe topic=%s", topic); + MQTT_API_UNLOCK(client); + return -1; + } + + ESP_LOGD(TAG, "Sent Unsubscribe topic=%s, id: %d, successful", topic, client->mqtt_state.pending_msg_id); + + int pending_msg_id = client->mqtt_state.pending_msg_id; + MQTT_API_UNLOCK(client); + return pending_msg_id; +} + +static int make_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, + int len, int qos, int retain) +{ + uint16_t pending_msg_id = 0; + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { +#ifdef MQTT_PROTOCOL_5 + mqtt5_msg_publish(&client->mqtt_state.connection, + topic, data, len, + qos, retain, + &pending_msg_id, client->mqtt5_config->publish_property_info, client->mqtt5_config->server_resp_property_info.response_info); + if (client->mqtt_state.connection.outbound_message.length) { + client->mqtt5_config->publish_property_info = NULL; + } +#endif + } else { + mqtt_msg_publish(&client->mqtt_state.connection, + topic, data, len, + qos, retain, + &pending_msg_id); + } + + if (client->mqtt_state.connection.outbound_message.length == 0) { + ESP_LOGE(TAG, "Publish message cannot be created"); + return -1; + } + return pending_msg_id; +} +static inline int mqtt_client_enqueue_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, + int len, int qos, int retain, bool store) +{ + int pending_msg_id = make_publish(client, topic, data, len, qos, retain); + if (pending_msg_id < 0) { + return -1; + } + /* We have to set as pending all the qos>0 messages */ + //TODO: client->mqtt_state.outbound_message = publish_msg; + if (qos > 0 || store) { + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.connection.outbound_message.data); + client->mqtt_state.pending_msg_id = pending_msg_id; + client->mqtt_state.pending_publish_qos = qos; + // by default store as QUEUED (not transmitted yet) only for messages which would fit outbound buffer + if (client->mqtt_state.connection.outbound_message.fragmented_msg_total_length == 0) { + if (!mqtt_enqueue(client, NULL, 0)) { + return -1; + } + } else { + int first_fragment = client->mqtt_state.connection.outbound_message.length - client->mqtt_state.connection.outbound_message.fragmented_msg_data_offset; + if (!mqtt_enqueue(client, ((uint8_t *)data) + first_fragment, len - first_fragment)) { + return -1; + } + client->mqtt_state.connection.outbound_message.fragmented_msg_total_length = 0; + } + } + return pending_msg_id; +} + +int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return -1; + } +#if MQTT_SKIP_PUBLISH_IF_DISCONNECTED + if (client->state != MQTT_STATE_CONNECTED) { + ESP_LOGI(TAG, "Publishing skipped: client is not connected"); + return -1; + } +#endif + +MQTT_API_LOCK(client); +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + if (esp_mqtt5_client_publish_check(client, qos, retain) != ESP_OK) { + ESP_LOGI(TAG, "MQTT5 publish check fail"); + MQTT_API_UNLOCK(client); + return -1; + } + } +#endif + + /* Acceptable publish messages: + data == NULL, len == 0: publish null message + data valid, len == 0: publish all data, payload len is determined from string length + data valid, len > 0: publish data with defined length + */ + if (len <= 0 && data != NULL) { + len = strlen(data); + } + + if (client->config->outbox_limit > 0 && qos > 0) { + if (len + outbox_get_size(client->outbox) > client->config->outbox_limit) { + MQTT_API_UNLOCK(client); + return -2; + } + } + + int pending_msg_id = mqtt_client_enqueue_publish(client, topic, data, len, qos, retain, false); + if (pending_msg_id < 0) { + MQTT_API_UNLOCK(client); + return -1; + } + int ret = 0; + + /* Skip sending if not connected (rely on resending) */ + if (client->state != MQTT_STATE_CONNECTED) { + ESP_LOGD(TAG, "Publish: client is not connected"); + if (qos > 0) { + ret = pending_msg_id; + } else { + ret = -1; + } + + goto cannot_publish; + } + + /* Provide support for sending fragmented message if it doesn't fit buffer */ + int remaining_len = len; + const char *current_data = data; + bool sending = true; + + while (sending) { + + if (esp_mqtt_write(client) != ESP_OK) { + esp_mqtt_abort_connection(client); + ret = -1; + goto cannot_publish; + } + + int data_sent = client->mqtt_state.connection.outbound_message.length - client->mqtt_state.connection.outbound_message.fragmented_msg_data_offset; + client->mqtt_state.connection.outbound_message.fragmented_msg_data_offset = 0; + client->mqtt_state.connection.outbound_message.fragmented_msg_total_length = 0; + remaining_len -= data_sent; + current_data += data_sent; + + if (remaining_len > 0) { + mqtt_connection_t *connection = &client->mqtt_state.connection; + ESP_LOGD(TAG, "Sending fragmented message, remains to send %d bytes of %d", remaining_len, len); + int write_len = remaining_len > connection->buffer_length ? connection->buffer_length : remaining_len; + memcpy(connection->buffer, current_data, write_len); + connection->outbound_message.data = connection->buffer; + connection->outbound_message.length = write_len; + sending = true; + } else { + // Message was sent correctly + sending = false; + } + } + + if (qos > 0) { +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + esp_mqtt5_increment_packet_counter(client); + } +#endif + //Tick is set after transmit to avoid retransmitting too early due slow network speed / big messages + outbox_set_tick(client->outbox, pending_msg_id, platform_tick_get_ms()); + outbox_set_pending(client->outbox, pending_msg_id, TRANSMITTED); + } + MQTT_API_UNLOCK(client); + return pending_msg_id; + +cannot_publish: + // clear out possible fragmented publish if failed or skipped + client->mqtt_state.connection.outbound_message.fragmented_msg_total_length = 0; + if (qos == 0) { + ESP_LOGW(TAG, "Publish: Losing qos0 data when client not connected"); + } + MQTT_API_UNLOCK(client); + + return ret; +} + +int esp_mqtt_client_enqueue(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain, bool store) +{ + if (!client) { + ESP_LOGE(TAG, "Client was not initialized"); + return -1; + } + + /* Acceptable publish messages: + data == NULL, len == 0: publish null message + data valid, len == 0: publish all data, payload len is determined from string length + data valid, len > 0: publish data with defined length + */ + if (len <= 0 && data != NULL) { + len = strlen(data); + } + + if (client->config->outbox_limit > 0) { + if (len + outbox_get_size(client->outbox) > client->config->outbox_limit) { + return -2; + } + + } + + MQTT_API_LOCK(client); +#ifdef MQTT_PROTOCOL_5 + if (client->mqtt_state.connection.information.protocol_ver == MQTT_PROTOCOL_V_5) { + if (esp_mqtt5_client_publish_check(client, qos, retain) != ESP_OK) { + ESP_LOGI(TAG, "esp_mqtt_client_enqueue check fail"); + MQTT_API_UNLOCK(client); + return -1; + } + } +#endif + int ret = mqtt_client_enqueue_publish(client, topic, data, len, qos, retain, store); + MQTT_API_UNLOCK(client); + if (ret == 0 && store == false) { + // messages with qos=0 are not enqueued if not overridden by store_in_outobx -> indicate as error + return -1; + } + return ret; +} + +esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler, void *event_handler_arg) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP + + return esp_event_handler_register_with(client->config->event_loop_handle, MQTT_EVENTS, event, event_handler, event_handler_arg); +#else + ESP_LOGE(TAG, "Registering event handler while event loop not available in IDF version %s", IDF_VER); + return ESP_FAIL; +#endif +} + +esp_err_t esp_mqtt_client_unregister_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } +#ifdef MQTT_SUPPORTED_FEATURE_EVENT_LOOP + + return esp_event_handler_unregister_with(client->config->event_loop_handle, MQTT_EVENTS, event, event_handler); +#else + ESP_LOGE(TAG, "Unregistering event handler while event loop not available in IDF version %s", IDF_VER); + return ESP_FAIL; +#endif +} + +static void esp_mqtt_client_dispatch_transport_error(esp_mqtt_client_handle_t client) +{ + client->event.event_id = MQTT_EVENT_ERROR; + client->event.error_handle->error_type = MQTT_ERROR_TYPE_TCP_TRANSPORT; + client->event.error_handle->connect_return_code = 0; +#ifdef MQTT_PROTOCOL_5 + client->event.error_handle->disconnect_return_code = 0; +#endif +#ifdef MQTT_SUPPORTED_FEATURE_TRANSPORT_ERR_REPORTING + client->event.error_handle->esp_tls_last_esp_err = esp_tls_get_and_clear_last_error(esp_transport_get_error_handle(client->transport), + &client->event.error_handle->esp_tls_stack_err, + &client->event.error_handle->esp_tls_cert_verify_flags); +#ifdef MQTT_SUPPORTED_FEATURE_TRANSPORT_SOCK_ERRNO_REPORTING + client->event.error_handle->esp_transport_sock_errno = esp_transport_get_errno(client->transport); +#endif +#endif + esp_mqtt_dispatch_event_with_msgid(client); +} + +int esp_mqtt_client_get_outbox_size(esp_mqtt_client_handle_t client) +{ + int outbox_size = 0; + + if (client == NULL) { + return 0; + } + + MQTT_API_LOCK(client); + + if (client->outbox) { + outbox_size = outbox_get_size(client->outbox); + } + + MQTT_API_UNLOCK(client); + + return outbox_size; +} + +esp_transport_handle_t esp_mqtt_client_get_transport(esp_mqtt_client_handle_t client, char *transport_scheme){ + if (client == NULL || (transport_scheme == NULL && client->config->transport == NULL)) { + return NULL; + } + if (transport_scheme == NULL && client->config->transport != NULL) { + return client->config->transport; + } + return esp_transport_list_get_transport(client->transport_list, transport_scheme); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/pytest.ini b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/pytest.ini new file mode 100644 index 000000000..3bbea5355 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/pytest.ini @@ -0,0 +1,28 @@ +[pytest] +python_files = pytest_*.py +addopts = + --embedded-services esp,idf + --ignore-no-tests-collected-error + --ignore-glob */managed_components/* + --ignore=examples/ssl + --ignore=examples/wss + --junitxml=junit.xml + --ignore-result-files .gitlab/ignored_cases.txt + --root-logdir=test_logs + +filterwarnings = + ignore::FutureWarning + +junit_family = xunit1 + +env_markers = + eth_ip101: Ethernet IP101 PHY required for test + eth_ip101_stress: Ethernet IP101 PHY required for stress test + generic: applicable to generic ESP devices + +# log related +log_cli = True +log_cli_level = INFO +log_cli_format = %(asctime)s %(levelname)s %(message)s +log_cli_date_format = %Y-%m-%d %H:%M:%S + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/static-analysis-rules.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/static-analysis-rules.yml new file mode 100644 index 000000000..bd36de885 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/static-analysis-rules.yml @@ -0,0 +1,9 @@ +limits: + "clang-analyzer-core.NullDereference" : 0 + "clang-analyzer-unix.Malloc" : 0 + +ignore: + - "llvm-header-guard" + - "llvm-include-order" + +skip: diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/CMakeLists.txt new file mode 100644 index 000000000..97ab3b53b --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/include/test_mqtt_connection.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/include/test_mqtt_connection.h new file mode 100644 index 000000000..460beccfe --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/include/test_mqtt_connection.h @@ -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); diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/test_mqtt_connection.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/test_mqtt_connection.c new file mode 100644 index 000000000..a6cb70210 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/common/test_mqtt_connection.c @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/CMakeLists.txt new file mode 100644 index 000000000..8a681178a --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/CMakeLists.txt @@ -0,0 +1,16 @@ +#This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS "../common") + +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.5") + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/test_apps/components") +else() + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +endif() + + +idf_build_set_property(MINIMAL_BUILD ON) +project(esp_mqtt_client_test) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/README.md new file mode 100644 index 000000000..1fb88efd1 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C3 | +| ----------------- | ----- | -------- | diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/CMakeLists.txt new file mode 100644 index 000000000..0647fe29f --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/CMakeLists.txt @@ -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) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/Kconfig.projbuild new file mode 100644 index 000000000..30b2c1087 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/idf_component.yml new file mode 100644 index 000000000..30ca4eed7 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/mqtt: + version: "*" + override_path: "../../../.." + diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt.c new file mode 100644 index 000000000..cb56a5e06 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt.c @@ -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 +#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; iqos; + 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; +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt_client_broker.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt_client_broker.h new file mode 100644 index 000000000..63e7856f7 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/main/test_mqtt_client_broker.h @@ -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); diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/pytest_mqtt_ut.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/pytest_mqtt_ut.py new file mode 100644 index 000000000..429b85747 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/pytest_mqtt_ut.py @@ -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() diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.ci.default b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.ci.default new file mode 100644 index 000000000..1d40815a9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.ci.default @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.defaults b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.defaults new file mode 100644 index 000000000..2bcae3f3b --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt/sdkconfig.defaults @@ -0,0 +1,3 @@ +# General options for additional checks +CONFIG_ESP_TASK_WDT_EN=n +CONFIG_UNITY_ENABLE_FIXTURE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/CMakeLists.txt new file mode 100644 index 000000000..6b8e1e8dd --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/CMakeLists.txt @@ -0,0 +1,16 @@ +#This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS "../common") + +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.5") + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/test_apps/components") +else() + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +endif() + + +idf_build_set_property(MINIMAL_BUILD ON) +project(esp_mqtt5_client_test) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/README.md new file mode 100644 index 000000000..1fb88efd1 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C3 | +| ----------------- | ----- | -------- | diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/CMakeLists.txt new file mode 100644 index 000000000..d33a86ceb --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs test_mqtt5_client_broker.c test_mqtt5.c) + +idf_component_register(SRCS "${srcs}" + PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/Kconfig.projbuild b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/Kconfig.projbuild new file mode 100644 index 000000000..30b2c1087 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/Kconfig.projbuild @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/idf_component.yml b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/idf_component.yml new file mode 100644 index 000000000..1b39baac9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/idf_component.yml @@ -0,0 +1,4 @@ +dependencies: + espressif/mqtt: + version: "*" + override_path: "../../../.." \ No newline at end of file diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5.c new file mode 100644 index 000000000..9d8705d83 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5.c @@ -0,0 +1,172 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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_mqtt5_client_broker.h" +#include "test_mqtt_connection.h" +#include "esp_partition.h" + + +TEST_GROUP(mqtt5); + +TEST_SETUP(mqtt5) +{ + 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(mqtt5) +{ + 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)); +} + +static esp_mqtt5_user_property_item_t user_property_arr[3] = { + {"board", "esp32"}, + {"u", "user"}, + {"p", "password"} +}; + +TEST(mqtt5, init_with_invalid_url) +{ + const esp_mqtt_client_config_t mqtt5_cfg = { + .broker.address.uri = "INVALID", + .session.protocol_ver = MQTT_PROTOCOL_V_5, + }; + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg); + TEST_ASSERT_EQUAL(NULL, client ); +} + +TEST(mqtt5, init_and_deinit) +{ + const esp_mqtt_client_config_t mqtt5_cfg = { + // no connection takes place, but the uri has to be valid for init() to succeed + .broker.address.uri = "mqtts://localhost:8883", + .session.protocol_ver = MQTT_PROTOCOL_V_5, + .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, + }; + 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, + .content_type = "json", + .response_topic = "/test/response", + .correlation_data = "123456", + .correlation_data_len = 6, + }; + + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg); + esp_mqtt5_client_set_user_property(&connect_property.user_property, user_property_arr, 3); + esp_mqtt5_client_set_user_property(&connect_property.will_user_property, user_property_arr, 3); + esp_mqtt5_client_set_connect_property(client, &connect_property); + esp_mqtt5_client_delete_user_property(connect_property.user_property); + esp_mqtt5_client_delete_user_property(connect_property.will_user_property); + 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(mqtt5, 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 mqtt5_cfg = { + // no connection takes place, but the uri has to be valid for init() to succeed + .broker.address.uri = "mqtts://localhost:8883", + .session.protocol_ver = MQTT_PROTOCOL_V_5, + }; + 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, + .content_type = "json", + }; + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg); + TEST_ASSERT_NOT_EQUAL(NULL, client ); + int bytes_before = esp_get_free_heap_size(); + for (int i = 0; i < messages; i ++) { + esp_mqtt5_client_set_user_property(&publish_property.user_property, user_property_arr, 3); + esp_mqtt5_client_set_publish_property(client, &publish_property); + esp_mqtt_client_publish(client, "test", bin_addr, size, 1, 0); + esp_mqtt5_client_delete_user_property(publish_property.user_property); + publish_property.user_property = NULL; + } + 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(mqtt5, broker_tests) +{ + test_case_uses_tcpip(); + connect_test_fixture_setup(); + + RUN_MQTT5_BROKER_TEST(mqtt5_connect_disconnect); + RUN_MQTT5_BROKER_TEST(mqtt5_subscribe_publish); + RUN_MQTT5_BROKER_TEST(mqtt5_lwt_clean_disconnect); + RUN_MQTT5_BROKER_TEST(mqtt5_subscribe_payload); + + connect_test_fixture_teardown(); +} +#endif // SOC_EMAC_SUPPORTED + +TEST_GROUP_RUNNER(mqtt5) +{ +#if !DISABLED_FOR_TARGETS(ESP32H2) + RUN_TEST_CASE(mqtt5, init_with_invalid_url); + RUN_TEST_CASE(mqtt5, init_and_deinit); + RUN_TEST_CASE(mqtt5, enqueue_and_destroy_outbox); + +#if SOC_EMAC_SUPPORTED + RUN_TEST_CASE(mqtt5, broker_tests); +#endif // SOC_EMAC_SUPPORTED +#endif //!DISABLED_FOR_TARGETS(ESP32H2) +} + + +void app_main(void) +{ + UNITY_MAIN(mqtt5); +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.c b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.c new file mode 100644 index 000000000..0ac4c3dd0 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.c @@ -0,0 +1,285 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 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_mqtt5_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 esp_mqtt5_user_property_item_t user_property_arr[3] = { + {"board", "esp32"}, + {"u", "user"}, + {"p", "password"} +}; + +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 mqtt5_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 mqtt5_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("mqtt5-lwt", "count=%d", *count); + } + } +} + +static void mqtt5_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("mqtt5-subscribe", "MQTT_EVENT_SUBSCRIBED, data size=%d", event->data_len); + int * sub_payload = handler_args; + if (event->data_len == 1) { + ESP_LOGI("mqtt5-subscribe", "DATA=%d", *(uint8_t*)event->data); + *sub_payload = *(uint8_t*)event->data; + } + xEventGroupSetBits(s_event_group, DATA_BIT); + } +} + + +static void mqtt5_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 mqtt5_connect_disconnect(void) +{ + const esp_mqtt_client_config_t mqtt5_cfg = { + .broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI, + .network.disable_auto_reconnect = true, + .session.protocol_ver = MQTT_PROTOCOL_V_5, + }; + 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, + }; + esp_mqtt5_disconnect_property_config_t disconnect_property = { + .session_expiry_interval = 10, + .disconnect_reason = 0, + }; + s_event_group = xEventGroupCreate(); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg); + TEST_ASSERT_TRUE(NULL != client ); + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_user_property(&connect_property.user_property, user_property_arr, 3)); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_connect_property(client, &connect_property)); + esp_mqtt5_client_delete_user_property(connect_property.user_property); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client)); + WAIT_FOR_EVENT(CONNECT_BIT); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_user_property(&disconnect_property.user_property, user_property_arr, 3)); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_disconnect_property(client, &disconnect_property)); + esp_mqtt5_client_delete_user_property(disconnect_property.user_property); + 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 mqtt5_subscribe_publish(void) +{ + const esp_mqtt_client_config_t mqtt5_cfg = { + .broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI, + .session.protocol_ver = MQTT_PROTOCOL_V_5, + }; + esp_mqtt5_publish_property_config_t publish_property = { + .payload_format_indicator = 1, + .message_expiry_interval = 1000, + .topic_alias = 1, + .response_topic = "/topic/test/response", + .correlation_data = "123456", + .correlation_data_len = 6, + .content_type = "json", + }; + esp_mqtt5_subscribe_property_config_t subscribe_property = { + .subscribe_id = 25555, + .no_local_flag = false, + .retain_as_published_flag = true, + .retain_handle = 0, + }; + char* topic = append_mac("topic"); + TEST_ASSERT_TRUE(NULL != topic); + s_event_group = xEventGroupCreate(); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg); + TEST_ASSERT_TRUE(NULL != client ); + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_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, mqtt5_data_handler_qos, &qos); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_subscribe_property(client, &subscribe_property)); + TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 2) != -1); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_publish_property(client, &publish_property)); + 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 mqtt5_lwt_clean_disconnect(void) +{ + char* lwt = append_mac("lwt"); + TEST_ASSERT_TRUE(lwt); + const esp_mqtt_client_config_t mqtt5_cfg1 = { + .broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI, + .credentials.set_null_client_id = true, + .session.last_will.topic = lwt, + .session.last_will.msg = "lwt_msg", + .session.protocol_ver = MQTT_PROTOCOL_V_5, + }; + const esp_mqtt_client_config_t mqtt5_cfg2 = { + .broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI, + .credentials.set_null_client_id = true, + .session.last_will.topic = lwt, + .session.last_will.msg = "lwt_msg", + .session.protocol_ver = MQTT_PROTOCOL_V_5, + }; + esp_mqtt5_connection_property_config_t connect_property = { + .will_delay_interval = 10, + .payload_format_indicator = true, + .message_expiry_interval = 10, + .content_type = "json", + .response_topic = "/test/response", + .correlation_data = "123456", + .correlation_data_len = 6, + }; + s_event_group = xEventGroupCreate(); + + esp_mqtt_client_handle_t client1 = esp_mqtt_client_init(&mqtt5_cfg1); + esp_mqtt_client_handle_t client2 = esp_mqtt_client_init(&mqtt5_cfg2); + TEST_ASSERT_TRUE(NULL != client1 && NULL != client2 ); + esp_mqtt_client_register_event(client1, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL); + esp_mqtt_client_register_event(client2, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_connect_property(client1, &connect_property)); + TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_connect_property(client2, &connect_property)); + 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, mqtt5_data_handler_lwt, &counter); + esp_mqtt_client_register_event(client2, MQTT_EVENT_DATA, mqtt5_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 mqtt5_subscribe_payload(void) +{ + const esp_mqtt_client_config_t mqtt5_cfg = { + .broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI, + .network.disable_auto_reconnect = true, + .session.protocol_ver = MQTT_PROTOCOL_V_5, + }; + char* topic = append_mac("topic"); + TEST_ASSERT_TRUE(NULL != topic); + s_event_group = xEventGroupCreate(); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg); + TEST_ASSERT_TRUE(NULL != client ); + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_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, mqtt5_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; +} diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.h b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.h new file mode 100644 index 000000000..a181dd8e0 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/main/test_mqtt5_client_broker.h @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include "esp_log.h" + +/** + * @brief MQTT5 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 "mqtt5 broker tests" test case. + */ +#define RUN_MQTT5_BROKER_TEST(test_name) \ + do { \ + ESP_LOGI("mqtt5_test", "Running test:" #test_name "()"); \ + TEST_ASSERT_TRUE_MESSAGE(test_name(), "Mqtt5 test failed: " #test_name "() "); \ + ESP_LOGI("mqtt5_test", "Test:" #test_name "() passed "); \ + } while(0) + + +/** + * @brief This module contains mqtt5 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 mqtt5_subscribe_publish(void); + +/** + * @brief The client connects, disconnects and reconnects. + * Tests basic client state transitions + */ +bool mqtt5_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 mqtt5_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 mqtt5_subscribe_payload(void); diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/pytest_mqtt5_ut.py b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/pytest_mqtt5_ut.py new file mode 100644 index 000000000..7e38dfac8 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/pytest_mqtt5_ut.py @@ -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_mqtt5_client(dut: Dut) -> None: + dut.expect_unity_test_output() diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.ci.default b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.ci.default new file mode 100644 index 000000000..1d40815a9 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.ci.default @@ -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 diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.defaults b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.defaults new file mode 100644 index 000000000..06c58d7b6 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/mqtt5/sdkconfig.defaults @@ -0,0 +1,4 @@ +# General options for additional checks +CONFIG_ESP_TASK_WDT_EN=n +CONFIG_MQTT_PROTOCOL_5=y +CONFIG_UNITY_ENABLE_FIXTURE=y diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/CMakeLists.txt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/CMakeLists.txt new file mode 100644 index 000000000..543259e6a --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/CMakeLists.txt @@ -0,0 +1,16 @@ +# 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) +idf_build_set_property(MINIMAL_BUILD ON) + +project(mqtt_publish_connect_test) + +target_add_binary_data(mqtt_publish_connect_test.elf "main/mqtt_eclipseprojects_io.pem" TEXT) +target_add_binary_data(mqtt_publish_connect_test.elf "ca.crt" TEXT) +target_add_binary_data(mqtt_publish_connect_test.elf "ca.der" TEXT) +target_add_binary_data(mqtt_publish_connect_test.elf "client_pwd.key" TEXT) +target_add_binary_data(mqtt_publish_connect_test.elf "client_pwd.crt" TEXT) +target_add_binary_data(mqtt_publish_connect_test.elf "client_no_pwd.key" TEXT) +target_add_binary_data(mqtt_publish_connect_test.elf "client_inv.crt" TEXT) diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/README.md b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/README.md new file mode 100644 index 000000000..ec2cd41e2 --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/README.md @@ -0,0 +1,25 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | +| ----------------- | ----- | -------- | -------- | + +# ESP-MQTT advanced publish and connect test project + +Main purpose of this application is to test the MQTT library to correctly publish and receive messages (of different size and sequences) over different transports. +It is possible to run this example manually without any test to exercise how the MQTT library deals with + +- reception of fragmented messages +- runtime updates of URI + +## Runtime settings + +This app waits for user input to provide these parameters: +- test-type: "conn" if connection test (host, port, test-case number) +- publish test: + * transport: string parameter, one of: tcp, ssl, ws, wss + * pattern: sample string to be transmitted as message + * pattern repeats: number of repeats of pattern in one MQTT message + * repeated: number of repeats ESP32 publishes the message, also ESP32 expects to receive the same message the same number of repeats + * qos: number specifying qos, one of: 0, 1, 2 + +## Hardware Required + +This test-app can be executed on any ESP32 board, the only required interface is WiFi and connection to a local network, then depending on the test either a mqtt test broker or a tls server. diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.crt b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.crt new file mode 100644 index 000000000..e371e070c --- /dev/null +++ b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGTCCAgGgAwIBAgIUY6kAA+U+ZPIJYIff8dlbi6NCzKswDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJRXNwcmVzc2lmMB4XDTI1MDQwMjA1MjcwMloXDTM1MDMz +MTA1MjcwMlowFDESMBAGA1UEAwwJRXNwcmVzc2lmMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAwSY/p8zDP8W3f37xfL1jy/WcWVOOS2msWRyxjpXQM2e+ +66McSkn8mVKTW5/aZ96sFQbmBBuhp3ypopH+kBQHxK4kla6roEcN/Nx9wpC8X64l +U9EqPmOvcIG8HElEY05LzZ9Rzc4LIBREq/sM8FE5+YHO2za8rN2XIaMii0mm2alf +o1MFEq1nkHBeJKlXkk6eZDwcQ9kqLWBz9YQWygE2pmDCjdCoY97/dZpgAjvkrAGN +9UYno9ZmNOYefL1P1ZmVtdBRW/xDGTDSZCJGYHOrtvfD8VS6cguOOl+rsy3obFdh +A4AgGFEFtfdY/+2fJHFkn6Pep6j+7h8f9n89qpSwswIDAQABo2MwYTAdBgNVHQ4E +FgQUJ+QsjjuS10OtEEcU0Wh2XhXTa1YwHwYDVR0jBBgwFoAUJ+QsjjuS10OtEEcU +0Wh2XhXTa1YwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZI +hvcNAQELBQADggEBABKWpI+QdMYoDwyssIbfwpbqJxb5M1w3PLnMsPzg1d5aEqLh +zwN9EnEQ5TxfeC7Lxdv3hKEGtif/aVxBhs48wPSxD7Fuw17kX6P4l9Cu9Ro2+1Oy +0lUxHi61xXxf7zVkdPQ0JLXdSMUvSUuKfvBtHCwEfdC+lsamxIDmCJys69kDhsCM +VJzY8Yz4MA9WOY3Z2YYMRp6ryFBZ9UgSUEnFxSOpggymkcM5mNxod1jshvSJ3FDG +dmvfbmK0+dN3rCiooORsIYVbopAYxralavA9IY24oiULE+GyVt5pNSONmJ96Y7GK +dL72B8RxX+jUSzgu/N3D1DwbPHP/xRiI7EqaYvg= +-----END CERTIFICATE----- diff --git a/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.der b/ESP32-IDF_Temperture-Node-v2/managed_components/espressif__mqtt/test/apps/publish_connect_test/ca.der new file mode 100644 index 0000000000000000000000000000000000000000..8f0d12006aceaf0753b903aba07c6822dfbb2fe2 GIT binary patch literal 797 zcmXqLVwN;$Vq#pt%*4pVB$B+6f%&Oj$|uf*_WK`iMt3iEI0ro;}B{AmXz6H_wMa%b$(sZkz2{b9cJpVx?}+ zWj9yGFAioETAMzhAWmgv_$0r1DK;|BH??#ViodpqonkawmT;)|!iwa3|4U~jFj+rY z!`S=PO?~mTG?Qm?HGBQ9&YZgSLSXbCXGw!gDN1e$#jCe{Km0LdR}pugRs8DBx-W9V z6PX(nBm!BtevkP7cD_ns%KXLmmaq8tPG0_7z3r+g8#XgBGcqtPPBut1kOhXgEFX&) zi-`IYoj&VH*PYi2xQkrOD2o%loE>H$50X}9kuVTzz^;HFq(GRF@jnZz0W**?-~$Qp zg9KQZnV4FTqX8Jpz-VA(5Sq56e?rMI4St?A8`|z4n)XUv?5A;zxy{Zq8~!}FdM`?7 z(Zlo1wL*mgPi^8W^iChW{k>%&+cx$8nK6!S=WGsq*~q^!?{M6c_{Be_Us(55%ItUW zrc0rQa(Y{j*2KRzO)2?eqO$d_$5DMx@2