Skip to content

Commit 840a561

Browse files
authored
Merge pull request #710 from david-cermak/feat/mosq_p2p_example
[mosq]: Add serverless broker example
2 parents 9c11003 + e6fb8aa commit 840a561

23 files changed

+797
-8
lines changed

.github/workflows/mosq__build.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ jobs:
1717
runs-on: ubuntu-22.04
1818
container: espressif/idf:${{ matrix.idf_ver }}
1919
env:
20-
TEST_DIR: components/mosquitto/examples/broker
20+
TEST_DIR: components/mosquitto/examples
21+
TARGET_TEST: broker
2122
TARGET_TEST_DIR: build_esp32_default
2223
steps:
2324
- name: Checkout esp-protocols
@@ -29,14 +30,15 @@ jobs:
2930
run: |
3031
. ${IDF_PATH}/export.sh
3132
pip install idf-component-manager idf-build-apps --upgrade
32-
python ci/build_apps.py ${TEST_DIR}
33-
cd ${TEST_DIR}
33+
python ci/build_apps.py -c ${TEST_DIR} -m components/mosquitto/.build-test-rules.yml
34+
# upload only the target test artifacts
35+
cd ${TEST_DIR}/${TARGET_TEST}
3436
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
3537
zip -qur artifacts.zip ${TARGET_TEST_DIR}
3638
- uses: actions/upload-artifact@v4
3739
with:
3840
name: mosq_target_esp32_${{ matrix.idf_ver }}
39-
path: ${{ env.TEST_DIR }}/artifacts.zip
41+
path: ${{ env.TEST_DIR }}/${{ env.TARGET_TEST }}/artifacts.zip
4042
if-no-files-found: error
4143

4244
test_mosq:

ci/check_copyright_ignore.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
components/mosquitto/examples/serverless_mqtt:
2+
disable:
3+
- if: IDF_TARGET not in ["esp32", "esp32s3", "esp32c3"]

components/mosquitto/.cz.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ commitizen:
33
bump_message: 'bump(mosq): $current_version -> $new_version'
44
pre_bump_hooks: python ../../ci/changelog.py mosquitto
55
tag_format: mosq-v$version
6-
version: 2.0.28~0
6+
version: 2.0.20
77
version_files:
88
- idf_component.yml

components/mosquitto/CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
1+
# Changelog
2+
3+
## [2.0.20](https://github.com/espressif/esp-protocols/commits/mosq-v2.0.20)
4+
5+
### Features
6+
7+
- Upgrade to mosquitto v2.0.20 ([3b2c614d](https://github.com/espressif/esp-protocols/commit/3b2c614d))
8+
- Add support for on-message callback ([cdeab8f5](https://github.com/espressif/esp-protocols/commit/cdeab8f5))
9+
- Add example with two brokers synced on P2P ([d57b8c5b](https://github.com/espressif/esp-protocols/commit/d57b8c5b))
10+
11+
### Bug Fixes
12+
13+
- Fix dependency issues moving esp-tls to public deps ([6cce87e4](https://github.com/espressif/esp-protocols/commit/6cce87e4))
14+
115
## [2.0.28~0](https://github.com/espressif/esp-protocols/commits/mosq-v2.0.28_0)
216

17+
### Warning
18+
19+
Incorrect version number! This version published under `2.0.28~0` is based on upstream v2.0.18
20+
321
### Features
422

523
- Added support for TLS transport using ESP-TLS ([1af4bbe1](https://github.com/espressif/esp-protocols/commit/1af4bbe1))

components/mosquitto/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ idf_component_register(SRCS ${m_srcs}
8181
PRIV_INCLUDE_DIRS port/priv_include port/priv_include/sys ${m_dir} ${m_src_dir}
8282
${m_incl_dir} ${m_lib_dir} ${m_deps_dir}
8383
INCLUDE_DIRS ${m_incl_dir} port/include
84-
PRIV_REQUIRES newlib esp-tls
84+
REQUIRES esp-tls
85+
PRIV_REQUIRES newlib
8586
)
8687

8788
target_compile_definitions(${COMPONENT_LIB} PRIVATE "WITH_BROKER")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The following five lines of boilerplate have to be in your project's
2+
# CMakeLists in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.16)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
project(serverless_mqtt)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Brokerless MQTT Example
2+
3+
MQTT served by (two) mosquitto's running on two ESP chips.
4+
5+
* Leverages MQTT connectivity between two private networks without cloud premisses.
6+
* 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)).
7+
8+
## How it works
9+
10+
This example needs two ESP32 chipsets, that will create two separate Wi-Fi networks (IoT networks) used for IoT devices.
11+
Each IoT network is served by an MQTT server (using mosquitto component).
12+
This example will also synchronize these two MQTT brokers, as if there was only one IoT network with one broker.
13+
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.
14+
15+
* Diagram
16+
17+
![demo](serverless.png)
18+
19+
Here's a step-by-step procedure of establishing this remote connection:
20+
1) Initialize and start Wi-Fi AP (for IoT networks) and Wi-Fi station (for internet connection)
21+
2) Start mosquitto broker on IoT network
22+
3) Start libjuice to gather connection candidates
23+
4) Synchronize using a public MQTT broker and exchange ICE descriptors
24+
5) Establish ICE UDP connection between the two ESP32 chipsets
25+
6) Start forwarding mqtt messages
26+
- Each remote datagram (received from ICE-UDP channel) is re-published to the local MQTT server
27+
- Each local MQTT message (received from mosquitto on_message callback) is sent in ICE-UDP datagram
28+
29+
## How to use this example
30+
31+
You need two ESP32 devices that support Wi-Fi station and Wi-Fi software access point.
32+
33+
* Configure Wi-Fi credentials for both devices on both interfaces
34+
* These devices would be deployed in distinct Wi-Fi environments, so the Wi-Fi station credentials would likely be different.
35+
* 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).
36+
* 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.
37+
* Optionally: You can use `idf.py` `-D` and `-B` flag to keep separate build directories and sdkconfigs for these two roles
38+
```
39+
idf.py -B build1 -DSDKCONFIG=build1/sdkconfig menuconfig build flash monitor
40+
```
41+
* Flash and run the two devices and wait for them to connect and synchronize.
42+
* Now you can test MQTT connectivity, for example:
43+
* Join PEER1 device's AP and connect to the MQTT broker with one or more clients, subscribing to one or more topics.
44+
* Join PEER2 device's AP and connect to the MQTT broker with one or more clients, subscribing to one or more topics.
45+
* Whenever you publish to a topic, all subscribed clients should receive the message, no matter which Wi-Fi network they're connected to.
46+
47+
## Warning
48+
49+
This example uses libjuice as a dependency:
50+
51+
* libjuice (UDP Interactive Connectivity Establishment): https://github.com/paullouisageneau/libjuice
52+
53+
which is distributed under Mozilla Public License v2.0.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
set(LIBJUICE_VERSION "73785387eafe15c02b6a210edb10f722474e8e14")
2+
set(LIBJUICE_URL "https://github.com/paullouisageneau/libjuice/archive/${LIBJUICE_VERSION}.zip")
3+
4+
set(libjuice_dir ${CMAKE_BINARY_DIR}/libjuice/libjuice-${LIBJUICE_VERSION})
5+
6+
# Fetch the library
7+
if(NOT EXISTS ${libjuice_dir})
8+
message(STATUS "Downloading libjuice ${LIBJUICE_VERSION}...")
9+
file(DOWNLOAD ${LIBJUICE_URL} ${CMAKE_BINARY_DIR}/libjuice.zip SHOW_PROGRESS)
10+
execute_process(COMMAND unzip -o ${CMAKE_BINARY_DIR}/libjuice.zip -d ${CMAKE_BINARY_DIR}/libjuice
11+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
12+
endif()
13+
14+
set(JUICE_SOURCES ${libjuice_dir}/src/addr.c
15+
${libjuice_dir}/src/agent.c
16+
${libjuice_dir}/src/base64.c
17+
${libjuice_dir}/src/conn.c
18+
${libjuice_dir}/src/conn_mux.c
19+
${libjuice_dir}/src/conn_poll.c
20+
${libjuice_dir}/src/conn_thread.c
21+
${libjuice_dir}/src/const_time.c
22+
${libjuice_dir}/src/crc32.c
23+
${libjuice_dir}/src/hash.c
24+
${libjuice_dir}/src/ice.c
25+
${libjuice_dir}/src/juice.c
26+
${libjuice_dir}/src/log.c
27+
${libjuice_dir}/src/server.c
28+
${libjuice_dir}/src/stun.c
29+
${libjuice_dir}/src/timestamp.c
30+
${libjuice_dir}/src/turn.c
31+
${libjuice_dir}/src/udp.c
32+
# Use hmac from mbedtls and random numbers from esp_random:
33+
# ${libjuice_dir}/src/hmac.c
34+
# ${libjuice_dir}/src/random.c
35+
)
36+
37+
idf_component_register(SRCS port/juice_random.c
38+
${JUICE_SOURCES}
39+
INCLUDE_DIRS "include" "${libjuice_dir}/include" "${libjuice_dir}/include/juice"
40+
REQUIRES esp_netif
41+
PRIV_REQUIRES sock_utils)
42+
43+
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
44+
set_source_files_properties(${libjuice_dir}/src/udp.c PROPERTIES COMPILE_FLAGS -Wno-unused-variable)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
#pragma once
7+
8+
// Purpose of this header is to replace udp_sendto() to avoid name conflict with lwip
9+
// added here since ifaddrs.h is included from juice_udp sources
10+
#define udp_sendto juice_udp_sendto
11+
12+
// other than that, let's just include the ifaddrs (from sock_utils)
13+
#include_next "ifaddrs.h"

0 commit comments

Comments
 (0)