ESP32 Matter: Temperature and Humidity with BME280 (Arduino) – Alexa, Apple Home, Google, etc…

This guide shows you how to create a Matter ESP32 compatible device that sends temperature, humidity, and pressure readings from a BME280 sensor. The device can be commissioned into Apple Home, Google Home, Amazon Alexa, Home Assistant, or other Matter controllers. The ESP32 will be programmed with Arduini IDE.

ESP32 Matter Temperature and Humidity with BME280 Arduino Alexa Apple Home Google

Prerequisites

Before proceeding with this tutorial, you should have the ESP32 boards installed in your Arduino IDE:

You will also need an ESP32 development board model of your choice and a Home Automation controller like Amazon Echo Dot Max (Alexa).

Matter Protocol Introduction

Matter, formerly known as Project CHIP (Connected Home over IP), is an open-source and industry standard connectivity protocol for smart home devices. Matter protocol was developed by the Connectivity Standards Alliance (CSA) with contributions from major companies including Apple, Google, Amazon, Samsung, and others. Matter aims to solve the fragmentation problem where each company builds its own proprietary protocol to interact with its devices.

Matter icon logo

Key features of the Matter protocol:

  • Interoperability: devices from different manufacturers work together seamlessly in the same ecosystem (Apple Home, Google Home, Amazon Alexa, Home Assistant, Samsung SmartThings, etc…).
  • Local control: communication happens primarily on the local network (Wi-Fi, Thread, or Ethernet). The Cloud connectivity is optional.
  • Security: built-in encrypted communication and secure commissioning.
  • Simple setup: devices are commissioned using a QR code or a manual pairing code.
  • Multi-admin support: a single device can be controlled by multiple smart home controllers at the same time.
  • IP-based: runs over standard IP networks.
Matter Protocol with ESP32 Overview Topology

A few concepts worth knowing before you dive into this guide:

  • Node: a single Matter device (example: in this guide the ESP32 is a node).
  • Endpoint: a functional unit inside a node. A single node (Matter device) can expose multiple endpoints (example: temperature/humidity sensor).
  • Cluster: a group of related attributes and commands tied to a function (example: the Temperature Measurement cluster has a MeasuredValue attribute).
  • Fabric: the logical network created when a controller (Apple Home, Google Home, Alexa, Home Assistant, etc…) commissions your device. A node can belong to multiple fabrics at once.
  • Commissioning: the process of assigning a Matter device (node) to a fabric, using a QR code or an 11-digit manual pairing code. It’s typically done over BLE or Wi-Fi.
  • Wi-Fi: Matter runs over IP, and nodes (example: ESP32 devices) can join a Matter network over Wi-Fi.

The ESP32 Arduino Core since version 3.1.0 comes with the Matter library, so you don’t need to install any additional libraries in your Arduino IDE.

Typical Matter Device Workflow

The following diagram illustrates the complete workflow of a Matter device from when it is uncommissioned to normal operation and optional sharing across multiple smart home controller ecosystems.

Typical Matter Protocol Topology  Device Workflow Sequence

1. Uncommissioned Device / Node

  • First device usage (or after reset)
  • Shows QR code + manual pairing code
  • User scans QR code or enters manual pairing code into a smart home controller (fabric): Alexa, Apple Home, Google Home, Home Assistant, etc…

2. Commissioning

  • Secure pairing session starts (PASE)
  • Confirms it’s a Matter device
  • Wi-Fi credentials are given (usually over BLE)
  • Device joins the Matter fabric (example: Alexa – Echo Dot Max)

3. Joins the Network

  • Connects to Wi-Fi
  • Becomes reachable via IPv6 + mDNS

4. Normal Operation

  • Controllers discover and control the Matter device
  • All communication is encrypted
  • Works locally even without internet

5. Multi-admin (optional)

  • Original QR/pairing code cannot be reused
  • Open pairing mode from the first connected app to generate / share device by creating a new temporary manual pairing code
  • Use the new generated code to add the device to another ecosystem: Apple Home, Google Home, Home Assistant, etc…
  • The same Matter device belongs to multiple fabrics and can be controlled by several ecosystems at the same time

Supported ESP32 Chips

The following ESP32 chips support the Matter protocol. Additionally, it also shows which ones support CHIPoBLE. For chips that don’t support it, the credentials need to be inserted in the sketch. In the other scenarios, they are transferred over BLE from the controller.

ChipCommissioning PathCHIPoBLE *
ESP32Wi-Fi (enter SSID/Password in sketch)Off
ESP32-S2Wi-Fi (enter SSID/Password in sketch)Off
ESP32-S3Wi-Fi (fabric/controller)On
ESP32-C3Wi-Fi (fabric/controller)On
ESP32-C5Wi-Fi (fabric/controller)On
ESP32-C6Wi-Fi (fabric/controller)On
ESP32-H2Thread (fabric/controller)On

* CHIPoBLE stands for CHIP (Connected Home over IP), the original name of the Matter protocol, over BLE (Bluetooth Low Energy).

Parts Required

To complete this tutorial, you need the following parts:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

The BME280 sensor module reads barometric pressure, temperature, and humidity. There are several versions of this sensor module. We’re using the module illustrated in the figure below.

BME280 Sensor I2C Module reads pressure, temperature, and humidity

This sensor communicates via I2C communication protocol. You can use the default ESP32 I2C pins as shown in the following table:

BME280ESP32ESP32-S3
Vin3.3V3.3V
GNDGNDGND
SCLGPIO 22GPIO 9
SDAGPIO 21GPIO 8 

If you have a different ESP32 board model, double-check its pinout to locate the default I2C pins.

Schematic – ESP32 with BME280 using I2C

Wire the BME280 sensor to the ESP32 SDA and SCL pins, as shown in the following schematic diagram (check ESP32 Pinout Reference).

ESP32 with BME280 Wiring Schematic Diagram I2C

In the case of ESP32-S3 boards, the I2C pins are SDA connected to GPIO 8 and SCL connected to GPIO 9, as shown in the following schematic diagram (check ESP32-S3 GPIO Reference Guide).

ESP-IDF ESP32 BME280 Sensor I2C SDA SCL Wiring Schematic Diagram

Installing BME280 Library

For this tutorial, we’ll use a BME280 sensor and the Adafruit_BME280 library. Install it before proceeding.

In the Arduino IDE, go to Sketch > Include Library > Manage Libraries… and search for the library name: Adafruit BME280. You also need to install the Adafruit Unified Sensor Library (a pop-up shows up to install it if you haven’t already)

Installing Adafruit BME280 Sensor Library Arduino IDE

Arduino Sketch – ESP32 Matter Device: Send Temperature, Humidity, and Pressure

The following example is based on the official Espressif Arduino ESP32 Matter library. It turns your ESP32 into a fully functional Matter device (node) that sends readings from a BME280 sensor. The device can be commissioned into any major Matter ecosystem.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-matter-temperature-humidity-bme280-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#include <Matter.h>
#include <Wire.h>
#include <Adafruit_BME280.h>

// Wi-Fi credentials for this sketch. Fill these in when the board cannot commission over BLE (Arduino prebuild on ESP32 / ESP32-S2): the sketch
// joins the AP itself. When Matter commissions over BLE (CHIPoBLE), the hub sends SSID and password — leave the placeholders; they are unused.
#define WIFI_SSID     "your-ssid"
#define WIFI_PASSWORD "your-password"

// Matter endpoints
MatterTemperatureSensor TemperatureSensor;
MatterHumiditySensor HumiditySensor;
MatterPressureSensor PressureSensor;

// I2C pins for the BME280
#define I2C_SDA 8
#define I2C_SCL 9

// BME280 
Adafruit_BME280 bme;

// Latest BME280 readings
float temperature, humidity, pressure;

// Update interval for the BME280 sensor readings (in milliseconds)
const uint32_t SENSOR_INTERVAL_MS = 30000;

// Button pin for decommissioning the Matter accessory
const uint8_t buttonPin = BOOT_PIN;
MatterButton button;

// Read BME280 sensor values
bool readBME280() {
  temperature = bme.readTemperature();
  humidity = bme.readHumidity();
  pressure = bme.readPressure() / 100.0F;
  return !(isnan(temperature) || isnan(humidity) || isnan(pressure));
}

void setup() {
  button.begin(buttonPin);

  Serial.begin(115200);

  // Initialize BME280 Sensor
  Wire.begin(I2C_SDA, I2C_SCL);
  if (!bme.begin(0x76, &Wire) && !bme.begin(0x77, &Wire)) {
    Serial.println("BME280 not found!");
    while(1); 
  }

// Connect to Wi-Fi if CHIPoBLE is not enabled
#if !CONFIG_ENABLE_CHIPOBLE
  matterConnectWiFi(WIFI_SSID, WIFI_PASSWORD);
#endif

  // Read initial sensor values and initialize Matter endpoints
  readBME280();
  TemperatureSensor.begin(temperature);
  HumiditySensor.begin(humidity);
  PressureSensor.begin(pressure);

  // Start Matter stack and wait until ready
  Matter.begin();
  matterWaitUntilReady();
}

void loop() {
  matterRestartIfNoFabric();

  static uint32_t lastUpdate = 0;
  // Read BME280 sensor values at defined intervals
  if (millis() - lastUpdate >= SENSOR_INTERVAL_MS) {
    lastUpdate = millis();

    if (readBME280()) {
      Serial.printf("Temperature: %.2f C | Humidity: %.2f %% | Pressure: %.2f hPa\r\n",
                    temperature, humidity, pressure);

      TemperatureSensor.setTemperature(temperature);
      HumiditySensor.setHumidity(humidity);
      PressureSensor.setPressure(pressure);
    }
  }

  matterButtonEvent_t ev;
  // Poll the button for events and handle long hold for decommissioning
  while ((ev = button.poll()) != MATTER_BUTTON_NONE) {
    if (ev == MATTER_BUTTON_LONG_HOLD) {
      Serial.println("Decommissioning Matter Accessory. It shall be commissioned again.");
      Matter.decommission();
    }
  }

  delay(100);
}

View raw code

You must select in the Tools – Partition Scheme: “Huge APP (3MB No OT /1MB SPIFFS)” and the code will work straight away. Depending on your board you might need to insert your network credentials in the following lines in the code.

#define WIFI_SSID "REPLACE_WITH_YOUR_SSID";
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD";

How the Code Works

Continue reading to learn how the code works, or skip to the Demonstration section.

Including Libraries

Start by including the following libraries:

#include <Arduino.h>
#include <Matter.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
  • Matter.h – Main Matter library (handles the protocol stack)
  • Wire.h – library for I2C (Two-Wire Interface) communication
  • Adafruit_BME280.h – library for BME280 environmental sensor. It reads temperature, humidity, and barometric pressure

Network Credentials

These Wi-Fi credentials are only needed if the board can’t commission over BLE (Arduino prebuild on ESP32 or ESP32-S2), in that case the sketch joins the network itself. When Matter uses BLE commissioning (CHIPoBLE), the hub provides the SSID and password, so you can leave the default SSID/Password placeholders.

#define WIFI_SSID "REPLACE_WITH_YOUR_SSID";
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD";

Matter Endpoints

These next lines create three Matter sensor objects on the ESP32. Each object represents a virtual Matter device that can report its sensor measurement to a Matter controller.

MatterTemperatureSensor TemperatureSensor;
MatterHumiditySensor HumiditySensor;
MatterPressureSensor PressureSensor;

BME280

Define the pins that the BME280 sensor is connected to. We’re using GPIOs 8 and 9 (ESP32-S3).

// I2C pins for the BME280
#define SDA_PIN 8
#define SCL_PIN 9

Create an instance of the Adafruit_BME280 called bme.

Adafruit_BME280 bme;

Variables that will store the sensor readings:

float temperature, humidity, pressure;

The update interval for the BME280 sensor readings (in milliseconds) by default is set to 30000 ms (30 seconds).

const uint32_t SENSOR_INTERVAL_MS = 30000;

BOOT Button

We’ll use the ESP32 on-board BOOT button (usually GPIO 0) for local GPIO control and factory reset (decommissioning).

const uint8_t buttonPin = BOOT_PIN;
MatterButton button;

Take new readings

This function takes a new BME280 measurement: reads temperature, humidity, and pressure. Then, it returns true if all three readings are valid.

bool readBME280() {
  temperature = bme.readTemperature();
  humidity = bme.readHumidity();
  pressure = bme.readPressure() / 100.0F;
  return !(isnan(temperature) || isnan(humidity) || isnan(pressure));
}

setup()

The setup() function starts by initializing the buttonPin. It also starts the serial communication.

void setup() {
  button.begin(buttonPin);

  Serial.begin(115200);

This code section initializes the I2C bus on the specified pins, tries to connect to a BME280 sensor using the address 0x76 or 0x77. Next, it configures the sensor for forced mode measurements with minimal oversampling and no filtering.

// Initialize BME280 Sensor
Wire.begin(I2C_SDA, I2C_SCL);
if (!bme.begin(0x76, &Wire) && !bme.begin(0x77, &Wire)) {
  Serial.println("BME280 not found!");
  while(1); 
}

Depending on your board, it connects to Wi-Fi using the network credentials if CHIPoBLE is disabled.

// CONFIG_ENABLE_CHIPOBLE=n: sketch starts Wi-Fi here; with CHIPoBLE the hub delivers credentials.
#if !CONFIG_ENABLE_CHIPOBLE
  matterConnectWiFi(WIFI_SSID, WIFI_PASSWORD);
#endif

Read initial sensor values and initialize Matter endpoints:

readBME280();
TemperatureSensor.begin(temperature);
HumiditySensor.begin(humidity);
PressureSensor.begin(pressure);

The first line begins the Matter stack and waits until it is fully ready.

Matter.begin();
matterWaitUntilReady();

loop()

The loop() starts by calling the matterRestartIfNoFabric() function. This is a helper function that checks whether the device is still part of a Matter fabric (it’s still commissioned to a controller). If the device has no fabric (it’s currently decommissioned), it restarts the Matter stack so it can be discovered and commissioned.

matterRestartIfNoFabric();

This next snippet reads the BME280 sensor every 30 seconds, prints the values to Serial, and updates the three Matter sensor endpoints with the new readings (keeping previous values if the read fails).

static uint32_t lastUpdate = 0;
// Read BME280 sensor values at defined intervals
if (millis() - lastUpdate >= SENSOR_INTERVAL_MS) {
  lastUpdate = millis();

  if (readBME280()) {
    Serial.printf("Temperature: %.2f C | Humidity: %.2f %% | Pressure: %.2f hPa\r\n",
                  temperature, humidity, pressure);

    TemperatureSensor.setTemperature(temperature);
    HumiditySensor.setHumidity(humidity);
    PressureSensor.setPressure(pressure);
  }
}

Declares a variable ev of type matterButtonEvent_t that checks for button events (long press).

matterButtonEvent_t ev;

Finally, if the on-board BOOT button is pressed for more than 5 seconds, it removes the device from all Matter fabrics (factory reset). The device will need to be commissioned again.

while ((ev = button.poll()) != MATTER_BUTTON_NONE) {
  if (ev == MATTER_BUTTON_LONG_HOLD) {
    Serial.println("Decommissioning Matter Accessory. It shall be commissioned again.");
    Matter.decommission();
  }
}

Upload Code to Your Board

After inserting your network credentials, follow these next steps to upload the code to the ESP32 board.

First, select your board: Tools – Board – ESP32 Arduino – select your board (for example, ESP32S3 Dev Module).

Then, go to Tools and select the Partition Scheme: “Huge APP (3MB No OT /1MB SPIFFS)”

ESP32 Matter Device Select Huge APP Partition Scheme Arduino IDE

Important: before the first upload, we recommend erasing all the flash memory. Go to Tools and enable the option Erase All Flash Before Sketch Upload: Enabled. This clears previous Wi-Fi credentials and Matter fabric data. Do this at least for the first upload or when commissioning fails.

ESP32 Matter Device Erase Flash Memory Enabled Arduino IDE

Finally, having your board plugged into your computer and with the correct serial port selected, click the Arduino IDE Upload button.

Arduino IDE 2 Upload Button

Commissioning Your ESP32 Matter Device

On the first ESP32 boot (or after erasing all the flash memory), open your Arduino IDE Serial Monitor, press the ESP32 on-board RST/EN button

Open Serial Monitor Arduino 2

It should print something like this:

ESP32 Matter Device Scan QR Code or Copy Manual Pairing Code Arduino IDE Serial Monitor

You can either use the 11-digit manual pairing code or open the URL in your browser to get a QR code to scan in your smart home app.

ESP32 Matter Device Scan QR Code

Add Matter Device to Amazon Alexa

For this example, we’ll be using the Amazon Alexa app, but in the next section we’ll show the steps to add to other controller applications.

First, open the Amazon Alexa app and tap the + icon:

ESP32 Matter Device Node Add to Alexa

Choose the Add Device option:

ESP32 Matter Device Node Adding Device to Alexa

Select Matter logo or Other.

ESP32 Matter Add Device Node Select Matter option

When asked if the device has a logo, select the “YES” option. Then, scan QR code or enter the manual pairing code:

ESP32 Matter Yes Add Matter Device

Having your device fairly close to the matter device, click “Connect“.

ESP32 Matter Device Node Connect Board

The ESP32 is not Matter-certified, but add the device by tapping Yes.

ESP32 Matter Device Node Yes add it

Your ESP32 Matter device will be found and connected; click Next.

ESP32 Matter Sensor Device Node Complete Setup

After successful commissioning, the Arduino IDE serial monitor prints “Matter Node is commissioned…” and the LED reflects the current state.

ESP32 Matter Device Connected Alexa Node Comissioned Arduino IDE Serial Monitor

Your temperature and humidity readings will be added to your Devices list. You can open it as shown in the next image.

ESP32 Matter Sensor Device Reporting Temperature Readings

Note: the Matter temperature attribute is defined in Celsius. The controller converts it for display, so Alexa shows Fahrenheit if your phone or app settings are set to Fahrenheit.

Add Matter Device to Apple Home, Google Home, Home Assistant, or SmartThings

These are the quick instructions on how to add a Matter device to different controller applications. You must have the controller running in your home like Apple Home, Google Home, Home Asssistant or SmartThings.

  • Apple Home:
    • Open the iPhone Home app
    • Tap the + icon in the top right corner
    • Add Accessory
    • Scan QR code or tap the “More options” link to enter the manual pairing code
  • Google Home:
    • Open the Google Home app
    • Tap the + icon
    • Set up device
    • New device
    • Matter device
    • Scan QR code or enter the manual pairing code
  • Home Assistant:
    • Open Home Assistant
    • Go to Settings
    • Devices & Services
    • Add Integration
    • Matter
    • Enter the manual pairing code or scan QR code
  • Samsung SmartThings:
    • Open the SmartThings app
    • Tap the + icon
    • Select Partner devices: Matter
    • Scan QR code or enter the manual pairing code

Important: after commissioning a Matter device to one controller, you cannot reuse the original QR code or manual pairing code to add it to another controller. Instead, you must open a new commissioning window from the first controller’s app (Share / Turn on Pairing Mode / Link to another platform) to generate a temporary new code, then use that code to share the device into the new platform.

Note: some apps may warn that this is not an official or certified device, but you need to select the option to add it.

Demonstration

From a Matter app (like Alexa) or voice hub, you can view or request the temperature and humidity values.

ESP32 Matter Device Temperature Humidity BME280 Readings Demonstration

You can also monitor the readings being sent out every 30 seconds in the Arduino IDE Serial Monitor.

ESP32 Matter Device Send Sensor Readings Demonstration

IMPORTANT: you can hold the ESP32 BOOT button for more than 5 seconds to decommission the Matter device (factory reset). The device must be re-commissioned afterwards with a new QR code or by entering the manual pairing code.

Home Assistant Integration

Some Matter controllers (Alexa, Apple Home) don’t support pressure, but Home Assistant does. You can commission this Matter device into your Home Assistant installation to view all three BME280 readings.

ESP32 Matter Device Connected to Home Assistant

Arduino Sketch – ESP32 Matter Device in Deep Sleep Mode: Temperature, Humidity, and Pressure

The following example turns your ESP32 into a functional Matter device (node) that is constantly in deep sleep to save power, so it can be battery powered. Then, it wakes up at regular intervals to send readings from a BME280 sensor.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-matter-temperature-humidity-bme280-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#include <Matter.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include "esp_sleep.h"

// Matter endpoints
MatterTemperatureSensor TemperatureSensor;
MatterHumiditySensor HumiditySensor;
MatterPressureSensor PressureSensor;

// Wi-Fi credentials for this sketch. Fill these in when the board cannot commission over BLE (Arduino prebuild on ESP32 / ESP32-S2): the sketch
// joins the AP itself. When Matter commissions over BLE (CHIPoBLE), the hub sends SSID and password — leave the placeholders; they are unused.
#define WIFI_SSID     "your-ssid"
#define WIFI_PASSWORD "your-password"

// I2C pins for the BME280
#define I2C_SDA 8
#define I2C_SCL 9

// These 4 strings are used for Matter device identity and commissioning (They have a limit of 32 characters)
const char* MATTER_VENDOR_NAME = "MyESP32";         
const char* MATTER_PRODUCT_NAME = "BME280 Sensor";     
const char* MATTER_DEVICE_NAME = "Living Room BME280";
const char* MATTER_SERIAL_NUMBER = "BME-001";           

// Hardware version
const uint16_t MATTER_HW_VERSION = 1;
// Hardware version string
const char* MATTER_HW_VERSION_STR = "RevA";               

// Commissioning codes: custom manual pairing code / QR code 
const uint32_t MATTER_SETUP_PASSCODE = 20202021;   // 8-digit setup PIN
const uint16_t MATTER_SETUP_DISCRIMINATOR = 0xF00; // 0–4095

const uint32_t FIRST_AWAKE_MS = 5UL * 60UL * 1000UL;  // 5 minutes after first boot or board reset
const uint32_t SENSOR_INTERVAL_MS = 30000;            // 30s while fully awake
const uint32_t SLEEP_TIME_SECONDS = 60;               // Deep sleep interval
const uint32_t ONLINE_TIMEOUT_MS = 20000;             // Wait for CASE on timer wake
const uint32_t POST_UPDATE_AWAKE_MS = 10000;          // Stay awake after publish

// Button pin for decommissioning the Matter accessory
const uint8_t buttonPin = BOOT_PIN;
MatterButton button;

Adafruit_BME280 bme;

bool isTimerWake = false;
uint32_t awakeStartMs = 0;

// Read BME280 sensor values
bool readBME280(float &temperature, float &humidity, float &pressure) {
  if (!bme.takeForcedMeasurement()) {
    return false;
  }
  temperature = bme.readTemperature();
  humidity = bme.readHumidity();
  pressure = bme.readPressure() / 100.0F;
  return !(isnan(temperature) || isnan(humidity) || isnan(pressure));
}

// Go to deep sleep for SLEEP_TIME_SECONDS
void goToDeepSleep() {
  uint64_t sleep_us = (uint64_t)SLEEP_TIME_SECONDS * 1000000ULL;
  esp_sleep_enable_timer_wakeup(sleep_us);

  Serial.printf("Going to deep sleep for %u seconds...\r\n", SLEEP_TIME_SECONDS);
  Serial.flush();
  delay(50);
  esp_deep_sleep_start();
}

// Update sensor readings and publish to Matter endpoints
void updateSensorsAndMatter() {
  float t, h, p;
  if (readBME280(t, h, p)) {
    Serial.printf("Temperature: %.2f C | Humidity: %.2f %% | Pressure: %.2f hPa\r\n", t, h, p);

    TemperatureSensor.setTemperature(t);
    HumiditySensor.setHumidity(h);
    PressureSensor.setPressure(p);
  } else {
    Serial.println("BME280 read failed.");
  }
}

// Handle button events for decommissioning
void handleButton() {
  matterButtonEvent_t ev;
  while ((ev = button.poll()) != MATTER_BUTTON_NONE) {
    if (ev == MATTER_BUTTON_LONG_HOLD) {
      Serial.println("Decommissioning Matter Accessory. It shall be commissioned again.");
      Matter.decommission();
    }
  }
}

// Apply Matter device identity and commissioning codes
void applyMatterIdentity() {
  // These configurations must be called BEFORE Matter.begin()
  Matter.setVendorName(MATTER_VENDOR_NAME);
  Matter.setProductName(MATTER_PRODUCT_NAME);
  Matter.setDeviceName(MATTER_DEVICE_NAME);
  Matter.setSerialNumber(MATTER_SERIAL_NUMBER);
  Matter.setHardwareVersion(MATTER_HW_VERSION);
  Matter.setHardwareVersionString(MATTER_HW_VERSION_STR);

  Matter.setSetupPasscode(MATTER_SETUP_PASSCODE);
  Matter.setSetupDiscriminator(MATTER_SETUP_DISCRIMINATOR);

  Serial.println("Matter identity configured:");
  Serial.printf(" Vendor: %s\r\n", MATTER_VENDOR_NAME);
  Serial.printf(" Product: %s\r\n", MATTER_PRODUCT_NAME);
  Serial.printf(" Device: %s\r\n", MATTER_DEVICE_NAME);
  Serial.printf(" Passcode: %lu\r\n", (unsigned long)MATTER_SETUP_PASSCODE);
  Serial.printf(" Discriminator: 0x%03X (%u)\r\n", MATTER_SETUP_DISCRIMINATOR, MATTER_SETUP_DISCRIMINATOR);
}

void setup() {
  button.begin(buttonPin);
  Serial.begin(115200);
  delay(100);

  // Check wakeup reason
  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  isTimerWake = (cause == ESP_SLEEP_WAKEUP_TIMER);
  if (isTimerWake) {
    Serial.println("Wakeup caused by timer. It will go back to deep sleep after publishing readings.");
  } else {
    Serial.println("ESP32 first boot / reset. It will stay awake for 5 minutes to allow commissioning.");
  }

  // Initialize BME280 sensor
  Wire.begin(I2C_SDA, I2C_SCL);
  if (!bme.begin(0x76, &Wire) && !bme.begin(0x77, &Wire)) {
    Serial.println("BME280 not found - check wiring and I2C pins.");
    while (true) delay(1000);
  }
  bme.setSampling(
    Adafruit_BME280::MODE_FORCED,
    Adafruit_BME280::SAMPLING_X1,
    Adafruit_BME280::SAMPLING_X1,
    Adafruit_BME280::SAMPLING_X1,
    Adafruit_BME280::FILTER_OFF
  );

// Connect to Wi-Fi if CHIPoBLE is not enabled
#if !CONFIG_ENABLE_CHIPOBLE
  matterConnectWiFi(WIFI_SSID, WIFI_PASSWORD);
#endif

  // Read initial sensor values and initialize Matter endpoints
  float t = 0, h = 0, p = 0;
  if (!readBME280(t, h, p)) {
    t = h = p = 0;
  }
  TemperatureSensor.begin(t);
  HumiditySensor.begin(h);
  PressureSensor.begin(p);

  // Apply Matter identity and commissioning codes
  applyMatterIdentity();

  // Start Matter stack and wait until ready
  Matter.begin();
  matterWaitUntilReady();

  // If not commissioned, print manual pairing code and QR code URL
  if (!Matter.isDeviceCommissioned()) {
    Serial.println("----------------------------------------");
    Serial.println("Device not commissioned yet.");
    Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
    Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
    Serial.println("----------------------------------------");
  }

  matterRestartIfNoFabric();

  // If this is a timer wakeup, wait for CASE session and publish readings
  if (isTimerWake) {
    uint32_t t0 = millis();
    while (!Matter.isOnline() && (millis() - t0) < ONLINE_TIMEOUT_MS) {
      matterRestartIfNoFabric();
      handleButton();
      delay(100);
    }

    if (Matter.isOnline()) {
      Serial.println("Controller online (CASE up) – publishing readings");
    } else {
      Serial.println("WARNING: Controller not online – publishing anyway");
    }

    // Publish sensor values
    updateSensorsAndMatter();

    // Stay awake so reports can reach Alexa; re-publish halfway
    Serial.printf("Staying awake %u ms...\r\n", POST_UPDATE_AWAKE_MS);

    t0 = millis();
    bool resent = false;
    while (millis() - t0 < POST_UPDATE_AWAKE_MS) {
      matterRestartIfNoFabric();
      handleButton();

      if (!resent && (millis() - t0) > (POST_UPDATE_AWAKE_MS / 2)) {
        Serial.println("Re-publishing readings...");
        updateSensorsAndMatter();
        resent = true;
      }

      delay(50);
    }

    goToDeepSleep();
  }

  // First boot / reset: one update, then 5 minute fully awake to allow commissioning to other controllers
  updateSensorsAndMatter();
  awakeStartMs = millis();
  Serial.println("Entering 5 minutes awake period...");
}

void loop() {
  // Check if the device is still commissioned. If not, restart to allow re-commissioning
  matterRestartIfNoFabric();
  handleButton();

  // Update sensor readings every SENSOR_INTERVAL_MS
  static uint32_t lastUpdate = 0;
  if (millis() - lastUpdate >= SENSOR_INTERVAL_MS) {
    lastUpdate = millis();
    updateSensorsAndMatter();
  }

  // After 5 minutes, go to deep sleep
  if (millis() - awakeStartMs >= FIRST_AWAKE_MS) {
    Serial.println("5 minutes finished: entering deep sleep cycle.");
    goToDeepSleep();
  }

  delay(50);
}

View raw code

You must select in the Tools – Partition Scheme: “Huge APP (3MB No OT /1MB SPIFFS)” and the code will work straight away. Depending on your board, you might need to insert your network credentials in the following lines in the code.

#define WIFI_SSID "REPLACE_WITH_YOUR_SSID";
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD";

When you board first powers on or resets, it stays fully awake for 5 minutes, reading the BME280 and sending temperature, humidity, and pressure to the Matter controller every 30 seconds while also watching the BOOT button for a long press decommission or re-commissioned to another controller.

ESP32 Matter Device Send Sensor Readings DeepSleep Demonstration

After that 5-minute window, your board enters into the following deep sleep cycle:

  1. It deep sleeps for 60 seconds (wakes on a timer wake up).
  2. Reconnects Wi‑Fi/Matter.
  3. Publishes the latest sensor values.
  4. Stays awake another 20 seconds (re-publishing once halfway through so your controller has a better chance to receive the reports).
  5. Finally, goes back to deep sleep.

As described earlier, powering the board or pressing the on-board reset button wakes your ESP32 for 5 minutes, so you can decommission or share it with another controller.

ESP32 Matter Device Send Temperature Humidity BME280 Readings DeepSleep Demonstration

Troubleshooting

The following table shows the most common errors when following this tutorial, and possible solutions.

ErrorSolution
Sketch too large / not enough space / compilation failsIn the Tools menu, you must select the option: Partition Scheme: “Huge APP (3MB No OT /1MB SPIFFS)”
Device never shows the pairing codeCheck that you’ve entered the correct SSID/password in your code
Commissioning fails after previous attempt / Want to re-commission to another controller– Press the BOOT button for 5 seconds

– Or you can also go to Tools and enable the option Erase All Flash Before Sketch Upload: Enabled, then re-upload the code to your board
No serial output printedPress the RST/EN button to restart the ESP32 while the Arduino IDE Serial Monitor is open with 115200 baud rate with the correct serial port selected

Note: in the Arduino IDE Serial monitor, you might see many log messages being printed over time and right after setup. You might see messages like “sending failed”, “transient send error”, “request on unknown cluster”, or similar. They’re usually harmless, and you can ignore them unless the device stays unreachable.

Wrapping Up

In this guide, you learned how to turn your ESP32 into a Matter device that reports temperature, humidity and pressure readings from a BME280 sensor. You’ve also learned the basics about the Matter protocol and how to commission the device to different controllers, such as Alexa, Apple Home, Google Home, Home Assistant, and SmartThings.

We have a similar tutorial for an On/Off Matter device, check it out below:

If you liked this project, you may also like these other tutorials:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.