[Telink] Add air quality sensor app (#29579)

* [Telink] add draft air quality app

* [Telink] add air-quality example

* [Telink] Clear code

* [Telink] add air-quality example to github-CI

* [Telink] Adopt to latest master chnages

* [Telink] update AppTask of air-quality-sensor-app

* [Telink] use new APIs

* Restyled by whitespace

* Restyled by autopep8

* [Telink] Remove read example due to spelling errors

* [Telink] fix spelling errors

* [Telink] Fix typo

---------

Co-authored-by: UR6LAL <ur6lal@gmail.com>
Co-authored-by: Serhii Salamakha <serhii.salamakha@gmail.com>
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml
index 7951fe5..34afad3 100644
--- a/.github/workflows/examples-telink.yaml
+++ b/.github/workflows/examples-telink.yaml
@@ -54,6 +54,18 @@
               with:
                 gh-context: ${{ toJson(github) }}
 
+            - name: Build example Telink (B92) Air Quality Sensor App
+              run: |
+                  ./scripts/run_in_build_env.sh \
+                    "./scripts/build/build_examples.py --target 'telink-tlsr9528a-air-quality-sensor' build"
+                  .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \
+                    telink tlsr9528a air-quality-sensor-app \
+                    out/telink-tlsr9528a-air-quality-sensor/zephyr/zephyr.elf \
+                    /tmp/bloat_reports/
+
+            - name: clean out build output
+              run: rm -rf ./out
+
             - name: Build example Telink (B91) All Clusters App
               run: |
                   ./scripts/run_in_build_env.sh \
@@ -124,25 +136,13 @@
             - name: clean out build output (keep tools)
               run: rm -rf ./out/telink*
 
-            - name: Build example Telink (B92) Lighting App with RPC, Shell and Factory Data
+            - name: Build example Telink (B92) Light Switch App with RPC, Shell and Factory Data
               run: |
                   ./scripts/run_in_build_env.sh \
-                    "./scripts/build/build_examples.py --target 'telink-tlsr9528a-light-rpc-shell-factory-data' build"
+                    "./scripts/build/build_examples.py --target 'telink-tlsr9528a-light-switch-rpc-shell-factory-data' build"
                   .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \
-                    telink tlsr9528a lighting-app-rpc-shell-factory-data \
-                    out/telink-tlsr9528a-light-rpc-shell-factory-data/zephyr/zephyr.elf \
-                    /tmp/bloat_reports/
-
-            - name: clean out build output
-              run: rm -rf ./out
-
-            - name: Build example Telink (B91) Light Switch App
-              run: |
-                  ./scripts/run_in_build_env.sh \
-                    "./scripts/build/build_examples.py --target 'telink-tlsr9518adk80d-light-switch' build"
-                  .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \
-                    telink tlsr9518adk80d light-switch-app \
-                    out/telink-tlsr9518adk80d-light-switch/zephyr/zephyr.elf \
+                    telink tlsr9528a light-switch-app-rpc-shell-factory-data \
+                    out/telink-tlsr9528a-light-switch-rpc-shell-factory-data/zephyr/zephyr.elf \
                     /tmp/bloat_reports/
 
             - name: clean out build output
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index c5949bd..6d6c19e 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -663,6 +663,7 @@
                 "openiotsdk-lock",
                 "openiotsdk-shell",
                 "qpg-qpg6100-lock",
+                "telink-tlsr9518adk80d-air-quality-sensor",
                 "telink-tlsr9518adk80d-all-clusters",
                 "telink-tlsr9518adk80d-all-clusters-minimal",
                 "telink-tlsr9518adk80d-bridge",
diff --git a/examples/air-quality-sensor-app/telink/.gitignore b/examples/air-quality-sensor-app/telink/.gitignore
new file mode 100644
index 0000000..84c048a
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/.gitignore
@@ -0,0 +1 @@
+/build/
diff --git a/examples/air-quality-sensor-app/telink/CMakeLists.txt b/examples/air-quality-sensor-app/telink/CMakeLists.txt
new file mode 100644
index 0000000..9900d9b
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/CMakeLists.txt
@@ -0,0 +1,86 @@
+#
+#    Copyright (c) 2023 Project CHIP Authors
+#
+#    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.
+#
+cmake_minimum_required(VERSION 3.13.1)
+
+get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connectedhomeip REALPATH)
+get_filename_component(TELINK_COMMON ${CHIP_ROOT}/examples/platform/telink REALPATH)
+get_filename_component(GEN_DIR ${CHIP_ROOT}/zzz_generated/ REALPATH)
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD}.overlay")
+  set(LOCAL_DTC_OVERLAY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD}.overlay")
+else()
+  unset(LOCAL_DTC_OVERLAY_FILE)
+endif()
+
+if(EXISTS "${CHIP_ROOT}/src/platform/telink/${BOARD}.overlay")
+  set(GLOBAL_DTC_OVERLAY_FILE "${CHIP_ROOT}/src/platform/telink/${BOARD}.overlay")
+else()
+  unset(GLOBAL_DTC_OVERLAY_FILE)
+endif()
+
+if(DTC_OVERLAY_FILE)
+  set(DTC_OVERLAY_FILE
+    "${DTC_OVERLAY_FILE} ${GLOBAL_DTC_OVERLAY_FILE} ${LOCAL_DTC_OVERLAY_FILE}"
+    CACHE STRING "" FORCE
+  )
+else()
+  set(DTC_OVERLAY_FILE ${GLOBAL_DTC_OVERLAY_FILE} ${LOCAL_DTC_OVERLAY_FILE})
+endif()
+
+set(CONF_FILE prj.conf)
+
+# Load NCS/Zephyr build system
+list(APPEND ZEPHYR_EXTRA_MODULES ${CHIP_ROOT}/config/telink/chip-module)
+find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
+
+project(chip-telink-air-quality-sensor-example)
+
+include(${CHIP_ROOT}/config/telink/app/enable-gnu-std.cmake)
+include(${CHIP_ROOT}/src/app/chip_data_model.cmake)
+
+target_compile_options(app PRIVATE -fpermissive)
+
+target_include_directories(app PRIVATE
+                           include
+                           ${GEN_DIR}/app-common
+                           ${GEN_DIR}/air-quality-sensor-app
+                           ${TELINK_COMMON}/common/include
+                           ${TELINK_COMMON}/util/include
+                           ${CHIP_ROOT}/examples/air-quality-sensor-app/air-quality-sensor-common/include)
+
+add_definitions(
+    "-DCHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER=<lib/address_resolve/AddressResolve_DefaultImpl.h>"
+)
+
+target_sources(app PRIVATE
+               src/AppTask.cpp
+               src/ZclCallbacks.cpp
+               ${TELINK_COMMON}/common/src/mainCommon.cpp
+               ${TELINK_COMMON}/common/src/AppTaskCommon.cpp
+               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/ButtonManager.cpp
+               ${TELINK_COMMON}/util/src/ThreadUtil.cpp
+               ${TELINK_COMMON}/util/src/PWMDevice.cpp
+               ${CHIP_ROOT}/examples/air-quality-sensor-app/air-quality-sensor-common/src/air-quality-sensor-manager.cpp)
+
+chip_configure_data_model(app
+    INCLUDE_SERVER
+    ZAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../air-quality-sensor-common/air-quality-sensor-app.zap
+)
+
+if(CONFIG_CHIP_OTA_REQUESTOR)
+    target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
+endif()
diff --git a/examples/air-quality-sensor-app/telink/Kconfig b/examples/air-quality-sensor-app/telink/Kconfig
new file mode 100644
index 0000000..e7d4bee
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/Kconfig
@@ -0,0 +1,19 @@
+#
+#    Copyright (c) 2023 Project CHIP Authors
+#
+#    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.
+#
+mainmenu "Matter Telink Air Quality Sensor Example Application"
+
+rsource "../../../config/telink/chip-module/Kconfig.defaults"
+source "Kconfig.zephyr"
diff --git a/examples/air-quality-sensor-app/telink/README.md b/examples/air-quality-sensor-app/telink/README.md
new file mode 100644
index 0000000..371a26c
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/README.md
@@ -0,0 +1,172 @@
+# Matter Telink Air Quality Sensor Example Application
+
+You can use this example as a reference for creating your own application.
+
+![Telink B91 EVK](http://wiki.telink-semi.cn/wiki/assets/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/connection_chart.png)
+
+## Build and flash
+
+1. Run the Docker container:
+
+    ```bash
+    $ docker run -it --rm -v $PWD:/host -w /host ghcr.io/project-chip/chip-build-telink:$(wget -q -O - https://raw.githubusercontent.com/project-chip/connectedhomeip/master/.github/workflows/examples-telink.yaml 2> /dev/null | grep chip-build-telink | awk -F: '{print $NF}')
+    ```
+
+    Compatible docker image version can be found in next file:
+
+    ```bash
+    $ .github/workflows/examples-telink.yaml
+    ```
+
+2. Activate the build environment:
+
+    ```bash
+    $ source ./scripts/activate.sh
+    ```
+
+3. In the example dir run (replace _<build_target>_ with your board name, for
+   example, `tlsr9518adk80d` or `tlsr9528a`):
+
+    ```bash
+    $ west build -b <build_target>
+    ```
+
+4. Flash binary:
+
+    ```
+    $ west flash --erase
+    ```
+
+## Usage
+
+### UART
+
+To get output from device, connect UART to following pins:
+
+| Name | Pin                           |
+| :--: | :---------------------------- |
+|  RX  | PB3 (pin 17 of J34 connector) |
+|  TX  | PB2 (pin 16 of J34 connector) |
+| GND  | GND                           |
+
+### Buttons
+
+The following buttons are available on **tlsr9518adk80d** board:
+
+| Name     | Function               | Description                                                                                            |
+| :------- | :--------------------- | :----------------------------------------------------------------------------------------------------- |
+| Button 1 | Factory reset          | Perform factory reset to forget currently commissioned Thread network and back to uncommissioned state |
+| Button 2 | `AirQuality` control   | Manually triggers the `AirQuality` state                                                               |
+| Button 3 | Thread start           | Commission thread with static credentials and enables the Thread on device                             |
+| Button 4 | Open commission window | The button is opening commissioning window to perform commissioning over BLE                           |
+
+### LEDs
+
+#### Indicate current state of Thread network
+
+**Red** LED indicates current state of Thread network. It is able to be in
+following states:
+
+| State                       | Description                                                                  |
+| :-------------------------- | :--------------------------------------------------------------------------- |
+| Blinks with short pulses    | Device is not commissioned to Thread, Thread is disabled                     |
+| Blinks with frequent pulses | Device is commissioned, Thread enabled. Device trying to JOIN thread network |
+| Blinks with wide pulses     | Device commissioned and joined to thread network as CHILD                    |
+
+#### Indicate identify of device
+
+**Green** LED used to identify the device. The LED starts blinking when the
+Identify command of the Identify cluster is received. The command's argument can
+be used to specify the the effect. It is able to be in following effects:
+
+| Effect                          | Description                                                                  |
+| :------------------------------ | :--------------------------------------------------------------------------- |
+| Blinks (200 ms on/200 ms off)   | Blink (`Clusters::Identify::EffectIdentifierEnum::kBlink`)                   |
+| Breathe (during 1000 ms)        | Breathe (`Clusters::Identify::EffectIdentifierEnum::kBreathe`)               |
+| Blinks (50 ms on/950 ms off)    | Okay (`Clusters::Identify::EffectIdentifierEnum::kOkay`)                     |
+| Blinks (1000 ms on/1000 ms off) | Channel Change ( `Clusters::Identify::EffectIdentifierEnum::kChannelChange`) |
+| Blinks (950 ms on/50 ms off)    | Finish ( `Clusters::Identify::EffectIdentifierEnum::kFinishEffect`)          |
+| LED off                         | Stop (`Clusters::Identify::EffectIdentifierEnum::kStopEffect`)               |
+
+### CHIP tool commands
+
+1. Build
+   [chip-tool cli](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md)
+
+2. Pair with device
+
+    ```
+    ${CHIP_TOOL_DIR}/chip-tool pairing ble-thread ${NODE_ID} hex:${DATASET} ${PIN_CODE} ${DISCRIMINATOR}
+    ```
+
+    Example:
+
+    ```
+    ./chip-tool pairing ble-thread 1234 hex:0e080000000000010000000300000f35060004001fffe0020811111111222222220708fd61f77bd3df233e051000112233445566778899aabbccddeeff030e4f70656e54687265616444656d6f010212340410445f2b5ca6f2a93a55ce570a70efeecb0c0402a0fff8 20202021 3840
+    ```
+
+### OTA with Linux OTA Provider
+
+OTA feature enabled by default only for ota-requestor-app example. To enable OTA
+feature for another Telink example:
+
+-   set CONFIG_CHIP_OTA_REQUESTOR=y in corresponding "prj.conf" configuration
+    file.
+
+After build application with enabled OTA feature, use next binary files:
+
+-   zephyr.bin - main binary to flash PCB (Use 2MB PCB).
+-   zephyr-ota.bin - binary for OTA Provider
+
+All binaries has the same SW version. To test OTA “zephyr-ota.bin” should have
+higher SW version than base SW. Set CONFIG_CHIP_DEVICE_SOFTWARE_VERSION=2 in
+corresponding “prj.conf” configuration file.
+
+Usage of OTA:
+
+-   Build the [Linux OTA Provider](../../ota-provider-app/linux)
+
+    ```
+    ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false
+    ```
+
+-   Run the Linux OTA Provider with OTA image.
+
+    ```
+    ./chip-ota-provider-app -f zephyr-ota.bin
+    ```
+
+-   Provision the Linux OTA Provider using chip-tool
+
+    ```
+    ./chip-tool pairing onnetwork ${OTA_PROVIDER_NODE_ID} 20202021
+    ```
+
+    here:
+
+    -   \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider
+
+-   Configure the ACL of the ota-provider-app to allow access
+
+    ```
+    ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' ${OTA_PROVIDER_NODE_ID} 0
+    ```
+
+    here:
+
+    -   \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider
+
+-   Use the chip-tool to announce the ota-provider-app to start the OTA process
+
+    ```
+    ./chip-tool otasoftwareupdaterequestor announce-otaprovider ${OTA_PROVIDER_NODE_ID} 0 0 0 ${DEVICE_NODE_ID} 0
+    ```
+
+    here:
+
+    -   \${OTA_PROVIDER_NODE_ID} is the node id of Linux OTA Provider
+    -   \${DEVICE_NODE_ID} is the node id of paired device
+
+Once the transfer is complete, OTA requestor sends ApplyUpdateRequest command to
+OTA provider for applying the image. Device will restart on successful
+application of OTA image.
diff --git a/examples/air-quality-sensor-app/telink/include/AppConfig.h b/examples/air-quality-sensor-app/telink/include/AppConfig.h
new file mode 100644
index 0000000..ec5c543
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/include/AppConfig.h
@@ -0,0 +1,28 @@
+/*
+ *
+ *    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
+
+// ---- Air Quality Example App Config ----
+
+#define APP_USE_EXAMPLE_START_BUTTON 1
+#define APP_USE_BLE_START_BUTTON 0
+#define APP_USE_THREAD_START_BUTTON 0
+#define APP_SET_DEVICE_INFO_PROVIDER 1
+#define APP_SET_NETWORK_COMM_ENDPOINT_SEC 0
+#define APP_USE_IDENTIFY_PWM 1
diff --git a/examples/air-quality-sensor-app/telink/include/AppTask.h b/examples/air-quality-sensor-app/telink/include/AppTask.h
new file mode 100644
index 0000000..a1b55a9
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/include/AppTask.h
@@ -0,0 +1,42 @@
+/*
+ *
+ *    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 "AppTaskCommon.h"
+
+class AppTask : public AppTaskCommon
+{
+public:
+    void UpdateClusterState(void);
+
+private:
+    friend AppTask & GetAppTask(void);
+    friend class AppTaskCommon;
+
+    CHIP_ERROR Init(void);
+
+    static void AirQualityActionEventHandler(AppEvent * aEvent);
+
+    static AppTask sAppTask;
+};
+
+inline AppTask & GetAppTask(void)
+{
+    return AppTask::sAppTask;
+}
diff --git a/examples/air-quality-sensor-app/telink/include/CHIPProjectConfig.h b/examples/air-quality-sensor-app/telink/include/CHIPProjectConfig.h
new file mode 100644
index 0000000..8465c19
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/include/CHIPProjectConfig.h
@@ -0,0 +1,32 @@
+/*
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Example project configuration file for CHIP.
+ *
+ *          This is a place to put application or project-specific overrides
+ *          to the default configuration values for general CHIP features.
+ *
+ */
+
+#pragma once
+
+// Use a default pairing code if one hasn't been provisioned in flash.
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00
diff --git a/examples/air-quality-sensor-app/telink/prj.conf b/examples/air-quality-sensor-app/telink/prj.conf
new file mode 100644
index 0000000..703e78e
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/prj.conf
@@ -0,0 +1,57 @@
+#
+#    Copyright (c) 2023 Project CHIP Authors
+#
+#    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 sample uses sample-defaults.conf to set options common for all
+# samples. This file should contain only options specific for this sample
+# or overrides of default values.
+
+# Enable CHIP
+CONFIG_CHIP=y
+CONFIG_STD_CPP17=y
+
+# enable GPIO
+CONFIG_GPIO=y
+
+# enable PWM
+CONFIG_PWM=y
+
+# CHIP configuration
+CONFIG_CHIP_PROJECT_CONFIG="include/CHIPProjectConfig.h"
+CONFIG_CHIP_OPENTHREAD_CONFIG="../../platform/telink/project_include/OpenThreadConfig.h"
+
+# 32774 == 0x8006 (example air-quality-sensor-app)
+CONFIG_CHIP_DEVICE_PRODUCT_ID=32774
+
+# Bluetooth Low Energy configuration
+CONFIG_BT_DEVICE_NAME="TelinkSensor"
+
+# Disable Matter OTA DFU
+CONFIG_CHIP_OTA_REQUESTOR=n
+CONFIG_CHIP_DEVICE_SOFTWARE_VERSION=1
+
+# Enable CHIP pairing automatically on application start.
+CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y
+
+# Disable CHIP shell support
+CONFIG_CHIP_LIB_SHELL=n
+
+# Disable factory data support
+CONFIG_CHIP_FACTORY_DATA=n
+CONFIG_CHIP_FACTORY_DATA_BUILD=n
+CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE=n
+
+# Enable Power Management
+CONFIG_PM=y
diff --git a/examples/air-quality-sensor-app/telink/src/AppTask.cpp b/examples/air-quality-sensor-app/telink/src/AppTask.cpp
new file mode 100644
index 0000000..94988ea
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/src/AppTask.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ *    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.
+ */
+
+#include "AppTask.h"
+#include <air-quality-sensor-manager.h>
+
+LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
+
+using namespace ::chip::app::Clusters;
+using namespace ::chip::app::Clusters::AirQuality;
+
+AppTask AppTask::sAppTask;
+
+constexpr EndpointId kAirQualityEndpoint = 1;
+
+CHIP_ERROR AppTask::Init(void)
+{
+#if APP_USE_EXAMPLE_START_BUTTON
+    SetExampleButtonCallbacks(AirQualityActionEventHandler);
+#endif
+    InitCommonParts();
+
+    AirQualitySensorManager::InitInstance(kAirQualityEndpoint);
+
+    return CHIP_NO_ERROR;
+}
+
+void AppTask::UpdateClusterState(void)
+{
+    AirQualitySensorManager * mInstance = AirQualitySensorManager::GetInstance();
+
+    // Update AirQuality value
+    mInstance->OnAirQualityChangeHandler(AirQualityEnum::kModerate);
+
+    // Update Carbon Dioxide
+    mInstance->OnCarbonDioxideMeasurementChangeHandler(400);
+
+    // Update Temperature value
+    mInstance->OnTemperatureMeasurementChangeHandler(18);
+
+    // Update Humidity value
+    mInstance->OnHumidityMeasurementChangeHandler(60);
+}
+
+void AppTask::AirQualityActionEventHandler(AppEvent * aEvent)
+{
+    if (aEvent->Type == AppEvent::kEventType_Button)
+    {
+        sAppTask.UpdateClusterState();
+    }
+}
diff --git a/examples/air-quality-sensor-app/telink/src/ZclCallbacks.cpp b/examples/air-quality-sensor-app/telink/src/ZclCallbacks.cpp
new file mode 100644
index 0000000..f9959be
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/src/ZclCallbacks.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ *    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.
+ */
+
+#include "AppTask.h"
+
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/ConcreteAttributePath.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
+
+using namespace chip;
+using namespace chip::app::Clusters;
+
+void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
+                                       uint8_t * value)
+{
+    ClusterId clusterId     = attributePath.mClusterId;
+    AttributeId attributeId = attributePath.mAttributeId;
+    ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId));
+
+    if (clusterId == AirQuality::Id && attributeId == AirQuality::Attributes::AirQuality::Id)
+    {
+        static_assert(sizeof(AirQuality::AirQualityEnum) == 1, "Wrong size");
+        AirQuality::AirQualityEnum AirQuality = *(reinterpret_cast<AirQuality::AirQualityEnum *>(value));
+        ChipLogProgress(Zcl, "AirQuality cluster: " ChipLogFormatMEI " state %d", ChipLogValueMEI(clusterId),
+                        to_underlying(AirQuality));
+    }
+}
+
+/** @brief AirQuality Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint   Ver.: always
+ *
+ */
+void emberAfAirQualityClusterInitCallback(EndpointId endpoint)
+{
+    // TODO: implement any additional Cluster Server init actions
+}
diff --git a/examples/air-quality-sensor-app/telink/third_party/connectedhomeip b/examples/air-quality-sensor-app/telink/third_party/connectedhomeip
new file mode 120000
index 0000000..c866b86
--- /dev/null
+++ b/examples/air-quality-sensor-app/telink/third_party/connectedhomeip
@@ -0,0 +1 @@
+../../../..
\ No newline at end of file
diff --git a/examples/light-switch-app/telink/factory_data.overlay b/examples/light-switch-app/telink/factory_data.overlay
new file mode 100644
index 0000000..4f7289d
--- /dev/null
+++ b/examples/light-switch-app/telink/factory_data.overlay
@@ -0,0 +1,22 @@
+#
+#    Copyright (c) 2023 Project CHIP Authors
+#
+#    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 file should be used as a configuration overlay to enable Factory Data.
+
+# Enable factory data support. 
+CONFIG_CHIP_FACTORY_DATA=y
+CONFIG_CHIP_FACTORY_DATA_BUILD=y
+CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE=y
diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py
index 758c10d..c1b0fad 100755
--- a/scripts/build/build/targets.py
+++ b/scripts/build/build/targets.py
@@ -695,6 +695,7 @@
     ])
 
     target.AppendFixedTargets([
+        TargetPart('air-quality-sensor', app=TelinkApp.AIR_QUALITY_SENSOR),
         TargetPart('all-clusters', app=TelinkApp.ALL_CLUSTERS),
         TargetPart('all-clusters-minimal', app=TelinkApp.ALL_CLUSTERS_MINIMAL),
         TargetPart('bridge', app=TelinkApp.BRIDGE),
diff --git a/scripts/build/builders/telink.py b/scripts/build/builders/telink.py
index 5e62a51..9487a17 100644
--- a/scripts/build/builders/telink.py
+++ b/scripts/build/builders/telink.py
@@ -21,6 +21,7 @@
 
 
 class TelinkApp(Enum):
+    AIR_QUALITY_SENSOR = auto()
     ALL_CLUSTERS = auto()
     ALL_CLUSTERS_MINIMAL = auto()
     BRIDGE = auto()
@@ -39,7 +40,9 @@
     WINDOW_COVERING = auto()
 
     def ExampleName(self):
-        if self == TelinkApp.ALL_CLUSTERS:
+        if self == TelinkApp.AIR_QUALITY_SENSOR:
+            return 'air-quality-sensor-app'
+        elif self == TelinkApp.ALL_CLUSTERS:
             return 'all-clusters-app'
         elif self == TelinkApp.ALL_CLUSTERS_MINIMAL:
             return 'all-clusters-minimal-app'
@@ -75,7 +78,9 @@
             raise Exception('Unknown app type: %r' % self)
 
     def AppNamePrefix(self):
-        if self == TelinkApp.ALL_CLUSTERS:
+        if self == TelinkApp.AIR_QUALITY_SENSOR:
+            return 'chip-telink-air-quality-sensor-example'
+        elif self == TelinkApp.ALL_CLUSTERS:
             return 'chip-telink-all-clusters-example'
         elif self == TelinkApp.ALL_CLUSTERS_MINIMAL:
             return 'chip-telink-all-clusters-minimal-example'
diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt
index 57604bc..dd29cce 100644
--- a/scripts/build/testdata/all_targets_linux_x64.txt
+++ b/scripts/build/testdata/all_targets_linux_x64.txt
@@ -22,5 +22,5 @@
 qpg-qpg6105-{lock,light,shell,persistent-storage}
 stm32-stm32wb5mm-dk-light
 tizen-arm-{all-clusters,all-clusters-minimal,chip-tool,light,tests}[-no-ble][-no-thread][-no-wifi][-asan][-ubsan]
-telink-{tlsr9518adk80d,tlsr9528a}-{all-clusters,all-clusters-minimal,bridge,contact-sensor,light,light-switch,lock,ota-requestor,pump,pump-controller,resource-monitoring,shell,smoke-co-alarm,temperature-measurement,thermostat,window-covering}[-shell][-rpc][-factory-data]
+telink-{tlsr9518adk80d,tlsr9528a}-{air-quality-sensor,all-clusters,all-clusters-minimal,bridge,contact-sensor,light,light-switch,lock,ota-requestor,pump,pump-controller,resource-monitoring,shell,smoke-co-alarm,temperature-measurement,thermostat,window-covering}[-shell][-rpc][-factory-data]
 openiotsdk-{shell,lock}[-mbedtls][-psa]