[Chef] [Pump] Add OnOff and LevelControl functionality (#38811)

* Set up files for pump

* nit: compilation

* +

* missing include

* +

* Update setpoints onOff

* Fix compilation

* Fix compilation

* Init chef pump

* +

* Setpoint to level update

* compilation fix

* compilation fix

* compilation fix

* compilation fix

* Call handleMoveToLevel on Attribute change

* compilation fix

* Report attribute change on level change

* Max level is 254 not 255

* Debug

* Debug

* Debug

* Fix implementation: Change gLevel to onLevel. This now tracks the targetted on level when device goes from off to on. It is null when device is On. It gets captured when device goes from On to Off.

* compilation fix

* Remove ifdefs

* Update ZAP: Add level contorl cluster

* clean up ifdef

* add ifdefs

* Add anonymous namespace

* Capture default range into constant

* Last set of comments

* Fix NRF break.

* Make ranges realistic

* Fix rev

* OnOff to not update level. Setpoints updated to non-nul when pump is On.

* +

* +

* Set min level to 1 for temperature control cluster

* update docstring postOnOff

* check for kNullLevel in LevelToSetpoint

* Set pump status to RUNNING (32) and ControlMode to Automatic

* Capacity, PumpStatus, and set controlMode attribute

* Restyled by whitespace

* Review comments: Set measured values to 0 when pump isn't running. Check pump status and update only the running bit

* nit: update capacity at initialisation

---------

Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/examples/chef/common/DeviceTypes.h b/examples/chef/common/DeviceTypes.h
index a4f8e1d..9c7dcc1 100644
--- a/examples/chef/common/DeviceTypes.h
+++ b/examples/chef/common/DeviceTypes.h
@@ -30,6 +30,7 @@
 constexpr chip::DeviceTypeId kCookSurfaceDeviceId                  = 0x0077;
 constexpr chip::DeviceTypeId kCooktopDeviceId                      = 0x0078;
 constexpr chip::DeviceTypeId kOvenDeviceId                         = 0x007B;
+constexpr chip::DeviceTypeId kPumpDeviceId                         = 0x0303;
 constexpr chip::DeviceTypeId kRefrigeratorDeviceId                 = 0x0070;
 constexpr chip::DeviceTypeId kTemperatureControlledCabinetDeviceId = 0x0071;
 
diff --git a/examples/chef/common/chef-pump.cpp b/examples/chef/common/chef-pump.cpp
new file mode 100644
index 0000000..89dab20
--- /dev/null
+++ b/examples/chef/common/chef-pump.cpp
@@ -0,0 +1,349 @@
+/*
+ *
+ *    Copyright (c) 2025 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "chef-pump.h"
+#include "DeviceTypes.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
+#include <app/reporting/reporting.h>
+#include <app/util/attribute-storage.h>
+#include <app/util/endpoint-config-api.h>
+#include <lib/support/logging/CHIPLogging.h>
+#include <platform/CHIPDeviceLayer.h>
+
+using namespace chip;
+using namespace chip::app;
+using namespace chip::app::Clusters;
+using chip::Protocols::InteractionModel::Status;
+
+namespace chef {
+namespace pump {
+
+namespace {
+
+constexpr size_t kTemperatureMeasurementCount = MATTER_DM_TEMPERATURE_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT;
+DataModel::Nullable<int16_t> TemperatureRangeMin[kTemperatureMeasurementCount];
+DataModel::Nullable<int16_t> TemperatureRangeMax[kTemperatureMeasurementCount];
+uint16_t getIndexTemperatureMeasurement(EndpointId endpointId)
+{
+    return emberAfGetClusterServerEndpointIndex(endpointId, TemperatureMeasurement::Id, kTemperatureMeasurementCount);
+}
+int16_t kDefaultMinTemperature = 100;
+int16_t kDefaultMaxTemperature = 9000;
+
+constexpr size_t kPressureMeasurementCount = MATTER_DM_PRESSURE_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT;
+DataModel::Nullable<int16_t> PressureRangeMin[kPressureMeasurementCount];
+DataModel::Nullable<int16_t> PressureRangeMax[kPressureMeasurementCount];
+uint16_t getIndexPressureMeasurement(EndpointId endpointId)
+{
+    return emberAfGetClusterServerEndpointIndex(endpointId, PressureMeasurement::Id, kPressureMeasurementCount);
+}
+int16_t kDefaultMinPressure = 30;
+int16_t kDefaultMaxPressure = 10000;
+
+constexpr size_t kFlowMeasurementCount = MATTER_DM_FLOW_MEASUREMENT_CLUSTER_SERVER_ENDPOINT_COUNT;
+DataModel::Nullable<uint16_t> FlowRangeMin[kFlowMeasurementCount];
+DataModel::Nullable<uint16_t> FlowRangeMax[kFlowMeasurementCount];
+uint16_t getIndexFlowMeasurement(EndpointId endpointId)
+{
+    return emberAfGetClusterServerEndpointIndex(endpointId, FlowMeasurement::Id, kFlowMeasurementCount);
+}
+uint16_t kDefaultMinFlow = 1;
+uint16_t kDefaultMaxFlow = 10;
+
+int16_t kMinCapacity = 0;
+int16_t kMaxCapacity = 100;
+
+/**
+ * @brief Sets all setpoints to Max if state is On else NULL.
+ */
+void updateSetPointsOnOff(EndpointId endpointId, bool onOff)
+{
+    uint16_t epIndex;
+
+    epIndex = getIndexTemperatureMeasurement(endpointId);
+    if (epIndex < kTemperatureMeasurementCount)
+    {
+        auto updatedTemperature = onOff ? TemperatureRangeMax[epIndex] : chip::app::DataModel::Nullable<int16_t>(0);
+        TemperatureMeasurement::Attributes::MeasuredValue::Set(endpointId, updatedTemperature);
+        MatterReportingAttributeChangeCallback(endpointId, TemperatureMeasurement::Id,
+                                               TemperatureMeasurement::Attributes::MeasuredValue::Id);
+    }
+
+    epIndex = getIndexPressureMeasurement(endpointId);
+    if (epIndex < kPressureMeasurementCount)
+    {
+        auto updatedPressure = onOff ? PressureRangeMax[epIndex] : chip::app::DataModel::Nullable<int16_t>(0);
+        PressureMeasurement::Attributes::MeasuredValue::Set(endpointId, updatedPressure);
+        MatterReportingAttributeChangeCallback(endpointId, PressureMeasurement::Id,
+                                               PressureMeasurement::Attributes::MeasuredValue::Id);
+    }
+
+    epIndex = getIndexFlowMeasurement(endpointId);
+    if (epIndex < kFlowMeasurementCount)
+    {
+        auto updatedFlow = onOff ? FlowRangeMax[epIndex] : chip::app::DataModel::Nullable<uint16_t>(0);
+        FlowMeasurement::Attributes::MeasuredValue::Set(endpointId, updatedFlow);
+        MatterReportingAttributeChangeCallback(endpointId, FlowMeasurement::Id, FlowMeasurement::Attributes::MeasuredValue::Id);
+    }
+
+    DataModel::Nullable<int16_t> capacity = onOff ? DataModel::Nullable<int16_t>(kMaxCapacity) : DataModel::Nullable<int16_t>(0);
+    PumpConfigurationAndControl::Attributes::Capacity::Set(endpointId, capacity);
+    MatterReportingAttributeChangeCallback(endpointId, PumpConfigurationAndControl::Id,
+                                           PumpConfigurationAndControl::Attributes::Capacity::Id);
+}
+
+constexpr size_t kLevelControlCount = MATTER_DM_LEVEL_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT;
+
+uint16_t getIndexLevelControl(EndpointId endpointId)
+{
+    return emberAfGetClusterServerEndpointIndex(endpointId, LevelControl::Id, kLevelControlCount);
+}
+constexpr uint8_t kMinLevel  = 1;
+constexpr uint8_t kMaxLevel  = 254;
+constexpr uint8_t kNullLevel = 255;
+
+/**
+ * @brief Maps the level (from LevelControl) to a setpoint value within range.
+ */
+template <typename T>
+DataModel::Nullable<T> LevelToSetpoint(DataModel::Nullable<uint8_t> level, DataModel::Nullable<T> RangeMin,
+                                       DataModel::Nullable<T> RangeMax)
+{
+    if (level.IsNull() || level.Value() == kNullLevel || RangeMin.IsNull() || RangeMax.IsNull())
+        return DataModel::NullNullable;
+
+    if (!level.Value())
+    {
+        return DataModel::Nullable<T>(0);
+    }
+
+    return RangeMin.Value() + (RangeMax.Value() - RangeMin.Value()) * std::min(level.ValueOr(0), (uint8_t) 200) / 200;
+}
+
+/**
+ * Updates setpoints based on the current level.
+ */
+void updateSetPointsLevel(EndpointId endpointId, DataModel::Nullable<uint8_t> level)
+{
+    uint16_t epIndex;
+
+    epIndex = getIndexTemperatureMeasurement(endpointId);
+    if (epIndex < kTemperatureMeasurementCount)
+    {
+        DataModel::Nullable<int16_t> updatedTemperature =
+            LevelToSetpoint(level, TemperatureRangeMin[epIndex], TemperatureRangeMax[epIndex]);
+        TemperatureMeasurement::Attributes::MeasuredValue::Set(endpointId, updatedTemperature);
+        MatterReportingAttributeChangeCallback(endpointId, TemperatureMeasurement::Id,
+                                               TemperatureMeasurement::Attributes::MeasuredValue::Id);
+    }
+
+    epIndex = getIndexPressureMeasurement(endpointId);
+    if (epIndex < kPressureMeasurementCount)
+    {
+        DataModel::Nullable<int16_t> updatedPressure = LevelToSetpoint(level, PressureRangeMin[epIndex], PressureRangeMax[epIndex]);
+        PressureMeasurement::Attributes::MeasuredValue::Set(endpointId, updatedPressure);
+        MatterReportingAttributeChangeCallback(endpointId, PressureMeasurement::Id,
+                                               PressureMeasurement::Attributes::MeasuredValue::Id);
+    }
+
+    epIndex = getIndexFlowMeasurement(endpointId);
+    if (epIndex < kFlowMeasurementCount)
+    {
+        DataModel::Nullable<uint16_t> updatedFlow = LevelToSetpoint(level, FlowRangeMin[epIndex], FlowRangeMax[epIndex]);
+        FlowMeasurement::Attributes::MeasuredValue::Set(endpointId, updatedFlow);
+        MatterReportingAttributeChangeCallback(endpointId, FlowMeasurement::Id, FlowMeasurement::Attributes::MeasuredValue::Id);
+    }
+
+    DataModel::Nullable<int16_t> capacity =
+        LevelToSetpoint(level, DataModel::Nullable<int16_t>(kMinCapacity), DataModel::Nullable<int16_t>(kMaxCapacity));
+    PumpConfigurationAndControl::Attributes::Capacity::Set(endpointId, capacity);
+    MatterReportingAttributeChangeCallback(endpointId, PumpConfigurationAndControl::Id,
+                                           PumpConfigurationAndControl::Attributes::Capacity::Id);
+}
+
+CHIP_ERROR setPumpStatus(EndpointId endpoint, uint16_t status)
+{
+
+    Status res = PumpConfigurationAndControl::Attributes::PumpStatus::Set(
+        endpoint, BitMask<PumpConfigurationAndControl::PumpStatusBitmap>(status));
+    VerifyOrReturnLogError(res == Status::Success, CHIP_ERROR_INTERNAL);
+    MatterReportingAttributeChangeCallback(endpoint, PumpConfigurationAndControl::Id,
+                                           PumpConfigurationAndControl::Attributes::PumpStatus::Id);
+    return CHIP_NO_ERROR;
+}
+} // namespace
+
+/**
+ * @brief Post moveToLevel handler. Updates all setpoint values to match current level.
+ */
+void postMoveToLevel(EndpointId endpoint, uint8_t level)
+{
+    ChipLogDetail(DeviceLayer, "[chef-pump] Inside handleMoveToLevel. level = %d", level);
+
+    bool pumpOn = false;
+    OnOff::Attributes::OnOff::Get(endpoint, &pumpOn);
+
+    if (!pumpOn)
+    {
+        ChipLogDetail(DeviceLayer, "[chef-pump] Pump is not on. Setpoints not updated.");
+        return;
+    }
+
+    if (level && level != kNullLevel)
+        updateSetPointsLevel(endpoint, DataModel::Nullable<uint8_t>(level));
+    else
+        updateSetPointsLevel(endpoint, DataModel::Nullable<uint8_t>(0));
+}
+
+/**
+ * @brief Post onOff change handler. Matches setpoints to currentLevel when going from
+ * off to on. Sets setpoints to NULL when going from On to Off.
+ */
+void postOnOff(EndpointId endpoint, bool value)
+{
+    ChipLogDetail(DeviceLayer, "[chef-pump] Inside postOnOff. value: %d", value);
+    uint16_t epIndex = getIndexLevelControl(endpoint);
+    if (epIndex < kLevelControlCount)
+    {
+        if (value) // Off to On
+        {
+            auto level = DataModel::Nullable<uint8_t>(kMaxLevel);
+            LevelControl::Attributes::CurrentLevel::Get(endpoint, level);
+            updateSetPointsLevel(endpoint, level);
+        }
+        else // On to Off
+        {
+            updateSetPointsLevel(endpoint, DataModel::Nullable<uint8_t>(0));
+        }
+    }
+    else
+    {
+        updateSetPointsOnOff(endpoint, value);
+    }
+
+    BitMask<PumpConfigurationAndControl::PumpStatusBitmap> currentStatus;
+    Status res = PumpConfigurationAndControl::Attributes::PumpStatus::Get(endpoint, &currentStatus);
+    VerifyOrReturn(res == Status::Success, ChipLogError(DeviceLayer, "Failed to read pump status."));
+    if (value)
+    {
+        if (!currentStatus.GetField(PumpConfigurationAndControl::PumpStatusBitmap::kRunning))
+        {
+            currentStatus.SetField(PumpConfigurationAndControl::PumpStatusBitmap::kRunning, 1);
+            setPumpStatus(endpoint, currentStatus.Raw());
+        }
+    }
+    else
+    {
+        if (currentStatus.GetField(PumpConfigurationAndControl::PumpStatusBitmap::kRunning))
+        {
+            currentStatus.SetField(PumpConfigurationAndControl::PumpStatusBitmap::kRunning, 0);
+            setPumpStatus(endpoint, currentStatus.Raw());
+        }
+    }
+}
+
+void init()
+{
+    const uint16_t endpointCount = emberAfEndpointCount();
+
+    for (uint16_t endpointIndex = 0; endpointIndex < endpointCount; endpointIndex++)
+    {
+
+        EndpointId endpointId = emberAfEndpointFromIndex(endpointIndex);
+        if (endpointId == kInvalidEndpointId)
+        {
+            continue;
+        }
+
+        if (!chef::DeviceTypes::EndpointHasDeviceType(endpointId, chef::DeviceTypes::kPumpDeviceId))
+        {
+            continue;
+        }
+
+        uint16_t epIndex;
+
+        epIndex = getIndexTemperatureMeasurement(endpointId);
+        if (epIndex < kTemperatureMeasurementCount)
+        {
+            VerifyOrDieWithMsg(TemperatureMeasurement::Attributes::MeasuredValue::SetNull(endpointId) == Status::Success,
+                               DeviceLayer, "Failed to initialize Temperature Measured Value to NULL for Endpoint: %d", endpointId);
+            if (TemperatureMeasurement::Attributes::MinMeasuredValue::Get(endpointId, TemperatureRangeMin[epIndex]) !=
+                    Status::Success ||
+                TemperatureRangeMin[epIndex].IsNull())
+            {
+                TemperatureRangeMin[epIndex].SetNonNull(kDefaultMinTemperature);
+            }
+            if (TemperatureMeasurement::Attributes::MaxMeasuredValue::Get(endpointId, TemperatureRangeMax[epIndex]) !=
+                    Status::Success ||
+                TemperatureRangeMax[epIndex].IsNull())
+            {
+                TemperatureRangeMax[epIndex].SetNonNull(kDefaultMaxTemperature);
+            }
+        }
+
+        epIndex = getIndexPressureMeasurement(endpointId);
+        if (epIndex < kPressureMeasurementCount)
+        {
+            VerifyOrDieWithMsg(PressureMeasurement::Attributes::MeasuredValue::SetNull(endpointId) == Status::Success, DeviceLayer,
+                               "Failed to initialize Pressure Measured Value to NULL for Endpoint: %d", endpointId);
+            if (PressureMeasurement::Attributes::MinMeasuredValue::Get(endpointId, PressureRangeMin[epIndex]) != Status::Success ||
+                PressureRangeMin[epIndex].IsNull())
+            {
+                PressureRangeMin[epIndex].SetNonNull(kDefaultMinPressure);
+            }
+            if (PressureMeasurement::Attributes::MaxMeasuredValue::Get(endpointId, PressureRangeMax[epIndex]) != Status::Success ||
+                PressureRangeMax[epIndex].IsNull())
+            {
+                PressureRangeMax[epIndex].SetNonNull(kDefaultMaxPressure);
+            }
+        }
+
+        epIndex = getIndexFlowMeasurement(endpointId);
+        if (epIndex < kFlowMeasurementCount)
+        {
+            VerifyOrDieWithMsg(FlowMeasurement::Attributes::MeasuredValue::SetNull(endpointId) == Status::Success, DeviceLayer,
+                               "Failed to initialize Flow Measured Value to NULL for Endpoint: %d", endpointId);
+            if (FlowMeasurement::Attributes::MinMeasuredValue::Get(endpointId, FlowRangeMin[epIndex]) != Status::Success ||
+                FlowRangeMin[epIndex].IsNull())
+            {
+                FlowRangeMin[epIndex].SetNonNull(kDefaultMinFlow);
+            }
+            if (FlowMeasurement::Attributes::MaxMeasuredValue::Get(endpointId, FlowRangeMax[epIndex]) != Status::Success ||
+                FlowRangeMax[epIndex].IsNull())
+            {
+                FlowRangeMax[epIndex].SetNonNull(kDefaultMaxFlow);
+            }
+        }
+
+        epIndex = getIndexLevelControl(endpointId);
+        if (epIndex < kLevelControlCount)
+        {
+            VerifyOrDieWithMsg(LevelControl::Attributes::CurrentLevel::Set(endpointId, 0) == Status::Success, DeviceLayer,
+                               "Failed to initialize Current Level to 0 for Endpoint: %d", endpointId);
+        }
+
+        VerifyOrDieWithMsg(OnOff::Attributes::OnOff::Set(endpointId, false) == Status::Success, DeviceLayer,
+                           "Failed to initialize OnOff to false for Endpoint: %d", endpointId);
+        updateSetPointsOnOff(endpointId, false);
+
+        setPumpStatus(endpointId, 0);
+    }
+}
+
+} // namespace pump
+} // namespace chef
diff --git a/examples/chef/common/chef-pump.h b/examples/chef/common/chef-pump.h
new file mode 100644
index 0000000..32e13a9
--- /dev/null
+++ b/examples/chef/common/chef-pump.h
@@ -0,0 +1,36 @@
+/*
+ *
+ *    Copyright (c) 2025 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/util/attribute-metadata.h>
+#include <app/util/config.h>
+#include <protocols/interaction_model/StatusCode.h>
+
+namespace chef {
+namespace pump {
+
+void postMoveToLevel(chip::EndpointId endpoint, uint8_t level);
+
+void postOnOff(chip::EndpointId endpoint, bool value);
+
+void init();
+
+} // namespace pump
+} // namespace chef
diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp
index 4b8da59..e267d6a 100644
--- a/examples/chef/common/stubs.cpp
+++ b/examples/chef/common/stubs.cpp
@@ -40,6 +40,12 @@
 #include "refrigerator-and-temperature-controlled-cabinet-mode/tcc-mode.h"
 #endif // MATTER_DM_PLUGIN_REFRIGERATOR_AND_TEMPERATURE_CONTROLLED_CABINET_MODE_SERVER
 
+#ifdef MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
+#ifdef MATTER_DM_PLUGIN_ON_OFF_SERVER
+#include "chef-pump.h"
+#endif // MATTER_DM_PLUGIN_ON_OFF_SERVER
+#endif // MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
+
 namespace {
 
 // Please refer to https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/namespaces
@@ -278,12 +284,32 @@
         HandleOnOffAttributeChangeForFan(attributePath.mEndpointId, bool(*value));
 #endif // MATTER_DM_PLUGIN_ON_OFF_SERVER
 #endif // MATTER_DM_PLUGIN_FAN_CONTROL_SERVER
+
+#ifdef MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
+#ifdef MATTER_DM_PLUGIN_ON_OFF_SERVER
+        if (chef::DeviceTypes::EndpointHasDeviceType(attributePath.mEndpointId, chef::DeviceTypes::kPumpDeviceId))
+        {
+            chef::pump::postOnOff(attributePath.mEndpointId, bool(*value));
+        }
+#endif // #ifdef MATTER_DM_PLUGIN_ON_OFF_SERVER
+#endif // MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
     }
     else if (clusterId == LevelControl::Id)
     {
         ChipLogProgress(Zcl, "Level Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u",
                         ChipLogValueMEI(attributeId), type, *value, size);
 
+#ifdef MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
+#ifdef MATTER_DM_PLUGIN_ON_OFF_SERVER
+#ifdef MATTER_DM_PLUGIN_LEVEL_CONTROL_SERVER
+        if (chef::DeviceTypes::EndpointHasDeviceType(attributePath.mEndpointId, chef::DeviceTypes::kPumpDeviceId))
+        {
+            chef::pump::postMoveToLevel(attributePath.mEndpointId, *value);
+        }
+#endif // MATTER_DM_PLUGIN_LEVEL_CONTROL_SERVER
+#endif // #ifdef MATTER_DM_PLUGIN_ON_OFF_SERVER
+#endif // MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
+
         // WIP Apply attribute change to Light
     }
 #ifdef MATTER_DM_PLUGIN_FAN_CONTROL_SERVER
@@ -482,6 +508,12 @@
     RefrigeratorTemperatureControlledCabinetInit();
     OvenTemperatureControlledCabinetCooktopCookSurfaceInit();
 
+#ifdef MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
+#ifdef MATTER_DM_PLUGIN_ON_OFF_SERVER
+    chef::pump::init();
+#endif // MATTER_DM_PLUGIN_ON_OFF_SERVER
+#endif // MATTER_DM_PLUGIN_PUMP_CONFIGURATION_AND_CONTROL_SERVER
+
 #ifdef MATTER_DM_PLUGIN_WINDOW_COVERING_SERVER
     ChipLogProgress(NotSpecified, "Initializing WindowCovering cluster delegate.");
     ChefWindowCovering::InitChefWindowCoveringCluster();
diff --git a/examples/chef/devices/rootnode_pump_5f904818cc.matter b/examples/chef/devices/rootnode_pump_5f904818cc.matter
index 7aef8cc..630ac9b 100644
--- a/examples/chef/devices/rootnode_pump_5f904818cc.matter
+++ b/examples/chef/devices/rootnode_pump_5f904818cc.matter
@@ -460,6 +460,130 @@
   command OnWithTimedOff(OnWithTimedOffRequest): DefaultSuccess = 66;
 }
 
+/** Attributes and commands for controlling devices that can be set to a level between fully 'On' and fully 'Off.' */
+cluster LevelControl = 8 {
+  revision 6;
+
+  enum MoveModeEnum : enum8 {
+    kUp = 0;
+    kDown = 1;
+  }
+
+  enum StepModeEnum : enum8 {
+    kUp = 0;
+    kDown = 1;
+  }
+
+  bitmap Feature : bitmap32 {
+    kOnOff = 0x1;
+    kLighting = 0x2;
+    kFrequency = 0x4;
+  }
+
+  bitmap OptionsBitmap : bitmap8 {
+    kExecuteIfOff = 0x1;
+    kCoupleColorTempToLevel = 0x2;
+  }
+
+  readonly attribute nullable int8u currentLevel = 0;
+  readonly attribute optional int16u remainingTime = 1;
+  readonly attribute optional int8u minLevel = 2;
+  readonly attribute optional int8u maxLevel = 3;
+  readonly attribute optional int16u currentFrequency = 4;
+  readonly attribute optional int16u minFrequency = 5;
+  readonly attribute optional int16u maxFrequency = 6;
+  attribute OptionsBitmap options = 15;
+  attribute optional int16u onOffTransitionTime = 16;
+  attribute nullable int8u onLevel = 17;
+  attribute optional nullable int16u onTransitionTime = 18;
+  attribute optional nullable int16u offTransitionTime = 19;
+  attribute optional nullable int8u defaultMoveRate = 20;
+  attribute access(write: manage) optional nullable int8u startUpCurrentLevel = 16384;
+  readonly attribute command_id generatedCommandList[] = 65528;
+  readonly attribute command_id acceptedCommandList[] = 65529;
+  readonly attribute attrib_id attributeList[] = 65531;
+  readonly attribute bitmap32 featureMap = 65532;
+  readonly attribute int16u clusterRevision = 65533;
+
+  request struct MoveToLevelRequest {
+    int8u level = 0;
+    nullable int16u transitionTime = 1;
+    OptionsBitmap optionsMask = 2;
+    OptionsBitmap optionsOverride = 3;
+  }
+
+  request struct MoveRequest {
+    MoveModeEnum moveMode = 0;
+    nullable int8u rate = 1;
+    OptionsBitmap optionsMask = 2;
+    OptionsBitmap optionsOverride = 3;
+  }
+
+  request struct StepRequest {
+    StepModeEnum stepMode = 0;
+    int8u stepSize = 1;
+    nullable int16u transitionTime = 2;
+    OptionsBitmap optionsMask = 3;
+    OptionsBitmap optionsOverride = 4;
+  }
+
+  request struct StopRequest {
+    OptionsBitmap optionsMask = 0;
+    OptionsBitmap optionsOverride = 1;
+  }
+
+  request struct MoveToLevelWithOnOffRequest {
+    int8u level = 0;
+    nullable int16u transitionTime = 1;
+    OptionsBitmap optionsMask = 2;
+    OptionsBitmap optionsOverride = 3;
+  }
+
+  request struct MoveWithOnOffRequest {
+    MoveModeEnum moveMode = 0;
+    nullable int8u rate = 1;
+    OptionsBitmap optionsMask = 2;
+    OptionsBitmap optionsOverride = 3;
+  }
+
+  request struct StepWithOnOffRequest {
+    StepModeEnum stepMode = 0;
+    int8u stepSize = 1;
+    nullable int16u transitionTime = 2;
+    OptionsBitmap optionsMask = 3;
+    OptionsBitmap optionsOverride = 4;
+  }
+
+  request struct StopWithOnOffRequest {
+    OptionsBitmap optionsMask = 0;
+    OptionsBitmap optionsOverride = 1;
+  }
+
+  request struct MoveToClosestFrequencyRequest {
+    int16u frequency = 0;
+  }
+
+  /** Command description for MoveToLevel */
+  command MoveToLevel(MoveToLevelRequest): DefaultSuccess = 0;
+  /** Command description for Move */
+  command Move(MoveRequest): DefaultSuccess = 1;
+  /** Command description for Step */
+  command Step(StepRequest): DefaultSuccess = 2;
+  /** Command description for Stop */
+  command Stop(StopRequest): DefaultSuccess = 3;
+  /** Command description for MoveToLevelWithOnOff */
+  command MoveToLevelWithOnOff(MoveToLevelWithOnOffRequest): DefaultSuccess = 4;
+  /** Command description for MoveWithOnOff */
+  command MoveWithOnOff(MoveWithOnOffRequest): DefaultSuccess = 5;
+  /** Command description for StepWithOnOff */
+  command StepWithOnOff(StepWithOnOffRequest): DefaultSuccess = 6;
+  /** Command description for StopWithOnOff */
+  command StopWithOnOff(StopWithOnOffRequest): DefaultSuccess = 7;
+  /** Change the currrent frequency to the provided one, or a close
+        approximation if the exact provided one is not possible. */
+  command MoveToClosestFrequency(MoveToClosestFrequencyRequest): DefaultSuccess = 8;
+}
+
 /** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */
 cluster Descriptor = 29 {
   revision 3;
@@ -1807,6 +1931,27 @@
     handle command Toggle;
   }
 
+  server cluster LevelControl {
+    ram      attribute currentLevel;
+    ram      attribute minLevel default = 0x01;
+    ram      attribute options default = 0x00;
+    ram      attribute onLevel;
+    callback attribute generatedCommandList;
+    callback attribute acceptedCommandList;
+    callback attribute attributeList;
+    ram      attribute featureMap default = 0;
+    ram      attribute clusterRevision default = 6;
+
+    handle command MoveToLevel;
+    handle command Move;
+    handle command Step;
+    handle command Stop;
+    handle command MoveToLevelWithOnOff;
+    handle command MoveWithOnOff;
+    handle command StepWithOnOff;
+    handle command StopWithOnOff;
+  }
+
   server cluster Descriptor {
     callback attribute deviceTypeList;
     callback attribute serverList;
@@ -1823,15 +1968,12 @@
     ram      attribute maxPressure default = 32767;
     ram      attribute maxSpeed default = 65534;
     ram      attribute maxFlow default = 65534;
-    ram      attribute minConstTemp default = 0;
-    ram      attribute maxConstTemp default = 10000;
-    ram      attribute pumpStatus default = 5;
+    ram      attribute pumpStatus default = 32;
     persist  attribute effectiveOperationMode default = 0;
-    persist  attribute effectiveControlMode default = 5;
+    persist  attribute effectiveControlMode default = 0;
     ram      attribute capacity;
     ram      attribute speed default = 1000;
     persist  attribute operationMode default = 0;
-    persist  attribute controlMode default = 5;
     callback attribute generatedCommandList;
     callback attribute acceptedCommandList;
     callback attribute attributeList;
@@ -1841,19 +1983,19 @@
 
   server cluster TemperatureMeasurement {
     ram      attribute measuredValue default = 6000;
-    ram      attribute minMeasuredValue default = -27315;
-    ram      attribute maxMeasuredValue default = 32767;
+    ram      attribute minMeasuredValue default = 100;
+    ram      attribute maxMeasuredValue default = 9000;
     callback attribute generatedCommandList;
     callback attribute acceptedCommandList;
     callback attribute attributeList;
     ram      attribute featureMap default = 0;
-    ram      attribute clusterRevision default = 1;
+    ram      attribute clusterRevision default = 4;
   }
 
   server cluster PressureMeasurement {
     ram      attribute measuredValue default = 4500;
-    ram      attribute minMeasuredValue default = -32767;
-    ram      attribute maxMeasuredValue default = 32767;
+    ram      attribute minMeasuredValue default = 30;
+    ram      attribute maxMeasuredValue default = 10000;
     callback attribute generatedCommandList;
     callback attribute acceptedCommandList;
     callback attribute attributeList;
@@ -1862,14 +2004,14 @@
   }
 
   server cluster FlowMeasurement {
-    ram      attribute measuredValue default = 50;
-    ram      attribute minMeasuredValue default = 0;
-    ram      attribute maxMeasuredValue default = 65534;
+    ram      attribute measuredValue default = 5;
+    ram      attribute minMeasuredValue default = 1;
+    ram      attribute maxMeasuredValue default = 10;
     callback attribute generatedCommandList;
     callback attribute acceptedCommandList;
     callback attribute attributeList;
     ram      attribute featureMap default = 0;
-    ram      attribute clusterRevision default = 1;
+    ram      attribute clusterRevision default = 3;
   }
 }
 
diff --git a/examples/chef/devices/rootnode_pump_5f904818cc.zap b/examples/chef/devices/rootnode_pump_5f904818cc.zap
index a457a21..663f96e 100644
--- a/examples/chef/devices/rootnode_pump_5f904818cc.zap
+++ b/examples/chef/devices/rootnode_pump_5f904818cc.zap
@@ -2495,6 +2495,226 @@
           ]
         },
         {
+          "name": "Level Control",
+          "code": 8,
+          "mfgCode": null,
+          "define": "LEVEL_CONTROL_CLUSTER",
+          "side": "server",
+          "enabled": 1,
+          "commands": [
+            {
+              "name": "MoveToLevel",
+              "code": 0,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "Move",
+              "code": 1,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "Step",
+              "code": 2,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "Stop",
+              "code": 3,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "MoveToLevelWithOnOff",
+              "code": 4,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "MoveWithOnOff",
+              "code": 5,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "StepWithOnOff",
+              "code": 6,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "StopWithOnOff",
+              "code": 7,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            }
+          ],
+          "attributes": [
+            {
+              "name": "CurrentLevel",
+              "code": 0,
+              "mfgCode": null,
+              "side": "server",
+              "type": "int8u",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "MinLevel",
+              "code": 2,
+              "mfgCode": null,
+              "side": "server",
+              "type": "int8u",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "0x01",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "Options",
+              "code": 15,
+              "mfgCode": null,
+              "side": "server",
+              "type": "OptionsBitmap",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "0x00",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "OnLevel",
+              "code": 17,
+              "mfgCode": null,
+              "side": "server",
+              "type": "int8u",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "GeneratedCommandList",
+              "code": 65528,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "AcceptedCommandList",
+              "code": 65529,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "AttributeList",
+              "code": 65531,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": null,
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "FeatureMap",
+              "code": 65532,
+              "mfgCode": null,
+              "side": "server",
+              "type": "bitmap32",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "0",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "ClusterRevision",
+              "code": 65533,
+              "mfgCode": null,
+              "side": "server",
+              "type": "int16u",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "6",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            }
+          ]
+        },
+        {
           "name": "Descriptor",
           "code": 29,
           "mfgCode": null,
@@ -2705,38 +2925,6 @@
               "reportableChange": 0
             },
             {
-              "name": "MinConstTemp",
-              "code": 11,
-              "mfgCode": null,
-              "side": "server",
-              "type": "int16s",
-              "included": 1,
-              "storageOption": "RAM",
-              "singleton": 0,
-              "bounded": 0,
-              "defaultValue": "0",
-              "reportable": 1,
-              "minInterval": 1,
-              "maxInterval": 65534,
-              "reportableChange": 0
-            },
-            {
-              "name": "MaxConstTemp",
-              "code": 12,
-              "mfgCode": null,
-              "side": "server",
-              "type": "int16s",
-              "included": 1,
-              "storageOption": "RAM",
-              "singleton": 0,
-              "bounded": 0,
-              "defaultValue": "10000",
-              "reportable": 1,
-              "minInterval": 1,
-              "maxInterval": 65534,
-              "reportableChange": 0
-            },
-            {
               "name": "PumpStatus",
               "code": 16,
               "mfgCode": null,
@@ -2746,7 +2934,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "5",
+              "defaultValue": "32",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -2778,7 +2966,7 @@
               "storageOption": "NVM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "5",
+              "defaultValue": "0",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -2795,7 +2983,7 @@
               "singleton": 0,
               "bounded": 0,
               "defaultValue": null,
-              "reportable": 0,
+              "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
               "reportableChange": 0
@@ -2833,22 +3021,6 @@
               "reportableChange": 0
             },
             {
-              "name": "ControlMode",
-              "code": 33,
-              "mfgCode": null,
-              "side": "server",
-              "type": "ControlModeEnum",
-              "included": 1,
-              "storageOption": "NVM",
-              "singleton": 0,
-              "bounded": 0,
-              "defaultValue": "5",
-              "reportable": 1,
-              "minInterval": 1,
-              "maxInterval": 65534,
-              "reportableChange": 0
-            },
-            {
               "name": "GeneratedCommandList",
               "code": 65528,
               "mfgCode": null,
@@ -2964,7 +3136,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "-27315",
+              "defaultValue": "100",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -2980,7 +3152,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "32767",
+              "defaultValue": "9000",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -3060,7 +3232,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "1",
+              "defaultValue": "4",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -3102,7 +3274,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "-32767",
+              "defaultValue": "30",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -3118,7 +3290,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "32767",
+              "defaultValue": "10000",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -3224,7 +3396,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "50",
+              "defaultValue": "5",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -3240,7 +3412,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "0",
+              "defaultValue": "1",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -3256,7 +3428,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "65534",
+              "defaultValue": "10",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
@@ -3336,7 +3508,7 @@
               "storageOption": "RAM",
               "singleton": 0,
               "bounded": 0,
-              "defaultValue": "1",
+              "defaultValue": "3",
               "reportable": 1,
               "minInterval": 1,
               "maxInterval": 65534,
diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn
index b82ae23..7a7a20c 100644
--- a/examples/chef/linux/BUILD.gn
+++ b/examples/chef/linux/BUILD.gn
@@ -49,6 +49,7 @@
     "${project_dir}/common/chef-laundry-washer-controls-delegate-impl.cpp",
     "${project_dir}/common/chef-laundry-washer-mode.cpp",
     "${project_dir}/common/chef-operational-state-delegate-impl.cpp",
+    "${project_dir}/common/chef-pump.cpp",
     "${project_dir}/common/chef-rpc-actions-worker.cpp",
     "${project_dir}/common/chef-rvc-mode-delegate.cpp",
     "${project_dir}/common/chef-rvc-operational-state-delegate.cpp",
diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt
index f71734f..7c95021 100644
--- a/examples/chef/nrfconnect/CMakeLists.txt
+++ b/examples/chef/nrfconnect/CMakeLists.txt
@@ -87,6 +87,7 @@
     ${CHEF}/common/chef-dishwasher-alarm-delegate-impl.cpp
     ${CHEF}/common/chef-dishwasher-mode-delegate-impl.cpp
     ${CHEF}/common/chef-operational-state-delegate-impl.cpp
+    ${CHEF}/common/chef-pump.cpp
     ${CHEF}/common/chef-rpc-actions-worker.cpp
     ${CHEF}/common/chef-rvc-mode-delegate.cpp
     ${CHEF}/common/chef-rvc-operational-state-delegate.cpp