Update Quiet reporting conditions for LVL and CC remaining time attribute (#35224)

* Update Quiet reporting conditions for LVL and CC remaining time attribute

* Restyled by clang-format

* Fix/cleaup of startUpColorTempCommand

* Add missing SetQuietReportRemainingTime for moveToColorTemp command. Add remainingTime Report condition on command invoke. Fix clang-tidy

* Update src/app/clusters/color-control-server/color-control-server.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

---------

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
diff --git a/src/app/clusters/color-control-server/color-control-server.cpp b/src/app/clusters/color-control-server/color-control-server.cpp
index 0555352..2a85888 100644
--- a/src/app/clusters/color-control-server/color-control-server.cpp
+++ b/src/app/clusters/color-control-server/color-control-server.cpp
@@ -1040,7 +1040,7 @@
     colorHueTransitionState->transitionTime = MAX_INT16U_VALUE;
     colorHueTransitionState->endpoint       = endpoint;
 
-    SetQuietReportRemainingTime(endpoint, MAX_INT16U_VALUE);
+    SetQuietReportRemainingTime(endpoint, MAX_INT16U_VALUE, true /* isNewTransition */);
 
     scheduleTimerCallbackMs(configureHSVEventControl(endpoint), TRANSITION_UPDATE_TIME_MS.count());
 }
@@ -1091,7 +1091,10 @@
     // When the hue transition is loop, RemainingTime stays at MAX_INT16
     if (hueTransitionState->repeat == false)
     {
-        SetQuietReportRemainingTime(endpoint, max(hueTransitionState->timeRemaining, saturationTransitionState->timeRemaining));
+        bool hsvTransitionStart = (hueTransitionState->stepsRemaining == hueTransitionState->stepsTotal) ||
+            (saturationTransitionState->stepsRemaining == saturationTransitionState->stepsTotal);
+        SetQuietReportRemainingTime(endpoint, max(hueTransitionState->timeRemaining, saturationTransitionState->timeRemaining),
+                                    hsvTransitionStart);
     }
 }
 
@@ -1484,7 +1487,7 @@
     colorHueTransitionState->repeat         = true;
 
     // hue movement can last forever. Indicate this with a remaining time of maxint
-    SetQuietReportRemainingTime(endpoint, MAX_INT16U_VALUE);
+    SetQuietReportRemainingTime(endpoint, MAX_INT16U_VALUE, true /* isNewTransition */);
 
     // kick off the state machine:
     scheduleTimerCallbackMs(configureHSVEventControl(endpoint), TRANSITION_UPDATE_TIME_MS.count());
@@ -2052,7 +2055,7 @@
                 uint16_t storedEnhancedHue = 0;
                 Attributes::ColorLoopStoredEnhancedHue::Get(endpoint, &storedEnhancedHue);
                 MarkAttributeDirty markDirty =
-                    SetQuietReportAttribute(quietEnhancedHue[epIndex], storedEnhancedHue, true /*isStartOrEndOfTransition*/, 0);
+                    SetQuietReportAttribute(quietEnhancedHue[epIndex], storedEnhancedHue, true /*isEndOfTransition*/, 0);
                 Attributes::EnhancedCurrentHue::Set(endpoint, quietEnhancedHue[epIndex].value().Value(), markDirty);
             }
             else
@@ -2094,10 +2097,6 @@
     uint16_t previousSaturation  = colorSaturationTransitionState->currentValue;
     uint16_t previousEnhancedhue = colorHueTransitionState->currentEnhancedHue;
 
-    bool isHueTansitionStart = (colorHueTransitionState->stepsRemaining == colorHueTransitionState->stepsTotal);
-    bool isSaturationTransitionStart =
-        (colorSaturationTransitionState->stepsRemaining == colorSaturationTransitionState->stepsTotal);
-
     bool isHueTansitionDone         = computeNewHueValue(colorHueTransitionState);
     bool isSaturationTransitionDone = computeNewColor16uValue(colorSaturationTransitionState);
 
@@ -2117,7 +2116,7 @@
     if (colorHueTransitionState->isEnhancedHue)
     {
         markDirty = SetQuietReportAttribute(quietEnhancedHue[epIndex], colorHueTransitionState->currentEnhancedHue,
-                                            (isHueTansitionStart || isHueTansitionDone), colorHueTransitionState->transitionTime);
+                                            isHueTansitionDone, colorHueTransitionState->transitionTime);
         Attributes::EnhancedCurrentHue::Set(endpoint, quietEnhancedHue[epIndex].value().Value(), markDirty);
         currentHue = static_cast<uint8_t>(colorHueTransitionState->currentEnhancedHue >> 8);
 
@@ -2135,8 +2134,7 @@
         }
     }
 
-    markDirty = SetQuietReportAttribute(quietHue[epIndex], currentHue, (isHueTansitionStart || isHueTansitionDone),
-                                        colorHueTransitionState->transitionTime);
+    markDirty = SetQuietReportAttribute(quietHue[epIndex], currentHue, isHueTansitionDone, colorHueTransitionState->transitionTime);
     Attributes::CurrentHue::Set(endpoint, quietHue[epIndex].value().Value(), markDirty);
 
     if (previousSaturation != colorSaturationTransitionState->currentValue)
@@ -2145,8 +2143,7 @@
     }
 
     markDirty = SetQuietReportAttribute(quietSaturation[epIndex], colorSaturationTransitionState->currentValue,
-                                        (isSaturationTransitionStart || isSaturationTransitionDone),
-                                        colorSaturationTransitionState->transitionTime);
+                                        isSaturationTransitionDone, colorSaturationTransitionState->transitionTime);
     Attributes::CurrentSaturation::Set(endpoint, quietSaturation[epIndex].value().Value(), markDirty);
 
     computePwmFromHsv(endpoint);
@@ -2298,7 +2295,7 @@
     colorYTransitionState->lowLimit       = MIN_CIE_XY_VALUE;
     colorYTransitionState->highLimit      = MAX_CIE_XY_VALUE;
 
-    SetQuietReportRemainingTime(endpoint, transitionTime);
+    SetQuietReportRemainingTime(endpoint, transitionTime, true /* isNewTransition */);
 
     // kick off the state machine:
     scheduleTimerCallbackMs(configureXYEventControl(endpoint), transitionTime ? TRANSITION_UPDATE_TIME_MS.count() : 0);
@@ -2405,7 +2402,7 @@
     colorYTransitionState->lowLimit       = MIN_CIE_XY_VALUE;
     colorYTransitionState->highLimit      = MAX_CIE_XY_VALUE;
 
-    SetQuietReportRemainingTime(endpoint, max(transitionTimeX, transitionTimeY));
+    SetQuietReportRemainingTime(endpoint, max(transitionTimeX, transitionTimeY), true /* isNewTransition */);
 
     // kick off the state machine:
     scheduleTimerCallbackMs(configureXYEventControl(endpoint), TRANSITION_UPDATE_TIME_MS.count());
@@ -2485,7 +2482,7 @@
     colorYTransitionState->lowLimit       = MIN_CIE_XY_VALUE;
     colorYTransitionState->highLimit      = MAX_CIE_XY_VALUE;
 
-    SetQuietReportRemainingTime(endpoint, transitionTime);
+    SetQuietReportRemainingTime(endpoint, transitionTime, true /* isNewTransition */);
 
     // kick off the state machine:
     scheduleTimerCallbackMs(configureXYEventControl(endpoint), transitionTime ? TRANSITION_UPDATE_TIME_MS.count() : 0);
@@ -2521,15 +2518,10 @@
         scheduleTimerCallbackMs(configureXYEventControl(endpoint), TRANSITION_UPDATE_TIME_MS.count());
     }
 
-    bool isXTransitionStart = (colorXTransitionState->stepsRemaining == colorXTransitionState->stepsTotal);
-    bool isYTransitionStart = (colorYTransitionState->stepsRemaining == colorYTransitionState->stepsTotal);
-
-    MarkAttributeDirty markXDirty =
-        SetQuietReportAttribute(quietColorX[epIndex], colorXTransitionState->currentValue,
-                                (isXTransitionStart || isXTransitionDone), colorXTransitionState->transitionTime);
-    MarkAttributeDirty markYDirty =
-        SetQuietReportAttribute(quietColorY[epIndex], colorYTransitionState->currentValue,
-                                (isYTransitionStart || isYTransitionDone), colorYTransitionState->transitionTime);
+    MarkAttributeDirty markXDirty = SetQuietReportAttribute(quietColorX[epIndex], colorXTransitionState->currentValue,
+                                                            isXTransitionDone, colorXTransitionState->transitionTime);
+    MarkAttributeDirty markYDirty = SetQuietReportAttribute(quietColorY[epIndex], colorYTransitionState->currentValue,
+                                                            isYTransitionDone, colorYTransitionState->transitionTime);
 
     Attributes::CurrentX::Set(endpoint, quietColorX[epIndex].value().Value(), markXDirty);
     Attributes::CurrentY::Set(endpoint, quietColorY[epIndex].value().Value(), markYDirty);
@@ -2623,6 +2615,8 @@
     colorTempTransitionState->lowLimit       = temperatureMin;
     colorTempTransitionState->highLimit      = temperatureMax;
 
+    SetQuietReportRemainingTime(endpoint, transitionTime, true /* isNewTransition */);
+
     // kick off the state machine
     scheduleTimerCallbackMs(configureTempEventControl(endpoint), transitionTime ? TRANSITION_UPDATE_TIME_MS.count() : 0);
     return Status::Success;
@@ -2687,36 +2681,32 @@
 
     if (status == Status::Success && !startUpColorTemp.IsNull())
     {
-        uint16_t updatedColorTemp = MAX_TEMPERATURE_VALUE;
-        status                    = Attributes::ColorTemperatureMireds::Get(endpoint, &updatedColorTemp);
+        uint16_t tempPhysicalMin = MIN_TEMPERATURE_VALUE;
+        Attributes::ColorTempPhysicalMinMireds::Get(endpoint, &tempPhysicalMin);
+        // Avoid potential divide-by-zero in future Kelvin conversions.
+        tempPhysicalMin = std::max(static_cast<uint16_t>(1u), tempPhysicalMin);
 
-        if (status == Status::Success)
+        uint16_t tempPhysicalMax = MAX_TEMPERATURE_VALUE;
+        Attributes::ColorTempPhysicalMaxMireds::Get(endpoint, &tempPhysicalMax);
+
+        if (tempPhysicalMin <= startUpColorTemp.Value() && startUpColorTemp.Value() <= tempPhysicalMax)
         {
-            uint16_t tempPhysicalMin = MIN_TEMPERATURE_VALUE;
-            Attributes::ColorTempPhysicalMinMireds::Get(endpoint, &tempPhysicalMin);
-            // Avoid potential divide-by-zero in future Kelvin conversions.
-            tempPhysicalMin = std::max(static_cast<uint16_t>(1u), tempPhysicalMin);
+            // Apply valid startup color temp value that is within physical limits of device.
+            // Otherwise, the startup value is outside the device's supported range, and the
+            // existing setting of ColorTemp attribute will be left unchanged (i.e., treated as
+            // if startup color temp was set to null).
+            uint16_t epIndex             = getEndpointIndex(endpoint);
+            MarkAttributeDirty markDirty = SetQuietReportAttribute(quietTemperatureMireds[epIndex], startUpColorTemp.Value(),
+                                                                   false /* isEndOfTransition */, 0);
+            status = Attributes::ColorTemperatureMireds::Set(endpoint, quietTemperatureMireds[epIndex].value().Value(), markDirty);
 
-            uint16_t tempPhysicalMax = MAX_TEMPERATURE_VALUE;
-            Attributes::ColorTempPhysicalMaxMireds::Get(endpoint, &tempPhysicalMax);
-
-            if (tempPhysicalMin <= startUpColorTemp.Value() && startUpColorTemp.Value() <= tempPhysicalMax)
+            if (status == Status::Success)
             {
-                // Apply valid startup color temp value that is within physical limits of device.
-                // Otherwise, the startup value is outside the device's supported range, and the
-                // existing setting of ColorTemp attribute will be left unchanged (i.e., treated as
-                // if startup color temp was set to null).
-                updatedColorTemp = startUpColorTemp.Value();
-                status           = Attributes::ColorTemperatureMireds::Set(endpoint, updatedColorTemp);
+                // Set ColorMode attributes to reflect ColorTemperature.
+                auto updateColorMode = ColorModeEnum::kColorTemperatureMireds;
+                Attributes::ColorMode::Set(endpoint, updateColorMode);
 
-                if (status == Status::Success)
-                {
-                    // Set ColorMode attributes to reflect ColorTemperature.
-                    auto updateColorMode = ColorModeEnum::kColorTemperatureMireds;
-                    Attributes::ColorMode::Set(endpoint, updateColorMode);
-
-                    Attributes::EnhancedColorMode::Set(endpoint, static_cast<EnhancedColorModeEnum>(updateColorMode));
-                }
+                Attributes::EnhancedColorMode::Set(endpoint, static_cast<EnhancedColorModeEnum>(updateColorMode));
             }
         }
     }
@@ -2729,7 +2719,8 @@
  */
 void ColorControlServer::updateTempCommand(EndpointId endpoint)
 {
-    Color16uTransitionState * colorTempTransitionState = getTempTransitionState(endpoint);
+    uint16_t epIndex                                   = getEndpointIndex(endpoint);
+    Color16uTransitionState * colorTempTransitionState = getTempTransitionStateByIndex(epIndex);
     bool isColorTempTransitionDone;
 
     isColorTempTransitionDone = computeNewColor16uValue(colorTempTransitionState);
@@ -2763,7 +2754,9 @@
         scheduleTimerCallbackMs(configureTempEventControl(endpoint), TRANSITION_UPDATE_TIME_MS.count());
     }
 
-    Attributes::ColorTemperatureMireds::Set(endpoint, colorTempTransitionState->currentValue);
+    MarkAttributeDirty markDirty = SetQuietReportAttribute(quietTemperatureMireds[epIndex], colorTempTransitionState->currentValue,
+                                                           isColorTempTransitionDone, colorTempTransitionState->timeRemaining);
+    Attributes::ColorTemperatureMireds::Set(endpoint, quietTemperatureMireds[epIndex].value().Value(), markDirty);
 
     ChipLogProgress(Zcl, "Color Temperature %d", colorTempTransitionState->currentValue);
 
@@ -2882,7 +2875,7 @@
     colorTempTransitionState->lowLimit       = colorTemperatureMinimum;
     colorTempTransitionState->highLimit      = colorTemperatureMaximum;
 
-    SetQuietReportRemainingTime(endpoint, transitionTime);
+    SetQuietReportRemainingTime(endpoint, transitionTime, true /* isNewTransition */);
 
     // kick off the state machine:
     scheduleTimerCallbackMs(configureTempEventControl(endpoint), TRANSITION_UPDATE_TIME_MS.count());
@@ -3005,7 +2998,7 @@
     colorTempTransitionState->lowLimit       = colorTemperatureMinimum;
     colorTempTransitionState->highLimit      = colorTemperatureMaximum;
 
-    SetQuietReportRemainingTime(endpoint, transitionTime);
+    SetQuietReportRemainingTime(endpoint, transitionTime, true /* isNewTransition */);
 
     // kick off the state machine:
     scheduleTimerCallbackMs(configureTempEventControl(endpoint), transitionTime ? TRANSITION_UPDATE_TIME_MS.count() : 0);
@@ -3103,7 +3096,6 @@
  * Utility function used to update a color control attribute which has the quiet reporting quality.
  * matching the following report conditions:
  * - At most once per second, or
- * - At the start of the movement/transition, or
  * - At the end of the movement/transition, or
  * - When it changes from null to any other value and vice versa. (Implicit to the QuieterReportingAttribute class)
  *
@@ -3114,20 +3106,20 @@
  *
  * @param quietReporter: The QuieterReportingAttribute<TYPE> object for the attribute to update.
  * @param newValue: Value to update the attribute with
- * @param isStartOrEndOfTransition: Boolean that indicatse whether the update is occurring at the start or end of a level transition
+ * @param isEndOfTransition: Boolean that indicates whether the update is occurring at the end of a color transition
  * @return MarkAttributeDirty::kYes when the attribute must be marked dirty and be reported. MarkAttributeDirty::kNo when
  * no report is needed.
  */
 template <typename Q, typename V>
 MarkAttributeDirty ColorControlServer::SetQuietReportAttribute(QuieterReportingAttribute<Q> & quietReporter, V newValue,
-                                                               bool isStartOrEndOfTransition, uint16_t transitionTime)
+                                                               bool isEndOfTransition, uint16_t transitionTime)
 {
     AttributeDirtyState dirtyState;
     auto now = System::SystemClock().GetMonotonicTimestamp();
 
-    if (isStartOrEndOfTransition)
+    if (isEndOfTransition)
     {
-        // At the start or end of the movement/transition we must report if the value changed
+        // At the end of the movement/transition we must report if the value changed
         auto predicate = [](const typename QuieterReportingAttribute<Q>::SufficientChangePredicateCandidate &) -> bool {
             return true;
         };
@@ -3157,23 +3149,42 @@
  * @brief
  * Function used to set the remaining time based on quiet reporting conditions.
  * It will update the attribute storage and report the attribute if it is determined dirty.
- * The condition on which the attribute must be reported are defined by the set QuieterReportingPolicyFlags
- * of the quietRemainingTime object and the implicit conditions of the QuieterReportingAttribute class
+ * The conditions on which the attribute must be reported are:
+ * - When it changes from 0 to any value higher than 10, or
+ * - When it changes, with a delta larger than 10, caused by the invoke of a command, or
+ * - When it changes to 0.
  *
  * @param endpoint: Endpoint of the RemainingTime attribute to set
  * @param newRemainingTime: Value to update the RemainingTime attribute with
  * @return Success in setting the attribute value or the IM error code for the failure.
  */
-Status ColorControlServer::SetQuietReportRemainingTime(EndpointId endpoint, uint16_t newRemainingTime)
+Status ColorControlServer::SetQuietReportRemainingTime(EndpointId endpoint, uint16_t newRemainingTime, bool isNewTransition)
 {
-    uint16_t epIndex = getEndpointIndex(endpoint);
-    auto markDirty   = MarkAttributeDirty::kNo;
-    auto now         = System::SystemClock().GetMonotonicTimestamp();
-    // Establish the quiet report condition for the RemainingTime Attribute
-    // The quiet report is by the previously set policies :
-    // - kMarkDirtyOnChangeToFromZero : When the value changes from 0 to any other value and vice versa, or
-    // - kMarkDirtyOnIncrement : When the value increases.
-    if (quietRemainingTime[epIndex].SetValue(newRemainingTime, now) == AttributeDirtyState::kMustReport)
+    uint16_t epIndex           = getEndpointIndex(endpoint);
+    uint16_t lastRemainingTime = quietRemainingTime[epIndex].value().ValueOr(0);
+    auto markDirty             = MarkAttributeDirty::kNo;
+    auto now                   = System::SystemClock().GetMonotonicTimestamp();
+
+    auto predicate =
+        [isNewTransition, lastRemainingTime](
+            const typename QuieterReportingAttribute<uint16_t>::SufficientChangePredicateCandidate & candidate) -> bool {
+        constexpr uint16_t reportDelta = 10;
+        bool isDirty                   = false;
+        if (candidate.newValue.Value() == 0 || (candidate.lastDirtyValue.Value() == 0 && candidate.newValue.Value() > reportDelta))
+        {
+            isDirty = true;
+        }
+        else if (isNewTransition &&
+                 (candidate.newValue.Value() > static_cast<uint32_t>(lastRemainingTime + reportDelta) ||
+                  static_cast<uint32_t>(candidate.newValue.Value() + reportDelta) < lastRemainingTime ||
+                  candidate.newValue.Value() > static_cast<uint32_t>(candidate.lastDirtyValue.Value() + reportDelta)))
+        {
+            isDirty = true;
+        }
+        return isDirty;
+    };
+
+    if (quietRemainingTime[epIndex].SetValue(newRemainingTime, now, predicate) == AttributeDirtyState::kMustReport)
     {
         markDirty = MarkAttributeDirty::kYes;
     }
diff --git a/src/app/clusters/color-control-server/color-control-server.h b/src/app/clusters/color-control-server/color-control-server.h
index 88343e7..422c7f5 100644
--- a/src/app/clusters/color-control-server/color-control-server.h
+++ b/src/app/clusters/color-control-server/color-control-server.h
@@ -203,27 +203,16 @@
 
     template <typename Q, typename V>
     chip::app::MarkAttributeDirty SetQuietReportAttribute(chip::app::QuieterReportingAttribute<Q> & quietReporter, V newValue,
-                                                          bool isStartOrEndOfTransition, uint16_t transitionTime);
-    chip::Protocols::InteractionModel::Status SetQuietReportRemainingTime(chip::EndpointId endpoint, uint16_t newRemainingTime);
+                                                          bool isEndOfTransition, uint16_t transitionTime);
+    chip::Protocols::InteractionModel::Status SetQuietReportRemainingTime(chip::EndpointId endpoint, uint16_t newRemainingTime,
+                                                                          bool isNewTransition = false);
 
 private:
     /**********************************************************
      * Functions Definitions
      *********************************************************/
 
-    ColorControlServer()
-    {
-        for (size_t i = 0; i < kColorControlClusterServerMaxEndpointCount; i++)
-        {
-            // Set the quiet report policies for the RemaininTime Attribute on all endpoint
-            // - kMarkDirtyOnChangeToFromZero : When the value changes from 0 to any other value and vice versa, or
-            // - kMarkDirtyOnIncrement : When the value increases.
-            quietRemainingTime[i]
-                .policy()
-                .Set(chip::app::QuieterReportingPolicyEnum::kMarkDirtyOnIncrement)
-                .Set(chip::app::QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero);
-        }
-    }
+    ColorControlServer() {}
 
     bool shouldExecuteIfOff(chip::EndpointId endpoint, chip::BitMask<chip::app::Clusters::ColorControl::OptionsBitmap> optionMask,
                             chip::BitMask<chip::app::Clusters::ColorControl::OptionsBitmap> optionOverride);
@@ -312,6 +301,7 @@
 
 #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP
     Color16uTransitionState colorTempTransitionStates[kColorControlClusterServerMaxEndpointCount];
+    chip::app::QuieterReportingAttribute<uint16_t> quietTemperatureMireds[kColorControlClusterServerMaxEndpointCount];
 #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP
 
     EmberEventControl eventControls[kColorControlClusterServerMaxEndpointCount];
diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp
index 231a542..c176d6f 100644
--- a/src/app/clusters/level-control/level-control.cpp
+++ b/src/app/clusters/level-control/level-control.cpp
@@ -121,12 +121,12 @@
                         chip::Optional<BitMask<OptionsBitmap>> optionsMask, chip::Optional<BitMask<OptionsBitmap>> optionsOverride);
 
 static void setOnOffValue(EndpointId endpoint, bool onOff);
-static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs);
+static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs, bool isNewTransition = false);
 static bool shouldExecuteIfOff(EndpointId endpoint, CommandId commandId, chip::Optional<chip::BitMask<OptionsBitmap>> optionsMask,
                                chip::Optional<chip::BitMask<OptionsBitmap>> optionsOverride);
 
 static Status SetCurrentLevelQuietReport(EndpointId endpoint, EmberAfLevelControlState * state,
-                                         DataModel::Nullable<uint8_t> newValue, bool isStartOrEndOfTransition);
+                                         DataModel::Nullable<uint8_t> newValue, bool isEndOfTransition);
 
 #if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS
 class DefaultLevelControlSceneHandler : public scenes::DefaultSceneHandlerImpl
@@ -372,23 +372,22 @@
  * while respecting its defined quiet reporting quality:
  * The attribute will be reported:
  * - At most once per second, or
- * - At the start of the movement/transition, or
  * - At the end of the movement/transition, or
  * - When it changes from null to any other value and vice versa.
  *
  * @param endpoint: endpoint on which the currentLevel attribute must be updated.
  * @param state: LevelControlState struct of this given endpoint.
  * @param newValue: Value to update the attribute with
- * @param isStartOrEndOfTransition: Boolean that indicate whether the update is occuring at the start or end of a level transition
+ * @param isEndOfTransition: Boolean that indicate whether the update is occuring at the end of a level transition
  * @return Success in setting the attribute value or the IM error code for the failure.
  */
 static Status SetCurrentLevelQuietReport(EndpointId endpoint, EmberAfLevelControlState * state,
-                                         DataModel::Nullable<uint8_t> newValue, bool isStartOrEndOfTransition)
+                                         DataModel::Nullable<uint8_t> newValue, bool isEndOfTransition)
 {
     AttributeDirtyState dirtyState;
     auto now = System::SystemClock().GetMonotonicTimestamp();
 
-    if (isStartOrEndOfTransition)
+    if (isEndOfTransition)
     {
         // At the start or end of the movement/transition we must report
         auto predicate = [](const decltype(state->quietCurrentLevel)::SufficientChangePredicateCandidate &) -> bool {
@@ -467,7 +466,7 @@
 
     // Are we at the requested level?
     isTransitionEnd = (currentLevel.Value() == state->moveToLevel);
-    status          = SetCurrentLevelQuietReport(endpoint, state, currentLevel, (isTransitionStart || isTransitionEnd));
+    status          = SetCurrentLevelQuietReport(endpoint, state, currentLevel, isTransitionEnd);
     if (status != Status::Success)
     {
         ChipLogProgress(Zcl, "ERR: writing current level %x", to_underlying(status));
@@ -506,12 +505,12 @@
     else
     {
         state->callbackSchedule.runTime = System::SystemClock().GetMonotonicTimestamp() - callbackStartTimestamp;
-        writeRemainingTime(endpoint, static_cast<uint16_t>(state->transitionTimeMs - state->elapsedTimeMs));
+        writeRemainingTime(endpoint, static_cast<uint16_t>(state->transitionTimeMs - state->elapsedTimeMs), isTransitionStart);
         scheduleTimerCallbackMs(endpoint, computeCallbackWaitTimeMs(state->callbackSchedule, state->eventDurationMs));
     }
 }
 
-static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs)
+static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs, bool isNewTransition)
 {
 #ifndef IGNORE_LEVEL_CONTROL_CLUSTER_LEVEL_CONTROL_REMAINING_TIME
     if (emberAfContainsAttribute(endpoint, LevelControl::Id, LevelControl::Attributes::RemainingTime::Id))
@@ -531,16 +530,36 @@
         //
         // This is done to ensure that the attribute, in tenths of a second, only
         // goes to zero when the remaining time in milliseconds is actually zero.
-        uint16_t remainingTimeDs = static_cast<uint16_t>((remainingTimeMs + 99) / 100);
-        auto markDirty           = MarkAttributeDirty::kNo;
-        auto state               = getState(endpoint);
-        auto now                 = System::SystemClock().GetMonotonicTimestamp();
+        auto markDirty             = MarkAttributeDirty::kNo;
+        auto state                 = getState(endpoint);
+        auto now                   = System::SystemClock().GetMonotonicTimestamp();
+        uint16_t remainingTimeDs   = static_cast<uint16_t>((remainingTimeMs + 99) / 100);
+        uint16_t lastRemainingTime = state->quietRemainingTime.value().ValueOr(0);
 
-        // Establish the quiet report condition for the RemainingTime Attribute
-        // The quiet report is determined by the previously set policies:
-        // - kMarkDirtyOnChangeToFromZero : When the value changes from 0 to any other value and vice versa, or
-        // - kMarkDirtyOnIncrement : When the value increases.
-        if (state->quietRemainingTime.SetValue(remainingTimeDs, now) == AttributeDirtyState::kMustReport)
+        // RemainingTime Quiet report conditions:
+        // - When it changes to 0, or
+        // - When it changes from 0 to any value higher than 10, or
+        // - When it changes, with a delta larger than 10, caused by the invoke of a command.
+        auto predicate = [isNewTransition, lastRemainingTime](
+                             const decltype(state->quietRemainingTime)::SufficientChangePredicateCandidate & candidate) -> bool {
+            constexpr uint16_t reportDelta = 10;
+            bool isDirty                   = false;
+            if (candidate.newValue.Value() == 0 ||
+                (candidate.lastDirtyValue.Value() == 0 && candidate.newValue.Value() > reportDelta))
+            {
+                isDirty = true;
+            }
+            else if (isNewTransition &&
+                     (candidate.newValue.Value() > static_cast<uint32_t>(lastRemainingTime + reportDelta) ||
+                      static_cast<uint32_t>(candidate.newValue.Value() + reportDelta) < lastRemainingTime ||
+                      candidate.newValue.Value() > static_cast<uint32_t>(candidate.lastDirtyValue.Value() + reportDelta)))
+            {
+                isDirty = true;
+            }
+            return isDirty;
+        };
+
+        if (state->quietRemainingTime.SetValue(remainingTimeDs, now, predicate) == AttributeDirtyState::kMustReport)
         {
             markDirty = MarkAttributeDirty::kYes;
         }
@@ -1316,7 +1335,7 @@
 
     // Cancel any currently active command.
     cancelEndpointTimerCallback(endpoint);
-    SetCurrentLevelQuietReport(endpoint, state, state->quietCurrentLevel.value(), true /*isStartOrEndOfTransition*/);
+    SetCurrentLevelQuietReport(endpoint, state, state->quietCurrentLevel.value(), true /*isEndOfTransition*/);
     writeRemainingTime(endpoint, 0);
 
 send_default_response:
@@ -1410,7 +1429,7 @@
     {
         // If newValue is OnOff::Commands::On::Id...
         // "Set CurrentLevel to minimum level allowed for the device."
-        status = SetCurrentLevelQuietReport(endpoint, state, minimumLevelAllowedForTheDevice, true /*isStartOrEndOfTransition*/);
+        status = SetCurrentLevelQuietReport(endpoint, state, minimumLevelAllowedForTheDevice, false /*isEndOfTransition*/);
         if (status != Status::Success)
         {
             ChipLogProgress(Zcl, "ERR: reading current level %x", to_underlying(status));
@@ -1453,9 +1472,6 @@
         return;
     }
 
-    state->quietRemainingTime.policy()
-        .Set(QuieterReportingPolicyEnum::kMarkDirtyOnIncrement)
-        .Set(QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero);
     state->minLevel = MATTER_DM_PLUGIN_LEVEL_CONTROL_MINIMUM_LEVEL;
     state->maxLevel = MATTER_DM_PLUGIN_LEVEL_CONTROL_MAXIMUM_LEVEL;
 
@@ -1528,18 +1544,18 @@
                     }
                 }
                 // Otherwise Set the CurrentLevel attribute to its previous value which was already fetch above
-                SetCurrentLevelQuietReport(endpoint, state, currentLevel, true /*isStartOrEndOfTransition*/);
+                SetCurrentLevelQuietReport(endpoint, state, currentLevel, false /*isEndOfTransition*/);
             }
         }
 #endif // IGNORE_LEVEL_CONTROL_CLUSTER_START_UP_CURRENT_LEVEL
        // In any case, we make sure that the respects min/max
         if (currentLevel.IsNull() || currentLevel.Value() < state->minLevel)
         {
-            SetCurrentLevelQuietReport(endpoint, state, state->minLevel, true /*isStartOrEndOfTransition*/);
+            SetCurrentLevelQuietReport(endpoint, state, state->minLevel, false /*isEndOfTransition*/);
         }
         else if (currentLevel.Value() > state->maxLevel)
         {
-            SetCurrentLevelQuietReport(endpoint, state, state->maxLevel, true /*isStartOrEndOfTransition*/);
+            SetCurrentLevelQuietReport(endpoint, state, state->maxLevel, false /*isEndOfTransition*/);
         }
     }