From d57b8c5b297c6223a285e390df281cf1eb20043f Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 11 Dec 2024 19:21:46 +0100 Subject: [PATCH] feat(mosq): Add example with two brokers synced on P2P Broker-less two chip example which virtual private IoT networks on MQTT protocol. --- .github/workflows/mosq__build.yml | 10 +- ci/check_copyright_ignore.txt | 1 + components/mosquitto/.build-test-rules.yml | 3 + .../examples/serverless_mqtt/CMakeLists.txt | 6 + .../examples/serverless_mqtt/README.md | 53 +++ .../components/libjuice/CMakeLists.txt | 44 +++ .../components/libjuice/include/ifaddrs.h | 13 + .../components/libjuice/port/juice_random.c | 40 ++ .../serverless_mqtt/main/CMakeLists.txt | 4 + .../serverless_mqtt/main/Kconfig.projbuild | 85 ++++ .../serverless_mqtt/main/idf_component.yml | 5 + .../serverless_mqtt/main/serverless_mqtt.c | 374 ++++++++++++++++++ .../serverless_mqtt/main/wifi_connect.c | 122 ++++++ .../serverless_mqtt/sdkconfig.defaults | 3 + .../examples/serverless_mqtt/serverless.png | Bin 0 -> 86433 bytes 15 files changed, 759 insertions(+), 4 deletions(-) create mode 100644 components/mosquitto/.build-test-rules.yml create mode 100644 components/mosquitto/examples/serverless_mqtt/CMakeLists.txt create mode 100644 components/mosquitto/examples/serverless_mqtt/README.md create mode 100644 components/mosquitto/examples/serverless_mqtt/components/libjuice/CMakeLists.txt create mode 100644 components/mosquitto/examples/serverless_mqtt/components/libjuice/include/ifaddrs.h create mode 100644 components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c create mode 100644 components/mosquitto/examples/serverless_mqtt/main/CMakeLists.txt create mode 100644 components/mosquitto/examples/serverless_mqtt/main/Kconfig.projbuild create mode 100644 components/mosquitto/examples/serverless_mqtt/main/idf_component.yml create mode 100644 components/mosquitto/examples/serverless_mqtt/main/serverless_mqtt.c create mode 100644 components/mosquitto/examples/serverless_mqtt/main/wifi_connect.c create mode 100644 components/mosquitto/examples/serverless_mqtt/sdkconfig.defaults create mode 100644 components/mosquitto/examples/serverless_mqtt/serverless.png diff --git a/.github/workflows/mosq__build.yml b/.github/workflows/mosq__build.yml index abf9dbb4b..27ff2581c 100644 --- a/.github/workflows/mosq__build.yml +++ b/.github/workflows/mosq__build.yml @@ -17,7 +17,8 @@ jobs: runs-on: ubuntu-22.04 container: espressif/idf:${{ matrix.idf_ver }} env: - TEST_DIR: components/mosquitto/examples/broker + TEST_DIR: components/mosquitto/examples + TARGET_TEST: broker TARGET_TEST_DIR: build_esp32_default steps: - name: Checkout esp-protocols @@ -29,14 +30,15 @@ jobs: run: | . ${IDF_PATH}/export.sh pip install idf-component-manager idf-build-apps --upgrade - python ci/build_apps.py ${TEST_DIR} - cd ${TEST_DIR} + python ci/build_apps.py -c ${TEST_DIR} -m components/mosquitto/.build-test-rules.yml + # upload only the target test artifacts + cd ${TEST_DIR}/${TARGET_TEST} ${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR} zip -qur artifacts.zip ${TARGET_TEST_DIR} - uses: actions/upload-artifact@v4 with: name: mosq_target_esp32_${{ matrix.idf_ver }} - path: ${{ env.TEST_DIR }}/artifacts.zip + path: ${{ env.TEST_DIR }}/${{ env.TARGET_TEST }}/artifacts.zip if-no-files-found: error test_mosq: diff --git a/ci/check_copyright_ignore.txt b/ci/check_copyright_ignore.txt index e69de29bb..1cd8798f5 100644 --- a/ci/check_copyright_ignore.txt +++ b/ci/check_copyright_ignore.txt @@ -0,0 +1 @@ +components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c diff --git a/components/mosquitto/.build-test-rules.yml b/components/mosquitto/.build-test-rules.yml new file mode 100644 index 000000000..e1f584648 --- /dev/null +++ b/components/mosquitto/.build-test-rules.yml @@ -0,0 +1,3 @@ +components/mosquitto/examples/serverless_mqtt: + disable: + - if: IDF_TARGET not in ["esp32", "esp32s3", "esp32c3"] diff --git a/components/mosquitto/examples/serverless_mqtt/CMakeLists.txt b/components/mosquitto/examples/serverless_mqtt/CMakeLists.txt new file mode 100644 index 000000000..c9935c956 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/CMakeLists.txt @@ -0,0 +1,6 @@ +# 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(serverless_mqtt) diff --git a/components/mosquitto/examples/serverless_mqtt/README.md b/components/mosquitto/examples/serverless_mqtt/README.md new file mode 100644 index 000000000..5ee8369e6 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/README.md @@ -0,0 +1,53 @@ +# Brokerless MQTT Example + +MQTT served by (two) mosquitto's running on two ESP chips. + +* Leverages MQTT connectivity between two private networks without cloud premisses. +* Creates two local MQTT servers (on ESP32x's) which are being synchronized over peer to peer connection (established via ICE protocol, by [libjuice](https://github.com/paullouisageneau/libjuice)). + +## How it works + +This example needs two ESP32 chipsets, that will create two separate Wi-Fi networks (IoT networks) used for IoT devices. +Each IoT network is served by an MQTT server (using mosquitto component). +This example will also synchronize these two MQTT brokers, as if there was only one IoT network with one broker. +This example creates a peer to peer connection between two chipsets to keep them synchronize. This connection utilizes libjuice (which implements a simplified ICE-UDP) to traverse NATs, which enabling direct connection between two private networks behind NATs. + +* Diagram + +![demo](serverless.png) + +Here's a step-by-step procedure of establishing this remote connection: +1) Initialize and start Wi-Fi AP (for IoT networks) and Wi-Fi station (for internet connection) +2) Start mosquitto broker on IoT network +3) Start libjuice to gather connection candidates +4) Synchronize using a public MQTT broker and exchange ICE descriptors +5) Establish ICE UDP connection between the two ESP32 chipsets +6) Start forwarding mqtt messages + - Each remote datagram (received from ICE-UDP channel) is re-published to the local MQTT server + - Each local MQTT message (received from mosquitto on_message callback) is sent in ICE-UDP datagram + +## How to use this example + +You need two ESP32 devices that support Wi-Fi station and Wi-Fi software access point. + +* Configure Wi-Fi credentials for both devices on both interfaces + * These devices would be deployed in distinct Wi-Fi environments, so the Wi-Fi station credentials would likely be different. + * They also create their own IoT network (on the soft-AP interface) Wi-Fi, so the AP credentials would likely be the same, suggesting the IoT networks will be keep synchronized (even though these are two distict Wi-Fi networks). +* Choose `CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1` for one device and `CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER2` for another. It's not important which device is PEER1, since the code is symmetric, but these two devices need to have different role. +* Optionally: You can use `idf.py` `-D` and `-B` flag to keep separate build directories and sdkconfigs for these two roles +``` +idf.py -B build1 -DSDKCONFIG=build1/sdkconfig menuconfig build flash monitor +``` +* Flash and run the two devices and wait for them to connect and synchronize. +* Now you can test MQTT connectivity, for example: + * Join PEER1 device's AP and connect to the MQTT broker with one or more clients, subscribing to one or more topics. + * Join PEER2 device's AP and connect to the MQTT broker with one or more clients, subscribing to one or more topics. + * Whenever you publish to a topic, all subscribed clients should receive the message, no matter which Wi-Fi network they're connected to. + +## Warning + +This example uses libjuice as a dependency: + +* libjuice (UDP Interactive Connectivity Establishment): https://github.com/paullouisageneau/libjuice + +which is distributed under Mozilla Public License v2.0. diff --git a/components/mosquitto/examples/serverless_mqtt/components/libjuice/CMakeLists.txt b/components/mosquitto/examples/serverless_mqtt/components/libjuice/CMakeLists.txt new file mode 100644 index 000000000..f7cf012d1 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/components/libjuice/CMakeLists.txt @@ -0,0 +1,44 @@ +set(LIBJUICE_VERSION "73785387eafe15c02b6a210edb10f722474e8e14") +set(LIBJUICE_URL "https://github.com/paullouisageneau/libjuice/archive/${LIBJUICE_VERSION}.zip") + +set(libjuice_dir ${CMAKE_BINARY_DIR}/libjuice/libjuice-${LIBJUICE_VERSION}) + +# Fetch the library +if(NOT EXISTS ${libjuice_dir}) + message(STATUS "Downloading libjuice ${LIBJUICE_VERSION}...") + file(DOWNLOAD ${LIBJUICE_URL} ${CMAKE_BINARY_DIR}/libjuice.zip SHOW_PROGRESS) + execute_process(COMMAND unzip -o ${CMAKE_BINARY_DIR}/libjuice.zip -d ${CMAKE_BINARY_DIR}/libjuice + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +endif() + +set(JUICE_SOURCES ${libjuice_dir}/src/addr.c + ${libjuice_dir}/src/agent.c + ${libjuice_dir}/src/base64.c + ${libjuice_dir}/src/conn.c + ${libjuice_dir}/src/conn_mux.c + ${libjuice_dir}/src/conn_poll.c + ${libjuice_dir}/src/conn_thread.c + ${libjuice_dir}/src/const_time.c + ${libjuice_dir}/src/crc32.c + ${libjuice_dir}/src/hash.c + ${libjuice_dir}/src/ice.c + ${libjuice_dir}/src/juice.c + ${libjuice_dir}/src/log.c + ${libjuice_dir}/src/server.c + ${libjuice_dir}/src/stun.c + ${libjuice_dir}/src/timestamp.c + ${libjuice_dir}/src/turn.c + ${libjuice_dir}/src/udp.c +# Use hmac from mbedtls and random numbers from esp_random: +# ${libjuice_dir}/src/hmac.c +# ${libjuice_dir}/src/random.c + ) + +idf_component_register(SRCS port/juice_random.c + ${JUICE_SOURCES} + INCLUDE_DIRS "include" "${libjuice_dir}/include" "${libjuice_dir}/include/juice" + REQUIRES esp_netif + PRIV_REQUIRES sock_utils) + +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") +set_source_files_properties(${libjuice_dir}/src/udp.c PROPERTIES COMPILE_FLAGS -Wno-unused-variable) diff --git a/components/mosquitto/examples/serverless_mqtt/components/libjuice/include/ifaddrs.h b/components/mosquitto/examples/serverless_mqtt/components/libjuice/include/ifaddrs.h new file mode 100644 index 000000000..ba92bc72b --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/components/libjuice/include/ifaddrs.h @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#pragma once + +// Purpose of this header is to replace udp_sendto() to avoid name conflict with lwip +// added here since ifaddrs.h is included from juice_udp sources +#define udp_sendto juice_udp_sendto + +// other than that, let's just include the ifaddrs (from sock_utils) +#include_next "ifaddrs.h" diff --git a/components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c b/components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c new file mode 100644 index 000000000..89c1c6bda --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020 Paul-Louis Ageneau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#include "esp_random.h" + +void juice_random(void *buf, size_t size) +{ + esp_fill_random(buf, size); +} + +void juice_random_str64(char *buf, size_t size) +{ + static const char chars64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t i = 0; + for (i = 0; i + 1 < size; ++i) { + uint8_t byte = 0; + juice_random(&byte, 1); + buf[i] = chars64[byte & 0x3F]; + } + buf[i] = '\0'; +} + +uint32_t juice_rand32(void) +{ + uint32_t r = 0; + juice_random(&r, sizeof(r)); + return r; +} + +uint64_t juice_rand64(void) +{ + uint64_t r = 0; + juice_random(&r, sizeof(r)); + return r; +} diff --git a/components/mosquitto/examples/serverless_mqtt/main/CMakeLists.txt b/components/mosquitto/examples/serverless_mqtt/main/CMakeLists.txt new file mode 100644 index 000000000..b757b7286 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "serverless_mqtt.c" + "wifi_connect.c" + INCLUDE_DIRS "." + REQUIRES libjuice nvs_flash mqtt json esp_wifi) diff --git a/components/mosquitto/examples/serverless_mqtt/main/Kconfig.projbuild b/components/mosquitto/examples/serverless_mqtt/main/Kconfig.projbuild new file mode 100644 index 000000000..7e0e97de0 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/main/Kconfig.projbuild @@ -0,0 +1,85 @@ +menu "Example Configuration" + + menu "AP Configuration" + comment "AP Configuration" + + config EXAMPLE_AP_SSID + string "Wi-Fi SSID" + default "myssid" + help + Set the SSID of Wi-Fi ap interface. + + config EXAMPLE_AP_PASSWORD + string "Wi-Fi Password" + default "12345678" + help + Set the password of Wi-Fi ap interface. + + endmenu + + menu "STA Configuration" + comment "STA Configuration" + + config EXAMPLE_STA_SSID + string "WiFi Station SSID" + default "mystationssid" + help + SSID for the example's sta to connect to. + + config EXAMPLE_STA_PASSWORD + string "WiFi Station Password" + default "mystationpassword" + help + WiFi station password for the example to use. + endmenu + + config EXAMPLE_MQTT_BROKER_URI + string "MQTT Broker URL" + default "mqtt://mqtt.eclipseprojects.io" + help + URL of the mqtt broker use for synchronisation and exchanging + ICE connect info (description and candidates). + + config EXAMPLE_MQTT_SYNC_TOPIC + string "MQTT topic for synchronisation" + default "/topic/serverless_mqtt" + help + MQTT topic used fo synchronisation. + + config EXAMPLE_STUN_SERVER + string "Hostname of STUN server" + default "stun.l.google.com" + help + STUN server hostname. + + config EXAMPLE_MQTT_CLIENT_STACK_SIZE + int "Stack size for mqtt client" + default 16384 + help + Set stack size for the mqtt client. + Need more stack, since calling juice API from the handler. + + config EXAMPLE_MQTT_BROKER_PORT + int "port for the mosquitto to listen to" + default 1883 + help + This is a port which the local mosquitto uses. + + choice EXAMPLE_SERVERLESS_ROLE + prompt "Choose your role" + default EXAMPLE_SERVERLESS_ROLE_PEER1 + help + Choose either peer1 or peer2. + It's not very important which device is peer1 + (peer-1 sends sync messages, peer2 listens for them) + It is important that we have two peers, + one with peer1 config, another one with peer2 config + + config EXAMPLE_SERVERLESS_ROLE_PEER1 + bool "peer1" + + config EXAMPLE_SERVERLESS_ROLE_PEER2 + bool "peer2" + endchoice + +endmenu diff --git a/components/mosquitto/examples/serverless_mqtt/main/idf_component.yml b/components/mosquitto/examples/serverless_mqtt/main/idf_component.yml new file mode 100644 index 000000000..e3297d535 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/main/idf_component.yml @@ -0,0 +1,5 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/mosquitto: + override_path: ../../.. + espressif/sock_utils: "*" diff --git a/components/mosquitto/examples/serverless_mqtt/main/serverless_mqtt.c b/components/mosquitto/examples/serverless_mqtt/main/serverless_mqtt.c new file mode 100644 index 000000000..8dd0bee7c --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/main/serverless_mqtt.c @@ -0,0 +1,374 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "mqtt_client.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_random.h" +#include "esp_check.h" +#include "esp_sleep.h" +#include "mosq_broker.h" +#include "juice/juice.h" +#include "cJSON.h" + +#if defined(CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1) +#define OUR_PEER "1" +#define THEIR_PEER "2" +#elif defined(CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER2) +#define OUR_PEER "2" +#define THEIR_PEER "1" +#endif + +#define PEER_SYNC0 BIT(0) +#define PEER_SYNC1 BIT(1) +#define PEER_SYNC2 BIT(2) +#define PEER_FAIL BIT(3) +#define PEER_GATHER_DONE BIT(4) +#define PEER_DESC_PUBLISHED BIT(5) +#define PEER_CONNECTED BIT(6) + +#define SYNC_BITS (PEER_SYNC1 | PEER_SYNC2 | PEER_FAIL) + +#define PUBLISH_SYNC_TOPIC CONFIG_EXAMPLE_MQTT_SYNC_TOPIC OUR_PEER +#define SUBSCRIBE_SYNC_TOPIC CONFIG_EXAMPLE_MQTT_SYNC_TOPIC THEIR_PEER +#define MAX_BUFFER_SIZE JUICE_MAX_SDP_STRING_LEN + +typedef struct message_wrap { + uint16_t topic_len; + uint16_t data_len; + char data[]; +} __attribute__((packed)) message_wrap_t; + +static const char *TAG = "serverless_mqtt" OUR_PEER; +static char s_buffer[MAX_BUFFER_SIZE]; +static EventGroupHandle_t s_state = NULL; +static juice_agent_t *s_agent = NULL; +static cJSON *s_peer_desc_json = NULL; +static char *s_peer_desc = NULL; +static esp_mqtt_client_handle_t s_local_mqtt = NULL; + +char *wifi_get_ipv4(wifi_interface_t interface); +esp_err_t wifi_connect(void); +static esp_err_t sync_peers(void); +static esp_err_t create_candidates(void); +static esp_err_t create_local_client(void); +static esp_err_t create_local_broker(void); + +void app_main(void) +{ + __attribute__((__unused__)) esp_err_t ret; + ESP_GOTO_ON_ERROR(wifi_connect(), err, TAG, "Failed to initialize WiFi"); + ESP_GOTO_ON_ERROR(create_local_broker(), err, TAG, "Failed to create local broker"); + ESP_GOTO_ON_ERROR(create_candidates(), err, TAG, "Failed to create juice candidates"); + ESP_GOTO_ON_ERROR(sync_peers(), err, TAG, "Failed to sync with the other peer"); + EventBits_t bits = xEventGroupWaitBits(s_state, PEER_FAIL | PEER_CONNECTED, pdFALSE, pdFALSE, pdMS_TO_TICKS(90000)); + if (bits & PEER_CONNECTED) { + ESP_LOGI(TAG, "Peer is connected!"); + ESP_GOTO_ON_ERROR(create_local_client(), err, TAG, "Failed to create forwarding mqtt client"); + ESP_LOGI(TAG, "Everything is ready, exiting main task"); + return; + } +err: + ESP_LOGE(TAG, "Non recoverable error, going to sleep for some time (random, max 20s)"); + esp_deep_sleep(1000000LL * (esp_random() % 20)); +} + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + esp_mqtt_event_handle_t event = event_data; + esp_mqtt_client_handle_t client = event->client; + switch ((esp_mqtt_event_id_t)event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + if (esp_mqtt_client_subscribe(client, SUBSCRIBE_SYNC_TOPIC, 1) < 0) { + ESP_LOGE(TAG, "Failed to subscribe to the sync topic"); + } + xEventGroupSetBits(s_state, PEER_SYNC0); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + xEventGroupSetBits(s_state, PEER_FAIL); + break; + + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + if (s_state == NULL || memcmp(event->topic, SUBSCRIBE_SYNC_TOPIC, event->topic_len) != 0) { + break; + } + EventBits_t bits = xEventGroupGetBits(s_state); + if (event->data_len > 1 && s_agent) { + cJSON *root = cJSON_Parse(event->data); + if (root == NULL) { + break; + } + cJSON *desc = cJSON_GetObjectItem(root, "desc"); + if (desc == NULL) { + cJSON_Delete(root); + break; + } + printf("desc->valuestring:%s\n", desc->valuestring); + juice_set_remote_description(s_agent, desc->valuestring); + char cand_name[] = "cand0"; + while (true) { + cJSON *cand = cJSON_GetObjectItem(root, cand_name); + if (cand == NULL) { + break; + } + printf("%s: cand->valuestring:%s\n", cand_name, cand->valuestring); + juice_add_remote_candidate(s_agent, cand->valuestring); + cand_name[4]++; + } + cJSON_Delete(root); + xEventGroupSetBits(s_state, PEER_DESC_PUBLISHED); // this will complete the sync process + // and destroy the mqtt client + } +#ifdef CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1 + if (event->data_len == 1 && event->data[0] == '1' && (bits & PEER_SYNC2) == 0) { + if (esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, "2", 1, 1, 0) >= 0) { + xEventGroupSetBits(s_state, PEER_SYNC2); + } else { + xEventGroupSetBits(s_state, PEER_FAIL); + } + } +#else + if (event->data_len == 1 && event->data[0] == '0' && (bits & PEER_SYNC1) == 0) { + if (esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, "1", 1, 1, 0) >= 0) { + xEventGroupSetBits(s_state, PEER_SYNC1); + } else { + xEventGroupSetBits(s_state, PEER_FAIL); + } + } else if (event->data_len == 1 && event->data[0] == '2' && (bits & PEER_SYNC2) == 0) { + xEventGroupSetBits(s_state, PEER_SYNC2); + } +#endif + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + xEventGroupSetBits(s_state, PEER_FAIL); + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } +} + +static esp_err_t sync_peers(void) +{ + esp_err_t ret = ESP_OK; + esp_mqtt_client_config_t mqtt_cfg = { + .broker.address.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI, + .task.stack_size = CONFIG_EXAMPLE_MQTT_CLIENT_STACK_SIZE, + }; + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + ESP_GOTO_ON_FALSE(client, ESP_ERR_NO_MEM, err, TAG, "Failed to create mqtt client"); + ESP_GOTO_ON_ERROR(esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL), + err, TAG, "Failed to register mqtt event handler"); + ESP_GOTO_ON_ERROR(esp_mqtt_client_start(client), err, TAG, "Failed to start mqtt client"); + ESP_GOTO_ON_FALSE(xEventGroupWaitBits(s_state, PEER_SYNC0, pdTRUE, pdTRUE, pdMS_TO_TICKS(10000)), + ESP_FAIL, err, TAG, "Failed to connect to the sync broker"); + ESP_LOGI(TAG, "Waiting for the other peer..."); + const int max_sync_retry = 60; + int retry = 0; + while (true) { + EventBits_t bits = xEventGroupWaitBits(s_state, SYNC_BITS, pdTRUE, pdFALSE, pdMS_TO_TICKS(1000)); + if (bits & PEER_SYNC2) { + break; + } + if (bits & PEER_SYNC1) { + continue; + } + ESP_GOTO_ON_FALSE((bits & PEER_FAIL) == 0, ESP_FAIL, err, TAG, "Failed to sync with the other peer"); + ESP_GOTO_ON_FALSE(retry++ < max_sync_retry, ESP_FAIL, err, TAG, "Failed to sync after %d seconds", retry); +#ifdef CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1 + ESP_RETURN_ON_FALSE(esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, "0", 1, 1, 0) >= 0, + ESP_FAIL, TAG, "Failed to publish mqtt message"); +#endif + } + ESP_LOGI(TAG, "Sync done"); + ESP_RETURN_ON_FALSE(esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, s_peer_desc, 0, 1, 0) >= 0, + ESP_FAIL, TAG, "Failed to publish peer's description"); + ESP_LOGI(TAG, "Waiting for the other peer description and candidates..."); + ESP_GOTO_ON_FALSE(xEventGroupWaitBits(s_state, PEER_DESC_PUBLISHED, pdTRUE, pdTRUE, pdMS_TO_TICKS(10000)), + ESP_FAIL, err, TAG, "Timeout in waiting for the other peer candidates"); +err: + free(s_peer_desc); + esp_mqtt_client_destroy(client); + return ret; +} + +static void juice_state(juice_agent_t *agent, juice_state_t state, void *user_ptr) +{ + ESP_LOGI(TAG, "JUICE state change: %s", juice_state_to_string(state)); + if (state == JUICE_STATE_CONNECTED) { + xEventGroupSetBits(s_state, PEER_CONNECTED); + } else if (state == JUICE_STATE_FAILED || state == JUICE_STATE_DISCONNECTED) { + esp_restart(); + } +} + +static void juice_candidate(juice_agent_t *agent, const char *sdp, void *user_ptr) +{ + static uint8_t cand_nr = 0; + if (s_peer_desc_json && cand_nr < 10) { // supporting only 10 candidates + char cand_name[] = "cand0"; + cand_name[4] += cand_nr++; + cJSON_AddStringToObject(s_peer_desc_json, cand_name, sdp); + } +} + +static void juice_gathering_done(juice_agent_t *agent, void *user_ptr) +{ + ESP_LOGI(TAG, "Gathering done"); + if (s_state) { + xEventGroupSetBits(s_state, PEER_GATHER_DONE); + } +} + +#define ALIGN(size) (((size) + 3U) & ~(3U)) + +static void juice_recv(juice_agent_t *agent, const char *data, size_t size, void *user_ptr) +{ + if (s_local_mqtt) { + message_wrap_t *message = (message_wrap_t *)data; + int topic_len = message->topic_len; + int payload_len = message->data_len; + int topic_len_aligned = ALIGN(topic_len); + char *topic = message->data; + char *payload = message->data + topic_len_aligned; + if (topic_len + topic_len_aligned + 4 > size) { + ESP_LOGE(TAG, "Received invalid message"); + return; + } + ESP_LOGI(TAG, "forwarding remote message: topic:%s", topic); + ESP_LOGI(TAG, "forwarding remote message: payload:%.*s", payload_len, payload); + esp_mqtt_client_publish(s_local_mqtt, topic, payload, payload_len, 0, 0); + } +} + +static esp_err_t create_candidates(void) +{ + ESP_RETURN_ON_FALSE(s_state = xEventGroupCreate(), ESP_ERR_NO_MEM, TAG, "Failed to create state event group"); + s_peer_desc_json = cJSON_CreateObject(); + esp_err_t ret = ESP_OK; + juice_set_log_level(JUICE_LOG_LEVEL_INFO); + juice_config_t config = { .stun_server_host = CONFIG_EXAMPLE_STUN_SERVER, + .bind_address = wifi_get_ipv4(WIFI_IF_STA), + .stun_server_port = 19302, + .cb_state_changed = juice_state, + .cb_candidate = juice_candidate, + .cb_gathering_done = juice_gathering_done, + .cb_recv = juice_recv, + }; + + s_agent = juice_create(&config); + ESP_RETURN_ON_FALSE(s_agent, ESP_FAIL, TAG, "Failed to create juice agent"); + ESP_GOTO_ON_FALSE(juice_get_local_description(s_agent, s_buffer, MAX_BUFFER_SIZE) == JUICE_ERR_SUCCESS, + ESP_FAIL, err, TAG, "Failed to get local description"); + ESP_LOGI(TAG, "desc: %s", s_buffer); + cJSON_AddStringToObject(s_peer_desc_json, "desc", s_buffer); + + ESP_GOTO_ON_FALSE(juice_gather_candidates(s_agent) == JUICE_ERR_SUCCESS, + ESP_FAIL, err, TAG, "Failed to start gathering candidates"); + ESP_GOTO_ON_FALSE(xEventGroupWaitBits(s_state, PEER_GATHER_DONE, pdTRUE, pdTRUE, pdMS_TO_TICKS(30000)), + ESP_FAIL, err, TAG, "Failed to connect to the sync broker"); + s_peer_desc = cJSON_Print(s_peer_desc_json); + ESP_LOGI(TAG, "desc: %s", s_peer_desc); + cJSON_Delete(s_peer_desc_json); + return ESP_OK; + +err: + juice_destroy(s_agent); + s_agent = NULL; + cJSON_Delete(s_peer_desc_json); + s_peer_desc_json = NULL; + return ret; +} + +static void local_handler(void *args, esp_event_base_t base, int32_t id, void *data) +{ + switch (id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "local client connected"); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "local client disconnected"); + break; + + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "local client error"); + break; + default: + ESP_LOGI(TAG, "local client event id:%d", (int)id); + break; + } +} + +static esp_err_t create_local_client(void) +{ + esp_err_t ret = ESP_OK; + esp_mqtt_client_config_t mqtt_cfg = { + .broker.address.transport = MQTT_TRANSPORT_OVER_TCP, + .broker.address.hostname = wifi_get_ipv4(WIFI_IF_AP), + .broker.address.port = CONFIG_EXAMPLE_MQTT_BROKER_PORT, + .task.stack_size = CONFIG_EXAMPLE_MQTT_CLIENT_STACK_SIZE, + .credentials.client_id = "local_mqtt" + }; + s_local_mqtt = esp_mqtt_client_init(&mqtt_cfg); + ESP_GOTO_ON_FALSE(s_local_mqtt, ESP_ERR_NO_MEM, err, TAG, "Failed to create mqtt client"); + ESP_GOTO_ON_ERROR(esp_mqtt_client_register_event(s_local_mqtt, ESP_EVENT_ANY_ID, local_handler, NULL), + err, TAG, "Failed to register mqtt event handler"); + ESP_GOTO_ON_ERROR(esp_mqtt_client_start(s_local_mqtt), err, TAG, "Failed to start mqtt client"); + + return ESP_OK; +err: + esp_mqtt_client_destroy(s_local_mqtt); + s_local_mqtt = NULL; + return ret; +} + +static void handle_message(char *client, char *topic, char *payload, int len, int qos, int retain) +{ + if (client && strcmp(client, "local_mqtt") == 0 ) { + // This is our little local client -- do not forward + return; + } + ESP_LOGI(TAG, "handle_message topic:%s", topic); + ESP_LOGI(TAG, "handle_message data:%.*s", len, payload); + ESP_LOGI(TAG, "handle_message qos=%d, retain=%d", qos, retain); + if (s_local_mqtt && s_agent) { + int topic_len = strlen(topic) + 1; // null term + int topic_len_aligned = ALIGN(topic_len); + int total_msg_len = 2 + 2 /* msg_wrap header */ + topic_len_aligned + len; + if (total_msg_len > MAX_BUFFER_SIZE) { + ESP_LOGE(TAG, "Fail to forward, message too long"); + return; + } + message_wrap_t *message = (message_wrap_t *)s_buffer; + message->topic_len = topic_len; + message->data_len = len; + + memcpy(s_buffer + 4, topic, topic_len); + memcpy(s_buffer + 4 + topic_len_aligned, payload, len); + juice_send(s_agent, s_buffer, total_msg_len); + } +} + +static void broker_task(void *ctx) +{ + struct mosq_broker_config config = { .host = wifi_get_ipv4(WIFI_IF_AP), .port = CONFIG_EXAMPLE_MQTT_BROKER_PORT, .handle_message_cb = handle_message }; + mosq_broker_run(&config); + vTaskDelete(NULL); +} + +static esp_err_t create_local_broker(void) +{ + return xTaskCreate(broker_task, "mqtt_broker_task", 1024 * 32, NULL, 5, NULL) == pdTRUE ? + ESP_OK : ESP_FAIL; +} diff --git a/components/mosquitto/examples/serverless_mqtt/main/wifi_connect.c b/components/mosquitto/examples/serverless_mqtt/main/wifi_connect.c new file mode 100644 index 000000000..aeb3af759 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/main/wifi_connect.c @@ -0,0 +1,122 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_check.h" +#include "esp_wifi.h" +#include "esp_mac.h" + +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +static const char *TAG = "serverless_wifi"; +static EventGroupHandle_t s_wifi_events; +static int s_retry_num = 0; +static const int s_max_retry = 30; + +static void wifi_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_id == WIFI_EVENT_AP_STACONNECTED) { + wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *) event_data; + ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", + MAC2STR(event->mac), event->aid); + } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { + wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data; + ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", + MAC2STR(event->mac), event->aid); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < s_max_retry) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_wifi_events, WIFI_FAIL_BIT); + } + ESP_LOGI(TAG, "Connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + ESP_LOGI(TAG, "Got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_events, WIFI_CONNECTED_BIT); + } +} + +esp_err_t wifi_connect(void) +{ + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(s_wifi_events = xEventGroupCreate(), ESP_ERR_NO_MEM, err, TAG, "Failed to create wifi_events"); + ESP_GOTO_ON_ERROR(nvs_flash_init(), err, TAG, "Failed to init nvs flash"); + ESP_GOTO_ON_ERROR(esp_netif_init(), err, TAG, "Failed to init esp_netif"); + ESP_GOTO_ON_ERROR(esp_event_loop_create_default(), err, TAG, "Failed to create default event loop"); + ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL), + err, TAG, "Failed to register WiFi event handler"); + ESP_GOTO_ON_ERROR(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL), + err, TAG, "Failed to register IP event handler"); + + // Initialize WiFi + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_GOTO_ON_ERROR(esp_wifi_init(&cfg), err, TAG, "Failed to initialize WiFi"); + ESP_GOTO_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_APSTA), err, TAG, "Failed to set STA+AP mode"); + + // Initialize AP + esp_netif_t *ap = esp_netif_create_default_wifi_ap(); + ESP_GOTO_ON_FALSE(ap, ESP_FAIL, err, TAG, "Failed to create AP network interface"); + wifi_config_t wifi_ap_config = { + .ap = { + .ssid = CONFIG_EXAMPLE_AP_SSID, + .password = CONFIG_EXAMPLE_AP_PASSWORD, + .authmode = WIFI_AUTH_WPA2_PSK, + .max_connection = 4, + }, + }; + ESP_GOTO_ON_ERROR(esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config), err, TAG, "Failed to set AP config"); + + + // Initialize STA + esp_netif_t *sta = esp_netif_create_default_wifi_sta(); + ESP_GOTO_ON_FALSE(sta, ESP_FAIL, err, TAG, "Failed to create WiFi station network interface"); + wifi_config_t wifi_sta_config = { + .sta = { + .ssid = CONFIG_EXAMPLE_STA_SSID, + .password = CONFIG_EXAMPLE_STA_PASSWORD, + }, + }; + ESP_GOTO_ON_ERROR(esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config), err, TAG, "Failed to set STA config"); + + // Start WiFi + ESP_GOTO_ON_ERROR(esp_wifi_start(), err, TAG, "Failed to start WiFi"); + + // Wait for connection + EventBits_t bits = xEventGroupWaitBits(s_wifi_events, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, pdFALSE, pdMS_TO_TICKS(30000)); + ESP_GOTO_ON_FALSE((bits & WIFI_CONNECTED_BIT) == WIFI_CONNECTED_BIT, ESP_FAIL, err, + TAG, "Failed to obtain IP address from WiFi station"); + return ESP_OK; +err: + esp_wifi_stop(); + esp_wifi_deinit(); + nvs_flash_deinit(); + esp_netif_deinit(); + esp_event_loop_delete_default(); + return ret; + +} + +_Thread_local char s_ipv4_addr[4 * 4]; // 4 octets + '.'/term + +char *wifi_get_ipv4(wifi_interface_t interface) +{ + esp_netif_t *netif = esp_netif_get_handle_from_ifkey(interface == WIFI_IF_AP ? "WIFI_AP_DEF" : "WIFI_STA_DEF"); + ESP_RETURN_ON_FALSE(netif, NULL, TAG, "Failed to find default Wi-Fi netif"); + esp_netif_ip_info_t ip_info; + ESP_RETURN_ON_FALSE(esp_netif_get_ip_info(netif, &ip_info) == ESP_OK, NULL, TAG, "Failed to get IP from netif"); + ESP_RETURN_ON_FALSE(esp_ip4addr_ntoa(&ip_info.ip, s_ipv4_addr, sizeof(s_ipv4_addr)) != NULL, NULL, TAG, "Failed to convert IP"); + return s_ipv4_addr; +} diff --git a/components/mosquitto/examples/serverless_mqtt/sdkconfig.defaults b/components/mosquitto/examples/serverless_mqtt/sdkconfig.defaults new file mode 100644 index 000000000..037b68015 --- /dev/null +++ b/components/mosquitto/examples/serverless_mqtt/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y +CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=32768 diff --git a/components/mosquitto/examples/serverless_mqtt/serverless.png b/components/mosquitto/examples/serverless_mqtt/serverless.png new file mode 100644 index 0000000000000000000000000000000000000000..6822526427e764d6b0d8377665240eae41e77cf8 GIT binary patch literal 86433 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 z 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 literal 0 HcmV?d00001