This is the first successful integration of Zenoh-Pico on the ESP32 using the ESP-IDF. I could not find other such working examples online.
This is a fully functional template with all the necessary patches needed for zenoh-pico to be ported over ESP-IDF v5.4.1, for both PUB/SUB over zenoh. Also includes Python scripts for testing.
More about zenoh and zenoh-pico, here Zenoh-Pico
More about ESP-IDF, here ESP-IDF Setup Guide
Rearding the Python scripts and running the zenoh local server, read carefully the readme.txt file inside the folder /python_scripts
#Zenoh #ESP32 #ESPRESSIF #ESP-IDF #IoT #EdgeComputing #Microcontrollers #FreeRTOS
- ESP-IDF Environment: You must have the ESP-IDF development environment installed and configured.
- Git: You must have Git installed on your system.
- ESP-IDF v5.4.1 installed and configured
- ESP32-S3 board (or compatible, used also ESP32-CAM)
- Git, Python, and required ESP-IDF tools installed
How to create a new project named esp32_zenoh
- Open the ESP-IDF Command Prompt Open the enabled command prompt for your ESP-IDF version (e.g., "ESP-IDF 5.x CMD").
- Create the Project
idf.py create-project esp32_zenoh- Enter the Project Directory
cd esp32_zenohNext, install the zenoh library as a component
Use git submodule to add the zenoh-pico library to the project.
- Create the
componentsDirectory From the root ofesp32_zenohproject, create the directory components (exact name needed).
mkdir components- Add
zenoh-picoas a Git Submodule Go into the components directory and clone the git repo.
cd components
git submodule add [https://github.com/eclipse-zenoh/zenoh-pico.git](https://github.com/eclipse-zenoh/zenoh-pico.git)- Initialize the Submodule Goto to the project root and run the update command, just in case.
cd ..
git submodule update --init --recursiveIn project root, create the CMakeLists.txt file:
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(zenoh_esp32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DZENOHPICO_PLATFORM_ESP32")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DZENOH_ESPIDF")
add_definitions(-DZENOH_FREERTOS_LWIP)
the name in project(zenoh_esp32) should match the folder name.
in /main folder, add this CMakeList.txt file
idf_component_register(SRCS "z_pub.c" "utils/wifi.c"
INCLUDE_DIRS "." "utils"
REQUIRES zenoh-pico nvs_flash
PRIV_REQUIRES esp_event esp_wifi log freertos
)
add_definitions(-DZENOHPICO_PLATFORM_ESP32)
NOTE Folder 'utils' will hold the wifi connection and the configuration(s).
Make sure you substitute the file /components/zenoh-pico/CMakeList.txt with the follwoing (the original creates alot of errors!)
# Find all the common source files
file(GLOB_RECURSE PICO_SRCS_COMMON
"src/api/*.c"
"src/collections/*.c"
"src/link/*.c"
"src/net/*.c"
"src/protocol/*.c"
"src/session/*.c"
"src/transport/*.c"
"src/utils/*.c"
"src/system/common/*.c"
)
# Find the platform-specific files for FreeRTOS + LWIP (used by ESP-IDF)
file(GLOB_RECURSE PICO_SRCS_PLATFORM
"src/system/freertos/lwip/*.c"
"src/system/freertos/system.c"
)
# Combine the lists of common and platform-specific files
list(APPEND PICO_SRCS_COMMON ${PICO_SRCS_PLATFORM})
# Register the component with the specific source files.
idf_component_register(SRCS ${PICO_SRCS_COMMON}
INCLUDE_DIRS "include"
REQUIRES freertos lwip)
# Add all compile definitions to the correct __idf_zenoh-pico component target
target_compile_definitions(__idf_zenoh-pico PUBLIC
ZENOH_FREERTOS_LWIP
Z_LOG_LEVEL_DEFAULT=Z_LOG_LEVEL_TRACE
# Definitions for memory and timeout fix
Z_FRAG_MAX_SIZE=1024
Z_BATCH_UNICAST_SIZE=1024
Z_BATCH_MULTICAST_SIZE=1024
Z_CONFIG_SOCKET_TIMEOUT=5000
)
file /components/zenoh-pico/include/zenoh-pico/config.h MUST ALTER
#define Z_FRAG_MAX_SIZE 4096
#define Z_BATCH_UNICAST_SIZE 2048
#define Z_BATCH_MULTICAST_SIZE 2048
#define Z_CONFIG_SOCKET_TIMEOUT 5000
MOST IMPORTANT seems to be the line Z_CONFIG_SOCKET_TIMEOUT 100from 100 to 5000. LATER ADDITION: It seems to work with #define Z_CONFIG_SOCKET_TIMEOUT 1000. Feel free to experiment with shorter values, but definitely much bigger than the initial 100. Moreover, it mentions in the config.h "*pass values to CMake to change the following tokens*", so feel free to pass them via CMake.
zenoh can listen to both UDP and TCP. The only line you need to change is
#define LOCATOR "udp/demo.zenoh.io:7447"
to
#define LOCATOR "tcp/demo.zenoh.io:7447"
Make sure that the server is working (the zenoh people kindly enabled during the writing of this project, thank you!). The easiest way to test is telnet demo.zenoh.io:7447. If it stays connected, it works.
If you have DHCP issues with demo.zenoh.io, switch to IP address of it.
Running the ESP on the IP address of the computer where you will run the subscriber.py script.
- On Windows: Open Command Prompt and type ipconfig.
- On macOS/Linux: Open a terminal and type ifconfig or ip a.
File: components\zenoh-pico\include\zenoh-pico\system\platform\freertos\lwip.h
Alter by adding "freertos/" in front of any include "not found"
// George
#include "freertos/FreeRTOS.h"
#include "lwip/sockets.h"
#include "freertos/semphr.h"
#ifdef __cplusplus
extern "C" {
#endif
#if Z_FEATURE_MULTI_THREAD == 1
// George
#include "freertos/event_groups.h"
in file /components/zenoh-pico/src/system/freertos/lwip/network.c
alter the
#include "FreeRTOS.h"
to
#include "freertos/FreeRTOS.h"
File \components\zenoh-pico\src\system\freertos\system.c
Add in line ~49
static portMUX_TYPE task_mux = portMUX_INITIALIZER_UNLOCKED;
Line ~151
// George
taskENTER_CRITICAL(&task_mux);
if (task->handle != NULL) {
vTaskDelete(task->handle);
task->handle = NULL;
}
// George
taskEXIT_CRITICAL(&task_mux);
Line ~168
// George
taskENTER_CRITICAL(&task_mux);
if (task->handle != NULL) {
vTaskDelete(task->handle);
task->handle = NULL;
}
// George
taskEXIT_CRITICAL(&task_mux);
File components/zenoh-pico/src/system/freertos/lwip/network.c
replace:
inet_addr_from_ip4addr(&lsockaddr_in->sin_addr, ip_2_ip4(ip4_addr));
with
inet_addr_from_ip4addr(&lsockaddr_in->sin_addr, ip4_addr);
Errors of not finding libraries like this #include "FreeRTOS.h", replace with #include "freertos/FreeRTOS.h"
Run idf.py menuconfig
Go to Component config ---> Log output ---> Set Default log verbosity to Debug or Info.
Go to Component config ---> LWIP ---> Enable LWIP DEBUG.
Inside the LWIP DEBUG menu, enable TCP & UDP Debug (CONFIG_LWIP_TCP_DEBUG).
BE CAREFUL: Flood of messages, could crash.
MUST DO: Go to folder main/utils, rename the file secret.h.template to secret.h and fill the wifi credentials (SSID, password).
the /main folder has two files: z_pub.c, z_sub.c. You can choose which one to run by altering the first line of the main/CMakeList.txt file. By defauit it runs the z_pub.c.
Configure the target chip and build the project
- Set the Target Chip (e.g., for a standard ESP32)
idf.py set-target esp32
If you switch chips, it will complain, you have to run it again.
- Build & Flash
idf.py fullclean build flash monitor -p COMXX
You can run the python scripts to establish ping/pong (PUB/SUB). Feel free to use for non-commercial apps.


