This commit is contained in:
2026-05-22 21:52:50 +03:00
commit be7c60e4dd
1854 changed files with 583428 additions and 0 deletions
@@ -0,0 +1,113 @@
#include "OThread.h"
OpenThread threadLeaderNode;
DataSet dataset;
// Track last known device role for state change detection
ot_device_role_t lastKnownRole = OT_ROLE_DISABLED;
void setup() {
Serial.begin(115200);
// Start OpenThread Stack - false for not using NVS dataset information
threadLeaderNode.begin(false);
// Create a new Thread Network Dataset for a Leader Node
dataset.initNew();
// Configure the dataset
dataset.setNetworkName("ESP_OpenThread");
uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = {0xDE, 0xAD, 0x00, 0xBE, 0xEF, 0x00, 0xCA, 0xFE};
dataset.setExtendedPanId(extPanId);
uint8_t networkKey[OT_NETWORK_KEY_SIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
dataset.setNetworkKey(networkKey);
dataset.setChannel(15);
dataset.setPanId(0x1234);
// Apply the dataset and start the network
threadLeaderNode.commitDataSet(dataset);
threadLeaderNode.networkInterfaceUp();
threadLeaderNode.start();
}
void loop() {
// Get current device role
ot_device_role_t currentRole = threadLeaderNode.otGetDeviceRole();
// Only print network information when not detached
if (currentRole != OT_ROLE_DETACHED && currentRole != OT_ROLE_DISABLED) {
Serial.println("==============================================");
Serial.println("OpenThread Network Information:");
// Basic network information
Serial.printf("Role: %s\r\n", threadLeaderNode.otGetStringDeviceRole());
Serial.printf("RLOC16: 0x%04x\r\n", threadLeaderNode.getRloc16());
Serial.printf("Network Name: %s\r\n", threadLeaderNode.getNetworkName().c_str());
Serial.printf("Channel: %d\r\n", threadLeaderNode.getChannel());
Serial.printf("PAN ID: 0x%04x\r\n", threadLeaderNode.getPanId());
// Extended PAN ID
const uint8_t *extPanId = threadLeaderNode.getExtendedPanId();
if (extPanId) {
Serial.print("Extended PAN ID: ");
for (int i = 0; i < OT_EXT_PAN_ID_SIZE; i++) {
Serial.printf("%02x", extPanId[i]);
}
Serial.println();
}
// Network Key
const uint8_t *networkKey = threadLeaderNode.getNetworkKey();
if (networkKey) {
Serial.print("Network Key: ");
for (int i = 0; i < OT_NETWORK_KEY_SIZE; i++) {
Serial.printf("%02x", networkKey[i]);
}
Serial.println();
}
// Mesh Local EID
IPAddress meshLocalEid = threadLeaderNode.getMeshLocalEid();
Serial.printf("Mesh Local EID: %s\r\n", meshLocalEid.toString().c_str());
// Leader RLOC
IPAddress leaderRloc = threadLeaderNode.getLeaderRloc();
Serial.printf("Leader RLOC: %s\r\n", leaderRloc.toString().c_str());
// Node RLOC
IPAddress nodeRloc = threadLeaderNode.getRloc();
Serial.printf("Node RLOC: %s\r\n", nodeRloc.toString().c_str());
// Demonstrate address listing with two different methods:
// Method 1: Unicast addresses using counting API (individual access)
Serial.println("\r\n--- Unicast Addresses (Using Count + Index API) ---");
size_t unicastCount = threadLeaderNode.getUnicastAddressCount();
for (size_t i = 0; i < unicastCount; i++) {
IPAddress addr = threadLeaderNode.getUnicastAddress(i);
Serial.printf(" [%zu]: %s\r\n", i, addr.toString().c_str());
}
// Method 2: Multicast addresses using std::vector (bulk access)
Serial.println("\r\n--- Multicast Addresses (Using std::vector API) ---");
std::vector<IPAddress> allMulticast = threadLeaderNode.getAllMulticastAddresses();
for (size_t i = 0; i < allMulticast.size(); i++) {
Serial.printf(" [%zu]: %s\r\n", i, allMulticast[i].toString().c_str());
}
// Check for role change and clear cache if needed (only when active)
if (currentRole != lastKnownRole) {
Serial.printf(
"Role changed from %s to %s - clearing address cache\r\n", (lastKnownRole < 5) ? otRoleString[lastKnownRole] : "Unknown",
threadLeaderNode.otGetStringDeviceRole()
);
threadLeaderNode.clearAllAddressCache();
lastKnownRole = currentRole;
}
} else {
Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", threadLeaderNode.otGetStringDeviceRole());
// Update role tracking even when detached/disabled, but don't clear cache
lastKnownRole = currentRole;
}
delay(5000);
}
@@ -0,0 +1,183 @@
# OpenThread Leader Node Example (Native API)
This example demonstrates how to create an OpenThread Leader node using the Classes API (native OpenThread API).\
The Leader node is the first device in a Thread network that manages the network and assigns router IDs. This example shows how to configure a Leader node using the `OpenThread` and `DataSet` classes.
## Supported Targets
| SoC | Thread | Status |
| --- | ------ | ------ |
| ESP32-H2 | ✅ | Fully supported |
| ESP32-C6 | ✅ | Fully supported |
| ESP32-C5 | ✅ | Fully supported |
### Note on Thread Support:
- Thread support must be enabled in the ESP-IDF configuration (`CONFIG_OPENTHREAD_ENABLED`). This is done automatically when using the ESP32 Arduino OpenThread library.
- This example uses the Classes API (`OpenThread` and `DataSet` classes) instead of CLI Helper Functions.
- This example uses `OpenThread.begin(false)` which does not use NVS dataset information, allowing fresh configuration.
## Features
- Leader node configuration using Classes API
- Dataset creation and configuration using `DataSet` class
- Network information display using `OpenThread` class methods
- IPv6 address management (unicast and multicast)
- Address cache management on role changes
- Comprehensive network status monitoring
## Hardware Requirements
- ESP32 compatible development board with Thread support (ESP32-H2, ESP32-C6, or ESP32-C5)
- USB cable for Serial communication
## Software Setup
### Prerequisites
1. Install the Arduino IDE (2.0 or newer recommended)
2. Install ESP32 Arduino Core with OpenThread support
3. ESP32 Arduino libraries:
- `OpenThread`
### Configuration
Before uploading the sketch, you can modify the network configuration:
```cpp
dataset.setNetworkName("ESP_OpenThread");
dataset.setChannel(15);
dataset.setPanId(0x1234);
uint8_t networkKey[OT_NETWORK_KEY_SIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
dataset.setNetworkKey(networkKey);
```
**Important:**
- The network key must be a 16-byte array
- The channel must be between 11 and 26 (IEEE 802.15.4 channels)
- All devices in the same network must use the same network key and channel
- Extended PAN ID should be unique for your network
## Building and Flashing
1. Open the `LeaderNode.ino` sketch in the Arduino IDE.
2. Select your ESP32 board from the **Tools > Board** menu (ESP32-H2, ESP32-C6, or ESP32-C5).
3. Connect your ESP32 board to your computer via USB.
4. Click the **Upload** button to compile and flash the sketch.
## Expected Output
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. You should see output similar to the following:
```
==============================================
OpenThread Network Information:
Role: Leader
RLOC16: 0x0000
Network Name: ESP_OpenThread
Channel: 15
PAN ID: 0x1234
Extended PAN ID: dead00beef00cafe
Network Key: 00112233445566778899aabbccddeeff
Mesh Local EID: fd00:db8:a0:0:0:ff:fe00:0
Leader RLOC: fd00:db8:a0:0:0:ff:fe00:0
Node RLOC: fd00:db8:a0:0:0:ff:fe00:0
--- Unicast Addresses (Using Count + Index API) ---
[0]: fd00:db8:a0:0:0:ff:fe00:0
[1]: fe80:0:0:0:0:ff:fe00:0
--- Multicast Addresses (Using std::vector API) ---
[0]: ff02::1
[1]: ff03::1
[2]: ff03::fc
...
```
## Using the Device
### Leader Node Setup
The Leader node is automatically configured in `setup()` using the Classes API:
1. **Initialize OpenThread**: `threadLeaderNode.begin(false)` - Starts OpenThread stack without using NVS
2. **Create dataset**: `dataset.initNew()` - Creates a new complete dataset
3. **Configure dataset**: Sets network name, extended PAN ID, network key, channel, and PAN ID
4. **Apply dataset**: `threadLeaderNode.commitDataSet(dataset)` - Applies the dataset
5. **Start network**: `threadLeaderNode.networkInterfaceUp()` and `threadLeaderNode.start()` - Starts the Thread network
### Network Information
The `loop()` function displays comprehensive network information using Classes API methods:
- Device role and RLOC16
- Network name, channel, PAN ID
- Extended PAN ID and network key
- IPv6 addresses (Mesh Local EID, Leader RLOC, Node RLOC)
- Unicast addresses (using count + index API)
- Multicast addresses (using std::vector API)
### Address Cache Management
The example demonstrates address cache management:
- Clears address cache when device role changes
- Tracks role changes to optimize address resolution
### Joining Other Devices
To join other devices to this network:
1. Use the same network key and channel in the Router/Child node examples
2. Start the Leader node first
3. Then start the Router/Child nodes
## Code Structure
The LeaderNode example consists of the following main components:
1. **`setup()`**:
- Initializes Serial communication
- Starts OpenThread stack with `OpenThread.begin(false)`
- Creates and configures a `DataSet` object:
- `dataset.initNew()` - Initialize new dataset
- `dataset.setNetworkName()` - Set network name
- `dataset.setExtendedPanId()` - Set extended PAN ID
- `dataset.setNetworkKey()` - Set network key
- `dataset.setChannel()` - Set channel
- `dataset.setPanId()` - Set PAN ID
- Applies dataset: `threadLeaderNode.commitDataSet(dataset)`
- Starts network: `threadLeaderNode.networkInterfaceUp()` and `threadLeaderNode.start()`
2. **`loop()`**:
- Gets current device role using `threadLeaderNode.otGetDeviceRole()`
- Displays network information using Classes API methods:
- `threadLeaderNode.otGetStringDeviceRole()` - Device role as string
- `threadLeaderNode.getRloc16()` - RLOC16
- `threadLeaderNode.getNetworkName()` - Network name
- `threadLeaderNode.getChannel()` - Channel
- `threadLeaderNode.getPanId()` - PAN ID
- `threadLeaderNode.getExtendedPanId()` - Extended PAN ID
- `threadLeaderNode.getNetworkKey()` - Network key
- `threadLeaderNode.getMeshLocalEid()` - Mesh Local EID
- `threadLeaderNode.getLeaderRloc()` - Leader RLOC
- `threadLeaderNode.getRloc()` - Node RLOC
- `threadLeaderNode.getUnicastAddressCount()` and `threadLeaderNode.getUnicastAddress(i)` - Unicast addresses
- `threadLeaderNode.getAllMulticastAddresses()` - Multicast addresses
- Manages address cache on role changes
- Updates every 5 seconds
## Troubleshooting
- **Device not becoming Leader**: Ensure this is the first device started, or clear NVS to start fresh
- **Network key/channel mismatch**: Verify all devices use the same network key and channel
- **No network information**: Wait for the device to become Leader (may take a few seconds)
- **Address cache issues**: The example automatically clears cache on role changes
- **No serial output**: Check baudrate (115200) and USB connection
## Related Documentation
- [OpenThread Core API](https://docs.espressif.com/projects/arduino-esp32/en/latest/openthread/openthread_core.html)
- [OpenThread Dataset API](https://docs.espressif.com/projects/arduino-esp32/en/latest/openthread/openthread_dataset.html)
- [OpenThread Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/openthread/openthread.html)
## License
This example is licensed under the Apache License, Version 2.0.
@@ -0,0 +1,3 @@
requires:
- CONFIG_OPENTHREAD_ENABLED=y
- CONFIG_SOC_IEEE802154_SUPPORTED=y
@@ -0,0 +1,174 @@
# OpenThread Router/Child Node Example (Native API)
This example demonstrates how to create an OpenThread Router or Child node that joins an existing Thread network using the Classes API (native OpenThread API).\
The Router/Child node joins a network created by a Leader node and can route messages or operate as an end device. This example shows how to configure a Router/Child node using the `OpenThread` and `DataSet` classes.
## Supported Targets
| SoC | Thread | Status |
| --- | ------ | ------ |
| ESP32-H2 | ✅ | Fully supported |
| ESP32-C6 | ✅ | Fully supported |
| ESP32-C5 | ✅ | Fully supported |
### Note on Thread Support:
- Thread support must be enabled in the ESP-IDF configuration (`CONFIG_OPENTHREAD_ENABLED`). This is done automatically when using the ESP32 Arduino OpenThread library.
- This example uses the Classes API (`OpenThread` and `DataSet` classes) instead of CLI Helper Functions.
- This example uses `OpenThread.begin(false)` which does not use NVS dataset information, allowing fresh configuration.
- **Important:** A Leader node must be running before starting this Router/Child node.
## Features
- Router/Child node configuration using Classes API
- Dataset configuration using `DataSet` class
- Joins an existing Thread network created by a Leader node
- Network information display using `OpenThread` class methods
- Active dataset retrieval and display
- Comprehensive network status monitoring
## Hardware Requirements
- ESP32 compatible development board with Thread support (ESP32-H2, ESP32-C6, or ESP32-C5)
- USB cable for Serial communication
- A Leader node must be running on the same network
## Software Setup
### Prerequisites
1. Install the Arduino IDE (2.0 or newer recommended)
2. Install ESP32 Arduino Core with OpenThread support
3. ESP32 Arduino libraries:
- `OpenThread`
### Configuration
Before uploading the sketch, configure the network parameters to match the Leader node:
```cpp
uint8_t networkKey[OT_NETWORK_KEY_SIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
dataset.setNetworkKey(networkKey);
```
**Important:**
- The network key **must match** the Leader node's network key exactly
- The network key must be a 16-byte array
- Only the network key is required to join (other parameters are learned from the Leader)
- **Start the Leader node first** before starting this Router/Child node
## Building and Flashing
1. **First, start the Leader node** using the LeaderNode example (Native API)
2. Open the `RouterNode.ino` sketch in the Arduino IDE.
3. Select your ESP32 board from the **Tools > Board** menu (ESP32-H2, ESP32-C6, or ESP32-C5).
4. Connect your ESP32 board to your computer via USB.
5. Click the **Upload** button to compile and flash the sketch.
## Expected Output
Once the sketch is running, open the Serial Monitor at a baud rate of **115200**. You should see output similar to the following:
```
==============================================
OpenThread Network Information (Active Dataset):
Role: Router
RLOC16: 0xfc00
Network Name: ESP_OpenThread
Channel: 15
PAN ID: 0x1234
Extended PAN ID: dead00beef00cafe
Network Key: 00112233445566778899aabbccddeeff
Mesh Local EID: fd00:db8:a0:0:0:ff:fe00:fc00
Node RLOC: fd00:db8:a0:0:0:ff:fe00:fc00
Leader RLOC: fd00:db8:a0:0:0:ff:fe00:0
```
The device will join as either a **Router** (if network needs more routers) or **Child** (end device).
## Using the Device
### Router/Child Node Setup
The Router/Child node is automatically configured in `setup()` using the Classes API:
1. **Initialize OpenThread**: `threadChildNode.begin(false)` - Starts OpenThread stack without using NVS
2. **Clear dataset**: `dataset.clear()` - Clears any existing dataset
3. **Configure dataset**: Sets only the network key (must match Leader)
4. **Apply dataset**: `threadChildNode.commitDataSet(dataset)` - Applies the dataset
5. **Start network**: `threadChildNode.networkInterfaceUp()` and `threadChildNode.start()` - Starts the Thread network and joins existing network
### Network Information
The `loop()` function displays network information using Classes API methods:
- Device role and RLOC16
- Active dataset information (retrieved using `threadChildNode.getCurrentDataSet()`):
- Network name, channel, PAN ID
- Extended PAN ID and network key
- Runtime information:
- Mesh Local EID, Node RLOC, Leader RLOC
### Active Dataset Retrieval
This example demonstrates how to retrieve the active dataset:
- Uses `threadChildNode.getCurrentDataSet()` to get the current active dataset
- Displays dataset parameters that were learned from the Leader node
- Shows that only the network key needs to be configured to join
### Multi-Device Network
To create a multi-device Thread network:
1. Start the Leader node first (using Native API LeaderNode example)
2. Start Router/Child nodes (using this example)
3. All devices will form a mesh network
4. Routers extend network range and route messages
5. Children are end devices that can sleep
## Code Structure
The RouterNode example consists of the following main components:
1. **`setup()`**:
- Initializes Serial communication
- Starts OpenThread stack with `OpenThread.begin(false)`
- Creates and configures a `DataSet` object:
- `dataset.clear()` - Clear existing dataset
- `dataset.setNetworkKey()` - Set network key (must match Leader)
- Applies dataset: `threadChildNode.commitDataSet(dataset)`
- Starts network: `threadChildNode.networkInterfaceUp()` and `threadChildNode.start()`
2. **`loop()`**:
- Gets current device role using `threadChildNode.otGetDeviceRole()`
- Retrieves active dataset using `threadChildNode.getCurrentDataSet()`
- Displays network information using Classes API methods:
- `threadChildNode.otGetStringDeviceRole()` - Device role as string
- `threadChildNode.getRloc16()` - RLOC16
- `activeDataset.getNetworkName()` - Network name from dataset
- `activeDataset.getChannel()` - Channel from dataset
- `activeDataset.getPanId()` - PAN ID from dataset
- `activeDataset.getExtendedPanId()` - Extended PAN ID from dataset
- `activeDataset.getNetworkKey()` - Network key from dataset
- `threadChildNode.getMeshLocalEid()` - Mesh Local EID
- `threadChildNode.getRloc()` - Node RLOC
- `threadChildNode.getLeaderRloc()` - Leader RLOC
- Updates every 5 seconds
## Troubleshooting
- **Device not joining network**: Ensure the Leader node is running first. Verify network key matches the Leader exactly.
- **Role stuck as "Detached"**: Wait a few seconds for the device to join. Check that network key matches the Leader.
- **Network key mismatch**: Double-check that both Leader and Router/Child nodes use identical network key values.
- **No network information**: Wait for the device to join the network (may take 10-30 seconds)
- **Active dataset empty**: Ensure device has successfully joined the network before checking dataset
- **No serial output**: Check baudrate (115200) and USB connection
## Related Documentation
- [OpenThread Core API](https://docs.espressif.com/projects/arduino-esp32/en/latest/openthread/openthread_core.html)
- [OpenThread Dataset API](https://docs.espressif.com/projects/arduino-esp32/en/latest/openthread/openthread_dataset.html)
- [OpenThread Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/openthread/openthread.html)
## License
This example is licensed under the Apache License, Version 2.0.
@@ -0,0 +1,84 @@
#include "OThread.h"
OpenThread threadChildNode;
DataSet dataset;
void setup() {
Serial.begin(115200);
// Start OpenThread Stack - false for not using NVS dataset information
threadChildNode.begin(false);
// clear dataset
dataset.clear();
// Configure the dataset with the same Network Key of the Leader Node
uint8_t networkKey[OT_NETWORK_KEY_SIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
dataset.setNetworkKey(networkKey);
// Apply the dataset and start the network
threadChildNode.commitDataSet(dataset);
threadChildNode.networkInterfaceUp();
threadChildNode.start();
}
void loop() {
// Get current device role
ot_device_role_t currentRole = threadChildNode.otGetDeviceRole();
// Only print detailed network information when node is active
if (currentRole != OT_ROLE_DETACHED && currentRole != OT_ROLE_DISABLED) {
Serial.println("==============================================");
Serial.println("OpenThread Network Information (Active Dataset):");
// Get and display the current active dataset
const DataSet &activeDataset = threadChildNode.getCurrentDataSet();
Serial.printf("Role: %s\r\n", threadChildNode.otGetStringDeviceRole());
Serial.printf("RLOC16: 0x%04x\r\n", threadChildNode.getRloc16());
// Dataset information
Serial.printf("Network Name: %s\r\n", activeDataset.getNetworkName());
Serial.printf("Channel: %d\r\n", activeDataset.getChannel());
Serial.printf("PAN ID: 0x%04x\r\n", activeDataset.getPanId());
// Extended PAN ID from dataset
const uint8_t *extPanId = activeDataset.getExtendedPanId();
if (extPanId) {
Serial.print("Extended PAN ID: ");
for (int i = 0; i < OT_EXT_PAN_ID_SIZE; i++) {
Serial.printf("%02x", extPanId[i]);
}
Serial.println();
}
// Network Key from dataset
const uint8_t *networkKey = activeDataset.getNetworkKey();
if (networkKey) {
Serial.print("Network Key: ");
for (int i = 0; i < OT_NETWORK_KEY_SIZE; i++) {
Serial.printf("%02x", networkKey[i]);
}
Serial.println();
}
// Additional runtime information
IPAddress meshLocalEid = threadChildNode.getMeshLocalEid();
Serial.printf("Mesh Local EID: %s\r\n", meshLocalEid.toString().c_str());
IPAddress nodeRloc = threadChildNode.getRloc();
Serial.printf("Node RLOC: %s\r\n", nodeRloc.toString().c_str());
IPAddress leaderRloc = threadChildNode.getLeaderRloc();
Serial.printf("Leader RLOC: %s\r\n", leaderRloc.toString().c_str());
Serial.println();
} else {
Serial.println("==============================================");
Serial.printf("Thread Node Status: %s - Waiting for thread network start...\r\n", threadChildNode.otGetStringDeviceRole());
Serial.println();
}
delay(5000);
}
@@ -0,0 +1,3 @@
requires:
- CONFIG_OPENTHREAD_ENABLED=y
- CONFIG_SOC_IEEE802154_SUPPORTED=y