[Telink] Add Thermostat app example (#23717)

* [Telink] Add thermostat example

* [Telink] Add new target for CI

* [Telink] Fix build after rebase

* [Telink] misspell fix

* [Telink] correct app name
diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml
index 5f04033..d4f1a9b 100644
--- a/.github/workflows/examples-telink.yaml
+++ b/.github/workflows/examples-telink.yaml
@@ -99,6 +99,15 @@
                     out/telink-tlsr9518adk80d-ota-requestor/zephyr/zephyr.elf \
                     /tmp/bloat_reports/
 
+            - name: Build example Telink Thermostat App
+              run: |
+                  ./scripts/run_in_build_env.sh \
+                    "./scripts/build/build_examples.py --no-log-timestamps --target 'telink-tlsr9518adk80d-thermostat' build"
+                  .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \
+                    telink tlsr9518adk80d thermostat \
+                    out/telink-tlsr9518adk80d-thermostat/zephyr/zephyr.elf \
+                    /tmp/bloat_reports/
+
             - name: Uploading Size Reports
               uses: actions/upload-artifact@v3
               if: ${{ !env.ACT }}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 56b9357..f8cf998 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -434,6 +434,7 @@
                 "telink-tlsr9518adk80d-light",
                 "telink-tlsr9518adk80d-light-switch",
                 "telink-tlsr9518adk80d-ota-requestor",
+                "telink-tlsr9518adk80d-thermostat",
                 "tizen-arm-light"
             ]
         },
diff --git a/examples/light-switch-app/telink/src/ZclCallbacks.cpp b/examples/light-switch-app/telink/src/ZclCallbacks.cpp
index 8510126..cb2b2ab 100644
--- a/examples/light-switch-app/telink/src/ZclCallbacks.cpp
+++ b/examples/light-switch-app/telink/src/ZclCallbacks.cpp
@@ -26,8 +26,8 @@
 using namespace chip;
 using namespace chip::app::Clusters;
 
-void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type,
-                                       uint16_t size, uint8_t * value)
+void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
+                                       uint8_t * value)
 {
     ClusterId clusterId     = attributePath.mClusterId;
     AttributeId attributeId = attributePath.mAttributeId;
diff --git a/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp b/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp
index 74bc8f2..159ce1f 100644
--- a/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp
+++ b/examples/ota-requestor-app/telink/src/ZclCallbacks.cpp
@@ -26,8 +26,8 @@
 using namespace chip;
 using namespace chip::app::Clusters;
 
-void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type,
-                                       uint16_t size, uint8_t * value)
+void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
+                                       uint8_t * value)
 {
     ClusterId clusterId     = attributePath.mClusterId;
     AttributeId attributeId = attributePath.mAttributeId;
diff --git a/examples/thermostat/telink/.gitignore b/examples/thermostat/telink/.gitignore
new file mode 100644
index 0000000..84c048a
--- /dev/null
+++ b/examples/thermostat/telink/.gitignore
@@ -0,0 +1 @@
+/build/
diff --git a/examples/thermostat/telink/CMakeLists.txt b/examples/thermostat/telink/CMakeLists.txt
new file mode 100755
index 0000000..78b4f7c
--- /dev/null
+++ b/examples/thermostat/telink/CMakeLists.txt
@@ -0,0 +1,68 @@
+#
+#    Copyright (c) 2022 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)
+
+set(BOARD tlsr9518adk80d)
+
+get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/connectedhomeip REALPATH)
+get_filename_component(NLIO_ROOT ${CHIP_ROOT}/third_party/nlio/repo/include REALPATH)
+get_filename_component(TELINK_COMMON ${CHIP_ROOT}/examples/platform/telink REALPATH)
+get_filename_component(GEN_DIR ${CHIP_ROOT}/zzz_generated/ REALPATH)
+
+set(CONF_FILE ${CHIP_ROOT}/config/telink/app/zephyr.conf 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-thermostat-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}/thermostat
+                           ${NLIO_ROOT}
+                           ${TELINK_COMMON}/util/include
+                           ${TELINK_COMMON}/app/include)
+
+add_definitions(
+    "-DCHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER=<lib/address_resolve/AddressResolve_DefaultImpl.h>"
+)
+
+target_sources(app PRIVATE
+               src/AppTask.cpp
+               src/SensorManager.cpp
+               src/TemperatureManager.cpp
+               src/main.cpp
+               src/ZclCallbacks.cpp
+               ${GEN_DIR}/thermostat/zap-generated/IMClusterCommandHandler.cpp
+               ${TELINK_COMMON}/util/src/LEDWidget.cpp
+               ${TELINK_COMMON}/util/src/ButtonManager.cpp
+               ${TELINK_COMMON}/util/src/ThreadUtil.cpp)
+
+chip_configure_data_model(app
+    INCLUDE_SERVER
+    ZAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../thermostat-common/thermostat.zap
+)
+
+if(CONFIG_CHIP_OTA_REQUESTOR)
+    target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
+endif()
diff --git a/examples/thermostat/telink/Readme.md b/examples/thermostat/telink/Readme.md
new file mode 100755
index 0000000..18dd713
--- /dev/null
+++ b/examples/thermostat/telink/Readme.md
@@ -0,0 +1,157 @@
+# Matter Telink Thermostat 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. Pull docker image from repository:
+
+    ```bash
+    $ docker pull connectedhomeip/chip-build-telink:latest
+    ```
+
+1. Run docker container:
+
+    ```bash
+    $ docker run -it --rm -v ${CHIP_BASE}:/root/chip -v /dev/bus/usb:/dev/bus/usb --device-cgroup-rule "c 189:* rmw" connectedhomeip/chip-build-telink:latest
+    ```
+
+    here `${CHIP_BASE}` is directory which contains CHIP repo files **!!!Pay
+    attention that OUTPUT_DIR should contains ABSOLUTE path to output dir**
+
+1. Activate the build environment:
+
+    ```bash
+    $ source ./scripts/activate.sh
+    ```
+
+1. In the example dir run:
+
+    ```bash
+    $ west build
+    ```
+
+1. 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 | NA                     | NA                                                                                                     |
+| 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
+
+**Red** LED indicates current state of Thread network. It ables to be in
+following states:
+
+| State                       | Description                                                                  |
+| :-------------------------- | :--------------------------------------------------------------------------- |
+| Blinks with short pulses    | Device is not commissioned to Thread, Thread is disabled                     |
+| Blinls with frequent pulses | Device is commissioned, Thread enabled. Device trying to JOIN thread network |
+| Blinks with whde pulses     | Device commissioned and joined to thread network as CHILD                    |
+
+### 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-ota-provider ${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/thermostat/telink/include/AppConfig.h b/examples/thermostat/telink/include/AppConfig.h
new file mode 100755
index 0000000..d852da9
--- /dev/null
+++ b/examples/thermostat/telink/include/AppConfig.h
@@ -0,0 +1,34 @@
+/*
+ *
+ *    Copyright (c) 2022 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
+
+// ---- Thermostat Example App Config ----
+
+// Buttons config
+#define BUTTON_PORT DEVICE_DT_GET(DT_NODELABEL(gpioc))
+
+#define BUTTON_PIN_1 2
+#define BUTTON_PIN_3 3
+#define BUTTON_PIN_4 1
+#define BUTTON_PIN_2 0
+
+// LEDs config
+// System led config
+#define SYSTEM_STATE_LED_PORT DEVICE_DT_GET(DT_NODELABEL(gpiob))
+#define SYSTEM_STATE_LED_PIN 7
diff --git a/examples/thermostat/telink/include/AppEvent.h b/examples/thermostat/telink/include/AppEvent.h
new file mode 100755
index 0000000..21933d1
--- /dev/null
+++ b/examples/thermostat/telink/include/AppEvent.h
@@ -0,0 +1,51 @@
+/*
+ *
+ *    Copyright (c) 2022 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 <cstdint>
+
+struct AppEvent;
+typedef void (*EventHandler)(AppEvent *);
+
+struct AppEvent
+{
+    enum AppEventTypes
+    {
+        kEventType_Button = 0,
+        kEventType_Timer,
+        kEventType_Thermostat,
+        kEventType_Install,
+    };
+
+    uint16_t Type;
+
+    union
+    {
+        struct
+        {
+            uint8_t Action;
+        } ButtonEvent;
+        struct
+        {
+            void * Context;
+        } TimerEvent;
+    };
+
+    EventHandler Handler;
+};
diff --git a/examples/thermostat/telink/include/AppTask.h b/examples/thermostat/telink/include/AppTask.h
new file mode 100755
index 0000000..8a3322d
--- /dev/null
+++ b/examples/thermostat/telink/include/AppTask.h
@@ -0,0 +1,78 @@
+/*
+ *
+ *    Copyright (c) 2022 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 "AppEvent.h"
+#include "SensorManager.h"
+#include "TemperatureManager.h"
+
+#include <zephyr/drivers/gpio.h>
+
+#include <platform/CHIPDeviceLayer.h>
+
+#if CONFIG_CHIP_FACTORY_DATA
+#include <platform/telink/FactoryDataProvider.h>
+#endif
+
+#include <cstdint>
+
+struct k_timer;
+
+class AppTask
+{
+public:
+    CHIP_ERROR StartApp();
+
+    void PostEvent(AppEvent * event);
+    void UpdateClusterState();
+    void UpdateThermoStatUI();
+
+private:
+    friend AppTask & GetAppTask(void);
+    CHIP_ERROR Init();
+
+    void DispatchEvent(AppEvent * event);
+
+    static void UpdateStatusLED();
+    static void FactoryResetButtonEventHandler(void);
+    static void StartThreadButtonEventHandler(void);
+    static void StartBleAdvButtonEventHandler(void);
+
+    static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg);
+
+    static void FactoryResetHandler(AppEvent * aEvent);
+    static void StartThreadHandler(AppEvent * aEvent);
+    static void StartBleAdvHandler(AppEvent * aEvent);
+
+    static void InitButtons(void);
+
+    static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg);
+
+    static AppTask sAppTask;
+
+#if CONFIG_CHIP_FACTORY_DATA
+    // chip::DeviceLayer::FactoryDataProvider<chip::DeviceLayer::InternalFlashFactoryData> mFactoryDataProvider;
+    chip::DeviceLayer::FactoryDataProvider<chip::DeviceLayer::ExternalFlashFactoryData> mFactoryDataProvider;
+#endif
+};
+
+inline AppTask & GetAppTask(void)
+{
+    return AppTask::sAppTask;
+}
diff --git a/examples/thermostat/telink/include/CHIPProjectConfig.h b/examples/thermostat/telink/include/CHIPProjectConfig.h
new file mode 100755
index 0000000..ade0219
--- /dev/null
+++ b/examples/thermostat/telink/include/CHIPProjectConfig.h
@@ -0,0 +1,46 @@
+/*
+ *
+ *    Copyright (c) 2022 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
+
+/**
+ * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+ *
+ * Enable support for Chip-over-BLE (CHIPoBLE).
+ */
+#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1
+
+/**
+ * CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE
+ *
+ * Reduce packet buffer pool size to 8 (default 15) to reduce ram consumption
+ */
+#define CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE 8
diff --git a/examples/thermostat/telink/include/SensorManager.h b/examples/thermostat/telink/include/SensorManager.h
new file mode 100644
index 0000000..828b3ef
--- /dev/null
+++ b/examples/thermostat/telink/include/SensorManager.h
@@ -0,0 +1,47 @@
+/*
+ *
+ *    Copyright (c) 2022 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 <stdbool.h>
+#include <stdint.h>
+
+#include "AppEvent.h"
+
+#include <app-common/zap-generated/attributes/Accessors.h>
+#include <lib/core/CHIPError.h>
+
+class SensorManager
+{
+public:
+    CHIP_ERROR Init();
+
+private:
+    friend SensorManager & SensorMgr();
+
+    // Reads new generated sensor value, stores it, and updates local temperature attribute
+    static void TimerEventHandler(k_timer * timer);
+    static void SensorTimerEventHandler(AppEvent * aEvent);
+
+    static SensorManager sSensorManager;
+};
+
+inline SensorManager & SensorMgr()
+{
+    return SensorManager::sSensorManager;
+}
diff --git a/examples/thermostat/telink/include/TemperatureManager.h b/examples/thermostat/telink/include/TemperatureManager.h
new file mode 100644
index 0000000..c55f064
--- /dev/null
+++ b/examples/thermostat/telink/include/TemperatureManager.h
@@ -0,0 +1,67 @@
+/*
+ *
+ *    Copyright (c) 2022 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 <stdbool.h>
+#include <stdint.h>
+
+#include "AppEvent.h"
+
+#include <app-common/zap-generated/attributes/Accessors.h>
+
+#include <lib/core/CHIPError.h>
+
+using namespace chip;
+
+// AppCluster Spec Table 85.
+enum ThermMode
+{
+    OFF = 0,
+    AUTO,
+    NOT_USED,
+    COOL,
+    HEAT,
+};
+
+class TemperatureManager
+{
+public:
+    CHIP_ERROR Init();
+    void AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size);
+    uint8_t GetMode();
+    int8_t GetCurrentTemp();
+    int8_t GetHeatingSetPoint();
+    int8_t GetCoolingSetPoint();
+
+private:
+    friend TemperatureManager & TempMgr();
+
+    int8_t mCurrentTempCelsius;
+    int8_t mCoolingCelsiusSetPoint;
+    int8_t mHeatingCelsiusSetPoint;
+    uint8_t mThermMode;
+
+    int8_t ConvertToPrintableTemp(int16_t temperature);
+    static TemperatureManager sTempMgr;
+};
+
+inline TemperatureManager & TempMgr()
+{
+    return TemperatureManager::sTempMgr;
+}
diff --git a/examples/thermostat/telink/prj.conf b/examples/thermostat/telink/prj.conf
new file mode 100755
index 0000000..ad1e20d
--- /dev/null
+++ b/examples/thermostat/telink/prj.conf
@@ -0,0 +1,58 @@
+#
+#    Copyright (c) 2022 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 GPIO
+CONFIG_GPIO=y
+
+# OpenThread configs
+CONFIG_OPENTHREAD_MTD=y
+CONFIG_OPENTHREAD_FTD=n
+
+# Default OpenThread network settings
+CONFIG_OPENTHREAD_PANID=4660
+CONFIG_OPENTHREAD_CHANNEL=15
+CONFIG_OPENTHREAD_NETWORK_NAME="OpenThreadDemo"
+CONFIG_OPENTHREAD_XPANID="11:11:11:11:22:22:22:22"
+CONFIG_NET_CONFIG_IEEE802154_DEV_NAME="IEEE802154_b91"
+
+# Disable Matter OTA DFU
+CONFIG_CHIP_OTA_REQUESTOR=n
+
+# CHIP configuration
+CONFIG_CHIP_PROJECT_CONFIG="include/CHIPProjectConfig.h"
+CONFIG_CHIP_OPENTHREAD_CONFIG="../../platform/telink/project_include/OpenThreadConfig.h"
+
+CONFIG_CHIP_DEVICE_VENDOR_ID=65521
+# 32782 == 0x800E (example thermostat)
+CONFIG_CHIP_DEVICE_PRODUCT_ID=32782
+CONFIG_CHIP_DEVICE_TYPE=65535
+
+CONFIG_CHIP_DEVICE_SOFTWARE_VERSION=1
+CONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING="2022"
+
+# Enable CHIP pairing automatically on application start.
+CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y
+
+# CHIP shell
+CONFIG_CHIP_LIB_SHELL=n
+
+# Disable factory data support. 
+CONFIG_CHIP_FACTORY_DATA=n
+CONFIG_CHIP_FACTORY_DATA_BUILD=n
\ No newline at end of file
diff --git a/examples/thermostat/telink/src/AppTask.cpp b/examples/thermostat/telink/src/AppTask.cpp
new file mode 100644
index 0000000..40d78ab
--- /dev/null
+++ b/examples/thermostat/telink/src/AppTask.cpp
@@ -0,0 +1,378 @@
+/*

+ *

+ *    Copyright (c) 2022 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 "AppConfig.h"

+#include "AppEvent.h"

+#include "ButtonManager.h"

+#include "LEDWidget.h"

+

+#include "ThreadUtil.h"

+

+#include <DeviceInfoProviderImpl.h>

+#include <app-common/zap-generated/attribute-id.h>

+#include <app-common/zap-generated/attribute-type.h>

+#include <app-common/zap-generated/cluster-id.h>

+#include <app/clusters/identify-server/identify-server.h>

+#include <app/server/OnboardingCodesUtil.h>

+#include <app/server/Server.h>

+#include <credentials/DeviceAttestationCredsProvider.h>

+#include <credentials/examples/DeviceAttestationCredsExample.h>

+#include <lib/support/ErrorStr.h>

+#include <system/SystemClock.h>

+

+#if CONFIG_CHIP_OTA_REQUESTOR

+#include "OTAUtil.h"

+#endif

+

+#include <zephyr/logging/log.h>

+#include <zephyr/zephyr.h>

+

+#include <algorithm>

+

+LOG_MODULE_DECLARE(app);

+

+using namespace ::chip;

+using namespace ::chip::app;

+using namespace ::chip::Credentials;

+using namespace ::chip::DeviceLayer;

+

+namespace {

+

+constexpr int kAppEventQueueSize      = 10;

+constexpr uint8_t kButtonPushEvent    = 1;

+constexpr uint8_t kButtonReleaseEvent = 0;

+

+// NOTE! This key is for test/certification only and should not be available in production devices!

+// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data.

+uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,

+                                                                                   0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };

+

+K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent));

+

+LEDWidget sStatusLED;

+

+Button sFactoryResetButton;

+Button sThreadStartButton;

+Button sBleAdvStartButton;

+

+bool sIsThreadProvisioned = false;

+bool sIsThreadEnabled     = false;

+bool sIsThreadAttached    = false;

+bool sHaveBLEConnections  = false;

+

+chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;

+

+void OnIdentifyTriggerEffect(Identify * identify)

+{

+    switch (identify->mCurrentEffectIdentifier)

+    {

+    case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK:

+        ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK");

+        break;

+    case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE:

+        ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE");

+        break;

+    case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY:

+        ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY");

+        break;

+    case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE:

+        ChipLogProgress(Zcl, "EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE");

+        break;

+    default:

+        ChipLogProgress(Zcl, "No identifier effect");

+        break;

+    }

+    return;

+}

+

+Identify sIdentify = {

+    chip::EndpointId{ 1 },

+    [](Identify *) { ChipLogProgress(Zcl, "OnIdentifyStart"); },

+    [](Identify *) { ChipLogProgress(Zcl, "OnIdentifyStop"); },

+    EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED,

+    OnIdentifyTriggerEffect,

+};

+

+} // namespace

+

+AppTask AppTask::sAppTask;

+

+CHIP_ERROR AppTask::Init()

+{

+    CHIP_ERROR err;

+

+    LOG_INF("Current Software Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION,

+            CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING);

+

+    // Initialize status LED

+    LEDWidget::InitGpio(SYSTEM_STATE_LED_PORT);

+    sStatusLED.Init(SYSTEM_STATE_LED_PIN);

+

+    UpdateStatusLED();

+

+    InitButtons();

+

+    // Initialize CHIP server

+#if CONFIG_CHIP_FACTORY_DATA

+    ReturnErrorOnFailure(mFactoryDataProvider.Init());

+    SetDeviceInstanceInfoProvider(&mFactoryDataProvider);

+    SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider);

+    SetCommissionableDataProvider(&mFactoryDataProvider);

+    // Read EnableKey from the factory data.

+    MutableByteSpan enableKey(sTestEventTriggerEnableKey);

+    err = mFactoryDataProvider.GetEnableKey(enableKey);

+    if (err != CHIP_NO_ERROR)

+    {

+        LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger");

+        memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey));

+    }

+#else

+    SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider());

+#endif

+

+    static CommonCaseDeviceServerInitParams initParams;

+    // static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) };

+    (void) initParams.InitializeStaticResourcesBeforeServerInit();

+    // initParams.testEventTriggerDelegate = &testEventTriggerDelegate;

+    ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams));

+

+    gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage());

+    chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);

+

+#if CONFIG_CHIP_OTA_REQUESTOR

+    InitBasicOTARequestor();

+#endif

+

+    ConfigurationMgr().LogDeviceConfig();

+    PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE));

+

+    // Add CHIP event handler and start CHIP thread.

+    // Note that all the initialization code should happen prior to this point to avoid data races

+    // between the main and the CHIP threads.

+    PlatformMgr().AddEventHandler(ChipEventHandler, 0);

+

+    err = SensorMgr().Init();

+    if (err != CHIP_NO_ERROR)

+    {

+        LOG_ERR("SensorMgr::Init() failed");

+        return err;

+    }

+    err = TempMgr().Init();

+    if (err != CHIP_NO_ERROR)

+    {

+        LOG_ERR("TempMgr::Init() failed");

+        return err;

+    }

+

+    err = ConnectivityMgr().SetBLEDeviceName("TelinkThermo");

+    if (err != CHIP_NO_ERROR)

+    {

+        LOG_ERR("Fail to set BLE device name");

+    }

+

+    return err;

+}

+

+CHIP_ERROR AppTask::StartApp()

+{

+    CHIP_ERROR err = Init();

+

+    if (err != CHIP_NO_ERROR)

+    {

+        LOG_ERR("AppTask.Init() failed");

+        return err;

+    }

+

+    AppEvent event = {};

+

+    while (true)

+    {

+        int ret = k_msgq_get(&sAppEventQueue, &event, K_MSEC(10));

+

+        while (!ret)

+        {

+            DispatchEvent(&event);

+            ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT);

+        }

+

+        sStatusLED.Animate();

+    }

+}

+

+void AppTask::UpdateThermoStatUI()

+{

+    LOG_INF("Thermostat Status - M:%d T:%d'C H:%d'C C:%d'C", TempMgr().GetMode(), TempMgr().GetCurrentTemp(),

+            TempMgr().GetHeatingSetPoint(), TempMgr().GetCoolingSetPoint());

+}

+

+void AppTask::FactoryResetButtonEventHandler(void)

+{

+    AppEvent event;

+

+    event.Type               = AppEvent::kEventType_Button;

+    event.ButtonEvent.Action = kButtonPushEvent;

+    event.Handler            = FactoryResetHandler;

+    sAppTask.PostEvent(&event);

+}

+

+void AppTask::FactoryResetHandler(AppEvent * aEvent)

+{

+    LOG_INF("Factory Reset triggered.");

+    chip::Server::GetInstance().ScheduleFactoryReset();

+}

+

+void AppTask::StartThreadButtonEventHandler(void)

+{

+    AppEvent event;

+

+    event.Type               = AppEvent::kEventType_Button;

+    event.ButtonEvent.Action = kButtonPushEvent;

+    event.Handler            = StartThreadHandler;

+    sAppTask.PostEvent(&event);

+}

+

+void AppTask::StartThreadHandler(AppEvent * aEvent)

+{

+

+    if (!chip::DeviceLayer::ConnectivityMgr().IsThreadProvisioned())

+    {

+        // Switch context from BLE to Thread

+        Internal::BLEManagerImpl sInstance;

+        sInstance.SwitchToIeee802154();

+        StartDefaultThreadNetwork();

+        LOG_INF("Device is not commissioned to a Thread network. Starting with the default configuration.");

+    }

+    else

+    {

+        LOG_INF("Device is commissioned to a Thread network.");

+    }

+}

+

+void AppTask::StartBleAdvButtonEventHandler(void)

+{

+    AppEvent event;

+

+    event.Type               = AppEvent::kEventType_Button;

+    event.ButtonEvent.Action = kButtonPushEvent;

+    event.Handler            = StartBleAdvHandler;

+    sAppTask.PostEvent(&event);

+}

+

+void AppTask::StartBleAdvHandler(AppEvent * aEvent)

+{

+    LOG_INF("BLE advertising start button pressed");

+

+    // Don't allow on starting Matter service BLE advertising after Thread provisioning.

+    if (ConnectivityMgr().IsThreadProvisioned())

+    {

+        LOG_INF("Matter service BLE advertising not started - device is commissioned to a Thread network.");

+        return;

+    }

+

+    if (ConnectivityMgr().IsBLEAdvertisingEnabled())

+    {

+        LOG_INF("BLE advertising is already enabled");

+        return;

+    }

+

+    if (chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != CHIP_NO_ERROR)

+    {

+        LOG_ERR("OpenBasicCommissioningWindow() failed");

+    }

+}

+

+void AppTask::UpdateStatusLED()

+{

+    if (sIsThreadProvisioned && sIsThreadEnabled)

+    {

+        if (sIsThreadAttached)

+        {

+            sStatusLED.Blink(950, 50);

+        }

+        else

+        {

+            sStatusLED.Blink(100, 100);

+        }

+    }

+    else

+    {

+        sStatusLED.Blink(50, 950);

+    }

+}

+

+void AppTask::ChipEventHandler(const ChipDeviceEvent * event, intptr_t /* arg */)

+{

+    switch (event->Type)

+    {

+    case DeviceEventType::kCHIPoBLEAdvertisingChange:

+        sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0;

+        UpdateStatusLED();

+        break;

+    case DeviceEventType::kThreadStateChange:

+        sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned();

+        sIsThreadEnabled     = ConnectivityMgr().IsThreadEnabled();

+        sIsThreadAttached    = ConnectivityMgr().IsThreadAttached();

+        UpdateStatusLED();

+        break;

+    case DeviceEventType::kThreadConnectivityChange:

+#if CONFIG_CHIP_OTA_REQUESTOR

+        if (event->ThreadConnectivityChange.Result == kConnectivity_Established)

+        {

+            InitBasicOTARequestor();

+        }

+#endif

+        break;

+    default:

+        break;

+    }

+}

+

+void AppTask::PostEvent(AppEvent * aEvent)

+{

+    if (k_msgq_put(&sAppEventQueue, aEvent, K_NO_WAIT) != 0)

+    {

+        LOG_INF("Failed to post event to app task event queue");

+    }

+}

+

+void AppTask::DispatchEvent(AppEvent * aEvent)

+{

+    if (aEvent->Handler)

+    {

+        aEvent->Handler(aEvent);

+    }

+    else

+    {

+        LOG_INF("Event received with no handler. Dropping event.");

+    }

+}

+

+void AppTask::UpdateClusterState() {}

+

+void AppTask::InitButtons(void)

+{

+    sFactoryResetButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_1, FactoryResetButtonEventHandler);

+    sThreadStartButton.Configure(BUTTON_PORT, BUTTON_PIN_3, BUTTON_PIN_2, StartThreadButtonEventHandler);

+    sBleAdvStartButton.Configure(BUTTON_PORT, BUTTON_PIN_4, BUTTON_PIN_2, StartBleAdvButtonEventHandler);

+

+    ButtonManagerInst().AddButton(sFactoryResetButton);

+    ButtonManagerInst().AddButton(sThreadStartButton);

+    ButtonManagerInst().AddButton(sBleAdvStartButton);

+}

diff --git a/examples/thermostat/telink/src/SensorManager.cpp b/examples/thermostat/telink/src/SensorManager.cpp
new file mode 100644
index 0000000..c692ae9
--- /dev/null
+++ b/examples/thermostat/telink/src/SensorManager.cpp
@@ -0,0 +1,91 @@
+/*
+ *
+ *    Copyright (c) 2022 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 "SensorManager.h"
+#include "AppConfig.h"
+#include "AppEvent.h"
+#include "AppTask.h"
+
+LOG_MODULE_DECLARE(app);
+
+using namespace chip;
+using namespace ::chip::DeviceLayer;
+
+constexpr EndpointId kThermostatEndpoint = 1;
+constexpr uint16_t kSensorTimerPeriodMs  = 30000; // 30s timer period
+constexpr uint16_t kMinTemperatureDelta  = 50;    // 0.5 degree Celsius
+
+k_timer sSensorTimer;
+
+SensorManager SensorManager::sSensorManager;
+
+constexpr uint16_t kSimulatedReadingFrequency = (60000 / kSensorTimerPeriodMs); // Change Simulated number at each minutes
+static int16_t mSimulatedTemp[]               = { 2300, 2400, 2800, 2550, 2200, 2125, 2100, 2600, 1800, 2700 };
+
+CHIP_ERROR SensorManager::Init()
+{
+    // Initialize temp sensor timer
+    k_timer_init(&sSensorTimer, &TimerEventHandler, nullptr);
+    k_timer_user_data_set(&sSensorTimer, this);
+    k_timer_start(&sSensorTimer, K_MSEC(kSensorTimerPeriodMs), K_NO_WAIT);
+
+    return CHIP_NO_ERROR;
+}
+
+void SensorManager::TimerEventHandler(k_timer * timer)
+{
+    AppEvent event;
+    event.Type               = AppEvent::kEventType_Thermostat;
+    event.TimerEvent.Context = k_timer_user_data_get(timer);
+    event.Handler            = SensorTimerEventHandler;
+    GetAppTask().PostEvent(&event);
+}
+
+void SensorManager::SensorTimerEventHandler(AppEvent * aEvent)
+{
+    int16_t temperature            = 0;
+    static int16_t lastTemperature = 0;
+
+    static uint8_t nbOfRepetition = 0;
+    static uint8_t simulatedIndex = 0;
+    if (simulatedIndex >= sizeof(mSimulatedTemp))
+    {
+        simulatedIndex = 0;
+    }
+    temperature = mSimulatedTemp[simulatedIndex];
+
+    nbOfRepetition++;
+    if (nbOfRepetition >= kSimulatedReadingFrequency)
+    {
+        simulatedIndex++;
+        nbOfRepetition = 0;
+    }
+
+    LOG_INF("Sensor Temp is : %d", temperature);
+
+    if ((temperature >= (lastTemperature + kMinTemperatureDelta)) || temperature <= (lastTemperature - kMinTemperatureDelta))
+    {
+        lastTemperature = temperature;
+        PlatformMgr().LockChipStack();
+        app::Clusters::Thermostat::Attributes::LocalTemperature::Set(kThermostatEndpoint, temperature);
+        PlatformMgr().UnlockChipStack();
+    }
+
+    // Start next timer to handle temp sensor.
+    k_timer_start(&sSensorTimer, K_MSEC(kSensorTimerPeriodMs), K_NO_WAIT);
+}
diff --git a/examples/thermostat/telink/src/TemperatureManager.cpp b/examples/thermostat/telink/src/TemperatureManager.cpp
new file mode 100644
index 0000000..9798cc0
--- /dev/null
+++ b/examples/thermostat/telink/src/TemperatureManager.cpp
@@ -0,0 +1,139 @@
+/*
+ *
+ *    Copyright (c) 2022 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 "TemperatureManager.h"
+#include "AppConfig.h"
+#include "AppEvent.h"
+#include "AppTask.h"
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_DECLARE(app);
+
+using namespace chip;
+using namespace ::chip::DeviceLayer;
+
+constexpr EndpointId kThermostatEndpoint = 1;
+
+namespace ThermAttr = chip::app::Clusters::Thermostat::Attributes;
+
+TemperatureManager TemperatureManager::sTempMgr;
+
+CHIP_ERROR TemperatureManager::Init()
+{
+    app::DataModel::Nullable<int16_t> temp;
+    int16_t heatingSetpoint, coolingSetpoint;
+    uint8_t systemMode;
+
+    PlatformMgr().LockChipStack();
+    ThermAttr::LocalTemperature::Get(kThermostatEndpoint, temp);
+    ThermAttr::OccupiedCoolingSetpoint::Get(kThermostatEndpoint, &coolingSetpoint);
+    ThermAttr::OccupiedHeatingSetpoint::Get(kThermostatEndpoint, &heatingSetpoint);
+    ThermAttr::SystemMode::Get(kThermostatEndpoint, &systemMode);
+    PlatformMgr().UnlockChipStack();
+
+    mCurrentTempCelsius     = ConvertToPrintableTemp(temp.Value());
+    mHeatingCelsiusSetPoint = ConvertToPrintableTemp(coolingSetpoint);
+    mCoolingCelsiusSetPoint = ConvertToPrintableTemp(heatingSetpoint);
+    mThermMode              = systemMode;
+
+    GetAppTask().UpdateThermoStatUI();
+
+    return CHIP_NO_ERROR;
+}
+
+int8_t TemperatureManager::ConvertToPrintableTemp(int16_t temperature)
+{
+    constexpr uint8_t kRoundUpValue = 50;
+
+    // Round up the temperature as we won't print decimals on LCD
+    // Is it a negative temperature
+    if (temperature < 0)
+    {
+        temperature -= kRoundUpValue;
+    }
+    else
+    {
+        temperature += kRoundUpValue;
+    }
+
+    return static_cast<int8_t>(temperature / 100);
+}
+
+void TemperatureManager::AttributeChangeHandler(EndpointId endpointId, AttributeId attributeId, uint8_t * value, uint16_t size)
+{
+    switch (attributeId)
+    {
+    case ThermAttr::LocalTemperature::Id: {
+        int8_t Temp = ConvertToPrintableTemp(*((int16_t *) value));
+        LOG_INF("Local temp %d", Temp);
+        mCurrentTempCelsius = Temp;
+    }
+    break;
+
+    case ThermAttr::OccupiedCoolingSetpoint::Id: {
+        int8_t coolingTemp = ConvertToPrintableTemp(*((int16_t *) value));
+        LOG_INF("CoolingSetpoint %d", coolingTemp);
+        mCoolingCelsiusSetPoint = coolingTemp;
+    }
+    break;
+
+    case ThermAttr::OccupiedHeatingSetpoint::Id: {
+        int8_t heatingTemp = ConvertToPrintableTemp(*((int16_t *) value));
+        LOG_INF("HeatingSetpoint %d", heatingTemp);
+        mHeatingCelsiusSetPoint = heatingTemp;
+    }
+    break;
+
+    case ThermAttr::SystemMode::Id: {
+        LOG_INF("SystemMode %d", static_cast<uint8_t>(*value));
+        uint8_t mode = static_cast<uint8_t>(*value);
+        if (mThermMode != mode)
+        {
+            mThermMode = mode;
+        }
+    }
+    break;
+
+    default: {
+        LOG_INF("Unhandled thermostat attribute %x", attributeId);
+        return;
+    }
+    break;
+    }
+
+    GetAppTask().UpdateThermoStatUI();
+}
+
+uint8_t TemperatureManager::GetMode()
+{
+    return mThermMode;
+}
+
+int8_t TemperatureManager::GetCurrentTemp()
+{
+    return mCurrentTempCelsius;
+}
+int8_t TemperatureManager::GetHeatingSetPoint()
+{
+    return mHeatingCelsiusSetPoint;
+}
+
+int8_t TemperatureManager::GetCoolingSetPoint()
+{
+    return mCoolingCelsiusSetPoint;
+}
diff --git a/examples/thermostat/telink/src/ZclCallbacks.cpp b/examples/thermostat/telink/src/ZclCallbacks.cpp
new file mode 100644
index 0000000..4dc43fb
--- /dev/null
+++ b/examples/thermostat/telink/src/ZclCallbacks.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ *    Copyright (c) 2022 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 "TemperatureManager.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>
+
+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 == Identify::Id)
+    {
+        // Following print is used for printing single-byte value. Change it for printing non-single-byte values.
+        ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u",
+                        ChipLogValueMEI(attributeId), type, *value, size);
+    }
+    else if (clusterId == Thermostat::Id)
+    {
+        TempMgr().AttributeChangeHandler(attributePath.mEndpointId, attributeId, value, size);
+    }
+}
diff --git a/examples/thermostat/telink/src/main.cpp b/examples/thermostat/telink/src/main.cpp
new file mode 100755
index 0000000..6fdd036
--- /dev/null
+++ b/examples/thermostat/telink/src/main.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ *    Copyright (c) 2022 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 <lib/support/CHIPMem.h>
+#include <platform/CHIPDeviceLayer.h>
+
+#include <zephyr/kernel.h>
+
+LOG_MODULE_REGISTER(app);
+
+using namespace ::chip;
+using namespace ::chip::Inet;
+using namespace ::chip::DeviceLayer;
+
+int main(void)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    err = chip::Platform::MemoryInit();
+    if (err != CHIP_NO_ERROR)
+    {
+        LOG_ERR("Platform::MemoryInit() failed");
+        goto exit;
+    }
+
+    LOG_INF("Init CHIP stack");
+    err = PlatformMgr().InitChipStack();
+    if (err != CHIP_NO_ERROR)
+    {
+        LOG_ERR("PlatformMgr().InitChipStack() failed");
+        goto exit;
+    }
+
+    LOG_INF("Starting CHIP task");
+    err = PlatformMgr().StartEventLoopTask();
+    if (err != CHIP_NO_ERROR)
+    {
+        LOG_ERR("PlatformMgr().StartEventLoopTask() failed");
+        goto exit;
+    }
+
+    LOG_INF("Init Thread stack");
+    err = ThreadStackMgr().InitThreadStack();
+    if (err != CHIP_NO_ERROR)
+    {
+        LOG_ERR("ThreadStackMgr().InitThreadStack() failed");
+        goto exit;
+    }
+
+#ifdef CONFIG_OPENTHREAD_MTD_SED
+    err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice);
+#elif CONFIG_OPENTHREAD_MTD
+    err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice);
+#else
+    err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router);
+#endif
+    if (err != CHIP_NO_ERROR)
+    {
+        LOG_ERR("ConnectivityMgr().SetThreadDeviceType() failed");
+        goto exit;
+    }
+
+    err = GetAppTask().StartApp();
+
+exit:
+    LOG_ERR("Exited with code %" CHIP_ERROR_FORMAT, err.Format());
+    return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/examples/thermostat/telink/third_party/connectedhomeip b/examples/thermostat/telink/third_party/connectedhomeip
new file mode 120000
index 0000000..c866b86
--- /dev/null
+++ b/examples/thermostat/telink/third_party/connectedhomeip
@@ -0,0 +1 @@
+../../../..
\ No newline at end of file
diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py
index 4c8ed88..3c424d3 100755
--- a/scripts/build/build/targets.py
+++ b/scripts/build/build/targets.py
@@ -508,6 +508,7 @@
         TargetPart('light', app=TelinkApp.LIGHT),
         TargetPart('light-switch', app=TelinkApp.SWITCH),
         TargetPart('ota-requestor', app=TelinkApp.OTA_REQUESTOR),
+        TargetPart('thermostat', app=TelinkApp.THERMOSTAT),
     ])
 
     return target
diff --git a/scripts/build/builders/telink.py b/scripts/build/builders/telink.py
index 9b448e5..a85ec7c 100644
--- a/scripts/build/builders/telink.py
+++ b/scripts/build/builders/telink.py
@@ -26,6 +26,7 @@
     LIGHT = auto()
     SWITCH = auto()
     OTA_REQUESTOR = auto()
+    THERMOSTAT = auto()
 
     def ExampleName(self):
         if self == TelinkApp.ALL_CLUSTERS:
@@ -38,6 +39,8 @@
             return 'light-switch-app'
         elif self == TelinkApp.OTA_REQUESTOR:
             return 'ota-requestor-app'
+        elif self == TelinkApp.THERMOSTAT:
+            return 'thermostat'
         else:
             raise Exception('Unknown app type: %r' % self)
 
@@ -52,6 +55,8 @@
             return 'chip-telink-light-switch-example'
         elif self == TelinkApp.OTA_REQUESTOR:
             return 'chip-telink-ota-requestor-example'
+        elif self == TelinkApp.THERMOSTAT:
+            return 'chip-telink-thermostat-example'
         else:
             raise Exception('Unknown app type: %r' % self)
 
diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt
index f893b28..dcb2963 100644
--- a/scripts/build/testdata/all_targets_linux_x64.txt
+++ b/scripts/build/testdata/all_targets_linux_x64.txt
@@ -18,4 +18,4 @@
 nrf-native-posix-64-tests
 qpg-qpg6105-{lock,light,shell,persistent-storage}
 tizen-arm-{all-clusters,all-clusters-minimal,chip-tool,light}[-no-ble][-no-wifi][-asan]
-telink-tlsr9518adk80d-{all-clusters,all-clusters-minimal,light,light-switch,ota-requestor}
+telink-tlsr9518adk80d-{all-clusters,all-clusters-minimal,light,light-switch,ota-requestor,thermostat}