서론
이전 Zephyr 실습 시리즈에서는 Skpang사의 ESP32 CAN 보드를 이용하여 Zephyr 포팅에서부터 Wi-Fi Scan, AP 등록, UDP 통신, TCP 통신 그리고 마지막으로 MQTT IoT 프로젝트까지 단계적으로 실습하였습니다.
이 과정에서 Wi-Fi와 TCP/IP 네트워크, MQTT와 같은 기능을 Zephyr의 API를 이용하여 구현하였으며, ESP32에서 MQTT Broker를 거쳐 FastAPI 서버까지 연결되는 전체 IoT 통신 구조도 확인하였습니다.
이번에는 Seeed Studio사의 XIAO ESP32S3 보드에 Zephyr RTOS를 포팅하고, 이전 ESP32 보드에서 작성한 Zephyr 애플리케이션을 이식하여 정상적으로 동작하는지를 검증해 보도록 하겠습니다.
단순히 XIAO ESP32S3에서 Wi-Fi나 MQTT를 다시 구현하는 것이 이번 실습의 목적은 아닙니다. 기존 보드에서 작성한 Zephyr 애플리케이션을 다른 보드로 옮겼을 때 어느 정도까지 코드를 그대로 재사용할 수 있는가를 실제 하드웨어를 통해 확인하는 것이 주된 목적입니다.
먼저 Wi-Fi Scan 프로젝트를 이식하여 기본적인 Wi-Fi 동작을 확인하고, 이후 기존 ESP32 MQTT 프로젝트의 네트워크 및 MQTT 코드를 XIAO ESP32S3로 확장하여 MQTT Publish와 Subscribe를 시험합니다. 마지막으로 기존 Mosquitto MQTT Broker 및 FastAPI/Uvicorn 서버와 연동하여 실제 IoT 통신 경로까지 확인합니다.
이를 통해 Zephyr를 사용했을 때 보드 변경에 따른 하드웨어 의존성을 어느 정도 줄일 수 있는지, 그리고 기존 애플리케이션 코드를 새로운 보드에서 얼마나 재사용할 수 있는지를 살펴보겠습니다.
XIAO ESP32S3 보드 소개
Seeed Studio의 XIAO 시리즈는 ESP32-S3를 비롯하여 다양한 제조사의 MCU를 탑재한 소형 개발 보드 제품군입니다.
아래는 XIAO시리즈의 사진입니다.

대표적인 MCU로는 ESP32 계열, RA4M1, RP2350, RP2040, nRF52840, nRF54L15 등이 있습니다.
21 × 17.8 mm 크기의 초소형 보드로, 웨어러블 디바이스를 비롯하여 크기가 제한되는 소형 IoT 애플리케이션에 적용할 수 있습니다.
아래 링크는 XIAO 공식 사이트 입니다.
이번 포팅 실습에 사용할 보드는 XIAO ESP32S3입니다.
XIAO ESP32S3는 Espressif의 ESP32-S3 MCU를 기반으로 하는 소형 개발 보드입니다. 작은 크기에도 Wi-Fi와 Bluetooth 통신 기능을 내장하고 있어 센서 노드나 IoT 장치처럼 크기가 제한되는 애플리케이션에 활용하기에 적합합니다.
Aliexpress 에서 13,150원에 구매를 하였습니다.
아래는 제품 사진입니다. 왼쪽의 플라스틱으로 된 소형 원통에 포장되어 배달되었으며 꺼내어 안테나를 장착한 그림입니다.

아래는 주요 사양입니다.
| 항목 | 사양 |
|---|---|
| MCU | ESP32-S3R8 SoC |
| CPU | Xtensa LX7 Dual-Core 32-bit |
| 최대 동작 주파수 | 240 MHz |
| Wi-Fi | 2.4 GHz Wi-Fi |
| Bluetooth | Bluetooth Low Energy 5.0 / Bluetooth Mesh |
| PSRAM | 8 MB |
| Flash | 8 MB |
| UART | 1개 |
| I2C | 1개 |
| SPI | 1개 |
| GPIO (PWM) | 11개 |
| ADC | 9개 |
| User LED | 1개 |
| Charge LED | 1개 |
| Reset Button | 1개 |
| Boot Button | 1개 |
| 크기 | 21 × 17.8 mm |
아래 그림은 보드의 Pinout 입니다.

아래는 실험을 위해 XIAO ESP32S3를 브레드보드에 장착한 모습입니다. USB-C 커넥터를 통해 PC와 연결하여 Zephyr 애플리케이션을 다운로드하고 동작 상태를 확인할 수 있습니다.

커스텀 보드 my_xiao_esp32s3 준비
XIAO ESP32S3보드는 Zephyr에서 지원하는 공식 보드로 등록이 되어 있습니다.
아래는 Zephyr 공식 사이트의 XIAO ESP32S3 보드 관련 링크입니다.
XIAO ESP32S3가 Zephyr에서 공식 보드로 지원되고 있기 때문에 공식 보드 정의를 그대로 사용하여 애플리케이션을 빌드하고 실행할 수도 있습니다.
그러나 이번 실습에서는 Zephyr의 보드 구조를 이해하고, 이후 사용자가 직접 제작한 하드웨어에도 동일한 방법을 적용하기 위해 공식 XIAO ESP32S3 보드 정의를 기반으로 my_xiao_esp32s3라는 커스텀 보드를 만들어 사용하였습니다.
가장 먼저 할 일은 Zephyr에서 제공하는 XIAO ESP32S3의 공식 보드 파일을 확인하는 것입니다.
아래는 공식 보드 파일이 들어 있는 폴더 입니다.

Zephyr의 보드 정의에는 MCU 종류, CPU 코어, Flash 및 메모리 구성, GPIO, UART를 비롯한 주변장치와 DeviceTree 설정 등 해당 보드를 빌드하는 데 필요한 정보가 포함되어 있습니다.
이번 실습에서는 이러한 공식 보드 정의를 처음부터 새로 작성하지 않고, 기존 XIAO ESP32S3의 보드 파일을 복사하여 Custom 보드를 만듦니다.
xiao_esp32s3 폴더를 복사하여 D:\Zephyr\workspace\my_boards\boards\seeed 폴더에 붙여넣기 하고 이름을 my_xiao_esp32s3로 바꿉니다.
그리고 복사한 파일 중 파일 이름에 xiao_esp32s3가 포함된 경우 이를 my_xiao_esp32s3로 변경합니다. 파일 내부에서 보드 이름을 참조하는 부분도 새로운 커스텀 보드 이름에 맞게 수정합니다.
아래는 custom 보드인 my_xiao_esp32s3 폴더의 구조 입니다.

이렇게 커스텀 보드를 Zephyr 원본과 분리해 두면 Zephyr 소스 트리를 변경하지 않고도 보드 설정을 독립적으로 관리할 수 있습니다.
또한 애플리케이션을 빌드할 때는 BOARD_ROOT를 지정하여 Zephyr 빌드 시스템이 이 커스텀 보드를 찾을 수 있도록 합니다.
-DBOARD_ROOT="D:/Zephyr/workspace/my_boards"
이렇게 쓰면 실제 현재 디렉터리 구조와 빌드 명령의 BOARD_ROOT가 왜 my_boards까지만 지정되는지도 자연스럽게 연결됩니다.
프로젝트 생성 및 구조 재정립
커스텀 보드 my_xiao_esp32s3의 준비를 마쳤으므로 XIAO ESP32S3에서 사용할 Zephyr 애플리케이션 프로젝트를 구성하겠습니다.
이번 포팅의 최종 목표는 기존 ESP32 보드에서 동작하던 MQTT 프로젝트를 XIAO ESP32S3로 이식하는 것이므로 프로젝트 이름은 다음과 같이 정하였습니다.
xiao_esp32s3_wifimqtt
프로젝트는 기존 ESP32 MQTT 프로젝트의 소스코드를 바로 모두 복사하기보다는, 먼저 기본적인 프로젝트 구조를 만들고 XIAO ESP32S3에서 필요한 기능을 단계적으로 확인하는 방법으로 진행하였습니다.
프로젝트 구조
프로젝트의 기본 구조는 다음과 같이 구성하였습니다.

main.c에는 애플리케이션의 주요 기능을 작성하고, LED 제어 부분은 led.c와 led.h로 분리하였습니다.
MQTT 관련 기능은 main.c에 모두 포함하지 않고 mqtt_client.c와 mqtt_client.h로 분리하여 구성하였습니다. 이를 통해 Wi-Fi 연결 및 애플리케이션의 전체 흐름과 MQTT 처리 부분을 구분하여 관리할 수 있도록 하였습니다.
또한 프로젝트의 변경 과정은 CHANGELOG.md에 기록하여 Wi-Fi Scan을 이용한 기본 동작 확인에서 MQTT 기능을 추가하는 과정까지 포팅 과정을 단계별로 기록하였습니다.
프로젝트별 IntelliSense 관리
이번 프로젝트부터는 VS Code의 IntelliSense 설정도 프로젝트별로 관리하도록 구조를 변경하였습니다.
기존에는 Zephyr Workspace의 .vscode 폴더에서 IntelliSense 설정을 관리하였지만, 프로젝트가 증가하면서 각 프로젝트마다 서로 다른 빌드 결과와 compile_commands.json이 생성되므로, 이를 프로젝트별로 독립적으로 참조하는 것이 관리에 더 편리하다고 판단하였습니다.
따라서 xiao_esp32s3_wifimqtt 프로젝트 내부에 .vscode 폴더를 만들고 다음과 같이 c_cpp_properties.json 파일을 추가하였습니다.

c_cpp_properties.json의 내용은 다음과 같습니다.

여기서는 Zephyr 빌드 과정에서 생성되는 다음 파일을 IntelliSense가 직접 참조하도록 하였습니다.
${workspaceFolder}/build/compile_commands.json
Open Folder로 열어 사용합니다.이번 프로젝트의 경우 다음 폴더를 직접 열었습니다.
D:\Zephyr\workspace\my_projects\xiao_esp32s3_wifimqtt
${workspaceFolder}가 현재 프로젝트 디렉터리를 가리키게 되고, 각 프로젝트에서 생성된 build/compile_commands.json을 독립적으로 사용할 수 있습니다.실제로 이 방법으로 변경한 후 Zephyr 헤더 파일에 표시되던 IntelliSense 오류가 사라지는 것을 확인하였습니다.
앞으로 새로 생성하는 Zephyr 프로젝트에서도 IntelliSense 설정은 각 프로젝트의
.vscode폴더에서 개별적으로 관리하는 방법을 사용하도록 하겠습니다.
아래는 Zephyr 공식 사이트의 Visual Studio Code 설정 관련 문서입니다.
Zephyr 공식 문서 : Visual Studio Code
Wi-Fi Scan을 이용한 사전 확인
MQTT 프로젝트를 본격적으로 이식하기 전에 간단한 Wi-Fi Scan 프로젝트를 이용하여 앞에서 구성한 커스텀 보드 설정과 Wi-Fi 기능을 함께 확인하였습니다.
기존 ESP32 보드에서 작성했던 Wi-Fi Scan 프로젝트를 XIAO ESP32S3에 맞게 이식하고, 커스텀 보드 my_xiao_esp32s3를 대상으로 빌드 및 다운로드를 진행하였습니다.
실행 결과 Zephyr가 XIAO ESP32S3에서 정상적으로 구동되었으며, 주변 Wi-Fi AP의 SSID, RSSI, Channel 정보도 정상적으로 출력되는 것을 확인하였습니다.
이를 통해 앞에서 작성한 my_xiao_esp32s3 보드 설정이 정상적으로 적용되고 있으며, 동시에 ESP32-S3의 Wi-Fi 기능도 Zephyr에서 정상적으로 동작하는 것을 확인할 수 있었습니다.
Wi-Fi Scan 의 자세한 내용은 이전 글인 Zephyr ESP32 실습 #2 – Wi-Fi Scan 를 참조 하시기 바랍니다.
이번 확인 과정에서 이전 Wi-Fi Scan 실습과 달라진 부분은 대상 보드가 my_xiao_esp32s3로 변경되었다는 점입니다. 애플리케이션의 기본 구조와 동작은 기존 프로젝트와 동일하게 유지하였으며, 이를 통해 보드가 변경된 상태에서도 기존 Zephyr 애플리케이션이 정상적으로 동작하는지 쉽게 확인할 수 있었습니다.
이제 커스텀 보드와 Wi-Fi의 기본 동작이 확인되었으므로, 다음 단계에서는 기존 ESP32 보드에서 동작하던 MQTT 프로젝트를 XIAO ESP32S3로 본격적으로 이식해 보겠습니다.
MQTT 프로젝트 이전
프로젝트 구성파일 작성
우리가 새로 작성해야 할 구성파일은 CMakeLists.txt, prj.conf, CHANGELOG.md 입니다.
CHANGELOG.md는 프로그램 동작과는 관계가 없는 프로젝트 관리 차원의 파일 이므로 기본적인 내용과 build 명령, flash 명령, espressif monitor 명령 등을 기록 해 두고 필요 시 복사하여 사용 할 수 있도록 합니다.
먼저 CMakeLists.txt 부터 알아 보겠습니다. 아래는 CMakeLists.txt 의 내용입니다.

project에 xiao_esp32s3_wifimqtt로 표시되고, target_source에는 main.c. led.c, mqtt_client.c가 포함된 것을 확인 할 수 있습니다.
led.c는 이번 프로젝트에 추가한 것으로 보드에서 Zephyr 애플리케이션이 정상적으로 실행되고 있음을 표시하기 위해 500ms 주기로 led를 토글하는 프로그램 입니다.
별도의 thread로 동작 시켰으며 프로젝트 이식과는 관계없는 기능입니다.
우리가 중점적으로 봐야 할 부부은 mqtt_client.c 입니다.
다음은 prj.conf 파일 입니다.

먼저 GPIO와 UART Console을 사용하기 위한 기본 설정은 다음과 같습니다.
CONFIG_GPIO=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_NETWORKING=y
CONFIG_WIFI=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_DHCPV4는 Wi-Fi AP에 연결된 후 DHCP를 이용하여 IPv4 주소를 할당받기 위해 사용합니다.
이번 프로젝트에서는 Wi-Fi 연결 이후 MQTT Broker와 TCP/IP 통신을 해야 하므로 Socket과 TCP 기능도 활성화하였습니다.
CONFIG_NET_SOCKETS=y
CONFIG_NET_TCP=y
CONFIG_MQTT_LIB=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_TCP=y
CONFIG_MQTT_LIB=y
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_KERNEL_BIN_NAME="xiao_esp32s3_wifimqtt"
CONFIG_ESP32_USE_UNSUPPORTED_REVISION=y
이와 같이 CMakeLists.txt와 prj.conf를 구성하면 MQTT 프로그램을 이식하기 위한 기본적인 빌드 환경이 준비됩니다.
다음에는 기존 skpang_esp32_can_wifimqtt 프로젝트에서 작성했던 main.c와 mqtt_client.c, mqtt_client.h를 가져와 XIAO ESP32S3에서 사용하기 위해 어떤 부분을 그대로 사용할 수 있고 어떤 부분을 변경해야 하는지 살펴보겠습니다.
프로그램 이전 및 변경사항 검토
앞에서 CMakeLists.txt와 prj.conf의 구성을 완료하였으므로, 기존 Skpang ESP32 CAN 보드에서 사용했던 MQTT 프로젝트의 프로그램을 XIAO ESP32S3 프로젝트로 이전하였습니다.
기존 프로젝트에서 MQTT 통신을 위해 작성했던 주요 파일은 다음과 같습니다.
main.c
mqtt_client.c
mqtt_client.h
이번 실습의 목적은 MQTT 프로그램을 새로 작성하는 것이 아니라 보드가 변경되었을 때 기존 Zephyr 애플리케이션을 어느 정도 그대로 사용할 수 있는지를 확인하는 것입니다.
따라서 기존 MQTT 프로젝트의 프로그램 구조와 동작 방식은 그대로 유지하고, XIAO ESP32S3에서 사용할 수 있도록 필요한 부분만 확인하였습니다.
기존 MQTT 프로그램의 구성
기존 프로그램의 전체적인 동작은 다음과 같습니다.
Zephyr 시작
↓
Wi-Fi AP 연결
↓
DHCP를 통한 IP 주소 할당
↓
MQTT Broker 연결
↓
esp32/control Subscribe
↓
esp32/test Publish
MQTT Broker : 192.168.0.7:1883
Publish : esp32/test
Subscribe : esp32/control
따라서 이번 포팅에서는 MQTT 통신 방식이나 프로토콜을 변경할 필요가 없었습니다.
보드 변경에 따른 검토
기존 프로젝트는 ESP32를 사용하고 새로운 보드는 ESP32-S3를 사용하지만, 애플리케이션에서는 GPIO 레지스터나 Wi-Fi 하드웨어를 직접 제어하지 않고 Zephyr가 제공하는 Wi-Fi, Network Socket 및 MQTT API를 사용하고 있습니다.
따라서 MQTT를 처리하는 mqtt_client.c와 mqtt_client.h는 보드에 직접 종속되는 부분이 거의 없었으며, 기존 프로그램을 대부분 그대로 사용할 수 있었습니다.
Wi-Fi 연결 부분 역시 Zephyr Network API를 사용하고 있기 때문에 애플리케이션 코드의 큰 변경 없이 XIAO ESP32S3로 이전할 수 있었습니다.
결과적으로 이번 포팅에서 중요한 변경은 MQTT 프로그램 자체를 다시 작성하는 것이 아니라, 대상 보드를 my_xiao_esp32s3로 변경하고, 해당 보드에 맞게 Zephyr의 Kconfig 설정과 빌드 구성을 적용하는 것이라고 할 수 있습니다.
다만 보드에서 Zephyr 애플리케이션이 정상적으로 실행되고 있음을 LED로 확인하기 위해 main() 함수의 시작 부분에 led_thread_start()를 추가하였습니다.

이외의 MQTT 프로그램은 기존 ESP32 프로젝트에서 사용하던 코드를 대부분 그대로 사용하였습니다. 전체 MQTT 프로그램에 대한 자세한 설명은 이전 ESP32 MQTT 실습에서 이미 다루었으므로 여기서는 생략하겠습니다.
아래는 MQTT 관련 이전 프로젝트의 링크 입니다.
이제 실제로 my_xiao_esp32s3 보드를 대상으로 프로젝트를 빌드하고 다운로드하여, 보드가 변경된 상태에서도 기존 MQTT 애플리케이션이 정상적으로 동작하는지 확인해 보겠습니다.
빌드 및 다운로드
이제 XIAO ESP32S3 MQTT 프로젝트를 Build하고 보드에 Flash해 보겠습니다.
앞에서 작성한 커스텀 보드 my_xiao_esp32s3를 사용하므로 다음과 같이 BOARD_ROOT를 지정하여 빌드하였습니다.
west build -b my_xiao_esp32s3/esp32s3/procpu -p always -- -DBOARD_ROOT="D:/Zephyr/workspace/my_boards"
다음은 Build가 성공한 Visual Studio Code의 Terminal 화면입니다.

빌드 결과를 보면 대상 보드가 다음과 같이 정상적으로 인식된 것을 확인할 수 있습니다.
my_xiao_esp32s3/esp32s3/procpu
또한 prj.conf에서 CONFIG_KERNEL_BIN_NAME으로 지정한 프로젝트 이름에 따라 다음 실행 파일이 생성되었습니다.
xiao_esp32s3_wifimqtt.elf
마지막에 SUCCESSFULLY created ESP32-S3 image.가 출력되면서 ESP32-S3용 이미지 생성까지 정상적으로 완료된 것을 확인할 수 있습니다.
이제 XIAO ESP32S3 보드를 USB로 연결하고 다음 명령으로 Flash를 진행하였습니다.
west flash
Flash가 정상적으로 완료되면 다음 명령을 사용하여 XIAO ESP32S3의 실행 상태를 확인할 수 있습니다.
west espressif monitor
이제 Monitor를 통해 Wi-Fi AP 연결과 IP 주소 할당, MQTT Broker 연결이 정상적으로 이루어지는지 확인해 보겠습니다.
아래는 monitor 화면입니다.

Monitor 화면을 확인하면 먼저 XIAO ESP32S3에서 Zephyr가 정상적으로 부팅되고 애플리케이션이 실행되는 것을 확인할 수 있습니다.
*** Booting Zephyr OS build ...
XIAO ESP32-S3 Wi-Fi MQTT Test
이후 설정된 Wi-Fi AP에 연결되고 DHCP를 통해 다음과 같이 IPv4 주소가 정상적으로 할당되었습니다.
Connecting to Wi-Fi AP...
IPv4 address: 192.168.0.10
Wi-Fi 연결이 완료된 후에는 192.168.0.7:1883에서 동작하고 있는 MQTT Broker에 연결하고, esp32/control Topic을 Subscribe한 것을 확인할 수 있습니다.
Connecting to MQTT broker 192.168.0.7:1883...
MQTT connected
Subscribed to esp32/control
마지막으로 esp32/test Topic으로 값이 계속 Publish되고 있습니다.
Published: esp32/test -> 0
Published: esp32/test -> 1
Published: esp32/test -> 2
Published: esp32/test -> 3
따라서 기존 ESP32 보드에서 작성했던 MQTT 프로젝트가 XIAO ESP32S3에서도 정상적으로 빌드 및 실행되고, Wi-Fi 연결에서 MQTT Broker 접속과 Publish까지 정상적으로 동작하는 것을 확인하였습니다.
다음 장에서는 기존에 구축해 놓은 FastAPI 서버와의 연동으로 전체 포팅 결과를 검증해 보겠습니다.
포팅 결과
MQTT 프로젝트 이식에 대한 최종 결과는 Orange Pi에서 동작하는 FastAPI + Uvicorn 웹서버를 이용하여 확인하겠습니다.
우선 Visual Studio Code의 Terminal에서 Remote SSH로 오렌지 파이 서버로 접속 하여 uvicorn 웹서버를 가동 시키겠습니다.
아래는 웹서버를 가동시킨 화면입니다.

Uvicorn이 실행되면서 FastAPI 웹서버가 정상적으로 시작되었으며, 동시에 MQTT Broker의 esp32/test Topic을 Subscribe하고 있는 것을 확인할 수 있습니다.
MQTT connected: 0
Subscribed: esp32/test
INFO: Uvicorn running on http://0.0.0.0:8000
esp32/test Topic으로 Publish한 데이터가 Mosquitto MQTT Broker를 거쳐 FastAPI 프로그램으로 전달됩니다.실제 Terminal에서도 다음과 같이 XIAO ESP32S3에서 전송한 값이 연속적으로 수신되는 것을 확인할 수 있습니다.
MQTT received: esp32/test 773
MQTT received: esp32/test 774
MQTT received: esp32/test 775
XIAO ESP32S3
↓
Wi-Fi
↓
MQTT Publish
esp32/test
↓
Mosquitto Broker
192.168.0.7:1883
↓
FastAPI
다음은 브라우저에서 확인을 해 보겠습니다.

위 화면과 같이 브라우저의 주소항에 http://192.168.0.7:8000/est32 를 입력하면
{"topic":"esp32/test","value":"968"}
topic과 value가 나타납니다. 새로 고침을 하면 value가 계속 바뀌는 것을 확인 할 수 있습니다.
이는 XIAO ESP32S3에서 카운터 값을 계속 증가시키면서 esp32/test Topic으로 Publish하고 있기 때문입니다.

새로 고침 후 value가 968에서 1124로 변경된 것을 확인할 수 있습니다. 이를 통해 XIAO ESP32S3에서 Publish한 데이터가 Mosquitto MQTT Broker를 거쳐 FastAPI까지 지속적으로 전달되고 있으며, FastAPI의 /esp32 API를 통해 브라우저에서도 정상적으로 확인할 수 있음을 알 수 있습니다.
다음은 반대 방향의 통신도 확인해 보겠습니다.
앞에서는 XIAO ESP32S3에서 Publish한 데이터를 MQTT Broker와 FastAPI를 거쳐 브라우저에서 확인하였습니다. 이번에는 반대로 브라우저에서 FastAPI의 Control API를 호출하고, FastAPI가 MQTT 메시지를 Publish하여 XIAO ESP32S3에서 수신하는지 확인해 보겠습니다.
Zephyr Application에서는 이미 다음 Topic을 Subscribe하고 있습니다.
esp32/control
On 또는 Off 명령을 입력하였습니다.http://192.168.0.7:8000/control/On
http://192.168.0.7:8000/control/Off
esp32/control Topic으로 MQTT Broker에 Publish하고, 해당 Topic을 Subscribe하고 있는 XIAO ESP32S3가 이를 수신하게 됩니다.전체적인 데이터 전달 경로는 다음과 같습니다.
Web Browser
↓
FastAPI + Uvicorn
↓
MQTT Publish
esp32/control
↓
Mosquitto MQTT Broker
↓
MQTT Subscribe
↓
XIAO ESP32S3
실제로 west espressif monitor를 확인하면 다음과 같이 esp32/control Topic으로 전달된 on과 off Payload가 XIAO ESP32S3에서 정상적으로 수신되는 것을 확인할 수 있습니다.

따라서 XIAO ESP32S3에서 서버 방향으로 데이터를 전송하는 것뿐만 아니라, FastAPI를 통해 전달한 제어 명령을 MQTT Broker를 거쳐 XIAO ESP32S3에서 수신하는 반대 방향의 통신도 정상적으로 동작하는 것을 확인하였습니다.
이번 포팅 테스트를 통해 최종적으로 다음 두 방향의 통신을 모두 확인하였습니다.
[상태 데이터 전송]
XIAO ESP32S3
↓
MQTT Broker
↓
FastAPI
↓
Web Browser
[제어 명령 전송]
Web Browser
↓
FastAPI
↓
MQTT Broker
↓
XIAO ESP32S3
이로써 기존 ESP32 보드에서 작성했던 Zephyr MQTT Application이 XIAO ESP32S3로 이식된 후에도 Publish와 Subscribe를 포함한 양방향 MQTT 통신이 정상적으로 동작하며, 기존 FastAPI 기반 IoT 서버와도 그대로 연동할 수 있음을 확인하였습니다.
결론
이번 실습에서는 Seeed Studio의 XIAO ESP32S3 보드에 Zephyr RTOS를 적용하고, 기존 ESP32 보드에서 작성했던 MQTT Application을 이식하여 정상적으로 동작하는지 확인하였습니다.
먼저 Zephyr에서 제공하는 XIAO ESP32S3 공식 보드 파일을 기반으로 커스텀 보드 my_xiao_esp32s3를 구성하였습니다. 그리고 간단한 Wi-Fi Scan 프로젝트를 이식하여 커스텀 보드 설정과 ESP32-S3의 Wi-Fi 기능이 정상적으로 동작하는 것을 확인하였습니다.
이후 기존 ESP32 MQTT 프로젝트의 프로그램을 XIAO ESP32S3 프로젝트로 이전하였습니다. 이 과정에서 MQTT 프로그램 자체를 새로 작성하기보다는 대상 보드에 맞게 Kconfig와 빌드 구성을 설정하는 것이 포팅의 주요 작업이었습니다.
특히 기존 프로그램이 Wi-Fi와 MQTT 하드웨어를 직접 제어하지 않고 Zephyr에서 제공하는 Network 및 MQTT API를 기반으로 작성되어 있었기 때문에, 보드가 ESP32에서 ESP32-S3로 변경되었음에도 애플리케이션의 주요 코드를 대부분 그대로 사용할 수 있었습니다.
최종적으로 XIAO ESP32S3에서 Publish한 데이터가
XIAO ESP32S3
↓
Mosquitto MQTT Broker
↓
FastAPI + Uvicorn
↓
Web Browser
반대로 브라우저에서 FastAPI의 Control API를 호출하여 전달한 On과 Off 명령도
Web Browser
↓
FastAPI + Uvicorn
↓
Mosquitto MQTT Broker
↓
XIAO ESP32S3
이번 실습을 통해 Zephyr를 사용하면 보드가 변경되더라도 하드웨어에 직접 종속되지 않는 애플리케이션 코드는 상당 부분 재사용할 수 있다는 것을 실제 포팅을 통해 확인할 수 있었습니다.
물론 이번 결과는 같은 Espressif 계열의 ESP32와 ESP32-S3 사이에서 진행한 것이므로 모든 MCU에서 동일한 수준의 이식성이 보장된다고 볼 수는 없습니다. 하지만 보드별 차이는 DeviceTree, Kconfig 및 보드 설정에서 처리하고 애플리케이션은 Zephyr의 공통 API를 사용하도록 구성하는 것이 향후 여러 하드웨어를 지원하는 프로젝트에서 중요한 개발 방법이 될 수 있음을 확인하였습니다.
이번 XIAO ESP32S3 포팅 실습은 단순히 새로운 보드에서 MQTT를 동작시켜 본 것보다는, 지금까지 작성해 온 Zephyr Application을 다른 하드웨어에서도 재사용할 수 있는지 직접 확인해 보았다는 점에 의미가 있다고 생각합니다.