diff --git a/examples/lighting-app/qpg/src/AppTask.cpp b/examples/lighting-app/qpg/src/AppTask.cpp index 5781e4069ad1eb..1dd1aa85514a7a 100644 --- a/examples/lighting-app/qpg/src/AppTask.cpp +++ b/examples/lighting-app/qpg/src/AppTask.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -72,6 +73,7 @@ using namespace ::chip::DeviceLayer; static uint8_t countdown = 0; namespace { +constexpr EndpointId kLightEndpointId = 1; TaskHandle_t sAppTaskHandle; QueueHandle_t sAppEventQueue; @@ -93,6 +95,25 @@ StaticTask_t appTaskStruct; Clusters::Identify::EffectIdentifierEnum sIdentifyEffect = Clusters::Identify::EffectIdentifierEnum::kStopEffect; chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; +// Define a custom attribute persister which makes actual write of the attribute value +// to the non-volatile storage only when it has remained constant for 5 seconds. This is to reduce +// the flash wearout when the attribute changes frequently as a result of commands. +// DeferredAttribute object describes a deferred attribute, but also holds a buffer with a value to +// be written, so it must live so long as the DeferredAttributePersistenceProvider object. +// +DeferredAttribute gPersisters[] = { DeferredAttribute(ConcreteAttributePath(kLightEndpointId, Clusters::ColorControl::Id, + Clusters::ColorControl::Attributes::CurrentX::Id)), + DeferredAttribute(ConcreteAttributePath(kLightEndpointId, Clusters::ColorControl::Id, + Clusters::ColorControl::Attributes::CurrentY::Id)), + DeferredAttribute(ConcreteAttributePath(kLightEndpointId, Clusters::LevelControl::Id, + Clusters::LevelControl::Attributes::CurrentLevel::Id)) + +}; + +DeferredAttributePersistenceProvider gDeferredAttributePersister(Server::GetInstance().GetDefaultAttributePersister(), + Span(gPersisters, 3), + System::Clock::Milliseconds32(5000)); + /********************************************************** * Identify Callbacks *********************************************************/ @@ -250,6 +271,8 @@ void AppTask::InitServer(intptr_t arg) chip::Server::GetInstance().Init(initParams); + app::SetAttributePersistenceProvider(&gDeferredAttributePersister); + #if CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY chip::app::DnssdServer::Instance().SetExtendedDiscoveryTimeoutSecs(extDiscTimeoutSecs); #endif diff --git a/examples/lighting-app/qpg/src/ZclCallbacks.cpp b/examples/lighting-app/qpg/src/ZclCallbacks.cpp index fce10c0d60f1d1..0b75837a64a8cc 100644 --- a/examples/lighting-app/qpg/src/ZclCallbacks.cpp +++ b/examples/lighting-app/qpg/src/ZclCallbacks.cpp @@ -160,13 +160,41 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & */ void emberAfOnOffClusterInitCallback(EndpointId endpoint) { + uint8_t levelValue; + XyColor_t xy; bool onOffValue = false; + app::DataModel::Nullable currentLevel; + EmberAfStatus status; - EmberAfStatus status = OnOff::Attributes::OnOff::Get(1, &onOffValue); + status = OnOff::Attributes::OnOff::Get(1, &onOffValue); if (status == EMBER_ZCL_STATUS_SUCCESS) { LightingMgr().InitiateAction(onOffValue ? LightingManager::ON_ACTION : LightingManager::OFF_ACTION, 0, 1, (uint8_t *) onOffValue); } + + /* restore values saved by DeferredAttributePersistenceProvider */ + status = LevelControl::Attributes::CurrentLevel::Get(endpoint, currentLevel); + if (status != EMBER_ZCL_STATUS_SUCCESS || currentLevel.IsNull()) + { + return; + } + + levelValue = currentLevel.Value(); + + status = ColorControl::Attributes::CurrentY::Get(endpoint, &xy.y); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + return; + } + status = ColorControl::Attributes::CurrentX::Get(endpoint, &xy.x); + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + return; + } + ChipLogProgress(Zcl, "restore level: %u", levelValue); + LightingMgr().InitiateAction(LightingManager::LEVEL_ACTION, 0, 1, &levelValue); + ChipLogProgress(Zcl, "restore XY color: %u|%u", xy.x, xy.y); + LightingMgr().InitiateAction(LightingManager::COLOR_ACTION_XY, 0, sizeof(xy), (uint8_t *) &xy); } diff --git a/examples/lighting-app/qpg/zap/light.matter b/examples/lighting-app/qpg/zap/light.matter index 40bde659477d8a..231379b7dcecc8 100644 --- a/examples/lighting-app/qpg/zap/light.matter +++ b/examples/lighting-app/qpg/zap/light.matter @@ -2330,8 +2330,8 @@ endpoint 1 { ram attribute currentHue default = 0x00; ram attribute currentSaturation default = 0x00; ram attribute remainingTime default = 0x0000; - ram attribute currentX default = 0x616B; - ram attribute currentY default = 0x607D; + persist attribute currentX default = 0x616B; + persist attribute currentY default = 0x607D; ram attribute colorTemperatureMireds default = 0x00FA; ram attribute colorMode default = 0x01; ram attribute options default = 0x00; diff --git a/examples/lighting-app/qpg/zap/light.zap b/examples/lighting-app/qpg/zap/light.zap index 2c881ce56c2e37..32c773385f5b54 100644 --- a/examples/lighting-app/qpg/zap/light.zap +++ b/examples/lighting-app/qpg/zap/light.zap @@ -5310,7 +5310,7 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x616B", @@ -5326,7 +5326,7 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x607D", @@ -5980,4 +5980,4 @@ "networkId": 0 } ] -} \ No newline at end of file +}