MatterTemperatureControlledCabinet

About

The MatterTemperatureControlledCabinet class provides a temperature controlled cabinet endpoint for Matter networks. This endpoint implements the Matter temperature control standard for managing temperature setpoints with min/max limits, step control (always enabled), or temperature level support.

Features:

  • Two initialization modes:

    • Temperature Number Mode (begin(tempSetpoint, minTemp, maxTemp, step)): Temperature setpoint control with min/max limits and step control

    • Temperature Level Mode (begin(supportedLevels, levelCount, selectedLevel)): Temperature level control with array of supported levels

  • 1/100th degree Celsius precision (for temperature_number mode)

  • Min/max temperature limits with validation (temperature_number mode)

  • Temperature step control (temperature_number mode, always enabled)

  • Temperature level array support (temperature_level mode)

  • Automatic setpoint validation against limits

  • Feature validation - methods return errors if called with wrong feature mode

  • Integration with Apple HomeKit, Amazon Alexa, and Google Home

  • Matter standard compliance

Important: The temperature_number and temperature_level features are mutually exclusive. Only one can be enabled at a time. Use begin(tempSetpoint, minTemp, maxTemp, step) for temperature_number mode or begin(supportedLevels, levelCount, selectedLevel) for temperature_level mode.

Use Cases:

  • Refrigerators and freezers

  • Wine coolers

  • Medical storage cabinets

  • Laboratory equipment

  • Food storage systems

  • Temperature-controlled storage units

API Reference

Constructor

MatterTemperatureControlledCabinet

Creates a new Matter temperature controlled cabinet endpoint.

MatterTemperatureControlledCabinet();

Initialization

begin

Initializes the Matter temperature controlled cabinet endpoint with temperature_number feature mode. This enables temperature setpoint control with min/max limits and optional step.

Note: This mode is mutually exclusive with temperature_level mode. Use begin(supportedLevels, levelCount, selectedLevel) for temperature level control.

bool begin(double tempSetpoint = 0.00, double minTemperature = -10.0, double maxTemperature = 32.0, double step = 0.50);
  • tempSetpoint - Initial temperature setpoint in Celsius (default: 0.00)

  • minTemperature - Minimum allowed temperature in Celsius (default: -10.0)

  • maxTemperature - Maximum allowed temperature in Celsius (default: 32.0)

  • step - Initial temperature step value in Celsius (default: 0.50)

This function will return true if successful, false otherwise.

Note: The implementation stores temperature with 1/100th degree Celsius precision internally. The temperature_step feature is always enabled for temperature_number mode, allowing setStep() to be called later even if step is not provided in begin().

begin (overloaded)

Initializes the Matter temperature controlled cabinet endpoint with temperature_level feature mode. This enables temperature level control with an array of supported levels.

Note: This mode is mutually exclusive with temperature_number mode. Use begin(tempSetpoint, minTemp, maxTemp, step) for temperature setpoint control.

bool begin(uint8_t *supportedLevels, uint16_t levelCount, uint8_t selectedLevel = 0);
  • supportedLevels - Pointer to array of temperature level values (uint8_t, 0-255)

  • levelCount - Number of levels in the array (maximum: 16)

  • selectedLevel - Initial selected temperature level (default: 0)

This function will return true if successful, false otherwise.

Note: The maximum number of supported levels is 16 (defined by temperature_control::k_max_temp_level_count). The array is copied internally, so it does not need to remain valid after the function returns. This method uses a custom endpoint implementation that properly supports the temperature_level feature.

end

Stops processing Matter temperature controlled cabinet events.

void end();

Temperature Setpoint Control

setTemperatureSetpoint

Sets the temperature setpoint value. The setpoint will be validated against min/max limits.

Requires: temperature_number feature mode (use begin())

bool setTemperatureSetpoint(double temperature);
  • temperature - Temperature setpoint in Celsius

This function will return true if successful, false otherwise (e.g., if temperature is out of range or wrong feature mode).

Note: Temperature is stored with 1/100th degree Celsius precision. The setpoint must be within the min/max temperature range. This method will return false and log an error if called when using temperature_level mode.

getTemperatureSetpoint

Gets the current temperature setpoint value.

double getTemperatureSetpoint();

This function will return the temperature setpoint in Celsius with 1/100th degree precision.

Min/Max Temperature Control

setMinTemperature

Sets the minimum allowed temperature.

Requires: temperature_number feature mode (use begin())

bool setMinTemperature(double temperature);
  • temperature - Minimum temperature in Celsius

This function will return true if successful, false otherwise. Will return false and log an error if called when using temperature_level mode.

getMinTemperature

Gets the minimum allowed temperature.

double getMinTemperature();

This function will return the minimum temperature in Celsius with 1/100th degree precision.

setMaxTemperature

Sets the maximum allowed temperature.

Requires: temperature_number feature mode (use begin())

bool setMaxTemperature(double temperature);
  • temperature - Maximum temperature in Celsius

This function will return true if successful, false otherwise. Will return false and log an error if called when using temperature_level mode.

getMaxTemperature

Gets the maximum allowed temperature.

double getMaxTemperature();

This function will return the maximum temperature in Celsius with 1/100th degree precision.

Temperature Step Control

setStep

Sets the temperature step value.

Requires: temperature_number feature mode (use begin())

bool setStep(double step);
  • step - Temperature step value in Celsius

This function will return true if successful, false otherwise.

Note: The temperature_step feature is always enabled when using temperature_number mode, so this method can be called at any time to set or change the step value, even if step was not provided in begin(). This method will return false and log an error if called when using temperature_level mode.

getStep

Gets the current temperature step value.

double getStep();

This function will return the temperature step in Celsius with 1/100th degree precision.

Temperature Level Control (Optional)

setSelectedTemperatureLevel

Sets the selected temperature level.

Requires: temperature_level feature mode (use begin(supportedLevels, levelCount, selectedLevel))

bool setSelectedTemperatureLevel(uint8_t level);
  • level - Temperature level (0-255)

This function will return true if successful, false otherwise.

Note: Temperature level and temperature number features are mutually exclusive. This method will return false and log an error if called when using temperature_number mode.

getSelectedTemperatureLevel

Gets the current selected temperature level.

uint8_t getSelectedTemperatureLevel();

This function will return the selected temperature level (0-255).

setSupportedTemperatureLevels

Sets the supported temperature levels array.

Requires: temperature_level feature mode (use begin(supportedLevels, levelCount, selectedLevel))

bool setSupportedTemperatureLevels(uint8_t *levels, uint16_t count);
  • levels - Pointer to array of temperature level values (array is copied internally)

  • count - Number of levels in the array (maximum: 16)

This function will return true if successful, false otherwise.

Note: The maximum number of supported levels is 16. The array is copied internally, so it does not need to remain valid after the function returns. This method will return false and log an error if called when using temperature_number mode or if count exceeds the maximum.

getSupportedTemperatureLevelsCount

Gets the count of supported temperature levels.

uint16_t getSupportedTemperatureLevelsCount();

This function will return the number of supported temperature levels.

Example

Temperature Controlled Cabinet

The example demonstrates the temperature_number mode with dynamic temperature updates. The temperature setpoint automatically cycles between the minimum and maximum limits every 1 second using the configured step value, allowing Matter controllers to observe real-time changes. The example also monitors and logs when the initial setpoint is reached or overpassed in each direction.

// Copyright 2025 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 demonstrates the Temperature Number mode of the Matter Temperature Controlled Cabinet Device.
 *
 * This example 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.
 *
 * The example will create a Matter Temperature Controlled Cabinet Device using temperature_number feature.
 * The Temperature Controlled Cabinet can be controlled via Matter controllers to set
 * temperature setpoint with min/max limits and optional step control.
 *
 * This mode is mutually exclusive with temperature_level mode.
 * See MatterTemperatureControlledCabinetLevels example for temperature level control.
 */

// Matter Manager
#include <Matter.h>
#if !CONFIG_ENABLE_CHIPOBLE
// if the device can be commissioned using BLE, WiFi is not used - save flash space
#include <WiFi.h>
#endif

// List of Matter Endpoints for this Node
// Matter Temperature Controlled Cabinet Endpoint
MatterTemperatureControlledCabinet TemperatureCabinet;

// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
#if !CONFIG_ENABLE_CHIPOBLE
// 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
#endif

// set your board USER BUTTON pin here - decommissioning button
const uint8_t buttonPin = BOOT_PIN;  // Set your pin here. Using BOOT Button.

// Button control - decommission 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

// Temperature control state
struct TemperatureControlState {
  bool initialized;
  bool increasing;
  double currentSetpoint;
  double initialSetpoint;
  bool setpointReachedIncreasing;
  bool setpointReachedDecreasing;
};

static TemperatureControlState tempState = {
  .initialized = false,
  .increasing = true,
  .currentSetpoint = 0.0,
  .initialSetpoint = 0.0,
  .setpointReachedIncreasing = false,
  .setpointReachedDecreasing = false
};

// Initialize temperature control state
void initTemperatureControl() {
  if (!tempState.initialized) {
    tempState.currentSetpoint = TemperatureCabinet.getTemperatureSetpoint();
    tempState.initialSetpoint = tempState.currentSetpoint;
    tempState.initialized = true;
  }
}

// Check and log when initial setpoint is reached/overpassed
void checkSetpointReached(double newSetpoint, bool isIncreasing, bool directionChanged) {
  if (directionChanged) {
    // Reset flags when direction changes
    tempState.setpointReachedIncreasing = false;
    tempState.setpointReachedDecreasing = false;
    return;
  }

  if (isIncreasing && !tempState.setpointReachedIncreasing && newSetpoint >= tempState.initialSetpoint) {
    Serial.printf("*** Temperature setpoint %.02f°C reached/overpassed while increasing ***\r\n", tempState.initialSetpoint);
    tempState.setpointReachedIncreasing = true;
  } else if (!isIncreasing && !tempState.setpointReachedDecreasing && newSetpoint <= tempState.initialSetpoint) {
    Serial.printf("*** Temperature setpoint %.02f°C reached/overpassed while decreasing ***\r\n", tempState.initialSetpoint);
    tempState.setpointReachedDecreasing = true;
  }
}

// Update temperature setpoint with cycling logic
void updateTemperatureSetpoint() {
  double minTemp = TemperatureCabinet.getMinTemperature();
  double maxTemp = TemperatureCabinet.getMaxTemperature();
  double step = TemperatureCabinet.getStep();

  // Calculate next setpoint based on direction and step
  bool directionChanged = false;

  if (tempState.increasing) {
    tempState.currentSetpoint += step;
    if (tempState.currentSetpoint >= maxTemp) {
      tempState.currentSetpoint = maxTemp;
      tempState.increasing = false;  // Reverse direction
      directionChanged = true;
    }
  } else {
    tempState.currentSetpoint -= step;
    if (tempState.currentSetpoint <= minTemp) {
      tempState.currentSetpoint = minTemp;
      tempState.increasing = true;  // Reverse direction
      directionChanged = true;
    }
  }

  // Check if setpoint has been reached or overpassed
  checkSetpointReached(tempState.currentSetpoint, tempState.increasing, directionChanged);

  // Update the temperature setpoint
  if (TemperatureCabinet.setTemperatureSetpoint(tempState.currentSetpoint)) {
    Serial.printf("Temperature setpoint updated to: %.02f°C (Range: %.02f°C to %.02f°C)\r\n", tempState.currentSetpoint, minTemp, maxTemp);
  } else {
    Serial.printf("Failed to update temperature setpoint to: %.02f°C\r\n", tempState.currentSetpoint);
  }
}

// Print current temperature status
void printTemperatureStatus() {
  Serial.printf(
    "Current Temperature Setpoint: %.02f°C (Range: %.02f°C to %.02f°C)\r\n", TemperatureCabinet.getTemperatureSetpoint(),
    TemperatureCabinet.getMinTemperature(), TemperatureCabinet.getMaxTemperature()
  );
}

// Handle button press for decommissioning
void handleButtonPress() {
  // 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 Temperature Controlled Cabinet Matter Accessory. It shall be commissioned again.");
    Matter.decommission();
    button_time_stamp = millis();  // avoid running decommissioning again, reboot takes a second or so
  }
}

void setup() {
  // Initialize the USER BUTTON (Boot button) that will be used to decommission the Matter Node
  pinMode(buttonPin, INPUT_PULLUP);

  Serial.begin(115200);

// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
#if !CONFIG_ENABLE_CHIPOBLE
  // Manually connect to WiFi
  WiFi.begin(ssid, password);
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
#endif

  // Initialize Temperature Controlled Cabinet with:
  // - Initial setpoint: 4.0°C (typical refrigerator temperature)
  // - Min temperature: -10.0°C
  // - Max temperature: 10.0°C
  // - Step: 0.5°C (optional, for temperature_step feature)
  TemperatureCabinet.begin(4.0, -10.0, 10.0, 0.5);

  // 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 Temperature Controlled Cabinet 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 the network. Ready for use.");
  }

  // Print initial configuration
  Serial.println("\nTemperature Controlled Cabinet Configuration:");
  Serial.printf("  Setpoint: %.02f°C\n", TemperatureCabinet.getTemperatureSetpoint());
  Serial.printf("  Min Temperature: %.02f°C\n", TemperatureCabinet.getMinTemperature());
  Serial.printf("  Max Temperature: %.02f°C\n", TemperatureCabinet.getMaxTemperature());
  Serial.printf("  Step: %.02f°C\n", TemperatureCabinet.getStep());
}

void loop() {
  static uint32_t timeCounter = 0;
  static uint32_t lastUpdateTime = 0;

  // Initialize temperature control state on first run
  initTemperatureControl();

  // Update temperature setpoint dynamically every 1 second
  uint32_t currentTime = millis();
  if (currentTime - lastUpdateTime >= 1000) {  // 1 second interval
    lastUpdateTime = currentTime;
    updateTemperatureSetpoint();
  }

  // Print the current temperature setpoint every 5s
  if (!(timeCounter++ % 10)) {  // delaying for 500ms x 10 = 5s
    printTemperatureStatus();
  }

  // Handle button press for decommissioning
  handleButtonPress();

  delay(500);
}

Temperature Controlled Cabinet (Level Mode)

A separate example demonstrates the temperature_level mode with dynamic level updates. The temperature level automatically cycles through all supported levels every 1 second in both directions (increasing and decreasing), allowing Matter controllers to observe real-time changes. The example also monitors and logs when the initial level is reached or overpassed in each direction.

See MatterTemperatureControlledCabinetLevels example for the temperature level mode implementation.