-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #710 from david-cermak/feat/mosq_p2p_example
[mosq]: Add serverless broker example
- Loading branch information
Showing
23 changed files
with
797 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
components/mosquitto/examples/serverless_mqtt: | ||
disable: | ||
- if: IDF_TARGET not in ["esp32", "esp32s3", "esp32c3"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
44 changes: 44 additions & 0 deletions
44
components/mosquitto/examples/serverless_mqtt/components/libjuice/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
13 changes: 13 additions & 0 deletions
13
components/mosquitto/examples/serverless_mqtt/components/libjuice/include/ifaddrs.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |
40 changes: 40 additions & 0 deletions
40
components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
4 changes: 4 additions & 0 deletions
4
components/mosquitto/examples/serverless_mqtt/main/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
idf_component_register(SRCS "serverless_mqtt.c" | ||
"wifi_connect.c" | ||
INCLUDE_DIRS "." | ||
REQUIRES libjuice nvs_flash mqtt json esp_wifi) |
85 changes: 85 additions & 0 deletions
85
components/mosquitto/examples/serverless_mqtt/main/Kconfig.projbuild
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
5 changes: 5 additions & 0 deletions
5
components/mosquitto/examples/serverless_mqtt/main/idf_component.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
## IDF Component Manager Manifest File | ||
dependencies: | ||
espressif/mosquitto: | ||
override_path: ../../.. | ||
espressif/sock_utils: "*" |
Oops, something went wrong.