diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml index 76cac3d612a..e9830622593 100644 --- a/.github/ISSUE_TEMPLATE/Issue-report.yml +++ b/.github/ISSUE_TEMPLATE/Issue-report.yml @@ -42,6 +42,7 @@ body: options: - Please select a version from the list below - latest master (checkout manually) + - v3.3.5 - v3.3.4 - v3.3.3 - v3.3.2 diff --git a/.github/workflows/build_py_tools.yml b/.github/workflows/build_py_tools.yml index e22d8df5eff..0b19e1fcf33 100644 --- a/.github/workflows/build_py_tools.yml +++ b/.github/workflows/build_py_tools.yml @@ -8,6 +8,7 @@ on: - "tools/espota.py" - "tools/gen_esp32part.py" - "tools/gen_insights_package.py" + - "tools/bin_signing.py" permissions: contents: write @@ -44,6 +45,7 @@ jobs: tools/espota.py tools/gen_esp32part.py tools/gen_insights_package.py + tools/bin_signing.py - name: List all changed files shell: bash @@ -108,7 +110,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pyinstaller requests + pip install pyinstaller requests cryptography - name: Build with PyInstaller shell: bash @@ -119,16 +121,14 @@ jobs: - name: Sign binaries if: matrix.os == 'windows-latest' - env: - CERTIFICATE: ${{ secrets.CERTIFICATE }} - CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} - shell: pwsh - run: | - $data = Write-Output ${{ env.CHANGED_TOOLS }} - foreach ( $node in $data ) - { - ./.github/pytools/Sign-File.ps1 -Path ./${{ env.DISTPATH }}/$node.exe - } + uses: espressif/release-sign@33f3684091168d78b2cf6c8265bd9968c376254c # master + with: + path: ./${{ env.DISTPATH }} + azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} + azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} + azure-keyvault-uri: ${{ secrets.AZURE_KEYVAULT_URI }} + azure-keyvault-cert-name: ${{ secrets.AZURE_KEYVAULT_CERT_NAME }} - name: Test binaries shell: bash diff --git a/.gitlab/workflows/common.yml b/.gitlab/workflows/common.yml index 0f4bda9bcce..13cf060546a 100644 --- a/.gitlab/workflows/common.yml +++ b/.gitlab/workflows/common.yml @@ -13,7 +13,7 @@ stages: variables: ESP_IDF_VERSION: "5.5" - ESP_ARDUINO_VERSION: "3.3.4" + ESP_ARDUINO_VERSION: "3.3.5" ############# # `default` # diff --git a/CMakeLists.txt b/CMakeLists.txt index c88b7e1ba96..ada0087731b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,9 +206,7 @@ set(ARDUINO_LIBRARY_Matter_SRCS libraries/Matter/src/Matter.cpp libraries/Matter/src/MatterEndPoint.cpp) -set(ARDUINO_LIBRARY_PPP_SRCS - libraries/PPP/src/PPP.cpp - libraries/PPP/src/ppp.c) +set(ARDUINO_LIBRARY_PPP_SRCS libraries/PPP/src/PPP.cpp) set(ARDUINO_LIBRARY_Preferences_SRCS libraries/Preferences/src/Preferences.cpp) @@ -239,7 +237,8 @@ set(ARDUINO_LIBRARY_Ticker_SRCS libraries/Ticker/src/Ticker.cpp) set(ARDUINO_LIBRARY_Update_SRCS libraries/Update/src/Updater.cpp - libraries/Update/src/HttpsOTAUpdate.cpp) + libraries/Update/src/HttpsOTAUpdate.cpp + libraries/Update/src/Updater_Signing.cpp) set(ARDUINO_LIBRARY_USB_SRCS libraries/USB/src/USBHID.cpp diff --git a/boards.txt b/boards.txt index 8c1e38702fd..a2c988e93ee 100644 --- a/boards.txt +++ b/boards.txt @@ -44315,7 +44315,169 @@ waveshare_esp32s3_touch_lcd_128.menu.EraseFlash.all.upload.erase_cmd=-e ############################################################## -waveshare_esp32_c6_zero.name=Waveshare ESP32-C6 Zero +waveshare_esp32_c3_zero.name=Waveshare ESP32-C3-Zero + +waveshare_esp32_c3_zero.bootloader.tool=esptool_py +waveshare_esp32_c3_zero.bootloader.tool.default=esptool_py + +waveshare_esp32_c3_zero.upload.tool=esptool_py +waveshare_esp32_c3_zero.upload.tool.default=esptool_py +waveshare_esp32_c3_zero.upload.tool.network=esp_ota + +waveshare_esp32_c3_zero.upload.maximum_size=1310720 +waveshare_esp32_c3_zero.upload.maximum_data_size=327680 +waveshare_esp32_c3_zero.upload.flags= +waveshare_esp32_c3_zero.upload.extra_flags= +waveshare_esp32_c3_zero.upload.use_1200bps_touch=false +waveshare_esp32_c3_zero.upload.wait_for_upload_port=false + +waveshare_esp32_c3_zero.serial.disableDTR=false +waveshare_esp32_c3_zero.serial.disableRTS=false + +waveshare_esp32_c3_zero.build.tarch=riscv32 +waveshare_esp32_c3_zero.build.target=esp +waveshare_esp32_c3_zero.build.mcu=esp32c3 +waveshare_esp32_c3_zero.build.core=esp32 +waveshare_esp32_c3_zero.build.variant=waveshare_esp32_c3_zero +waveshare_esp32_c3_zero.build.board=WAVESHARE_ESP32_C3_ZERO +waveshare_esp32_c3_zero.build.bootloader_addr=0x0 + +waveshare_esp32_c3_zero.build.cdc_on_boot=1 +waveshare_esp32_c3_zero.build.f_cpu=160000000L +waveshare_esp32_c3_zero.build.flash_size=4MB +waveshare_esp32_c3_zero.build.flash_freq=80m +waveshare_esp32_c3_zero.build.flash_mode=qio +waveshare_esp32_c3_zero.build.boot=qio +waveshare_esp32_c3_zero.build.partitions=default +waveshare_esp32_c3_zero.build.defines= + +## IDE 2.0 Seems to not update the value +waveshare_esp32_c3_zero.menu.JTAGAdapter.default=Disabled +waveshare_esp32_c3_zero.menu.JTAGAdapter.default.build.copy_jtag_files=0 +waveshare_esp32_c3_zero.menu.JTAGAdapter.builtin=Integrated USB JTAG +waveshare_esp32_c3_zero.menu.JTAGAdapter.builtin.build.openocdscript=esp32c3-builtin.cfg +waveshare_esp32_c3_zero.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +waveshare_esp32_c3_zero.menu.JTAGAdapter.external=FTDI Adapter +waveshare_esp32_c3_zero.menu.JTAGAdapter.external.build.openocdscript=esp32c3-ftdi.cfg +waveshare_esp32_c3_zero.menu.JTAGAdapter.external.build.copy_jtag_files=1 +waveshare_esp32_c3_zero.menu.JTAGAdapter.bridge=ESP USB Bridge +waveshare_esp32_c3_zero.menu.JTAGAdapter.bridge.build.openocdscript=esp32c3-bridge.cfg +waveshare_esp32_c3_zero.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +waveshare_esp32_c3_zero.menu.CDCOnBoot.default=Enabled +waveshare_esp32_c3_zero.menu.CDCOnBoot.default.build.cdc_on_boot=1 +waveshare_esp32_c3_zero.menu.CDCOnBoot.cdc=Disabled +waveshare_esp32_c3_zero.menu.CDCOnBoot.cdc.build.cdc_on_boot=0 + +waveshare_esp32_c3_zero.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.default.build.partitions=default +waveshare_esp32_c3_zero.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +waveshare_esp32_c3_zero.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.minimal.build.partitions=minimal +waveshare_esp32_c3_zero.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2) +waveshare_esp32_c3_zero.menu.PartitionScheme.no_fs.build.partitions=no_fs +waveshare_esp32_c3_zero.menu.PartitionScheme.no_fs.upload.maximum_size=2031616 +waveshare_esp32_c3_zero.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.no_ota.build.partitions=no_ota +waveshare_esp32_c3_zero.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +waveshare_esp32_c3_zero.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +waveshare_esp32_c3_zero.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.huge_app.build.partitions=huge_app +waveshare_esp32_c3_zero.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +waveshare_esp32_c3_zero.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/128KB SPIFFS) +waveshare_esp32_c3_zero.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +waveshare_esp32_c3_zero.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +waveshare_esp32_c3_zero.menu.PartitionScheme.rainmaker=RainMaker 4MB +waveshare_esp32_c3_zero.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +waveshare_esp32_c3_zero.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080 +waveshare_esp32_c3_zero.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA +waveshare_esp32_c3_zero.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota +waveshare_esp32_c3_zero.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656 +waveshare_esp32_c3_zero.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs +waveshare_esp32_c3_zero.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr +waveshare_esp32_c3_zero.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720 +waveshare_esp32_c3_zero.menu.PartitionScheme.custom=Custom +waveshare_esp32_c3_zero.menu.PartitionScheme.custom.build.partitions= +waveshare_esp32_c3_zero.menu.PartitionScheme.custom.upload.maximum_size=4194304 + +waveshare_esp32_c3_zero.menu.CPUFreq.160=160MHz (WiFi) +waveshare_esp32_c3_zero.menu.CPUFreq.160.build.f_cpu=160000000L +waveshare_esp32_c3_zero.menu.CPUFreq.80=80MHz (WiFi) +waveshare_esp32_c3_zero.menu.CPUFreq.80.build.f_cpu=80000000L +waveshare_esp32_c3_zero.menu.CPUFreq.40=40MHz +waveshare_esp32_c3_zero.menu.CPUFreq.40.build.f_cpu=40000000L +waveshare_esp32_c3_zero.menu.CPUFreq.20=20MHz +waveshare_esp32_c3_zero.menu.CPUFreq.20.build.f_cpu=20000000L +waveshare_esp32_c3_zero.menu.CPUFreq.10=10MHz +waveshare_esp32_c3_zero.menu.CPUFreq.10.build.f_cpu=10000000L + +waveshare_esp32_c3_zero.menu.FlashMode.qio=QIO +waveshare_esp32_c3_zero.menu.FlashMode.qio.build.flash_mode=dio +waveshare_esp32_c3_zero.menu.FlashMode.qio.build.boot=qio +waveshare_esp32_c3_zero.menu.FlashMode.dio=DIO +waveshare_esp32_c3_zero.menu.FlashMode.dio.build.flash_mode=dio +waveshare_esp32_c3_zero.menu.FlashMode.dio.build.boot=dio + +waveshare_esp32_c3_zero.menu.FlashFreq.80=80MHz +waveshare_esp32_c3_zero.menu.FlashFreq.80.build.flash_freq=80m +waveshare_esp32_c3_zero.menu.FlashFreq.40=40MHz +waveshare_esp32_c3_zero.menu.FlashFreq.40.build.flash_freq=40m + +waveshare_esp32_c3_zero.menu.FlashSize.4M=4MB (32Mb) +waveshare_esp32_c3_zero.menu.FlashSize.4M.build.flash_size=4MB + +waveshare_esp32_c3_zero.menu.UploadSpeed.921600=921600 +waveshare_esp32_c3_zero.menu.UploadSpeed.921600.upload.speed=921600 +waveshare_esp32_c3_zero.menu.UploadSpeed.115200=115200 +waveshare_esp32_c3_zero.menu.UploadSpeed.115200.upload.speed=115200 +waveshare_esp32_c3_zero.menu.UploadSpeed.256000.windows=256000 +waveshare_esp32_c3_zero.menu.UploadSpeed.256000.upload.speed=256000 +waveshare_esp32_c3_zero.menu.UploadSpeed.230400.windows.upload.speed=256000 +waveshare_esp32_c3_zero.menu.UploadSpeed.230400=230400 +waveshare_esp32_c3_zero.menu.UploadSpeed.230400.upload.speed=230400 +waveshare_esp32_c3_zero.menu.UploadSpeed.460800.linux=460800 +waveshare_esp32_c3_zero.menu.UploadSpeed.460800.macosx=460800 +waveshare_esp32_c3_zero.menu.UploadSpeed.460800.upload.speed=460800 +waveshare_esp32_c3_zero.menu.UploadSpeed.512000.windows=512000 +waveshare_esp32_c3_zero.menu.UploadSpeed.512000.upload.speed=512000 + +waveshare_esp32_c3_zero.menu.DebugLevel.none=None +waveshare_esp32_c3_zero.menu.DebugLevel.none.build.code_debug=0 +waveshare_esp32_c3_zero.menu.DebugLevel.error=Error +waveshare_esp32_c3_zero.menu.DebugLevel.error.build.code_debug=1 +waveshare_esp32_c3_zero.menu.DebugLevel.warn=Warn +waveshare_esp32_c3_zero.menu.DebugLevel.warn.build.code_debug=2 +waveshare_esp32_c3_zero.menu.DebugLevel.info=Info +waveshare_esp32_c3_zero.menu.DebugLevel.info.build.code_debug=3 +waveshare_esp32_c3_zero.menu.DebugLevel.debug=Debug +waveshare_esp32_c3_zero.menu.DebugLevel.debug.build.code_debug=4 +waveshare_esp32_c3_zero.menu.DebugLevel.verbose=Verbose +waveshare_esp32_c3_zero.menu.DebugLevel.verbose.build.code_debug=5 + +waveshare_esp32_c3_zero.menu.EraseFlash.none=Disabled +waveshare_esp32_c3_zero.menu.EraseFlash.none.upload.erase_cmd= +waveshare_esp32_c3_zero.menu.EraseFlash.all=Enabled +waveshare_esp32_c3_zero.menu.EraseFlash.all.upload.erase_cmd=-e + +waveshare_esp32_c3_zero.menu.ZigbeeMode.default=Disabled +waveshare_esp32_c3_zero.menu.ZigbeeMode.default.build.zigbee_mode= +waveshare_esp32_c3_zero.menu.ZigbeeMode.default.build.zigbee_libs= +waveshare_esp32_c3_zero.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router) +waveshare_esp32_c3_zero.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR +waveshare_esp32_c3_zero.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote + +############################################################## + +waveshare_esp32_c6_zero.name=Waveshare ESP32-C6-Zero waveshare_esp32_c6_zero.bootloader.tool=esptool_py waveshare_esp32_c6_zero.bootloader.tool.default=esptool_py @@ -44364,10 +44526,10 @@ waveshare_esp32_c6_zero.menu.JTAGAdapter.bridge=ESP USB Bridge waveshare_esp32_c6_zero.menu.JTAGAdapter.bridge.build.openocdscript=esp32c6-bridge.cfg waveshare_esp32_c6_zero.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 -waveshare_esp32_c6_zero.menu.CDCOnBoot.default=Disabled -waveshare_esp32_c6_zero.menu.CDCOnBoot.default.build.cdc_on_boot=0 -waveshare_esp32_c6_zero.menu.CDCOnBoot.cdc=Enabled -waveshare_esp32_c6_zero.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +waveshare_esp32_c6_zero.menu.CDCOnBoot.default=Enabled +waveshare_esp32_c6_zero.menu.CDCOnBoot.default.build.cdc_on_boot=1 +waveshare_esp32_c6_zero.menu.CDCOnBoot.cdc=Disabled +waveshare_esp32_c6_zero.menu.CDCOnBoot.cdc.build.cdc_on_boot=0 waveshare_esp32_c6_zero.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) waveshare_esp32_c6_zero.menu.PartitionScheme.default.build.partitions=default @@ -53065,6 +53227,154 @@ esp32p4_4ds_mipi.build.defines=-DBOARD_HAS_PSRAM -D{build.board} -D{build.Displa ############################################################## +esp32p4_4ds_mipi_round.name=4D Systems ESP32-P4 Round MIPI Displays + +esp32p4_4ds_mipi_round.bootloader.tool=esptool_py +esp32p4_4ds_mipi_round.bootloader.tool.default=esptool_py + +esp32p4_4ds_mipi_round.upload.tool=esptool_py +esp32p4_4ds_mipi_round.upload.tool.default=esptool_py +esp32p4_4ds_mipi_round.upload.tool.network=esp_ota + +esp32p4_4ds_mipi_round.upload.maximum_size=1310720 +esp32p4_4ds_mipi_round.upload.maximum_data_size=327680 +esp32p4_4ds_mipi_round.upload.flags= +esp32p4_4ds_mipi_round.upload.extra_flags= +esp32p4_4ds_mipi_round.upload.use_1200bps_touch=false +esp32p4_4ds_mipi_round.upload.wait_for_upload_port=false + +esp32p4_4ds_mipi_round.serial.disableDTR=false +esp32p4_4ds_mipi_round.serial.disableRTS=false + +esp32p4_4ds_mipi_round.build.tarch=riscv32 +esp32p4_4ds_mipi_round.build.target=esp +esp32p4_4ds_mipi_round.build.mcu=esp32p4 +esp32p4_4ds_mipi_round.build.core=esp32 +esp32p4_4ds_mipi_round.build.variant=esp32p4_4ds_mipi_round +esp32p4_4ds_mipi_round.build.board=ESP32P4_4DS_MIPI_ROUND +esp32p4_4ds_mipi_round.build.bootloader_addr=0x2000 + +esp32p4_4ds_mipi_round.build.usb_mode=0 +esp32p4_4ds_mipi_round.build.cdc_on_boot=0 +esp32p4_4ds_mipi_round.build.msc_on_boot=0 +esp32p4_4ds_mipi_round.build.dfu_on_boot=0 +esp32p4_4ds_mipi_round.build.f_cpu=360000000L +esp32p4_4ds_mipi_round.build.flash_size=32MB +esp32p4_4ds_mipi_round.build.flash_freq=80m +esp32p4_4ds_mipi_round.build.img_freq=80m +esp32p4_4ds_mipi_round.build.flash_mode=qio +esp32p4_4ds_mipi_round.build.boot=qio +esp32p4_4ds_mipi_round.build.partitions=app5M_fat24M_32MB + +esp32p4_4ds_mipi_round.menu.JTAGAdapter.default=Disabled +esp32p4_4ds_mipi_round.menu.JTAGAdapter.default.build.copy_jtag_files=0 +esp32p4_4ds_mipi_round.menu.JTAGAdapter.builtin=Integrated USB JTAG +esp32p4_4ds_mipi_round.menu.JTAGAdapter.builtin.build.openocdscript=esp32p4-builtin.cfg +esp32p4_4ds_mipi_round.menu.JTAGAdapter.builtin.build.copy_jtag_files=1 +esp32p4_4ds_mipi_round.menu.JTAGAdapter.external=FTDI Adapter +esp32p4_4ds_mipi_round.menu.JTAGAdapter.external.build.openocdscript=esp32p4-ftdi.cfg +esp32p4_4ds_mipi_round.menu.JTAGAdapter.external.build.copy_jtag_files=1 +esp32p4_4ds_mipi_round.menu.JTAGAdapter.bridge=ESP USB Bridge +esp32p4_4ds_mipi_round.menu.JTAGAdapter.bridge.build.openocdscript=esp32p4-bridge.cfg +esp32p4_4ds_mipi_round.menu.JTAGAdapter.bridge.build.copy_jtag_files=1 + +esp32p4_4ds_mipi_round.menu.USBMode.default=USB-OTG (TinyUSB) +esp32p4_4ds_mipi_round.menu.USBMode.default.build.usb_mode=0 +esp32p4_4ds_mipi_round.menu.USBMode.hwcdc=Hardware CDC and JTAG +esp32p4_4ds_mipi_round.menu.USBMode.hwcdc.build.usb_mode=1 + +esp32p4_4ds_mipi_round.menu.CDCOnBoot.default=Disabled +esp32p4_4ds_mipi_round.menu.CDCOnBoot.default.build.cdc_on_boot=0 +esp32p4_4ds_mipi_round.menu.CDCOnBoot.cdc=Enabled +esp32p4_4ds_mipi_round.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +esp32p4_4ds_mipi_round.menu.MSCOnBoot.default=Disabled +esp32p4_4ds_mipi_round.menu.MSCOnBoot.default.build.msc_on_boot=0 +esp32p4_4ds_mipi_round.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode) +esp32p4_4ds_mipi_round.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +esp32p4_4ds_mipi_round.menu.DFUOnBoot.default=Disabled +esp32p4_4ds_mipi_round.menu.DFUOnBoot.default.build.dfu_on_boot=0 +esp32p4_4ds_mipi_round.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode) +esp32p4_4ds_mipi_round.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 + +esp32p4_4ds_mipi_round.menu.UploadMode.default=UART0 / Hardware CDC +esp32p4_4ds_mipi_round.menu.UploadMode.default.upload.use_1200bps_touch=false +esp32p4_4ds_mipi_round.menu.UploadMode.default.upload.wait_for_upload_port=false +esp32p4_4ds_mipi_round.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB) +esp32p4_4ds_mipi_round.menu.UploadMode.cdc.upload.use_1200bps_touch=true +esp32p4_4ds_mipi_round.menu.UploadMode.cdc.upload.wait_for_upload_port=true + +esp32p4_4ds_mipi_round.menu.PartitionScheme.app5M_fat24M_32MB=32M Flash (4.8MB APP/22MB FATFS) +esp32p4_4ds_mipi_round.menu.PartitionScheme.app5M_fat24M_32MB.build.partitions=large_fat_32MB +esp32p4_4ds_mipi_round.menu.PartitionScheme.app5M_fat24M_32MB.upload.maximum_size=4718592 +esp32p4_4ds_mipi_round.menu.PartitionScheme.app5M_little24M_32MB=32M Flash (4.8MB APP/22MB LittleFS) +esp32p4_4ds_mipi_round.menu.PartitionScheme.app5M_little24M_32MB.build.partitions=large_littlefs_32MB +esp32p4_4ds_mipi_round.menu.PartitionScheme.app5M_little24M_32MB.upload.maximum_size=4718592 +esp32p4_4ds_mipi_round.menu.PartitionScheme.app13M_data7M_32MB=32M Flash (13MB APP/6.75MB SPIFFS) +esp32p4_4ds_mipi_round.menu.PartitionScheme.app13M_data7M_32MB.build.partitions=default_32MB +esp32p4_4ds_mipi_round.menu.PartitionScheme.app13M_data7M_32MB.upload.maximum_size=13107200 + +## From https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/kconfig.html#config-esp-default-cpu-freq-mhz +esp32p4_4ds_mipi_round.menu.CPUFreq.360=360MHz +esp32p4_4ds_mipi_round.menu.CPUFreq.360.build.f_cpu=360000000L +esp32p4_4ds_mipi_round.menu.CPUFreq.40=40MHz +esp32p4_4ds_mipi_round.menu.CPUFreq.40.build.f_cpu=40000000L + +esp32p4_4ds_mipi_round.menu.UploadSpeed.921600=921600 +esp32p4_4ds_mipi_round.menu.UploadSpeed.921600.upload.speed=921600 +esp32p4_4ds_mipi_round.menu.UploadSpeed.115200=115200 +esp32p4_4ds_mipi_round.menu.UploadSpeed.115200.upload.speed=115200 +esp32p4_4ds_mipi_round.menu.UploadSpeed.256000.windows=256000 +esp32p4_4ds_mipi_round.menu.UploadSpeed.256000.upload.speed=256000 +esp32p4_4ds_mipi_round.menu.UploadSpeed.230400.windows.upload.speed=256000 +esp32p4_4ds_mipi_round.menu.UploadSpeed.230400=230400 +esp32p4_4ds_mipi_round.menu.UploadSpeed.230400.upload.speed=230400 +esp32p4_4ds_mipi_round.menu.UploadSpeed.460800.linux=460800 +esp32p4_4ds_mipi_round.menu.UploadSpeed.460800.macosx=460800 +esp32p4_4ds_mipi_round.menu.UploadSpeed.460800.upload.speed=460800 +esp32p4_4ds_mipi_round.menu.UploadSpeed.512000.windows=512000 +esp32p4_4ds_mipi_round.menu.UploadSpeed.512000.upload.speed=512000 + +esp32p4_4ds_mipi_round.menu.DebugLevel.none=None +esp32p4_4ds_mipi_round.menu.DebugLevel.none.build.code_debug=0 +esp32p4_4ds_mipi_round.menu.DebugLevel.error=Error +esp32p4_4ds_mipi_round.menu.DebugLevel.error.build.code_debug=1 +esp32p4_4ds_mipi_round.menu.DebugLevel.warn=Warn +esp32p4_4ds_mipi_round.menu.DebugLevel.warn.build.code_debug=2 +esp32p4_4ds_mipi_round.menu.DebugLevel.info=Info +esp32p4_4ds_mipi_round.menu.DebugLevel.info.build.code_debug=3 +esp32p4_4ds_mipi_round.menu.DebugLevel.debug=Debug +esp32p4_4ds_mipi_round.menu.DebugLevel.debug.build.code_debug=4 +esp32p4_4ds_mipi_round.menu.DebugLevel.verbose=Verbose +esp32p4_4ds_mipi_round.menu.DebugLevel.verbose.build.code_debug=5 + +esp32p4_4ds_mipi_round.menu.EraseFlash.none=Disabled +esp32p4_4ds_mipi_round.menu.EraseFlash.none.upload.erase_cmd= +esp32p4_4ds_mipi_round.menu.EraseFlash.all=Enabled +esp32p4_4ds_mipi_round.menu.EraseFlash.all.upload.erase_cmd=-e + +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34r=ESP32-P4-34R +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34r.build.DisplayModel=ESP32P4_34R +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34r_clb=ESP32-P4-34R-CLB +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34r_clb.build.DisplayModel=ESP32P4_34R +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34rct=ESP32-P4-34RCT +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34rct.build.DisplayModel=ESP32P4_34RCT +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34rct_clb=ESP32-P4-34RCT-CLB +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_34rct_clb.build.DisplayModel=ESP32P4_34RCT +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40r=ESP32-P4-40R +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40r.build.DisplayModel=ESP32P4_40R +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40r_clb=ESP32-P4-40R-CLB +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40r_clb.build.DisplayModel=ESP32P4_40R +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40rct=ESP32-P4-40RCT +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40rct.build.DisplayModel=ESP32P4_40RCT +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40rct_clb=ESP32-P4-40RCT-CLB +esp32p4_4ds_mipi_round.menu.DisplayModel.esp32p4_40rct_clb.build.DisplayModel=ESP32P4_40RCT + +esp32p4_4ds_mipi_round.build.defines=-DBOARD_HAS_PSRAM -D{build.board} -D{build.DisplayModel} + +############################################################## + # Axiometa PIXIE M1 - Based on ESP32-S3-Mini-N4R2 # 4MB Quad SPI Flash, 2MB Quad SPI PSRAM diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index 342ce9aefb0..4fb62ad7518 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -20,6 +20,7 @@ #include "esp_adc/adc_oneshot.h" #include "esp_adc/adc_continuous.h" #include "esp_adc/adc_cali_scheme.h" +#include "esp_heap_caps.h" #if CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL >= 300 // NOTE: These weak definitions allow successful linkage if the real efuse calibration functions are missing. @@ -403,43 +404,40 @@ adc_continuous_result_t *adc_result = NULL; static bool adcContinuousDetachBus(void *adc_unit_number) { adc_unit_t adc_unit = (adc_unit_t)adc_unit_number - 1; + // Guard against double-cleanup: check if already cleaned up if (adc_handle[adc_unit].adc_continuous_handle == NULL) { return true; - } else { - esp_err_t err = adc_continuous_deinit(adc_handle[adc_unit].adc_continuous_handle); + } + + // Clean up ADC driver + esp_err_t err = adc_continuous_deinit(adc_handle[adc_unit].adc_continuous_handle); + if (err != ESP_OK) { + return false; + } + adc_handle[adc_unit].adc_continuous_handle = NULL; + + // Clean up calibration handle if exists + if (adc_handle[adc_unit].adc_cali_handle != NULL) { +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); if (err != ESP_OK) { return false; } - adc_handle[adc_unit].adc_continuous_handle = NULL; - if (adc_handle[adc_unit].adc_cali_handle != NULL) { -#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED - err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); - if (err != ESP_OK) { - return false; - } #elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED - err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); - if (err != ESP_OK) { - return false; - } -#else - log_e("ADC Calibration scheme is not supported!"); + err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); + if (err != ESP_OK) { return false; -#endif } +#else + log_e("ADC Calibration scheme is not supported!"); + return false; +#endif adc_handle[adc_unit].adc_cali_handle = NULL; - - //set all used pins to INIT state - for (uint8_t channel = 0; channel < SOC_ADC_CHANNEL_NUM(adc_unit); channel++) { - int io_pin; - adc_oneshot_channel_to_io(adc_unit, channel, &io_pin); - if (perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_CONT) { - if (!perimanClearPinBus(io_pin)) { - return false; - } - } - } } + + // Don't call perimanClearPinBus() here - the peripheral manager already handles it. + // This callback is only responsible for cleaning up the IDF's ADC driver and calibration handles. + // It does NOT free the adc_result buffer. The caller is responsible for freeing adc_result. return true; } @@ -549,6 +547,14 @@ bool analogContinuous(const uint8_t pins[], size_t pins_count, uint32_t conversi } #endif +#if CONFIG_IDF_TARGET_ESP32P4 + // Align conversion frame size to cache line size (required for DMA on targets with cache) + uint32_t alignment_remainder = adc_handle[adc_unit].conversion_frame_size % CONFIG_CACHE_L1_CACHE_LINE_SIZE; + if (alignment_remainder != 0) { + adc_handle[adc_unit].conversion_frame_size += (CONFIG_CACHE_L1_CACHE_LINE_SIZE - alignment_remainder); + } +#endif + adc_handle[adc_unit].buffer_size = adc_handle[adc_unit].conversion_frame_size * 2; //Conversion frame size buffer cant be bigger than 4092 bytes @@ -626,8 +632,21 @@ bool analogContinuousRead(adc_continuous_result_t **buffer, uint32_t timeout_ms) uint32_t bytes_read = 0; uint32_t read_raw[used_adc_channels]; uint32_t read_count[used_adc_channels]; - uint8_t adc_read[adc_handle[ADC_UNIT_1].conversion_frame_size]; - memset(adc_read, 0xcc, sizeof(adc_read)); + + // Allocate DMA buffer with cache line alignment (required for ESP32-P4 and other targets with cache) + size_t buffer_size = adc_handle[ADC_UNIT_1].conversion_frame_size; +#if CONFIG_IDF_TARGET_ESP32P4 + uint8_t *adc_read = (uint8_t *)heap_caps_aligned_alloc(CONFIG_CACHE_L1_CACHE_LINE_SIZE, buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); +#else + uint8_t *adc_read = (uint8_t *)heap_caps_malloc(buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); +#endif + if (adc_read == NULL) { + log_e("Failed to allocate DMA buffer"); + *buffer = NULL; + return false; + } + + memset(adc_read, 0xcc, buffer_size); memset(read_raw, 0, sizeof(read_raw)); memset(read_count, 0, sizeof(read_count)); @@ -638,6 +657,8 @@ bool analogContinuousRead(adc_continuous_result_t **buffer, uint32_t timeout_ms) } else { log_e("Reading data failed with error: %X", err); } + free(adc_read); + adc_read = NULL; *buffer = NULL; return false; } @@ -676,6 +697,8 @@ bool analogContinuousRead(adc_continuous_result_t **buffer, uint32_t timeout_ms) } } + free(adc_read); + adc_read = NULL; *buffer = adc_result; return true; @@ -708,16 +731,29 @@ bool analogContinuousStop() { } bool analogContinuousDeinit() { - if (adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL) { - esp_err_t err = adc_continuous_deinit(adc_handle[ADC_UNIT_1].adc_continuous_handle); - if (err != ESP_OK) { - return false; + if (adc_handle[ADC_UNIT_1].adc_continuous_handle == NULL) { + log_i("ADC Continuous was not initialized"); + return true; + } + + // Clear all used pins from peripheral manager + // This will trigger adcContinuousDetachBus() callback which cleans up the ADC driver + for (uint8_t channel = 0; channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1); channel++) { + int io_pin; + adc_oneshot_channel_to_io(ADC_UNIT_1, channel, &io_pin); + if (perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_CONT) { + if (!perimanClearPinBus(io_pin)) { + return false; + } } + } + + // Free the result buffer (callback doesn't do this) + if (adc_result != NULL) { free(adc_result); - adc_handle[ADC_UNIT_1].adc_continuous_handle = NULL; - } else { - log_i("ADC Continuous was not initialized"); + adc_result = NULL; } + return true; } diff --git a/cores/esp32/esp_arduino_version.h b/cores/esp32/esp_arduino_version.h index 587fe02cd16..15a04bbd1ac 100644 --- a/cores/esp32/esp_arduino_version.h +++ b/cores/esp32/esp_arduino_version.h @@ -23,7 +23,7 @@ extern "C" { /** Minor version number (x.X.x) */ #define ESP_ARDUINO_VERSION_MINOR 3 /** Patch version number (x.x.X) */ -#define ESP_ARDUINO_VERSION_PATCH 4 +#define ESP_ARDUINO_VERSION_PATCH 5 /** * Macro to convert ARDUINO version number into an integer diff --git a/docs/_static/matter_erase_flash.png b/docs/_static/matter_erase_flash.png new file mode 100644 index 00000000000..621fbe9a5b2 Binary files /dev/null and b/docs/_static/matter_erase_flash.png differ diff --git a/docs/_static/matter_partition_scheme.png b/docs/_static/matter_partition_scheme.png new file mode 100644 index 00000000000..f835e8b7268 Binary files /dev/null and b/docs/_static/matter_partition_scheme.png differ diff --git a/docs/conf_common.py b/docs/conf_common.py index 7f6e9324d29..0dddb8cc037 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -4,7 +4,7 @@ # Used for substituting variables in the documentation rst_prolog = """ -.. |version| replace:: 3.3.4 +.. |version| replace:: 3.3.5 .. |idf_version| replace:: 5.5 .. |no| replace:: ❌ .. |yes| replace:: ✅ diff --git a/docs/en/external_libraries_test.rst b/docs/en/external_libraries_test.rst index 4dda53cda0b..6e9b6e1519f 100644 --- a/docs/en/external_libraries_test.rst +++ b/docs/en/external_libraries_test.rst @@ -129,4 +129,4 @@ In the table the results are in order ``BEFORE -> AFTER``. :class: no-scaled-link .. _LIBRARIES_TEST.md: https://github.com/espressif/arduino-esp32/blob/gh-pages/LIBRARIES_TEST.md -.. _lib.json: https://github.com/espressif/arduino-esp32/.github/workflow/lib.json +.. _lib.json: https://github.com/espressif/arduino-esp32/blob/master/.github/workflows/lib.json diff --git a/docs/en/libraries.rst b/docs/en/libraries.rst index c4032c786c7..6b8e7d520dd 100644 --- a/docs/en/libraries.rst +++ b/docs/en/libraries.rst @@ -53,7 +53,7 @@ Here is a matrix of the library support status for the main features and periphe +----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ | Matter (Thread) [6]_ | |n/a| | |n/a| | |n/a| | |yes| | |yes| | |n/a| | |yes| | |n/a| | |n/a| | |n/a| | +----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -| Matter (Wi-Fi) | |yes| | |no| | |yes| | |yes| | |yes| | |no| | |n/a| | |n/a| | |yes| | |yes| | +| Matter (Wi-Fi) [7]_ | |yes| | |no| | |yes| | |no| | |yes| | |no| | |n/a| | |n/a| | |yes| | |yes| | +----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ | MIPI CSI | |n/a| | |n/a| | |n/a| | |n/a| | |n/a| | |n/a| | |n/a| | |no| | |n/a| | |n/a| | +----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ @@ -109,6 +109,10 @@ Here is a matrix of the library support status for the main features and periphe In order to use Matter over Thread, you need to use Arduino as an ESP-IDF component or rebuild the static libraries. Check the `Arduino_ESP_Matter_over_OpenThread example `_ for more details. +.. [7] Matter over Wi-Fi is supported by our library but is not included in the pre-compiled libraries for ESP32-C5. + Although ESP32-C5 has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. + In order to use Matter over Wi-Fi, you need to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. + .. note:: The ESP32-C2 and ESP32-C61 are only supported using Arduino as an ESP-IDF component or by rebuilding the static libraries. .. include:: common/datasheet.inc diff --git a/docs/en/matter/ep_occupancy_sensor.rst b/docs/en/matter/ep_occupancy_sensor.rst index 456cafccefe..a11afb1c28f 100644 --- a/docs/en/matter/ep_occupancy_sensor.rst +++ b/docs/en/matter/ep_occupancy_sensor.rst @@ -10,6 +10,9 @@ The ``MatterOccupancySensor`` class provides an occupancy sensor endpoint for Ma **Features:** * Occupancy state reporting (occupied/unoccupied) * Multiple sensor type support (PIR, Ultrasonic, Physical Contact) +* HoldTime attribute for configuring how long the sensor holds the "occupied" state +* HoldTimeLimits (min, max, default) for validation and controller guidance +* HoldTime change callback for real-time updates from Matter controllers * Simple boolean state * Read-only sensor (no control functionality) * Automatic state updates @@ -104,6 +107,83 @@ Gets the current occupancy state. This function will return ``true`` if occupied, ``false`` if unoccupied. +HoldTime Control +**************** + +setHoldTime +^^^^^^^^^^^ + +Sets the HoldTime value (in seconds). The HoldTime determines how long the sensor maintains the "occupied" state after the last detection. + +.. code-block:: arduino + + bool setHoldTime(uint16_t _holdTime_seconds); + +* ``_holdTime_seconds`` - HoldTime value in seconds + +**Important:** This function must be called after ``Matter.begin()`` has been called, as it requires the Matter event loop to be running. + +This function will return ``true`` if successful, ``false`` otherwise. + +getHoldTime +^^^^^^^^^^^ + +Gets the current HoldTime value (in seconds). + +.. code-block:: arduino + + uint16_t getHoldTime(); + +This function will return the current HoldTime value in seconds. + +setHoldTimeLimits +^^^^^^^^^^^^^^^^^ + +Sets the HoldTime limits (minimum, maximum, and default values). These limits define the valid range for HoldTime values and provide metadata for Matter controllers. + +.. code-block:: arduino + + bool setHoldTimeLimits(uint16_t _holdTimeMin_seconds, uint16_t _holdTimeMax_seconds, uint16_t _holdTimeDefault_seconds); + +* ``_holdTimeMin_seconds`` - Minimum HoldTime value in seconds +* ``_holdTimeMax_seconds`` - Maximum HoldTime value in seconds +* ``_holdTimeDefault_seconds`` - Default/recommended HoldTime value in seconds (informational metadata for controllers) + +**Important:** +* This function must be called after ``Matter.begin()`` has been called, as it requires the Matter event loop to be running. +* The ``holdTimeDefault_seconds`` parameter is informational metadata for Matter controllers (recommended default value). It does NOT automatically set the HoldTime attribute - use ``setHoldTime()`` to set the actual value. +* If the current HoldTime value is outside the new limits, it will be automatically adjusted to the nearest limit (minimum or maximum). + +This function will return ``true`` if successful, ``false`` otherwise. + +onHoldTimeChange +^^^^^^^^^^^^^^^^ + +Sets a callback function that will be called when the HoldTime value is changed by a Matter Controller. + +.. code-block:: arduino + + void onHoldTimeChange(HoldTimeChangeCB onHoldTimeChangeCB); + +* ``onHoldTimeChangeCB`` - Callback function of type ``HoldTimeChangeCB`` + +The callback function signature is: + +.. code-block:: arduino + + using HoldTimeChangeCB = std::function; + +The callback receives the new HoldTime value and can return ``true`` to accept the change or ``false`` to reject it. + +Example: + +.. code-block:: arduino + + OccupancySensor.onHoldTimeChange([](uint16_t holdTime_seconds) -> bool { + Serial.printf("HoldTime changed to %u seconds\n", holdTime_seconds); + return true; // Accept the change + }); + Operators ********* @@ -145,8 +225,22 @@ Example: Example ------- -Occupancy Sensor -**************** +Basic Occupancy Sensor +********************** .. literalinclude:: ../../../libraries/Matter/examples/MatterOccupancySensor/MatterOccupancySensor.ino :language: arduino + +Occupancy Sensor with HoldTime +******************************* + +For an example that demonstrates HoldTime functionality, see: + +.. literalinclude:: ../../../libraries/Matter/examples/MatterOccupancyWithHoldTime/MatterOccupancyWithHoldTime.ino + :language: arduino + +This example shows: +* How to configure HoldTimeLimits after ``Matter.begin()`` +* How to set and persist HoldTime values +* How to use the ``onHoldTimeChange()`` callback +* How to implement HoldTime expiration logic in sensor simulation diff --git a/docs/en/matter/matter.rst b/docs/en/matter/matter.rst index 69bcf10603c..1ea5b3573b7 100644 --- a/docs/en/matter/matter.rst +++ b/docs/en/matter/matter.rst @@ -16,6 +16,30 @@ The Matter library provides support for creating Matter-compatible devices inclu The Matter library is built on top of `ESP Matter SDK `_ and provides a high-level Arduino-style interface for creating Matter devices. +Building and Flashing Matter Examples +-------------------------------------- + +Before uploading any Matter example sketch, it is necessary to configure the Arduino IDE with the following settings: + +1. **Partition Scheme**: Select **"Huge APP (3 MB No OTA / 1 MB SPIFFS)"** from **Tools > Partition Scheme** menu. + + .. figure:: ../../_static/matter_partition_scheme.png + :align: center + :alt: "Partition Scheme: Huge APP (3 MB No OTA / 1 MB SPIFFS)" Arduino IDE menu option + :figclass: align-center + +2. **Erase Flash**: Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. + + .. figure:: ../../_static/matter_erase_flash.png + :align: center + :alt: "Erase All Flash Before Sketch Upload: Enabled" Arduino IDE menu option + :figclass: align-center + +These settings are required for the following reasons: + +* **Partition Scheme**: Matter firmware requires a large application partition (3 MB) to accommodate the Matter stack and application code. +* **Erase Flash**: Erasing flash is necessary to remove any leftover Wi-Fi or Matter configuration from the NVS (Non-Volatile Storage) partition. Without erasing, previous network credentials, Matter fabric information, or device commissioning data may interfere with the new firmware, causing commissioning failures or connectivity issues. + Matter Protocol Overview ************************ @@ -83,9 +107,13 @@ The ``Matter`` class provides the following key methods: * ``begin()``: Initializes the Matter stack * ``isDeviceCommissioned()``: Checks if the device is commissioned -* ``isWi-FiConnected()``: Checks Wi-Fi connection status (if Wi-Fi is enabled) -* ``isThreadConnected()``: Checks Thread connection status (if Thread is enabled) +* ``isWiFiConnected()``: Checks Wi-Fi connection status +* ``isThreadConnected()``: Checks Thread connection status * ``isDeviceConnected()``: Checks overall device connectivity +* ``isWiFiStationEnabled()``: Checks if Wi-Fi Station mode is supported and enabled +* ``isWiFiAccessPointEnabled()``: Checks if Wi-Fi AP mode is supported and enabled +* ``isThreadEnabled()``: Checks if Thread network is supported and enabled +* ``isBLECommissioningEnabled()``: Checks if BLE commissioning is supported and enabled * ``decommission()``: Factory resets the device * ``getManualPairingCode()``: Gets the manual pairing code for commissioning * ``getOnboardingQRCodeUrl()``: Gets the QR code URL for commissioning @@ -148,6 +176,56 @@ The library provides specialized endpoint classes for different device types. Ea ep_* +Matter Examples +--------------- + +The Matter library includes a comprehensive set of examples demonstrating various device types and use cases. All examples are available in the `ESP Arduino GitHub repository `_. + +**Basic Examples:** + +* **Matter Minimum** - The smallest code required to create a Matter-compatible device. Ideal starting point for understanding Matter basics. `View Matter Minimum code on GitHub `_ +* **Matter Status** - Demonstrates how to check enabled Matter features and connectivity status. Implements a basic on/off light and periodically reports capability and connection status. `View Matter Status code on GitHub `_ +* **Matter Events** - Shows how to monitor and handle Matter events. Provides a comprehensive view of all Matter events during device operation. `View Matter Events code on GitHub `_ +* **Matter Commission Test** - Tests Matter commissioning functionality with automatic decommissioning after a 30-second delay for continuous testing cycles. `View Matter Commission Test code on GitHub `_ + +**Lighting Examples:** + +* **Matter On/Off Light** - Creates a Matter-compatible on/off light device with commissioning, device control via smart home ecosystems, and manual control using a physical button with state persistence. `View Matter On/Off Light code on GitHub `_ +* **Matter Dimmable Light** - Creates a Matter-compatible dimmable light device with brightness control. `View Matter Dimmable Light code on GitHub `_ +* **Matter Color Temperature Light** - Creates a Matter-compatible color temperature light device with adjustable color temperature control. `View Matter Color Temperature Light code on GitHub `_ +* **Matter Color Light** - Creates a Matter-compatible color light device with RGB color control (HSV color model). `View Matter Color Light code on GitHub `_ +* **Matter Enhanced Color Light** - Creates a Matter-compatible enhanced color light with color temperature and brightness control. `View Matter Enhanced Color Light code on GitHub `_ +* **Matter Composed Lights** - Creates a Matter node with multiple light endpoints (On/Off Light, Dimmable Light, and Color Light) in a single node. `View Matter Composed Lights code on GitHub `_ +* **Matter On Identify** - Implements the Matter Identify cluster callback for an on/off light device, making the LED blink when the device is identified from a Matter app. `View Matter On Identify code on GitHub `_ + +**Sensor Examples:** + +* **Matter Temperature Sensor** - Creates a Matter-compatible temperature sensor device with sensor data reporting to smart home ecosystems. `View Matter Temperature Sensor code on GitHub `_ +* **Matter Humidity Sensor** - Creates a Matter-compatible humidity sensor device with sensor data reporting. `View Matter Humidity Sensor code on GitHub `_ +* **Matter Pressure Sensor** - Creates a Matter-compatible pressure sensor device with automatic simulation of pressure readings. `View Matter Pressure Sensor code on GitHub `_ +* **Matter Contact Sensor** - Creates a Matter-compatible contact sensor device (open/closed state). `View Matter Contact Sensor code on GitHub `_ +* **Matter Occupancy Sensor** - Creates a Matter-compatible occupancy sensor device with automatic simulation of occupancy state changes. `View Matter Occupancy Sensor code on GitHub `_ +* **Matter Occupancy Sensor with HoldTime** - Creates a Matter-compatible occupancy sensor device with HoldTime functionality, automatic simulation of occupancy state changes, HoldTime configuration with persistence across reboots, and HoldTime change callback for real-time updates from Matter controllers. `View Matter Occupancy Sensor with HoldTime code on GitHub `_ +* **Matter Water Leak Detector** - Creates a Matter-compatible water leak detector device with automatic simulation of water leak detection state changes. `View Matter Water Leak Detector code on GitHub `_ +* **Matter Water Freeze Detector** - Creates a Matter-compatible water freeze detector device with automatic simulation of water freeze detection state changes. `View Matter Water Freeze Detector code on GitHub `_ +* **Matter Rain Sensor** - Creates a Matter-compatible rain sensor device with automatic simulation of rain detection state changes. `View Matter Rain Sensor code on GitHub `_ + +**Control Examples:** + +* **Matter Fan** - Creates a Matter-compatible fan device with speed and mode control. `View Matter Fan code on GitHub `_ +* **Matter Thermostat** - Creates a Matter-compatible thermostat device with temperature setpoint management and simulated heating/cooling systems with automatic temperature regulation. `View Matter Thermostat code on GitHub `_ +* **Matter Temperature Controlled Cabinet** - Creates a Matter-compatible temperature controlled cabinet device with precise temperature setpoint control with min/max limits (temperature_number mode). `View Matter Temperature Controlled Cabinet code on GitHub `_ +* **Matter Temperature Controlled Cabinet Levels** - Creates a Matter-compatible temperature controlled cabinet device using predefined temperature levels (temperature_level mode). `View Matter Temperature Controlled Cabinet Levels code on GitHub `_ +* **Matter On/Off Plugin** - Creates a Matter-compatible on/off plugin unit (power relay) device with state persistence for power control applications. `View Matter On/Off Plugin code on GitHub `_ +* **Matter Dimmable Plugin** - Creates a Matter-compatible dimmable plugin unit (power outlet with level control) device with state persistence for dimmable power control applications. `View Matter Dimmable Plugin code on GitHub `_ +* **Matter Smart Button** - Creates a Matter-compatible smart button (generic switch) device that sends button click events to smart home ecosystems and triggers automations. `View Matter Smart Button code on GitHub `_ +* **Matter Window Covering** - Creates a Matter-compatible window covering device with lift and tilt control (blinds, shades) with manual control using a physical button. `View Matter Window Covering code on GitHub `_ +* **Matter Simple Blinds** - A minimal example that only controls lift percentage using a single onGoToLiftPercentage() callback. `View Matter Simple Blinds code on GitHub `_ + +**Advanced Examples:** + +* **Matter Lambda Single Callback Many Endpoints** - Demonstrates how to create multiple Matter endpoints in a single node using a shared lambda function callback with capture for efficient callback handling. `View Matter Lambda Single Callback Many Endpoints code on GitHub `_ + Common Problems and Issues -------------------------- diff --git a/docs/en/zigbee/ep_carbon_dioxide_sensor.rst b/docs/en/zigbee/ep_carbon_dioxide_sensor.rst index 6f219a16fd0..d595fda8e1f 100644 --- a/docs/en/zigbee/ep_carbon_dioxide_sensor.rst +++ b/docs/en/zigbee/ep_carbon_dioxide_sensor.rst @@ -54,6 +54,21 @@ Sets the minimum and maximum measurement values. This function will return ``true`` if successful, ``false`` otherwise. +setDefaultValue +^^^^^^^^^^^^^^^ + +Sets the default (initial) value for the carbon dioxide sensor in ppm. This value will be used as the initial measured value when the device is in factory reset mode and before the sensor provides actual readings. + +.. code-block:: arduino + + bool setDefaultValue(float defaultValue); + +* ``defaultValue`` - Default CO2 concentration value in ppm + +**Important:** Must be called before adding the EP to Zigbee class. Only effective when the device is in factory reset mode (before commissioning/joining a network). + +This function will return ``true`` if successful, ``false`` otherwise. + setTolerance ^^^^^^^^^^^^ diff --git a/docs/en/zigbee/ep_flow_sensor.rst b/docs/en/zigbee/ep_flow_sensor.rst index 9423f321a5d..95c3b5c72c4 100644 --- a/docs/en/zigbee/ep_flow_sensor.rst +++ b/docs/en/zigbee/ep_flow_sensor.rst @@ -70,6 +70,21 @@ Sets the minimum and maximum measurement values. This function will return ``true`` if successful, ``false`` otherwise. +setDefaultValue +^^^^^^^^^^^^^^^ + +Sets the default (initial) value for the flow sensor in 0.1 m³/h. This value will be used as the initial measured value when the device is in factory reset mode and before the sensor provides actual readings. + +.. code-block:: arduino + + bool setDefaultValue(float defaultValue); + +* ``defaultValue`` - Default flow rate value in 0.1 m³/h + +**Important:** Must be called before adding the EP to Zigbee class. Only effective when the device is in factory reset mode (before commissioning/joining a network). + +This function will return ``true`` if successful, ``false`` otherwise. + setTolerance ^^^^^^^^^^^^ diff --git a/docs/en/zigbee/ep_illuminance_sensor.rst b/docs/en/zigbee/ep_illuminance_sensor.rst index 1e627f7dfe9..73b676e3f52 100644 --- a/docs/en/zigbee/ep_illuminance_sensor.rst +++ b/docs/en/zigbee/ep_illuminance_sensor.rst @@ -60,6 +60,21 @@ Sets the minimum and maximum measurement values. This function will return ``true`` if successful, ``false`` otherwise. +setDefaultValue +^^^^^^^^^^^^^^^ + +Sets the default (initial) value for the illuminance sensor. This value will be used as the initial measured value when the device is in factory reset mode and before the sensor provides actual readings. + +.. code-block:: arduino + + bool setDefaultValue(uint16_t defaultValue); + +* ``defaultValue`` - Default illuminance value in lux + +**Important:** Must be called before adding the EP to Zigbee class. Only effective when the device is in factory reset mode (before commissioning/joining a network). + +This function will return ``true`` if successful, ``false`` otherwise. + setTolerance ^^^^^^^^^^^^ diff --git a/docs/en/zigbee/ep_pm25_sensor.rst b/docs/en/zigbee/ep_pm25_sensor.rst index 2f1432f8224..feac3c54e66 100644 --- a/docs/en/zigbee/ep_pm25_sensor.rst +++ b/docs/en/zigbee/ep_pm25_sensor.rst @@ -60,6 +60,21 @@ Sets the minimum and maximum measurement values. This function will return ``true`` if successful, ``false`` otherwise. +setDefaultValue +^^^^^^^^^^^^^^^ + +Sets the default (initial) value for the PM2.5 sensor in 0.1 μg/m³. This value will be used as the initial measured value when the device is in factory reset mode and before the sensor provides actual readings. + +.. code-block:: arduino + + bool setDefaultValue(float defaultValue); + +* ``defaultValue`` - Default PM2.5 concentration value in 0.1 μg/m³ + +**Important:** Must be called before adding the EP to Zigbee class. Only effective when the device is in factory reset mode (before commissioning/joining a network). + +This function will return ``true`` if successful, ``false`` otherwise. + setTolerance ^^^^^^^^^^^^ diff --git a/docs/en/zigbee/ep_pressure_sensor.rst b/docs/en/zigbee/ep_pressure_sensor.rst index 5d857bb163e..b8a5fbeb18d 100644 --- a/docs/en/zigbee/ep_pressure_sensor.rst +++ b/docs/en/zigbee/ep_pressure_sensor.rst @@ -60,6 +60,21 @@ Sets the minimum and maximum measurement values. This function will return ``true`` if successful, ``false`` otherwise. +setDefaultValue +^^^^^^^^^^^^^^^ + +Sets the default (initial) value for the pressure sensor in 1 hPa. This value will be used as the initial measured value when the device is in factory reset mode and before the sensor provides actual readings. + +.. code-block:: arduino + + bool setDefaultValue(int16_t defaultValue); + +* ``defaultValue`` - Default pressure value in hPa + +**Important:** Must be called before adding the EP to Zigbee class. Only effective when the device is in factory reset mode (before commissioning/joining a network). + +This function will return ``true`` if successful, ``false`` otherwise. + setTolerance ^^^^^^^^^^^^ diff --git a/docs/en/zigbee/ep_temperature_sensor.rst b/docs/en/zigbee/ep_temperature_sensor.rst index 85c2147f1a1..f14082d59f0 100644 --- a/docs/en/zigbee/ep_temperature_sensor.rst +++ b/docs/en/zigbee/ep_temperature_sensor.rst @@ -60,6 +60,21 @@ Sets the minimum and maximum temperature values for the sensor. This function will return ``true`` if successful, ``false`` otherwise. +setDefaultValue +^^^^^^^^^^^^^^^ + +Sets the default (initial) value for the temperature sensor in 0.01°C resolution. This value will be used as the initial measured value when the device is in factory reset mode and before the sensor provides actual readings. + +.. code-block:: arduino + + bool setDefaultValue(float defaultValue); + +* ``defaultValue`` - Default temperature value in degrees Celsius + +**Important:** Must be called before adding the EP to Zigbee class. Only effective when the device is in factory reset mode (before commissioning/joining a network). + +This function will return ``true`` if successful, ``false`` otherwise. + setTolerance ^^^^^^^^^^^^ diff --git a/docs/en/zigbee/ep_wind_speed_sensor.rst b/docs/en/zigbee/ep_wind_speed_sensor.rst index 67c4958e37c..7b294674e89 100644 --- a/docs/en/zigbee/ep_wind_speed_sensor.rst +++ b/docs/en/zigbee/ep_wind_speed_sensor.rst @@ -70,6 +70,21 @@ Sets the minimum and maximum measurement values. This function will return ``true`` if successful, ``false`` otherwise. +setDefaultValue +^^^^^^^^^^^^^^^ + +Sets the default (initial) value for the wind speed sensor in 0.01 m/s. This value will be used as the initial measured value when the device is in factory reset mode and before the sensor provides actual readings. + +.. code-block:: arduino + + bool setDefaultValue(float defaultValue); + +* ``defaultValue`` - Default wind speed value in 0.01 m/s + +**Important:** Must be called before adding the EP to Zigbee class. Only effective when the device is in factory reset mode (before commissioning/joining a network). + +This function will return ``true`` if successful, ``false`` otherwise. + setTolerance ^^^^^^^^^^^^ diff --git a/idf_component.yml b/idf_component.yml index 3e376391af2..fc83e00af5c 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -54,7 +54,7 @@ dependencies: version: "^1.2.3" require: public espressif/esp_modem: - version: "^1.1.0" + version: "^2.0.0" espressif/esp-zboss-lib: version: "==1.6.4" # compatible with esp-zigbee-lib 1.6.8 require: public @@ -109,11 +109,11 @@ dependencies: rules: - if: "target in [esp32s3, esp32p4]" espressif/esp_hosted: - version: "^2.0.12" + version: "^2.8.0" rules: - if: "target == esp32p4" espressif/esp_wifi_remote: - version: "^0.13.0" + version: "^1.2.2" rules: - if: "target == esp32p4" espressif/libsodium: diff --git a/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino b/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino index 934789a52bf..4dba9351ebf 100644 --- a/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino +++ b/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino @@ -38,9 +38,6 @@ void setup() { // Hostname defaults to esp3232-[MAC] // ArduinoOTA.setHostname("myesp32"); - // No authentication by default - // ArduinoOTA.setPassword("admin"); - // Password can be set with plain text (will be hashed internally) // The authentication uses PBKDF2-HMAC-SHA256 with 10,000 iterations // ArduinoOTA.setPassword("admin"); diff --git a/libraries/ArduinoOTA/examples/SignedOTA/README.md b/libraries/ArduinoOTA/examples/SignedOTA/README.md new file mode 100644 index 00000000000..bf5f12b6d67 --- /dev/null +++ b/libraries/ArduinoOTA/examples/SignedOTA/README.md @@ -0,0 +1,323 @@ +# SignedOTA - Secure OTA Updates with Signature Verification + +This example demonstrates how to perform secure OTA updates with cryptographic signature verification using the ArduinoOTA library. + +## Overview + +**SignedOTA** adds an extra layer of security to Arduino OTA updates by requiring all firmware to be cryptographically signed with your private key. This protects against: + +- ✅ Unauthorized firmware updates +- ✅ Man-in-the-middle attacks +- ✅ Compromised networks +- ✅ Firmware tampering +- ✅ Supply chain attacks + +Even if an attacker gains access to your network, they **cannot** install unsigned firmware on your devices. + +## Features + +- **RSA & ECDSA Support**: RSA-2048/3072/4096 and ECDSA-P256/P384 +- **Multiple Hash Algorithms**: SHA-256, SHA-384, SHA-512 +- **Arduino IDE Compatible**: Works with standard Arduino OTA workflow +- **Optional Password Protection**: Add password authentication in addition to signature verification +- **Easy Integration**: Just a few lines of code + +## Requirements + +- **ESP32 Arduino Core 3.3.0+** +- **Python 3.6+** with `cryptography` library + +- **OTA-capable partition scheme** (e.g., "Minimal SPIFFS (1.9MB APP with OTA)") + + +## Quick Start Guide + +### 1. Generate Cryptographic Keys + +```bash +# Navigate to Arduino ESP32 tools directory +cd /tools + +# Install Python dependencies +pip install cryptography + +# Generate RSA-2048 key pair (recommended) +python bin_signing.py --generate-key rsa-2048 --out private_key.pem + +# Extract public key +python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +``` + +**⚠️ IMPORTANT: Keep `private_key.pem` secure! Anyone with this key can sign firmware for your devices.** + +### 2. Setup the Example + +1. Copy `public_key.h` (generated in step 1) to this sketch directory +2. Open `SignedOTA.ino` in Arduino IDE + +3. Configure WiFi credentials: + ```cpp + const char *ssid = "YourWiFiSSID"; + const char *password = "YourWiFiPassword"; + ``` + + +4. Select appropriate partition scheme: + - **Tools → Partition Scheme → "Minimal SPIFFS (1.9MB APP with OTA)"** + + +### 3. Upload Initial Firmware + +1. Connect your ESP32 via USB +2. Upload the sketch normally +3. Open Serial Monitor (115200 baud) +4. Note the device IP address + +### 4. Build & Sign Firmware for OTA Update Example + +**Option A: Using Arduino IDE** + +```bash +# Export compiled binary +# In Arduino IDE: Sketch → Export Compiled Binary + +# Sign the firmware +cd /tools +python bin_signing.py \ + --bin /path/to/SignedOTA.ino.bin \ + --key private_key.pem \ + --out firmware_signed.bin +``` + +**Option B: Using arduino-cli** + +```bash +# Compile and export +arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries SignedOTA + +# Sign the firmware +cd /tools +python bin_signing.py \ + --bin build/esp32.esp32.esp32/SignedOTA.ino.bin \ + --key private_key.pem \ + --out firmware_signed.bin +``` + +### 5. Upload Signed Firmware via OTA + +Upload the signed firmware using `espota.py`: + +```bash +python /tools/espota.py -i -f firmware_signed.bin +``` + +The device will automatically: +1. Receive the signed firmware (firmware + signature) +2. Hash only the firmware portion +3. Verify the signature +4. Install if valid, reject if invalid + +**Note**: You can also use the Update library's `Signed_OTA_Update` example for HTTP-based OTA updates. + +## Configuration Options + +### Hash Algorithms + +Choose one in `SignedOTA.ino`: + +```cpp +#define USE_SHA256 // Default, fastest +// #define USE_SHA384 +// #define USE_SHA512 +``` + +**Must match** the `--hash` parameter when signing: + +```bash +python bin_signing.py --bin firmware.bin --key private.pem --out signed.bin --hash sha256 +``` + +### Signature Algorithms + +Choose one in `SignedOTA.ino`: + +```cpp +#define USE_RSA // For RSA keys +// #define USE_ECDSA // For ECDSA keys +``` + +### Optional Password Protection + +Add password authentication **in addition to** signature verification: + +```cpp +const char *ota_password = "yourpassword"; // Set password +// const char *ota_password = nullptr; // Disable password +``` + +## How It Works + +``` +┌─────────────────┐ +│ Build Firmware │ +└────────┬────────┘ + │ + ▼ +┌─────────────────┐ +│ Sign Firmware │ ← Uses your private key +│ (bin_signing) │ +└────────┬────────┘ + │ + ▼ +┌─────────────────────────┐ +│ firmware_signed.bin │ +│ [firmware][signature] │ +└────────┬────────────────┘ + │ + ▼ OTA Upload +┌─────────────────────────┐ +│ ESP32 Device │ +│ ┌──────────────────┐ │ +│ │ Verify Signature │ │ ← Uses your public key +│ │ ✓ or ✗ │ │ +│ └──────────────────┘ │ +│ │ │ +│ ✓ Valid? │ +│ ├─ Yes: Install │ +│ └─ No: Reject │ +└─────────────────────────┘ +``` + +## Troubleshooting + +### "Begin Failed" Error + +**Cause**: Signature verification setup failed, or partition scheme issue + +**Solutions**: + +1. Check partition scheme (use "Minimal SPIFFS (1.9MB APP with OTA)") +2. Verify `public_key.h` is in the sketch directory +3. Check hash and signature algorithm match your key type + + +### "End Failed" Error + +**Cause**: Signature verification failed + +**Solutions**: +1. Ensure firmware was signed with the **correct private key** +2. Verify hash algorithm matches (SHA-256, SHA-384, SHA-512) +3. Check firmware wasn't corrupted during signing/transfer +4. Confirm you signed the **correct** `.bin` file + +### "Receive Failed" Error + +**Cause**: Network timeout or connection issue + +**Solutions**: +1. Check Wi-Fi signal strength +2. Ensure device is reachable on the network +3. Try increasing timeout: `ArduinoOTA.setTimeout(5000)` + +### Upload Fails + +**Issue**: OTA upload fails or times out + +**Solutions**: +1. Verify device is on the same network +2. Check firewall settings aren't blocking port 3232 +3. Ensure Wi-Fi signal strength is adequate +4. If using password protection, ensure the password is correct +5. Try: `python /tools/espota.py -i -f firmware_signed.bin -d` + +## Security Considerations + +### Best Practices + +✅ **Keep private key secure**: Never commit to git, store encrypted +✅ **Use strong keys**: RSA-2048+ or ECDSA-P256+ +✅ **Use HTTPS when possible**: For additional transport security +✅ **Add password authentication**: Extra layer of protection +✅ **Rotate keys periodically**: Generate new keys every 1-2 years + +### What This Protects Against + +- ✅ Unsigned firmware installation +- ✅ Firmware signed with wrong key +- ✅ Tampered/corrupted firmware +- ✅ Network-based attacks (when combined with password) + +### What This Does NOT Protect Against + + +- ❌ Physical access (USB flashing still works) +- ❌ Downgrade attacks (no version checking by default) +- ❌ Replay attacks (no timestamp/nonce by default) +- ❌ Key compromise (if private key is stolen) + + +### Additional Security + +For production deployments, consider: + +1. **Add version checking** to prevent downgrades +2. **Add timestamp validation** to prevent replay attacks +3. **Use secure boot** for additional protection +4. **Store keys in HSM** or secure key management system +5. **Implement key rotation** mechanism + +## Advanced Usage + +### Using ECDSA Instead of RSA + +ECDSA keys are smaller and faster: + +```bash +# Generate ECDSA-P256 key +python bin_signing.py --generate-key ecdsa-p256 --out private_key.pem +python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +``` + +In `SignedOTA.ino`: + +```cpp +#define USE_SHA256 +#define USE_ECDSA // Instead of USE_RSA +``` + +### Using SHA-384 or SHA-512 + +For higher security: + +```bash +# Sign with SHA-384 +python bin_signing.py --bin firmware.bin --key private.pem --out signed.bin --hash sha384 +``` + +In `SignedOTA.ino`: + +```cpp +#define USE_SHA384 // Instead of USE_SHA256 +#define USE_RSA +``` + +### Custom Partition Label + +To update a specific partition: + +```cpp +ArduinoOTA.setPartitionLabel("my_partition"); +``` + +## Support + +For issues and questions: + +- Update Library README: `libraries/Update/README.md` +- ESP32 Arduino Core: https://github.com/espressif/arduino-esp32 +- Forum: https://github.com/espressif/arduino-esp32/discussions + +## License + +This library is part of the Arduino-ESP32 project and is licensed under the Apache License 2.0. diff --git a/libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino b/libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino new file mode 100644 index 00000000000..ec23489ee4b --- /dev/null +++ b/libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino @@ -0,0 +1,204 @@ +/* + * SignedOTA Example - Secure OTA Updates with Signature Verification + * + * This example demonstrates how to perform OTA updates with cryptographic + * signature verification using ArduinoOTA library. + * + * IMPORTANT: This example requires firmware to be signed with bin_signing.py + * + * NOTE: Signature verification support is enabled via the build_opt.h file + * in this directory. + * + * Setup: + * 1. Generate keys: + * python /tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem + * python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem + * + * 2. Copy public_key.h to this sketch directory + * + * 3. Configure WiFi credentials below + * + * 4. Upload this sketch to your device + * + * 5. Build your firmware and sign it: + * arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries SignedOTA + * python /tools/bin_signing.py --bin build/.bin --key private_key.pem --out firmware_signed.bin + * + * 6. Upload signed firmware using espota.py or Arduino IDE (after modifying espota.py to handle signed binaries) + * python /tools/espota.py -i -f firmware_signed.bin + * + * For more information, see the Update library's Signed_OTA_Update example + * and README.md in the Update library folder. + * + * Created by lucasssvaz + */ + +#include +#include +#include +#include + +// Include your public key (generated with bin_signing.py) +#include "public_key.h" + +// ==================== CONFIGURATION ==================== + +// WiFi credentials +const char *ssid = ".........."; +const char *password = ".........."; + +// Optional: Set a password for OTA authentication +// This is in ADDITION to signature verification +// ArduinoOTA password protects the OTA connection +// Signature verification ensures firmware authenticity +const char *ota_password = nullptr; // Set to nullptr to disable, or "yourpassword" to enable + +// Choose hash algorithm (must match what you use with bin_signing.py --hash) +// Uncomment ONE of these: +#define USE_SHA256 // Default, recommended +// #define USE_SHA384 +// #define USE_SHA512 + +// Choose signature algorithm (must match your key type) +// Uncomment ONE of these: +#define USE_RSA // Recommended (works with rsa-2048, rsa-3072, rsa-4096) +// #define USE_ECDSA // Works with ecdsa-p256, ecdsa-p384 + +// ======================================================= + +uint32_t last_ota_time = 0; + +void setup() { + Serial.begin(115200); + Serial.println("\n\n================================="); + Serial.println("SignedOTA - Secure OTA Updates"); + Serial.println("=================================\n"); + Serial.println("Booting..."); + + // Connect to WiFi + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("Connection Failed! Rebooting..."); + delay(5000); + ESP.restart(); + } + + Serial.println("WiFi Connected!"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // ==================== SIGNATURE VERIFICATION SETUP ==================== + + // Select hash algorithm +#ifdef USE_SHA256 + int hashType = HASH_SHA256; + Serial.println("Using SHA-256 hash"); +#elif defined(USE_SHA384) + int hashType = HASH_SHA384; + Serial.println("Using SHA-384 hash"); +#elif defined(USE_SHA512) + int hashType = HASH_SHA512; + Serial.println("Using SHA-512 hash"); +#else +#error "Please define a hash algorithm (USE_SHA256, USE_SHA384, or USE_SHA512)" +#endif + + // Create verifier object +#ifdef USE_RSA + static UpdaterRSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType); + Serial.println("Using RSA signature verification"); +#elif defined(USE_ECDSA) + static UpdaterECDSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType); + Serial.println("Using ECDSA signature verification"); +#else +#error "Please define a signature type (USE_RSA or USE_ECDSA)" +#endif + + // Install signature verification BEFORE ArduinoOTA.begin() + ArduinoOTA.setSignature(&sign); + Serial.println("✓ Signature verification enabled"); + + // ======================================================================= + + // Optional: Set hostname + // ArduinoOTA.setHostname("myesp32"); + + // Optional: Set OTA password (in addition to signature verification) + if (ota_password != nullptr) { + ArduinoOTA.setPassword(ota_password); + Serial.println("✓ OTA password protection enabled"); + } + + // Configure OTA callbacks + ArduinoOTA + .onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) { + type = "sketch"; + } else { // U_SPIFFS + type = "filesystem"; + } + Serial.println("\n================================="); + Serial.println("OTA Update Starting: " + type); + Serial.println("================================="); + Serial.println("⚠️ Signature will be verified!"); + }) + .onEnd([]() { + Serial.println("\n================================="); + Serial.println("✅ OTA Update Complete!"); + Serial.println("✅ Signature Verified!"); + Serial.println("================================="); + Serial.println("Rebooting..."); + }) + .onProgress([](unsigned int progress, unsigned int total) { + if (millis() - last_ota_time > 500) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + last_ota_time = millis(); + } + }) + .onError([](ota_error_t error) { + Serial.println("\n================================="); + Serial.println("❌ OTA Update Failed!"); + Serial.println("================================="); + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) { + Serial.println("Authentication Failed"); + Serial.println("Check your OTA password"); + } else if (error == OTA_BEGIN_ERROR) { + Serial.println("Begin Failed"); + Serial.println("This could be:"); + Serial.println("- Signature verification setup failed"); + Serial.println("- Not enough space for update"); + Serial.println("- Invalid partition"); + } else if (error == OTA_CONNECT_ERROR) { + Serial.println("Connect Failed"); + } else if (error == OTA_RECEIVE_ERROR) { + Serial.println("Receive Failed"); + } else if (error == OTA_END_ERROR) { + Serial.println("End Failed"); + Serial.println("This could be:"); + Serial.println("- ❌ SIGNATURE VERIFICATION FAILED!"); + Serial.println("- Firmware not signed with correct key"); + Serial.println("- Firmware corrupted during transfer"); + Serial.println("- MD5 checksum mismatch"); + } + Serial.println("================================="); + }); + + // Start ArduinoOTA service + ArduinoOTA.begin(); + + Serial.println("\n================================="); + Serial.println("✓ OTA Server Ready"); + Serial.println("================================="); + Serial.printf("Hostname: %s.local\n", ArduinoOTA.getHostname().c_str()); + Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str()); + Serial.println("Port: 3232"); + Serial.println("\n⚠️ Only signed firmware will be accepted!"); + Serial.println("=================================\n"); +} + +void loop() { + ArduinoOTA.handle(); +} diff --git a/libraries/ArduinoOTA/examples/SignedOTA/build_opt.h b/libraries/ArduinoOTA/examples/SignedOTA/build_opt.h new file mode 100644 index 00000000000..1b328fa2487 --- /dev/null +++ b/libraries/ArduinoOTA/examples/SignedOTA/build_opt.h @@ -0,0 +1 @@ +-DUPDATE_SIGN diff --git a/libraries/ArduinoOTA/examples/SignedOTA/ci.yml b/libraries/ArduinoOTA/examples/SignedOTA/ci.yml new file mode 100644 index 00000000000..006e6e07dda --- /dev/null +++ b/libraries/ArduinoOTA/examples/SignedOTA/ci.yml @@ -0,0 +1,3 @@ +requires_any: + - CONFIG_SOC_WIFI_SUPPORTED=y + - CONFIG_ESP_WIFI_REMOTE_ENABLED=y diff --git a/libraries/ArduinoOTA/examples/SignedOTA/public_key.h b/libraries/ArduinoOTA/examples/SignedOTA/public_key.h new file mode 100644 index 00000000000..fd820287134 --- /dev/null +++ b/libraries/ArduinoOTA/examples/SignedOTA/public_key.h @@ -0,0 +1,30 @@ +// Public key for OTA signature verification +// Include this in your Arduino sketch + +// ⚠️ THIS IS A TEST KEY - DO NOT USE IN PRODUCTION! +// Generate your own keys using: +// python /tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem +// python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +// +// Then replace this file with the generated public_key.h + +// Test RSA-2048 Public Key (PEM format) +const uint8_t PUBLIC_KEY[] PROGMEM = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x73, 0x35, 0x35, 0x66, 0x4f, 0x74, 0x51, + 0x64, 0x69, 0x70, 0x39, 0x58, 0x6f, 0x49, 0x61, 0x6c, 0x52, 0x5a, 0x4b, 0x6c, 0x4a, 0x0a, 0x52, 0x62, 0x55, 0x73, 0x49, 0x30, 0x4c, 0x48, 0x5a, 0x74, 0x2b, + 0x50, 0x58, 0x35, 0x4b, 0x58, 0x43, 0x79, 0x54, 0x64, 0x63, 0x78, 0x71, 0x6c, 0x6f, 0x44, 0x45, 0x2b, 0x63, 0x38, 0x43, 0x6f, 0x32, 0x50, 0x77, 0x37, 0x6f, + 0x66, 0x63, 0x66, 0x30, 0x47, 0x41, 0x38, 0x4a, 0x55, 0x65, 0x6e, 0x6d, 0x45, 0x46, 0x6b, 0x57, 0x6a, 0x50, 0x53, 0x48, 0x4c, 0x55, 0x55, 0x79, 0x44, 0x0a, + 0x63, 0x65, 0x4b, 0x63, 0x2b, 0x71, 0x45, 0x47, 0x54, 0x58, 0x72, 0x59, 0x39, 0x56, 0x6f, 0x4d, 0x38, 0x6f, 0x42, 0x58, 0x39, 0x67, 0x48, 0x41, 0x64, 0x4b, + 0x4f, 0x51, 0x48, 0x33, 0x50, 0x4d, 0x70, 0x4a, 0x69, 0x56, 0x51, 0x71, 0x4e, 0x43, 0x36, 0x37, 0x31, 0x44, 0x37, 0x54, 0x45, 0x76, 0x4e, 0x52, 0x43, 0x67, + 0x6e, 0x4f, 0x41, 0x37, 0x77, 0x62, 0x77, 0x6f, 0x78, 0x4e, 0x0a, 0x63, 0x75, 0x59, 0x30, 0x49, 0x6e, 0x51, 0x4e, 0x30, 0x64, 0x6b, 0x42, 0x43, 0x4f, 0x63, + 0x34, 0x4e, 0x66, 0x31, 0x56, 0x42, 0x76, 0x35, 0x64, 0x71, 0x55, 0x57, 0x41, 0x62, 0x66, 0x43, 0x57, 0x68, 0x5a, 0x37, 0x31, 0x72, 0x4a, 0x56, 0x32, 0x53, + 0x68, 0x79, 0x35, 0x48, 0x42, 0x48, 0x48, 0x52, 0x4e, 0x43, 0x78, 0x4f, 0x67, 0x58, 0x68, 0x4f, 0x6c, 0x66, 0x6c, 0x66, 0x0a, 0x72, 0x49, 0x57, 0x56, 0x71, + 0x66, 0x51, 0x4b, 0x2b, 0x75, 0x54, 0x4d, 0x62, 0x39, 0x4a, 0x4c, 0x51, 0x67, 0x76, 0x4a, 0x66, 0x70, 0x4c, 0x61, 0x65, 0x35, 0x35, 0x61, 0x61, 0x4e, 0x77, + 0x63, 0x72, 0x62, 0x59, 0x38, 0x58, 0x67, 0x53, 0x79, 0x31, 0x64, 0x6c, 0x58, 0x76, 0x4e, 0x37, 0x4d, 0x33, 0x75, 0x4c, 0x52, 0x72, 0x4b, 0x79, 0x61, 0x75, + 0x34, 0x59, 0x0a, 0x39, 0x51, 0x53, 0x71, 0x76, 0x4a, 0x71, 0x67, 0x52, 0x61, 0x36, 0x66, 0x47, 0x51, 0x2f, 0x4d, 0x41, 0x63, 0x6c, 0x48, 0x59, 0x33, 0x6d, + 0x4b, 0x64, 0x6e, 0x64, 0x68, 0x51, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4c, + 0x49, 0x43, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, +}; +const size_t PUBLIC_KEY_LEN = 451; diff --git a/libraries/ArduinoOTA/keywords.txt b/libraries/ArduinoOTA/keywords.txt index 9774de881ea..9c8a81df3ae 100644 --- a/libraries/ArduinoOTA/keywords.txt +++ b/libraries/ArduinoOTA/keywords.txt @@ -29,6 +29,7 @@ setPartitionLabel KEYWORD2 getPartitionLabel KEYWORD2 setRebootOnSuccess KEYWORD2 setMdnsEnabled KEYWORD2 +setSignature KEYWORD2 getCommand KEYWORD2 setTimeout KEYWORD2 diff --git a/libraries/ArduinoOTA/library.properties b/libraries/ArduinoOTA/library.properties index 604e21d2819..9b9c5e4cf8d 100644 --- a/libraries/ArduinoOTA/library.properties +++ b/libraries/ArduinoOTA/library.properties @@ -1,5 +1,5 @@ name=ArduinoOTA -version=3.3.4 +version=3.3.5 author=Ivan Grokhotkov and Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download. diff --git a/libraries/ArduinoOTA/src/ArduinoOTA.cpp b/libraries/ArduinoOTA/src/ArduinoOTA.cpp index e6e17cb9781..d20cfb07aa9 100644 --- a/libraries/ArduinoOTA/src/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/src/ArduinoOTA.cpp @@ -28,7 +28,13 @@ ArduinoOTAClass::ArduinoOTAClass(UpdateClass *updater) : _updater(updater), _port(0), _initialized(false), _rebootOnSuccess(true), _mdnsEnabled(true), _state(OTA_IDLE), _size(0), _cmd(0), _ota_port(0), - _ota_timeout(1000), _start_callback(NULL), _end_callback(NULL), _error_callback(NULL), _progress_callback(NULL) {} + _ota_timeout(1000), _start_callback(NULL), _end_callback(NULL), _error_callback(NULL), _progress_callback(NULL) +#ifdef UPDATE_SIGN + , + _sign(NULL) +#endif /* UPDATE_SIGN */ +{ +} ArduinoOTAClass::~ArduinoOTAClass() { end(); @@ -136,6 +142,21 @@ ArduinoOTAClass &ArduinoOTAClass::setMdnsEnabled(bool enabled) { return *this; } +#ifdef UPDATE_SIGN +ArduinoOTAClass &ArduinoOTAClass::setSignature(UpdaterVerifyClass *sign) { + if (_state == OTA_IDLE && sign) { + _sign = sign; + int hashType = sign->getHashType(); + [[maybe_unused]] + const char *hashName = (hashType == HASH_SHA256) ? "SHA-256" + : (hashType == HASH_SHA384) ? "SHA-384" + : "SHA-512"; + log_i("Signature verification enabled for ArduinoOTA (hash: %s)", hashName); + } + return *this; +} +#endif /* UPDATE_SIGN */ + void ArduinoOTAClass::begin() { if (_initialized) { log_w("already initialized"); @@ -301,6 +322,22 @@ void ArduinoOTAClass::_runUpdate() { log_e("UpdateClass is NULL!"); return; } + +#ifdef UPDATE_SIGN + // Install signature verification if enabled + if (_sign) { + if (!_updater->installSignature(_sign)) { + log_e("Failed to install signature verification"); + if (_error_callback) { + _error_callback(OTA_BEGIN_ERROR); + } + _state = OTA_IDLE; + return; + } + log_i("Signature verification installed for OTA update"); + } +#endif /* UPDATE_SIGN */ + const char *partition_label = _partition_label.length() ? _partition_label.c_str() : NULL; if (!_updater->begin(_size, _cmd, -1, LOW, partition_label)) { diff --git a/libraries/ArduinoOTA/src/ArduinoOTA.h b/libraries/ArduinoOTA/src/ArduinoOTA.h index d95c9d798f8..e291f1b9abe 100644 --- a/libraries/ArduinoOTA/src/ArduinoOTA.h +++ b/libraries/ArduinoOTA/src/ArduinoOTA.h @@ -74,6 +74,14 @@ class ArduinoOTAClass { //Sets if the device should advertise itself to Arduino IDE. Default true ArduinoOTAClass &setMdnsEnabled(bool enabled); +#ifdef UPDATE_SIGN + //Install signature verification for OTA updates + //Must be called before begin() + //sign: Signature verifier to use (e.g., UpdaterRSAVerifier or UpdaterECDSAVerifier) + // The hash type is determined from the verifier's configuration + ArduinoOTAClass &setSignature(UpdaterVerifyClass *sign); +#endif /* UPDATE_SIGN */ + //This callback will be called when OTA connection has begun ArduinoOTAClass &onStart(THandlerFunction fn); @@ -124,6 +132,10 @@ class ArduinoOTAClass { THandlerFunction_Error _error_callback; THandlerFunction_Progress _progress_callback; +#ifdef UPDATE_SIGN + UpdaterVerifyClass *_sign; +#endif /* UPDATE_SIGN */ + void _runUpdate(void); void _onRx(void); int parseInt(void); diff --git a/libraries/AsyncUDP/library.properties b/libraries/AsyncUDP/library.properties index 0dc51eae1f7..62608388dd6 100644 --- a/libraries/AsyncUDP/library.properties +++ b/libraries/AsyncUDP/library.properties @@ -1,5 +1,5 @@ name=ESP32 Async UDP -version=3.3.4 +version=3.3.5 author=Me-No-Dev maintainer=Me-No-Dev sentence=Async UDP Library for ESP32 diff --git a/libraries/BLE/examples/Client_Server/Client_Server.ino b/libraries/BLE/examples/Client_Server/Client_Server.ino new file mode 100644 index 00000000000..af8db874bc4 --- /dev/null +++ b/libraries/BLE/examples/Client_Server/Client_Server.ino @@ -0,0 +1,280 @@ +/* + * BLE Client and Server Coexistence Example + * + * This example demonstrates how to run both BLE client and server + * functionality on the same ESP32 device simultaneously. + * + * The device will: + * - Act as a BLE server, advertising a service with a characteristic + * - Act as a BLE client, scanning for other BLE servers + * - Connect to found servers and interact with their services + * - Handle both incoming and outgoing connections + * + * You can test this example by uploading it to two ESP32 boards. + * + * Author: lucasssvaz + * Based on Arduino BLE examples + */ + +#include +#include +#include +#include +#include + +// Server-side definitions +#define SERVER_SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define SERVER_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + +// Client-side definitions (looking for the same service) +static BLEUUID clientServiceUUID(SERVER_SERVICE_UUID); +static BLEUUID clientCharUUID(SERVER_CHARACTERISTIC_UUID); + +// Server objects +BLEServer *pServer = nullptr; +BLECharacteristic *pServerCharacteristic = nullptr; + +// Client objects +static boolean doConnect = false; +static boolean clientConnected = false; +static BLERemoteCharacteristic *pRemoteCharacteristic; +static BLEAdvertisedDevice *targetDevice; +static BLEClient *pClient = nullptr; +BLEScan *pBLEScan = nullptr; + +// Server callbacks +class ServerCallbacks : public BLEServerCallbacks { + void onConnect(BLEServer *pServer) { + Serial.println("Server: Client connected"); + } + + void onDisconnect(BLEServer *pServer) { + Serial.println("Server: Client disconnected"); + // Restart advertising + BLEDevice::startAdvertising(); + } +}; + +// Characteristic callbacks for server +class CharacteristicCallbacks : public BLECharacteristicCallbacks { + void onWrite(BLECharacteristic *pCharacteristic) { + String value = pCharacteristic->getValue(); + Serial.print("Server: Characteristic written, value: "); + Serial.println(value.c_str()); + } + + void onRead(BLECharacteristic *pCharacteristic) { + Serial.println("Server: Characteristic read"); + } +}; + +// Client callbacks +class ClientCallbacks : public BLEClientCallbacks { + void onConnect(BLEClient *pClient) { + Serial.println("Client: Connected to server"); + clientConnected = true; + } + + void onDisconnect(BLEClient *pClient) { + Serial.println("Client: Disconnected from server"); + clientConnected = false; + } +}; + +// Client notification callback +static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify) { + Serial.print("Client: Notify callback for characteristic "); + Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); + Serial.print(" of data length "); + Serial.println(length); + Serial.print("Client: Data: "); + Serial.write(pData, length); + Serial.println(); +} + +// Scan callbacks +class AdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks { + void onResult(BLEAdvertisedDevice advertisedDevice) { + Serial.print("Client: Found device: "); + Serial.println(advertisedDevice.toString().c_str()); + + // Check if this device has our target service + if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(clientServiceUUID) && !clientConnected) { + + Serial.println("Client: Found target service, attempting connection..."); + BLEDevice::getScan()->stop(); + targetDevice = new BLEAdvertisedDevice(advertisedDevice); + doConnect = true; + } + } +}; + +bool connectToServer() { + Serial.print("Client: Forming connection to "); + Serial.println(targetDevice->getAddress().toString().c_str()); + + // Create client if it doesn't exist, otherwise reuse existing one + if (pClient == nullptr) { + pClient = BLEDevice::createClient(); + pClient->setClientCallbacks(new ClientCallbacks()); + Serial.println("Client: Created new client"); + } else { + Serial.println("Client: Reusing existing client"); + } + + if (!pClient->connect(targetDevice)) { + Serial.println("Client: Failed to connect"); + return false; + } + + Serial.println("Client: Connected to server"); + pClient->setMTU(517); // Request maximum MTU + + // Get the service + BLERemoteService *pRemoteService = pClient->getService(clientServiceUUID); + if (pRemoteService == nullptr) { + Serial.print("Client: Failed to find service UUID: "); + Serial.println(clientServiceUUID.toString().c_str()); + pClient->disconnect(); + return false; + } + Serial.println("Client: Found service"); + + // Get the characteristic + pRemoteCharacteristic = pRemoteService->getCharacteristic(clientCharUUID); + if (pRemoteCharacteristic == nullptr) { + Serial.print("Client: Failed to find characteristic UUID: "); + Serial.println(clientCharUUID.toString().c_str()); + pClient->disconnect(); + return false; + } + Serial.println("Client: Found characteristic"); + + // Read the initial value + if (pRemoteCharacteristic->canRead()) { + String value = pRemoteCharacteristic->readValue(); + Serial.print("Client: Initial characteristic value: "); + Serial.println(value.c_str()); + } + + // Register for notifications if available + if (pRemoteCharacteristic->canNotify()) { + pRemoteCharacteristic->registerForNotify(notifyCallback); + Serial.println("Client: Registered for notifications"); + } + + return true; +} + +void setupServer() { + Serial.println("Setting up BLE Server..."); + + // Create server + pServer = BLEDevice::createServer(); + pServer->setCallbacks(new ServerCallbacks()); + + // Create service + BLEService *pService = pServer->createService(SERVER_SERVICE_UUID); + + // Create characteristic + pServerCharacteristic = pService->createCharacteristic( + SERVER_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY + ); + + pServerCharacteristic->setCallbacks(new CharacteristicCallbacks()); + pServerCharacteristic->setValue("Hello from Coexistence Server"); + + // Start service + pService->start(); + + // Start advertising + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVER_SERVICE_UUID); + pAdvertising->setScanResponse(true); + pAdvertising->setMinPreferred(0x06); + pAdvertising->setMinPreferred(0x12); + + BLEDevice::startAdvertising(); + + Serial.println("Server: Advertising started"); +} + +void setupClient() { + Serial.println("Setting up BLE Client..."); + + // Create scanner + pBLEScan = BLEDevice::getScan(); + pBLEScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks()); + pBLEScan->setActiveScan(true); + pBLEScan->setInterval(100); + pBLEScan->setWindow(99); + + Serial.println("Client: Scanner configured"); +} + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE Client-Server Coexistence Example..."); + + // Initialize BLE device with a name + BLEDevice::init("ESP32-Coexistence"); + + // Setup both server and client + setupServer(); + setupClient(); + + // Start initial scan + pBLEScan->start(10, false); // Scan for 10 seconds, don't repeat + + Serial.println("Setup complete. Device is advertising as server and scanning as client."); +} + +void loop() { + static unsigned long lastServerUpdate = 0; + static unsigned long lastClientWrite = 0; + static unsigned long lastScanStart = 0; + unsigned long currentTime = millis(); + + // Handle client connection attempts + if (doConnect && !clientConnected) { + if (connectToServer()) { + Serial.println("Client: Successfully connected to remote server"); + } else { + Serial.println("Client: Failed to connect, will retry scanning"); + // Restart scanning after failed connection + pBLEScan->start(10, false); + } + doConnect = false; + } + + // Update server characteristic periodically + if (currentTime - lastServerUpdate > 5000) { // Every 5 seconds + String value = "Server time: " + String(millis() / 1000); + pServerCharacteristic->setValue(value.c_str()); + pServerCharacteristic->notify(); // Notify connected clients + Serial.print("Server: Updated characteristic to: "); + Serial.println(value); + + lastServerUpdate = currentTime; + } + + // Write to remote characteristic if connected as client + if (clientConnected && pRemoteCharacteristic && currentTime - lastClientWrite > 3000) { + if (pRemoteCharacteristic->canWrite()) { + String clientValue = "Client msg: " + String(millis() / 1000); + pRemoteCharacteristic->writeValue(clientValue.c_str(), clientValue.length()); + Serial.print("Client: Wrote to remote characteristic: "); + Serial.println(clientValue); + lastClientWrite = currentTime; + } + } + + // Restart scanning periodically if not connected + if (!clientConnected && currentTime - lastScanStart > 15000) { // Every 15 seconds + Serial.println("Client: Restarting scan..."); + pBLEScan->start(10, false); + lastScanStart = currentTime; + } + + delay(100); +} diff --git a/libraries/BLE/examples/Client_Server/ci.yml b/libraries/BLE/examples/Client_Server/ci.yml new file mode 100644 index 00000000000..cfee8c8935f --- /dev/null +++ b/libraries/BLE/examples/Client_Server/ci.yml @@ -0,0 +1,5 @@ +fqbn_append: PartitionScheme=huge_app + +requires_any: + - CONFIG_SOC_BLE_SUPPORTED=y + - CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y diff --git a/libraries/BLE/examples/Server/Server.ino b/libraries/BLE/examples/Server/Server.ino index e86ed723267..4d70d4e897d 100644 --- a/libraries/BLE/examples/Server/Server.ino +++ b/libraries/BLE/examples/Server/Server.ino @@ -31,7 +31,7 @@ void setup() { pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue - pAdvertising->setMinPreferred(0x12); + pAdvertising->setMaxPreferred(0x12); BLEDevice::startAdvertising(); Serial.println("Characteristic defined! Now you can read it in your phone!"); } diff --git a/libraries/BLE/examples/Server_secure_authorization/Server_secure_authorization.ino b/libraries/BLE/examples/Server_secure_authorization/Server_secure_authorization.ino index b1ab9cd5931..2056e793393 100644 --- a/libraries/BLE/examples/Server_secure_authorization/Server_secure_authorization.ino +++ b/libraries/BLE/examples/Server_secure_authorization/Server_secure_authorization.ino @@ -140,7 +140,7 @@ void setup() { pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); // helps with iPhone connections - pAdvertising->setMinPreferred(0x12); + pAdvertising->setMaxPreferred(0x12); BLEDevice::startAdvertising(); diff --git a/libraries/BLE/examples/Server_secure_static_passkey/Server_secure_static_passkey.ino b/libraries/BLE/examples/Server_secure_static_passkey/Server_secure_static_passkey.ino index fef8c0bd15f..3ccba21bf71 100644 --- a/libraries/BLE/examples/Server_secure_static_passkey/Server_secure_static_passkey.ino +++ b/libraries/BLE/examples/Server_secure_static_passkey/Server_secure_static_passkey.ino @@ -185,7 +185,7 @@ void setup() { pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue - pAdvertising->setMinPreferred(0x12); + pAdvertising->setMaxPreferred(0x12); BLEDevice::startAdvertising(); Serial.println("Characteristic defined! Now you can read it in your phone!"); } diff --git a/libraries/BLE/library.properties b/libraries/BLE/library.properties index f4faf62a79e..e3707702526 100644 --- a/libraries/BLE/library.properties +++ b/libraries/BLE/library.properties @@ -1,5 +1,5 @@ name=BLE -version=3.3.4 +version=3.3.5 author=Neil Kolban maintainer=lucasssvaz sentence=BLE functions for ESP32 diff --git a/libraries/BluetoothSerial/library.properties b/libraries/BluetoothSerial/library.properties index 03d5687a49e..3fd21176ee4 100644 --- a/libraries/BluetoothSerial/library.properties +++ b/libraries/BluetoothSerial/library.properties @@ -1,5 +1,5 @@ name=BluetoothSerial -version=3.3.4 +version=3.3.5 author=Evandro Copercini maintainer=Evandro Copercini sentence=Simple UART to Classical Bluetooth bridge for ESP32 diff --git a/libraries/DNSServer/library.properties b/libraries/DNSServer/library.properties index 6d124cace69..647cbe35357 100644 --- a/libraries/DNSServer/library.properties +++ b/libraries/DNSServer/library.properties @@ -1,5 +1,5 @@ name=DNSServer -version=3.3.4 +version=3.3.5 author=Kristijan Novoselić maintainer=Kristijan Novoselić, sentence=A simple DNS server for ESP32. diff --git a/libraries/EEPROM/library.properties b/libraries/EEPROM/library.properties index bf03f1a66e1..40ce1d67917 100644 --- a/libraries/EEPROM/library.properties +++ b/libraries/EEPROM/library.properties @@ -1,5 +1,5 @@ name=EEPROM -version=3.3.4 +version=3.3.5 author=Ivan Grokhotkov maintainer=Paolo Becchi sentence=Enables reading and writing data a sequential, addressable FLASH storage diff --git a/libraries/ESP32/library.properties b/libraries/ESP32/library.properties index ef14a246302..00d94ac114b 100644 --- a/libraries/ESP32/library.properties +++ b/libraries/ESP32/library.properties @@ -1,5 +1,5 @@ name=ESP32 -version=3.3.4 +version=3.3.5 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 sketches examples diff --git a/libraries/ESP_HostedOTA/library.properties b/libraries/ESP_HostedOTA/library.properties index a45ab7aa138..80e74ce8c32 100644 --- a/libraries/ESP_HostedOTA/library.properties +++ b/libraries/ESP_HostedOTA/library.properties @@ -1,5 +1,5 @@ name=ESP_HostedOTA -version=3.3.4 +version=3.3.5 author=me-no-dev maintainer=me-no-dev sentence=Library for updating the ESP-Hosted co-processor diff --git a/libraries/ESP_I2S/library.properties b/libraries/ESP_I2S/library.properties index da985780ca7..cbcc6a5f2e1 100644 --- a/libraries/ESP_I2S/library.properties +++ b/libraries/ESP_I2S/library.properties @@ -1,5 +1,5 @@ name=ESP_I2S -version=3.3.4 +version=3.3.5 author=me-no-dev maintainer=me-no-dev sentence=Library for ESP I2S communication diff --git a/libraries/ESP_NOW/library.properties b/libraries/ESP_NOW/library.properties index cae0ed03dc3..dc4b8410f17 100644 --- a/libraries/ESP_NOW/library.properties +++ b/libraries/ESP_NOW/library.properties @@ -1,5 +1,5 @@ name=ESP_NOW -version=3.3.4 +version=3.3.5 author=me-no-dev maintainer=P-R-O-C-H-Y sentence=Library for ESP_NOW diff --git a/libraries/ESP_SR/library.properties b/libraries/ESP_SR/library.properties index 5e019e501a2..1f07d3101f9 100644 --- a/libraries/ESP_SR/library.properties +++ b/libraries/ESP_SR/library.properties @@ -1,5 +1,5 @@ name=ESP_SR -version=3.3.4 +version=3.3.5 author=me-no-dev maintainer=me-no-dev sentence=Library for ESP Sound Recognition diff --git a/libraries/ESPmDNS/library.properties b/libraries/ESPmDNS/library.properties index 44a14541f40..718d6f1c394 100644 --- a/libraries/ESPmDNS/library.properties +++ b/libraries/ESPmDNS/library.properties @@ -1,5 +1,5 @@ name=ESPmDNS -version=3.3.4 +version=3.3.5 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 mDNS Library diff --git a/libraries/Ethernet/library.properties b/libraries/Ethernet/library.properties index bc342dff285..d125a154943 100644 --- a/libraries/Ethernet/library.properties +++ b/libraries/Ethernet/library.properties @@ -1,5 +1,5 @@ name=Ethernet -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables network connection (local and Internet) using the ESP32 Ethernet. diff --git a/libraries/FFat/library.properties b/libraries/FFat/library.properties index 707c593d9d2..72060ea9388 100644 --- a/libraries/FFat/library.properties +++ b/libraries/FFat/library.properties @@ -1,5 +1,5 @@ name=FFat -version=3.3.4 +version=3.3.5 author=Hristo Gochkov, Ivan Grokhtkov, Larry Bernstone maintainer=Hristo Gochkov sentence=ESP32 FAT on Flash File System diff --git a/libraries/FS/library.properties b/libraries/FS/library.properties index 1ff59d3308d..f27b326b0d2 100644 --- a/libraries/FS/library.properties +++ b/libraries/FS/library.properties @@ -1,5 +1,5 @@ name=FS -version=3.3.4 +version=3.3.5 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 File System diff --git a/libraries/HTTPClient/library.properties b/libraries/HTTPClient/library.properties index ffbcc9101be..13f48197815 100644 --- a/libraries/HTTPClient/library.properties +++ b/libraries/HTTPClient/library.properties @@ -1,5 +1,5 @@ name=HTTPClient -version=3.3.4 +version=3.3.5 author=Markus Sattler maintainer=Markus Sattler sentence=HTTP Client for ESP32 diff --git a/libraries/HTTPUpdate/library.properties b/libraries/HTTPUpdate/library.properties index dcf5f1219d7..ea0aa7f30fd 100644 --- a/libraries/HTTPUpdate/library.properties +++ b/libraries/HTTPUpdate/library.properties @@ -1,5 +1,5 @@ name=HTTPUpdate -version=3.3.4 +version=3.3.5 author=Markus Sattler maintainer=Markus Sattler sentence=Http Update for ESP32 diff --git a/libraries/HTTPUpdateServer/library.properties b/libraries/HTTPUpdateServer/library.properties index bd034861f1e..e1ab0fe698d 100644 --- a/libraries/HTTPUpdateServer/library.properties +++ b/libraries/HTTPUpdateServer/library.properties @@ -1,5 +1,5 @@ name=HTTPUpdateServer -version=3.3.4 +version=3.3.5 author=Hristo Kapanakov maintainer= sentence=Simple HTTP Update server based on the WebServer diff --git a/libraries/Hash/library.properties b/libraries/Hash/library.properties index c497c42f71e..7f6ff2e80c9 100644 --- a/libraries/Hash/library.properties +++ b/libraries/Hash/library.properties @@ -1,5 +1,5 @@ name=Hash -version=3.3.4 +version=3.3.5 author=lucasssvaz maintainer=lucasssvaz sentence=Bundle of hashing functions for the ESP32 diff --git a/libraries/Insights/library.properties b/libraries/Insights/library.properties index 27285e999fe..969da7475d1 100644 --- a/libraries/Insights/library.properties +++ b/libraries/Insights/library.properties @@ -1,5 +1,5 @@ name=ESP Insights -version=3.3.4 +version=3.3.5 author=Sanket Wadekar maintainer=Sanket Wadekar sentence=ESP Insights diff --git a/libraries/LittleFS/library.properties b/libraries/LittleFS/library.properties index f5ad750a315..3b443bcc94a 100644 --- a/libraries/LittleFS/library.properties +++ b/libraries/LittleFS/library.properties @@ -1,5 +1,5 @@ name=LittleFS -version=3.3.4 +version=3.3.5 author= maintainer= sentence=LittleFS for esp32 diff --git a/libraries/Matter/examples/MatterColorLight/README.md b/libraries/Matter/examples/MatterColorLight/README.md index 4d9e39e4f75..446e2af6a54 100644 --- a/libraries/Matter/examples/MatterColorLight/README.md +++ b/libraries/Matter/examples/MatterColorLight/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -78,8 +78,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterColorLight.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterCommissionTest/README.md b/libraries/Matter/examples/MatterCommissionTest/README.md index db5d0e158ea..038419b2dc2 100644 --- a/libraries/Matter/examples/MatterCommissionTest/README.md +++ b/libraries/Matter/examples/MatterCommissionTest/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device connection to smart home | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -59,8 +59,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterCommissionTest.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterComposedLights/README.md b/libraries/Matter/examples/MatterComposedLights/README.md index 96446810f9f..20c6a165bda 100644 --- a/libraries/Matter/examples/MatterComposedLights/README.md +++ b/libraries/Matter/examples/MatterComposedLights/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, a single Matter node containing | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -74,8 +74,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterComposedLights.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterContactSensor/README.md b/libraries/Matter/examples/MatterContactSensor/README.md index 0f54a8f0010..de65e8aee01 100644 --- a/libraries/Matter/examples/MatterContactSensor/README.md +++ b/libraries/Matter/examples/MatterContactSensor/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -78,8 +78,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterContactSensor.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterDimmableLight/README.md b/libraries/Matter/examples/MatterDimmableLight/README.md index f1381b2641c..ab2c19b5155 100644 --- a/libraries/Matter/examples/MatterDimmableLight/README.md +++ b/libraries/Matter/examples/MatterDimmableLight/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -79,8 +79,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterDimmableLight.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterDimmablePlugin/README.md b/libraries/Matter/examples/MatterDimmablePlugin/README.md index d823c5c1ca7..0587e834d4a 100644 --- a/libraries/Matter/examples/MatterDimmablePlugin/README.md +++ b/libraries/Matter/examples/MatterDimmablePlugin/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -82,8 +82,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterDimmablePlugin.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterEnhancedColorLight/README.md b/libraries/Matter/examples/MatterEnhancedColorLight/README.md index 100c216cedf..dfa7111ec40 100644 --- a/libraries/Matter/examples/MatterEnhancedColorLight/README.md +++ b/libraries/Matter/examples/MatterEnhancedColorLight/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -81,8 +81,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterEnhancedColorLight.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterEvents/README.md b/libraries/Matter/examples/MatterEvents/README.md index 985fb8748e5..6c593c0fbe2 100644 --- a/libraries/Matter/examples/MatterEvents/README.md +++ b/libraries/Matter/examples/MatterEvents/README.md @@ -11,15 +11,15 @@ The application showcases Matter event handling, commissioning, and automatic de | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -62,8 +62,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterEvents.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterFan/README.md b/libraries/Matter/examples/MatterFan/README.md index cae9e15ba5f..3b6672a3005 100644 --- a/libraries/Matter/examples/MatterFan/README.md +++ b/libraries/Matter/examples/MatterFan/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -89,8 +89,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterFan.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterHumiditySensor/README.md b/libraries/Matter/examples/MatterHumiditySensor/README.md index 838073093cf..51fc528f61f 100644 --- a/libraries/Matter/examples/MatterHumiditySensor/README.md +++ b/libraries/Matter/examples/MatterHumiditySensor/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, sensor data reporting to smart h | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -76,8 +76,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterHumiditySensor.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterLambdaSingleCallbackManyEPs/README.md b/libraries/Matter/examples/MatterLambdaSingleCallbackManyEPs/README.md index 62c923e3655..2b303bdf5ba 100644 --- a/libraries/Matter/examples/MatterLambdaSingleCallbackManyEPs/README.md +++ b/libraries/Matter/examples/MatterLambdaSingleCallbackManyEPs/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, multiple endpoint management, an | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -98,8 +98,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterLambdaSingleCallbackManyEPs.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterMinimum/README.md b/libraries/Matter/examples/MatterMinimum/README.md index b3687718543..c02d7e4d919 100644 --- a/libraries/Matter/examples/MatterMinimum/README.md +++ b/libraries/Matter/examples/MatterMinimum/README.md @@ -11,15 +11,15 @@ The application showcases the minimal implementation for Matter commissioning an | ESP32-S2 | ✅ | ❌ | ❌ | Optional | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Optional | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Optional | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Optional | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Optional | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Optional | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Optional | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -78,8 +78,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterMinimum.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterOccupancySensor/README.md b/libraries/Matter/examples/MatterOccupancySensor/README.md index cb38c63ac6a..afe6bcce131 100644 --- a/libraries/Matter/examples/MatterOccupancySensor/README.md +++ b/libraries/Matter/examples/MatterOccupancySensor/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, sensor data reporting to smart h | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -79,8 +79,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterOccupancySensor.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterOccupancyWithHoldTime/MatterOccupancyWithHoldTime.ino b/libraries/Matter/examples/MatterOccupancyWithHoldTime/MatterOccupancyWithHoldTime.ino new file mode 100644 index 00000000000..0eb6fe4113e --- /dev/null +++ b/libraries/Matter/examples/MatterOccupancyWithHoldTime/MatterOccupancyWithHoldTime.ino @@ -0,0 +1,230 @@ +// 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. + +/* + * This example is an example code that will create a Matter Device which can be + * commissioned and controlled from a Matter Environment APP. + * Additionally the ESP32 will send debug messages indicating the Matter activity. + * Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages. + * + * The example will create a Matter Occupancy Sensor Device. + * The Occupancy Sensor will be simulated to toggle occupancy every 2 minutes. + * When occupancy is detected, the sensor holds the "occupied" state for the HoldTime duration + * (default: 30 seconds, configurable via Matter Controller). After HoldTime expires, + * the sensor automatically switches to "unoccupied" state. + * + * The HoldTime attribute allows you to adjust how long the active status is retained + * after the person leaves. The HoldTime can be changed by a Matter Controller, and the + * onHoldTimeChange() callback is used to update the simulated sensor functionality. + * + * The HoldTime value is persisted to Preferences (NVS) and restored on reboot, so the + * last configured HoldTime value is maintained across device restarts. + * + * The onboard button can be kept pressed for 5 seconds to decommission the Matter Node. + * The example will also show the manual commissioning code and QR code to be used in the Matter environment. + * + */ + +// Matter Manager +#include +// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network +#if !CONFIG_ENABLE_CHIPOBLE +// if the device can be commissioned using BLE, WiFi is not used - save flash space +#include +// WiFi is manually set and started +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password +#endif +#include + +// HoldTime configuration constants +const uint16_t HOLD_TIME_MIN = 0; // Minimum HoldTime in seconds +const uint16_t HOLD_TIME_MAX = 3600; // Maximum HoldTime in seconds (1 hour) +const uint16_t HOLD_TIME_DEFAULT = 30; // Default HoldTime in seconds + +// List of Matter Endpoints for this Node +// Matter Occupancy Sensor Endpoint +MatterOccupancySensor OccupancySensor; + +// Preferences to store HoldTime value across reboots +Preferences matterPref; +const char *holdTimePrefKey = "HoldTime"; + +// set your board USER BUTTON pin here - decommissioning only +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 decommissioningTimeout = 5000; // keep the button pressed for 5s, or longer, to decommission + +// Simulated Occupancy Sensor with HoldTime support +// When occupancy is detected, it holds the "occupied" state for HoldTime seconds +// After HoldTime expires, it automatically switches to "unoccupied" +// +// Behavior for different HoldTime vs detectionInterval relationships: +// - holdTime_ms < detectionInterval: State switches to unoccupied after HoldTime, then waits for next detection +// - holdTime_ms == detectionInterval: If detections keep coming, timer resets (continuous occupancy) +// - holdTime_ms > detectionInterval: If detections keep coming, timer resets (continuous occupancy) +// If detections stop, HoldTime expires after the last detection +bool simulatedHWOccupancySensor() { + static bool occupancyState = false; + static uint32_t lastDetectionTime = 0; + static uint32_t lastDetectionEvent = millis(); + const uint32_t detectionInterval = 120000; // Simulate detection every 2 minutes + + // Get current HoldTime from the sensor (can be changed by Matter Controller) + uint32_t holdTime_ms = OccupancySensor.getHoldTime() * 1000; // Convert seconds to milliseconds + + // Check HoldTime expiration FIRST (before processing new detections) + // This ensures HoldTime can expire even if a detection occurs in the same iteration + if (occupancyState && (millis() - lastDetectionTime > holdTime_ms)) { + occupancyState = false; + // Reset detection interval counter so next detection can happen immediately + // This makes the simulation more responsive after the room becomes unoccupied + lastDetectionEvent = millis(); + Serial.println("HoldTime expired. Switching to unoccupied state."); + } + + // Simulate periodic occupancy detection (e.g., motion detected) + // Check this AFTER HoldTime expiration so new detections can immediately re-trigger occupancy + if (millis() - lastDetectionEvent > detectionInterval) { + // New detection event occurred + lastDetectionEvent = millis(); + + if (!occupancyState) { + // Transition from unoccupied to occupied - start hold timer + occupancyState = true; + lastDetectionTime = millis(); + Serial.printf("Occupancy detected! Holding state for %u seconds (HoldTime)\n", OccupancySensor.getHoldTime()); + } else { + // Already occupied - new detection extends the hold period by resetting the timer + // This simulates continuous occupancy (person still present) + lastDetectionTime = millis(); + Serial.printf("Occupancy still detected. Resetting hold timer to %u seconds (HoldTime)\n", OccupancySensor.getHoldTime()); + } + } + + return occupancyState; +} + +void setup() { + // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node + pinMode(buttonPin, INPUT_PULLUP); + + Serial.begin(115200); + +// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network +#if !CONFIG_ENABLE_CHIPOBLE + // Manually connect to WiFi + WiFi.begin(ssid, password); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); +#endif + + // Initialize Preferences and read stored HoldTime value + matterPref.begin("MatterPrefs", false); + uint16_t storedHoldTime = matterPref.getUShort(holdTimePrefKey, HOLD_TIME_DEFAULT); + + // Validate stored value is within limits + if (storedHoldTime < HOLD_TIME_MIN || storedHoldTime > HOLD_TIME_MAX) { + uint16_t invalidValue = storedHoldTime; + storedHoldTime = HOLD_TIME_DEFAULT; + Serial.printf("Invalid stored HoldTime (%u), using default: %u seconds\n", invalidValue, HOLD_TIME_DEFAULT); + } else if (storedHoldTime != HOLD_TIME_DEFAULT) { + Serial.printf("Restored HoldTime from Preferences: %u seconds\n", storedHoldTime); + } + + // Register callback for HoldTime changes from Matter Controller + OccupancySensor.onHoldTimeChange([](uint16_t holdTime_seconds) -> bool { + Serial.printf("HoldTime changed to %u seconds by Matter Controller\n", holdTime_seconds); + // Store the new HoldTime value to Preferences for persistence across reboots + matterPref.putUShort(holdTimePrefKey, holdTime_seconds); + // The callback can return false to reject the change, or true to accept it + // In this case, we always accept the change and update the simulator + return true; + }); + + // set initial occupancy sensor state as false and connected to a PIR sensor type (default) + OccupancySensor.begin(); + + // Matter beginning - Last step, after all EndPoints are initialized + Matter.begin(); + + // Set HoldTimeLimits after Matter.begin() (optional, but recommended for validation) + if (!OccupancySensor.setHoldTimeLimits(HOLD_TIME_MIN, HOLD_TIME_MAX, HOLD_TIME_DEFAULT)) { + Serial.println("Warning: Failed to set HoldTimeLimits"); + } else { + Serial.printf("HoldTimeLimits set: Min=%u, Max=%u, Default=%u seconds\n", HOLD_TIME_MIN, HOLD_TIME_MAX, HOLD_TIME_DEFAULT); + } + + // Set initial HoldTime (use stored value if valid, otherwise use default) + // This must be done after Matter.begin() because setHoldTime() requires the Matter event loop + if (!OccupancySensor.setHoldTime(storedHoldTime)) { + Serial.printf("Warning: Failed to set HoldTime to %u seconds\n", storedHoldTime); + } else { + Serial.printf("HoldTime set to: %u seconds\n", storedHoldTime); + } + + Serial.printf("Initial HoldTime: %u seconds\n", OccupancySensor.getHoldTime()); + + // Check Matter Accessory 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 Occupancy Sensor 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.println("Matter Node is commissioned and connected to the network. Ready for use."); + } +} + +void loop() { + // 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. + } + + if (button_state && digitalRead(buttonPin) == HIGH) { + button_state = false; // released + } + + // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node + uint32_t time_diff = millis() - button_time_stamp; + if (button_state && time_diff > decommissioningTimeout) { + Serial.println("Decommissioning Occupancy Sensor Matter Accessory. It shall be commissioned again."); + Matter.decommission(); + button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so + } + + // Check Simulated Occupancy Sensor and set Matter Attribute + OccupancySensor.setOccupancy(simulatedHWOccupancySensor()); + + delay(50); +} diff --git a/libraries/Matter/examples/MatterOccupancyWithHoldTime/README.md b/libraries/Matter/examples/MatterOccupancyWithHoldTime/README.md new file mode 100644 index 00000000000..2c44f3fc549 --- /dev/null +++ b/libraries/Matter/examples/MatterOccupancyWithHoldTime/README.md @@ -0,0 +1,329 @@ +# Matter Occupancy Sensor with HoldTime Example + +This example demonstrates how to create a Matter-compatible occupancy sensor device with HoldTime functionality using an ESP32 SoC microcontroller.\ +The application showcases Matter commissioning, sensor data reporting to smart home ecosystems, automatic simulation of occupancy state changes, and HoldTime configuration with persistence across reboots. + +## Supported Targets + +| SoC | Wi-Fi | Thread | BLE Commissioning | Status | +| --- | ---- | ------ | ----------------- | ------ | +| ESP32 | ✅ | ❌ | ❌ | Fully supported | +| ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | +| ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | +| ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | + +### Note on Commissioning: + +- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. + +## Features + +- Matter protocol implementation for an occupancy sensor device with HoldTime support +- Support for both Wi-Fi and Thread(*) connectivity +- Occupancy state reporting (Occupied/Unoccupied) +- HoldTime attribute for configuring how long the sensor holds the "occupied" state +- HoldTimeLimits (min, max, default) for validation and controller guidance +- HoldTime persistence across reboots using Preferences (NVS) +- Automatic simulation of occupancy state changes every 2 minutes with HoldTime expiration +- HoldTime change callback for real-time updates from Matter controllers +- Button control for factory reset (decommission) +- Matter commissioning via QR code or manual pairing code +- Integration with Apple HomeKit, Amazon Alexa, and Google Home +(*) It is necessary to compile the project using Arduino as IDF Component. + +## Hardware Requirements + +- ESP32 compatible development board (see supported targets table) +- User button for factory reset (uses BOOT button by default) +- Optional: PIR (Passive Infrared) motion sensor (e.g., HC-SR501, AM312) for real occupancy detection + +## Pin Configuration + +- **Button**: Uses `BOOT_PIN` by default +- **PIR Sensor** (optional): Connect to any available GPIO pin (e.g., GPIO 4) when using a real sensor + +## Software Setup + +### Prerequisites + +1. Install the Arduino IDE (2.0 or newer recommended) +2. Install ESP32 Arduino Core with Matter support +3. ESP32 Arduino libraries: + - `Matter` + - `Wi-Fi` (only for ESP32 and ESP32-S2) + +### Configuration + +Before uploading the sketch, configure the following: + +1. **Wi-Fi credentials** (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2): + ```cpp + const char *ssid = "your-ssid"; // Change to your Wi-Fi SSID + const char *password = "your-password"; // Change to your Wi-Fi password + ``` + +2. **HoldTime configuration** (optional): + The example uses default HoldTime limits. You can customize them: + ```cpp + const uint16_t HOLD_TIME_MIN = 0; // Minimum HoldTime in seconds + const uint16_t HOLD_TIME_MAX = 3600; // Maximum HoldTime in seconds (1 hour) + const uint16_t HOLD_TIME_DEFAULT = 30; // Default HoldTime in seconds + ``` + +3. **Button pin configuration** (optional): + By default, the `BOOT` button (GPIO 0) is used for factory reset. You can change this to a different pin if needed. + ```cpp + const uint8_t buttonPin = BOOT_PIN; // Set your button pin here + ``` + +4. **PIR sensor pin configuration** (optional, if using a real PIR sensor): + ```cpp + const uint8_t pirPin = 4; // Set your PIR sensor pin here + ``` + See the "PIR Sensor Integration Example" section below for complete integration instructions. + +## Building and Flashing + +1. Open the `MatterOccupancyWithHoldTime.ino` sketch in the Arduino IDE. +2. Select your ESP32 board from the **Tools > Board** menu. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. 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**. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following, which provides the necessary information for commissioning: + +``` +Connecting to your-wifi-ssid +....... +Wi-Fi connected +IP address: 192.168.1.100 + +Restored HoldTime from Preferences: 30 seconds +HoldTimeLimits set: Min=0, Max=3600, Default=30 seconds +HoldTime set to: 30 seconds +Initial HoldTime: 30 seconds + +Matter Node is not commissioned yet. +Initiate the device discovery in your Matter environment. +Commission it to your Matter hub with the manual pairing code or QR code +Manual pairing code: 34970112332 +QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00 +Matter Node not commissioned yet. Waiting for commissioning. +Matter Node not commissioned yet. Waiting for commissioning. +... +Matter Node is commissioned and connected to the network. Ready for use. +Occupancy detected! Holding state for 30 seconds (HoldTime) +HoldTime expired. Switching to unoccupied state. +``` + +After commissioning, the occupancy sensor will automatically simulate occupancy detections every 2 minutes. When occupancy is detected, the sensor holds the "occupied" state for the configured HoldTime duration (default: 30 seconds). After HoldTime expires, it automatically switches to "unoccupied" state. The Matter controller will receive these state updates and can also configure the HoldTime value. + +## Using the Device + +### Manual Control + +The user button (BOOT button by default) provides factory reset functionality: + +- **Long press (>5 seconds)**: Factory reset the device (decommission) + +### Sensor Simulation + +The example includes a simulated occupancy sensor with HoldTime support that: + +- Starts in the unoccupied state (false) +- Simulates occupancy detection every 2 minutes +- When occupancy is detected, holds the "occupied" state for the HoldTime duration +- After HoldTime expires, automatically switches to "unoccupied" state +- If new detections occur while occupied, the HoldTime timer resets (continuous occupancy) +- Updates the Matter attribute automatically + +**HoldTime Behavior:** +- The HoldTime value determines how long the sensor maintains the "occupied" state after the last detection +- HoldTime can be configured via Matter Controller (within the min/max limits) +- HoldTime value is persisted to Preferences and restored on reboot +- When HoldTime expires, the sensor transitions to "unoccupied" even if no new detection occurs + +To use a real occupancy sensor, replace the `simulatedHWOccupancySensor()` function with your sensor library code. The HoldTime functionality will work the same way - the sensor will hold the occupied state for the configured HoldTime duration after motion is no longer detected. + +### PIR Sensor Integration Example + +Here's a complete example for integrating a simple PIR (Passive Infrared) motion sensor: + +#### Hardware Connections + +Connect the PIR sensor to your ESP32: +- **PIR VCC** → ESP32 3.3 V or 5 V (check your PIR sensor specifications) +- **PIR GND** → ESP32 GND +- **PIR OUT** → ESP32 GPIO pin (e.g., GPIO 4) + +Common PIR sensors (HC-SR501, AM312, etc.) typically have three pins: VCC, GND, and OUT (digital output). + +#### Code Modifications + +1. **Add PIR pin definition** at the top of the sketch (after the button pin definition): + +```cpp +// PIR sensor pin +const uint8_t pirPin = 4; // Change this to your PIR sensor pin +``` + +2. **Initialize PIR pin in setup()** (after button initialization): + +```cpp +void setup() { + // ... existing code ... + pinMode(buttonPin, INPUT_PULLUP); + + // Initialize PIR sensor pin + pinMode(pirPin, INPUT); + + // ... rest of setup code ... +} +``` + +3. **Replace the simulated function** with the real PIR reading function: + +```cpp +bool simulatedHWOccupancySensor() { + // Read PIR sensor digital input + // HIGH = motion detected (occupied), LOW = no motion (unoccupied) + return digitalRead(pirPin) == HIGH; +} +``` + +#### Complete Modified Function Example + +Here's the complete modified function with debouncing for more reliable readings: + +```cpp +bool simulatedHWOccupancySensor() { + // Read PIR sensor with debouncing + static bool lastState = false; + static uint32_t lastChangeTime = 0; + const uint32_t debounceTime = 100; // 100ms debounce + + bool currentState = digitalRead(pirPin) == HIGH; + + // Only update if state has changed and debounce time has passed + if (currentState != lastState) { + if (millis() - lastChangeTime > debounceTime) { + lastState = currentState; + lastChangeTime = millis(); + Serial.printf("Occupancy state changed: %s\r\n", currentState ? "OCCUPIED" : "UNOCCUPIED"); + } + } + + return lastState; +} +``` + +#### Testing the PIR Sensor + +After making these changes: +1. Upload the modified sketch to your ESP32 +2. Open the Serial Monitor at 115200 baud +3. Move in front of the PIR sensor - you should see "OCCUPIED" messages +4. Stay still for a few seconds - you should see "UNOCCUPIED" messages +5. The Matter controller will automatically receive these occupancy state updates + +### Smart Home Integration + +Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device. + +#### Apple Home + +1. Open the Home app on your iOS device +2. Tap the "+" button > Add Accessory +3. Scan the QR code displayed in the Serial Monitor, or +4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code +5. Follow the prompts to complete setup +6. The device will appear as an occupancy sensor in your Home app +7. You can monitor the occupancy state and set up automations based on occupancy (e.g., turn on lights when occupied) +8. You can configure the HoldTime value through the device settings (if supported by your Home app version) + +#### Amazon Alexa + +1. Open the Alexa app +2. Tap More > Add Device > Matter +3. Select "Scan QR code" or "Enter code manually" +4. Complete the setup process +5. The occupancy sensor will appear in your Alexa app +6. You can monitor occupancy readings and create routines based on occupancy state changes + +#### Google Home + +1. Open the Google Home app +2. Tap "+" > Set up device > New device +3. Choose "Matter device" +4. Scan the QR code or enter the manual pairing code +5. Follow the prompts to complete setup +6. You can monitor occupancy readings and create automations based on occupancy state changes + +## Code Structure + +The MatterOccupancyWithHoldTime example consists of the following main components: + +1. **`setup()`**: + - Initializes hardware (button), configures Wi-Fi (if needed) + - Initializes Preferences and restores stored HoldTime value + - Registers HoldTime change callback for persistence + - Sets up the Matter Occupancy Sensor endpoint with initial state (unoccupied) + - Calls `Matter.begin()` to start the Matter stack + - Sets HoldTimeLimits (min, max, default) after Matter.begin() + - Sets initial HoldTime value (from Preferences or default) + - Waits for Matter commissioning + +2. **`loop()`**: + - Handles button input for factory reset + - Continuously checks the simulated occupancy sensor and updates the Matter attribute + - Allows the Matter stack to process events + +3. **`simulatedHWOccupancySensor()`**: + - Simulates a hardware occupancy sensor with HoldTime support + - Detects occupancy every 2 minutes + - Holds the "occupied" state for HoldTime seconds after detection + - Automatically transitions to "unoccupied" when HoldTime expires + - Resets HoldTime timer on new detections while occupied (continuous occupancy) + - Replace this function with your actual sensor reading code + +4. **HoldTime Callback**: + - `onHoldTimeChange()` callback persists HoldTime changes to Preferences + - Ensures HoldTime value is maintained across device reboots + +## Troubleshooting + +- **Device not visible during commissioning**: Ensure Wi-Fi or Thread connectivity is properly configured +- **Occupancy readings not updating**: Check that the sensor simulation function is being called correctly. For real sensors, verify sensor wiring and library initialization +- **State not changing**: The simulated sensor detects occupancy every 2 minutes (120000 ms). The state will hold for HoldTime seconds after detection. If you're using a real sensor, ensure it's properly connected and reading correctly +- **HoldTime not persisting**: Verify that Preferences is properly initialized and the callback is saving the value. Check Serial Monitor for "HoldTime changed" messages +- **HoldTime not working**: Ensure `setHoldTimeLimits()` and `setHoldTime()` are called after `Matter.begin()`. Check Serial Monitor for error messages +- **PIR sensor not detecting motion**: + - Verify PIR sensor wiring (VCC, GND, OUT connections) + - Check if PIR sensor requires 5 V or 3.3 V power (some PIR sensors need 5 V) + - Allow 30-60 seconds for PIR sensor to stabilize after power-on + - Adjust PIR sensor sensitivity and time delay potentiometers (if available on your sensor) + - Ensure the PIR sensor has a clear view of the detection area + - Test the PIR sensor directly by reading the GPIO pin value in Serial Monitor +- **PIR sensor false triggers**: Add debouncing to the sensor reading function (see the "Complete Modified Function Example" above) +- **Failed to commission**: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port erase_flash` +- **No serial output**: Check baudrate (115200) and USB connection + +## Related Documentation + +- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html) +- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html) +- [Matter Occupancy Sensor Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_occupancy_sensor.html) + +## License + +This example is licensed under the Apache License, Version 2.0. diff --git a/libraries/Matter/examples/MatterSimpleWidowsBlind/ci.yml b/libraries/Matter/examples/MatterOccupancyWithHoldTime/ci.yml similarity index 100% rename from libraries/Matter/examples/MatterSimpleWidowsBlind/ci.yml rename to libraries/Matter/examples/MatterOccupancyWithHoldTime/ci.yml diff --git a/libraries/Matter/examples/MatterOnIdentify/README.md b/libraries/Matter/examples/MatterOnIdentify/README.md index ce873f9397f..922c09e537a 100644 --- a/libraries/Matter/examples/MatterOnIdentify/README.md +++ b/libraries/Matter/examples/MatterOnIdentify/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -79,8 +79,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterOnIdentify.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterOnOffLight/README.md b/libraries/Matter/examples/MatterOnOffLight/README.md index b973302129a..59857fff605 100644 --- a/libraries/Matter/examples/MatterOnOffLight/README.md +++ b/libraries/Matter/examples/MatterOnOffLight/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -79,8 +79,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterOnOffLight.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterOnOffPlugin/README.md b/libraries/Matter/examples/MatterOnOffPlugin/README.md index 2603961353c..655fc28dbf7 100644 --- a/libraries/Matter/examples/MatterOnOffPlugin/README.md +++ b/libraries/Matter/examples/MatterOnOffPlugin/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -80,8 +80,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterOnOffPlugin.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterPressureSensor/README.md b/libraries/Matter/examples/MatterPressureSensor/README.md index 2f0665067ac..6878d84d048 100644 --- a/libraries/Matter/examples/MatterPressureSensor/README.md +++ b/libraries/Matter/examples/MatterPressureSensor/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, sensor data reporting to smart h | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -76,8 +76,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterPressureSensor.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterRainSensor/README.md b/libraries/Matter/examples/MatterRainSensor/README.md index 1e81b3ea3c9..91431a9bd86 100644 --- a/libraries/Matter/examples/MatterRainSensor/README.md +++ b/libraries/Matter/examples/MatterRainSensor/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -78,8 +78,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterRainSensor.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterSimpleWidowsBlind/MatterSimpleWidowsBlind.ino b/libraries/Matter/examples/MatterSimpleBlinds/MatterSimpleBlinds.ino similarity index 90% rename from libraries/Matter/examples/MatterSimpleWidowsBlind/MatterSimpleWidowsBlind.ino rename to libraries/Matter/examples/MatterSimpleBlinds/MatterSimpleBlinds.ino index 51c4192d7f2..a2f21d1e9aa 100644 --- a/libraries/Matter/examples/MatterSimpleWidowsBlind/MatterSimpleWidowsBlind.ino +++ b/libraries/Matter/examples/MatterSimpleBlinds/MatterSimpleBlinds.ino @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Matter Simple Window Blinds Example +// Matter Simple Blinds Example // This is a minimal example that only controls Lift percentage using a single onGoToLiftPercentage() callback #include @@ -33,7 +33,7 @@ const char *password = "your-password"; // Change this to your WiFi password #endif // Simple callback - handles window Lift change request -bool onBlindLift(uint8_t liftPercent) { +bool onBlindsLift(uint8_t liftPercent) { // This example only uses lift Serial.printf("Window Covering change request: Lift=%d%%\r\n", liftPercent); @@ -44,9 +44,9 @@ bool onBlindLift(uint8_t liftPercent) { void setup() { Serial.begin(115200); delay(1000); - Serial.println("\n========================================"); - Serial.println("Matter Simple Window Blinds Example"); - Serial.println("========================================\n"); + Serial.println("\n============================"); + Serial.println("Matter Simple Blinds Example"); + Serial.println("============================\n"); // CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network #if !CONFIG_ENABLE_CHIPOBLE @@ -70,7 +70,7 @@ void setup() { WindowBlinds.begin(100, 0, MatterWindowCovering::ROLLERSHADE); // Set up the onGoToLiftPercentage callback - this handles all window covering changes requested by the Matter Controller - WindowBlinds.onGoToLiftPercentage(onBlindLift); + WindowBlinds.onGoToLiftPercentage(onBlindsLift); // Start Matter Matter.begin(); diff --git a/libraries/Matter/examples/MatterSimpleWidowsBlind/README.md b/libraries/Matter/examples/MatterSimpleBlinds/README.md similarity index 77% rename from libraries/Matter/examples/MatterSimpleWidowsBlind/README.md rename to libraries/Matter/examples/MatterSimpleBlinds/README.md index 637d2a4b398..ed7cca71047 100644 --- a/libraries/Matter/examples/MatterSimpleWidowsBlind/README.md +++ b/libraries/Matter/examples/MatterSimpleBlinds/README.md @@ -1,4 +1,4 @@ -# Matter Simple Window Blinds Example +# Matter Simple Blinds Example This is a minimal example demonstrating how to create a Matter-compatible window covering device with lift control only. This example uses a single `onGoToLiftPercentage()` callback to handle all window covering lift changes, making it ideal for simple implementations. @@ -10,15 +10,15 @@ This is a minimal example demonstrating how to create a Matter-compatible window | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -53,12 +53,23 @@ Before uploading the sketch, configure the following: const char *password = "your-password"; ``` +## Building and Flashing + +1. Open the `MatterSimpleBlinds.ino` sketch in the Arduino IDE. +2. Select your ESP32 board from the **Tools > Board** menu. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. + ## Expected Output ``` -======================================== -Matter Simple Window Blinds Example -======================================== +============================ +Matter Simple Blinds Example +============================ Connecting to your-ssid WiFi connected @@ -87,7 +98,7 @@ Window Covering change request: Lift=50% ## Code Structure -- **`onBlindLift()`**: Callback function that handles window covering lift changes. This is registered with `WindowBlinds.onGoToLiftPercentage()` and is triggered when `TargetPositionLiftPercent100ths` changes. The callback receives the target lift percentage (0-100%). +- **`onBlindsLift()`**: Callback function that handles window covering lift changes. This is registered with `WindowBlinds.onGoToLiftPercentage()` and is triggered when `TargetPositionLiftPercent100ths` changes. The callback receives the target lift percentage (0-100%). - **`setup()`**: Initializes Wi-Fi (if needed), Window Covering endpoint with `ROLLERSHADE` type, registers the callback, and starts Matter. - **`loop()`**: Empty - all control is handled via Matter callbacks. @@ -95,10 +106,10 @@ Window Covering change request: Lift=50% ### Adding Motor Control -In the `onBlindLift()` callback, replace the simulation code with actual motor control: +In the `onBlindsLift()` callback, replace the simulation code with actual motor control: ```cpp -bool onBlindLift(uint8_t liftPercent) { +bool onBlindsLift(uint8_t liftPercent) { Serial.printf("Moving window covering to %d%%\r\n", liftPercent); // Here you would control your actual motor/actuator @@ -122,7 +133,7 @@ bool onBlindLift(uint8_t liftPercent) { 3. **Commands not working**: Ensure the callback returns `true` to accept the command. If it returns `false`, the command will be rejected. -4. **Motor not responding**: Replace the simulation code in `onBlindLift()` with your actual motor control implementation. Remember to update `CurrentPosition` and set `OperationalState` to `STALL` when movement is complete. +4. **Motor not responding**: Replace the simulation code in `onBlindsLift()` with your actual motor control implementation. Remember to update `CurrentPosition` and set `OperationalState` to `STALL` when movement is complete. ## Notes diff --git a/libraries/Matter/examples/MatterSimpleBlinds/ci.yml b/libraries/Matter/examples/MatterSimpleBlinds/ci.yml new file mode 100644 index 00000000000..050a80ff543 --- /dev/null +++ b/libraries/Matter/examples/MatterSimpleBlinds/ci.yml @@ -0,0 +1,4 @@ +fqbn_append: PartitionScheme=huge_app + +requires: + - CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y diff --git a/libraries/Matter/examples/MatterSmartButton/README.md b/libraries/Matter/examples/MatterSmartButton/README.md index e7290ba40b3..cfbba343cb7 100644 --- a/libraries/Matter/examples/MatterSmartButton/README.md +++ b/libraries/Matter/examples/MatterSmartButton/README.md @@ -12,14 +12,14 @@ The application showcases Matter commissioning, sending button click events to s | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -71,8 +71,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterSmartButton.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterStatus/MatterStatus.ino b/libraries/Matter/examples/MatterStatus/MatterStatus.ino new file mode 100644 index 00000000000..ffbb5fa6212 --- /dev/null +++ b/libraries/Matter/examples/MatterStatus/MatterStatus.ino @@ -0,0 +1,119 @@ +// 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 Status Example +// This example demonstrates how to check enabled Matter features and connectivity status +// It implements a basic on/off light and reports capability and connection status + +#include +// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network +#if !CONFIG_ENABLE_CHIPOBLE // ESP32 and ESP32-S2 do not support BLE commissioning +// if the device can be commissioned using BLE, WiFi is not used - save flash space +#include +// WiFi is manually set and started +const char *ssid = "your-ssid"; // Change this to your WiFi SSID +const char *password = "your-password"; // Change this to your WiFi password +#endif + +// List of Matter Endpoints for this Node +// On/Off Light Endpoint +MatterOnOffLight OnOffLight; + +// set your board LED pin here +#ifdef LED_BUILTIN +const uint8_t ledPin = LED_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 LED pin" +#endif + +// Matter Protocol Endpoint Callback +bool setLightOnOff(bool state) { + Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF"); + if (state) { + digitalWrite(ledPin, HIGH); + } else { + digitalWrite(ledPin, LOW); + } + // This callback must return the success state to Matter core + return true; +} + +void setup() { + // Initialize the LED (light) GPIO + pinMode(ledPin, OUTPUT); + digitalWrite(ledPin, LOW); // Start with light OFF + + Serial.begin(115200); + delay(1000); + Serial.println("\n========================================"); + Serial.println("Matter Status Example"); + Serial.println("========================================\n"); + + // Report enabled features + Serial.println("=== Enabled Features ==="); + Serial.printf("WiFi Station Enabled: %s\r\n", Matter.isWiFiStationEnabled() ? "YES" : "NO"); + Serial.printf("WiFi Access Point Enabled: %s\r\n", Matter.isWiFiAccessPointEnabled() ? "YES" : "NO"); + Serial.printf("Thread Enabled: %s\r\n", Matter.isThreadEnabled() ? "YES" : "NO"); + Serial.printf("BLE Commissioning Enabled: %s\r\n", Matter.isBLECommissioningEnabled() ? "YES" : "NO"); + Serial.println(); + +// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network +#if !CONFIG_ENABLE_CHIPOBLE + // We start by connecting to a WiFi network + if (Matter.isWiFiStationEnabled()) { + Serial.print("Connecting to "); + Serial.println(ssid); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + } +#endif + + // Initialize On/Off Light endpoint + OnOffLight.begin(false); // Start with light OFF + OnOffLight.onChange(setLightOnOff); + + // Start Matter + Matter.begin(); + Serial.println("Matter started"); + Serial.println(); + + // Print commissioning information + 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()); + Serial.println("========================================\n"); +} + +void loop() { + // Report connection status every 10 seconds + Serial.println("=== Connection Status ==="); + Serial.printf("WiFi Connected: %s\r\n", Matter.isWiFiConnected() ? "YES" : "NO"); + Serial.printf("Thread Connected: %s\r\n", Matter.isThreadConnected() ? "YES" : "NO"); + Serial.printf("Device Connected: %s\r\n", Matter.isDeviceConnected() ? "YES" : "NO"); + Serial.printf("Device Commissioned: %s\r\n", Matter.isDeviceCommissioned() ? "YES" : "NO"); + Serial.println(); + delay(10000); +} diff --git a/libraries/Matter/examples/MatterStatus/README.md b/libraries/Matter/examples/MatterStatus/README.md new file mode 100644 index 00000000000..d4c37798712 --- /dev/null +++ b/libraries/Matter/examples/MatterStatus/README.md @@ -0,0 +1,204 @@ +# Matter Status Example + +This example demonstrates how to check enabled Matter features and connectivity status using the Matter library's capability query functions. It implements a basic on/off light device and periodically reports the status of enabled features and network connections. + +## Supported Targets + +| SoC | Wi-Fi | Thread | BLE Commissioning | LED | Status | +| --- | ---- | ------ | ----------------- | --- | ------ | +| ESP32 | ✅ | ❌ | ❌ | Required | Fully supported | +| ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | +| ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | +| ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | + +### Note on Commissioning: + +- **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. + +## Features + +- Matter protocol implementation for an on/off light device +- **Capability reporting**: Checks and reports enabled Matter features at startup + - `isWiFiStationEnabled()`: Checks if Wi-Fi Station mode is supported and enabled + - `isWiFiAccessPointEnabled()`: Checks if Wi-Fi AP mode is supported and enabled + - `isThreadEnabled()`: Checks if Thread network is supported and enabled + - `isBLECommissioningEnabled()`: Checks if BLE commissioning is supported and enabled +- **Connection status monitoring**: Reports connection status every 10 seconds + - `isWiFiConnected()`: Checks Wi-Fi connection status (if Wi-Fi Station is enabled) + - `isThreadConnected()`: Checks Thread connection status (if Thread is enabled) + - `isDeviceConnected()`: Checks overall device connectivity (Wi-Fi or Thread) + - `isDeviceCommissioned()`: Checks if the device is commissioned to a Matter fabric +- Simple on/off light control +- Matter commissioning via QR code or manual pairing code +- Integration with Apple HomeKit, Amazon Alexa, and Google Home + +## Hardware Requirements + +- ESP32 compatible development board (see supported targets table) +- LED connected to GPIO pin (or using built-in LED) for visual feedback + +## Pin Configuration + +- **LED**: Uses `LED_BUILTIN` if defined, otherwise pin 2 + +## Software Setup + +### Prerequisites + +1. Install the Arduino IDE (2.0 or newer recommended) +2. Install ESP32 Arduino Core with Matter support +3. ESP32 Arduino libraries: + - `Matter` + - `Wi-Fi` (only for ESP32 and ESP32-S2) + +### Configuration + +Before uploading the sketch, configure the following: + +1. **Wi-Fi Credentials** (for ESP32 and ESP32-S2 only): + ```cpp + const char *ssid = "your-ssid"; + const char *password = "your-password"; + ``` + +2. **LED pin configuration** (if not using built-in LED): + ```cpp + const uint8_t ledPin = 2; // Set your LED pin here + ``` + +## Building and Flashing + +1. Open the `MatterStatus.ino` sketch in the Arduino IDE. +2. Select your ESP32 board from the **Tools > Board** menu. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. 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: + +``` +======================================== +Matter Status Example +======================================== + +=== Enabled Features === +WiFi Station Enabled: YES +WiFi Access Point Enabled: NO +Thread Enabled: NO +BLE Commissioning Enabled: NO + +Connecting to your-ssid +....... +WiFi connected +IP address: 192.168.1.100 +Matter started + +======================================== +Matter Node is not commissioned yet. +Initiate the device discovery in your Matter environment. +Commission it to your Matter hub with the manual pairing code or QR code +Manual pairing code: 34970112332 +QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00 +======================================== + +=== Connection Status === +WiFi Connected: YES +Thread Connected: NO +Device Connected: YES +Device Commissioned: NO + +=== Connection Status === +WiFi Connected: YES +Thread Connected: NO +Device Connected: YES +Device Commissioned: NO + +... (reports every 10 seconds) + +User Callback :: New Light State = ON +=== Connection Status === +WiFi Connected: YES +Thread Connected: NO +Device Connected: YES +Device Commissioned: YES + +... (reports every 10 seconds) +``` + +## Usage + +### Capability Queries + +The example demonstrates the use of capability query functions that check both hardware support (SoC capabilities) and Matter configuration: + +- **`Matter.isWiFiStationEnabled()`**: Returns `true` if the device supports Wi-Fi Station mode and it's enabled in Matter configuration +- **`Matter.isWiFiAccessPointEnabled()`**: Returns `true` if the device supports Wi-Fi AP mode and it's enabled in Matter configuration +- **`Matter.isThreadEnabled()`**: Returns `true` if the device supports Thread networking and it's enabled in Matter configuration +- **`Matter.isBLECommissioningEnabled()`**: Returns `true` if the device supports BLE and BLE commissioning is enabled + +These functions are useful for: +- Determining which features are available on the current device +- Adapting application behavior based on available capabilities +- Debugging configuration issues + +### Connection Status Monitoring + +The example periodically reports connection status every 10 seconds: + +- **`Matter.isWiFiConnected()`**: Returns `true` if Wi-Fi Station is connected. If Wi-Fi Station is not enabled, always returns `false`. +- **`Matter.isThreadConnected()`**: Returns `true` if Thread is attached to a network. If Thread is not enabled, always returns `false`. +- **`Matter.isDeviceConnected()`**: Returns `true` if the device is connected via Wi-Fi or Thread (overall connectivity status) +- **`Matter.isDeviceCommissioned()`**: Returns `true` if the device has been commissioned to a Matter fabric + +### Smart Home Integration + +Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device. Once commissioned, you can control the light from your smart home app. + +## Code Structure + +- **`setup()`**: + - Initializes hardware (LED) + - Reports enabled features using capability query functions + - Connects to Wi-Fi (if needed and enabled) + - Initializes On/Off Light endpoint + - Starts Matter stack + - Prints commissioning information + +- **`loop()`**: + - Reports connection status every 10 seconds + - All light control is handled via Matter callbacks + +- **Callbacks**: + - `setLightOnOff()`: Controls the physical LED based on the on/off state and prints the state change to Serial Monitor + +## Troubleshooting + +1. **Device not discoverable**: Ensure Wi-Fi is connected (for ESP32/ESP32-S2) or BLE is enabled (for other chips). + +2. **Capability queries return unexpected values**: These functions check both hardware support and Matter configuration. Verify that the features are enabled in your Matter build configuration. + +3. **Connection status not updating**: The status is reported every 10 seconds. Check Serial Monitor output to see the periodic reports. + +4. **LED not responding**: Verify pin configurations and connections. + +5. **Failed to commission**: Try factory resetting the device by calling `Matter.decommission()`. Other option would be to erase the SoC Flash Memory by using `Arduino IDE Menu` -> `Tools` -> `Erase All Flash Before Sketch Upload: "Enabled"` or directly with `esptool.py --port erase_flash` + +## Related Documentation + +- [Matter Overview](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter.html) +- [Matter Endpoint Base Class](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/matter_ep.html) +- [Matter On/Off Light Endpoint](https://docs.espressif.com/projects/arduino-esp32/en/latest/matter/ep_on_off_light.html) + +## License + +This example is licensed under the Apache License, Version 2.0. diff --git a/libraries/Matter/examples/MatterStatus/ci.yml b/libraries/Matter/examples/MatterStatus/ci.yml new file mode 100644 index 00000000000..050a80ff543 --- /dev/null +++ b/libraries/Matter/examples/MatterStatus/ci.yml @@ -0,0 +1,4 @@ +fqbn_append: PartitionScheme=huge_app + +requires: + - CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y diff --git a/libraries/Matter/examples/MatterTemperatureControlledCabinet/README.md b/libraries/Matter/examples/MatterTemperatureControlledCabinet/README.md index 8ed6c69454a..99246602697 100644 --- a/libraries/Matter/examples/MatterTemperatureControlledCabinet/README.md +++ b/libraries/Matter/examples/MatterTemperatureControlledCabinet/README.md @@ -12,15 +12,15 @@ This example demonstrates how to create a Matter-compatible temperature controll | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -86,8 +86,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterTemperatureControlledCabinet.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterTemperatureControlledCabinetLevels/README.md b/libraries/Matter/examples/MatterTemperatureControlledCabinetLevels/README.md index 88f74a634bd..4e7adf777fe 100644 --- a/libraries/Matter/examples/MatterTemperatureControlledCabinetLevels/README.md +++ b/libraries/Matter/examples/MatterTemperatureControlledCabinetLevels/README.md @@ -12,15 +12,15 @@ This example demonstrates how to create a Matter-compatible temperature controll | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -87,8 +87,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterTemperatureControlledCabinetLevels.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterTemperatureLight/README.md b/libraries/Matter/examples/MatterTemperatureLight/README.md index 4eb9432400b..e65e23fa0d2 100644 --- a/libraries/Matter/examples/MatterTemperatureLight/README.md +++ b/libraries/Matter/examples/MatterTemperatureLight/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -82,8 +82,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterTemperatureLight.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterTemperatureSensor/README.md b/libraries/Matter/examples/MatterTemperatureSensor/README.md index 9a494aec932..c9d90ac3492 100644 --- a/libraries/Matter/examples/MatterTemperatureSensor/README.md +++ b/libraries/Matter/examples/MatterTemperatureSensor/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, sensor data reporting to smart h | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -76,8 +76,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterTemperatureSensor.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterThermostat/README.md b/libraries/Matter/examples/MatterThermostat/README.md index 2a87f4d93af..5529bf08402 100644 --- a/libraries/Matter/examples/MatterThermostat/README.md +++ b/libraries/Matter/examples/MatterThermostat/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, thermostat control via smart hom | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -78,8 +78,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterThermostat.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterWaterFreezeDetector/README.md b/libraries/Matter/examples/MatterWaterFreezeDetector/README.md index 0701a5af979..8bbdabc92b6 100644 --- a/libraries/Matter/examples/MatterWaterFreezeDetector/README.md +++ b/libraries/Matter/examples/MatterWaterFreezeDetector/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -78,8 +78,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterWaterFreezeDetector.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterWaterLeakDetector/README.md b/libraries/Matter/examples/MatterWaterLeakDetector/README.md index 3dcf2f2e9f7..1f3b25662f6 100644 --- a/libraries/Matter/examples/MatterWaterLeakDetector/README.md +++ b/libraries/Matter/examples/MatterWaterLeakDetector/README.md @@ -11,15 +11,15 @@ The application showcases Matter commissioning, device control via smart home ec | ESP32-S2 | ✅ | ❌ | ❌ | Required | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Required | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Required | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Required | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Required | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been pre compiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -78,8 +78,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterWaterLeakDetector.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/examples/MatterWindowCovering/README.md b/libraries/Matter/examples/MatterWindowCovering/README.md index 8e18539c65a..9a1b830a86c 100644 --- a/libraries/Matter/examples/MatterWindowCovering/README.md +++ b/libraries/Matter/examples/MatterWindowCovering/README.md @@ -10,15 +10,15 @@ This example demonstrates how to create a Matter-compatible window covering devi | ESP32-S2 | ✅ | ❌ | ❌ | Fully supported | | ESP32-S3 | ✅ | ❌ | ✅ | Fully supported | | ESP32-C3 | ✅ | ❌ | ✅ | Fully supported | -| ESP32-C5 | ✅ | ❌ | ✅ | Fully supported | +| ESP32-C5 | ❌ | ✅ | ✅ | Supported (Thread only) | | ESP32-C6 | ✅ | ❌ | ✅ | Fully supported | | ESP32-H2 | ❌ | ✅ | ✅ | Supported (Thread only) | ### Note on Commissioning: - **ESP32 & ESP32-S2** do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually. -- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. -- **ESP32-C5** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project as an ESP-IDF component and to disable the Matter Wi-Fi station feature. +- **ESP32-C6** Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature. +- **ESP32-C5** Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station. ## Features @@ -82,8 +82,12 @@ Before uploading the sketch, configure the following: 1. Open the `MatterWindowCovering.ino` sketch in the Arduino IDE. 2. Select your ESP32 board from the **Tools > Board** menu. -3. Connect your ESP32 board to your computer via USB. -4. Click the **Upload** button to compile and flash the sketch. + +3. Select **"Huge APP (3MB No OTA/1MB SPIFFS)"** from **Tools > Partition Scheme** menu. + +4. Enable **"Erase All Flash Before Sketch Upload"** option from **Tools** menu. +5. Connect your ESP32 board to your computer via USB. +6. Click the **Upload** button to compile and flash the sketch. ## Expected Output diff --git a/libraries/Matter/keywords.txt b/libraries/Matter/keywords.txt index 4baaf54f17f..11f58d7ea12 100644 --- a/libraries/Matter/keywords.txt +++ b/libraries/Matter/keywords.txt @@ -54,6 +54,8 @@ EndPointIdentifyCB KEYWORD1 matterEvent_t KEYWORD1 matterEventCB KEYWORD1 attrOperation_t KEYWORD1 +OccupancySensorType_t KEYWORD1 +HoldTimeChangeCB KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -63,10 +65,14 @@ begin KEYWORD2 end KEYWORD2 getManualPairingCode KEYWORD2 getOnboardingQRCodeUrl KEYWORD2 +isBLECommissioningEnabled KEYWORD2 isDeviceCommissioned KEYWORD2 -isWiFiConnected KEYWORD2 -isThreadConnected KEYWORD2 isDeviceConnected KEYWORD2 +isThreadConnected KEYWORD2 +isThreadEnabled KEYWORD2 +isWiFiAccessPointEnabled KEYWORD2 +isWiFiConnected KEYWORD2 +isWiFiStationEnabled KEYWORD2 decommission KEYWORD2 attributeChangeCB KEYWORD2 setOnOff KEYWORD2 @@ -128,6 +134,10 @@ setPressure KEYWORD2 getPressure KEYWORD2 setOccupancy KEYWORD2 getOccupancy KEYWORD2 +setHoldTime KEYWORD2 +getHoldTime KEYWORD2 +setHoldTimeLimits KEYWORD2 +onHoldTimeChange KEYWORD2 getControlSequence KEYWORD2 getMinHeatSetpoint KEYWORD2 getMaxHeatSetpoint KEYWORD2 @@ -269,3 +279,7 @@ MOVING_DOWN_OR_CLOSE LITERAL1 GLOBAL LITERAL1 LIFT LITERAL1 TILT LITERAL1 +OCCUPANCY_SENSOR_TYPE_PIR LITERAL1 +OCCUPANCY_SENSOR_TYPE_ULTRASONIC LITERAL1 +OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC LITERAL1 +OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT LITERAL1 diff --git a/libraries/Matter/library.properties b/libraries/Matter/library.properties index b95e4e09a10..15cdd6e9358 100644 --- a/libraries/Matter/library.properties +++ b/libraries/Matter/library.properties @@ -1,5 +1,5 @@ name=Matter -version=3.3.4 +version=3.3.5 author=Rodrigo Garcia | GitHub @SuGlider maintainer=Rodrigo Garcia sentence=Library for supporting Matter environment on ESP32. diff --git a/libraries/Matter/src/Matter.cpp b/libraries/Matter/src/Matter.cpp index 5ddacc1622c..151a9e8990e 100644 --- a/libraries/Matter/src/Matter.cpp +++ b/libraries/Matter/src/Matter.cpp @@ -175,31 +175,70 @@ void ArduinoMatter::begin() { } } -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD -bool ArduinoMatter::isThreadConnected() { - return false; // Thread Network TBD +// Network and Commissioning Capability Queries +bool ArduinoMatter::isWiFiStationEnabled() { + // Check hardware support (SOC capabilities) AND Matter configuration +#ifdef SOC_WIFI_SUPPORTED +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION + return true; +#else + return false; +#endif +#else + return false; +#endif +} + +bool ArduinoMatter::isWiFiAccessPointEnabled() { + // Check hardware support (SOC capabilities) AND Matter configuration +#ifdef SOC_WIFI_SUPPORTED +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP + return true; +#else + return false; +#endif +#else + return false; +#endif +} + +bool ArduinoMatter::isThreadEnabled() { + // Check Matter configuration only +#if CONFIG_ENABLE_MATTER_OVER_THREAD || CHIP_DEVICE_CONFIG_ENABLE_THREAD + return true; +#else + return false; +#endif } + +bool ArduinoMatter::isBLECommissioningEnabled() { + // Check hardware support (SOC capabilities) AND Matter/ESP configuration + // BLE commissioning requires: SOC BLE support AND (CHIPoBLE or NimBLE enabled) +#ifdef SOC_BLE_SUPPORTED +#if CONFIG_ENABLE_CHIPOBLE + return true; +#else + return false; +#endif +#else + return false; #endif +} bool ArduinoMatter::isDeviceCommissioned() { return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0; } -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION bool ArduinoMatter::isWiFiConnected() { return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected(); } -#endif + +bool ArduinoMatter::isThreadConnected() { + return chip::DeviceLayer::ConnectivityMgr().IsThreadAttached(); +} bool ArduinoMatter::isDeviceConnected() { - bool retCode = false; -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD - retCode |= ArduinoMatter::isThreadConnected(); -#endif -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION - retCode |= ArduinoMatter::isWiFiConnected(); -#endif - return retCode; + return ArduinoMatter::isWiFiConnected() || ArduinoMatter::isThreadConnected(); } void ArduinoMatter::decommission() { diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h index 73b3b35de62..dc72017a7d3 100644 --- a/libraries/Matter/src/Matter.h +++ b/libraries/Matter/src/Matter.h @@ -179,13 +179,17 @@ class ArduinoMatter { return String("https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00"); } static void begin(); + + // Network and Commissioning Capability Queries + // These methods check both hardware support (SOC capabilities) and Matter configuration + static bool isWiFiStationEnabled(); // Check if WiFi Station mode is supported and enabled + static bool isWiFiAccessPointEnabled(); // Check if WiFi AP mode is supported and enabled + static bool isThreadEnabled(); // Check if Thread network is supported and enabled + static bool isBLECommissioningEnabled(); // Check if BLE commissioning is supported and enabled + static bool isDeviceCommissioned(); -#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION static bool isWiFiConnected(); -#endif -#if CHIP_DEVICE_CONFIG_ENABLE_THREAD static bool isThreadConnected(); -#endif static bool isDeviceConnected(); static void decommission(); diff --git a/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp index f91a02e14a9..ec84ea9b0a5 100644 --- a/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp +++ b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp @@ -18,11 +18,153 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace esp_matter; using namespace esp_matter::endpoint; +using namespace esp_matter::cluster; +using namespace esp_matter::cluster::occupancy_sensing::attribute; using namespace chip::app::Clusters; +// Custom AttributeAccessInterface wrapper that intercepts HoldTime writes to call user callbacks +// This wraps the standard OccupancySensing::Instance to add callback support +class OccupancySensingAttrAccessWrapper : public chip::app::AttributeAccessInterface { +public: + OccupancySensingAttrAccessWrapper() + : chip::app::AttributeAccessInterface(chip::Optional::Missing(), OccupancySensing::Id), + mInstance(chip::BitMask(0)) {} + + CHIP_ERROR Init() { + // Register THIS wrapper instance, not the standard instance + // The wrapper will delegate reads/writes to mInstance internally + bool registered = chip::app::AttributeAccessInterfaceRegistry::Instance().Register(this); + if (!registered) { + log_e("Failed to register OccupancySensing AttributeAccessInterface (duplicate?)"); + return CHIP_ERROR_INCORRECT_STATE; + } + return CHIP_NO_ERROR; + } + + CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath &aPath, chip::app::AttributeValueEncoder &aEncoder) override { + // Delegate reads to the standard instance + return mInstance.Read(aPath, aEncoder); + } + + CHIP_ERROR Write(const chip::app::ConcreteDataAttributePath &aPath, chip::app::AttributeValueDecoder &aDecoder) override { + // Intercept HoldTime writes to call user callbacks + if (aPath.mAttributeId == OccupancySensing::Attributes::HoldTime::Id) { + uint16_t newHoldTime; + CHIP_ERROR err = aDecoder.Decode(newHoldTime); + if (err != CHIP_NO_ERROR) { + return err; + } + + // Validate against HoldTimeLimits first (same as Instance::Write does) + OccupancySensing::Structs::HoldTimeLimitsStruct::Type *currHoldTimeLimits = OccupancySensing::GetHoldTimeLimitsForEndpoint(aPath.mEndpointId); + if (currHoldTimeLimits == nullptr) { + return CHIP_ERROR_INVALID_ARGUMENT; + } + if (newHoldTime < currHoldTimeLimits->holdTimeMin || newHoldTime > currHoldTimeLimits->holdTimeMax) { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + // Find the MatterOccupancySensor instance for this endpoint and call its callback + MatterOccupancySensor *sensor = FindOccupancySensorForEndpoint(aPath.mEndpointId); + if (sensor != nullptr) { + // Call the user callback if set (this allows rejection of the change) + if (sensor->_onHoldTimeChangeCB) { + if (!sensor->_onHoldTimeChangeCB(newHoldTime)) { + // User callback rejected the change + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + } + } + + // Call SetHoldTime directly (same as Instance::Write does) + err = OccupancySensing::SetHoldTime(aPath.mEndpointId, newHoldTime); + if (err == CHIP_NO_ERROR && sensor != nullptr) { + // Update the internal value to keep it in sync + sensor->holdTime_seconds = newHoldTime; + } + return err; + } + + // For other attributes, delegate to the standard instance + return mInstance.Write(aPath, aDecoder); + } + +private: + OccupancySensing::Instance mInstance; + + // Helper to find MatterOccupancySensor instance for an endpoint + static MatterOccupancySensor *FindOccupancySensorForEndpoint(chip::EndpointId endpointId) { + // Get the endpoint's private data (set when creating the endpoint) + void *priv_data = esp_matter::endpoint::get_priv_data(endpointId); + if (priv_data == nullptr) { + return nullptr; + } + + MatterOccupancySensor *sensor = static_cast(priv_data); + // Verify it's actually a MatterOccupancySensor by checking if it's started + if (sensor != nullptr && sensor->started) { + return sensor; + } + + return nullptr; + } +}; + +// Static AttributeAccessInterface wrapper instance +// Registered once globally to handle all OccupancySensing endpoints +namespace { +static OccupancySensingAttrAccessWrapper sOccupancySensingAttrAccess; +static bool sOccupancySensingAttrAccessRegistered = false; +} // namespace + +// Static helper functions for Matter event loop operations +namespace { +void SetHoldTimeInEventLoop(uint16_t endpoint_id, uint16_t holdTime_seconds) { + CHIP_ERROR err = OccupancySensing::SetHoldTime(endpoint_id, holdTime_seconds); + if (err != CHIP_NO_ERROR) { + ChipLogError(NotSpecified, "Failed to set HoldTime: %" CHIP_ERROR_FORMAT, err.Format()); + } else { + ChipLogDetail(NotSpecified, "HoldTime set to %u seconds", holdTime_seconds); + } +} + +void SetHoldTimeLimitsInEventLoop(uint16_t endpoint_id, uint16_t min_seconds, uint16_t max_seconds, uint16_t default_seconds) { + OccupancySensing::Structs::HoldTimeLimitsStruct::Type holdTimeLimits; + holdTimeLimits.holdTimeMin = min_seconds; + holdTimeLimits.holdTimeMax = max_seconds; + holdTimeLimits.holdTimeDefault = default_seconds; + + CHIP_ERROR err = OccupancySensing::SetHoldTimeLimits(endpoint_id, holdTimeLimits); + if (err != CHIP_NO_ERROR) { + ChipLogError(NotSpecified, "Failed to set HoldTimeLimits: %" CHIP_ERROR_FORMAT, err.Format()); + } else { + ChipLogDetail(NotSpecified, "HoldTimeLimits set: Min=%u, Max=%u, Default=%u seconds", min_seconds, max_seconds, default_seconds); + } +} + +void SetHoldTimeLimitsAndHoldTimeInEventLoop( + uint16_t endpoint_id, uint16_t min_seconds, uint16_t max_seconds, uint16_t default_seconds, uint16_t holdTime_seconds +) { + // Set HoldTimeLimits first + SetHoldTimeLimitsInEventLoop(endpoint_id, min_seconds, max_seconds, default_seconds); + + // Then adjust HoldTime to be within the new limits + SetHoldTimeInEventLoop(endpoint_id, holdTime_seconds); +} +} // namespace + // clang-format off const uint8_t MatterOccupancySensor::occupancySensorTypeBitmap[4] = { MatterOccupancySensor::occupancySensorTypePir, @@ -33,17 +175,26 @@ const uint8_t MatterOccupancySensor::occupancySensorTypeBitmap[4] = { // clang-format on bool MatterOccupancySensor::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { - bool ret = true; if (!started) { log_e("Matter Occupancy Sensor device has not begun."); return false; } - log_d("Occupancy Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32); - return ret; + log_d("Occupancy Sensor Attr update callback: endpoint: %u, cluster: %u, attribute: %u", endpoint_id, cluster_id, attribute_id); + + // Note: HoldTime writes are handled by OccupancySensingAttrAccessWrapper::Write() + // since HoldTime is MANAGED_INTERNALLY and doesn't go through the normal esp-matter callback path + + return true; +} + +void MatterOccupancySensor::onHoldTimeChange(HoldTimeChangeCB onHoldTimeChangeCB) { + _onHoldTimeChangeCB = onHoldTimeChangeCB; } -MatterOccupancySensor::MatterOccupancySensor() {} +MatterOccupancySensor::MatterOccupancySensor() { + // HoldTimeLimits must be set explicitly via setHoldTimeLimits() after Matter.begin() +} MatterOccupancySensor::~MatterOccupancySensor() { end(); @@ -52,24 +203,84 @@ MatterOccupancySensor::~MatterOccupancySensor() { bool MatterOccupancySensor::begin(bool _occupancyState, OccupancySensorType_t _occupancySensorType) { ArduinoMatter::_init(); + // Initial HoldTime value is 0 (can be set later via setHoldTime() or setHoldTimeLimits()) + holdTime_seconds = 0; if (getEndPointId() != 0) { log_e("Matter Occupancy Sensor with Endpoint Id %d device has already been created.", getEndPointId()); return false; } - occupancy_sensor::config_t occupancy_sensor_config; occupancy_sensor_config.occupancy_sensing.occupancy = _occupancyState; occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type = _occupancySensorType; occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type_bitmap = occupancySensorTypeBitmap[_occupancySensorType]; + // Set features based on sensor type + // Available features: other, passive_infrared, ultrasonic, physical_contact, active_infrared, radar, rf_sensing, vision + using namespace esp_matter::cluster::occupancy_sensing::feature; + + switch (_occupancySensorType) { + case OCCUPANCY_SENSOR_TYPE_PIR: occupancy_sensor_config.occupancy_sensing.features = passive_infrared::get_id(); break; + case OCCUPANCY_SENSOR_TYPE_ULTRASONIC: occupancy_sensor_config.occupancy_sensing.features = ultrasonic::get_id(); break; + case OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC: + occupancy_sensor_config.occupancy_sensing.features = passive_infrared::get_id() | ultrasonic::get_id(); + break; + case OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT: occupancy_sensor_config.occupancy_sensing.features = physical_contact::get_id(); break; + default: + // For unknown types, use "other" feature + occupancy_sensor_config.occupancy_sensing.features = other::get_id(); + break; + } // endpoint handles can be used to add/modify clusters. endpoint_t *endpoint = occupancy_sensor::create(node::get(), &occupancy_sensor_config, ENDPOINT_FLAG_NONE, (void *)this); if (endpoint == nullptr) { log_e("Failed to create Occupancy Sensor endpoint"); return false; } - occupancyState = _occupancyState; setEndPointId(endpoint::get_id(endpoint)); + occupancyState = _occupancyState; + + // Register AttributeAccessInterface for OccupancySensing cluster if not already registered + // This enables HoldTime and HoldTimeLimits (MANAGED_INTERNALLY attributes) to be read + // via the server implementation instead of falling back to esp-matter's placeholder storage + if (!sOccupancySensingAttrAccessRegistered) { + CHIP_ERROR err = sOccupancySensingAttrAccess.Init(); + if (err == CHIP_NO_ERROR) { + sOccupancySensingAttrAccessRegistered = true; + } else { + log_e("Failed to register OccupancySensing AttributeAccessInterface: %" CHIP_ERROR_FORMAT, err.Format()); + } + } + + // Add HoldTime and HoldTimeLimits attributes to the occupancy sensing cluster + cluster_t *cluster = cluster::get(endpoint, OccupancySensing::Id); + if (cluster != nullptr) { + // Create HoldTime attribute first (HoldTimeLimits may depend on it) + attribute_t *hold_time_attr = create_hold_time(cluster, holdTime_seconds); + if (hold_time_attr == nullptr) { + log_e("Failed to create HoldTime attribute"); + // Continue anyway, as HoldTime is optional + } else { + log_d("HoldTime attribute created with value %u seconds", holdTime_seconds); + } + + // Create the HoldTimeLimits attribute + // Since this attribute is MANAGED_INTERNALLY, we pass NULL/0/0 and let the CHIP server manage the value + // The server will handle TLV encoding/decoding automatically via AttributeAccessInterface + // Note: HoldTimeLimits should only be created if HoldTime was successfully created + if (hold_time_attr != nullptr) { + attribute_t *hold_time_limits_attr = create_hold_time_limits(cluster, NULL, 0, 0); + if (hold_time_limits_attr == nullptr) { + log_e("Failed to create HoldTimeLimits attribute"); + } else { + log_d("HoldTimeLimits attribute created"); + } + } else { + log_w("Skipping HoldTimeLimits creation because HoldTime attribute creation failed"); + } + } else { + log_e("Failed to get Occupancy Sensing cluster"); + } + log_i("Occupancy Sensor created with endpoint_id %d", getEndPointId()); started = true; @@ -99,9 +310,7 @@ bool MatterOccupancySensor::setOccupancy(bool _occupancyState) { } if (occupancyVal.val.u8 != _occupancyState) { occupancyVal.val.u8 = _occupancyState; - bool ret; - ret = updateAttributeVal(OccupancySensing::Id, OccupancySensing::Attributes::Occupancy::Id, &occupancyVal); - if (!ret) { + if (!updateAttributeVal(OccupancySensing::Id, OccupancySensing::Attributes::Occupancy::Id, &occupancyVal)) { log_e("Failed to update Occupancy Sensor Attribute."); return false; } @@ -112,4 +321,137 @@ bool MatterOccupancySensor::setOccupancy(bool _occupancyState) { return true; } +bool MatterOccupancySensor::setHoldTime(uint16_t _holdTime_seconds) { + if (!started) { + log_e("Matter Occupancy Sensor device has not begun."); + return false; + } + + if (getEndPointId() == 0) { + log_e("Endpoint ID is not set"); + return false; + } + + // avoid processing if there was no change + if (holdTime_seconds == _holdTime_seconds) { + return true; + } + + // Validate against HoldTimeLimits if they are set (using member variables) + if (holdTimeMax_seconds > 0) { + // Limits are set, validate the new value + if (_holdTime_seconds < holdTimeMin_seconds) { + log_e("HoldTime (%u) is below minimum (%u seconds)", _holdTime_seconds, holdTimeMin_seconds); + return false; + } + if (_holdTime_seconds > holdTimeMax_seconds) { + log_e("HoldTime (%u) exceeds maximum (%u seconds)", _holdTime_seconds, holdTimeMax_seconds); + return false; + } + } + + // SetHoldTime() calls MatterReportingAttributeChangeCallback() which must be called + // from the Matter event loop context to avoid stack locking errors. + // Schedule the call on the Matter event loop using ScheduleLambda. + if (!chip::DeviceLayer::SystemLayer().IsInitialized()) { + log_e("SystemLayer is not initialized. Matter.begin() must be called before setHoldTime()."); + return false; + } + + uint16_t endpoint_id = getEndPointId(); + + CHIP_ERROR schedule_err = chip::DeviceLayer::SystemLayer().ScheduleLambda([endpoint_id, holdTime = _holdTime_seconds]() { + SetHoldTimeInEventLoop(endpoint_id, holdTime); + }); + + if (schedule_err != CHIP_NO_ERROR) { + log_e("Failed to schedule HoldTime update: %" CHIP_ERROR_FORMAT, schedule_err.Format()); + return false; + } + + // Update member variable immediately + holdTime_seconds = _holdTime_seconds; + log_v("HoldTime scheduled for update with value %u seconds", _holdTime_seconds); + + return true; +} + +bool MatterOccupancySensor::setHoldTimeLimits(uint16_t _holdTimeMin_seconds, uint16_t _holdTimeMax_seconds, uint16_t _holdTimeDefault_seconds) { + if (!started) { + log_e("Matter Occupancy Sensor device has not begun."); + return false; + } + + if (getEndPointId() == 0) { + log_e("Endpoint ID is not set"); + return false; + } + + // Validate limits + if (_holdTimeMin_seconds > _holdTimeMax_seconds) { + log_e("HoldTimeMin (%u) must be <= HoldTimeMax (%u)", _holdTimeMin_seconds, _holdTimeMax_seconds); + return false; + } + + if (_holdTimeDefault_seconds < _holdTimeMin_seconds || _holdTimeDefault_seconds > _holdTimeMax_seconds) { + log_e("HoldTimeDefault (%u) must be between HoldTimeMin (%u) and HoldTimeMax (%u)", _holdTimeDefault_seconds, _holdTimeMin_seconds, _holdTimeMax_seconds); + return false; + } + + // SetHoldTimeLimits() calls MatterReportingAttributeChangeCallback() which must be called + // from the Matter event loop context to avoid stack locking errors. + // Schedule the call on the Matter event loop using ScheduleLambda. + // First check if the scheduler is available (Matter.begin() must have been called) + if (!chip::DeviceLayer::SystemLayer().IsInitialized()) { + log_e("SystemLayer is not initialized. Matter.begin() must be called before setHoldTimeLimits()."); + return false; + } + + // Update member variables immediately + holdTimeMin_seconds = _holdTimeMin_seconds; + holdTimeMax_seconds = _holdTimeMax_seconds; + holdTimeDefault_seconds = _holdTimeDefault_seconds; + + // Check if current HoldTime is outside the new limits and adjust if necessary + uint16_t adjustedHoldTime = holdTime_seconds; + bool holdTimeAdjusted = false; + + if (holdTime_seconds < _holdTimeMin_seconds) { + adjustedHoldTime = _holdTimeMin_seconds; + holdTimeAdjusted = true; + log_i("Current HoldTime (%u) is below new minimum (%u), adjusting to minimum", holdTime_seconds, _holdTimeMin_seconds); + } else if (holdTime_seconds > _holdTimeMax_seconds) { + adjustedHoldTime = _holdTimeMax_seconds; + holdTimeAdjusted = true; + log_i("Current HoldTime (%u) exceeds new maximum (%u), adjusting to maximum", holdTime_seconds, _holdTimeMax_seconds); + } + + uint16_t endpoint_id = getEndPointId(); + CHIP_ERROR schedule_err; + + if (holdTimeAdjusted) { + // Schedule both limits and HoldTime updates together + schedule_err = chip::DeviceLayer::SystemLayer().ScheduleLambda([endpoint_id, min = _holdTimeMin_seconds, max = _holdTimeMax_seconds, + def = _holdTimeDefault_seconds, holdTime = adjustedHoldTime]() { + SetHoldTimeLimitsAndHoldTimeInEventLoop(endpoint_id, min, max, def, holdTime); + }); + holdTime_seconds = adjustedHoldTime; + } else { + // No adjustment needed, just schedule the limits update + schedule_err = + chip::DeviceLayer::SystemLayer().ScheduleLambda([endpoint_id, min = _holdTimeMin_seconds, max = _holdTimeMax_seconds, def = _holdTimeDefault_seconds]() { + SetHoldTimeLimitsInEventLoop(endpoint_id, min, max, def); + }); + } + + if (schedule_err != CHIP_NO_ERROR) { + log_e("Failed to schedule HoldTimeLimits update: %" CHIP_ERROR_FORMAT, schedule_err.Format()); + return false; + } + + log_v("HoldTimeLimits scheduled for update: Min=%u, Max=%u, Default=%u seconds", _holdTimeMin_seconds, _holdTimeMax_seconds, _holdTimeDefault_seconds); + + return true; +} + #endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h index acfa7fec632..aceef50c349 100644 --- a/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h +++ b/libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.h @@ -19,10 +19,16 @@ #include #include #include +#include using namespace chip::app::Clusters::OccupancySensing; +// Forward declaration for friend class +class OccupancySensingAttrAccessWrapper; + class MatterOccupancySensor : public MatterEndPoint { + friend class OccupancySensingAttrAccessWrapper; + public: // Different Occupancy Sensor Types enum OccupancySensorType_t { @@ -32,9 +38,11 @@ class MatterOccupancySensor : public MatterEndPoint { OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT = (uint8_t)OccupancySensorTypeEnum::kPhysicalContact }; + // Constructor MatterOccupancySensor(); ~MatterOccupancySensor(); // begin Matter Occupancy Sensor endpoint with initial occupancy state and default PIR sensor type + // Note: Call setHoldTimeLimits() after Matter.begin() to configure HoldTimeLimits (optional) bool begin(bool _occupancyState = false, OccupancySensorType_t _occupancySensorType = OCCUPANCY_SENSOR_TYPE_PIR); // this will just stop processing Occupancy Sensor Matter events void end(); @@ -46,6 +54,20 @@ class MatterOccupancySensor : public MatterEndPoint { return occupancyState; } + // set the hold time (in seconds) + // Must be called after Matter.begin() has been called (requires Matter event loop to be running) + bool setHoldTime(uint16_t _holdTime_seconds); + // returns the hold time (in seconds) + uint16_t getHoldTime() { + return holdTime_seconds; + } + + // set the hold time limits (min, max, default in seconds) + // Must be called after Matter.begin() has been called (requires Matter event loop to be running) + // Note: holdTimeDefault_seconds is informational metadata for Matter controllers (recommended default value). + // It does NOT automatically set the HoldTime attribute - use setHoldTime() to set the actual value. + bool setHoldTimeLimits(uint16_t _holdTimeMin_seconds, uint16_t _holdTimeMax_seconds, uint16_t _holdTimeDefault_seconds); + // bool conversion operator void operator=(bool _occupancyState) { setOccupancy(_occupancyState); @@ -55,6 +77,12 @@ class MatterOccupancySensor : public MatterEndPoint { return getOccupancy(); } + // User callback for HoldTime attribute changes + using HoldTimeChangeCB = std::function; + + // Set callback for HoldTime changes (called when Matter Controller changes HoldTime) + void onHoldTimeChange(HoldTimeChangeCB onHoldTimeChangeCB); + // this function is called by Matter internal event processor. It could be overwritten by the application, if necessary. bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val); @@ -69,5 +97,14 @@ class MatterOccupancySensor : public MatterEndPoint { bool started = false; bool occupancyState = false; + uint16_t holdTime_seconds = 0; + + // HoldTimeLimits settings (set via setHoldTimeLimits() after Matter.begin()) + uint16_t holdTimeMin_seconds = 0; + uint16_t holdTimeMax_seconds = 0; // 0 means no maximum, no limits enforced + uint16_t holdTimeDefault_seconds = 0; + + // User callback + HoldTimeChangeCB _onHoldTimeChangeCB = nullptr; }; #endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */ diff --git a/libraries/NetBIOS/library.properties b/libraries/NetBIOS/library.properties index 527a4aa1835..576acecec45 100644 --- a/libraries/NetBIOS/library.properties +++ b/libraries/NetBIOS/library.properties @@ -1,5 +1,5 @@ name=NetBIOS -version=3.3.4 +version=3.3.5 author=Pablo@xpablo.cz maintainer=Hristo Gochkov sentence=Enables NBNS (NetBIOS) name resolution. diff --git a/libraries/Network/library.properties b/libraries/Network/library.properties index f6c465eebb5..a9cbddd759f 100644 --- a/libraries/Network/library.properties +++ b/libraries/Network/library.properties @@ -1,5 +1,5 @@ name=Networking -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=General network management library. diff --git a/libraries/NetworkClientSecure/library.properties b/libraries/NetworkClientSecure/library.properties index 2b867985222..22950661f43 100644 --- a/libraries/NetworkClientSecure/library.properties +++ b/libraries/NetworkClientSecure/library.properties @@ -1,5 +1,5 @@ name=NetworkClientSecure -version=3.3.4 +version=3.3.5 author=Evandro Luis Copercini maintainer=Github Community sentence=Enables secure network connection (local and Internet) using the ESP32 built-in WiFi. diff --git a/libraries/OpenThread/library.properties b/libraries/OpenThread/library.properties index 68b9c85f864..5bf1eea7467 100644 --- a/libraries/OpenThread/library.properties +++ b/libraries/OpenThread/library.properties @@ -1,5 +1,5 @@ name=OpenThread -version=3.3.4 +version=3.3.5 author=Rodrigo Garcia | GitHub @SuGlider maintainer=Rodrigo Garcia sentence=Library for OpenThread Network on ESP32. diff --git a/libraries/PPP/library.properties b/libraries/PPP/library.properties index b6ce0d16f34..6c9e53a9b05 100644 --- a/libraries/PPP/library.properties +++ b/libraries/PPP/library.properties @@ -1,5 +1,5 @@ name=PPP -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables network connection using GSM Modem. diff --git a/libraries/PPP/src/PPP.cpp b/libraries/PPP/src/PPP.cpp index 01989429ae5..5ce0164762c 100644 --- a/libraries/PPP/src/PPP.cpp +++ b/libraries/PPP/src/PPP.cpp @@ -23,17 +23,6 @@ typedef struct { } PdpContext; #include "esp_modem_api.h" -// Because of how esp_modem functions are declared, we need to workaround some APIs that take strings as input (output works OK) -// Following APIs work only when called through this interface -extern "C" { -esp_err_t _esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout); -esp_err_t _esp_modem_at_raw(esp_modem_dce_t *dce_wrap, const char *cmd, char *p_out, const char *pass, const char *fail, int timeout); -esp_err_t _esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message); -esp_err_t _esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin); -esp_err_t _esp_modem_set_operator(esp_modem_dce_t *dce_wrap, int mode, int format, const char *oper); -esp_err_t _esp_modem_set_network_bands(esp_modem_dce_t *dce_wrap, const char *mode, const int *bands, int size); -}; - static PPPClass *_esp_modem = NULL; static esp_event_handler_instance_t _ppp_ev_instance = NULL; @@ -354,8 +343,8 @@ bool PPPClass::begin(ppp_modem_model_t model, uint8_t uart_num, int baud_rate) { } /* check if PIN needed */ - if (esp_modem_read_pin(_dce, pin_ok) == ESP_OK && pin_ok == false) { - if (_pin == NULL || _esp_modem_set_pin(_dce, _pin) != ESP_OK) { + if (esp_modem_read_pin(_dce, &pin_ok) == ESP_OK && pin_ok == false) { + if (_pin == NULL || esp_modem_set_pin(_dce, _pin) != ESP_OK) { log_e("PIN verification failed!"); goto err; } @@ -461,7 +450,7 @@ bool PPPClass::attached() const { PPP_CMD_MODE_CHECK(false); int m = 0; - esp_err_t err = esp_modem_get_network_attachment_state(_dce, m); + esp_err_t err = esp_modem_get_network_attachment_state(_dce, &m); if (err != ESP_OK) { // log_e("esp_modem_get_network_attachment_state failed with %d %s", err, esp_err_to_name(err)); return false; @@ -526,7 +515,7 @@ int PPPClass::RSSI() const { PPP_CMD_MODE_CHECK(-1); int rssi, ber; - esp_err_t err = esp_modem_get_signal_quality(_dce, rssi, ber); + esp_err_t err = esp_modem_get_signal_quality(_dce, &rssi, &ber); if (err != ESP_OK) { log_e("esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err)); return -1; @@ -538,7 +527,7 @@ int PPPClass::BER() const { PPP_CMD_MODE_CHECK(-1); int rssi, ber; - esp_err_t err = esp_modem_get_signal_quality(_dce, rssi, ber); + esp_err_t err = esp_modem_get_signal_quality(_dce, &rssi, &ber); if (err != ESP_OK) { log_e("esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err)); return -1; @@ -550,7 +539,7 @@ String PPPClass::IMSI() const { PPP_CMD_MODE_CHECK(String()); char imsi[32]; - esp_err_t err = esp_modem_get_imsi(_dce, (std::string &)imsi); + esp_err_t err = esp_modem_get_imsi(_dce, imsi); if (err != ESP_OK) { log_e("esp_modem_get_imsi failed with %d %s", err, esp_err_to_name(err)); return String(); @@ -563,7 +552,7 @@ String PPPClass::IMEI() const { PPP_CMD_MODE_CHECK(String()); char imei[32]; - esp_err_t err = esp_modem_get_imei(_dce, (std::string &)imei); + esp_err_t err = esp_modem_get_imei(_dce, imei); if (err != ESP_OK) { log_e("esp_modem_get_imei failed with %d %s", err, esp_err_to_name(err)); return String(); @@ -576,7 +565,7 @@ String PPPClass::moduleName() const { PPP_CMD_MODE_CHECK(String()); char name[32]; - esp_err_t err = esp_modem_get_module_name(_dce, (std::string &)name); + esp_err_t err = esp_modem_get_module_name(_dce, name); if (err != ESP_OK) { log_e("esp_modem_get_module_name failed with %d %s", err, esp_err_to_name(err)); return String(); @@ -590,7 +579,7 @@ String PPPClass::operatorName() const { char oper[32]; int act = 0; - esp_err_t err = esp_modem_get_operator_name(_dce, (std::string &)oper, act); + esp_err_t err = esp_modem_get_operator_name(_dce, oper, &act); if (err != ESP_OK) { log_e("esp_modem_get_operator_name failed with %d %s", err, esp_err_to_name(err)); return String(); @@ -603,7 +592,7 @@ int PPPClass::networkMode() const { PPP_CMD_MODE_CHECK(-1); int m = 0; - esp_err_t err = esp_modem_get_network_system_mode(_dce, m); + esp_err_t err = esp_modem_get_network_system_mode(_dce, &m); if (err != ESP_OK) { log_e("esp_modem_get_network_system_mode failed with %d %s", err, esp_err_to_name(err)); return -1; @@ -615,7 +604,7 @@ int PPPClass::radioState() const { PPP_CMD_MODE_CHECK(-1); int m = 0; - esp_err_t err = esp_modem_get_radio_state(_dce, m); + esp_err_t err = esp_modem_get_radio_state(_dce, &m); if (err != ESP_OK) { // log_e("esp_modem_get_radio_state failed with %d %s", err, esp_err_to_name(err)); return -1; @@ -683,7 +672,7 @@ int PPPClass::batteryVoltage() const { PPP_CMD_MODE_CHECK(-1); int volt, bcs, bcl; - esp_err_t err = esp_modem_get_battery_status(_dce, volt, bcs, bcl); + esp_err_t err = esp_modem_get_battery_status(_dce, &volt, &bcs, &bcl); if (err != ESP_OK) { log_e("esp_modem_get_battery_status failed with %d %s", err, esp_err_to_name(err)); return -1; @@ -695,7 +684,7 @@ int PPPClass::batteryLevel() const { PPP_CMD_MODE_CHECK(-1); int volt, bcs, bcl; - esp_err_t err = esp_modem_get_battery_status(_dce, volt, bcs, bcl); + esp_err_t err = esp_modem_get_battery_status(_dce, &volt, &bcs, &bcl); if (err != ESP_OK) { log_e("esp_modem_get_battery_status failed with %d %s", err, esp_err_to_name(err)); return -1; @@ -707,7 +696,7 @@ int PPPClass::batteryStatus() const { PPP_CMD_MODE_CHECK(-1); int volt, bcs, bcl; - esp_err_t err = esp_modem_get_battery_status(_dce, volt, bcs, bcl); + esp_err_t err = esp_modem_get_battery_status(_dce, &volt, &bcs, &bcl); if (err != ESP_OK) { log_e("esp_modem_get_battery_status failed with %d %s", err, esp_err_to_name(err)); return -1; @@ -737,7 +726,7 @@ bool PPPClass::sms(const char *num, const char *message) { return false; } - err = _esp_modem_send_sms(_dce, num, message); + err = esp_modem_send_sms(_dce, num, message); if (err != ESP_OK) { log_e("esp_modem_send_sms() failed with %d %s", err, esp_err_to_name(err)); return false; @@ -749,7 +738,7 @@ String PPPClass::cmd(const char *at_command, int timeout) { PPP_CMD_MODE_CHECK(String()); char out[128] = {0}; - esp_err_t err = _esp_modem_at(_dce, at_command, out, timeout); + esp_err_t err = esp_modem_at(_dce, at_command, out, timeout); if (err != ESP_OK) { log_e("esp_modem_at failed %d %s", err, esp_err_to_name(err)); return String(); @@ -761,7 +750,7 @@ bool PPPClass::cmd(const char *at_command, String &response, int timeout) { PPP_CMD_MODE_CHECK(false); char out[128] = {0}; - esp_err_t err = _esp_modem_at(_dce, at_command, out, timeout); + esp_err_t err = esp_modem_at(_dce, at_command, out, timeout); response = String(out); if (err != ESP_OK) { diff --git a/libraries/PPP/src/ppp.c b/libraries/PPP/src/ppp.c deleted file mode 100644 index 52896e76c8e..00000000000 --- a/libraries/PPP/src/ppp.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "sdkconfig.h" -#if CONFIG_LWIP_PPP_SUPPORT && defined __has_include && __has_include("esp_modem_api.h") -#include "esp_modem_api.h" - -esp_err_t _esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout) { - return esp_modem_at(dce_wrap, at, p_out, timeout); -} - -esp_err_t _esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message) { - return esp_modem_send_sms(dce_wrap, number, message); -} - -esp_err_t _esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin) { - return esp_modem_set_pin(dce_wrap, pin); -} - -esp_err_t _esp_modem_at_raw(esp_modem_dce_t *dce_wrap, const char *cmd, char *p_out, const char *pass, const char *fail, int timeout) { - return esp_modem_at_raw(dce_wrap, cmd, p_out, pass, fail, timeout); -} - -esp_err_t _esp_modem_set_operator(esp_modem_dce_t *dce_wrap, int mode, int format, const char *oper) { - return esp_modem_set_operator(dce_wrap, mode, format, oper); -} - -esp_err_t _esp_modem_set_network_bands(esp_modem_dce_t *dce_wrap, const char *mode, const int *bands, int size) { - return esp_modem_set_network_bands(dce_wrap, mode, bands, size); -} -#endif // CONFIG_LWIP_PPP_SUPPORT diff --git a/libraries/Preferences/library.properties b/libraries/Preferences/library.properties index a9e3932888e..6662b447a33 100644 --- a/libraries/Preferences/library.properties +++ b/libraries/Preferences/library.properties @@ -1,5 +1,5 @@ name=Preferences -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Provides friendly access to ESP32's Non-Volatile Storage diff --git a/libraries/RainMaker/library.properties b/libraries/RainMaker/library.properties index af0c63b233b..9f480085c44 100644 --- a/libraries/RainMaker/library.properties +++ b/libraries/RainMaker/library.properties @@ -1,5 +1,5 @@ name=ESP RainMaker -version=3.3.4 +version=3.3.5 author=Sweety Mhaiske maintainer=Hristo Gochkov sentence=ESP RainMaker Support diff --git a/libraries/SD/library.properties b/libraries/SD/library.properties index 4bb9876e684..e2562b2bf5a 100644 --- a/libraries/SD/library.properties +++ b/libraries/SD/library.properties @@ -1,5 +1,5 @@ name=SD -version=3.3.4 +version=3.3.5 author=Arduino, SparkFun maintainer=Arduino sentence=Enables reading and writing on SD cards. For all Arduino boards. diff --git a/libraries/SD_MMC/library.properties b/libraries/SD_MMC/library.properties index 6011ed115ea..90cc63db3a2 100644 --- a/libraries/SD_MMC/library.properties +++ b/libraries/SD_MMC/library.properties @@ -1,5 +1,5 @@ name=SD_MMC -version=3.3.4 +version=3.3.5 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 SDMMC File System diff --git a/libraries/SPI/library.properties b/libraries/SPI/library.properties index 15a17d9101c..814de9e84f8 100644 --- a/libraries/SPI/library.properties +++ b/libraries/SPI/library.properties @@ -1,5 +1,5 @@ name=SPI -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE. diff --git a/libraries/SPIFFS/library.properties b/libraries/SPIFFS/library.properties index 923172dd6ae..01068279ec2 100644 --- a/libraries/SPIFFS/library.properties +++ b/libraries/SPIFFS/library.properties @@ -1,5 +1,5 @@ name=SPIFFS -version=3.3.4 +version=3.3.5 author=Hristo Gochkov, Ivan Grokhtkov maintainer=Hristo Gochkov sentence=ESP32 SPIFFS File System diff --git a/libraries/SimpleBLE/library.properties b/libraries/SimpleBLE/library.properties index cfa030f860d..28db48dae7f 100644 --- a/libraries/SimpleBLE/library.properties +++ b/libraries/SimpleBLE/library.properties @@ -1,5 +1,5 @@ name=SimpleBLE -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Provides really simple BLE advertizer with just on and off diff --git a/libraries/TFLiteMicro/library.properties b/libraries/TFLiteMicro/library.properties index 52641b149d1..e8953970874 100644 --- a/libraries/TFLiteMicro/library.properties +++ b/libraries/TFLiteMicro/library.properties @@ -1,5 +1,5 @@ name=TFLite Micro -version=3.3.4 +version=3.3.5 author=Sanket Wadekar maintainer=Sanket Wadekar sentence=TensorFlow Lite for Microcontrollers diff --git a/libraries/Ticker/library.properties b/libraries/Ticker/library.properties index 441519edab0..1965126c42c 100644 --- a/libraries/Ticker/library.properties +++ b/libraries/Ticker/library.properties @@ -1,5 +1,5 @@ name=Ticker -version=3.3.4 +version=3.3.5 author=Bert Melis maintainer=Hristo Gochkov sentence=Allows to call functions with a given interval. diff --git a/libraries/USB/library.properties b/libraries/USB/library.properties index 8698f2cffbe..e8da72d7fa6 100644 --- a/libraries/USB/library.properties +++ b/libraries/USB/library.properties @@ -1,5 +1,5 @@ name=USB -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=ESP32S2 USB Library diff --git a/libraries/Update/README.md b/libraries/Update/README.md new file mode 100644 index 00000000000..7483cb35308 --- /dev/null +++ b/libraries/Update/README.md @@ -0,0 +1,431 @@ +# ESP32 Arduino Update Library + +The Update library provides functionality for Over-The-Air (OTA) firmware updates on ESP32 devices. It supports secure updates with signature verification, encrypted updates, and various update sources. + +## Features + +- **OTA Updates**: Update firmware over Wi-Fi +- **Signature Verification**: RSA and ECDSA signature verification for secure updates (optional, must be enabled with `UPDATE_SIGN`) +- **Image Encryption**: Support for encrypted firmware updates (optional, can be disabled with `UPDATE_NOCRYPT`) +- **Multiple Sources**: HTTP, HTTPS, SD card, and custom sources +- **Progress Callbacks**: Monitor update progress +- **MD5 Verification**: Optional MD5 checksum verification + +## Quick Start + +### Basic OTA Update + +```cpp +#include + +WiFiClient client; +size_t updateSize = client.available(); + +if (Update.begin(updateSize)) { + Update.writeStream(client); + if (Update.end()) { + Serial.println("Update successful!"); + ESP.restart(); + } else { + Serial.println("Update failed!"); + } +} +``` + +### Signed OTA Update (Recommended) + +To enable signature verification, add `-DUPDATE_SIGN` to your build flags (e.g., in `build_opt.h`): +``` +-DUPDATE_SIGN +``` + +Then in your sketch: +```cpp +#include + +// Include your public key (generated with bin_signing.py) +#include "public_key.h" + +// Create verifier object (defaults to SHA-256) +UpdaterRSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN); + +// Install signature verification BEFORE Update.begin() +Update.installSignature(&sign); + +// Now perform the update as usual +if (Update.begin(updateSize)) { + Update.writeStream(client); + if (Update.end()) { + // Signature was verified successfully! + Serial.println("Signed update successful!"); + ESP.restart(); + } else { + if (Update.getError() == UPDATE_ERROR_SIGN) { + Serial.println("Signature verification failed!"); + } + } +} +``` + +## Signature Verification + +### Overview + +Code signing ensures that only firmware signed with your private key will be accepted by your devices. This protects against: + +- Unauthorized firmware updates +- Man-in-the-middle attacks +- Compromised update servers +- Supply chain attacks + +### Supported Algorithms + +**Signature Schemes:** +- RSA-2048, RSA-3072, RSA-4096 +- ECDSA-P256, ECDSA-P384 + +**Hash Algorithms:** +- SHA-256, SHA-384, SHA-512 + +### Setup + +1. **Generate Key Pair:** + +```bash +# RSA-2048 (recommended) +python /tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem +python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem + +# ECDSA-P256 (smaller, faster) +python /tools/bin_signing.py --generate-key ecdsa-p256 --out private_key.pem +python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +``` + +2. **Include Public Key in Sketch:** + +```cpp +#include "public_key.h" // Generated by bin_signing.py +``` + +3. **Install Signature Verification:** + +Enable the feature by adding to `build_opt.h`: +``` +-DUPDATE_SIGN +``` + +Then in your sketch: +```cpp +// For RSA with SHA-256 +UpdaterRSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, HASH_SHA256); +Update.installSignature(&sign); + +// For ECDSA with SHA-384 +UpdaterECDSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, HASH_SHA384); +Update.installSignature(&sign); +``` + +4. **Sign Your Firmware:** + +```bash +python /tools/bin_signing.py --bin --key private_key.pem --out firmware_signed.bin --hash +``` + +5. **Upload Signed Application Firmware:** + +The signed firmware includes the signature appended to the binary. Upload the newly created signed firmware instead of the original application binary. + +### Security Best Practices + +1. **Protect Your Private Key:** + - Never commit it to version control + - Store it in secure, encrypted storage + - Limit access to authorized personnel only + - Consider using HSM for production + +2. **Use HTTPS:** + - While signature verification protects integrity, HTTPS protects confidentiality + +## API Reference + +### UpdateClass Methods + +#### begin() +```cpp +bool begin(size_t size = UPDATE_SIZE_UNKNOWN, + int command = U_FLASH, + int ledPin = -1, + uint8_t ledOn = LOW, + const char *label = NULL) +``` +Starts an update operation. + +**Parameters:** +- `size`: Size of the update in bytes (including signature if using signed updates) +- `command`: Update type (U_FLASH, U_SPIFFS, U_FATFS, U_LITTLEFS) +- `ledPin`: Optional LED pin to indicate progress +- `ledOn`: LED on state (LOW or HIGH) +- `label`: Optional partition label + +**Returns:** `true` on success, `false` on failure + +#### installSignature() +```cpp +bool installSignature(UpdaterVerifyClass *sign) +``` +Installs signature verification. Must be called before `begin()`. + +**Parameters:** +- `sign`: Signature verifier (UpdaterRSAVerifier or UpdaterECDSAVerifier) + +**Returns:** `true` on success, `false` on failure + +#### write() +```cpp +size_t write(uint8_t *data, size_t len) +``` +Writes data to the update. + +**Parameters:** +- `data`: Data buffer +- `len`: Length of data + +**Returns:** Number of bytes written + +#### writeStream() +```cpp +size_t writeStream(Stream &data) +``` +Writes data from a stream. + +**Parameters:** +- `data`: Input stream + +**Returns:** Number of bytes written + +#### end() +```cpp +bool end(bool evenIfRemaining = false) +``` +Completes the update and verifies signature if enabled. + +**Parameters:** +- `evenIfRemaining`: Complete even if not all data was written + +**Returns:** `true` if update succeeded and signature is valid, `false` otherwise + +#### abort() +```cpp +void abort() +``` +Aborts the current update. + +#### setMD5() +```cpp +bool setMD5(const char *expected_md5) +``` +Sets expected MD5 hash for verification. + +**Parameters:** +- `expected_md5`: MD5 hash as hex string (32 characters) + +**Returns:** `true` on success, `false` on failure + +#### getError() +```cpp +uint8_t getError() +``` +Returns the last error code. + +**Returns:** Error code (see Error Codes below) + +#### errorString() +```cpp +const char *errorString() +``` +Returns a human-readable error message. + +**Returns:** Error message string + +### Hash Classes (from Hash Library) + +The Update library uses the Hash library for hashing. Simply use the builders from that library: + +```cpp +#include + +SHA256Builder hash256; // SHA-256 +SHA384Builder hash384; // SHA-384 +SHA512Builder hash512; // SHA-512 +``` + +See the [Hash library documentation](../Hash/README.md) for more details. + +### Signature Verifier Classes + +#### UpdaterRSAVerifier +RSA signature verifier. + +```cpp +UpdaterRSAVerifier(const uint8_t *pubkey, size_t pubkeyLen, int hashType = HASH_SHA256) +``` + +**Parameters:** +- `pubkey`: Public key in PEM format +- `pubkeyLen`: Length of public key +- `hashType`: Hash algorithm (`HASH_SHA256`, `HASH_SHA384`, or `HASH_SHA512`). Defaults to `HASH_SHA256`. + +#### UpdaterECDSAVerifier +ECDSA signature verifier. + +```cpp +UpdaterECDSAVerifier(const uint8_t *pubkey, size_t pubkeyLen, int hashType = HASH_SHA256) +``` + +**Parameters:** +- `pubkey`: Public key in PEM format +- `pubkeyLen`: Length of public key +- `hashType`: Hash algorithm (`HASH_SHA256`, `HASH_SHA384`, or `HASH_SHA512`). Defaults to `HASH_SHA256`. + +### Error Codes + +| Code | Name | Description | +|------|------|-------------| +| 0 | UPDATE_ERROR_OK | No error | +| 1 | UPDATE_ERROR_WRITE | Flash write failed | +| 2 | UPDATE_ERROR_ERASE | Flash erase failed | +| 3 | UPDATE_ERROR_READ | Flash read failed | +| 4 | UPDATE_ERROR_SPACE | Not enough space | +| 5 | UPDATE_ERROR_SIZE | Bad size given | +| 6 | UPDATE_ERROR_STREAM | Stream read timeout | +| 7 | UPDATE_ERROR_MD5 | MD5 check failed | +| 8 | UPDATE_ERROR_MAGIC_BYTE | Wrong magic byte | +| 9 | UPDATE_ERROR_ACTIVATE | Could not activate firmware | +| 10 | UPDATE_ERROR_NO_PARTITION | Partition not found | +| 11 | UPDATE_ERROR_BAD_ARGUMENT | Bad argument | +| 12 | UPDATE_ERROR_ABORT | Aborted | +| 13 | UPDATE_ERROR_DECRYPT | Decryption error | +| 14 | UPDATE_ERROR_SIGN | Signature verification failed | + +## Examples + +- **Signed_OTA_Update**: Demonstrates signed OTA updates with RSA/ECDSA +- **HTTPS_OTA_Update**: HTTPS OTA update +- **HTTP_Client_AES_OTA_Update**: Encrypted OTA update +- **SD_Update**: Update from SD card + +See the `examples/` directory for complete examples. + +## Tools + +### bin_signing.py + +Python script for key generation and firmware signing. Located in `/tools/bin_signing.py`. + +**Requirements:** +```bash +pip install cryptography +``` + +**Usage:** +```bash +# Generate keys +python /tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem +python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem + +# Sign firmware (defaults to SHA-256) +python /tools/bin_signing.py --bin firmware.bin --key private_key.pem --out firmware_signed.bin + +# Sign firmware with SHA-384 +python /tools/bin_signing.py --bin firmware.bin --key private_key.pem --out firmware_signed.bin --hash sha384 + +# Verify signature +python /tools/bin_signing.py --verify firmware_signed.bin --pubkey public_key.pem +``` + +See `/tools/bin_signing.py --help` for more options. + +## Troubleshooting + +### "Signature verification failed" + +- Ensure firmware was signed with correct private key +- Verify public key in sketch matches private key +- Check signature scheme and hash algorithm match +- Verify signed binary wasn't corrupted + +### "Failed to install signature verification" + +- Call `installSignature()` before `Update.begin()` +- Ensure hash and sign objects are properly initialized + +### "Update failed" with no specific error + +- Check firmware size is correct (including signature) +- Ensure enough space in target partition +- Verify magic byte (0xE9) at start of firmware + +### Memory Issues + +- Signature verification requires ~2KB of heap +- RSA-4096 uses more memory than ECDSA-P256 +- Ensure sufficient free heap before starting update + +## Compile-Time Options + +The Update library supports compile-time configuration to reduce code size if certain features are not needed: + +### UPDATE_SIGN + +Enable signature verification support (disabled by default). + +Add to your project's `build_opt.h`: +``` +-DUPDATE_SIGN +``` + +Or add to your build flags in `platformio.ini`: +```ini +build_flags = -DUPDATE_SIGN +``` + +**Effects:** +- Enables signature verification classes and methods +- Adds RSA and ECDSA signature verification support +- `installSignature()` method becomes available +- Increases code size due to mbedtls cryptographic functions + +### UPDATE_NOCRYPT + +Disable encryption/decryption support: + +```cpp +#define UPDATE_NOCRYPT +#include +``` + +**Effects:** +- Removes AES encryption support +- Reduces code size +- `setupCrypt()` and related methods will not be available + +**Note:** To enable signature verification while disabling encryption, add to `build_opt.h`: +``` +-DUPDATE_SIGN +-DUPDATE_NOCRYPT +``` + +## License + +This library is part of the Arduino-ESP32 project and is licensed under the Apache License 2.0. + +## Contributing + +Contributions are welcome! Please submit issues and pull requests on GitHub: +https://github.com/espressif/arduino-esp32 + +## Support + +- Documentation: https://docs.espressif.com/ +- Forum: https://esp32.com/ +- GitHub Issues: https://github.com/espressif/arduino-esp32/issues diff --git a/libraries/Update/examples/Signed_OTA_Update/README.md b/libraries/Update/examples/Signed_OTA_Update/README.md new file mode 100644 index 00000000000..be449f492d4 --- /dev/null +++ b/libraries/Update/examples/Signed_OTA_Update/README.md @@ -0,0 +1,202 @@ +# Signed OTA Update Example + +This example demonstrates how to perform secure OTA (Over-The-Air) updates with signature verification on ESP32 devices using Arduino. + +## Overview + +Code signing ensures that only firmware signed with your private key will be accepted by your devices. This protects against unauthorized firmware updates, even if an attacker gains access to your update server. + +## Features + +- **RSA Signature Verification**: Supports RSA-2048, RSA-3072, and RSA-4096 +- **ECDSA Signature Verification**: Supports ECDSA-P256 and ECDSA-P384 +- **Multiple Hash Algorithms**: SHA-256, SHA-384, and SHA-512 +- **Automatic Signature Verification**: Signatures are verified automatically during OTA update +- **Secure by Default**: Update fails if signature verification fails + +## Prerequisites + +1. **Python 3** with the `cryptography` package: + ```bash + pip install cryptography + ``` + +2. **ESP32 Arduino Core** with Update library + +## Quick Start Guide + +### Step 1: Generate Key Pair + +Generate an RSA-2048 key pair (recommended): +```bash +python /tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem +python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +``` + +Or generate an ECDSA-P256 key pair (smaller, faster): +```bash +python /tools/bin_signing.py --generate-key ecdsa-p256 --out private_key.pem +python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +``` + +Where `` is your ESP32 Arduino installation path (e.g., `~/Arduino/hardware/espressif/esp32/`). + +**IMPORTANT**: Keep `private_key.pem` secure! Anyone with access to it can sign firmware for your devices. + +### Step 2: Update the Example Sketch + +1. Copy the generated `public_key.h` to the example directory +2. Open `Signed_OTA_Update.ino` +3. Update Wi-Fi credentials: + ```cpp + const char *ssid = "YOUR_SSID"; + const char *password = "YOUR_PASSWORD"; + ``` +4. Update firmware URL: + ```cpp + const char *firmwareUrl = "http://your-server.com/firmware_signed.bin"; + ``` +5. Uncomment the appropriate key type (RSA or ECDSA) +6. Uncomment the appropriate hash algorithm (SHA-256, SHA-384, or SHA-512) + +### Step 3: Build and Upload Initial Firmware + +1. Compile and upload the sketch to your ESP32 +2. Open Serial Monitor to verify it's running + +### Step 4: Build and Sign New Firmware + +1. Make changes to your sketch (e.g., add a version number) +2. Build the sketch and export the binary: + - Arduino IDE: `Sketch` → `Export Compiled Binary` + - Find the application `.bin` file in the `build` folder of your sketch folder. For example `build/espressif.esp32.esp32c6/Signed_OTA_Update.ino.bin`. + +3. Sign the binary: + ```bash + python /tools/bin_signing.py --bin --key private_key.pem --out firmware_signed.bin + ``` + + For other hash algorithms (for example SHA-384): + ```bash + python /tools/bin_signing.py --bin --key private_key.pem --out firmware_signed.bin --hash sha384 + ``` + +### Step 5: Host the Signed Firmware + +Upload `firmware_signed.bin` to your web server and make it accessible at the URL you configured. + +### Step 6: Perform OTA Update + +Reset your ESP32. It will: +1. Connect to Wi-Fi +2. Download the signed firmware +3. Verify the signature +4. Apply the update if signature is valid +5. Reboot with the new firmware + +## Security Considerations + +### Private Key Management + +- **NEVER** commit your private key to version control +- Store it securely (encrypted storage, HSM, etc.) +- Limit access to authorized personnel only +- Consider using separate keys for development and production + +### Recommended Practices + +1. **Use HTTPS**: While signature verification protects firmware integrity, HTTPS protects against MitM attacks +2. **Key Rotation**: Periodically rotate keys (requires firmware update to include new public key) + +## Signature Schemes Comparison + +| Scheme | Key Size | Signature Size | Verification Speed | Security | +|--------|----------|----------------|-------------------|----------| +| RSA-2048 | 2048 bits | 256 bytes | Medium | High | +| RSA-3072 | 3072 bits | 384 bytes | Slower | Very High | +| RSA-4096 | 4096 bits | 512 bytes | Slowest | Maximum | +| ECDSA-P256 | 256 bits | 64 bytes | Fast | High | +| ECDSA-P384 | 384 bits | 96 bytes | Fast | Very High | + +**Recommendation**: RSA-2048 or ECDSA-P256 provide good security with reasonable performance. + +## Hash Algorithms Comparison + +| Algorithm | Output Size | Speed | Security | +|-----------|-------------|-------|----------| +| SHA-256 | 32 bytes | Fast | High | +| SHA-384 | 48 bytes | Medium | Very High | +| SHA-512 | 64 bytes | Medium | Very High | + +**Recommendation**: SHA-256 is sufficient for most applications. + +## Troubleshooting + +### "Signature verification failed" + +- Ensure the firmware was signed with the correct private key +- Verify that the public key in the sketch matches the private key used for signing +- Check that the signature scheme (RSA/ECDSA) and hash algorithm match between signing and verification +- Ensure the signed binary wasn't corrupted during transfer + +### "Failed to install signature verification" + +- Check that `installSignature()` is called before `Update.begin()` +- Ensure hash and sign objects are properly initialized + +### "Public key parsing failed" + +- Verify the public key PEM format is correct +- Ensure PUBLIC_KEY_LEN matches the actual key length + +## Advanced Usage + +### Verifying a Signed Binary + +You can verify a signed binary without flashing it: + +```bash +python bin_signing.py --verify firmware_signed.bin --pubkey public_key.pem +``` + +### Using Different Hash Algorithms + +Match the hash algorithm between signing and verification: + +**Signing with SHA-384:** +```bash +python bin_signing.py --bin firmware.bin --key private_key.pem --out firmware_signed.bin --hash sha384 +``` + +**Sketch configuration:** +```cpp +#define USE_SHA384 +``` + +## API Reference + +### Classes + +- **UpdaterRSAVerifier**: RSA signature verifier +- **UpdaterECDSAVerifier**: ECDSA signature verifier + +### Methods + +```cpp +// Install signature verification (call before Update.begin()) +bool Update.installSignature(UpdaterVerifyClass *sign); +``` + +### Error Codes + +- `UPDATE_ERROR_SIGN (14)`: Signature verification failed + +## License + +This example is part of the Arduino-ESP32 project and is licensed under the Apache License 2.0. + +## Support + +For issues and questions: +- GitHub: https://github.com/espressif/arduino-esp32/issues +- Documentation: https://docs.espressif.com/ diff --git a/libraries/Update/examples/Signed_OTA_Update/Signed_OTA_Update.ino b/libraries/Update/examples/Signed_OTA_Update/Signed_OTA_Update.ino new file mode 100644 index 00000000000..1690d024bfb --- /dev/null +++ b/libraries/Update/examples/Signed_OTA_Update/Signed_OTA_Update.ino @@ -0,0 +1,231 @@ +/* + Signed OTA Update Example + + This example demonstrates how to perform a secure OTA update with signature verification. + Only firmware signed with the correct private key will be accepted. + + NOTE: This example requires signature verification support to be enabled. + This is done automatically via the build_opt.h file in this directory. + + Steps to use this example: + 1. Generate a key pair (see instructions below) + 2. Include the public key in this sketch (see public_key.h) + 3. Build and upload this sketch to your ESP32 + 4. Build your new firmware binary + 5. Sign the binary with the private key (see instructions below) + 6. Upload the signed firmware via OTA (HTTP/HTTPS server) + + Generating keys: + ------------------ + RSA (recommended for maximum compatibility): + python bin_signing.py --generate-key rsa-2048 --out private_key.pem + python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem + + ECDSA (smaller keys, faster verification): + python bin_signing.py --generate-key ecdsa-p256 --out private_key.pem + python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem + + Signing firmware: + ----------------- + python bin_signing.py --bin firmware.bin --key private_key.pem --out firmware_signed.bin + + IMPORTANT: Keep your private_key.pem secure! Anyone with access to it can + sign firmware that will be accepted by your devices. + + Created by lucasssvaz +*/ + +#include +#include +#include +#include + +// WiFi credentials +const char *ssid = "YOUR_SSID"; +const char *password = "YOUR_PASSWORD"; + +// URL to the signed firmware binary +const char *firmwareUrl = "http://your-server.com/firmware_signed.bin"; + +// Public key for signature verification +// Generated with: python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +// This will create a public_key.h file that you should include below +#include "public_key.h" + +// Uncomment the key type you're using: +#define USE_RSA // RSA signature verification +//#define USE_ECDSA // ECDSA signature verification + +// Uncomment the hash algorithm you're using (must match the one used for signing): +#define USE_SHA256 // SHA-256 (recommended and default) +//#define USE_SHA384 // SHA-384 +//#define USE_SHA512 // SHA-512 + +void performOTAUpdate() { + HTTPClient http; + + Serial.println("Starting OTA update..."); + Serial.print("Firmware URL: "); + Serial.println(firmwareUrl); + + http.begin(firmwareUrl); + int httpCode = http.GET(); + + if (httpCode != HTTP_CODE_OK) { + Serial.printf("HTTP GET failed, error: %s\n", http.errorToString(httpCode).c_str()); + http.end(); + return; + } + + int contentLength = http.getSize(); + Serial.printf("Firmware size: %d bytes\n", contentLength); + + if (contentLength <= 0) { + Serial.println("Invalid content length"); + http.end(); + return; + } + + // The signed firmware includes the signature (512 bytes padding) + // The actual firmware size is contentLength - 512 + const size_t signatureSize = 512; + size_t firmwareSize = contentLength - signatureSize; + + Serial.printf("Actual firmware size: %d bytes\n", firmwareSize); + Serial.printf("Signature size: %d bytes\n", signatureSize); + + // Select hash algorithm +#ifdef USE_SHA256 + int hashType = HASH_SHA256; + Serial.println("Using SHA-256 hash"); +#elif defined(USE_SHA384) + int hashType = HASH_SHA384; + Serial.println("Using SHA-384 hash"); +#elif defined(USE_SHA512) + int hashType = HASH_SHA512; + Serial.println("Using SHA-512 hash"); +#else +#error "Please define a hash algorithm (USE_SHA256, USE_SHA384, or USE_SHA512)" +#endif + + // Create verifier object +#ifdef USE_RSA + UpdaterRSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType); + Serial.println("Using RSA signature verification"); +#elif defined(USE_ECDSA) + UpdaterECDSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType); + Serial.println("Using ECDSA signature verification"); +#else +#error "Please define a signature scheme (USE_RSA or USE_ECDSA)" +#endif + + // Install signature verification BEFORE calling Update.begin() + if (!Update.installSignature(&sign)) { + Serial.println("Failed to install signature verification"); + http.end(); + return; + } + Serial.println("Signature verification installed"); + + // Begin update with the TOTAL size (firmware + signature) + if (!Update.begin(contentLength)) { + Serial.printf("Update.begin failed: %s\n", Update.errorString()); + http.end(); + return; + } + + // Get the stream + WiFiClient *stream = http.getStreamPtr(); + + // Write firmware data + Serial.println("Writing firmware..."); + size_t written = 0; + uint8_t buff[1024]; + int progress = 0; + + while (http.connected() && (written < contentLength)) { + size_t available = stream->available(); + + if (available) { + int bytesRead = stream->readBytes(buff, min(available, sizeof(buff))); + + if (bytesRead > 0) { + size_t bytesWritten = Update.write(buff, bytesRead); + + if (bytesWritten > 0) { + written += bytesWritten; + + // Print progress + int newProgress = (written * 100) / contentLength; + if (newProgress != progress && newProgress % 10 == 0) { + progress = newProgress; + Serial.printf("Progress: %d%%\n", progress); + } + } else { + Serial.printf("Update.write failed: %s\n", Update.errorString()); + break; + } + } + } + delay(1); + } + + Serial.printf("Written: %d bytes\n", written); + + // End the update - this will verify the signature + if (Update.end()) { + Serial.println("OTA update completed successfully!"); + Serial.println("Signature verified!"); + + if (Update.isFinished()) { + Serial.println("Update successfully completed. Rebooting..."); + delay(1000); + ESP.restart(); + } else { + Serial.println("Update not finished? Something went wrong!"); + } + } else { + Serial.printf("Update.end failed: %s\n", Update.errorString()); + + // Check if it was a signature verification failure + if (Update.getError() == UPDATE_ERROR_SIGN) { + Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Serial.println("SIGNATURE VERIFICATION FAILED!"); + Serial.println("The firmware was not signed with the"); + Serial.println("correct private key or is corrupted."); + Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + } + + http.end(); +} + +void setup() { + Serial.begin(115200); + Serial.println("\n\nSigned OTA Update Example"); + Serial.println("=========================\n"); + + // Connect to WiFi + Serial.printf("Connecting to WiFi: %s\n", ssid); + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println("\nWiFi connected!"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Wait a bit before starting OTA + delay(2000); + + // Perform OTA update + performOTAUpdate(); +} + +void loop() { + // Nothing to do here + delay(1000); +} diff --git a/libraries/Update/examples/Signed_OTA_Update/build_opt.h b/libraries/Update/examples/Signed_OTA_Update/build_opt.h new file mode 100644 index 00000000000..1b328fa2487 --- /dev/null +++ b/libraries/Update/examples/Signed_OTA_Update/build_opt.h @@ -0,0 +1 @@ +-DUPDATE_SIGN diff --git a/libraries/Update/examples/Signed_OTA_Update/ci.yml b/libraries/Update/examples/Signed_OTA_Update/ci.yml new file mode 100644 index 00000000000..006e6e07dda --- /dev/null +++ b/libraries/Update/examples/Signed_OTA_Update/ci.yml @@ -0,0 +1,3 @@ +requires_any: + - CONFIG_SOC_WIFI_SUPPORTED=y + - CONFIG_ESP_WIFI_REMOTE_ENABLED=y diff --git a/libraries/Update/examples/Signed_OTA_Update/public_key.h b/libraries/Update/examples/Signed_OTA_Update/public_key.h new file mode 100644 index 00000000000..90ff6507a1e --- /dev/null +++ b/libraries/Update/examples/Signed_OTA_Update/public_key.h @@ -0,0 +1,32 @@ +// Public key for OTA signature verification +// Include this in your Arduino sketch + +// ⚠️ THIS IS A TEST KEY - DO NOT USE IN PRODUCTION! +// Generate your own keys using: +// python /tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem +// python /tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +// +// Then replace this file with the generated public_key.h + +// Test RSA-2048 Public Key (PEM format) +const uint8_t PUBLIC_KEY[] PROGMEM = { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x42, 0x49, 0x6a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, + 0x41, 0x4f, 0x43, 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49, 0x49, 0x42, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, 0x36, 0x42, 0x33, 0x52, 0x67, 0x34, 0x39, + 0x6b, 0x4e, 0x47, 0x72, 0x44, 0x2b, 0x50, 0x46, 0x6e, 0x39, 0x64, 0x69, 0x4b, 0x0a, 0x57, 0x50, 0x34, 0x65, 0x42, 0x59, 0x4d, 0x2f, 0x49, 0x79, 0x6b, 0x55, + 0x4b, 0x4d, 0x34, 0x39, 0x63, 0x6a, 0x65, 0x56, 0x56, 0x4f, 0x39, 0x42, 0x4f, 0x30, 0x66, 0x6c, 0x47, 0x47, 0x6e, 0x47, 0x71, 0x79, 0x34, 0x50, 0x72, 0x69, + 0x4e, 0x71, 0x32, 0x62, 0x4a, 0x4a, 0x6a, 0x7a, 0x68, 0x38, 0x46, 0x32, 0x42, 0x53, 0x4f, 0x75, 0x74, 0x48, 0x77, 0x75, 0x7a, 0x6d, 0x62, 0x45, 0x52, 0x6f, + 0x0a, 0x30, 0x38, 0x51, 0x72, 0x32, 0x30, 0x4e, 0x61, 0x52, 0x72, 0x7a, 0x6e, 0x71, 0x6e, 0x59, 0x4e, 0x57, 0x4e, 0x69, 0x6e, 0x43, 0x67, 0x7a, 0x34, 0x34, + 0x49, 0x4e, 0x50, 0x50, 0x78, 0x70, 0x45, 0x55, 0x65, 0x68, 0x61, 0x32, 0x66, 0x6d, 0x6d, 0x39, 0x77, 0x5a, 0x67, 0x57, 0x31, 0x69, 0x31, 0x67, 0x31, 0x77, + 0x70, 0x68, 0x56, 0x51, 0x6c, 0x5a, 0x30, 0x49, 0x63, 0x72, 0x6d, 0x5a, 0x5a, 0x0a, 0x42, 0x61, 0x33, 0x49, 0x64, 0x6a, 0x78, 0x63, 0x52, 0x67, 0x51, 0x6c, + 0x69, 0x32, 0x4b, 0x74, 0x78, 0x72, 0x41, 0x4a, 0x67, 0x33, 0x4a, 0x47, 0x43, 0x54, 0x2f, 0x39, 0x6d, 0x7a, 0x52, 0x31, 0x70, 0x37, 0x59, 0x34, 0x50, 0x34, + 0x65, 0x71, 0x30, 0x6b, 0x2b, 0x78, 0x2b, 0x45, 0x72, 0x6f, 0x35, 0x73, 0x47, 0x69, 0x49, 0x7a, 0x33, 0x44, 0x67, 0x61, 0x50, 0x43, 0x54, 0x41, 0x37, 0x52, + 0x0a, 0x4b, 0x69, 0x75, 0x6e, 0x2f, 0x67, 0x64, 0x56, 0x71, 0x34, 0x35, 0x2f, 0x75, 0x62, 0x64, 0x53, 0x58, 0x65, 0x62, 0x50, 0x46, 0x43, 0x73, 0x36, 0x66, + 0x46, 0x73, 0x52, 0x39, 0x6d, 0x43, 0x6f, 0x37, 0x70, 0x43, 0x4b, 0x74, 0x45, 0x55, 0x51, 0x78, 0x34, 0x4d, 0x68, 0x55, 0x4e, 0x5a, 0x48, 0x48, 0x31, 0x49, + 0x33, 0x62, 0x79, 0x57, 0x35, 0x7a, 0x39, 0x36, 0x49, 0x6a, 0x46, 0x44, 0x68, 0x0a, 0x54, 0x2f, 0x64, 0x5a, 0x71, 0x32, 0x6d, 0x44, 0x54, 0x64, 0x76, 0x59, + 0x2b, 0x6d, 0x5a, 0x75, 0x51, 0x4d, 0x37, 0x6c, 0x72, 0x31, 0x4d, 0x4e, 0x6a, 0x35, 0x36, 0x79, 0x74, 0x41, 0x56, 0x4a, 0x39, 0x56, 0x7a, 0x74, 0x44, 0x75, + 0x35, 0x4f, 0x6a, 0x48, 0x32, 0x76, 0x6f, 0x32, 0x6b, 0x59, 0x46, 0x4f, 0x72, 0x52, 0x49, 0x57, 0x70, 0x5a, 0x4c, 0x56, 0x35, 0x6c, 0x47, 0x79, 0x7a, 0x45, + 0x0a, 0x33, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, 0x42, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, + 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, +}; +const size_t PUBLIC_KEY_LEN = 452; diff --git a/libraries/Update/keywords.txt b/libraries/Update/keywords.txt index 53544dbaf6c..5ddd5d46c91 100644 --- a/libraries/Update/keywords.txt +++ b/libraries/Update/keywords.txt @@ -1,5 +1,5 @@ ####################################### -# Syntax Coloring Map For Ultrasound +# Syntax Coloring Map For Update ####################################### ####################################### @@ -7,6 +7,9 @@ ####################################### Update KEYWORD1 +UpdaterVerifyClass KEYWORD1 +UpdaterRSAVerifier KEYWORD1 +UpdaterECDSAVerifier KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -17,7 +20,44 @@ end KEYWORD2 write KEYWORD2 writeStream KEYWORD2 printError KEYWORD2 +installSignature KEYWORD2 +setMD5 KEYWORD2 +md5String KEYWORD2 +canRollBack KEYWORD2 +rollBack KEYWORD2 +onProgress KEYWORD2 +abort KEYWORD2 +setupCrypt KEYWORD2 +setCryptKey KEYWORD2 +setCryptMode KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### + +UPDATE_ERROR_OK LITERAL1 +UPDATE_ERROR_WRITE LITERAL1 +UPDATE_ERROR_ERASE LITERAL1 +UPDATE_ERROR_READ LITERAL1 +UPDATE_ERROR_SPACE LITERAL1 +UPDATE_ERROR_SIZE LITERAL1 +UPDATE_ERROR_STREAM LITERAL1 +UPDATE_ERROR_MD5 LITERAL1 +UPDATE_ERROR_MAGIC_BYTE LITERAL1 +UPDATE_ERROR_ACTIVATE LITERAL1 +UPDATE_ERROR_NO_PARTITION LITERAL1 +UPDATE_ERROR_BAD_ARGUMENT LITERAL1 +UPDATE_ERROR_ABORT LITERAL1 +UPDATE_ERROR_DECRYPT LITERAL1 +UPDATE_ERROR_SIGN LITERAL1 +U_FLASH LITERAL1 +U_FLASHFS LITERAL1 +U_SPIFFS LITERAL1 +U_FATFS LITERAL1 +U_LITTLEFS LITERAL1 +SIGN_NONE LITERAL1 +SIGN_RSA LITERAL1 +SIGN_ECDSA LITERAL1 +HASH_SHA256 LITERAL1 +HASH_SHA384 LITERAL1 +HASH_SHA512 LITERAL1 diff --git a/libraries/Update/library.properties b/libraries/Update/library.properties index e1b77c462b1..69e2f5e86ae 100644 --- a/libraries/Update/library.properties +++ b/libraries/Update/library.properties @@ -1,5 +1,5 @@ name=Update -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=ESP32 Sketch Update Library diff --git a/libraries/Update/src/Update.h b/libraries/Update/src/Update.h index 5f52e6b3b73..86a1a5f1a26 100644 --- a/libraries/Update/src/Update.h +++ b/libraries/Update/src/Update.h @@ -11,6 +11,9 @@ #include #include #include "esp_partition.h" +#ifdef UPDATE_SIGN +#include "Updater_Signing.h" +#endif /* UPDATE_SIGN */ #define UPDATE_ERROR_OK (0) #define UPDATE_ERROR_WRITE (1) @@ -26,6 +29,7 @@ #define UPDATE_ERROR_BAD_ARGUMENT (11) #define UPDATE_ERROR_ABORT (12) #define UPDATE_ERROR_DECRYPT (13) +#define UPDATE_ERROR_SIGN (14) #define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF @@ -168,6 +172,16 @@ class UpdateClass { return _md5.getBytes(result); } +#ifdef UPDATE_SIGN + /* + Install signature verification for the update + Call this before begin() to enable signature verification + sign: Signature verifier to use (e.g., UpdaterRSAVerifier or UpdaterECDSAVerifier) + The hash type is determined from the verifier's configuration + */ + bool installSignature(UpdaterVerifyClass *sign); +#endif /* UPDATE_SIGN */ + //Helpers uint8_t getError() { return _error; @@ -287,6 +301,14 @@ class UpdateClass { size_t _cryptAddress; uint8_t _cryptCfg; #endif /* UPDATE_NOCRYPT */ + +#ifdef UPDATE_SIGN + SHA2Builder *_hash; + UpdaterVerifyClass *_sign; + uint8_t *_signatureBuffer; + size_t _signatureSize; + int _hashType; +#endif /* UPDATE_SIGN */ }; #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_UPDATE) diff --git a/libraries/Update/src/Updater.cpp b/libraries/Update/src/Updater.cpp index 3d3569f019e..607502069aa 100644 --- a/libraries/Update/src/Updater.cpp +++ b/libraries/Update/src/Updater.cpp @@ -44,6 +44,10 @@ static const char *_err2str(uint8_t _error) { } else if (_error == UPDATE_ERROR_DECRYPT) { return ("Decryption error"); #endif /* UPDATE_NOCRYPT */ +#ifdef UPDATE_SIGN + } else if (_error == UPDATE_ERROR_SIGN) { + return ("Signature Verification Failed"); +#endif /* UPDATE_SIGN */ } return ("UNKNOWN"); } @@ -80,6 +84,10 @@ UpdateClass::UpdateClass() , _cryptMode(U_AES_DECRYPT_AUTO), _cryptAddress(0), _cryptCfg(0xf) #endif /* UPDATE_NOCRYPT */ +#ifdef UPDATE_SIGN + , + _hash(NULL), _sign(NULL), _signatureBuffer(NULL), _signatureSize(0), _hashType(-1) +#endif /* UPDATE_SIGN */ { } @@ -95,6 +103,17 @@ void UpdateClass::_reset() { if (_skipBuffer) { delete[] _skipBuffer; } +#ifdef UPDATE_SIGN + if (_signatureBuffer) { + delete[] _signatureBuffer; + _signatureBuffer = nullptr; + } + if (_hash && _hashType >= 0) { + // Clean up internally-created hash object + delete _hash; + _hash = nullptr; + } +#endif /* UPDATE_SIGN */ #ifndef UPDATE_NOCRYPT _cryptBuffer = nullptr; @@ -105,6 +124,9 @@ void UpdateClass::_reset() { _progress = 0; _size = 0; _command = U_FLASH; +#ifdef UPDATE_SIGN + _signatureSize = 0; +#endif /* UPDATE_SIGN */ if (_ledPin != -1) { digitalWrite(_ledPin, !_ledOn); // off @@ -127,6 +149,36 @@ bool UpdateClass::rollBack() { return _partitionIsBootable(partition) && !esp_ota_set_boot_partition(partition); } +#ifdef UPDATE_SIGN +bool UpdateClass::installSignature(UpdaterVerifyClass *sign) { + if (_size > 0) { + log_w("Update already running"); + return false; + } + if (!sign) { + log_e("Invalid verifier"); + return false; + } + + int hashType = sign->getHashType(); + if (hashType != HASH_SHA256 && hashType != HASH_SHA384 && hashType != HASH_SHA512) { + log_e("Invalid hash type: %d", hashType); + return false; + } + + _sign = sign; + _hashType = hashType; + _signatureSize = 512; // Fixed signature size (padded to 512 bytes) + + [[maybe_unused]] + const char *hashName = (hashType == HASH_SHA256) ? "SHA-256" + : (hashType == HASH_SHA384) ? "SHA-384" + : "SHA-512"; + log_i("Signature verification installed (hash: %s, signature size: %u bytes)", hashName, _signatureSize); + return true; +} +#endif /* UPDATE_SIGN */ + bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn, const char *label) { (void)label; @@ -143,11 +195,41 @@ bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn, con _target_md5 = emptyString; _md5 = MD5Builder(); +#ifdef UPDATE_SIGN + // Create and initialize signature hash if signature verification is enabled + if (_sign && _hashType >= 0) { + // Create the appropriate hash builder based on hashType + switch (_hashType) { + case HASH_SHA256: _hash = new SHA256Builder(); break; + case HASH_SHA384: _hash = new SHA384Builder(); break; + case HASH_SHA512: _hash = new SHA512Builder(); break; + default: log_e("Invalid hash type"); return false; + } + + if (_hash) { + _hash->begin(); + log_i("Signature hash initialized"); + } else { + log_e("Failed to create hash builder"); + return false; + } + } +#endif /* UPDATE_SIGN */ + if (size == 0) { _error = UPDATE_ERROR_SIZE; return false; } +#ifdef UPDATE_SIGN + // Validate size is large enough to contain firmware + signature + if (_signatureSize > 0 && size < _signatureSize) { + _error = UPDATE_ERROR_SIZE; + log_e("Size too small for signature: %u < %u", size, _signatureSize); + return false; + } +#endif /* UPDATE_SIGN */ + if (command == U_FLASH) { _partition = esp_ota_get_next_update_partition(NULL); if (!_partition) { @@ -462,6 +544,23 @@ bool UpdateClass::_writeBuffer() { #ifndef UPDATE_NOCRYPT } #endif /* UPDATE_NOCRYPT */ + +#ifdef UPDATE_SIGN + // Add data to signature hash if signature verification is enabled + // Only hash firmware bytes, not the signature bytes at the end + if (_hash && _signatureSize > 0) { + size_t firmwareSize = _size - _signatureSize; + if (_progress < firmwareSize) { + // Calculate how many bytes of this buffer are firmware (not signature) + size_t bytesToHash = _bufferLen; + if (_progress + _bufferLen > firmwareSize) { + bytesToHash = firmwareSize - _progress; + } + _hash->add(_buffer, bytesToHash); + } + } +#endif /* UPDATE_SIGN */ + _progress += _bufferLen; _bufferLen = 0; if (_progress_callback) { @@ -547,6 +646,41 @@ bool UpdateClass::end(bool evenIfRemaining) { } } +#ifdef UPDATE_SIGN + // Verify signature if signature verification is enabled + if (_hash && _sign && _signatureSize > 0) { + log_i("Verifying signature..."); + _hash->calculate(); + + // Allocate buffer for signature (max 512 bytes for RSA-4096) + const size_t maxSigSize = 512; + _signatureBuffer = new (std::nothrow) uint8_t[maxSigSize]; + if (!_signatureBuffer) { + log_e("Failed to allocate signature buffer"); + _abort(UPDATE_ERROR_SIGN); + return false; + } + + // Read signature from partition (last 512 bytes of what was written) + size_t firmwareSize = _size - _signatureSize; + log_d("Reading signature from offset %u (firmware size: %u, total size: %u)", firmwareSize, firmwareSize, _size); + if (!ESP.partitionRead(_partition, firmwareSize, (uint32_t *)_signatureBuffer, maxSigSize)) { + log_e("Failed to read signature from partition"); + _abort(UPDATE_ERROR_SIGN); + return false; + } + + // Verify the signature + if (!_sign->verify(_hash, _signatureBuffer, maxSigSize)) { + log_e("Signature verification failed"); + _abort(UPDATE_ERROR_SIGN); + return false; + } + + log_i("Signature verified successfully"); + } +#endif /* UPDATE_SIGN */ + return _verifyEnd(); } diff --git a/libraries/Update/src/Updater_Signing.cpp b/libraries/Update/src/Updater_Signing.cpp new file mode 100644 index 00000000000..3332fe11942 --- /dev/null +++ b/libraries/Update/src/Updater_Signing.cpp @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef UPDATE_SIGN + +#include "Updater_Signing.h" +#include "mbedtls/pk.h" +#include "mbedtls/rsa.h" +#include "mbedtls/ecdsa.h" +#include "mbedtls/ecp.h" +#include "mbedtls/md.h" +#include "esp32-hal-log.h" + +// ==================== UpdaterRSAVerifier (using mbedtls) ==================== + +UpdaterRSAVerifier::UpdaterRSAVerifier(const uint8_t *pubkey, size_t pubkeyLen, int hashType) : _hashType(hashType), _valid(false) { + _ctx = new mbedtls_pk_context; + mbedtls_pk_init((mbedtls_pk_context *)_ctx); + + // Try to parse the public key + int ret = mbedtls_pk_parse_public_key((mbedtls_pk_context *)_ctx, pubkey, pubkeyLen); + if (ret != 0) { + log_e("Failed to parse RSA public key: -0x%04X", -ret); + return; + } + + // Verify it's an RSA key + if (mbedtls_pk_get_type((mbedtls_pk_context *)_ctx) != MBEDTLS_PK_RSA) { + log_e("Public key is not RSA"); + return; + } + + _valid = true; + log_i("RSA public key loaded successfully"); +} + +UpdaterRSAVerifier::~UpdaterRSAVerifier() { + if (_ctx) { + mbedtls_pk_free((mbedtls_pk_context *)_ctx); + delete (mbedtls_pk_context *)_ctx; + _ctx = nullptr; + } +} + +bool UpdaterRSAVerifier::verify(SHA2Builder *hash, const void *signature, size_t signatureLen) { + if (!_valid || !hash) { + log_e("Invalid RSA verifier or hash"); + return false; + } + + mbedtls_md_type_t md_type; + switch (_hashType) { + case HASH_SHA256: md_type = MBEDTLS_MD_SHA256; break; + case HASH_SHA384: md_type = MBEDTLS_MD_SHA384; break; + case HASH_SHA512: md_type = MBEDTLS_MD_SHA512; break; + default: log_e("Invalid hash type"); return false; + } + + // Get hash bytes from the builder + uint8_t hashBytes[64]; // Max hash size (SHA-512) + hash->getBytes(hashBytes); + + int ret = mbedtls_pk_verify((mbedtls_pk_context *)_ctx, md_type, hashBytes, hash->getHashSize(), (const unsigned char *)signature, signatureLen); + + if (ret == 0) { + log_i("RSA signature verified successfully"); + return true; + } else { + log_e("RSA signature verification failed: -0x%04X", -ret); + return false; + } +} + +// ==================== UpdaterECDSAVerifier (using mbedtls) ==================== + +UpdaterECDSAVerifier::UpdaterECDSAVerifier(const uint8_t *pubkey, size_t pubkeyLen, int hashType) : _hashType(hashType), _valid(false) { + _ctx = new mbedtls_pk_context; + mbedtls_pk_init((mbedtls_pk_context *)_ctx); + + // Try to parse the public key + int ret = mbedtls_pk_parse_public_key((mbedtls_pk_context *)_ctx, pubkey, pubkeyLen); + if (ret != 0) { + log_e("Failed to parse ECDSA public key: -0x%04X", -ret); + return; + } + + // Verify it's an ECDSA key + mbedtls_pk_type_t type = mbedtls_pk_get_type((mbedtls_pk_context *)_ctx); + if (type != MBEDTLS_PK_ECKEY && type != MBEDTLS_PK_ECDSA) { + log_e("Public key is not ECDSA"); + return; + } + + _valid = true; + log_i("ECDSA public key loaded successfully"); +} + +UpdaterECDSAVerifier::~UpdaterECDSAVerifier() { + if (_ctx) { + mbedtls_pk_free((mbedtls_pk_context *)_ctx); + delete (mbedtls_pk_context *)_ctx; + _ctx = nullptr; + } +} + +bool UpdaterECDSAVerifier::verify(SHA2Builder *hash, const void *signature, size_t signatureLen) { + if (!_valid || !hash) { + log_e("Invalid ECDSA verifier or hash"); + return false; + } + + mbedtls_md_type_t md_type; + switch (_hashType) { + case HASH_SHA256: md_type = MBEDTLS_MD_SHA256; break; + case HASH_SHA384: md_type = MBEDTLS_MD_SHA384; break; + case HASH_SHA512: md_type = MBEDTLS_MD_SHA512; break; + default: log_e("Invalid hash type"); return false; + } + + // Get hash bytes from the builder + uint8_t hashBytes[64]; // Max hash size (SHA-512) + hash->getBytes(hashBytes); + + int ret = mbedtls_pk_verify((mbedtls_pk_context *)_ctx, md_type, hashBytes, hash->getHashSize(), (const unsigned char *)signature, signatureLen); + + if (ret == 0) { + log_i("ECDSA signature verified successfully"); + return true; + } else { + log_e("ECDSA signature verification failed: -0x%04X", -ret); + return false; + } +} + +#endif // UPDATE_SIGN diff --git a/libraries/Update/src/Updater_Signing.h b/libraries/Update/src/Updater_Signing.h new file mode 100644 index 00000000000..1134a17e5b4 --- /dev/null +++ b/libraries/Update/src/Updater_Signing.h @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#ifdef UPDATE_SIGN + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Signature schemes +#define SIGN_NONE 0 +#define SIGN_RSA 1 +#define SIGN_ECDSA 2 + +// Hash algorithms for signature verification +#define HASH_SHA256 0 +#define HASH_SHA384 1 +#define HASH_SHA512 2 + +// Signature sizes (in bytes) +#define RSA_2048_SIGNATURE_SIZE 256 +#define RSA_3072_SIGNATURE_SIZE 384 +#define RSA_4096_SIGNATURE_SIZE 512 +#define ECDSA_P256_SIGNATURE_SIZE 64 +#define ECDSA_P384_SIGNATURE_SIZE 96 + +// Hash sizes (in bytes) +#define SHA256_SIZE 32 +#define SHA384_SIZE 48 +#define SHA512_SIZE 64 + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +class UpdaterVerifyClass { +public: + virtual bool verify(SHA2Builder *hash, const void *signature, size_t signatureLen) = 0; + virtual int getHashType() const = 0; + virtual ~UpdaterVerifyClass() {} +}; + +// Signature verifiers using mbedtls (required for public key cryptography) +class UpdaterRSAVerifier : public UpdaterVerifyClass { +public: + UpdaterRSAVerifier(const uint8_t *pubkey, size_t pubkeyLen, int hashType = HASH_SHA256); + ~UpdaterRSAVerifier(); + bool verify(SHA2Builder *hash, const void *signature, size_t signatureLen) override; + int getHashType() const override { + return _hashType; + } + +private: + void *_ctx; + int _hashType; + bool _valid; +}; + +class UpdaterECDSAVerifier : public UpdaterVerifyClass { +public: + UpdaterECDSAVerifier(const uint8_t *pubkey, size_t pubkeyLen, int hashType = HASH_SHA256); + ~UpdaterECDSAVerifier(); + bool verify(SHA2Builder *hash, const void *signature, size_t signatureLen) override; + int getHashType() const override { + return _hashType; + } + +private: + void *_ctx; + int _hashType; + bool _valid; +}; + +#endif // __cplusplus + +#endif // UPDATE_SIGN diff --git a/libraries/WebServer/library.properties b/libraries/WebServer/library.properties index 4d491effc14..4cc40fe9540 100644 --- a/libraries/WebServer/library.properties +++ b/libraries/WebServer/library.properties @@ -1,5 +1,5 @@ name=WebServer -version=3.3.4 +version=3.3.5 author=Ivan Grokhotkov maintainer=Ivan Grokhtkov sentence=Simple web server library diff --git a/libraries/WiFi/library.properties b/libraries/WiFi/library.properties index 61e8ddb0ca5..c058bec077a 100644 --- a/libraries/WiFi/library.properties +++ b/libraries/WiFi/library.properties @@ -1,5 +1,5 @@ name=WiFi -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Enables network connection (local and Internet) using the ESP32 built-in WiFi. diff --git a/libraries/WiFiProv/library.properties b/libraries/WiFiProv/library.properties index 0a4aa5f9837..36eca3677f2 100644 --- a/libraries/WiFiProv/library.properties +++ b/libraries/WiFiProv/library.properties @@ -1,5 +1,5 @@ name=WiFiProv -version=3.3.4 +version=3.3.5 author=Switi Mhaiske maintainer=Hristo Gochkov sentence=Enables provisioning. diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties index f016c349b88..4360f64b4f5 100644 --- a/libraries/Wire/library.properties +++ b/libraries/Wire/library.properties @@ -1,5 +1,5 @@ name=Wire -version=3.3.4 +version=3.3.5 author=Hristo Gochkov maintainer=Hristo Gochkov sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For esp8266 boards. diff --git a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino index 54c085fbfea..401c4ab4552 100644 --- a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino +++ b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino @@ -135,6 +135,9 @@ void setup() { // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) zbTempSensor.setMinMaxValue(10, 50); + // Set default (initial) value for the temperature sensor to 10.0°C to match the minimum temperature measurement value (default value is 0.0°C) + zbTempSensor.setDefaultValue(10.0); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) zbTempSensor.setTolerance(1); @@ -142,8 +145,8 @@ void setup() { // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); - // Add humidity cluster to the temperature sensor device with min, max and tolerance values - zbTempSensor.addHumiditySensor(0, 100, 1); + // Add humidity cluster to the temperature sensor device with min, max, tolerance and default values + zbTempSensor.addHumiditySensor(0, 100, 1, 0.0); // Set callback for default response to handle status of reported data, there are 2 options. diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino index ad007abbbaa..e7f4721b47d 100644 --- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino +++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino @@ -68,6 +68,9 @@ void setup() { // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) zbTempSensor.setMinMaxValue(10, 50); + // Optional: Set default (initial) value for the temperature sensor to 10.0°C to match the minimum temperature measurement value + zbTempSensor.setDefaultValue(10.0); + // Optional: Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) zbTempSensor.setTolerance(1); diff --git a/libraries/Zigbee/library.properties b/libraries/Zigbee/library.properties index cb671149723..4c2d00b45ac 100644 --- a/libraries/Zigbee/library.properties +++ b/libraries/Zigbee/library.properties @@ -1,5 +1,5 @@ name=Zigbee -version=3.3.4 +version=3.3.5 author=P-R-O-C-H-Y maintainer=Jan Procházka sentence=Enables zigbee connection with the ESP32 diff --git a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp index 225bb620f0b..711dd1e6879 100644 --- a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp @@ -38,6 +38,19 @@ ZigbeeCarbonDioxideSensor::ZigbeeCarbonDioxideSensor(uint8_t endpoint) : ZigbeeE _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } +bool ZigbeeCarbonDioxideSensor::setDefaultValue(float defaultValue) { + float zb_default_value = defaultValue / 1000000.0f; + esp_zb_attribute_list_t *carbon_dioxide_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_CARBON_DIOXIDE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = + esp_zb_cluster_update_attr(carbon_dioxide_measure_cluster, ESP_ZB_ZCL_ATTR_CARBON_DIOXIDE_MEASUREMENT_MEASURED_VALUE_ID, (void *)&zb_default_value); + if (ret != ESP_OK) { + log_e("Failed to set default value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + bool ZigbeeCarbonDioxideSensor::setMinMaxValue(float min, float max) { float zb_min = min / 1000000.0f; float zb_max = max / 1000000.0f; diff --git a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h index bd64e50e51e..2d6a87d946b 100644 --- a/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.h @@ -58,6 +58,10 @@ class ZigbeeCarbonDioxideSensor : public ZigbeeEP { // Set the carbon dioxide value in ppm bool setCarbonDioxide(float carbon_dioxide); + // Set the default (initial) value for the carbon dioxide sensor in ppm + // Must be called before adding the EP to Zigbee class. Only effective in factory reset mode (before commissioning) + bool setDefaultValue(float defaultValue); + // Set the min and max value for the carbon dioxide sensor in ppm bool setMinMaxValue(float min, float max); diff --git a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp index ddaee3ea88f..a946f7ad720 100644 --- a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.cpp @@ -36,6 +36,18 @@ ZigbeeFlowSensor::ZigbeeFlowSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } +bool ZigbeeFlowSensor::setDefaultValue(float defaultValue) { + uint16_t zb_default_value = (uint16_t)(defaultValue * 10); + esp_zb_attribute_list_t *flow_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_FLOW_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(flow_measure_cluster, ESP_ZB_ZCL_ATTR_FLOW_MEASUREMENT_VALUE_ID, (void *)&zb_default_value); + if (ret != ESP_OK) { + log_e("Failed to set default value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + bool ZigbeeFlowSensor::setMinMaxValue(float min, float max) { uint16_t zb_min = (uint16_t)(min * 10); uint16_t zb_max = (uint16_t)(max * 10); diff --git a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h index 0402dd15377..0bc7b767bfe 100644 --- a/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeFlowSensor.h @@ -58,6 +58,10 @@ class ZigbeeFlowSensor : public ZigbeeEP { // Set the flow value in 0,1 m3/h bool setFlow(float value); + // Set the default (initial) value for the flow sensor in 0,1 m3/h + // Must be called before adding the EP to Zigbee class. Only effective in factory reset mode (before commissioning) + bool setDefaultValue(float defaultValue); + // Set the min and max value for the flow sensor in 0,1 m3/h bool setMinMaxValue(float min, float max); diff --git a/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp index a2a6d364f9d..351dbbac182 100644 --- a/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp @@ -24,6 +24,17 @@ ZigbeeIlluminanceSensor::ZigbeeIlluminanceSensor(uint8_t endpoint) : ZigbeeEP(en _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_LIGHT_SENSOR_DEVICE_ID, .app_device_version = 0}; } +bool ZigbeeIlluminanceSensor::setDefaultValue(uint16_t defaultValue) { + esp_zb_attribute_list_t *light_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(light_measure_cluster, ESP_ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ID, (void *)&defaultValue); + if (ret != ESP_OK) { + log_e("Failed to set default value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + bool ZigbeeIlluminanceSensor::setMinMaxValue(uint16_t min, uint16_t max) { esp_zb_attribute_list_t *light_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); diff --git a/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.h b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.h index fdc369b4a55..5ae36b0c890 100644 --- a/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.h @@ -49,6 +49,10 @@ class ZigbeeIlluminanceSensor : public ZigbeeEP { // Set the illuminance value bool setIlluminance(uint16_t value); + // Set the default (initial) value for the illuminance sensor + // Must be called before adding the EP to Zigbee class. Only effective in factory reset mode (before commissioning) + bool setDefaultValue(uint16_t defaultValue); + // Set the min and max value for the illuminance sensor bool setMinMaxValue(uint16_t min, uint16_t max); diff --git a/libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp index fc2ca820c9a..ab3f47d81bf 100644 --- a/libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp @@ -36,6 +36,17 @@ ZigbeePM25Sensor::ZigbeePM25Sensor(uint8_t endpoint) : ZigbeeEP(endpoint) { _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } +bool ZigbeePM25Sensor::setDefaultValue(float defaultValue) { + esp_zb_attribute_list_t *pm2_5_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(pm2_5_measure_cluster, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MEASURED_VALUE_ID, (void *)&defaultValue); + if (ret != ESP_OK) { + log_e("Failed to set default value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + bool ZigbeePM25Sensor::setMinMaxValue(float min, float max) { esp_zb_attribute_list_t *pm2_5_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); diff --git a/libraries/Zigbee/src/ep/ZigbeePM25Sensor.h b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.h index e4b47574704..967ccdca167 100644 --- a/libraries/Zigbee/src/ep/ZigbeePM25Sensor.h +++ b/libraries/Zigbee/src/ep/ZigbeePM25Sensor.h @@ -58,6 +58,10 @@ class ZigbeePM25Sensor : public ZigbeeEP { // Set the PM2.5 value in 0.1 µg/m³ bool setPM25(float pm25); + // Set the default (initial) value for the PM2.5 sensor in 0.1 µg/m³ + // Must be called before adding the EP to Zigbee class. Only effective in factory reset mode (before commissioning) + bool setDefaultValue(float defaultValue); + // Set the min and max value for the PM2.5 sensor in 0.1 µg/m³ bool setMinMaxValue(float min, float max); diff --git a/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp b/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp index 4fdf8600fbe..da356334965 100644 --- a/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp @@ -36,6 +36,17 @@ ZigbeePressureSensor::ZigbeePressureSensor(uint8_t endpoint) : ZigbeeEP(endpoint _ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0}; } +bool ZigbeePressureSensor::setDefaultValue(int16_t defaultValue) { + esp_zb_attribute_list_t *pressure_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(pressure_measure_cluster, ESP_ZB_ZCL_ATTR_PRESSURE_MEASUREMENT_VALUE_ID, (void *)&defaultValue); + if (ret != ESP_OK) { + log_e("Failed to set default value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + bool ZigbeePressureSensor::setMinMaxValue(int16_t min, int16_t max) { esp_zb_attribute_list_t *pressure_measure_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); diff --git a/libraries/Zigbee/src/ep/ZigbeePressureSensor.h b/libraries/Zigbee/src/ep/ZigbeePressureSensor.h index cd38a24d4a0..930846c8721 100644 --- a/libraries/Zigbee/src/ep/ZigbeePressureSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeePressureSensor.h @@ -58,6 +58,10 @@ class ZigbeePressureSensor : public ZigbeeEP { // Set the pressure value in 1 hPa bool setPressure(int16_t value); + // Set the default (initial) value for the pressure sensor in 1 hPa + // Must be called before adding the EP to Zigbee class. Only effective in factory reset mode (before commissioning) + bool setDefaultValue(int16_t defaultValue); + // Set the min and max value for the pressure sensor in 1 hPa bool setMinMaxValue(int16_t min, int16_t max); diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp index 484506e139d..79b39b14c56 100644 --- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp @@ -22,6 +22,9 @@ ZigbeeTempSensor::ZigbeeTempSensor(uint8_t endpoint) : ZigbeeEP(endpoint) { esp_zb_temperature_sensor_cfg_t temp_sensor_cfg = ESP_ZB_DEFAULT_TEMPERATURE_SENSOR_CONFIG(); _cluster_list = esp_zb_temperature_sensor_clusters_create(&temp_sensor_cfg); + // Set default (initial) value for the temperature sensor to 0.0°C + setDefaultValue(0.0); + _ep_config = { .endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID, .app_device_version = 0 }; @@ -49,6 +52,18 @@ bool ZigbeeTempSensor::setMinMaxValue(float min, float max) { return true; } +bool ZigbeeTempSensor::setDefaultValue(float defaultValue) { + int16_t zb_default_value = zb_float_to_s16(defaultValue); + esp_zb_attribute_list_t *temp_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(temp_measure_cluster, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, (void *)&zb_default_value); + if (ret != ESP_OK) { + log_e("Failed to set default value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + bool ZigbeeTempSensor::setTolerance(float tolerance) { // Convert tolerance to ZCL uint16_t uint16_t zb_tolerance = (uint16_t)(tolerance * 100); @@ -126,11 +141,11 @@ bool ZigbeeTempSensor::reportTemperature() { return true; } -void ZigbeeTempSensor::addHumiditySensor(float min, float max, float tolerance) { +void ZigbeeTempSensor::addHumiditySensor(float min, float max, float tolerance, float defaultValue) { uint16_t zb_min = (uint16_t)(min * 100); uint16_t zb_max = (uint16_t)(max * 100); uint16_t zb_tolerance = (uint16_t)(tolerance * 100); - uint16_t default_hum = ESP_ZB_ZCL_REL_HUMIDITY_MEASUREMENT_MEASURED_VALUE_DEFAULT; + uint16_t default_hum = (uint16_t)(defaultValue * 100); esp_zb_attribute_list_t *humidity_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT); esp_zb_humidity_meas_cluster_add_attr(humidity_cluster, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, &default_hum); esp_zb_humidity_meas_cluster_add_attr(humidity_cluster, ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_MIN_VALUE_ID, &zb_min); diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h index e7219c17335..edc8812d5ae 100644 --- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h @@ -31,6 +31,10 @@ class ZigbeeTempSensor : public ZigbeeEP { // Set the temperature value in 0,01°C bool setTemperature(float value); + // Set the default (initial) value for the temperature sensor in 0,01°C + // Must be called before adding the EP to Zigbee class. Only effective in factory reset mode (before commissioning) + bool setDefaultValue(float defaultValue); + // Set the min and max value for the temperature sensor in 0,01°C bool setMinMaxValue(float min, float max); @@ -44,7 +48,7 @@ class ZigbeeTempSensor : public ZigbeeEP { bool reportTemperature(); // Add humidity cluster to the temperature sensor device - void addHumiditySensor(float min, float max, float tolerance); + void addHumiditySensor(float min = 0.0, float max = 100.0, float tolerance = 0.1, float defaultValue = 0.0); // Set the humidity value in 0,01% bool setHumidity(float value); diff --git a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp index 672b6254017..85e7efa655d 100644 --- a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp +++ b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp @@ -42,6 +42,18 @@ static uint16_t zb_windspeed_to_u16(float windspeed) { return (uint16_t)(windspeed * 100); } +bool ZigbeeWindSpeedSensor::setDefaultValue(float defaultValue) { + uint16_t zb_default_value = zb_windspeed_to_u16(defaultValue); + esp_zb_attribute_list_t *windspeed_measure_cluster = + esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WIND_SPEED_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + esp_err_t ret = esp_zb_cluster_update_attr(windspeed_measure_cluster, ESP_ZB_ZCL_ATTR_WIND_SPEED_MEASUREMENT_MEASURED_VALUE_ID, (void *)&zb_default_value); + if (ret != ESP_OK) { + log_e("Failed to set default value: 0x%x: %s", ret, esp_err_to_name(ret)); + return false; + } + return true; +} + bool ZigbeeWindSpeedSensor::setMinMaxValue(float min, float max) { uint16_t zb_min = zb_windspeed_to_u16(min); uint16_t zb_max = zb_windspeed_to_u16(max); diff --git a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h index b5371f8fdef..011cb5e663c 100644 --- a/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h +++ b/libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.h @@ -56,6 +56,10 @@ class ZigbeeWindSpeedSensor : public ZigbeeEP { // Set the WindSpeed value in 0,01 m/s bool setWindSpeed(float value); + // Set the default (initial) value for the wind speed sensor in 0,01 m/s + // Must be called before adding the EP to Zigbee class. Only effective in factory reset mode (before commissioning) + bool setDefaultValue(float defaultValue); + // Set the min and max value for the WindSpeed sensor bool setMinMaxValue(float min, float max); diff --git a/package.json b/package.json index b8e8085d815..b67f11b72cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "framework-arduinoespressif32", - "version": "3.3.4", + "version": "3.3.5", "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-P4, ESP32-S and ESP32-C series of SoCs", "keywords": [ "framework", diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index 716af37fddb..9e0cb83a8a0 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -54,7 +54,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.5-d66ebb86-v1" + "version": "idf-release_v5.5-9bb7aa84-v2" }, { "packager": "esp32", @@ -107,63 +107,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.5-d66ebb86-v1", + "version": "idf-release_v5.5-9bb7aa84-v2", "systems": [ { "host": "i686-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" }, { "host": "x86_64-mingw32", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" }, { "host": "arm64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-d66ebb86-v1.zip", - "checksum": "SHA-256:e44eefcf645cbf3d8f9270c0cdcc836621cbb10a8f5fac62e337d0da2e564fc8", - "size": "508996777" + "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.5/esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "archiveFileName": "esp32-arduino-libs-idf-release_v5.5-9bb7aa84-v2.zip", + "checksum": "SHA-256:a404a45e2251f3647137970bc7366e60e1b9536c59268df5612f289ca5b2080a", + "size": "509488664" } ] }, diff --git a/platform.txt b/platform.txt index 4bab878172a..000de65e95d 100644 --- a/platform.txt +++ b/platform.txt @@ -1,5 +1,5 @@ name=ESP32 Arduino -version=3.3.4 +version=3.3.5 tools.esp32-arduino-libs.path={runtime.platform.path}/tools/esp32-arduino-libs tools.esp32-arduino-libs.path.windows={runtime.platform.path}\tools\esp32-arduino-libs @@ -195,6 +195,36 @@ recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build recipe.size.regex=^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|\.dram1\.data|\.flash\.text|\.flash\.rodata|\.flash\.appdesc|\.flash\.init_array|\.eh_frame|)\s+([0-9]+).* recipe.size.regex.data=^(?:\.dram0\.data|\.dram0\.bss|\.dram1\.data|\.dram1\.bss|\.noinit)\s+([0-9]+).* +## Export extra build artifacts when "Export compiled Binary" is selected + +## By default Arduino IDE exports everything that starts with the sketch name +## We need to export other files as well + +## Define FQBN transformation logic as reusable properties +## Converts FQBN to vendor.arch.board format matching Arduino IDE default export path +recipe.hooks.savehex.fqbn_to_dir=FQBN_DIR=$(echo '{build.fqbn}' | cut -d: -f1-3 | tr ':' '.') +recipe.hooks.savehex.fqbn_to_dir.windows=$env:FQBN_DIR=('{build.fqbn}' -split ':')[0..2] -join '.' + +## Export partitions.csv (for reference) +recipe.hooks.savehex.postsavehex.1.pattern=/usr/bin/env bash -c "{recipe.hooks.savehex.fqbn_to_dir} && cp '{build.path}/partitions.csv' '{sketch_path}/build/'$FQBN_DIR'/partitions.csv' 2>/dev/null || true" +recipe.hooks.savehex.postsavehex.1.pattern.windows=powershell -Command "{recipe.hooks.savehex.fqbn_to_dir}; Copy-Item -ErrorAction SilentlyContinue '{build.path}\partitions.csv' ('{sketch_path}\build\' + $env:FQBN_DIR + '\partitions.csv')" + +## Export sdkconfig (for reference) +recipe.hooks.savehex.postsavehex.2.pattern=/usr/bin/env bash -c "{recipe.hooks.savehex.fqbn_to_dir} && cp '{build.path}/sdkconfig' '{sketch_path}/build/'$FQBN_DIR'/sdkconfig' 2>/dev/null || true" +recipe.hooks.savehex.postsavehex.2.pattern.windows=powershell -Command "{recipe.hooks.savehex.fqbn_to_dir}; Copy-Item -ErrorAction SilentlyContinue '{build.path}\sdkconfig' ('{sketch_path}\build\' + $env:FQBN_DIR + '\sdkconfig')" + +## Export flash_args +recipe.hooks.savehex.postsavehex.3.pattern=/usr/bin/env bash -c "{recipe.hooks.savehex.fqbn_to_dir} && cp '{build.path}/flash_args' '{sketch_path}/build/'$FQBN_DIR'/flash_args' 2>/dev/null || true" +recipe.hooks.savehex.postsavehex.3.pattern.windows=powershell -Command "{recipe.hooks.savehex.fqbn_to_dir}; Copy-Item -ErrorAction SilentlyContinue '{build.path}\flash_args' ('{sketch_path}\build\' + $env:FQBN_DIR + '\flash_args')" + +## Export boot_app0.bin +recipe.hooks.savehex.postsavehex.4.pattern=/usr/bin/env bash -c "{recipe.hooks.savehex.fqbn_to_dir} && cp '{runtime.platform.path}/tools/partitions/boot_app0.bin' '{sketch_path}/build/'$FQBN_DIR'/boot_app0.bin' 2>/dev/null || true" +recipe.hooks.savehex.postsavehex.4.pattern.windows=powershell -Command "{recipe.hooks.savehex.fqbn_to_dir}; Copy-Item -ErrorAction SilentlyContinue '{runtime.platform.path}\tools\partitions\boot_app0.bin' ('{sketch_path}\build\' + $env:FQBN_DIR + '\boot_app0.bin')" + +## Export build.options.json +recipe.hooks.savehex.postsavehex.5.pattern=/usr/bin/env bash -c "{recipe.hooks.savehex.fqbn_to_dir} && cp '{build.path}/build.options.json' '{sketch_path}/build/'$FQBN_DIR'/build.options.json' 2>/dev/null || true" +recipe.hooks.savehex.postsavehex.5.pattern.windows=powershell -Command "{recipe.hooks.savehex.fqbn_to_dir}; Copy-Item -ErrorAction SilentlyContinue '{build.path}\build.options.json' ('{sketch_path}\build\' + $env:FQBN_DIR + '\build.options.json')" + ## Required discoveries and monitors ## --------------------------------- pluggable_discovery.required.0=builtin:serial-discovery diff --git a/tests/validation/periman/ci.yml b/tests/validation/periman/ci.yml index 85d8f908f4e..a5625fc9fa1 100644 --- a/tests/validation/periman/ci.yml +++ b/tests/validation/periman/ci.yml @@ -1,6 +1,3 @@ platforms: qemu: false wokwi: false - -targets: - esp32p4: false diff --git a/tests/validation/periman/periman.ino b/tests/validation/periman/periman.ino index 2b89e3529fd..64d4359f135 100644 --- a/tests/validation/periman/periman.ino +++ b/tests/validation/periman/periman.ino @@ -71,8 +71,6 @@ void setup_test(String test_name, int8_t rx_pin = UART1_RX_DEFAULT, int8_t tx_pi uart1_tx_pin = tx_pin; test_executed = false; - pinMode(uart1_rx_pin, INPUT_PULLUP); - pinMode(uart1_tx_pin, OUTPUT); // Ensure Serial1 is initialized and callback is set (in case it was terminated previously) Serial1.setPins(uart1_rx_pin, uart1_tx_pin); Serial1.begin(115200); @@ -86,20 +84,20 @@ void setup_test(String test_name, int8_t rx_pin = UART1_RX_DEFAULT, int8_t tx_pi void teardown_test(void) { log_v("Tearing down %s test", current_test.c_str()); if (test_executed) { + // Test 1: Peripheral manager auto-detach via pinMode pinMode(uart1_rx_pin, INPUT_PULLUP); pinMode(uart1_tx_pin, OUTPUT); Serial1.print(current_test); Serial1.println(" test: This should not be printed"); Serial1.flush(); - } - // Even if test didn't execute, ensure Serial1 is initialized - // (in case it was terminated by a previous test or setup issue) - Serial1.setPins(uart1_rx_pin, uart1_tx_pin); - Serial1.begin(115200); - Serial1.onReceive(onReceive_cb); - uart_internal_loopback(1, uart1_rx_pin); - delay(100); + // Restore Serial1 via peripheral manager + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + } Serial1.print(current_test); Serial1.println(" test: This should be printed"); @@ -134,7 +132,35 @@ void sigmadelta_test(void) { Serial.println("SigmaDelta init failed"); } #endif - teardown_test(); + teardown_test(); // Tests auto-detach via pinMode + +#if SOC_SDM_SUPPORTED + // Now test manual deinit path + setup_test("SigmaDelta_deinit"); + test_executed = false; // Skip the pinMode test in teardown + + if (!sigmaDeltaAttach(uart1_rx_pin, 312500)) { + Serial.println("SigmaDelta init failed"); + } + if (!sigmaDeltaAttach(uart1_tx_pin, 312500)) { + Serial.println("SigmaDelta init failed"); + } + + // Manual deinit + sigmaDeltaDetach(uart1_rx_pin); + sigmaDeltaDetach(uart1_tx_pin); + + // Verify Serial1 can be restored after manual deinit + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + + Serial1.print("SigmaDelta_deinit"); + Serial1.println(" test: This should be printed"); + Serial1.flush(); +#endif } void adc_oneshot_test(void) { @@ -153,9 +179,9 @@ void adc_oneshot_test(void) { } #if SOC_ADC_SUPPORTED -volatile bool adc_coversion_done = false; +volatile bool adc_conversion_done = false; void ARDUINO_ISR_ATTR adcComplete() { - adc_coversion_done = true; + adc_conversion_done = true; } #endif @@ -175,7 +201,7 @@ void adc_continuous_test(void) { analogContinuous(adc_pins, adc_pins_count, 6, 20000, &adcComplete); analogContinuousStart(); - while (adc_coversion_done == false) { + while (adc_conversion_done == false) { delay(1); } @@ -185,7 +211,43 @@ void adc_continuous_test(void) { analogContinuousStop(); #endif - teardown_test(); + teardown_test(); // Tests auto-detach via pinMode + +#if SOC_ADC_SUPPORTED + // Now test manual deinit path + setup_test("ADC_Continuous_deinit", ADC1_DEFAULT, ADC2_DEFAULT); + test_executed = false; // Skip the pinMode test in teardown + adc_conversion_done = false; // Reset flag + + analogContinuousSetWidth(12); + analogContinuousSetAtten(ADC_11db); + analogContinuous(adc_pins, adc_pins_count, 6, 20000, &adcComplete); + analogContinuousStart(); + + while (adc_conversion_done == false) { + delay(1); + } + + if (!analogContinuousRead(&result, 0)) { + Serial.println("ADC continuous read failed"); + } + + analogContinuousStop(); + + // Manual deinit + analogContinuousDeinit(); + + // Verify Serial1 can be restored after manual deinit + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + + Serial1.print("ADC_Continuous_deinit"); + Serial1.println(" test: This should be printed"); + Serial1.flush(); +#endif } void dac_test(void) { @@ -211,7 +273,35 @@ void ledc_test(void) { Serial.println("LEDC init failed"); } #endif - teardown_test(); + teardown_test(); // Tests auto-detach via pinMode + +#if SOC_LEDC_SUPPORTED + // Now test manual deinit path + setup_test("LEDC_deinit"); + test_executed = false; // Skip the pinMode test in teardown + + if (!ledcAttach(uart1_rx_pin, 5000, 12)) { + Serial.println("LEDC init failed"); + } + if (!ledcAttach(uart1_tx_pin, 5000, 12)) { + Serial.println("LEDC init failed"); + } + + // Manual deinit + ledcDetach(uart1_rx_pin); + ledcDetach(uart1_tx_pin); + + // Verify Serial1 can be restored after manual deinit + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + + Serial1.print("LEDC_deinit"); + Serial1.println(" test: This should be printed"); + Serial1.flush(); +#endif } void rmt_test(void) { @@ -225,7 +315,35 @@ void rmt_test(void) { Serial.println("RMT init failed"); } #endif - teardown_test(); + teardown_test(); // Tests auto-detach via pinMode + +#if SOC_RMT_SUPPORTED + // Now test manual deinit path + setup_test("RMT_deinit"); + test_executed = false; // Skip the pinMode test in teardown + + if (!rmtInit(uart1_rx_pin, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)) { + Serial.println("RMT init failed"); + } + if (!rmtInit(uart1_tx_pin, RMT_RX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)) { + Serial.println("RMT init failed"); + } + + // Manual deinit + rmtDeinit(uart1_rx_pin); + rmtDeinit(uart1_tx_pin); + + // Verify Serial1 can be restored after manual deinit + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + + Serial1.print("RMT_deinit"); + Serial1.println(" test: This should be printed"); + Serial1.flush(); +#endif } void i2s_test(void) { @@ -240,7 +358,34 @@ void i2s_test(void) { Serial.println("I2S init failed"); } #endif - teardown_test(); + teardown_test(); // Tests auto-detach via pinMode + +#if SOC_I2S_SUPPORTED + // Now test manual deinit path + setup_test("I2S_deinit"); + test_executed = false; // Skip the pinMode test in teardown + + I2SClass i2s2; + i2s2.setPins(uart1_rx_pin, uart1_tx_pin, -1); + i2s2.setTimeout(1000); + if (!i2s2.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO)) { + Serial.println("I2S init failed"); + } + + // Manual deinit + i2s2.end(); + + // Verify Serial1 can be restored after manual deinit + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + + Serial1.print("I2S_deinit"); + Serial1.println(" test: This should be printed"); + Serial1.flush(); +#endif } void i2c_test(void) { @@ -251,7 +396,31 @@ void i2c_test(void) { Serial.println("I2C init failed"); } #endif - teardown_test(); + teardown_test(); // Tests auto-detach via pinMode + +#if SOC_I2C_SUPPORTED + // Now test manual deinit path + setup_test("I2C_deinit"); + test_executed = false; // Skip the pinMode test in teardown + + if (!Wire.begin(uart1_rx_pin, uart1_tx_pin)) { + Serial.println("I2C init failed"); + } + + // Manual deinit + Wire.end(); + + // Verify Serial1 can be restored after manual deinit + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + + Serial1.print("I2C_deinit"); + Serial1.println(" test: This should be printed"); + Serial1.flush(); +#endif } void spi_test(void) { @@ -260,7 +429,29 @@ void spi_test(void) { test_executed = true; SPI.begin(uart1_rx_pin, uart1_tx_pin, -1, -1); #endif - teardown_test(); + teardown_test(); // Tests auto-detach via pinMode + +#if SOC_GPSPI_SUPPORTED + // Now test manual deinit path + setup_test("SPI_deinit"); + test_executed = false; // Skip the pinMode test in teardown + + SPI.begin(uart1_rx_pin, uart1_tx_pin, -1, -1); + + // Manual deinit + SPI.end(); + + // Verify Serial1 can be restored after manual deinit + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + Serial1.begin(115200); + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + + Serial1.print("SPI_deinit"); + Serial1.println(" test: This should be printed"); + Serial1.flush(); +#endif } void touch_test(void) { diff --git a/tests/validation/periman/test_periman.py b/tests/validation/periman/test_periman.py index 2728abcef80..56be51406ca 100644 --- a/tests/validation/periman/test_periman.py +++ b/tests/validation/periman/test_periman.py @@ -3,21 +3,31 @@ def test_periman(dut): LOGGER = logging.getLogger(__name__) - peripherals = [ - "GPIO", - "SigmaDelta", - "LEDC", - "RMT", - "I2S", - "I2C", - "SPI", - "ADC_Oneshot", - "ADC_Continuous", - "DAC", - "Touch", + + # Define peripherals and whether they have a manual deinit test + # Format: (name, has_deinit_test) + PERIPHERALS = [ + ("GPIO", False), + ("SigmaDelta", True), + ("LEDC", True), + ("RMT", True), + ("I2S", True), + ("I2C", True), + ("SPI", True), + ("ADC_Oneshot", False), + ("ADC_Continuous", True), + ("DAC", False), + ("Touch", False), ] - pattern = rb"(?:\b\w+\b test: This should(?: not)? be printed|Peripheral Manager test done)" + # Build expected test names + pending_tests = set() + for name, has_deinit in PERIPHERALS: + pending_tests.add(name) + if has_deinit: + pending_tests.add(f"{name}_deinit") + + pattern = rb"(?:\b[\w_]+\b test: This should(?: not)? be printed|Peripheral Manager test done)" while True: try: @@ -26,17 +36,19 @@ def test_periman(dut): assert False, "Could not detect end of test" console_output = res.group(0).decode("utf-8") - peripheral = console_output.split()[0] + test_name = console_output.split()[0] if "Peripheral Manager test done" in console_output: break - if peripheral in peripherals: + if test_name in pending_tests: if "not" in console_output: - assert False, f"Output printed when it should not after peripheral {peripheral}" - LOGGER.info(f"Correct output after peripheral: {peripheral}") - peripherals.remove(peripheral) + assert False, f"Output printed when it should not for test: {test_name}" + else: + test_type = "manual deinit" if test_name.endswith("_deinit") else "auto-detach" + LOGGER.info(f"✓ {test_type} works for: {test_name}") + pending_tests.remove(test_name) else: - assert False, f"Unknown peripheral: {peripheral}" + assert False, f"Unknown test: {test_name}" - assert peripherals == [], f"Missing output after peripherals: {peripherals}" + assert not pending_tests, f"Missing tests: {sorted(pending_tests)}" diff --git a/tests/validation/sdcard/ci.yml b/tests/validation/sdcard/ci.yml new file mode 100644 index 00000000000..3f53d32a04e --- /dev/null +++ b/tests/validation/sdcard/ci.yml @@ -0,0 +1,3 @@ +platforms: + hardware: false + qemu: false diff --git a/tests/validation/sdcard/diagram.esp32h2.json b/tests/validation/sdcard/diagram.esp32h2.json new file mode 100644 index 00000000000..2bd0d65f8f3 --- /dev/null +++ b/tests/validation/sdcard/diagram.esp32h2.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "author": "lucasssvaz", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-h2-devkitm-1", + "id": "esp32", + "top": -55.37, + "left": -177.9, + "attrs": {} + }, + { + "type": "wokwi-microsd-card", + "id": "sd1", + "top": -151.03, + "left": -60.53, + "rotate": 90, + "attrs": {} + } + ], + "connections": [ + [ "esp32:RX", "$serialMonitor:TX", "", [] ], + [ "esp32:TX", "$serialMonitor:RX", "", [] ], + [ "sd1:DI", "esp32:6", "green", [ "v0.09", "h-142.56" ] ], + [ "sd1:CS", "esp32:7", "green", [ "h-57.66", "v-9.3" ] ], + [ "sd1:GND", "esp32:GND.7", "black", [ "h0" ] ], + [ "esp32:10", "sd1:SCK", "green", [ "h65.38", "v-74.57" ] ], + [ "sd1:GND", "esp32:GND.6", "black", [ "h-0.11", "v48" ] ], + [ "esp32:25", "sd1:DI", "green", [ "h46.18", "v-93.77" ] ], + [ "sd1:DO", "esp32:11", "green", [ "h-0.11", "v84.17" ] ], + [ "sd1:VCC", "esp32:3V3", "red", [ "v9.6", "h-0.14" ] ], + [ "esp32:0", "sd1:CS", "green", [ "h-19.2", "v-48", "h144" ] ] + ], + "dependencies": {} +} diff --git a/tests/validation/sdcard/diagram.esp32p4.json b/tests/validation/sdcard/diagram.esp32p4.json new file mode 100644 index 00000000000..1756f0ef2d1 --- /dev/null +++ b/tests/validation/sdcard/diagram.esp32p4.json @@ -0,0 +1,51 @@ +{ + "version": 1, + "author": "lucasssvaz", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-p4-function-ev", + "id": "esp", + "top": 164.08, + "left": -76.03, + "attrs": {} + }, + { + "type": "wokwi-microsd-card", + "id": "sd1", + "top": -26.23, + "left": 112.27, + "rotate": 90, + "attrs": {} + }, + { + "type": "wokwi-microsd-card", + "id": "sd2", + "top": -26.23, + "left": 237.07, + "rotate": 90, + "attrs": {} + } + ], + "connections": [ + [ "esp:37", "$serialMonitor:RX", "", [] ], + [ "esp:38", "$serialMonitor:TX", "", [] ], + [ "sd1:CS", "esp:10", "green", [ "h57.6", "v-38.16" ] ], + [ "sd1:DI", "esp:11", "green", [ "h48", "v-19.11" ] ], + [ "sd1:SCK", "esp:12", "green", [ "h38.4", "v9.77" ] ], + [ "sd1:DO", "esp:13", "green", [ "h67.2", "v38.69" ] ], + [ "sd1:VCC", "esp:3V3.1", "red", [ "v19.2", "h-105.74", "v115.2" ] ], + [ "sd2:VCC", "esp:3V3.1", "red", [ "v19.2", "h-230.54", "v115.2" ] ], + [ "esp:GND.1", "sd1:GND", "black", [ "v-9.6", "h-76.8", "v-86.4", "h115.2" ] ], + [ "esp:GND.1", "sd2:GND", "black", [ "v-9.6", "h-76.8", "v-86.4", "h240" ] ], + [ "esp:26", "sd2:CS", "green", [ "v0" ] ], + [ "esp:33", "sd2:DO", "green", [ "v-19.2", "h57.71" ] ], + [ "esp:36", "sd2:SCK", "green", [ "v-19.2", "h67.19" ] ], + [ "esp:32", "sd2:DI", "green", [ "v-28.8", "h38.31" ] ], + [ "esp:1", "sd1:SCK", "green", [ "v-19.2", "h-48" ] ], + [ "esp:2", "sd1:DO", "green", [ "v9.6", "h-124.8", "v-96", "h96.11" ] ], + [ "esp:3", "sd1:DI", "green", [ "v19.2", "h-124.8", "v-115.2", "h67.2", "v9.6" ] ], + [ "esp:8", "sd1:CS", "green", [ "v28.8", "h-67.2", "v-153.6", "h67.2" ] ] + ], + "dependencies": {} +} diff --git a/tools/bin_signing.exe b/tools/bin_signing.exe new file mode 100644 index 00000000000..524fd03a5ed Binary files /dev/null and b/tools/bin_signing.exe differ diff --git a/tools/bin_signing.py b/tools/bin_signing.py new file mode 100755 index 00000000000..1b020089b50 --- /dev/null +++ b/tools/bin_signing.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python3 +""" +OTA Update Signing Tool for ESP32 Arduino + +This script signs firmware binaries for secure OTA updates. +It supports both RSA and ECDSA signing schemes with various hash algorithms. + +Usage: + python bin_signing.py --bin firmware.bin --key private_key.pem --out firmware_signed.bin + python bin_signing.py --generate-key rsa-2048 --out private_key.pem + python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem +""" + +import argparse +import sys +import os +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.serialization import load_pem_private_key, load_pem_public_key + + +def generate_rsa_key(key_size, output_file): + """Generate an RSA private key""" + print(f"Generating RSA-{key_size} private key...") + private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_size, backend=default_backend()) + + pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + + with open(output_file, "wb") as f: + f.write(pem) + + print(f"Private key saved to: {output_file}") + print("\nIMPORTANT: Keep this private key secure!") + print("Extract the public key with: python bin_signing.py --extract-pubkey", output_file) + + +def generate_ecdsa_key(curve_name, output_file): + """Generate an ECDSA private key""" + curves = { + "p256": ec.SECP256R1(), + "p384": ec.SECP384R1(), + } + + if curve_name not in curves: + print(f"Error: Unsupported curve. Supported curves: {', '.join(curves.keys())}") + sys.exit(1) + + print(f"Generating ECDSA-{curve_name.upper()} private key...") + private_key = ec.generate_private_key(curves[curve_name], backend=default_backend()) + + pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + + with open(output_file, "wb") as f: + f.write(pem) + + print(f"Private key saved to: {output_file}") + print("\nIMPORTANT: Keep this private key secure!") + print("Extract the public key with: python bin_signing.py --extract-pubkey", output_file) + + +def extract_public_key(private_key_file, output_file): + """Extract public key from private key""" + print(f"Extracting public key from {private_key_file}...") + + with open(private_key_file, "rb") as f: + private_key = load_pem_private_key(f.read(), password=None, backend=default_backend()) + + public_key = private_key.public_key() + + pem = public_key.public_bytes( + encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + + with open(output_file, "wb") as f: + f.write(pem) + + print(f"Public key saved to: {output_file}") + + # Also generate a C header file for embedding in Arduino sketch + header_file = os.path.splitext(output_file)[0] + ".h" + with open(header_file, "w") as f: + f.write("// Public key for OTA signature verification\n") + f.write("// Include this in your Arduino sketch\n\n") + f.write("const uint8_t PUBLIC_KEY[] PROGMEM = {\n") + + # Add null terminator for mbedtls PEM parser + pem_bytes = pem + b"\x00" + for i in range(0, len(pem_bytes), 16): + chunk = pem_bytes[i : i + 16] + hex_str = ", ".join(f"0x{b:02x}" for b in chunk) + f.write(f" {hex_str},\n") + + f.write("};\n") + f.write(f"const size_t PUBLIC_KEY_LEN = {len(pem_bytes)};\n") + + print(f"C header file saved to: {header_file}") + + +def sign_binary(binary_file, key_file, output_file, hash_algo="sha256"): + """Sign a binary file""" + print(f"Signing {binary_file} with {key_file}...") + + # Read the binary + with open(binary_file, "rb") as f: + binary_data = f.read() + + print(f"Binary size: {len(binary_data)} bytes") + + # Load private key + with open(key_file, "rb") as f: + private_key = load_pem_private_key(f.read(), password=None, backend=default_backend()) + + # Select hash algorithm + hash_algos = { + "sha256": hashes.SHA256(), + "sha384": hashes.SHA384(), + "sha512": hashes.SHA512(), + } + + if hash_algo not in hash_algos: + print(f"Error: Unsupported hash algorithm. Supported: {', '.join(hash_algos.keys())}") + sys.exit(1) + + hash_obj = hash_algos[hash_algo] + + # Sign the binary + if isinstance(private_key, rsa.RSAPrivateKey): + print(f"Using RSA-PSS with {hash_algo.upper()}") + signature = private_key.sign( + binary_data, padding.PSS(mgf=padding.MGF1(hash_obj), salt_length=padding.PSS.MAX_LENGTH), hash_obj + ) + key_type = "RSA" + elif isinstance(private_key, ec.EllipticCurvePrivateKey): + print(f"Using ECDSA with {hash_algo.upper()}") + signature = private_key.sign(binary_data, ec.ECDSA(hash_obj)) + key_type = "ECDSA" + else: + print("Error: Unsupported key type") + sys.exit(1) + + print(f"Signature size: {len(signature)} bytes") + + # Pad signature to max size (512 bytes for RSA-4096) + max_sig_size = 512 + padded_signature = signature + b"\x00" * (max_sig_size - len(signature)) + + # Write signed binary (firmware + signature) + with open(output_file, "wb") as f: + f.write(binary_data) + f.write(padded_signature) + + signed_size = len(binary_data) + len(padded_signature) + print(f"Signed binary saved to: {output_file}") + print(f"Signed binary size: {signed_size} bytes (firmware: {len(binary_data)}, signature: {len(padded_signature)})") + print(f"\nKey type: {key_type}") + print(f"Hash algorithm: {hash_algo.upper()}") + + +def verify_signature(binary_file, pubkey_file, hash_algo="sha256"): + """Verify a signed binary""" + print(f"Verifying signature of {binary_file} with {pubkey_file}...") + + # Read the signed binary + with open(binary_file, "rb") as f: + signed_data = f.read() + + # The signature is the last 512 bytes (padded) + max_sig_size = 512 + if len(signed_data) < max_sig_size: + print("Error: File too small to contain signature") + sys.exit(1) + + binary_data = signed_data[:-max_sig_size] + signature = signed_data[-max_sig_size:] + + # Load public key + with open(pubkey_file, "rb") as f: + public_key = load_pem_public_key(f.read(), backend=default_backend()) + + # Select hash algorithm + hash_algos = { + "sha256": hashes.SHA256(), + "sha384": hashes.SHA384(), + "sha512": hashes.SHA512(), + } + + if hash_algo not in hash_algos: + print(f"Error: Unsupported hash algorithm. Supported: {', '.join(hash_algos.keys())}") + sys.exit(1) + + hash_obj = hash_algos[hash_algo] + + # Remove padding from signature + signature = signature.rstrip(b"\x00") + + # Verify the signature + try: + if isinstance(public_key, rsa.RSAPublicKey): + print(f"Verifying RSA-PSS signature with {hash_algo.upper()}") + public_key.verify( + signature, + binary_data, + padding.PSS(mgf=padding.MGF1(hash_obj), salt_length=padding.PSS.MAX_LENGTH), + hash_obj, + ) + elif isinstance(public_key, ec.EllipticCurvePublicKey): + print(f"Verifying ECDSA signature with {hash_algo.upper()}") + public_key.verify(signature, binary_data, ec.ECDSA(hash_obj)) + else: + print("Error: Unsupported key type") + sys.exit(1) + + print("✓ Signature verification SUCCESSFUL!") + return True + except Exception as e: + print(f"✗ Signature verification FAILED: {e}") + return False + + +def main(): + parser = argparse.ArgumentParser( + description="OTA Update Signing Tool for ESP32 Arduino", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + Generate RSA-2048 key: + python bin_signing.py --generate-key rsa-2048 --out private_key.pem + + Generate ECDSA-P256 key: + python bin_signing.py --generate-key ecdsa-p256 --out private_key.pem + + Extract public key: + python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem + + Sign firmware: + python bin_signing.py --bin firmware.bin --key private_key.pem --out firmware_signed.bin + + Sign with SHA-384: + python bin_signing.py --bin firmware.bin --key private_key.pem --out firmware_signed.bin --hash sha384 + + Verify signed firmware: + python bin_signing.py --verify firmware_signed.bin --pubkey public_key.pem + """, + ) + + parser.add_argument( + "--generate-key", + metavar="TYPE", + help="Generate a new key (rsa-2048, rsa-3072, rsa-4096, ecdsa-p256, ecdsa-p384)", + ) + parser.add_argument("--extract-pubkey", metavar="PRIVATE_KEY", help="Extract public key from private key") + parser.add_argument("--bin", metavar="FILE", help="Binary file to sign") + parser.add_argument("--key", metavar="FILE", help="Private key file (PEM format)") + parser.add_argument("--pubkey", metavar="FILE", help="Public key file for verification (PEM format)") + parser.add_argument("--out", metavar="FILE", help="Output file") + parser.add_argument( + "--hash", default="sha256", choices=["sha256", "sha384", "sha512"], help="Hash algorithm (default: sha256)" + ) + parser.add_argument("--verify", metavar="FILE", help="Verify a signed binary") + + args = parser.parse_args() + + if args.generate_key: + if not args.out: + print("Error: --out required for key generation") + sys.exit(1) + + key_type = args.generate_key.lower() + if key_type.startswith("rsa-"): + key_size = int(key_type.split("-")[1]) + generate_rsa_key(key_size, args.out) + elif key_type.startswith("ecdsa-"): + curve = key_type.split("-")[1] + generate_ecdsa_key(curve, args.out) + else: + print("Error: Invalid key type. Supported: rsa-2048, rsa-3072, rsa-4096, ecdsa-p256, ecdsa-p384") + sys.exit(1) + + elif args.extract_pubkey: + if not args.out: + print("Error: --out required for public key extraction") + sys.exit(1) + extract_public_key(args.extract_pubkey, args.out) + + elif args.verify: + if not args.pubkey: + print("Error: --pubkey required for verification") + sys.exit(1) + verify_signature(args.verify, args.pubkey, args.hash) + + elif args.bin and args.key: + if not args.out: + print("Error: --out required for signing") + sys.exit(1) + sign_binary(args.bin, args.key, args.out, args.hash) + + else: + parser.print_help() + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/variants/axiometa_genesis_one/pins_arduino.h b/variants/axiometa_genesis_one/pins_arduino.h index 042abfcd495..279514ad2ea 100644 --- a/variants/axiometa_genesis_one/pins_arduino.h +++ b/variants/axiometa_genesis_one/pins_arduino.h @@ -26,44 +26,44 @@ static const uint8_t MISO = 12; static const uint8_t SCK = 13; // Port 1 IO pins -static const uint8_t P1_IO1 = 1; -static const uint8_t P1_IO2 = 14; -static const uint8_t P1_IO3 = 41; +static const uint8_t P1_IO0 = 1; +static const uint8_t P1_IO1 = 14; +static const uint8_t P1_IO2 = 41; // Port 2 IO pins -static const uint8_t P2_IO1 = 2; -static const uint8_t P2_IO2 = 15; -static const uint8_t P2_IO3 = 42; +static const uint8_t P2_IO0 = 2; +static const uint8_t P2_IO1 = 15; +static const uint8_t P2_IO2 = 42; // Port 3 IO pins -static const uint8_t P3_IO1 = 3; -static const uint8_t P3_IO2 = 16; -static const uint8_t P3_IO3 = 45; +static const uint8_t P3_IO0 = 3; +static const uint8_t P3_IO1 = 16; +static const uint8_t P3_IO2 = 45; // Port 4 IO pins -static const uint8_t P4_IO1 = 4; -static const uint8_t P4_IO2 = 17; -static const uint8_t P4_IO3 = 46; +static const uint8_t P4_IO0 = 4; +static const uint8_t P4_IO1 = 17; +static const uint8_t P4_IO2 = 46; // Port 5 IO pins -static const uint8_t P5_IO1 = 5; -static const uint8_t P5_IO2 = 18; -static const uint8_t P5_IO3 = 21; +static const uint8_t P5_IO0 = 5; +static const uint8_t P5_IO1 = 18; +static const uint8_t P5_IO2 = 21; // Port 6 IO pins -static const uint8_t P6_IO1 = 6; -static const uint8_t P6_IO2 = 40; -static const uint8_t P6_IO3 = 38; +static const uint8_t P6_IO0 = 6; +static const uint8_t P6_IO1 = 40; +static const uint8_t P6_IO2 = 38; // Port 7 IO pins -static const uint8_t P7_IO1 = 7; -static const uint8_t P7_IO2 = 9; -static const uint8_t P7_IO3 = 39; +static const uint8_t P7_IO0 = 7; +static const uint8_t P7_IO1 = 9; +static const uint8_t P7_IO2 = 39; // Port 8 IO pins -static const uint8_t P8_IO1 = 48; -static const uint8_t P8_IO2 = 43; -static const uint8_t P8_IO3 = 44; +static const uint8_t P8_IO0 = 48; +static const uint8_t P8_IO1 = 43; +static const uint8_t P8_IO2 = 44; // Analog capable pins (ESP32-S3 specific) static const uint8_t A0 = 1; diff --git a/variants/esp32p4_4ds_mipi_round/pins_arduino.h b/variants/esp32p4_4ds_mipi_round/pins_arduino.h new file mode 100644 index 00000000000..c017db208ca --- /dev/null +++ b/variants/esp32p4_4ds_mipi_round/pins_arduino.h @@ -0,0 +1,73 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +// Use default UART0 pins +static const uint8_t TX = 37; +static const uint8_t RX = 38; + +// Default pins (7 and 8) are used by on-board components already, +// for libraries, this can be set manually +// so let's keep the default for the user +static const uint8_t SDA = 2; // careful, also used as T0 pin +static const uint8_t SCL = 3; // careful, also used as T1 pin + +static const uint8_t SCK = 6; // careful, also used as T2 pin +static const uint8_t MOSI = 14; // careful, also used as T1 pin +static const uint8_t MISO = 15; // careful, also used as T0 pin +static const uint8_t SS = 16; // careful, also used as A9 pin + +static const uint8_t A0 = 21; +static const uint8_t A1 = 20; +static const uint8_t A2 = 19; +static const uint8_t A3 = 18; +static const uint8_t A4 = 17; +static const uint8_t A5 = 52; +static const uint8_t A6 = 51; +static const uint8_t A7 = 50; +static const uint8_t A8 = 49; +static const uint8_t A9 = 16; // careful, also used as SPI SS pin + +static const uint8_t T0 = 15; // careful, also used as SPI MISO pin +static const uint8_t T1 = 14; // careful, also used as SPI MOSI pin +static const uint8_t T2 = 6; // careful, also used as SPI SCK pin +static const uint8_t T3 = 3; // careful, also used as I2C SCL pin +static const uint8_t T4 = 2; // careful, also used as I2C SDA pin + +/* 4D Systems ESP32-P4 round board specific definitions */ +// LCD +#define LCD_INTERFACE_MIPI + +#define LCD_BL_IO 22 +#define LCD_BL_ON_LEVEL 1 +#define LCD_BL_OFF_LEVEL !LCD_BL_ON_LEVEL + +#define LCD_RST_IO 23 +#define LCD_RST_ACTIVE_HIGH true + +// I2C for on-board components +#define I2C_SDA 7 +#define I2C_SCL 8 + +// Touch +#define CTP_RST 4 +#define CTP_INT 5 + +// Audio +#define AMP_CTRL 53 +#define I2S_DSDIN 9 +#define I2S_LRCK 10 +#define I2S_ASDOUT 11 +#define I2S_SCLK 12 +#define I2S_MCLK 13 + +// SDMMC +#define BOARD_HAS_SDMMC +#define BOARD_SDMMC_SLOT 0 +#define BOARD_SDMMC_POWER_CHANNEL 4 +#define BOARD_SDMMC_POWER_PIN 45 +#define BOARD_SDMMC_POWER_ON_LEVEL LOW + +#endif /* Pins_Arduino_h */ diff --git a/variants/waveshare_esp32_c3_zero/pins_arduino.h b/variants/waveshare_esp32_c3_zero/pins_arduino.h new file mode 100644 index 00000000000..97ff8294628 --- /dev/null +++ b/variants/waveshare_esp32_c3_zero/pins_arduino.h @@ -0,0 +1,48 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include "soc/soc_caps.h" + +#define PIN_RGB_LED 10 +// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino +static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN +// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite() +#define RGB_BUILTIN LED_BUILTIN +#define RGB_BRIGHTNESS 64 + +static const uint8_t TX = 21; +static const uint8_t RX = 20; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +static const uint8_t SS = 7; +static const uint8_t MOSI = 6; +static const uint8_t MISO = 5; +static const uint8_t SCK = 4; + +static const uint8_t A0 = 0; +static const uint8_t A1 = 1; +static const uint8_t A2 = 2; +static const uint8_t A3 = 3; +static const uint8_t A4 = 4; +static const uint8_t A5 = 5; + +static const uint8_t D0 = 0; +static const uint8_t D1 = 1; +static const uint8_t D2 = 2; +static const uint8_t D3 = 3; +static const uint8_t D4 = 4; +static const uint8_t D5 = 5; +static const uint8_t D6 = 6; +static const uint8_t D7 = 7; +static const uint8_t D8 = 8; +static const uint8_t D9 = 9; +static const uint8_t D10 = 10; +static const uint8_t D11 = 20; +static const uint8_t D12 = 21; + +#endif /* Pins_Arduino_h */