diff --git a/CMakeLists.txt b/CMakeLists.txt
index dd15e06dac8..afe3f2fc8c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -181,6 +181,7 @@ set(ARDUINO_LIBRARY_Matter_SRCS
   libraries/Matter/src/MatterEndpoints/MatterPressureSensor.cpp
   libraries/Matter/src/MatterEndpoints/MatterOccupancySensor.cpp
   libraries/Matter/src/MatterEndpoints/MatterOnOffPlugin.cpp
+  libraries/Matter/src/MatterEndpoints/MatterThermostat.cpp
   libraries/Matter/src/Matter.cpp)
 
 set(ARDUINO_LIBRARY_PPP_SRCS
diff --git a/libraries/Matter/examples/MatterThermostat/MatterThermostat.ino b/libraries/Matter/examples/MatterThermostat/MatterThermostat.ino
new file mode 100644
index 00000000000..508b508573a
--- /dev/null
+++ b/libraries/Matter/examples/MatterThermostat/MatterThermostat.ino
@@ -0,0 +1,243 @@
+// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+/*
+   This example is an example code that will create a Matter Device which can be
+   commissioned and controlled from a Matter Environment APP.
+   Additionally the ESP32 will send debug messages indicating the Matter activity.
+   Turning DEBUG Level ON may be useful to following Matter Accessory and Controller messages.
+*/
+
+// Matter Manager
+#include <Matter.h>
+#include <WiFi.h>
+
+// List of Matter Endpoints for this Node
+// Matter Thermostat Endpoint
+MatterThermostat SimulatedThermostat;
+
+// WiFi is manually set and started
+const char *ssid = "your-ssid";          // Change this to your WiFi SSID
+const char *password = "your-password";  // Change this to your WiFi password
+
+// set your board USER BUTTON pin here - decommissioning button
+const uint8_t buttonPin = BOOT_PIN;  // Set your pin here. Using BOOT Button.
+
+// Button control - decommision the Matter Node
+uint32_t button_time_stamp = 0;                // debouncing control
+bool button_state = false;                     // false = released | true = pressed
+const uint32_t decommissioningTimeout = 5000;  // keep the button pressed for 5s, or longer, to decommission
+
+// Simulate a system that will activate heating/cooling in addition to a temperature sensor - add your preferred code here
+float getSimulatedTemperature(bool isHeating, bool isCooling) {
+  // read sensor temperature and apply heating/cooling
+  float simulatedTempHWSensor = SimulatedThermostat.getLocalTemperature();
+
+  if (isHeating) {
+    // it will increase to simulate a heating system
+    simulatedTempHWSensor = simulatedTempHWSensor + 0.5;
+  }
+  if (isCooling) {
+    // it will decrease to simulate a colling system
+    simulatedTempHWSensor = simulatedTempHWSensor - 0.5;
+  }
+  // otherwise, it will keep the temperature stable
+  return simulatedTempHWSensor;
+}
+
+void setup() {
+  // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
+  pinMode(buttonPin, INPUT_PULLUP);
+
+  Serial.begin(115200);
+
+  // Manually connect to WiFi
+  WiFi.begin(ssid, password);
+  // Wait for connection
+  while (WiFi.status() != WL_CONNECTED) {
+    delay(500);
+    Serial.print(".");
+  }
+  Serial.println();
+
+  // Simulated Thermostat in COOLING and HEATING mode with Auto Mode to keep the temperature between setpoints
+  // Auto Mode can only be used when the control sequence of operation is Cooling & Heating
+  SimulatedThermostat.begin(MatterThermostat::THERMOSTAT_SEQ_OP_COOLING_HEATING, MatterThermostat::THERMOSTAT_AUTO_MODE_ENABLED);
+
+  // Matter beginning - Last step, after all EndPoints are initialized
+  Matter.begin();
+
+  // Check Matter Accessory Commissioning state, which may change during execution of loop()
+  if (!Matter.isDeviceCommissioned()) {
+    Serial.println("");
+    Serial.println("Matter Node is not commissioned yet.");
+    Serial.println("Initiate the device discovery in your Matter environment.");
+    Serial.println("Commission it to your Matter hub with the manual pairing code or QR code");
+    Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
+    Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
+    // waits for Matter Thermostat Commissioning.
+    uint32_t timeCount = 0;
+    while (!Matter.isDeviceCommissioned()) {
+      delay(100);
+      if ((timeCount++ % 50) == 0) {  // 50*100ms = 5 sec
+        Serial.println("Matter Node not commissioned yet. Waiting for commissioning.");
+      }
+    }
+    Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use.");
+
+    // after commissioning, set initial thermostat parameters
+    // start the thermostat in AUTO mode
+    SimulatedThermostat.setMode(MatterThermostat::THERMOSTAT_MODE_AUTO);
+    // cooling setpoint must be lower than heating setpoint by at least 2.5C (deadband), in auto mode
+    SimulatedThermostat.setCoolingHeatingSetpoints(20.0, 23.00);  // the target cooler and heating setpoint
+    // set the local temperature sensor in Celsius
+    SimulatedThermostat.setLocalTemperature(12.50);
+
+    Serial.println();
+    Serial.printf(
+      "Initial Setpoints are %.01fC to %.01fC with a minimum 2.5C difference\r\n", SimulatedThermostat.getHeatingSetpoint(),
+      SimulatedThermostat.getCoolingSetpoint()
+    );
+    Serial.printf("Auto mode is ON. Initial Temperature of %.01fC \r\n", SimulatedThermostat.getLocalTemperature());
+    Serial.println("Local Temperature Sensor will be simulated every 10 seconds and changed by a simulated heater and cooler to move in between setpoints.");
+  }
+}
+
+// This will simulate the thermostat control system (heating and cooling)
+// User can set a local temperature using the Serial input (type a number and press Enter)
+// New temperature can be an positive or negative temperature in Celsius, between -50C and 50C
+// Initial local temperature is 10C as defined in getSimulatedTemperature() function
+void readSerialForNewTemperature() {
+  static String newTemperatureStr;
+
+  while (Serial.available()) {
+    char c = Serial.read();
+    if (c == '\n' || c == '\r') {
+      if (newTemperatureStr.length() > 0) {
+        // convert the string to a float value
+        float newTemperature = newTemperatureStr.toFloat();
+        // check if the new temperature is valid
+        if (newTemperature >= -50.0 && newTemperature <= 50.0) {
+          // set the new temperature
+          SimulatedThermostat.setLocalTemperature(newTemperature);
+          Serial.printf("New Temperature is %.01fC\r\n", newTemperature);
+        } else {
+          Serial.println("Invalid Temperature value. Please type a number between -50 and 50");
+        }
+        newTemperatureStr = "";
+      }
+    } else {
+      if (c == '+' || c == '-' || (c >= '0' && c <= '9') || c == '.') {
+        newTemperatureStr += c;
+      } else {
+        Serial.println("Invalid character. Please type a number between -50 and 50");
+        newTemperatureStr = "";
+      }
+    }
+  }
+}
+
+// loop will simulate the thermostat control system
+// User can set a local temperature using the Serial input (type a number and press Enter)
+// User can change the thermostat mode using the Matter APP (smartphone)
+// The loop will simulate a heating and cooling system and the associated local temperature change
+void loop() {
+  static uint32_t timeCounter = 0;
+
+  // Simulate the heating and cooling systems
+  static bool isHeating = false;
+  static bool isCooling = false;
+
+  // check if a new temperature is typed in the Serial Monitor
+  readSerialForNewTemperature();
+
+  // simulate thermostat with heating/cooling system and the associated local temperature change, every 10s
+  if (!(timeCounter++ % 20)) {  // delaying for 500ms x 20 = 10s
+    float localTemperature = getSimulatedTemperature(isHeating, isCooling);
+    // Print the current thermostat local temperature value
+    Serial.printf("Current Local Temperature is %.01fC\r\n", localTemperature);
+    SimulatedThermostat.setLocalTemperature(localTemperature);  // publish the new temperature value
+
+    // Simulate the thermostat control system - User has 4 modes: OFF, HEAT, COOL, AUTO
+    switch (SimulatedThermostat.getMode()) {
+      case MatterThermostat::THERMOSTAT_MODE_OFF:
+        // turn off the heating and cooling systems
+        isHeating = false;
+        isCooling = false;
+        break;
+      case MatterThermostat::THERMOSTAT_MODE_AUTO:
+        // User APP has set the thermostat to AUTO mode -- keeping the tempeature between both setpoints
+        // check if the heating system should be turned on or off
+        if (localTemperature < SimulatedThermostat.getHeatingSetpoint() + SimulatedThermostat.getDeadBand()) {
+          // turn on the heating system and turn off the cooling system
+          isHeating = true;
+          isCooling = false;
+        }
+        if (localTemperature > SimulatedThermostat.getCoolingSetpoint() - SimulatedThermostat.getDeadBand()) {
+          // turn off the heating system and turn on the cooling system
+          isHeating = false;
+          isCooling = true;
+        }
+        break;
+      case MatterThermostat::THERMOSTAT_MODE_HEAT:
+        // Simulate the heating system - User has turned the heating system ON
+        isHeating = true;
+        isCooling = false;  // keep the cooling system off as it is in heating mode
+        // when the heating system is in HEATING mode, it will be turned off as soon as the local temperature is above the setpoint
+        if (localTemperature > SimulatedThermostat.getHeatingSetpoint()) {
+          // turn off the heating system
+          isHeating = false;
+        }
+        break;
+      case MatterThermostat::THERMOSTAT_MODE_COOL:
+        // Simulate the cooling system - User has turned the cooling system ON
+        if (SimulatedThermostat.getMode() == MatterThermostat::THERMOSTAT_MODE_COOL) {
+          isCooling = true;
+          isHeating = false;  // keep the heating system off as it is in cooling mode
+          // when the cooling system is in COOLING mode, it will be turned off as soon as the local temperature is bellow the setpoint
+          if (localTemperature < SimulatedThermostat.getCoolingSetpoint()) {
+            // turn off the cooling system
+            isCooling = false;
+          }
+        }
+        break;
+      default: log_e("Invalid Thermostat Mode %d", SimulatedThermostat.getMode());
+    }
+    // Reporting Heating and Cooling status
+    Serial.printf(
+      "\tThermostat Mode: %s >>> Heater is %s -- Cooler is %s\r\n", MatterThermostat::getThermostatModeString(SimulatedThermostat.getMode()),
+      isHeating ? "ON" : "OFF", isCooling ? "ON" : "OFF"
+    );
+  }
+  // Check if the button has been pressed
+  if (digitalRead(buttonPin) == LOW && !button_state) {
+    // deals with button debouncing
+    button_time_stamp = millis();  // record the time while the button is pressed.
+    button_state = true;           // pressed.
+  }
+
+  if (digitalRead(buttonPin) == HIGH && button_state) {
+    button_state = false;  // released
+  }
+
+  // Onboard User Button is kept pressed for longer than 5 seconds in order to decommission matter node
+  uint32_t time_diff = millis() - button_time_stamp;
+  if (button_state && time_diff > decommissioningTimeout) {
+    Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
+    Matter.decommission();
+    button_time_stamp = millis();  // avoid running decommissining again, reboot takes a second or so
+  }
+
+  delay(500);
+}
diff --git a/libraries/Matter/examples/MatterThermostat/ci.json b/libraries/Matter/examples/MatterThermostat/ci.json
new file mode 100644
index 00000000000..556a8a9ee6b
--- /dev/null
+++ b/libraries/Matter/examples/MatterThermostat/ci.json
@@ -0,0 +1,7 @@
+{
+  "fqbn_append": "PartitionScheme=huge_app",
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y",
+    "CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
+  ]
+}
diff --git a/libraries/Matter/keywords.txt b/libraries/Matter/keywords.txt
index 3f40e598ada..a63d9a65acb 100644
--- a/libraries/Matter/keywords.txt
+++ b/libraries/Matter/keywords.txt
@@ -24,6 +24,18 @@ MatterContactSensor	KEYWORD1
 MatterPressureSensor	KEYWORD1
 MatterOccupancySensor	KEYWORD1
 MatterOnOffPlugin	KEYWORD1
+MatterThermostat	KEYWORD1
+ControlSequenceOfOperation_t	KEYWORD1
+ThermostatMode_t	KEYWORD1
+EndPointCB	KEYWORD1
+EndPointHeatingSetpointCB	KEYWORD1
+EndPointCoolingSetpointCB	KEYWORD1
+EndPointTemperatureCB	KEYWORD1
+EndPointModeCB	KEYWORD1
+EndPointSpeedCB	KEYWORD1
+EndPointOnOffCB	KEYWORD1
+EndPointBrightnessCB	KEYWORD1
+EndPointRGBColorCB	KEYWORD1
 
 #######################################
 # Methods and Functions (KEYWORD2)
@@ -78,6 +90,24 @@ setPressure	KEYWORD2
 getPressure	KEYWORD2
 setOccupancy	KEYWORD2
 getOccupancy	KEYWORD2
+getControlSequence	KEYWORD2
+getMinHeatSetpoint	KEYWORD2
+getMaxHeatSetpoint	KEYWORD2
+getMinCoolSetpoint	KEYWORD2
+getMaxCoolSetpoint	KEYWORD2
+getDeadBand	KEYWORD2
+setCoolingSetpoint	KEYWORD2
+getCoolingSetpoint	KEYWORD2
+setHeatingSetpoint	KEYWORD2
+getHeatingSetpoint	KEYWORD2
+setCoolingHeatingSetpoints	KEYWORD2
+setLocalTemperature	KEYWORD2
+getLocalTemperature	KEYWORD2
+getThermostatModeString	KEYWORD2
+onChangeMode	KEYWORD2
+onChangeLocalTemperature	KEYWORD2
+onChangeCoolingSetpoint	KEYWORD2
+onChangeHeatingSetpoint	KEYWORD2
 
 #######################################
 # Constants (LITERAL1)
@@ -104,3 +134,15 @@ FAN_MODE_SEQ_OFF_LOW_MED_HIGH_AUTO	LITERAL1
 FAN_MODE_SEQ_OFF_LOW_HIGH_AUTO	LITERAL1
 FAN_MODE_SEQ_OFF_HIGH_AUTO	LITERAL1
 FAN_MODE_SEQ_OFF_HIGH	LITERAL1
+THERMOSTAT_SEQ_OP_COOLING	LITERAL1
+THERMOSTAT_SEQ_OP_COOLING_REHEAT	LITERAL1
+THERMOSTAT_SEQ_OP_HEATING	LITERAL1
+THERMOSTAT_SEQ_OP_HEATING_REHEAT	LITERAL1
+THERMOSTAT_SEQ_OP_COOLING_HEATING	LITERAL1
+THERMOSTAT_SEQ_OP_COOLING_HEATING_REHEAT	LITERAL1
+THERMOSTAT_MODE_OFF	LITERAL1
+THERMOSTAT_MODE_AUTO	LITERAL1
+THERMOSTAT_MODE_COOL	LITERAL1
+THERMOSTAT_MODE_HEAT	LITERAL1
+THERMOSTAT_AUTO_MODE_DISABLED	LITERAL1
+THERMOSTAT_AUTO_MODE_ENABLED	LITERAL1
diff --git a/libraries/Matter/src/Matter.h b/libraries/Matter/src/Matter.h
index 7fcab363f11..e54ceb47e5e 100644
--- a/libraries/Matter/src/Matter.h
+++ b/libraries/Matter/src/Matter.h
@@ -32,6 +32,7 @@
 #include <MatterEndpoints/MatterPressureSensor.h>
 #include <MatterEndpoints/MatterOccupancySensor.h>
 #include <MatterEndpoints/MatterOnOffPlugin.h>
+#include <MatterEndpoints/MatterThermostat.h>
 
 using namespace esp_matter;
 
@@ -70,6 +71,7 @@ class ArduinoMatter {
   friend class MatterPressureSensor;
   friend class MatterOccupancySensor;
   friend class MatterOnOffPlugin;
+  friend class MatterThermostat;
 
 protected:
   static void _init();
diff --git a/libraries/Matter/src/MatterEndpoints/MatterThermostat.cpp b/libraries/Matter/src/MatterEndpoints/MatterThermostat.cpp
new file mode 100644
index 00000000000..5a68421bd8a
--- /dev/null
+++ b/libraries/Matter/src/MatterEndpoints/MatterThermostat.cpp
@@ -0,0 +1,370 @@
+// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
+//
+// 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 <sdkconfig.h>
+#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
+
+#include <Matter.h>
+#include <MatterEndpoints/MatterThermostat.h>
+
+using namespace esp_matter;
+using namespace esp_matter::endpoint;
+using namespace chip::app::Clusters;
+
+// string helper for the THERMOSTAT MODE
+const char *MatterThermostat::thermostatModeString[5] = {"OFF", "AUTO", "UNKNOWN", "COOL", "HEAT"};
+
+// endpoint for color light device
+namespace esp_matter {
+using namespace cluster;
+namespace endpoint {
+namespace multi_mode_thermostat {
+typedef struct config {
+  cluster::descriptor::config_t descriptor;
+  cluster::identify::config_t identify;
+  cluster::scenes_management::config_t scenes_management;
+  cluster::groups::config_t groups;
+  cluster::thermostat::config_t thermostat;
+} config_t;
+
+uint32_t get_device_type_id() {
+  return ESP_MATTER_THERMOSTAT_DEVICE_TYPE_ID;
+}
+
+uint8_t get_device_type_version() {
+  return ESP_MATTER_THERMOSTAT_DEVICE_TYPE_VERSION;
+}
+
+esp_err_t add(endpoint_t *endpoint, config_t *config) {
+  if (!endpoint) {
+    log_e("Endpoint cannot be NULL");
+    return ESP_ERR_INVALID_ARG;
+  }
+  esp_err_t err = add_device_type(endpoint, get_device_type_id(), get_device_type_version());
+  if (err != ESP_OK) {
+    log_e("Failed to add device type id:%" PRIu32 ",err: %d", get_device_type_id(), err);
+    return err;
+  }
+
+  descriptor::create(endpoint, &(config->descriptor), CLUSTER_FLAG_SERVER);
+  identify::create(endpoint, &(config->identify), CLUSTER_FLAG_SERVER);
+  groups::create(endpoint, &(config->groups), CLUSTER_FLAG_SERVER);
+  uint32_t thermostatFeatures = 0;
+  switch (config->thermostat.control_sequence_of_operation) {
+    case MatterThermostat::THERMOSTAT_SEQ_OP_COOLING:
+    case MatterThermostat::THERMOSTAT_SEQ_OP_COOLING_REHEAT: thermostatFeatures = cluster::thermostat::feature::cooling::get_id(); break;
+    case MatterThermostat::THERMOSTAT_SEQ_OP_HEATING:
+    case MatterThermostat::THERMOSTAT_SEQ_OP_HEATING_REHEAT: thermostatFeatures = cluster::thermostat::feature::heating::get_id(); break;
+    case MatterThermostat::THERMOSTAT_SEQ_OP_COOLING_HEATING:
+    case MatterThermostat::THERMOSTAT_SEQ_OP_COOLING_HEATING_REHEAT:
+      thermostatFeatures = cluster::thermostat::feature::cooling::get_id() | cluster::thermostat::feature::heating::get_id();
+      break;
+  }
+  cluster::thermostat::create(endpoint, &(config->thermostat), CLUSTER_FLAG_SERVER, thermostatFeatures);
+  return ESP_OK;
+}
+
+endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data) {
+  endpoint_t *endpoint = endpoint::create(node, flags, priv_data);
+  add(endpoint, config);
+  return endpoint;
+}
+}  // namespace multi_mode_thermostat
+}  // namespace endpoint
+}  // namespace esp_matter
+
+bool MatterThermostat::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) {
+  bool ret = true;
+  if (!started) {
+    log_e("Matter Thermostat device has not begun.");
+    return false;
+  }
+  log_d("Thermostat Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32);
+
+  if (cluster_id == Thermostat::Id) {
+    switch (attribute_id) {
+      case Thermostat::Attributes::SystemMode::Id:
+        if (_onChangeModeCB != NULL) {
+          ret &= _onChangeModeCB((ThermostatMode_t)val->val.u8);
+        }
+        if (_onChangeCB != NULL) {
+          ret &= _onChangeCB();
+        }
+        if (ret == true) {
+          currentMode = (ThermostatMode_t)val->val.u8;
+          log_v("Thermostat Mode updated to %d", val->val.u8);
+        }
+        break;
+      case Thermostat::Attributes::LocalTemperature::Id:
+        if (_onChangeTemperatureCB != NULL) {
+          ret &= _onChangeTemperatureCB((float)val->val.i16 / 100.00);
+        }
+        if (_onChangeCB != NULL) {
+          ret &= _onChangeCB();
+        }
+        if (ret == true) {
+          localTemperature = val->val.i16;
+          log_v("Local Temperature updated to %.01fC", (float)val->val.i16 / 100.00);
+        }
+        break;
+      case Thermostat::Attributes::OccupiedCoolingSetpoint::Id:
+        if (_onChangeCoolingSetpointCB != NULL) {
+          ret &= _onChangeCoolingSetpointCB((float)val->val.i16 / 100.00);
+        }
+        if (_onChangeCB != NULL) {
+          ret &= _onChangeCB();
+        }
+        if (ret == true) {
+          coolingSetpointTemperature = val->val.i16;
+          log_v("Cooling Setpoint updated to %.01fC", (float)val->val.i16 / 100.00);
+        }
+        break;
+      case Thermostat::Attributes::OccupiedHeatingSetpoint::Id:
+        if (_onChangeHeatingSetpointCB != NULL) {
+          ret &= _onChangeHeatingSetpointCB((float)val->val.i16 / 100.00);
+        }
+        if (_onChangeCB != NULL) {
+          ret &= _onChangeCB();
+        }
+        if (ret == true) {
+          heatingSetpointTemperature = val->val.i16;
+          log_v("Heating Setpoint updated to %.01fC", (float)val->val.i16 / 100.00);
+        }
+        break;
+      default: log_w("Unhandled Thermostat Attribute ID: %u", attribute_id); break;
+    }
+  }
+  return ret;
+}
+
+MatterThermostat::MatterThermostat() {}
+
+MatterThermostat::~MatterThermostat() {
+  end();
+}
+
+bool MatterThermostat::begin(ControlSequenceOfOperation_t _controlSequence, ThermostatAutoMode_t _autoMode) {
+  ArduinoMatter::_init();
+
+  if (getEndPointId() != 0) {
+    log_e("Matter Thermostat with Endpoint Id %d device has already been created.", getEndPointId());
+    return false;
+  }
+
+  // check if auto mode is allowed with the control sequence of operation - only allowed for Cooling & Heating
+  if (_autoMode == THERMOSTAT_AUTO_MODE_ENABLED && _controlSequence != THERMOSTAT_SEQ_OP_COOLING_HEATING
+      && _controlSequence != THERMOSTAT_SEQ_OP_COOLING_HEATING_REHEAT) {
+    log_e("Thermostat in Auto Mode requires a Cooling & Heating Control Sequence of Operation.");
+    return false;
+  }
+
+  const int16_t _localTemperature = 2000;            // initial value to be automatically changed by the Matter Thermostat
+  const int16_t _coolingSetpointTemperature = 2400;  // 24C cooling setpoint
+  const int16_t _heatingSetpointTemperature = 1600;  // 16C heating setpoint
+  const ThermostatMode_t _currentMode = THERMOSTAT_MODE_OFF;
+
+  multi_mode_thermostat::config_t thermostat_config;
+  thermostat_config.thermostat.control_sequence_of_operation = (uint8_t)_controlSequence;
+  thermostat_config.thermostat.cooling.occupied_cooling_setpoint = _coolingSetpointTemperature;
+  thermostat_config.thermostat.heating.occupied_heating_setpoint = _heatingSetpointTemperature;
+  thermostat_config.thermostat.system_mode = (uint8_t)_currentMode;
+  thermostat_config.thermostat.local_temperature = _localTemperature;
+
+  // endpoint handles can be used to add/modify clusters
+  endpoint_t *endpoint = multi_mode_thermostat::create(node::get(), &thermostat_config, ENDPOINT_FLAG_NONE, (void *)this);
+  if (endpoint == nullptr) {
+    log_e("Failed to create Thermostat endpoint");
+    return false;
+  }
+  if (_autoMode == THERMOSTAT_AUTO_MODE_ENABLED) {
+    cluster_t *cluster = cluster::get(endpoint, Thermostat::Id);
+    thermostat_config.thermostat.auto_mode.min_setpoint_dead_band = kDefaultDeadBand;  // fixed by default to 2.5C
+    cluster::thermostat::feature::auto_mode::add(cluster, &thermostat_config.thermostat.auto_mode);
+  }
+
+  controlSequence = _controlSequence;
+  autoMode = _autoMode;
+  coolingSetpointTemperature = _coolingSetpointTemperature;
+  heatingSetpointTemperature = _heatingSetpointTemperature;
+  localTemperature = _localTemperature;
+  currentMode = _currentMode;
+
+  setEndPointId(endpoint::get_id(endpoint));
+  log_i("Thermostat created with endpoint_id %d", getEndPointId());
+  started = true;
+  return true;
+}
+
+void MatterThermostat::end() {
+  started = false;
+}
+
+bool MatterThermostat::setMode(ThermostatMode_t _mode) {
+  if (!started) {
+    log_e("Matter Thermostat device has not begun.");
+    return false;
+  }
+
+  if (autoMode == THERMOSTAT_AUTO_MODE_DISABLED && _mode == THERMOSTAT_MODE_AUTO) {
+    log_e("Thermostat can't set Auto Mode.");
+    return false;
+  }
+  // check if the requested mode is valid based on the control sequence of operation
+  // no restrictions for OFF mode
+  if (_mode != THERMOSTAT_MODE_OFF) {
+    // check HEAT, COOL and AUTO modes
+    switch (controlSequence) {
+      case THERMOSTAT_SEQ_OP_COOLING:
+      case THERMOSTAT_SEQ_OP_COOLING_REHEAT:
+        if (_mode == THERMOSTAT_MODE_HEAT || _mode == THERMOSTAT_MODE_AUTO) {
+          break;
+        }
+        log_e("Invalid Thermostat Mode for Cooling Control Sequence of Operation.");
+        return false;
+      case THERMOSTAT_SEQ_OP_HEATING:
+      case THERMOSTAT_SEQ_OP_HEATING_REHEAT:
+        if (_mode == THERMOSTAT_MODE_COOL || _mode == THERMOSTAT_MODE_AUTO) {
+          break;
+        }
+        log_e("Invalid Thermostat Mode for Heating Control Sequence of Operation.");
+        return false;
+      default:
+        // compiler warning about not handling all enum values
+        break;
+    }
+  }
+
+  // avoid processing if there was no change
+  if (currentMode == _mode) {
+    return true;
+  }
+
+  esp_matter_attr_val_t modeVal = esp_matter_invalid(NULL);
+  if (!getAttributeVal(Thermostat::Id, Thermostat::Attributes::SystemMode::Id, &modeVal)) {
+    log_e("Failed to get Thermostat Mode Attribute.");
+    return false;
+  }
+  if (modeVal.val.u8 != _mode) {
+    modeVal.val.u8 = _mode;
+    bool ret;
+    ret = updateAttributeVal(Thermostat::Id, Thermostat::Attributes::SystemMode::Id, &modeVal);
+    if (!ret) {
+      log_e("Failed to update Thermostat Mode Attribute.");
+      return false;
+    }
+    currentMode = _mode;
+  }
+  log_v("Thermostat Mode set to %d", _mode);
+
+  return true;
+}
+
+bool MatterThermostat::setRawTemperature(int16_t _rawTemperature, uint32_t attribute_id, int16_t *internalValue) {
+  if (!started) {
+    log_e("Matter Thermostat device has not begun.");
+    return false;
+  }
+
+  // avoid processing if there was no change
+  if (*internalValue == _rawTemperature) {
+    return true;
+  }
+
+  esp_matter_attr_val_t temperatureVal = esp_matter_invalid(NULL);
+  if (!getAttributeVal(Thermostat::Id, attribute_id, &temperatureVal)) {
+    log_e("Failed to get Thermostat Temperature or Setpoint Attribute.");
+    return false;
+  }
+  if (temperatureVal.val.i16 != _rawTemperature) {
+    temperatureVal.val.i16 = _rawTemperature;
+    bool ret;
+    ret = updateAttributeVal(Thermostat::Id, attribute_id, &temperatureVal);
+    if (!ret) {
+      log_e("Failed to update Thermostat Temperature or Setpoint Attribute.");
+      return false;
+    }
+    *internalValue = _rawTemperature;
+  }
+  log_v("Temperature set to %.01fC", (float)_rawTemperature / 100.00);
+
+  return true;
+}
+
+bool MatterThermostat::setCoolingHeatingSetpoints(double _setpointHeatingTemperature, double _setpointCollingTemperature) {
+  // at least one of the setpoints must be valid
+  bool settingCooling = _setpointCollingTemperature != (float)0xffff;
+  bool settingHeating = _setpointHeatingTemperature != (float)0xffff;
+  if (!settingCooling && !settingHeating) {
+    log_e("Invalid Setpoints values. Set correctly at least one of them in Celsius.");
+    return false;
+  }
+  int16_t _rawHeatValue = static_cast<int16_t>(_setpointHeatingTemperature * 100.0f);
+  int16_t _rawCoolValue = static_cast<int16_t>(_setpointCollingTemperature * 100.0f);
+
+  // check limits for the setpoints
+  if (settingHeating && (_rawHeatValue < kDefaultMinHeatSetpointLimit || _rawHeatValue > kDefaultMaxHeatSetpointLimit)) {
+    log_e(
+      "Invalid Heating Setpoint value: %.01fC - valid range %d..%d", _setpointHeatingTemperature, kDefaultMinHeatSetpointLimit / 100,
+      kDefaultMaxHeatSetpointLimit / 100
+    );
+    return false;
+  }
+  if (settingCooling && (_rawCoolValue < kDefaultMinCoolSetpointLimit || _rawCoolValue > kDefaultMaxCoolSetpointLimit)) {
+    log_e(
+      "Invalid Cooling Setpoint value: %.01fC - valid range %d..%d", _setpointCollingTemperature, kDefaultMinCoolSetpointLimit / 100,
+      kDefaultMaxCoolSetpointLimit / 100
+    );
+    return false;
+  }
+
+  // AUTO mode requires both setpoints to be valid to each other and respect the deadband
+  if (currentMode == THERMOSTAT_MODE_AUTO) {
+#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
+    float deadband = getDeadBand();
+#endif
+    // only setting Cooling Setpoint
+    if (settingCooling && !settingHeating && _rawCoolValue < (heatingSetpointTemperature + (kDefaultDeadBand * 10))) {
+      log_e(
+        "AutoMode :: Invalid Cooling Setpoint value: %.01fC - must be higher or equal than %.01fC", _setpointCollingTemperature, getHeatingSetpoint() + deadband
+      );
+      return false;
+    }
+    // only setting Heating Setpoint
+    if (!settingCooling && settingHeating && _rawHeatValue > (coolingSetpointTemperature - (kDefaultDeadBand * 10))) {
+      log_e(
+        "AutoMode :: Invalid Heating Setpoint value: %.01fC - must be lower or equal than %.01fC", _setpointHeatingTemperature, getCoolingSetpoint() - deadband
+      );
+      return false;
+    }
+    // setting both setpoints
+    if (settingCooling && settingHeating && (_rawCoolValue <= _rawHeatValue || _rawCoolValue - _rawHeatValue < kDefaultDeadBand * 10.0)) {
+      log_e(
+        "AutoMode :: Error - Heating Setpoint %.01fC must be lower than Cooling Setpoint %.01fC with a minimum difference of %0.1fC",
+        _setpointHeatingTemperature, _setpointCollingTemperature, deadband
+      );
+      return false;
+    }
+  }
+
+  bool ret = true;
+  if (settingCooling) {
+    ret &= setRawTemperature(_rawCoolValue, Thermostat::Attributes::OccupiedCoolingSetpoint::Id, &coolingSetpointTemperature);
+  }
+  if (settingHeating) {
+    ret &= setRawTemperature(_rawHeatValue, Thermostat::Attributes::OccupiedHeatingSetpoint::Id, &heatingSetpointTemperature);
+  }
+  return ret;
+}
+
+#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
diff --git a/libraries/Matter/src/MatterEndpoints/MatterThermostat.h b/libraries/Matter/src/MatterEndpoints/MatterThermostat.h
new file mode 100644
index 00000000000..2d64bdf3b01
--- /dev/null
+++ b/libraries/Matter/src/MatterEndpoints/MatterThermostat.h
@@ -0,0 +1,207 @@
+// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
+//
+// 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 <sdkconfig.h>
+#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
+
+#include <Matter.h>
+#include <MatterEndPoint.h>
+#include <app-common/zap-generated/cluster-enums.h>
+
+using namespace chip::app::Clusters;
+
+class MatterThermostat : public MatterEndPoint {
+public:
+  // clang-format off
+  enum ControlSequenceOfOperation_t {
+    THERMOSTAT_SEQ_OP_COOLING                = (uint8_t) Thermostat::ControlSequenceOfOperationEnum::kCoolingOnly,
+    THERMOSTAT_SEQ_OP_COOLING_REHEAT         = (uint8_t) Thermostat::ControlSequenceOfOperationEnum::kCoolingWithReheat,
+    THERMOSTAT_SEQ_OP_HEATING                = (uint8_t) Thermostat::ControlSequenceOfOperationEnum::kHeatingOnly,
+    THERMOSTAT_SEQ_OP_HEATING_REHEAT         = (uint8_t) Thermostat::ControlSequenceOfOperationEnum::kHeatingWithReheat,
+    THERMOSTAT_SEQ_OP_COOLING_HEATING        = (uint8_t) Thermostat::ControlSequenceOfOperationEnum::kCoolingAndHeating,
+    THERMOSTAT_SEQ_OP_COOLING_HEATING_REHEAT = (uint8_t) Thermostat::ControlSequenceOfOperationEnum::kCoolingAndHeatingWithReheat,
+  };
+
+  enum ThermostatMode_t {
+    THERMOSTAT_MODE_OFF            = (uint8_t) Thermostat::SystemModeEnum::kOff,
+    THERMOSTAT_MODE_AUTO           = (uint8_t) Thermostat::SystemModeEnum::kAuto,
+    THERMOSTAT_MODE_COOL           = (uint8_t) Thermostat::SystemModeEnum::kCool,
+    THERMOSTAT_MODE_HEAT           = (uint8_t) Thermostat::SystemModeEnum::kHeat,
+    THERMOSTAT_MODE_EMERGENCY_HEAT = (uint8_t) Thermostat::SystemModeEnum::kEmergencyHeat,
+    THERMOSTAT_MODE_PRECOOLING     = (uint8_t) Thermostat::SystemModeEnum::kPrecooling,
+    THERMOSTAT_MODE_FAN_ONLY       = (uint8_t) Thermostat::SystemModeEnum::kFanOnly,
+    THERMOSTAT_MODE_DRY            = (uint8_t) Thermostat::SystemModeEnum::kDry,
+    THERMOSTAT_MODE_SLEEP          = (uint8_t) Thermostat::SystemModeEnum::kSleep
+  };
+
+  enum ThermostatAutoMode_t {
+    THERMOSTAT_AUTO_MODE_DISABLED = (uint8_t) Thermostat::SystemModeEnum::kOff,
+    THERMOSTAT_AUTO_MODE_ENABLED  = (uint8_t) Thermostat::SystemModeEnum::kAuto,
+  };
+  // clang-format on
+
+  MatterThermostat();
+  ~MatterThermostat();
+  // begin Matter Thermostat endpoint with initial Operation Mode
+  bool begin(ControlSequenceOfOperation_t controlSequence = THERMOSTAT_SEQ_OP_COOLING, ThermostatAutoMode_t autoMode = THERMOSTAT_AUTO_MODE_DISABLED);
+  // this will stop processing Thermostat Matter events
+  void end();
+
+  // set the Thermostat Mode
+  bool setMode(ThermostatMode_t mode);
+  // get the Thermostat Mode
+  ThermostatMode_t getMode() {
+    return currentMode;
+  }
+  // returns a friendly string for the Fan Mode
+  static const char *getThermostatModeString(uint8_t mode) {
+    return thermostatModeString[mode];
+  }
+
+  // get the Thermostat Control Sequence of Operation
+  ControlSequenceOfOperation_t getControlSequence() {
+    return controlSequence;
+  }
+
+  // get the minimum heating setpoint in 1/100th of a Celsio degree
+  float getMinHeatSetpoint() {
+    return (float)kDefaultMinHeatSetpointLimit / 100.00;
+  }
+  // get the maximum heating setpoint in 1/100th of a Celsio degree
+  float getMaxHeatSetpoint() {
+    return (float)kDefaultMaxHeatSetpointLimit / 100.00;
+  }
+  // get the minimum cooling setpoint in 1/100th of a Celsio degree
+  float getMinCoolSetpoint() {
+    return (float)kDefaultMinCoolSetpointLimit / 100.00;
+  }
+  // get the maximum cooling setpoint in 1/100th of a Celsio degree
+  float getMaxCoolSetpoint() {
+    return (float)kDefaultMaxCoolSetpointLimit / 100.00;
+  }
+  // get the deadband in 1/10th of a Celsio degree
+  float getDeadBand() {
+    return (float)kDefaultDeadBand / 10.00;
+  }
+
+  // generic function for setting the cooling and heating setpoints - checks if the setpoints are valid
+  // it can be used to set both setpoints at the same time or only one of them, by setting the other to (float)0xffff
+  // Heating Setpoint must be lower than Cooling Setpoint
+  // When using AUTO mode the Cooling Setpoint must be higher than Heating Setpoint by at least the 2.5C (deadband)
+  // Thermostat Matter Server will enforce those rules and the Max/Min setpoints limits as in the Matter Specification
+  bool setCoolingHeatingSetpoints(double _setpointHeatingTemperature, double _setpointCollingTemperature);
+
+  // set the heating setpoint in 1/100th of a Celsio degree
+  bool setHeatingSetpoint(double _setpointHeatingTemperature) {
+    return setCoolingHeatingSetpoints((double)0xffff, _setpointHeatingTemperature);
+  }
+  // get the heating setpoint in 1/100th of a Celsio degree
+  double getHeatingSetpoint() {
+    return heatingSetpointTemperature / 100.0;
+  }
+  // set the cooling setpoint in 1/100th of a Celsio degree
+  bool setCoolingSetpoint(double _setpointCollingTemperature) {
+    return setCoolingHeatingSetpoints(_setpointCollingTemperature, (double)0xffff);
+  }
+  // get the cooling setpoint in 1/100th of a Celsio degree
+  double getCoolingSetpoint() {
+    return coolingSetpointTemperature / 100.0;
+  }
+
+  // set the local Thermostat temperature in  Celsio degrees
+  bool setLocalTemperature(double temperature) {
+    // stores up to 1/100th of a Celsio degree precision
+    int16_t rawValue = static_cast<int16_t>(temperature * 100.0f);
+    return setRawTemperature(rawValue, Thermostat::Attributes::LocalTemperature::Id, &localTemperature);
+  }
+  // returns the local Thermostat float temperature with 1/100th of a Celsio degree precision
+  double getLocalTemperature() {
+    return (double)localTemperature / 100.0;
+  }
+
+  // User Callback for whenever the Thermostat Mode is changed by the Matter Controller
+  using EndPointModeCB = std::function<bool(ThermostatMode_t)>;
+  void onChangeMode(EndPointModeCB onChangeCB) {
+    _onChangeModeCB = onChangeCB;
+  }
+
+  // User Callback for whenever the Local Temperature is changed by the Matter Controller
+  using EndPointTemperatureCB = std::function<bool(float)>;
+  void onChangeLocalTemperature(EndPointTemperatureCB onChangeCB) {
+    _onChangeTemperatureCB = onChangeCB;
+  }
+
+  // User Callback for whenever the Cooling or Heating Setpoint is changed by the Matter Controller
+  using EndPointCoolingSetpointCB = std::function<bool(double)>;
+  void onChangeCoolingSetpoint(EndPointCoolingSetpointCB onChangeCB) {
+    _onChangeCoolingSetpointCB = onChangeCB;
+  }
+
+  // User Callback for whenever the Cooling or Heating Setpoint is changed by the Matter Controller
+  using EndPointHeatingSetpointCB = std::function<bool(double)>;
+  void onChangeHeatingSetpoint(EndPointHeatingSetpointCB onChangeCB) {
+    _onChangeHeatingSetpointCB = onChangeCB;
+  }
+
+  // User Callback for whenever any parameter is changed by the Matter Controller
+  // Main parameters are Thermostat Mode, Local Temperature, Cooling Setpoint and Heating Setpoint
+  // Those can be obtained using getMode(), getTemperature(), getCoolingSetpoint() and getHeatingSetpoint()
+  using EndPointCB = std::function<bool(void)>;
+  void onChange(EndPointCB onChangeCB) {
+    _onChangeCB = onChangeCB;
+  }
+
+  // this function is called by Matter internal event processor. It could be overwritten by the application, if necessary.
+  bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val);
+
+protected:
+  bool started = false;
+  // implementation keeps temperature in 1/100th of a Celsio degree
+  int16_t coolingSetpointTemperature = 2400;  // 24C cooling setpoint
+  int16_t localTemperature = 2000;            // 20C local temperature
+  int16_t heatingSetpointTemperature = 1600;  // 16C heating setpoint
+
+  ThermostatMode_t currentMode = THERMOSTAT_MODE_OFF;
+  ControlSequenceOfOperation_t controlSequence = THERMOSTAT_SEQ_OP_COOLING;
+  ThermostatAutoMode_t autoMode = THERMOSTAT_AUTO_MODE_DISABLED;
+
+  EndPointModeCB _onChangeModeCB = NULL;
+  EndPointTemperatureCB _onChangeTemperatureCB = NULL;
+  EndPointCoolingSetpointCB _onChangeCoolingSetpointCB = NULL;
+  EndPointHeatingSetpointCB _onChangeHeatingSetpointCB = NULL;
+  EndPointCB _onChangeCB = NULL;
+
+  // internal function to set the raw temperature value (Matter Cluster)
+  bool setRawTemperature(int16_t _rawTemperature, uint32_t attribute_id, int16_t *internalValue);
+
+  // clang-format off
+  // Default Thermostat values - can't be changed - defined in the Thermostat Cluster Server code
+  static const int16_t kDefaultAbsMinHeatSetpointLimit = 700;  // 7C (44.5 F)
+  static const int16_t kDefaultMinHeatSetpointLimit    = 700;  // 7C (44.5 F)
+  static const int16_t kDefaultAbsMaxHeatSetpointLimit = 3000; // 30C (86 F)
+  static const int16_t kDefaultMaxHeatSetpointLimit    = 3000; // 30C (86 F)
+
+  static const int16_t kDefaultAbsMinCoolSetpointLimit = 1600; // 16C (61 F)
+  static const int16_t kDefaultMinCoolSetpointLimit    = 1600; // 16C (61 F)
+  static const int16_t kDefaultAbsMaxCoolSetpointLimit = 3200; // 32C (90 F)
+  static const int16_t kDefaultMaxCoolSetpointLimit    = 3200; // 32C (90 F)
+
+  static const int8_t  kDefaultDeadBand                = 25; // 2.5C when in AUTO mode
+  // clang-format on
+
+  // string helper for the THERMOSTAT MODE
+  static const char *thermostatModeString[5];
+};
+#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */