diff --git a/components/esp_matter/esp_matter_feature.cpp b/components/esp_matter/esp_matter_feature.cpp index ea196c975..715e76210 100644 --- a/components/esp_matter/esp_matter_feature.cpp +++ b/components/esp_matter/esp_matter_feature.cpp @@ -4165,6 +4165,7 @@ esp_err_t add(cluster_t *cluster, config_t *config) ESP_LOGE(TAG, "Should add at least one of PIN, RID, FGP and FACE feature before add USR feature"); return ESP_FAIL; } + update_feature_map(cluster, get_id()); /* Attributes not managed internally */ diff --git a/components/esp_matter/esp_matter_feature.h b/components/esp_matter/esp_matter_feature.h index e07527456..9c6962f52 100644 --- a/components/esp_matter/esp_matter_feature.h +++ b/components/esp_matter/esp_matter_feature.h @@ -1822,6 +1822,7 @@ esp_err_t add(cluster_t *cluster); } /* feature */ } /* electrical_energy_measurement */ + namespace door_lock { namespace feature { diff --git a/examples/.build-rules.yml b/examples/.build-rules.yml index 5b95f3efe..c4c093664 100644 --- a/examples/.build-rules.yml +++ b/examples/.build-rules.yml @@ -92,3 +92,9 @@ examples/managed_component_light: - if: IDF_TARGET in [""] temporary: true reason: this should be compiled without setting up environment, another CI has been added + +examples/door_lock: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3", "esp32c2", "esp32c6", "esp32h2"] + temporary: true + reason: the other targets are not tested yet diff --git a/examples/door_lock/CMakeLists.txt b/examples/door_lock/CMakeLists.txt new file mode 100644 index 000000000..efc0ba7e7 --- /dev/null +++ b/examples/door_lock/CMakeLists.txt @@ -0,0 +1,40 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +if(NOT DEFINED ENV{ESP_MATTER_PATH}) + message(FATAL_ERROR "Please set ESP_MATTER_PATH to the path of esp-matter repo") +endif(NOT DEFINED ENV{ESP_MATTER_PATH}) + +set(PROJECT_VER "1.0") +set(PROJECT_VER_NUMBER 1) + +set(ESP_MATTER_PATH $ENV{ESP_MATTER_PATH}) +set(MATTER_SDK_PATH ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip) + +# This should be done before using the IDF_TARGET variable. +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS + "${ESP_MATTER_PATH}/examples/common" + "${MATTER_SDK_PATH}/config/esp32/components" + "${ESP_MATTER_PATH}/components" + ${extra_components_dirs_append}) + +project(door_lock) + +# WARNING: This is just an example for using key for decrypting the encrypted OTA image +# Please do not use it as is. +if(CONFIG_ENABLE_ENCRYPTED_OTA) + target_add_binary_data(light.elf "esp_image_encryption_key.pem" TEXT) +endif() + +if(CONFIG_IDF_TARGET_ESP32C2) + include(relinker) +endif() + +idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H;-Wno-overloaded-virtual" APPEND) +idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND) +# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various +# flags that depend on -Wformat +idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND) diff --git a/examples/door_lock/README.md b/examples/door_lock/README.md new file mode 100644 index 000000000..0696b074d --- /dev/null +++ b/examples/door_lock/README.md @@ -0,0 +1,15 @@ +# Doorlock + +This example creates a Doorlock device using the ESP Matter data model. + +See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware. + +## 1. Additional Environment Setup + +No additional setup is required. + +## 2. Post Commissioning Setup + +No additional setup is required. + +## 3. Device Performance diff --git a/examples/door_lock/main/CMakeLists.txt b/examples/door_lock/main/CMakeLists.txt new file mode 100644 index 000000000..2b3a07d3e --- /dev/null +++ b/examples/door_lock/main/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register(SRC_DIRS "." "./lock" + PRIV_INCLUDE_DIRS + "." "./lock" "${ESP_MATTER_PATH}/examples/common/utils") + +set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17) +target_compile_options(${COMPONENT_LIB} PRIVATE "-DCHIP_HAVE_CONFIG_H") \ No newline at end of file diff --git a/examples/door_lock/main/app_driver.cpp b/examples/door_lock/main/app_driver.cpp new file mode 100644 index 000000000..d99b9e1fb --- /dev/null +++ b/examples/door_lock/main/app_driver.cpp @@ -0,0 +1,37 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include + +#include +#include "bsp/esp-bsp.h" + +#include + +static const char *TAG = "app_driver"; + +using namespace chip::app::Clusters; +using namespace esp_matter; + +esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, + uint32_t attribute_id, esp_matter_attr_val_t *val) +{ + esp_err_t err = ESP_OK; + return err; +} + +app_driver_handle_t app_driver_button_init() +{ + /* Initialize button */ + button_handle_t btns[BSP_BUTTON_NUM]; + ESP_ERROR_CHECK(bsp_iot_button_create(btns, NULL, BSP_BUTTON_NUM)); + + return (app_driver_handle_t)btns[0]; +} diff --git a/examples/door_lock/main/app_main.cpp b/examples/door_lock/main/app_main.cpp new file mode 100644 index 000000000..ee130b29d --- /dev/null +++ b/examples/door_lock/main/app_main.cpp @@ -0,0 +1,220 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#if CONFIG_PM_ENABLE +#include +#endif + +#include +#include +#include + +#include +#include +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include +#endif + +#include +#include + +static const char *TAG = "app_main"; +uint16_t door_lock_endpoint_id = 0; + +using namespace esp_matter; +using namespace esp_matter::attribute; +using namespace esp_matter::endpoint; +using namespace chip::app::Clusters; +using namespace chip; + +constexpr auto k_timeout_seconds = 300; + +#if CONFIG_ENABLE_ENCRYPTED_OTA +extern const char decryption_key_start[] asm("_binary_esp_image_encryption_key_pem_start"); +extern const char decryption_key_end[] asm("_binary_esp_image_encryption_key_pem_end"); + +static const char *s_decryption_key = decryption_key_start; +static const uint16_t s_decryption_key_len = decryption_key_end - decryption_key_start; +#endif // CONFIG_ENABLE_ENCRYPTED_OTA + +static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) +{ + switch (event->Type) { + case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged: + ESP_LOGI(TAG, "Interface IP Address changed"); + break; + + case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: + ESP_LOGI(TAG, "Commissioning complete"); + break; + + case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: + ESP_LOGI(TAG, "Commissioning failed, fail safe timer expired"); + break; + + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: + ESP_LOGI(TAG, "Commissioning session started"); + break; + + case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: + ESP_LOGI(TAG, "Commissioning session stopped"); + break; + + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: + ESP_LOGI(TAG, "Commissioning window opened"); + break; + + case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: + ESP_LOGI(TAG, "Commissioning window closed"); + break; + + case chip::DeviceLayer::DeviceEventType::kFabricRemoved: + { + ESP_LOGI(TAG, "Fabric removed successfully"); + if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) + { + chip::CommissioningWindowManager & commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager(); + constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds); + if (!commissionMgr.IsCommissioningWindowOpen()) + { + /* After removing last fabric, this example does not remove the Wi-Fi credentials + * and still has IP connectivity so, only advertising on DNS-SD. + */ + CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds, + chip::CommissioningWindowAdvertisement::kDnssdOnly); + if (err != CHIP_NO_ERROR) + { + ESP_LOGE(TAG, "Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format()); + } + } + } + break; + } + + case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: + ESP_LOGI(TAG, "Fabric will be removed"); + break; + + case chip::DeviceLayer::DeviceEventType::kFabricUpdated: + ESP_LOGI(TAG, "Fabric is updated"); + break; + + case chip::DeviceLayer::DeviceEventType::kFabricCommitted: + ESP_LOGI(TAG, "Fabric is committed"); + break; + + case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized: + ESP_LOGI(TAG, "BLE deinitialized and memory reclaimed"); + break; + + default: + break; + } +} + +// This callback is invoked when clients interact with the Identify Cluster. +// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light). +static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id, + uint8_t effect_variant, void *priv_data) +{ + ESP_LOGI(TAG, "Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant); + return ESP_OK; +} + +// This callback is called for every attribute update. The callback implementation shall +// handle the desired attributes and return an appropriate error code. If the attribute +// is not of your interest, please do not return an error code and strictly return ESP_OK. +static esp_err_t app_attribute_update_cb(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, + uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) +{ + esp_err_t err = ESP_OK; + + if (type == PRE_UPDATE) { + /* Driver update */ + app_driver_handle_t driver_handle = (app_driver_handle_t)priv_data; + err = app_driver_attribute_update(driver_handle, endpoint_id, cluster_id, attribute_id, val); + } + + return err; +} + +extern "C" void app_main() +{ + esp_err_t err = ESP_OK; + + /* Initialize the ESP NVS layer */ + nvs_flash_init(); + +#if CONFIG_PM_ENABLE + esp_pm_config_t pm_config = { + .max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, + .min_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = true +#endif + }; + err = esp_pm_configure(&pm_config); +#endif + + /* Create a Matter node and add the mandatory Root Node device type on endpoint 0 */ + node::config_t node_config; + + // node handle can be used to add/modify other endpoints. + node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb); + ABORT_APP_ON_FAILURE(node != nullptr, ESP_LOGE(TAG, "Failed to create Matter node")); + + door_lock::config_t door_lock_config; + cluster::door_lock::feature::credential_over_the_air_access::config_t cota_config; + cluster::door_lock::feature::pin_credential::config_t pin_credential_config; + cluster::door_lock::feature::user::config_t user_config; + // endpoint handles can be used to add/modify clusters. + endpoint_t *endpoint = door_lock::create(node, &door_lock_config, ENDPOINT_FLAG_NONE, NULL); + ABORT_APP_ON_FAILURE(endpoint != nullptr, ESP_LOGE(TAG, "Failed to create door lock endpoint")); + cluster_t *door_lock_cluster = cluster::get(endpoint, DoorLock::Id); + cluster::door_lock::feature::credential_over_the_air_access::add(door_lock_cluster, &cota_config); + cluster::door_lock::feature::pin_credential::add(door_lock_cluster, &pin_credential_config); + cluster::door_lock::feature::user::add(door_lock_cluster, &user_config); + cluster::door_lock::attribute::create_auto_relock_time(door_lock_cluster, 5); + + door_lock_endpoint_id = endpoint::get_id(endpoint); + ESP_LOGI(TAG, "Door lock created with endpoint_id %d", door_lock_endpoint_id); + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + /* Set OpenThread platform config */ + esp_openthread_platform_config_t config = { + .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(), + .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(), + .port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(), + }; + set_openthread_platform_config(&config); +#endif + + /* Matter start */ + err = esp_matter::start(app_event_cb); + ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to start Matter, err:%d", err)); + + /* do nothing now */ + door_lock_init(); + +#if CONFIG_ENABLE_ENCRYPTED_OTA + err = esp_matter_ota_requestor_encrypted_init(s_decryption_key, s_decryption_key_len); + ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to initialized the encrypted OTA, err: %d", err)); +#endif // CONFIG_ENABLE_ENCRYPTED_OTA + +#if CONFIG_ENABLE_CHIP_SHELL + esp_matter::console::diagnostics_register_commands(); + esp_matter::console::wifi_register_commands(); +#if CONFIG_OPENTHREAD_CLI + esp_matter::console::otcli_register_commands(); +#endif + esp_matter::console::init(); +#endif +} diff --git a/examples/door_lock/main/app_priv.h b/examples/door_lock/main/app_priv.h new file mode 100644 index 000000000..3fc55002f --- /dev/null +++ b/examples/door_lock/main/app_priv.h @@ -0,0 +1,65 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#pragma once + +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include "esp_openthread_types.h" +#endif + +typedef void *app_driver_handle_t; + +/** Initialize the button driver + * + * This initializes the button driver associated with the selected board. + * + * @return Handle on success. + * @return NULL in case of failure. + */ +app_driver_handle_t app_driver_button_init(); + +/** Driver Update + * + * This API should be called to update the driver for the attribute being updated. + * This is usually called from the common `app_attribute_update_cb()`. + * + * @param[in] endpoint_id Endpoint ID of the attribute. + * @param[in] cluster_id Cluster ID of the attribute. + * @param[in] attribute_id Attribute ID of the attribute. + * @param[in] val Pointer to `esp_matter_attr_val_t`. Use appropriate elements as per the value type. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, + uint32_t attribute_id, esp_matter_attr_val_t *val); + +/** The definition and invocation of this function are intended to resolve the issue: + * unable to link and call the callback functions defined in the door_lock_callbacks.cpp file. +*/ +void door_lock_init(); + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \ + { \ + .radio_mode = RADIO_MODE_NATIVE, \ + } + +#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ + { \ + .host_connection_mode = HOST_CONNECTION_MODE_NONE, \ + } + +#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ + { \ + .storage_partition_name = "nvs", .netif_queue_size = 10, .task_queue_size = 10, \ + } +#endif diff --git a/examples/door_lock/main/idf_component.yml b/examples/door_lock/main/idf_component.yml new file mode 100644 index 000000000..547b39ec2 --- /dev/null +++ b/examples/door_lock/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + espressif/cmake_utilities: + version: 0.* + rules: # will add "optional_component" only when all if clauses are True + - if: "idf_version >=5.0" + - if: "target in [esp32c2]" + esp_bsp_generic: + version: "^1.1.0" diff --git a/examples/door_lock/main/lock/door_lock_callbacks.cpp b/examples/door_lock/main/lock/door_lock_callbacks.cpp new file mode 100644 index 000000000..9767e76de --- /dev/null +++ b/examples/door_lock/main/lock/door_lock_callbacks.cpp @@ -0,0 +1,124 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include "door_lock_manager.h" +#include +#include + +#include +#include +#include +#include +#include + +using namespace chip::app::Clusters; +using chip::app::DataModel::Nullable; + +static const char *TAG = "doorlock_callback"; + +void door_lock_init() +{ + ESP_LOGI(TAG, "doorlock example init"); +} + +void emberAfDoorLockClusterInitCallback(EndpointId endpoint) +{ + DoorLockServer::Instance().InitServer(endpoint); + BoltLockMgr().InitLockState(); +} + +bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const Nullable & fabricIdx, + const Nullable & nodeId, const Optional & pinCode, + OperationErrorEnum & err) +{ + ESP_LOGI(TAG, "Door Lock App: Lock Command endpoint=%d", endpointId); + bool status = BoltLockMgr().Lock(endpointId, pinCode, err); + return status; +} + +bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const Nullable & fabricIdx, + const Nullable & nodeId, const Optional & pinCode, + OperationErrorEnum & err) +{ + ESP_LOGI(TAG, "Door Lock App: Unlock Command endpoint=%d", endpointId); + bool status = BoltLockMgr().Unlock(endpointId, pinCode, err); + return status; +} + +bool emberAfPluginDoorLockGetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType, + EmberAfPluginDoorLockCredentialInfo & credential) +{ + return BoltLockMgr().GetCredential(endpointId, credentialIndex, credentialType, credential); +} + +bool emberAfPluginDoorLockSetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, chip::FabricIndex creator, + chip::FabricIndex modifier, DlCredentialStatus credentialStatus, + CredentialTypeEnum credentialType, const chip::ByteSpan & credentialData) +{ + return BoltLockMgr().SetCredential(endpointId, credentialIndex, creator, modifier, credentialStatus, credentialType, + credentialData); +} + +bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) +{ + return BoltLockMgr().GetUser(endpointId, userIndex, user); +} + +bool emberAfPluginDoorLockSetUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator, + chip::FabricIndex modifier, const chip::CharSpan & userName, uint32_t uniqueId, + UserStatusEnum userStatus, UserTypeEnum usertype, CredentialRuleEnum credentialRule, + const CredentialStruct * credentials, size_t totalCredentials) +{ + + return BoltLockMgr().SetUser(endpointId, userIndex, creator, modifier, userName, uniqueId, userStatus, usertype, credentialRule, + credentials, totalCredentials); +} + +DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + EmberAfPluginDoorLockWeekDaySchedule & schedule) +{ + return BoltLockMgr().GetWeekdaySchedule(endpointId, weekdayIndex, userIndex, schedule); +} + +DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + EmberAfPluginDoorLockYearDaySchedule & schedule) +{ + return BoltLockMgr().GetYeardaySchedule(endpointId, yearDayIndex, userIndex, schedule); +} + +DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, + EmberAfPluginDoorLockHolidaySchedule & holidaySchedule) +{ + return BoltLockMgr().GetHolidaySchedule(endpointId, holidayIndex, holidaySchedule); +} + +DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + DlScheduleStatus status, DaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, + uint8_t endHour, uint8_t endMinute) +{ + return BoltLockMgr().SetWeekdaySchedule(endpointId, weekdayIndex, userIndex, status, daysMask, startHour, startMinute, endHour, + endMinute); +} + +DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime) +{ + return BoltLockMgr().SetYeardaySchedule(endpointId, yearDayIndex, userIndex, status, localStartTime, localEndTime); +} + +DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, + uint32_t localStartTime, uint32_t localEndTime, OperatingModeEnum operatingMode) +{ + return BoltLockMgr().SetHolidaySchedule(endpointId, holidayIndex, status, localStartTime, localEndTime, operatingMode); +} + +void emberAfPluginDoorLockOnAutoRelock(chip::EndpointId endpointId) +{ + ESP_LOGI(TAG, "Door auto relock"); +} diff --git a/examples/door_lock/main/lock/door_lock_manager.cpp b/examples/door_lock/main/lock/door_lock_manager.cpp new file mode 100644 index 000000000..5ce985f32 --- /dev/null +++ b/examples/door_lock/main/lock/door_lock_manager.cpp @@ -0,0 +1,588 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include "door_lock_manager.h" + +#include +#include +#include +#include + +static const char *TAG = "doorlock_manager"; + +BoltLockManager BoltLockManager::sLock; + +TimerHandle_t sLockTimer; + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::DeviceLayer::Internal; +using namespace ESP32DoorLock::LockInitParams; +using namespace chip::Protocols::InteractionModel; + +CHIP_ERROR BoltLockManager::Init(DataModel::Nullable state, + LockParam lockParam) +{ + LockParams = lockParam; + + if (LockParams.numberOfUsers > kMaxUsers) + { + ESP_LOGI(TAG,"Max number of users is greater than %d, the maximum amount of users currently supported on this platform", kMaxUsers); + return CHIP_ERROR_NO_MEMORY; + } + + if (LockParams.numberOfCredentialsPerUser > kMaxCredentialsPerUser) + { + ESP_LOGI(TAG, "Max number of credentials per user is greater than %d, the maximum amount of users currently supported on " + "this platform", kMaxCredentialsPerUser); + return CHIP_ERROR_NO_MEMORY; + } + + if (LockParams.numberOfWeekdaySchedulesPerUser > kMaxWeekdaySchedulesPerUser) + { + ESP_LOGI(TAG, " Max number of schedules is greater than %d, the maximum amount of schedules currently supported on this platform", + kMaxWeekdaySchedulesPerUser); + return CHIP_ERROR_NO_MEMORY; + } + + if (LockParams.numberOfYeardaySchedulesPerUser > kMaxYeardaySchedulesPerUser) + { + ESP_LOGI(TAG, "Max number of schedules is greater than %d, the maximum amount of schedules currently supported on this platform", + kMaxYeardaySchedulesPerUser); + return CHIP_ERROR_NO_MEMORY; + } + + if (LockParams.numberOfHolidaySchedules > kMaxHolidaySchedules) + { + ESP_LOGI(TAG, "Max number of schedules is greater than %d, the maximum amount of schedules currently supported on this platform", + kMaxHolidaySchedules); + return CHIP_ERROR_NO_MEMORY; + } + + return CHIP_NO_ERROR; +} + +bool BoltLockManager::IsValidUserIndex(uint16_t userIndex) +{ + return (userIndex < kMaxUsers); +} + +bool BoltLockManager::IsValidCredentialIndex(uint16_t credentialIndex, CredentialTypeEnum type) +{ + if (CredentialTypeEnum::kProgrammingPIN == type) + { + return (0 == credentialIndex); // 0 is required index for Programming PIN + } + return (credentialIndex < kMaxCredentialsPerUser); +} + +bool BoltLockManager::IsValidWeekdayScheduleIndex(uint8_t scheduleIndex) +{ + return (scheduleIndex < kMaxWeekdaySchedulesPerUser); +} + +bool BoltLockManager::IsValidYeardayScheduleIndex(uint8_t scheduleIndex) +{ + return (scheduleIndex < kMaxYeardaySchedulesPerUser); +} + +bool BoltLockManager::IsValidHolidayScheduleIndex(uint8_t scheduleIndex) +{ + return (scheduleIndex < kMaxHolidaySchedules); +} + +bool BoltLockManager::ReadConfigValues() +{ + size_t outLen; + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), + sizeof(EmberAfPluginDoorLockUserInfo) * ArraySize(mLockUsers), outLen); + + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo) * ArraySize(mLockCredentials), outLen); + + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_LockUserName, reinterpret_cast(mUserNames), + sizeof(mUserNames), outLen); + + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_CredentialData, reinterpret_cast(mCredentialData), + sizeof(mCredentialData), outLen); + + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), + sizeof(CredentialStruct) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser, + outLen); + + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), + sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * + LockParams.numberOfUsers, + outLen); + + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), + sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * + LockParams.numberOfUsers, + outLen); + + ESP32Config::ReadConfigValueBin(ESP32Config::kConfigKey_HolidaySchedules, reinterpret_cast(&(mHolidaySchedule)), + sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules, outLen); + + return true; +} + +bool BoltLockManager::Lock(EndpointId endpointId, const Optional & pin, OperationErrorEnum & err) +{ + return setLockState(endpointId, DlLockState::kLocked, pin, err); +} + +bool BoltLockManager::Unlock(EndpointId endpointId, const Optional & pin, OperationErrorEnum & err) +{ + return setLockState(endpointId, DlLockState::kUnlocked, pin, err); +} + +bool BoltLockManager::GetUser(EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) +{ + VerifyOrReturnValue(userIndex > 0, false); // indices are one-indexed + + userIndex--; + + VerifyOrReturnValue(IsValidUserIndex(userIndex), false); + + ESP_LOGI(TAG, "Door Lock App: BoltLockManager::GetUser [endpoint=%d,userIndex=%hu]", endpointId, userIndex); + + const auto & userInDb = mLockUsers[userIndex]; + + user.userStatus = userInDb.userStatus; + if (UserStatusEnum::kAvailable == user.userStatus) + { + ESP_LOGI(TAG, "Found unoccupied user [endpoint=%d]", endpointId); + return true; + } + + user.userName = CharSpan(userInDb.userName.data(), userInDb.userName.size()); + user.credentials = Span(mCredentials[userIndex], userInDb.credentials.size()); + user.userUniqueId = userInDb.userUniqueId; + user.userType = userInDb.userType; + user.credentialRule = userInDb.credentialRule; + // So far there's no way to actually create the credential outside Matter, so here we always set the creation/modification + // source to Matter + user.creationSource = DlAssetSource::kMatterIM; + user.createdBy = userInDb.createdBy; + user.modificationSource = DlAssetSource::kMatterIM; + user.lastModifiedBy = userInDb.lastModifiedBy; + + ESP_LOGI(TAG, "Found occupied user [endpoint=%d,name=\"%.*s\",credentialsCount=%u,uniqueId=%" PRIu32 + ",type=%u,credentialRule=%u,createdBy=%d,lastModifiedBy=%d]", + endpointId, static_cast(user.userName.size()), user.userName.data(), user.credentials.size(), user.userUniqueId, + to_underlying(user.userType), to_underlying(user.credentialRule), user.createdBy, user.lastModifiedBy); + + return true; +} + +bool BoltLockManager::SetUser(EndpointId endpointId, uint16_t userIndex, FabricIndex creator, + FabricIndex modifier, const CharSpan & userName, uint32_t uniqueId, + UserStatusEnum userStatus, UserTypeEnum usertype, CredentialRuleEnum credentialRule, + const CredentialStruct * credentials, size_t totalCredentials) +{ + ESP_LOGI(TAG, "Door Lock App: BoltLockManager::SetUser " + "[endpoint=%d,userIndex=%d,creator=%d,modifier=%d,userName=%s,uniqueId=%" PRIu32 "" + "userStatus=%u,userType=%u,credentialRule=%u,credentials=%p,totalCredentials=%u]", + endpointId, userIndex, creator, modifier, userName.data(), uniqueId, to_underlying(userStatus), + to_underlying(usertype), to_underlying(credentialRule), credentials, totalCredentials); + + VerifyOrReturnValue(userIndex > 0, false); // indices are one-indexed + + userIndex--; + + VerifyOrReturnValue(IsValidUserIndex(userIndex), false); + + auto & userInStorage = mLockUsers[userIndex]; + + if (userName.size() > DOOR_LOCK_MAX_USER_NAME_SIZE) + { + ESP_LOGE(TAG, "Cannot set user - user name is too long [endpoint=%d,index=%d]", endpointId, userIndex); + return false; + } + + if (totalCredentials > LockParams.numberOfCredentialsPerUser) + { + ESP_LOGE(TAG, "Cannot set user - total number of credentials is too big [endpoint=%d,index=%d,totalCredentials=%u]", + endpointId, userIndex, totalCredentials); + return false; + } + + Platform::CopyString(mUserNames[userIndex], userName); + userInStorage.userName = CharSpan(mUserNames[userIndex], userName.size()); + userInStorage.userUniqueId = uniqueId; + userInStorage.userStatus = userStatus; + userInStorage.userType = usertype; + userInStorage.credentialRule = credentialRule; + userInStorage.lastModifiedBy = modifier; + userInStorage.createdBy = creator; + + for (size_t i = 0; i < totalCredentials; ++i) + { + mCredentials[userIndex][i] = credentials[i]; + } + userInStorage.credentials = Span(mCredentials[userIndex], totalCredentials); + + // Save user information in NVM flash + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), + sizeof(EmberAfPluginDoorLockUserInfo) * LockParams.numberOfUsers); + + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), + sizeof(CredentialStruct) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser); + + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_LockUserName, reinterpret_cast(mUserNames), + sizeof(mUserNames)); + + ESP_LOGI(TAG, "Successfully set the user [mEndpointId=%d,index=%d]", endpointId, userIndex); + + return true; +} + +bool BoltLockManager::GetCredential(EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType, + EmberAfPluginDoorLockCredentialInfo & credential) +{ + + if (CredentialTypeEnum::kProgrammingPIN == credentialType) + { + VerifyOrReturnValue(IsValidCredentialIndex(credentialIndex, credentialType), + false); // programming pin index is only index allowed to contain 0 + } + else + { + VerifyOrReturnValue(IsValidCredentialIndex(--credentialIndex, credentialType), false); // otherwise, indices are one-indexed + } + + ESP_LOGI(TAG, "Lock App: BoltLockManager::GetCredential [credentialType=%u], credentialIndex=%d", to_underlying(credentialType), + credentialIndex); + + const auto & credentialInStorage = mLockCredentials[credentialIndex]; + + credential.status = credentialInStorage.status; + ESP_LOGI(TAG, "CredentialStatus: %d, CredentialIndex: %d ", (int) credential.status, credentialIndex); + + if (DlCredentialStatus::kAvailable == credential.status) + { + ESP_LOGI(TAG, "Found unoccupied credential "); + return true; + } + credential.credentialType = credentialInStorage.credentialType; + credential.credentialData = credentialInStorage.credentialData; + credential.createdBy = credentialInStorage.createdBy; + credential.lastModifiedBy = credentialInStorage.lastModifiedBy; + // So far there's no way to actually create the credential outside Matter, so here we always set the creation/modification + // source to Matter + credential.creationSource = DlAssetSource::kMatterIM; + credential.modificationSource = DlAssetSource::kMatterIM; + + ESP_LOGI(TAG, "Found occupied credential [type=%u,dataSize=%u]", to_underlying(credential.credentialType), + credential.credentialData.size()); + + return true; +} + +bool BoltLockManager::SetCredential(EndpointId endpointId, uint16_t credentialIndex, FabricIndex creator, + FabricIndex modifier, DlCredentialStatus credentialStatus, + CredentialTypeEnum credentialType, const ByteSpan & credentialData) +{ + + if (CredentialTypeEnum::kProgrammingPIN == credentialType) + { + VerifyOrReturnValue(IsValidCredentialIndex(credentialIndex, credentialType), + false); // programming pin index is only index allowed to contain 0 + } + else + { + VerifyOrReturnValue(IsValidCredentialIndex(--credentialIndex, credentialType), false); // otherwise, indices are one-indexed + } + + ESP_LOGI(TAG, "Door Lock App: BoltLockManager::SetCredential " + "[credentialStatus=%u,credentialType=%u,credentialDataSize=%u,creator=%d,modifier=%d]", + to_underlying(credentialStatus), to_underlying(credentialType), credentialData.size(), creator, modifier); + + auto & credentialInStorage = mLockCredentials[credentialIndex]; + + credentialInStorage.status = credentialStatus; + credentialInStorage.credentialType = credentialType; + credentialInStorage.createdBy = creator; + credentialInStorage.lastModifiedBy = modifier; + + memcpy(mCredentialData[credentialIndex], credentialData.data(), credentialData.size()); + credentialInStorage.credentialData = ByteSpan{ mCredentialData[credentialIndex], credentialData.size() }; + + // Save credential information in NVM flash + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo) * LockParams.numberOfCredentialsPerUser); + + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_CredentialData, reinterpret_cast(&mCredentialData), + sizeof(mCredentialData)); + + ESP_LOGI(TAG, "Successfully set the credential [credentialType=%u]", to_underlying(credentialType)); + + return true; +} + +DlStatus BoltLockManager::GetWeekdaySchedule(EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + EmberAfPluginDoorLockWeekDaySchedule & schedule) +{ + + VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + weekdayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + const auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; + if (DlScheduleStatus::kAvailable == scheduleInStorage.status) + { + return DlStatus::kNotFound; + } + + schedule = scheduleInStorage.schedule; + + return DlStatus::kSuccess; +} + +DlStatus BoltLockManager::SetWeekdaySchedule(EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + DlScheduleStatus status, DaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, + uint8_t endHour, uint8_t endMinute) +{ + + VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + weekdayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; + + scheduleInStorage.schedule.daysMask = daysMask; + scheduleInStorage.schedule.startHour = startHour; + scheduleInStorage.schedule.startMinute = startMinute; + scheduleInStorage.schedule.endHour = endHour; + scheduleInStorage.schedule.endMinute = endMinute; + scheduleInStorage.status = status; + + // Save schedule information in NVM flash + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), + sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * + LockParams.numberOfUsers); + + return DlStatus::kSuccess; +} + +DlStatus BoltLockManager::GetYeardaySchedule(EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + EmberAfPluginDoorLockYearDaySchedule & schedule) +{ + VerifyOrReturnValue(yearDayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + yearDayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + const auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; + if (DlScheduleStatus::kAvailable == scheduleInStorage.status) + { + return DlStatus::kNotFound; + } + + schedule = scheduleInStorage.schedule; + + return DlStatus::kSuccess; +} + +DlStatus BoltLockManager::SetYeardaySchedule(EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime) +{ + VerifyOrReturnValue(yearDayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + yearDayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; + + scheduleInStorage.schedule.localStartTime = localStartTime; + scheduleInStorage.schedule.localEndTime = localEndTime; + scheduleInStorage.status = status; + + // Save schedule information in NVM flash + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), + sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * + LockParams.numberOfUsers); + + return DlStatus::kSuccess; +} + +DlStatus BoltLockManager::GetHolidaySchedule(EndpointId endpointId, uint8_t holidayIndex, + EmberAfPluginDoorLockHolidaySchedule & schedule) +{ + VerifyOrReturnValue(holidayIndex > 0, DlStatus::kFailure); // indices are one-indexed + + holidayIndex--; + + VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); + + const auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; + if (DlScheduleStatus::kAvailable == scheduleInStorage.status) + { + return DlStatus::kNotFound; + } + + schedule = scheduleInStorage.schedule; + + return DlStatus::kSuccess; +} + +DlStatus BoltLockManager::SetHolidaySchedule(EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, + uint32_t localStartTime, uint32_t localEndTime, OperatingModeEnum operatingMode) +{ + VerifyOrReturnValue(holidayIndex > 0, DlStatus::kFailure); // indices are one-indexed + + holidayIndex--; + + VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; + + scheduleInStorage.schedule.localStartTime = localStartTime; + scheduleInStorage.schedule.localEndTime = localEndTime; + scheduleInStorage.schedule.operatingMode = operatingMode; + scheduleInStorage.status = status; + + // Save schedule information in NVM flash + ESP32Config::WriteConfigValueBin(ESP32Config::kConfigKey_HolidaySchedules, + reinterpret_cast(&(mHolidaySchedule)), + sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules); + + return DlStatus::kSuccess; +} + +const char * BoltLockManager::lockStateToString(DlLockState lockState) const +{ + switch (lockState) + { + case DlLockState::kNotFullyLocked: + return "Not Fully Locked"; + case DlLockState::kLocked: + return "Locked"; + case DlLockState::kUnlocked: + return "Unlocked"; + case DlLockState::kUnlatched: + return "Unlatched"; + case DlLockState::kUnknownEnumValue: + break; + } + + return "Unknown"; +} + +bool BoltLockManager::setLockState(EndpointId endpointId, DlLockState lockState, const Optional & pin, + OperationErrorEnum & err) +{ + + // Assume pin is required until told otherwise + bool requirePin = true; + if ( Status::Success != DoorLock::Attributes::RequirePINforRemoteOperation::Get(endpointId, &requirePin)) { + requirePin = false; + } + + // If a pin code is not given + if (!pin.HasValue()) + { + ESP_LOGI(TAG, "Door Lock App: PIN code is not specified [endpointId=%d]", endpointId); + + // If a pin code is not required + if (!requirePin) + { + ESP_LOGI(TAG, "Door Lock App: setting door lock state to \"%s\" [endpointId=%d]", lockStateToString(lockState), + endpointId); + + DoorLockServer::Instance().SetLockState(endpointId, lockState); + + return true; + } + + ESP_LOGI(TAG, "Door Lock App: PIN code is not specified, but it is required [endpointId=%d]", endpointId); + + return false; + } + + // Check the PIN code + for (uint8_t i = 0; i < kMaxCredentials; i++) + { + if (mLockCredentials[i].credentialType != CredentialTypeEnum::kPin || + mLockCredentials[i].status == DlCredentialStatus::kAvailable) + { + continue; + } + + if (mLockCredentials[i].credentialData.data_equal(pin.Value())) + { + ESP_LOGI(TAG, "Lock App: specified PIN code was found in the database, setting lock state to \"%s\" [endpointId=%d]", + lockStateToString(lockState), endpointId); + + DoorLockServer::Instance().SetLockState(endpointId, lockState); + + return true; + } + } + + ESP_LOGI(TAG, "Door Lock App: specified PIN code was not found in the database, ignoring command to set lock state to \"%s\" " + "[endpointId=%d]", + lockStateToString(lockState), endpointId); + + err = OperationErrorEnum::kInvalidCredential; + return false; +} + +CHIP_ERROR BoltLockManager::InitLockState() +{ + // Initial lock state + DataModel::Nullable state; + EndpointId endpointId{ 1 }; + DoorLock::Attributes::LockState::Get(endpointId, state); + + uint8_t numberOfCredentialsPerUser = 0; + if (!DoorLockServer::Instance().GetNumberOfCredentialsSupportedPerUser(endpointId, numberOfCredentialsPerUser)) + { + ESP_LOGE(TAG, "Unable to get number of credentials supported per user when initializing lock endpoint, defaulting to 5 [endpointId=%d]", endpointId); + numberOfCredentialsPerUser = 5; + } + + uint16_t numberOfUsers = 0; + if (!DoorLockServer::Instance().GetNumberOfUserSupported(endpointId, numberOfUsers)) + { + ESP_LOGE(TAG, "Unable to get number of supported users when initializing lock endpoint, defaulting to 10 [endpointId=%d]", endpointId); + numberOfUsers = 10; + } + + CHIP_ERROR err = BoltLockMgr().Init(state, ParamBuilder() + .SetNumberOfUsers(numberOfUsers) + .SetNumberOfCredentialsPerUser(numberOfCredentialsPerUser) + .GetLockParam()); + ReadConfigValues(); + if (err != CHIP_NO_ERROR) + { + ESP_LOGE(TAG, "BoltLockMgr().Init() failed"); + return err; + } + + return err; +} diff --git a/examples/door_lock/main/lock/door_lock_manager.h b/examples/door_lock/main/lock/door_lock_manager.h new file mode 100644 index 000000000..8f661050d --- /dev/null +++ b/examples/door_lock/main/lock/door_lock_manager.h @@ -0,0 +1,182 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#pragma once +#include + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" // provides FreeRTOS timer support + +#include + +struct WeekDaysScheduleInfo +{ + DlScheduleStatus status; + EmberAfPluginDoorLockWeekDaySchedule schedule; +}; + +struct YearDayScheduleInfo +{ + DlScheduleStatus status; + EmberAfPluginDoorLockYearDaySchedule schedule; +}; + +struct HolidayScheduleInfo +{ + DlScheduleStatus status; + EmberAfPluginDoorLockHolidaySchedule schedule; +}; + +namespace ESP32DoorLock { +namespace ResourceRanges { +// Used to size arrays +static constexpr uint16_t kMaxUsers = 10; +static constexpr uint8_t kMaxCredentialsPerUser = 10; +static constexpr uint8_t kMaxWeekdaySchedulesPerUser = 10; +static constexpr uint8_t kMaxYeardaySchedulesPerUser = 10; +static constexpr uint8_t kMaxHolidaySchedules = 10; +static constexpr uint8_t kMaxCredentialSize = 8; + +static constexpr uint8_t kMaxCredentials = kMaxUsers * kMaxCredentialsPerUser; +} // namespace ResourceRanges + +namespace LockInitParams { + +struct LockParam +{ + // Read from zap attributes + uint16_t numberOfUsers = 0; + uint8_t numberOfCredentialsPerUser = 0; + uint8_t numberOfWeekdaySchedulesPerUser = 0; + uint8_t numberOfYeardaySchedulesPerUser = 0; + uint8_t numberOfHolidaySchedules = 0; +}; + +class ParamBuilder +{ +public: + ParamBuilder & SetNumberOfUsers(uint16_t numberOfUsers) + { + lockParam_.numberOfUsers = numberOfUsers; + return *this; + } + ParamBuilder & SetNumberOfCredentialsPerUser(uint8_t numberOfCredentialsPerUser) + { + lockParam_.numberOfCredentialsPerUser = numberOfCredentialsPerUser; + return *this; + } + ParamBuilder & SetNumberOfWeekdaySchedulesPerUser(uint8_t numberOfWeekdaySchedulesPerUser) + { + lockParam_.numberOfWeekdaySchedulesPerUser = numberOfWeekdaySchedulesPerUser; + return *this; + } + ParamBuilder & SetNumberOfYeardaySchedulesPerUser(uint8_t numberOfYeardaySchedulesPerUser) + { + lockParam_.numberOfYeardaySchedulesPerUser = numberOfYeardaySchedulesPerUser; + return *this; + } + ParamBuilder & SetNumberOfHolidaySchedules(uint8_t numberOfHolidaySchedules) + { + lockParam_.numberOfHolidaySchedules = numberOfHolidaySchedules; + return *this; + } + LockParam GetLockParam() { return lockParam_; } + +private: + LockParam lockParam_; +}; + +} // namespace LockInitParams +} // namespace ESP32DoorLock + +using namespace chip; +using namespace ESP32DoorLock::ResourceRanges; + +class BoltLockManager +{ +public: + enum Action_t + { + LOCK_ACTION = 0, + UNLOCK_ACTION, + + INVALID_ACTION + } Action; + + CHIP_ERROR InitLockState(); + CHIP_ERROR Init(chip::app::DataModel::Nullable state, + ESP32DoorLock::LockInitParams::LockParam lockParam); + + bool Lock(chip::EndpointId endpointId, const Optional & pin, OperationErrorEnum & err); + bool Unlock(chip::EndpointId endpointId, const Optional & pin, OperationErrorEnum & err); + + bool GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user); + bool SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier, + const chip::CharSpan & userName, uint32_t uniqueId, UserStatusEnum userStatus, UserTypeEnum usertype, + CredentialRuleEnum credentialRule, const CredentialStruct * credentials, size_t totalCredentials); + + bool GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType, + EmberAfPluginDoorLockCredentialInfo & credential); + + bool SetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, chip::FabricIndex creator, chip::FabricIndex modifier, + DlCredentialStatus credentialStatus, CredentialTypeEnum credentialType, + const chip::ByteSpan & credentialData); + + DlStatus GetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + EmberAfPluginDoorLockWeekDaySchedule & schedule); + + DlStatus SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, DlScheduleStatus status, + DaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute); + + DlStatus GetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + EmberAfPluginDoorLockYearDaySchedule & schedule); + + DlStatus SetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status, + uint32_t localStartTime, uint32_t localEndTime); + + DlStatus GetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule & schedule); + + DlStatus SetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime, + uint32_t localEndTime, OperatingModeEnum operatingMode); + + bool IsValidUserIndex(uint16_t userIndex); + bool IsValidCredentialIndex(uint16_t credentialIndex, CredentialTypeEnum type); + bool IsValidWeekdayScheduleIndex(uint8_t scheduleIndex); + bool IsValidYeardayScheduleIndex(uint8_t scheduleIndex); + bool IsValidHolidayScheduleIndex(uint8_t scheduleIndex); + + bool setLockState(chip::EndpointId endpointId, DlLockState lockState, const Optional & pin, + OperationErrorEnum & err); + const char * lockStateToString(DlLockState lockState) const; + + bool ReadConfigValues(); + +private: + friend BoltLockManager & BoltLockMgr(); + + EmberAfPluginDoorLockUserInfo mLockUsers[kMaxUsers]; + EmberAfPluginDoorLockCredentialInfo mLockCredentials[kMaxCredentials]; + WeekDaysScheduleInfo mWeekdaySchedule[kMaxUsers][kMaxWeekdaySchedulesPerUser]; + YearDayScheduleInfo mYeardaySchedule[kMaxUsers][kMaxYeardaySchedulesPerUser]; + HolidayScheduleInfo mHolidaySchedule[kMaxHolidaySchedules]; + + char mUserNames[ArraySize(mLockUsers)][DOOR_LOCK_MAX_USER_NAME_SIZE]; + uint8_t mCredentialData[kMaxCredentials][kMaxCredentialSize]; + CredentialStruct mCredentials[kMaxUsers][kMaxCredentialsPerUser]; + + static BoltLockManager sLock; + ESP32DoorLock::LockInitParams::LockParam LockParams; +}; + +inline BoltLockManager & BoltLockMgr() +{ + return BoltLockManager::sLock; +} diff --git a/examples/door_lock/partitions.csv b/examples/door_lock/partitions.csv new file mode 100644 index 000000000..428705154 --- /dev/null +++ b/examples/door_lock/partitions.csv @@ -0,0 +1,11 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table +esp_secure_cert, 0x3F, ,0xd000, 0x2000, encrypted +nvs, data, nvs, 0x10000, 0xC000, +nvs_keys, data, nvs_keys,, 0x1000, encrypted +otadata, data, ota, , 0x2000 +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, 0x20000, 0x1E0000, +ota_1, app, ota_1, 0x200000, 0x1E0000, +fctry, data, nvs, 0x3E0000, 0x6000 +coredump, data, coredump,, 64K diff --git a/examples/door_lock/sdkconfig.defaults b/examples/door_lock/sdkconfig.defaults new file mode 100644 index 000000000..9b6905016 --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults @@ -0,0 +1,65 @@ +# Default to 921600 baud when flashing and monitoring device +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_ESPTOOLPY_BAUD=921600 +CONFIG_ESPTOOLPY_COMPRESSED=y +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + +#enable BT +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y + +#disable BT connection reattempt +CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n + +#enable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=y + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0xC000 + +# Enable chip shell +CONFIG_ENABLE_CHIP_SHELL=y + +#enable lwIP route hooks +CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y +CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Button +CONFIG_BUTTON_PERIOD_TIME_MS=20 +CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000 + +# disable softap by default +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n + +# Disable DS Peripheral +CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n + +# Use compact attribute storage mode +CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y + +# Enable HKDF in mbedtls +CONFIG_MBEDTLS_HKDF_C=y + +# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1) +# unique local addresses for fabrics(MAX_FABRIC), a link local address(1) +CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 + +# ESP32-DevKitC Settings +# Buttons +CONFIG_BSP_BUTTONS_NUM=1 +CONFIG_BSP_BUTTON_1_TYPE_GPIO=y +CONFIG_BSP_BUTTON_1_GPIO=0 +CONFIG_BSP_BUTTON_1_LEVEL=0 +# LEDs +CONFIG_BSP_LEDS_NUM=0 + +# configurations required for diagnostic logs cluster +# Enable the diagnostic logs transfer over BDX protocol +CONFIG_CHIP_ENABLE_BDX_LOG_TRANSFER=y + +CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y +CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF=y diff --git a/examples/door_lock/sdkconfig.defaults.c6_thread b/examples/door_lock/sdkconfig.defaults.c6_thread new file mode 100644 index 000000000..0c65765db --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.c6_thread @@ -0,0 +1,51 @@ +CONFIG_IDF_TARGET="esp32c6" + +# libsodium +CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y + +# NIMBLE +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=n +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n + +# FreeRTOS should use legacy API +CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y + +# Enable OpenThread +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_OPENTHREAD_SRP_CLIENT=y +CONFIG_OPENTHREAD_DNS_CLIENT=y +CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC=n +CONFIG_OPENTHREAD_LOG_LEVEL_NOTE=y +CONFIG_OPENTHREAD_CLI=n + +# Disable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=n + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# LwIP config for OpenThread +CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 +CONFIG_LWIP_MULTICAST_PING=y + +# MDNS platform +CONFIG_USE_MINIMAL_MDNS=n +CONFIG_ENABLE_EXTENDED_DISCOVERY=y + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y + +# Disable STA and AP for ESP32C6 +CONFIG_ENABLE_WIFI_STATION=n +CONFIG_ENABLE_WIFI_AP=n + +# Button +CONFIG_BUTTON_PERIOD_TIME_MS=20 +CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000 + +# Enable chip shell +CONFIG_ENABLE_CHIP_SHELL=y diff --git a/examples/door_lock/sdkconfig.defaults.esp32c2 b/examples/door_lock/sdkconfig.defaults.esp32c2 new file mode 100644 index 000000000..540d7e147 --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.esp32c2 @@ -0,0 +1,176 @@ +# Bluetooth +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +## NimBLE Options +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_BONDS=2 +CONFIG_BT_NIMBLE_MAX_CCCDS=2 +CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=3072 +CONFIG_BT_NIMBLE_ROLE_CENTRAL=n +CONFIG_BT_NIMBLE_ROLE_OBSERVER=n +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=10 +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=100 +CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=4 +CONFIG_BT_NIMBLE_ACL_BUF_COUNT=5 +CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT=5 +CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT=3 +CONFIG_BT_NIMBLE_GATT_MAX_PROCS=1 +CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n +CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=n +CONFIG_BT_NIMBLE_WHITELIST_SIZE=1 +## Controller Options +CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE=3072 +CONFIG_BT_LE_LL_RESOLV_LIST_SIZE=1 +CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT=1 + +# Release BT IRAM memory +CONFIG_BT_RELEASE_IRAM=y + +# SPI Configuration +CONFIG_SPI_MASTER_ISR_IN_IRAM=n +CONFIG_SPI_SLAVE_ISR_IN_IRAM=n + +# Ethernet +CONFIG_ETH_USE_SPI_ETHERNET=n + +# Event Loop Library +CONFIG_ESP_EVENT_POST_FROM_ISR=n + +# Chip revision +CONFIG_ESP32C2_REV2_DEVELOPMENT=y + +# ESP Ringbuf +CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH=y +CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y + +# ESP System Settings +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=16 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2048 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3072 + +## Memory protection +CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=n + +# High resolution timer (esp_timer) +CONFIG_ESP_TIMER_TASK_STACK_SIZE=2048 + +# Wi-Fi +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=n +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=3 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=6 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=6 +CONFIG_ESP32_WIFI_IRAM_OPT=n +CONFIG_ESP32_WIFI_RX_IRAM_OPT=n +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=n +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=n +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=n +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n + +# FreeRTOS +## Kernel +CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y +## Port +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=n +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y +CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y + +# Hardware Abstraction Layer (HAL) and Low Level (LL) +CONFIG_HAL_ASSERTION_DISABLE=y + +# LWIP +CONFIG_LWIP_MAX_SOCKETS=5 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=16 +CONFIG_LWIP_DHCPS=n +CONFIG_LWIP_IPV6_AUTOCONFIG=y +CONFIG_LWIP_MAX_ACTIVE_TCP=5 +CONFIG_LWIP_MAX_LISTENING_TCP=5 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=n +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSL=40000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=16000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=4096 +CONFIG_LWIP_TCP_WND_DEFAULT=2440 +CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS=y +CONFIG_LWIP_TCP_RTO_TIME=1500 +CONFIG_LWIP_MAX_UDP_PCBS=8 +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=2560 +CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y +CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# mbedTLS +CONFIG_MBEDTLS_DYNAMIC_BUFFER=y +CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y +CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT=y +CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH=y +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=n +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y +CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y +CONFIG_MBEDTLS_SSL_PROTO_SSL3=n +CONFIG_MBEDTLS_SSL_PROTO_TLS1=n +CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=n + +# ESP-MQTT Configurations +CONFIG_MQTT_PROTOCOL_311=n + +# Protocomm +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=n +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=n + +# SPI Flash driver +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=n +CONFIG_SPI_FLASH_ROM_IMPL=y + +# Websocket +CONFIG_WS_TRANSPORT=n + +# Virtual file system +CONFIG_VFS_SUPPORT_DIR=n +CONFIG_VFS_SUPPORT_SELECT=n +CONFIG_VFS_SUPPORT_TERMIOS=n + +# Wear Levelling +CONFIG_WL_SECTOR_SIZE_512=y + +# CHIP Core +## General Options +CONFIG_MAX_EXCHANGE_CONTEXTS=6 +CONFIG_MAX_BINDINGS=6 +CONFIG_MAX_PEER_NODES=12 +CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS=6 +CONFIG_ENABLE_CHIP_SHELL=n +CONFIG_DISABLE_IPV4=y +CONFIG_BUILD_CHIP_TESTS=n +## Networking Options +CONFIG_NUM_TCP_ENDPOINTS=1 +CONFIG_NUM_UDP_ENDPOINTS=6 +## System Options +CONFIG_NUM_TIMERS=24 +CONFIG_ENABLE_OTA_REQUESTOR=y + +# CHIP Device Layer +## General Options +CONFIG_CHIP_TASK_STACK_SIZE=6144 +CONFIG_MAX_EVENT_QUEUE_SIZE=20 +## Event Logging Options +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=256 +CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE=256 +CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE=256 + +# ESP Matter +CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT=4 +CONFIG_ESP_MATTER_MAX_DYNAMIC_ENDPOINT_COUNT=4 + +# ESP32-C2-DevKitM-1 Settings +# Buttons +CONFIG_BSP_BUTTONS_NUM=1 +CONFIG_BSP_BUTTON_1_TYPE_GPIO=y +CONFIG_BSP_BUTTON_1_GPIO=0 +CONFIG_BSP_BUTTON_1_LEVEL=0 +# LEDs +CONFIG_BSP_LEDS_NUM=1 +CONFIG_BSP_LED_TYPE_RGB_CLASSIC=y +CONFIG_BSP_LED_RGB_RED_GPIO=0 +CONFIG_BSP_LED_RGB_GREEN_GPIO=1 +CONFIG_BSP_LED_RGB_BLUE_GPIO=8 + diff --git a/examples/door_lock/sdkconfig.defaults.esp32c2.v5.1 b/examples/door_lock/sdkconfig.defaults.esp32c2.v5.1 new file mode 100644 index 000000000..245ec1227 --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.esp32c2.v5.1 @@ -0,0 +1,4 @@ +# CMake Utilities +CONFIG_CU_RELINKER_ENABLE=y +CONFIG_CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES=y +CONFIG_CU_RELINKER_CUSTOMIZED_CONFIGURATION_FILES_PATH="../common/relinker/esp32c2_v5.1" diff --git a/examples/door_lock/sdkconfig.defaults.esp32c2.v5.2 b/examples/door_lock/sdkconfig.defaults.esp32c2.v5.2 new file mode 100644 index 000000000..5d4ed95fe --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.esp32c2.v5.2 @@ -0,0 +1,4 @@ +# CMake Utilities +CONFIG_CU_RELINKER_ENABLE=y +CONFIG_CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES=y +CONFIG_CU_RELINKER_CUSTOMIZED_CONFIGURATION_FILES_PATH="../common/relinker/esp32c2_v5.2" diff --git a/examples/door_lock/sdkconfig.defaults.esp32c3 b/examples/door_lock/sdkconfig.defaults.esp32c3 new file mode 100644 index 000000000..1c873a0cf --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.esp32c3 @@ -0,0 +1,21 @@ +CONFIG_IDF_TARGET="esp32c3" + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y + +# Disable AP +CONFIG_ENABLE_WIFI_STATION=y +CONFIG_ENABLE_WIFI_AP=n + +# ESP32-C3-DevKitC-02 Settings +# Buttons +CONFIG_BSP_BUTTONS_NUM=1 +CONFIG_BSP_BUTTON_1_TYPE_GPIO=y +CONFIG_BSP_BUTTON_1_GPIO=9 +CONFIG_BSP_BUTTON_1_LEVEL=0 +# LEDs +CONFIG_BSP_LEDS_NUM=1 +CONFIG_BSP_LED_TYPE_RGB=y +CONFIG_BSP_LED_RGB_GPIO=8 +CONFIG_BSP_LED_RGB_BACKEND_RMT=y + diff --git a/examples/door_lock/sdkconfig.defaults.esp32c6 b/examples/door_lock/sdkconfig.defaults.esp32c6 new file mode 100644 index 000000000..7ac4003f2 --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.esp32c6 @@ -0,0 +1,95 @@ +CONFIG_IDF_TARGET="esp32c6" + +# libsodium +CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y + +# NIMBLE +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=n +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y + +# FreeRTOS should use legacy API +CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y + +# Enable OpenThread +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_OPENTHREAD_SRP_CLIENT=y +CONFIG_OPENTHREAD_DNS_CLIENT=y +CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC=n +CONFIG_OPENTHREAD_LOG_LEVEL_NOTE=y +CONFIG_OPENTHREAD_CLI=n + +# Disable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=n + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# LwIP config for OpenThread +CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 +CONFIG_LWIP_MULTICAST_PING=y + +# MDNS platform +CONFIG_USE_MINIMAL_MDNS=n +CONFIG_ENABLE_EXTENDED_DISCOVERY=y + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y + +# Disable STA and AP for ESP32H2 +CONFIG_ENABLE_WIFI_STATION=n +CONFIG_ENABLE_WIFI_AP=n + +# Disable chip shell +CONFIG_ENABLE_CHIP_SHELL=n + +# Enable DS Peripheral +CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=y + +# BLE Sleep +CONFIG_BT_LE_SLEEP_ENABLE=y +CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL=y + +# Disable external 32K crystal +CONFIG_RTC_CLK_SRC_EXT_CRYS=n + +# Enable power management +CONFIG_PM_ENABLE=y +CONFIG_PM_DFS_INIT_AUTO=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y +CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=n +CONFIG_ESP_PHY_MAC_BB_PD=y + +# FreeRTOS config for light sleep +CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y + +# Enable IEEE 802.15.4 sleep +CONFIG_IEEE802154_SLEEP_ENABLE=y + +# FreeRTOS config for light sleep +CONFIG_LWIP_ND6=n +CONFIG_LWIP_IPV4=n +CONFIG_DISABLE_IPV4=y + +# Disable hardware acceleration +CONFIG_MBEDTLS_HARDWARE_AES=n +CONFIG_MBEDTLS_HARDWARE_MPI=n +CONFIG_MBEDTLS_HARDWARE_SHA=n +CONFIG_MBEDTLS_HARDWARE_ECC=n +CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY=n +CONFIG_MBEDTLS_SSL_PROTO_DTLS=y + +# Use OpenThread MTD +CONFIG_OPENTHREAD_MTD=y + +# ICD configurations +CONFIG_ENABLE_ICD_SERVER=y +CONFIG_ICD_FAST_POLL_INTERVAL_MS=500 +CONFIG_ICD_IDLE_MODE_INTERVAL_SEC=60 +CONFIG_ICD_ACTIVE_MODE_INTERVAL_MS=1000 +CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS=1000 +CONFIG_ENABLE_ICD_LIT=y diff --git a/examples/door_lock/sdkconfig.defaults.esp32h2 b/examples/door_lock/sdkconfig.defaults.esp32h2 new file mode 100644 index 000000000..03a2900c6 --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.esp32h2 @@ -0,0 +1,94 @@ +CONFIG_IDF_TARGET="esp32h2" + +# libsodium +CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y + +# NIMBLE +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=n +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y + +# FreeRTOS should use legacy API +CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y + +# Enable OpenThread +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_OPENTHREAD_SRP_CLIENT=y +CONFIG_OPENTHREAD_DNS_CLIENT=y +CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC=n +CONFIG_OPENTHREAD_LOG_LEVEL_NOTE=y +CONFIG_OPENTHREAD_CLI=n + +# Disable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=n + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# LwIP config for OpenThread +CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 +CONFIG_LWIP_MULTICAST_PING=y + +# MDNS platform +CONFIG_USE_MINIMAL_MDNS=n +CONFIG_ENABLE_EXTENDED_DISCOVERY=y + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y + +# Disable STA and AP for ESP32H2 +CONFIG_ENABLE_WIFI_STATION=n +CONFIG_ENABLE_WIFI_AP=n + +# Disable chip shell +CONFIG_ENABLE_CHIP_SHELL=n + +# Enable DS Peripheral +CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=y + +# BLE Sleep +CONFIG_BT_LE_SLEEP_ENABLE=y +CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL=y + +# Disable external 32K crystal +CONFIG_RTC_CLK_SRC_EXT_CRYS=n + +# Enable power management +CONFIG_PM_ENABLE=y +CONFIG_PM_DFS_INIT_AUTO=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y +CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y + +# FreeRTOS config for light sleep +CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y + +# Enable IEEE 802.15.4 sleep +CONFIG_IEEE802154_SLEEP_ENABLE=y + +# FreeRTOS config for light sleep +CONFIG_LWIP_ND6=n +CONFIG_LWIP_IPV4=n +CONFIG_DISABLE_IPV4=y + +# Disable hardware acceleration +CONFIG_MBEDTLS_HARDWARE_AES=n +CONFIG_MBEDTLS_HARDWARE_MPI=n +CONFIG_MBEDTLS_HARDWARE_SHA=n +CONFIG_MBEDTLS_HARDWARE_ECC=n +CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY=n +CONFIG_MBEDTLS_SSL_PROTO_DTLS=y + +# Use OpenThread MTD +CONFIG_OPENTHREAD_MTD=y + +# ICD configurations +CONFIG_ENABLE_ICD_SERVER=y +CONFIG_ICD_FAST_POLL_INTERVAL_MS=500 +CONFIG_ICD_IDLE_MODE_INTERVAL_SEC=60 +CONFIG_ICD_ACTIVE_MODE_INTERVAL_MS=1000 +CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS=1000 +CONFIG_ENABLE_ICD_LIT=y diff --git a/examples/door_lock/sdkconfig.defaults.esp32s3 b/examples/door_lock/sdkconfig.defaults.esp32s3 new file mode 100644 index 000000000..111eb7ebd --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.esp32s3 @@ -0,0 +1,53 @@ +#enable BT +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y + +#disable BT connection reattempt +CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n + +#enable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=y + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0xC000 + +# Enable chip shell +CONFIG_ENABLE_CHIP_SHELL=y + +#enable lwIP route hooks +CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y +CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Button +CONFIG_BUTTON_PERIOD_TIME_MS=20 +CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000 + +# disable softap by default +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n + +# Disable DS Peripheral +CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n + +# Use compact attribute storage mode +CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y + +# Enable HKDF in mbedtls +CONFIG_MBEDTLS_HKDF_C=y + +# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1) +# unique local addresses for fabrics(MAX_FABRIC), a link local address(1) +CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 + +# ESP32-S3-DevKitC-1 Settings +# Buttons +CONFIG_BSP_BUTTONS_NUM=1 +CONFIG_BSP_BUTTON_1_TYPE_GPIO=y +CONFIG_BSP_BUTTON_1_GPIO=0 +CONFIG_BSP_BUTTON_1_LEVEL=0 +# LEDs +CONFIG_BSP_LEDS_NUM=1 +CONFIG_BSP_LED_TYPE_RGB=y +CONFIG_BSP_LED_RGB_GPIO=48 +CONFIG_BSP_LED_RGB_BACKEND_RMT=y diff --git a/examples/door_lock/sdkconfig.defaults.ext_plat_ci b/examples/door_lock/sdkconfig.defaults.ext_plat_ci new file mode 100644 index 000000000..e03657152 --- /dev/null +++ b/examples/door_lock/sdkconfig.defaults.ext_plat_ci @@ -0,0 +1,61 @@ +# Default to 921600 baud when flashing and monitoring device +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_ESPTOOLPY_BAUD=921600 +CONFIG_ESPTOOLPY_COMPRESSED=y +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + +#enable BT +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y + +#disable BT connection reattempt +CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n + +#enable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=y + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" + +# Disable chip shell +CONFIG_ENABLE_CHIP_SHELL=n + +# Disable chip tests +CONFIG_BUILD_CHIP_TESTS=n + +#enable lwIP route hooks +CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y +CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Button +CONFIG_BUTTON_PERIOD_TIME_MS=20 +CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000 + +# External Platform +CONFIG_CHIP_ENABLE_EXTERNAL_PLATFORM=y +CONFIG_CHIP_EXTERNAL_PLATFORM_DIR="../../../../../platform/ESP32_custom" +CONFIG_CHIP_EXTERNAL_PLATFORM_INCLUDE_DIR="../../../../.." + +# disable softap by default +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n + +# Disable DS Peripheral +CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n + +# Use compact attribute storage mode +CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y + +# Enable HKDF in mbedtls +CONFIG_MBEDTLS_HKDF_C=y + +# ESP32-DevKit Settings +# Buttons +CONFIG_BSP_BUTTONS_NUM=1 +CONFIG_BSP_BUTTON_1_TYPE_GPIO=y +CONFIG_BSP_BUTTON_1_GPIO=0 +CONFIG_BSP_BUTTON_1_LEVEL=0 +# LEDs +CONFIG_BSP_LEDS_NUM=0 \ No newline at end of file