diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt
index 4e3560d7fba70e..6ed9654a620149 100644
--- a/.github/.wordlist.txt
+++ b/.github/.wordlist.txt
@@ -48,11 +48,9 @@ algs
alloc
Ameba
amebad
-AmebaD
amebaiot
AmebaZ
amebaz2
-AmebaZ2
announcementReason
AnnounceOTAProvider
AnnounceOtaProviderRequest
@@ -84,8 +82,6 @@ args
argv
armeabi
armino
-Armino
-ARMINO
ARMmbed
armv
ASAN
@@ -294,8 +290,8 @@ connstring
conntype
const
ContentApp
-ContentApp's
ContentAppPlatform
+ContentApp's
ContentLaunch
ContentLauncher
continuousHinting
@@ -1116,8 +1112,8 @@ REPL
repo
req
Requestor
-Requestor's
RequestorCanConsent
+Requestor's
Requestors
responder
RestrictedEvent
@@ -1164,8 +1160,8 @@ SDB
SDC
SDHC
SDK
-SDK's
sdkconfig
+SDK's
SDKs
SDKTARGETSYSROOT
sdl
@@ -1342,6 +1338,7 @@ trackFree
TransferSession
transitionTime
TransportMgrBase
+TriggerEffect
TRNG
TrustedRootCertificates
tsan
diff --git a/examples/lighting-app/nxp/k32w/k32w0/README.md b/examples/lighting-app/nxp/k32w/k32w0/README.md
index 6b638d0660447a..8ea1d9848debcd 100644
--- a/examples/lighting-app/nxp/k32w/k32w0/README.md
+++ b/examples/lighting-app/nxp/k32w/k32w0/README.md
@@ -167,6 +167,25 @@ DS3, which can be found on the DK6 board.
Also, by long pressing the **USERINTERFACE** button, the factory reset action
will be initiated.
+### Identify cluster LED state
+
+The Identify cluster server supports two identification commands: **Identify**
+and **TriggerEffect**. These commands allow a user to identify a particular
+device. For these commands, the **LED D3** is used.
+
+The **Identify command** will use the **LED D3** to flash with a period of 0.5
+seconds.
+
+The **TriggerEffect command** will use the **LED D3** with the following
+effects:
+
+- _Blink_ — flash with a 1 second period for 2 seconds
+- _Breathe_ — flash with a 1 second period for 15 seconds
+- _Okay_ — flash with a 1 second period for 4 seconds
+- _Channel change_ — same as Blink
+- _Finish effect_ — complete current effect sequence and terminate
+- _Stop effect_ — terminate as soon as possible
+
## Building
diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp b/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp
index d5f30e05b79224..8d3f2f0bd0afac 100644
--- a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp
+++ b/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp
@@ -82,10 +82,16 @@ extern "C" void K32WUartProcess(void);
using namespace ::chip::Credentials;
using namespace ::chip::DeviceLayer;
using namespace chip;
-;
AppTask AppTask::sAppTask;
+static Identify gIdentify = { chip::EndpointId{ 1 }, AppTask::OnIdentifyStart, AppTask::OnIdentifyStop,
+ EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, AppTask::OnTriggerEffect,
+ // Use invalid value for identifiers to enable TriggerEffect command
+ // to stop Identify command for each effect
+ (EmberAfIdentifyEffectIdentifier)(EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT - 0x10),
+ EMBER_ZCL_IDENTIFY_EFFECT_VARIANT_DEFAULT };
+
/* OTA related variables */
#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR
static DefaultOTARequestor gRequestorCore;
@@ -415,15 +421,7 @@ void AppTask::ResetActionEventHandler(AppEvent * aEvent)
sAppTask.CancelTimer();
sAppTask.mFunction = kFunction_NoneSelected;
- /* restore initial state for the LED indicating Lighting state */
- if (LightingMgr().IsTurnedOff())
- {
- sLightLED.Set(false);
- }
- else
- {
- sLightLED.Set(true);
- }
+ RestoreLightingState();
K32W_LOG("Factory Reset was cancelled!");
}
@@ -682,6 +680,127 @@ void AppTask::ActionCompleted(LightingManager::Action_t aAction)
sAppTask.mFunction = kFunction_NoneSelected;
}
+void AppTask::RestoreLightingState(void)
+{
+ /* restore initial state for the LED indicating Lighting state */
+ if (LightingMgr().IsTurnedOff())
+ {
+ sLightLED.Set(false);
+ }
+ else
+ {
+ sLightLED.Set(true);
+ }
+}
+
+void AppTask::OnIdentifyStart(Identify * identify)
+{
+ if ((kFunction_NoneSelected != sAppTask.mFunction) && (kFunction_TriggerEffect != sAppTask.mFunction))
+ {
+ K32W_LOG("Another function is scheduled. Could not initiate Identify process!");
+ return;
+ }
+
+ if (kFunction_TriggerEffect == sAppTask.mFunction)
+ {
+ chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerEffectComplete, identify);
+ OnTriggerEffectComplete(&chip::DeviceLayer::SystemLayer(), identify);
+ }
+
+ ChipLogProgress(Zcl, "Identify process has started. Status LED should blink with a period of 0.5 seconds.");
+ sAppTask.mFunction = kFunction_Identify;
+ sLightLED.Set(false);
+ sLightLED.Blink(250);
+}
+
+void AppTask::OnIdentifyStop(Identify * identify)
+{
+ if (kFunction_Identify == sAppTask.mFunction)
+ {
+ ChipLogProgress(Zcl, "Identify process has stopped.");
+ sAppTask.mFunction = kFunction_NoneSelected;
+
+ RestoreLightingState();
+ }
+}
+
+void AppTask::OnTriggerEffectComplete(chip::System::Layer * systemLayer, void * appState)
+{
+ // Let Identify command take over if called during TriggerEffect already running
+ if (kFunction_TriggerEffect == sAppTask.mFunction)
+ {
+ ChipLogProgress(Zcl, "TriggerEffect has stopped.");
+ sAppTask.mFunction = kFunction_NoneSelected;
+
+ // TriggerEffect finished - reset identifiers
+ // Use invalid value for identifiers to enable TriggerEffect command
+ // to stop Identify command for each effect
+ gIdentify.mCurrentEffectIdentifier =
+ (EmberAfIdentifyEffectIdentifier)(EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT - 0x10);
+ gIdentify.mTargetEffectIdentifier =
+ (EmberAfIdentifyEffectIdentifier)(EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT - 0x10);
+ gIdentify.mEffectVariant = EMBER_ZCL_IDENTIFY_EFFECT_VARIANT_DEFAULT;
+
+ RestoreLightingState();
+ }
+}
+
+void AppTask::OnTriggerEffect(Identify * identify)
+{
+ // Allow overlapping TriggerEffect calls
+ if ((kFunction_NoneSelected != sAppTask.mFunction) && (kFunction_TriggerEffect != sAppTask.mFunction))
+ {
+ K32W_LOG("Another function is scheduled. Could not initiate Identify process!");
+ return;
+ }
+
+ sAppTask.mFunction = kFunction_TriggerEffect;
+ uint16_t timerDelay = 0;
+
+ ChipLogProgress(Zcl, "TriggerEffect has started.");
+
+ switch (identify->mCurrentEffectIdentifier)
+ {
+ case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK:
+ timerDelay = 2;
+ break;
+
+ case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE:
+ timerDelay = 15;
+ break;
+
+ case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY:
+ timerDelay = 4;
+ break;
+
+ case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE:
+ ChipLogProgress(Zcl, "Channel Change effect not supported, using effect %d", EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK);
+ timerDelay = 2;
+ break;
+
+ case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_FINISH_EFFECT:
+ chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerEffectComplete, identify);
+ timerDelay = 1;
+ break;
+
+ case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT:
+ chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerEffectComplete, identify);
+ OnTriggerEffectComplete(&chip::DeviceLayer::SystemLayer(), identify);
+ break;
+
+ default:
+ ChipLogProgress(Zcl, "Invalid effect identifier.");
+ }
+
+ if (timerDelay)
+ {
+ sLightLED.Set(false);
+ sLightLED.Blink(500);
+
+ chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(timerDelay), OnTriggerEffectComplete, identify);
+ }
+}
+
void AppTask::PostTurnOnActionRequest(int32_t aActor, LightingManager::Action_t aAction)
{
AppEvent event;
diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/include/AppTask.h b/examples/lighting-app/nxp/k32w/k32w0/main/include/AppTask.h
index d0ef272e00350c..fc8c164871d15e 100644
--- a/examples/lighting-app/nxp/k32w/k32w0/main/include/AppTask.h
+++ b/examples/lighting-app/nxp/k32w/k32w0/main/include/AppTask.h
@@ -24,6 +24,7 @@
#include "AppEvent.h"
#include "LightingManager.h"
+#include
#include
#include "FreeRTOS.h"
@@ -49,6 +50,12 @@ class AppTask
void UpdateClusterState(void);
void UpdateDeviceState(void);
+ // Identify cluster callbacks.
+ static void OnIdentifyStart(Identify * identify);
+ static void OnIdentifyStop(Identify * identify);
+ static void OnTriggerEffect(Identify * identify);
+ static void OnTriggerEffectComplete(chip::System::Layer * systemLayer, void * appState);
+
private:
friend AppTask & GetAppTask(void);
@@ -77,6 +84,8 @@ class AppTask
static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg);
void StartTimer(uint32_t aTimeoutInMs);
+ static void RestoreLightingState(void);
+
#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR
static void InitOTA(intptr_t arg);
static void StartOTAQuery(intptr_t arg);
@@ -93,6 +102,8 @@ class AppTask
kFunction_SoftwareUpdate = 0,
kFunction_FactoryReset,
kFunctionTurnOnTurnOff,
+ kFunction_Identify,
+ kFunction_TriggerEffect,
kFunction_Invalid
} Function;
diff --git a/src/app/clusters/identify-server/identify-server.cpp b/src/app/clusters/identify-server/identify-server.cpp
index a9294aea5bbab5..23a3cae299ca23 100644
--- a/src/app/clusters/identify-server/identify-server.cpp
+++ b/src/app/clusters/identify-server/identify-server.cpp
@@ -179,9 +179,7 @@ void MatterIdentifyClusterServerAttributeChangedCallback(const app::ConcreteAttr
/* finish identify process */
if (EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_FINISH_EFFECT == identify->mCurrentEffectIdentifier && identifyTime > 0)
{
- (void) chip::DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds16(1), onIdentifyClusterTick,
- identify);
- return;
+ Clusters::Identify::Attributes::IdentifyTime::Set(endpoint, 1);
}
/* stop identify process */
if (EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT == identify->mCurrentEffectIdentifier && identifyTime > 0)