Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/mqtt_cxx__build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_ver: ["release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5"]
idf_target: ["esp32"]
test: [ { app: mqtt-basic, path: "components/esp_mqtt_cxx/examples" }]
test: [ { app: mqtt-basic, path: "components/esp_mqtt_cxx/examples" }, { app: test, path: "components/esp_mqtt_cxx/test/unit" }]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
Expand All @@ -25,8 +25,7 @@ jobs:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
working-directory: ${{matrix.test.path}}
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
python ./ci/build_apps.py ./${{ matrix.test.path }} --target ${{ matrix.idf_target }} -vv --preserve-all -c
2 changes: 1 addition & 1 deletion components/esp_mqtt_cxx/.cz.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ commitizen:
bump_message: 'bump(mqtt_cxx): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py esp_mqtt_cxx
tag_format: mqtt_cxx-v$version
version: 0.4.0
version: 0.5.0
version_files:
- idf_component.yml
8 changes: 8 additions & 0 deletions components/esp_mqtt_cxx/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [0.5.0](https://github.com/espressif/esp-protocols/commits/mqtt_cxx-v0.5.0)

### Bug Fixes

- Implement simple unit tests ([f41c4a0a](https://github.com/espressif/esp-protocols/commit/f41c4a0a))
- Fix to construct in two steps ([d979e1b3](https://github.com/espressif/esp-protocols/commit/d979e1b3), [#631](https://github.com/espressif/esp-protocols/issues/631))
- Add explicit dependency on esp-mqtt if needed ([3d5e11b8](https://github.com/espressif/esp-protocols/commit/3d5e11b8))

## [0.4.0](https://github.com/espressif/esp-protocols/commits/mqtt_cxx-v0.4.0)

### Bug Fixes
Expand Down
15 changes: 14 additions & 1 deletion components/esp_mqtt_cxx/esp_mqtt_cxx.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -163,7 +163,20 @@ Client::Client(esp_mqtt_client_config_t const &config) : handler(esp_mqtt_clien
throw MQTTException(ESP_FAIL);
};
CHECK_THROW_SPECIFIC(esp_mqtt_client_register_event(handler.get(), MQTT_EVENT_ANY, mqtt_event_handler, this), mqtt::MQTTException);
}

void Client::start()
{
if (started) {
return;
}
CHECK_THROW_SPECIFIC(esp_mqtt_client_start(handler.get()), mqtt::MQTTException);
started = true;
}

bool Client::is_started() const noexcept
{
return started;
}

void Client::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) noexcept
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ extern "C" void app_main(void)
idf::mqtt::Configuration config{};

MyClient client{broker, credentials, config};
client.start();
while (true) {
constexpr TickType_t xDelay = 500 / portTICK_PERIOD_MS;
vTaskDelay( xDelay );
vTaskDelay(xDelay);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ extern "C" void app_main(void)
mqtt::Configuration config{};

MyClient client{broker, credentials, config};
client.start();

while (true) {
constexpr TickType_t xDelay = 500 / portTICK_PERIOD_MS;
Expand Down
4 changes: 2 additions & 2 deletions components/esp_mqtt_cxx/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "0.4.0"
version: "0.5.0"
description: C++ APIs for ESP-MQTT library
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_mqtt_cxx
issues: https://github.com/espressif/esp-protocols/issues
Expand All @@ -8,7 +8,7 @@ dependencies:
espressif/esp-idf-cxx: "^1.0.0-beta"
# Required IDF version
idf:
version: ">=5.0"
version: ">=5.0,<6.0"
espressif/mqtt:
rules:
- if: idf_version >=6.0
Expand Down
28 changes: 21 additions & 7 deletions components/esp_mqtt_cxx/include/esp_mqtt.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -165,6 +165,19 @@ class Client {
*/
Client(const esp_mqtt_client_config_t &config);

/**
* @brief Start the underlying esp-mqtt client
*
* Must be called after the derived class has finished constructing to avoid
* events being dispatched to partially constructed objects.
*/
void start();

/**
* @brief Check whether start() has been called
*/
[[nodiscard]] bool is_started() const noexcept;

/**
* @brief Subscribe to topic
*
Expand Down Expand Up @@ -245,13 +258,13 @@ class Client {
*/
virtual void on_error(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an disconnection event
* @brief Called if there is a disconnection event
*
* @param event mqtt event data
*/
virtual void on_disconnected(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an subscribed event
* @brief Called if there is a subscribed event
*
* @param event mqtt event data
*/
Expand All @@ -263,26 +276,26 @@ class Client {
*/
virtual void on_unsubscribed(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an published event
* @brief Called if there is a published event
*
* @param event mqtt event data
*/
virtual void on_published(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an before connect event
* @brief Called if there is a before connect event
*
* @param event mqtt event data
*/
virtual void on_before_connect(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an connected event
* @brief Called if there is a connected event
*
* @param event mqtt event data
*
*/
virtual void on_connected(const esp_mqtt_event_handle_t event) = 0;
/**
* @brief Called if there is an data event
* @brief Called if there is a data event
*
* @param event mqtt event data
*
Expand All @@ -292,5 +305,6 @@ class Client {
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id,
void *event_data) noexcept;
void init(const esp_mqtt_client_config_t &config);
bool started{false};
};
} // namespace idf::mqtt
10 changes: 10 additions & 0 deletions components/esp_mqtt_cxx/test/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.5)


include($ENV{IDF_PATH}/tools/cmake/project.cmake)
if(${IDF_TARGET} STREQUAL "linux")
set(EXTRA_COMPONENT_DIRS "../../../../common_components/linux_compat")
set(COMPONENTS main)
endif()

project(esp_mqtt_cxx_host_test)
24 changes: 24 additions & 0 deletions components/esp_mqtt_cxx/test/unit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Test basic mqtt_cxx wrapper operations

## Warning: Linux target not supported, this test works only on target

## Example output
```
I (588) main_task: Started on CPU0
I (598) main_task: Calling app_main()
Randomness seeded to: 374196253
I (608) mqtt_client_cpp: MQTT_EVENT_BEFORE_CONNECT
E (618) esp-tls: [sock=54] delayed connect error: Connection reset by peer
E (618) transport_base: Failed to open a new connection: 32772
E (618) mqtt_client: Error transport connect
I (618) mqtt_client_cpp: MQTT_EVENT_ERROR
E (628) mqtt_client_cpp: Last error reported from esp-tls: 0x8004
E (628) mqtt_client_cpp: Last error captured as transport's socket errno: 0x68
I (638) mqtt_client_cpp: Last errno string (Connection reset by peer)
I (648) mqtt_client_cpp: MQTT_EVENT_DISCONNECTED
===============================================================================
All tests passed (6 assertions in 1 test case)

Test passed!
I (5658) main_task: Returned from app_main()
```
2 changes: 2 additions & 0 deletions components/esp_mqtt_cxx/test/unit/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRCS "test_esp_mqtt_cxx.cpp"
WHOLE_ARCHIVE)
5 changes: 5 additions & 0 deletions components/esp_mqtt_cxx/test/unit/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies:
espressif/catch2: "^3.4.0"
esp_mqtt_cxx:
version: "*"
override_path: '../../../'
92 changes: 92 additions & 0 deletions components/esp_mqtt_cxx/test/unit/main/test_esp_mqtt_cxx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "catch2/catch_session.hpp"
#include "catch2/catch_test_macros.hpp"
#include "esp_mqtt.hpp"
#include "esp_mqtt_client_config.hpp"
#include "esp_netif.h"

namespace mqtt = idf::mqtt;

namespace {
class TestClient final : public mqtt::Client {
public:
using mqtt::Client::Client;

bool constructed{false};
bool before_connect{false};
bool disconnected{false};

TestClient(const mqtt::BrokerConfiguration &broker, const mqtt::ClientCredentials &credentials, const mqtt::Configuration &config) :
mqtt::Client(broker, credentials, config)
{
constructed = true;
}

private:
void on_connected(esp_mqtt_event_handle_t const event) override
{
CHECK(constructed);
}

void on_data(esp_mqtt_event_handle_t const event) override
{
CHECK(constructed);
}

void on_before_connect(esp_mqtt_event_handle_t const event) override
{
CHECK(constructed);
before_connect = true;
}

void on_disconnected(const esp_mqtt_event_handle_t event) override
{
CHECK(constructed);
disconnected = true;

}

};
} // namespace

TEST_CASE("Client does not auto-start and can dispatch events after construction", "[esp_mqtt_cxx]")
{
mqtt::BrokerConfiguration broker{
.address = mqtt::URI{std::string{"mqtt://127.0.0.1:1883"}},
.security = mqtt::Insecure{}
};
mqtt::ClientCredentials credentials{};
mqtt::Configuration config{};

TestClient client{broker, credentials, config};

REQUIRE(client.is_started() == false);

// start the client and expect disconnection (reset by peer)
// since no server's running on this ESP32
client.start();
CHECK(client.is_started() == true);

CHECK(client.before_connect);
usleep(10000);
CHECK(client.disconnected);
}

extern "C" void app_main(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());

Catch::Session session;

int failures = session.run();
if (failures > 0) {
printf("TEST FAILED! number of failures=%d\n", failures);
return;
}
printf("Test passed!\n");
}
4 changes: 4 additions & 0 deletions components/esp_mqtt_cxx/test/unit/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
1 change: 0 additions & 1 deletion test_app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ include($ENV{IDF_PATH}/tools/cmake/version.cmake)
set(EXTRA_COMPONENT_DIRS
../components/eppp_link
../components/esp_modem
../components/esp_mqtt_cxx
../components/esp_websocket_client
../components/console_cmd_ifconfig
../components/console_cmd_ping
Expand Down
Loading