diff --git a/.github/workflows/console_cmd_mqtt__build.yml b/.github/workflows/console_cmd_mqtt__build.yml new file mode 100644 index 00000000000..b965980605b --- /dev/null +++ b/.github/workflows/console_cmd_mqtt__build.yml @@ -0,0 +1,32 @@ +name: "console_cmd_mqtt: build-tests" + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, labeled] + +jobs: + build_console_cmd_mqtt: + if: contains(github.event.pull_request.labels.*.name, 'console') || github.event_name == 'push' + name: Build + strategy: + matrix: + idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"] + idf_target: ["esp32"] + test: [ { app: ssl_mutual_auth, path: "components/console_cmd_mqtt/examples" }] + runs-on: ubuntu-22.04 + container: espressif/idf:${{ matrix.idf_ver }} + steps: + - name: Checkout esp-protocols + uses: actions/checkout@v4 + with: + 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 diff --git a/components/console_cmd_mqtt/.cz.yaml b/components/console_cmd_mqtt/.cz.yaml new file mode 100644 index 00000000000..9d23eecba0d --- /dev/null +++ b/components/console_cmd_mqtt/.cz.yaml @@ -0,0 +1,8 @@ +--- +commitizen: + bump_message: 'bump(console): $current_version -> $new_version' + pre_bump_hooks: python ../../ci/changelog.py console_cmd_mqtt + tag_format: console_cmd_mqtt-v$version + version: 1.0.0 + version_files: + - idf_component.yml diff --git a/components/console_cmd_mqtt/CMakeLists.txt b/components/console_cmd_mqtt/CMakeLists.txt new file mode 100644 index 00000000000..e3b7e587f1d --- /dev/null +++ b/components/console_cmd_mqtt/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register(SRCS "console_mqtt.c" + INCLUDE_DIRS "." + PRIV_REQUIRES esp_netif console mqtt) + +if(CONFIG_MQTT_CMD_AUTO_REGISTRATION) + target_link_libraries(${COMPONENT_LIB} PRIVATE "-u console_cmd_mqtt_register") +endif() diff --git a/components/console_cmd_mqtt/Kconfig.projbuild b/components/console_cmd_mqtt/Kconfig.projbuild new file mode 100644 index 00000000000..235bcc4b31e --- /dev/null +++ b/components/console_cmd_mqtt/Kconfig.projbuild @@ -0,0 +1,15 @@ +menu "MQTT Configuration" + + config MQTT_CMD_AUTO_REGISTRATION + bool "Enable Console command mqtt Auto-registration" + default y + help + Enabling this allows for the autoregistration of the wifi command. + + config MQTT_BROKER_URL + string "Broker URL or IP address" + default "mqtt://mqtt.eclipseprojects.io" + help + URL or IP address of the broker to connect to + +endmenu diff --git a/components/console_cmd_mqtt/README.md b/components/console_cmd_mqtt/README.md new file mode 100644 index 00000000000..93c0154da20 --- /dev/null +++ b/components/console_cmd_mqtt/README.md @@ -0,0 +1,87 @@ +# Console command mqtt +The component provides a console where mqtt commands can be executed. + + +## MQTT Configuration: +1. Broker: Use menuconfig **"MQTT Configuration"** to configure the broker url. + + +## API + +### Steps to enable console in an example code: +1. Add this component to your project using ```idf.py add-dependency``` command. +2. In the main file of the example, add the following line: + ```c + #include "console_mqtt.h" + ``` +3. Ensure esp-netif is initialized and default event loop is created in your app_main(): + ```c + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ``` +4. In your app_main() function, add the following line as the last line: + ```c + ESP_ERROR_CHECK(console_cmd_init()); // Initialize console + + // Register all plugin command added to your project + ESP_ERROR_CHECK(console_cmd_all_register()); + + // To register only mqtt command skip calling console_cmd_all_register() + ESP_ERROR_CHECK(console_cmd_mqtt_register()); + + ESP_ERROR_CHECK(console_cmd_start()); // Start console + ``` + +Note: Auto-registration of a specific plugin command can be disabled from menuconfig. + +### Certificate Integration for Mutual Authentication +To enhance security and enable secure communication over MQTT, three functions have been added to the API, allowing users to set client certificates, client keys, and server certificates separately. + +Setting the client certificate: +```c +set_mqtt_client_cert(client_cert_pem_start, client_cert_pem_end); +``` +Setting the client key: +```c +set_mqtt_client_key(client_key_pem_start, client_key_pem_end); +``` +Setting the server certificate: +```c +set_mqtt_server_certs(server_cert_pem_start, server_cert_pem_end); +``` +Each function takes pointers to the start and end of the respective PEM-encoded data, allowing users to specify the necessary certificate and key information independently. For a complete secure MQTT setup, users should call all three functions in their application code. + +To utilize these certificates, users need to include additional arguments when establishing MQTT connections using the library. Specifically, users should provide the `--cert`, `--key`, and `--cafile` options along with the MQTT connection command. + +### Adding a plugin command or component: +To add a plugin command or any component from IDF component manager into your project, simply include an entry within the `idf_component.yml` file. + +For more details refer [IDF Component Manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html) + + +## Suported command: + +### mqtt: +``` +mqtt [-CsD] [-h ] [-u ] [-P ] [--cert] [--key] [--cafile] + mqtt command + -C, --connect Connect to a broker (flag, no argument) + -h, --host= Specify the host uri to connect to + -s, --status Displays the status of the mqtt client (flag, no argument) + -u, --username= Provide a username to be used for authenticating with the broker + -P, --password= Provide a password to be used for authenticating with the broker + --cert Define the PEM encoded certificate for this client, if required by the server (flag, no argument) + --key Define the PEM encoded private key for this client, if required by the server (flag, no argument) + --cafile Define the PEM encoded CA certificates that are trusted (flag, no argument) + -D, --disconnect Disconnect from the broker (flag, no argument) + +mqtt_pub [-t ] [-m ] + mqtt publish command + -t, --topic= Topic to Subscribe/Publish + -m, --message= Message to Publish + +mqtt_sub [-U] [-t ] + mqtt subscribe command + -t, --topic= Topic to Subscribe/Publish + -U, --unsubscribe Unsubscribe from a topic +``` diff --git a/components/console_cmd_mqtt/console_mqtt.c b/components/console_cmd_mqtt/console_mqtt.c new file mode 100644 index 00000000000..873601ec12a --- /dev/null +++ b/components/console_cmd_mqtt/console_mqtt.c @@ -0,0 +1,472 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "esp_console.h" +#include "esp_event.h" +#include "esp_log.h" +#include "argtable3/argtable3.h" +#include "console_mqtt.h" +#include "mqtt_client.h" + +static const char *TAG = "console_mqtt"; + +#define CONNECT_HELP_MSG "mqtt -C -h -u -P --cert --key --cafile\n" +#define PUBLISH_HELP_MSG "Usage: mqtt -P -t -d \n" +#define SUBSCRIBE_HELP_MSG "Usage: mqtt -S -t \n" +#define UNSUBSCRIBE_HELP_MSG "Usage: mqtt -U\n" +#define DISCONNECT_HELP_MSG "Usage: mqtt -D\n" + +#if CONFIG_MQTT_CMD_AUTO_REGISTRATION +/** + * Static registration of this plugin is achieved by defining the plugin description + * structure and placing it into .console_cmd_desc section. + * The name of the section and its placement is determined by linker.lf file in 'plugins' component. + */ +static const console_cmd_plugin_desc_t __attribute__((section(".console_cmd_desc"), used)) PLUGIN = { + .name = "console_cmd_mqtt", + .plugin_regd_fn = &console_cmd_mqtt_register +}; +#endif + +static struct { + struct arg_lit *connect; + struct arg_str *uri; + struct arg_lit *status; + struct arg_str *username; + struct arg_str *password; + struct arg_lit *cert; + struct arg_lit *key; + struct arg_lit *cafile; + struct arg_lit *disconnect; + + struct arg_end *end; +} mqtt_args; + +static struct { + struct arg_str *topic; + struct arg_lit *unsubscribe; + + struct arg_end *end; +} mqtt_sub_args; + +static struct { + struct arg_str *topic; + struct arg_str *message; + + struct arg_end *end; +} mqtt_pub_args; + +typedef enum { + MQTT_STATE_INIT = 0, + MQTT_STATE_DISCONNECTED, + MQTT_STATE_CONNECTED, + MQTT_STATE_ERROR, + MQTT_STATE_STOPPED, +} mqtt_client_state_t; + +mqtt_client_state_t client_status = MQTT_STATE_INIT; + +static esp_mqtt_client_handle_t client_handle = NULL; + +static const uint8_t *s_own_cert_pem_start = NULL; +static const uint8_t *s_own_cert_pem_end = NULL; +static const uint8_t *s_own_key_pem_start = NULL; +static const uint8_t *s_own_key_pem_end = NULL; +static const uint8_t *s_ca_cert_pem_start = NULL; +static const uint8_t *s_ca_cert_pem_end = NULL; + +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; + switch ((esp_mqtt_event_id_t)event_id) { + case MQTT_EVENT_BEFORE_CONNECT: + ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT"); + break; + case MQTT_EVENT_CONNECTED: + client_status = MQTT_STATE_CONNECTED; + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + break; + case MQTT_EVENT_DISCONNECTED: + client_status = MQTT_STATE_DISCONNECTED; + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + ESP_LOGI(TAG, "TOPIC=%.*s\r\n", event->topic_len, event->topic); + ESP_LOGI(TAG, "DATA=%.*s\r\n", event->data_len, event->data); + break; + case MQTT_EVENT_ERROR: + client_status = MQTT_STATE_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_config_free(esp_mqtt_client_config_t mqtt_cfg) +{ + if (mqtt_cfg.broker.address.uri) { + free((char *)mqtt_cfg.broker.address.uri); + } +} + + +static const char *mqtt_state_to_string(mqtt_client_state_t state) +{ + switch (state) { + case MQTT_STATE_INIT: + return "Initializing"; + case MQTT_STATE_DISCONNECTED: + return "Disconnected"; + case MQTT_STATE_CONNECTED: + return "Connected"; + case MQTT_STATE_ERROR: + return "Error"; + case MQTT_STATE_STOPPED: + return "Disconnected and Stopped"; + default: + return "Unknown State"; + } +} + + +static int do_mqtt_cmd(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&mqtt_args); + if (nerrors != 0) { + arg_print_errors(stderr, mqtt_args.end, argv[0]); + return 1; + } + + if (mqtt_args.status->count > 0) { + ESP_LOGI(TAG, "MQTT Client Status: %s\n", mqtt_state_to_string(client_status)); + return 0; + } + + if (mqtt_args.connect->count > 0) { + + if (client_handle != NULL) { + ESP_LOGI(TAG, "mqtt client already connected"); + ESP_LOGI(TAG, "Try: %s", DISCONNECT_HELP_MSG); + return 0; + } + + char *uri; + if (mqtt_args.uri->count > 0) { + uri = strdup(mqtt_args.uri->sval[0]); + } else { + uri = strdup(CONFIG_MQTT_BROKER_URL); + } + + if (uri == NULL) { + ESP_LOGE(TAG, "Memory allocation failure"); + return 1; + } + + esp_mqtt_client_config_t mqtt_cfg = { + .broker.address.uri = uri, + }; + + if ((mqtt_args.username->count > 0) && (mqtt_args.password->count > 0)) { + mqtt_cfg.credentials.username = mqtt_args.username->sval[0]; + mqtt_cfg.credentials.authentication.password = mqtt_args.password->sval[0]; + } + + ESP_LOGI(TAG, "broker: %s", mqtt_cfg.broker.address.uri); + + if (mqtt_args.cafile->count > 0) { + if (s_ca_cert_pem_start && s_ca_cert_pem_end) { + mqtt_cfg.broker.verification.certificate = (const char *)s_ca_cert_pem_start; + } else { + ESP_LOGW(TAG, "cafile not provided"); + } + } + + if (mqtt_args.cert->count > 0) { + if (s_own_cert_pem_start && s_own_cert_pem_end) { + mqtt_cfg.credentials.authentication.certificate = (const char *)s_own_cert_pem_start; + } else { + ESP_LOGW(TAG, "cert not provided"); + } + + if (mqtt_args.key->count > 0) { + if (s_own_key_pem_start && s_own_key_pem_end) { + mqtt_cfg.credentials.authentication.key = (const char *)s_own_key_pem_start; + } else { + ESP_LOGW(TAG, "key not provided"); + } + } else { + mqtt_cfg.credentials.authentication.key = NULL; + } + } + + client_handle = esp_mqtt_client_init(&mqtt_cfg); + if (client_handle == NULL) { + ESP_LOGE(TAG, "ERROR: Client init"); + ESP_LOGI(TAG, "Try: %s", DISCONNECT_HELP_MSG); + ESP_LOGE(TAG, CONNECT_HELP_MSG); + mqtt_config_free(mqtt_cfg); + return 1; + } + + /* 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_handle, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); + esp_mqtt_client_start(client_handle); + + mqtt_config_free(mqtt_cfg); + + } else if (mqtt_args.disconnect->count > 0) { + ESP_LOGD(TAG, "Disconnect command received:"); + + if (client_handle == NULL) { + ESP_LOGE(TAG, "mqtt client not connected"); + return 0; + } + + if (esp_mqtt_client_stop(client_handle) != ESP_OK) { + ESP_LOGE(TAG, "Failed to stop mqtt client task"); + return 1; + } + + client_handle = NULL; + client_status = MQTT_STATE_STOPPED; + ESP_LOGI(TAG, "mqtt client disconnected and stopped"); + } + + return 0; +} + + +esp_err_t set_mqtt_client_cert(const uint8_t *client_cert_pem_start_i, const uint8_t *client_cert_pem_end_i) +{ + if (!client_cert_pem_start_i || !client_cert_pem_end_i || + (client_cert_pem_start_i > client_cert_pem_end_i)) { + ESP_LOGE(TAG, "Invalid mqtt Client certs(%d)\n", __LINE__); + return ESP_ERR_INVALID_ARG; + } + + s_own_cert_pem_start = client_cert_pem_start_i; + s_own_cert_pem_end = client_cert_pem_end_i; + + return ESP_OK; +} + + +esp_err_t set_mqtt_client_key(const uint8_t *client_key_pem_start_i, const uint8_t *client_key_pem_end_i) +{ + if (client_key_pem_start_i && client_key_pem_end_i && + (client_key_pem_start_i >= client_key_pem_end_i)) { + ESP_LOGE(TAG, "Invalid mqtt Client key(%d)\n", __LINE__); + return ESP_ERR_INVALID_ARG; + } + + s_own_key_pem_start = client_key_pem_start_i; + s_own_key_pem_end = client_key_pem_end_i; + + return ESP_OK; +} + + +esp_err_t set_mqtt_server_certs(const uint8_t *ca_cert_pem_start_i, const uint8_t *ca_cert_pem_end_i) +{ + if (!ca_cert_pem_start_i || !ca_cert_pem_end_i || + (ca_cert_pem_start_i > ca_cert_pem_end_i)) { + ESP_LOGE(TAG, "Invalid mqtt ca cert(%d)\n", __LINE__); + return ESP_ERR_INVALID_ARG; + } + + s_ca_cert_pem_start = ca_cert_pem_start_i; + s_ca_cert_pem_end = ca_cert_pem_end_i; + + return ESP_OK; +} + + +static int do_mqtt_sub_cmd(int argc, char **argv) +{ + int msg_id; + int nerrors = arg_parse(argc, argv, (void **)&mqtt_sub_args); + if (nerrors != 0) { + arg_print_errors(stderr, mqtt_sub_args.end, argv[0]); + return 1; + } + + if (client_handle == NULL) { + ESP_LOGE(TAG, "mqtt client not connected"); + return 0; + } + + if (mqtt_sub_args.unsubscribe->count > 0) { + if (mqtt_sub_args.topic->count <= 0) { + ESP_LOGE(TAG, UNSUBSCRIBE_HELP_MSG); + return 0; + } + char *topic = (char *)mqtt_sub_args.topic->sval[0]; + + msg_id = esp_mqtt_client_unsubscribe(client_handle, mqtt_sub_args.topic->sval[0]); + ESP_LOGI(TAG, "Unsubscribe successful, msg_id=%d, topic=%s", msg_id, topic); + + } else { + if (mqtt_sub_args.topic->count <= 0) { + ESP_LOGE(TAG, SUBSCRIBE_HELP_MSG); + return 0; + } + char *topic = (char *)mqtt_sub_args.topic->sval[0]; + + msg_id = esp_mqtt_client_subscribe(client_handle, topic, 0); + ESP_LOGI(TAG, "Subscribe successful, msg_id=%d, topic=%s", msg_id, topic); + + } + + return 0; +} + + +static int do_mqtt_pub_cmd(int argc, char **argv) +{ + int msg_id; + int nerrors = arg_parse(argc, argv, (void **)&mqtt_pub_args); + if (nerrors != 0) { + arg_print_errors(stderr, mqtt_pub_args.end, argv[0]); + return 1; + } + + if (client_handle == NULL) { + ESP_LOGE(TAG, "mqtt client not connected"); + return 0; + } + + if ((mqtt_pub_args.topic->count <= 0) || (mqtt_pub_args.message->count <= 0)) { + ESP_LOGE(TAG, PUBLISH_HELP_MSG); + } + + msg_id = esp_mqtt_client_publish(client_handle, + mqtt_pub_args.topic->sval[0], + mqtt_pub_args.message->sval[0], + 0, 1, 0); + if (msg_id == -1) { + ESP_LOGE(TAG, "mqtt client not connected"); + return 0; + } + ESP_LOGI(TAG, "Publish successful, msg_id=%d, topic=%s, data=%s", + msg_id, mqtt_pub_args.topic->sval[0], mqtt_pub_args.message->sval[0]); + + return 0; +} + +/** + * @brief Registers the mqtt commands. + * + * @return + * - esp_err_t + */ +esp_err_t console_cmd_mqtt_register(void) +{ + esp_err_t ret = ESP_OK; + + /* Register mqtt */ + mqtt_args.connect = arg_lit0("C", "connect", "Connect to a broker (flag, no argument)"); + mqtt_args.uri = arg_str0("h", "host", "", "Specify the host uri to connect to"); + mqtt_args.status = arg_lit0("s", "status", "Displays the status of the mqtt client (flag, no argument)"); + mqtt_args.username = arg_str0("u", "username", "", "Provide a username to be used for authenticating with the broker"); + mqtt_args.password = arg_str0("P", "password", "", "Provide a password to be used for authenticating with the broker"); + mqtt_args.cert = arg_lit0(NULL, "cert", "Define the PEM encoded certificate for this client, if required by the server (flag, no argument)"); + mqtt_args.key = arg_lit0(NULL, "key", "Define the PEM encoded private key for this client, if required by the server (flag, no argument)"); + mqtt_args.cafile = arg_lit0(NULL, "cafile", "Define the PEM encoded CA certificates that are trusted (flag, no argument)"); + mqtt_args.disconnect = arg_lit0("D", "disconnect", "Disconnect from the broker (flag, no argument)"); + mqtt_args.end = arg_end(1); + + const esp_console_cmd_t mqtt_cmd = { + .command = "mqtt", + .help = "mqtt command", + .hint = NULL, + .func = &do_mqtt_cmd, + .argtable = &mqtt_args + }; + + ret = esp_console_cmd_register(&mqtt_cmd); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Unable to register mqtt"); + return ret; + } + + /* Register mqtt_pub */ + mqtt_pub_args.topic = arg_str0("t", "topic", "", "Topic to Subscribe/Publish"); + mqtt_pub_args.message = arg_str0("m", "message", "", "Message to Publish"); + mqtt_pub_args.end = arg_end(1); + + const esp_console_cmd_t mqtt_pub_cmd = { + .command = "mqtt_pub", + .help = "mqtt publish command", + .hint = NULL, + .func = &do_mqtt_pub_cmd, + .argtable = &mqtt_pub_args + }; + + ret = esp_console_cmd_register(&mqtt_pub_cmd); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Unable to register mqtt_pub"); + return ret; + } + + /* Register mqtt_sub */ + mqtt_sub_args.topic = arg_str0("t", "topic", "", "Topic to Subscribe/Publish"); + mqtt_sub_args.unsubscribe = arg_lit0("U", "unsubscribe", "Unsubscribe from a topic"); + mqtt_sub_args.end = arg_end(1); + + const esp_console_cmd_t mqtt_sub_cmd = { + .command = "mqtt_sub", + .help = "mqtt subscribe command", + .hint = NULL, + .func = &do_mqtt_sub_cmd, + .argtable = &mqtt_sub_args + }; + + ret = esp_console_cmd_register(&mqtt_sub_cmd); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Unable to register mqtt_sub"); + } + + return ret; +} diff --git a/components/console_cmd_mqtt/console_mqtt.h b/components/console_cmd_mqtt/console_mqtt.h new file mode 100644 index 00000000000..b4a639a80d3 --- /dev/null +++ b/components/console_cmd_mqtt/console_mqtt.h @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "console_simple_init.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Registers the mqtt command. + * + * @return + * - esp_err_t + */ +esp_err_t console_cmd_mqtt_register(void); + + +/** + * @brief Set MQTT client certificate + * + * This function sets the MQTT client certificate for secure communication. + * The function takes the PEM(Privacy Enhanced Mail) encoded certificate arguments. + * + * @param client_cert_pem_start_i Pointer to the beginning of the client certificate PEM data. + * @param client_cert_pem_end_i Pointer to the end of the client certificate PEM data. + * + * @return + * ESP_OK on success + * ESP_ERR_INVALID_ARG on invalid arguments + */ +esp_err_t set_mqtt_client_cert(const uint8_t *client_cert_pem_start_i, const uint8_t *client_cert_pem_end_i); + + +/** + * @brief Set MQTT client key + * + * This function sets the MQTT client key for secure communication. + * The function takes the PEM(Privacy Enhanced Mail) encoded key arguments. + * + * @param client_key_pem_start_i Pointer to the beginning of the client key PEM data. + * @param client_key_pem_end_i Pointer to the end of the client key PEM data. + * + * @return + * ESP_OK on success + * ESP_ERR_INVALID_ARG on invalid arguments + */ +esp_err_t set_mqtt_client_key(const uint8_t *client_key_pem_start_i, const uint8_t *client_key_pem_end_i); + + +/** + * @brief Set MQTT server certificate + * + * This function sets the MQTT server certificate for secure communication. + * The function takes the PEM(Privacy Enhanced Mail) encoded server certificate arguments. + * + * @param server_cert_pem_start_i Pointer to the beginning of the server certificate PEM data. + * @param server_cert_pem_end_i Pointer to the end of the server certificate PEM data. + * + * @return + * ESP_OK on success + * ESP_ERR_INVALID_ARG on invalid arguments + */ +esp_err_t set_mqtt_server_certs(const uint8_t *server_cert_pem_start_i, const uint8_t *server_cert_pem_end_i); + +#ifdef __cplusplus +} +#endif diff --git a/components/console_cmd_mqtt/examples/ssl_mutual_auth/CMakeLists.txt b/components/console_cmd_mqtt/examples/ssl_mutual_auth/CMakeLists.txt new file mode 100644 index 00000000000..2466c7aa300 --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/CMakeLists.txt @@ -0,0 +1,11 @@ +# The following five 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) +project(ssl_mutual_auth) + +# Certs for mqtts://test.mosquitto.org:8884 +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/components/console_cmd_mqtt/examples/ssl_mutual_auth/README.md b/components/console_cmd_mqtt/examples/ssl_mutual_auth/README.md new file mode 100644 index 00000000000..7205a137993 --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/README.md @@ -0,0 +1,139 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | + +# ESP-MQTT SSL Sample application (mutual authentication) + +This example illustrates the use of the MQTT command component for both secured and unsecured MQTT brokers. +It connects to the broker at test.mosquitto.org using either unsecured transport or SSL transport with a client certificate. The operations of subscribing to and unsubscribing from a specified topic, as well as sending a message on that topic, can be performed using commands. +(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). + +Note: Incase your certificate and keys file name differs, please update the root `CMakeLists.txt` file and main/`ssl_mutual_auth.c` accordingly. + +### 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. + + +### Command Usage: +``` +esp> help +help [] + Print the summary of all registered commands if no arguments are given, + otherwise print summary of given command. + Name of command + +mqtt [-CsD] [-h ] [-u ] [-P ] [--cert] [--key] [--cafile] + mqtt command + -C, --connect Connect to a broker (flag, no argument) + -h, --host= Specify the host uri to connect to + -s, --status Displays the status of the mqtt client (flag, no argument) + -u, --username= Provide a username to be used for authenticating with the broker + -P, --password= Provide a password to be used for authenticating with the broker + --cert Define the PEM encoded certificate for this client, if required by the server (flag, no argument) + --key Define the PEM encoded private key for this client, if required by the server (flag, no argument) + --cafile Define the PEM encoded CA certificates that are trusted (flag, no argument) + -D, --disconnect Disconnect from the broker (flag, no argument) + +mqtt_pub [-t ] [-m ] + mqtt publish command + -t, --topic= Topic to Subscribe/Publish + -m, --message= Message to Publish + +mqtt_sub [-U] [-t ] + mqtt subscribe command + -t, --topic= Topic to Subscribe/Publish + -U, --unsubscribe Unsubscribe from a topic +``` + +#### Connect: +``` +esp> mqtt -h mqtts://test.mosquitto.org -C +I (168235) console_mqtt: broker: mqtts://test.mosquitto.org +I (168235) console_mqtt: MQTT_EVENT_BEFORE_CONNECT +esp> I (170285) console_mqtt: MQTT_EVENT_CONNECTED +esp> +``` + +#### Connect(encrypted, client certificate required): +``` +esp> mqtt -h mqtts://test.mosquitto.org:8884 -C --cert --key --cafile +I (668129) console_mqtt: broker: mqtts://test.mosquitto.org:8884 +I (668129) console_mqtt: MQTT_EVENT_BEFORE_CONNECT +esp> I (671679) console_mqtt: MQTT_EVENT_CONNECTED +esp> +``` + +#### Disconnect: +``` +esp> mqtt -D +I (1189949) console_mqtt: mqtt client disconnected +``` + +#### Subscribe/Unsubscribe: +``` +esp> mqtt_sub -t test0 +I (897289) console_mqtt: Subscribe successful, msg_id=57425, topic=test0 +esp> I (897799) console_mqtt: MQTT_EVENT_SUBSCRIBED, msg_id=57425 +esp> +esp> mqtt_sub -U -t test0 +I (902009) console_mqtt: Unsubscribe successful, msg_id=27663, topic=test0 +esp> I (902509) console_mqtt: MQTT_EVENT_UNSUBSCRIBED, msg_id=27663 +``` + +#### Publish: +``` +esp> mqtt_pub -t test0 -m "Hello, Testing 123" +I (999469) console_mqtt: Publish successful, msg_id=55776, topic=test0, data=Hello, Testing 123 +I (1000009) console_mqtt: MQTT_EVENT_PUBLISHED, msg_id=55776 +esp> +``` + +#### Receiving data event: +``` +esp> I (999999) console_mqtt: MQTT_EVENT_DATA +I (999999) console_mqtt: TOPIC=test0 + +I (999999) console_mqtt: DATA=Hello, Testing 123 +``` diff --git a/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/CMakeLists.txt b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/CMakeLists.txt new file mode 100644 index 00000000000..3e381022792 --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "ssl_mutual_auth.c" + INCLUDE_DIRS ".") diff --git a/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/client.crt b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/client.crt new file mode 100644 index 00000000000..fe6f78f84c1 --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/client.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBkDELMAkGA1UEBhMCR0Ix +FzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTESMBAGA1UE +CgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVpdHRvLm9y +ZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzAeFw0yNDA1MDgwMTM5 +MzVaFw0yNDA4MDYwMTM5MzVaMIGVMQswCQYDVQQGEwJBVTERMA8GA1UECAwIVmlj +dG9yaWExEjAQBgNVBAcMCU1lbGJvdXJuZTESMBAGA1UECgwJRXNwcmVzc2lmMRMw +EQYDVQQLDApOZXR3b3JraW5nMQ4wDAYDVQQDDAVBYmhpazEmMCQGCSqGSIb3DQEJ +ARYXYWJoaWsucm95QGVzcHJlc3NpZi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDTtaF4ilaKKq5Ff409KNblfmJkfqjXBxSWj6fneIbsGssNZopi +6/CRqy0fbnr9fgHXIACdjk5HOmyStdtTHqFOAF+RIOqtjE2kAA2YJmomF9pD28Ph +sDppicxi561j0rvQgWcn1bWaRQe7ZmNXxtoOrXnVlWVwcdUcBiWQ29/2K8r8wNhk +m1O2qdyWsYphIdLutURbH5PkXht6HNoqXIuOTfYcXdz3QDV5Slph105Pox9lNPBg +99RVV8I3DFiDDr1BElqudcSLaecYr8bxiiwjciOcCmX5MX5DccLWzwMSTjknRCEx +wL2T64qnBRYsaKOTp1FwybuMDlvw3J6nbMhpAgMBAAGjGjAYMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQBJs3n1mSASzav7qq+UsTza +iWlsY9vio8ikhvtr1tfZyad1lTF9j2g68l5xyJMd34qY+EmSfOOAwKBZUBf36Qya +wDbmOEXmpM89QtZZqG2Nm0GyQTcJ9KMDWE1b0ckt/rkRrWi5mrKbonT250YpPOrt +SCe7Ah4W8kzN58VgmiMjSGKPzYXzJ8D1OmEw93NMGYsHwZ90U3QDVxd3WzHpPSwn +aOOel6eAE4L7FifzoO+6wGHqJz+9LRAqOVH3BFQ5KlIyoNAzJjA6Zz7eFfIRhYKC +1sOzNj04mU783sctgYrya7IzQBihjOESCdZrGMiM14LtpIkjVh3JPMe7CdLHzeYs +-----END CERTIFICATE----- diff --git a/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/client.key b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/client.key new file mode 100644 index 00000000000..9cf1a4c14ff --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTtaF4ilaKKq5F +f409KNblfmJkfqjXBxSWj6fneIbsGssNZopi6/CRqy0fbnr9fgHXIACdjk5HOmyS +tdtTHqFOAF+RIOqtjE2kAA2YJmomF9pD28PhsDppicxi561j0rvQgWcn1bWaRQe7 +ZmNXxtoOrXnVlWVwcdUcBiWQ29/2K8r8wNhkm1O2qdyWsYphIdLutURbH5PkXht6 +HNoqXIuOTfYcXdz3QDV5Slph105Pox9lNPBg99RVV8I3DFiDDr1BElqudcSLaecY +r8bxiiwjciOcCmX5MX5DccLWzwMSTjknRCExwL2T64qnBRYsaKOTp1FwybuMDlvw +3J6nbMhpAgMBAAECggEAJxUwPmL3b+FKM71E0yYPaeVnf5rcS3ncpKDXg8U9zydx +FcO4x2M8EYAyv8sy/En/R/n58xwauk6ATaMx3onYiGBMRCv59tjgWmbCG7T3wpmD +qyROaIMSfXo5V4bifPuhvW+uHe33bQfSUheoPkOQ7MW8qJ/ATr5M87P0ymW01ipQ +RBMZlYOJ6h47GJdMZNuUCbCmclS2cVOES6E8grF7gvlJ+6LFZCaGJ6K819e3Mw/h +jhI+VbQUSpnfLA+6D85ShESXNHQUf+WTluVCqqUsTjWUj/WdTRRUIWQ9q4mVWqxB +CrC0p/UAw0PbjB1Anwh/qIjTe+664S9PcM7vN3yJUwKBgQD7getItO2c6+RaOiCi +5xwqwg0SLF+eLnuKg5AND12xDUK43tJYY6j8PeDphVq9sZVgQTBW4lfdn3s0A28H +h6I8YYW3TN2ghJyyrerNyzf2qIHvbyru6Of4jIBGB1G8h45DPzksWJk03nPELVbW +fJWXaAe7VW19Gzo4f1BBimOz7wKBgQDXfbmwzywPT2WpfVLKViWBIRQmT/z/5eWp +4B6/NH44PgOs8Zu0VeQXEQKdsmYXrG4SzpRe7QQ9SNqqntUkudz1yfmO3bM/SpBR +ct29QmHY0GTZ6Epuo1Kl9Q9n7j1So8+oD64fKgM9liC9MokbzflwCxHQ+mZPLgjC +hO7koc6RJwKBgDvKWwDh4ksX2SWKBBA2GQAhObJEUkbsjfoT5L72FDPvDxmb/y18 +I8QzgbCCP1wxR22mkbNWA8VwEH4BAvgrSmpIVN2KrHVokUf5CIT79sXwsVMWfoJl +ZCA2Zpg/TTMglrVt5k2gkmt7JtJQZQCAhZ+E37GtUWYYfvLHcXDjUWiJAoGBALjt +qlez0wnoh0Qmys/dkh3490PRzTsGXkukjH5mXBOEFL9sMMVYGIA7FtWibb7POT9m +jSnRmZvGU/GskRoNbzR3enVCiTs9kBB11RlASJw6avIeSRIdkyXc4rW8XF/5OJHv +suwHr/RATCRRpBx6bR/cQBPpb7dvuBDG6ATJX25tAoGBAPVOfEMFS3uAWy7TCg/v +/KC0s7NqV3MyA0/P4DfbS8soYekd2BE3ISNLcwffHoIVtcIZ5ElM5CVC2opw167J +jvwa2it6/nGQZqIFLtb4xYC291iL4IiTYm0v82jBWDBtw8xqN43vU2hk5EaWhpW0 +8GqLjexkQUVbpe9GS+AKFEbD +-----END PRIVATE KEY----- diff --git a/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/idf_component.yml b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/idf_component.yml new file mode 100644 index 00000000000..c426c8a6aa2 --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + idf: + version: ">=5.0" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common + console_cmd_mqtt: + version: "*" + override_path: '../../../' diff --git a/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/mosquitto.org.crt b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/mosquitto.org.crt new file mode 100644 index 00000000000..e76dbd85598 --- /dev/null +++ b/components/console_cmd_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/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/ssl_mutual_auth.c b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/ssl_mutual_auth.c new file mode 100644 index 00000000000..6b342c7c10e --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/main/ssl_mutual_auth.c @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include "nvs_flash.h" +#include "esp_netif.h" +#include "esp_event.h" +#include +#include "console_mqtt.h" +#include "protocol_examples_common.h" + +// Certs for mqtts://test.mosquitto.org:8884 +extern const uint8_t g_client_cert_pem_start[] asm("_binary_client_crt_start"); +extern const uint8_t g_client_cert_pem_end[] asm("_binary_client_crt_end"); +extern const uint8_t g_client_key_pem_start[] asm("_binary_client_key_start"); +extern const uint8_t g_client_key_pem_end[] asm("_binary_client_key_end"); +extern const uint8_t g_server_cert_pem_start[] asm("_binary_mosquitto_org_crt_start"); +extern const uint8_t g_server_cert_pem_end[] asm("_binary_mosquitto_org_crt_end"); + + +void app_main(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_err_t ret = nvs_flash_init(); //Initialize NVS + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * ${IDF_PATH}/examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + // Initialize console REPL + ESP_ERROR_CHECK(console_cmd_init()); + ESP_ERROR_CHECK(console_cmd_all_register()); + + set_mqtt_client_cert(g_client_cert_pem_start, g_client_cert_pem_end); + set_mqtt_client_key(g_client_key_pem_start, g_client_key_pem_end); + set_mqtt_server_certs(g_server_cert_pem_start, g_server_cert_pem_end); + + // start console REPL + ESP_ERROR_CHECK(console_cmd_start()); + +} diff --git a/components/console_cmd_mqtt/examples/ssl_mutual_auth/pytest_ssl_mutual_auth.py b/components/console_cmd_mqtt/examples/ssl_mutual_auth/pytest_ssl_mutual_auth.py new file mode 100644 index 00000000000..e2950d3db1b --- /dev/null +++ b/components/console_cmd_mqtt/examples/ssl_mutual_auth/pytest_ssl_mutual_auth.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 + +# -*- coding: utf-8 -*- + +import pytest + + +@pytest.mark.esp32 +def test_examples_ifconfig_command(dut): + dut.expect('esp>', timeout=30) + dut.write('help mqtt') + dut.expect(r'mqtt [-CsD] [-h ] [-u ] [-P ] [--cert] [--key] [--cafile]', timeout=30) + + dut.write('help mqtt_pub') + dut.expect(r'mqtt_pub [-t ] [-m ]', timeout=30) + + dut.write('help mqtt_sub') + dut.expect(r'mqtt_sub [-U] [-t ]', timeout=30) diff --git a/components/console_cmd_mqtt/idf_component.yml b/components/console_cmd_mqtt/idf_component.yml new file mode 100644 index 00000000000..10e42226ef6 --- /dev/null +++ b/components/console_cmd_mqtt/idf_component.yml @@ -0,0 +1,11 @@ +version: 1.0.0 +url: https://github.com/espressif/esp-protocols/tree/master/components/console_cmd_mqtt +description: The component provides a console where the 'mqtt' command can be executed. +license: Apache-2.0 +dependencies: + idf: + version: '>=5.0' + espressif/console_simple_init: + version: '>=1.1.0' + override_path: '../console_simple_init' + public: true