[Chef] Implement DoorLock example app (#32532)
* Update Chef Lock to enable user PIN and more
* Remove unused clusters (Groups). Add Power Source
* Refer to the latest lock-app codes
* Update device PowerSource attributes
* Enable PrivacyMode, Remove debug message
* Fix typo
* Restyled by whitespace
* Restyled by clang-format
* Add macro to doorlock to avoid compilation of light
* [Chef] support doorlock in esp32 & nrfconnect
* Update the date from 2023 to 2024
* Use CharSpan instead of "char *". Refine ifdef
* Restyled by clang-format
---------
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/examples/chef/common/clusters/door-lock/chef-doorlock-stubs.cpp b/examples/chef/common/clusters/door-lock/chef-doorlock-stubs.cpp
new file mode 100644
index 0000000..7d92300
--- /dev/null
+++ b/examples/chef/common/clusters/door-lock/chef-doorlock-stubs.cpp
@@ -0,0 +1,133 @@
+/*
+ *
+ * Copyright (c) 2020-2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <app/data-model/Nullable.h>
+#include <app/util/af.h>
+#include <lib/core/DataModelTypes.h>
+
+#ifdef MATTER_DM_PLUGIN_DOOR_LOCK_SERVER
+#include "chef-lock-manager.h"
+#include <app/clusters/door-lock-server/door-lock-server.h>
+
+using namespace chip;
+using namespace chip::app::Clusters;
+using namespace chip::app::Clusters::DoorLock;
+using chip::app::DataModel::Nullable;
+
+// =============================================================================
+// 'Default' callbacks for cluster commands
+// =============================================================================
+
+// App handles physical aspects of locking but not locking logic. That is it
+// should wait for door to be locked on lock command and return success) but
+// door lock server should check pin before even calling the lock-door
+// callback.
+bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
+ const Nullable<chip::NodeId> & nodeId, const Optional<ByteSpan> & pinCode,
+ OperationErrorEnum & err)
+{
+ return LockManager::Instance().Lock(endpointId, fabricIdx, nodeId, pinCode, err, OperationSourceEnum::kRemote);
+}
+
+bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
+ const Nullable<chip::NodeId> & nodeId, const Optional<ByteSpan> & pinCode,
+ OperationErrorEnum & err)
+{
+ return LockManager::Instance().Unlock(endpointId, fabricIdx, nodeId, pinCode, err, OperationSourceEnum::kRemote);
+}
+
+bool emberAfPluginDoorLockOnDoorUnboltCommand(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
+ const Nullable<chip::NodeId> & nodeId, const Optional<ByteSpan> & pinCode,
+ OperationErrorEnum & err)
+{
+ return LockManager::Instance().Unbolt(endpointId, fabricIdx, nodeId, pinCode, err, OperationSourceEnum::kRemote);
+}
+
+bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
+{
+ return LockManager::Instance().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 LockManager::Instance().SetUser(endpointId, userIndex, creator, modifier, userName, uniqueId, userStatus, usertype,
+ credentialRule, credentials, totalCredentials);
+}
+
+bool emberAfPluginDoorLockGetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType,
+ EmberAfPluginDoorLockCredentialInfo & credential)
+{
+ return LockManager::Instance().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 LockManager::Instance().SetCredential(endpointId, credentialIndex, creator, modifier, credentialStatus, credentialType,
+ credentialData);
+}
+
+DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex,
+ EmberAfPluginDoorLockWeekDaySchedule & schedule)
+{
+ return LockManager::Instance().GetSchedule(endpointId, weekdayIndex, userIndex, schedule);
+}
+
+DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex,
+ EmberAfPluginDoorLockHolidaySchedule & schedule)
+{
+ return LockManager::Instance().GetSchedule(endpointId, holidayIndex, schedule);
+}
+
+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 LockManager::Instance().SetSchedule(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 LockManager::Instance().SetSchedule(endpointId, yearDayIndex, userIndex, status, localStartTime, localEndTime);
+}
+
+DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex,
+ EmberAfPluginDoorLockYearDaySchedule & schedule)
+{
+ return LockManager::Instance().GetSchedule(endpointId, yearDayIndex, userIndex, schedule);
+}
+
+DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status,
+ uint32_t localStartTime, uint32_t localEndTime, OperatingModeEnum operatingMode)
+{
+ return LockManager::Instance().SetSchedule(endpointId, holidayIndex, status, localStartTime, localEndTime, operatingMode);
+}
+
+void emberAfDoorLockClusterInitCallback(EndpointId endpoint)
+{
+ DoorLockServer::Instance().InitServer(endpoint);
+ LockManager::Instance().InitEndpoint(endpoint);
+}
+#endif // MATTER_DM_PLUGIN_DOOR_LOCK_SERVER
diff --git a/examples/chef/common/clusters/door-lock/chef-lock-endpoint.cpp b/examples/chef/common/clusters/door-lock/chef-lock-endpoint.cpp
new file mode 100644
index 0000000..7cff212
--- /dev/null
+++ b/examples/chef/common/clusters/door-lock/chef-lock-endpoint.cpp
@@ -0,0 +1,680 @@
+/*
+ *
+ * Copyright (c) 2022-2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <app-common/zap-generated/attributes/Accessors.h>
+#include <app/util/af.h>
+#include <cstring>
+#include <platform/CHIPDeviceLayer.h>
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+#ifdef MATTER_DM_PLUGIN_DOOR_LOCK_SERVER
+#include "chef-lock-endpoint.h"
+
+using chip::to_underlying;
+using chip::app::DataModel::MakeNullable;
+
+struct LockActionData
+{
+ chip::EndpointId endpointId;
+ DlLockState lockState;
+ OperationSourceEnum opSource;
+ Nullable<uint16_t> userIndex;
+ uint16_t credentialIndex;
+ Nullable<chip::FabricIndex> fabricIdx;
+ Nullable<chip::NodeId> nodeId;
+ bool moving = false;
+};
+
+static LockActionData gCurrentAction;
+
+bool LockEndpoint::Lock(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource)
+{
+ return setLockState(fabricIdx, nodeId, DlLockState::kLocked, pin, err, opSource);
+}
+
+bool LockEndpoint::Unlock(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource)
+{
+ if (DoorLockServer::Instance().SupportsUnbolt(mEndpointId))
+ {
+ // If Unbolt is supported Unlock is supposed to pull the latch
+ return setLockState(fabricIdx, nodeId, DlLockState::kUnlatched, pin, err, opSource);
+ }
+
+ return setLockState(fabricIdx, nodeId, DlLockState::kUnlocked, pin, err, opSource);
+}
+
+bool LockEndpoint::Unbolt(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource)
+{
+ return setLockState(fabricIdx, nodeId, DlLockState::kUnlocked, pin, err, opSource);
+}
+
+bool LockEndpoint::GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const
+{
+ ChipLogProgress(Zcl, "Lock App: LockEndpoint::GetUser [endpoint=%d,userIndex=%hu]", mEndpointId, userIndex);
+
+ auto adjustedUserIndex = static_cast<uint16_t>(userIndex - 1);
+ if (adjustedUserIndex > mLockUsers.size())
+ {
+ ChipLogError(Zcl, "Cannot get user - index out of range [endpoint=%d,index=%hu,adjustedIndex=%d]", mEndpointId, userIndex,
+ adjustedUserIndex);
+ return false;
+ }
+
+ const auto & userInDb = mLockUsers[adjustedUserIndex];
+ user.userStatus = userInDb.userStatus;
+ if (UserStatusEnum::kAvailable == user.userStatus)
+ {
+ ChipLogDetail(Zcl, "Found unoccupied user [endpoint=%d,adjustedIndex=%hu]", mEndpointId, adjustedUserIndex);
+ return true;
+ }
+
+ user.userName = userInDb.userName;
+ user.credentials = chip::Span<const CredentialStruct>(userInDb.credentials.data(), 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 the 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;
+
+ ChipLogDetail(Zcl,
+ "Found occupied user "
+ "[endpoint=%d,adjustedIndex=%hu,name=\"%.*s\",credentialsCount=%u,uniqueId=%x,type=%u,credentialRule=%u,"
+ "createdBy=%d,lastModifiedBy=%d]",
+ mEndpointId, adjustedUserIndex, static_cast<int>(user.userName.size()), user.userName.data(),
+ static_cast<unsigned int>(user.credentials.size()), user.userUniqueId, to_underlying(user.userType),
+ to_underlying(user.credentialRule), user.createdBy, user.lastModifiedBy);
+
+ return true;
+}
+
+bool LockEndpoint::SetUser(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)
+{
+ ChipLogProgress(Zcl,
+ "Lock App: LockEndpoint::SetUser "
+ "[endpoint=%d,userIndex=%u,creator=%d,modifier=%d,userName=\"%.*s\",uniqueId=%" PRIx32
+ ",userStatus=%u,userType=%u,"
+ "credentialRule=%u,credentials=%p,totalCredentials=%u]",
+ mEndpointId, userIndex, creator, modifier, static_cast<int>(userName.size()), userName.data(), uniqueId,
+ to_underlying(userStatus), to_underlying(usertype), to_underlying(credentialRule), credentials,
+ static_cast<unsigned int>(totalCredentials));
+
+ auto adjustedUserIndex = static_cast<uint16_t>(userIndex - 1);
+ if (adjustedUserIndex > mLockUsers.size())
+ {
+ ChipLogError(Zcl, "Cannot set user - index out of range [endpoint=%d,index=%d,adjustedUserIndex=%u]", mEndpointId,
+ userIndex, adjustedUserIndex);
+ return false;
+ }
+
+ auto & userInStorage = mLockUsers[adjustedUserIndex];
+ if (userName.size() > DOOR_LOCK_MAX_USER_NAME_SIZE)
+ {
+ ChipLogError(Zcl, "Cannot set user - user name is too long [endpoint=%d,index=%d,adjustedUserIndex=%u]", mEndpointId,
+ userIndex, adjustedUserIndex);
+ return false;
+ }
+
+ if (totalCredentials > userInStorage.credentials.capacity())
+ {
+ ChipLogError(Zcl,
+ "Cannot set user - total number of credentials is too big [endpoint=%d,index=%d,adjustedUserIndex=%u"
+ ",totalCredentials=%u,maxNumberOfCredentials=%u]",
+ mEndpointId, userIndex, adjustedUserIndex, static_cast<unsigned int>(totalCredentials),
+ static_cast<unsigned int>(userInStorage.credentials.capacity()));
+ return false;
+ }
+
+ userInStorage.userName = chip::MutableCharSpan(userInStorage.userNameBuf, DOOR_LOCK_USER_NAME_BUFFER_SIZE);
+ CopyCharSpanToMutableCharSpan(userName, userInStorage.userName);
+ userInStorage.userUniqueId = uniqueId;
+ userInStorage.userStatus = userStatus;
+ userInStorage.userType = usertype;
+ userInStorage.credentialRule = credentialRule;
+ userInStorage.lastModifiedBy = modifier;
+ userInStorage.createdBy = creator;
+
+ userInStorage.credentials.clear();
+ for (size_t i = 0; i < totalCredentials; ++i)
+ {
+ userInStorage.credentials.push_back(credentials[i]);
+ }
+
+ ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d,adjustedIndex=%d]", mEndpointId, userIndex,
+ adjustedUserIndex);
+
+ return true;
+}
+
+DoorStateEnum LockEndpoint::GetDoorState() const
+{
+ return mDoorState;
+}
+
+bool LockEndpoint::SetDoorState(DoorStateEnum newState)
+{
+ if (mDoorState != newState)
+ {
+ ChipLogProgress(Zcl, "Changing the door state to: %d [endpointId=%d,previousState=%d]", to_underlying(newState),
+ mEndpointId, to_underlying(mDoorState));
+
+ mDoorState = newState;
+ return DoorLockServer::Instance().SetDoorState(mEndpointId, mDoorState);
+ }
+ return true;
+}
+
+bool LockEndpoint::SendLockAlarm(AlarmCodeEnum alarmCode) const
+{
+ ChipLogProgress(Zcl, "Sending the LockAlarm event [endpointId=%d,alarmCode=%u]", mEndpointId, to_underlying(alarmCode));
+ return DoorLockServer::Instance().SendLockAlarmEvent(mEndpointId, alarmCode);
+}
+
+bool LockEndpoint::GetCredential(uint16_t credentialIndex, CredentialTypeEnum credentialType,
+ EmberAfPluginDoorLockCredentialInfo & credential) const
+{
+ ChipLogProgress(Zcl, "Lock App: LockEndpoint::GetCredential [endpoint=%d,credentialIndex=%u,credentialType=%u]", mEndpointId,
+ credentialIndex, to_underlying(credentialType));
+
+ if (to_underlying(credentialType) >= mLockCredentials.size())
+ {
+ ChipLogError(Zcl, "Cannot get the credential - index out of range [endpoint=%d,index=%d]", mEndpointId, credentialIndex);
+ return false;
+ }
+
+ if (credentialIndex >= mLockCredentials.at(to_underlying(credentialType)).size() ||
+ (0 == credentialIndex && CredentialTypeEnum::kProgrammingPIN != credentialType))
+ {
+ ChipLogError(Zcl, "Cannot get the credential - index out of range [endpoint=%d,index=%d]", mEndpointId, credentialIndex);
+ return false;
+ }
+
+ const auto & credentialInStorage = mLockCredentials[to_underlying(credentialType)][credentialIndex];
+
+ credential.status = credentialInStorage.status;
+ if (DlCredentialStatus::kAvailable == credential.status)
+ {
+ ChipLogDetail(Zcl, "Found unoccupied credential [endpoint=%d,index=%u]", mEndpointId, credentialIndex);
+ return true;
+ }
+ credential.credentialType = credentialInStorage.credentialType;
+ credential.credentialData = chip::ByteSpan(credentialInStorage.credentialData, credentialInStorage.credentialDataSize);
+ // So far there's no way to actually create the credential outside the matter, so here we always set the creation/modification
+ // source to Matter
+ credential.creationSource = DlAssetSource::kMatterIM;
+ credential.createdBy = credentialInStorage.createdBy;
+ credential.modificationSource = DlAssetSource::kMatterIM;
+ credential.lastModifiedBy = credentialInStorage.modifiedBy;
+
+ ChipLogDetail(Zcl, "Found occupied credential [endpoint=%d,index=%u,type=%u,dataSize=%u,createdBy=%u,modifiedBy=%u]",
+ mEndpointId, credentialIndex, to_underlying(credential.credentialType),
+ static_cast<unsigned int>(credential.credentialData.size()), credential.createdBy, credential.lastModifiedBy);
+
+ return true;
+}
+
+bool LockEndpoint::SetCredential(uint16_t credentialIndex, chip::FabricIndex creator, chip::FabricIndex modifier,
+ DlCredentialStatus credentialStatus, CredentialTypeEnum credentialType,
+ const chip::ByteSpan & credentialData)
+{
+ ChipLogProgress(
+ Zcl,
+ "Lock App: LockEndpoint::SetCredential "
+ "[endpoint=%d,credentialIndex=%u,credentialStatus=%u,credentialType=%u,credentialDataSize=%u,creator=%u,modifier=%u]",
+ mEndpointId, credentialIndex, to_underlying(credentialStatus), to_underlying(credentialType),
+ static_cast<unsigned int>(credentialData.size()), creator, modifier);
+
+ if (to_underlying(credentialType) >= mLockCredentials.capacity())
+ {
+ ChipLogError(Zcl, "Cannot set the credential - type out of range [endpoint=%d,type=%d]", mEndpointId,
+ to_underlying(credentialType));
+ return false;
+ }
+
+ if (credentialIndex >= mLockCredentials.at(to_underlying(credentialType)).size() ||
+ (0 == credentialIndex && CredentialTypeEnum::kProgrammingPIN != credentialType))
+ {
+ ChipLogError(Zcl, "Cannot set the credential - index out of range [endpoint=%d,index=%d]", mEndpointId, credentialIndex);
+ return false;
+ }
+
+ // Assign to array by credentialIndex. Note: 0 is reserved for programmingPIN only
+ auto & credentialInStorage = mLockCredentials[to_underlying(credentialType)][credentialIndex];
+ if (credentialData.size() > DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE)
+ {
+ ChipLogError(Zcl,
+ "Cannot get the credential - data size exceeds limit "
+ "[endpoint=%d,index=%d,dataSize=%u,maxDataSize=%u]",
+ mEndpointId, credentialIndex, static_cast<unsigned int>(credentialData.size()),
+ static_cast<unsigned int>(DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE));
+ return false;
+ }
+ credentialInStorage.status = credentialStatus;
+ credentialInStorage.credentialType = credentialType;
+ credentialInStorage.createdBy = creator;
+ credentialInStorage.modifiedBy = modifier;
+ std::memcpy(credentialInStorage.credentialData, credentialData.data(), credentialData.size());
+ credentialInStorage.credentialDataSize = credentialData.size();
+
+ ChipLogProgress(Zcl, "Successfully set the credential [mEndpointId=%d,index=%d,credentialType=%u,creator=%u,modifier=%u]",
+ mEndpointId, credentialIndex, to_underlying(credentialType), credentialInStorage.createdBy,
+ credentialInStorage.modifiedBy);
+
+ return true;
+}
+
+DlStatus LockEndpoint::GetSchedule(uint8_t weekDayIndex, uint16_t userIndex, EmberAfPluginDoorLockWeekDaySchedule & schedule)
+{
+ if (0 == userIndex || userIndex > mWeekDaySchedules.size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ if (0 == weekDayIndex || weekDayIndex > mWeekDaySchedules.at(userIndex - 1).size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ const auto & scheduleInStorage = mWeekDaySchedules.at(userIndex - 1).at(weekDayIndex - 1);
+ if (DlScheduleStatus::kAvailable == scheduleInStorage.status)
+ {
+ return DlStatus::kNotFound;
+ }
+
+ schedule = scheduleInStorage.schedule;
+
+ return DlStatus::kSuccess;
+}
+
+DlStatus LockEndpoint::SetSchedule(uint8_t weekDayIndex, uint16_t userIndex, DlScheduleStatus status, DaysMaskMap daysMask,
+ uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute)
+{
+ if (0 == userIndex || userIndex > mWeekDaySchedules.size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ if (0 == weekDayIndex || weekDayIndex > mWeekDaySchedules.at(userIndex - 1).size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ auto & scheduleInStorage = mWeekDaySchedules.at(userIndex - 1).at(weekDayIndex - 1);
+
+ scheduleInStorage.schedule.daysMask = daysMask;
+ scheduleInStorage.schedule.startHour = startHour;
+ scheduleInStorage.schedule.startMinute = startMinute;
+ scheduleInStorage.schedule.endHour = endHour;
+ scheduleInStorage.schedule.endMinute = endMinute;
+ scheduleInStorage.status = status;
+
+ return DlStatus::kSuccess;
+}
+
+DlStatus LockEndpoint::GetSchedule(uint8_t yearDayIndex, uint16_t userIndex, EmberAfPluginDoorLockYearDaySchedule & schedule)
+{
+ if (0 == userIndex || userIndex > mYearDaySchedules.size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ if (0 == yearDayIndex || yearDayIndex > mYearDaySchedules.at(userIndex - 1).size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ const auto & scheduleInStorage = mYearDaySchedules.at(userIndex - 1).at(yearDayIndex - 1);
+ if (DlScheduleStatus::kAvailable == scheduleInStorage.status)
+ {
+ return DlStatus::kNotFound;
+ }
+
+ schedule = scheduleInStorage.schedule;
+
+ return DlStatus::kSuccess;
+}
+
+DlStatus LockEndpoint::SetSchedule(uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status, uint32_t localStartTime,
+ uint32_t localEndTime)
+{
+ if (0 == userIndex || userIndex > mYearDaySchedules.size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ if (0 == yearDayIndex || yearDayIndex > mYearDaySchedules.at(userIndex - 1).size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ auto & scheduleInStorage = mYearDaySchedules.at(userIndex - 1).at(yearDayIndex - 1);
+ scheduleInStorage.schedule.localStartTime = localStartTime;
+ scheduleInStorage.schedule.localEndTime = localEndTime;
+ scheduleInStorage.status = status;
+
+ return DlStatus::kSuccess;
+}
+
+DlStatus LockEndpoint::GetSchedule(uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule & schedule)
+{
+ if (0 == holidayIndex || holidayIndex > mHolidaySchedules.size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ const auto & scheduleInStorage = mHolidaySchedules[holidayIndex - 1];
+ if (DlScheduleStatus::kAvailable == scheduleInStorage.status)
+ {
+ return DlStatus::kNotFound;
+ }
+
+ schedule = scheduleInStorage.schedule;
+ return DlStatus::kSuccess;
+}
+
+DlStatus LockEndpoint::SetSchedule(uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime,
+ OperatingModeEnum operatingMode)
+{
+ if (0 == holidayIndex || holidayIndex > mHolidaySchedules.size())
+ {
+ return DlStatus::kFailure;
+ }
+
+ auto & scheduleInStorage = mHolidaySchedules[holidayIndex - 1];
+ scheduleInStorage.schedule.localStartTime = localStartTime;
+ scheduleInStorage.schedule.localEndTime = localEndTime;
+ scheduleInStorage.schedule.operatingMode = operatingMode;
+ scheduleInStorage.status = status;
+
+ return DlStatus::kSuccess;
+}
+
+bool LockEndpoint::setLockState(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ DlLockState lockState, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
+ OperationSourceEnum opSource)
+{
+ // Assume pin is required until told otherwise
+ bool requirePin = true;
+ chip::app::Clusters::DoorLock::Attributes::RequirePINforRemoteOperation::Get(mEndpointId, &requirePin);
+
+ // If a pin code is not given
+ if (!pin.HasValue())
+ {
+ ChipLogDetail(Zcl, "Door Lock App: PIN code is not specified [endpointId=%d]", mEndpointId);
+
+ // If a pin code is not required
+ if (!requirePin)
+ {
+ ChipLogProgress(Zcl, "Door Lock App: setting door lock state to \"%s\" [endpointId=%d]", lockStateToString(lockState),
+ mEndpointId);
+
+ if (gCurrentAction.moving == true)
+ {
+ ChipLogProgress(Zcl, "Lock App: not executing lock action as another lock action is already active [endpointId=%d]",
+ mEndpointId);
+ return false;
+ }
+
+ gCurrentAction.moving = true;
+ gCurrentAction.endpointId = mEndpointId;
+ gCurrentAction.lockState = lockState;
+ gCurrentAction.opSource = opSource;
+ gCurrentAction.userIndex = NullNullable;
+ gCurrentAction.fabricIdx = fabricIdx;
+ gCurrentAction.nodeId = nodeId;
+
+ // Do this async as a real lock would do too but use 0s delay to speed up CI tests
+ chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(0), OnLockActionCompleteCallback, nullptr);
+
+ return true;
+ }
+
+ ChipLogError(Zcl, "Door Lock App: PIN code is not specified, but it is required [endpointId=%d]", mEndpointId);
+
+ err = OperationErrorEnum::kInvalidCredential;
+ return false;
+ }
+
+ // Find the credential so we can make sure it is not absent right away
+ auto & pinCredentials = mLockCredentials[to_underlying(CredentialTypeEnum::kPin)];
+ auto credential = std::find_if(pinCredentials.begin(), pinCredentials.end(), [&pin](const LockCredentialInfo & c) {
+ return (c.status != DlCredentialStatus::kAvailable) &&
+ chip::ByteSpan{ c.credentialData, c.credentialDataSize }.data_equal(pin.Value());
+ });
+ if (credential == pinCredentials.end())
+ {
+ ChipLogDetail(Zcl,
+ "Lock App: specified PIN code was not found in the database, ignoring command to set lock state to \"%s\" "
+ "[endpointId=%d]",
+ lockStateToString(lockState), mEndpointId);
+
+ err = OperationErrorEnum::kInvalidCredential;
+ return false;
+ }
+
+ // Find a user that correspond to this credential
+ auto credentialIndex = static_cast<unsigned>(credential - pinCredentials.begin());
+ auto user = std::find_if(mLockUsers.begin(), mLockUsers.end(), [credential, credentialIndex](const LockUserInfo & u) {
+ return std::any_of(u.credentials.begin(), u.credentials.end(), [&credential, credentialIndex](const CredentialStruct & c) {
+ return c.credentialIndex == credentialIndex && c.credentialType == credential->credentialType;
+ });
+ });
+ if (user == mLockUsers.end())
+ {
+ ChipLogDetail(Zcl,
+ "Lock App: specified PIN code was found in the database, but the lock user is not associated with it "
+ "[endpointId=%d,credentialIndex=%u]",
+ mEndpointId, credentialIndex);
+ }
+
+ auto userIndex = static_cast<uint8_t>(user - mLockUsers.begin());
+
+ // Check if schedules affect the user
+ bool haveWeekDaySchedules = false;
+ bool haveYearDaySchedules = false;
+ if (weekDayScheduleForbidsAccess(userIndex, &haveWeekDaySchedules) ||
+ yearDayScheduleForbidsAccess(userIndex, &haveYearDaySchedules) ||
+ // Also disallow access for a user that's supposed to have _some_
+ // schedule but doesn't have any
+ (user->userType == UserTypeEnum::kScheduleRestrictedUser && !haveWeekDaySchedules && !haveYearDaySchedules))
+ {
+ ChipLogDetail(Zcl,
+ "Lock App: associated user is not allowed to operate the lock due to schedules"
+ "[endpointId=%d,userIndex=%u]",
+ mEndpointId, userIndex);
+ err = OperationErrorEnum::kRestricted;
+ return false;
+ }
+ ChipLogProgress(
+ Zcl,
+ "Lock App: specified PIN code was found in the database, setting door lock state to \"%s\" [endpointId=%d,userIndex=%u]",
+ lockStateToString(lockState), mEndpointId, userIndex);
+
+ if (gCurrentAction.moving == true)
+ {
+ ChipLogProgress(Zcl,
+ "Lock App: not executing lock action as another lock action is already active [endpointId=%d,userIndex=%u]",
+ mEndpointId, userIndex);
+ return false;
+ }
+
+ gCurrentAction.moving = true;
+ gCurrentAction.endpointId = mEndpointId;
+ gCurrentAction.lockState = lockState;
+ gCurrentAction.opSource = opSource;
+ gCurrentAction.userIndex = MakeNullable(static_cast<uint16_t>(userIndex + 1));
+ gCurrentAction.credentialIndex = static_cast<uint16_t>(credentialIndex);
+ gCurrentAction.fabricIdx = fabricIdx;
+ gCurrentAction.nodeId = nodeId;
+
+ // Do this async as a real lock would do too but use 0s delay to speed up CI tests
+ chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(0), OnLockActionCompleteCallback, nullptr);
+
+ return true;
+}
+
+void LockEndpoint::OnLockActionCompleteCallback(chip::System::Layer *, void * callbackContext)
+{
+ if (gCurrentAction.userIndex.IsNull())
+ {
+ DoorLockServer::Instance().SetLockState(gCurrentAction.endpointId, gCurrentAction.lockState, gCurrentAction.opSource,
+ NullNullable, NullNullable, gCurrentAction.fabricIdx, gCurrentAction.nodeId);
+ }
+ else
+ {
+ LockOpCredentials userCredential[] = { { CredentialTypeEnum::kPin, gCurrentAction.credentialIndex } };
+ auto userCredentials = MakeNullable<List<const LockOpCredentials>>(userCredential);
+
+ DoorLockServer::Instance().SetLockState(gCurrentAction.endpointId, gCurrentAction.lockState, gCurrentAction.opSource,
+ gCurrentAction.userIndex, userCredentials, gCurrentAction.fabricIdx,
+ gCurrentAction.nodeId);
+ }
+
+ // move back to Unlocked after Unlatch
+ if (gCurrentAction.lockState == DlLockState::kUnlatched)
+ {
+ gCurrentAction.lockState = DlLockState::kUnlocked;
+
+ // Do this async as a real lock would do too but use 0s delay to speed up CI tests
+ chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(0), OnLockActionCompleteCallback, nullptr);
+ }
+ else
+ {
+ gCurrentAction.moving = false;
+ }
+}
+
+bool LockEndpoint::weekDayScheduleForbidsAccess(uint16_t userIndex, bool * haveSchedule) const
+{
+ *haveSchedule = std::any_of(mWeekDaySchedules[userIndex].begin(), mWeekDaySchedules[userIndex].end(),
+ [](const WeekDaysScheduleInfo & s) { return s.status == DlScheduleStatus::kOccupied; });
+
+ const auto & user = mLockUsers[userIndex];
+ if (user.userType != UserTypeEnum::kScheduleRestrictedUser && user.userType != UserTypeEnum::kWeekDayScheduleUser)
+ {
+ // Weekday schedules don't apply to this user.
+ return false;
+ }
+
+ if (user.userType == UserTypeEnum::kScheduleRestrictedUser && !*haveSchedule)
+ {
+ // It's valid to not have any schedules of a given type; on its own this
+ // does not prevent access.
+ return false;
+ }
+
+ chip::System::Clock::Milliseconds64 cTMs;
+ auto chipError = chip::System::SystemClock().GetClock_RealTimeMS(cTMs);
+ if (chipError != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Lock App: unable to get current time to check user schedules [endpointId=%d,error=%d (%s)]", mEndpointId,
+ chipError.AsInteger(), chipError.AsString());
+ return true;
+ }
+ time_t unixEpoch = std::chrono::duration_cast<chip::System::Clock::Seconds32>(cTMs).count();
+
+ tm calendarTime{};
+ localtime_r(&unixEpoch, &calendarTime);
+
+ auto currentTime =
+ calendarTime.tm_hour * chip::kSecondsPerHour + calendarTime.tm_min * chip::kSecondsPerMinute + calendarTime.tm_sec;
+
+ // Now check whether any schedule allows the current time. If it does,
+ // access is not forbidden.
+ return !std::any_of(
+ mWeekDaySchedules[userIndex].begin(), mWeekDaySchedules[userIndex].end(),
+ [currentTime, calendarTime](const WeekDaysScheduleInfo & s) {
+ auto startTime = s.schedule.startHour * chip::kSecondsPerHour + s.schedule.startMinute * chip::kSecondsPerMinute;
+ auto endTime = s.schedule.endHour * chip::kSecondsPerHour + s.schedule.endMinute * chip::kSecondsPerMinute;
+
+ return s.status == DlScheduleStatus::kOccupied && (to_underlying(s.schedule.daysMask) & (1 << calendarTime.tm_wday)) &&
+ startTime <= currentTime && currentTime <= endTime;
+ });
+}
+
+bool LockEndpoint::yearDayScheduleForbidsAccess(uint16_t userIndex, bool * haveSchedule) const
+{
+ *haveSchedule = std::any_of(mYearDaySchedules[userIndex].begin(), mYearDaySchedules[userIndex].end(),
+ [](const YearDayScheduleInfo & sch) { return sch.status == DlScheduleStatus::kOccupied; });
+
+ const auto & user = mLockUsers[userIndex];
+ if (user.userType != UserTypeEnum::kScheduleRestrictedUser && user.userType != UserTypeEnum::kYearDayScheduleUser)
+ {
+ return false;
+ }
+
+ if (user.userType == UserTypeEnum::kScheduleRestrictedUser && !*haveSchedule)
+ {
+ // It's valid to not have any schedules of a given type; on its own this
+ // does not prevent access.
+ return false;
+ }
+
+ chip::System::Clock::Milliseconds64 cTMs;
+ auto chipError = chip::System::SystemClock().GetClock_RealTimeMS(cTMs);
+ if (chipError != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Lock App: unable to get current time to check user schedules [endpointId=%d,error=%d (%s)]", mEndpointId,
+ chipError.AsInteger(), chipError.AsString());
+ return true;
+ }
+ auto unixEpoch = std::chrono::duration_cast<chip::System::Clock::Seconds32>(cTMs).count();
+ uint32_t chipEpoch = 0;
+ if (!chip::UnixEpochToChipEpochTime(unixEpoch, chipEpoch))
+ {
+ ChipLogError(Zcl,
+ "Lock App: unable to convert Unix Epoch time to Matter Epoch Time to check user schedules "
+ "[endpointId=%d,userIndex=%d]",
+ mEndpointId, userIndex);
+ return false;
+ }
+
+ return !std::any_of(mYearDaySchedules[userIndex].begin(), mYearDaySchedules[userIndex].end(),
+ [chipEpoch](const YearDayScheduleInfo & sch) {
+ return sch.status == DlScheduleStatus::kOccupied && sch.schedule.localStartTime <= chipEpoch &&
+ chipEpoch <= sch.schedule.localEndTime;
+ });
+}
+
+const char * LockEndpoint::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";
+}
+#endif // MATTER_DM_PLUGIN_DOOR_LOCK_SERVER
diff --git a/examples/chef/common/clusters/door-lock/chef-lock-endpoint.h b/examples/chef/common/clusters/door-lock/chef-lock-endpoint.h
new file mode 100644
index 0000000..285e703
--- /dev/null
+++ b/examples/chef/common/clusters/door-lock/chef-lock-endpoint.h
@@ -0,0 +1,162 @@
+/*
+ *
+ * Copyright (c) 2022-2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <app/clusters/door-lock-server/door-lock-server.h>
+#include <vector>
+
+struct LockUserInfo
+{
+ char userNameBuf[DOOR_LOCK_USER_NAME_BUFFER_SIZE];
+ chip::MutableCharSpan userName;
+ uint32_t userUniqueId;
+ UserStatusEnum userStatus;
+ UserTypeEnum userType;
+ CredentialRuleEnum credentialRule;
+ std::vector<CredentialStruct> credentials;
+ chip::FabricIndex createdBy;
+ chip::FabricIndex lastModifiedBy;
+};
+
+struct LockCredentialInfo;
+struct WeekDaysScheduleInfo;
+struct YearDayScheduleInfo;
+struct HolidayScheduleInfo;
+
+static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE = 20;
+static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_TYPES = 6; // 0: ProgrammingPIN ~ 5: Face
+
+class LockEndpoint
+{
+public:
+ LockEndpoint(chip::EndpointId endpointId, uint16_t numberOfLockUsersSupported, uint16_t numberOfCredentialsSupported,
+ uint8_t weekDaySchedulesPerUser, uint8_t yearDaySchedulesPerUser, uint8_t numberOfCredentialsPerUser,
+ uint8_t numberOfHolidaySchedules) :
+ mEndpointId{ endpointId },
+ mLockState{ DlLockState::kLocked }, mDoorState{ DoorStateEnum::kDoorClosed }, mLockUsers(numberOfLockUsersSupported),
+ mLockCredentials(DOOR_LOCK_CREDENTIAL_INFO_MAX_TYPES, std::vector<LockCredentialInfo>(numberOfCredentialsSupported + 1)),
+ mWeekDaySchedules(numberOfLockUsersSupported, std::vector<WeekDaysScheduleInfo>(weekDaySchedulesPerUser)),
+ mYearDaySchedules(numberOfLockUsersSupported, std::vector<YearDayScheduleInfo>(yearDaySchedulesPerUser)),
+ mHolidaySchedules(numberOfHolidaySchedules)
+ {
+ for (auto & lockUser : mLockUsers)
+ {
+ lockUser.credentials.reserve(numberOfCredentialsPerUser);
+ }
+ DoorLockServer::Instance().SetDoorState(endpointId, mDoorState);
+ DoorLockServer::Instance().SetLockState(endpointId, mLockState);
+ }
+
+ inline chip::EndpointId GetEndpointId() const { return mEndpointId; }
+
+ bool Lock(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
+ bool Unlock(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
+ bool Unbolt(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
+
+ bool GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const;
+ bool SetUser(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 SetDoorState(DoorStateEnum newState);
+
+ DoorStateEnum GetDoorState() const;
+
+ bool SendLockAlarm(AlarmCodeEnum alarmCode) const;
+
+ bool GetCredential(uint16_t credentialIndex, CredentialTypeEnum credentialType,
+ EmberAfPluginDoorLockCredentialInfo & credential) const;
+
+ bool SetCredential(uint16_t credentialIndex, chip::FabricIndex creator, chip::FabricIndex modifier,
+ DlCredentialStatus credentialStatus, CredentialTypeEnum credentialType,
+ const chip::ByteSpan & credentialData);
+
+ DlStatus GetSchedule(uint8_t weekDayIndex, uint16_t userIndex, EmberAfPluginDoorLockWeekDaySchedule & schedule);
+ DlStatus GetSchedule(uint8_t yearDayIndex, uint16_t userIndex, EmberAfPluginDoorLockYearDaySchedule & schedule);
+ DlStatus GetSchedule(uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule & schedule);
+
+ DlStatus SetSchedule(uint8_t weekDayIndex, uint16_t userIndex, DlScheduleStatus status, DaysMaskMap daysMask, uint8_t startHour,
+ uint8_t startMinute, uint8_t endHour, uint8_t endMinute);
+ DlStatus SetSchedule(uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status, uint32_t localStartTime,
+ uint32_t localEndTime);
+ DlStatus SetSchedule(uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime,
+ OperatingModeEnum operatingMode);
+
+private:
+ bool setLockState(const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId, DlLockState lockState,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
+ OperationSourceEnum opSource = OperationSourceEnum::kUnspecified);
+ const char * lockStateToString(DlLockState lockState) const;
+
+ // Returns true if week day schedules should apply to the user, there are
+ // schedules defined for the user, and access is not currently allowed by
+ // those schedules. The outparam indicates whether there were in fact any
+ // year day schedules defined for the user.
+ bool weekDayScheduleForbidsAccess(uint16_t userIndex, bool * haveSchedule) const;
+ // Returns true if year day schedules should apply to the user, there are
+ // schedules defined for the user, and access is not currently allowed by
+ // those schedules. The outparam indicates whether there were in fact any
+ // year day schedules defined for the user.
+ bool yearDayScheduleForbidsAccess(uint16_t userIndex, bool * haveSchedule) const;
+
+ static void OnLockActionCompleteCallback(chip::System::Layer *, void * callbackContext);
+
+ chip::EndpointId mEndpointId;
+ DlLockState mLockState;
+ DoorStateEnum mDoorState;
+
+ // This is very naive implementation of users/credentials/schedules database and by no means the best practice. Proper storage
+ // of those items is out of scope of this example.
+ std::vector<LockUserInfo> mLockUsers;
+ std::vector<std::vector<LockCredentialInfo>> mLockCredentials;
+ std::vector<std::vector<WeekDaysScheduleInfo>> mWeekDaySchedules;
+ std::vector<std::vector<YearDayScheduleInfo>> mYearDaySchedules;
+ std::vector<HolidayScheduleInfo> mHolidaySchedules;
+};
+
+struct LockCredentialInfo
+{
+ DlCredentialStatus status;
+ CredentialTypeEnum credentialType;
+ chip::FabricIndex createdBy;
+ chip::FabricIndex modifiedBy;
+ uint8_t credentialData[DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE];
+ size_t credentialDataSize;
+};
+
+struct WeekDaysScheduleInfo
+{
+ DlScheduleStatus status;
+ EmberAfPluginDoorLockWeekDaySchedule schedule;
+};
+
+struct YearDayScheduleInfo
+{
+ DlScheduleStatus status;
+ EmberAfPluginDoorLockYearDaySchedule schedule;
+};
+
+struct HolidayScheduleInfo
+{
+ DlScheduleStatus status;
+ EmberAfPluginDoorLockHolidaySchedule schedule;
+};
diff --git a/examples/chef/common/clusters/door-lock/chef-lock-manager.cpp b/examples/chef/common/clusters/door-lock/chef-lock-manager.cpp
new file mode 100644
index 0000000..0b81cce
--- /dev/null
+++ b/examples/chef/common/clusters/door-lock/chef-lock-manager.cpp
@@ -0,0 +1,376 @@
+/*
+ *
+ * Copyright (c) 2020-2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <app/util/af.h>
+#include <iostream>
+#include <lib/support/logging/CHIPLogging.h>
+
+#ifdef MATTER_DM_PLUGIN_DOOR_LOCK_SERVER
+#include "chef-lock-manager.h"
+
+using chip::to_underlying;
+
+LockManager LockManager::instance;
+
+LockManager & LockManager::Instance()
+{
+ return instance;
+}
+
+bool LockManager::InitEndpoint(chip::EndpointId endpointId)
+{
+ uint16_t numberOfSupportedUsers = 0;
+ if (!DoorLockServer::Instance().GetNumberOfUserSupported(endpointId, numberOfSupportedUsers))
+ {
+ ChipLogError(Zcl,
+ "Unable to get number of supported users when initializing lock endpoint, defaulting to 10 [endpointId=%d]",
+ endpointId);
+ numberOfSupportedUsers = 10;
+ }
+
+ uint16_t numberOfSupportedCredentials = 0;
+ // We're planning to use shared storage for PIN and RFID users so we will have the maximum of both sizes her to simplify logic
+ uint16_t numberOfPINCredentialsSupported = 0;
+ uint16_t numberOfRFIDCredentialsSupported = 0;
+ if (!DoorLockServer::Instance().GetNumberOfPINCredentialsSupported(endpointId, numberOfPINCredentialsSupported) ||
+ !DoorLockServer::Instance().GetNumberOfRFIDCredentialsSupported(endpointId, numberOfRFIDCredentialsSupported))
+ {
+ ChipLogError(
+ Zcl, "Unable to get number of supported credentials when initializing lock endpoint, defaulting to 10 [endpointId=%d]",
+ endpointId);
+ numberOfSupportedCredentials = 10;
+ }
+ else
+ {
+ numberOfSupportedCredentials = std::max(numberOfPINCredentialsSupported, numberOfRFIDCredentialsSupported);
+ }
+
+ uint8_t numberOfCredentialsSupportedPerUser = 0;
+ if (!DoorLockServer::Instance().GetNumberOfCredentialsSupportedPerUser(endpointId, numberOfCredentialsSupportedPerUser))
+ {
+ ChipLogError(Zcl,
+ "Unable to get number of credentials supported per user when initializing lock endpoint, defaulting to 5 "
+ "[endpointId=%d]",
+ endpointId);
+ numberOfCredentialsSupportedPerUser = 5;
+ }
+
+ uint8_t numberOfWeekDaySchedulesPerUser = 0;
+ if (!DoorLockServer::Instance().GetNumberOfWeekDaySchedulesPerUserSupported(endpointId, numberOfWeekDaySchedulesPerUser))
+ {
+ ChipLogError(Zcl,
+ "Unable to get number of supported week day schedules per user when initializing lock endpoint, defaulting to "
+ "10 [endpointId=%d]",
+ endpointId);
+ numberOfWeekDaySchedulesPerUser = 10;
+ }
+
+ uint8_t numberOfYearDaySchedulesPerUser = 0;
+ if (!DoorLockServer::Instance().GetNumberOfYearDaySchedulesPerUserSupported(endpointId, numberOfYearDaySchedulesPerUser))
+ {
+ ChipLogError(Zcl,
+ "Unable to get number of supported year day schedules per user when initializing lock endpoint, defaulting to "
+ "10 [endpointId=%d]",
+ endpointId);
+ numberOfYearDaySchedulesPerUser = 10;
+ }
+
+ uint8_t numberOfHolidaySchedules = 0;
+ if (!DoorLockServer::Instance().GetNumberOfHolidaySchedulesSupported(endpointId, numberOfHolidaySchedules))
+ {
+ ChipLogError(
+ Zcl,
+ "Unable to get number of supported holiday schedules when initializing lock endpoint, defaulting to 10 [endpointId=%d]",
+ endpointId);
+ numberOfHolidaySchedules = 10;
+ }
+
+ mEndpoints.emplace_back(endpointId, numberOfSupportedUsers, numberOfSupportedCredentials, numberOfWeekDaySchedulesPerUser,
+ numberOfYearDaySchedulesPerUser, numberOfCredentialsSupportedPerUser, numberOfHolidaySchedules);
+
+ // Refer to 5.2.10.34. SetUser Command, when Creat a new user record
+ // - UserIndex value SHALL be set to a user record with UserType set to Available
+ // - UserName MAY be null causing new user record to use empty string for UserName
+ // otherwise UserName SHALL be set to the value provided in the new user record.
+ // - UserUniqueID MAY be null causing new user record to use 0xFFFFFFFF for UserUniqueID
+ // otherwise UserUniqueID SHALL be set to the value provided in the new user record
+ // - UserStatus MAY be null causing new user record to use OccupiedEnabled for UserStatus
+ // otherwise UserStatus SHALL be set to the value provided in the new user record
+ // - UserType MAY be null causing new user record to use UnrestrictedUser for UserType
+ // otherwise UserType SHALL be set to the value provided in the new user record.
+ uint16_t userIndex(1);
+ chip::FabricIndex creator(1);
+ chip::FabricIndex modifier(1);
+ const chip::CharSpan userName = chip::CharSpan::fromCharString("user1"); // default
+ // username
+ uint32_t uniqueId = 0xFFFFFFFF; // null
+ UserStatusEnum userStatus = UserStatusEnum::kOccupiedEnabled;
+ // Set to programming user instead of unrestrict user to perform
+ // priviledged function
+ UserTypeEnum usertype = UserTypeEnum::kProgrammingUser;
+ CredentialRuleEnum credentialRule = CredentialRuleEnum::kSingle;
+
+ constexpr size_t totalCredentials(2);
+ // According to spec (5.2.6.26.2. CredentialIndex Field), programming PIN credential should be always indexed as 0
+ uint16_t credentialIndex0(0);
+ // 1st non ProgrammingPIN credential should be indexed as 1
+ uint16_t credentialIndex1(1);
+
+ const CredentialStruct credentials[totalCredentials] = {
+ { credentialType : CredentialTypeEnum::kProgrammingPIN, credentialIndex : credentialIndex0 },
+ { credentialType : CredentialTypeEnum::kPin, credentialIndex : credentialIndex1 }
+ };
+
+ if (!SetUser(endpointId, userIndex, creator, modifier, userName, uniqueId, userStatus, usertype, credentialRule,
+ &credentials[0], totalCredentials))
+ {
+ ChipLogError(Zcl, "Unable to set the User [endpointId=%d]", endpointId);
+ return false;
+ }
+
+ DlCredentialStatus credentialStatus = DlCredentialStatus::kOccupied;
+
+ // Set the default user's ProgrammingPIN credential
+ uint8_t defaultProgrammingPIN[6] = { 0x39, 0x39, 0x39, 0x39, 0x39, 0x39 }; // 000000
+ if (!SetCredential(endpointId, credentialIndex0, creator, modifier, credentialStatus, CredentialTypeEnum::kProgrammingPIN,
+ chip::ByteSpan(defaultProgrammingPIN)))
+ {
+ ChipLogError(Zcl, "Unable to set the credential - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+
+ // Set the default user's non ProgrammingPIN credential
+ uint8_t defaultPin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; // 123456
+ if (!SetCredential(endpointId, credentialIndex1, creator, modifier, credentialStatus, CredentialTypeEnum::kPin,
+ chip::ByteSpan(defaultPin)))
+ {
+ ChipLogError(Zcl, "Unable to set the credential - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+
+ ChipLogProgress(Zcl,
+ "Initialized new lock door endpoint "
+ "[id=%d,users=%d,credentials=%d,weekDaySchedulesPerUser=%d,yearDaySchedulesPerUser=%d,"
+ "numberOfCredentialsSupportedPerUser=%d,holidaySchedules=%d]",
+ endpointId, numberOfSupportedUsers, numberOfSupportedCredentials, numberOfWeekDaySchedulesPerUser,
+ numberOfYearDaySchedulesPerUser, numberOfCredentialsSupportedPerUser, numberOfHolidaySchedules);
+
+ return true;
+}
+
+bool LockManager::SetDoorState(chip::EndpointId endpointId, DoorStateEnum doorState)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to toggle the door state - endpoint does not exist or not initialized [endpointId=%d]",
+ endpointId);
+ return false;
+ }
+ return lockEndpoint->SetDoorState(doorState);
+}
+
+bool LockManager::SendLockAlarm(chip::EndpointId endpointId, AlarmCodeEnum alarmCode)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to send lock alarm - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->SendLockAlarm(alarmCode);
+}
+
+bool LockManager::Lock(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
+ const Nullable<chip::NodeId> & nodeId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
+ OperationSourceEnum opSource)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to lock the door - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->Lock(fabricIdx, nodeId, pin, err, opSource);
+}
+
+bool LockManager::Unlock(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
+ const Nullable<chip::NodeId> & nodeId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
+ OperationSourceEnum opSource)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to unlock the door - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->Unlock(fabricIdx, nodeId, pin, err, opSource);
+}
+
+bool LockManager::Unbolt(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
+ const Nullable<chip::NodeId> & nodeId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
+ OperationSourceEnum opSource)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to unbolt the door - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->Unbolt(fabricIdx, nodeId, pin, err, opSource);
+}
+
+bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to get the user - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->GetUser(userIndex, user);
+}
+
+bool LockManager::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)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to set the user - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->SetUser(userIndex, creator, modifier, userName, uniqueId, userStatus, usertype, credentialRule,
+ credentials, totalCredentials);
+}
+
+bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType,
+ EmberAfPluginDoorLockCredentialInfo & credential)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to get the credential - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->GetCredential(credentialIndex, credentialType, credential);
+}
+
+bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, chip::FabricIndex creator,
+ chip::FabricIndex modifier, DlCredentialStatus credentialStatus, CredentialTypeEnum credentialType,
+ const chip::ByteSpan & credentialData)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to set the credential - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
+ return false;
+ }
+ return lockEndpoint->SetCredential(credentialIndex, creator, modifier, credentialStatus, credentialType, credentialData);
+}
+
+DlStatus LockManager::GetSchedule(chip::EndpointId endpointId, uint8_t weekDayIndex, uint16_t userIndex,
+ EmberAfPluginDoorLockWeekDaySchedule & schedule)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to get the week day schedule - endpoint does not exist or not initialized [endpointId=%d]",
+ endpointId);
+ return DlStatus::kFailure;
+ }
+ return lockEndpoint->GetSchedule(weekDayIndex, userIndex, schedule);
+}
+
+DlStatus LockManager::SetSchedule(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)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to set the week day schedule - endpoint does not exist or not initialized [endpointId=%d]",
+ endpointId);
+ return DlStatus::kFailure;
+ }
+ return lockEndpoint->SetSchedule(weekDayIndex, userIndex, status, daysMask, startHour, startMinute, endHour, endMinute);
+}
+
+DlStatus LockManager::GetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex,
+ EmberAfPluginDoorLockYearDaySchedule & schedule)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to get the year day schedule - endpoint does not exist or not initialized [endpointId=%d]",
+ endpointId);
+ return DlStatus::kFailure;
+ }
+ return lockEndpoint->GetSchedule(yearDayIndex, userIndex, schedule);
+}
+
+DlStatus LockManager::SetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status,
+ uint32_t localStartTime, uint32_t localEndTime)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to set the year day schedule - endpoint does not exist or not initialized [endpointId=%d]",
+ endpointId);
+ return DlStatus::kFailure;
+ }
+ return lockEndpoint->SetSchedule(yearDayIndex, userIndex, status, localStartTime, localEndTime);
+}
+
+DlStatus LockManager::GetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex,
+ EmberAfPluginDoorLockHolidaySchedule & schedule)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to get the holiday schedule - endpoint does not exist or not initialized [endpointId=%d]",
+ endpointId);
+ return DlStatus::kFailure;
+ }
+ return lockEndpoint->GetSchedule(holidayIndex, schedule);
+}
+
+DlStatus LockManager::SetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status,
+ uint32_t localStartTime, uint32_t localEndTime, OperatingModeEnum operatingMode)
+{
+ auto lockEndpoint = getEndpoint(endpointId);
+ if (nullptr == lockEndpoint)
+ {
+ ChipLogError(Zcl, "Unable to set the holiday schedule - endpoint does not exist or not initialized [endpointId=%d]",
+ endpointId);
+ return DlStatus::kFailure;
+ }
+ return lockEndpoint->SetSchedule(holidayIndex, status, localStartTime, localEndTime, operatingMode);
+}
+
+LockEndpoint * LockManager::getEndpoint(chip::EndpointId endpointId)
+{
+ for (auto & mEndpoint : mEndpoints)
+ {
+ if (mEndpoint.GetEndpointId() == endpointId)
+ {
+ return &mEndpoint;
+ }
+ }
+ return nullptr;
+}
+#endif // MATTER_DM_PLUGIN_DOOR_LOCK_SERVER
diff --git a/examples/chef/common/clusters/door-lock/chef-lock-manager.h b/examples/chef/common/clusters/door-lock/chef-lock-manager.h
new file mode 100644
index 0000000..709f13c
--- /dev/null
+++ b/examples/chef/common/clusters/door-lock/chef-lock-manager.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright (c) 2020-2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "chef-lock-endpoint.h"
+#include <app/clusters/door-lock-server/door-lock-server.h>
+#include <cstdint>
+
+#include <app/util/af.h>
+
+class LockManager
+{
+public:
+ LockManager() = default;
+
+ bool InitEndpoint(chip::EndpointId endpointId);
+
+ bool SetDoorState(chip::EndpointId endpointId, DoorStateEnum doorState);
+
+ bool SendLockAlarm(chip::EndpointId endpointId, AlarmCodeEnum alarmCode);
+
+ bool Lock(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
+ bool Unlock(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
+ bool Unbolt(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
+ const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
+
+ 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 GetSchedule(chip::EndpointId endpointId, uint8_t weekDayIndex, uint16_t userIndex,
+ EmberAfPluginDoorLockWeekDaySchedule & schedule);
+ DlStatus GetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex,
+ EmberAfPluginDoorLockYearDaySchedule & schedule);
+ DlStatus GetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule & schedule);
+
+ DlStatus SetSchedule(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 SetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status,
+ uint32_t localStartTime, uint32_t localEndTime);
+ DlStatus SetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime,
+ uint32_t localEndTime, OperatingModeEnum operatingMode);
+
+ static LockManager & Instance();
+
+private:
+ LockEndpoint * getEndpoint(chip::EndpointId endpointId);
+
+ std::vector<LockEndpoint> mEndpoints;
+
+ static LockManager instance;
+};
diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp
index 48c4862..91a7b5a 100644
--- a/examples/chef/common/stubs.cpp
+++ b/examples/chef/common/stubs.cpp
@@ -111,238 +111,6 @@
return Protocols::InteractionModel::Status::Success;
}
-// Include door lock callbacks only when the server is enabled
-#ifdef MATTER_DM_PLUGIN_DOOR_LOCK_SERVER
-#include <app/clusters/door-lock-server/door-lock-server.h>
-
-class LockManager
-{
-public:
- static constexpr uint32_t kNumEndpoints = 1;
- static constexpr uint32_t kNumUsersPerEndpoint = 2;
- static constexpr uint32_t kNumCredentialsPerEndpoint = 20;
- static constexpr uint32_t kNumCredentialsPerUser = 10;
- static constexpr uint32_t kMaxNameLength = 32;
- static constexpr uint32_t kMaxDataLength = 16;
-
- struct Credential
- {
- bool set(DlCredentialStatus status, CredentialTypeEnum type, chip::ByteSpan newData)
- {
- if (newData.size() > kMaxDataLength || type != CredentialTypeEnum::kPin)
- return false;
- memcpy(data, newData.data(), newData.size());
- info = EmberAfPluginDoorLockCredentialInfo{
- status,
- type,
- chip::ByteSpan(data, newData.size()),
- };
- return true;
- }
-
- EmberAfPluginDoorLockCredentialInfo info = { DlCredentialStatus::kAvailable };
- uint8_t data[kMaxDataLength];
- };
-
- struct User
- {
- void set(chip::CharSpan newName, uint32_t userId, UserStatusEnum userStatus, UserTypeEnum type,
- CredentialRuleEnum credentialRule)
- {
- size_t sz = std::min(sizeof(name), newName.size());
- memcpy(name, newName.data(), sz);
- info = EmberAfPluginDoorLockUserInfo{
- chip::CharSpan(name, sz), chip::Span<const CredentialStruct>(), userId, userStatus, type, credentialRule,
- };
- }
- bool addCredential(CredentialTypeEnum type, uint16_t index)
- {
- if (info.credentials.size() == kNumCredentialsPerUser)
- return false;
- auto & cr = credentialMap[info.credentials.size()];
- cr.credentialType = type;
- cr.credentialIndex = index;
- info.credentials = chip::Span<const CredentialStruct>(credentialMap, info.credentials.size() + 1);
- return true;
- }
-
- EmberAfPluginDoorLockUserInfo info = { .userStatus = UserStatusEnum::kAvailable };
- char name[kMaxNameLength];
- CredentialStruct credentialMap[kNumCredentialsPerUser];
- };
-
- struct Endpoint
- {
- chip::EndpointId id;
- User users[kNumUsersPerEndpoint];
- Credential credentials[kNumCredentialsPerEndpoint];
- };
-
- static LockManager & Instance()
- {
- static LockManager instance;
- return instance;
- }
-
- LockManager() { defaultInitialize(); }
-
- bool getUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
- {
- auto ep = findEndpoint(endpointId);
- if (!ep)
- return false;
- if (userIndex >= kNumUsersPerEndpoint)
- return false;
- user = ep->users[userIndex].info;
- return true;
- }
-
- 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)
- {
- auto ep = findEndpoint(endpointId);
- if (!ep)
- return false;
- if (userIndex >= kNumUsersPerEndpoint || totalCredentials > kNumCredentialsPerUser)
- return false;
- ep->users[userIndex].set(userName, uniqueId, userStatus, usertype, credentialRule);
- ep->users[userIndex].info.creationSource = DlAssetSource::kMatterIM;
- ep->users[userIndex].info.createdBy = creator;
- ep->users[userIndex].info.modificationSource = DlAssetSource::kMatterIM;
- ep->users[userIndex].info.lastModifiedBy = modifier;
- for (size_t i = 0; i < totalCredentials; i++)
- ep->users[userIndex].addCredential(credentials[i].credentialType, credentials[i].credentialIndex);
- return true;
- }
-
- bool getCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType,
- EmberAfPluginDoorLockCredentialInfo & credential)
- {
- auto ep = findEndpoint(endpointId);
- if (!ep)
- return false;
- if (credentialIndex >= kNumCredentialsPerEndpoint)
- return false;
- if (credentialType != CredentialTypeEnum::kPin)
- return false;
- credential = ep->credentials[credentialIndex].info;
- return true;
- }
-
- bool setCredential(chip::EndpointId endpointId, uint16_t credentialIndex, chip::FabricIndex creator, chip::FabricIndex modifier,
- DlCredentialStatus credentialStatus, CredentialTypeEnum credentialType,
- const chip::ByteSpan & credentialData)
- {
- auto ep = findEndpoint(endpointId);
- if (!ep)
- return false;
- if (credentialIndex >= kNumCredentialsPerEndpoint)
- return false;
- if (credentialType != CredentialTypeEnum::kPin)
- return false;
- auto & credential = ep->credentials[credentialIndex];
- if (!credential.set(credentialStatus, credentialType, credentialData))
- return false;
- credential.info.creationSource = DlAssetSource::kMatterIM;
- credential.info.createdBy = creator;
- credential.info.modificationSource = DlAssetSource::kMatterIM;
- credential.info.lastModifiedBy = modifier;
- return true;
- }
-
- bool checkPin(chip::EndpointId endpointId, const chip::Optional<chip::ByteSpan> & pinCode,
- chip::app::Clusters::DoorLock::OperationErrorEnum & err)
- {
- if (!pinCode.HasValue())
- {
- err = OperationErrorEnum::kInvalidCredential;
- return false;
- }
- auto ep = findEndpoint(endpointId);
- if (!ep)
- return false;
- for (auto & pin : ep->credentials)
- {
- if (pin.info.status == DlCredentialStatus::kOccupied && pin.info.credentialData.data_equal(pinCode.Value()))
- {
- return true;
- }
- }
- err = OperationErrorEnum::kInvalidCredential;
- return false;
- }
-
-private:
- Endpoint * findEndpoint(chip::EndpointId endpointId)
- {
- for (auto & e : endpoints)
- {
- if (e.id == endpointId)
- return &e;
- }
- return nullptr;
- }
-
- void defaultInitialize()
- {
- endpoints[0].id = 1;
- uint8_t pin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
- endpoints[0].credentials[0].set(DlCredentialStatus::kOccupied, CredentialTypeEnum::kPin, chip::ByteSpan(pin));
- endpoints[0].users[0].set("default"_span, 1, UserStatusEnum::kOccupiedEnabled, UserTypeEnum::kUnrestrictedUser,
- CredentialRuleEnum::kSingle);
- endpoints[0].users[0].addCredential(CredentialTypeEnum::kPin, 1);
- }
-
- Endpoint endpoints[kNumEndpoints];
-};
-
-bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
- const Nullable<chip::NodeId> & nodeId, const chip::Optional<chip::ByteSpan> & pinCode,
- chip::app::Clusters::DoorLock::OperationErrorEnum & err)
-{
- err = OperationErrorEnum::kUnspecified;
- return DoorLockServer::Instance().SetLockState(endpointId, DlLockState::kLocked);
-}
-
-bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
- const Nullable<chip::NodeId> & nodeId, const chip::Optional<chip::ByteSpan> & pinCode,
- chip::app::Clusters::DoorLock::OperationErrorEnum & err)
-{
- err = OperationErrorEnum::kUnspecified;
- return DoorLockServer::Instance().SetLockState(endpointId, DlLockState::kUnlocked);
-}
-
-bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
-{
- return LockManager::Instance().getUser(endpointId, userIndex - 1, 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 LockManager::Instance().setUser(endpointId, userIndex - 1, creator, modifier, userName, uniqueId, userStatus, usertype,
- credentialRule, credentials, totalCredentials);
-}
-
-bool emberAfPluginDoorLockGetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType,
- EmberAfPluginDoorLockCredentialInfo & credential)
-{
- return LockManager::Instance().getCredential(endpointId, credentialIndex - 1, 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 LockManager::Instance().setCredential(endpointId, credentialIndex - 1, creator, modifier, credentialStatus,
- credentialType, credentialData);
-}
-
-#endif /* MATTER_DM_PLUGIN_DOOR_LOCK_SERVER */
-
void emberAfPluginSmokeCoAlarmSelfTestRequestCommand(EndpointId endpointId) {}
void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
diff --git a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter
index 5819641..bceebc6 100644
--- a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter
+++ b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter
@@ -51,83 +51,6 @@
command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64;
}
-/** Attributes and commands for group configuration and manipulation. */
-cluster Groups = 4 {
- revision 4;
-
- bitmap Feature : bitmap32 {
- kGroupNames = 0x1;
- }
-
- bitmap NameSupportBitmap : bitmap8 {
- kGroupNames = 0x80;
- }
-
- readonly attribute NameSupportBitmap nameSupport = 0;
- readonly attribute command_id generatedCommandList[] = 65528;
- readonly attribute command_id acceptedCommandList[] = 65529;
- readonly attribute event_id eventList[] = 65530;
- readonly attribute attrib_id attributeList[] = 65531;
- readonly attribute bitmap32 featureMap = 65532;
- readonly attribute int16u clusterRevision = 65533;
-
- request struct AddGroupRequest {
- group_id groupID = 0;
- char_string<16> groupName = 1;
- }
-
- response struct AddGroupResponse = 0 {
- enum8 status = 0;
- group_id groupID = 1;
- }
-
- request struct ViewGroupRequest {
- group_id groupID = 0;
- }
-
- response struct ViewGroupResponse = 1 {
- enum8 status = 0;
- group_id groupID = 1;
- char_string<16> groupName = 2;
- }
-
- request struct GetGroupMembershipRequest {
- group_id groupList[] = 0;
- }
-
- response struct GetGroupMembershipResponse = 2 {
- nullable int8u capacity = 0;
- group_id groupList[] = 1;
- }
-
- request struct RemoveGroupRequest {
- group_id groupID = 0;
- }
-
- response struct RemoveGroupResponse = 3 {
- enum8 status = 0;
- group_id groupID = 1;
- }
-
- request struct AddGroupIfIdentifyingRequest {
- group_id groupID = 0;
- char_string<16> groupName = 1;
- }
-
- /** Command description for AddGroup */
- fabric command access(invoke: manage) AddGroup(AddGroupRequest): AddGroupResponse = 0;
- /** Command description for ViewGroup */
- fabric command ViewGroup(ViewGroupRequest): ViewGroupResponse = 1;
- /** Command description for GetGroupMembership */
- fabric command GetGroupMembership(GetGroupMembershipRequest): GetGroupMembershipResponse = 2;
- /** Command description for RemoveGroup */
- fabric command access(invoke: manage) RemoveGroup(RemoveGroupRequest): RemoveGroupResponse = 3;
- /** Command description for RemoveAllGroups */
- fabric command access(invoke: manage) RemoveAllGroups(): DefaultSuccess = 4;
- /** Command description for AddGroupIfIdentifying */
- fabric command access(invoke: manage) AddGroupIfIdentifying(AddGroupIfIdentifyingRequest): DefaultSuccess = 5;
-}
-
/** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */
cluster Descriptor = 29 {
revision 2;
@@ -161,27 +84,6 @@
readonly attribute int16u clusterRevision = 65533;
}
-/** The Binding Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for supporting the binding table. */
-cluster Binding = 30 {
- revision 1; // NOTE: Default/not specifically set
-
- fabric_scoped struct TargetStruct {
- optional node_id node = 1;
- optional group_id group = 2;
- optional endpoint_no endpoint = 3;
- optional cluster_id cluster = 4;
- fabric_idx fabricIndex = 254;
- }
-
- attribute access(write: manage) TargetStruct binding[] = 0;
- readonly attribute command_id generatedCommandList[] = 65528;
- readonly attribute command_id acceptedCommandList[] = 65529;
- readonly attribute event_id eventList[] = 65530;
- readonly attribute attrib_id attributeList[] = 65531;
- readonly attribute bitmap32 featureMap = 65532;
- readonly attribute int16u clusterRevision = 65533;
-}
-
/** The Access Control Cluster exposes a data model view of a
Node's Access Control List (ACL), which codifies the rules used to manage
and enforce Access Control for the Node's endpoints and their associated
@@ -569,6 +471,265 @@
readonly attribute int16u clusterRevision = 65533;
}
+/** This cluster is used to describe the configuration and capabilities of a physical power source that provides power to the Node. */
+cluster PowerSource = 47 {
+ revision 1; // NOTE: Default/not specifically set
+
+ enum BatApprovedChemistryEnum : enum16 {
+ kUnspecified = 0;
+ kAlkaline = 1;
+ kLithiumCarbonFluoride = 2;
+ kLithiumChromiumOxide = 3;
+ kLithiumCopperOxide = 4;
+ kLithiumIronDisulfide = 5;
+ kLithiumManganeseDioxide = 6;
+ kLithiumThionylChloride = 7;
+ kMagnesium = 8;
+ kMercuryOxide = 9;
+ kNickelOxyhydride = 10;
+ kSilverOxide = 11;
+ kZincAir = 12;
+ kZincCarbon = 13;
+ kZincChloride = 14;
+ kZincManganeseDioxide = 15;
+ kLeadAcid = 16;
+ kLithiumCobaltOxide = 17;
+ kLithiumIon = 18;
+ kLithiumIonPolymer = 19;
+ kLithiumIronPhosphate = 20;
+ kLithiumSulfur = 21;
+ kLithiumTitanate = 22;
+ kNickelCadmium = 23;
+ kNickelHydrogen = 24;
+ kNickelIron = 25;
+ kNickelMetalHydride = 26;
+ kNickelZinc = 27;
+ kSilverZinc = 28;
+ kSodiumIon = 29;
+ kSodiumSulfur = 30;
+ kZincBromide = 31;
+ kZincCerium = 32;
+ }
+
+ enum BatChargeFaultEnum : enum8 {
+ kUnspecified = 0;
+ kAmbientTooHot = 1;
+ kAmbientTooCold = 2;
+ kBatteryTooHot = 3;
+ kBatteryTooCold = 4;
+ kBatteryAbsent = 5;
+ kBatteryOverVoltage = 6;
+ kBatteryUnderVoltage = 7;
+ kChargerOverVoltage = 8;
+ kChargerUnderVoltage = 9;
+ kSafetyTimeout = 10;
+ }
+
+ enum BatChargeLevelEnum : enum8 {
+ kOK = 0;
+ kWarning = 1;
+ kCritical = 2;
+ }
+
+ enum BatChargeStateEnum : enum8 {
+ kUnknown = 0;
+ kIsCharging = 1;
+ kIsAtFullCharge = 2;
+ kIsNotCharging = 3;
+ }
+
+ enum BatCommonDesignationEnum : enum16 {
+ kUnspecified = 0;
+ kAAA = 1;
+ kAA = 2;
+ kC = 3;
+ kD = 4;
+ k4v5 = 5;
+ k6v0 = 6;
+ k9v0 = 7;
+ k12AA = 8;
+ kAAAA = 9;
+ kA = 10;
+ kB = 11;
+ kF = 12;
+ kN = 13;
+ kNo6 = 14;
+ kSubC = 15;
+ kA23 = 16;
+ kA27 = 17;
+ kBA5800 = 18;
+ kDuplex = 19;
+ k4SR44 = 20;
+ k523 = 21;
+ k531 = 22;
+ k15v0 = 23;
+ k22v5 = 24;
+ k30v0 = 25;
+ k45v0 = 26;
+ k67v5 = 27;
+ kJ = 28;
+ kCR123A = 29;
+ kCR2 = 30;
+ k2CR5 = 31;
+ kCRP2 = 32;
+ kCRV3 = 33;
+ kSR41 = 34;
+ kSR43 = 35;
+ kSR44 = 36;
+ kSR45 = 37;
+ kSR48 = 38;
+ kSR54 = 39;
+ kSR55 = 40;
+ kSR57 = 41;
+ kSR58 = 42;
+ kSR59 = 43;
+ kSR60 = 44;
+ kSR63 = 45;
+ kSR64 = 46;
+ kSR65 = 47;
+ kSR66 = 48;
+ kSR67 = 49;
+ kSR68 = 50;
+ kSR69 = 51;
+ kSR516 = 52;
+ kSR731 = 53;
+ kSR712 = 54;
+ kLR932 = 55;
+ kA5 = 56;
+ kA10 = 57;
+ kA13 = 58;
+ kA312 = 59;
+ kA675 = 60;
+ kAC41E = 61;
+ k10180 = 62;
+ k10280 = 63;
+ k10440 = 64;
+ k14250 = 65;
+ k14430 = 66;
+ k14500 = 67;
+ k14650 = 68;
+ k15270 = 69;
+ k16340 = 70;
+ kRCR123A = 71;
+ k17500 = 72;
+ k17670 = 73;
+ k18350 = 74;
+ k18500 = 75;
+ k18650 = 76;
+ k19670 = 77;
+ k25500 = 78;
+ k26650 = 79;
+ k32600 = 80;
+ }
+
+ enum BatFaultEnum : enum8 {
+ kUnspecified = 0;
+ kOverTemp = 1;
+ kUnderTemp = 2;
+ }
+
+ enum BatReplaceabilityEnum : enum8 {
+ kUnspecified = 0;
+ kNotReplaceable = 1;
+ kUserReplaceable = 2;
+ kFactoryReplaceable = 3;
+ }
+
+ enum PowerSourceStatusEnum : enum8 {
+ kUnspecified = 0;
+ kActive = 1;
+ kStandby = 2;
+ kUnavailable = 3;
+ }
+
+ enum WiredCurrentTypeEnum : enum8 {
+ kAC = 0;
+ kDC = 1;
+ }
+
+ enum WiredFaultEnum : enum8 {
+ kUnspecified = 0;
+ kOverVoltage = 1;
+ kUnderVoltage = 2;
+ }
+
+ bitmap Feature : bitmap32 {
+ kWired = 0x1;
+ kBattery = 0x2;
+ kRechargeable = 0x4;
+ kReplaceable = 0x8;
+ }
+
+ struct BatChargeFaultChangeType {
+ BatChargeFaultEnum current[] = 0;
+ BatChargeFaultEnum previous[] = 1;
+ }
+
+ struct BatFaultChangeType {
+ BatFaultEnum current[] = 0;
+ BatFaultEnum previous[] = 1;
+ }
+
+ struct WiredFaultChangeType {
+ WiredFaultEnum current[] = 0;
+ WiredFaultEnum previous[] = 1;
+ }
+
+ info event WiredFaultChange = 0 {
+ WiredFaultEnum current[] = 0;
+ WiredFaultEnum previous[] = 1;
+ }
+
+ info event BatFaultChange = 1 {
+ BatFaultEnum current[] = 0;
+ BatFaultEnum previous[] = 1;
+ }
+
+ info event BatChargeFaultChange = 2 {
+ BatChargeFaultEnum current[] = 0;
+ BatChargeFaultEnum previous[] = 1;
+ }
+
+ readonly attribute PowerSourceStatusEnum status = 0;
+ readonly attribute int8u order = 1;
+ readonly attribute char_string<60> description = 2;
+ readonly attribute optional nullable int32u wiredAssessedInputVoltage = 3;
+ readonly attribute optional nullable int16u wiredAssessedInputFrequency = 4;
+ readonly attribute optional WiredCurrentTypeEnum wiredCurrentType = 5;
+ readonly attribute optional nullable int32u wiredAssessedCurrent = 6;
+ readonly attribute optional int32u wiredNominalVoltage = 7;
+ readonly attribute optional int32u wiredMaximumCurrent = 8;
+ readonly attribute optional boolean wiredPresent = 9;
+ readonly attribute optional WiredFaultEnum activeWiredFaults[] = 10;
+ readonly attribute optional nullable int32u batVoltage = 11;
+ readonly attribute optional nullable int8u batPercentRemaining = 12;
+ readonly attribute optional nullable int32u batTimeRemaining = 13;
+ readonly attribute optional BatChargeLevelEnum batChargeLevel = 14;
+ readonly attribute optional boolean batReplacementNeeded = 15;
+ readonly attribute optional BatReplaceabilityEnum batReplaceability = 16;
+ readonly attribute optional boolean batPresent = 17;
+ readonly attribute optional BatFaultEnum activeBatFaults[] = 18;
+ readonly attribute optional char_string<60> batReplacementDescription = 19;
+ readonly attribute optional BatCommonDesignationEnum batCommonDesignation = 20;
+ readonly attribute optional char_string<20> batANSIDesignation = 21;
+ readonly attribute optional char_string<20> batIECDesignation = 22;
+ readonly attribute optional BatApprovedChemistryEnum batApprovedChemistry = 23;
+ readonly attribute optional int32u batCapacity = 24;
+ readonly attribute optional int8u batQuantity = 25;
+ readonly attribute optional BatChargeStateEnum batChargeState = 26;
+ readonly attribute optional nullable int32u batTimeToFullCharge = 27;
+ readonly attribute optional boolean batFunctionalWhileCharging = 28;
+ readonly attribute optional nullable int32u batChargingCurrent = 29;
+ readonly attribute optional BatChargeFaultEnum activeBatChargeFaults[] = 30;
+ readonly attribute endpoint_no endpointList[] = 31;
+ readonly attribute command_id generatedCommandList[] = 65528;
+ readonly attribute command_id acceptedCommandList[] = 65529;
+ readonly attribute event_id eventList[] = 65530;
+ readonly attribute attrib_id attributeList[] = 65531;
+ readonly attribute bitmap32 featureMap = 65532;
+ readonly attribute int16u clusterRevision = 65533;
+}
+
/** This cluster is used to manage global aspects of the Commissioning flow. */
cluster GeneralCommissioning = 48 {
revision 1; // NOTE: Default/not specifically set
@@ -2178,40 +2339,22 @@
}
}
endpoint 1 {
+ device type ma_powersource = 17, version 1;
device type ma_doorlock = 10, version 1;
- binding cluster Binding;
server cluster Identify {
ram attribute identifyTime default = 0x0;
ram attribute identifyType default = 0x0;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
+ callback attribute eventList;
callback attribute attributeList;
ram attribute featureMap default = 0;
ram attribute clusterRevision default = 2;
handle command Identify;
- }
-
- server cluster Groups {
- ram attribute nameSupport default = 0;
- callback attribute generatedCommandList;
- callback attribute acceptedCommandList;
- callback attribute attributeList;
- ram attribute featureMap default = 0;
- ram attribute clusterRevision default = 3;
-
- handle command AddGroup;
- handle command AddGroupResponse;
- handle command ViewGroup;
- handle command ViewGroupResponse;
- handle command GetGroupMembership;
- handle command GetGroupMembershipResponse;
- handle command RemoveGroup;
- handle command RemoveGroupResponse;
- handle command RemoveAllGroups;
- handle command AddGroupIfIdentifying;
+ handle command TriggerEffect;
}
server cluster Descriptor {
@@ -2221,39 +2364,90 @@
callback attribute partsList;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
+ callback attribute eventList;
callback attribute attributeList;
callback attribute featureMap;
callback attribute clusterRevision;
}
+ server cluster PowerSource {
+ ram attribute status default = 1;
+ ram attribute order default = 1;
+ ram attribute description default = "Battery";
+ ram attribute batVoltage;
+ ram attribute batPercentRemaining;
+ ram attribute batTimeRemaining;
+ ram attribute batChargeLevel;
+ ram attribute batReplacementNeeded;
+ ram attribute batReplaceability;
+ ram attribute batPresent;
+ ram attribute batReplacementDescription;
+ ram attribute batQuantity default = 1;
+ callback attribute endpointList;
+ callback attribute generatedCommandList;
+ callback attribute acceptedCommandList;
+ callback attribute eventList;
+ callback attribute attributeList;
+ ram attribute featureMap default = 0x0A;
+ ram attribute clusterRevision default = 2;
+ }
+
server cluster DoorLock {
emits event DoorLockAlarm;
+ emits event DoorStateChange;
emits event LockOperation;
emits event LockOperationError;
+ emits event LockUserChange;
ram attribute lockState default = 1;
ram attribute lockType default = 0;
ram attribute actuatorEnabled default = 0;
- ram attribute numberOfTotalUsersSupported default = 2;
- ram attribute numberOfPINUsersSupported default = 2;
- ram attribute maxPINCodeLength default = 10;
- ram attribute minPINCodeLength default = 5;
+ ram attribute doorState default = 1;
+ ram attribute doorOpenEvents;
+ ram attribute doorClosedEvents;
+ ram attribute numberOfTotalUsersSupported default = 10;
+ ram attribute numberOfPINUsersSupported default = 10;
+ ram attribute numberOfRFIDUsersSupported default = 10;
+ ram attribute numberOfWeekDaySchedulesSupportedPerUser default = 10;
+ ram attribute numberOfYearDaySchedulesSupportedPerUser default = 10;
+ ram attribute numberOfHolidaySchedulesSupported default = 10;
+ ram attribute maxPINCodeLength default = 8;
+ ram attribute minPINCodeLength default = 6;
+ ram attribute maxRFIDCodeLength default = 20;
+ ram attribute minRFIDCodeLength default = 10;
+ ram attribute credentialRulesSupport default = 1;
ram attribute numberOfCredentialsSupportedPerUser default = 5;
- ram attribute autoRelockTime default = 0;
+ ram attribute language default = "en";
+ ram attribute autoRelockTime default = 5;
+ ram attribute soundVolume default = 0;
ram attribute operatingMode default = 0;
- ram attribute supportedOperatingModes default = 0xFFF6;
+ ram attribute supportedOperatingModes default = 0xFFFF;
+ ram attribute enableOneTouchLocking default = 0;
+ ram attribute enablePrivacyModeButton default = 0;
ram attribute wrongCodeEntryLimit default = 3;
ram attribute userCodeTemporaryDisableTime default = 10;
- ram attribute sendPINOverTheAir default = 0;
- ram attribute requirePINforRemoteOperation default = 1;
+ ram attribute requirePINforRemoteOperation default = 0;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
+ callback attribute eventList;
callback attribute attributeList;
- ram attribute featureMap default = 0x0181;
- ram attribute clusterRevision default = 6;
+ ram attribute featureMap default = 0x1DB3;
+ ram attribute clusterRevision default = 7;
handle command LockDoor;
handle command UnlockDoor;
handle command UnlockWithTimeout;
+ handle command SetWeekDaySchedule;
+ handle command GetWeekDaySchedule;
+ handle command GetWeekDayScheduleResponse;
+ handle command ClearWeekDaySchedule;
+ handle command SetYearDaySchedule;
+ handle command GetYearDaySchedule;
+ handle command GetYearDayScheduleResponse;
+ handle command ClearYearDaySchedule;
+ handle command SetHolidaySchedule;
+ handle command GetHolidaySchedule;
+ handle command GetHolidayScheduleResponse;
+ handle command ClearHolidaySchedule;
handle command SetUser;
handle command GetUser;
handle command GetUserResponse;
@@ -2263,6 +2457,7 @@
handle command GetCredentialStatus;
handle command GetCredentialStatusResponse;
handle command ClearCredential;
+ handle command UnboltDoor;
}
}
diff --git a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.zap b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.zap
index 66f7adb..1e9094f 100644
--- a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.zap
+++ b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.zap
@@ -2480,13 +2480,21 @@
"profileId": 259,
"label": "MA-doorlock",
"name": "MA-doorlock"
+ },
+ {
+ "code": 17,
+ "profileId": 259,
+ "label": "MA-powersource",
+ "name": "MA-powersource"
}
],
"deviceVersions": [
+ 1,
1
],
"deviceIdentifiers": [
- 10
+ 10,
+ 17
],
"deviceTypeName": "MA-doorlock",
"deviceTypeCode": 10,
@@ -2507,6 +2515,14 @@
"source": "client",
"isIncoming": 1,
"isEnabled": 1
+ },
+ {
+ "name": "TriggerEffect",
+ "code": 64,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
}
],
"attributes": [
@@ -2575,6 +2591,22 @@
"reportableChange": 0
},
{
+ "name": "EventList",
+ "code": 65530,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
"name": "AttributeList",
"code": 65531,
"mfgCode": null,
@@ -2625,194 +2657,6 @@
]
},
{
- "name": "Groups",
- "code": 4,
- "mfgCode": null,
- "define": "GROUPS_CLUSTER",
- "side": "server",
- "enabled": 1,
- "commands": [
- {
- "name": "AddGroup",
- "code": 0,
- "mfgCode": null,
- "source": "client",
- "isIncoming": 1,
- "isEnabled": 1
- },
- {
- "name": "AddGroupResponse",
- "code": 0,
- "mfgCode": null,
- "source": "server",
- "isIncoming": 0,
- "isEnabled": 1
- },
- {
- "name": "ViewGroup",
- "code": 1,
- "mfgCode": null,
- "source": "client",
- "isIncoming": 1,
- "isEnabled": 1
- },
- {
- "name": "ViewGroupResponse",
- "code": 1,
- "mfgCode": null,
- "source": "server",
- "isIncoming": 0,
- "isEnabled": 1
- },
- {
- "name": "GetGroupMembership",
- "code": 2,
- "mfgCode": null,
- "source": "client",
- "isIncoming": 1,
- "isEnabled": 1
- },
- {
- "name": "GetGroupMembershipResponse",
- "code": 2,
- "mfgCode": null,
- "source": "server",
- "isIncoming": 0,
- "isEnabled": 1
- },
- {
- "name": "RemoveGroup",
- "code": 3,
- "mfgCode": null,
- "source": "client",
- "isIncoming": 1,
- "isEnabled": 1
- },
- {
- "name": "RemoveGroupResponse",
- "code": 3,
- "mfgCode": null,
- "source": "server",
- "isIncoming": 0,
- "isEnabled": 1
- },
- {
- "name": "RemoveAllGroups",
- "code": 4,
- "mfgCode": null,
- "source": "client",
- "isIncoming": 1,
- "isEnabled": 1
- },
- {
- "name": "AddGroupIfIdentifying",
- "code": 5,
- "mfgCode": null,
- "source": "client",
- "isIncoming": 1,
- "isEnabled": 1
- }
- ],
- "attributes": [
- {
- "name": "NameSupport",
- "code": 0,
- "mfgCode": null,
- "side": "server",
- "type": "NameSupportBitmap",
- "included": 1,
- "storageOption": "RAM",
- "singleton": 0,
- "bounded": 0,
- "defaultValue": "0",
- "reportable": 1,
- "minInterval": 1,
- "maxInterval": 65534,
- "reportableChange": 0
- },
- {
- "name": "GeneratedCommandList",
- "code": 65528,
- "mfgCode": null,
- "side": "server",
- "type": "array",
- "included": 1,
- "storageOption": "External",
- "singleton": 0,
- "bounded": 0,
- "defaultValue": null,
- "reportable": 1,
- "minInterval": 1,
- "maxInterval": 65534,
- "reportableChange": 0
- },
- {
- "name": "AcceptedCommandList",
- "code": 65529,
- "mfgCode": null,
- "side": "server",
- "type": "array",
- "included": 1,
- "storageOption": "External",
- "singleton": 0,
- "bounded": 0,
- "defaultValue": null,
- "reportable": 1,
- "minInterval": 1,
- "maxInterval": 65534,
- "reportableChange": 0
- },
- {
- "name": "AttributeList",
- "code": 65531,
- "mfgCode": null,
- "side": "server",
- "type": "array",
- "included": 1,
- "storageOption": "External",
- "singleton": 0,
- "bounded": 0,
- "defaultValue": null,
- "reportable": 1,
- "minInterval": 1,
- "maxInterval": 65534,
- "reportableChange": 0
- },
- {
- "name": "FeatureMap",
- "code": 65532,
- "mfgCode": null,
- "side": "server",
- "type": "bitmap32",
- "included": 1,
- "storageOption": "RAM",
- "singleton": 0,
- "bounded": 0,
- "defaultValue": "0",
- "reportable": 1,
- "minInterval": 1,
- "maxInterval": 65534,
- "reportableChange": 0
- },
- {
- "name": "ClusterRevision",
- "code": 65533,
- "mfgCode": null,
- "side": "server",
- "type": "int16u",
- "included": 1,
- "storageOption": "RAM",
- "singleton": 0,
- "bounded": 0,
- "defaultValue": "3",
- "reportable": 1,
- "minInterval": 1,
- "maxInterval": 65534,
- "reportableChange": 0
- }
- ]
- },
- {
"name": "Descriptor",
"code": 29,
"mfgCode": null,
@@ -2917,6 +2761,22 @@
"reportableChange": 0
},
{
+ "name": "EventList",
+ "code": 65530,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
"name": "AttributeList",
"code": 65531,
"mfgCode": null,
@@ -2967,19 +2827,19 @@
]
},
{
- "name": "Binding",
- "code": 30,
+ "name": "Power Source",
+ "code": 47,
"mfgCode": null,
- "define": "BINDING_CLUSTER",
- "side": "client",
+ "define": "POWER_SOURCE_CLUSTER",
+ "side": "server",
"enabled": 1,
"attributes": [
{
- "name": "ClusterRevision",
- "code": 65533,
+ "name": "Status",
+ "code": 0,
"mfgCode": null,
- "side": "client",
- "type": "int16u",
+ "side": "server",
+ "type": "PowerSourceStatusEnum",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
@@ -2989,6 +2849,294 @@
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
+ },
+ {
+ "name": "Order",
+ "code": 1,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "1",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "Description",
+ "code": 2,
+ "mfgCode": null,
+ "side": "server",
+ "type": "char_string",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "Battery",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatVoltage",
+ "code": 11,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int32u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatPercentRemaining",
+ "code": 12,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatTimeRemaining",
+ "code": 13,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int32u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatChargeLevel",
+ "code": 14,
+ "mfgCode": null,
+ "side": "server",
+ "type": "BatChargeLevelEnum",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatReplacementNeeded",
+ "code": 15,
+ "mfgCode": null,
+ "side": "server",
+ "type": "boolean",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatReplaceability",
+ "code": 16,
+ "mfgCode": null,
+ "side": "server",
+ "type": "BatReplaceabilityEnum",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatPresent",
+ "code": 17,
+ "mfgCode": null,
+ "side": "server",
+ "type": "boolean",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatReplacementDescription",
+ "code": 19,
+ "mfgCode": null,
+ "side": "server",
+ "type": "char_string",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "BatQuantity",
+ "code": 25,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "1",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "EndpointList",
+ "code": 31,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "GeneratedCommandList",
+ "code": 65528,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "AcceptedCommandList",
+ "code": 65529,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "EventList",
+ "code": 65530,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "AttributeList",
+ "code": 65531,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "FeatureMap",
+ "code": 65532,
+ "mfgCode": null,
+ "side": "server",
+ "type": "bitmap32",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "0x0A",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "ClusterRevision",
+ "code": 65533,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int16u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "2",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
}
]
},
@@ -3025,6 +3173,102 @@
"isEnabled": 1
},
{
+ "name": "SetWeekDaySchedule",
+ "code": 11,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "GetWeekDaySchedule",
+ "code": 12,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "GetWeekDayScheduleResponse",
+ "code": 12,
+ "mfgCode": null,
+ "source": "server",
+ "isIncoming": 0,
+ "isEnabled": 1
+ },
+ {
+ "name": "ClearWeekDaySchedule",
+ "code": 13,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "SetYearDaySchedule",
+ "code": 14,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "GetYearDaySchedule",
+ "code": 15,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "GetYearDayScheduleResponse",
+ "code": 15,
+ "mfgCode": null,
+ "source": "server",
+ "isIncoming": 0,
+ "isEnabled": 1
+ },
+ {
+ "name": "ClearYearDaySchedule",
+ "code": 16,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "SetHolidaySchedule",
+ "code": 17,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "GetHolidaySchedule",
+ "code": 18,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
+ "name": "GetHolidayScheduleResponse",
+ "code": 18,
+ "mfgCode": null,
+ "source": "server",
+ "isIncoming": 0,
+ "isEnabled": 1
+ },
+ {
+ "name": "ClearHolidaySchedule",
+ "code": 19,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
+ },
+ {
"name": "SetUser",
"code": 26,
"mfgCode": null,
@@ -3095,6 +3339,14 @@
"source": "client",
"isIncoming": 1,
"isEnabled": 1
+ },
+ {
+ "name": "UnboltDoor",
+ "code": 39,
+ "mfgCode": null,
+ "source": "client",
+ "isIncoming": 1,
+ "isEnabled": 1
}
],
"attributes": [
@@ -3147,6 +3399,54 @@
"reportableChange": 0
},
{
+ "name": "DoorState",
+ "code": 3,
+ "mfgCode": null,
+ "side": "server",
+ "type": "DoorStateEnum",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "1",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "DoorOpenEvents",
+ "code": 4,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int32u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "DoorClosedEvents",
+ "code": 5,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int32u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
"name": "NumberOfTotalUsersSupported",
"code": 17,
"mfgCode": null,
@@ -3156,7 +3456,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "2",
+ "defaultValue": "10",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3172,7 +3472,71 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "2",
+ "defaultValue": "10",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "NumberOfRFIDUsersSupported",
+ "code": 19,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int16u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "10",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "NumberOfWeekDaySchedulesSupportedPerUser",
+ "code": 20,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "10",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "NumberOfYearDaySchedulesSupportedPerUser",
+ "code": 21,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "10",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "NumberOfHolidaySchedulesSupported",
+ "code": 22,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "10",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3188,7 +3552,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "10",
+ "defaultValue": "8",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3204,7 +3568,55 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "5",
+ "defaultValue": "6",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "MaxRFIDCodeLength",
+ "code": 25,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "20",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "MinRFIDCodeLength",
+ "code": 26,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "10",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "CredentialRulesSupport",
+ "code": 27,
+ "mfgCode": null,
+ "side": "server",
+ "type": "DlCredentialRuleMask",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "1",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3227,6 +3639,22 @@
"reportableChange": 0
},
{
+ "name": "Language",
+ "code": 33,
+ "mfgCode": null,
+ "side": "server",
+ "type": "char_string",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "en",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
"name": "AutoRelockTime",
"code": 35,
"mfgCode": null,
@@ -3236,6 +3664,22 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
+ "defaultValue": "5",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "SoundVolume",
+ "code": 36,
+ "mfgCode": null,
+ "side": "server",
+ "type": "int8u",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
"defaultValue": "0",
"reportable": 1,
"minInterval": 1,
@@ -3268,7 +3712,39 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "0xFFF6",
+ "defaultValue": "0xFFFF",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "EnableOneTouchLocking",
+ "code": 41,
+ "mfgCode": null,
+ "side": "server",
+ "type": "boolean",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "0",
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
+ "name": "EnablePrivacyModeButton",
+ "code": 43,
+ "mfgCode": null,
+ "side": "server",
+ "type": "boolean",
+ "included": 1,
+ "storageOption": "RAM",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": "0",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3307,22 +3783,6 @@
"reportableChange": 0
},
{
- "name": "SendPINOverTheAir",
- "code": 50,
- "mfgCode": null,
- "side": "server",
- "type": "boolean",
- "included": 1,
- "storageOption": "RAM",
- "singleton": 0,
- "bounded": 0,
- "defaultValue": "0",
- "reportable": 1,
- "minInterval": 1,
- "maxInterval": 65534,
- "reportableChange": 0
- },
- {
"name": "RequirePINforRemoteOperation",
"code": 51,
"mfgCode": null,
@@ -3332,7 +3792,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "1",
+ "defaultValue": "0",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3371,6 +3831,22 @@
"reportableChange": 0
},
{
+ "name": "EventList",
+ "code": 65530,
+ "mfgCode": null,
+ "side": "server",
+ "type": "array",
+ "included": 1,
+ "storageOption": "External",
+ "singleton": 0,
+ "bounded": 0,
+ "defaultValue": null,
+ "reportable": 1,
+ "minInterval": 1,
+ "maxInterval": 65534,
+ "reportableChange": 0
+ },
+ {
"name": "AttributeList",
"code": 65531,
"mfgCode": null,
@@ -3396,7 +3872,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "0x0181",
+ "defaultValue": "0x1DB3",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3412,7 +3888,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
- "defaultValue": "6",
+ "defaultValue": "7",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
@@ -3428,6 +3904,13 @@
"included": 1
},
{
+ "name": "DoorStateChange",
+ "code": 1,
+ "mfgCode": null,
+ "side": "server",
+ "included": 1
+ },
+ {
"name": "LockOperation",
"code": 2,
"mfgCode": null,
@@ -3440,6 +3923,13 @@
"mfgCode": null,
"side": "server",
"included": 1
+ },
+ {
+ "name": "LockUserChange",
+ "code": 4,
+ "mfgCode": null,
+ "side": "server",
+ "included": 1
}
]
}
@@ -3458,10 +3948,10 @@
{
"endpointTypeName": "Anonymous Endpoint Type",
"endpointTypeIndex": 1,
- "profileId": 260,
+ "profileId": 259,
"endpointId": 1,
"networkId": 0,
"parentEndpointIdentifier": null
}
]
-}
\ No newline at end of file
+}
diff --git a/examples/chef/esp32/main/CMakeLists.txt b/examples/chef/esp32/main/CMakeLists.txt
index 8278cf9..75cf0b8 100644
--- a/examples/chef/esp32/main/CMakeLists.txt
+++ b/examples/chef/esp32/main/CMakeLists.txt
@@ -63,14 +63,15 @@
${SRC_DIRS_LIST}
"${CMAKE_CURRENT_LIST_DIR}"
"${CMAKE_SOURCE_DIR}/../common"
- "${CMAKE_SOURCE_DIR}/../common/clusters/media-input/"
+ "${CMAKE_SOURCE_DIR}/../common/clusters/audio-output/"
+ "${CMAKE_SOURCE_DIR}/../common/clusters/channel/"
+ "${CMAKE_SOURCE_DIR}/../common/clusters/door-lock/"
+ "${CMAKE_SOURCE_DIR}/../common/clusters/keypad-input/"
"${CMAKE_SOURCE_DIR}/../common/clusters/low-power/"
+ "${CMAKE_SOURCE_DIR}/../common/clusters/media-input/"
"${CMAKE_SOURCE_DIR}/../common/clusters/media-playback/"
"${CMAKE_SOURCE_DIR}/../common/clusters/target-navigator/"
"${CMAKE_SOURCE_DIR}/../common/clusters/wake-on-lan/"
- "${CMAKE_SOURCE_DIR}/../common/clusters/channel/"
- "${CMAKE_SOURCE_DIR}/../common/clusters/keypad-input/"
- "${CMAKE_SOURCE_DIR}/../common/clusters/audio-output/"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/attributes"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util"
diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn
index 0a4e238..3cf4bdc 100644
--- a/examples/chef/linux/BUILD.gn
+++ b/examples/chef/linux/BUILD.gn
@@ -49,6 +49,9 @@
"${project_dir}/common/chef-rvc-operational-state-delegate.cpp",
"${project_dir}/common/clusters/audio-output/AudioOutputManager.cpp",
"${project_dir}/common/clusters/channel/ChannelManager.cpp",
+ "${project_dir}/common/clusters/door-lock/chef-doorlock-stubs.cpp",
+ "${project_dir}/common/clusters/door-lock/chef-lock-endpoint.cpp",
+ "${project_dir}/common/clusters/door-lock/chef-lock-manager.cpp",
"${project_dir}/common/clusters/keypad-input/KeypadInputManager.cpp",
"${project_dir}/common/clusters/low-power/LowPowerManager.cpp",
"${project_dir}/common/clusters/media-input/MediaInputManager.cpp",
diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt
index 25d6632..29b2181 100644
--- a/examples/chef/nrfconnect/CMakeLists.txt
+++ b/examples/chef/nrfconnect/CMakeLists.txt
@@ -88,14 +88,17 @@
${CHEF}/common/chef-resource-monitoring-delegates.cpp
${CHEF}/common/chef-rvc-mode-delegate.cpp
${CHEF}/common/chef-rvc-operational-state-delegate.cpp
- ${CHEF}/common/clusters/media-input/MediaInputManager.cpp
+ ${CHEF}/common/clusters/audio-output/AudioOutputManager.cpp
+ ${CHEF}/common/clusters/channel/ChannelManager.cpp
+ ${CHEF}/common/clusters/door-lock/chef-doorlock-stubs.cpp
+ ${CHEF}/common/clusters/door-lock/chef-lock-endpoint.cpp
+ ${CHEF}/common/clusters/door-lock/chef-lock-manager.cpp
+ ${CHEF}/common/clusters/keypad-input/KeypadInputManager.cpp
${CHEF}/common/clusters/low-power/LowPowerManager.cpp
+ ${CHEF}/common/clusters/media-input/MediaInputManager.cpp
${CHEF}/common/clusters/media-playback/MediaPlaybackManager.cpp
${CHEF}/common/clusters/target-navigator/TargetNavigatorManager.cpp
${CHEF}/common/clusters/wake-on-lan/WakeOnLanManager.cpp
- ${CHEF}/common/clusters/channel/ChannelManager.cpp
- ${CHEF}/common/clusters/keypad-input/KeypadInputManager.cpp
- ${CHEF}/common/clusters/audio-output/AudioOutputManager.cpp
${CHEF}/common/stubs.cpp
${CHEF}/nrfconnect/main.cpp
)