mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-23 07:17:29 +02:00
Adds esp_mqtt_cxx component
- Component moved from esp-idf - Files moved to adjust to esp-protocol structure
This commit is contained in:
296
components/esp_mqtt_cxx/include/esp_mqtt.hpp
Normal file
296
components/esp_mqtt_cxx/include/esp_mqtt.hpp
Normal file
@ -0,0 +1,296 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#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.
|
||||
*
|
||||
* @note
|
||||
* When subscribing to a topic the QoS means the maximum QoS that should be sent to
|
||||
* client on this topic
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* Topic filter.
|
||||
*
|
||||
*/
|
||||
class Filter {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructs the topic filter from the user filter
|
||||
* @throws std::domain_error if the filter is invalid.
|
||||
*
|
||||
* @param user_filter Filter to be used.
|
||||
*/
|
||||
explicit Filter(std::string user_filter);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the filter string used.
|
||||
*
|
||||
* @return Reference to the topic filter.
|
||||
*/
|
||||
const std::string &get();
|
||||
|
||||
/**
|
||||
* @brief Checks the filter string against a topic name.
|
||||
*
|
||||
* @param topic_begin Iterator to the beginning of the sequence.
|
||||
* @param topic_end Iterator to the end of the sequence.
|
||||
*
|
||||
* @return true if the topic name match the filter
|
||||
*/
|
||||
[[nodiscard]] bool match(std::string::const_iterator topic_begin, std::string::const_iterator topic_end) 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 begin Char array with topic name.
|
||||
* @param size Size of given topic name.
|
||||
*
|
||||
* @return true if the topic name match the filter
|
||||
*/
|
||||
[[nodiscard]] bool match(char *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:
|
||||
/**
|
||||
* @brief Constructor of the client
|
||||
*
|
||||
* @param broker Configuration for broker connection
|
||||
* @param credentials client credentials to be presented to the broker
|
||||
* @param config Mqtt client configuration
|
||||
*/
|
||||
Client(const BrokerConfiguration &broker, const ClientCredentials &credentials, const Configuration &config);
|
||||
|
||||
/**
|
||||
* @brief Constructs Client using the same configuration used for
|
||||
* `esp_mqtt_client`
|
||||
* @param config config struct to `esp_mqtt_client`
|
||||
*/
|
||||
Client(const esp_mqtt_client_config_t &config);
|
||||
|
||||
/**
|
||||
* @brief Subscribe to topic
|
||||
*
|
||||
* @param topic_filter MQTT topic 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 &topic_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 qos Set qos message
|
||||
* @param retain Set if message should be retained
|
||||
*
|
||||
* @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:
|
||||
/**
|
||||
* @brief Helper type to be used as custom deleter for std::unique_ptr.
|
||||
*/
|
||||
struct MqttClientDeleter {
|
||||
void operator()(esp_mqtt_client *client_handler)
|
||||
{
|
||||
esp_mqtt_client_destroy(client_handler);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type of the handler for the underlying mqtt_client handler.
|
||||
* It uses std::unique_ptr for lifetime management
|
||||
*/
|
||||
using ClientHandler = std::unique_ptr<esp_mqtt_client, MqttClientDeleter>;
|
||||
/**
|
||||
* @brief esp_mqtt_client handler
|
||||
*
|
||||
*/
|
||||
ClientHandler handler;
|
||||
|
||||
/**
|
||||
* @brief Called if there is an error event
|
||||
*
|
||||
* @param event mqtt event data
|
||||
*/
|
||||
virtual void on_error(const esp_mqtt_event_handle_t event);
|
||||
/**
|
||||
* @brief Called if there is an 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
|
||||
*
|
||||
* @param event mqtt event data
|
||||
*/
|
||||
virtual void on_subscribed(const esp_mqtt_event_handle_t event);
|
||||
/**
|
||||
* @brief Called if there is an unsubscribed event
|
||||
*
|
||||
* @param event mqtt event data
|
||||
*/
|
||||
virtual void on_unsubscribed(const esp_mqtt_event_handle_t event);
|
||||
/**
|
||||
* @brief Called if there is an 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
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @param event mqtt event data
|
||||
*
|
||||
*/
|
||||
virtual void on_data(const esp_mqtt_event_handle_t event) = 0;
|
||||
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);
|
||||
};
|
||||
} // namespace idf::mqtt
|
213
components/esp_mqtt_cxx/include/esp_mqtt_client_config.hpp
Normal file
213
components/esp_mqtt_cxx/include/esp_mqtt_client_config.hpp
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#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
|
Reference in New Issue
Block a user