Hello,
I recently bought a nrf52840 dev kit + dongle to test the functionalities of Matter.
To commission devices "On network" without the use of Bluetooth, i wanted to use the Thread commissioner/joiner mechanism, based on a pre-shared key or the EUI+64 of the device.
I started from the matter light bulb example, and added the necessary flags in prj.conf.
# Enable CHIP CONFIG_CHIP=y CONFIG_CHIP_PROJECT_CONFIG="src/chip_project_config.h" # 32773 == 0x8005 (example lighting-app) CONFIG_CHIP_DEVICE_PRODUCT_ID=32773 CONFIG_STD_CPP17=y # Enable Matter pairing automatically on application start. CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y # Enable Matter extended announcement and increase duration to 1 hour. CONFIG_CHIP_BLE_EXT_ADVERTISING=y CONFIG_CHIP_BLE_ADVERTISING_DURATION=60 # Add support for LEDs and buttons on Nordic development kits CONFIG_DK_LIBRARY=y CONFIG_PWM=y # Bluetooth Low Energy configuration CONFIG_BT_DEVICE_NAME="MatterLight" # Other settings CONFIG_THREAD_NAME=y CONFIG_MPU_STACK_GUARD=y CONFIG_RESET_ON_FATAL_ERROR=n CONFIG_CHIP_LIB_SHELL=y CONFIG_NCS_SAMPLE_MATTER_TEST_SHELL=y # Reduce application size CONFIG_USE_SEGGER_RTT=n # Enable Factory Data feature CONFIG_CHIP_FACTORY_DATA=y CONFIG_CHIP_FACTORY_DATA_BUILD=y # extra: mbedTLS CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_AES_C=y CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y CONFIG_NRF_SECURITY=y CONFIG_MBEDTLS=y CONFIG_MBEDTLS_CMAC_C=y CONFIG_MBEDTLS_SSL_PROTO_DTLS=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED=y CONFIG_MBEDTLS_ECJPAKE_C=y # Enable elliptic curve cryptography # CONFIG_MBEDTLS_ECP=y # Enable specific elliptic curves (example: CURVE25519 and CURVE448) CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y CONFIG_MBEDTLS_ECP_DP_CURVE448_ENABLED=y # extra: Thread # Enable OpenThread support CONFIG_OPENTHREAD=y CONFIG_OPENTHREAD_THREAD_VERSION_1_3=y # start the joiner CONFIG_OPENTHREAD_JOINER=y CONFIG_CHIP_OPENTHREAD_JOINER_ENABLED=y # Enable Thread networking CONFIG_NET_L2_OPENTHREAD=y CONFIG_OPENTHREAD_FTD=y # Full Thread Device (use MTD for Minimal Thread Device) # Enable IPv6 support (required for Thread) CONFIG_NETWORKING=y CONFIG_NET_IPV6=y CONFIG_NET_IPV6_MLD=y CONFIG_NET_IPV6_NBR_CACHE=y CONFIG_NET_IPV6_ND=y # Network shell CONFIG_SHELL=y CONFIG_OPENTHREAD_SHELL=y CONFIG_SHELL_ARGC_MAX=26 CONFIG_SHELL_CMD_BUFF_SIZE=416
in my src/main.cpp code i adjusted the program to print the EUI64 in the console and start the thread joiner.
#include "app_task.h" #include <zephyr/logging/log.h> #include <zephyr/kernel.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/gpio.h> #include <openthread/thread.h> #include <openthread/joiner.h> #include <openthread/platform/radio.h> // For otPlatRadioGetIeeeEui64 #define THREAD_JOINER_TIMEOUT 900 // 15 minutes in seconds // Global flag to indicate Thread Joiner completion static volatile bool is_thread_joiner_complete = false; static const struct gpio_dt_spec button1 = GPIO_DT_SPEC_GET(DT_ALIAS(sw1), gpios); static struct gpio_callback button1_cb_data; LOG_MODULE_REGISTER(app, CONFIG_CHIP_APP_LOG_LEVEL); // Callback for Thread Joiner completion void JoinerCallback(otError result, void *context) { if (result == OT_ERROR_NONE) { LOG_INF("Thread Joiner completed successfully"); is_thread_joiner_complete = true; } else { LOG_ERR("Thread Joiner failed: %d", result); } } void StartThreadJoiner() { otInstance *instance = openthread_get_default_instance(); if (instance == NULL) { LOG_ERR("Failed to get OpenThread instance"); return; } // Retrieve the EUI64 uint8_t eui64[OT_EXT_ADDRESS_SIZE]; otPlatRadioGetIeeeEui64(instance, eui64); // Print the EUI64 to the console LOG_INF("Device EUI64: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", eui64[0], eui64[1], eui64[2], eui64[3], eui64[4], eui64[5], eui64[6], eui64[7]); // Start the Thread Joiner const char *pskd = NULL; // No PSKd since you're using EUI64 otError error = otJoinerStart(instance, pskd, NULL, NULL, NULL, NULL, NULL, JoinerCallback, NULL); if (error == OT_ERROR_NONE) { LOG_INF("Thread Joiner started successfully"); } else { LOG_ERR("Failed to start Thread Joiner: %d", error); } } void button1_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { LOG_INF("Button 1 (sw1 alias) pressed, starting Thread Joiner..."); StartThreadJoiner(); } void init_buttons() { if (!device_is_ready(button1.port)) { LOG_ERR("Button 1 GPIO port not ready"); return; } gpio_pin_configure_dt(&button1, GPIO_INPUT); gpio_pin_interrupt_configure_dt(&button1, GPIO_INT_EDGE_TO_ACTIVE); gpio_init_callback(&button1_cb_data, button1_pressed, BIT(button1.pin)); gpio_add_callback(button1.port, &button1_cb_data); LOG_INF("Button 1 configured successfully"); } int main() { // Initialize Button 1 for Thread Joiner init_buttons(); LOG_INF("Waiting for Thread Joiner to complete..."); while (!is_thread_joiner_complete) { k_sleep(K_SECONDS(1)); // Polling to check if Joiner has completed } LOG_INF("Starting Matter application..."); CHIP_ERROR err = AppTask::Instance().StartApp(); LOG_ERR("Exited with code %" CHIP_ERROR_FORMAT, err.Format()); return err == CHIP_NO_ERROR ? EXIT_SUCCESS : EXIT_FAILURE; }
there is an issue with the link to the Openthread libraries though, because i get the error:
C:/ncs/workspace/light_bulb/src/main.cpp:62: undefined reference to `otJoinerStart'
Has anyone tried this before?
Do i need to add extra lines in the config file or is it not possible to use both Opentread and Matter due to conflicts?
Thanks in advance for your help!