diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/CMakeLists.txt b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/CMakeLists.txt new file mode 100644 index 00000000000..282ad5bb137 --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/CMakeLists.txt @@ -0,0 +1,19 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +#target_compile_options(espressif__esp_matter PUBLIC +# -DCHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER= +# -DCHIP_HAVE_CONFIG_H) +#list(APPEND compile_definitions "CHIP_HAVE_CONFIG_H=1") +#list(APPEND compile_definitions "CHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER=") + +project(Matter_Thread_Light) + +idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++2a;-Os;-DCHIP_HAVE_CONFIG_H" APPEND) +idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND) +# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various +# flags that depend on -Wformat +idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND) diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/README.md b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/README.md new file mode 100644 index 00000000000..4c88aef7199 --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/README.md @@ -0,0 +1,38 @@ +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | -------- | + +# Arduino ESP-Matter over Thread example using ESP32-C5, ESP32-C6 and ESP32-H2 (any SoC with Thread radio) +This is an Arduino as IDF Project to build an ESP-Matter over Thread RGB Light using ESP32-C5/C6/H2 and ESP-Matter Arduino API \ +This example shall work with Arduino 3.3.2+ and also IDF 5.5.1+\ +It is necessary to make sure that the IDF version matches with the one used to release the Arduino Core version.\ +This can be done looking into release information in https://github.com/espressif/arduino-esp32/releases \ + +Any example from [ESP32 Matter Library examples](https://github.com/espressif/arduino-esp32/tree/master/libraries/Matter/examples) +can be used to build the application.\ +Feel free to create your own Arduino Matter sketch!\ +Do not forget to rename the `sketch_file_name.ino` to `sketch_file_name.cpp` in `main` folder. + +The `main/idf_component.yml` file holds the ESP-Matter component version and Arduino Core version.\ +Edit this file to set the target versions, if necessary. + +# General Instructions: + +1- Install the required IDF version into your computer. It can be done following the guide in +https://docs.espressif.com/projects/esp-idf/en/stable/esp32c6/get-started/index.html + +For Windows: https://docs.espressif.com/projects/esp-idf/en/stable/esp32c6/get-started/index.html \ +For Linux or macOS: https://docs.espressif.com/projects/esp-idf/en/stable/esp32c6/get-started/linux-macos-setup.html + +2- Test IDF with `idf.py --version` to check if it is installed and configured correctly. + +3- To create a ESP-IDF project from this example with the latest release of Arduino-esp32, you can simply run command: +`idf.py create-project-from-example "espressif/arduino-esp32:Arduino_ESP_Matter_over_OpenThread"` +ESP-IDF will download all dependencies needed from the component registry and setup the project for you. + +4- Open an IDF terminal and execute `idf.py set-target esp32c6` (esp32c5 and esp32h2 are also possible targets) + +5- Execute `idf.py -p flash monitor` + +6- It will build, upload and show the UART0 output in the screen. + +7- Try to add the new Matter device to your local Matter environment. diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/ci.yml b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/ci.yml new file mode 100644 index 00000000000..8fde8e9096c --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/ci.yml @@ -0,0 +1,9 @@ +targets: + esp32s2: false + esp32s3: false + esp32c2: false + esp32p4: false +requires: + - CONFIG_OPENTHREAD_ENABLED=y + - CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y + - CONFIG_MBEDTLS_HKDF_C=y diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/CMakeLists.txt b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/CMakeLists.txt new file mode 100644 index 00000000000..f18fa805695 --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS ".") diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/MatterEnhancedColorLight.cpp b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/MatterEnhancedColorLight.cpp new file mode 100644 index 00000000000..3f4735f0d22 --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/MatterEnhancedColorLight.cpp @@ -0,0 +1,186 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Matter Manager +#include +#include + +// List of Matter Endpoints for this Node +// Color Light Endpoint +MatterEnhancedColorLight EnhancedColorLight; + +// It will use HSV color to control all Matter Attribute Changes +HsvColor_t currentHSVColor = {0, 0, 0}; + +// it will keep last OnOff & HSV Color state stored, using Preferences +Preferences matterPref; +const char *onOffPrefKey = "OnOff"; +const char *hsvColorPrefKey = "HSV"; + +// set your board RGB LED pin here +#ifdef RGB_BUILTIN +const uint8_t ledPin = RGB_BUILTIN; +#else +const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN +#warning "Do not forget to set the RGB LED pin" +#endif + +// set your board USER BUTTON pin here +const uint8_t buttonPin = BOOT_PIN; // Set your pin here. Using BOOT Button. + +// Button control +uint32_t button_time_stamp = 0; // debouncing control +bool button_state = false; // false = released | true = pressed +const uint32_t debounceTime = 250; // button debouncing time (ms) +const uint32_t decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Set the RGB LED Light based on the current state of the Enhanced Color Light +bool setLightState(bool state, espHsvColor_t colorHSV, uint8_t brightness, uint16_t temperature_Mireds) { + + if (state) { +#ifdef RGB_BUILTIN + // currentHSVColor keeps final color result + espRgbColor_t rgbColor = espHsvColorToRgbColor(currentHSVColor); + // set the RGB LED + rgbLedWrite(ledPin, rgbColor.r, rgbColor.g, rgbColor.b); +#else + // No Color RGB LED, just use the HSV value (brightness) to control the LED + analogWrite(ledPin, colorHSV.v); +#endif + } else { +#ifndef RGB_BUILTIN + // after analogWrite(), it is necessary to set the GPIO to digital mode first + pinMode(ledPin, OUTPUT); +#endif + digitalWrite(ledPin, LOW); + } + // store last HSV Color and OnOff state for when the Light is restarted / power goes off + matterPref.putBool(onOffPrefKey, state); + matterPref.putUInt(hsvColorPrefKey, currentHSVColor.h << 16 | currentHSVColor.s << 8 | currentHSVColor.v); + // This callback must return the success state to Matter core + return true; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch + pinMode(buttonPin, INPUT_PULLUP); + // Initialize the LED (light) GPIO and Matter End Point + pinMode(ledPin, OUTPUT); + + Serial.begin(115200); + + // Initialize Matter EndPoint + matterPref.begin("MatterPrefs", false); + // default OnOff state is ON if not stored before + bool lastOnOffState = matterPref.getBool(onOffPrefKey, true); + // default HSV color is (21, 216, 25) - Warm White Color at 10% intensity + uint32_t prefHsvColor = matterPref.getUInt(hsvColorPrefKey, 21 << 16 | 216 << 8 | 25); + currentHSVColor = {uint8_t(prefHsvColor >> 16), uint8_t(prefHsvColor >> 8), uint8_t(prefHsvColor)}; + EnhancedColorLight.begin(lastOnOffState, currentHSVColor); + // set the callback function to handle the Light state change + EnhancedColorLight.onChange(setLightState); + + // lambda functions are used to set the attribute change callbacks + EnhancedColorLight.onChangeOnOff([](bool state) { + Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF"); + return true; + }); + EnhancedColorLight.onChangeColorTemperature([](uint16_t colorTemperature) { + Serial.printf("Light Color Temperature changed to %d\r\n", colorTemperature); + // get correspondent Hue and Saturation of the color temperature + HsvColor_t hsvTemperature = espRgbColorToHsvColor(espCTToRgbColor(colorTemperature)); + // keep previous the brightness and just change the Hue and Saturation + currentHSVColor.h = hsvTemperature.h; + currentHSVColor.s = hsvTemperature.s; + return true; + }); + EnhancedColorLight.onChangeBrightness([](uint8_t brightness) { + Serial.printf("Light brightness changed to %d\r\n", brightness); + // change current brightness (HSV value) + currentHSVColor.v = brightness; + return true; + }); + EnhancedColorLight.onChangeColorHSV([](HsvColor_t hsvColor) { + Serial.printf("Light HSV Color changed to (%d,%d,%d)\r\n", hsvColor.h, hsvColor.s, hsvColor.v); + // keep the current brightness and just change Hue and Saturation + currentHSVColor.h = hsvColor.h; + currentHSVColor.s = hsvColor.s; + return true; + }); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + // This may be a restart of a already commissioned Matter accessory + if (Matter.isDeviceCommissioned()) { + Serial.println("Matter Node is commissioned and connected to the network. Ready for use."); + Serial.printf( + "Initial state: %s | RGB Color: (%d,%d,%d) \r\n", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r, + EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b + ); + // configure the Light based on initial on-off state and its color + EnhancedColorLight.updateAccessory(); + } +} + +void loop() { + // Check Matter Light Commissioning state, which may change during execution of loop() + if (!Matter.isDeviceCommissioned()) { + Serial.println(""); + Serial.println("Matter Node is not commissioned yet."); + Serial.println("Initiate the device discovery in your Matter environment."); + Serial.println("Commission it to your Matter hub with the manual pairing code or QR code"); + Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str()); + Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str()); + // waits for Matter Light Commissioning. + uint32_t timeCount = 0; + while (!Matter.isDeviceCommissioned()) { + delay(100); + if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec + Serial.println("Matter Node not commissioned yet. Waiting for commissioning."); + } + } + Serial.printf( + "Initial state: %s | RGB Color: (%d,%d,%d) \r\n", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r, + EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b + ); + // configure the Light based on initial on-off state and its color + EnhancedColorLight.updateAccessory(); + Serial.println("Matter Node is commissioned and connected to the network. Ready for use."); + } + + // A button is also used to control the light + // Check if the button has been pressed + if (digitalRead(buttonPin) == LOW && !button_state) { + // deals with button debouncing + button_time_stamp = millis(); // record the time while the button is pressed. + button_state = true; // pressed. + } + + // Onboard User Button is used as a Light toggle switch or to decommission it + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > debounceTime && digitalRead(buttonPin) == HIGH) { + button_state = false; // released + // Toggle button is released - toggle the light + Serial.println("User button released. Toggling Light!"); + EnhancedColorLight.toggle(); // Matter Controller also can see the change + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again."); + EnhancedColorLight = false; // turn the light off + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } +} diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/idf_component.yml b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/idf_component.yml new file mode 100644 index 00000000000..233b595e654 --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + espressif/esp_matter: + version: ">=1.3.0" + require: public + espressif/arduino-esp32: + version: ">=3.1.0" + override_path: "../../../" + pre_release: true diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/partitions.csv b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/partitions.csv new file mode 100644 index 00000000000..ffe5f242e76 --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/partitions.csv @@ -0,0 +1,10 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table +esp_secure_cert, 0x3F, ,0xd000, 0x2000, encrypted +nvs, data, nvs, 0x10000, 0xC000, +nvs_keys, data, nvs_keys,, 0x1000, encrypted +otadata, data, ota, , 0x2000 +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, 0x20000, 0x1E0000, +ota_1, app, ota_1, 0x200000, 0x1E0000, +fctry, data, nvs, 0x3E0000, 0x6000 diff --git a/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/sdkconfig.defaults b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/sdkconfig.defaults new file mode 100644 index 00000000000..aa3d5c838eb --- /dev/null +++ b/idf_component_examples/Arduino_ESP_Matter_over_OpenThread/sdkconfig.defaults @@ -0,0 +1,68 @@ +# Arduino ESP32 settings +CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y +CONFIG_AUTOSTART_ARDUINO=y +CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y +CONFIG_FREERTOS_HZ=1000 +CONFIG_LOG_DEFAULT_LEVEL_ERROR=y + +# Enables Arduino Selective Library Compilation: Arduino Matter + Preferences Library +CONFIG_ARDUINO_SELECTIVE_COMPILATION=y +CONFIG_ARDUINO_SELECTIVE_Preferences=y +CONFIG_ARDUINO_SELECTIVE_Network=y +CONFIG_ARDUINO_SELECTIVE_ESPmDNS=y +CONFIG_ARDUINO_SELECTIVE_Matter=y + +# Flash Configuration +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y +CONFIG_ESPTOOLPY_BEFORE_RESET=y +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 + +# libsodium +CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y + +# NIMBLE +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=n +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n + +# Enable OpenThread +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_OPENTHREAD_SRP_CLIENT=y +CONFIG_OPENTHREAD_DNS_CLIENT=y +CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC=n +CONFIG_OPENTHREAD_LOG_LEVEL_NOTE=y +CONFIG_OPENTHREAD_CLI=n + +# Disable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=n + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# LwIP config for OpenThread +CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 +CONFIG_LWIP_MULTICAST_PING=y + +# MDNS platform +CONFIG_USE_MINIMAL_MDNS=n +CONFIG_ENABLE_EXTENDED_DISCOVERY=y + +# Disable STA and AP for ESP32C6 ==> no Wifi, thread only +CONFIG_ENABLE_WIFI_STATION=n +CONFIG_ENABLE_WIFI_AP=n + +# Enable HKDF in mbedtls +CONFIG_MBEDTLS_HKDF_C=y