From 091079ab84a5b09f13bfdd99cbcc5e255304e21f Mon Sep 17 00:00:00 2001 From: Tony Date: Sun, 2 Aug 2026 10:02:56 +0800 Subject: [PATCH] feat(gateway): Implement Matter-to-DALI bridge functionality - Added support for Matter protocol in the gateway, enabling integration with DALI devices. - Introduced new configuration options in sdkconfig.defaults for Matter bridge settings. - Created CMakeLists.txt and idf_component.yml for the new gateway_matter component. - Developed GatewayMatterBridge class to manage DALI device bindings and Matter interactions. - Implemented methods for scanning DALI devices, handling attribute updates, and managing provisioning. - Enhanced GatewayNetworkService to support Wi-Fi provisioning and select preferred network routes. Signed-off-by: Tony --- README.md | 50 ++ apps/gateway/CMakeLists.txt | 16 +- apps/gateway/dependencies.lock | 361 +++++++++- apps/gateway/main/CMakeLists.txt | 2 +- apps/gateway/main/Kconfig.projbuild | 65 ++ apps/gateway/main/app_main.cpp | 64 +- apps/gateway/sdkconfig | 632 +++++++++++++++++- apps/gateway/sdkconfig.defaults | 174 +++++ components/gateway_matter/CMakeLists.txt | 7 + components/gateway_matter/idf_component.yml | 4 + .../gateway_matter/include/gateway_matter.hpp | 108 +++ .../gateway_matter/src/gateway_matter.cpp | 566 ++++++++++++++++ .../include/gateway_network.hpp | 4 + .../gateway_network/src/gateway_network.cpp | 42 +- 14 files changed, 2083 insertions(+), 12 deletions(-) create mode 100644 components/gateway_matter/CMakeLists.txt create mode 100644 components/gateway_matter/idf_component.yml create mode 100644 components/gateway_matter/include/gateway_matter.hpp create mode 100644 components/gateway_matter/src/gateway_matter.cpp diff --git a/README.md b/README.md index b1c16d3..24f7bb0 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ update as the project evolves: - `gateway_ble/`: NimBLE GATT bridge for BLE transport parity on `FFF1`/`FFF2`/`FFF3`, including raw DALI notifications. - `gateway_controller/`: Lua-compatible gateway command dispatcher, internal scene/group state, and notification fan-out. - `gateway_network/`: HTTP `/info`, `/dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP port `2020` command/notify routing, Wi-Fi STA lifecycle, W5500 SPI Ethernet startup/teardown, ESP-Touch smartconfig, setup AP mode, ESP-NOW setup ingress, setup AP GPIO handling, and optional Wi-Fi reset GPIO handling for the native gateway. + - `gateway_matter/`: ESP-Matter 1.5.1 adapter that discovers DALI control gear, persists endpoint bindings in normal NVS, and exposes supported DALI lighting behavior through dynamic Matter endpoints. - `gateway_runtime/`: persistent runtime state, command queueing, and device info services. - `gateway_485_control/`: optional 485 control bridge at `9600 8N1`; disabled by default because UART0 must be moved off the ESP-IDF console first. C++ gateway commands on this raw multi-client bus use the session-scoped frame described below. - `gateway_usb_setup/`: optional USB Serial/JTAG setup bridge; disabled by default so USB remains available for debug at boot. @@ -93,6 +94,13 @@ gateway id: operation `0x00` reads the group and operation `0x01` writes group ## Ethernet control +Ethernet is the preferred default route whenever the W5500 has an address. +Wi-Fi remains a fallback; the gateway does not start Wi-Fi provisioning at +startup. `GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO` defaults to `-1`; assigning +a GPIO allows a long press to start ESP-Touch SmartConfig and reopen the Matter +commissioning window. The long-press duration and active level are configurable +beside the GPIO in `main/Kconfig.projbuild`. + The network service accepts Lua-style raw gateway frames on UDP port `2020` and, when enabled, TCP port `2020`. It also accepts JSON control frames on the same ports: @@ -112,6 +120,48 @@ Raw UDP, raw TCP, and UART0 session control all expand gateway target `255` to all physical gateway ids and targets `128..254` to channels whose configured gateway group matches the target. +## Matter-to-DALI development bridge + +`GATEWAY_MATTER_SUPPORTED` enables the Matter bridge by default. It creates one +aggregator and resumes or discovers up to +`GATEWAY_MATTER_MAX_BRIDGED_DEVICES` direct-address DALI control gear. The +adapter queries all DALI device types `0` through `8`: DT8 becomes an extended +color light, DT7 becomes an on/off light, and the remaining types become +dimmable lights. Matter On/Off, Level Control, Color Control (mirek, XY, and +hue/saturation converted to DALI RGB), Groups, Scenes, and Identify are the +only application clusters retained. Root-node commissioning, credentials, +descriptor, access-control, diagnostics, and the ESP-Matter internal Binding +manager are retained because the server requires them; unrelated device-type +clusters, Thread, OTA, and the Matter shell are excluded. + +Matter and the legacy `gateway_ble` transport both own the NimBLE host. While +Matter is enabled, the app does not start the legacy BLE GATT bridge; USB, +Ethernet, Wi-Fi, KNX, Modbus, BACnet, and the portable DALI behavior remain in +their existing components. ESP-Matter's Ethernet platform path is compiled so +CHIP receives Ethernet address events, while its Ethernet Network Commissioning +driver stays disabled because wired Ethernet needs no credentials. Standard +Matter Wi-Fi Network Commissioning remains compiled. Separately, the gateway's +ESP-Touch SmartConfig path starts only through the configured long-press button; +it is disabled at startup. When both interfaces have addresses, +`gateway_network` selects Ethernet as the default route. The project +build omits ESP-Matter's unused internal-EMAC commissioning source because the +ESP32-S3 gateway's W5500 lifecycle remains owned by `gateway_network`. + +This configuration is development-only. The ESP-Matter factory, device +instance, DAC, and commissionable-data providers read the normal `nvs` +partition. Flash encryption, NVS encryption, and secure boot remain disabled +so credentials and state are visible during debugging. DaliMaster's ESP burner +uses the local `packages/matter_mfg_tool` package to generate a fresh P-256 test +DAC and ESP-IDF NVS v2 image, then inserts it at `0x9000`. The package hardcodes +the ESP-Matter test PAI signing key/certificate and Certification Declaration; +it does not invoke an external manufacturing executable. The burner reads a selected partition-table image +at `0x8000` and fills the declared normal NVS size (`0x14000` in the checked-in +4 MiB profile or `0x6000` in the 16 MiB default layout) so stale NVS pages are +erased. Each image contains the test VID/PID `FFF2/8001`, its unique test DAC +private key/certificate, PAI, certification declaration, passcode `20202021`, +and discriminator `3840`. Flashing that image replaces all existing normal NVS +data and must never be used for production hardware. + ## Gateway operation protocol Opcode `0x67` starts, aborts, and polls gateway-executed high-level DALI diff --git a/apps/gateway/CMakeLists.txt b/apps/gateway/CMakeLists.txt index d9a5e3c..5a621d7 100644 --- a/apps/gateway/CMakeLists.txt +++ b/apps/gateway/CMakeLists.txt @@ -11,4 +11,18 @@ set(EXTRA_COMPONENT_DIRS ) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(gateway_app) \ No newline at end of file +project(gateway_app) + +# CONFIG_ENABLE_ETHERNET_TELEMETRY is ESP-Matter's switch for the CHIP +# Ethernet connectivity implementation. Its component also compiles the +# internal-EMAC commissioning driver unconditionally, even when that driver is +# disabled. ESP32-S3 has no internal EMAC and this gateway already owns its +# W5500, so omit only that unused source from the managed component target. +if(CONFIG_ENABLE_ETHERNET_TELEMETRY AND + NOT CONFIG_ETHERNET_NETWORK_COMMISSIONING_DRIVER) + idf_component_get_property(esp_matter_lib espressif__esp_matter COMPONENT_LIB) + get_target_property(esp_matter_sources ${esp_matter_lib} SOURCES) + list(FILTER esp_matter_sources EXCLUDE REGEX + "/NetworkCommissioningDriver_Ethernet\\.cpp$") + set_property(TARGET ${esp_matter_lib} PROPERTY SOURCES ${esp_matter_sources}) +endif() diff --git a/apps/gateway/dependencies.lock b/apps/gateway/dependencies.lock index 698d774..a5144a0 100644 --- a/apps/gateway/dependencies.lock +++ b/apps/gateway/dependencies.lock @@ -1,6 +1,17 @@ dependencies: + espressif/cbor: + component_hash: + dad9ca860963e930366510a10b422b3125a4fb27b979712ed65efcbcd742de50 + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com + type: service + version: 0.6.1~4 espressif/cjson: - component_hash: + component_hash: e788323270d90738662d66fffa910bfe1fba019bba087f01557e70c40485b469 dependencies: - name: idf @@ -10,8 +21,182 @@ dependencies: registry_url: https://components.espressif.com/ type: service version: 1.7.19~2 + espressif/esp-serial-flasher: + component_hash: + dcc42a16712a1a636509cf0bf90e14032d7f2141784b533613b267b6aa318d52 + dependencies: [] + source: + registry_url: https://components.espressif.com + type: service + version: 0.0.11 + espressif/esp_delta_ota: + component_hash: + 147161b602ef51e9f6649eb6d90c4d4ac3c94228cb264fa0e68be7877180462d + dependencies: + - name: idf + require: private + version: '>=4.3' + source: + registry_url: https://components.espressif.com + type: service + version: 1.1.4 + espressif/esp_diag_data_store: + component_hash: + 1967397300fbea608f688f71365b298a613eed48b694ee236cc60e6d06fda086 + dependencies: + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.1.1 + espressif/esp_diagnostics: + component_hash: + f91cd5bd3d6a9be134d7196bdecd5336825ab3fa37eab482647b07a6dabaa842 + dependencies: + - name: espressif/rmaker_common + registry_url: https://components.espressif.com + require: private + version: ^1.5 + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.3.4 + espressif/esp_encrypted_img: + component_hash: + e5a065c140fbc6a69a1de4fa1731b7596cc34a4a50b57913b2dc34c9ad3a0a70 + dependencies: + - name: idf + require: private + version: '>=4.4' + source: + registry_url: https://components.espressif.com + type: service + version: 2.3.0 + espressif/esp_insights: + component_hash: + 102d0a141d5123a5ebb827832f73fcc4135aefed6c38fca98e7b655bd18735c5 + dependencies: + - name: espressif/cbor + registry_url: https://components.espressif.com + require: private + version: ~0.6 + - name: espressif/esp_diag_data_store + registry_url: https://components.espressif.com + require: private + version: ~1.1.1 + - name: espressif/esp_diagnostics + registry_url: https://components.espressif.com + require: private + version: '>=1.3.0' + - name: espressif/rmaker_common + registry_url: https://components.espressif.com + require: private + version: ^1.5 + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.3.4 + espressif/esp_matter: + component_hash: + d7db95c3fdd162a3a378f48c11257ded9fcdc59d18caa58d936a2cac327d1796 + dependencies: + - name: espressif/esp_delta_ota + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=4.3 + version: ^1.1.0 + - name: espressif/esp_encrypted_img + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=4.4 + version: 2.3.0 + - name: espressif/esp_hosted + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32p4] + version: ~2 + - name: espressif/esp_insights + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=5.0 + - if: target != esp32h2 + version: ^1.2.4 + - name: espressif/esp_rcp_update + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=5.0 + version: ~1.3.0 + - name: espressif/esp_secure_cert_mgr + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=4.3 + version: ^2.5.0 + - name: espressif/esp_wifi_remote + registry_url: https://components.espressif.com + require: private + rules: + - if: target in [esp32p4] + version: ^0.7.0 + - name: espressif/json_generator + registry_url: https://components.espressif.com + require: private + version: ~1.1.0 + - name: espressif/json_parser + registry_url: https://components.espressif.com + require: private + version: ~1.0.0 + - name: espressif/mdns + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=5.0 + version: ^1.1.0 + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.5.1 + espressif/esp_rcp_update: + component_hash: + 37f535edd527a45faeaad649c0c56af36e5399074e52d83f0990fce466844dde + dependencies: + - name: espressif/esp-serial-flasher + registry_url: https://components.espressif.com + require: private + version: ~0.0.0 + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com + type: service + version: 1.3.1 + espressif/esp_secure_cert_mgr: + component_hash: + 0b83e150f48d6839f0a0a8753850be55a51cc298cfca7658f21d355d5f41dd67 + dependencies: + - name: idf + require: private + version: '>=4.3' + source: + registry_url: https://components.espressif.com + type: service + version: 2.9.3 espressif/esp_tinyusb: - component_hash: + component_hash: 9a73a76a6bc17907f6e523342ff6b1e440023e8aac2c11f4691212106ec24e66 dependencies: - name: idf @@ -31,8 +216,52 @@ dependencies: - esp32h4 - esp32s31 version: 2.2.1 + espressif/jsmn: + component_hash: + d80350c41bbaa827c98a25b6072df00884e72f54885996fab4a4f0aebce6b6c3 + dependencies: + - name: idf + require: private + version: '>=4.3' + source: + registry_url: https://components.espressif.com + type: service + version: 1.1.0 + espressif/json_generator: + component_hash: + 45033e1c199b13f1c8c1b544fb7d4e2df6a8e3071ebdcb1b22582b61a7974ff2 + dependencies: [] + source: + registry_url: https://components.espressif.com + type: service + version: 1.1.2 + espressif/json_parser: + component_hash: + d74b81729ad06ec11ff5eb5b1b0d7df1d00e6027fc11471f4b139c70dcf1b1e4 + dependencies: + - name: espressif/jsmn + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=5.0 + version: ~1.1 + source: + registry_url: https://components.espressif.com + type: service + version: 1.0.3 + espressif/mdns: + component_hash: + e81ca7a7f53ea34e78274df054da692c272e1315572876b237b1748e267c013b + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com + type: service + version: 1.11.3 espressif/mqtt: - component_hash: + component_hash: ffdad5659706b4dc14bc63f8eb73ef765efa015bf7e9adf71c813d52a2dc9342 dependencies: - name: idf @@ -42,6 +271,129 @@ dependencies: registry_url: https://components.espressif.com/ type: service version: 1.0.0 + espressif/rmaker_cmd_resp: + component_hash: + 343ccd5d3a2789ecb241f9de5ac7f67fc39db126c1af139116a20c9a6e3669f3 + dependencies: + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.0.0 + espressif/rmaker_common: + component_hash: + 276ee0baf9552805bf66a3e34a19cf38df6f5a7b167c47bf215b7196e03ef1fc + dependencies: + - name: espressif/mqtt + registry_url: https://components.espressif.com + require: private + rules: + - if: idf_version >=6.0.0 + version: '*' + - name: espressif/rmaker_cmd_resp + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: espressif/rmaker_common_events + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: espressif/rmaker_console + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: espressif/rmaker_system_ctrl + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: espressif/rmaker_time_sync + registry_url: https://components.espressif.com + require: private + version: ^1.0.2 + - name: espressif/rmaker_work_queue + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.8.5 + espressif/rmaker_common_events: + component_hash: + ced95feff88c368e6306ff67ff3696ac76a5273de9fe1f907a7c115d4370fe6e + dependencies: + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.0.0 + espressif/rmaker_console: + component_hash: + 24af13dad8da5ca7219203f7d6f37e888246d5adc8910ea3e018fac84492ab9b + dependencies: + - name: espressif/rmaker_system_ctrl + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: espressif/rmaker_time_sync + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.0.0 + espressif/rmaker_system_ctrl: + component_hash: + b4208fbc7e99b30fb1d272cbd30e578327079a6495499d12fb466b6c2fc0d899 + dependencies: + - name: espressif/rmaker_common_events + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.0.0 + espressif/rmaker_time_sync: + component_hash: + 5797d2fcd903cad6e9142981e1d0602d7b5efa2c9197a72da8d2e05be7ef568b + dependencies: + - name: espressif/rmaker_common_events + registry_url: https://components.espressif.com + require: private + version: ^1.0.0 + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.0.2 + espressif/rmaker_work_queue: + component_hash: + 7d2a9ee4e0343eb36e1816e987dde7babe892b99873c8dc5bae15e647a0e4028 + dependencies: + - name: idf + require: private + version: '>=5.1' + source: + registry_url: https://components.espressif.com + type: service + version: 1.0.0 espressif/tinyusb: component_hash: a72b7d67472914ab76309340fd50d578b31e310963d45ad0f81144bde3314752 @@ -65,9 +417,10 @@ dependencies: version: 5.5.4 direct_dependencies: - espressif/cjson +- espressif/esp_matter - espressif/esp_tinyusb - espressif/mqtt - idf -manifest_hash: f0d438b2b6a63a6d50fc9bb059765c7ee2a95c05ac2541c179e9064331c07f0e +manifest_hash: fb55a359d8a152f0d34963a4f2b6c07f2e0120e4dd222dab1d9a780b952fec48 target: esp32s3 version: 2.0.0 diff --git a/apps/gateway/main/CMakeLists.txt b/apps/gateway/main/CMakeLists.txt index 8845d3a..cafeeaa 100644 --- a/apps/gateway/main/CMakeLists.txt +++ b/apps/gateway/main/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register( SRCS "app_main.cpp" - REQUIRES gateway_core gateway_controller gateway_network gateway_bridge gateway_cache dali_domain gateway_runtime gateway_ble gateway_usb_setup gateway_tridonic_hid gateway_485_control gateway_knx log + REQUIRES gateway_core gateway_controller gateway_network gateway_bridge gateway_cache dali_domain gateway_runtime gateway_ble gateway_matter gateway_usb_setup gateway_tridonic_hid gateway_485_control gateway_knx log ) set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17) diff --git a/apps/gateway/main/Kconfig.projbuild b/apps/gateway/main/Kconfig.projbuild index a6ec653..e715f32 100644 --- a/apps/gateway/main/Kconfig.projbuild +++ b/apps/gateway/main/Kconfig.projbuild @@ -1658,6 +1658,71 @@ config GATEWAY_START_SMARTCONFIG_ENABLED help Starts ESP-Touch provisioning at boot. Disabled by default so Wi-Fi stays off unless configured. +menu "Matter-to-DALI Bridge" + +config GATEWAY_MATTER_SUPPORTED + bool "Enable ESP-Matter DALI bridge" + default y + help + Builds the development Matter bridge and dynamically binds discovered + DALI control gear. ESP-Matter owns NimBLE while this option is enabled, + so the legacy gateway BLE GATT transport is not started in this build. + +config GATEWAY_MATTER_MAX_BRIDGED_DEVICES + int "Maximum bridged DALI devices" + depends on GATEWAY_MATTER_SUPPORTED + range 1 16 + default 16 + help + Limits dynamic Matter endpoints and DALI startup discovery work. Every + DALI device type 0 through 8 remains supported regardless of this count. + +config GATEWAY_MATTER_SCAN_START_DELAY_MS + int "DALI discovery startup delay ms" + depends on GATEWAY_MATTER_SUPPORTED + range 0 30000 + default 2000 + +config GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS + int "Delay between discovered DALI addresses ms" + depends on GATEWAY_MATTER_SUPPORTED + range 0 1000 + default 20 + +config GATEWAY_MATTER_SCAN_TASK_STACK_SIZE + int "Matter DALI scan task stack bytes" + depends on GATEWAY_MATTER_SUPPORTED + range 6144 16384 + default 8192 + +config GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO + int "Matter Wi-Fi provisioning button GPIO" + depends on GATEWAY_MATTER_SUPPORTED && GATEWAY_SMARTCONFIG_SUPPORTED + range -1 48 + default -1 + help + Long-press GPIO that starts Wi-Fi SmartConfig and reopens the Matter + commissioning window. Set to -1 to leave this development path disabled. + +config GATEWAY_MATTER_WIFI_PROVISION_BUTTON_ACTIVE_LOW + bool "Matter Wi-Fi provisioning button is active low" + depends on GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO >= 0 + default y + +config GATEWAY_MATTER_WIFI_PROVISION_LONG_PRESS_MS + int "Matter Wi-Fi provisioning long press ms" + depends on GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO >= 0 + range 1000 15000 + default 5000 + +config GATEWAY_MATTER_BUTTON_TASK_STACK_SIZE + int "Matter provisioning button task stack bytes" + depends on GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO >= 0 + range 3072 8192 + default 4096 + +endmenu + config GATEWAY_SMARTCONFIG_TIMEOUT_SEC int "ESP-Touch smartconfig timeout seconds" depends on GATEWAY_SMARTCONFIG_SUPPORTED diff --git a/apps/gateway/main/app_main.cpp b/apps/gateway/main/app_main.cpp index eb62a7a..d65ba3b 100644 --- a/apps/gateway/main/app_main.cpp +++ b/apps/gateway/main/app_main.cpp @@ -4,6 +4,7 @@ #include "gateway_cache.hpp" #include "gateway_controller.hpp" #include "gateway_core.hpp" +#include "gateway_matter.hpp" #include "gateway_network.hpp" #include "gateway_runtime.hpp" #include "gateway_485_control.hpp" @@ -74,6 +75,34 @@ #define CONFIG_GATEWAY_BUTTON_TASK_STACK_SIZE 8192 #endif +#ifndef CONFIG_GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO +#define CONFIG_GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO -1 +#endif + +#ifndef CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES +#define CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES 16 +#endif + +#ifndef CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS +#define CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS 2000 +#endif + +#ifndef CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS +#define CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS 20 +#endif + +#ifndef CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE +#define CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE 8192 +#endif + +#ifndef CONFIG_GATEWAY_MATTER_WIFI_PROVISION_LONG_PRESS_MS +#define CONFIG_GATEWAY_MATTER_WIFI_PROVISION_LONG_PRESS_MS 5000 +#endif + +#ifndef CONFIG_GATEWAY_MATTER_BUTTON_TASK_STACK_SIZE +#define CONFIG_GATEWAY_MATTER_BUTTON_TASK_STACK_SIZE 4096 +#endif + #ifndef CONFIG_GATEWAY_USB_SETUP_CHANNEL_INDEX #define CONFIG_GATEWAY_USB_SETUP_CHANNEL_INDEX 0 #endif @@ -351,12 +380,18 @@ constexpr bool kEthernetStartupEnabled = true; constexpr bool kEthernetStartupEnabled = false; #endif -#ifdef CONFIG_GATEWAY_BLE_SUPPORTED +#if defined(CONFIG_GATEWAY_BLE_SUPPORTED) && !defined(CONFIG_GATEWAY_MATTER_SUPPORTED) constexpr bool kBleSupported = true; #else constexpr bool kBleSupported = false; #endif +#ifdef CONFIG_GATEWAY_MATTER_SUPPORTED +constexpr bool kMatterSupported = true; +#else +constexpr bool kMatterSupported = false; +#endif + #ifdef CONFIG_GATEWAY_START_BLE_ENABLED constexpr bool kBleStartupEnabled = true; #else @@ -563,6 +598,7 @@ std::unique_ptr s_cache; std::unique_ptr s_controller; std::unique_ptr s_bridge; std::unique_ptr s_network; +std::unique_ptr s_matter_bridge; std::unique_ptr s_ble_bridge; std::unique_ptr s_uart0_control_bridge; std::unique_ptr s_usb_setup_bridge; @@ -1461,6 +1497,32 @@ extern "C" void app_main(void) { ESP_ERROR_CHECK(s_bridge->start()); } + if (kMatterSupported) { + gateway::GatewayMatterBridgeConfig matter_config; + matter_config.enabled = true; + matter_config.max_bridged_devices = CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES; + matter_config.scan_start_delay_ms = CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS; + matter_config.scan_address_delay_ms = CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS; + matter_config.scan_task_stack_size = CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE; + matter_config.wifi_provision_button_gpio = + CONFIG_GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO; +#ifdef CONFIG_GATEWAY_MATTER_WIFI_PROVISION_BUTTON_ACTIVE_LOW + matter_config.wifi_provision_button_active_low = true; +#else + matter_config.wifi_provision_button_active_low = false; +#endif + matter_config.wifi_provision_long_press_ms = + CONFIG_GATEWAY_MATTER_WIFI_PROVISION_LONG_PRESS_MS; + matter_config.button_task_stack_size = CONFIG_GATEWAY_MATTER_BUTTON_TASK_STACK_SIZE; + matter_config.wifi_provisioning_callback = []() { + return s_network != nullptr ? s_network->startWifiProvisioning() + : ESP_ERR_NOT_SUPPORTED; + }; + s_matter_bridge = + std::make_unique(*s_dali_domain, matter_config); + ESP_ERROR_CHECK(s_matter_bridge->start()); + } + if (profile.enable_ble) { s_ble_bridge = std::make_unique(*s_controller, *s_runtime, *s_dali_domain); diff --git a/apps/gateway/sdkconfig b/apps/gateway/sdkconfig index 8d3ba0b..f3827b3 100644 --- a/apps/gateway/sdkconfig +++ b/apps/gateway/sdkconfig @@ -725,6 +725,18 @@ CONFIG_GATEWAY_ESPNOW_SETUP_SUPPORTED=y CONFIG_GATEWAY_SMARTCONFIG_SUPPORTED=y # CONFIG_GATEWAY_START_ESPNOW_SETUP_ENABLED is not set # CONFIG_GATEWAY_START_SMARTCONFIG_ENABLED is not set + +# +# Matter-to-DALI Bridge +# +CONFIG_GATEWAY_MATTER_SUPPORTED=y +CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES=16 +CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS=2000 +CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS=20 +CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE=8192 +CONFIG_GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO=-1 +# end of Matter-to-DALI Bridge + CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC=60 CONFIG_GATEWAY_ETHERNET_SUPPORTED=y CONFIG_GATEWAY_START_ETHERNET_ENABLED=y @@ -2304,8 +2316,9 @@ CONFIG_LOG_IN_IRAM=y CONFIG_LWIP_ENABLE=y CONFIG_LWIP_LOCAL_HOSTNAME="espressif" CONFIG_LWIP_TCPIP_TASK_PRIO=18 -# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set -# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_TCPIP_CORE_LOCKING=y +# CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT is not set +CONFIG_LWIP_CHECK_THREAD_SAFETY=y CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y # CONFIG_LWIP_L2_TO_L3_COPY is not set # CONFIG_LWIP_IRAM_OPTIMIZATION is not set @@ -2621,7 +2634,7 @@ CONFIG_MBEDTLS_ECP_NIST_OPTIM=y # CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM is not set # CONFIG_MBEDTLS_POLY1305_C is not set # CONFIG_MBEDTLS_CHACHA20_C is not set -# CONFIG_MBEDTLS_HKDF_C is not set +CONFIG_MBEDTLS_HKDF_C=y # CONFIG_MBEDTLS_THREADING_C is not set CONFIG_MBEDTLS_ERROR_STRINGS=y CONFIG_MBEDTLS_FS_IO=y @@ -2969,6 +2982,521 @@ CONFIG_CJSON_NESTING_LIMIT=1000 CONFIG_CJSON_CIRCULAR_LIMIT=10000 # end of cJSON +# +# ESP serial flasher +# +CONFIG_SERIAL_FLASHER_MD5_ENABLED=y +CONFIG_SERIAL_FLASHER_RESET_HOLD_TIME_MS=100 +CONFIG_SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50 +# end of ESP serial flasher + +# +# Diagnostics data store +# +CONFIG_DIAG_DATA_STORE_RTC=y +# CONFIG_DIAG_DATA_STORE_RAM is not set +# CONFIG_DIAG_DATA_STORE_FLASH is not set +# CONFIG_DIAG_DATA_STORE_DBG_PRINTS is not set +CONFIG_DIAG_DATA_STORE_REPORTING_WATERMARK_PERCENT=80 + +# +# RTC Store +# +CONFIG_RTC_STORE_DATA_SIZE=6144 +CONFIG_RTC_STORE_CRITICAL_DATA_SIZE=4096 +# end of RTC Store +# end of Diagnostics data store + +# +# Diagnostics +# +CONFIG_DIAG_LOG_MSG_ARG_FORMAT_TLV=y +# CONFIG_DIAG_LOG_MSG_ARG_FORMAT_STRING is not set +CONFIG_DIAG_LOG_MSG_ARG_MAX_SIZE=64 +CONFIG_DIAG_LOG_DROP_WIFI_LOGS=y +# CONFIG_DIAG_ENABLE_WRAP_LOG_FUNCTIONS is not set +CONFIG_DIAG_ENABLE_METRICS=y +CONFIG_DIAG_METRICS_MAX_COUNT=20 +CONFIG_DIAG_ENABLE_HEAP_METRICS=y +CONFIG_DIAG_HEAP_POLLING_INTERVAL=30 +CONFIG_DIAG_ENABLE_WIFI_METRICS=y +CONFIG_DIAG_WIFI_POLLING_INTERVAL=30 +CONFIG_DIAG_ENABLE_VARIABLES=y +CONFIG_DIAG_VARIABLES_MAX_COUNT=20 +CONFIG_DIAG_ENABLE_NETWORK_VARIABLES=y +# CONFIG_DIAG_MORE_NETWORK_VARS is not set +# CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP is not set +# end of Diagnostics + +# +# ESP Insights +# +# CONFIG_ESP_INSIGHTS_ENABLED is not set +# CONFIG_ESP_INSIGHTS_TRANSPORT_MQTT is not set +CONFIG_ESP_INSIGHTS_TRANSPORT_HTTPS=y +CONFIG_ESP_INSIGHTS_TRANSPORT_HTTPS_HOST="https://client.insights.espressif.com" +CONFIG_ESP_INSIGHTS_CLOUD_POST_MIN_INTERVAL_SEC=60 +CONFIG_ESP_INSIGHTS_CLOUD_POST_MAX_INTERVAL_SEC=240 +CONFIG_ESP_INSIGHTS_META_VERSION_10=y +# end of ESP Insights + +# +# CHIP Core +# + +# +# General Options +# +CONFIG_MAX_EXCHANGE_CONTEXTS=8 +CONFIG_MAX_FABRICS=5 +CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS=8 +# CONFIG_ENABLE_PW_RPC is not set +CONFIG_USE_MINIMAL_MDNS=y +# CONFIG_ENABLE_CHIP_SHELL is not set +# CONFIG_ENABLE_CHIP_CONTROLLER_BUILD is not set +# CONFIG_DISABLE_IPV4 is not set +# CONFIG_DISABLE_READ_CLIENT is not set +CONFIG_ENABLE_PERSIST_SUBSCRIPTIONS=y +# CONFIG_BUILD_CHIP_TESTS is not set +CONFIG_DISPATCH_EVENT_LONG_DISPATCH_TIME_WARNING_THRESHOLD_MS=700 +# CONFIG_CHIP_LOG_FILTERING is not set +# CONFIG_CHIP_SYSTEM_CONFIG_POOL_USE_HEAP is not set +CONFIG_MAX_GROUP_ENDPOINTS_PER_FABRIC=1 +CONFIG_MAX_GROUPS_PER_FABRIC_PER_ENDPOINT=4 +CONFIG_MAX_GROUP_KEYS_PER_FABRIC=3 +# CONFIG_CHIP_DEVICE_ENABLE_DYNAMIC_SERVER is not set +# CONFIG_CHIP_MEM_ALLOC_MODE_INTERNAL is not set +# CONFIG_CHIP_MEM_ALLOC_MODE_EXTERNAL is not set +CONFIG_CHIP_MEM_ALLOC_MODE_DEFAULT=y +# end of General Options + +# +# Networking Options +# +CONFIG_NUM_TCP_ENDPOINTS=8 +CONFIG_NUM_UDP_ENDPOINTS=8 +CONFIG_ENABLE_ENDPOINT_QUEUE_FILTER=y +CONFIG_USE_TCPIP_CORE_LOCK_FOR_THREAD_SAFETY=y +# CONFIG_USE_LWIP_PBUF_RAM_PACKETBUFFER is not set +# end of Networking Options + +# +# System Options +# +CONFIG_NUM_TIMERS=32 +# CONFIG_ENABLE_OTA_REQUESTOR is not set +CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y +# CONFIG_ENABLE_SNTP_TIME_SYNC is not set +# end of System Options + +# +# Security Options +# + +# +# Debugging +# +# CONFIG_SECURITY_TEST_MODE is not set +# end of Debugging +# end of Security Options +# end of CHIP Core + +# +# CHIP Device Layer +# + +# +# General Options +# +CONFIG_CHIP_PROJECT_CONFIG="" +CONFIG_CHIP_TASK_STACK_SIZE=8192 +CONFIG_CHIP_TASK_PRIORITY=1 +CONFIG_MAX_EVENT_QUEUE_SIZE=40 +# CONFIG_ENABLE_EXTENDED_DISCOVERY is not set +# CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE is not set +# CONFIG_ENABLE_BG_EVENT_PROCESSING is not set +# end of General Options + +# +# Device Identification Options +# +CONFIG_DEVICE_VENDOR_ID=0xFFF2 +CONFIG_DEVICE_PRODUCT_ID=0x8001 +CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION=0 +CONFIG_DEVICE_SOFTWARE_VERSION_NUMBER=0 +CONFIG_DEVICE_TYPE=0 +# end of Device Identification Options + +# +# WiFi Station Options +# +CONFIG_ENABLE_WIFI_STATION=y +CONFIG_DEFAULT_WIFI_SSID="" +CONFIG_DEFAULT_WIFI_PASSWORD="" +CONFIG_WIFI_STATION_RECONNECT_INTERVAL=100 +CONFIG_MAX_SCAN_NETWORKS_RESULTS=10 +CONFIG_WIFI_SCAN_COMPLETION_TIMEOUT=10000 +CONFIG_WIFI_CONNECTIVITY_TIMEOUT=30000 +# end of WiFi Station Options + +# +# BLE Options +# +CONFIG_ENABLE_CHIPOBLE=y +CONFIG_BLE_DEVICE_NAME_PREFIX="MATTER-" +CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN=40 +CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX=40 +CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN=800 +CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX=800 +CONFIG_CHIPOBLE_SINGLE_CONNECTION=y +CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART=0 +CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y +# end of BLE Options + +# +# Ethernet Options +# +CONFIG_GPIO_RANGE_MIN=0 +CONFIG_GPIO_RANGE_MAX=48 +CONFIG_ETH_MDC_GPIO=23 +CONFIG_ETH_MDIO_GPIO=18 +CONFIG_ETH_PHY_RST_GPIO=5 +CONFIG_ETH_PHY_ADDR=1 +# end of Ethernet Options + +# +# Commissioning options +# +# CONFIG_ENABLE_ROTATING_DEVICE_ID is not set +CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER=y +CONFIG_ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER=y +# CONFIG_ENABLE_ESP32_DEVICE_INFO_PROVIDER is not set +# CONFIG_ENABLE_ESP32_LOCATIONCAPABILITY is not set +# CONFIG_SEC_CERT_DAC_PROVIDER is not set +# CONFIG_ENABLE_SET_CERT_DECLARATION_API is not set +# end of Commissioning options + +# +# Diagnostics Options +# +# CONFIG_ENABLE_ESP_DIAGNOSTICS is not set +# end of Diagnostics Options + +# +# Testing Options +# +CONFIG_USE_TEST_SERIAL_NUMBER="TEST_SN" +# CONFIG_ENABLE_TEST_SETUP_PARAMS is not set +# CONFIG_TEST_EVENT_TRIGGER_ENABLED is not set +# end of Testing Options + +# +# Network Telemetry Options +# +# CONFIG_ENABLE_WIFI_TELEMETRY is not set +# CONFIG_ENABLE_THREAD_TELEMETRY is not set +# CONFIG_ENABLE_THREAD_TELEMETRY_FULL is not set +# CONFIG_ENABLE_TUNNEL_TELEMETRY is not set +CONFIG_ENABLE_ETHERNET_TELEMETRY=y +# end of Network Telemetry Options + +# +# Event Logging Options +# +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=4096 +CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE=1024 +CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE=1024 +CONFIG_CHIP_CONFIG_IM_PRETTY_PRINT=y +CONFIG_CHIP_LOG_DEFAULT_LEVEL_EQUALS_LOG_DEFAULT_LEVEL=y +# CONFIG_CHIP_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_CHIP_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_CHIP_LOG_DEFAULT_LEVEL_PROGRESS is not set +# CONFIG_CHIP_LOG_DEFAULT_LEVEL_DETAIL is not set +# CONFIG_CHIP_LOG_DEFAULT_LEVEL_AUTOMATION is not set +CONFIG_CHIP_LOG_DEFAULT_LEVEL=3 +# end of Event Logging Options + +# CONFIG_CHIP_ENABLE_BDX_LOG_TRANSFER is not set + +# +# Matter OTA Image +# +# CONFIG_CHIP_OTA_IMAGE_BUILD is not set +# end of Matter OTA Image + +# +# External Platform +# +# CONFIG_CHIP_ENABLE_EXTERNAL_PLATFORM is not set +# end of External Platform + +# +# Matter Manufacturing Options +# +CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL="nvs" +CONFIG_CHIP_CONFIG_NAMESPACE_PARTITION_LABEL="nvs" +CONFIG_CHIP_COUNTERS_NAMESPACE_PARTITION_LABEL="nvs" +CONFIG_CHIP_KVS_NAMESPACE_PARTITION_LABEL="nvs" +# end of Matter Manufacturing Options + +# +# Commissioning Window Options +# +CONFIG_CHIP_DISCOVERY_TIMEOUT_SECS=900 +# end of Commissioning Window Options + +# +# Enable ESP32 as a BLE Commissioner +# +# CONFIG_ENABLE_ESP32_BLE_CONTROLLER is not set +# end of Enable ESP32 as a BLE Commissioner + +# +# Enable BLE Extended Announcement +# +# CONFIG_ENABLE_BLE_EXT_ANNOUNCEMENT is not set +# end of Enable BLE Extended Announcement + +# +# Message Reliable Protocol Options +# +CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL_FOR_WIFI_ETHERNET=300 +CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL_FOR_WIFI_ETHERNET=500 +CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST_FOR_WIFI_ETHERNET=0 +CONFIG_MRP_MAX_RETRANS=4 +# end of Message Reliable Protocol Options + +# +# Matter TCP transport options +# +# CONFIG_ENABLE_TCP_TRANSPORT is not set +# end of Matter TCP transport options + +# +# Network Commissioning Driver Endpoint Id +# +CONFIG_WIFI_NETWORK_COMMISSIONING_DRIVER=y +CONFIG_WIFI_NETWORK_ENDPOINT_ID=0 +# CONFIG_ETHERNET_NETWORK_COMMISSIONING_DRIVER is not set +# end of Network Commissioning Driver Endpoint Id + +# +# Cluster Configuration Options +# +# CONFIG_ENABLE_ACCESS_RESTRICTIONS is not set +# end of Cluster Configuration Options +# end of CHIP Device Layer + +# +# ESP Matter +# +CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT=16 +CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST=259 +CONFIG_ESP_MATTER_NVS_PART_NAME="nvs" +CONFIG_ESP_MATTER_DEFERRED_ATTR_PERSISTENCE_TIME_MS=3000 +# CONFIG_EXAMPLE_DAC_PROVIDER is not set +CONFIG_FACTORY_PARTITION_DAC_PROVIDER=y +# CONFIG_CUSTOM_DAC_PROVIDER is not set +CONFIG_FACTORY_COMMISSIONABLE_DATA_PROVIDER=y +# CONFIG_SEC_CERT_COMMISSIONABLE_DATA_PROVIDER is not set +# CONFIG_CUSTOM_COMMISSIONABLE_DATA_PROVIDER is not set +# CONFIG_EXAMPLE_DEVICE_INSTANCE_INFO_PROVIDER is not set +CONFIG_FACTORY_DEVICE_INSTANCE_INFO_PROVIDER=y +# CONFIG_SEC_CERT_DEVICE_INSTANCE_INFO_PROVIDER is not set +# CONFIG_CUSTOM_DEVICE_INSTANCE_INFO_PROVIDER is not set +CONFIG_NONE_DEVICE_INFO_PROVIDER=y +# CONFIG_CUSTOM_DEVICE_INFO_PROVIDER is not set +CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT=18 +CONFIG_ESP_MATTER_MODE_SELECT_CLUSTER_ENDPOINT_COUNT=0 +CONFIG_ESP_MATTER_TEMPERATURE_CONTROL_CLUSTER_ENDPOINT_COUNT=0 +CONFIG_ESP_MATTER_SCENES_TABLE_SIZE=16 +CONFIG_ESP_MATTER_BINDING_TABLE_SIZE=10 +CONFIG_ESP_MATTER_MEM_ALLOC_MODE_INTERNAL=y +# CONFIG_ESP_MATTER_MEM_ALLOC_MODE_EXTERNAL is not set +# CONFIG_ESP_MATTER_MEM_ALLOC_MODE_DEFAULT is not set +CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y +CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER=y +# CONFIG_ESP_MATTER_ENABLE_OPENTHREAD is not set +CONFIG_CUSTOM_NETWORK_CONFIG=y + +# +# Select Supported Matter Clusters +# +CONFIG_SUPPORT_ACCESS_CONTROL_CLUSTER=y +# CONFIG_SUPPORT_ACCOUNT_LOGIN_CLUSTER is not set +# CONFIG_SUPPORT_ACTIONS_CLUSTER is not set +# CONFIG_SUPPORT_ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER is not set +CONFIG_SUPPORT_ADMINISTRATOR_COMMISSIONING_CLUSTER=y +# CONFIG_SUPPORT_AIR_QUALITY_CLUSTER is not set +# CONFIG_SUPPORT_APPLICATION_BASIC_CLUSTER is not set +# CONFIG_SUPPORT_APPLICATION_LAUNCHER_CLUSTER is not set +# CONFIG_SUPPORT_AUDIO_OUTPUT_CLUSTER is not set +CONFIG_SUPPORT_BASIC_INFORMATION_CLUSTER=y +CONFIG_SUPPORT_BINDING_CLUSTER=y +# CONFIG_SUPPORT_BOOLEAN_STATE_CLUSTER is not set +# CONFIG_SUPPORT_BOOLEAN_STATE_CONFIGURATION_CLUSTER is not set +CONFIG_SUPPORT_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER=y +# CONFIG_SUPPORT_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_CAMERA_AV_STREAM_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_CARBON_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_CARBON_MONOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_CHANNEL_CLUSTER is not set +# CONFIG_SUPPORT_CHIME_CLUSTER is not set +# CONFIG_SUPPORT_CLOSURE_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_CLOSURE_DIMENSION_CLUSTER is not set +CONFIG_SUPPORT_COLOR_CONTROL_CLUSTER=y +# CONFIG_SUPPORT_COMMISSIONER_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_COMMODITY_METERING_CLUSTER is not set +# CONFIG_SUPPORT_COMMODITY_PRICE_CLUSTER is not set +# CONFIG_SUPPORT_COMMODITY_TARIFF_CLUSTER is not set +# CONFIG_SUPPORT_CONTENT_LAUNCHER_CLUSTER is not set +# CONFIG_SUPPORT_CONTENT_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_CONTENT_APP_OBSERVER_CLUSTER is not set +CONFIG_SUPPORT_DESCRIPTOR_CLUSTER=y +# CONFIG_SUPPORT_DEVICE_ENERGY_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_DEVICE_ENERGY_MANAGEMENT_MODE_CLUSTER is not set +# CONFIG_SUPPORT_DIAGNOSTIC_LOGS_CLUSTER is not set +# CONFIG_SUPPORT_DISHWASHER_ALARM_CLUSTER is not set +# CONFIG_SUPPORT_DISHWASHER_MODE_CLUSTER is not set +# CONFIG_SUPPORT_ELECTRICAL_GRID_CONDITIONS_CLUSTER is not set +# CONFIG_SUPPORT_GROUPCAST_CLUSTER is not set +# CONFIG_SUPPORT_METER_IDENTIFICATION_CLUSTER is not set +# CONFIG_SUPPORT_MICROWAVE_OVEN_MODE_CLUSTER is not set +# CONFIG_SUPPORT_DOOR_LOCK_CLUSTER is not set +# CONFIG_SUPPORT_ECOSYSTEM_INFORMATION_CLUSTER is not set +# CONFIG_SUPPORT_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_ELECTRICAL_POWER_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_ENERGY_EVSE_CLUSTER is not set +# CONFIG_SUPPORT_ENERGY_EVSE_MODE_CLUSTER is not set +# CONFIG_SUPPORT_ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER is not set +# CONFIG_SUPPORT_ENERGY_PREFERENCE_CLUSTER is not set +# CONFIG_SUPPORT_FAN_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_FAULT_INJECTION_CLUSTER is not set +# CONFIG_SUPPORT_FIXED_LABEL_CLUSTER is not set +# CONFIG_SUPPORT_FORMALDEHYDE_CONCENTRATION_MEASUREMENT_CLUSTER is not set +CONFIG_SUPPORT_GENERAL_COMMISSIONING_CLUSTER=y +CONFIG_SUPPORT_GENERAL_DIAGNOSTICS_CLUSTER=y +CONFIG_SUPPORT_GROUPS_CLUSTER=y +# CONFIG_SUPPORT_HEPA_FILTER_MONITORING_CLUSTER is not set +CONFIG_SUPPORT_GROUP_KEY_MANAGEMENT_CLUSTER=y +# CONFIG_SUPPORT_ICD_MANAGEMENT_CLUSTER is not set +CONFIG_SUPPORT_IDENTIFY_CLUSTER=y +# CONFIG_SUPPORT_JOINT_FABRIC_DATASTORE_CLUSTER is not set +# CONFIG_SUPPORT_JOINT_FABRIC_ADMINISTRATOR_CLUSTER is not set +# CONFIG_SUPPORT_KEYPAD_INPUT_CLUSTER is not set +# CONFIG_SUPPORT_LAUNDRY_WASHER_MODE_CLUSTER is not set +CONFIG_SUPPORT_LEVEL_CONTROL_CLUSTER=y +# CONFIG_SUPPORT_LOCALIZATION_CONFIGURATION_CLUSTER is not set +# CONFIG_SUPPORT_LOW_POWER_CLUSTER is not set +# CONFIG_SUPPORT_MEDIA_INPUT_CLUSTER is not set +# CONFIG_SUPPORT_MEDIA_PLAYBACK_CLUSTER is not set +# CONFIG_SUPPORT_MICROWAVE_OVEN_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_MESSAGES_CLUSTER is not set +# CONFIG_SUPPORT_MODE_SELECT_CLUSTER is not set +# CONFIG_SUPPORT_NETWORK_COMMISSIONING_CLUSTER is not set +# CONFIG_SUPPORT_NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_PUSH_AV_STREAM_TRANSPORT_CLUSTER is not set +# CONFIG_SUPPORT_SAMPLE_MEI_CLUSTER is not set +# CONFIG_SUPPORT_OCCUPANCY_SENSING_CLUSTER is not set +CONFIG_SUPPORT_ON_OFF_CLUSTER=y +# CONFIG_SUPPORT_POWER_TOPOLOGY_CLUSTER is not set +CONFIG_SUPPORT_OPERATIONAL_CREDENTIALS_CLUSTER=y +# CONFIG_SUPPORT_OPERATIONAL_STATE_CLUSTER is not set +# CONFIG_SUPPORT_OPERATIONAL_STATE_OVEN_CLUSTER is not set +# CONFIG_SUPPORT_OPERATIONAL_STATE_RVC_CLUSTER is not set +# CONFIG_SUPPORT_OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER is not set +# CONFIG_SUPPORT_OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER is not set +# CONFIG_SUPPORT_OVEN_MODE_CLUSTER is not set +# CONFIG_SUPPORT_OZONE_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_PM10_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_PM1_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_PM2_5_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_POWER_SOURCE_CLUSTER is not set +# CONFIG_SUPPORT_POWER_SOURCE_CONFIGURATION_CLUSTER is not set +# CONFIG_SUPPORT_PUMP_CONFIGURATION_AND_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_RADON_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_REFRIGERATOR_ALARM_CLUSTER is not set +# CONFIG_SUPPORT_REFRIGERATOR_AND_TEMPERATURE_CONTROLLED_CABINET_MODE_CLUSTER is not set +# CONFIG_SUPPORT_RVC_CLEAN_MODE_CLUSTER is not set +# CONFIG_SUPPORT_RVC_RUN_MODE_CLUSTER is not set +CONFIG_SUPPORT_SCENES_CLUSTER=y +# CONFIG_SUPPORT_SERVICE_AREA_CLUSTER is not set +# CONFIG_SUPPORT_SMOKE_CO_ALARM_CLUSTER is not set +# CONFIG_SUPPORT_SOFTWARE_DIAGNOSTICS_CLUSTER is not set +# CONFIG_SUPPORT_SOIL_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_SWITCH_CLUSTER is not set +# CONFIG_SUPPORT_TARGET_NAVIGATOR_CLUSTER is not set +# CONFIG_SUPPORT_TEMPERATURE_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_THERMOSTAT_CLUSTER is not set +# CONFIG_SUPPORT_THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER is not set +# CONFIG_SUPPORT_THREAD_BORDER_ROUTER_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_THREAD_NETWORK_DIAGNOSTICS_CLUSTER is not set +# CONFIG_SUPPORT_THREAD_NETWORK_DIRECTORY_CLUSTER is not set +# CONFIG_SUPPORT_TIME_FORMAT_LOCALIZATION_CLUSTER is not set +# CONFIG_SUPPORT_TIME_SYNCHRONIZATION_CLUSTER is not set +# CONFIG_SUPPORT_TIMER_CLUSTER is not set +# CONFIG_SUPPORT_TLS_CERTIFICATE_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_TLS_CLIENT_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_TVOC_CONCENTRATION_MEASUREMENT_CLUSTER is not set +# CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER is not set +# CONFIG_SUPPORT_UNIT_TESTING_CLUSTER is not set +# CONFIG_SUPPORT_USER_LABEL_CLUSTER is not set +# CONFIG_SUPPORT_VALVE_CONFIGURATION_AND_CONTROL_CLUSTER is not set +# CONFIG_SUPPORT_WAKE_ON_LAN_CLUSTER is not set +# CONFIG_SUPPORT_LAUNDRY_WASHER_CONTROLS_CLUSTER is not set +# CONFIG_SUPPORT_LAUNDRY_DRYER_CONTROLS_CLUSTER is not set +# CONFIG_SUPPORT_WEB_RTC_TRANSPORT_PROVIDER_CLUSTER is not set +# CONFIG_SUPPORT_WEB_RTC_TRANSPORT_REQUESTOR_CLUSTER is not set +# CONFIG_SUPPORT_WIFI_NETWORK_DIAGNOSTICS_CLUSTER is not set +# CONFIG_SUPPORT_WIFI_NETWORK_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_WINDOW_COVERING_CLUSTER is not set +# CONFIG_SUPPORT_WATER_HEATER_MANAGEMENT_CLUSTER is not set +# CONFIG_SUPPORT_WATER_HEATER_MODE_CLUSTER is not set +# CONFIG_SUPPORT_ZONE_MANAGEMENT_CLUSTER is not set +# end of Select Supported Matter Clusters +# end of ESP Matter + +# +# ESP Matter Bridge +# +CONFIG_ESP_MATTER_AGGREGATOR_ENDPOINT_COUNT=1 +CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME="nvs" +# end of ESP Matter Bridge + +# +# ESP Matter Console +# +CONFIG_ESP_MATTER_CONSOLE_TASK_STACK=2048 +CONFIG_ESP_MATTER_CONSOLE_MAX_COMMANDS=10 +# end of ESP Matter Console + +# +# ESP Matter Controller +# +# CONFIG_ESP_MATTER_CONTROLLER_ENABLE is not set +# end of ESP Matter Controller + +# +# ESP Matter OTA Provider +# +# CONFIG_ESP_MATTER_OTA_PROVIDER_ENABLED is not set +# end of ESP Matter OTA Provider + +# +# OpenThread RCP Update +# +# CONFIG_AUTO_UPDATE_RCP is not set +# CONFIG_CREATE_OTA_IMAGE_WITH_RCP_FW is not set +# end of OpenThread RCP Update + +# +# ESP Secure Cert Manager +# +CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=y +# CONFIG_ESP_SECURE_CERT_SUPPORT_LEGACY_FORMATS is not set +# CONFIG_ESP_SECURE_CERT_WRITE_ENABLE_LOGGING is not set +# end of ESP Secure Cert Manager + # # TinyUSB Stack # @@ -3056,6 +3584,55 @@ CONFIG_TINYUSB_VENDOR_COUNT=0 # end of Vendor Specific Interface # end of TinyUSB Stack +# +# jsmn +# +# CONFIG_JSMN_PARENT_LINKS is not set +# CONFIG_JSMN_STRICT is not set +# CONFIG_JSMN_STATIC is not set +# end of jsmn + +# +# mDNS +# +CONFIG_MDNS_MAX_INTERFACES=3 +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_ACTION_QUEUE_LEN=16 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 + +# +# MDNS Memory Configuration +# +# CONFIG_MDNS_TASK_CREATE_FROM_SPIRAM is not set +CONFIG_MDNS_TASK_CREATE_FROM_INTERNAL=y +# CONFIG_MDNS_MEMORY_ALLOC_SPIRAM is not set +CONFIG_MDNS_MEMORY_ALLOC_INTERNAL=y +# CONFIG_MDNS_MEMORY_CUSTOM_IMPL is not set +# end of MDNS Memory Configuration + +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +# CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES is not set +# CONFIG_MDNS_ENABLE_DEBUG_PRINTS is not set +CONFIG_MDNS_ENABLE_CONSOLE_CLI=y +# CONFIG_MDNS_RESPOND_REVERSE_QUERIES is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y + +# +# MDNS Predefined interfaces +# +CONFIG_MDNS_PREDEF_NETIF_STA=y +CONFIG_MDNS_PREDEF_NETIF_AP=y +CONFIG_MDNS_PREDEF_NETIF_ETH=y +# end of MDNS Predefined interfaces +# end of mDNS + # # ESP-MQTT Configurations # @@ -3073,6 +3650,55 @@ CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED=y CONFIG_MQTT_USE_CORE_1=y # CONFIG_MQTT_CUSTOM_OUTBOX is not set # end of ESP-MQTT Configurations + +# +# ESP RainMaker Command-Response +# +CONFIG_ESP_RMAKER_MAX_COMMANDS=10 +# end of ESP RainMaker Command-Response + +# +# ESP RainMaker Common +# +CONFIG_ESP_RMAKER_LIB_ESP_MQTT=y +# CONFIG_ESP_RMAKER_LIB_AWS_IOT is not set +CONFIG_ESP_RMAKER_MQTT_GLUE_LIB=1 +CONFIG_ESP_RMAKER_MQTT_PORT_443=y +# CONFIG_ESP_RMAKER_MQTT_PORT_8883 is not set +CONFIG_ESP_RMAKER_MQTT_PORT=1 +# CONFIG_ESP_RMAKER_MQTT_PERSISTENT_SESSION is not set +CONFIG_ESP_RMAKER_MQTT_SEND_USERNAME=y +CONFIG_ESP_RMAKER_MQTT_PRODUCT_NAME="RMDev" +CONFIG_ESP_RMAKER_MQTT_PRODUCT_VERSION="1x0" +CONFIG_ESP_RMAKER_MQTT_PRODUCT_SKU="EX00" +CONFIG_ESP_RMAKER_MQTT_USE_CERT_BUNDLE=y +CONFIG_ESP_RMAKER_MAX_MQTT_SUBSCRIPTIONS=10 +CONFIG_ESP_RMAKER_MQTT_KEEP_ALIVE_INTERVAL=120 +CONFIG_ESP_RMAKER_FACTORY_PARTITION_NAME="fctry" +CONFIG_ESP_RMAKER_FACTORY_NAMESPACE="rmaker_creds" +# end of ESP RainMaker Common + +# +# ESP RainMaker Console +# +CONFIG_ESP_RMAKER_CONSOLE_ENABLED=y +CONFIG_ESP_RMAKER_CONSOLE_TASK_STACK=4096 +CONFIG_ESP_RMAKER_CONSOLE_TASK_PRIORITY=5 +# end of ESP RainMaker Console + +# +# ESP RainMaker Time Sync +# +CONFIG_ESP_RMAKER_DEF_TIMEZONE="Asia/Shanghai" +CONFIG_ESP_RMAKER_SNTP_SERVER_NAME="pool.ntp.org" +# end of ESP RainMaker Time Sync + +# +# ESP RainMaker Work Queue +# +CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK=5120 +CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_PRIORITY=5 +# end of ESP RainMaker Work Queue # end of Component config # CONFIG_IDF_EXPERIMENTAL_FEATURES is not set diff --git a/apps/gateway/sdkconfig.defaults b/apps/gateway/sdkconfig.defaults index 1c83c58..bff6eb2 100644 --- a/apps/gateway/sdkconfig.defaults +++ b/apps/gateway/sdkconfig.defaults @@ -20,3 +20,177 @@ CONFIG_GATEWAY_START_ETHERNET_ENABLED=y CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE=y CONFIG_GATEWAY_KNX_DATA_SECURE_SUPPORTED=y CONFIG_TINYUSB_HID_COUNT=1 + +# Matter-to-DALI development bridge. Matter owns NimBLE in this build; wired +# Ethernet remains the default route and Wi-Fi starts only when provisioned. +CONFIG_GATEWAY_MATTER_SUPPORTED=y +CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES=16 +CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS=2000 +CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS=20 +CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE=8192 +CONFIG_GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO=-1 +CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER=y +CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y +CONFIG_ESP_MATTER_ENABLE_OPENTHREAD=n +CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT=18 +CONFIG_ESP_MATTER_AGGREGATOR_ENDPOINT_COUNT=1 +CONFIG_ESP_MATTER_NVS_PART_NAME="nvs" +CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME="nvs" +CONFIG_CUSTOM_NETWORK_CONFIG=y +CONFIG_ENABLE_WIFI_STATION=y +CONFIG_ENABLE_CHIPOBLE=y +CONFIG_ENABLE_CHIP_SHELL=n +CONFIG_MBEDTLS_HKDF_C=y +CONFIG_DEVICE_VENDOR_ID=0xFFF2 +CONFIG_DEVICE_PRODUCT_ID=0x8001 +CONFIG_TEST_EVENT_TRIGGER_ENABLED=n +CONFIG_ENABLE_WIFI_TELEMETRY=n +# Despite its legacy name, this option enables CHIP's ESP32 Ethernet platform +# path and event handling. Ethernet itself is initialized by gateway_network. +CONFIG_ENABLE_ETHERNET_TELEMETRY=y +CONFIG_ETHERNET_NETWORK_COMMISSIONING_DRIVER=n + +# Development factory providers read the burner-supplied test DAC, PAI, CD, +# and commissioning data from the ordinary unencrypted NVS partition. +CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER=y +CONFIG_ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER=y +CONFIG_FACTORY_PARTITION_DAC_PROVIDER=y +CONFIG_FACTORY_COMMISSIONABLE_DATA_PROVIDER=y +CONFIG_FACTORY_DEVICE_INSTANCE_INFO_PROVIDER=y +CONFIG_NONE_DEVICE_INFO_PROVIDER=y +CONFIG_ENABLE_TEST_SETUP_PARAMS=n +CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL="nvs" +CONFIG_SECURE_FLASH_ENC_ENABLED=n + +# Compile only the clusters needed by the root node and DALI light endpoints. +CONFIG_SUPPORT_ACCESS_CONTROL_CLUSTER=y +CONFIG_SUPPORT_ACCOUNT_LOGIN_CLUSTER=n +CONFIG_SUPPORT_ACTIONS_CLUSTER=n +CONFIG_SUPPORT_ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER=n +CONFIG_SUPPORT_ADMINISTRATOR_COMMISSIONING_CLUSTER=y +CONFIG_SUPPORT_AIR_QUALITY_CLUSTER=n +CONFIG_SUPPORT_APPLICATION_BASIC_CLUSTER=n +CONFIG_SUPPORT_APPLICATION_LAUNCHER_CLUSTER=n +CONFIG_SUPPORT_AUDIO_OUTPUT_CLUSTER=n +CONFIG_SUPPORT_BASIC_INFORMATION_CLUSTER=y +CONFIG_SUPPORT_BINDING_CLUSTER=y +CONFIG_SUPPORT_BOOLEAN_STATE_CLUSTER=n +CONFIG_SUPPORT_BOOLEAN_STATE_CONFIGURATION_CLUSTER=n +CONFIG_SUPPORT_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER=y +CONFIG_SUPPORT_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_CAMERA_AV_STREAM_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_CARBON_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_CARBON_MONOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_CHANNEL_CLUSTER=n +CONFIG_SUPPORT_CHIME_CLUSTER=n +CONFIG_SUPPORT_CLOSURE_CONTROL_CLUSTER=n +CONFIG_SUPPORT_CLOSURE_DIMENSION_CLUSTER=n +CONFIG_SUPPORT_COLOR_CONTROL_CLUSTER=y +CONFIG_SUPPORT_COMMISSIONER_CONTROL_CLUSTER=n +CONFIG_SUPPORT_COMMODITY_METERING_CLUSTER=n +CONFIG_SUPPORT_COMMODITY_PRICE_CLUSTER=n +CONFIG_SUPPORT_COMMODITY_TARIFF_CLUSTER=n +CONFIG_SUPPORT_CONTENT_LAUNCHER_CLUSTER=n +CONFIG_SUPPORT_CONTENT_CONTROL_CLUSTER=n +CONFIG_SUPPORT_CONTENT_APP_OBSERVER_CLUSTER=n +CONFIG_SUPPORT_DESCRIPTOR_CLUSTER=y +CONFIG_SUPPORT_DEVICE_ENERGY_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_DEVICE_ENERGY_MANAGEMENT_MODE_CLUSTER=n +CONFIG_SUPPORT_DIAGNOSTIC_LOGS_CLUSTER=n +CONFIG_SUPPORT_DISHWASHER_ALARM_CLUSTER=n +CONFIG_SUPPORT_DISHWASHER_MODE_CLUSTER=n +CONFIG_SUPPORT_ELECTRICAL_GRID_CONDITIONS_CLUSTER=n +CONFIG_SUPPORT_GROUPCAST_CLUSTER=n +CONFIG_SUPPORT_METER_IDENTIFICATION_CLUSTER=n +CONFIG_SUPPORT_MICROWAVE_OVEN_MODE_CLUSTER=n +CONFIG_SUPPORT_DOOR_LOCK_CLUSTER=n +CONFIG_SUPPORT_ECOSYSTEM_INFORMATION_CLUSTER=n +CONFIG_SUPPORT_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_ELECTRICAL_POWER_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_ENERGY_EVSE_CLUSTER=n +CONFIG_SUPPORT_ENERGY_EVSE_MODE_CLUSTER=n +CONFIG_SUPPORT_ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER=n +CONFIG_SUPPORT_ENERGY_PREFERENCE_CLUSTER=n +CONFIG_SUPPORT_FAN_CONTROL_CLUSTER=n +CONFIG_SUPPORT_FAULT_INJECTION_CLUSTER=n +CONFIG_SUPPORT_FIXED_LABEL_CLUSTER=n +CONFIG_SUPPORT_FORMALDEHYDE_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_GENERAL_COMMISSIONING_CLUSTER=y +CONFIG_SUPPORT_GENERAL_DIAGNOSTICS_CLUSTER=y +CONFIG_SUPPORT_GROUPS_CLUSTER=y +CONFIG_SUPPORT_HEPA_FILTER_MONITORING_CLUSTER=n +CONFIG_SUPPORT_GROUP_KEY_MANAGEMENT_CLUSTER=y +CONFIG_SUPPORT_ICD_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_IDENTIFY_CLUSTER=y +CONFIG_SUPPORT_JOINT_FABRIC_DATASTORE_CLUSTER=n +CONFIG_SUPPORT_JOINT_FABRIC_ADMINISTRATOR_CLUSTER=n +CONFIG_SUPPORT_KEYPAD_INPUT_CLUSTER=n +CONFIG_SUPPORT_LAUNDRY_WASHER_MODE_CLUSTER=n +CONFIG_SUPPORT_LEVEL_CONTROL_CLUSTER=y +CONFIG_SUPPORT_LOCALIZATION_CONFIGURATION_CLUSTER=n +CONFIG_SUPPORT_LOW_POWER_CLUSTER=n +CONFIG_SUPPORT_MEDIA_INPUT_CLUSTER=n +CONFIG_SUPPORT_MEDIA_PLAYBACK_CLUSTER=n +CONFIG_SUPPORT_MICROWAVE_OVEN_CONTROL_CLUSTER=n +CONFIG_SUPPORT_MESSAGES_CLUSTER=n +CONFIG_SUPPORT_MODE_SELECT_CLUSTER=n +CONFIG_SUPPORT_NETWORK_COMMISSIONING_CLUSTER=n +CONFIG_SUPPORT_NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_PUSH_AV_STREAM_TRANSPORT_CLUSTER=n +CONFIG_SUPPORT_SAMPLE_MEI_CLUSTER=n +CONFIG_SUPPORT_OCCUPANCY_SENSING_CLUSTER=n +CONFIG_SUPPORT_ON_OFF_CLUSTER=y +CONFIG_SUPPORT_POWER_TOPOLOGY_CLUSTER=n +CONFIG_SUPPORT_OPERATIONAL_CREDENTIALS_CLUSTER=y +CONFIG_SUPPORT_OPERATIONAL_STATE_CLUSTER=n +CONFIG_SUPPORT_OPERATIONAL_STATE_OVEN_CLUSTER=n +CONFIG_SUPPORT_OPERATIONAL_STATE_RVC_CLUSTER=n +CONFIG_SUPPORT_OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER=n +CONFIG_SUPPORT_OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER=n +CONFIG_SUPPORT_OVEN_MODE_CLUSTER=n +CONFIG_SUPPORT_OZONE_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_PM10_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_PM1_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_PM2_5_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_POWER_SOURCE_CLUSTER=n +CONFIG_SUPPORT_POWER_SOURCE_CONFIGURATION_CLUSTER=n +CONFIG_SUPPORT_PUMP_CONFIGURATION_AND_CONTROL_CLUSTER=n +CONFIG_SUPPORT_RADON_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_REFRIGERATOR_ALARM_CLUSTER=n +CONFIG_SUPPORT_REFRIGERATOR_AND_TEMPERATURE_CONTROLLED_CABINET_MODE_CLUSTER=n +CONFIG_SUPPORT_RVC_CLEAN_MODE_CLUSTER=n +CONFIG_SUPPORT_RVC_RUN_MODE_CLUSTER=n +CONFIG_SUPPORT_SCENES_CLUSTER=y +CONFIG_SUPPORT_SERVICE_AREA_CLUSTER=n +CONFIG_SUPPORT_SMOKE_CO_ALARM_CLUSTER=n +CONFIG_SUPPORT_SOFTWARE_DIAGNOSTICS_CLUSTER=n +CONFIG_SUPPORT_SOIL_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_SWITCH_CLUSTER=n +CONFIG_SUPPORT_TARGET_NAVIGATOR_CLUSTER=n +CONFIG_SUPPORT_TEMPERATURE_CONTROL_CLUSTER=n +CONFIG_SUPPORT_THERMOSTAT_CLUSTER=n +CONFIG_SUPPORT_THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER=n +CONFIG_SUPPORT_THREAD_BORDER_ROUTER_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_THREAD_NETWORK_DIAGNOSTICS_CLUSTER=n +CONFIG_SUPPORT_THREAD_NETWORK_DIRECTORY_CLUSTER=n +CONFIG_SUPPORT_TIME_FORMAT_LOCALIZATION_CLUSTER=n +CONFIG_SUPPORT_TIME_SYNCHRONIZATION_CLUSTER=n +CONFIG_SUPPORT_TIMER_CLUSTER=n +CONFIG_SUPPORT_TLS_CERTIFICATE_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_TLS_CLIENT_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_TVOC_CONCENTRATION_MEASUREMENT_CLUSTER=n +CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER=n +CONFIG_SUPPORT_UNIT_TESTING_CLUSTER=n +CONFIG_SUPPORT_USER_LABEL_CLUSTER=n +CONFIG_SUPPORT_VALVE_CONFIGURATION_AND_CONTROL_CLUSTER=n +CONFIG_SUPPORT_WAKE_ON_LAN_CLUSTER=n +CONFIG_SUPPORT_LAUNDRY_WASHER_CONTROLS_CLUSTER=n +CONFIG_SUPPORT_LAUNDRY_DRYER_CONTROLS_CLUSTER=n +CONFIG_SUPPORT_WEB_RTC_TRANSPORT_PROVIDER_CLUSTER=n +CONFIG_SUPPORT_WEB_RTC_TRANSPORT_REQUESTOR_CLUSTER=n +CONFIG_SUPPORT_WIFI_NETWORK_DIAGNOSTICS_CLUSTER=n +CONFIG_SUPPORT_WIFI_NETWORK_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_WINDOW_COVERING_CLUSTER=n +CONFIG_SUPPORT_WATER_HEATER_MANAGEMENT_CLUSTER=n +CONFIG_SUPPORT_WATER_HEATER_MODE_CLUSTER=n +CONFIG_SUPPORT_ZONE_MANAGEMENT_CLUSTER=n diff --git a/components/gateway_matter/CMakeLists.txt b/components/gateway_matter/CMakeLists.txt new file mode 100644 index 0000000..6360ad9 --- /dev/null +++ b/components/gateway_matter/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register( + SRCS "src/gateway_matter.cpp" + INCLUDE_DIRS "include" + REQUIRES dali_domain esp_driver_gpio esp_matter freertos log nvs_flash +) + +set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17) diff --git a/components/gateway_matter/idf_component.yml b/components/gateway_matter/idf_component.yml new file mode 100644 index 0000000..a0e1667 --- /dev/null +++ b/components/gateway_matter/idf_component.yml @@ -0,0 +1,4 @@ +dependencies: + espressif/esp_matter: "1.5.1" + idf: + version: "==5.5.4" diff --git a/components/gateway_matter/include/gateway_matter.hpp b/components/gateway_matter/include/gateway_matter.hpp new file mode 100644 index 0000000..5127175 --- /dev/null +++ b/components/gateway_matter/include/gateway_matter.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "dali_domain.hpp" +#include "esp_err.h" +#include "esp_matter.h" +#include "esp_matter_bridge.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +namespace gateway { + +struct GatewayMatterBridgeConfig { + bool enabled{false}; + size_t max_bridged_devices{16}; + uint32_t scan_start_delay_ms{2000}; + uint32_t scan_address_delay_ms{20}; + uint32_t scan_task_stack_size{8192}; + UBaseType_t scan_task_priority{3}; + int wifi_provision_button_gpio{-1}; + bool wifi_provision_button_active_low{true}; + uint32_t wifi_provision_long_press_ms{5000}; + uint32_t button_task_stack_size{4096}; + UBaseType_t button_task_priority{2}; + std::function wifi_provisioning_callback; +}; + +// ESP-Matter adapter for the platform-neutral DALI domain. Each discovered +// control gear becomes a persistent dynamic endpoint under one aggregator. +class GatewayMatterBridge { + public: + GatewayMatterBridge(DaliDomainService& dali_domain, + GatewayMatterBridgeConfig config = {}); + ~GatewayMatterBridge() = default; + + esp_err_t start(); + + private: + struct Binding { + GatewayMatterBridge* owner{nullptr}; + uint8_t gateway_id{0}; + uint8_t short_address{0}; + uint16_t dali_device_type_mask{0}; + uint32_t matter_device_type{0}; + uint16_t endpoint_id{0}; + uint16_t current_x{32768}; + uint16_t current_y{32768}; + uint8_t current_hue{0}; + uint8_t current_saturation{0}; + bool suppress_attribute_write{false}; + esp_matter_bridge::device_t* matter_device{nullptr}; + }; + + struct StatusWork; + + static esp_err_t AttributeUpdate(esp_matter::attribute::callback_type_t type, + uint16_t endpoint_id, uint32_t cluster_id, + uint32_t attribute_id, + esp_matter_attr_val_t* value, void* private_data); + static esp_err_t Identify(esp_matter::identification::callback_type_t type, + uint16_t endpoint_id, uint8_t effect_id, + uint8_t effect_variant, void* private_data); + static esp_err_t AddDeviceType(esp_matter::endpoint_t* endpoint, + uint32_t device_type_id, void* private_data); + static void MatterEvent(const chip::DeviceLayer::ChipDeviceEvent* event, + intptr_t argument); + static void ScanTaskEntry(void* argument); + static void ButtonTaskEntry(void* argument); + static void ApplyStatusWork(intptr_t argument); + static void OpenCommissioningWindowWork(intptr_t argument); + + esp_err_t handleAttributeUpdate(Binding& binding, uint32_t cluster_id, + uint32_t attribute_id, + const esp_matter_attr_val_t& value); + esp_err_t initializeBridgeStorage(); + esp_err_t resumeBindings(); + esp_err_t configureProvisioningButton(); + void scanDaliDevices(); + void buttonTaskLoop(); + void handleStatusUpdate(const DaliGatewayStatusUpdate& update); + Binding* findBinding(uint8_t gateway_id, uint8_t short_address) const; + Binding* findBinding(uint16_t endpoint_id) const; + esp_err_t createBinding(uint8_t gateway_id, uint8_t short_address, + uint16_t device_type_mask, + uint8_t initial_level = 0); + esp_err_t storeBinding(const Binding& binding) const; + std::unique_ptr readBinding(uint16_t endpoint_id) const; + void updateMatterLevel(Binding& binding, uint8_t level); + void requestWifiProvisioning(); + + DaliDomainService& dali_domain_; + GatewayMatterBridgeConfig config_; + esp_matter::node_t* node_{nullptr}; + uint16_t aggregator_endpoint_id_{0}; + mutable std::mutex bindings_mutex_; + std::vector> bindings_; + TaskHandle_t scan_task_{nullptr}; + TaskHandle_t button_task_{nullptr}; + bool started_{false}; +}; + +} // namespace gateway diff --git a/components/gateway_matter/src/gateway_matter.cpp b/components/gateway_matter/src/gateway_matter.cpp new file mode 100644 index 0000000..7c220b7 --- /dev/null +++ b/components/gateway_matter/src/gateway_matter.cpp @@ -0,0 +1,566 @@ +#include "gateway_matter.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "app/server/CommissioningWindowManager.h" +#include "app/server/Server.h" +#include "esp_check.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "freertos/task.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "platform/CHIPDeviceLayer.h" + +namespace gateway { +namespace { + +constexpr char kTag[] = "gateway_matter"; +constexpr char kBindingNamespace[] = "dali_matter"; +constexpr uint8_t kBindingVersion = 1; +constexpr uint16_t kAllDaliDeviceTypesMask = 0x01FF; +constexpr uint32_t kCommissioningWindowSeconds = 300; + +struct PersistedBinding { + uint8_t version; + uint8_t gateway_id; + uint8_t short_address; + uint8_t reserved; + uint16_t dali_device_type_mask; + uint16_t endpoint_id; + uint32_t matter_device_type; +}; + +std::string BindingKey(uint16_t endpoint_id) { + char key[16] = {}; + std::snprintf(key, sizeof(key), "b%04x", endpoint_id); + return key; +} + +uint16_t DeviceTypeMask(const DaliDomainSnapshot& snapshot) { + uint16_t mask = 0; + const auto types = snapshot.int_arrays.find("types"); + if (types != snapshot.int_arrays.end()) { + for (const int type : types->second) { + if (type >= 0 && type <= 8) mask |= static_cast(1U << type); + } + } + const auto primary = snapshot.ints.find("primaryType"); + if (primary != snapshot.ints.end() && primary->second >= 0 && primary->second <= 8) { + mask |= static_cast(1U << primary->second); + } + return mask == 0 ? 1U : static_cast(mask & kAllDaliDeviceTypesMask); +} + +uint32_t MatterDeviceType(uint16_t dali_device_type_mask) { + if ((dali_device_type_mask & (1U << 8)) != 0) { + return ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_ID; + } + if ((dali_device_type_mask & (1U << 7)) != 0) { + return ESP_MATTER_ON_OFF_LIGHT_DEVICE_TYPE_ID; + } + return ESP_MATTER_DIMMABLE_LIGHT_DEVICE_TYPE_ID; +} + +void HsvToRgb(uint8_t hue, uint8_t saturation, int* red, int* green, int* blue) { + const double h = static_cast(hue) * 360.0 / 254.0; + const double s = static_cast(saturation) / 254.0; + const double c = s; + const double x = c * (1.0 - std::fabs(std::fmod(h / 60.0, 2.0) - 1.0)); + double r = 0.0; + double g = 0.0; + double b = 0.0; + if (h < 60.0) { + r = c; + g = x; + } else if (h < 120.0) { + r = x; + g = c; + } else if (h < 180.0) { + g = c; + b = x; + } else if (h < 240.0) { + g = x; + b = c; + } else if (h < 300.0) { + r = x; + b = c; + } else { + r = c; + b = x; + } + const double m = 1.0 - c; + *red = static_cast(std::round((r + m) * 255.0)); + *green = static_cast(std::round((g + m) * 255.0)); + *blue = static_cast(std::round((b + m) * 255.0)); +} + +} // namespace + +struct GatewayMatterBridge::StatusWork { + GatewayMatterBridge* bridge; + uint16_t endpoint_id; + uint8_t level; +}; + +GatewayMatterBridge::GatewayMatterBridge(DaliDomainService& dali_domain, + GatewayMatterBridgeConfig config) + : dali_domain_(dali_domain), config_(std::move(config)) {} + +esp_err_t GatewayMatterBridge::start() { + if (!config_.enabled) return ESP_OK; + if (started_) return ESP_OK; + if (config_.max_bridged_devices == 0 || + config_.max_bridged_devices > MAX_BRIDGED_DEVICE_COUNT) { + ESP_LOGE(kTag, "max devices %u exceeds ESP-Matter capacity %u", + static_cast(config_.max_bridged_devices), + static_cast(MAX_BRIDGED_DEVICE_COUNT)); + return ESP_ERR_INVALID_SIZE; + } + + esp_matter::node::config_t node_config; + node_ = esp_matter::node::create(&node_config, AttributeUpdate, Identify); + ESP_RETURN_ON_FALSE(node_ != nullptr, ESP_FAIL, kTag, "failed to create Matter node"); + + esp_matter::endpoint::aggregator::config_t aggregator_config; + auto* aggregator = esp_matter::endpoint::aggregator::create( + node_, &aggregator_config, esp_matter::ENDPOINT_FLAG_NONE, nullptr); + ESP_RETURN_ON_FALSE(aggregator != nullptr, ESP_FAIL, kTag, + "failed to create Matter aggregator"); + aggregator_endpoint_id_ = esp_matter::endpoint::get_id(aggregator); + + ESP_RETURN_ON_ERROR(esp_matter::start(MatterEvent), kTag, + "failed to start ESP-Matter"); + ESP_RETURN_ON_ERROR(initializeBridgeStorage(), kTag, + "failed to initialize Matter binding storage"); + ESP_RETURN_ON_ERROR(resumeBindings(), kTag, "failed to resume DALI bindings"); + + dali_domain_.gatewayCache().addStatusUpdateCallback( + [this](const DaliGatewayStatusUpdate& update) { handleStatusUpdate(update); }); + ESP_RETURN_ON_ERROR(configureProvisioningButton(), kTag, + "failed to configure Matter provisioning button"); + + if (xTaskCreate(ScanTaskEntry, "matter_dali_scan", config_.scan_task_stack_size, this, + config_.scan_task_priority, &scan_task_) != pdPASS) { + return ESP_ERR_NO_MEM; + } + started_ = true; + ESP_LOGI(kTag, "Matter-to-DALI bridge started aggregator=%u restored=%u max=%u", + aggregator_endpoint_id_, static_cast(bindings_.size()), + static_cast(config_.max_bridged_devices)); + return ESP_OK; +} + +esp_err_t GatewayMatterBridge::initializeBridgeStorage() { + const esp_err_t nvs_err = nvs_flash_init_partition("nvs"); + if (nvs_err != ESP_OK && nvs_err != ESP_ERR_INVALID_STATE) return nvs_err; + return esp_matter_bridge::initialize(node_, AddDeviceType); +} + +esp_err_t GatewayMatterBridge::resumeBindings() { + uint16_t endpoint_ids[MAX_BRIDGED_DEVICE_COUNT] = {}; + ESP_RETURN_ON_ERROR(esp_matter_bridge::get_bridged_endpoint_ids(endpoint_ids), kTag, + "failed to read endpoint ids"); + for (const uint16_t endpoint_id : endpoint_ids) { + if (endpoint_id == chip::kInvalidEndpointId) continue; + auto binding = readBinding(endpoint_id); + if (!binding) { + ESP_LOGW(kTag, "removing orphan Matter endpoint=%u", endpoint_id); + esp_matter_bridge::erase_bridged_device_info(endpoint_id); + continue; + } + binding->owner = this; + binding->matter_device = + esp_matter_bridge::resume_device(node_, endpoint_id, binding.get()); + if (binding->matter_device == nullptr) continue; + esp_matter::endpoint::enable(binding->matter_device->endpoint); + { + std::lock_guard guard(bindings_mutex_); + bindings_.push_back(std::move(binding)); + } + if (bindings_.size() >= config_.max_bridged_devices) break; + } + return ESP_OK; +} + +esp_err_t GatewayMatterBridge::createBinding(uint8_t gateway_id, uint8_t short_address, + uint16_t device_type_mask, + uint8_t initial_level) { + if (bindings_.size() >= config_.max_bridged_devices) return ESP_ERR_NO_MEM; + auto binding = std::make_unique(); + binding->owner = this; + binding->gateway_id = gateway_id; + binding->short_address = short_address; + binding->dali_device_type_mask = device_type_mask; + binding->matter_device_type = MatterDeviceType(device_type_mask); + binding->matter_device = esp_matter_bridge::create_device( + node_, aggregator_endpoint_id_, binding->matter_device_type, binding.get()); + ESP_RETURN_ON_FALSE(binding->matter_device != nullptr, ESP_FAIL, kTag, + "failed to create bridged endpoint"); + binding->endpoint_id = + esp_matter::endpoint::get_id(binding->matter_device->endpoint); + const esp_err_t store_err = storeBinding(*binding); + if (store_err != ESP_OK) { + ESP_LOGE(kTag, "failed to store DALI binding: %s", esp_err_to_name(store_err)); + const esp_err_t remove_err = esp_matter_bridge::remove_device(binding->matter_device); + if (remove_err != ESP_OK) { + ESP_LOGW(kTag, "failed to roll back bridged endpoint: %s", + esp_err_to_name(remove_err)); + } + return store_err; + } + esp_matter::endpoint::enable(binding->matter_device->endpoint); + Binding* created = binding.get(); + { + std::lock_guard guard(bindings_mutex_); + bindings_.push_back(std::move(binding)); + } + updateMatterLevel(*created, initial_level); + ESP_LOGI(kTag, "bound gateway=%u short=%u types=0x%03x endpoint=%u matter=0x%lx", + gateway_id, short_address, device_type_mask, created->endpoint_id, + static_cast(created->matter_device_type)); + return ESP_OK; +} + +esp_err_t GatewayMatterBridge::storeBinding(const Binding& binding) const { + nvs_handle_t handle = 0; + ESP_RETURN_ON_ERROR(nvs_open_from_partition("nvs", kBindingNamespace, + NVS_READWRITE, &handle), + kTag, "failed to open DALI Matter NVS"); + const PersistedBinding persisted{ + kBindingVersion, + binding.gateway_id, + binding.short_address, + 0, + binding.dali_device_type_mask, + binding.endpoint_id, + binding.matter_device_type, + }; + const std::string key = BindingKey(binding.endpoint_id); + esp_err_t err = nvs_set_blob(handle, key.c_str(), &persisted, sizeof(persisted)); + if (err == ESP_OK) err = nvs_commit(handle); + nvs_close(handle); + return err; +} + +std::unique_ptr GatewayMatterBridge::readBinding( + uint16_t endpoint_id) const { + nvs_handle_t handle = 0; + if (nvs_open_from_partition("nvs", kBindingNamespace, NVS_READONLY, &handle) != ESP_OK) { + return nullptr; + } + PersistedBinding persisted{}; + size_t length = sizeof(persisted); + const std::string key = BindingKey(endpoint_id); + const esp_err_t err = nvs_get_blob(handle, key.c_str(), &persisted, &length); + nvs_close(handle); + const uint16_t dali_device_type_mask = + persisted.dali_device_type_mask & kAllDaliDeviceTypesMask; + const uint32_t expected_matter_device_type = MatterDeviceType(dali_device_type_mask); + if (err != ESP_OK || length != sizeof(persisted) || + persisted.version != kBindingVersion || persisted.endpoint_id != endpoint_id || + persisted.short_address >= 64 || dali_device_type_mask == 0 || + persisted.matter_device_type != expected_matter_device_type) { + return nullptr; + } + auto binding = std::make_unique(); + binding->gateway_id = persisted.gateway_id; + binding->short_address = persisted.short_address; + binding->dali_device_type_mask = dali_device_type_mask; + binding->matter_device_type = persisted.matter_device_type; + binding->endpoint_id = endpoint_id; + return binding; +} + +void GatewayMatterBridge::scanDaliDevices() { + vTaskDelay(pdMS_TO_TICKS(config_.scan_start_delay_ms)); + static const std::vector kSupportedDaliDeviceTypes{0, 1, 2, 3, 4, 5, 6, 7, 8}; + for (const auto& channel : dali_domain_.channelInfo()) { + for (uint8_t short_address = 0; short_address < 64; ++short_address) { + if (bindings_.size() >= config_.max_bridged_devices) { + ESP_LOGW(kTag, "DALI scan stopped at configured endpoint limit=%u", + static_cast(config_.max_bridged_devices)); + return; + } + if (findBinding(channel.gateway_id, short_address) != nullptr) continue; + const auto level = dali_domain_.queryActualLevel(channel.gateway_id, short_address); + if (!level.has_value() || *level > 254) continue; + const auto discovery = dali_domain_.discoverDeviceTypes( + channel.gateway_id, short_address, kSupportedDaliDeviceTypes); + const uint16_t type_mask = discovery.has_value() ? DeviceTypeMask(*discovery) : 1U; + const esp_err_t err = + createBinding(channel.gateway_id, short_address, type_mask, *level); + if (err != ESP_OK) { + ESP_LOGW(kTag, "failed binding gateway=%u short=%u: %s", channel.gateway_id, + short_address, esp_err_to_name(err)); + } + vTaskDelay(pdMS_TO_TICKS(config_.scan_address_delay_ms)); + } + } +} + +void GatewayMatterBridge::ScanTaskEntry(void* argument) { + auto* bridge = static_cast(argument); + bridge->scanDaliDevices(); + bridge->scan_task_ = nullptr; + vTaskDelete(nullptr); +} + +GatewayMatterBridge::Binding* GatewayMatterBridge::findBinding( + uint8_t gateway_id, uint8_t short_address) const { + std::lock_guard guard(bindings_mutex_); + const auto found = std::find_if(bindings_.begin(), bindings_.end(), + [gateway_id, short_address](const auto& binding) { + return binding->gateway_id == gateway_id && + binding->short_address == short_address; + }); + return found == bindings_.end() ? nullptr : found->get(); +} + +GatewayMatterBridge::Binding* GatewayMatterBridge::findBinding(uint16_t endpoint_id) const { + std::lock_guard guard(bindings_mutex_); + const auto found = std::find_if(bindings_.begin(), bindings_.end(), + [endpoint_id](const auto& binding) { + return binding->endpoint_id == endpoint_id; + }); + return found == bindings_.end() ? nullptr : found->get(); +} + +esp_err_t GatewayMatterBridge::AddDeviceType(esp_matter::endpoint_t* endpoint, + uint32_t device_type_id, + void* private_data) { + auto* binding = static_cast(private_data); + if (binding == nullptr) return ESP_ERR_INVALID_ARG; + switch (device_type_id) { + case ESP_MATTER_ON_OFF_LIGHT_DEVICE_TYPE_ID: { + esp_matter::endpoint::on_off_light::config_t config; + return esp_matter::endpoint::on_off_light::add(endpoint, &config); + } + case ESP_MATTER_DIMMABLE_LIGHT_DEVICE_TYPE_ID: { + esp_matter::endpoint::dimmable_light::config_t config; + return esp_matter::endpoint::dimmable_light::add(endpoint, &config); + } + case ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_ID: { + esp_matter::endpoint::extended_color_light::config_t config; + return esp_matter::endpoint::extended_color_light::add(endpoint, &config); + } + default: + return ESP_ERR_NOT_SUPPORTED; + } +} + +esp_err_t GatewayMatterBridge::AttributeUpdate( + esp_matter::attribute::callback_type_t type, uint16_t endpoint_id, + uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t* value, + void* private_data) { + if (type != esp_matter::attribute::PRE_UPDATE || private_data == nullptr || + value == nullptr) { + return ESP_OK; + } + auto* binding = static_cast(private_data); + if (binding->owner == nullptr || binding->endpoint_id != endpoint_id || + binding->suppress_attribute_write) { + return ESP_OK; + } + return binding->owner->handleAttributeUpdate(*binding, cluster_id, attribute_id, + *value); +} + +esp_err_t GatewayMatterBridge::handleAttributeUpdate( + Binding& binding, uint32_t cluster_id, uint32_t attribute_id, + const esp_matter_attr_val_t& value) { + using namespace chip::app::Clusters; + bool accepted = true; + if (cluster_id == OnOff::Id && attribute_id == OnOff::Attributes::OnOff::Id) { + accepted = value.val.b ? dali_domain_.on(binding.gateway_id, binding.short_address) + : dali_domain_.off(binding.gateway_id, binding.short_address); + } else if (cluster_id == LevelControl::Id && + attribute_id == LevelControl::Attributes::CurrentLevel::Id) { + accepted = dali_domain_.setBright(binding.gateway_id, binding.short_address, + std::min(value.val.u8, 254)); + } else if (cluster_id == ColorControl::Id && + attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) { + accepted = dali_domain_.setColTempRaw(binding.gateway_id, binding.short_address, + value.val.u16); + } else if (cluster_id == ColorControl::Id && + attribute_id == ColorControl::Attributes::CurrentX::Id) { + binding.current_x = value.val.u16; + accepted = dali_domain_.setColourRaw(binding.gateway_id, + binding.short_address * 2 + 1, + binding.current_x, binding.current_y); + } else if (cluster_id == ColorControl::Id && + attribute_id == ColorControl::Attributes::CurrentY::Id) { + binding.current_y = value.val.u16; + accepted = dali_domain_.setColourRaw(binding.gateway_id, + binding.short_address * 2 + 1, + binding.current_x, binding.current_y); + } else if (cluster_id == ColorControl::Id && + (attribute_id == ColorControl::Attributes::CurrentHue::Id || + attribute_id == ColorControl::Attributes::CurrentSaturation::Id)) { + if (attribute_id == ColorControl::Attributes::CurrentHue::Id) { + binding.current_hue = value.val.u8; + } else { + binding.current_saturation = value.val.u8; + } + int red = 0; + int green = 0; + int blue = 0; + HsvToRgb(binding.current_hue, binding.current_saturation, &red, &green, &blue); + accepted = dali_domain_.setColourRGB(binding.gateway_id, binding.short_address, + red, green, blue); + } + return accepted ? ESP_OK : ESP_FAIL; +} + +esp_err_t GatewayMatterBridge::Identify( + esp_matter::identification::callback_type_t type, uint16_t endpoint_id, + uint8_t effect_id, uint8_t effect_variant, void* private_data) { + auto* binding = static_cast(private_data); + if (binding != nullptr) { + ESP_LOGI(kTag, "identify endpoint=%u gateway=%u short=%u type=%u effect=%u variant=%u", + endpoint_id, binding->gateway_id, binding->short_address, + static_cast(type), effect_id, effect_variant); + } + return ESP_OK; +} + +void GatewayMatterBridge::handleStatusUpdate(const DaliGatewayStatusUpdate& update) { + if (!started_ || !update.status.actualLevel.has_value() || + *update.status.actualLevel > 254) { + return; + } + const auto schedule = [this, &update](uint8_t short_address) { + Binding* binding = findBinding(update.channel, short_address); + if (binding == nullptr) return; + auto* work = new (std::nothrow) + StatusWork{this, binding->endpoint_id, *update.status.actualLevel}; + if (work == nullptr) return; + chip::DeviceLayer::PlatformMgr().ScheduleWork( + ApplyStatusWork, reinterpret_cast(work)); + }; + if (update.target.kind == DaliGatewayTargetKind::shortAddress) { + schedule(update.target.value); + } else { + for (const uint8_t address : update.affectedShortAddresses) schedule(address); + } +} + +void GatewayMatterBridge::ApplyStatusWork(intptr_t argument) { + std::unique_ptr work(reinterpret_cast(argument)); + if (!work || work->bridge == nullptr) return; + Binding* binding = work->bridge->findBinding(work->endpoint_id); + if (binding != nullptr) work->bridge->updateMatterLevel(*binding, work->level); +} + +void GatewayMatterBridge::updateMatterLevel(Binding& binding, uint8_t level) { + using namespace chip::app::Clusters; + binding.suppress_attribute_write = true; + auto on = esp_matter_bool(level > 0); + esp_matter::attribute::update(binding.endpoint_id, OnOff::Id, + OnOff::Attributes::OnOff::Id, &on); + if (binding.matter_device_type != ESP_MATTER_ON_OFF_LIGHT_DEVICE_TYPE_ID) { + auto current_level = esp_matter_uint8(std::min(level, 254)); + esp_matter::attribute::update(binding.endpoint_id, LevelControl::Id, + LevelControl::Attributes::CurrentLevel::Id, + ¤t_level); + } + binding.suppress_attribute_write = false; +} + +esp_err_t GatewayMatterBridge::configureProvisioningButton() { + if (config_.wifi_provision_button_gpio < 0) return ESP_OK; + gpio_config_t button_config{}; + button_config.pin_bit_mask = 1ULL << config_.wifi_provision_button_gpio; + button_config.mode = GPIO_MODE_INPUT; + button_config.pull_up_en = config_.wifi_provision_button_active_low ? GPIO_PULLUP_ENABLE + : GPIO_PULLUP_DISABLE; + button_config.pull_down_en = config_.wifi_provision_button_active_low + ? GPIO_PULLDOWN_DISABLE + : GPIO_PULLDOWN_ENABLE; + button_config.intr_type = GPIO_INTR_DISABLE; + ESP_RETURN_ON_ERROR(gpio_config(&button_config), kTag, + "failed to configure provisioning GPIO"); + if (xTaskCreate(ButtonTaskEntry, "matter_wifi_btn", config_.button_task_stack_size, + this, config_.button_task_priority, &button_task_) != pdPASS) { + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +void GatewayMatterBridge::ButtonTaskEntry(void* argument) { + static_cast(argument)->buttonTaskLoop(); +} + +void GatewayMatterBridge::buttonTaskLoop() { + constexpr uint32_t kPollMs = 50; + uint32_t pressed_ms = 0; + bool fired = false; + while (true) { + const int level = gpio_get_level( + static_cast(config_.wifi_provision_button_gpio)); + const bool pressed = config_.wifi_provision_button_active_low ? level == 0 : level != 0; + if (pressed) { + pressed_ms = std::min(pressed_ms + kPollMs, + config_.wifi_provision_long_press_ms); + if (!fired && pressed_ms >= config_.wifi_provision_long_press_ms) { + fired = true; + requestWifiProvisioning(); + } + } else { + pressed_ms = 0; + fired = false; + } + vTaskDelay(pdMS_TO_TICKS(kPollMs)); + } +} + +void GatewayMatterBridge::requestWifiProvisioning() { + if (config_.wifi_provisioning_callback) { + const esp_err_t err = config_.wifi_provisioning_callback(); + if (err != ESP_OK) { + ESP_LOGW(kTag, "Wi-Fi provisioning callback failed: %s", esp_err_to_name(err)); + } + } + chip::DeviceLayer::PlatformMgr().ScheduleWork( + OpenCommissioningWindowWork, reinterpret_cast(this)); +} + +void GatewayMatterBridge::OpenCommissioningWindowWork(intptr_t argument) { + auto* bridge = reinterpret_cast(argument); + if (bridge == nullptr || !bridge->started_) return; + auto& manager = + chip::Server::GetInstance().GetCommissioningWindowManager(); + if (manager.IsCommissioningWindowOpen()) return; + const CHIP_ERROR err = manager.OpenBasicCommissioningWindow( + chip::System::Clock::Seconds16(kCommissioningWindowSeconds), + chip::CommissioningWindowAdvertisement::kAllSupported); + if (err != CHIP_NO_ERROR) { + ESP_LOGE(kTag, "failed to open commissioning window: %s", err.AsString()); + } +} + +void GatewayMatterBridge::MatterEvent( + const chip::DeviceLayer::ChipDeviceEvent* event, intptr_t argument) { + (void)argument; + switch (event->Type) { + case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: + ESP_LOGI(kTag, "Matter commissioning complete"); + break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: + ESP_LOGI(kTag, "Matter commissioning window opened"); + break; + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: + ESP_LOGI(kTag, "Matter commissioning window closed"); + break; + default: + break; + } +} + +} // namespace gateway diff --git a/components/gateway_network/include/gateway_network.hpp b/components/gateway_network/include/gateway_network.hpp index c11c62c..f4d0abe 100644 --- a/components/gateway_network/include/gateway_network.hpp +++ b/components/gateway_network/include/gateway_network.hpp @@ -89,6 +89,9 @@ class GatewayNetworkService { GatewayBridgeService* bridge_service = nullptr); esp_err_t start(); + // Enables the opt-in Wi-Fi provisioning path used by physical adapters such + // as the Matter commissioning button. Ethernet remains the preferred route. + esp_err_t startWifiProvisioning(); // Physical adapter for the Part 103 IDENTIFY DEVICE action. The DALI core // remains hardware-independent and invokes this only through the app wiring. void identify(); @@ -162,6 +165,7 @@ class GatewayNetworkService { std::string gatewaySnapshotJson(); esp_err_t sendBridgeResponse(httpd_req_t* req, bool post); void setStatusLed(bool on); + void selectPreferredDefaultNetwork(); GatewayController& controller_; GatewayRuntime& runtime_; diff --git a/components/gateway_network/src/gateway_network.cpp b/components/gateway_network/src/gateway_network.cpp index 82fbd39..0938b6a 100644 --- a/components/gateway_network/src/gateway_network.cpp +++ b/components/gateway_network/src/gateway_network.cpp @@ -483,6 +483,14 @@ esp_err_t GatewayNetworkService::start() { return ESP_OK; } +esp_err_t GatewayNetworkService::startWifiProvisioning() { + if (!config_.wifi_supported || !config_.smartconfig_enabled) { + return ESP_ERR_NOT_SUPPORTED; + } + config_.wifi_enabled = true; + return startSmartconfig(); +} + void GatewayNetworkService::identify() { if (config_.status_led_gpio < 0) { ESP_LOGI(kTag, "Part 103 identity requested; no status LED is configured"); @@ -760,7 +768,13 @@ esp_err_t GatewayNetworkService::startWifi() { setup_ap_started_ = false; if (wifi_sta_netif_ == nullptr) { - wifi_sta_netif_ = esp_netif_create_default_wifi_sta(); + // ESP-Matter can initialize the default station netif before the optional + // long-press provisioning path is entered. Reuse it when present instead + // of trying to create a second WIFI_STA_DEF netif. + wifi_sta_netif_ = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (wifi_sta_netif_ == nullptr) { + wifi_sta_netif_ = esp_netif_create_default_wifi_sta(); + } if (wifi_sta_netif_ == nullptr) { ESP_LOGE(kTag, "failed to create default Wi-Fi STA netif"); return ESP_ERR_NO_MEM; @@ -1275,6 +1289,7 @@ void GatewayNetworkService::handleEthernetEvent(esp_event_base_t event_base, int if (event_id == ETHERNET_EVENT_DISCONNECTED) { runtime_.clearEthernetIp(); + selectPreferredDefaultNetwork(); ESP_LOGI(kTag, "Ethernet link down"); return; } @@ -1286,6 +1301,7 @@ void GatewayNetworkService::handleEthernetEvent(esp_event_base_t event_base, int if (event_id == ETHERNET_EVENT_STOP) { runtime_.clearEthernetIp(); + selectPreferredDefaultNetwork(); ESP_LOGI(kTag, "Ethernet driver stopped"); } return; @@ -1302,6 +1318,7 @@ void GatewayNetworkService::handleEthernetEvent(esp_event_base_t event_base, int } info.ip = ip; runtime_.setEthernetInfo(std::move(info)); + selectPreferredDefaultNetwork(); ESP_LOGI(kTag, "Ethernet got IP %s", ip); } } @@ -1381,10 +1398,31 @@ void GatewayNetworkService::handleWifiEvent(esp_event_base_t event_base, int32_t wireless.mac = MacToHex(mac); } runtime_.setWirelessInfo(std::move(wireless)); + selectPreferredDefaultNetwork(); ESP_LOGI(kTag, "Wi-Fi got IP %s", ip); } } +void GatewayNetworkService::selectPreferredDefaultNetwork() { + const auto info = runtime_.deviceInfo(); + esp_netif_t* preferred = nullptr; + const char* name = nullptr; + if (eth_netif_ != nullptr && info.eth.has_value() && !info.eth->ip.empty()) { + preferred = eth_netif_; + name = "Ethernet"; + } else if (wifi_sta_netif_ != nullptr && info.wlan.has_value() && !info.wlan->ip.empty()) { + preferred = wifi_sta_netif_; + name = "Wi-Fi"; + } + if (preferred == nullptr) return; + const esp_err_t err = esp_netif_set_default_netif(preferred); + if (err != ESP_OK) { + ESP_LOGW(kTag, "failed to prefer %s route: %s", name, esp_err_to_name(err)); + } else { + ESP_LOGI(kTag, "%s is the preferred default route", name); + } +} + void GatewayNetworkService::handleEspNowReceive(const esp_now_recv_info_t* info, const uint8_t* data, int data_len) { if (!espnow_started_ || info == nullptr || info->src_addr == nullptr || data == nullptr || @@ -1890,7 +1928,7 @@ void GatewayNetworkService::handleWifiControl(uint8_t mode) { return; } if (mode == 100) { - ESP_ERROR_CHECK_WITHOUT_ABORT(startSmartconfig()); + ESP_ERROR_CHECK_WITHOUT_ABORT(startWifiProvisioning()); return; } if (mode == 1) {