[Level Control] Added ability to disable transitioning and OnOff feature (#23679)

* Added ability to disable transitioning and onoff feature

* Fixes from restyle

* Fixed missing OnOff attribute change

* Only handle OnOff state for off
diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp
index 87f60446..22db98f 100644
--- a/src/app/clusters/level-control/level-control.cpp
+++ b/src/app/clusters/level-control/level-control.cpp
@@ -701,6 +701,7 @@
         actualStepSize    = static_cast<uint8_t>(currentLevel.Value() - state->moveToLevel);
     }
 
+#ifndef IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
     // If the Transition time field takes the value null, then the time taken
     // to move to the new level shall instead be determined by the On/Off
     // Transition Time attribute.  If On/Off Transition Time, which is an
@@ -740,6 +741,12 @@
         // Time) as tenths of a second, but we work in milliseconds.
         state->transitionTimeMs = (transitionTimeDs.Value() * MILLISECOND_TICKS_PER_SECOND / 10);
     }
+#else
+    // Transition is not supported so always use fastest transition time and ignore
+    // both the provided transition time as well as OnOffTransitionTime.
+    emberAfLevelControlClusterPrintln("Device does not support transition, ignoring transition time");
+    state->transitionTimeMs = FASTEST_TRANSITION_TIME_MS;
+#endif // IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
 
     // The duration between events will be the transition time divided by the
     // distance we must move.
@@ -844,6 +851,7 @@
         }
     }
 
+#ifndef IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
     // If the Rate field is null, the device should move at the default move rate, if available,
     // Otherwise, move as fast as possible
     if (rate.IsNull())
@@ -870,6 +878,12 @@
     {
         state->eventDurationMs = MILLISECOND_TICKS_PER_SECOND / rate.Value();
     }
+#else
+    // Transition/rate is not supported so always use fastest transition time and ignore
+    // both the provided transition time as well as OnOffTransitionTime.
+    emberAfLevelControlClusterPrintln("Device does not support transition, ignoring rate");
+    state->eventDurationMs = FASTEST_TRANSITION_TIME_MS;
+#endif // IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
 
     state->transitionTimeMs = difference * state->eventDurationMs;
     state->elapsedTimeMs    = 0;
@@ -979,6 +993,7 @@
         }
     }
 
+#ifndef IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
     // If the Transition Time field is null, the device should move as fast as
     // it is able.
     if (transitionTimeDs.IsNull())
@@ -998,6 +1013,12 @@
             state->transitionTimeMs = (state->transitionTimeMs * actualStepSize / stepSize);
         }
     }
+#else
+    // Transition is not supported so always use fastest transition time and ignore
+    // both the provided transition time as well as OnOffTransitionTime.
+    emberAfLevelControlClusterPrintln("Device does not support transition, ignoring transition time");
+    state->transitionTimeMs = FASTEST_TRANSITION_TIME_MS;
+#endif // IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
 
     // The duration between events will be the transition time divided by the
     // distance we must move.
@@ -1063,6 +1084,20 @@
         return;
     }
 
+    // if the OnOff feature is not supported, the effect on LevelControl is ignored
+    if (!HasFeature(endpoint, chip::app::Clusters::LevelControl::LevelControlFeature::kOnOff))
+    {
+        emberAfLevelControlClusterPrintln("OnOff feature not supported, ignore LevelControlEffect");
+        if (!newValue)
+        {
+            // OnOff server expects LevelControl to handle the OnOff attribute change,
+            // when going to off state. The attribute is set directly rather
+            // than using setOnOff function to avoid misleading comments in log.
+            OnOff::Attributes::OnOff::Set(endpoint, OnOff::Commands::Off::Id);
+        }
+        return;
+    }
+
     uint8_t minimumLevelAllowedForTheDevice = state->minLevel;
 
     // "Temporarily store CurrentLevel."
@@ -1277,4 +1312,13 @@
 
 void emberAfPluginLevelControlClusterServerPostInitCallback(EndpointId endpoint) {}
 
+bool HasFeature(chip::EndpointId endpoint, chip::app::Clusters::LevelControl::LevelControlFeature feature)
+{
+    bool success;
+    uint32_t featureMap;
+    success = (Attributes::FeatureMap::Get(endpoint, &featureMap) == EMBER_ZCL_STATUS_SUCCESS);
+
+    return success ? ((featureMap & to_underlying(feature)) != 0) : false;
+}
+
 void MatterLevelControlPluginServerInitCallback() {}
diff --git a/src/app/clusters/level-control/level-control.h b/src/app/clusters/level-control/level-control.h
index 4abb510..d87d41d 100644
--- a/src/app/clusters/level-control/level-control.h
+++ b/src/app/clusters/level-control/level-control.h
@@ -26,6 +26,7 @@
 
 #include <stdint.h>
 
+#include <app-common/zap-generated/cluster-objects.h>
 #include <app/util/basic-types.h>
 
 /** @brief On/off Cluster Server Post Init
@@ -36,3 +37,5 @@
  * @param endpoint Endpoint that is being initialized  Ver.: always
  */
 void emberAfPluginLevelControlClusterServerPostInitCallback(chip::EndpointId endpoint);
+
+bool HasFeature(chip::EndpointId endpoint, chip::app::Clusters::LevelControl::LevelControlFeature feature);