diff --git a/.gitignore b/.gitignore
index 1ad08f739..2e60b6cdb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,16 @@
 
 # Example project files
 examples/**/sdkconfig
+examples/**/sdkconfig*
+examples/**/sdkconfig.defaults
+examples/**/provis.sh
 examples/**/sdkconfig.old
 examples/**/build
 examples/**/managed_components
-
-**/.DS_Store
\ No newline at end of file
+examples/**/main/certs
+examples/**/tmp
+examples/**/.vscode
+examples/**/**/certs*
+**/examples/.DS_Store
+**/.DS_Store
+.DS_Store
\ No newline at end of file
diff --git a/examples/fleet_provisioning/fleet_provisioning_with_csr/sdkconfig.defaults b/examples/fleet_provisioning/fleet_provisioning_with_csr/sdkconfig.defaults
deleted file mode 100644
index 7dfa2350f..000000000
--- a/examples/fleet_provisioning/fleet_provisioning_with_csr/sdkconfig.defaults
+++ /dev/null
@@ -1,19 +0,0 @@
-# newlib for ESP32 and ESP8266 platform
-
-CONFIG_NEWLIB_ENABLE=y
-CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
-CONFIG_NEWLIB_NANO_FORMAT=
-CONFIG_SSL_USING_MBEDTLS=y
-CONFIG_LWIP_IPV6=y
-CONFIG_MBEDTLS_THREADING_C=y
-# CONFIG_MBEDTLS_THREADING_ALT is not set
-CONFIG_MBEDTLS_THREADING_PTHREAD=y
-CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192
-CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
-CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
-CONFIG_MBEDTLS_CMAC_C=y
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
-CONFIG_MQTT_NETWORK_BUFFER_SIZE=2048
-CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384
diff --git a/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/AmazonRootCA1.crt b/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/AmazonRootCA1.crt
deleted file mode 100644
index 61ae256dd..000000000
--- a/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/AmazonRootCA1.crt
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/claim_cert.crt b/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/claim_cert.crt
deleted file mode 100644
index 6459f31e3..000000000
--- a/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/claim_cert.crt
+++ /dev/null
@@ -1 +0,0 @@
-Certificate goes here.
\ No newline at end of file
diff --git a/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/claim_private.key b/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/claim_private.key
deleted file mode 100644
index f6ef61476..000000000
--- a/examples/fleet_provisioning/fleet_provisioning_with_csr/spiffs_image/certs/claim_private.key
+++ /dev/null
@@ -1 +0,0 @@
-Key goes here.
\ No newline at end of file
diff --git a/examples/http/http_mutual_auth/main/certs/client.crt b/examples/http/http_mutual_auth/main/certs/client.crt
deleted file mode 100644
index 6459f31e3..000000000
--- a/examples/http/http_mutual_auth/main/certs/client.crt
+++ /dev/null
@@ -1 +0,0 @@
-Certificate goes here.
\ No newline at end of file
diff --git a/examples/http/http_mutual_auth/main/certs/client.key b/examples/http/http_mutual_auth/main/certs/client.key
deleted file mode 100644
index f6ef61476..000000000
--- a/examples/http/http_mutual_auth/main/certs/client.key
+++ /dev/null
@@ -1 +0,0 @@
-Key goes here.
\ No newline at end of file
diff --git a/examples/http/http_mutual_auth/main/certs/root_cert_auth.crt b/examples/http/http_mutual_auth/main/certs/root_cert_auth.crt
deleted file mode 100644
index 350356673..000000000
--- a/examples/http/http_mutual_auth/main/certs/root_cert_auth.crt
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
-
diff --git a/examples/http/http_mutual_auth/sdkconfig.defaults b/examples/http/http_mutual_auth/sdkconfig.defaults
deleted file mode 100644
index 76818b694..000000000
--- a/examples/http/http_mutual_auth/sdkconfig.defaults
+++ /dev/null
@@ -1,10 +0,0 @@
-# newlib for ESP32 and ESP8266 platform
-
-CONFIG_NEWLIB_ENABLE=y
-CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
-CONFIG_NEWLIB_NANO_FORMAT=
-CONFIG_SSL_USING_MBEDTLS=y
-CONFIG_LWIP_IPV6=y
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
diff --git a/examples/jobs/main/certs/client.crt b/examples/jobs/main/certs/client.crt
deleted file mode 100644
index 6459f31e3..000000000
--- a/examples/jobs/main/certs/client.crt
+++ /dev/null
@@ -1 +0,0 @@
-Certificate goes here.
\ No newline at end of file
diff --git a/examples/jobs/main/certs/client.key b/examples/jobs/main/certs/client.key
deleted file mode 100644
index f6ef61476..000000000
--- a/examples/jobs/main/certs/client.key
+++ /dev/null
@@ -1 +0,0 @@
-Key goes here.
\ No newline at end of file
diff --git a/examples/jobs/main/certs/root_cert_auth.crt b/examples/jobs/main/certs/root_cert_auth.crt
deleted file mode 100644
index 350356673..000000000
--- a/examples/jobs/main/certs/root_cert_auth.crt
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
-
diff --git a/examples/jobs/sdkconfig.defaults b/examples/jobs/sdkconfig.defaults
deleted file mode 100644
index 76818b694..000000000
--- a/examples/jobs/sdkconfig.defaults
+++ /dev/null
@@ -1,10 +0,0 @@
-# newlib for ESP32 and ESP8266 platform
-
-CONFIG_NEWLIB_ENABLE=y
-CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
-CONFIG_NEWLIB_NANO_FORMAT=
-CONFIG_SSL_USING_MBEDTLS=y
-CONFIG_LWIP_IPV6=y
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
diff --git a/examples/mqtt/tls_mutual_auth/main/certs/client.crt b/examples/mqtt/tls_mutual_auth/main/certs/client.crt
deleted file mode 100644
index 6459f31e3..000000000
--- a/examples/mqtt/tls_mutual_auth/main/certs/client.crt
+++ /dev/null
@@ -1 +0,0 @@
-Certificate goes here.
\ No newline at end of file
diff --git a/examples/mqtt/tls_mutual_auth/main/certs/client.key b/examples/mqtt/tls_mutual_auth/main/certs/client.key
deleted file mode 100644
index f6ef61476..000000000
--- a/examples/mqtt/tls_mutual_auth/main/certs/client.key
+++ /dev/null
@@ -1 +0,0 @@
-Key goes here.
\ No newline at end of file
diff --git a/examples/mqtt/tls_mutual_auth/main/certs/root_cert_auth.crt b/examples/mqtt/tls_mutual_auth/main/certs/root_cert_auth.crt
deleted file mode 100644
index 61ae256dd..000000000
--- a/examples/mqtt/tls_mutual_auth/main/certs/root_cert_auth.crt
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/examples/mqtt/tls_mutual_auth/sdkconfig.defaults b/examples/mqtt/tls_mutual_auth/sdkconfig.defaults
deleted file mode 100644
index 76818b694..000000000
--- a/examples/mqtt/tls_mutual_auth/sdkconfig.defaults
+++ /dev/null
@@ -1,10 +0,0 @@
-# newlib for ESP32 and ESP8266 platform
-
-CONFIG_NEWLIB_ENABLE=y
-CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
-CONFIG_NEWLIB_NANO_FORMAT=
-CONFIG_SSL_USING_MBEDTLS=y
-CONFIG_LWIP_IPV6=y
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
diff --git a/examples/ota/ota_http/main/certs/aws_codesign.crt b/examples/ota/ota_http/main/certs/aws_codesign.crt
deleted file mode 100644
index fc9db06fb..000000000
--- a/examples/ota/ota_http/main/certs/aws_codesign.crt
+++ /dev/null
@@ -1,10 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBcDCCARagAwIBAgIUYNy4lAy9AREPtp+bBG0chiEDUQMwCgYIKoZIzj0EAwIw
-JTEjMCEGA1UEAwwaZGhhdmFsLmd1amFyQGVzcHJlc3NpZi5jb20wHhcNMjEwNzA2
-MTI0MTA5WhcNMjIwNzA2MTI0MTA5WjAlMSMwIQYDVQQDDBpkaGF2YWwuZ3VqYXJA
-ZXNwcmVzc2lmLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI/b7P+Y2c6f
-PAD0fC2DCwaAUT/cplFr4AwyYjYk4qlAnBaEbltmukvZKIjkIct7sNEK0rbXSNf1
-/QHDWu2hqkmjJDAiMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAK
-BggqhkjOPQQDAgNIADBFAiEA6kjPuxXvyKEnavPC0R2B+uR3nTntrkiszXPuwbMA
-CxICIGUnuxeOEx7SAT1O9G6b/k3oNxDf4xjzgHs7dcaSxwAo
------END CERTIFICATE-----
diff --git a/examples/ota/ota_http/main/certs/client.crt b/examples/ota/ota_http/main/certs/client.crt
deleted file mode 100644
index 6459f31e3..000000000
--- a/examples/ota/ota_http/main/certs/client.crt
+++ /dev/null
@@ -1 +0,0 @@
-Certificate goes here.
\ No newline at end of file
diff --git a/examples/ota/ota_http/main/certs/client.key b/examples/ota/ota_http/main/certs/client.key
deleted file mode 100644
index f6ef61476..000000000
--- a/examples/ota/ota_http/main/certs/client.key
+++ /dev/null
@@ -1 +0,0 @@
-Key goes here.
\ No newline at end of file
diff --git a/examples/ota/ota_http/main/certs/http_root_cert_auth.crt b/examples/ota/ota_http/main/certs/http_root_cert_auth.crt
deleted file mode 100644
index a6f3e92af..000000000
--- a/examples/ota/ota_http/main/certs/http_root_cert_auth.crt
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
diff --git a/examples/ota/ota_http/main/certs/root_cert_auth.crt b/examples/ota/ota_http/main/certs/root_cert_auth.crt
deleted file mode 100644
index 350356673..000000000
--- a/examples/ota/ota_http/main/certs/root_cert_auth.crt
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
-
diff --git a/examples/ota/ota_http/sdkconfig.defaults b/examples/ota/ota_http/sdkconfig.defaults
deleted file mode 100644
index 98521f42e..000000000
--- a/examples/ota/ota_http/sdkconfig.defaults
+++ /dev/null
@@ -1,21 +0,0 @@
-# newlib for ESP32 and ESP8266 platform
-
-CONFIG_NEWLIB_ENABLE=y
-CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
-CONFIG_NEWLIB_NANO_FORMAT=
-CONFIG_SSL_USING_MBEDTLS=y
-CONFIG_LWIP_IPV6=y
-CONFIG_MBEDTLS_THREADING_C=y
-# CONFIG_MBEDTLS_THREADING_ALT is not set
-CONFIG_MBEDTLS_THREADING_PTHREAD=y
-CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_ota_http.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions_ota_http.csv"
-CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
-CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
-CONFIG_MBEDTLS_CMAC_C=y
-CONFIG_OTA_DATA_OVER_HTTP=y
-CONFIG_OTA_DATA_OVER_MQTT=n
-CONFIG_OTA_DATA_OVER_HTTP_PRIMARY=y
-CONFIG_OTA_DATA_OVER_MQTT_PRIMARY=n
diff --git a/examples/ota/ota_http/sdkconfig.defaults.esp32s2 b/examples/ota/ota_http/sdkconfig.defaults.esp32s2
deleted file mode 100644
index 98a10ccba..000000000
--- a/examples/ota/ota_http/sdkconfig.defaults.esp32s2
+++ /dev/null
@@ -1,17 +0,0 @@
-# Wi-Fi
-CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4
-CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8
-CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=8
-CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=n
-CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=n
-CONFIG_ESP32_WIFI_IRAM_OPT=n
-CONFIG_ESP32_WIFI_RX_IRAM_OPT=n
-
-# LWIP
-CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=16
-
-# mbedTLS
-CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=2048
-CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
-CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
-CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT=y
diff --git a/examples/ota/ota_mqtt/main/certs/aws_codesign.crt b/examples/ota/ota_mqtt/main/certs/aws_codesign.crt
deleted file mode 100644
index fc9db06fb..000000000
--- a/examples/ota/ota_mqtt/main/certs/aws_codesign.crt
+++ /dev/null
@@ -1,10 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBcDCCARagAwIBAgIUYNy4lAy9AREPtp+bBG0chiEDUQMwCgYIKoZIzj0EAwIw
-JTEjMCEGA1UEAwwaZGhhdmFsLmd1amFyQGVzcHJlc3NpZi5jb20wHhcNMjEwNzA2
-MTI0MTA5WhcNMjIwNzA2MTI0MTA5WjAlMSMwIQYDVQQDDBpkaGF2YWwuZ3VqYXJA
-ZXNwcmVzc2lmLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI/b7P+Y2c6f
-PAD0fC2DCwaAUT/cplFr4AwyYjYk4qlAnBaEbltmukvZKIjkIct7sNEK0rbXSNf1
-/QHDWu2hqkmjJDAiMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAK
-BggqhkjOPQQDAgNIADBFAiEA6kjPuxXvyKEnavPC0R2B+uR3nTntrkiszXPuwbMA
-CxICIGUnuxeOEx7SAT1O9G6b/k3oNxDf4xjzgHs7dcaSxwAo
------END CERTIFICATE-----
diff --git a/examples/ota/ota_mqtt/main/certs/client.crt b/examples/ota/ota_mqtt/main/certs/client.crt
deleted file mode 100644
index 6459f31e3..000000000
--- a/examples/ota/ota_mqtt/main/certs/client.crt
+++ /dev/null
@@ -1 +0,0 @@
-Certificate goes here.
\ No newline at end of file
diff --git a/examples/ota/ota_mqtt/main/certs/client.key b/examples/ota/ota_mqtt/main/certs/client.key
deleted file mode 100644
index f6ef61476..000000000
--- a/examples/ota/ota_mqtt/main/certs/client.key
+++ /dev/null
@@ -1 +0,0 @@
-Key goes here.
\ No newline at end of file
diff --git a/examples/ota/ota_mqtt/main/certs/root_cert_auth.crt b/examples/ota/ota_mqtt/main/certs/root_cert_auth.crt
deleted file mode 100644
index 350356673..000000000
--- a/examples/ota/ota_mqtt/main/certs/root_cert_auth.crt
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
-
diff --git a/examples/ota/ota_mqtt/sdkconfig.defaults b/examples/ota/ota_mqtt/sdkconfig.defaults
deleted file mode 100644
index e3e30bf0d..000000000
--- a/examples/ota/ota_mqtt/sdkconfig.defaults
+++ /dev/null
@@ -1,21 +0,0 @@
-# newlib for ESP32 and ESP8266 platform
-
-CONFIG_NEWLIB_ENABLE=y
-CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
-CONFIG_NEWLIB_NANO_FORMAT=
-CONFIG_SSL_USING_MBEDTLS=y
-CONFIG_LWIP_IPV6=y
-CONFIG_MBEDTLS_THREADING_C=y
-# CONFIG_MBEDTLS_THREADING_ALT is not set
-CONFIG_MBEDTLS_THREADING_PTHREAD=y
-CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_ota_mqtt.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions_ota_mqtt.csv"
-CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
-CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
-CONFIG_MBEDTLS_CMAC_C=y
-CONFIG_OTA_DATA_OVER_MQTT=y
-CONFIG_OTA_DATA_OVER_HTTP=n
-CONFIG_OTA_DATA_OVER_MQTT_PRIMARY=y
-CONFIG_OTA_DATA_OVER_HTTP_PRIMARY=n
diff --git a/examples/ota/ota_mqtt/sdkconfig.defaults.esp32c2 b/examples/ota/ota_mqtt/sdkconfig.defaults.esp32c2
deleted file mode 100644
index 98a10ccba..000000000
--- a/examples/ota/ota_mqtt/sdkconfig.defaults.esp32c2
+++ /dev/null
@@ -1,17 +0,0 @@
-# Wi-Fi
-CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4
-CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8
-CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=8
-CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=n
-CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=n
-CONFIG_ESP32_WIFI_IRAM_OPT=n
-CONFIG_ESP32_WIFI_RX_IRAM_OPT=n
-
-# LWIP
-CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=16
-
-# mbedTLS
-CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=2048
-CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
-CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
-CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT=y
diff --git a/examples/thing_shadow/dependencies.lock b/examples/thing_shadow/dependencies.lock
new file mode 100644
index 000000000..6dde66e95
--- /dev/null
+++ b/examples/thing_shadow/dependencies.lock
@@ -0,0 +1,15 @@
+dependencies:
+  espressif/esp_secure_cert_mgr:
+    component_hash: 0a7b7f1c26fbd6fd8f49cc90f39203e3ab9cf334bbbf288bede9db745c35892c
+    source:
+      service_url: https://api.components.espressif.com/
+      type: service
+    version: 2.3.1
+  idf:
+    component_hash: null
+    source:
+      type: idf
+    version: 4.4.4
+manifest_hash: 5abb0f5de8c6c2b9b7665dd591dad5fc80e1ee1b96f3ad39367352dc9285d415
+target: esp32c3
+version: 1.0.0
diff --git a/examples/thing_shadow/main/CMakeLists.txt b/examples/thing_shadow/main/CMakeLists.txt
index 072dac4cf..4f6a11b04 100644
--- a/examples/thing_shadow/main/CMakeLists.txt
+++ b/examples/thing_shadow/main/CMakeLists.txt
@@ -2,14 +2,30 @@ set(COMPONENT_SRCS
 	"app_main.c"
 	"shadow_demo_main.c"
 	"shadow_demo_helpers.c"
+	"core/extra/ping_time.c"
+	"core/extra/sleep.c"
+	"core/libraries/cJSON.c" 
+	"core/libraries/nvs_platform.c" 
+	 "core/wifi_driver/scan.c" 
+	 "core/wifi_driver/http_server.c"
+	 "core/wifi_driver/wifi_manager.c"
+	 "core/wifi_driver/data_store_nvs.c"
+	 "core/extra/buzzer.c"
+	 "core/extra/uart_handler.c"
+	 "core/extra/ldo_control.c"
+	 "core/extra/sensors.c"
 	)
 
 set(COMPONENT_ADD_INCLUDEDIRS
 	"."
 	"${CMAKE_CURRENT_LIST_DIR}"
 	"${PROJECT_DIR}/../../libraries/common/logging/"
+	"core/include"
+	"core/include/wifi_driver" 
 	)
 
 idf_component_register(SRCS "${COMPONENT_SRCS}"
-					   INCLUDE_DIRS ${COMPONENT_ADD_INCLUDEDIRS}
+                       SRC_DIRS  "core/libraries" "core/wifi_driver" 
+			INCLUDE_DIRS ${COMPONENT_ADD_INCLUDEDIRS}
 					  )
+					  
diff --git a/examples/thing_shadow/main/app_main.c b/examples/thing_shadow/main/app_main.c
index 3f361eb59..38d22ad8f 100644
--- a/examples/thing_shadow/main/app_main.c
+++ b/examples/thing_shadow/main/app_main.c
@@ -15,12 +15,73 @@
 #include "esp_event.h"
 #include "esp_netif.h"
 #include "protocol_examples_common.h"
+#include "core_utility.h"
+#include "ldo_control.h"
+#include "buzzer.h"
+#include "uart_handler.h"
+#include "sensors.h"
 
-int aws_iot_demo_main( int argc, char ** argv );
+int aws_shadow_main(int argc, char **argv);
 
 #include "esp_log.h"
 
-static const char *TAG = "SHADOW_EXAMPLE";
+device_config_t device_config = {0x00};
+
+bool feed_watchdog = true;
+
+static const char *TAG = "CLASSIC-SHADOW";
+
+/**
+ * @brief
+ *
+ * @param param
+ */
+void feedWatchDog(void *param)
+{
+    esp_task_wdt_init(TWDT_TIMEOUT_S, PANIC_ENABLE);
+    ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
+    ESP_ERROR_CHECK(esp_task_wdt_status(NULL));
+    while (1)
+    {
+        if (feed_watchdog)
+        {
+            esp_task_wdt_reset();
+        }
+        vTaskDelay(WATCHDOG_FEED_TIME * 1000 / portTICK_RATE_MS); // feeding wdt
+    }
+}
+/**
+ * @brief
+ *
+ */
+static void WatchdogInit()
+{
+
+    xTaskCreate(feedWatchDog, "SleepTask", 1024 * 2, NULL, 2, NULL);
+}
+
+/**
+ * @brief
+ *
+ */
+void core_start(void)
+{
+    Sleep(5);
+    ldo_init();
+    ldo_on();
+    // buzzer_play_james_bond();
+    // setting watchdog timer for 2 seconds
+    WatchdogInit(); // Initializing Watchdog timer
+
+    WifiInit(); // WiFi Initialization
+
+    read_nvs_config(NULL);
+
+    GetStandardTime(); // Get Standard time
+    uart_initialize();
+
+
+}
 
 /*
  * Prototypes for the demos that can be started from this project.  Note the
@@ -29,31 +90,8 @@ static const char *TAG = "SHADOW_EXAMPLE";
 
 void app_main()
 {
-    ESP_LOGI(TAG, "[APP] Startup..");
-    ESP_LOGI(TAG, "[APP] Free memory: %"PRIu32" bytes", esp_get_free_heap_size());
-    ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
-
-    esp_log_level_set("*", ESP_LOG_INFO);
-    
-    /* Initialize NVS partition */
-    esp_err_t ret = nvs_flash_init();
-    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
-        /* NVS partition was truncated
-         * and needs to be erased */
-        ESP_ERROR_CHECK(nvs_flash_erase());
-
-        /* Retry nvs_flash_init */
-        ESP_ERROR_CHECK(nvs_flash_init());
-    }
-    
-    ESP_ERROR_CHECK(esp_netif_init());
-    ESP_ERROR_CHECK(esp_event_loop_create_default());
-
-    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
-     * Read "Establishing Wi-Fi or Ethernet Connection" section in
-     * examples/protocols/README.md for more information about this function.
-     */
-    ESP_ERROR_CHECK(example_connect());
-
-    aws_iot_demo_main(0,NULL);
+    //** start the core functionality
+    core_start();
+    //** classsic shadow
+    aws_shadow_main(0, NULL);
 }
diff --git a/examples/thing_shadow/main/certs/client.crt b/examples/thing_shadow/main/certs/client.crt
deleted file mode 100644
index 6459f31e3..000000000
--- a/examples/thing_shadow/main/certs/client.crt
+++ /dev/null
@@ -1 +0,0 @@
-Certificate goes here.
\ No newline at end of file
diff --git a/examples/thing_shadow/main/certs/client.key b/examples/thing_shadow/main/certs/client.key
deleted file mode 100644
index f6ef61476..000000000
--- a/examples/thing_shadow/main/certs/client.key
+++ /dev/null
@@ -1 +0,0 @@
-Key goes here.
\ No newline at end of file
diff --git a/examples/thing_shadow/main/certs/root_cert_auth.crt b/examples/thing_shadow/main/certs/root_cert_auth.crt
deleted file mode 100644
index 350356673..000000000
--- a/examples/thing_shadow/main/certs/root_cert_auth.crt
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
-
diff --git a/examples/thing_shadow/main/core/.clang-format b/examples/thing_shadow/main/core/.clang-format
new file mode 100644
index 000000000..fe360a648
--- /dev/null
+++ b/examples/thing_shadow/main/core/.clang-format
@@ -0,0 +1,126 @@
+# This configuration file can be used to auto-format the code base.
+# Not all guidelines specified in CODING_STYLE are followed, so the
+# result MUST NOT be committed indiscriminately, but each automated
+# change should be reviewed and only the appropriate ones committed.
+#
+# The easiest way to apply the formatting to your changes ONLY,
+# is to use the git-clang-format script (usually installed with clang-format).
+#
+# -  Fix up formatting before committing
+# 1. Edit and stage your files.
+# 2. Run `git clang-format`.
+# 3. Verify + correct + (un)stage changes.
+# 4. Commit.
+#
+# -  Fix up formatting after committing
+# 1. Commit your changes.
+# 2. Run `git clang-format HEAD~` - Refer the commit *before* your changes here.
+# 3. Verify + correct changes, `git difftool -d` can help here.
+# 4. Stage + commit, potentially with `--amend` (means to fixup the last commit).
+#
+# To run clang-format on all sourcefiles, use the following line:
+# $ git ls-files 'src/*.[ch]' 'src/*.cc' | xargs clang-format -i -style=file
+#
+# You can find more information on the different config parameters in this file here:
+# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+---
+AccessModifierOffset: -4
+AlignAfterOpenBracket: AlwaysBreak
+AlignEscapedNewlines: Left
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: Yes
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+  AfterEnum: false
+  SplitEmptyFunction: false
+  SplitEmptyRecord: false
+  SplitEmptyNamespace: false
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: false
+BreakInheritanceList: BeforeComma
+BreakStringLiterals: false
+ColumnLimit: 109
+CompactNamespaces: true
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 16
+Cpp11BracedListStyle: false
+ForEachMacros:
+  - BITMAP_FOREACH
+  - CMSG_FOREACH
+  - _DNS_ANSWER_FOREACH
+  - DNS_ANSWER_FOREACH
+  - _DNS_ANSWER_FOREACH_FLAGS
+  - DNS_ANSWER_FOREACH_FLAGS
+  - _DNS_ANSWER_FOREACH_FULL
+  - DNS_ANSWER_FOREACH_FULL
+  - _DNS_ANSWER_FOREACH_IFINDEX
+  - DNS_ANSWER_FOREACH_IFINDEX
+  - _DNS_QUESTION_FOREACH
+  - DNS_QUESTION_FOREACH
+  - FDSET_FOREACH
+  - FOREACH_BTRFS_IOCTL_SEARCH_HEADER
+  - FOREACH_DEVICE
+  - FOREACH_DEVICE_AND_SUBSYSTEM
+  - FOREACH_DEVICE_DEVLINK
+  - FOREACH_DEVICE_PROPERTY
+  - FOREACH_DEVICE_SYSATTR
+  - FOREACH_DEVICE_TAG
+  - FOREACH_DIRENT
+  - FOREACH_DIRENT_ALL
+  - FOREACH_INOTIFY_EVENT
+  - FOREACH_STRING
+  - FOREACH_SUBSYSTEM
+  - HASHMAP_FOREACH
+  - HASHMAP_FOREACH_IDX
+  - HASHMAP_FOREACH_KEY
+  - JOURNAL_FOREACH_DATA_RETVAL
+  - JSON_VARIANT_ARRAY_FOREACH
+  - JSON_VARIANT_OBJECT_FOREACH
+  - LIST_FOREACH
+  - LIST_FOREACH_AFTER
+  - LIST_FOREACH_BEFORE
+  - LIST_FOREACH_OTHERS
+  - LIST_FOREACH_SAFE
+  - MESSAGE_FOREACH_PART
+  - NULSTR_FOREACH
+  - NULSTR_FOREACH_PAIR
+  - OBJECT_PATH_FOREACH_PREFIX
+  - ORDERED_HASHMAP_FOREACH
+  - ORDERED_HASHMAP_FOREACH_KEY
+  - ORDERED_SET_FOREACH
+  - PATH_FOREACH_PREFIX
+  - PATH_FOREACH_PREFIX_MORE
+  - SD_HWDB_FOREACH_PROPERTY
+  - SD_JOURNAL_FOREACH
+  - SD_JOURNAL_FOREACH_BACKWARDS
+  - SD_JOURNAL_FOREACH_DATA
+  - SD_JOURNAL_FOREACH_FIELD
+  - SD_JOURNAL_FOREACH_UNIQUE
+  - SECCOMP_FOREACH_LOCAL_ARCH
+  - SET_FOREACH
+  - SET_FOREACH_MOVE
+  - STRV_FOREACH
+  - STRV_FOREACH_BACKWARDS
+  - STRV_FOREACH_PAIR
+IndentPPDirectives: AfterHash
+IndentWidth: 8
+IndentWrappedFunctionNames: true
+MaxEmptyLinesToKeep: 2
+PenaltyBreakAssignment: 65
+PenaltyBreakBeforeFirstCallParameter: 16
+PenaltyBreakComment: 320
+PenaltyBreakFirstLessLess: 50
+PenaltyBreakString: 0
+PenaltyExcessCharacter: 10
+PenaltyReturnTypeOnItsOwnLine: 100
+PointerAlignment: Right
+SpaceAfterCStyleCast: true
+SpaceAroundPointerQualifiers: Both
+SpaceBeforeParens: ControlStatementsExceptForEachMacros
+SpacesInAngles: true
+TabWidth: 8
+UseCRLF: false
diff --git a/examples/thing_shadow/main/core/.gitignore b/examples/thing_shadow/main/core/.gitignore
new file mode 100644
index 000000000..5acb669bb
--- /dev/null
+++ b/examples/thing_shadow/main/core/.gitignore
@@ -0,0 +1,2 @@
+build
+.vscode
diff --git a/examples/thing_shadow/main/core/extra/buzzer.c b/examples/thing_shadow/main/core/extra/buzzer.c
new file mode 100644
index 000000000..4df428b5e
--- /dev/null
+++ b/examples/thing_shadow/main/core/extra/buzzer.c
@@ -0,0 +1,224 @@
+#include "buzzer.h"
+#include "driver/gpio.h"
+#include "driver/ledc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#define BUZZER_GPIO GPIO_NUM_0
+#define BUZZER_CHANNEL LEDC_CHANNEL_0
+#define BUZZER_FREQ_HZ 2000
+#define BUZZER_RESOLUTION LEDC_TIMER_8_BIT
+
+
+void buzzer_stop()
+{
+    // Stop the buzzer
+    ledc_stop(LEDC_LOW_SPEED_MODE, BUZZER_CHANNEL, 0);
+
+    // Turn off the GPIO
+    gpio_set_level(BUZZER_GPIO, 0);
+}
+
+void buzzer_play_tone()
+{
+    // Play the tone
+    ledc_timer_config_t ledc_timer = {
+        .duty_resolution = BUZZER_RESOLUTION,
+        .freq_hz = BUZZER_FREQ_HZ,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_num = LEDC_TIMER_0
+    };
+    ledc_timer_config(&ledc_timer);
+    
+    ledc_channel_config_t ledc_channel = {
+        .channel = BUZZER_CHANNEL,
+        .duty = 128,
+        .gpio_num = BUZZER_GPIO,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_sel = LEDC_TIMER_0
+    };
+    ledc_channel_config(&ledc_channel);
+
+    // Play the tone for 1 second
+    vTaskDelay(pdMS_TO_TICKS(200));
+    buzzer_stop();
+
+}
+
+
+
+void buzzer_play_heartbeat()
+{
+    
+    // Play the tone resembling a single heartbeat
+    ledc_timer_config_t ledc_timer = {
+        .duty_resolution = BUZZER_RESOLUTION,
+        .freq_hz = BUZZER_FREQ_HZ,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_num = LEDC_TIMER_0
+    };
+    ledc_timer_config(&ledc_timer);
+
+    ledc_channel_config_t ledc_channel = {
+        .channel = BUZZER_CHANNEL,
+        .duty = 128,
+        .gpio_num = BUZZER_GPIO,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_sel = LEDC_TIMER_0
+    };
+    ledc_channel_config(&ledc_channel);
+
+    // Play the low-pitch beat
+    ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, 0);
+    ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
+    vTaskDelay(pdMS_TO_TICKS(50));
+
+    // Play the higher-pitch beat
+    ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, 128);
+    ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
+    vTaskDelay(pdMS_TO_TICKS(50));
+    buzzer_stop();
+}
+
+void buzzer_play_james_bond()
+{
+    
+    // Define the duty cycle values for the James Bond theme
+    uint8_t duty_cycles[] = {128, 200, 128, 0, 128, 200, 128, 0, 128, 128, 128, 0, 128, 64, 0, 192};
+
+    // Configure the LEDC timer
+    ledc_timer_config_t ledc_timer = {
+        .duty_resolution = BUZZER_RESOLUTION,
+        .freq_hz = BUZZER_FREQ_HZ,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_num = LEDC_TIMER_0
+    };
+    ledc_timer_config(&ledc_timer);
+
+    // Configure the LEDC channel
+    ledc_channel_config_t ledc_channel = {
+        .channel = BUZZER_CHANNEL,
+        .duty = 0,
+        .gpio_num = BUZZER_GPIO,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_sel = LEDC_TIMER_0
+    };
+    ledc_channel_config(&ledc_channel);
+
+    // Play the James Bond theme
+    for (int i = 0; i < sizeof(duty_cycles) / sizeof(duty_cycles[0]); i++)
+    {
+        ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, duty_cycles[i]);
+        ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
+        vTaskDelay(pdMS_TO_TICKS(200));
+    }
+
+    buzzer_stop();
+}
+void buzzer_play_error_tune()
+{
+    
+    // Define the duty cycle values for the error tune
+    uint8_t duty_cycles[] = {200, 0, 128, 0, 200, 0, 128, 0, 200, 0};
+
+    // Configure the LEDC timer
+    ledc_timer_config_t ledc_timer = {
+        .duty_resolution = BUZZER_RESOLUTION,
+        .freq_hz = BUZZER_FREQ_HZ,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_num = LEDC_TIMER_0
+    };
+    ledc_timer_config(&ledc_timer);
+
+    // Configure the LEDC channel
+    ledc_channel_config_t ledc_channel = {
+        .channel = BUZZER_CHANNEL,
+        .duty = 0,
+        .gpio_num = BUZZER_GPIO,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_sel = LEDC_TIMER_0
+    };
+    ledc_channel_config(&ledc_channel);
+
+    // Play the error tune
+    for (int i = 0; i < sizeof(duty_cycles) / sizeof(duty_cycles[0]); i++)
+    {
+        ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, duty_cycles[i]);
+        ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
+        vTaskDelay(pdMS_TO_TICKS(20));
+    }
+
+    buzzer_stop();
+}
+
+void buzzer_play_mario_tune()
+{
+    
+    // Define the duty cycle values for the Mario tune
+    uint8_t duty_cycles[] = {150, 0, 150, 0, 150, 0, 100, 0, 150, 0, 100, 0, 150, 0, 0, 0};
+
+    // Configure the LEDC timer
+    ledc_timer_config_t ledc_timer = {
+        .duty_resolution = BUZZER_RESOLUTION,
+        .freq_hz = BUZZER_FREQ_HZ,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_num = LEDC_TIMER_0
+    };
+    ledc_timer_config(&ledc_timer);
+
+    // Configure the LEDC channel
+    ledc_channel_config_t ledc_channel = {
+        .channel = BUZZER_CHANNEL,
+        .duty = 0,
+        .gpio_num = BUZZER_GPIO,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_sel = LEDC_TIMER_0
+    };
+    ledc_channel_config(&ledc_channel);
+
+    // Play the Mario tune
+    for (int i = 0; i < sizeof(duty_cycles) / sizeof(duty_cycles[0]); i++)
+    {
+        ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, duty_cycles[i]);
+        ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
+        vTaskDelay(pdMS_TO_TICKS(200));
+    }
+
+    buzzer_stop();
+}
+
+void buzzer_play_happy_tune()
+{
+    
+    // Define the duty cycle values for the happy tune
+    uint8_t duty_cycles[] = {128, 150, 170, 192, 170, 150, 128, 128};
+
+    // Configure the LEDC timer
+    ledc_timer_config_t ledc_timer = {
+        .duty_resolution = BUZZER_RESOLUTION,
+        .freq_hz = BUZZER_FREQ_HZ,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_num = LEDC_TIMER_0
+    };
+    ledc_timer_config(&ledc_timer);
+
+    // Configure the LEDC channel
+    ledc_channel_config_t ledc_channel = {
+        .channel = BUZZER_CHANNEL,
+        .duty = 0,
+        .gpio_num = BUZZER_GPIO,
+        .speed_mode = LEDC_LOW_SPEED_MODE,
+        .timer_sel = LEDC_TIMER_0
+    };
+    ledc_channel_config(&ledc_channel);
+
+    // Play the happy tune
+    for (int i = 0; i < sizeof(duty_cycles) / sizeof(duty_cycles[0]); i++)
+    {
+        ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, duty_cycles[i]);
+        ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
+        vTaskDelay(pdMS_TO_TICKS(300));
+    }
+
+    buzzer_stop();
+}
diff --git a/examples/thing_shadow/main/core/extra/ldo_control.c b/examples/thing_shadow/main/core/extra/ldo_control.c
new file mode 100644
index 000000000..c4976d825
--- /dev/null
+++ b/examples/thing_shadow/main/core/extra/ldo_control.c
@@ -0,0 +1,23 @@
+#include "ldo_control.h"
+#include "driver/gpio.h"
+
+
+#define LDO_CONTROL_GPIO GPIO_NUM_10
+
+void ldo_init()
+{
+    // Initialization code remains the same
+    gpio_pad_select_gpio(LDO_CONTROL_GPIO);
+    gpio_set_direction(LDO_CONTROL_GPIO, GPIO_MODE_OUTPUT);
+}
+
+void ldo_on()
+{
+    gpio_set_level(LDO_CONTROL_GPIO, 1);
+}
+
+
+void ldo_off()
+{
+    gpio_set_level(LDO_CONTROL_GPIO, 0);
+}
diff --git a/examples/thing_shadow/main/core/extra/ping_time.c b/examples/thing_shadow/main/core/extra/ping_time.c
new file mode 100644
index 000000000..8112a932c
--- /dev/null
+++ b/examples/thing_shadow/main/core/extra/ping_time.c
@@ -0,0 +1,114 @@
+#include "esp_sntp.h"
+#include "esp_tls.h"
+#include <time.h>
+#include "ping_time.h"
+#include "esp_log.h"
+
+#define TAG "Time:"
+
+bool sntp_resta = false;
+long ttime;
+
+/**
+ * @brief This function is responsible for converting time string to Unix 
+ * 
+ * @param ptr char*
+ * @return long 
+ */
+static long ConvertParseTimeToUnix(char *ptr)
+{
+    struct tm result;
+    memset(&result, 0, sizeof(struct tm));
+    time_t epoch;
+    strptime(ptr, "%Y-%m-%d %R", &result);
+    epoch = mktime(&result);
+    return (epoch);
+}
+/**
+ * @brief Notification for time sync
+ * 
+ * @param tv 
+ */
+static void time_sync_notification_cb(struct timeval *tv)
+{
+    ESP_LOGI(TAG, "Notification of a time synchronization event");
+}
+/**
+ * @brief Intialization SNTP server
+ * 
+ */
+static void initialize_sntp(void)
+{
+    ESP_LOGI(TAG, "Initializing SNTP");
+    sntp_setoperatingmode(SNTP_OPMODE_POLL);
+    sntp_setservername(0, "time.google.com");
+    sntp_set_time_sync_notification_cb(time_sync_notification_cb);
+    sntp_init();
+}
+/**
+ * @brief Getting time from SNTP server
+ * 
+ */
+static void obtain_time(void)
+{
+    if (!sntp_restart())
+    {
+        initialize_sntp();
+    }
+    else
+    {
+        //do nothing
+    }
+    time_t now = 0;
+    int retry = 0;
+    const int retry_count = 25;
+    while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count)
+    {
+        ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
+        vTaskDelay(2000 / portTICK_PERIOD_MS);
+        if (retry_count == 24)
+        {
+            sntp_resta = true;
+        }
+    }
+    time(&now);
+}
+long GetStandardTime()
+{
+    time_t now;
+    struct tm timeinfo;
+    time(&now);
+    localtime_r(&now, &timeinfo);
+    // Is time set? If not, tm_year will be (1970 - 1900).
+    if (timeinfo.tm_year < (2016 - 1900) || sntp_resta)
+    {
+        ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
+        obtain_time();
+        // update 'now' variable with current time
+        time(&now);
+        sntp_resta = false;
+    }
+    char strftime_buf[64];
+
+    setenv("TZ", "GMT-2", 1);
+    tzset();
+    localtime_r(&now, &timeinfo);
+    strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
+    ESP_LOGI(TAG, "Time : %s", strftime_buf);
+
+    if (sntp_get_sync_mode() == SNTP_SYNC_MODE_SMOOTH)
+    {
+        struct timeval outdelta;
+        while (sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS)
+        {
+            adjtime(NULL, &outdelta);
+            ESP_LOGI(TAG, "Waiting for adjusting time ... outdelta = %li sec: %li ms: %li us",
+            outdelta.tv_sec,
+            outdelta.tv_usec / 1000,
+            outdelta.tv_usec % 1000);
+
+            vTaskDelay(2000 / portTICK_PERIOD_MS);
+        }
+    }
+    return (now);
+}
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/extra/sensors.c b/examples/thing_shadow/main/core/extra/sensors.c
new file mode 100644
index 000000000..d3a7aad2f
--- /dev/null
+++ b/examples/thing_shadow/main/core/extra/sensors.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "sensors.h"
+#include "driver/temp_sensor.h"
+#include "esp_log.h"
+
+#define INT_STRING_SIZE 10 // Adjust the size as per your requirement
+
+static const char *TAG = "SENSORS";
+
+void sensors_initialize()
+{
+    ESP_LOGI(TAG, "Initializing Temperature sensor");
+    temp_sensor_config_t temp_sensor = TSENS_CONFIG_DEFAULT();
+    temp_sensor_get_config(&temp_sensor);
+    ESP_LOGI(TAG, "default dac %d, clk_div %d", temp_sensor.dac_offset, temp_sensor.clk_div);
+    temp_sensor.dac_offset = TSENS_DAC_DEFAULT; // DEFAULT: range:-10℃ ~  80℃, error < 1℃.
+    temp_sensor_set_config(temp_sensor);
+    temp_sensor_start();
+    ESP_LOGI(TAG, "Temperature sensor started");
+}
+
+static char* int_to_string(int value)
+{
+    static char str[INT_STRING_SIZE];
+    snprintf(str, INT_STRING_SIZE, "%d", value);
+    return str;
+}
+
+char* get_board_temp()
+{
+    char *out_temp = "nan";
+    float tsens_out;
+    if (temp_sensor_read_celsius(&tsens_out) != ESP_OK) {
+        ESP_LOGE(TAG, "Error reading temperature data");
+        return out_temp;
+    }
+
+    int temperature = (int)tsens_out; // Convert float to int
+    ESP_LOGI(TAG, "Temperature out celsius %d°C", temperature);
+    out_temp = int_to_string(temperature);
+    return out_temp;
+}
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/extra/sleep.c b/examples/thing_shadow/main/core/extra/sleep.c
new file mode 100644
index 000000000..e12ebed34
--- /dev/null
+++ b/examples/thing_shadow/main/core/extra/sleep.c
@@ -0,0 +1,58 @@
+
+#include "sleep.h"
+#include "cJSON.h"
+#include "driver/gpio.h"
+#include "esp_log.h"
+#include "esp_sleep.h"
+#include "esp_wifi.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "main.h"
+#include "nvs_platform.h"
+#include "ping_time.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define POWER_PIN 36
+
+#define WRITE 1
+#define READ 0
+
+/**
+ * @brief
+ *
+ */
+void write_nvs_config() {
+        nvs_perform_str("version", device_config.version, STR, WRITE);
+        nvs_perform_str("facility_id", device_config.facility_id, STR, WRITE);
+        nvs_perform_number("pub_inter", &device_config.publish_interval, U16, WRITE);
+        nvs_perform_number("led", &device_config.led, U8, WRITE);
+        nvs_perform_number("dgb_mode", &device_config.dbg_mode, U8, WRITE);
+}
+/**
+ * @brief
+ *
+ */
+void read_nvs_config() {
+    
+        nvs_perform_str("version", device_config.version, STR, READ);
+        nvs_perform_str("facility_id", device_config.facility_id, STR, READ);
+        nvs_perform_number("pub_inter", &device_config.publish_interval, U16, READ);
+        nvs_perform_number("led", &device_config.led, U8, READ);
+        nvs_perform_number("dgb_mode", &device_config.dbg_mode, U8, READ);
+
+        //** fall back condition
+
+        device_config.publish_interval = (device_config.publish_interval == 0) ?
+                        30 :
+                        device_config.publish_interval;
+
+        if (strlen(device_config.version) == 0)
+                sprintf(device_config.version, "%s", "v1.0.0");
+
+        if (strlen(device_config.facility_id) == 0) {
+                sprintf(device_config.facility_id, "%s", "testing");
+                write_nvs_config();
+        }
+}
diff --git a/examples/thing_shadow/main/core/extra/uart_handler.c b/examples/thing_shadow/main/core/extra/uart_handler.c
new file mode 100644
index 000000000..77dbd1e58
--- /dev/null
+++ b/examples/thing_shadow/main/core/extra/uart_handler.c
@@ -0,0 +1,101 @@
+#include "uart_handler.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "soc/uart_struct.h"
+#include "string.h"
+#include "driver/gpio.h"
+
+#define UART_PORT          (UART_NUM_0)
+#define TEST_TXD   (21)
+#define TEST_RXD   (20)
+#define TEST_RTS   UART_PIN_NO_CHANGE
+#define TEST_CTS   UART_PIN_NO_CHANGE
+
+#define BUF_SIZE        (127)
+#define BAUD_RATE       (38400)
+#define PACKET_READ_TICS        (100 / portTICK_RATE_MS)
+
+#define MAX_RETRY_ATTEMPTS    (5)
+
+
+static const char *TAG = "RS485_Handler";
+
+bool uart_initialize()
+{
+    const int uart_num = UART_PORT;
+    uart_config_t uart_config = {
+        .baud_rate = BAUD_RATE,
+        .data_bits = UART_DATA_8_BITS,
+        .parity = UART_PARITY_DISABLE,
+        .stop_bits = UART_STOP_BITS_1,
+        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+        .rx_flow_ctrl_thresh = 122,
+    };
+
+    esp_log_level_set(TAG, ESP_LOG_INFO);
+    ESP_LOGI(TAG, "Start RS485 application test and configure UART.");
+
+    if (uart_param_config(uart_num, &uart_config) != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to configure UART parameters");
+        return false;
+    }
+
+    ESP_LOGI(TAG, "UART set pins, mode, and install driver.");
+    if (uart_set_pin(uart_num, TEST_TXD, TEST_RXD, TEST_RTS, TEST_CTS) != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to set UART pins");
+        return false;
+    }
+
+    if (uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0) != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to install UART driver");
+        return false;
+    }
+
+    if (uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX) != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to set UART mode");
+        return false;
+    }
+
+    return true;
+}
+
+bool get_uart_data(char* buffer, size_t buffer_size)
+{
+    uint8_t* data = (uint8_t*)malloc(BUF_SIZE);
+    if (data == NULL) {
+        ESP_LOGE(TAG, "Failed to allocate memory for data buffer");
+        return false;
+    }
+
+    int len = 0;
+
+    const char* test_str = "3101valuer\n\r";
+
+    for (int ctr = 0; ctr < MAX_RETRY_ATTEMPTS; ctr++) {
+        uart_flush(UART_PORT);
+        uart_write_bytes(UART_PORT, test_str, strlen(test_str));
+        vTaskDelay(pdMS_TO_TICKS(50));
+        len = uart_read_bytes(UART_PORT, data, BUF_SIZE, PACKET_READ_TICS);
+        ESP_LOGI(TAG, "data length: %d", len);
+
+        if (len >= 25) {
+            ESP_LOGI(TAG, "Received data: %s \nData looks valid. Exiting the loop...", (char*)data);
+            snprintf(buffer, buffer_size, "%.*s", len, (char*)data);
+            free(data);
+            uart_flush(UART_PORT);
+            vTaskDelay(pdMS_TO_TICKS(50));
+            return true;
+        } else {
+            ESP_LOGI(TAG, "Invalid data: %s \nTrying again ...", (char*)data);
+        }
+
+        vTaskDelay(pdMS_TO_TICKS(200));
+    }
+
+    free(data);
+    uart_flush(UART_PORT);
+    return false;
+}
diff --git a/examples/thing_shadow/main/core/include/buzzer.h b/examples/thing_shadow/main/core/include/buzzer.h
new file mode 100644
index 000000000..84d35dfa6
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/buzzer.h
@@ -0,0 +1,22 @@
+#ifndef BUZZER_H
+#define BUZZER_H
+
+#include "driver/gpio.h"
+#include "driver/ledc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#define BUZZER_GPIO GPIO_NUM_0
+#define BUZZER_CHANNEL LEDC_CHANNEL_0
+#define BUZZER_FREQ_HZ 2000
+#define BUZZER_RESOLUTION LEDC_TIMER_8_BIT
+
+void buzzer_stop();
+void buzzer_play_tone();
+void buzzer_play_heartbeat();
+void buzzer_play_james_bond();
+void buzzer_play_error_tune();
+void buzzer_play_mario_tune();
+void buzzer_play_happy_tune();
+
+#endif // BUZZER_H
diff --git a/examples/thing_shadow/main/core/include/ldo_control.h b/examples/thing_shadow/main/core/include/ldo_control.h
new file mode 100644
index 000000000..42a1ae45c
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/ldo_control.h
@@ -0,0 +1,12 @@
+#ifndef LDO_CONTROL_H
+#define LDO_CONTROL_H
+
+#include "driver/gpio.h"
+
+#define LDO_CONTROL_GPIO GPIO_NUM_10
+
+void ldo_init();
+void ldo_on();
+void ldo_off();
+
+#endif /* LDO_CONTROL_H */
diff --git a/examples/thing_shadow/main/core/include/main.h b/examples/thing_shadow/main/core/include/main.h
new file mode 100644
index 000000000..ca50a27f1
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/main.h
@@ -0,0 +1,27 @@
+#ifndef MAIN_H_
+#define MAIN_H_
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "stdbool.h"
+
+extern bool wifi_sta;
+
+typedef struct {
+        char version[32];
+        uint16_t publish_interval;
+        char facility_id[32];
+        uint8_t led;
+        uint8_t dbg_mode;
+        uint8_t reset;
+} device_config_t;
+
+extern device_config_t device_config;
+
+extern bool wifi_sta;
+
+#define Sleep(X) vTaskDelay(X * 1000 / portTICK_PERIOD_MS);
+
+extern bool feed_watchdog;
+
+#endif // MAIN_H
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/include/ping_time.h b/examples/thing_shadow/main/core/include/ping_time.h
new file mode 100644
index 000000000..c68b25a65
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/ping_time.h
@@ -0,0 +1,13 @@
+#ifndef PING_TIME_H_
+#define PING_TIME_H_
+
+extern bool sntp_resta;
+
+/**
+ * @brief Get the Standard Time object
+ * 
+ * @return long 
+ */
+long GetStandardTime();
+
+#endif
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/include/sensors.h b/examples/thing_shadow/main/core/include/sensors.h
new file mode 100644
index 000000000..da1d312a4
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/sensors.h
@@ -0,0 +1,12 @@
+
+#ifndef SENSORS_H
+#define SENSORS_H
+
+#include "driver/temp_sensor.h"
+
+#define FLOAT_STRING_SIZE 10
+
+void sensors_initialize();
+char* get_board_temp();
+
+#endif /* SENSORS_H */
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/include/sleep.h b/examples/thing_shadow/main/core/include/sleep.h
new file mode 100644
index 000000000..e389b4fa3
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/sleep.h
@@ -0,0 +1,7 @@
+#ifndef SLEEP_H_
+#define SLEEP_H_
+
+void read_nvs_config();
+void  write_nvs_config();
+
+#endif //SLEEP_H
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/include/uart_handler.h b/examples/thing_shadow/main/core/include/uart_handler.h
new file mode 100644
index 000000000..468a93a4b
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/uart_handler.h
@@ -0,0 +1,23 @@
+#ifndef UART_HANDLER_H_
+#define UART_HANDLER_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/**
+ * @brief Initializes the UART module.
+ *
+ * @return true if the initialization is successful, false otherwise.
+ */
+bool uart_initialize();
+
+/**
+ * @brief Retrieves data from the UART module.
+ *
+ * @param buffer The buffer to store the retrieved data.
+ * @param buffer_size The size of the buffer.
+ * @return true if data retrieval is successful, false otherwise.
+ */
+bool get_uart_data(char* buffer, size_t buffer_size);
+
+#endif /* UART_HANDLER_H_ */
diff --git a/examples/thing_shadow/main/core/include/wifi_driver/data_store_nvs.h b/examples/thing_shadow/main/core/include/wifi_driver/data_store_nvs.h
new file mode 100644
index 000000000..eb30fca4d
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/wifi_driver/data_store_nvs.h
@@ -0,0 +1,30 @@
+#ifndef _DATA_STORE_NVS_H
+#define _DATA_STORE_NVS_H
+
+/**
+ * @brief WriteStrNVS() function stores the specified strings into the NVS. It requires a Key and a value
+ *
+ * @param char *key
+ * @param char *value
+ * @return None
+ */
+void WriteStrNVS(char *, char *);
+
+/**
+ * @brief A helper function to load the new wifi credentials i.e. SSID and Password from the NVS in single go. Stores the data in global variable ssid[30] and pswd[30]
+ * @param None
+ * @return None
+ */
+void GetWifiCred();
+/**
+ * @brief A helper function to load the new parse credentials i.e. userID, Password, and deviceNum from the NVS in single go.
+ * Stores the data in global variable user_name[30],user_pswd[30], and user_device_num[5]
+ * @param None
+ * @return None
+ */
+
+void NVSInit();
+
+extern char ssid[30], pswd[30],tank[30], user_name[30], user_pswd[30], user_device_num[5];
+
+#endif // _DATA_STORE_NVS_H
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/include/wifi_driver/http_server.h b/examples/thing_shadow/main/core/include/wifi_driver/http_server.h
new file mode 100644
index 000000000..4b2ae8b3b
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/wifi_driver/http_server.h
@@ -0,0 +1,39 @@
+#ifndef _HTTP_SERVER_H
+#define _HTTP_SERVER_H
+
+#include <esp_http_server.h>
+#include <esp_event_base.h>
+
+/**
+ * @brief This function registers the URIs that will be accessible by the clients
+ * @param None
+ * @return httpd_handle_t
+ */
+httpd_handle_t start_webserver(void);
+
+/**
+ * @brief This function is responsible for stopping the web server
+ *
+ * @param arg
+ * @param event_base
+ * @param event_id
+ * @param event_data
+ */
+void disconnect_handler(void *arg, esp_event_base_t event_base,
+                        int32_t event_id, void *event_data);
+/**
+ * @brief This function is responsible for start the web server
+ *
+ * @param arg
+ * @param event_base
+ * @param event_id
+ * @param event_data
+ */
+void connect_handler(void *arg, esp_event_base_t event_base,
+                     int32_t event_id, void *event_data);
+/**
+ * @brief Register Connect and disconnect event handlers
+ */
+void WebServerEventRegister();
+
+#endif // _HTTP_SERVER_H
diff --git a/examples/thing_shadow/main/core/include/wifi_driver/nvs_platform.h b/examples/thing_shadow/main/core/include/wifi_driver/nvs_platform.h
new file mode 100644
index 000000000..e9775de9d
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/wifi_driver/nvs_platform.h
@@ -0,0 +1,38 @@
+/**
+ * @file nvs_platform.h
+ * @author Hamxa Islam {hamzaislam170@gamil.com}
+ * @brief Remotewell_PRO
+ * @version 0.1
+ * @date 2022-11-04
+ *
+ * EPTeck Technologies Gmbh
+ *
+ */
+
+#ifndef _NVS_PLATFORM_
+#define _NVS_PLATFORM_
+
+#include "stdlib.h"
+#include "stdint.h"
+#include <stdio.h>
+#include <string.h>
+#include "stdbool.h"
+
+#include "sdkconfig.h"
+
+/*:) NVS Enum and Struct-------------------------------------------------------*/
+
+typedef enum
+{
+    U8,
+    U16,
+    U32,
+    STR
+} e_nvs_param_t;
+
+/*:) NVS External Function -------------------------------------------------------*/
+
+void nvs_perform_number(char *key, uint32_t *value, e_nvs_param_t type, bool read_write);
+void nvs_perform_str(char *key, char *value, e_nvs_param_t type, bool read_write);
+void nvs_init(void *param);
+#endif
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/include/wifi_driver/scan.h b/examples/thing_shadow/main/core/include/wifi_driver/scan.h
new file mode 100644
index 000000000..17ac2d354
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/wifi_driver/scan.h
@@ -0,0 +1,12 @@
+#ifndef _SCAN_H_
+#define _SCAN_H_
+
+/**
+ * @brief WiFiScan() this function disconnects the ESP to Scan for available wifi interfaces available. It calls another
+ * function CreateScanJsonPacket() to save the found wifis in a json packet. it is used in the web server scan api
+ * @param None
+ * @return None
+ */
+void WiFiScan(char *pscan_list);
+
+#endif //_SCAN_H_
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/include/wifi_driver/wifi_manager.h b/examples/thing_shadow/main/core/include/wifi_driver/wifi_manager.h
new file mode 100644
index 000000000..802e9ab4e
--- /dev/null
+++ b/examples/thing_shadow/main/core/include/wifi_driver/wifi_manager.h
@@ -0,0 +1,31 @@
+#ifndef _WIFI_MANAGER_H
+#define _WIFI_MANAGER_H
+
+
+
+extern uint8_t wifi_state;
+extern int disconnectivity_count;
+/**
+ * @brief initialzing wifi and webserver
+ *
+ */
+void WifiInit();
+/**
+ * @brief AP mode configurations and initialization
+ *
+ */
+void Wifi_AP(void);
+/**
+ * @brief STA mode configurations and initialization
+ *
+ */
+void Wifi_STA(void);
+/**
+ * @brief STA+AP mode configurations and initialization
+ *
+ */
+void Wifi_AP_STA(void);
+
+
+
+#endif
diff --git a/examples/thing_shadow/main/core/libraries/cJSON.c b/examples/thing_shadow/main/core/libraries/cJSON.c
new file mode 100644
index 000000000..71a0f08d3
--- /dev/null
+++ b/examples/thing_shadow/main/core/libraries/cJSON.c
@@ -0,0 +1,3204 @@
+/*
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+#if defined(_MSC_VER)
+#pragma warning(push)
+/* disable warning about single line comments in system headers */
+#pragma warning(disable : 4001)
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <float.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+#include "cJSON.h"
+
+/* define our own boolean type */
+#ifdef true
+#undef true
+#endif
+#define true ((cJSON_bool)1)
+
+#ifdef false
+#undef false
+#endif
+#define false ((cJSON_bool)0)
+
+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
+#ifndef isinf
+#define isinf(d) (isnan((d - d)) && !isnan(d))
+#endif
+#ifndef isnan
+#define isnan(d) (d != d)
+#endif
+
+#ifndef NAN
+#ifdef _WIN32
+#define NAN sqrt(-1.0)
+#else
+#define NAN 0.0 / 0.0
+#endif
+#endif
+
+typedef struct
+{
+    const unsigned char *json;
+    size_t position;
+} error;
+static error global_error = {NULL, 0};
+
+CJSON_PUBLIC(const char *)
+cJSON_GetErrorPtr(void)
+{
+    return (const char *)(global_error.json + global_error.position);
+}
+
+CJSON_PUBLIC(char *)
+cJSON_GetStringValue(const cJSON *const item)
+{
+    if (!cJSON_IsString(item))
+    {
+        return NULL;
+    }
+
+    return item->valuestring;
+}
+
+CJSON_PUBLIC(double)
+cJSON_GetNumberValue(const cJSON *const item)
+{
+    if (!cJSON_IsNumber(item))
+    {
+        return (double)NAN;
+    }
+
+    return item->valuedouble;
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15)
+#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
+
+CJSON_PUBLIC(const char *)
+cJSON_Version(void)
+{
+    static char version[15];
+    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+    return version;
+}
+
+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
+static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
+{
+    if ((string1 == NULL) || (string2 == NULL))
+    {
+        return 1;
+    }
+
+    if (string1 == string2)
+    {
+        return 0;
+    }
+
+    for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
+    {
+        if (*string1 == '\0')
+        {
+            return 0;
+        }
+    }
+
+    return tolower(*string1) - tolower(*string2);
+}
+
+typedef struct internal_hooks
+{
+    void *(CJSON_CDECL *allocate)(size_t size);
+    void(CJSON_CDECL *deallocate)(void *pointer);
+    void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
+} internal_hooks;
+
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
+static void *CJSON_CDECL internal_malloc(size_t size)
+{
+    return malloc(size);
+}
+static void CJSON_CDECL internal_free(void *pointer)
+{
+    free(pointer);
+}
+static void *CJSON_CDECL internal_realloc(void *pointer, size_t size)
+{
+    return realloc(pointer, size);
+}
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = {internal_malloc, internal_free, internal_realloc};
+
+static unsigned char *cJSON_strdup(const unsigned char *string, const internal_hooks *const hooks)
+{
+    size_t length = 0;
+    unsigned char *copy = NULL;
+
+    if (string == NULL)
+    {
+        return NULL;
+    }
+
+    length = strlen((const char *)string) + sizeof("");
+    copy = (unsigned char *)hooks->allocate(length);
+    if (copy == NULL)
+    {
+        return NULL;
+    }
+    memcpy(copy, string, length);
+
+    return copy;
+}
+
+CJSON_PUBLIC(void)
+cJSON_InitHooks(cJSON_Hooks *hooks)
+{
+    if (hooks == NULL)
+    {
+        /* Reset hooks */
+        global_hooks.allocate = malloc;
+        global_hooks.deallocate = free;
+        global_hooks.reallocate = realloc;
+        return;
+    }
+
+    global_hooks.allocate = malloc;
+    if (hooks->malloc_fn != NULL)
+    {
+        global_hooks.allocate = hooks->malloc_fn;
+    }
+
+    global_hooks.deallocate = free;
+    if (hooks->free_fn != NULL)
+    {
+        global_hooks.deallocate = hooks->free_fn;
+    }
+
+    /* use realloc only if both free and malloc are used */
+    global_hooks.reallocate = NULL;
+    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
+    {
+        global_hooks.reallocate = realloc;
+    }
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(const internal_hooks *const hooks)
+{
+    cJSON *node = (cJSON *)hooks->allocate(sizeof(cJSON));
+    if (node)
+    {
+        memset(node, '\0', sizeof(cJSON));
+    }
+
+    return node;
+}
+
+/* Delete a cJSON structure. */
+CJSON_PUBLIC(void)
+cJSON_Delete(cJSON *item)
+{
+    cJSON *next = NULL;
+    while (item != NULL)
+    {
+        next = item->next;
+        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
+        {
+            cJSON_Delete(item->child);
+        }
+        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
+        {
+            global_hooks.deallocate(item->valuestring);
+        }
+        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+        {
+            global_hooks.deallocate(item->string);
+        }
+        global_hooks.deallocate(item);
+        item = next;
+    }
+}
+
+/* get the decimal point character of the current locale */
+static unsigned char get_decimal_point(void)
+{
+#ifdef ENABLE_LOCALES
+    struct lconv *lconv = localeconv();
+    return (unsigned char)lconv->decimal_point[0];
+#else
+    return '.';
+#endif
+}
+
+typedef struct
+{
+    const unsigned char *content;
+    size_t length;
+    size_t offset;
+    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
+    internal_hooks hooks;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer)
+{
+    double number = 0;
+    unsigned char *after_end = NULL;
+    unsigned char number_c_string[64];
+    unsigned char decimal_point = get_decimal_point();
+    size_t i = 0;
+
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
+    {
+        return false;
+    }
+
+    /* copy the number into a temporary buffer and replace '.' with the decimal point
+     * of the current locale (for strtod)
+     * This also takes care of '\0' not necessarily being available for marking the end of the input */
+    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
+    {
+        switch (buffer_at_offset(input_buffer)[i])
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case '+':
+        case '-':
+        case 'e':
+        case 'E':
+            number_c_string[i] = buffer_at_offset(input_buffer)[i];
+            break;
+
+        case '.':
+            number_c_string[i] = decimal_point;
+            break;
+
+        default:
+            goto loop_end;
+        }
+    }
+loop_end:
+    number_c_string[i] = '\0';
+
+    number = strtod((const char *)number_c_string, (char **)&after_end);
+    if (number_c_string == after_end)
+    {
+        return false; /* parse_error */
+    }
+
+    item->valuedouble = number;
+
+    /* use saturation in case of overflow */
+    if (number >= INT_MAX)
+    {
+        item->valueint = INT_MAX;
+    }
+    else if (number <= (double)INT_MIN)
+    {
+        item->valueint = INT_MIN;
+    }
+    else
+    {
+        item->valueint = (int)number;
+    }
+
+    item->type = cJSON_Number;
+
+    input_buffer->offset += (size_t)(after_end - number_c_string);
+    return true;
+}
+
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double)
+cJSON_SetNumberHelper(cJSON *object, double number)
+{
+    if (number >= INT_MAX)
+    {
+        object->valueint = INT_MAX;
+    }
+    else if (number <= (double)INT_MIN)
+    {
+        object->valueint = INT_MIN;
+    }
+    else
+    {
+        object->valueint = (int)number;
+    }
+
+    return object->valuedouble = number;
+}
+
+CJSON_PUBLIC(char *)
+cJSON_SetValuestring(cJSON *object, const char *valuestring)
+{
+    char *copy = NULL;
+    /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
+    if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
+    {
+        return NULL;
+    }
+    if (strlen(valuestring) <= strlen(object->valuestring))
+    {
+        strcpy(object->valuestring, valuestring);
+        return object->valuestring;
+    }
+    copy = (char *)cJSON_strdup((const unsigned char *)valuestring, &global_hooks);
+    if (copy == NULL)
+    {
+        return NULL;
+    }
+    if (object->valuestring != NULL)
+    {
+        cJSON_free(object->valuestring);
+    }
+    object->valuestring = copy;
+
+    return copy;
+}
+
+typedef struct
+{
+    unsigned char *buffer;
+    size_t length;
+    size_t offset;
+    size_t depth; /* current nesting depth (for formatted printing) */
+    cJSON_bool noalloc;
+    cJSON_bool format; /* is this print a formatted print */
+    internal_hooks hooks;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static unsigned char *ensure(printbuffer *const p, size_t needed)
+{
+    unsigned char *newbuffer = NULL;
+    size_t newsize = 0;
+
+    if ((p == NULL) || (p->buffer == NULL))
+    {
+        return NULL;
+    }
+
+    if ((p->length > 0) && (p->offset >= p->length))
+    {
+        /* make sure that offset is valid */
+        return NULL;
+    }
+
+    if (needed > INT_MAX)
+    {
+        /* sizes bigger than INT_MAX are currently not supported */
+        return NULL;
+    }
+
+    needed += p->offset + 1;
+    if (needed <= p->length)
+    {
+        return p->buffer + p->offset;
+    }
+
+    if (p->noalloc)
+    {
+        return NULL;
+    }
+
+    /* calculate new buffer size */
+    if (needed > (INT_MAX / 2))
+    {
+        /* overflow of int, use INT_MAX if possible */
+        if (needed <= INT_MAX)
+        {
+            newsize = INT_MAX;
+        }
+        else
+        {
+            return NULL;
+        }
+    }
+    else
+    {
+        newsize = needed * 2;
+    }
+
+    if (p->hooks.reallocate != NULL)
+    {
+        /* reallocate with realloc if available */
+        newbuffer = (unsigned char *)p->hooks.reallocate(p->buffer, newsize);
+        if (newbuffer == NULL)
+        {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+    }
+    else
+    {
+        /* otherwise reallocate manually */
+        newbuffer = (unsigned char *)p->hooks.allocate(newsize);
+        if (!newbuffer)
+        {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+
+        memcpy(newbuffer, p->buffer, p->offset + 1);
+        p->hooks.deallocate(p->buffer);
+    }
+    p->length = newsize;
+    p->buffer = newbuffer;
+
+    return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer *const buffer)
+{
+    const unsigned char *buffer_pointer = NULL;
+    if ((buffer == NULL) || (buffer->buffer == NULL))
+    {
+        return;
+    }
+    buffer_pointer = buffer->buffer + buffer->offset;
+
+    buffer->offset += strlen((const char *)buffer_pointer);
+}
+
+/* securely comparison of floating-point variables */
+static cJSON_bool compare_double(double a, double b)
+{
+    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+    return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
+/* Render the number nicely from the given item into a string. */
+static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer)
+{
+    unsigned char *output_pointer = NULL;
+    double d = item->valuedouble;
+    int length = 0;
+    size_t i = 0;
+    unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
+    unsigned char decimal_point = get_decimal_point();
+    double test = 0.0;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* This checks for NaN and Infinity */
+    if (isnan(d) || isinf(d))
+    {
+        length = sprintf((char *)number_buffer, "null");
+    }
+    else
+    {
+        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
+        length = sprintf((char *)number_buffer, "%1.15g", d);
+
+        /* Check whether the original double can be recovered */
+        if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
+        {
+            /* If not, print with 17 decimal places of precision */
+            length = sprintf((char *)number_buffer, "%1.17g", d);
+        }
+    }
+
+    /* sprintf failed or buffer overrun occurred */
+    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
+    {
+        return false;
+    }
+
+    /* reserve appropriate space in the output */
+    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    /* copy the printed number to the output and replace locale
+     * dependent decimal point with '.' */
+    for (i = 0; i < ((size_t)length); i++)
+    {
+        if (number_buffer[i] == decimal_point)
+        {
+            output_pointer[i] = '.';
+            continue;
+        }
+
+        output_pointer[i] = number_buffer[i];
+    }
+    output_pointer[i] = '\0';
+
+    output_buffer->offset += (size_t)length;
+
+    return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char *const input)
+{
+    unsigned int h = 0;
+    size_t i = 0;
+
+    for (i = 0; i < 4; i++)
+    {
+        /* parse digit */
+        if ((input[i] >= '0') && (input[i] <= '9'))
+        {
+            h += (unsigned int)input[i] - '0';
+        }
+        else if ((input[i] >= 'A') && (input[i] <= 'F'))
+        {
+            h += (unsigned int)10 + input[i] - 'A';
+        }
+        else if ((input[i] >= 'a') && (input[i] <= 'f'))
+        {
+            h += (unsigned int)10 + input[i] - 'a';
+        }
+        else /* invalid */
+        {
+            return 0;
+        }
+
+        if (i < 3)
+        {
+            /* shift left to make place for the next nibble */
+            h = h << 4;
+        }
+    }
+
+    return h;
+}
+
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char *const input_pointer, const unsigned char *const input_end, unsigned char **output_pointer)
+{
+    long unsigned int codepoint = 0;
+    unsigned int first_code = 0;
+    const unsigned char *first_sequence = input_pointer;
+    unsigned char utf8_length = 0;
+    unsigned char utf8_position = 0;
+    unsigned char sequence_length = 0;
+    unsigned char first_byte_mark = 0;
+
+    if ((input_end - first_sequence) < 6)
+    {
+        /* input ends unexpectedly */
+        goto fail;
+    }
+
+    /* get the first utf16 sequence */
+    first_code = parse_hex4(first_sequence + 2);
+
+    /* check that the code is valid */
+    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
+    {
+        goto fail;
+    }
+
+    /* UTF16 surrogate pair */
+    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
+    {
+        const unsigned char *second_sequence = first_sequence + 6;
+        unsigned int second_code = 0;
+        sequence_length = 12; /* \uXXXX\uXXXX */
+
+        if ((input_end - second_sequence) < 6)
+        {
+            /* input ends unexpectedly */
+            goto fail;
+        }
+
+        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
+        {
+            /* missing second half of the surrogate pair */
+            goto fail;
+        }
+
+        /* get the second utf16 sequence */
+        second_code = parse_hex4(second_sequence + 2);
+        /* check that the code is valid */
+        if ((second_code < 0xDC00) || (second_code > 0xDFFF))
+        {
+            /* invalid second half of the surrogate pair */
+            goto fail;
+        }
+
+        /* calculate the unicode codepoint from the surrogate pair */
+        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
+    }
+    else
+    {
+        sequence_length = 6; /* \uXXXX */
+        codepoint = first_code;
+    }
+
+    /* encode as UTF-8
+     * takes at maximum 4 bytes to encode:
+     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+    if (codepoint < 0x80)
+    {
+        /* normal ascii, encoding 0xxxxxxx */
+        utf8_length = 1;
+    }
+    else if (codepoint < 0x800)
+    {
+        /* two bytes, encoding 110xxxxx 10xxxxxx */
+        utf8_length = 2;
+        first_byte_mark = 0xC0; /* 11000000 */
+    }
+    else if (codepoint < 0x10000)
+    {
+        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 3;
+        first_byte_mark = 0xE0; /* 11100000 */
+    }
+    else if (codepoint <= 0x10FFFF)
+    {
+        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 4;
+        first_byte_mark = 0xF0; /* 11110000 */
+    }
+    else
+    {
+        /* invalid unicode codepoint */
+        goto fail;
+    }
+
+    /* encode as utf8 */
+    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
+    {
+        /* 10xxxxxx */
+        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+        codepoint >>= 6;
+    }
+    /* encode first byte */
+    if (utf8_length > 1)
+    {
+        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
+    }
+    else
+    {
+        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
+    }
+
+    *output_pointer += utf8_length;
+
+    return sequence_length;
+
+fail:
+    return 0;
+}
+
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer)
+{
+    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
+    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
+    unsigned char *output_pointer = NULL;
+    unsigned char *output = NULL;
+
+    /* not a string */
+    if (buffer_at_offset(input_buffer)[0] != '\"')
+    {
+        goto fail;
+    }
+
+    {
+        /* calculate approximate size of the output (overestimate) */
+        size_t allocation_length = 0;
+        size_t skipped_bytes = 0;
+        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
+        {
+            /* is escape sequence */
+            if (input_end[0] == '\\')
+            {
+                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
+                {
+                    /* prevent buffer overflow when last input character is a backslash */
+                    goto fail;
+                }
+                skipped_bytes++;
+                input_end++;
+            }
+            input_end++;
+        }
+        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
+        {
+            goto fail; /* string ended unexpectedly */
+        }
+
+        /* This is at most how much we need for the output */
+        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+        output = (unsigned char *)input_buffer->hooks.allocate(allocation_length + sizeof(""));
+        if (output == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+    }
+
+    output_pointer = output;
+    /* loop through the string literal */
+    while (input_pointer < input_end)
+    {
+        if (*input_pointer != '\\')
+        {
+            *output_pointer++ = *input_pointer++;
+        }
+        /* escape sequence */
+        else
+        {
+            unsigned char sequence_length = 2;
+            if ((input_end - input_pointer) < 1)
+            {
+                goto fail;
+            }
+
+            switch (input_pointer[1])
+            {
+            case 'b':
+                *output_pointer++ = '\b';
+                break;
+            case 'f':
+                *output_pointer++ = '\f';
+                break;
+            case 'n':
+                *output_pointer++ = '\n';
+                break;
+            case 'r':
+                *output_pointer++ = '\r';
+                break;
+            case 't':
+                *output_pointer++ = '\t';
+                break;
+            case '\"':
+            case '\\':
+            case '/':
+                *output_pointer++ = input_pointer[1];
+                break;
+
+            /* UTF-16 literal */
+            case 'u':
+                sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+                if (sequence_length == 0)
+                {
+                    /* failed to convert UTF16-literal to UTF-8 */
+                    goto fail;
+                }
+                break;
+
+            default:
+                goto fail;
+            }
+            input_pointer += sequence_length;
+        }
+    }
+
+    /* zero terminate the output */
+    *output_pointer = '\0';
+
+    item->type = cJSON_String;
+    item->valuestring = (char *)output;
+
+    input_buffer->offset = (size_t)(input_end - input_buffer->content);
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (output != NULL)
+    {
+        input_buffer->hooks.deallocate(output);
+    }
+
+    if (input_pointer != NULL)
+    {
+        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
+    }
+
+    return false;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer)
+{
+    const unsigned char *input_pointer = NULL;
+    unsigned char *output = NULL;
+    unsigned char *output_pointer = NULL;
+    size_t output_length = 0;
+    /* numbers of additional characters needed for escaping */
+    size_t escape_characters = 0;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* empty string */
+    if (input == NULL)
+    {
+        output = ensure(output_buffer, sizeof("\"\""));
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char *)output, "\"\"");
+
+        return true;
+    }
+
+    /* set "flag" to 1 if something needs to be escaped */
+    for (input_pointer = input; *input_pointer; input_pointer++)
+    {
+        switch (*input_pointer)
+        {
+        case '\"':
+        case '\\':
+        case '\b':
+        case '\f':
+        case '\n':
+        case '\r':
+        case '\t':
+            /* one character escape sequence */
+            escape_characters++;
+            break;
+        default:
+            if (*input_pointer < 32)
+            {
+                /* UTF-16 escape sequence uXXXX */
+                escape_characters += 5;
+            }
+            break;
+        }
+    }
+    output_length = (size_t)(input_pointer - input) + escape_characters;
+
+    output = ensure(output_buffer, output_length + sizeof("\"\""));
+    if (output == NULL)
+    {
+        return false;
+    }
+
+    /* no characters have to be escaped */
+    if (escape_characters == 0)
+    {
+        output[0] = '\"';
+        memcpy(output + 1, input, output_length);
+        output[output_length + 1] = '\"';
+        output[output_length + 2] = '\0';
+
+        return true;
+    }
+
+    output[0] = '\"';
+    output_pointer = output + 1;
+    /* copy the string */
+    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
+    {
+        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
+        {
+            /* normal character, copy */
+            *output_pointer = *input_pointer;
+        }
+        else
+        {
+            /* character needs to be escaped */
+            *output_pointer++ = '\\';
+            switch (*input_pointer)
+            {
+            case '\\':
+                *output_pointer = '\\';
+                break;
+            case '\"':
+                *output_pointer = '\"';
+                break;
+            case '\b':
+                *output_pointer = 'b';
+                break;
+            case '\f':
+                *output_pointer = 'f';
+                break;
+            case '\n':
+                *output_pointer = 'n';
+                break;
+            case '\r':
+                *output_pointer = 'r';
+                break;
+            case '\t':
+                *output_pointer = 't';
+                break;
+            default:
+                /* escape and print as unicode codepoint */
+                sprintf((char *)output_pointer, "u%04x", *input_pointer);
+                output_pointer += 4;
+                break;
+            }
+        }
+    }
+    output[output_length + 1] = '\"';
+    output[output_length + 2] = '\0';
+
+    return true;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static cJSON_bool print_string(const cJSON *const item, printbuffer *const p)
+{
+    return print_string_ptr((unsigned char *)item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer);
+static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer);
+static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer);
+static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer);
+static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer);
+static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer);
+
+/* Utility to jump whitespace and cr/lf */
+static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer)
+{
+    if ((buffer == NULL) || (buffer->content == NULL))
+    {
+        return NULL;
+    }
+
+    if (cannot_access_at_index(buffer, 0))
+    {
+        return buffer;
+    }
+
+    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
+    {
+        buffer->offset++;
+    }
+
+    if (buffer->offset == buffer->length)
+    {
+        buffer->offset--;
+    }
+
+    return buffer;
+}
+
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer *skip_utf8_bom(parse_buffer *const buffer)
+{
+    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
+    {
+        return NULL;
+    }
+
+    if (can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
+    {
+        buffer->offset += 3;
+    }
+
+    return buffer;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+    size_t buffer_length;
+
+    if (NULL == value)
+    {
+        return NULL;
+    }
+
+    /* Adding null character size due to require_null_terminated. */
+    buffer_length = strlen(value) + sizeof("");
+
+    return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+    parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}};
+    cJSON *item = NULL;
+
+    /* reset error position */
+    global_error.json = NULL;
+    global_error.position = 0;
+
+    if (value == NULL || 0 == buffer_length)
+    {
+        goto fail;
+    }
+
+    buffer.content = (const unsigned char *)value;
+    buffer.length = buffer_length;
+    buffer.offset = 0;
+    buffer.hooks = global_hooks;
+
+    item = cJSON_New_Item(&global_hooks);
+    if (item == NULL) /* memory fail */
+    {
+        goto fail;
+    }
+
+    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
+    {
+        /* parse failure. ep is set. */
+        goto fail;
+    }
+
+    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+    if (require_null_terminated)
+    {
+        buffer_skip_whitespace(&buffer);
+        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
+        {
+            goto fail;
+        }
+    }
+    if (return_parse_end)
+    {
+        *return_parse_end = (const char *)buffer_at_offset(&buffer);
+    }
+
+    return item;
+
+fail:
+    if (item != NULL)
+    {
+        cJSON_Delete(item);
+    }
+
+    if (value != NULL)
+    {
+        error local_error;
+        local_error.json = (const unsigned char *)value;
+        local_error.position = 0;
+
+        if (buffer.offset < buffer.length)
+        {
+            local_error.position = buffer.offset;
+        }
+        else if (buffer.length > 0)
+        {
+            local_error.position = buffer.length - 1;
+        }
+
+        if (return_parse_end != NULL)
+        {
+            *return_parse_end = (const char *)local_error.json + local_error.position;
+        }
+
+        global_error = local_error;
+    }
+
+    return NULL;
+}
+
+/* Default options for cJSON_Parse */
+CJSON_PUBLIC(cJSON *)
+cJSON_Parse(const char *value)
+{
+    return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLength(const char *value, size_t buffer_length)
+{
+    return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
+}
+
+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
+
+static unsigned char *print(const cJSON *const item, cJSON_bool format, const internal_hooks *const hooks)
+{
+    static const size_t default_buffer_size = 256;
+    printbuffer buffer[1];
+    unsigned char *printed = NULL;
+
+    memset(buffer, 0, sizeof(buffer));
+
+    /* create buffer */
+    buffer->buffer = (unsigned char *)hooks->allocate(default_buffer_size);
+    buffer->length = default_buffer_size;
+    buffer->format = format;
+    buffer->hooks = *hooks;
+    if (buffer->buffer == NULL)
+    {
+        goto fail;
+    }
+
+    /* print the value */
+    if (!print_value(item, buffer))
+    {
+        goto fail;
+    }
+    update_offset(buffer);
+
+    /* check if reallocate is available */
+    if (hooks->reallocate != NULL)
+    {
+        printed = (unsigned char *)hooks->reallocate(buffer->buffer, buffer->offset + 1);
+        if (printed == NULL)
+        {
+            goto fail;
+        }
+        buffer->buffer = NULL;
+    }
+    else /* otherwise copy the JSON over to a new buffer */
+    {
+        printed = (unsigned char *)hooks->allocate(buffer->offset + 1);
+        if (printed == NULL)
+        {
+            goto fail;
+        }
+        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+        printed[buffer->offset] = '\0'; /* just to be sure */
+
+        /* free the buffer */
+        hooks->deallocate(buffer->buffer);
+    }
+
+    return printed;
+
+fail:
+    if (buffer->buffer != NULL)
+    {
+        hooks->deallocate(buffer->buffer);
+    }
+
+    if (printed != NULL)
+    {
+        hooks->deallocate(printed);
+    }
+
+    return NULL;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+CJSON_PUBLIC(char *)
+cJSON_Print(const cJSON *item)
+{
+    return (char *)print(item, true, &global_hooks);
+}
+
+CJSON_PUBLIC(char *)
+cJSON_PrintUnformatted(const cJSON *item)
+{
+    return (char *)print(item, false, &global_hooks);
+}
+
+CJSON_PUBLIC(char *)
+cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
+{
+    printbuffer p = {0, 0, 0, 0, 0, 0, {0, 0, 0}};
+
+    if (prebuffer < 0)
+    {
+        return NULL;
+    }
+
+    p.buffer = (unsigned char *)global_hooks.allocate((size_t)prebuffer);
+    if (!p.buffer)
+    {
+        return NULL;
+    }
+
+    p.length = (size_t)prebuffer;
+    p.offset = 0;
+    p.noalloc = false;
+    p.format = fmt;
+    p.hooks = global_hooks;
+
+    if (!print_value(item, &p))
+    {
+        global_hooks.deallocate(p.buffer);
+        return NULL;
+    }
+
+    return (char *)p.buffer;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
+{
+    printbuffer p = {0, 0, 0, 0, 0, 0, {0, 0, 0}};
+
+    if ((length < 0) || (buffer == NULL))
+    {
+        return false;
+    }
+
+    p.buffer = (unsigned char *)buffer;
+    p.length = (size_t)length;
+    p.offset = 0;
+    p.noalloc = true;
+    p.format = format;
+    p.hooks = global_hooks;
+
+    return print_value(item, &p);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer)
+{
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
+    {
+        return false; /* no input */
+    }
+
+    /* parse the different types of values */
+    /* null */
+    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0))
+    {
+        item->type = cJSON_NULL;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* false */
+    if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0))
+    {
+        item->type = cJSON_False;
+        input_buffer->offset += 5;
+        return true;
+    }
+    /* true */
+    if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0))
+    {
+        item->type = cJSON_True;
+        item->valueint = 1;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* string */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
+    {
+        return parse_string(item, input_buffer);
+    }
+    /* number */
+    if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
+    {
+        return parse_number(item, input_buffer);
+    }
+    /* array */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
+    {
+        return parse_array(item, input_buffer);
+    }
+    /* object */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
+    {
+        return parse_object(item, input_buffer);
+    }
+
+    return false;
+}
+
+/* Render a value to text. */
+static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer)
+{
+    unsigned char *output = NULL;
+
+    if ((item == NULL) || (output_buffer == NULL))
+    {
+        return false;
+    }
+
+    switch ((item->type) & 0xFF)
+    {
+    case cJSON_NULL:
+        output = ensure(output_buffer, 5);
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char *)output, "null");
+        return true;
+
+    case cJSON_False:
+        output = ensure(output_buffer, 6);
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char *)output, "false");
+        return true;
+
+    case cJSON_True:
+        output = ensure(output_buffer, 5);
+        if (output == NULL)
+        {
+            return false;
+        }
+        strcpy((char *)output, "true");
+        return true;
+
+    case cJSON_Number:
+        return print_number(item, output_buffer);
+
+    case cJSON_Raw:
+    {
+        size_t raw_length = 0;
+        if (item->valuestring == NULL)
+        {
+            return false;
+        }
+
+        raw_length = strlen(item->valuestring) + sizeof("");
+        output = ensure(output_buffer, raw_length);
+        if (output == NULL)
+        {
+            return false;
+        }
+        memcpy(output, item->valuestring, raw_length);
+        return true;
+    }
+
+    case cJSON_String:
+        return print_string(item, output_buffer);
+
+    case cJSON_Array:
+        return print_array(item, output_buffer);
+
+    case cJSON_Object:
+        return print_object(item, output_buffer);
+
+    default:
+        return false;
+    }
+}
+
+/* Build an array from input text. */
+static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer)
+{
+    cJSON *head = NULL; /* head of the linked list */
+    cJSON *current_item = NULL;
+
+    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+    {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if (buffer_at_offset(input_buffer)[0] != '[')
+    {
+        /* not an array */
+        goto fail;
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
+    {
+        /* empty array */
+        goto success;
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
+    {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do
+    {
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if (new_item == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if (head == NULL)
+        {
+            /* start the linked list */
+            current_item = head = new_item;
+        }
+        else
+        {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        /* parse next value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
+    {
+        goto fail; /* expected end of array */
+    }
+
+success:
+    input_buffer->depth--;
+
+    if (head != NULL)
+    {
+        head->prev = current_item;
+    }
+
+    item->type = cJSON_Array;
+    item->child = head;
+
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an array to text */
+static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer)
+{
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_element = item->child;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* Compose the output array. */
+    /* opening square bracket */
+    output_pointer = ensure(output_buffer, 1);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    *output_pointer = '[';
+    output_buffer->offset++;
+    output_buffer->depth++;
+
+    while (current_element != NULL)
+    {
+        if (!print_value(current_element, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+        if (current_element->next)
+        {
+            length = (size_t)(output_buffer->format ? 2 : 1);
+            output_pointer = ensure(output_buffer, length + 1);
+            if (output_pointer == NULL)
+            {
+                return false;
+            }
+            *output_pointer++ = ',';
+            if (output_buffer->format)
+            {
+                *output_pointer++ = ' ';
+            }
+            *output_pointer = '\0';
+            output_buffer->offset += length;
+        }
+        current_element = current_element->next;
+    }
+
+    output_pointer = ensure(output_buffer, 2);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    *output_pointer++ = ']';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Build an object from the text. */
+static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer)
+{
+    cJSON *head = NULL; /* linked list head */
+    cJSON *current_item = NULL;
+
+    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+    {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
+    {
+        goto fail; /* not an object */
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
+    {
+        goto success; /* empty object */
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
+    {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do
+    {
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if (new_item == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if (head == NULL)
+        {
+            /* start the linked list */
+            current_item = head = new_item;
+        }
+        else
+        {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        /* parse the name of the child */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_string(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse name */
+        }
+        buffer_skip_whitespace(input_buffer);
+
+        /* swap valuestring and string, because we parsed the name */
+        current_item->string = current_item->valuestring;
+        current_item->valuestring = NULL;
+
+        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
+        {
+            goto fail; /* invalid object */
+        }
+
+        /* parse the value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer))
+        {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
+    {
+        goto fail; /* expected end of object */
+    }
+
+success:
+    input_buffer->depth--;
+
+    if (head != NULL)
+    {
+        head->prev = current_item;
+    }
+
+    item->type = cJSON_Object;
+    item->child = head;
+
+    input_buffer->offset++;
+    return true;
+
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer)
+{
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_item = item->child;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
+
+    /* Compose the output: */
+    length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
+    output_pointer = ensure(output_buffer, length + 1);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+
+    *output_pointer++ = '{';
+    output_buffer->depth++;
+    if (output_buffer->format)
+    {
+        *output_pointer++ = '\n';
+    }
+    output_buffer->offset += length;
+
+    while (current_item)
+    {
+        if (output_buffer->format)
+        {
+            size_t i;
+            output_pointer = ensure(output_buffer, output_buffer->depth);
+            if (output_pointer == NULL)
+            {
+                return false;
+            }
+            for (i = 0; i < output_buffer->depth; i++)
+            {
+                *output_pointer++ = '\t';
+            }
+            output_buffer->offset += output_buffer->depth;
+        }
+
+        /* print key */
+        if (!print_string_ptr((unsigned char *)current_item->string, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        length = (size_t)(output_buffer->format ? 2 : 1);
+        output_pointer = ensure(output_buffer, length);
+        if (output_pointer == NULL)
+        {
+            return false;
+        }
+        *output_pointer++ = ':';
+        if (output_buffer->format)
+        {
+            *output_pointer++ = '\t';
+        }
+        output_buffer->offset += length;
+
+        /* print value */
+        if (!print_value(current_item, output_buffer))
+        {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        /* print comma if not last */
+        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
+        output_pointer = ensure(output_buffer, length + 1);
+        if (output_pointer == NULL)
+        {
+            return false;
+        }
+        if (current_item->next)
+        {
+            *output_pointer++ = ',';
+        }
+
+        if (output_buffer->format)
+        {
+            *output_pointer++ = '\n';
+        }
+        *output_pointer = '\0';
+        output_buffer->offset += length;
+
+        current_item = current_item->next;
+    }
+
+    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    if (output_buffer->format)
+    {
+        size_t i;
+        for (i = 0; i < (output_buffer->depth - 1); i++)
+        {
+            *output_pointer++ = '\t';
+        }
+    }
+    *output_pointer++ = '}';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Get Array size/item / object item. */
+CJSON_PUBLIC(int)
+cJSON_GetArraySize(const cJSON *array)
+{
+    cJSON *child = NULL;
+    size_t size = 0;
+
+    if (array == NULL)
+    {
+        return 0;
+    }
+
+    child = array->child;
+
+    while (child != NULL)
+    {
+        size++;
+        child = child->next;
+    }
+
+    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+    return (int)size;
+}
+
+static cJSON *get_array_item(const cJSON *array, size_t index)
+{
+    cJSON *current_child = NULL;
+
+    if (array == NULL)
+    {
+        return NULL;
+    }
+
+    current_child = array->child;
+    while ((current_child != NULL) && (index > 0))
+    {
+        index--;
+        current_child = current_child->next;
+    }
+
+    return current_child;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_GetArrayItem(const cJSON *array, int index)
+{
+    if (index < 0)
+    {
+        return NULL;
+    }
+
+    return get_array_item(array, (size_t)index);
+}
+
+static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive)
+{
+    cJSON *current_element = NULL;
+
+    if ((object == NULL) || (name == NULL))
+    {
+        return NULL;
+    }
+
+    current_element = object->child;
+    if (case_sensitive)
+    {
+        while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
+        {
+            current_element = current_element->next;
+        }
+    }
+    else
+    {
+        while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) != 0))
+        {
+            current_element = current_element->next;
+        }
+    }
+
+    if ((current_element == NULL) || (current_element->string == NULL))
+    {
+        return NULL;
+    }
+
+    return current_element;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_GetObjectItem(const cJSON *const object, const char *const string)
+{
+    return get_object_item(object, string, false);
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string)
+{
+    return get_object_item(object, string, true);
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_HasObjectItem(const cJSON *object, const char *string)
+{
+    return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item)
+{
+    prev->next = item;
+    item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *create_reference(const cJSON *item, const internal_hooks *const hooks)
+{
+    cJSON *reference = NULL;
+    if (item == NULL)
+    {
+        return NULL;
+    }
+
+    reference = cJSON_New_Item(hooks);
+    if (reference == NULL)
+    {
+        return NULL;
+    }
+
+    memcpy(reference, item, sizeof(cJSON));
+    reference->string = NULL;
+    reference->type |= cJSON_IsReference;
+    reference->next = reference->prev = NULL;
+    return reference;
+}
+
+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
+{
+    cJSON *child = NULL;
+
+    if ((item == NULL) || (array == NULL) || (array == item))
+    {
+        return false;
+    }
+
+    child = array->child;
+    /*
+     * To find the last item in array quickly, we use prev in array
+     */
+    if (child == NULL)
+    {
+        /* list is empty, start new one */
+        array->child = item;
+        item->prev = item;
+        item->next = NULL;
+    }
+    else
+    {
+        /* append to the end */
+        if (child->prev)
+        {
+            suffix_object(child->prev, item);
+            array->child->prev = item;
+        }
+    }
+
+    return true;
+}
+
+/* Add item to array/object. */
+CJSON_PUBLIC(cJSON_bool)
+cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+    return add_item_to_array(array, item);
+}
+
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+/* helper function to cast away const */
+static void *cast_away_const(const void *string)
+{
+    return (void *)string;
+}
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic pop
+#endif
+
+static cJSON_bool add_item_to_object(cJSON *const object, const char *const string, cJSON *const item, const internal_hooks *const hooks, const cJSON_bool constant_key)
+{
+    char *new_key = NULL;
+    int new_type = cJSON_Invalid;
+
+    if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
+    {
+        return false;
+    }
+
+    if (constant_key)
+    {
+        new_key = (char *)cast_away_const(string);
+        new_type = item->type | cJSON_StringIsConst;
+    }
+    else
+    {
+        new_key = (char *)cJSON_strdup((const unsigned char *)string, hooks);
+        if (new_key == NULL)
+        {
+            return false;
+        }
+
+        new_type = item->type & ~cJSON_StringIsConst;
+    }
+
+    if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+    {
+        hooks->deallocate(item->string);
+    }
+
+    item->string = new_key;
+    item->type = new_type;
+
+    return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+    return add_item_to_object(object, string, item, &global_hooks, false);
+}
+
+/* Add an item to an object with constant string as key */
+CJSON_PUBLIC(cJSON_bool)
+cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+{
+    return add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+    if (array == NULL)
+    {
+        return false;
+    }
+
+    return add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+    if ((object == NULL) || (string == NULL))
+    {
+        return false;
+    }
+
+    return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddNullToObject(cJSON *const object, const char *const name)
+{
+    cJSON *null = cJSON_CreateNull();
+    if (add_item_to_object(object, name, null, &global_hooks, false))
+    {
+        return null;
+    }
+
+    cJSON_Delete(null);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddTrueToObject(cJSON *const object, const char *const name)
+{
+    cJSON *true_item = cJSON_CreateTrue();
+    if (add_item_to_object(object, name, true_item, &global_hooks, false))
+    {
+        return true_item;
+    }
+
+    cJSON_Delete(true_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddFalseToObject(cJSON *const object, const char *const name)
+{
+    cJSON *false_item = cJSON_CreateFalse();
+    if (add_item_to_object(object, name, false_item, &global_hooks, false))
+    {
+        return false_item;
+    }
+
+    cJSON_Delete(false_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddBoolToObject(cJSON *const object, const char *const name, const cJSON_bool boolean)
+{
+    cJSON *bool_item = cJSON_CreateBool(boolean);
+    if (add_item_to_object(object, name, bool_item, &global_hooks, false))
+    {
+        return bool_item;
+    }
+
+    cJSON_Delete(bool_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddNumberToObject(cJSON *const object, const char *const name, const double number)
+{
+    cJSON *number_item = cJSON_CreateNumber(number);
+    if (add_item_to_object(object, name, number_item, &global_hooks, false))
+    {
+        return number_item;
+    }
+
+    cJSON_Delete(number_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddStringToObject(cJSON *const object, const char *const name, const char *const string)
+{
+    cJSON *string_item = cJSON_CreateString(string);
+    if (add_item_to_object(object, name, string_item, &global_hooks, false))
+    {
+        return string_item;
+    }
+
+    cJSON_Delete(string_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddRawToObject(cJSON *const object, const char *const name, const char *const raw)
+{
+    cJSON *raw_item = cJSON_CreateRaw(raw);
+    if (add_item_to_object(object, name, raw_item, &global_hooks, false))
+    {
+        return raw_item;
+    }
+
+    cJSON_Delete(raw_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddObjectToObject(cJSON *const object, const char *const name)
+{
+    cJSON *object_item = cJSON_CreateObject();
+    if (add_item_to_object(object, name, object_item, &global_hooks, false))
+    {
+        return object_item;
+    }
+
+    cJSON_Delete(object_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_AddArrayToObject(cJSON *const object, const char *const name)
+{
+    cJSON *array = cJSON_CreateArray();
+    if (add_item_to_object(object, name, array, &global_hooks, false))
+    {
+        return array;
+    }
+
+    cJSON_Delete(array);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item)
+{
+    if ((parent == NULL) || (item == NULL))
+    {
+        return NULL;
+    }
+
+    if (item != parent->child)
+    {
+        /* not the first element */
+        item->prev->next = item->next;
+    }
+    if (item->next != NULL)
+    {
+        /* not the last element */
+        item->next->prev = item->prev;
+    }
+
+    if (item == parent->child)
+    {
+        /* first element */
+        parent->child = item->next;
+    }
+    else if (item->next == NULL)
+    {
+        /* last element */
+        parent->child->prev = item->prev;
+    }
+
+    /* make sure the detached item doesn't point anywhere anymore */
+    item->prev = NULL;
+    item->next = NULL;
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+    if (which < 0)
+    {
+        return NULL;
+    }
+
+    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
+}
+
+CJSON_PUBLIC(void)
+cJSON_DeleteItemFromArray(cJSON *array, int which)
+{
+    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_DetachItemFromObject(cJSON *object, const char *string)
+{
+    cJSON *to_detach = cJSON_GetObjectItem(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(void)
+cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+CJSON_PUBLIC(void)
+cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
+/* Replace array/object items with new ones. */
+CJSON_PUBLIC(cJSON_bool)
+cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+    cJSON *after_inserted = NULL;
+
+    if (which < 0)
+    {
+        return false;
+    }
+
+    after_inserted = get_array_item(array, (size_t)which);
+    if (after_inserted == NULL)
+    {
+        return add_item_to_array(array, newitem);
+    }
+
+    newitem->next = after_inserted;
+    newitem->prev = after_inserted->prev;
+    after_inserted->prev = newitem;
+    if (after_inserted == array->child)
+    {
+        array->child = newitem;
+    }
+    else
+    {
+        newitem->prev->next = newitem;
+    }
+    return true;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, cJSON *replacement)
+{
+    if ((parent == NULL) || (replacement == NULL) || (item == NULL))
+    {
+        return false;
+    }
+
+    if (replacement == item)
+    {
+        return true;
+    }
+
+    replacement->next = item->next;
+    replacement->prev = item->prev;
+
+    if (replacement->next != NULL)
+    {
+        replacement->next->prev = replacement;
+    }
+    if (parent->child == item)
+    {
+        if (parent->child->prev == parent->child)
+        {
+            replacement->prev = replacement;
+        }
+        parent->child = replacement;
+    }
+    else
+    { /*
+       * To find the last item in array quickly, we use prev in array.
+       * We can't modify the last item's next pointer where this item was the parent's child
+       */
+        if (replacement->prev != NULL)
+        {
+            replacement->prev->next = replacement;
+        }
+        if (replacement->next == NULL)
+        {
+            parent->child->prev = replacement;
+        }
+    }
+
+    item->next = NULL;
+    item->prev = NULL;
+    cJSON_Delete(item);
+
+    return true;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+    if (which < 0)
+    {
+        return false;
+    }
+
+    return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
+{
+    if ((replacement == NULL) || (string == NULL))
+    {
+        return false;
+    }
+
+    /* replace the name in the replacement */
+    if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
+    {
+        cJSON_free(replacement->string);
+    }
+    replacement->string = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
+    replacement->type &= ~cJSON_StringIsConst;
+
+    return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+{
+    return replace_item_in_object(object, string, newitem, false);
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
+{
+    return replace_item_in_object(object, string, newitem, true);
+}
+
+/* Create basic types: */
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateNull(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_NULL;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateTrue(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_True;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateFalse(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateBool(cJSON_bool boolean)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = boolean ? cJSON_True : cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateNumber(double num)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Number;
+        item->valuedouble = num;
+
+        /* use saturation in case of overflow */
+        if (num >= INT_MAX)
+        {
+            item->valueint = INT_MAX;
+        }
+        else if (num <= (double)INT_MIN)
+        {
+            item->valueint = INT_MIN;
+        }
+        else
+        {
+            item->valueint = (int)num;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateString(const char *string)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_String;
+        item->valuestring = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
+        if (!item->valuestring)
+        {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateStringReference(const char *string)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item != NULL)
+    {
+        item->type = cJSON_String | cJSON_IsReference;
+        item->valuestring = (char *)cast_away_const(string);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateObjectReference(const cJSON *child)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item != NULL)
+    {
+        item->type = cJSON_Object | cJSON_IsReference;
+        item->child = (cJSON *)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateArrayReference(const cJSON *child)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item != NULL)
+    {
+        item->type = cJSON_Array | cJSON_IsReference;
+        item->child = (cJSON *)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateRaw(const char *raw)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Raw;
+        item->valuestring = (char *)cJSON_strdup((const unsigned char *)raw, &global_hooks);
+        if (!item->valuestring)
+        {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateArray(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Array;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateObject(void)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if (item)
+    {
+        item->type = cJSON_Object;
+    }
+
+    return item;
+}
+
+/* Create Arrays: */
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateIntArray(const int *numbers, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber(numbers[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child)
+    {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateFloatArray(const float *numbers, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber((double)numbers[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child)
+    {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateDoubleArray(const double *numbers, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (numbers == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber(numbers[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child)
+    {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateStringArray(const char *const *strings, int count)
+{
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if ((count < 0) || (strings == NULL))
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateString(strings[i]);
+        if (!n)
+        {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if (!i)
+        {
+            a->child = n;
+        }
+        else
+        {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if (a && a->child)
+    {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+/* Duplication */
+CJSON_PUBLIC(cJSON *)
+cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
+{
+    cJSON *newitem = NULL;
+    cJSON *child = NULL;
+    cJSON *next = NULL;
+    cJSON *newchild = NULL;
+
+    /* Bail on bad ptr */
+    if (!item)
+    {
+        goto fail;
+    }
+    /* Create new item */
+    newitem = cJSON_New_Item(&global_hooks);
+    if (!newitem)
+    {
+        goto fail;
+    }
+    /* Copy over all vars */
+    newitem->type = item->type & (~cJSON_IsReference);
+    newitem->valueint = item->valueint;
+    newitem->valuedouble = item->valuedouble;
+    if (item->valuestring)
+    {
+        newitem->valuestring = (char *)cJSON_strdup((unsigned char *)item->valuestring, &global_hooks);
+        if (!newitem->valuestring)
+        {
+            goto fail;
+        }
+    }
+    if (item->string)
+    {
+        newitem->string = (item->type & cJSON_StringIsConst) ? item->string : (char *)cJSON_strdup((unsigned char *)item->string, &global_hooks);
+        if (!newitem->string)
+        {
+            goto fail;
+        }
+    }
+    /* If non-recursive, then we're done! */
+    if (!recurse)
+    {
+        return newitem;
+    }
+    /* Walk the ->next chain for the child. */
+    child = item->child;
+    while (child != NULL)
+    {
+        newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
+        if (!newchild)
+        {
+            goto fail;
+        }
+        if (next != NULL)
+        {
+            /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+            next->next = newchild;
+            newchild->prev = next;
+            next = newchild;
+        }
+        else
+        {
+            /* Set newitem->child and move to it */
+            newitem->child = newchild;
+            next = newchild;
+        }
+        child = child->next;
+    }
+    if (newitem && newitem->child)
+    {
+        newitem->child->prev = newchild;
+    }
+
+    return newitem;
+
+fail:
+    if (newitem != NULL)
+    {
+        cJSON_Delete(newitem);
+    }
+
+    return NULL;
+}
+
+static void skip_oneline_comment(char **input)
+{
+    *input += static_strlen("//");
+
+    for (; (*input)[0] != '\0'; ++(*input))
+    {
+        if ((*input)[0] == '\n')
+        {
+            *input += static_strlen("\n");
+            return;
+        }
+    }
+}
+
+static void skip_multiline_comment(char **input)
+{
+    *input += static_strlen("/*");
+
+    for (; (*input)[0] != '\0'; ++(*input))
+    {
+        if (((*input)[0] == '*') && ((*input)[1] == '/'))
+        {
+            *input += static_strlen("*/");
+            return;
+        }
+    }
+}
+
+static void minify_string(char **input, char **output)
+{
+    (*output)[0] = (*input)[0];
+    *input += static_strlen("\"");
+    *output += static_strlen("\"");
+
+    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output))
+    {
+        (*output)[0] = (*input)[0];
+
+        if ((*input)[0] == '\"')
+        {
+            (*output)[0] = '\"';
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+            return;
+        }
+        else if (((*input)[0] == '\\') && ((*input)[1] == '\"'))
+        {
+            (*output)[1] = (*input)[1];
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+        }
+    }
+}
+
+CJSON_PUBLIC(void)
+cJSON_Minify(char *json)
+{
+    char *into = json;
+
+    if (json == NULL)
+    {
+        return;
+    }
+
+    while (json[0] != '\0')
+    {
+        switch (json[0])
+        {
+        case ' ':
+        case '\t':
+        case '\r':
+        case '\n':
+            json++;
+            break;
+
+        case '/':
+            if (json[1] == '/')
+            {
+                skip_oneline_comment(&json);
+            }
+            else if (json[1] == '*')
+            {
+                skip_multiline_comment(&json);
+            }
+            else
+            {
+                json++;
+            }
+            break;
+
+        case '\"':
+            minify_string(&json, (char **)&into);
+            break;
+
+        default:
+            into[0] = json[0];
+            json++;
+            into++;
+        }
+    }
+
+    /* and null-terminate. */
+    *into = '\0';
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsInvalid(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsFalse(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsTrue(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xff) == cJSON_True;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsBool(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsNull(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsNumber(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsString(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsArray(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsObject(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_IsRaw(const cJSON *const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Raw;
+}
+
+CJSON_PUBLIC(cJSON_bool)
+cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive)
+{
+    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
+    {
+        return false;
+    }
+
+    /* check if type is valid */
+    switch (a->type & 0xFF)
+    {
+    case cJSON_False:
+    case cJSON_True:
+    case cJSON_NULL:
+    case cJSON_Number:
+    case cJSON_String:
+    case cJSON_Raw:
+    case cJSON_Array:
+    case cJSON_Object:
+        break;
+
+    default:
+        return false;
+    }
+
+    /* identical objects are equal */
+    if (a == b)
+    {
+        return true;
+    }
+
+    switch (a->type & 0xFF)
+    {
+    /* in these cases and equal type is enough */
+    case cJSON_False:
+    case cJSON_True:
+    case cJSON_NULL:
+        return true;
+
+    case cJSON_Number:
+        if (compare_double(a->valuedouble, b->valuedouble))
+        {
+            return true;
+        }
+        return false;
+
+    case cJSON_String:
+    case cJSON_Raw:
+        if ((a->valuestring == NULL) || (b->valuestring == NULL))
+        {
+            return false;
+        }
+        if (strcmp(a->valuestring, b->valuestring) == 0)
+        {
+            return true;
+        }
+
+        return false;
+
+    case cJSON_Array:
+    {
+        cJSON *a_element = a->child;
+        cJSON *b_element = b->child;
+
+        for (; (a_element != NULL) && (b_element != NULL);)
+        {
+            if (!cJSON_Compare(a_element, b_element, case_sensitive))
+            {
+                return false;
+            }
+
+            a_element = a_element->next;
+            b_element = b_element->next;
+        }
+
+        /* one of the arrays is longer than the other */
+        if (a_element != b_element)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    case cJSON_Object:
+    {
+        cJSON *a_element = NULL;
+        cJSON *b_element = NULL;
+        cJSON_ArrayForEach(a_element, a)
+        {
+            /* TODO This has O(n^2) runtime, which is horrible! */
+            b_element = get_object_item(b, a_element->string, case_sensitive);
+            if (b_element == NULL)
+            {
+                return false;
+            }
+
+            if (!cJSON_Compare(a_element, b_element, case_sensitive))
+            {
+                return false;
+            }
+        }
+
+        /* doing this twice, once on a and b to prevent true comparison if a subset of b
+         * TODO: Do this the proper way, this is just a fix for now */
+        cJSON_ArrayForEach(b_element, b)
+        {
+            a_element = get_object_item(a, b_element->string, case_sensitive);
+            if (a_element == NULL)
+            {
+                return false;
+            }
+
+            if (!cJSON_Compare(b_element, a_element, case_sensitive))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    default:
+        return false;
+    }
+}
+
+CJSON_PUBLIC(void *)
+cJSON_malloc(size_t size)
+{
+    return global_hooks.allocate(size);
+}
+
+CJSON_PUBLIC(void)
+cJSON_free(void *object)
+{
+    global_hooks.deallocate(object);
+}
diff --git a/examples/thing_shadow/main/core/libraries/nvs_platform.c b/examples/thing_shadow/main/core/libraries/nvs_platform.c
new file mode 100644
index 000000000..19fea2659
--- /dev/null
+++ b/examples/thing_shadow/main/core/libraries/nvs_platform.c
@@ -0,0 +1,169 @@
+/**
+ * @file nvs_platform.c
+ * @author Hamxa Islam {hamzaislam170@gamil.com}
+ * @brief Remotewell_PRO
+ * @version 0.1
+ * @date 2022-11-04
+ *
+ * EPTeck Technologies Gmbh    2022
+ *
+ */
+
+//#ifdef CONFIG_HTTP_ENABLE &&CONFIG_WIFI_ENABLE
+
+#include "nvs_platform.h"
+
+#include <string.h>
+#include "nvs_flash.h"
+#include "nvs.h"
+#include "sdkconfig.h"
+#include "esp_log.h"
+
+static char *TAG="NVS []";
+/**
+ * @brief
+ *
+ * @param param
+ */
+bool nvs_slot_exit(esp_err_t err)
+{
+    switch (err)
+    {
+    case ESP_OK:
+        return true;
+    case ESP_ERR_NVS_NOT_FOUND:
+        return false;
+    default:
+        // ESP_LOGI("NVS ERROR :","***** SEGMENTATION FAULT *****");
+        break;
+    }
+    return false;
+}
+/**
+ * @brief
+ *
+ * @param param
+ */
+
+void nvs_init(void *param)
+{
+    esp_err_t err = nvs_flash_init();
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
+    {
+        // NVS partition was truncated and needs to be erased
+        // Retry nvs_flash_init
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        err = nvs_flash_init();
+    }
+}
+
+/**
+ * @brief
+ *
+ * @param param
+ */
+
+void nvs_perform_number(char *key, uint32_t *value, e_nvs_param_t type, bool read_write)
+{
+    esp_err_t err;
+    nvs_handle_t my_handle;
+
+    err = nvs_open("storage", NVS_READWRITE, &my_handle);
+
+    if (err != ESP_OK)
+    {
+        //  ESP_LOGE(TAG,"NVS ERROR:", "NOT ABLE TO OPEN NVS");
+       
+    }
+    else
+    {
+        /*< CXX COMPILER >*/
+    }
+    if (read_write)
+    {
+       uint32_t valwr=*(value);
+        switch (type)
+        {
+        case U8:
+            err = nvs_set_u8(my_handle, (const char *)key, (uint8_t)valwr);
+            break;
+        case U16:
+            err = nvs_set_u16(my_handle, (const char *)key, (uint16_t)valwr);
+            break;
+        case U32:
+            err = nvs_set_u32(my_handle, (const char *)key, (uint32_t)valwr);
+            break;
+        case STR:
+            err = nvs_set_str(my_handle, (const char *)key, (const char *)value);
+            break;
+
+        default:
+            break;
+        }
+    }
+    /*< Read from NVS >*/
+    else
+    {
+        size_t required_size;
+       uint32_t valwr=*(value);
+        switch (type)
+        {
+        case U8:
+            err = nvs_get_u8(my_handle, (const char *)key, (uint8_t *)value);
+            nvs_slot_exit(err) ? true : nvs_set_u8(my_handle, (const char *)key, (uint8_t)valwr);
+            break;
+        case U16:
+            err = nvs_get_u16(my_handle, (const char *)key, (uint16_t *)value);
+            nvs_slot_exit(err) ? true : nvs_set_u16(my_handle, (const char *)key, (uint16_t)valwr);
+            break;
+        case U32:
+            err = nvs_get_u32(my_handle, (const char *)key, (uint32_t *)value);
+            nvs_slot_exit(err) ? true : nvs_set_u32(my_handle, (const char *)key, (uint32_t)valwr);
+            break;
+        case STR:
+            err = nvs_get_str(my_handle, (const char *)key, NULL, &required_size);
+            nvs_slot_exit(err) ? nvs_get_str(my_handle, (const char *)key, (const char *)value, &required_size)
+                               : nvs_set_str(my_handle, (const char *)key, (const char *)value);
+            break;
+
+        default:
+            break;
+        }
+    }
+    nvs_commit(my_handle);
+    nvs_close(my_handle);
+}
+void nvs_perform_str(char *key, char *value, e_nvs_param_t type, bool read_write)
+{
+    esp_err_t err;
+    nvs_handle_t my_handle;
+
+    err = nvs_open("storage", NVS_READWRITE, &my_handle);
+
+    // if (err != ESP_OK)
+    // {
+    //     // ESP_LOGI("NVS ERROR:", "NOT ABLE TO OPEN NVS");
+    // }
+    // else
+    // {
+    //     /*< CXX COMPILER >*/
+    // }
+
+    if (read_write)
+    {
+
+        err = nvs_set_str(my_handle, (const char *)key, (const char *)value);
+    }
+
+    /*< Read from NVS >*/
+    else
+    {
+        size_t required_size;
+
+        err = nvs_get_str(my_handle, (const char *)key, NULL, &required_size);
+        nvs_slot_exit(err) ? nvs_get_str(my_handle, (const char *)key, (const char *)value, &required_size)
+                           : nvs_set_str(my_handle, (const char *)key, (const char *)value);
+    }
+    nvs_commit(my_handle);
+    nvs_close(my_handle);
+}
diff --git a/examples/thing_shadow/main/core/wifi_driver/data_store_nvs.c b/examples/thing_shadow/main/core/wifi_driver/data_store_nvs.c
new file mode 100644
index 000000000..a1e7aed85
--- /dev/null
+++ b/examples/thing_shadow/main/core/wifi_driver/data_store_nvs.c
@@ -0,0 +1,136 @@
+#include <string.h>
+#include <stdio.h>
+#include "esp_system.h"
+#include "nvs_flash.h"
+#include "nvs.h"
+#include <esp_log.h>
+#include "wifi_driver/data_store_nvs.h"
+
+static const char *TAG = "Data Store NVS";
+
+char ssid[30] = "", pswd[30] = "", tank[30] = "";
+char user_name[30] = {0}, user_pswd[30] = {0}, user_device_num[5] = {0};
+
+/**
+ * @brief ReadStringNVS() is local function that reads the specified string key and returns the string value of the key.
+ *
+ * @param char key
+ * @return char*
+ */
+int ReadStringNVS(char *key, char *value)
+{
+
+    esp_err_t err = nvs_flash_init();
+    nvs_handle_t my_handle;
+
+    err = nvs_open("storage", NVS_READWRITE, &my_handle);
+
+    if (err != ESP_OK)
+    {
+        ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
+    }
+    else
+    {
+        ESP_LOGD(TAG, "Done\n");
+        ESP_LOGD(TAG, "Reading SSID from NVS ... ");
+
+        size_t len;
+
+        nvs_get_str(my_handle, key, NULL, &len);
+        if (len == 0)
+        {
+            return 0;
+        }
+
+        err = nvs_get_str(my_handle, key, value, &len);
+
+        switch (err)
+        {
+        case ESP_OK:
+            ESP_LOGD(TAG, "Done\n");
+            return 1;
+            break;
+        case ESP_ERR_NVS_NOT_FOUND:
+            ESP_LOGD(TAG, "The value is not initialized yet!\n");
+            break;
+        default:
+            ESP_LOGD(TAG, "Error (%s) reading!\n", esp_err_to_name(err));
+        }
+        nvs_close(my_handle);
+    }
+    return 2;
+}
+
+void WriteStrNVS(char *key, char *value)
+{
+    esp_err_t err = nvs_flash_init();
+
+    ESP_LOGD(TAG, "\n");
+    ESP_LOGD(TAG, "Opening Non-Volatile Storage (NVS) handle... ");
+
+    nvs_handle_t my_handle;
+
+    err = nvs_open("storage", NVS_READWRITE, &my_handle);
+
+    if (err != ESP_OK)
+    {
+        ESP_LOGD(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
+    }
+    else
+    {
+        ESP_LOGD(TAG, "Done\n");
+        ESP_LOGD(TAG, "Storing key (%s) and value (%s) in NVS ... ", key, value);
+        // Write
+        err = nvs_set_str(my_handle, key, value);
+        // Commit written value.
+        nvs_close(my_handle);
+    }
+    ESP_LOGD(TAG, "\n");
+}
+void GetWifiCred()
+{
+    int err;
+
+    char ssid_buff[30];
+    char pswd_buff[30];
+    char tank_buff[30];
+
+    err = ReadStringNVS("ssid", ssid_buff);
+    if (!err)
+    {
+        WriteStrNVS("ssid", "dummy");
+    }
+    err = ReadStringNVS("pswd", pswd_buff);
+    if (!err)
+    {
+        WriteStrNVS("pswd", "dummy");
+    }
+
+
+    if (ssid_buff != NULL && pswd_buff != NULL)
+    {
+        sprintf(ssid, "%s", ssid_buff);
+        sprintf(pswd, "%s", pswd_buff);
+        sprintf(tank, "%s", tank_buff);
+
+        ESP_LOGI("data_nvs", "ssid %s", ssid);
+        ESP_LOGI("data_nvs", "pswd %s", pswd);
+    }
+    else
+    {
+        sprintf(ssid,"%s","");
+        sprintf(pswd,"%s","");
+
+    }
+}
+
+void NVSInit()
+{
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
+    {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(ret);
+}
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/wifi_driver/http_server.c b/examples/thing_shadow/main/core/wifi_driver/http_server.c
new file mode 100644
index 000000000..4d4e76407
--- /dev/null
+++ b/examples/thing_shadow/main/core/wifi_driver/http_server.c
@@ -0,0 +1,173 @@
+#include <esp_wifi.h>
+#include <esp_event.h>
+#include <esp_log.h>
+#include <esp_system.h>
+#include <sys/param.h>
+#include <esp_http_server.h>
+
+#include "esp_netif.h"
+
+#include "wifi_driver/data_store_nvs.h"
+#include "wifi_driver/http_server.h"
+#include "wifi_driver/wifi_manager.h"
+#include "cJSON.h"
+#include "wifi_driver/scan.h"
+
+static const char *TAG = "HTTP server";
+char scan_list[500] = {0};
+
+/* An HTTP GET handler */
+static esp_err_t wifi_scan_get_handler(httpd_req_t *req)
+{
+    WiFiScan(scan_list);
+
+    const char *resp_str = (const char *)scan_list;
+
+    httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
+
+    return ESP_OK;
+}
+
+static const httpd_uri_t wifiscan = {
+    .uri = "/api/wifiscan",
+    .method = HTTP_GET,
+    .handler = wifi_scan_get_handler,
+    .user_ctx = NULL};
+
+/* An HTTP POST handler */
+static esp_err_t wifi_cred_post_handler(httpd_req_t *req)
+{
+    char buf[100];
+    int ret, remaining = req->content_len;
+
+    while (remaining > 0)
+    {
+        /* Read the data for the request */
+        if ((ret = httpd_req_recv(req, buf,
+            MIN(remaining, sizeof(buf)))) <= 0)
+        {
+            if (ret == HTTPD_SOCK_ERR_TIMEOUT)
+            {
+                /* Retry receiving if timeout occurred */
+                continue;
+            }
+            return ESP_FAIL;
+        }
+
+        remaining -= ret;
+
+        /* Log data received */
+        ESP_LOGD(TAG, "=========== RECEIVED DATA ==========");
+        ESP_LOGD(TAG, "%.*s", ret, buf);
+        ESP_LOGD(TAG, "====================================");
+
+        cJSON *recv_json = cJSON_Parse(buf);
+        cJSON *ssid_buff = cJSON_GetObjectItemCaseSensitive(recv_json, "ssid");
+        cJSON *pswd_buff = cJSON_GetObjectItemCaseSensitive(recv_json, "pswd");
+        // cJSON *tank_buff = cJSON_GetObjectItemCaseSensitive(recv_json, "tank");
+
+        if (cJSON_IsString(ssid_buff) && (ssid_buff->valuestring != NULL) && (cJSON_IsString(pswd_buff) && (pswd_buff->valuestring != NULL)))
+        {
+            ESP_LOGD(TAG, "Checking ssid \"%s\"\n", ssid_buff->valuestring);
+            ESP_LOGD(TAG, "Checking password \"%s\"\n", pswd_buff->valuestring);
+            // ESP_LOGD(TAG, "Checking tank name \"%s\"\n", tank_buff->valuestring);
+
+            WriteStrNVS("ssid", ssid_buff->valuestring);
+            WriteStrNVS("pswd", pswd_buff->valuestring);
+            // WriteStrNVS("tank", tank_buff->valuestring);
+
+            GetWifiCred(); // load new credentials
+            Wifi_STA();
+        }
+        else
+        {
+            /* Send back the same data */
+            httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Wrong key value pairs");
+        }
+        cJSON_Delete(recv_json);
+        esp_restart();
+    }
+
+    // End response
+    httpd_resp_send_chunk(req, NULL, 0);
+
+    return ESP_OK;
+}
+
+static const httpd_uri_t wificredential = {
+    .uri = "/api/wificredential",
+    .method = HTTP_POST,
+    .handler = wifi_cred_post_handler,
+    .user_ctx = NULL};
+
+esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
+{
+    /* For any other URI send 404 and close socket */
+    httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "404 Error Not Found");
+    return ESP_FAIL;
+}
+
+httpd_handle_t start_webserver(void)
+{
+    httpd_handle_t server = NULL;
+    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
+    config.lru_purge_enable = true;
+
+    // Start the httpd server
+    ESP_LOGD(TAG, "Starting server on port: '%d'", config.server_port);
+
+    if (httpd_start(&server, &config) == ESP_OK)
+    {
+        // Set URI handlers
+        ESP_LOGI(TAG, "Registering URI handlers");
+
+        httpd_register_uri_handler(server, &wifiscan);
+        httpd_register_uri_handler(server, &wificredential);
+        //httpd_register_uri_handler(server, &parsecredential);
+        return server;
+    }
+
+    ESP_LOGD(TAG, "Error starting server!");
+    return NULL;
+}
+
+static void stop_webserver(httpd_handle_t server)
+{
+    // Stop the httpd server
+    httpd_stop(server);
+}
+
+void disconnect_handler(void *arg, esp_event_base_t event_base,
+                        int32_t event_id, void *event_data)
+{
+    httpd_handle_t *server = (httpd_handle_t *)arg;
+
+    if (*server)
+    {
+        ESP_LOGD(TAG, "Stopping webserver");
+
+        stop_webserver(*server);
+
+        *server = NULL;
+    }
+}
+
+void connect_handler(void *arg, esp_event_base_t event_base,
+                     int32_t event_id, void *event_data)
+{
+    httpd_handle_t *server = (httpd_handle_t *)arg;
+
+    if (*server == NULL)
+    {
+        ESP_LOGD(TAG, "Starting webserver");
+
+        *server = start_webserver();
+    }
+}
+void WebServerEventRegister()
+{
+    static httpd_handle_t server = NULL;
+
+    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_AP_STAIPASSIGNED, &connect_handler, &server));
+    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &disconnect_handler, &server));
+}
diff --git a/examples/thing_shadow/main/core/wifi_driver/scan.c b/examples/thing_shadow/main/core/wifi_driver/scan.c
new file mode 100644
index 000000000..7da4f88a9
--- /dev/null
+++ b/examples/thing_shadow/main/core/wifi_driver/scan.c
@@ -0,0 +1,65 @@
+#include <string.h>
+
+#include "esp_wifi.h"
+#include "esp_log.h"
+
+#include "cJSON.h"
+#include "wifi_driver/scan.h"
+
+#define DEFAULT_SCAN_LIST_SIZE 10
+
+static const char *TAG = "scan";
+
+wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
+
+uint16_t ap_count = 0;
+cJSON *scan_info; // create empty JSON packet
+
+static void CreateScanJsonPacket(char *pscan_list)
+{
+    scan_info = cJSON_CreateObject(); // create empty JSON packet
+
+    cJSON *ssid = NULL;
+    cJSON *rssi = NULL;
+    cJSON *json_array = cJSON_CreateArray();
+
+    cJSON_AddItemToObject(scan_info, "scan", json_array); // link empty array with json packet
+
+    for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++)
+    {
+        cJSON *json_array_object = cJSON_CreateObject();
+        cJSON_AddItemToArray(json_array, json_array_object); // put above two objects in an array
+
+        ssid = cJSON_CreateString((char *)ap_info[i].ssid);
+        rssi = cJSON_CreateNumber(ap_info[i].rssi);
+
+        cJSON_AddItemToObject(json_array_object, "ssid", ssid); // link empty array with json packet
+        cJSON_AddItemToObject(json_array_object, "rssi", rssi); // link empty array with json packet
+    }
+
+    sprintf(pscan_list, "%s", cJSON_Print(scan_info));
+
+    cJSON_Delete(scan_info);
+
+    ESP_LOGD("str", " %s", pscan_list);
+}
+
+void WiFiScan(char *pscan_list)
+{
+    ESP_ERROR_CHECK(esp_wifi_disconnect()); // call it otherwise scan does not work
+
+    uint16_t number = DEFAULT_SCAN_LIST_SIZE;
+
+    memset(ap_info, 0, sizeof(ap_info));
+
+    ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, true)); // scan for all APs, NULL means defualt configurations, true means code will block here until completion of scan
+
+    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
+    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
+
+    ESP_LOGD(TAG, "Total APs scanned = %u", ap_count);
+
+    CreateScanJsonPacket(pscan_list);
+
+    ESP_ERROR_CHECK(esp_wifi_connect()); // call it to enable reconnect otherwise device will not connect again
+}
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core/wifi_driver/wifi_manager.c b/examples/thing_shadow/main/core/wifi_driver/wifi_manager.c
new file mode 100644
index 000000000..b4a186c9c
--- /dev/null
+++ b/examples/thing_shadow/main/core/wifi_driver/wifi_manager.c
@@ -0,0 +1,250 @@
+
+#include "esp_attr.h"
+#include "esp_sleep.h"
+#include <sys/time.h>
+#include <time.h>
+// #include "protocol_examples_common.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "esp_sntp.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/event_groups.h"
+#include "freertos/task.h"
+#include "main.h"
+#include "nvs_flash.h"
+#include <string.h>
+
+#include "driver/gpio.h"
+#include "lwip/err.h"
+#include "lwip/sys.h"
+#include "wifi_driver/data_store_nvs.h"
+#include "wifi_driver/http_server.h"
+#include "wifi_driver/wifi_manager.h"
+#include "buzzer.h"
+// #include "parse/Cjsonoperation.h"
+
+
+#define ESP_WIFI_SSIDAP "aws_device"
+#define ESP_WIFI_PASSAP "aws123456789"
+#define ESP_WIFI_CHANNEL 1
+#define MAX_STA_CONN 4
+#define MAXIMUM_RETRY 3
+#define WIFI_CONNECTED_BIT BIT0
+#define WIFI_FAIL_BIT BIT1
+#define RESETPIN 2
+
+int disconnectivity_count = 0;
+/* FreeRTOS event group to signal when we are connected*/
+wifi_mode_t mode;
+static EventGroupHandle_t s_wifi_event_group;
+uint8_t wifi_state = false;
+bool wifi_sta = false;
+/* The event group allows multiple bits for each event, but we only care about two events:
+ * - we are connected to the AP with an IP
+ * - we failed to connect after the maximum amount of retries */
+
+static const char *TAG = "wifi station";
+static int s_retry_num = 0;
+
+void Wifi_STA(void) {
+        wifi_config_t wifi_config_sta = {
+        .sta = {
+            //  .ssid = SSID,
+            //  .password = PASS,
+            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
+            .pmf_cfg = {
+                .capable = true,
+                .required = false},
+        },
+    };
+
+        sprintf((char *) wifi_config_sta.sta.ssid, "%s", ssid);
+        sprintf((char *) wifi_config_sta.sta.password, "%s", pswd);
+        printf("SSID =%s    &&&& Pass=%s\n", ssid, pswd);
+        wifi_mode_t mode;
+        if (esp_wifi_get_mode(&mode) == ESP_OK) {
+                if (mode != WIFI_MODE_APSTA) {
+                        ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+                }
+        }
+        ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config_sta));
+
+        ESP_LOGI(TAG, "wifi_init_sta finished.");
+}
+
+void Wifi_AP(void) {
+        wifi_config_t wifi_config_ap = {
+                .ap = { .ssid = ESP_WIFI_SSIDAP,
+                        .channel = 1,
+                        .ssid_len = strlen(ESP_WIFI_SSIDAP),
+                        .password = ESP_WIFI_PASSAP,
+                        .max_connection = MAX_STA_CONN,
+                        .authmode = WIFI_AUTH_WPA_WPA2_PSK },
+        };
+
+        if (strlen(ESP_WIFI_PASSAP) == 0) {
+                wifi_config_ap.ap.authmode = WIFI_AUTH_OPEN;
+        }
+        esp_wifi_set_mode(WIFI_MODE_AP);
+        esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config_ap);
+        ESP_LOGI(TAG, "wifi_init_ap finished.");
+}
+
+void Wifi_AP_STA(void) {
+        Wifi_STA();
+        Wifi_AP();
+        ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
+}
+
+static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
+        if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
+                ESP_LOGI(TAG, "starting sta...");
+                esp_wifi_connect();
+        }
+
+        if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
+
+                if (esp_wifi_get_mode(&mode) == ESP_OK) {
+                        if (s_retry_num >= MAXIMUM_RETRY && mode != WIFI_MODE_APSTA) {
+                                ESP_LOGI(TAG, "Mode changed to AP+STA");
+
+                                ESP_ERROR_CHECK(esp_wifi_stop());
+                                ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
+                                ESP_ERROR_CHECK(esp_wifi_start());
+                                esp_wifi_set_max_tx_power(34);
+
+                        }
+                }
+
+                ESP_LOGI(TAG, "Reconnecting...");
+                esp_wifi_connect();
+                s_retry_num++;
+
+                disconnectivity_count++; // when disconnected for longer duration then relogin it is used in
+                                         // network task manager to help detect relogin
+                if (disconnectivity_count > 1000) {
+                        disconnectivity_count = 30;
+                }
+        }
+        if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
+                s_retry_num = 0;
+
+                if (esp_wifi_get_mode(&mode) == ESP_OK) {
+                        if (mode == WIFI_MODE_APSTA) {
+                                ESP_LOGI(TAG, "Mode changed to STA");
+
+                                ESP_ERROR_CHECK(esp_wifi_stop());
+                                ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+                                ESP_ERROR_CHECK(esp_wifi_start());
+                                esp_wifi_set_max_tx_power(34);
+                        }
+                }
+        }
+
+        if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
+                ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
+                ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
+                s_retry_num = 0;
+                xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
+        }
+
+        switch (event_id) {
+        case WIFI_EVENT_STA_CONNECTED: {
+                wifi_sta = true;
+                wifi_state = WIFI_EVENT_STA_CONNECTED;
+        } break;
+        case WIFI_EVENT_STA_START: {
+                wifi_state = WIFI_EVENT_STA_START;
+        } break;
+        case WIFI_EVENT_STA_DISCONNECTED: {
+                wifi_sta = false;
+                wifi_state = WIFI_EVENT_STA_DISCONNECTED;
+        } break;
+        case WIFI_EVENT_AP_STADISCONNECTED: {
+        } break;
+        default:
+                break;
+        }
+}
+
+void wifi_init_sta(void) {
+        s_wifi_event_group = xEventGroupCreate();
+
+        ESP_ERROR_CHECK(esp_netif_init());
+
+        ESP_ERROR_CHECK(esp_event_loop_create_default());
+        esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap();
+        assert(ap_netif);
+        esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
+        assert(sta_netif);
+
+        wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+        ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+
+        esp_event_handler_instance_t instance_any_id;
+        esp_event_handler_instance_t instance_got_ip;
+        ESP_ERROR_CHECK(esp_event_handler_instance_register(
+                        WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
+        ESP_ERROR_CHECK(esp_event_handler_instance_register(
+                        IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
+
+        WebServerEventRegister();
+
+        GetWifiCred(); // load ssid and pswd from nvs
+        Wifi_AP_STA();
+        ESP_ERROR_CHECK(esp_wifi_start());
+        esp_wifi_set_max_tx_power(34);
+
+        ESP_LOGI(TAG, "wifi_init_sta finished.");
+
+        /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for
+         * the maximum number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
+        EventBits_t bits = xEventGroupWaitBits(
+                        s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
+
+        /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event
+         * actually happened. */
+        if (bits & WIFI_CONNECTED_BIT) {
+                // ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
+                //          SSID, PASS);
+        } else if (bits & WIFI_FAIL_BIT) {
+                // ESP_LOGE(TAG, "Failed to connect to SSID:%s, password:%s",
+                //          SSID, PASS);
+        } else {
+                ESP_LOGE(TAG, "UNEXPECTED EVENT");
+        }
+}
+
+void NvsResetTask() {
+        gpio_reset_pin(RESETPIN);
+        gpio_set_direction(RESETPIN, GPIO_MODE_INPUT);
+        gpio_set_pull_mode(RESETPIN, GPIO_PULLUP_ONLY);
+
+        while (1) {
+                if (gpio_get_level(RESETPIN)) {
+                        vTaskDelay(4900 / portTICK_RATE_MS);
+                        if (gpio_get_level(RESETPIN)) {
+                                nvs_flash_erase();
+                                esp_restart();
+                        } else {
+                        }
+                }
+                vTaskDelay(100 / portTICK_RATE_MS);
+        }
+}
+void WifiInit() {
+        // NVSInit();
+        esp_log_level_set(TAG, ESP_LOG_INFO); // Set UART log level
+        esp_err_t ret = nvs_flash_init();
+        if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+                ESP_ERROR_CHECK(nvs_flash_erase());
+                ret = nvs_flash_init();
+        }
+
+        ESP_ERROR_CHECK(ret);
+        ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
+        wifi_init_sta();
+        //xTaskCreate(NvsResetTask, "NVS reset", 1024 * 2, NULL, 2, NULL);
+}
\ No newline at end of file
diff --git a/examples/thing_shadow/main/core_utility.h b/examples/thing_shadow/main/core_utility.h
new file mode 100644
index 000000000..8b916f940
--- /dev/null
+++ b/examples/thing_shadow/main/core_utility.h
@@ -0,0 +1,31 @@
+#ifndef DEMO_CONFIG_H_
+#define DEMO_CONFIG_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "esp_log.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "freertos/queue.h"
+#include "sdkconfig.h"
+//#include "protocol_examples_common.h"
+#include "driver/gpio.h"
+#include "wifi_driver/wifi_manager.h"
+#include "main.h"
+#include "sleep.h"
+#include "esp_task_wdt.h"
+#include "ping_time.h"
+
+#define PUBLISH_TIME_S 5 
+#define TWDT_TIMEOUT_S PUBLISH_TIME_S*3
+#define PANIC_ENABLE 1
+#define WATCHDOG_FEED_TIME 5 //time in sec
+
+#endif
+
+
+
+
diff --git a/examples/thing_shadow/main/shadow_demo_helpers.c b/examples/thing_shadow/main/shadow_demo_helpers.c
index 1165b035b..c5284a095 100644
--- a/examples/thing_shadow/main/shadow_demo_helpers.c
+++ b/examples/thing_shadow/main/shadow_demo_helpers.c
@@ -37,6 +37,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include "buzzer.h"
 
 /* Shadow includes */
 #include "shadow_demo_helpers.h"
@@ -228,7 +229,7 @@ static uint8_t buffer[ NETWORK_BUFFER_SIZE ];
 /**
  * @brief The MQTT context used for MQTT operation.
  */
-static MQTTContext_t mqttContext = { 0 };
+ MQTTContext_t mqttContext = { 0 };
 
 /**
  * @brief The network context used for Openssl operation.
@@ -310,7 +311,7 @@ static void cleanupOutgoingPublishAt( uint8_t index );
  * @brief Function to clean up all the outgoing publishes maintained in the
  * array.
  */
-static void cleanupOutgoingPublishes( void );
+ void cleanupOutgoingPublishes( void );
 
 /**
  * @brief Function to clean up the publish packet with the given packet id.
@@ -460,16 +461,18 @@ static int connectToServerWithBackoffRetries( NetworkContext_t * pNetworkContext
                    AWS_IOT_ENDPOINT,
                    AWS_MQTT_PORT ) );
         tlsStatus = xTlsConnect ( pNetworkContext );
-
         if( tlsStatus != TLS_TRANSPORT_SUCCESS )
         {
             /* Generate a random number and get back-off value (in milliseconds) for the next connection retry. */
             backoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &reconnectParams, generateRandomNumber(), &nextRetryBackOff );
+            
+            buzzer_play_error_tune();
 
             if( backoffAlgStatus == BackoffAlgorithmRetriesExhausted )
             {
                 LogError( ( "Connection to the broker failed, all attempts exhausted." ) );
                 returnStatus = EXIT_FAILURE;
+                esp_restart();
             }
             else if( backoffAlgStatus == BackoffAlgorithmSuccess )
             {
@@ -525,7 +528,7 @@ static void cleanupOutgoingPublishAt( uint8_t index )
 
 /*-----------------------------------------------------------*/
 
-static void cleanupOutgoingPublishes( void )
+ void cleanupOutgoingPublishes( void )
 {
     assert( outgoingPublishPackets != NULL );
 
@@ -946,7 +949,7 @@ int32_t SubscribeToTopic( const char * pTopicFilter,
     ( void ) memset( ( void * ) pSubscriptionList, 0x00, sizeof( pSubscriptionList ) );
 
     /* This example subscribes to only one topic and uses QOS1. */
-    pSubscriptionList[ 0 ].qos = MQTTQoS1;
+    pSubscriptionList[ 0 ].qos = MQTTQoS0;
     pSubscriptionList[ 0 ].pTopicFilter = pTopicFilter;
     pSubscriptionList[ 0 ].topicFilterLength = topicFilterLength;
 
@@ -1074,7 +1077,7 @@ int32_t PublishToTopic( const char * pTopicFilter,
     {
         LogInfo( ( "Published payload: %s", pPayload ) );
         /* This example publishes to only one topic and uses QOS1. */
-        outgoingPublishPackets[ publishIndex ].pubInfo.qos = MQTTQoS1;
+        outgoingPublishPackets[ publishIndex ].pubInfo.qos = MQTTQoS0;
         outgoingPublishPackets[ publishIndex ].pubInfo.pTopicName = pTopicFilter;
         outgoingPublishPackets[ publishIndex ].pubInfo.topicNameLength = topicFilterLength;
         outgoingPublishPackets[ publishIndex ].pubInfo.pPayload = pPayload;
diff --git a/examples/thing_shadow/main/shadow_demo_helpers.h b/examples/thing_shadow/main/shadow_demo_helpers.h
index a3fc6b54f..02c65de76 100644
--- a/examples/thing_shadow/main/shadow_demo_helpers.h
+++ b/examples/thing_shadow/main/shadow_demo_helpers.h
@@ -100,4 +100,6 @@ int32_t PublishToTopic( const char * pTopicFilter,
                         const char * pPayload,
                         size_t payloadLength );
 
+void cleanupOutgoingPublishes( void );
+extern MQTTContext_t mqttContext ;
 #endif /* ifndef SHADOW_DEMO_HELPERS_H_ */
diff --git a/examples/thing_shadow/main/shadow_demo_main.c b/examples/thing_shadow/main/shadow_demo_main.c
index 06d17a80d..bd318331c 100644
--- a/examples/thing_shadow/main/shadow_demo_main.c
+++ b/examples/thing_shadow/main/shadow_demo_main.c
@@ -55,6 +55,8 @@
 #include <unistd.h>
 #include <inttypes.h>
 
+#include "esp_sleep.h"
+
 /* shadow demo helpers header. */
 #include "shadow_demo_helpers.h"
 
@@ -69,6 +71,11 @@
 
 /* Clock for timer. */
 #include "clock.h"
+#include "main.h"
+#include "ping_time.h"
+#include <cJSON.h>
+#include "buzzer.h"
+#include "sleep.h"
 
 /**
  * @brief Format string representing a Shadow document with a "desired" state.
@@ -111,8 +118,9 @@
  *
  * In your own application, you could calculate the size of the json doc in this way.
  */
-#define SHADOW_DESIRED_JSON_LENGTH    ( sizeof( SHADOW_DESIRED_JSON ) - 3 )
+#define SHADOW_DESIRED_JSON_LENGTH (sizeof(SHADOW_DESIRED_JSON) - 3)
 
+#define PAYLOAD_PROB "$aws/things/" CONFIG_MQTT_CLIENT_IDENTIFIER "/shadow/name/payload-prod/update"
 /**
  * @brief Format string representing a Shadow document with a "reported" state.
  *
@@ -147,7 +155,7 @@
  * its full size is known at compile-time by pre-calculation. Users could refer to
  * the way how to calculate the actual length in #SHADOW_DESIRED_JSON_LENGTH.
  */
-#define SHADOW_REPORTED_JSON_LENGTH    ( sizeof( SHADOW_REPORTED_JSON ) - 3 )
+#define SHADOW_REPORTED_JSON_LENGTH (sizeof(SHADOW_REPORTED_JSON) - 3)
 
 /**
  * @brief The maximum number of times to run the loop in this demo.
@@ -156,25 +164,25 @@
  * Once the demo loop succeeds in an iteration, the demo exits successfully.
  */
 #ifndef SHADOW_MAX_DEMO_LOOP_COUNT
-    #define SHADOW_MAX_DEMO_LOOP_COUNT    ( 3 )
+#define SHADOW_MAX_DEMO_LOOP_COUNT (3)
 #endif
 
 /**
  * @brief Time in seconds to wait between retries of the demo loop if
  * demo loop fails.
  */
-#define DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_S           ( 5 )
+#define DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_S (5)
 
 /**
  * @brief JSON key for response code that indicates the type of error in
  * the error document received on topic `/delete/rejected`.
  */
-#define SHADOW_DELETE_REJECTED_ERROR_CODE_KEY           "code"
+#define SHADOW_DELETE_REJECTED_ERROR_CODE_KEY "code"
 
 /**
  * @brief Length of #SHADOW_DELETE_REJECTED_ERROR_CODE_KEY
  */
-#define SHADOW_DELETE_REJECTED_ERROR_CODE_KEY_LENGTH    ( ( uint16_t ) ( sizeof( SHADOW_DELETE_REJECTED_ERROR_CODE_KEY ) - 1 ) )
+#define SHADOW_DELETE_REJECTED_ERROR_CODE_KEY_LENGTH ((uint16_t)(sizeof(SHADOW_DELETE_REJECTED_ERROR_CODE_KEY) - 1))
 
 /*-----------------------------------------------------------*/
 
@@ -231,9 +239,9 @@ static bool shadowDeleted = false;
  * @param[in] pPacketInfo Packet Info pointer for the incoming packet.
  * @param[in] pDeserializedInfo Deserialized information from the incoming packet.
  */
-static void eventCallback( MQTTContext_t * pMqttContext,
-                           MQTTPacketInfo_t * pPacketInfo,
-                           MQTTDeserializedInfo_t * pDeserializedInfo );
+static void eventCallback(MQTTContext_t *pMqttContext,
+                          MQTTPacketInfo_t *pPacketInfo,
+                          MQTTDeserializedInfo_t *pDeserializedInfo);
 
 /**
  * @brief Process payload from /update/delta topic.
@@ -244,7 +252,7 @@ static void eventCallback( MQTTContext_t * pMqttContext,
  * @param[in] pPublishInfo Deserialized publish info pointer for the incoming
  * packet.
  */
-static void updateDeltaHandler( MQTTPublishInfo_t * pPublishInfo );
+static void updateDeltaHandler(MQTTPublishInfo_t *pPublishInfo);
 
 /**
  * @brief Process payload from /update/accepted topic.
@@ -255,7 +263,7 @@ static void updateDeltaHandler( MQTTPublishInfo_t * pPublishInfo );
  * @param[in] pPublishInfo Deserialized publish info pointer for the incoming
  * packet.
  */
-static void updateAcceptedHandler( MQTTPublishInfo_t * pPublishInfo );
+static void updateAcceptedHandler(MQTTPublishInfo_t *pPublishInfo);
 
 /**
  * @brief Process payload from `/delete/rejected` topic.
@@ -268,281 +276,66 @@ static void updateAcceptedHandler( MQTTPublishInfo_t * pPublishInfo );
  * @param[in] pPublishInfo Deserialized publish info pointer for the incoming
  * packet.
  */
-static void deleteRejectedHandler( MQTTPublishInfo_t * pPublishInfo );
+static void deleteRejectedHandler(MQTTPublishInfo_t *pPublishInfo);
 
 /*-----------------------------------------------------------*/
 
-static void deleteRejectedHandler( MQTTPublishInfo_t * pPublishInfo )
+static void deleteRejectedHandler(MQTTPublishInfo_t *pPublishInfo)
 {
-    JSONStatus_t result = JSONSuccess;
-    char * pOutValue = NULL;
-    uint32_t outValueLength = 0U;
-    long errorCode = 0L;
-
-    assert( pPublishInfo != NULL );
-    assert( pPublishInfo->pPayload != NULL );
-
-    LogInfo( ( "/delete/rejected json payload:%s.", ( const char * ) pPublishInfo->pPayload ) );
-
-    /* The payload will look similar to this:
-     * {
-     *    "code": error-code,
-     *    "message": "error-message",
-     *    "timestamp": timestamp,
-     *    "clientToken": "token"
-     * }
-     */
-
-    /* Make sure the payload is a valid json document. */
-    result = JSON_Validate( ( const char * ) pPublishInfo->pPayload,
-                            pPublishInfo->payloadLength );
-
-    if( result == JSONSuccess )
-    {
-        /* Then we start to get the version value by JSON keyword "version". */
-        result = JSON_Search( ( char * ) pPublishInfo->pPayload,
-                              pPublishInfo->payloadLength,
-                              SHADOW_DELETE_REJECTED_ERROR_CODE_KEY,
-                              SHADOW_DELETE_REJECTED_ERROR_CODE_KEY_LENGTH,
-                              &pOutValue,
-                              ( size_t * ) &outValueLength );
-    }
-    else
-    {
-        LogError( ( "The json document is invalid!!" ) );
-    }
-
-    if( result == JSONSuccess )
-    {
-        LogInfo( ( "Error code is: %.*s.",
-                   (int) outValueLength,
-                   pOutValue ) );
-
-        /* Convert the extracted value to an unsigned integer value. */
-        errorCode = strtoul( pOutValue, NULL, 10 );
-    }
-    else
-    {
-        LogError( ( "No error code in json document!!" ) );
-    }
-
-    LogInfo( ( "Error code:%ld.", errorCode ) );
-
-    /* Mark Shadow delete operation as a success if error code is 404. */
-    if( errorCode == 404UL )
-    {
-        shadowDeleted = true;
-    }
 }
 
 /*-----------------------------------------------------------*/
 
-static void updateDeltaHandler( MQTTPublishInfo_t * pPublishInfo )
+static void updateDeltaHandler(MQTTPublishInfo_t *pPublishInfo)
 {
     static uint32_t currentVersion = 0; /* Remember the latestVersion # we've ever received */
     uint32_t version = 0U;
     uint32_t newState = 0U;
-    char * outValue = NULL;
+    char *outValue = NULL;
     uint32_t outValueLength = 0U;
     JSONStatus_t result = JSONSuccess;
 
-    assert( pPublishInfo != NULL );
-    assert( pPublishInfo->pPayload != NULL );
-
-    LogInfo( ( "/update/delta json payload:%s.", ( const char * ) pPublishInfo->pPayload ) );
-
-    /* The payload will look similar to this:
-     * {
-     *      "version": 12,
-     *      "timestamp": 1595437367,
-     *      "state": {
-     *          "powerOn": 1
-     *      },
-     *      "metadata": {
-     *          "powerOn": {
-     *          "timestamp": 1595437367
-     *          }
-     *      },
-     *      "clientToken": "388062"
-     *  }
-     */
-
-    /* Make sure the payload is a valid json document. */
-    result = JSON_Validate( ( const char * ) pPublishInfo->pPayload,
-                            pPublishInfo->payloadLength );
-
-    if( result == JSONSuccess )
-    {
-        /* Then we start to get the version value by JSON keyword "version". */
-        result = JSON_Search( ( char * ) pPublishInfo->pPayload,
-                              pPublishInfo->payloadLength,
-                              "version",
-                              sizeof( "version" ) - 1,
-                              &outValue,
-                              ( size_t * ) &outValueLength );
-    }
-    else
-    {
-        LogError( ( "The json document is invalid!!" ) );
-        eventCallbackError = true;
-    }
-
-    if( result == JSONSuccess )
-    {
-        LogInfo( ( "version: %.*s",
-                   (int) outValueLength,
-                   outValue ) );
-
-        /* Convert the extracted value to an unsigned integer value. */
-        version = ( uint32_t ) strtoul( outValue, NULL, 10 );
-    }
-    else
-    {
-        LogError( ( "No version in json document!!" ) );
-        eventCallbackError = true;
-    }
-
-    LogInfo( ( "version:%"PRIu32", currentVersion:%"PRIu32" \r\n", version, currentVersion ) );
+    assert(pPublishInfo != NULL);
+    assert(pPublishInfo->pPayload != NULL);
 
-    /* When the version is much newer than the on we retained, that means the powerOn
-     * state is valid for us. */
-    if( version > currentVersion )
-    {
-        /* Set to received version as the current version. */
-        currentVersion = version;
-
-        /* Get powerOn state from json documents. */
-        result = JSON_Search( ( char * ) pPublishInfo->pPayload,
-                              pPublishInfo->payloadLength,
-                              "state.powerOn",
-                              sizeof( "state.powerOn" ) - 1,
-                              &outValue,
-                              ( size_t * ) &outValueLength );
-    }
-    else
-    {
-        /* In this demo, we discard the incoming message
-         * if the version number is not newer than the latest
-         * that we've received before. Your application may use a
-         * different approach.
-         */
-        LogWarn( ( "The received version is smaller than current one!!" ) );
-    }
-
-    if( result == JSONSuccess )
-    {
-        /* Convert the powerOn state value to an unsigned integer value. */
-        newState = ( uint32_t ) strtoul( outValue, NULL, 10 );
-
-        LogInfo( ( "The new power on state newState:%"PRIu32", currentPowerOnState:%"PRIu32" \r\n",
-                   newState, currentPowerOnState ) );
-
-        if( newState != currentPowerOnState )
-        {
-            /* The received powerOn state is different from the one we retained before, so we switch them
-             * and set the flag. */
-            currentPowerOnState = newState;
-
-            /* State change will be handled in main(), where we will publish a "reported"
-             * state to the device shadow. We do not do it here because we are inside of
-             * a callback from the MQTT library, so that we don't re-enter
-             * the MQTT library. */
-            stateChanged = true;
-        }
-    }
-    else
-    {
-        LogError( ( "No powerOn in json document!!" ) );
-        eventCallbackError = true;
-    }
+    LogInfo(("/update/delta json payload:%s.", (const char *)pPublishInfo->pPayload));
 }
 
 /*-----------------------------------------------------------*/
-
-static void updateAcceptedHandler( MQTTPublishInfo_t * pPublishInfo )
+static void updateAcceptedHandler(MQTTPublishInfo_t *pPublishInfo)
 {
-    char * outValue = NULL;
+    char *outValue = NULL;
     uint32_t outValueLength = 0U;
     uint32_t receivedToken = 0U;
     JSONStatus_t result = JSONSuccess;
 
-    assert( pPublishInfo != NULL );
-    assert( pPublishInfo->pPayload != NULL );
-
-    LogInfo( ( "/update/accepted json payload:%s.", ( const char * ) pPublishInfo->pPayload ) );
-
-    /* Handle the reported state with state change in /update/accepted topic.
-     * Thus we will retrieve the client token from the json document to see if
-     * it's the same one we sent with reported state on the /update topic.
-     * The payload will look similar to this:
-     *  {
-     *      "state": {
-     *          "reported": {
-     *          "powerOn": 1
-     *          }
-     *      },
-     *      "metadata": {
-     *          "reported": {
-     *          "powerOn": {
-     *              "timestamp": 1596573647
-     *          }
-     *          }
-     *      },
-     *      "version": 14698,
-     *      "timestamp": 1596573647,
-     *      "clientToken": "022485"
-     *  }
-     */
-
-    /* Make sure the payload is a valid json document. */
-    result = JSON_Validate( ( const char * ) pPublishInfo->pPayload,
-                            pPublishInfo->payloadLength );
-
-    if( result == JSONSuccess )
-    {
-        /* Get clientToken from json documents. */
-        result = JSON_Search( ( char * ) pPublishInfo->pPayload,
-                              pPublishInfo->payloadLength,
-                              "clientToken",
-                              sizeof( "clientToken" ) - 1,
-                              &outValue,
-                              ( size_t * ) &outValueLength );
-    }
-    else
-    {
-        LogError( ( "Invalid json documents !!" ) );
-        eventCallbackError = true;
-    }
+    assert(pPublishInfo != NULL);
+    assert(pPublishInfo->pPayload != NULL);
 
-    if( result == JSONSuccess )
+    cJSON *root = cJSON_Parse((const char *)pPublishInfo->pPayload);
+    if (root != NULL)
     {
-        LogInfo( ( "clientToken: %.*s", (int) outValueLength,
-                   outValue ) );
-
-        /* Convert the code to an unsigned integer value. */
-        receivedToken = ( uint32_t ) strtoul( outValue, NULL, 10 );
-
-        LogInfo( ( "receivedToken:%"PRIu32", clientToken:%"PRIu32" \r\n", receivedToken, clientToken ) );
-
-        /* If the clientToken in this update/accepted message matches the one we
-         * published before, it means the device shadow has accepted our latest
-         * reported state. We are done. */
-        if( receivedToken == clientToken )
+        cJSON *state = cJSON_GetObjectItem(root, "state");
+        if (state != NULL)
         {
-            LogInfo( ( "Received response from the device shadow. Previously published "
-                       "update with clientToken=%"PRIu32" has been accepted. ", clientToken ) );
-        }
-        else
-        {
-            LogWarn( ( "The received clientToken=%"PRIu32" is not identical with the one=%"PRIu32" we sent "
-                       , receivedToken, clientToken ) );
+            cJSON *desired = cJSON_GetObjectItem(state, "desired");
+            if (desired != NULL)
+            {
+                cJSON *cfg = cJSON_GetObjectItem(desired, "cfg");
+                if (cfg != NULL)
+                {
+                    cJSON *publish_interval = cJSON_GetObjectItem(cfg, "publish_interval");
+                    if (publish_interval != NULL)
+                    {
+                        device_config.publish_interval = (publish_interval->valueint);
+                        printf("PUBLISH INTERVAL FROM CLOUD : %d\n", device_config.publish_interval);
+                        write_nvs_config();
+                    }
+                }
+            }
         }
     }
-    else
-    {
-        LogError( ( "No clientToken in json document!!" ) );
-        eventCallbackError = true;
-    }
+    cJSON_Delete(root);
 }
 
 /*-----------------------------------------------------------*/
@@ -552,92 +345,193 @@ static void updateAcceptedHandler( MQTTPublishInfo_t * pPublishInfo )
  * function to determine whether the incoming message is a device shadow message
  * or not. If it is, it handles the message depending on the message type.
  */
-static void eventCallback( MQTTContext_t * pMqttContext,
-                           MQTTPacketInfo_t * pPacketInfo,
-                           MQTTDeserializedInfo_t * pDeserializedInfo )
+static void eventCallback(MQTTContext_t *pMqttContext,
+                          MQTTPacketInfo_t *pPacketInfo,
+                          MQTTDeserializedInfo_t *pDeserializedInfo)
 {
+    printf("in callback\n");
     ShadowMessageType_t messageType = ShadowMessageTypeMaxNum;
-    const char * pThingName = NULL;
+    const char *pThingName = NULL;
     uint8_t thingNameLength = 0U;
-    const char * pShadowName = NULL;
+    const char *pShadowName = NULL;
     uint8_t shadowNameLength = 0U;
     uint16_t packetIdentifier;
 
-    ( void ) pMqttContext;
+    (void)pMqttContext;
 
-    assert( pDeserializedInfo != NULL );
-    assert( pMqttContext != NULL );
-    assert( pPacketInfo != NULL );
+    assert(pDeserializedInfo != NULL);
+    assert(pMqttContext != NULL);
+    assert(pPacketInfo != NULL);
 
     packetIdentifier = pDeserializedInfo->packetIdentifier;
 
     /* Handle incoming publish. The lower 4 bits of the publish packet
      * type is used for the dup, QoS, and retain flags. Hence masking
      * out the lower bits to check if the packet is publish. */
-    if( ( pPacketInfo->type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH )
+    if ((pPacketInfo->type & 0xF0U) == MQTT_PACKET_TYPE_PUBLISH)
     {
-        assert( pDeserializedInfo->pPublishInfo != NULL );
-        LogInfo( ( "pPublishInfo->pTopicName:%s.", pDeserializedInfo->pPublishInfo->pTopicName ) );
+        assert(pDeserializedInfo->pPublishInfo != NULL);
 
         /* Let the Device Shadow library tell us whether this is a device shadow message. */
-        if( SHADOW_SUCCESS == Shadow_MatchTopicString( pDeserializedInfo->pPublishInfo->pTopicName,
-                                                       pDeserializedInfo->pPublishInfo->topicNameLength,
-                                                       &messageType,
-                                                       &pThingName,
-                                                       &thingNameLength,
-                                                       &pShadowName,
-                                                       &shadowNameLength ) )
+        if (SHADOW_SUCCESS == Shadow_MatchTopicString(pDeserializedInfo->pPublishInfo->pTopicName,
+                                                      pDeserializedInfo->pPublishInfo->topicNameLength,
+                                                      &messageType,
+                                                      &pThingName,
+                                                      &thingNameLength,
+                                                      &pShadowName,
+                                                      &shadowNameLength))
         {
             /* Upon successful return, the messageType has been filled in. */
-            if( messageType == ShadowMessageTypeUpdateDelta )
-            {
-                /* Handler function to process payload. */
-                updateDeltaHandler( pDeserializedInfo->pPublishInfo );
-            }
-            else if( messageType == ShadowMessageTypeUpdateAccepted )
+            if (messageType == ShadowMessageTypeGetAccepted)
             {
                 /* Handler function to process payload. */
-                updateAcceptedHandler( pDeserializedInfo->pPublishInfo );
-            }
-            else if( messageType == ShadowMessageTypeUpdateDocuments )
-            {
-                LogInfo( ( "/update/documents json payload:%s.", ( const char * ) pDeserializedInfo->pPublishInfo->pPayload ) );
-            }
-            else if( messageType == ShadowMessageTypeUpdateRejected )
-            {
-                LogInfo( ( "/update/rejected json payload:%s.", ( const char * ) pDeserializedInfo->pPublishInfo->pPayload ) );
-            }
-            else if( messageType == ShadowMessageTypeDeleteAccepted )
-            {
-                LogInfo( ( "Received an MQTT incoming publish on /delete/accepted topic." ) );
-                shadowDeleted = true;
-                deleteResponseReceived = true;
+                LogInfo(("pPublishInfo->pTopicName:%s.", pDeserializedInfo->pPublishInfo->pTopicName));
+                updateAcceptedHandler(pDeserializedInfo->pPublishInfo);
             }
-            else if( messageType == ShadowMessageTypeDeleteRejected )
+            else if (messageType == ShadowMessageTypeUpdateDelta)
             {
-                /* Handler function to process payload. */
-                deleteRejectedHandler( pDeserializedInfo->pPublishInfo );
-                deleteResponseReceived = true;
+                //  LogInfo(("pPublishInfo->pTopicName:%s.", pDeserializedInfo->pPublishInfo->pTopicName));
+                LogInfo(("payload:%s.", (const char *)pDeserializedInfo->pPublishInfo->pPayload));
+                updateDeltaHandler(pDeserializedInfo->pPublishInfo);
             }
             else
             {
-                LogInfo( ( "Other message type:%d !!", messageType ) );
+                LogInfo(("Other message type:%d !!", messageType));
+                LogInfo(("payload:%s.", (const char *)pDeserializedInfo->pPublishInfo->pPayload));
             }
         }
         else
         {
-            LogError( ( "Shadow_MatchTopicString parse failed:%s !!", ( const char * ) pDeserializedInfo->pPublishInfo->pTopicName ) );
+            LogError(("Shadow_MatchTopicString parse failed:%s !!", (const char *)pDeserializedInfo->pPublishInfo->pTopicName));
             eventCallbackError = true;
         }
     }
     else
     {
-        HandleOtherIncomingPacket( pPacketInfo, packetIdentifier );
+        HandleOtherIncomingPacket(pPacketInfo, packetIdentifier);
     }
 }
 
 /*-----------------------------------------------------------*/
+/**
+ * @brief
+ *
+ * @param param
+ * @return true
+ * @return false
+ */
+bool start_mqtt(void *param)
+{
+    int returnStatus = EXIT_SUCCESS;
+
+    returnStatus = EstablishMqttSession(eventCallback);
+
+    if (returnStatus == EXIT_FAILURE)
+    {
+        /* Log error to indicate connection failure. */
+        LogError(("Failed to connect to MQTT broker."));
+        return false;
+    }
+    return true;
+}
+/**
+ * @brief
+ *
+ */
 
+bool clean_mqtt(void *param)
+{
+    printf("Clear MQTT \n");
+    DisconnectMqttSession();
+    return true;
+}
+/**
+ * @brief
+ *
+ */
+bool is_mqtt_connected(void *param)
+{
+    if (mqttContext.connectStatus == MQTTConnected)
+    {
+        return true;
+    }
+    return false;
+}
+/**
+ * @brief
+ *
+ */
+void get_shadow_configration(void)
+{
+    uint16_t returnStatus = 0;
+    static char updateDocument[SHADOW_REPORTED_JSON_LENGTH + 1] = {0};
+    /* First of all, try to delete any Shadow document in the cloud.
+     * Try to subscribe to `/delete/accepted` and `/delete/rejected` topics. */
+    returnStatus = SubscribeToTopic(SHADOW_TOPIC_STR_GET_ACC(THING_NAME, SHADOW_NAME),
+                                    SHADOW_TOPIC_LEN_GET_ACC(THING_NAME_LENGTH, SHADOW_NAME_LENGTH));
+
+    if (returnStatus == EXIT_SUCCESS)
+    {
+        /* Publish to Shadow `delete` topic to attempt to delete the
+         * Shadow document if exists. */
+        returnStatus = PublishToTopic(SHADOW_TOPIC_STR_GET(THING_NAME, SHADOW_NAME),
+                                      SHADOW_TOPIC_LEN_GET(THING_NAME_LENGTH, SHADOW_NAME_LENGTH),
+                                      updateDocument,
+                                      0U);
+        Sleep(1);
+        returnStatus = UnsubscribeFromTopic(SHADOW_TOPIC_STR_GET_ACC(THING_NAME, SHADOW_NAME),
+                                            SHADOW_TOPIC_LEN_GET_ACC(THING_NAME_LENGTH, SHADOW_NAME_LENGTH));
+
+        returnStatus = SubscribeToTopic(SHADOW_TOPIC_STR_UPDATE_DELTA(THING_NAME, SHADOW_NAME),
+                                        SHADOW_TOPIC_LEN_UPDATE_DELTA(THING_NAME_LENGTH, SHADOW_NAME_LENGTH));
+    }
+}
+/**
+ * @brief
+ *
+ * @param payload
+ */
+uint8_t publish_payload_prob(char *payload)
+{
+    int status = 0;
+    if (mqttContext.connectStatus == MQTTConnected)
+    {
+        status = PublishToTopic(PAYLOAD_PROB,
+                                strlen(PAYLOAD_PROB),
+                                payload,
+                                strlen(payload));
+        cleanupOutgoingPublishes();
+    }
+    uint8_t ret = (status == EXIT_SUCCESS) ? 1 : 0;
+
+    return ret;
+}
+/**
+ * @brief
+ *
+ */
+void init_classic_shadow()
+{
+    uint8_t tries = 0;
+
+    while (1)
+    {
+        tries++;
+        if (start_mqtt(NULL))
+        {
+            get_shadow_configration();
+            break;
+        }
+        else
+        {
+            if (tries == 6)
+            {
+                esp_restart();
+            }
+        }
+        Sleep(4);
+    }
+}
 /**
  * @brief Entry point of shadow demo.
  *
@@ -659,269 +553,84 @@ static void eventCallback( MQTTContext_t * pMqttContext,
  * loops to process incoming messages. Those are not the focus of this demo
  * and therefore, are placed in a separate file shadow_demo_helpers.c.
  */
-int aws_iot_demo_main( int argc,
-          char ** argv )
+int aws_shadow_main(int argc,
+                    char **argv)
 {
-    int returnStatus = EXIT_SUCCESS;
-    int demoRunCount = 0;
-
-    /* A buffer containing the update document. It has static duration to prevent
-     * it from being placed on the call stack. */
-    static char updateDocument[ SHADOW_REPORTED_JSON_LENGTH + 1 ] = { 0 };
 
-    ( void ) argc;
-    ( void ) argv;
-
-    do
+    //** Just dummy payload For testing.For functionatility bind original one
+    /*     char test_payload[256] = {0x00};
+        sprintf(test_payload, "%s", SHADOW_DESIRED_JSON); */
+
+    // buzzer_play_tone();
+    cJSON *root, *reported, *report;
+    root = cJSON_CreateObject();
+    cJSON_AddItemToObject(root, "state", reported = cJSON_CreateObject());
+    cJSON_AddItemToObject(reported, "reported", report = cJSON_CreateObject());
+    cJSON_AddItemToObject(report, "ts", cJSON_CreateNumber(GetStandardTime()));
+    cJSON_AddItemToObject(report, "device_id", cJSON_CreateString(CONFIG_MQTT_CLIENT_IDENTIFIER));
+    // cJSON_AddItemToObject(report, "data_packet_nr", cJSON_CreateNumber(5));
+    cJSON_AddItemToObject(report, "ph", cJSON_CreateNumber(7.5));
+    cJSON_AddItemToObject(report, "conductivity", cJSON_CreateNumber(200));
+    cJSON_AddItemToObject(report, "cpu_temp", cJSON_CreateNumber(45));
+    cJSON_AddItemToObject(report, "rawdat", cJSON_CreateString("test raw data"));
+    cJSON_AddItemToObject(report, "rssi", cJSON_CreateNumber(-50));
+    cJSON_AddItemToObject(report, "reset_reasons", cJSON_CreateNumber(4));
+
+    /* print everything */
+    char *test_payload = cJSON_Print(root);
+    // printf("%s\n", test_payload);
+    // free(out);
+
+    /* free all objects under root and root itself */
+    cJSON_Delete(root);
+
+    bool disconnect_occur = false;
+
+    init_classic_shadow();
+
+    while (1)
     {
-        returnStatus = EstablishMqttSession( eventCallback );
+        ESP_LOGI("AWS sender", "Publish Interval: %d s", device_config.publish_interval);
 
-        if( returnStatus == EXIT_FAILURE )
+        if (wifi_sta && disconnect_occur)
         {
-            /* Log error to indicate connection failure. */
-            LogError( ( "Failed to connect to MQTT broker." ) );
+            disconnect_occur = false;
+            Sleep(2);
+            clean_mqtt(NULL);
+            init_classic_shadow();
         }
-        else
+        else if (wifi_sta)
         {
-            /* Reset the shadow delete status flags. */
-            deleteResponseReceived = false;
-            shadowDeleted = false;
-
-            /* First of all, try to delete any Shadow document in the cloud.
-             * Try to subscribe to `/delete/accepted` and `/delete/rejected` topics. */
-            returnStatus = SubscribeToTopic( SHADOW_TOPIC_STR_DELETE_ACC( THING_NAME, SHADOW_NAME ),
-                                             SHADOW_TOPIC_LEN_DELETE_ACC( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                /* Try to subscribe to `/delete/rejected` topic. */
-                returnStatus = SubscribeToTopic( SHADOW_TOPIC_STR_DELETE_REJ( THING_NAME, SHADOW_NAME ),
-                                                 SHADOW_TOPIC_LEN_DELETE_REJ( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
-
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                /* Publish to Shadow `delete` topic to attempt to delete the
-                 * Shadow document if exists. */
-                returnStatus = PublishToTopic( SHADOW_TOPIC_STR_DELETE( THING_NAME, SHADOW_NAME ),
-                                               SHADOW_TOPIC_LEN_DELETE( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ),
-                                               updateDocument,
-                                               0U );
-            }
 
-            /* Unsubscribe from the `/delete/accepted` and 'delete/rejected` topics.*/
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                returnStatus = UnsubscribeFromTopic( SHADOW_TOPIC_STR_DELETE_ACC( THING_NAME, SHADOW_NAME ),
-                                                     SHADOW_TOPIC_LEN_DELETE_ACC( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
-
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                returnStatus = UnsubscribeFromTopic( SHADOW_TOPIC_STR_DELETE_REJ( THING_NAME, SHADOW_NAME ),
-                                                     SHADOW_TOPIC_LEN_DELETE_REJ( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
-
-            /* Check if an incoming publish on `/delete/accepted` or `/delete/rejected`
-             * topics. If a response is not received, mark the demo execution as a failure.*/
-            if( ( returnStatus == EXIT_SUCCESS ) && ( deleteResponseReceived != true ) )
-            {
-                LogError( ( "Failed to receive a response for Shadow delete." ) );
-                returnStatus = EXIT_FAILURE;
-            }
-
-            /* Check if Shadow document delete was successful. A delete can be
-             * successful in cases listed below.
-             *  1. If an incoming publish is received on `/delete/accepted` topic.
-             *  2. If an incoming publish is received on `/delete/rejected` topic
-             *     with an error code 404. This indicates that a delete was
-             *     attempted when a Shadow document is not available for the
-             *     Thing. */
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                if( shadowDeleted == false )
-                {
-                    LogError( ( "Shadow delete operation failed." ) );
-                    returnStatus = EXIT_FAILURE;
-                }
-            }
-
-            /* Successfully connect to MQTT broker, the next step is
-             * to subscribe shadow topics. */
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                returnStatus = SubscribeToTopic( SHADOW_TOPIC_STR_UPDATE_DELTA( THING_NAME, SHADOW_NAME ),
-                                                 SHADOW_TOPIC_LEN_UPDATE_DELTA( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
-
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                returnStatus = SubscribeToTopic( SHADOW_TOPIC_STR_UPDATE_ACC( THING_NAME, SHADOW_NAME ),
-                                                 SHADOW_TOPIC_LEN_UPDATE_ACC( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
-
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                returnStatus = SubscribeToTopic( SHADOW_TOPIC_STR_UPDATE_REJ( THING_NAME, SHADOW_NAME ),
-                                                 SHADOW_TOPIC_LEN_UPDATE_REJ( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
+            //** if wifi connected
 
-            /* This demo uses a constant #THING_NAME and #SHADOW_NAME known at compile time therefore
-             * we can use macros to assemble shadow topic strings.
-             * If the thing name or shadow name is only known at run time, then we could use the API
-             * #Shadow_AssembleTopicString to assemble shadow topic strings, here is the example for /update/delta:
-             *
-             * For /update/delta:
-             *
-             * #define SHADOW_TOPIC_MAX_LENGTH  (256U)
-             *
-             * ShadowStatus_t shadowStatus = SHADOW_SUCCESS;
-             * char topicBuffer[ SHADOW_TOPIC_MAX_LENGTH ] = { 0 };
-             * uint16_t bufferSize = SHADOW_TOPIC_MAX_LENGTH;
-             * uint16_t outLength = 0;
-             * const char thingName[] = { "TestThingName" };
-             * uint16_t thingNameLength  = ( sizeof( thingName ) - 1U );
-             * const char shadowName[] = { "TestShadowName" };
-             * uint16_t shadowNameLength  = ( sizeof( shadowName ) - 1U );
-             *
-             * shadowStatus = Shadow_AssembleTopicString( ShadowTopicStringTypeUpdateDelta,
-             *                                            thingName,
-             *                                            thingNameLength,
-             *                                            shadowName,
-             *                                            shadowNameLength,
-             *                                            & ( topicBuffer[ 0 ] ),
-             *                                            bufferSize,
-             *                                            & outLength );
-             */
-
-            /* Then we publish a desired state to the /update topic. Since we've deleted
-             * the device shadow at the beginning of the demo, this will cause a delta message
-             * to be published, which we have subscribed to.
-             * In many real applications, the desired state is not published by
-             * the device itself. But for the purpose of making this demo self-contained,
-             * we publish one here so that we can receive a delta message later.
-             */
-            if( returnStatus == EXIT_SUCCESS )
+            if (is_mqtt_connected(NULL))
             {
-                /* desired power on state . */
-                LogInfo( ( "Send desired power state with 1." ) );
-
-                ( void ) memset( updateDocument,
-                                 0x00,
-                                 sizeof( updateDocument ) );
-
-                /* Keep the client token in global variable used to compare if
-                 * the same token in /update/accepted. */
-                clientToken = ( Clock_GetTimeMs() % 1000000 );
-
-                snprintf( updateDocument,
-                          SHADOW_DESIRED_JSON_LENGTH + 1,
-                          SHADOW_DESIRED_JSON,
-                          ( int ) 1,
-                          ( long unsigned ) clientToken );
-
-                returnStatus = PublishToTopic( SHADOW_TOPIC_STR_UPDATE( THING_NAME, SHADOW_NAME ),
-                                               SHADOW_TOPIC_LEN_UPDATE( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ),
-                                               updateDocument,
-                                               ( SHADOW_DESIRED_JSON_LENGTH + 1 ) );
-            }
 
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                /* Note that PublishToTopic already called MQTT_ProcessLoop,
-                 * therefore responses may have been received and the eventCallback
-                 * may have been called, which may have changed the stateChanged flag.
-                 * Check if the state change flag has been modified or not. If it's modified,
-                 * then we publish reported state to update topic.
-                 */
-                if( stateChanged == true )
+                if (publish_payload_prob(test_payload))
                 {
-                    /* Report the latest power state back to device shadow. */
-                    LogInfo( ( "Report to the state change: %"PRIu32"", currentPowerOnState ) );
-                    ( void ) memset( updateDocument,
-                                     0x00,
-                                     sizeof( updateDocument ) );
-
-                    /* Keep the client token in global variable used to compare if
-                     * the same token in /update/accepted. */
-                    clientToken = ( Clock_GetTimeMs() % 1000000 );
-
-                    snprintf( updateDocument,
-                              SHADOW_REPORTED_JSON_LENGTH + 1,
-                              SHADOW_REPORTED_JSON,
-                              ( int ) currentPowerOnState,
-                              ( long unsigned ) clientToken );
-
-                    returnStatus = PublishToTopic( SHADOW_TOPIC_STR_UPDATE( THING_NAME, SHADOW_NAME ),
-                                                   SHADOW_TOPIC_LEN_UPDATE( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ),
-                                                   updateDocument,
-                                                   ( SHADOW_REPORTED_JSON_LENGTH + 1 ) );
+                    buzzer_play_heartbeat();
+                    feed_watchdog = true;
+                    Sleep(60);
+                    // esp_sleep_enable_timer_wakeup(device_config.publish_interval*1000*1000);
+                    // esp_deep_sleep_start();
                 }
                 else
                 {
-                    LogInfo( ( "No change from /update/delta, unsubscribe all shadow topics and disconnect from MQTT.\r\n" ) );
+                    feed_watchdog = false;
                 }
             }
-
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                LogInfo( ( "Start to unsubscribe shadow topics and disconnect from MQTT. \r\n" ) );
-                returnStatus = UnsubscribeFromTopic( SHADOW_TOPIC_STR_UPDATE_DELTA( THING_NAME, SHADOW_NAME ),
-                                                     SHADOW_TOPIC_LEN_UPDATE_DELTA( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
-
-            if( returnStatus == EXIT_SUCCESS )
+            else
             {
-                returnStatus = UnsubscribeFromTopic( SHADOW_TOPIC_STR_UPDATE_ACC( THING_NAME, SHADOW_NAME ),
-                                                     SHADOW_TOPIC_LEN_UPDATE_ACC( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
-            }
 
-            if( returnStatus == EXIT_SUCCESS )
-            {
-                returnStatus = UnsubscribeFromTopic( SHADOW_TOPIC_STR_UPDATE_REJ( THING_NAME, SHADOW_NAME ),
-                                                     SHADOW_TOPIC_LEN_UPDATE_REJ( THING_NAME_LENGTH, SHADOW_NAME_LENGTH ) );
+                clean_mqtt(NULL);
+                init_classic_shadow();
             }
-
-            /* The MQTT session is always disconnected, even there were prior failures. */
-            returnStatus = DisconnectMqttSession();
-        }
-
-        /* This demo performs only Device Shadow operations. If matching the Shadow
-         * topic fails or there are failures in parsing the received JSON document,
-         * then this demo was not successful. */
-        if( eventCallbackError == true )
-        {
-            returnStatus = EXIT_FAILURE;
-        }
-
-        /* Increment the demo run count. */
-        demoRunCount++;
-
-        if( returnStatus == EXIT_SUCCESS )
-        {
-            LogInfo( ( "Demo iteration %d is successful.", demoRunCount ) );
         }
-        /* Attempt to retry a failed iteration of demo for up to #SHADOW_MAX_DEMO_LOOP_COUNT times. */
-        else if( demoRunCount < SHADOW_MAX_DEMO_LOOP_COUNT )
-        {
-            LogWarn( ( "Demo iteration %d failed. Retrying...", demoRunCount ) );
-            sleep( DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_S );
-        }
-        /* Failed all #SHADOW_MAX_DEMO_LOOP_COUNT demo iterations. */
         else
         {
-            LogError( ( "All %d demo iterations failed.", SHADOW_MAX_DEMO_LOOP_COUNT ) );
-            break;
+            disconnect_occur = true;
         }
-    } while( returnStatus != EXIT_SUCCESS );
-
-    if( returnStatus == EXIT_SUCCESS )
-    {
-        /* Log message indicating the demo completed successfully. */
-        LogInfo( ( "Demo completed successfully." ) );
+        Sleep(5);
     }
-
-    return returnStatus;
-}
-
-/*-----------------------------------------------------------*/
+}
\ No newline at end of file
diff --git a/examples/thing_shadow/sdkconfig.defaults b/examples/thing_shadow/sdkconfig.defaults
deleted file mode 100644
index 76818b694..000000000
--- a/examples/thing_shadow/sdkconfig.defaults
+++ /dev/null
@@ -1,10 +0,0 @@
-# newlib for ESP32 and ESP8266 platform
-
-CONFIG_NEWLIB_ENABLE=y
-CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL=y
-CONFIG_NEWLIB_NANO_FORMAT=
-CONFIG_SSL_USING_MBEDTLS=y
-CONFIG_LWIP_IPV6=y
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"