Add Thermostat EP to Air Purifier Example (#31771)

* Adding example thermostat manager

* Integrating thermostat-manager into the Air Purifier Manager and adding to each build

* Restyled by whitespace

* Updating readme's for each example

* Added readme to common folder to outline the PICS implemented as might be useful for anyone trying to quickly interpret functionality

* Added missing include for std::function

* adding thermostat-manager to TI build

---------

Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/examples/air-purifier-app/air-purifier-common/README.md b/examples/air-purifier-app/air-purifier-common/README.md
new file mode 100644
index 0000000..2ed26ca
--- /dev/null
+++ b/examples/air-purifier-app/air-purifier-common/README.md
@@ -0,0 +1,353 @@
+# CHIP Air Purifier Example
+
+This example implements the following PICS:
+
+```
+# Fan Control
+FAN.S=1
+FAN.C=0
+FAN.S.F00=1
+FAN.S.F01=1
+FAN.S.F02=1
+FAN.S.F03=1
+FAN.S.F04=1
+FAN.S.F05=1
+FAN.S.A0000=1
+FAN.S.A0001=1
+FAN.S.A0002=1
+FAN.S.A0003=1
+FAN.S.A0004=1
+FAN.S.A0005=1
+FAN.S.A0006=1
+FAN.S.A0007=1
+FAN.S.A0008=1
+FAN.S.A0009=1
+FAN.S.A000A=1
+FAN.S.A000B=1
+FAN.S.C00.Rsp=1
+
+# HEPA Filter Monitoring Cluster
+HEPAFREMON.S=1
+HEPAFREMON.C=0
+HEPAFREMON.S.F00=1
+HEPAFREMON.S.F01=1
+HEPAFREMON.S.F02=1
+HEPAFREMON.S.A0000=1
+HEPAFREMON.S.A0001=1
+HEPAFREMON.S.A0002=1
+HEPAFREMON.S.A0003=1
+HEPAFREMON.S.A0004=1
+HEPAFREMON.S.A0005=1
+HEPAFREMON.S.C00.Rsp=1
+
+# Activated Carbon Filter Monitoring Cluster
+ACFREMON.S=1
+ACFREMON.C=0
+ACFREMON.S.F00=1
+ACFREMON.S.F01=1
+ACFREMON.S.F02=1
+ACFREMON.S.A0000=1
+ACFREMON.S.A0001=1
+ACFREMON.S.A0002=1
+ACFREMON.S.A0003=1
+ACFREMON.S.A0004=1
+ACFREMON.S.A0005=1
+ACFREMON.S.C00.Rsp=1
+
+# Air Quality Cluster
+AIRQUAL.C=0
+AIRQUAL.S=1
+AIRQUAL.S.F00=1
+AIRQUAL.S.F01=1
+AIRQUAL.S.F02=1
+AIRQUAL.S.F03=1
+AIRQUAL.S.A0000=1
+AIRQUAL.M.AirQualityChange=0
+
+# Concentration Measurement CLusters
+CDOCONC.C=0
+CDOCONC.S=1
+CDOCONC.S.F00=1
+CDOCONC.S.F01=1
+CDOCONC.S.F02=1
+CDOCONC.S.F03=1
+CDOCONC.S.F04=1
+CDOCONC.S.F05=1
+CDOCONC.S.A0000=1
+CDOCONC.S.A0001=1
+CDOCONC.S.A0002=1
+CDOCONC.S.A0003=1
+CDOCONC.S.A0004=1
+CDOCONC.S.A0005=1
+CDOCONC.S.A0006=1
+CDOCONC.S.A0007=1
+CDOCONC.S.A0008=1
+CDOCONC.S.A0009=1
+CDOCONC.S.A000a=1
+
+CMOCONC.C=0
+CMOCONC.S=1
+CMOCONC.S.F00=1
+CMOCONC.S.F01=1
+CMOCONC.S.F02=1
+CMOCONC.S.F03=1
+CMOCONC.S.F04=1
+CMOCONC.S.F05=1
+CMOCONC.S.A0000=1
+CMOCONC.S.A0001=1
+CMOCONC.S.A0002=1
+CMOCONC.S.A0003=1
+CMOCONC.S.A0004=1
+CMOCONC.S.A0005=1
+CMOCONC.S.A0006=1
+CMOCONC.S.A0007=1
+CMOCONC.S.A0008=1
+CMOCONC.S.A0009=1
+CMOCONC.S.A000a=1
+
+NDOCONC.C=0
+NDOCONC.S=1
+NDOCONC.S.F00=1
+NDOCONC.S.F01=1
+NDOCONC.S.F02=1
+NDOCONC.S.F03=1
+NDOCONC.S.F04=1
+NDOCONC.S.F05=1
+NDOCONC.S.A0000=1
+NDOCONC.S.A0001=1
+NDOCONC.S.A0002=1
+NDOCONC.S.A0003=1
+NDOCONC.S.A0004=1
+NDOCONC.S.A0005=1
+NDOCONC.S.A0006=1
+NDOCONC.S.A0007=1
+NDOCONC.S.A0008=1
+NDOCONC.S.A0009=1
+NDOCONC.S.A000a=1
+
+OZCONC.C=0
+OZCONC.S=1
+OZCONC.S.F00=1
+OZCONC.S.F01=1
+OZCONC.S.F02=1
+OZCONC.S.F03=1
+OZCONC.S.F04=1
+OZCONC.S.F05=1
+OZCONC.S.A0000=1
+OZCONC.S.A0001=1
+OZCONC.S.A0002=1
+OZCONC.S.A0003=1
+OZCONC.S.A0004=1
+OZCONC.S.A0005=1
+OZCONC.S.A0006=1
+OZCONC.S.A0007=1
+OZCONC.S.A0008=1
+OZCONC.S.A0009=1
+OZCONC.S.A000a=1
+
+PMICONC.C=0
+PMICONC.S=1
+PMICONC.S.F00=1
+PMICONC.S.F01=1
+PMICONC.S.F02=1
+PMICONC.S.F03=1
+PMICONC.S.F04=1
+PMICONC.S.F05=1
+PMICONC.S.A0000=1
+PMICONC.S.A0001=1
+PMICONC.S.A0002=1
+PMICONC.S.A0003=1
+PMICONC.S.A0004=1
+PMICONC.S.A0005=1
+PMICONC.S.A0006=1
+PMICONC.S.A0007=1
+PMICONC.S.A0008=1
+PMICONC.S.A0009=1
+PMICONC.S.A000a=1
+
+FLDCONC.C=0
+FLDCONC.S=1
+FLDCONC.S.F00=1
+FLDCONC.S.F01=1
+FLDCONC.S.F02=1
+FLDCONC.S.F03=1
+FLDCONC.S.F04=1
+FLDCONC.S.F05=1
+FLDCONC.S.A0000=1
+FLDCONC.S.A0001=1
+FLDCONC.S.A0002=1
+FLDCONC.S.A0003=1
+FLDCONC.S.A0004=1
+FLDCONC.S.A0005=1
+FLDCONC.S.A0006=1
+FLDCONC.S.A0007=1
+FLDCONC.S.A0008=1
+FLDCONC.S.A0009=1
+FLDCONC.S.A000a=1
+
+PMHCONC.C=0
+PMHCONC.S=1
+PMHCONC.S.F00=1
+PMHCONC.S.F01=1
+PMHCONC.S.F02=1
+PMHCONC.S.F03=1
+PMHCONC.S.F04=1
+PMHCONC.S.F05=1
+PMHCONC.S.A0000=1
+PMHCONC.S.A0001=1
+PMHCONC.S.A0002=1
+PMHCONC.S.A0003=1
+PMHCONC.S.A0004=1
+PMHCONC.S.A0005=1
+PMHCONC.S.A0006=1
+PMHCONC.S.A0007=1
+PMHCONC.S.A0008=1
+PMHCONC.S.A0009=1
+PMHCONC.S.A000a=1
+
+PMKCONC.C=0
+PMKCONC.S=1
+PMKCONC.S.F00=1
+PMKCONC.S.F01=1
+PMKCONC.S.F02=1
+PMKCONC.S.F03=1
+PMKCONC.S.F04=1
+PMKCONC.S.F05=1
+PMKCONC.S.A0000=1
+PMKCONC.S.A0001=1
+PMKCONC.S.A0002=1
+PMKCONC.S.A0003=1
+PMKCONC.S.A0004=1
+PMKCONC.S.A0005=1
+PMKCONC.S.A0006=1
+PMKCONC.S.A0007=1
+PMKCONC.S.A0008=1
+PMKCONC.S.A0009=1
+PMKCONC.S.A000a=1
+
+TVOCCONC.C=0
+TVOCCONC.S=1
+TVOCCONC.S.F00=1
+TVOCCONC.S.F01=1
+TVOCCONC.S.F02=1
+TVOCCONC.S.F03=1
+TVOCCONC.S.F04=1
+TVOCCONC.S.F05=1
+TVOCCONC.S.A0000=1
+TVOCCONC.S.A0001=1
+TVOCCONC.S.A0002=1
+TVOCCONC.S.A0003=1
+TVOCCONC.S.A0004=1
+TVOCCONC.S.A0005=1
+TVOCCONC.S.A0006=1
+TVOCCONC.S.A0007=1
+TVOCCONC.S.A0008=1
+TVOCCONC.S.A0009=1
+TVOCCONC.S.A000a=1
+
+RNCONC.C=0
+RNCONC.S=1
+RNCONC.S.F00=1
+RNCONC.S.F01=1
+RNCONC.S.F02=1
+RNCONC.S.F03=1
+RNCONC.S.F04=1
+RNCONC.S.F05=1
+RNCONC.S.A0000=1
+RNCONC.S.A0001=1
+RNCONC.S.A0002=1
+RNCONC.S.A0003=1
+RNCONC.S.A0004=1
+RNCONC.S.A0005=1
+RNCONC.S.A0006=1
+RNCONC.S.A0007=1
+RNCONC.S.A0008=1
+RNCONC.S.A0009=1
+RNCONC.S.A000a=1
+
+# Temperature Measurement Cluster
+TMP.S=1
+TMP.S.A0000=1
+TMP.S.A0001=1
+TMP.S.A0002=1
+TMP.S.A0003=1
+TMP.M.ManuallyControlled=0
+
+# Relative Humidity Cluster
+RH.S=1
+RH.S.A0000=1
+RH.S.A0001=1
+RH.S.A0002=1
+RH.S.A0003=1
+RH.M.ManuallyControlled=0
+
+# Thermostat Cluster
+TSTAT.S = 1
+TSTAT.S.F00 = 1
+TSTAT.S.F01 = 0
+TSTAT.S.F02 = 0
+TSTAT.S.F03 = 0
+TSTAT.S.F04 = 0
+TSTAT.S.F05 = 0
+TSTAT.S.F06 = 0
+
+TSTAT.S.A0000 = 1
+TSTAT.S.A0001 = 0
+TSTAT.S.A0002 = 0
+TSTAT.S.A0003 = 1
+TSTAT.S.A0004 = 1
+TSTAT.S.A0005 = 0
+TSTAT.S.A0006 = 0
+TSTAT.S.A0007 = 0
+TSTAT.S.A0008 = 0
+TSTAT.S.A0009 = 0
+TSTAT.S.A0010 = 0
+TSTAT.S.A0011 = 0
+TSTAT.S.A0012 = 1
+TSTAT.S.A0013 = 0
+TSTAT.S.A0014 = 0
+TSTAT.S.A0015 = 0
+TSTAT.S.A0016 = 0
+TSTAT.S.A0017 = 0
+TSTAT.S.A0018 = 0
+TSTAT.S.A0019 = 0
+TSTAT.S.A001a = 0
+TSTAT.S.A001b = 1
+TSTAT.S.A001c = 1
+TSTAT.S.A001d = 0
+TSTAT.S.A001e = 0
+TSTAT.S.A0020 = 0
+TSTAT.S.A0021 = 0
+TSTAT.S.A0022 = 0
+TSTAT.S.A0023 = 0
+TSTAT.S.A0024 = 0
+TSTAT.S.A0025 = 0
+TSTAT.S.A0029 = 1
+TSTAT.S.A0030 = 0
+TSTAT.S.A0031 = 0
+TSTAT.S.A0032 = 0
+TSTAT.S.A0034 = 0
+TSTAT.S.A0035 = 0
+TSTAT.S.A0036 = 0
+TSTAT.S.A0037 = 0
+TSTAT.S.A0038 = 0
+TSTAT.S.A0039 = 0
+TSTAT.S.A003a = 0
+TSTAT.S.A0040 = 0
+TSTAT.S.A0041 = 0
+TSTAT.S.A0042 = 0
+TSTAT.S.A0043 = 0
+TSTAT.S.A0044 = 0
+TSTAT.S.A0045 = 0
+TSTAT.S.A0046 = 0
+TSTAT.S.A0047 = 0
+TSTAT.S.M.MinSetpointDeadBandWritable = 0
+TSTAT.S.M.HVACSystemTypeConfigurationWritable = 0
+
+# Server Commands
+TSTAT.S.C00.Rsp = 1
+TSTAT.S.C01.Rsp = 0
+TSTAT.S.C02.Rsp = 0
+TSTAT.S.C03.Rsp = 0
+TSTAT.S.C04.Rsp = 0
+```
diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter
index 33de783..ac6dc5a 100644
--- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter
+++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter
@@ -1207,6 +1207,377 @@
   command ResetCondition(): DefaultSuccess = 0;
 }
 
+/** An interface for configuring and controlling the functionality of a thermostat. */
+cluster Thermostat = 513 {
+  revision 6;
+
+  enum ACCapacityFormatEnum : enum8 {
+    kBTUh = 0;
+  }
+
+  enum ACCompressorTypeEnum : enum8 {
+    kUnknown = 0;
+    kT1 = 1;
+    kT2 = 2;
+    kT3 = 3;
+  }
+
+  enum ACLouverPositionEnum : enum8 {
+    kClosed = 1;
+    kOpen = 2;
+    kQuarter = 3;
+    kHalf = 4;
+    kThreeQuarters = 5;
+  }
+
+  enum ACRefrigerantTypeEnum : enum8 {
+    kUnknown = 0;
+    kR22 = 1;
+    kR410a = 2;
+    kR407c = 3;
+  }
+
+  enum ACTypeEnum : enum8 {
+    kUnknown = 0;
+    kCoolingFixed = 1;
+    kHeatPumpFixed = 2;
+    kCoolingInverter = 3;
+    kHeatPumpInverter = 4;
+  }
+
+  enum ControlSequenceOfOperationEnum : enum8 {
+    kCoolingOnly = 0;
+    kCoolingWithReheat = 1;
+    kHeatingOnly = 2;
+    kHeatingWithReheat = 3;
+    kCoolingAndHeating = 4;
+    kCoolingAndHeatingWithReheat = 5;
+  }
+
+  enum PresetScenarioEnum : enum8 {
+    kUnspecified = 0;
+    kOccupied = 1;
+    kUnoccupied = 2;
+    kSleep = 3;
+    kWake = 4;
+    kVacation = 5;
+    kUserDefined = 6;
+  }
+
+  enum SetpointChangeSourceEnum : enum8 {
+    kManual = 0;
+    kSchedule = 1;
+    kExternal = 2;
+  }
+
+  enum SetpointRaiseLowerModeEnum : enum8 {
+    kHeat = 0;
+    kCool = 1;
+    kBoth = 2;
+  }
+
+  enum StartOfWeekEnum : enum8 {
+    kSunday = 0;
+    kMonday = 1;
+    kTuesday = 2;
+    kWednesday = 3;
+    kThursday = 4;
+    kFriday = 5;
+    kSaturday = 6;
+  }
+
+  enum SystemModeEnum : enum8 {
+    kOff = 0;
+    kAuto = 1;
+    kCool = 3;
+    kHeat = 4;
+    kEmergencyHeat = 5;
+    kPrecooling = 6;
+    kFanOnly = 7;
+    kDry = 8;
+    kSleep = 9;
+  }
+
+  enum TemperatureSetpointHoldEnum : enum8 {
+    kSetpointHoldOff = 0;
+    kSetpointHoldOn = 1;
+  }
+
+  enum ThermostatRunningModeEnum : enum8 {
+    kOff = 0;
+    kCool = 3;
+    kHeat = 4;
+  }
+
+  bitmap ACErrorCodeBitmap : bitmap32 {
+    kCompressorFail = 0x1;
+    kRoomSensorFail = 0x2;
+    kOutdoorSensorFail = 0x4;
+    kCoilSensorFail = 0x8;
+    kFanFail = 0x10;
+  }
+
+  bitmap Feature : bitmap32 {
+    kHeating = 0x1;
+    kCooling = 0x2;
+    kOccupancy = 0x4;
+    kScheduleConfiguration = 0x8;
+    kSetback = 0x10;
+    kAutoMode = 0x20;
+    kLocalTemperatureNotExposed = 0x40;
+    kMatterScheduleConfiguration = 0x80;
+    kPresets = 0x100;
+    kSetpoints = 0x200;
+    kQueuedPresetsSupported = 0x400;
+  }
+
+  bitmap HVACSystemTypeBitmap : bitmap8 {
+    kCoolingStage = 0x3;
+    kHeatingStage = 0xC;
+    kHeatingIsHeatPump = 0x10;
+    kHeatingUsesFuel = 0x20;
+  }
+
+  bitmap PresetTypeFeaturesBitmap : bitmap16 {
+    kAutomatic = 0x1;
+    kSupportsNames = 0x2;
+  }
+
+  bitmap ProgrammingOperationModeBitmap : bitmap8 {
+    kScheduleActive = 0x1;
+    kAutoRecovery = 0x2;
+    kEconomy = 0x4;
+  }
+
+  bitmap RelayStateBitmap : bitmap16 {
+    kHeat = 0x1;
+    kCool = 0x2;
+    kFan = 0x4;
+    kHeatStage2 = 0x8;
+    kCoolStage2 = 0x10;
+    kFanStage2 = 0x20;
+    kFanStage3 = 0x40;
+  }
+
+  bitmap RemoteSensingBitmap : bitmap8 {
+    kLocalTemperature = 0x1;
+    kOutdoorTemperature = 0x2;
+    kOccupancy = 0x4;
+  }
+
+  bitmap ScheduleDayOfWeekBitmap : bitmap8 {
+    kSunday = 0x1;
+    kMonday = 0x2;
+    kTuesday = 0x4;
+    kWednesday = 0x8;
+    kThursday = 0x10;
+    kFriday = 0x20;
+    kSaturday = 0x40;
+    kAway = 0x80;
+  }
+
+  bitmap ScheduleModeBitmap : bitmap8 {
+    kHeatSetpointPresent = 0x1;
+    kCoolSetpointPresent = 0x2;
+  }
+
+  bitmap ScheduleTypeFeaturesBitmap : bitmap16 {
+    kSupportsPresets = 0x1;
+    kSupportsSetpoints = 0x2;
+    kSupportsNames = 0x4;
+    kSupportsOff = 0x8;
+  }
+
+  bitmap TemperatureSetpointHoldPolicyBitmap : bitmap8 {
+    kHoldDurationElapsed = 0x1;
+    kHoldDurationElapsedOrPresetChanged = 0x2;
+  }
+
+  struct ScheduleTransitionStruct {
+    ScheduleDayOfWeekBitmap dayOfWeek = 0;
+    int16u transitionTime = 1;
+    optional octet_string<16> presetHandle = 2;
+    optional SystemModeEnum systemMode = 3;
+    optional temperature coolingSetpoint = 4;
+    optional temperature heatingSetpoint = 5;
+  }
+
+  struct ScheduleStruct {
+    nullable octet_string<16> scheduleHandle = 0;
+    SystemModeEnum systemMode = 1;
+    optional char_string<64> name = 2;
+    optional octet_string<16> presetHandle = 3;
+    ScheduleTransitionStruct transitions[] = 4;
+    optional nullable boolean builtIn = 5;
+  }
+
+  struct PresetStruct {
+    nullable octet_string<16> presetHandle = 0;
+    PresetScenarioEnum presetScenario = 1;
+    optional nullable char_string<64> name = 2;
+    optional temperature coolingSetpoint = 3;
+    optional temperature heatingSetpoint = 4;
+    nullable boolean builtIn = 5;
+  }
+
+  struct PresetTypeStruct {
+    PresetScenarioEnum presetScenario = 0;
+    int8u numberOfPresets = 1;
+    PresetTypeFeaturesBitmap presetTypeFeatures = 2;
+  }
+
+  struct QueuedPresetStruct {
+    nullable octet_string<16> presetHandle = 0;
+    nullable epoch_s transitionTimestamp = 1;
+  }
+
+  struct ScheduleTypeStruct {
+    SystemModeEnum systemMode = 0;
+    int8u numberOfSchedules = 1;
+    ScheduleTypeFeaturesBitmap scheduleTypeFeatures = 2;
+  }
+
+  struct WeeklyScheduleTransitionStruct {
+    int16u transitionTime = 0;
+    nullable temperature heatSetpoint = 1;
+    nullable temperature coolSetpoint = 2;
+  }
+
+  readonly attribute nullable temperature localTemperature = 0;
+  readonly attribute optional nullable temperature outdoorTemperature = 1;
+  readonly attribute optional bitmap8 occupancy = 2;
+  readonly attribute optional temperature absMinHeatSetpointLimit = 3;
+  readonly attribute optional temperature absMaxHeatSetpointLimit = 4;
+  readonly attribute optional temperature absMinCoolSetpointLimit = 5;
+  readonly attribute optional temperature absMaxCoolSetpointLimit = 6;
+  readonly attribute optional int8u PICoolingDemand = 7;
+  readonly attribute optional int8u PIHeatingDemand = 8;
+  attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9;
+  attribute access(write: manage) optional int8s localTemperatureCalibration = 16;
+  attribute optional int16s occupiedCoolingSetpoint = 17;
+  attribute optional int16s occupiedHeatingSetpoint = 18;
+  attribute optional int16s unoccupiedCoolingSetpoint = 19;
+  attribute optional int16s unoccupiedHeatingSetpoint = 20;
+  attribute access(write: manage) optional int16s minHeatSetpointLimit = 21;
+  attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22;
+  attribute access(write: manage) optional int16s minCoolSetpointLimit = 23;
+  attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24;
+  attribute access(write: manage) optional int8s minSetpointDeadBand = 25;
+  attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26;
+  attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27;
+  attribute access(write: manage) SystemModeEnum systemMode = 28;
+  readonly attribute optional ThermostatRunningModeEnum thermostatRunningMode = 30;
+  readonly attribute optional StartOfWeekEnum startOfWeek = 32;
+  readonly attribute optional int8u numberOfWeeklyTransitions = 33;
+  readonly attribute optional int8u numberOfDailyTransitions = 34;
+  attribute access(write: manage) optional TemperatureSetpointHoldEnum temperatureSetpointHold = 35;
+  attribute access(write: manage) optional nullable int16u temperatureSetpointHoldDuration = 36;
+  attribute access(write: manage) optional ProgrammingOperationModeBitmap thermostatProgrammingOperationMode = 37;
+  readonly attribute optional RelayStateBitmap thermostatRunningState = 41;
+  readonly attribute optional SetpointChangeSourceEnum setpointChangeSource = 48;
+  readonly attribute optional nullable int16s setpointChangeAmount = 49;
+  readonly attribute optional epoch_s setpointChangeSourceTimestamp = 50;
+  attribute access(write: manage) optional nullable int8u occupiedSetback = 52;
+  readonly attribute optional nullable int8u occupiedSetbackMin = 53;
+  readonly attribute optional nullable int8u occupiedSetbackMax = 54;
+  attribute access(write: manage) optional nullable int8u unoccupiedSetback = 55;
+  readonly attribute optional nullable int8u unoccupiedSetbackMin = 56;
+  readonly attribute optional nullable int8u unoccupiedSetbackMax = 57;
+  attribute access(write: manage) optional int8u emergencyHeatDelta = 58;
+  attribute access(write: manage) optional ACTypeEnum ACType = 64;
+  attribute access(write: manage) optional int16u ACCapacity = 65;
+  attribute access(write: manage) optional ACRefrigerantTypeEnum ACRefrigerantType = 66;
+  attribute access(write: manage) optional ACCompressorTypeEnum ACCompressorType = 67;
+  attribute access(write: manage) optional ACErrorCodeBitmap ACErrorCode = 68;
+  attribute access(write: manage) optional ACLouverPositionEnum ACLouverPosition = 69;
+  readonly attribute optional nullable temperature ACCoilTemperature = 70;
+  attribute access(write: manage) optional ACCapacityFormatEnum ACCapacityformat = 71;
+  readonly attribute optional PresetTypeStruct presetTypes[] = 72;
+  readonly attribute optional ScheduleTypeStruct scheduleTypes[] = 73;
+  readonly attribute optional int8u numberOfPresets = 74;
+  readonly attribute optional int8u numberOfSchedules = 75;
+  readonly attribute optional int8u numberOfScheduleTransitions = 76;
+  readonly attribute optional nullable int8u numberOfScheduleTransitionPerDay = 77;
+  readonly attribute optional nullable octet_string<16> activePresetHandle = 78;
+  readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79;
+  attribute access(write: manage) optional PresetStruct presets[] = 80;
+  attribute access(write: manage) optional ScheduleStruct schedules[] = 81;
+  readonly attribute optional boolean presetsSchedulesEditable = 82;
+  readonly attribute optional TemperatureSetpointHoldPolicyBitmap temperatureSetpointHoldPolicy = 83;
+  readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 84;
+  readonly attribute optional nullable QueuedPresetStruct queuedPreset = 85;
+  readonly attribute command_id generatedCommandList[] = 65528;
+  readonly attribute command_id acceptedCommandList[] = 65529;
+  readonly attribute event_id eventList[] = 65530;
+  readonly attribute attrib_id attributeList[] = 65531;
+  readonly attribute bitmap32 featureMap = 65532;
+  readonly attribute int16u clusterRevision = 65533;
+
+  request struct SetpointRaiseLowerRequest {
+    SetpointRaiseLowerModeEnum mode = 0;
+    int8s amount = 1;
+  }
+
+  response struct GetWeeklyScheduleResponse = 0 {
+    int8u numberOfTransitionsForSequence = 0;
+    ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1;
+    ScheduleModeBitmap modeForSequence = 2;
+    WeeklyScheduleTransitionStruct transitions[] = 3;
+  }
+
+  request struct SetWeeklyScheduleRequest {
+    int8u numberOfTransitionsForSequence = 0;
+    ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1;
+    ScheduleModeBitmap modeForSequence = 2;
+    WeeklyScheduleTransitionStruct transitions[] = 3;
+  }
+
+  request struct GetWeeklyScheduleRequest {
+    ScheduleDayOfWeekBitmap daysToReturn = 0;
+    ScheduleModeBitmap modeToReturn = 1;
+  }
+
+  request struct SetActiveScheduleRequestRequest {
+    octet_string<16> scheduleHandle = 0;
+  }
+
+  request struct SetActivePresetRequestRequest {
+    octet_string<16> presetHandle = 0;
+    optional int16u delayMinutes = 1;
+  }
+
+  request struct StartPresetsSchedulesEditRequestRequest {
+    int16u timeoutSeconds = 0;
+  }
+
+  request struct SetTemperatureSetpointHoldPolicyRequest {
+    TemperatureSetpointHoldPolicyBitmap temperatureSetpointHoldPolicy = 0;
+  }
+
+  /** Command description for SetpointRaiseLower */
+  command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0;
+  /** Command description for SetWeeklySchedule */
+  command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1;
+  /** Command description for GetWeeklySchedule */
+  command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2;
+  /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */
+  command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3;
+  /** This command is used to set the active schedule. */
+  command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5;
+  /** This command is used to set the active preset. */
+  command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6;
+  /** This command is used to start editing the presets and schedules. */
+  command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7;
+  /** This command is used to cancel editing presets and schedules. */
+  command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8;
+  /** This command is used to notify the server that all edits are done and should be committed. */
+  command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9;
+  /** This command is sent to cancel a queued preset. */
+  command access(invoke: manage) CancelSetActivePresetRequest(): DefaultSuccess = 10;
+  /** This command sets the set point hold policy. */
+  command SetTemperatureSetpointHoldPolicy(SetTemperatureSetpointHoldPolicyRequest): DefaultSuccess = 11;
+}
+
 /** An interface for controlling a fan in a heating/cooling system. */
 provisional cluster FanControl = 514 {
   revision 4;
@@ -2407,7 +2778,7 @@
   }
 }
 endpoint 3 {
-  device type ma_tempsensor = 770, version 1;
+  device type ma_tempsensor = 770, version 2;
 
 
   server cluster Identify {
@@ -2451,7 +2822,7 @@
   }
 }
 endpoint 4 {
-  device type ma_humiditysensor = 775, version 1;
+  device type ma_humiditysensor = 775, version 2;
 
 
   server cluster Identify {
@@ -2494,5 +2865,54 @@
     ram      attribute clusterRevision default = 3;
   }
 }
+endpoint 5 {
+  device type ma_thermostat = 769, version 2;
+
+
+  server cluster Identify {
+    ram      attribute identifyTime default = 0x0;
+    ram      attribute identifyType default = 0x00;
+    callback attribute generatedCommandList;
+    callback attribute acceptedCommandList;
+    callback attribute eventList;
+    callback attribute attributeList;
+    ram      attribute featureMap default = 0;
+    ram      attribute clusterRevision default = 4;
+
+    handle command Identify;
+    handle command TriggerEffect;
+  }
+
+  server cluster Descriptor {
+    callback attribute deviceTypeList;
+    callback attribute serverList;
+    callback attribute clientList;
+    callback attribute partsList;
+    callback attribute generatedCommandList;
+    callback attribute acceptedCommandList;
+    callback attribute eventList;
+    callback attribute attributeList;
+    callback attribute featureMap;
+    callback attribute clusterRevision;
+  }
+
+  server cluster Thermostat {
+    ram      attribute localTemperature;
+    ram      attribute absMinHeatSetpointLimit default = 1000;
+    ram      attribute absMaxHeatSetpointLimit default = 3000;
+    ram      attribute occupiedHeatingSetpoint default = 2000;
+    ram      attribute controlSequenceOfOperation default = 2;
+    ram      attribute systemMode default = 0;
+    ram      attribute thermostatRunningState default = 0;
+    callback attribute generatedCommandList;
+    callback attribute acceptedCommandList;
+    callback attribute eventList;
+    callback attribute attributeList;
+    ram      attribute featureMap default = 1;
+    ram      attribute clusterRevision default = 6;
+
+    handle command SetpointRaiseLower;
+  }
+}
 
 
diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap b/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap
index d71c47a..b868916 100644
--- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap
+++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap
@@ -6514,7 +6514,7 @@
         }
       ],
       "deviceVersions": [
-        1
+        2
       ],
       "deviceIdentifiers": [
         770
@@ -7039,7 +7039,7 @@
         }
       ],
       "deviceVersions": [
-        1
+        2
       ],
       "deviceIdentifiers": [
         775
@@ -7545,6 +7545,589 @@
           ]
         }
       ]
+    },
+    {
+      "id": 6,
+      "name": "Anonymous Endpoint Type",
+      "deviceTypeRef": {
+        "code": 769,
+        "profileId": 259,
+        "label": "MA-thermostat",
+        "name": "MA-thermostat"
+      },
+      "deviceTypes": [
+        {
+          "code": 769,
+          "profileId": 259,
+          "label": "MA-thermostat",
+          "name": "MA-thermostat"
+        }
+      ],
+      "deviceVersions": [
+        2
+      ],
+      "deviceIdentifiers": [
+        769
+      ],
+      "deviceTypeName": "MA-thermostat",
+      "deviceTypeCode": 769,
+      "deviceTypeProfileId": 259,
+      "clusters": [
+        {
+          "name": "Identify",
+          "code": 3,
+          "mfgCode": null,
+          "define": "IDENTIFY_CLUSTER",
+          "side": "server",
+          "enabled": 1,
+          "commands": [
+            {
+              "name": "Identify",
+              "code": 0,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            },
+            {
+              "name": "TriggerEffect",
+              "code": 64,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            }
+          ],
+          "attributes": [
+            {
+              "name": "IdentifyTime",
+              "code": 0,
+              "mfgCode": null,
+              "side": "server",
+              "type": "int16u",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "0x0",
+              "reportable": 0,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "IdentifyType",
+              "code": 1,
+              "mfgCode": null,
+              "side": "server",
+              "type": "IdentifyTypeEnum",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "0x00",
+              "reportable": 0,
+              "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": "",
+              "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": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "EventList",
+              "code": 65530,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "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": "",
+              "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": "4",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            }
+          ]
+        },
+        {
+          "name": "Descriptor",
+          "code": 29,
+          "mfgCode": null,
+          "define": "DESCRIPTOR_CLUSTER",
+          "side": "server",
+          "enabled": 1,
+          "attributes": [
+            {
+              "name": "DeviceTypeList",
+              "code": 0,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "ServerList",
+              "code": 1,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "reportable": 0,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "ClientList",
+              "code": 2,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "reportable": 0,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "PartsList",
+              "code": 3,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "reportable": 0,
+              "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": "",
+              "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": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "EventList",
+              "code": 65530,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "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": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "FeatureMap",
+              "code": 65532,
+              "mfgCode": null,
+              "side": "server",
+              "type": "bitmap32",
+              "included": 1,
+              "storageOption": "External",
+              "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": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "2",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            }
+          ]
+        },
+        {
+          "name": "Thermostat",
+          "code": 513,
+          "mfgCode": null,
+          "define": "THERMOSTAT_CLUSTER",
+          "side": "server",
+          "enabled": 1,
+          "commands": [
+            {
+              "name": "SetpointRaiseLower",
+              "code": 0,
+              "mfgCode": null,
+              "source": "client",
+              "isIncoming": 1,
+              "isEnabled": 1
+            }
+          ],
+          "attributes": [
+            {
+              "name": "LocalTemperature",
+              "code": 0,
+              "mfgCode": null,
+              "side": "server",
+              "type": "temperature",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "AbsMinHeatSetpointLimit",
+              "code": 3,
+              "mfgCode": null,
+              "side": "server",
+              "type": "temperature",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "1000",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "AbsMaxHeatSetpointLimit",
+              "code": 4,
+              "mfgCode": null,
+              "side": "server",
+              "type": "temperature",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "3000",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "OccupiedHeatingSetpoint",
+              "code": 18,
+              "mfgCode": null,
+              "side": "server",
+              "type": "int16s",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "2000",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "ControlSequenceOfOperation",
+              "code": 27,
+              "mfgCode": null,
+              "side": "server",
+              "type": "ControlSequenceOfOperationEnum",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "2",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "SystemMode",
+              "code": 28,
+              "mfgCode": null,
+              "side": "server",
+              "type": "SystemModeEnum",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "0",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "ThermostatRunningState",
+              "code": 41,
+              "mfgCode": null,
+              "side": "server",
+              "type": "RelayStateBitmap",
+              "included": 1,
+              "storageOption": "RAM",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "0",
+              "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": "",
+              "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": "",
+              "reportable": 1,
+              "minInterval": 1,
+              "maxInterval": 65534,
+              "reportableChange": 0
+            },
+            {
+              "name": "EventList",
+              "code": 65530,
+              "mfgCode": null,
+              "side": "server",
+              "type": "array",
+              "included": 1,
+              "storageOption": "External",
+              "singleton": 0,
+              "bounded": 0,
+              "defaultValue": "",
+              "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": "",
+              "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": "1",
+              "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
+            }
+          ]
+        }
+      ]
     }
   ],
   "endpoints": [
@@ -7582,6 +8165,14 @@
       "profileId": 259,
       "endpointId": 4,
       "networkId": 0
+    },
+    {
+      "endpointTypeName": "Anonymous Endpoint Type",
+      "endpointTypeIndex": 5,
+      "profileId": 259,
+      "endpointId": 5,
+      "networkId": 0
     }
-  ]
+  ],
+  "log": []
 }
\ No newline at end of file
diff --git a/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h b/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h
index 81565d5..e50ccd0 100644
--- a/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h
+++ b/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h
@@ -22,6 +22,7 @@
 #include <filter-delegates.h>
 #include <relative-humidity-sensor-manager.h>
 #include <temperature-sensor-manager.h>
+#include <thermostat-manager.h>
 
 #pragma once
 
@@ -52,12 +53,13 @@
     AirPurifierManager & operator=(const AirPurifierManager &) = delete;
 
     static void InitInstance(EndpointId aEndpointId = 1, EndpointId aAirQualitySensorEndpointId = 2,
-                             EndpointId aTemperatureSensorEndpointId = 3, EndpointId aHumiditySensorEndpointId = 4)
+                             EndpointId aTemperatureSensorEndpointId = 3, EndpointId aHumiditySensorEndpointId = 4,
+                             EndpointId aThermostatEndpointId = 5)
     {
         if (mInstance == nullptr)
         {
             mInstance = new AirPurifierManager(aEndpointId, aAirQualitySensorEndpointId, aTemperatureSensorEndpointId,
-                                               aHumiditySensorEndpointId);
+                                               aHumiditySensorEndpointId, aThermostatEndpointId);
             mInstance->Init();
         }
     };
@@ -89,6 +91,11 @@
      */
     Protocols::InteractionModel::Status HandleStep(FanControl::StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override;
 
+    /**
+     * @brief Callback that thermostat manager calls when the heating state changes
+     */
+    void HeatingCallback();
+
 private:
     inline static AirPurifierManager * mInstance;
 
@@ -96,10 +103,13 @@
     EndpointId mAirQualitySensorEndpointId;
     EndpointId mTemperatureSensorEndpointId;
     EndpointId mHumiditySensorEndpointId;
+    EndpointId mThermostatEndpointId;
 
     uint8_t percentCurrent;
     uint8_t speedCurrent;
 
+    bool fanWasStartedByUser = false;
+
     // Set up for Activated Carbon Filter Monitoring
     ActivatedCarbonFilterMonitoringDelegate activatedCarbonFilterDelegate;
     ResourceMonitoring::Instance activatedCarbonFilterInstance;
@@ -112,6 +122,7 @@
     AirQualitySensorManager mAirQualitySensorManager;
     TemperatureSensorManager mTemperatureSensorManager;
     RelativeHumiditySensorManager mHumiditySensorManager;
+    ThermostatManager mThermostatManager;
 
     // Fan Mode Limits
     static constexpr int FAN_MODE_LOW_LOWER_BOUND    = 1;
@@ -129,7 +140,7 @@
      * @param[in] aHumiditySensorEndpointId    Endpoint that the humidity sensor is on
      */
     AirPurifierManager(EndpointId aEndpointId, EndpointId aAirQualitySensorEndpointId, EndpointId aTemperatureSensorEndpointId,
-                       EndpointId aHumiditySensorEndpointId) :
+                       EndpointId aHumiditySensorEndpointId, EndpointId aThermostatEndpointId) :
         FanControl::Delegate(aEndpointId),
         mEndpointId(aEndpointId),
         activatedCarbonFilterInstance(&activatedCarbonFilterDelegate, mEndpointId, ActivatedCarbonFilterMonitoring::Id,
@@ -139,7 +150,9 @@
                            static_cast<uint32_t>(gHepaFilterFeatureMap.to_ulong()),
                            ResourceMonitoring::DegradationDirectionEnum::kDown, true),
         mAirQualitySensorManager(aAirQualitySensorEndpointId), mTemperatureSensorManager(aTemperatureSensorEndpointId),
-        mHumiditySensorManager(aHumiditySensorEndpointId){};
+        mHumiditySensorManager(aHumiditySensorEndpointId),
+        mThermostatManager(aThermostatEndpointId, [this]() { HeatingCallback(); })
+    {}
 
     /**
      * @brief Handle attribute changes for the Fan Control Cluster
@@ -155,6 +168,12 @@
     void FanModeWriteCallback(FanControl::FanModeEnum aNewFanMode);
 
     void SetSpeedSetting(DataModel::Nullable<uint8_t> aNewSpeedSetting);
+    DataModel::Nullable<uint8_t> GetSpeedSetting();
+    DataModel::Nullable<Percent> GetPercentSetting();
+
+    void HandleThermostatAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value);
+    void ThermostatHeatingSetpointWriteCallback(int16_t aNewHeatingSetpoint);
+    void ThermostatSystemModeWriteCallback(uint8_t aNewSystemMode);
 };
 
 } // namespace Clusters
diff --git a/examples/air-purifier-app/air-purifier-common/include/thermostat-manager.h b/examples/air-purifier-app/air-purifier-common/include/thermostat-manager.h
new file mode 100644
index 0000000..f19e596
--- /dev/null
+++ b/examples/air-purifier-app/air-purifier-common/include/thermostat-manager.h
@@ -0,0 +1,53 @@
+/*
+ *
+ *    Copyright (c) 2023 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/attributes/Accessors.h>
+#include <functional>
+
+namespace chip {
+namespace app {
+namespace Clusters {
+
+class ThermostatManager
+{
+public:
+    using HeatingCallbackType = std::function<void()>;
+
+    ThermostatManager(EndpointId aEndpointId, const HeatingCallbackType & callback) :
+        mEndpointId(aEndpointId), heatingCallback(callback)
+    {}
+
+    void Init();
+
+    void HeatingSetpointWriteCallback(int16_t newValue);
+    void SystemModeWriteCallback(uint8_t newValue);
+    void OnLocalTemperatureChangeCallback(int16_t temperature);
+    void SetHeatMode(bool heat);
+
+private:
+    EndpointId mEndpointId;
+
+    void SetHeating(bool isHeating);
+    HeatingCallbackType heatingCallback;
+};
+
+} // namespace Clusters
+} // namespace app
+} // namespace chip
diff --git a/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp b/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp
index 93e1e37..7ce8ac5 100644
--- a/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp
+++ b/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp
@@ -33,37 +33,31 @@
     mAirQualitySensorManager.Init();
     mTemperatureSensorManager.Init();
     mHumiditySensorManager.Init();
+    mThermostatManager.Init();
 
-    DataModel::Nullable<Percent> percentSetting;
-    EmberAfStatus status = FanControl::Attributes::PercentSetting::Get(mEndpointId, percentSetting);
-    if (EMBER_ZCL_STATUS_SUCCESS == status)
+    DataModel::Nullable<Percent> percentSetting = GetPercentSetting();
+    if (percentSetting.IsNull())
     {
-        if (percentSetting.IsNull())
-        {
-            PercentSettingWriteCallback(0);
-        }
-        else
-        {
-            PercentSettingWriteCallback(percentSetting.Value());
-        }
+        PercentSettingWriteCallback(0);
+    }
+    else
+    {
+        PercentSettingWriteCallback(percentSetting.Value());
     }
 
-    DataModel::Nullable<uint8_t> speedSetting;
-    status = FanControl::Attributes::SpeedSetting::Get(mEndpointId, speedSetting);
-    if (EMBER_ZCL_STATUS_SUCCESS == status)
+    DataModel::Nullable<uint8_t> speedSetting = GetSpeedSetting();
+    if (speedSetting.IsNull())
     {
-        if (speedSetting.IsNull())
-        {
-            SpeedSettingWriteCallback(0);
-        }
-        else
-        {
-            SpeedSettingWriteCallback(speedSetting.Value());
-        }
+        SpeedSettingWriteCallback(0);
+    }
+    else
+    {
+        SpeedSettingWriteCallback(speedSetting.Value());
     }
 
     // Set up some sane initial values for temperature and humidity - note these are fixed values for testing purposes only
     mTemperatureSensorManager.OnTemperatureChangeHandler(2000);
+    mThermostatManager.OnLocalTemperatureChangeCallback(2000);
     mHumiditySensorManager.OnHumidityChangeHandler(5000);
 }
 
@@ -77,6 +71,11 @@
         break;
     }
 
+    case Thermostat::Id: {
+        HandleThermostatAttributeChange(attributeId, type, size, value);
+        break;
+    }
+
     default:
         break;
     }
@@ -92,8 +91,7 @@
     uint8_t speedMax;
     FanControl::Attributes::SpeedMax::Get(mEndpointId, &speedMax);
 
-    DataModel::Nullable<uint8_t> speedSetting;
-    FanControl::Attributes::SpeedSetting::Get(mEndpointId, speedSetting);
+    DataModel::Nullable<uint8_t> speedSetting = GetSpeedSetting();
 
     uint8_t newSpeedSetting = speedSetting.IsNull() ? 0 : speedSetting.Value();
 
@@ -309,3 +307,68 @@
         }
     }
 }
+
+DataModel::Nullable<uint8_t> AirPurifierManager::GetSpeedSetting()
+{
+    DataModel::Nullable<uint8_t> speedSetting;
+    EmberAfStatus status = FanControl::Attributes::SpeedSetting::Get(mEndpointId, speedSetting);
+
+    if (status != EMBER_ZCL_STATUS_SUCCESS)
+    {
+        ChipLogError(NotSpecified, "AirPurifierManager::GetSpeedSetting: failed to get SpeedSetting attribute: %d", status);
+    }
+
+    return speedSetting;
+}
+
+DataModel::Nullable<Percent> AirPurifierManager::GetPercentSetting()
+{
+    DataModel::Nullable<Percent> percentSetting;
+    EmberAfStatus status = FanControl::Attributes::PercentSetting::Get(mEndpointId, percentSetting);
+
+    if (status != EMBER_ZCL_STATUS_SUCCESS)
+    {
+        ChipLogError(NotSpecified, "AirPurifierManager::GetPercentSetting: failed to get PercentSetting attribute: %d", status);
+    }
+
+    return percentSetting;
+}
+
+void AirPurifierManager::HandleThermostatAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value)
+{
+    switch (attributeId)
+    {
+    case Thermostat::Attributes::OccupiedHeatingSetpoint::Id: {
+        int16_t heatingSetpoint = static_cast<int16_t>(chip::Encoding::LittleEndian::Get16(value));
+        ThermostatHeatingSetpointWriteCallback(heatingSetpoint);
+        break;
+    }
+    case Thermostat::Attributes::SystemMode::Id: {
+        uint8_t systemMode = static_cast<uint8_t>(*value);
+        ThermostatSystemModeWriteCallback(systemMode);
+        break;
+    }
+    }
+}
+
+void AirPurifierManager::ThermostatHeatingSetpointWriteCallback(int16_t aNewHeatingSetpoint)
+{
+    mThermostatManager.HeatingSetpointWriteCallback(aNewHeatingSetpoint);
+}
+
+void AirPurifierManager::ThermostatSystemModeWriteCallback(uint8_t aNewSystemMode)
+{
+    mThermostatManager.SystemModeWriteCallback(aNewSystemMode);
+}
+
+void AirPurifierManager::HeatingCallback()
+{
+    // Check if the Fan is off and if it is, turn it on to 50% speed
+    DataModel::Nullable<uint8_t> speedSetting = GetSpeedSetting();
+
+    if (speedSetting.IsNull() || speedSetting.Value() == 0)
+    {
+        DataModel::Nullable<uint8_t> newSpeedSetting(5);
+        SetSpeedSetting(newSpeedSetting);
+    }
+}
diff --git a/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp b/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp
new file mode 100644
index 0000000..c2536e4
--- /dev/null
+++ b/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp
@@ -0,0 +1,135 @@
+/*
+ *
+ *    Copyright (c) 2024 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 "thermostat-manager.h"
+
+using namespace chip;
+using namespace chip::app;
+using namespace chip::app::Clusters;
+
+void ThermostatManager::Init()
+{
+    BitMask<Thermostat::Feature> FeatureMap;
+    FeatureMap.Set(Thermostat::Feature::kHeating);
+    EmberAfStatus status = Thermostat::Attributes::FeatureMap::Set(mEndpointId, FeatureMap.Raw());
+
+    status = Thermostat::Attributes::ControlSequenceOfOperation::Set(mEndpointId,
+                                                                     Thermostat::ControlSequenceOfOperationEnum::kHeatingOnly);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                   ChipLogError(NotSpecified, "Failed to set Thermostat ControlSequenceOfOperation attribute"));
+
+    status = Thermostat::Attributes::AbsMinHeatSetpointLimit::Set(mEndpointId, 500);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                   ChipLogError(NotSpecified, "Failed to set Thermostat MinHeatSetpointLimit attribute"));
+
+    status = Thermostat::Attributes::AbsMaxHeatSetpointLimit::Set(mEndpointId, 3000);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                   ChipLogError(NotSpecified, "Failed to set Thermostat MaxHeatSetpointLimit attribute"));
+}
+
+void ThermostatManager::HeatingSetpointWriteCallback(int16_t newValue)
+{
+    ChipLogDetail(NotSpecified, "ThermostatManager::HeatingSetpointWriteCallback: %d", newValue);
+    Thermostat::SystemModeEnum systemMode;
+    EmberAfStatus status = Thermostat::Attributes::SystemMode::Get(mEndpointId, &systemMode);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to get Thermostat SystemMode attribute"));
+
+    // A new setpoint has been set, so we shall infer that the we want to be in Heating mode
+    if (systemMode == Thermostat::SystemModeEnum::kOff)
+    {
+        SetHeatMode(true);
+    }
+
+    // Check the current temperature and turn on the heater if needed
+    DataModel::Nullable<int16_t> localTemperature;
+    status = Thermostat::Attributes::LocalTemperature::Get(mEndpointId, localTemperature);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                   ChipLogError(NotSpecified, "Failed to get TemperatureMeasurement MeasuredValue attribute"));
+
+    if (localTemperature.Value() < newValue)
+    {
+        SetHeating(true);
+    }
+    else
+    {
+        SetHeating(false);
+    }
+}
+
+void ThermostatManager::SystemModeWriteCallback(uint8_t newValue)
+{
+    ChipLogDetail(NotSpecified, "ThermostatManager::SystemModeWriteCallback: %d", newValue);
+    if ((Thermostat::SystemModeEnum) newValue == Thermostat::SystemModeEnum::kOff)
+    {
+        SetHeating(false);
+    }
+    else if ((Thermostat::SystemModeEnum) newValue == Thermostat::SystemModeEnum::kHeat)
+    {
+        DataModel::Nullable<int16_t> localTemperature;
+        EmberAfStatus status = Thermostat::Attributes::LocalTemperature::Get(mEndpointId, localTemperature);
+        VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                       ChipLogError(NotSpecified, "Failed to get TemperatureMeasurement MeasuredValue attribute"));
+
+        int16_t heatingSetpoint;
+        status = Thermostat::Attributes::OccupiedHeatingSetpoint::Get(mEndpointId, &heatingSetpoint);
+        VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                       ChipLogError(NotSpecified, "Failed to get Thermostat HeatingSetpoint attribute"));
+
+        if (localTemperature.Value() < heatingSetpoint)
+        {
+            SetHeating(true);
+        }
+    }
+}
+
+void ThermostatManager::OnLocalTemperatureChangeCallback(int16_t temperature)
+{
+    EmberAfStatus status = Thermostat::Attributes::LocalTemperature::Set(mEndpointId, temperature);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                   ChipLogError(NotSpecified, "Failed to set TemperatureMeasurement MeasuredValue attribute"));
+}
+
+void ThermostatManager::SetHeating(bool isHeating)
+{
+    BitMask<Thermostat::RelayStateBitmap> runningState;
+
+    if (isHeating)
+    {
+        runningState.Set(Thermostat::RelayStateBitmap::kHeat);
+
+        if (heatingCallback)
+        {
+            heatingCallback();
+        }
+    }
+    else
+    {
+        runningState.Clear(Thermostat::RelayStateBitmap::kHeat);
+    }
+
+    EmberAfStatus status = Thermostat::Attributes::ThermostatRunningState::Set(mEndpointId, runningState);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
+                   ChipLogError(NotSpecified, "Failed to set Thermostat RunningState attribute"));
+}
+
+void ThermostatManager::SetHeatMode(bool heat)
+{
+    EmberAfStatus status = Thermostat::Attributes::SystemMode::Set(
+        mEndpointId, heat ? Thermostat::SystemModeEnum::kHeat : Thermostat::SystemModeEnum::kOff);
+    VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set Thermostat SystemMode attribute"));
+}
diff --git a/examples/air-purifier-app/ameba/README.md b/examples/air-purifier-app/ameba/README.md
index be11ad8..ee2a451 100644
--- a/examples/air-purifier-app/ameba/README.md
+++ b/examples/air-purifier-app/ameba/README.md
@@ -10,7 +10,7 @@
     -   [Commissioning](#commissioning)
         -   [BLE mode](#ble-mode)
         -   [IP mode](#ip-mode)
-    -   [Cluster control](#cluster-control)
+    -   [Cluster Control](#cluster-control)
 
 ---
 
@@ -106,6 +106,7 @@
 -   Air quality sensor on endpoint 2
 -   Temperature sensor on endpoint 3
 -   Relative humidity sensor on endpoint 4
+-   Thermostat on endpoint 5
 
 Example commands using the chip tool:
 
diff --git a/examples/air-purifier-app/ameba/main/chipinterface.cpp b/examples/air-purifier-app/ameba/main/chipinterface.cpp
index bcda329..264ad53 100644
--- a/examples/air-purifier-app/ameba/main/chipinterface.cpp
+++ b/examples/air-purifier-app/ameba/main/chipinterface.cpp
@@ -48,6 +48,7 @@
 #define AIR_QUALITY_SENSOR_ENDPOINT 2
 #define TEMPERATURE_SENSOR_ENDPOINT 3
 #define RELATIVE_HUMIDITY_SENSOR_ENDPOINT 4
+#define THERMOSTAT_ENDPOINT 5
 
 using namespace ::chip;
 using namespace ::chip::app;
@@ -116,11 +117,12 @@
 {
     Clusters::AirPurifierManager::InitInstance(EndpointId(AIR_PURIFIER_ENDPOINT), EndpointId(AIR_QUALITY_SENSOR_ENDPOINT),
                                                EndpointId(TEMPERATURE_SENSOR_ENDPOINT),
-                                               EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT));
+                                               EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT), EndpointId(THERMOSTAT_ENDPOINT));
 
     SetParentEndpointForEndpoint(AIR_QUALITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
     SetParentEndpointForEndpoint(TEMPERATURE_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
     SetParentEndpointForEndpoint(RELATIVE_HUMIDITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
+    SetParentEndpointForEndpoint(THERMOSTAT_ENDPOINT, AIR_PURIFIER_ENDPOINT);
 }
 
 static void InitServer(intptr_t context)
diff --git a/examples/air-purifier-app/cc32xx/BUILD.gn b/examples/air-purifier-app/cc32xx/BUILD.gn
index 51916cc..f79e76c 100755
--- a/examples/air-purifier-app/cc32xx/BUILD.gn
+++ b/examples/air-purifier-app/cc32xx/BUILD.gn
@@ -85,6 +85,7 @@
     "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp",
     "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-quality-sensor-manager.cpp",
     "${chip_root}/examples/air-purifier-app/air-purifier-common/src/filter-delegates.cpp",
+    "${chip_root}/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp",
     "${project_dir}/main/AppTask.cpp",
     "${project_dir}/main/CHIPDeviceManager.cpp",
     "${project_dir}/main/CXXExceptionStubs.cpp",
diff --git a/examples/air-purifier-app/cc32xx/main/AppTask.cpp b/examples/air-purifier-app/cc32xx/main/AppTask.cpp
index e753e5a..0b28425 100644
--- a/examples/air-purifier-app/cc32xx/main/AppTask.cpp
+++ b/examples/air-purifier-app/cc32xx/main/AppTask.cpp
@@ -64,6 +64,7 @@
 #define AIR_QUALITY_SENSOR_ENDPOINT 2
 #define TEMPERATURE_SENSOR_ENDPOINT 3
 #define RELATIVE_HUMIDITY_SENSOR_ENDPOINT 4
+#define THERMOSTAT_ENDPOINT 5
 
 // Added the below three for DNS Server Initialization
 using namespace ::chip;
@@ -178,9 +179,11 @@
     SetParentEndpointForEndpoint(AIR_QUALITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
     SetParentEndpointForEndpoint(TEMPERATURE_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
     SetParentEndpointForEndpoint(RELATIVE_HUMIDITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
+    SetParentEndpointForEndpoint(THERMOSTAT_ENDPOINT, AIR_PURIFIER_ENDPOINT);
 
     AirPurifierManager::InitInstance(EndpointId(AIR_PURIFIER_ENDPOINT), EndpointId(AIR_QUALITY_SENSOR_ENDPOINT),
-                                     EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT));
+                                     EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT),
+                                     EndpointId(THERMOSTAT_ENDPOINT));
 
     ConfigurationMgr().LogDeviceConfig();
 
diff --git a/examples/air-purifier-app/linux/BUILD.gn b/examples/air-purifier-app/linux/BUILD.gn
index 0a0f86c..0f4d2a4 100644
--- a/examples/air-purifier-app/linux/BUILD.gn
+++ b/examples/air-purifier-app/linux/BUILD.gn
@@ -33,6 +33,7 @@
     "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp",
     "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-quality-sensor-manager.cpp",
     "${chip_root}/examples/air-purifier-app/air-purifier-common/src/filter-delegates.cpp",
+    "${chip_root}/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp",
     "include/CHIPProjectAppConfig.h",
     "main.cpp",
   ]
diff --git a/examples/air-purifier-app/linux/README.md b/examples/air-purifier-app/linux/README.md
index 88f5be7..d2352bc 100644
--- a/examples/air-purifier-app/linux/README.md
+++ b/examples/air-purifier-app/linux/README.md
@@ -4,9 +4,10 @@
 to build and run CHIP Air Purifier Example on A Linux System. This doc is tested
 on **Ubuntu 20.04 LTS**.
 
-The Air Purifier is a composed device with Endpoint 1 being the Air Purifier.
-Endpoint 2 is an Air Quality Sensor, Endpoint 3 is a Relative Humidity Sensor
-and endpoint 4 is a Temperature Sensor.
+The Air Purifier example demonstrates a fully functional Matter Air Purifier
+which is a composed device with Endpoint 1 being the Air Purifier. Endpoint 2 is
+an Air Quality Sensor, Endpoint 3 is a Relative Humidity Sensor, Endpoint 4 is a
+Temperature Sensor and Endpoint 5 is a Thermostat.
 
 To cross-compile this example on x64 host and run on **NXP i.MX 8M Mini**
 **EVK**, see the associated
@@ -99,11 +100,11 @@
                       RX bytes:8609495 acl:14 sco:0 events:217484 errors:0
                       TX bytes:92185 acl:20 sco:0 commands:5259 errors:0
 
-        -   Run Linux Lighting Example App
+        -   Run Linux Air Purifier Example App
 
-                  $ cd ~/connectedhomeip/examples/lighting-app/linux
-                  $ sudo out/debug/chip-lighting-app --ble-device [bluetooth device number]
+                  $ cd ~/connectedhomeip/examples/air-purifier-app/linux
+                  $ sudo out/debug/chip-air-purifier-app --ble-device [bluetooth device number]
                   # In this example, the device we want to use is hci1
-                  $ sudo out/debug/chip-lighting-app --ble-device 1
+                  $ sudo out/debug/chip-air-purifier-app --ble-device 1
 
         -   Test the device using ChipTool on your laptop / workstation etc.
diff --git a/examples/air-purifier-app/linux/main.cpp b/examples/air-purifier-app/linux/main.cpp
index 59ef9cf..98d8d40 100644
--- a/examples/air-purifier-app/linux/main.cpp
+++ b/examples/air-purifier-app/linux/main.cpp
@@ -27,7 +27,7 @@
 #define AIR_QUALITY_SENSOR_ENDPOINT 2
 #define TEMPERATURE_SENSOR_ENDPOINT 3
 #define RELATIVE_HUMIDITY_SENSOR_ENDPOINT 4
-// TODO: Add support for the thermostat endpoint in future PR.
+#define THERMOSTAT_ENDPOINT 5
 
 using namespace chip;
 using namespace chip::app;
@@ -48,11 +48,13 @@
 void ApplicationInit()
 {
     AirPurifierManager::InitInstance(EndpointId(AIR_PURIFIER_ENDPOINT), EndpointId(AIR_QUALITY_SENSOR_ENDPOINT),
-                                     EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT));
+                                     EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT),
+                                     EndpointId(THERMOSTAT_ENDPOINT));
 
     SetParentEndpointForEndpoint(AIR_QUALITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
     SetParentEndpointForEndpoint(TEMPERATURE_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
     SetParentEndpointForEndpoint(RELATIVE_HUMIDITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT);
+    SetParentEndpointForEndpoint(THERMOSTAT_ENDPOINT, AIR_PURIFIER_ENDPOINT);
 }
 
 void ApplicationShutdown()