Files
2026-05-22 21:52:50 +03:00
..
2026-05-22 21:52:50 +03:00
2026-05-22 21:52:50 +03:00
2026-05-22 21:52:50 +03:00

Matter Window Covering Example

This example demonstrates how to create a Matter-compatible window covering device using an ESP32 SoC microcontroller. The application showcases Matter commissioning, device control via smart home ecosystems, and manual control using a physical button.

Supported Targets

SoC Wi-Fi Thread BLE Commissioning Status
ESP32 Fully supported
ESP32-S2 Fully supported
ESP32-S3 Fully supported
ESP32-C3 Fully supported
ESP32-C5 Supported (Thread only)
ESP32-C6 Fully supported
ESP32-H2 Supported (Thread only)

Note on Commissioning:

  • ESP32 & ESP32-S2 do not support commissioning over Bluetooth LE. For these chips, you must provide Wi-Fi credentials directly in the sketch code so they can connect to your network manually.
  • ESP32-C6 Although it has Thread support, the ESP32 Arduino Matter Library has been precompiled using Wi-Fi only. In order to configure it for Thread-only operation it is necessary to build the project using Arduino as an IDF Component and to disable the Matter Wi-Fi station feature.
  • ESP32-C5 Although it has Wi-Fi 2.4 GHz and 5 GHz support, the ESP32 Arduino Matter Library has been pre compiled using Thread only. In order to configure it for Wi-Fi operation it is necessary to build the project using Arduino as an ESP-IDF component and disable Thread network, keeping only Wi-Fi station.

Features

  • Matter protocol implementation for a window covering device
  • Support for both Wi-Fi and Thread(*) connectivity
  • Lift position and percentage control (0-100%) - Lift represents the physical position (centimeters)
  • Tilt rotation and percentage control (0-100%) - Tilt represents rotation of the shade, not a linear measurement
  • Multiple window covering types support
  • State persistence using Preferences library
  • Button control for manual lift adjustment and factory reset
  • RGB LED visualization of lift (brightness) and tilt (color) positions
  • Installed limit configuration for lift (cm) and tilt (absolute values)
  • Matter commissioning via QR code or manual pairing code
  • Integration with Apple HomeKit, Amazon Alexa, and Google Home (*) It is necessary to compile the project using Arduino as IDF Component.

Hardware Requirements

  • ESP32 compatible development board (see supported targets table)
  • RGB LED for visualization (uses built-in RGB LED if available)
  • User button for manual control (uses BOOT button by default)

Pin Configuration

  • RGB LED: Uses RGB_BUILTIN if defined (for visualization), otherwise pin 2. The LED brightness represents lift position (0% = off, 100% = full brightness), and color represents tilt rotation (red = 0%, blue = 100%).
  • Button: Uses BOOT_PIN by default

Software Setup

Prerequisites

  1. Install the Arduino IDE (2.0 or newer recommended)
  2. Install ESP32 Arduino Core with Matter support
  3. ESP32 Arduino libraries:
    • Matter
    • Preferences
    • Wi-Fi (only for ESP32 and ESP32-S2)

Configuration

Before uploading the sketch, configure the following:

  1. Wi-Fi credentials (if not using BLE commissioning - mandatory for ESP32 | ESP32-S2):

    const char *ssid = "your-ssid";         // Change to your Wi-Fi SSID
    const char *password = "your-password"; // Change to your Wi-Fi password
    
  2. RGB LED pin configuration (if not using built-in RGB LED):

    const uint8_t ledPin = 2;  // Set your RGB LED pin here
    
  3. Button pin configuration (optional): By default, the BOOT button (GPIO 0) is used for manual lift control and factory reset. You can change this to a different pin if needed.

    const uint8_t buttonPin = BOOT_PIN;  // Set your button pin here
    

Building and Flashing

  1. Open the MatterWindowCovering.ino sketch in the Arduino IDE.
  2. Select your ESP32 board from the Tools > Board menu.
  1. Select "Huge APP (3MB No OTA/1MB SPIFFS)" from Tools > Partition Scheme menu.
  1. Enable "Erase All Flash Before Sketch Upload" option from Tools menu.
  2. Connect your ESP32 board to your computer via USB.
  3. Click the Upload button to compile and flash the sketch.

Expected Output

Once the sketch is running, open the Serial Monitor at a baud rate of 115200. The Wi-Fi connection messages will be displayed only for ESP32 and ESP32-S2. Other targets will use Matter CHIPoBLE to automatically setup the IP Network. You should see output similar to the following:

Connecting to your-wifi-ssid
.......
WiFi connected
IP address: 192.168.1.100

Matter Node is not commissioned yet.
Initiate the device discovery in your Matter environment.
Commission it to your Matter hub with the manual pairing code or QR code
Manual pairing code: 34970112332
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3A6FCJ142C00KA0648G00
Matter Node not commissioned yet. Waiting for commissioning.
...
Initial state: Lift=100%, Tilt=0%
Matter Node is commissioned and connected to the network. Ready for use.
Window Covering changed: Lift=100%, Tilt=0%
Moving lift to 50% (position: 100 cm)
Window Covering changed: Lift=50%, Tilt=0%

Using the Device

Manual Control

The user button (BOOT button by default) provides manual control:

  • Short press of the button: Cycle lift percentage by 20% increments. If the current position is not a multiple of 20%, it will round up to the next multiple of 20%. Otherwise, it will add 20% (0% → 20% → 40% → ... → 100% → 0%)
  • Long press (>5 seconds): Factory reset the device (decommission)

State Persistence

The device saves the last known lift and tilt percentages using the Preferences library. After a power cycle or restart:

  • The device will restore to the last saved lift and tilt percentages
  • Default state is 100% lift (fully open) and 0% tilt if no previous state was saved
  • The Matter controller will be notified of the restored state
  • The RGB LED will reflect the restored state

RGB LED Visualization

The RGB LED provides visual feedback:

  • Brightness: Represents lift position (0% = off, 100% = full brightness)
  • Color: Represents tilt position (red = 0% tilt, blue = 100% tilt)
  • For boards without RGB LED, only brightness is used

Window Covering Integration

For production use with a motorized window covering:

  1. Motor Control:

    • Connect your motor driver to your ESP32
    • Update the callback functions (fullOpen(), fullClose(), goToLiftPercentage(), goToTiltPercentage(), stopMotor()) to control your actual motor
    • The example currently simulates movement instantly - replace with actual motor control code
  2. Position Feedback:

    • Use encoders or limit switches to provide position feedback
    • For lift: Update currentLift (cm) based on actual motor position
    • For tilt: Update currentTiltPercent (rotation percentage) based on actual motor rotation
    • Important: Call setLiftPercentage() and setTiltPercentage() in your onGoToLiftPercentage() or onGoToTiltPercentage() callbacks to update CurrentPosition attributes when the physical device actually moves. This will trigger the onChange() callback if registered.
    • Call setOperationalState(LIFT, STALL) or setOperationalState(TILT, STALL) when movement is complete to indicate the device has reached the target position
    • Configure installed limits using setInstalledOpenLimitLift(), setInstalledClosedLimitLift(), setInstalledOpenLimitTilt(), and setInstalledClosedLimitTilt() to define the physical range of your window covering

    Callback Flow:

    • Matter command → TargetPosition changes → onGoToLiftPercentage()/onGoToTiltPercentage() called
    • Your callback moves the motor → When movement completes, call setLiftPercentage()/setTiltPercentage()
    • setLiftPercentage()/setTiltPercentage() update CurrentPositiononChange() called (if registered)
  3. Window Covering Type:

    • Pass the covering type to begin() to configure the appropriate type (e.g., BLIND_LIFT_AND_TILT, ROLLERSHADE, etc.)
    • Different types support different features (lift only, tilt only, or both)
    • The covering type must be specified during initialization to ensure the correct features are enabled

Smart Home Integration

Use a Matter-compatible hub (like an Apple HomePod, Google Nest Hub, or Amazon Echo) to commission the device.

Apple Home

  1. Open the Home app on your iOS device
  2. Tap the "+" button > Add Accessory
  3. Scan the QR code displayed in the Serial Monitor, or
  4. Tap "I Don't Have a Code or Cannot Scan" and enter the manual pairing code
  5. Follow the prompts to complete setup
  6. The device will appear as a window covering/blind in your Home app
  7. You can control both lift and tilt positions using sliders

Amazon Alexa

  1. Open the Alexa app
  2. Tap More > Add Device > Matter
  3. Select "Scan QR code" or "Enter code manually"
  4. Complete the setup process
  5. The window covering will appear in your Alexa app
  6. You can control positions using voice commands like "Alexa, set blinds to 50 percent"

Google Home

  1. Open the Google Home app
  2. Tap "+" > Set up device > New device
  3. Choose "Matter device"
  4. Scan the QR code or enter the manual pairing code
  5. Follow the prompts to complete setup
  6. You can control positions using voice commands or sliders in the app

Code Structure

The MatterWindowCovering example consists of the following main components:

  1. setup(): Initializes hardware (button, RGB LED), configures Wi-Fi (if needed), initializes Preferences library, sets up the Matter window covering endpoint with the last saved state, registers callback functions, and starts the Matter stack.

  2. loop(): Checks the Matter commissioning state, handles button input for manual lift control and factory reset, and allows the Matter stack to process events.

  3. Callbacks:

    Target Position Callbacks (called when TargetPosition attributes change):

    • fullOpen(): Registered with onOpen() - called when UpOrOpen command is received. Moves window covering to fully open (100% lift), calls setLiftPercentage() to update CurrentPosition, and sets operational state to STALL
    • fullClose(): Registered with onClose() - called when DownOrClose command is received. Moves window covering to fully closed (0% lift), calls setLiftPercentage() to update CurrentPosition, and sets operational state to STALL
    • goToLiftPercentage(): Registered with onGoToLiftPercentage() - called when TargetPositionLiftPercent100ths changes (from commands, setTargetLiftPercent100ths(), or direct attribute writes). Calculates absolute position (cm) based on installed limits, calls setLiftPercentage() to update CurrentPosition, and sets operational state to STALL when movement is complete
    • goToTiltPercentage(): Registered with onGoToTiltPercentage() - called when TargetPositionTiltPercent100ths changes. Calls setTiltPercentage() to update CurrentPosition, and sets operational state to STALL when movement is complete
    • stopMotor(): Registered with onStop() - called when StopMotion command is received. Stops any ongoing movement, calls setLiftPercentage() and setTiltPercentage() to update CurrentPosition for both, and sets operational state to STALL for both

    Current Position Callback (called when CurrentPosition attributes change):

    • onChange(): Registered with onChange() - called when CurrentPositionLiftPercent100ths or CurrentPositionTiltPercent100ths change (after setLiftPercentage() or setTiltPercentage() are called). Updates RGB LED visualization to reflect current positions

    Note: The Target Position callbacks (fullOpen(), fullClose(), goToLiftPercentage(), goToTiltPercentage(), stopMotor()) call setLiftPercentage() or setTiltPercentage() to update the CurrentPosition attributes. This triggers the onChange() callback, which updates the visualization.

Troubleshooting

  • Device not visible during commissioning: Ensure Wi-Fi or Thread connectivity is properly configured
  • Window covering not responding: Verify callback functions are properly implemented and motor control is working
  • Position not updating: Check that setLiftPercentage() and setTiltPercentage() are being called with correct values
  • State not persisting: Check that the Preferences library is properly initialized and that flash memory is not corrupted
  • RGB LED not working: For RGB LED, verify the pin supports RGB LED control. For non-RGB boards, ensure the pin supports PWM (analogWrite)
  • Tilt not working: Ensure the covering type supports tilt (e.g., BLIND_LIFT_AND_TILT, SHUTTER, or BLIND_TILT_ONLY) and that it is specified in begin()
  • Failed to commission: Try factory resetting the device by long-pressing the button. Other option would be to erase the SoC Flash Memory by using Arduino IDE Menu -> Tools -> Erase All Flash Before Sketch Upload: "Enabled" or directly with esptool.py --port <PORT> erase_flash
  • No serial output: Check baudrate (115200) and USB connection

License

This example is licensed under the Apache License, Version 2.0.