Implement Matter Endpoint Plan Logic and Unit Tests
- Added `gateway_matter_plan.cpp` to define the logic for building Matter endpoint plans, including functions for inferring capabilities and managing allocations based on channel configurations. - Introduced helper functions to determine the type of Matter endpoints and color methods based on device capabilities. - Created `gateway_matter_plan_test.cpp` to validate the functionality of the endpoint plan logic with various test cases, ensuring correct behavior for different configurations and address handling. Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -123,17 +123,46 @@ 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
|
||||
aggregator and owns a pool of 32 bridged DALI endpoints. ESP-Matter is configured
|
||||
for 34 dynamic entries: the root, the aggregator, and the 32-slot DALI pool.
|
||||
Every enabled channel receives a broadcast endpoint first, then cached non-empty
|
||||
groups (including manually retained empty groups), explicitly included short
|
||||
addresses, and automatic online short addresses in ascending order. Allocation
|
||||
stops at 32 and reports every dropped target; this means the highest automatic
|
||||
short addresses are removed first. Broadcast and group targets cannot be
|
||||
disabled. On a single DALI channel, the pool can therefore retain broadcast,
|
||||
all 16 groups, and 15 direct addresses when every group is present.
|
||||
|
||||
The portable DALI cache persists device-type masks and DT8 color-feature bits in
|
||||
addition to group, scene, settings, and runtime state. The planner infers the
|
||||
highest required multi-target capability in the order color, color temperature,
|
||||
dimmer, then switch. DT8 feature bits select XY, RGBCW, or both. Per-channel
|
||||
versioned configuration is stored in normal NVS by fixed channel index and can
|
||||
override the automatic short-address policy, sparse direct-address inclusion,
|
||||
and each broadcast/group type and color method. Existing direct-only bindings
|
||||
are migrated to stable channel-index plus target-kind bindings. Reconciliation
|
||||
retains unchanged endpoints and recreates one only when its Matter device type
|
||||
changes.
|
||||
|
||||
Matter On/Off, Level Control, Color Control (mirek, XY, and hue/saturation
|
||||
converted to equivalent DALI writes), 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.
|
||||
|
||||
The checked-in ESP32-S3 profile uses only ESP-IDF 5.5.4-supported PSRAM paths:
|
||||
CHIP, ESP-Matter, mDNS, TLS, NVS cache, Wi-Fi/lwIP allocations, and eligible BSS
|
||||
prefer external RAM. The mDNS task and gateway-owned BACnet and on-demand DALI
|
||||
operation stacks can use PSRAM with internal-RAM fallback. Tasks that write NVS,
|
||||
change network settings, run the DALI PHY, or have timing/DMA constraints remain
|
||||
in internal RAM; in particular, the Matter DALI scan stack stays internal because
|
||||
the scan commits its discovered capabilities. Eligible non-ISR FreeRTOS code is
|
||||
placed in flash to leave internal RAM headroom. This selective policy does not depend on
|
||||
the unreleased global `FREERTOS_PLACE_TASK_STACKS_IN_EXT_RAM` option. Wi-Fi IRAM
|
||||
throughput optimizations are disabled because Ethernet is the preferred data
|
||||
path and Wi-Fi is retained as a provisioning and fallback path.
|
||||
|
||||
CHIP owns the single NimBLE controller and host while Matter is enabled. The
|
||||
legacy `gateway_ble` transport registers its distinct FFF7 service in CHIP's
|
||||
GATT database through ESP-Matter's extra-service hook, and adds the FFF7 UUID plus
|
||||
@@ -173,6 +202,21 @@ 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.
|
||||
|
||||
DaliMaster's Matter Gateway page uses the transport-independent bridge action
|
||||
surface to read live Matter state, open or close the five-minute commissioning
|
||||
window, configure endpoints, and rescan DALI control gear. `matter_status`
|
||||
returns schema version, effective 32-slot capacity, candidates, saved
|
||||
configuration, active and dropped allocations, target kind/address, inferred or
|
||||
manual source, and the last partial-apply error. `matter_onboarding` returns the
|
||||
live serial number, VID/PID, QR payload, and manual pairing code from the active
|
||||
ESP-Matter factory providers; controllers must treat this response as sensitive
|
||||
and DaliMaster keeps it only in page memory. `matter_config` applies a selected
|
||||
channel patch, while `matter_config_reset` restores automatic selection.
|
||||
`matter_open_commissioning`, `matter_close_commissioning`, `matter_rescan`,
|
||||
`matter_config`, and `matter_config_reset` are POST actions. They are available through the active
|
||||
BLE/USB/IP/KNX/cloud bridge transport as well as the local HTTP `/bridge`
|
||||
endpoint, so Matter setup does not require a working IP profile.
|
||||
|
||||
## Gateway operation protocol
|
||||
|
||||
Opcode `0x67` starts, aborts, and polls gateway-executed high-level DALI
|
||||
|
||||
@@ -1594,12 +1594,22 @@ config GATEWAY_DALI_BAUDRATE
|
||||
config GATEWAY_CONTROLLER_TASK_STACK_SIZE
|
||||
int "Gateway controller task stack bytes"
|
||||
range 6144 24576
|
||||
default 12288
|
||||
default 10240
|
||||
help
|
||||
Stack used by the gateway command controller. BLE bridge transport
|
||||
requests are decoded in this task and may execute JSON-heavy bridge
|
||||
management actions such as KNX programming-mode changes.
|
||||
|
||||
config GATEWAY_PREFER_PSRAM_TASK_STACKS
|
||||
bool "Prefer PSRAM for supported gateway task stacks"
|
||||
depends on SPIRAM && FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
|
||||
default y
|
||||
help
|
||||
Moves only gateway tasks that do not write flash or require DMA-capable
|
||||
stacks to PSRAM, with an internal-RAM fallback if PSRAM allocation
|
||||
fails. Cache, settings, Matter scan, network configuration, DALI PHY,
|
||||
and other flash- or timing-sensitive tasks remain in internal RAM.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Connectivity Startup"
|
||||
@@ -1669,13 +1679,15 @@ config GATEWAY_MATTER_SUPPORTED
|
||||
so the legacy gateway BLE GATT transport is not started in this build.
|
||||
|
||||
config GATEWAY_MATTER_MAX_BRIDGED_DEVICES
|
||||
int "Maximum bridged DALI devices"
|
||||
int "Maximum bridged DALI endpoints"
|
||||
depends on GATEWAY_MATTER_SUPPORTED
|
||||
range 1 16
|
||||
default 16
|
||||
range 1 82
|
||||
default 32
|
||||
help
|
||||
Limits dynamic Matter endpoints and DALI startup discovery work. Every
|
||||
DALI device type 0 through 8 remains supported regardless of this count.
|
||||
Limits bridged DALI broadcast, group, and short-address endpoints.
|
||||
Matter root and aggregator endpoints are additional to this count. The
|
||||
32-slot default fits broadcast plus all 16 DALI groups and leaves 15
|
||||
automatic or explicitly included short-address endpoints.
|
||||
|
||||
config GATEWAY_MATTER_SCAN_START_DELAY_MS
|
||||
int "DALI discovery startup delay ms"
|
||||
@@ -1692,8 +1704,11 @@ config GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS
|
||||
config GATEWAY_MATTER_SCAN_TASK_STACK_SIZE
|
||||
int "Matter DALI scan task stack bytes"
|
||||
depends on GATEWAY_MATTER_SUPPORTED
|
||||
range 6144 16384
|
||||
range 8192 32768
|
||||
default 8192
|
||||
help
|
||||
This task performs NVS commits and therefore intentionally remains in
|
||||
internal RAM even when supported gateway task stacks prefer PSRAM.
|
||||
|
||||
config GATEWAY_MATTER_WIFI_PROVISION_BUTTON_GPIO
|
||||
int "Matter Wi-Fi provisioning button GPIO"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "gateway_usb_setup.hpp"
|
||||
#include "gateway_tridonic_hid.hpp"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@@ -80,7 +81,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES
|
||||
#define CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES 16
|
||||
#define CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES 32
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS
|
||||
@@ -392,6 +393,12 @@ constexpr bool kMatterSupported = true;
|
||||
constexpr bool kMatterSupported = false;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GATEWAY_PREFER_PSRAM_TASK_STACKS
|
||||
constexpr bool kPreferPsramTaskStacks = true;
|
||||
#else
|
||||
constexpr bool kPreferPsramTaskStacks = false;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GATEWAY_START_BLE_ENABLED
|
||||
constexpr bool kBleStartupEnabled = true;
|
||||
#else
|
||||
@@ -1038,6 +1045,20 @@ bool HasConfiguredDaliChannel(const std::vector<gateway::DaliChannelInfo>& chann
|
||||
});
|
||||
}
|
||||
|
||||
void LogHeapSnapshot(const char* phase) {
|
||||
ESP_LOGI(kTag,
|
||||
"heap %s internal_free=%u internal_largest=%u psram_free=%u psram_largest=%u",
|
||||
phase,
|
||||
static_cast<unsigned>(heap_caps_get_free_size(MALLOC_CAP_INTERNAL |
|
||||
MALLOC_CAP_8BIT)),
|
||||
static_cast<unsigned>(heap_caps_get_largest_free_block(
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)),
|
||||
static_cast<unsigned>(heap_caps_get_free_size(MALLOC_CAP_SPIRAM |
|
||||
MALLOC_CAP_8BIT)),
|
||||
static_cast<unsigned>(heap_caps_get_largest_free_block(
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
@@ -1147,6 +1168,7 @@ extern "C" void app_main(void) {
|
||||
gateway::GatewayControllerConfig controller_config;
|
||||
controller_config.task_stack_size =
|
||||
static_cast<uint32_t>(CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE);
|
||||
controller_config.operation_task_stack_in_psram = kPreferPsramTaskStacks;
|
||||
const bool network_transport_supported = profile.enable_wifi || profile.enable_eth;
|
||||
controller_config.setup_supported = true;
|
||||
controller_config.ble_supported = profile.enable_ble;
|
||||
@@ -1234,6 +1256,7 @@ extern "C" void app_main(void) {
|
||||
static_cast<uint32_t>(CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE);
|
||||
bridge_config.bacnet_task_priority =
|
||||
static_cast<UBaseType_t>(CONFIG_GATEWAY_BRIDGE_BACNET_TASK_PRIORITY);
|
||||
bridge_config.bacnet_task_stack_in_psram = kPreferPsramTaskStacks;
|
||||
if (kKnxBridgeSupported) {
|
||||
gateway::GatewayKnxConfig default_knx;
|
||||
default_knx.dali_router_enabled = true;
|
||||
@@ -1326,6 +1349,56 @@ extern "C" void app_main(void) {
|
||||
}
|
||||
return s_network->gatewaySettingsCloudResponse(request);
|
||||
};
|
||||
bridge_config.matter_status_getter = [](std::optional<uint8_t> gateway_id) {
|
||||
if (!kMatterSupported) {
|
||||
return gateway::GatewayBridgeHttpResponse{
|
||||
ESP_OK, "{\"matter\":{\"supported\":false,\"enabled\":false,\"started\":false}}"};
|
||||
}
|
||||
if (s_matter_bridge == nullptr) {
|
||||
return gateway::GatewayBridgeHttpResponse{
|
||||
ESP_ERR_INVALID_STATE,
|
||||
"{\"status\":\"error\",\"error\":\"Matter bridge is not ready\"}"};
|
||||
}
|
||||
return gateway::GatewayBridgeHttpResponse{ESP_OK,
|
||||
s_matter_bridge->statusJson(gateway_id)};
|
||||
};
|
||||
bridge_config.matter_onboarding_getter = []() {
|
||||
if (!kMatterSupported || s_matter_bridge == nullptr) {
|
||||
return gateway::GatewayBridgeHttpResponse{
|
||||
ESP_ERR_NOT_SUPPORTED,
|
||||
"{\"status\":\"error\",\"error\":\"Matter bridge is not available\"}"};
|
||||
}
|
||||
return gateway::GatewayBridgeHttpResponse{ESP_OK,
|
||||
s_matter_bridge->onboardingJson()};
|
||||
};
|
||||
bridge_config.matter_action_handler = [](std::string_view action,
|
||||
std::optional<uint8_t> gateway_id,
|
||||
std::string_view body) {
|
||||
if (!kMatterSupported || s_matter_bridge == nullptr) {
|
||||
return gateway::GatewayBridgeHttpResponse{
|
||||
ESP_ERR_NOT_SUPPORTED,
|
||||
"{\"status\":\"error\",\"error\":\"Matter bridge is not available\"}"};
|
||||
}
|
||||
esp_err_t err = ESP_ERR_INVALID_ARG;
|
||||
if (action == "matter_open_commissioning") {
|
||||
err = s_matter_bridge->openCommissioningWindow();
|
||||
} else if (action == "matter_close_commissioning") {
|
||||
err = s_matter_bridge->closeCommissioningWindow();
|
||||
} else if (action == "matter_rescan") {
|
||||
err = s_matter_bridge->rescanDaliDevices();
|
||||
} else if (action == "matter_config" && gateway_id.has_value()) {
|
||||
err = s_matter_bridge->applyConfiguration(*gateway_id, body);
|
||||
} else if (action == "matter_config_reset" && gateway_id.has_value()) {
|
||||
err = s_matter_bridge->resetConfiguration(*gateway_id);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
const std::string message = std::string("{\"status\":\"error\",\"error\":\"") +
|
||||
esp_err_to_name(err) + "\"}";
|
||||
return gateway::GatewayBridgeHttpResponse{err, message};
|
||||
}
|
||||
return gateway::GatewayBridgeHttpResponse{ESP_OK,
|
||||
s_matter_bridge->statusJson(gateway_id)};
|
||||
};
|
||||
bridge_config.knx_gateway_snapshot_provider = []() {
|
||||
gateway::GatewayKnxGatewaySnapshot out;
|
||||
if (s_controller == nullptr) {
|
||||
@@ -1532,7 +1605,10 @@ extern "C" void app_main(void) {
|
||||
}
|
||||
s_matter_bridge =
|
||||
std::make_unique<gateway::GatewayMatterBridge>(*s_dali_domain, matter_config);
|
||||
ESP_ERROR_CHECK(s_matter_bridge->start());
|
||||
LogHeapSnapshot("before Matter");
|
||||
const esp_err_t matter_err = s_matter_bridge->start();
|
||||
LogHeapSnapshot("after Matter");
|
||||
ESP_ERROR_CHECK(matter_err);
|
||||
}
|
||||
|
||||
// ESP-Matter needs several contiguous internal allocations for the CHIP
|
||||
|
||||
+30
-27
@@ -711,7 +711,8 @@ CONFIG_GATEWAY_CACHE_OUTSIDE_BUS_FIRST=y
|
||||
# end of Gateway Cache
|
||||
|
||||
# CONFIG_GATEWAY_ENABLE_DALI_BUS is not set
|
||||
CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE=12288
|
||||
CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE=10240
|
||||
CONFIG_GATEWAY_PREFER_PSRAM_TASK_STACKS=y
|
||||
# end of DALI Settings
|
||||
|
||||
#
|
||||
@@ -730,7 +731,7 @@ CONFIG_GATEWAY_SMARTCONFIG_SUPPORTED=y
|
||||
# Matter-to-DALI Bridge
|
||||
#
|
||||
CONFIG_GATEWAY_MATTER_SUPPORTED=y
|
||||
CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES=16
|
||||
CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES=82
|
||||
CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS=2000
|
||||
CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS=20
|
||||
CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE=8192
|
||||
@@ -1463,6 +1464,7 @@ CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||
# Common ESP-related
|
||||
#
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
||||
CONFIG_ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
|
||||
# end of Common ESP-related
|
||||
|
||||
#
|
||||
@@ -1551,7 +1553,6 @@ CONFIG_RMT_OBJ_CACHE_SAFE=y
|
||||
#
|
||||
# ESP-Driver:SPI Configurations
|
||||
#
|
||||
# CONFIG_SPI_MASTER_IN_IRAM is not set
|
||||
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
||||
# CONFIG_SPI_SLAVE_IN_IRAM is not set
|
||||
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
||||
@@ -1884,15 +1885,14 @@ CONFIG_SPIRAM_SPEED=80
|
||||
CONFIG_SPIRAM_BOOT_HW_INIT=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION=y
|
||||
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
|
||||
# CONFIG_SPIRAM_USE_MEMMAP is not set
|
||||
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
|
||||
CONFIG_SPIRAM_USE_MALLOC=y
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=512
|
||||
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65535
|
||||
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
|
||||
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
|
||||
# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set
|
||||
# end of SPI RAM config
|
||||
# end of ESP PSRAM
|
||||
@@ -2042,10 +2042,10 @@ CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
|
||||
CONFIG_ESP_WIFI_ENABLED=y
|
||||
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
|
||||
# CONFIG_ESP_WIFI_STATIC_TX_BUFFER is not set
|
||||
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER=y
|
||||
CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1
|
||||
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32
|
||||
CONFIG_ESP_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP_WIFI_STATIC_TX_BUFFER_NUM=16
|
||||
CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM=32
|
||||
# CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER is not set
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER=y
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=1
|
||||
@@ -2055,14 +2055,15 @@ CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
|
||||
CONFIG_ESP_WIFI_TX_BA_WIN=6
|
||||
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
|
||||
CONFIG_ESP_WIFI_RX_BA_WIN=6
|
||||
# CONFIG_ESP_WIFI_AMSDU_TX_ENABLED is not set
|
||||
# CONFIG_ESP_WIFI_NVS_ENABLED is not set
|
||||
# CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0 is not set
|
||||
CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_1=y
|
||||
CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752
|
||||
CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32
|
||||
CONFIG_ESP_WIFI_IRAM_OPT=y
|
||||
# CONFIG_ESP_WIFI_IRAM_OPT is not set
|
||||
# CONFIG_ESP_WIFI_EXTRA_IRAM_OPT is not set
|
||||
CONFIG_ESP_WIFI_RX_IRAM_OPT=y
|
||||
# CONFIG_ESP_WIFI_RX_IRAM_OPT is not set
|
||||
CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y
|
||||
CONFIG_ESP_WIFI_ENABLE_SAE_PK=y
|
||||
CONFIG_ESP_WIFI_ENABLE_SAE_H2E=y
|
||||
@@ -2215,7 +2216,7 @@ CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y
|
||||
CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y
|
||||
# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set
|
||||
CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y
|
||||
# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
|
||||
# end of Port
|
||||
|
||||
@@ -2406,6 +2407,7 @@ CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4
|
||||
CONFIG_LWIP_TCP_OVERSIZE_MSS=y
|
||||
# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
|
||||
# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
|
||||
# CONFIG_LWIP_WND_SCALE is not set
|
||||
CONFIG_LWIP_TCP_RTO_TIME=1500
|
||||
# end of TCP
|
||||
|
||||
@@ -2510,8 +2512,8 @@ CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT=y
|
||||
# mbedTLS
|
||||
#
|
||||
# CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set
|
||||
# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set
|
||||
CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC=y
|
||||
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
|
||||
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
|
||||
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
|
||||
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
|
||||
@@ -3287,7 +3289,7 @@ CONFIG_MRP_MAX_RETRANS=4
|
||||
#
|
||||
# ESP Matter
|
||||
#
|
||||
CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT=16
|
||||
CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT=5
|
||||
CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST=259
|
||||
CONFIG_ESP_MATTER_NVS_PART_NAME="nvs"
|
||||
CONFIG_ESP_MATTER_DEFERRED_ATTR_PERSISTENCE_TIME_MS=3000
|
||||
@@ -3303,7 +3305,7 @@ CONFIG_FACTORY_DEVICE_INSTANCE_INFO_PROVIDER=y
|
||||
# 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_MAX_DYNAMIC_ENDPOINT_COUNT=84
|
||||
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
|
||||
@@ -3605,10 +3607,10 @@ 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_TASK_CREATE_FROM_SPIRAM=y
|
||||
# CONFIG_MDNS_TASK_CREATE_FROM_INTERNAL is not set
|
||||
CONFIG_MDNS_MEMORY_ALLOC_SPIRAM=y
|
||||
# CONFIG_MDNS_MEMORY_ALLOC_INTERNAL is not set
|
||||
# CONFIG_MDNS_MEMORY_CUSTOM_IMPL is not set
|
||||
# end of MDNS Memory Configuration
|
||||
|
||||
@@ -3853,22 +3855,23 @@ CONFIG_TIMER_TASK_STACK_SIZE=3584
|
||||
CONFIG_ESP32_WIFI_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
|
||||
# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
|
||||
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16
|
||||
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32
|
||||
# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
|
||||
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TX_BA_WIN=6
|
||||
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_RX_BA_WIN=6
|
||||
# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set
|
||||
# CONFIG_ESP32_WIFI_NVS_ENABLED is not set
|
||||
# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 is not set
|
||||
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1=y
|
||||
CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
|
||||
CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
|
||||
CONFIG_ESP32_WIFI_IRAM_OPT=y
|
||||
CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
|
||||
# CONFIG_ESP32_WIFI_IRAM_OPT is not set
|
||||
# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set
|
||||
CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
|
||||
CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y
|
||||
CONFIG_WPA_MBEDTLS_CRYPTO=y
|
||||
|
||||
@@ -25,7 +25,7 @@ CONFIG_TINYUSB_HID_COUNT=1
|
||||
# Matter commissioning and legacy gateway GATT services share its database.
|
||||
# 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_MAX_BRIDGED_DEVICES=32
|
||||
CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS=2000
|
||||
CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS=20
|
||||
CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE=8192
|
||||
@@ -33,16 +33,33 @@ 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
|
||||
# Keep the large CHIP core and ESP-Matter data model in PSRAM so the internal
|
||||
# heap retains a contiguous block for the FreeRTOS event queue and radio/DMA
|
||||
# allocations. The queue itself keeps Espressif's Wi-Fi-safe default length.
|
||||
# Keep the large CHIP core, ESP-Matter data model, mDNS state, TLS allocations,
|
||||
# and NVS cache in PSRAM so the internal heap retains contiguous blocks for
|
||||
# event queues and radio/DMA allocations. Only stable, explicitly supported
|
||||
# task stacks are moved; flash-writing tasks remain in internal RAM.
|
||||
CONFIG_CHIP_MEM_ALLOC_MODE_EXTERNAL=y
|
||||
CONFIG_ESP_MATTER_MEM_ALLOC_MODE_EXTERNAL=y
|
||||
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
CONFIG_MDNS_TASK_CREATE_FROM_SPIRAM=y
|
||||
CONFIG_MDNS_MEMORY_ALLOC_SPIRAM=y
|
||||
CONFIG_NVS_ALLOCATE_CACHE_IN_SPIRAM=y
|
||||
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
|
||||
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=512
|
||||
CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM=y
|
||||
CONFIG_GATEWAY_PREFER_PSRAM_TASK_STACKS=y
|
||||
# Ethernet is the normal data path and Wi-Fi is a provisioning/fallback path,
|
||||
# so trade Wi-Fi peak throughput for substantial internal instruction RAM.
|
||||
CONFIG_ESP_WIFI_IRAM_OPT=n
|
||||
CONFIG_ESP_WIFI_RX_IRAM_OPT=n
|
||||
# This stable IDF 5.5 option moves eligible FreeRTOS code out of IRAM. ISR
|
||||
# functions remain in IRAM because the separate ISR option is not enabled.
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
# Preserve enough internal/DMA-capable RAM for gateway Wi-Fi RX buffers when
|
||||
# ESP-Touch is requested; app_main starts Matter before the allocation-heavy
|
||||
# KNX bridge so CHIP can obtain its queue and event-loop stack first.
|
||||
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65535
|
||||
CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT=18
|
||||
CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT=34
|
||||
CONFIG_ESP_MATTER_AGGREGATOR_ENDPOINT_COUNT=1
|
||||
CONFIG_ESP_MATTER_NVS_PART_NAME="nvs"
|
||||
CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME="nvs"
|
||||
|
||||
+42
-43
@@ -711,7 +711,8 @@ CONFIG_GATEWAY_CACHE_OUTSIDE_BUS_FIRST=y
|
||||
# end of Gateway Cache
|
||||
|
||||
# CONFIG_GATEWAY_ENABLE_DALI_BUS is not set
|
||||
CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE=12288
|
||||
CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE=10240
|
||||
CONFIG_GATEWAY_PREFER_PSRAM_TASK_STACKS=y
|
||||
# end of DALI Settings
|
||||
|
||||
#
|
||||
@@ -730,7 +731,7 @@ CONFIG_GATEWAY_SMARTCONFIG_SUPPORTED=y
|
||||
# Matter-to-DALI Bridge
|
||||
#
|
||||
CONFIG_GATEWAY_MATTER_SUPPORTED=y
|
||||
CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES=16
|
||||
CONFIG_GATEWAY_MATTER_MAX_BRIDGED_DEVICES=32
|
||||
CONFIG_GATEWAY_MATTER_SCAN_START_DELAY_MS=2000
|
||||
CONFIG_GATEWAY_MATTER_SCAN_ADDRESS_DELAY_MS=20
|
||||
CONFIG_GATEWAY_MATTER_SCAN_TASK_STACK_SIZE=8192
|
||||
@@ -1022,8 +1023,15 @@ CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=256
|
||||
CONFIG_BT_NIMBLE_ATT_MAX_PREP_ENTRIES=64
|
||||
CONFIG_BT_NIMBLE_GATT_MAX_PROCS=4
|
||||
# CONFIG_BT_NIMBLE_BLE_GATT_BLOB_TRANSFER is not set
|
||||
# CONFIG_BT_NIMBLE_GATT_CACHING is not set
|
||||
# CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY is not set
|
||||
CONFIG_BT_NIMBLE_GATT_CACHING=y
|
||||
# CONFIG_BT_NIMBLE_GATT_CACHING_INCLUDE_SERVICES is not set
|
||||
CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS=4
|
||||
CONFIG_BT_NIMBLE_GATT_CACHING_MAX_SVCS=8
|
||||
CONFIG_BT_NIMBLE_GATT_CACHING_MAX_INCL_SVCS=4
|
||||
CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS=16
|
||||
CONFIG_BT_NIMBLE_GATT_CACHING_MAX_DSCS=16
|
||||
# CONFIG_BT_NIMBLE_GATT_CACHING_DISABLE_AUTO is not set
|
||||
# CONFIG_BT_NIMBLE_GATT_CACHING_ASSOC_ENABLE is not set
|
||||
# end of GATT / ATT
|
||||
|
||||
#
|
||||
@@ -1130,7 +1138,7 @@ CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SUPERVISION_TMO=0
|
||||
#
|
||||
# Extra Features
|
||||
#
|
||||
# CONFIG_BT_NIMBLE_DYNAMIC_SERVICE is not set
|
||||
CONFIG_BT_NIMBLE_DYNAMIC_SERVICE=y
|
||||
# CONFIG_BT_NIMBLE_BLUFI_ENABLE is not set
|
||||
# CONFIG_BT_NIMBLE_ENC_ADV_DATA is not set
|
||||
# CONFIG_BT_NIMBLE_ADV_UUID_CONCAT is not set
|
||||
@@ -1456,6 +1464,7 @@ CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||
# Common ESP-related
|
||||
#
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
||||
CONFIG_ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
|
||||
# end of Common ESP-related
|
||||
|
||||
#
|
||||
@@ -1544,7 +1553,6 @@ CONFIG_RMT_OBJ_CACHE_SAFE=y
|
||||
#
|
||||
# ESP-Driver:SPI Configurations
|
||||
#
|
||||
# CONFIG_SPI_MASTER_IN_IRAM is not set
|
||||
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
||||
# CONFIG_SPI_SLAVE_IN_IRAM is not set
|
||||
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
||||
@@ -1877,15 +1885,14 @@ CONFIG_SPIRAM_SPEED=80
|
||||
CONFIG_SPIRAM_BOOT_HW_INIT=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION=y
|
||||
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
|
||||
# CONFIG_SPIRAM_USE_MEMMAP is not set
|
||||
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
|
||||
CONFIG_SPIRAM_USE_MALLOC=y
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=512
|
||||
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65535
|
||||
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
|
||||
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
|
||||
# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set
|
||||
# end of SPI RAM config
|
||||
# end of ESP PSRAM
|
||||
@@ -2035,10 +2042,10 @@ CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
|
||||
CONFIG_ESP_WIFI_ENABLED=y
|
||||
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
|
||||
# CONFIG_ESP_WIFI_STATIC_TX_BUFFER is not set
|
||||
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER=y
|
||||
CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1
|
||||
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32
|
||||
CONFIG_ESP_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP_WIFI_STATIC_TX_BUFFER_NUM=16
|
||||
CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM=32
|
||||
# CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER is not set
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER=y
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=1
|
||||
@@ -2048,18 +2055,18 @@ CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
|
||||
CONFIG_ESP_WIFI_TX_BA_WIN=6
|
||||
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
|
||||
CONFIG_ESP_WIFI_RX_BA_WIN=6
|
||||
CONFIG_ESP_WIFI_NVS_ENABLED=y
|
||||
# CONFIG_ESP_WIFI_AMSDU_TX_ENABLED is not set
|
||||
# CONFIG_ESP_WIFI_NVS_ENABLED is not set
|
||||
# CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0 is not set
|
||||
CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_1=y
|
||||
CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752
|
||||
CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32
|
||||
CONFIG_ESP_WIFI_IRAM_OPT=y
|
||||
# CONFIG_ESP_WIFI_IRAM_OPT is not set
|
||||
# CONFIG_ESP_WIFI_EXTRA_IRAM_OPT is not set
|
||||
CONFIG_ESP_WIFI_RX_IRAM_OPT=y
|
||||
# CONFIG_ESP_WIFI_RX_IRAM_OPT is not set
|
||||
CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y
|
||||
CONFIG_ESP_WIFI_ENABLE_SAE_PK=y
|
||||
CONFIG_ESP_WIFI_ENABLE_SAE_H2E=y
|
||||
CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y
|
||||
CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y
|
||||
# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
|
||||
CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME=50
|
||||
@@ -2070,7 +2077,7 @@ CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME=15
|
||||
CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y
|
||||
# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set
|
||||
CONFIG_ESP_WIFI_GMAC_SUPPORT=y
|
||||
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
|
||||
# CONFIG_ESP_WIFI_SOFTAP_SUPPORT is not set
|
||||
# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set
|
||||
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7
|
||||
CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y
|
||||
@@ -2081,7 +2088,6 @@ CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT=y
|
||||
# CONFIG_ESP_WIFI_MBO_SUPPORT is not set
|
||||
# CONFIG_ESP_WIFI_DPP_SUPPORT is not set
|
||||
# CONFIG_ESP_WIFI_11R_SUPPORT is not set
|
||||
# CONFIG_ESP_WIFI_WPS_SOFTAP_REGISTRAR is not set
|
||||
|
||||
#
|
||||
# WPS Configuration Options
|
||||
@@ -2210,7 +2216,7 @@ CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y
|
||||
CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y
|
||||
# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set
|
||||
CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y
|
||||
# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
|
||||
# end of Port
|
||||
|
||||
@@ -2401,6 +2407,7 @@ CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4
|
||||
CONFIG_LWIP_TCP_OVERSIZE_MSS=y
|
||||
# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
|
||||
# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
|
||||
# CONFIG_LWIP_WND_SCALE is not set
|
||||
CONFIG_LWIP_TCP_RTO_TIME=1500
|
||||
# end of TCP
|
||||
|
||||
@@ -2505,8 +2512,8 @@ CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT=y
|
||||
# mbedTLS
|
||||
#
|
||||
# CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set
|
||||
# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set
|
||||
CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC=y
|
||||
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
|
||||
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
|
||||
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
|
||||
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
|
||||
@@ -3066,8 +3073,8 @@ 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
|
||||
CONFIG_CHIP_MEM_ALLOC_MODE_EXTERNAL=y
|
||||
# CONFIG_CHIP_MEM_ALLOC_MODE_DEFAULT is not set
|
||||
# end of General Options
|
||||
|
||||
#
|
||||
@@ -3130,13 +3137,7 @@ CONFIG_DEVICE_TYPE=0
|
||||
#
|
||||
# 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
|
||||
# CONFIG_ENABLE_WIFI_STATION is not set
|
||||
# end of WiFi Station Options
|
||||
|
||||
#
|
||||
@@ -3148,9 +3149,9 @@ 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_SINGLE_CONNECTION is not set
|
||||
CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART=0
|
||||
CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y
|
||||
# CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING is not set
|
||||
# end of BLE Options
|
||||
|
||||
#
|
||||
@@ -3275,8 +3276,6 @@ CONFIG_MRP_MAX_RETRANS=4
|
||||
#
|
||||
# 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
|
||||
|
||||
@@ -3290,7 +3289,7 @@ CONFIG_WIFI_NETWORK_ENDPOINT_ID=0
|
||||
#
|
||||
# ESP Matter
|
||||
#
|
||||
CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT=16
|
||||
CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT=5
|
||||
CONFIG_ESP_MATTER_ATTRIBUTE_BUFFER_LARGEST=259
|
||||
CONFIG_ESP_MATTER_NVS_PART_NAME="nvs"
|
||||
CONFIG_ESP_MATTER_DEFERRED_ATTR_PERSISTENCE_TIME_MS=3000
|
||||
@@ -3306,13 +3305,13 @@ CONFIG_FACTORY_DEVICE_INSTANCE_INFO_PROVIDER=y
|
||||
# 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_MAX_DYNAMIC_ENDPOINT_COUNT=84
|
||||
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_INTERNAL is not set
|
||||
CONFIG_ESP_MATTER_MEM_ALLOC_MODE_EXTERNAL=y
|
||||
# CONFIG_ESP_MATTER_MEM_ALLOC_MODE_DEFAULT is not set
|
||||
CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y
|
||||
CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER=y
|
||||
@@ -3608,10 +3607,10 @@ 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_TASK_CREATE_FROM_SPIRAM=y
|
||||
# CONFIG_MDNS_TASK_CREATE_FROM_INTERNAL is not set
|
||||
CONFIG_MDNS_MEMORY_ALLOC_SPIRAM=y
|
||||
# CONFIG_MDNS_MEMORY_ALLOC_INTERNAL is not set
|
||||
# CONFIG_MDNS_MEMORY_CUSTOM_IMPL is not set
|
||||
# end of MDNS Memory Configuration
|
||||
|
||||
|
||||
@@ -190,6 +190,9 @@ class DaliDomainService {
|
||||
bool logarithmic_curve = false) const;
|
||||
bool setColTempRaw(uint8_t gateway_id, int short_address, int mirek) const;
|
||||
bool setColTemp(uint8_t gateway_id, int short_address, int kelvin) const;
|
||||
// Accepts a DALI logical target (short address 0-63, group 64-79, or
|
||||
// broadcast 127). Callers must not construct encoded command addresses.
|
||||
bool setColourXY(uint8_t gateway_id, int logical_target, int x, int y) const;
|
||||
bool setColourRaw(uint8_t gateway_id, int raw_addr, int x, int y) const;
|
||||
bool setColourRGB(uint8_t gateway_id, int short_address, int r, int g, int b) const;
|
||||
bool setColourRGBW(uint8_t gateway_id, int short_address, int r, int g, int b, int w) const;
|
||||
|
||||
@@ -1528,6 +1528,19 @@ bool DaliDomainService::setColTemp(uint8_t gateway_id, int short_address, int ke
|
||||
return channel->dali->dt8.setColorTemperature(short_address, kelvin);
|
||||
}
|
||||
|
||||
bool DaliDomainService::setColourXY(uint8_t gateway_id, int logical_target, int x,
|
||||
int y) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
if (channel == nullptr || channel->dali == nullptr || logical_target < 0 ||
|
||||
!((logical_target <= 79) || logical_target == 127)) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const double normalized_x = std::clamp(x, 0, 65535) / 65535.0;
|
||||
const double normalized_y = std::clamp(y, 0, 65535) / 65535.0;
|
||||
return channel->dali->dt8.setColour(logical_target, normalized_x, normalized_y);
|
||||
}
|
||||
|
||||
bool DaliDomainService::setColourRaw(uint8_t gateway_id, int raw_addr, int x, int y) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
|
||||
@@ -23,6 +23,7 @@ struct GatewayBacnetServerConfig {
|
||||
uint16_t udp_port{47808};
|
||||
uint32_t task_stack_size{8192};
|
||||
UBaseType_t task_priority{5};
|
||||
bool task_stack_in_psram{false};
|
||||
};
|
||||
|
||||
struct GatewayBacnetObjectBinding {
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "gateway_bacnet_stack_port.h"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -318,9 +320,21 @@ esp_err_t GatewayBacnetServer::startStackLocked(const GatewayBacnetServerConfig&
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
const BaseType_t created = xTaskCreate(&GatewayBacnetServer::TaskEntry, "gw_bacnet_ip",
|
||||
active_config_.task_stack_size, this,
|
||||
active_config_.task_priority, &task_handle_);
|
||||
BaseType_t created = pdFAIL;
|
||||
if (active_config_.task_stack_in_psram) {
|
||||
created = xTaskCreateWithCaps(
|
||||
&GatewayBacnetServer::TaskEntry, "gw_bacnet_ip",
|
||||
active_config_.task_stack_size, this, active_config_.task_priority,
|
||||
&task_handle_, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (created != pdPASS) {
|
||||
ESP_LOGW(kTag, "PSRAM BACnet stack allocation failed; using internal RAM");
|
||||
}
|
||||
}
|
||||
if (created != pdPASS) {
|
||||
created = xTaskCreate(&GatewayBacnetServer::TaskEntry, "gw_bacnet_ip",
|
||||
active_config_.task_stack_size, this,
|
||||
active_config_.task_priority, &task_handle_);
|
||||
}
|
||||
if (created != pdPASS) {
|
||||
task_handle_ = nullptr;
|
||||
gateway_bacnet_stack_cleanup();
|
||||
|
||||
@@ -45,6 +45,7 @@ struct GatewayBridgeServiceConfig {
|
||||
std::vector<int> reserved_uart_ports;
|
||||
uint32_t bacnet_task_stack_size{8192};
|
||||
UBaseType_t bacnet_task_priority{5};
|
||||
bool bacnet_task_stack_in_psram{false};
|
||||
uint32_t knx_task_stack_size{12288};
|
||||
UBaseType_t knx_task_priority{5};
|
||||
std::optional<GatewayKnxConfig> default_knx_config;
|
||||
@@ -52,6 +53,10 @@ struct GatewayBridgeServiceConfig {
|
||||
std::function<GatewayBridgeHttpResponse()> gateway_settings_getter;
|
||||
std::function<GatewayBridgeHttpResponse(std::string_view)> gateway_settings_setter;
|
||||
std::function<std::string(std::string_view)> gateway_settings_cloud_handler;
|
||||
std::function<GatewayBridgeHttpResponse(std::optional<uint8_t>)> matter_status_getter;
|
||||
std::function<GatewayBridgeHttpResponse()> matter_onboarding_getter;
|
||||
std::function<GatewayBridgeHttpResponse(std::string_view, std::optional<uint8_t>,
|
||||
std::string_view)> matter_action_handler;
|
||||
GatewayKnxGatewaySnapshotProvider knx_gateway_snapshot_provider;
|
||||
GatewayKnxGatewayCommandTransactor knx_gateway_command_transactor;
|
||||
};
|
||||
|
||||
@@ -2066,6 +2066,7 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
}
|
||||
config.task_stack_size = service_config.bacnet_task_stack_size;
|
||||
config.task_priority = service_config.bacnet_task_priority;
|
||||
config.task_stack_in_psram = service_config.bacnet_task_stack_in_psram;
|
||||
if (bacnet_server_config.has_value()) {
|
||||
config.device_instance = bacnet_server_config->deviceInstance;
|
||||
config.local_address = bacnet_server_config->localAddress;
|
||||
@@ -4636,6 +4637,18 @@ GatewayBridgeHttpResponse GatewayBridgeService::handleGet(
|
||||
}
|
||||
return config_.gateway_settings_getter();
|
||||
}
|
||||
if (action == "matter_status") {
|
||||
if (!config_.matter_status_getter) {
|
||||
return ErrorResponse(ESP_ERR_NOT_SUPPORTED, "Matter status is not available");
|
||||
}
|
||||
return config_.matter_status_getter(gateway_id);
|
||||
}
|
||||
if (action == "matter_onboarding") {
|
||||
if (!config_.matter_onboarding_getter) {
|
||||
return ErrorResponse(ESP_ERR_NOT_SUPPORTED, "Matter onboarding is not available");
|
||||
}
|
||||
return config_.matter_onboarding_getter();
|
||||
}
|
||||
|
||||
if (action == "status" && !gateway_id.has_value()) {
|
||||
cJSON* root = cJSON_CreateObject();
|
||||
@@ -4814,6 +4827,14 @@ GatewayBridgeHttpResponse GatewayBridgeService::handlePost(
|
||||
}
|
||||
return config_.gateway_settings_setter(body);
|
||||
}
|
||||
if (action == "matter_open_commissioning" ||
|
||||
action == "matter_close_commissioning" || action == "matter_rescan" ||
|
||||
action == "matter_config" || action == "matter_config_reset") {
|
||||
if (!config_.matter_action_handler) {
|
||||
return ErrorResponse(ESP_ERR_NOT_SUPPORTED, "Matter control is not available");
|
||||
}
|
||||
return config_.matter_action_handler(action, gateway_id, body);
|
||||
}
|
||||
if (!gateway_id.has_value()) {
|
||||
return ErrorResponse(ESP_ERR_INVALID_ARG, "gateway id is required");
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ class GatewayRuntime;
|
||||
struct GatewayControllerConfig {
|
||||
uint32_t task_stack_size{12288};
|
||||
UBaseType_t task_priority{5};
|
||||
bool operation_task_stack_in_psram{false};
|
||||
int color_temperature_min{2000};
|
||||
int color_temperature_max{6500};
|
||||
bool setup_supported{true};
|
||||
@@ -187,6 +188,7 @@ class GatewayController {
|
||||
|
||||
struct GatewayOperationTaskContext {
|
||||
GatewayController* controller{nullptr};
|
||||
bool external_stack{false};
|
||||
uint8_t gateway_id{0};
|
||||
uint8_t request_id{0};
|
||||
uint16_t operation_id{0};
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "gateway_controller.hpp"
|
||||
|
||||
#include "dali_domain.hpp"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "gateway_bridge.hpp"
|
||||
#include "gateway_runtime.hpp"
|
||||
|
||||
@@ -924,14 +926,20 @@ void GatewayController::TaskEntry(void* arg) {
|
||||
|
||||
void GatewayController::OperationTaskEntry(void* arg) {
|
||||
auto* context = static_cast<GatewayOperationTaskContext*>(arg);
|
||||
if (context == nullptr || context->controller == nullptr) {
|
||||
delete context;
|
||||
if (context == nullptr) {
|
||||
vTaskDelete(nullptr);
|
||||
return;
|
||||
}
|
||||
context->controller->runOperationTask(context);
|
||||
const bool external_stack = context->external_stack;
|
||||
if (context->controller != nullptr) {
|
||||
context->controller->runOperationTask(context);
|
||||
}
|
||||
delete context;
|
||||
vTaskDelete(nullptr);
|
||||
if (external_stack) {
|
||||
vTaskDeleteWithCaps(nullptr);
|
||||
} else {
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayController::taskLoop() {
|
||||
@@ -2495,9 +2503,21 @@ bool GatewayController::startOperation(uint8_t gateway_id, uint8_t request_id,
|
||||
context->request_id = request_id;
|
||||
context->operation_id = operation_id;
|
||||
context->fields = std::move(fields);
|
||||
const BaseType_t created = xTaskCreate(&GatewayController::OperationTaskEntry, "gateway_op",
|
||||
config_.task_stack_size, context,
|
||||
config_.task_priority, nullptr);
|
||||
BaseType_t created = pdFAIL;
|
||||
if (config_.operation_task_stack_in_psram) {
|
||||
created = xTaskCreateWithCaps(
|
||||
&GatewayController::OperationTaskEntry, "gateway_op", config_.task_stack_size,
|
||||
context, config_.task_priority, nullptr, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
context->external_stack = created == pdPASS;
|
||||
if (created != pdPASS) {
|
||||
ESP_LOGW(kTag, "PSRAM operation stack allocation failed; using internal RAM");
|
||||
}
|
||||
}
|
||||
if (created != pdPASS) {
|
||||
created = xTaskCreate(&GatewayController::OperationTaskEntry, "gateway_op",
|
||||
config_.task_stack_size, context,
|
||||
config_.task_priority, nullptr);
|
||||
}
|
||||
if (created != pdPASS) {
|
||||
delete context;
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
idf_component_register(
|
||||
SRCS "src/gateway_matter.cpp"
|
||||
SRCS "src/gateway_matter.cpp" "src/gateway_matter_plan.cpp"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES dali_domain esp_driver_gpio esp_matter freertos log nvs_flash
|
||||
REQUIRES dali_domain esp_driver_gpio esp_matter freertos json log nvs_flash
|
||||
)
|
||||
|
||||
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "dali_domain.hpp"
|
||||
#include "gateway_matter_plan.hpp"
|
||||
#include "esp_err.h"
|
||||
#include "esp_matter.h"
|
||||
#include "esp_matter_bridge.h"
|
||||
@@ -18,7 +23,7 @@ namespace gateway {
|
||||
|
||||
struct GatewayMatterBridgeConfig {
|
||||
bool enabled{false};
|
||||
size_t max_bridged_devices{16};
|
||||
size_t max_bridged_devices{32};
|
||||
uint32_t scan_start_delay_ms{2000};
|
||||
uint32_t scan_address_delay_ms{20};
|
||||
uint32_t scan_task_stack_size{8192};
|
||||
@@ -43,12 +48,23 @@ class GatewayMatterBridge {
|
||||
~GatewayMatterBridge() = default;
|
||||
|
||||
esp_err_t start();
|
||||
esp_err_t openCommissioningWindow();
|
||||
esp_err_t closeCommissioningWindow();
|
||||
esp_err_t rescanDaliDevices();
|
||||
esp_err_t applyConfiguration(uint8_t gateway_id, std::string_view patch);
|
||||
esp_err_t resetConfiguration(uint8_t gateway_id);
|
||||
std::string statusJson(std::optional<uint8_t> gateway_id = std::nullopt) const;
|
||||
std::string onboardingJson() const;
|
||||
|
||||
private:
|
||||
struct Binding {
|
||||
GatewayMatterBridge* owner{nullptr};
|
||||
uint8_t channel_index{0};
|
||||
uint8_t gateway_id{0};
|
||||
uint8_t short_address{0};
|
||||
MatterTargetKind target_kind{MatterTargetKind::shortAddress};
|
||||
uint8_t target_address{0};
|
||||
MatterEndpointType endpoint_type{MatterEndpointType::switchLight};
|
||||
std::optional<MatterColorMethod> color_method;
|
||||
uint16_t dali_device_type_mask{0};
|
||||
uint32_t matter_device_type{0};
|
||||
uint16_t endpoint_id{0};
|
||||
@@ -77,21 +93,25 @@ class GatewayMatterBridge {
|
||||
static void ButtonTaskEntry(void* argument);
|
||||
static void ApplyStatusWork(intptr_t argument);
|
||||
static void OpenCommissioningWindowWork(intptr_t argument);
|
||||
static void CloseCommissioningWindowWork(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 loadConfigurations();
|
||||
esp_err_t storeConfiguration(const MatterChannelConfiguration& configuration) const;
|
||||
esp_err_t configureProvisioningButton();
|
||||
void scanDaliDevices();
|
||||
esp_err_t reconcileEndpoints();
|
||||
void buttonTaskLoop();
|
||||
void handleStatusUpdate(const DaliGatewayStatusUpdate& update);
|
||||
Binding* findBinding(uint8_t gateway_id, uint8_t short_address) const;
|
||||
Binding* findBinding(const MatterTarget& target) 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 createBinding(const MatterEndpointAllocation& allocation,
|
||||
uint16_t device_type_mask, uint8_t initial_level = 0);
|
||||
esp_err_t removeBinding(size_t index);
|
||||
esp_err_t storeBinding(const Binding& binding) const;
|
||||
std::unique_ptr<Binding> readBinding(uint16_t endpoint_id) const;
|
||||
void updateMatterLevel(Binding& binding, uint8_t level);
|
||||
@@ -103,9 +123,16 @@ class GatewayMatterBridge {
|
||||
uint16_t aggregator_endpoint_id_{0};
|
||||
mutable std::mutex bindings_mutex_;
|
||||
std::vector<std::unique_ptr<Binding>> bindings_;
|
||||
std::vector<MatterChannelConfiguration> configurations_;
|
||||
MatterEndpointPlan endpoint_plan_;
|
||||
std::string last_apply_error_;
|
||||
TaskHandle_t scan_task_{nullptr};
|
||||
TaskHandle_t button_task_{nullptr};
|
||||
bool started_{false};
|
||||
std::atomic_bool scan_in_progress_{false};
|
||||
std::atomic_bool ble_advertising_{false};
|
||||
std::atomic_bool commissioning_window_open_{false};
|
||||
std::atomic_uint8_t fabric_count_{0};
|
||||
};
|
||||
|
||||
} // namespace gateway
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gateway {
|
||||
|
||||
enum class MatterTargetKind : uint8_t { shortAddress = 0, group = 1, broadcast = 2 };
|
||||
enum class MatterEndpointType : uint8_t { switchLight = 0, dimmer = 1, colorTemperature = 2, color = 3 };
|
||||
enum class MatterColorMethod : uint8_t { xy = 0, rgbcw = 1, both = 2 };
|
||||
enum class MatterAddressOverride : uint8_t { automatic = 0, include = 1, exclude = 2 };
|
||||
|
||||
struct MatterTarget {
|
||||
uint8_t channel_index{0};
|
||||
uint8_t gateway_id{0};
|
||||
MatterTargetKind kind{MatterTargetKind::shortAddress};
|
||||
uint8_t address{0};
|
||||
|
||||
bool sameIdentity(const MatterTarget& other) const {
|
||||
return channel_index == other.channel_index && kind == other.kind && address == other.address;
|
||||
}
|
||||
};
|
||||
|
||||
struct MatterEndpointOverride {
|
||||
std::optional<MatterEndpointType> type;
|
||||
std::optional<MatterColorMethod> color_method;
|
||||
|
||||
bool manual() const { return type.has_value() || color_method.has_value(); }
|
||||
};
|
||||
|
||||
struct MatterChannelConfiguration {
|
||||
uint8_t channel_index{0};
|
||||
bool automatic_short_addresses{true};
|
||||
std::array<MatterAddressOverride, 64> short_address_overrides{};
|
||||
MatterEndpointOverride broadcast;
|
||||
std::array<MatterEndpointOverride, 16> groups{};
|
||||
};
|
||||
|
||||
struct MatterAddressCandidate {
|
||||
bool online{false};
|
||||
bool group_mask_known{false};
|
||||
uint16_t group_mask{0};
|
||||
std::optional<uint16_t> dali_device_type_mask;
|
||||
std::optional<uint8_t> dt8_color_type_features;
|
||||
};
|
||||
|
||||
struct MatterChannelCandidates {
|
||||
uint8_t channel_index{0};
|
||||
uint8_t gateway_id{0};
|
||||
std::array<MatterAddressCandidate, 64> addresses{};
|
||||
};
|
||||
|
||||
struct MatterEndpointAllocation {
|
||||
MatterTarget target;
|
||||
MatterEndpointType type{MatterEndpointType::switchLight};
|
||||
std::optional<MatterColorMethod> color_method;
|
||||
bool type_is_manual{false};
|
||||
bool color_method_is_manual{false};
|
||||
bool explicitly_included{false};
|
||||
};
|
||||
|
||||
struct MatterDroppedAllocation {
|
||||
MatterEndpointAllocation allocation;
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
struct MatterEndpointPlan {
|
||||
size_t capacity{0};
|
||||
std::vector<MatterEndpointAllocation> active;
|
||||
std::vector<MatterDroppedAllocation> dropped;
|
||||
};
|
||||
|
||||
MatterEndpointPlan BuildMatterEndpointPlan(
|
||||
const std::vector<MatterChannelCandidates>& candidates,
|
||||
const std::vector<MatterChannelConfiguration>& configurations,
|
||||
size_t capacity);
|
||||
|
||||
const char* MatterTargetKindName(MatterTargetKind kind);
|
||||
const char* MatterEndpointTypeName(MatterEndpointType type);
|
||||
const char* MatterColorMethodName(MatterColorMethod method);
|
||||
|
||||
} // namespace gateway
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,212 @@
|
||||
#include "gateway_matter_plan.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace gateway {
|
||||
namespace {
|
||||
|
||||
constexpr uint16_t kDt8Mask = 1U << 8;
|
||||
constexpr uint16_t kDt7Mask = 1U << 7;
|
||||
|
||||
struct InferredCapability {
|
||||
MatterEndpointType type{MatterEndpointType::switchLight};
|
||||
bool has_xy{false};
|
||||
bool has_rgbcw{false};
|
||||
bool usable{false};
|
||||
};
|
||||
|
||||
const MatterChannelConfiguration* FindConfiguration(
|
||||
const std::vector<MatterChannelConfiguration>& configurations,
|
||||
uint8_t channel_index) {
|
||||
const auto found = std::find_if(
|
||||
configurations.begin(), configurations.end(),
|
||||
[channel_index](const auto& item) { return item.channel_index == channel_index; });
|
||||
return found == configurations.end() ? nullptr : &*found;
|
||||
}
|
||||
|
||||
InferredCapability InferAddress(const MatterAddressCandidate& address) {
|
||||
InferredCapability result;
|
||||
if (!address.dali_device_type_mask.has_value()) return result;
|
||||
result.usable = true;
|
||||
const uint16_t mask = *address.dali_device_type_mask;
|
||||
if ((mask & kDt8Mask) != 0) {
|
||||
const uint8_t features = address.dt8_color_type_features.value_or(0);
|
||||
result.has_xy = (features & 0x01) != 0;
|
||||
result.has_rgbcw = ((features >> 5) & 0x07) != 0;
|
||||
if (result.has_xy || result.has_rgbcw) {
|
||||
result.type = MatterEndpointType::color;
|
||||
} else if ((features & 0x02) != 0) {
|
||||
result.type = MatterEndpointType::colorTemperature;
|
||||
} else {
|
||||
result.type = MatterEndpointType::dimmer;
|
||||
}
|
||||
} else if ((mask & ~kDt7Mask) != 0) {
|
||||
result.type = MatterEndpointType::dimmer;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MatterEndpointAllocation InferMultiTarget(
|
||||
const MatterChannelCandidates& channel, MatterTargetKind kind, uint8_t address,
|
||||
const MatterEndpointOverride& override) {
|
||||
MatterEndpointAllocation allocation;
|
||||
allocation.target = {channel.channel_index, channel.gateway_id, kind, address};
|
||||
bool any_member = false;
|
||||
bool has_xy = false;
|
||||
bool has_rgbcw = false;
|
||||
for (const auto& member : channel.addresses) {
|
||||
const uint8_t group = kind == MatterTargetKind::group
|
||||
? static_cast<uint8_t>(address - 64)
|
||||
: 0;
|
||||
const bool included = kind == MatterTargetKind::broadcast ||
|
||||
(member.group_mask_known &&
|
||||
(member.group_mask & (1U << group)) != 0);
|
||||
if (!included) continue;
|
||||
any_member = true;
|
||||
const auto inferred = InferAddress(member);
|
||||
if (static_cast<uint8_t>(inferred.type) > static_cast<uint8_t>(allocation.type)) {
|
||||
allocation.type = inferred.type;
|
||||
}
|
||||
has_xy = has_xy || inferred.has_xy;
|
||||
has_rgbcw = has_rgbcw || inferred.has_rgbcw;
|
||||
}
|
||||
if (override.type.has_value()) {
|
||||
allocation.type = *override.type;
|
||||
allocation.type_is_manual = true;
|
||||
}
|
||||
if (allocation.type == MatterEndpointType::color) {
|
||||
if (override.color_method.has_value()) {
|
||||
allocation.color_method = *override.color_method;
|
||||
allocation.color_method_is_manual = true;
|
||||
} else if (has_xy && has_rgbcw) {
|
||||
allocation.color_method = MatterColorMethod::both;
|
||||
} else if (has_xy) {
|
||||
allocation.color_method = MatterColorMethod::xy;
|
||||
} else if (has_rgbcw) {
|
||||
allocation.color_method = MatterColorMethod::rgbcw;
|
||||
} else if (!any_member || override.manual()) {
|
||||
allocation.color_method = MatterColorMethod::both;
|
||||
} else {
|
||||
allocation.color_method = MatterColorMethod::both;
|
||||
}
|
||||
}
|
||||
return allocation;
|
||||
}
|
||||
|
||||
MatterEndpointAllocation InferShortAddress(
|
||||
const MatterChannelCandidates& channel, uint8_t address, bool explicitly_included) {
|
||||
MatterEndpointAllocation allocation;
|
||||
allocation.target = {channel.channel_index, channel.gateway_id,
|
||||
MatterTargetKind::shortAddress, address};
|
||||
allocation.explicitly_included = explicitly_included;
|
||||
const auto inferred = InferAddress(channel.addresses[address]);
|
||||
allocation.type = inferred.type;
|
||||
if (inferred.type == MatterEndpointType::color) {
|
||||
allocation.color_method = inferred.has_xy && inferred.has_rgbcw
|
||||
? MatterColorMethod::both
|
||||
: (inferred.has_xy ? MatterColorMethod::xy
|
||||
: MatterColorMethod::rgbcw);
|
||||
}
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void AppendWithinCapacity(MatterEndpointPlan* plan,
|
||||
const MatterEndpointAllocation& allocation) {
|
||||
if (plan->active.size() < plan->capacity) {
|
||||
plan->active.push_back(allocation);
|
||||
} else {
|
||||
plan->dropped.push_back({allocation, "capacity"});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MatterEndpointPlan BuildMatterEndpointPlan(
|
||||
const std::vector<MatterChannelCandidates>& raw_candidates,
|
||||
const std::vector<MatterChannelConfiguration>& configurations,
|
||||
size_t capacity) {
|
||||
auto candidates = raw_candidates;
|
||||
std::sort(candidates.begin(), candidates.end(), [](const auto& a, const auto& b) {
|
||||
return a.channel_index < b.channel_index;
|
||||
});
|
||||
MatterEndpointPlan plan;
|
||||
plan.capacity = capacity;
|
||||
|
||||
// Broadcasts and retained groups are deliberately allocated across every
|
||||
// channel before any short address can consume the shared pool.
|
||||
for (const auto& channel : candidates) {
|
||||
const auto* config = FindConfiguration(configurations, channel.channel_index);
|
||||
const MatterEndpointOverride empty;
|
||||
AppendWithinCapacity(&plan, InferMultiTarget(
|
||||
channel, MatterTargetKind::broadcast, 127,
|
||||
config == nullptr ? empty : config->broadcast));
|
||||
}
|
||||
for (const auto& channel : candidates) {
|
||||
const auto* config = FindConfiguration(configurations, channel.channel_index);
|
||||
for (uint8_t group = 0; group < 16; ++group) {
|
||||
const bool cached_non_empty = std::any_of(
|
||||
channel.addresses.begin(), channel.addresses.end(), [group](const auto& address) {
|
||||
return address.group_mask_known && (address.group_mask & (1U << group)) != 0;
|
||||
});
|
||||
const MatterEndpointOverride empty;
|
||||
const auto& override = config == nullptr ? empty : config->groups[group];
|
||||
if (!cached_non_empty && !override.manual()) continue;
|
||||
AppendWithinCapacity(&plan,
|
||||
InferMultiTarget(channel, MatterTargetKind::group,
|
||||
static_cast<uint8_t>(64 + group), override));
|
||||
}
|
||||
}
|
||||
for (const auto& channel : candidates) {
|
||||
const auto* config = FindConfiguration(configurations, channel.channel_index);
|
||||
if (config == nullptr) continue;
|
||||
for (uint8_t address = 0; address < 64; ++address) {
|
||||
if (config->short_address_overrides[address] == MatterAddressOverride::include) {
|
||||
AppendWithinCapacity(&plan, InferShortAddress(channel, address, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& channel : candidates) {
|
||||
const auto* config = FindConfiguration(configurations, channel.channel_index);
|
||||
const bool automatic_enabled = config == nullptr || config->automatic_short_addresses;
|
||||
if (!automatic_enabled) continue;
|
||||
for (uint8_t address = 0; address < 64; ++address) {
|
||||
const auto mode = config == nullptr ? MatterAddressOverride::automatic
|
||||
: config->short_address_overrides[address];
|
||||
if (mode != MatterAddressOverride::automatic || !channel.addresses[address].online) {
|
||||
continue;
|
||||
}
|
||||
AppendWithinCapacity(&plan, InferShortAddress(channel, address, false));
|
||||
}
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
|
||||
const char* MatterTargetKindName(MatterTargetKind kind) {
|
||||
switch (kind) {
|
||||
case MatterTargetKind::shortAddress: return "shortAddress";
|
||||
case MatterTargetKind::group: return "group";
|
||||
case MatterTargetKind::broadcast: return "broadcast";
|
||||
}
|
||||
return "shortAddress";
|
||||
}
|
||||
|
||||
const char* MatterEndpointTypeName(MatterEndpointType type) {
|
||||
switch (type) {
|
||||
case MatterEndpointType::switchLight: return "switch";
|
||||
case MatterEndpointType::dimmer: return "dimmer";
|
||||
case MatterEndpointType::colorTemperature: return "colorTemperature";
|
||||
case MatterEndpointType::color: return "color";
|
||||
}
|
||||
return "switch";
|
||||
}
|
||||
|
||||
const char* MatterColorMethodName(MatterColorMethod method) {
|
||||
switch (method) {
|
||||
case MatterColorMethod::xy: return "xy";
|
||||
case MatterColorMethod::rgbcw: return "rgbcw";
|
||||
case MatterColorMethod::both: return "both";
|
||||
}
|
||||
return "both";
|
||||
}
|
||||
|
||||
} // namespace gateway
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "gateway_matter_plan.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace gateway;
|
||||
|
||||
MatterChannelCandidates Channel(uint8_t index) {
|
||||
MatterChannelCandidates channel;
|
||||
channel.channel_index = index;
|
||||
channel.gateway_id = static_cast<uint8_t>(10 + index);
|
||||
return channel;
|
||||
}
|
||||
|
||||
int main() {
|
||||
{
|
||||
auto channel = Channel(0);
|
||||
channel.addresses[1].group_mask_known = true;
|
||||
channel.addresses[1].group_mask = 1U << 2;
|
||||
channel.addresses[1].dali_device_type_mask = 1U << 8;
|
||||
channel.addresses[1].dt8_color_type_features = 0x23;
|
||||
const auto plan = BuildMatterEndpointPlan({channel}, {}, 64);
|
||||
assert(plan.active.size() == 2);
|
||||
assert(plan.active[0].target.kind == MatterTargetKind::broadcast);
|
||||
assert(plan.active[1].target.address == 66);
|
||||
assert(plan.active[1].type == MatterEndpointType::color);
|
||||
assert(plan.active[1].color_method == MatterColorMethod::both);
|
||||
}
|
||||
{
|
||||
auto channel = Channel(0);
|
||||
MatterChannelConfiguration config;
|
||||
config.channel_index = 0;
|
||||
config.groups[4].type = MatterEndpointType::color;
|
||||
const auto plan = BuildMatterEndpointPlan({channel}, {config}, 64);
|
||||
assert(plan.active.size() == 2);
|
||||
assert(plan.active[1].target.address == 68);
|
||||
assert(plan.active[1].type_is_manual);
|
||||
assert(plan.active[1].color_method == MatterColorMethod::both);
|
||||
}
|
||||
{
|
||||
auto channel = Channel(0);
|
||||
channel.addresses[7].online = true;
|
||||
MatterChannelConfiguration config;
|
||||
config.channel_index = 0;
|
||||
config.automatic_short_addresses = false;
|
||||
config.short_address_overrides[9] = MatterAddressOverride::include;
|
||||
const auto plan = BuildMatterEndpointPlan({channel}, {config}, 64);
|
||||
assert(plan.active.size() == 2);
|
||||
assert(plan.active[1].target.address == 9);
|
||||
assert(plan.active[1].explicitly_included);
|
||||
}
|
||||
{
|
||||
auto channel1 = Channel(1);
|
||||
auto channel0 = Channel(0);
|
||||
channel0.addresses[0].online = true;
|
||||
channel1.addresses[0].online = true;
|
||||
const auto plan = BuildMatterEndpointPlan({channel1, channel0}, {}, 64);
|
||||
assert(plan.active[0].target.channel_index == 0);
|
||||
assert(plan.active[1].target.channel_index == 1);
|
||||
assert(plan.active[2].target.channel_index == 0);
|
||||
assert(plan.active[3].target.channel_index == 1);
|
||||
}
|
||||
{
|
||||
auto channel = Channel(0);
|
||||
for (auto& address : channel.addresses) address.online = true;
|
||||
const auto plan = BuildMatterEndpointPlan({channel}, {}, 32);
|
||||
assert(plan.active.size() == 32);
|
||||
assert(plan.dropped.size() == 33);
|
||||
assert(plan.active.back().target.address == 30);
|
||||
assert(plan.dropped.front().allocation.target.address == 31);
|
||||
assert(plan.dropped.front().reason == "capacity");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user