Skip to content

Commit

Permalink
samples: matter: Introduce Timed Schedule Access in Lock
Browse files Browse the repository at this point in the history
- Regenerated Matter Lock Zap to include Timed Schedule
Access feature

- Added Schedules for WeekDay, YearDay and Holiday
to the credentials manager according to Matter
Specification.

- Implemented callbacks for the schedule feature required
by door-lock-server.

- Moved credentials manager users, schedules and credentials
implementations to separate files due to a high number
of lines in the credentials_manager.cpp file.

- Added a guide to Matter Lock sample on how to use this
feature.

- Updated release notes.

Signed-off-by: Arkadiusz Balys <[email protected]>
  • Loading branch information
ArekBalysNordic committed May 24, 2024
1 parent 14ecdd9 commit 52979e8
Show file tree
Hide file tree
Showing 19 changed files with 1,825 additions and 440 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ Matter samples
* Added support for emulation of the nRF7001 Wi-Fi companion IC on the nRF7002 DK.
* Added a door lock credentials manager module.
The module is used to implement support for refined handling and persistent storage of PIN codes.
* Added the ::ref::`matter_lock_scheduled_timed_access` feature.

Multicore samples
-----------------
Expand Down
32 changes: 32 additions & 0 deletions samples/matter/lock/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,29 @@ config LOCK_MAX_CREDENTIAL_LENGTH
int "Maximum length of the single credential supported by the lock"
default 10

config LOCK_SCHEDULES
bool "Support for WeekDay, YearDay and Holiday schedules in lock"
help
This option adds support for an optional Timed Schedule Access Lock feature.
You can use Week Day, Year Day and Holiday schedules to restrict access for a
specific user for a specific amount of time. For example, use it to
allow access to a user only for three days in week.

config LOCK_MAX_WEEKDAY_SCHEDULES_PER_USER
int "Maximum number of WeekDay schedules per one user supported by the lock"
depends on LOCK_SCHEDULES
default 5

config LOCK_MAX_YEARDAY_SCHEDULES_PER_USER
int "Maximum number of YearDay schedules per one user supported by the lock"
depends on LOCK_SCHEDULES
default 5

config LOCK_MAX_HOLIDAY_SCHEDULES
int "Maximum number of Holiday schedules supported by the lock"
depends on LOCK_SCHEDULES
default 5

config LOCK_ENABLE_DEBUG
bool "Enable debug features to print users and credentials"
depends on SHELL
Expand All @@ -32,6 +55,15 @@ config LOCK_ENABLE_DEBUG

if LOCK_ENABLE_DEBUG

config LOCK_PRINT_STORAGE_STATUS
bool "Print storage status after each store call"
help
Debug feature to print the debug-level log that contains information of the entry storing
to persistent storage and how many bytes left to store the new entry. It can be used to verify
whether credentials, schedules or users entry are written properly to persistent storage.
This option should be disabled in production firmware
version.

# This should be deterined based on the maximum possible command length that depends on the LOCK_MAX_CREDENTIAL_LENGTH
config SHELL_CMD_BUFF_SIZE
default 300
Expand Down
147 changes: 147 additions & 0 deletions samples/matter/lock/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,48 @@ Upgrading the device firmware

To upgrade the device firmware, complete the steps listed for the selected method in the :doc:`matter:nrfconnect_examples_software_update` tutorial of the Matter documentation.

.. _matter_lock_scheduled_timed_access:

Schedule timed-access
=====================

Schedule timed-access feature is an optional Matter lock feature that can be applicable to all available lock users.
You can use the timed schedule access feature to allow guests users of the home to access the lock at the specific scheduled times.
To use this feature you need create at least one user on the lock device, and assign credentials.
To learn how to do it, see :ref:`matter_lock_sample_remote_access_with_pin`.

You can use the following types of the schedule timed-access:

- ``Week-day`` to restrict access to a specified time window on certain days of the week for a specific user.
This schedule is repeated each week.
When the schedule is cleared the unrestricted access is granted to the user.

- ``Year-day`` to restrict access to a specified data end time window.
This schedule is granted only once not repeated anymore.
When the schedule is cleared the unrestricted access is granted to the user.

- ``Holiday`` to setup a holiday operating mode in the lock device.
You can choose one of the operating mode option from the following list:

- ``Normal`` - the lock operates normally.
- ``Vacation`` - Only remote operations are enabled.
- ``Privacy`` - Possible only if lock is in the locked state.
All external interactions with the lock are disabled.
Manual unlocking changes the mode to ``Normal``.
- ``NoRemoteLockUnlock`` - Disables all remote operations.
- ``Passage`` - Allow using the lock without providing a PIN.
This option can be used for example for employees during working hours.

To enable the Schedule timed-access feature set the :kconfig:option:`CONFIG_LOCK_SCHEDULES` kconfig option to ``y``.

Use the following kconfig options to modify maximum number of the specific schedule type:

- :kconfig:option:`CONFIG_LOCK_MAX_WEEKDAY_SCHEDULES_PER_USER` to define the maximum number of week-day schedules per one user.
- :kconfig:option:`CONFIG_LOCK_MAX_YEARDAY_SCHEDULES_PER_USER` to define the maximum number of year-day schedules per one user.
- :kconfig:option:`CONFIG_LOCK_MAX_HOLIDAY_SCHEDULES` to define the maximum number of holiday schedules.

All schedule timed-access entries are saved to non-volatile memory and loaded automatically after device reboot.

.. _matter_lock_sample_remote_access_with_pin:

Testing remote access with PIN code credential
Expand Down Expand Up @@ -536,6 +578,111 @@ After building the sample and programming it to your development kit, complete t
.. note::
Accessing the door lock remotely without a valid PIN code credential will fail.

.. _matter_lock_sample_schedule_testing:

Testing schedule timed-access
=============================

.. note::
You can test :ref:`matter_lock_scheduled_timed_access` using any Matter compatible controller.
The following steps use the CHIP Tool controller as an example.

After building the sample with the feature enabled and programming it to your development kit, complete the following steps to test schedule timed-access:

1. |connect_kit|
#. |connect_terminal_ANSI|
#. Wait until the device boots.
#. Commission an accessory with node ID equal to 10 to the Matter network by following the steps described in the `Commissioning the device`_ section.
#. Add the example ``Home`` door lock user:

.. code-block:: console
./chip-tool doorlock set-user 0 2 Home 123 1 0 0 10 1 --timedInteractionTimeoutMs 5000
This command creates a ``Home`` user with a unique ID of ``123`` and an index of ``2``.
The new user's status is set to ``1``, and both its type and credential rule to ``0``.
The user is assigned to the door lock cluster residing on endpoint ``1`` of the node with ID ``10``.

#. Set the example ``week-day`` schedule using the following command:

./chip-tool doorlock set-week-day-schedule WeekDayIndex UserIndex DaysMask StartHour StartMinute EndHour EndMinute destination-id endpoint-id

Where:

* ``WeekDayIndex`` is an index of the new schedule, starting from ``1``.
The maximum value is defined by the :kconfig:option:`CONFIG_LOCK_MAX_WEEKDAY_SCHEDULES_PER_USER` kconfig option.
* ``UserIndex`` is the user index defined in the previous step, starting from ``1``.
* ``DaysMask`` is a bitmap of numbers of the week days starting from ``0`` as a Sunday and finishing at ``6`` as a Saturday.
For example, to assign this schedule to Tuesday, Thursday and Saturday you need to provide ``84`` because it is equivalent to the ``01010100`` bitmap.
* ``StartHour`` is the starting hour for the week day schedule.
* ``StartMinute`` is the starting minute for the week day schedule.
* ``EndHour`` is the ending hour for the week day schedule.
* ``EndMinute`` is the ending hour for the week day schedule.
* ``node-id`` is the device node ID.
* ``endpoint-id`` is the Matter door lock endpoint, in this sample assigned to ``1``.

For example, use the following command to set a ``week-day`` schedule for Tuesday, Thursday and Saturday to start at 7:30 AM and finish at 10:30 AM dedicated for user with ID ``1``:

.. code-block:: console
./chip-tool doorlock set-week-day-schedule 1 1 84 7 30 10 30 1 1
#. Set the example ``year-day`` schedule using the following command:

./chip-tool doorlock set-year-day-schedule YearDayIndex UserIndex LocalStartTime LocalEndTime node-id endpoint-id

Where:

* ``YearDayIndex`` is an index of the new schedule, starting from ``1``.
The maximum value is defined by the :kconfig:option:`CONFIG_LOCK_MAX_YEARDAY_SCHEDULES_PER_USER` kconfig option.
* ``UserIndex`` is the user index defined in the previous step, starting from ``1``.
* ``LocalStartTime`` is the starting time in Epoch Time.
* ``LocalEndTime`` is the ending time in Epoch Time.
* ``node-id`` is the device node ID.
* ``endpoint-id`` is the Matter door lock endpoint, in this sample assigned to ``1``.

Both ``LocalStartTime`` and ``LocalEndTime`` are in seconds with the local time offset based on the local timezone and DST offset on the day represented by the value.

For example:

.. code-block:: console
./chip-tool doorlock set-week-day-schedule 1 1 60 120 1 1
#. Set the example ``holiday`` schedule using the following command:

./chip-tool doorlock set-holiday-schedule HolidayIndex LocalStartTime LocalEndTime OperatingMode destination-id endpoint-id

Where:

* ``HolidayIndex`` is an index of the new schedule, starting from ``1``.
* ``LocalStartTime`` is the starting time in Epoch Time.
* ``LocalEndTime`` is the ending time in Epoch Time.
* ``OperatingMode`` is the operating mode described in the :ref:`matter_lock_scheduled_timed_access` section of this guide.
* ``node-id`` is the device node ID.
* ``endpoint-id`` is the Matter door lock endpoint, in this sample assigned to ``1``.

For example, to setup a ``holiday-schedule`` with type ``Vacation`` use the following command:

.. code-block:: console
./chip-tool doorlock set-holiday-schedule 1 60 120 1 1 1
#. Read saved schedules using the following commands providing the arguments in a similar way as above:

.. code-block:: console
./chip-tool doorlock get-week-day-schedule WeekDayIndex UserIndex destination-id endpoint-id
.. code-block:: console
./chip-tool doorlock get-year-day-schedule YearDayIndex UserIndex destination-id endpoint-id
.. code-block:: console
./chip-tool doorlock get-holiday-schedule HolidayIndex destination-id endpoint-id
.. _matter_lock_sample_switching_thread_wifi:

Testing switching between Thread and Wi-Fi
Expand Down
43 changes: 43 additions & 0 deletions samples/matter/lock/src/bolt_lock_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,49 @@ bool BoltLockManager::SetCredential(uint16_t credentialIndex, FabricIndex creato
credentialType, secret);
}

#ifdef CONFIG_LOCK_SCHEDULES

DlStatus BoltLockManager::GetWeekDaySchedule(uint8_t weekdayIndex, uint16_t userIndex,
EmberAfPluginDoorLockWeekDaySchedule &schedule)
{
return PinManager::Instance().GetWeekDaySchedule(weekdayIndex, userIndex, schedule);
}

DlStatus BoltLockManager::SetWeekDaySchedule(uint8_t weekdayIndex, uint16_t userIndex, DlScheduleStatus status,
DaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute,
uint8_t endHour, uint8_t endMinute)
{
return PinManager::Instance().SetWeekDaySchedule(weekdayIndex, userIndex, status, daysMask, startHour,
startMinute, endHour, endMinute);
}

DlStatus BoltLockManager::GetYearDaySchedule(uint8_t yearDayIndex, uint16_t userIndex,
EmberAfPluginDoorLockYearDaySchedule &schedule)
{
return PinManager::Instance().GetYearDaySchedule(yearDayIndex, userIndex, schedule);
}

DlStatus BoltLockManager::SetYearDaySchedule(uint8_t yeardayIndex, uint16_t userIndex, DlScheduleStatus status,
uint32_t localStartTime, uint32_t localEndTime)
{
return PinManager::Instance().SetYearDaySchedule(yeardayIndex, userIndex, status, localStartTime, localEndTime);
}

DlStatus BoltLockManager::GetHolidaySchedule(uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule &schedule)
{
return PinManager::Instance().GetHolidaySchedule(holidayIndex, schedule);
}

DlStatus BoltLockManager::SetHolidaySchedule(uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime,
uint32_t localEndTime, OperatingModeEnum operatingMode)
{
return PinManager::Instance().SetHolidaySchedule(holidayIndex, status, localStartTime, localEndTime,
operatingMode);
}

#endif /* CONFIG_LOCK_SCHEDULES */


bool BoltLockManager::ValidatePIN(const Optional<ByteSpan> &pinCode, OperationErrorEnum &err)
{
return PinManager::Instance().ValidatePIN(pinCode, err);
Expand Down
15 changes: 15 additions & 0 deletions samples/matter/lock/src/bolt_lock_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ class BoltLockManager {
DlCredentialStatus credentialStatus, CredentialTypeEnum credentialType,
const chip::ByteSpan &secret);

#ifdef CONFIG_LOCK_SCHEDULES
DlStatus GetWeekDaySchedule(uint8_t weekdayIndex, uint16_t userIndex,
EmberAfPluginDoorLockWeekDaySchedule &schedule);
DlStatus SetWeekDaySchedule(uint8_t weekdayIndex, uint16_t userIndex, DlScheduleStatus status,
DaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, uint8_t endHour,
uint8_t endMinute);
DlStatus GetYearDaySchedule(uint8_t yearDayIndex, uint16_t userIndex,
EmberAfPluginDoorLockYearDaySchedule &schedule);
DlStatus SetYearDaySchedule(uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status,
uint32_t localStartTime, uint32_t localEndTime);
DlStatus GetHolidaySchedule(uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule &schedule);
DlStatus SetHolidaySchedule(uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime,
uint32_t localEndTime, OperatingModeEnum operatingMode);
#endif /* CONFIG_LOCK_SCHEDULES */

bool ValidatePIN(const Optional<chip::ByteSpan> &pinCode, OperationErrorEnum &err);

void Lock(OperationSource source);
Expand Down
Loading

0 comments on commit 52979e8

Please sign in to comment.