OpenThread / Zigbee
August 7, 2026 · View on GitHub
Home · Getting Started: Linux · Getting Started: MCU · Troubleshooting
The MCU host runs the full 802.15.4 stack (OpenThread, or Zigbee), while a separate ESP chip acts as the Radio Co-Processor (RCP). Your host application drives the mesh; the RCP just provides the radio. Both stacks share the same RCP mechanism.
Host support
| Linux host | MCU host | Capability bit |
|---|---|---|
| No | Yes | ESP_EXT_CAP_OT (1 << 6) in ext_cap |
How it works — two links
Unlike Wi-Fi and Bluetooth (which ride the main SPI/SDIO ESP-Hosted transport), 802.15.4 uses two separate links:
- RCP lifecycle / control rides the shared ESP-Hosted transport as RPC (requires RPC ext-v2 on the host).
- 802.15.4 spinel data rides a dedicated UART between host and RCP. The "over Hosted transport" option exists in Kconfig but is not implemented yet — UART is the supported path today (and the only path for Zigbee).
flowchart LR
subgraph Host["MCU Host (e.g. ESP32-P4)"]
S["OpenThread / Zigbee stack"]
R["eh_host_openthread (RPC)"]
end
subgraph RCP["RCP (e.g. ESP32-C6 / H2)"]
RAD["802.15.4 radio"]
end
R -->|"Hosted transport · RPC (lifecycle)"| RCP
S -->|"dedicated UART · Spinel (data)"| RAD
RAD -.->|Thread / Zigbee mesh| NET((mesh))
RCP lifecycle
sequenceDiagram
participant App as Host app
participant OT as eh_host_openthread
participant CP as RCP (co-processor)
App->>OT: eh_host_openthread_rcp_init()
OT->>CP: FeatureControl RPC (init)
App->>OT: eh_host_openthread_rcp_start()
OT->>CP: FeatureControl RPC (start)
App->>OT: eh_host_openthread_rcp_query(READY)
OT-->>App: ready
Note over App,CP: stack now runs over the dedicated Spinel UART
Radio parameters (UART port, baud, pins) come from eh_host_port_openthread_get_radio_config(), which fills an eh_host_port_openthread_radio_config_t (type = UART, plus the UART settings).
Note
The RCP must be a chip with an 802.15.4 radio (ESP32-C6, ESP32-H2, or ESP32-C5). It is a distinct device/firmware from the SPI/SDIO co-processor that carries Wi-Fi. A Thread Border Router / Zigbee Gateway needs both radios (Wi-Fi + 802.15.4) — commonly a two-co-processor setup (e.g. C6 for Wi-Fi + H2 as RCP). See supported co-processors.
Enable / disable
Enable the feature on both sides, then set the dedicated-UART parameters.
Host:
Component config
└── ESP-Hosted
└── Configure host
└── Features
└── [*] OpenThread / Zigbee (RCP control) (ESP_HOSTED_HOST_FEAT_OPENTHREAD)
├── OpenThread RCP transport (host side) → (X) Dedicated UART (ESP_HOSTED_OT_HOST_TRANSPORT_UART)
├── (1) UART port (ESP_HOSTED_OT_HOST_UART_PORT)
├── (11) Host TX pin (to RCP RX) (ESP_HOSTED_OT_HOST_UART_TX_PIN_TO_RCP)
├── (10) Host RX pin (from RCP TX) (ESP_HOSTED_OT_HOST_UART_RX_PIN_TO_RCP)
└── (460800) Baud (ESP_HOSTED_OT_HOST_UART_BAUDRATE)
Co-processor (RCP):
Component config
└── ESP-Hosted
└── Configure coprocessor
└── Features
└── [*] OpenThread RCP (Radio Co-Processor) (ESP_HOSTED_CP_FEAT_OPENTHREAD)
├── OpenThread Transport → (X) UART (ESP_HOSTED_OT_TRANSPORT_UART)
├── (1) UART Port to Use (ESP_HOSTED_OT_UART_PORT)
├── (21) TX GPIO number (ESP_HOSTED_OT_UART_PIN_TX)
├── (20) RX GPIO number (ESP_HOSTED_OT_UART_PIN_RX)
└── (460800) Baud Rate (ESP_HOSTED_OT_UART_BAUDRATE)
The RCP firmware itself needs the ESP-IDF OpenThread radio config (CONFIG_OPENTHREAD_ENABLED=y, CONFIG_OPENTHREAD_RADIO=y, device type = Radio-only). The co-processor warns at build time if the OT UART port collides with the main Hosted UART transport port.
Start here
- OpenThread CLI — bring up a Thread node from the interactive CLI.
- Thread Border Router — Wi-Fi + 802.15.4 gateway.
Code reference
host/features/eh_host_feat_openthread/include/eh_host_openthread.h—eh_host_openthread_rcp_init/start/stop/deinit/query.port/os/include/eh_host_port_openthread.h—eh_host_port_openthread_radio_config_t+…_get_radio_config().coprocessor/features/eh_cp_feat_openthread/— RCP feature on the co-processor.
See also
- Supported co-processors — 802.15.4-capable chips.
- Architecture & Protocol · Getting Started: MCU