The following instructions use the
[lighting app](https://github.com/project-chip/connectedhomeip/tree/v1.0-branch/examples/lighting-app)
example from the Matter SDK along with an M5Stack ESP32
development board.

## Build environment setup

First, clone the Matter SDK.

In this example, we check out the minimum supported commit for Google Home's
Matter Release 5:

```bash
mkdir otaprep
```

```bash
cd otaprep
```

    `git clone https://github.com/project-chip/connectedhomeip.git`
    `cd connectedhomeip`
    `git fetch origin v1.0-branch`
    `git checkout FETCH_HEAD`
    `git submodule update --init --recursive`
    `source ./scripts/activate.sh`

Next, we check the version used in the ESP32 GitHub Workflow to determine
which Docker image best suits our build:

```bash
cat .github/workflows/examples-esp32.yaml | grep chip-build | head -n 1
```

```bash
image: connectedhomeip/chip-build-esp32:0.5.99
```

We run a container from the Docker image, passing flags to mount the
Matter SDK in the container and to provide access to the
ESP32 device.

```bash
docker run --name container_name -it --user $(id -u):$(id -g)--mount source=$(pwd),target=/workspace,type=bind --device=/dev/ttyUSB0 connectedhomeip/chip-build-esp32:0.5.99 /bin/bash
```

> [!NOTE]
> **Note:** The argument `--user $(id -u):$(id -g)` allows one to run the container as the current user, instead of the default (`root`). This avoids problems ownership of files generated by the build in the local Matter SDK repository. It also has two minor but harmless side effects to be aware of:  
> 1. When you first run the container, you may see the message `groups: cannot find name for group ID XXXX`, and  
> 2. The `bash` prompt in the container starts with `I have no name!`.

## Stop and start the Matter Docker container

Whenever you run a `docker run` command, you'll create a new container with
the specified image. When you do this, your old data, which was saved on a
previous container instance, is lost. Sometimes this is what you want to
happen, because it allows you to start with a fresh installation. But in this
example you most likely want to save your work and environment configuration
between sessions.

    user@host> docker stop container_name

When you are ready to run again, start the container and open a terminal
window:

    user@host> docker start container_name
    user@host> docker exec -it container_name /bin/bash

You may open additional terminal sessions to your container with:

    user@host> docker exec -it container_name /bin/bash

Or start a root session using:

    user@host> docker exec -u 0 -it container_name /bin/bash

## Initialize the SDK

In the container, we initialize the Matter SDK and ESP IDF:

```bash
cd /workspace
```

```bash
git submodule update --init --recursive
```

```bash
source ./scripts/activate.sh
```

```bash
source /opt/espressif/esp-idf/export.sh
```

## Build and flash

The next task is to build the image and flash the development kit to receive
the Matter OTA firmware update.

To do this, you must create an image.

First configure the build using the `menuconfig` utility from the ESP IDF.

```bash
cd examples/lighting-app/esp32
idf.py menuconfig
```

In the interactive menu, configure the following settings:

1. `Component config --->`

2. `CHIP Device Layer --->`

3. `Device Identification Options --->`

4. Set `Vendor ID` to your Connectivity Standards Alliance (Alliance)-assigned VID.

5. Set `Product ID` to the PID you set on the Matter
   integration in the Google Home Developer Console.

Enable the OTA Requestor flag:

1. `Component config -->`

2. `CHIP Core -->`

3. `System options --->`

4. Enable the OTA Requestor flag `[*] Enable OTA Requestor`

5. Press **ESC** twice to return to the top level menu.

Enable the Matter OTA Image creation flag:

1. `Component config -->`

2. `CHIP Device Layer --->`

3. `Matter OTA Image --->`

4. `[*] Generate OTA IMAGE`

Set the version number:

1. `Application manager --->`

2. Select `[*] Get the project version from Kconfig`

3. Set `Project version (NEW)` to `1.0`

4. Press **s** to save the configuration, press **Enter** twice, then **q** to
   exit `menuconfig`.

## Set up test certificates

Follow the steps in
[Create Matter device test certificates](https://developers.home.google.com/matter/test/certificates.md.txt) to create
CD, DAC, and PAI certificates.

## Build your device

Now run the build and flash the device:

```bash
idf.py build
idf.py -p /dev/ttyUSB0 erase_flash
idf.py -p /dev/ttyUSB0 flash
```

## Create and upload the OTA image

Now change the build settings again to create an OTA image. Use the
same image, but with an incremented version number.

Run `menuconfig`.

```bash
idf.py menuconfig
```

In the interactive menu, update the following:

1. `Application manager --->`
2. Select `[*] Get the project version from Kconfig`
3. Set `Project version (NEW)` to `2.0`
4. Press **s** to save the configuration, press **Enter** twice, then press **q** to exit `menuconfig`.

Build and retrieve the image. The example demonstrates both the location
of the image for OTA and the output when parsing with the `ota_image_tool.py`.

```bash
cd build && /workspace/src/app/ota_image_tool.py show ./chip-lighting-app-ota.bin
```

The output is as follows:

    Magic: 1beef11e
    Total Size: 1243360
    Header Size: 64
    Header TLV:
      [0] Vendor Id: XXXXX (0x000)
      [1] Product Id: XXXXX (0x000)
      [2] Version: 2 (0x2)
      [3] Version String: v2.0
      [4] Payload Size: 1243280 (0x12f890)
      [8] Digest Type: 1 (0x1)
      [9] Digest: e367f4d71e2ccd554b9a399c864abbf2c039382ef1def1b986fb2f59a99923a8

Because the Matter SDK is mounted from your container host,
the OTA image is available on your container host.

Upload the OTA image to the Developer Console by following the
[OTA upload instructions](https://developers.home.google.com/matter/ota/configuration.md.txt#upload_the_ota_image).

## Commission to Google Home and observe OTA

Ensure your device is connected to the host Linux machine with USB. The
following example shows the use of GNU `screen` to read the device logs:

```bash
screen -L /dev/ttyUSB0 115200
```

This displays the output from the device to your terminal and writes the
same output to the default screen log file named `screenlog.0`.

You may open the `screenlog.0` file in another text editor or display it in
another shell with `cat`, `tail`, `more`, or `grep`.

Press the red reset button on the side of the device to see logs from boot.

In the device output, you should see the VID and PID you set earlier, as well
as a URL to the QR code image that you'll use to commission the device.

    [0;32mI (2388) chip[DIS]: Advertise commission parameter vendorID=XXXXX productID=XXXX discriminator=3840/15 cm=1[0m

    [0;32mI (1928) chip[SVR]: SetupQRCode: [MT:E59-000000000000000][0m

    https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT%3AE59-000000000000000

Ensure your Hub is online in your home.

Commission the device with the Google Home app (GHA) using the QR code from
the link that appears in the log file.

Let the device run uninterrupted for several minutes after commissioning.
You should observe log output related to OTA Requestor, OTA image download,
and `OTAImageProcessor`.

After the image is installed, observe that the compile time of the image
matches that of the one uploaded to the console, and is later than the
compile time that was reported at first boot. Executing `grep` with the
following pattern in regular expression mode on `screenlog.0` can illustrate
the OTA process:

```bash
grep -E "(Compile time|OTA)" screenlog.0
```

The output is as follows:

    I (76) boot:  1 otadata          OTA data         01 00 0000f000 00002000
    I (91) boot:  3 ota_0            OTA app          00 10 00020000 00177000
    I (99) boot:  4 ota_1            OTA app          00 11 001a0000 00177000
    I (645) cpu_start: Compile time:     Oct 15 2022 06:21:59
    I (135558) chip[SWU]: OTA Requestor received AnnounceOTAProvider
    I (540658) chip[SWU]: OTA image downloaded to offset 0x1a0000
    I (541348) OTAImageProcessor: Applying, Boot partition set offset:0x1a0000
    I (76) boot:  1 otadata          OTA data         01 00 0000f000 00002000
    I (91) boot:  3 ota_0            OTA app          00 10 00020000 00177000
    I (99) boot:  4 ota_1            OTA app          00 11 001a0000 00177000
    I (645) cpu_start: Compile time:     Oct 15 2022 07:35:31
    I (76) boot:  1 otadata          OTA data         01 00 0000f000 00002000
    I (91) boot:  3 ota_0            OTA app          00 10 00020000 00177000
    I (99) boot:  4 ota_1            OTA app          00 11 001a0000 00177000
    I (645) cpu_start: Compile time:     Oct 15 2022 07:35:31

After initial execution, you may repeat the steps in the section
[Create and upload OTA image](https://developers.home.google.com/matter/ota/test/vendors/espressif.md.txt#create_and_upload_the_ota_image) without uploading a new image.
This time, set the versions back to `1`.

Run `menuconfig`, and in the interactive menu options:

1. `Component config -->`

2. `CHIP Device Layer --->`

3. `Device Identification Options`

4. Set `Version String` to `v1.0`.

5. Set `Device Software Version Number` to `1`.

6. Press **s** to save the configuration, then **q** to exit `menuconfig`.

Remove the device from your home in the GHA.

Build the image, if it's not already built:

```bash
idf.py build
```

Flash it:

```bash
idf.py -p /dev/ttyUSB0 erase_flash
```

```bash
idf.py -p /dev/ttyUSB0 flash
```

Repeat the steps in **Commission to Google Home and observe OTA** as needed.

## Validate the OTA Software Update

The device software version can be checked using the Google Home App (GHA). Once a device is commissioned, follow these procedures:

1. Long press the device tile on GHA main screen
2. Tap the icon in the top right
3. Tap **Technical information**
4. Check the **Software version** field

![Google Home App screen showing software version field](https://developers.home.google.com/static/matter/ota/images/gha-software-version.png)