Enable Thread joiner on matter light bulb example

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!

Parents Reply Children
No Data
Related