mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
Merge branch 'feature/esp_mqtt_cxx' into 'master'
Adds a C++ Mqtt client wrapper over mqtt_client See merge request espressif/esp-idf!11634
This commit is contained in:
commit
803c0bc380
@ -0,0 +1,25 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
idf_component_register(SRCS "esp_mqtt_cxx.cpp"
|
||||
INCLUDE_DIRS "include"
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-std=gnu++17")
|
||||
|
||||
if(TEST_BUILD)
|
||||
message(STATUS "Test build")
|
||||
idf_component_get_property(mqtt_dir mqtt COMPONENT_DIR)
|
||||
idf_component_get_property(experimental_cpp_component_dir experimental_cpp_component COMPONENT_DIR)
|
||||
idf_component_get_property(esp_common_dir esp_common COMPONENT_DIR)
|
||||
idf_component_get_property(esp_event_dir esp_event COMPONENT_DIR)
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC ${mqtt_dir}/esp-mqtt/include
|
||||
${esp_event_dir}/include
|
||||
${experimental_cpp_component_dir}/include
|
||||
${esp_common_dir}/include)
|
||||
|
||||
else()
|
||||
idf_component_get_property(mqtt_lib mqtt COMPONENT_LIB)
|
||||
idf_component_get_property(log_lib log COMPONENT_LIB)
|
||||
idf_component_get_property(experimental_cpp_component_lib experimental_cpp_component COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${log_lib} ${mqtt_lib} ${experimental_cpp_component_lib})
|
||||
endif()
|
@ -0,0 +1,5 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
|
||||
COMPONENT_SRCDIRS := ./
|
||||
|
||||
CXXFLAGS += -std=gnu++17
|
@ -0,0 +1,299 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) CO 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.
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_mqtt.hpp"
|
||||
#include "esp_mqtt_client_config.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper for static assert.
|
||||
template<class T>
|
||||
constexpr bool always_false = false;
|
||||
|
||||
template<class... Ts> struct overloaded : Ts... {
|
||||
using Ts::operator()...;
|
||||
};
|
||||
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
using namespace idf::mqtt;
|
||||
|
||||
/*
|
||||
* This function is responsible for fill in the configurations for the broker related data
|
||||
* of mqtt_client_config_t
|
||||
*/
|
||||
void config_broker(esp_mqtt_client_config_t &mqtt_client_cfg, BrokerConfiguration const &broker)
|
||||
{
|
||||
std::visit(overloaded{
|
||||
[&mqtt_client_cfg](Host const & host)
|
||||
{
|
||||
mqtt_client_cfg.host = host.address.c_str();
|
||||
mqtt_client_cfg.path = host.path.c_str();
|
||||
mqtt_client_cfg.transport = host.transport;
|
||||
},
|
||||
[&mqtt_client_cfg](URI const & uri)
|
||||
{
|
||||
mqtt_client_cfg.uri = uri.address.c_str();
|
||||
},
|
||||
[]([[maybe_unused ]]auto & unknown)
|
||||
{
|
||||
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");
|
||||
}
|
||||
},
|
||||
broker.address.address);
|
||||
|
||||
std::visit(overloaded{
|
||||
[]([[maybe_unused]]Insecure const & insecure) {},
|
||||
[&mqtt_client_cfg](GlobalCAStore const & use_global_store)
|
||||
{
|
||||
mqtt_client_cfg.use_global_ca_store = true;
|
||||
},
|
||||
[&mqtt_client_cfg](CryptographicInformation const & certificates)
|
||||
{
|
||||
std::visit(overloaded{
|
||||
[&mqtt_client_cfg](PEM const & pem)
|
||||
{
|
||||
mqtt_client_cfg.cert_pem = pem.data;
|
||||
}, [&mqtt_client_cfg](DER const & der)
|
||||
{
|
||||
mqtt_client_cfg.cert_pem = der.data;
|
||||
mqtt_client_cfg.cert_len = der.len;
|
||||
}}, certificates);
|
||||
},
|
||||
[]([[maybe_unused]] PSK const & psk) {},
|
||||
[]([[maybe_unused]] auto & unknown)
|
||||
{
|
||||
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");
|
||||
}
|
||||
},
|
||||
broker.security);
|
||||
mqtt_client_cfg.port = broker.address.port;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is responsible for fill in the configurations for the client credentials related data
|
||||
* of mqtt_client_config_t
|
||||
*/
|
||||
void config_client_credentials(esp_mqtt_client_config_t &mqtt_client_cfg, ClientCredentials const &credentials)
|
||||
{
|
||||
mqtt_client_cfg.client_id = credentials.client_id.has_value() ? credentials.client_id.value().c_str() : nullptr ;
|
||||
mqtt_client_cfg.username = credentials.username.has_value() ? credentials.username.value().c_str() : nullptr ;
|
||||
std::visit(overloaded{
|
||||
[&mqtt_client_cfg](Password const & password)
|
||||
{
|
||||
mqtt_client_cfg.password = password.data.c_str();
|
||||
},
|
||||
[](ClientCertificate const & certificate) {},
|
||||
[](SecureElement const & enable_secure_element) {},
|
||||
[]([[maybe_unused ]]auto & unknown)
|
||||
{
|
||||
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");
|
||||
}
|
||||
}, credentials.authentication);
|
||||
}
|
||||
|
||||
esp_mqtt_client_config_t make_config(BrokerConfiguration const &broker, ClientCredentials const &credentials, Configuration const &config)
|
||||
{
|
||||
esp_mqtt_client_config_t mqtt_client_cfg{};
|
||||
config_broker(mqtt_client_cfg, broker);
|
||||
config_client_credentials(mqtt_client_cfg, credentials);
|
||||
return mqtt_client_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
namespace idf::mqtt {
|
||||
|
||||
Client::Client(BrokerConfiguration const &broker, ClientCredentials const &credentials, Configuration const &config): Client(make_config(broker, credentials, config)) {}
|
||||
|
||||
Client::Client(esp_mqtt_client_config_t const &config) : handler(esp_mqtt_client_init(&config))
|
||||
{
|
||||
if (handler == nullptr) {
|
||||
throw MQTTException(ESP_FAIL);
|
||||
};
|
||||
CHECK_THROW_SPECIFIC(esp_mqtt_client_register_event(handler.get(), MQTT_EVENT_ANY, mqtt_event_handler, this), mqtt::MQTTException);
|
||||
CHECK_THROW_SPECIFIC(esp_mqtt_client_start(handler.get()), mqtt::MQTTException);
|
||||
}
|
||||
|
||||
|
||||
void Client::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) noexcept
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
|
||||
auto *event = static_cast<esp_mqtt_event_t *>(event_data);
|
||||
auto &client = *static_cast<Client *>(handler_args);
|
||||
switch (event->event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
client.on_connected(event);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
client.on_disconnected(event);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
client.on_subscribed(event);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
client.on_unsubscribed(event);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
client.on_published(event);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
client.on_data(event);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
client.on_error(event);
|
||||
break;
|
||||
case MQTT_EVENT_BEFORE_CONNECT:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT");
|
||||
client.on_before_connect(event);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::on_error(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
auto 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);
|
||||
}
|
||||
};
|
||||
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));
|
||||
}
|
||||
}
|
||||
void Client::on_disconnected(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
}
|
||||
void Client::on_subscribed(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
printf("Subscribed to %.*s\r\n", event->topic_len, event->topic);
|
||||
}
|
||||
void Client::on_unsubscribed(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
}
|
||||
void Client::on_published(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
}
|
||||
void Client::on_before_connect(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
}
|
||||
void Client::on_connected(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
}
|
||||
void Client::on_data(esp_mqtt_event_handle_t const event)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<MessageID> Client::subscribe(std::string const &topic, QoS qos)
|
||||
{
|
||||
auto res = esp_mqtt_client_subscribe(handler.get(), topic.c_str(),
|
||||
static_cast<int>(qos));
|
||||
if (res < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return MessageID{res};
|
||||
}
|
||||
|
||||
bool is_valid(std::string::const_iterator first, std::string::const_iterator last)
|
||||
{
|
||||
if (first == last) {
|
||||
return false;
|
||||
}
|
||||
auto number = std::find(first, last, '#');
|
||||
if (number != last) {
|
||||
if (std::next(number) != last) {
|
||||
return false;
|
||||
}
|
||||
if (*std::prev(number) != '/' && number != first) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto plus = std::find(first, last, '+');
|
||||
if (plus != last) {
|
||||
if (*(std::prev(plus)) != '/' && plus != first) {
|
||||
return false;
|
||||
}
|
||||
if (std::next(plus) != last && *(std::next(plus)) != '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Filter::Filter(std::string user_filter) : filter(std::move(user_filter))
|
||||
{
|
||||
if (!is_valid(filter.begin(), filter.end())) {
|
||||
throw std::domain_error("Forbidden Filter string");
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Filter::match(std::string::const_iterator topic_begin, std::string::const_iterator topic_end) const noexcept
|
||||
{
|
||||
auto filter_begin = filter.begin();
|
||||
auto filter_end = filter.end();
|
||||
for (auto mismatch = std::mismatch(filter_begin, filter_end, topic_begin);
|
||||
mismatch.first != filter.end() and mismatch.second != topic_end;
|
||||
mismatch = std::mismatch(filter_begin, filter_end, topic_begin)) {
|
||||
if (*mismatch.first != '#' and * mismatch.first != '+') {
|
||||
return false;
|
||||
}
|
||||
if (*mismatch.first == '#') {
|
||||
return true;
|
||||
}
|
||||
if (*mismatch.first == '+') {
|
||||
filter_begin = advance(mismatch.first, filter_end);
|
||||
topic_begin = advance(mismatch.second, topic_end);
|
||||
if (filter_begin == filter_end and topic_begin != topic_end) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const std::string &Filter::get()
|
||||
{
|
||||
return filter;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Filter::match(char const *const first, int size) const noexcept
|
||||
{
|
||||
auto it = static_cast<std::string::const_iterator>(first);
|
||||
return match(it, it + size);
|
||||
}
|
||||
std::string::const_iterator Filter::advance(std::string::const_iterator first, std::string::const_iterator last) const
|
||||
{
|
||||
constexpr auto separator = '/';
|
||||
return std::find(first, last, separator);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) CO 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.
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#ifndef __cpp_exceptions
|
||||
#error MQTT class can only be used when __cpp_exceptions is enabled. Enable CONFIG_COMPILER_CXX_EXCEPTIONS in Kconfig
|
||||
#endif
|
||||
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "esp_exception.hpp"
|
||||
#include "esp_mqtt_client_config.hpp"
|
||||
#include "mqtt_client.h"
|
||||
|
||||
namespace idf::mqtt {
|
||||
|
||||
constexpr auto *TAG = "mqtt_client_cpp";
|
||||
|
||||
struct MQTTException : ESPException {
|
||||
using ESPException::ESPException;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief QoS for publish and subscribe
|
||||
*
|
||||
* Sets the QoS as:
|
||||
* AtMostOnce : Best effort delivery of messages. Message loss can occur.
|
||||
* AtLeastOnce : Guaranteed delivery of messages. Duplicates can occur.
|
||||
* ExactlyOnce : Guaranteed delivery of messages exactly once.
|
||||
*
|
||||
*/
|
||||
enum class QoS { AtMostOnce = 0, AtLeastOnce = 1, ExactlyOnce = 2 };
|
||||
|
||||
/**
|
||||
* @brief Sets if a message must be retained.
|
||||
*
|
||||
* Retained messages are delivered to future subscribers that match the topic name.
|
||||
*
|
||||
*/
|
||||
enum class Retain : bool { NotRetained = false, Retained = true };
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message class template to publish.
|
||||
*
|
||||
*/
|
||||
template <typename T> struct Message {
|
||||
T data; /*!< Data for publish. Should be a contiguous type*/
|
||||
QoS qos = QoS::AtLeastOnce; /*!< QoS for the message*/
|
||||
Retain retain = Retain::NotRetained; /*!< Retention mark for the message.*/
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Message type that holds std::string for data
|
||||
*
|
||||
*/
|
||||
using StringMessage = Message<std::string>;
|
||||
|
||||
[[nodiscard]] bool filter_is_valid(std::string::const_iterator first, std::string::const_iterator last);
|
||||
|
||||
/**
|
||||
* @brief Filter for mqtt topic subscription.
|
||||
* @throws std::domain_error if the filter is invalid.
|
||||
*
|
||||
* Topic filter.
|
||||
*
|
||||
*/
|
||||
class Filter {
|
||||
public:
|
||||
|
||||
explicit Filter(std::string user_filter);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the filter string used.
|
||||
*
|
||||
*/
|
||||
const std::string &get();
|
||||
|
||||
/**
|
||||
* @brief Checks the filter string against a topic name.
|
||||
*
|
||||
* @param first Iterator to the beginning of the sequence.
|
||||
* @param last Iterator to the end of the sequence.
|
||||
*
|
||||
* @return true if the topic name match the filter
|
||||
*/
|
||||
[[nodiscard]] bool match(std::string::const_iterator first,
|
||||
std::string::const_iterator last) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Checks the filter string against a topic name.
|
||||
*
|
||||
* @param topic topic name
|
||||
*
|
||||
* @return true if the topic name match the filter
|
||||
*/
|
||||
[[nodiscard]] bool match(const std::string &topic) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Checks the filter string against a topic name.
|
||||
*
|
||||
* @param first Char array with topic name.
|
||||
* @param last Size of given topic name.
|
||||
*
|
||||
* @return true if the topic name match the filter
|
||||
*/
|
||||
[[nodiscard]] bool match(const char *const begin, int size) const noexcept;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief Advance the topic to the next level.
|
||||
*
|
||||
* An mqtt topic ends with a /. This function is used to iterate in topic levels.
|
||||
*
|
||||
* @return Iterator to the start of the topic.
|
||||
*/
|
||||
[[nodiscard]] std::string::const_iterator advance(std::string::const_iterator begin, std::string::const_iterator end) const;
|
||||
std::string filter;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Message identifier to track delivery.
|
||||
*
|
||||
*/
|
||||
enum class MessageID : int {};
|
||||
|
||||
/**
|
||||
* @brief Base class for MQTT client
|
||||
*
|
||||
* Should be inherited to provide event handlers.
|
||||
*/
|
||||
class Client {
|
||||
public:
|
||||
|
||||
Client(const BrokerConfiguration &broker,const ClientCredentials &credentials,const Configuration &config);
|
||||
|
||||
Client(const esp_mqtt_client_config_t &config);
|
||||
|
||||
/**
|
||||
* @brief Subscribe to topic
|
||||
*
|
||||
* @param filter
|
||||
* @param qos QoS subscription, defaulted as QoS::AtLeastOnce
|
||||
*
|
||||
* @return Optional MessageID. In case of failure std::nullopt is returned.
|
||||
*/
|
||||
std::optional<MessageID> subscribe(const std::string &filter, QoS qos = QoS::AtLeastOnce);
|
||||
|
||||
/**
|
||||
* @brief publish message to topic
|
||||
*
|
||||
* @tparam Container Type for data container. Must be a contiguous memory.
|
||||
* @param topic Topic name
|
||||
* @param message Message struct containing data, qos and retain configuration.
|
||||
*
|
||||
* @return Optional MessageID. In case of failure std::nullopt is returned.
|
||||
*/
|
||||
template <class Container> std::optional<MessageID> publish(const std::string &topic, const Message<Container>& message)
|
||||
{
|
||||
return publish(topic, std::begin(message.data), std::end(message.data), message.qos, message.retain);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief publish message to topic
|
||||
*
|
||||
* @tparam InputIt Input data iterator type.
|
||||
* @param topic Topic name
|
||||
* @param first, last Iterator pair of data to publish
|
||||
* @param message Message struct containing data, qos and retain configuration.
|
||||
*
|
||||
* @return Optional MessageID. In case of failure std::nullopt is returned.
|
||||
*/
|
||||
template <class InputIt>
|
||||
std::optional<MessageID> publish(const std::string &topic, InputIt first, InputIt last, QoS qos = QoS::AtLeastOnce, Retain retain = Retain::NotRetained)
|
||||
{
|
||||
auto size = std::distance(first, last);
|
||||
auto res = esp_mqtt_client_publish(handler.get(), topic.c_str(), &(*first), size, static_cast<int>(qos),
|
||||
static_cast<int>(retain));
|
||||
if (res < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return MessageID{res};
|
||||
}
|
||||
|
||||
virtual ~Client() = default;
|
||||
|
||||
protected:
|
||||
struct MqttClientDeleter {
|
||||
void operator()(esp_mqtt_client *client_handler)
|
||||
{
|
||||
esp_mqtt_client_destroy(client_handler);
|
||||
}
|
||||
};
|
||||
|
||||
using ClientHandler = std::unique_ptr<esp_mqtt_client, MqttClientDeleter>;
|
||||
ClientHandler handler;
|
||||
|
||||
private:
|
||||
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);
|
||||
virtual void on_error(const esp_mqtt_event_handle_t event);
|
||||
virtual void on_disconnected(const esp_mqtt_event_handle_t event);
|
||||
virtual void on_subscribed(const esp_mqtt_event_handle_t event);
|
||||
virtual void on_unsubscribed(const esp_mqtt_event_handle_t event);
|
||||
virtual void on_published(const esp_mqtt_event_handle_t event);
|
||||
virtual void on_before_connect(const esp_mqtt_event_handle_t event);
|
||||
virtual void on_connected(const esp_mqtt_event_handle_t event) = 0;
|
||||
virtual void on_data(const esp_mqtt_event_handle_t event) = 0;
|
||||
};
|
||||
} // namespace idf::mqtt
|
@ -0,0 +1,221 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) CO 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.
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "mqtt_client.h"
|
||||
|
||||
namespace idf::mqtt {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Broker addresss
|
||||
*
|
||||
* Use this to set the broker without parsing the URI string.
|
||||
*
|
||||
*/
|
||||
struct Host {
|
||||
std::string address; /*!< Host name*/
|
||||
std::string path; /*!< Route path of the broker in host*/
|
||||
esp_mqtt_transport_t transport; /*!< Transport scheme to use. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Broker addresss URI
|
||||
*
|
||||
* Use this to set the broker address using the URI.
|
||||
*
|
||||
*/
|
||||
struct URI {
|
||||
std::string address; /*!< Broker adddress URI*/
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Broker addresss.
|
||||
*
|
||||
*/
|
||||
struct BrokerAddress {
|
||||
std::variant<Host, URI> address; /*!< Address, defined by URI or Host struct */
|
||||
uint32_t port = 0; /*!< Port used, defaults to 0 to select common port for the scheme used */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief PEM formated data
|
||||
*
|
||||
* Store certificates, keys and cryptographic data.
|
||||
*
|
||||
*/
|
||||
struct PEM {
|
||||
const char *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DER formated data
|
||||
*
|
||||
* Store certificates, keys and cryptographic data.
|
||||
*
|
||||
*/
|
||||
struct DER {
|
||||
const char *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Holds cryptography related information
|
||||
*
|
||||
* Hold PEM or DER formated cryptographic data.
|
||||
*
|
||||
*/
|
||||
using CryptographicInformation = std::variant<PEM, DER>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Do not verify broker certificate.
|
||||
*
|
||||
* To be used when doing MQTT over TLS connection but not verify broker's certificates.
|
||||
*
|
||||
*/
|
||||
struct Insecure {};
|
||||
|
||||
/**
|
||||
* @brief Use global CA store
|
||||
*
|
||||
* To be used when client should use the Global CA Store to get trusted certificates for the broker.
|
||||
*
|
||||
*/
|
||||
struct GlobalCAStore {};
|
||||
|
||||
/**
|
||||
* @brief Use a pre shared key for broker authentication.
|
||||
*
|
||||
* To be used when client should use a PSK to authenticate the broker.
|
||||
*
|
||||
*/
|
||||
struct PSK {
|
||||
const struct psk_key_hint *hint_key;/* Pointer to PSK struct defined in esp_tls.h to enable PSK authentication */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Authentication method for Broker
|
||||
*
|
||||
* Selects the method for authentication based on the type it holds.
|
||||
*
|
||||
*/
|
||||
using BrokerAuthentication = std::variant<Insecure, GlobalCAStore, CryptographicInformation, PSK>;
|
||||
|
||||
/**
|
||||
* @brief Password related data.
|
||||
*
|
||||
*/
|
||||
struct Password {
|
||||
std::string data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Data to authenticate client with certificates.
|
||||
*
|
||||
*/
|
||||
struct ClientCertificate {
|
||||
CryptographicInformation certificate; /*!< Certificate in PEM or DER format.*/
|
||||
CryptographicInformation key; /*!< Key data in PEM or DER format.*/
|
||||
std::optional<Password> key_password = std::nullopt; /*!< Optional password for key */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Used to select usage of Secure Element
|
||||
*
|
||||
* Enables the usage of the secure element present in ESP32-WROOM-32SE.
|
||||
*
|
||||
*/
|
||||
struct SecureElement {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Used to select usage of Digital Signature Peripheral.
|
||||
*
|
||||
* Enables the usage of the Digital Signature hardware accelerator.
|
||||
*
|
||||
*/
|
||||
struct DigitalSignatureData {
|
||||
void *ds_data; /* carrier of handle for digital signature parameters */
|
||||
};
|
||||
|
||||
using AuthenticationFactor = std::variant<Password, ClientCertificate, SecureElement>;
|
||||
|
||||
struct BrokerConfiguration {
|
||||
BrokerAddress address;
|
||||
BrokerAuthentication security;
|
||||
};
|
||||
|
||||
struct ClientCredentials {
|
||||
std::optional<std::string> username; // MQTT username
|
||||
AuthenticationFactor authentication;
|
||||
std::vector<std::string> alpn_protos; /*!< List of supported application protocols to be used for ALPN */
|
||||
/* default is ``ESP32_%CHIPID%`` where %CHIPID% are last 3 bytes of MAC address in hex format */
|
||||
std::optional<std::string > client_id = std::nullopt;
|
||||
};
|
||||
|
||||
struct Event {
|
||||
mqtt_event_callback_t event_handle; /*!< handle for MQTT events as a callback in legacy mode */
|
||||
esp_event_loop_handle_t event_loop_handle; /*!< handle for MQTT event loop library */
|
||||
};
|
||||
|
||||
struct LastWill {
|
||||
const char *lwt_topic; /*!< LWT (Last Will and Testament) message topic (NULL by default) */
|
||||
const char *lwt_msg; /*!< LWT message (NULL by default) */
|
||||
int lwt_qos; /*!< LWT message qos */
|
||||
int lwt_retain; /*!< LWT retained message flag */
|
||||
int lwt_msg_len; /*!< LWT message length */
|
||||
};
|
||||
|
||||
struct Session {
|
||||
LastWill last_will;
|
||||
int disable_clean_session; /*!< mqtt clean session, default clean_session is true */
|
||||
int keepalive; /*!< mqtt keepalive, default is 120 seconds */
|
||||
bool disable_keepalive; /*!< Set disable_keepalive=true to turn off keep-alive mechanism, false by default (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, defaults to value from menuconfig*/
|
||||
};
|
||||
|
||||
struct Task {
|
||||
int task_prio; /*!< MQTT task priority, default is 5, can be changed in ``make menuconfig`` */
|
||||
int task_stack; /*!< MQTT task stack size, default is 6144 bytes, can be changed in ``make menuconfig`` */
|
||||
};
|
||||
|
||||
struct Connection {
|
||||
esp_mqtt_transport_t transport; /*!< overrides URI transport */
|
||||
int reconnect_timeout_ms; /*!< Reconnect to the broker after this value in miliseconds if auto reconnect is not disabled (defaults to 10s) */
|
||||
int network_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; /*!< this mqtt client will reconnect to server (when errors/disconnect). Set disable_auto_reconnect=true to disable */
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
Event event;
|
||||
Task task;
|
||||
Session session;
|
||||
Connection connection;
|
||||
void *user_context; /*!< pass user context to this option, then can receive that context in ``event->user_context`` */
|
||||
int buffer_size; /*!< size of MQTT send/receive buffer, default is 1024 (only receive buffer size if ``out_buffer_size`` defined) */
|
||||
int out_buffer_size; /*!< size of MQTT output buffer. If not defined, both output and input buffers have the same size defined as ``buffer_size`` */
|
||||
};
|
||||
|
||||
} // idf::mqtt
|
14
examples/cxx/experimental/esp_mqtt_cxx/ssl/CMakeLists.txt
Normal file
14
examples/cxx/experimental/esp_mqtt_cxx/ssl/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# 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.5)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
$ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component
|
||||
$ENV{IDF_PATH}/examples/cxx/experimental/esp_mqtt_cxx/components)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mqtt_ssl_cxx)
|
||||
|
||||
target_add_binary_data(mqtt_ssl_cxx.elf "main/mqtt_eclipseprojects_io.pem" TEXT)
|
12
examples/cxx/experimental/esp_mqtt_cxx/ssl/Makefile
Normal file
12
examples/cxx/experimental/esp_mqtt_cxx/ssl/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
PROJECT_NAME := mqtt_tcp_cxx
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/cxx/experimental/esp_mqtt_cxx/components
|
||||
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/cxx/experimental/experimental_cpp_component
|
||||
|
||||
CXXFLAGS += -std=gnu++17
|
||||
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "mqtt_ssl_example.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-std=gnu++17")
|
@ -0,0 +1,9 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URI
|
||||
string "Broker URL"
|
||||
default "mqtts://mqtt.eclipse.org:8883"
|
||||
help
|
||||
URL of the broker to connect to
|
||||
|
||||
endmenu
|
@ -0,0 +1 @@
|
||||
COMPONENT_EMBED_TXTFILES := mqtt_eclipseprojects_io.pem
|
@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
|
||||
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
|
||||
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
|
||||
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
|
||||
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
|
||||
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
|
||||
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
|
||||
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
|
||||
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
|
||||
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
|
||||
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
|
||||
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
|
||||
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
|
||||
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
|
||||
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
|
||||
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
|
||||
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
|
||||
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
|
||||
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
|
||||
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
|
||||
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
|
||||
-----END CERTIFICATE-----
|
@ -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-----
|
@ -0,0 +1,85 @@
|
||||
/* C++ 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 <cstdint>
|
||||
#include <string>
|
||||
#include "esp_mqtt_client_config.hpp"
|
||||
#include "nvs_flash.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_mqtt.hpp"
|
||||
|
||||
namespace {
|
||||
constexpr auto *TAG = "MQTT_EXAMPLE";
|
||||
|
||||
extern const char mqtt_eclipse_org_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start");
|
||||
extern const char mqtt_eclipse_org_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end");
|
||||
|
||||
class MyClient final : public idf::mqtt::Client {
|
||||
public:
|
||||
using idf::mqtt::Client::Client;
|
||||
private:
|
||||
void on_connected(esp_mqtt_event_handle_t const event) override
|
||||
{
|
||||
using idf::mqtt::QoS;
|
||||
subscribe(messages.get());
|
||||
subscribe(sent_load.get(), QoS::AtMostOnce);
|
||||
}
|
||||
void on_data(esp_mqtt_event_handle_t const event) override
|
||||
{
|
||||
if (messages.match(event->topic, event->topic_len)) {
|
||||
ESP_LOGI(TAG, "Received in the messages topic");
|
||||
}
|
||||
}
|
||||
idf::mqtt::Filter messages{std::string{"$SYS/broker/messages/received"}};
|
||||
idf::mqtt::Filter sent_load{std::string{"$SYS/broker/load/+/sent"}};
|
||||
};
|
||||
}
|
||||
|
||||
namespace mqtt = idf::mqtt;
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* 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::BrokerConfiguration broker{
|
||||
.address = {mqtt::URI{std::string{CONFIG_BROKER_URI}}},
|
||||
.security = mqtt::CryptographicInformation{mqtt::PEM{mqtt_eclipse_org_pem_start}}
|
||||
};
|
||||
idf::mqtt::ClientCredentials credentials{};
|
||||
idf::mqtt::Configuration config{};
|
||||
|
||||
MyClient client{broker, credentials, config};
|
||||
while (true) {
|
||||
constexpr TickType_t xDelay = 500 / portTICK_PERIOD_MS;
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
# Enable C++ exceptions and set emergency pool size for exception objects
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
|
12
examples/cxx/experimental/esp_mqtt_cxx/tcp/CMakeLists.txt
Normal file
12
examples/cxx/experimental/esp_mqtt_cxx/tcp/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# 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.5)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
$ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component
|
||||
$ENV{IDF_PATH}/examples/cxx/experimental/esp_mqtt_cxx/components)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mqtt_tcp_cxx)
|
12
examples/cxx/experimental/esp_mqtt_cxx/tcp/Makefile
Normal file
12
examples/cxx/experimental/esp_mqtt_cxx/tcp/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
PROJECT_NAME := mqtt_tcp_cxx
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/cxx/experimental/esp_mqtt_cxx/components
|
||||
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/cxx/experimental/experimental_cpp_component
|
||||
|
||||
CXXFLAGS += -std=gnu++17
|
||||
include $(IDF_PATH)/make/project.mk
|
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "mqtt_tcp_example.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-std=gnu++17")
|
@ -0,0 +1,9 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config BROKER_URL
|
||||
string "Broker URL"
|
||||
default "mqtt://mqtt.eclipse.org"
|
||||
help
|
||||
URL of the broker to connect to
|
||||
|
||||
endmenu
|
@ -0,0 +1,81 @@
|
||||
/* C++ 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 "nvs_flash.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_mqtt.hpp"
|
||||
#include "esp_mqtt_client_config.hpp"
|
||||
|
||||
namespace mqtt = idf::mqtt;
|
||||
|
||||
namespace {
|
||||
constexpr auto *TAG = "MQTT_EXAMPLE";
|
||||
|
||||
class MyClient final : public mqtt::Client {
|
||||
public:
|
||||
using mqtt::Client::Client;
|
||||
|
||||
private:
|
||||
void on_connected(esp_mqtt_event_handle_t const event) override
|
||||
{
|
||||
using mqtt::QoS;
|
||||
subscribe(messages.get());
|
||||
subscribe(sent_load.get(), QoS::AtMostOnce);
|
||||
}
|
||||
void on_data(esp_mqtt_event_handle_t const event) override
|
||||
{
|
||||
if (messages.match(event->topic, event->topic_len)) {
|
||||
ESP_LOGI(TAG, "Received in the messages topic");
|
||||
}
|
||||
}
|
||||
mqtt::Filter messages{"$SYS/broker/messages/received"};
|
||||
mqtt::Filter sent_load{"$SYS/broker/load/+/sent"};
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* 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::BrokerConfiguration broker{
|
||||
.address = {mqtt::URI{std::string{CONFIG_BROKER_URL}}},
|
||||
.security = mqtt::Insecure{}
|
||||
};
|
||||
mqtt::ClientCredentials credentials{};
|
||||
mqtt::Configuration config{};
|
||||
|
||||
MyClient client{broker, credentials, config};
|
||||
|
||||
while (true) {
|
||||
constexpr TickType_t xDelay = 500 / portTICK_PERIOD_MS;
|
||||
vTaskDelay(xDelay);
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
# Enable C++ exceptions and set emergency pool size for exception objects
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
|
Loading…
x
Reference in New Issue
Block a user