diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml
index d5b756085c7..436c8a57b7e 100644
--- a/.github/ISSUE_TEMPLATE/Issue-report.yml
+++ b/.github/ISSUE_TEMPLATE/Issue-report.yml
@@ -5,7 +5,7 @@ body:
   - type: markdown
     attributes:
       value: |
-        * Before reporting a new issue please check and search in [List of existing issues](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue) 
+        * Before reporting a new issue please check and search in [List of existing issues](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue)
         * Please check [Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/index.html)
         * Take a look on [Troubleshooting guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html)
         * If still experiencing the issue, please provide as many details as possible below about your hardware, computer setup and code.
@@ -24,7 +24,7 @@ body:
       description: What development board or other hardware is the chip attached to?
       placeholder: ex. DevKitC, plain module on breadboard, etc. If your hardware is custom or unusual, please attach a photo.
     validations:
-       required: true
+      required: true
   - type: textarea
     id: other-hw
     attributes:
@@ -60,7 +60,7 @@ body:
         - v2.0.8
         - v2.0.7
         - v2.0.6
-        - v2.0.5 
+        - v2.0.5
         - v2.0.4
         - v2.0.3
         - v2.0.2
@@ -75,9 +75,9 @@ body:
     attributes:
      label: IDE Name
      description: What IDE are you using?
-     placeholder: eg. Arduino IDE, PlatformIO, Sloeber...
+     placeholder: eg. Arduino IDE, VSCode, Sloeber...
     validations:
-     required: true
+      required: true
   - type: input
     id: os
     attributes:
@@ -95,13 +95,13 @@ body:
     validations:
       required: true
   - type: dropdown
-    id: PSRAM 
+    id: PSRAM
     attributes:
       label: PSRAM enabled
       description: Is PSRAM enabled?
       options:
-        - 'yes'
-        - 'no' 
+        - "yes"
+        - "no"
     validations:
       required: true
   - type: input
@@ -116,8 +116,8 @@ body:
     id: Description
     attributes:
       label: Description
-      description: Please describe your problem here and expected behaviour
-      placeholder: ex. Can't connect/weird behaviour/wrong function/missing parameter..
+      description: Please describe your problem here and expected behavior
+      placeholder: ex. Can't connect/weird behavior/wrong function/missing parameter..
     validations:
       required: true
   - type: textarea
@@ -128,7 +128,7 @@ body:
       placeholder: ex. Related part of the code to replicate the issue
       render: cpp
     validations:
-     required: true
+      required: true
   - type: textarea
     id: Debug
     attributes:
@@ -137,11 +137,11 @@ body:
       placeholder: Enable Core debug level - Debug on tools menu of Arduino IDE, then put the serial output here.
       render: plain
     validations:
-      required: true      
+      required: true
   - type: textarea
     id: other-remarks
     attributes:
-      label: Other Steps to Reproduce 
+      label: Other Steps to Reproduce
       description: Is there any other information you can think of which will help us reproduce this problem? Any additional info can be added as well.
       placeholder: ex. I also tried on other OS, HW...it works correctly on that setup.
   - type: checkboxes
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 2a9b0ef82e0..03b3a76df1e 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -5,4 +5,4 @@ contact_links:
     about: Community channel for questions and help
   - name: ESP32 Forum - Arduino
     url: https://esp32.com/viewforum.php?f=19
-    about: Official Forum for questions
\ No newline at end of file
+    about: Official Forum for questions
diff --git a/.github/scripts/check-cmakelists.sh b/.github/scripts/check-cmakelists.sh
index 98d9722ad83..7d4f6b4e2d9 100755
--- a/.github/scripts/check-cmakelists.sh
+++ b/.github/scripts/check-cmakelists.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
+
 #
 # This script is used in the CI workflow. It checks all non-examples source files in libraries/ and cores/ are listed in
 # CMakeLists.txt for the cmake-based IDF component
@@ -12,10 +13,10 @@ set -e
 git submodule update --init --recursive
 
 # find all source files in repo
-REPO_SRCS=`find cores/esp32/ libraries/ -name 'examples' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort`
+REPO_SRCS=$(find cores/esp32/ libraries/ -name 'examples' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort)
 
 # find all source files named in CMakeLists.txt COMPONENT_SRCS
-CMAKE_SRCS=`cmake --trace-expand -P CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort`
+CMAKE_SRCS=$(cmake --trace-expand -P CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort)
 
 if ! diff -u0 --label "Repo Files" --label "srcs" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then
     echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match"
diff --git a/.github/scripts/find_all_boards.sh b/.github/scripts/find_all_boards.sh
index b474a49bc2e..67b46661ca5 100755
--- a/.github/scripts/find_all_boards.sh
+++ b/.github/scripts/find_all_boards.sh
@@ -3,7 +3,9 @@
 # Get all boards
 boards_array=()
 
-for line in `grep '.tarch=' boards.txt`; do
+boards_list=$(grep '.tarch=' boards.txt)
+
+while read -r line; do
     board_name=$(echo "$line" | cut -d '.' -f1 | cut -d '#' -f1)
     # skip esp32c2 as we dont build libs for it
     if [ "$board_name" == "esp32c2" ]; then
@@ -12,29 +14,26 @@ for line in `grep '.tarch=' boards.txt`; do
     fi
     boards_array+=("espressif:esp32:$board_name")
     echo "Added 'espressif:esp32:$board_name' to array"
-done
+done <<< "$boards_list"
 
 # Create JSON like string with all boards found and pass it to env variable
 board_count=${#boards_array[@]}
 echo "Boards found: $board_count"
-echo "BOARD-COUNT=$board_count" >> $GITHUB_ENV
+echo "BOARD-COUNT=$board_count" >> "$GITHUB_ENV"
 
-if [ $board_count -gt 0 ]
-then
+if [ "$board_count" -gt 0 ]; then
     json_matrix='['
-    for board in ${boards_array[@]}
-    do
+    for board in "${boards_array[@]}"; do
         json_matrix+='"'$board'"'
-        if [ $board_count -gt 1 ]
-        then
+        if [ "$board_count" -gt 1 ]; then
             json_matrix+=","
         fi
-        board_count=$(($board_count - 1))
+        board_count=$((board_count - 1))
     done
     json_matrix+=']'
 
-    echo $json_matrix
-    echo "FQBNS=${json_matrix}" >> $GITHUB_ENV
+    echo "$json_matrix"
+    echo "FQBNS=${json_matrix}" >> "$GITHUB_ENV"
 else
-    echo "FQBNS=" >> $GITHUB_ENV
+    echo "FQBNS=" >> "$GITHUB_ENV"
 fi
diff --git a/.github/scripts/find_new_boards.sh b/.github/scripts/find_new_boards.sh
index 706676b4a4c..4482aa2b1da 100755
--- a/.github/scripts/find_new_boards.sh
+++ b/.github/scripts/find_new_boards.sh
@@ -5,14 +5,13 @@ owner_repository=$1
 base_ref=$2
 
 # Download the boards.txt file from the base branch
-curl -L -o boards_base.txt https://raw.githubusercontent.com/$owner_repository/$base_ref/boards.txt
+curl -L -o boards_base.txt https://raw.githubusercontent.com/"$owner_repository"/"$base_ref"/boards.txt
 
 # Compare boards.txt file in the repo with the modified file from PR
 diff=$(diff -u boards_base.txt boards.txt)
 
 # Check if the diff is empty
-if [ -z "$diff" ]
-then
+if [ -z "$diff" ]; then
     echo "No changes in boards.txt file"
     echo "FQBNS="
     exit 0
@@ -21,7 +20,7 @@ fi
 # Extract added or modified lines (lines starting with '+' or '-')
 modified_lines=$(echo "$diff" | grep -E '^[+-][^+-]')
 
-# Print the modified lines for debugging
+# Print the modified lines for debugging
 echo "Modified lines:"
 echo "$modified_lines"
 
@@ -29,15 +28,12 @@ boards_array=()
 previous_board=""
 
 # Extract board names from the modified lines, and add them to the boards_array
-while read -r line
-do
+while read -r line; do
     board_name=$(echo "$line" | cut -d '.' -f1 | cut -d '#' -f1)
     # remove + or - from the board name at the beginning
-    board_name=$(echo "$board_name" | sed 's/^[+-]//')
-    if [ "$board_name" != "" ] && [ "$board_name" != "+" ] && [ "$board_name" != "-" ] && [ "$board_name" != "esp32_family" ]
-    then
-        if [ "$board_name" != "$previous_board" ]
-        then
+    board_name=${board_name#[-+]}
+    if [ "$board_name" != "" ] && [ "$board_name" != "+" ] && [ "$board_name" != "-" ] && [ "$board_name" != "esp32_family" ]; then
+        if [ "$board_name" != "$previous_board" ]; then
             boards_array+=("espressif:esp32:$board_name")
             previous_board="$board_name"
             echo "Added 'espressif:esp32:$board_name' to array"
@@ -48,22 +44,19 @@ done <<< "$modified_lines"
 # Create JSON like string with all boards found and pass it to env variable
 board_count=${#boards_array[@]}
 
-if [ $board_count -gt 0 ]
-then
+if [ "$board_count" -gt 0 ]; then
     json_matrix='{"fqbn": ['
-    for board in ${boards_array[@]}
-    do
+    for board in "${boards_array[@]}"; do
         json_matrix+='"'$board'"'
-        if [ $board_count -gt 1 ]
-        then
+        if [ "$board_count" -gt 1 ]; then
             json_matrix+=","
         fi
-        board_count=$(($board_count - 1))
+        board_count=$((board_count - 1))
     done
     json_matrix+=']}'
 
-    echo $json_matrix
-    echo "FQBNS=${json_matrix}" >> $GITHUB_ENV
+    echo "$json_matrix"
+    echo "FQBNS=${json_matrix}" >> "$GITHUB_ENV"
 else
-    echo "FQBNS=" >> $GITHUB_ENV
-fi
\ No newline at end of file
+    echo "FQBNS=" >> "$GITHUB_ENV"
+fi
diff --git a/.github/scripts/install-arduino-cli.sh b/.github/scripts/install-arduino-cli.sh
index 533b39c7ddd..bb7f544e752 100755
--- a/.github/scripts/install-arduino-cli.sh
+++ b/.github/scripts/install-arduino-cli.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-OSBITS=`uname -m`
+OSBITS=$(uname -m)
 if [[ "$OSTYPE" == "linux"* ]]; then
     export OS_IS_LINUX="1"
     if [[ "$OSBITS" == "i686" ]]; then
@@ -49,4 +49,3 @@ if [ ! -d "$ARDUINO_IDE_PATH" ] || [ ! -f "$ARDUINO_IDE_PATH/arduino-cli" ]; the
         curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR="$ARDUINO_IDE_PATH" sh
     fi
 fi
-
diff --git a/.github/scripts/install-arduino-core-esp32.sh b/.github/scripts/install-arduino-core-esp32.sh
index fe50c909198..e0071a0eb83 100755
--- a/.github/scripts/install-arduino-core-esp32.sh
+++ b/.github/scripts/install-arduino-core-esp32.sh
@@ -5,7 +5,7 @@ if [ ! -d "$ARDUINO_ESP32_PATH" ]; then
     echo "Installing ESP32 Arduino Core ..."
     script_init_path="$PWD"
     mkdir -p "$ARDUINO_USR_PATH/hardware/espressif"
-    cd "$ARDUINO_USR_PATH/hardware/espressif"
+    cd "$ARDUINO_USR_PATH/hardware/espressif" || exit
 
     echo "Installing Python Serial ..."
     pip install pyserial > /dev/null
@@ -15,25 +15,25 @@ if [ ! -d "$ARDUINO_ESP32_PATH" ]; then
         pip install requests > /dev/null
     fi
 
-    if [ ! -z "$GITHUB_REPOSITORY" ];  then
+    if [ -n "$GITHUB_REPOSITORY" ];  then
         echo "Linking Core..."
-        ln -s $GITHUB_WORKSPACE esp32
+        ln -s "$GITHUB_WORKSPACE" esp32
     else
         echo "Cloning Core Repository..."
         git clone https://github.com/espressif/arduino-esp32.git esp32 > /dev/null 2>&1
     fi
 
     #echo "Updating Submodules ..."
-    cd esp32
+    cd esp32 || exit
     #git submodule update --init --recursive > /dev/null 2>&1
 
     echo "Installing Platform Tools ..."
     if [ "$OS_IS_WINDOWS" == "1" ]; then
-      cd tools && ./get.exe
+        cd tools && ./get.exe
     else
-      cd tools && python get.py
+        cd tools && python get.py
     fi
-    cd $script_init_path
+    cd "$script_init_path" || exit
 
     echo "ESP32 Arduino has been installed in '$ARDUINO_ESP32_PATH'"
     echo ""
diff --git a/.github/scripts/install-arduino-ide.sh b/.github/scripts/install-arduino-ide.sh
index 7fd95797834..5b3bcb1791e 100755
--- a/.github/scripts/install-arduino-ide.sh
+++ b/.github/scripts/install-arduino-ide.sh
@@ -4,7 +4,7 @@
 #OSTYPE: 'msys', ARCH: 'x86_64' => win32
 #OSTYPE: 'darwin18', ARCH: 'i386' => macos
 
-OSBITS=`uname -m`
+OSBITS=$(uname -m)
 if [[ "$OSTYPE" == "linux"* ]]; then
     export OS_IS_LINUX="1"
     ARCHIVE_FORMAT="tar.xz"
@@ -77,4 +77,3 @@ if [ ! -d "$ARDUINO_IDE_PATH" ]; then
     echo "Arduino IDE Installed in '$ARDUINO_IDE_PATH'"
     echo ""
 fi
-
diff --git a/.github/scripts/install-platformio-esp32.sh b/.github/scripts/install-platformio-esp32.sh
index 80c668bdc0e..8cd6552eb80 100755
--- a/.github/scripts/install-platformio-esp32.sh
+++ b/.github/scripts/install-platformio-esp32.sh
@@ -52,7 +52,7 @@ python -c "$replace_script"
 
 if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ];  then
     echo "Linking Core..."
-    ln -s $GITHUB_WORKSPACE "$PLATFORMIO_ESP32_PATH"
+    ln -s "$GITHUB_WORKSPACE" "$PLATFORMIO_ESP32_PATH"
 else
     echo "Cloning Core Repository ..."
     git clone --recursive https://github.com/espressif/arduino-esp32.git "$PLATFORMIO_ESP32_PATH" > /dev/null 2>&1
@@ -61,7 +61,7 @@ fi
 echo "PlatformIO for ESP32 has been installed"
 echo ""
 
-function build_pio_sketch(){ # build_pio_sketch <board> <options> <path-to-ino>
+function build_pio_sketch { # build_pio_sketch <board> <options> <path-to-ino>
     if [ "$#" -lt 3 ]; then
         echo "ERROR: Illegal number of parameters"
         echo "USAGE: build_pio_sketch <board> <options> <path-to-ino>"
@@ -71,13 +71,15 @@ function build_pio_sketch(){ # build_pio_sketch <board> <options> <path-to-ino>
     local board="$1"
     local options="$2"
     local sketch="$3"
-    local sketch_dir=$(dirname "$sketch")
+    local sketch_dir
+
+    sketch_dir=$(dirname "$sketch")
     echo ""
-    echo "Compiling '"$(basename "$sketch")"' ..."
+    echo "Compiling '$(basename "$sketch")' ..."
     python -m platformio ci --board "$board" "$sketch_dir" --project-option="$options"
 }
 
-function build_pio_sketches(){ # build_pio_sketches <board> <options> <examples-path> <chunk> <total-chunks>
+function build_pio_sketches { # build_pio_sketches <board> <options> <examples-path> <chunk> <total-chunks>
     if [ "$#" -lt 3 ]; then
         echo "ERROR: Illegal number of parameters"
         echo "USAGE: build_pio_sketches <board> <options> <examples-path> [<chunk> <total-chunks>]"
@@ -108,27 +110,34 @@ function build_pio_sketches(){ # build_pio_sketches <board> <options> <examples-
     ${COUNT_SKETCHES} "$examples" "esp32"
     local sketchcount=$?
     set -e
-    local sketches=$(cat sketches.txt)
+    local sketches
+    sketches=$(cat sketches.txt)
     rm -rf sketches.txt
 
-    local chunk_size=$(( $sketchcount / $chunks_num ))
-    local all_chunks=$(( $chunks_num * $chunk_size ))
+    local chunk_size
+    local all_chunks
+    local start_index
+    local end_index
+    local start_num
+
+    chunk_size=$(( sketchcount / chunks_num ))
+    all_chunks=$(( chunks_num * chunk_size ))
     if [ "$all_chunks" -lt "$sketchcount" ]; then
-        chunk_size=$(( $chunk_size + 1 ))
+        chunk_size=$(( chunk_size + 1 ))
     fi
 
-    local start_index=$(( $chunk_idex * $chunk_size ))
+    start_index=$(( chunk_idex * chunk_size ))
     if [ "$sketchcount" -le "$start_index" ]; then
         echo "Skipping job"
         return 0
     fi
 
-    local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
+    end_index=$(( $(( chunk_idex + 1 )) * chunk_size ))
     if [ "$end_index" -gt "$sketchcount" ]; then
         end_index=$sketchcount
     fi
 
-    local start_num=$(( $start_index + 1 ))
+    start_num=$(( start_index + 1 ))
     echo "Found $sketchcount Sketches";
     echo "Chunk Count : $chunks_num"
     echo "Chunk Size  : $chunk_size"
@@ -137,25 +146,32 @@ function build_pio_sketches(){ # build_pio_sketches <board> <options> <examples-
 
     local sketchnum=0
     for sketch in $sketches; do
-        local sketchdir=$(dirname $sketch)
-        local sketchdirname=$(basename $sketchdir)
-        local sketchname=$(basename $sketch)
+        local sketchdir
+        local sketchdirname
+        local sketchname
+        local is_target
+        local has_requirements
+
+        sketchdir=$(dirname "$sketch")
+        sketchdirname=$(basename "$sketchdir")
+        sketchname=$(basename "$sketch")
+
         if [[ "$sketchdirname.ino" != "$sketchname" ]]; then
             continue
-        elif [ -f $sketchdir/ci.json ]; then
+        elif [ -f "$sketchdir"/ci.json ]; then
             # If the target is listed as false, skip the sketch. Otherwise, include it.
-            is_target=$(jq -r '.targets[esp32]' $sketchdir/ci.json)
+            is_target=$(jq -r '.targets[esp32]' "$sketchdir"/ci.json)
             if [[ "$is_target" == "false" ]]; then
                 continue
             fi
 
-            local has_requirements=$(${CHECK_REQUIREMENTS} $sketchdir "$SDKCONFIG_DIR/esp32/sdkconfig")
+            has_requirements=$(${CHECK_REQUIREMENTS} "$sketchdir" "$SDKCONFIG_DIR/esp32/sdkconfig")
             if [ "$has_requirements" == "0" ]; then
                 continue
             fi
         fi
 
-        sketchnum=$(($sketchnum + 1))
+        sketchnum=$((sketchnum + 1))
         if [ "$sketchnum" -le "$start_index" ] \
         || [ "$sketchnum" -gt "$end_index" ]; then
             continue
diff --git a/.github/scripts/merge_packages.py b/.github/scripts/merge_packages.py
index 96999c17fd7..7e4f47ca8b3 100755
--- a/.github/scripts/merge_packages.py
+++ b/.github/scripts/merge_packages.py
@@ -1,50 +1,58 @@
 #!/usr/bin/env python
+
 # This script merges two Arduino Board Manager package json files.
 # Usage:
 #   python merge_packages.py package_esp8266com_index.json version/new/package_esp8266com_index.json
 # Written by Ivan Grokhotkov, 2015
 #
+
 from __future__ import print_function
-#from distutils.version import LooseVersion
+
+# from distutils.version import LooseVersion
 from packaging.version import Version
 import re
 import json
 import sys
 
+
 def load_package(filename):
-    pkg = json.load(open(filename))['packages'][0]
-    print("Loaded package {0} from {1}".format(pkg['name'], filename), file=sys.stderr)
-    print("{0} platform(s), {1} tools".format(len(pkg['platforms']), len(pkg['tools'])), file=sys.stderr)
+    pkg = json.load(open(filename))["packages"][0]
+    print("Loaded package {0} from {1}".format(pkg["name"], filename), file=sys.stderr)
+    print("{0} platform(s), {1} tools".format(len(pkg["platforms"]), len(pkg["tools"])), file=sys.stderr)
     return pkg
 
+
 def merge_objects(versions, obj):
     for o in obj:
-        name = o['name'].encode('ascii')
-        ver = o['version'].encode('ascii')
-        if not name in versions:
+        name = o["name"].encode("ascii")
+        ver = o["version"].encode("ascii")
+        if name not in versions:
             print("found new object, {0}".format(name), file=sys.stderr)
             versions[name] = {}
-        if not ver in versions[name]:
+        if ver not in versions[name]:
             print("found new version {0} for object {1}".format(ver, name), file=sys.stderr)
             versions[name][ver] = o
     return versions
 
-# Normalize ESP release version string (x.x.x) by adding '-rc<MAXINT>' (x.x.x-rc9223372036854775807) to ensure having REL above any RC
-# Dummy approach, functional anyway for current ESP package versioning (unlike NormalizedVersion/LooseVersion/StrictVersion & similar crap)
+
+# Normalize ESP release version string (x.x.x) by adding '-rc<MAXINT>' (x.x.x-rc9223372036854775807)
+# to ensure having REL above any RC
+# Dummy approach, functional anyway for current ESP package versioning
+# (unlike NormalizedVersion/LooseVersion/StrictVersion & similar crap)
 def pkgVersionNormalized(versionString):
 
     verStr = str(versionString)
-    verParts = re.split('\.|-rc|-alpha', verStr, flags=re.IGNORECASE)
-    
+    verParts = re.split(r"\.|-rc|-alpha", verStr, flags=re.IGNORECASE)
+
     if len(verParts) == 3:
-        if (sys.version_info > (3, 0)): # Python 3
-            verStr = str(versionString) + '-rc' + str(sys.maxsize)
-        else: # Python 2
-            verStr = str(versionString) + '-rc' + str(sys.maxint)
-        
+        if sys.version_info > (3, 0):  # Python 3
+            verStr = str(versionString) + "-rc" + str(sys.maxsize)
+        else:  # Python 2
+            verStr = str(versionString) + "-rc" + str(sys.maxint)
+
     elif len(verParts) != 4:
         print("pkgVersionNormalized WARNING: unexpected version format: {0})".format(verStr), file=sys.stderr)
-        
+
     return verStr
 
 
@@ -54,31 +62,37 @@ def main(args):
         return 1
 
     tools = {}
-    platforms = {} 
+    platforms = {}
     pkg1 = load_package(args[1])
-    tools = merge_objects(tools, pkg1['tools']);
-    platforms = merge_objects(platforms, pkg1['platforms']);
+    tools = merge_objects(tools, pkg1["tools"])
+    platforms = merge_objects(platforms, pkg1["platforms"])
     pkg2 = load_package(args[2])
-    tools = merge_objects(tools, pkg2['tools']);
-    platforms = merge_objects(platforms, pkg2['platforms']);
+    tools = merge_objects(tools, pkg2["tools"])
+    platforms = merge_objects(platforms, pkg2["platforms"])
 
-    pkg1['tools'] = []
-    pkg1['platforms'] = []
+    pkg1["tools"] = []
+    pkg1["platforms"] = []
 
     for name in tools:
         for version in tools[name]:
             print("Adding tool {0}-{1}".format(name, version), file=sys.stderr)
-            pkg1['tools'].append(tools[name][version])
+            pkg1["tools"].append(tools[name][version])
 
     for name in platforms:
         for version in platforms[name]:
             print("Adding platform {0}-{1}".format(name, version), file=sys.stderr)
-            pkg1['platforms'].append(platforms[name][version])
-                
-    #pkg1['platforms'] = sorted(pkg1['platforms'], key=lambda k: LooseVersion(pkgVersionNormalized(k['version'])), reverse=True)
-    pkg1['platforms'] = sorted(pkg1['platforms'], key=lambda k: Version(pkgVersionNormalized(k['version'])), reverse=True)
+            pkg1["platforms"].append(platforms[name][version])
+
+    # pkg1["platforms"] = sorted(
+    #     pkg1["platforms"], key=lambda k: LooseVersion(pkgVersionNormalized(k["version"])), reverse=True
+    # )
+
+    pkg1["platforms"] = sorted(
+        pkg1["platforms"], key=lambda k: Version(pkgVersionNormalized(k["version"])), reverse=True
+    )
+
+    json.dump({"packages": [pkg1]}, sys.stdout, indent=2)
 
-    json.dump({'packages':[pkg1]}, sys.stdout, indent=2)
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     sys.exit(main(sys.argv))
diff --git a/.github/scripts/on-pages.sh b/.github/scripts/on-pages.sh
index 124518469d2..877d036106b 100755
--- a/.github/scripts/on-pages.sh
+++ b/.github/scripts/on-pages.sh
@@ -1,12 +1,13 @@
-#/bin/bash
+#!/bin/bash
+
 set -e
 
-function get_file_size(){
+function get_file_size {
     local file="$1"
     if [[ "$OSTYPE" == "darwin"* ]]; then
-        eval `stat -s "$file"`
+        eval "$(stat -s "$file")"
         local res="$?"
-        echo "$st_size"
+        echo "${st_size:?}"
         return $res
     else
         stat --printf="%s" "$file"
@@ -15,25 +16,32 @@ function get_file_size(){
 }
 
 #git_remove_from_pages <file>
-function git_remove_from_pages(){
+function git_remove_from_pages {
     local path=$1
-    local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"`
-    local type=`echo "$info" | jq -r '.type'`
-    if [ ! $type == "file" ]; then
-        if [ ! $type == "null" ]; then
+    local info
+    local type
+    local sha
+    local message
+
+    info=$(curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages")
+    type=$(echo "$info" | jq -r '.type')
+
+    if [ ! "$type" == "file" ]; then
+        if [ ! "$type" == "null" ]; then
             echo "Wrong type '$type'"
         else
             echo "File is not on Pages"
         fi
         return 0
     fi
-    local sha=`echo "$info" | jq -r '.sha'`
-    local message="Deleting "$(basename $path)
+
+    sha=$(echo "$info" | jq -r '.sha')
+    message="Deleting "$(basename "$path")
     local json="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"sha\":\"$sha\"}"
     echo "$json" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X DELETE --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path"
 }
 
-function git_upload_to_pages(){
+function git_upload_to_pages {
     local path=$1
     local src=$2
 
@@ -42,41 +50,50 @@ function git_upload_to_pages(){
         return 1
     fi
 
-    local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"`
-    local type=`echo "$info" | jq -r '.type'`
-    local message=$(basename $path)
+    local info
+    local type
+    local message
     local sha=""
     local content=""
 
-    if [ $type == "file" ]; then
-        sha=`echo "$info" | jq -r '.sha'`
+    info=$(curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages")
+    type=$(echo "$info" | jq -r '.type')
+    message=$(basename "$path")
+
+    if [ "$type" == "file" ]; then
+        sha=$(echo "$info" | jq -r '.sha')
         sha=",\"sha\":\"$sha\""
         message="Updating $message"
-    elif [ ! $type == "null" ]; then
+    elif [ ! "$type" == "null" ]; then
         >&2 echo "Wrong type '$type'"
         return 1
     else
         message="Creating $message"
     fi
 
-    content=`base64 -i "$src"`
+    content=$(base64 -i "$src")
     data="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"content\":\"$content\"$sha}"
 
     echo "$data" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X PUT --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path"
 }
 
-function git_safe_upload_to_pages(){
+function git_safe_upload_to_pages {
     local path=$1
     local file="$2"
-    local name=$(basename "$file")
-    local size=`get_file_size "$file"`
-    local upload_res=`git_upload_to_pages "$path" "$file"`
-    if [ $? -ne 0 ]; then
+    local name
+    local size
+    local upload_res
+
+    name=$(basename "$file")
+    size=$(get_file_size "$file")
+
+    if ! upload_res=$(git_upload_to_pages "$path" "$file"); then
         >&2 echo "ERROR: Failed to upload '$name' ($?)"
         return 1
     fi
-    up_size=`echo "$upload_res" | jq -r '.content.size'`
-    if [ $up_size -ne $size ]; then
+
+    up_size=$(echo "$upload_res" | jq -r '.content.size')
+    if [ "$up_size" -ne "$size" ]; then
         >&2 echo "ERROR: Uploaded size does not match! $up_size != $size"
         #git_delete_asset
         return 1
diff --git a/.github/scripts/on-push.sh b/.github/scripts/on-push.sh
index 08ff505f1c0..5158df3cc9b 100755
--- a/.github/scripts/on-push.sh
+++ b/.github/scripts/on-push.sh
@@ -4,43 +4,44 @@ set -e
 
 export ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp"
 
-function build(){
+function build {
     local target=$1
     local chunk_index=$2
     local chunks_cnt=$3
     local build_log=$4
     local sketches_file=$5
-    shift; shift; shift; shift; shift;
-    local sketches=$*
+    shift 5
+    local sketches=("$@")
 
     local BUILD_SKETCH="${SCRIPTS_DIR}/sketch_utils.sh build"
     local BUILD_SKETCHES="${SCRIPTS_DIR}/sketch_utils.sh chunk_build"
 
-    local args="-ai $ARDUINO_IDE_PATH -au $ARDUINO_USR_PATH"
-
-    args+=" -t $target"
+    local args=("-ai" "$ARDUINO_IDE_PATH" "-au" "$ARDUINO_USR_PATH" "-t" "$target")
 
     if [ "$OS_IS_LINUX" == "1" ]; then
-        args+=" -p $ARDUINO_ESP32_PATH/libraries"
-        args+=" -i $chunk_index -m $chunks_cnt"
+        args+=("-p" "$ARDUINO_ESP32_PATH/libraries" "-i" "$chunk_index" "-m" "$chunks_cnt")
         if [ -n "$sketches_file" ]; then
-          args+=" -f $sketches_file"
+            args+=("-f" "$sketches_file")
         fi
-        if [ $build_log -eq 1 ]; then
-            args+=" -l $build_log"
+        if [ "$build_log" -eq 1 ]; then
+            args+=("-l" "$build_log")
         fi
-        ${BUILD_SKETCHES} ${args}
+        ${BUILD_SKETCHES} "${args[@]}"
     else
-        for sketch in ${sketches}; do
-            local sargs="$args -s $(dirname $sketch)"
+        for sketch in "${sketches[@]}"; do
+            local sargs=("${args[@]}")
+            local ctags_version
+            local preprocessor_version
+            sargs+=("-s" "$(dirname "$sketch")")
             if [ "$OS_IS_WINDOWS" == "1" ] && [ -d "$ARDUINO_IDE_PATH/tools-builder" ]; then
-                local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"`
-                local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"`
-                win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version
-                -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version"
-                sargs+=" ${win_opts}"
+                ctags_version=$(ls "$ARDUINO_IDE_PATH/tools-builder/ctags/")
+                preprocessor_version=$(ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/")
+                sargs+=(
+                    "-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version"
+                    "-prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version"
+                )
             fi
-            ${BUILD_SKETCH} ${sargs}
+            ${BUILD_SKETCH} "${sargs[@]}"
         done
     fi
 }
@@ -73,39 +74,40 @@ fi
 
 SCRIPTS_DIR="./.github/scripts"
 if [ "$BUILD_PIO" -eq 0 ]; then
-    source ${SCRIPTS_DIR}/install-arduino-cli.sh
-    source ${SCRIPTS_DIR}/install-arduino-core-esp32.sh
-
-    SKETCHES_ESP32="\
-      $ARDUINO_ESP32_PATH/libraries/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino\
-      $ARDUINO_ESP32_PATH/libraries/BLE/examples/Server/Server.ino\
-      $ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino\
-      $ARDUINO_ESP32_PATH/libraries/Insights/examples/MinimalDiagnostics/MinimalDiagnostics.ino\
-    "
+    source "${SCRIPTS_DIR}/install-arduino-cli.sh"
+    source "${SCRIPTS_DIR}/install-arduino-core-esp32.sh"
+
+    SKETCHES_ESP32=(
+        "$ARDUINO_ESP32_PATH/libraries/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
+        "$ARDUINO_ESP32_PATH/libraries/BLE/examples/Server/Server.ino"
+        "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
+        "$ARDUINO_ESP32_PATH/libraries/Insights/examples/MinimalDiagnostics/MinimalDiagnostics.ino"
+    )
     #create sizes_file
     sizes_file="$GITHUB_WORKSPACE/cli_compile_$CHUNK_INDEX.json"
 
     if [ "$BUILD_LOG" -eq 1 ]; then
         #create sizes_file and echo start of JSON array with "boards" key
-        echo "{\"boards\": [" > $sizes_file
+        echo "{\"boards\": [" > "$sizes_file"
     fi
 
     #build sketches for different targets
-    build "esp32s3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32"
-    build "esp32s2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32"
-    build "esp32c3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32"
-    build "esp32c6" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32"
-    build "esp32h2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32"
-    build "esp32"   "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "$SKETCHES_ESP32"
+    build "esp32p4" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}"
+    build "esp32s3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}"
+    build "esp32s2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}"
+    build "esp32c3" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}"
+    build "esp32c6" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}"
+    build "esp32h2" "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}"
+    build "esp32"   "$CHUNK_INDEX" "$CHUNKS_CNT" "$BUILD_LOG" "$SKETCHES_FILE" "${SKETCHES_ESP32[@]}"
 
     if [ "$BUILD_LOG" -eq 1 ]; then
         #remove last comma from the last JSON object
         sed -i '$ s/,$//' "$sizes_file"
         #echo end of JSON array
-        echo "]}" >> $sizes_file
+        echo "]}" >> "$sizes_file"
     fi
 else
-    source ${SCRIPTS_DIR}/install-platformio-esp32.sh
+    source "${SCRIPTS_DIR}/install-platformio-esp32.sh"
     # PlatformIO ESP32 Test
     BOARD="esp32dev"
     OPTIONS="board_build.partitions = huge_app.csv"
@@ -116,8 +118,7 @@ else
     build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
 
     # Basic sanity testing for other series
-    for board in "esp32-c3-devkitm-1" "esp32-s2-saola-1" "esp32-s3-devkitc-1"
-    do
+    for board in "esp32-c3-devkitm-1" "esp32-s2-saola-1" "esp32-s3-devkitc-1"; do
         python -m platformio ci --board "$board" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.partitions = huge_app.csv"
     done
 
diff --git a/.github/scripts/on-release.sh b/.github/scripts/on-release.sh
index e0dd7b752c5..119c66e1eab 100755
--- a/.github/scripts/on-release.sh
+++ b/.github/scripts/on-release.sh
@@ -1,29 +1,34 @@
 #!/bin/bash
+# Disable shellcheck warning about using 'cat' to read a file.
+# Disable shellcheck warning about using individual redirections for each command.
+# Disable shellcheck warning about $? uses.
+# shellcheck disable=SC2002,SC2129,SC2181,SC2319
 
-if [ ! $GITHUB_EVENT_NAME == "release" ]; then
+if [ ! "$GITHUB_EVENT_NAME" == "release" ]; then
     echo "Wrong event '$GITHUB_EVENT_NAME'!"
     exit 1
 fi
 
-EVENT_JSON=`cat $GITHUB_EVENT_PATH`
+EVENT_JSON=$(cat "$GITHUB_EVENT_PATH")
 
-action=`echo $EVENT_JSON | jq -r '.action'`
-if [ ! $action == "published" ]; then
+action=$(echo "$EVENT_JSON" | jq -r '.action')
+if [ ! "$action" == "published" ]; then
     echo "Wrong action '$action'. Exiting now..."
     exit 0
 fi
 
-draft=`echo $EVENT_JSON | jq -r '.release.draft'`
-if [ $draft == "true" ]; then
+draft=$(echo "$EVENT_JSON" | jq -r '.release.draft')
+if [ "$draft" == "true" ]; then
     echo "It's a draft release. Exiting now..."
     exit 0
 fi
 
-RELEASE_PRE=`echo $EVENT_JSON | jq -r '.release.prerelease'`
-RELEASE_TAG=`echo $EVENT_JSON | jq -r '.release.tag_name'`
-RELEASE_BRANCH=`echo $EVENT_JSON | jq -r '.release.target_commitish'`
-RELEASE_ID=`echo $EVENT_JSON | jq -r '.release.id'`
+RELEASE_PRE=$(echo "$EVENT_JSON" | jq -r '.release.prerelease')
+RELEASE_TAG=$(echo "$EVENT_JSON" | jq -r '.release.tag_name')
+RELEASE_BRANCH=$(echo "$EVENT_JSON" | jq -r '.release.target_commitish')
+RELEASE_ID=$(echo "$EVENT_JSON" | jq -r '.release.id')
 
+SCRIPTS_DIR="./.github/scripts"
 OUTPUT_DIR="$GITHUB_WORKSPACE/build"
 PACKAGE_NAME="esp32-$RELEASE_TAG"
 PACKAGE_JSON_MERGE="$GITHUB_WORKSPACE/.github/scripts/merge_packages.py"
@@ -36,17 +41,23 @@ echo "Action: $action, Branch: $RELEASE_BRANCH, ID: $RELEASE_ID"
 echo "Tag: $RELEASE_TAG, Draft: $draft, Pre-Release: $RELEASE_PRE"
 
 # Try extracting something like a JSON with a "boards" array/element and "vendor" fields
-BOARDS=`echo $RELEASE_BODY | grep -Pzo '(?s){.*}' | jq -r '.boards[]? // .boards? // empty' | xargs echo -n 2>/dev/null`
-VENDOR=`echo $RELEASE_BODY | grep -Pzo '(?s){.*}' | jq -r '.vendor? // empty' | xargs echo -n 2>/dev/null`
-if ! [ -z "${BOARDS}" ]; then echo "Releasing board(s): $BOARDS" ; fi
-if ! [ -z "${VENDOR}" ]; then echo "Setting packager: $VENDOR" ; fi
+BOARDS=$(echo "$RELEASE_BODY" | grep -Pzo '(?s){.*}' | jq -r '.boards[]? // .boards? // empty' | xargs echo -n 2>/dev/null)
+VENDOR=$(echo "$RELEASE_BODY" | grep -Pzo '(?s){.*}' | jq -r '.vendor? // empty' | xargs echo -n 2>/dev/null)
 
-function get_file_size(){
+if [ -n "${BOARDS}" ]; then
+    echo "Releasing board(s): $BOARDS"
+fi
+
+if [ -n "${VENDOR}" ]; then
+    echo "Setting packager: $VENDOR"
+fi
+
+function get_file_size {
     local file="$1"
     if [[ "$OSTYPE" == "darwin"* ]]; then
-        eval `stat -s "$file"`
+        eval "$(stat -s "$file")"
         local res="$?"
-        echo "$st_size"
+        echo "${st_size:?}"
         return $res
     else
         stat --printf="%s" "$file"
@@ -54,23 +65,29 @@ function get_file_size(){
     fi
 }
 
-function git_upload_asset(){
-    local name=$(basename "$1")
+function git_upload_asset {
+    local name
+    name=$(basename "$1")
     # local mime=$(file -b --mime-type "$1")
     curl -k -X POST -sH "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/octet-stream" --data-binary @"$1" "https://uploads.github.com/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?name=$name"
 }
 
-function git_safe_upload_asset(){
+function git_safe_upload_asset {
     local file="$1"
-    local name=$(basename "$file")
-    local size=`get_file_size "$file"`
-    local upload_res=`git_upload_asset "$file"`
-    if [ $? -ne 0 ]; then
+    local name
+    local size
+    local upload_res
+
+    name=$(basename "$file")
+    size=$(get_file_size "$file")
+
+    if ! upload_res=$(git_upload_asset "$file"); then
         >&2 echo "ERROR: Failed to upload '$name' ($?)"
         return 1
     fi
-    up_size=`echo "$upload_res" | jq -r '.size'`
-    if [ $up_size -ne $size ]; then
+
+    up_size=$(echo "$upload_res" | jq -r '.size')
+    if [ "$up_size" -ne "$size" ]; then
         >&2 echo "ERROR: Uploaded size does not match! $up_size != $size"
         #git_delete_asset
         return 1
@@ -79,7 +96,7 @@ function git_safe_upload_asset(){
     return $?
 }
 
-function git_upload_to_pages(){
+function git_upload_to_pages {
     local path=$1
     local src=$2
 
@@ -88,41 +105,50 @@ function git_upload_to_pages(){
         return 1
     fi
 
-    local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"`
-    local type=`echo "$info" | jq -r '.type'`
-    local message=$(basename $path)
+    local info
+    local type
+    local message
     local sha=""
     local content=""
 
-    if [ $type == "file" ]; then
-        sha=`echo "$info" | jq -r '.sha'`
+    info=$(curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages")
+    type=$(echo "$info" | jq -r '.type')
+    message=$(basename "$path")
+
+    if [ "$type" == "file" ]; then
+        sha=$(echo "$info" | jq -r '.sha')
         sha=",\"sha\":\"$sha\""
         message="Updating $message"
-    elif [ ! $type == "null" ]; then
+    elif [ ! "$type" == "null" ]; then
         >&2 echo "Wrong type '$type'"
         return 1
     else
         message="Creating $message"
     fi
 
-    content=`base64 -i "$src"`
+    content=$(base64 -i "$src")
     data="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"content\":\"$content\"$sha}"
 
     echo "$data" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X PUT --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path"
 }
 
-function git_safe_upload_to_pages(){
+function git_safe_upload_to_pages {
     local path=$1
     local file="$2"
-    local name=$(basename "$file")
-    local size=`get_file_size "$file"`
-    local upload_res=`git_upload_to_pages "$path" "$file"`
-    if [ $? -ne 0 ]; then
+    local name
+    local size
+    local upload_res
+
+    name=$(basename "$file")
+    size=$(get_file_size "$file")
+
+    if ! upload_res=$(git_upload_to_pages "$path" "$file"); then
         >&2 echo "ERROR: Failed to upload '$name' ($?)"
         return 1
     fi
-    up_size=`echo "$upload_res" | jq -r '.content.size'`
-    if [ $up_size -ne $size ]; then
+
+    up_size=$(echo "$upload_res" | jq -r '.content.size')
+    if [ "$up_size" -ne "$size" ]; then
         >&2 echo "ERROR: Uploaded size does not match! $up_size != $size"
         #git_delete_asset
         return 1
@@ -131,15 +157,20 @@ function git_safe_upload_to_pages(){
     return $?
 }
 
-function merge_package_json(){
+function merge_package_json {
     local jsonLink=$1
     local jsonOut=$2
     local old_json=$OUTPUT_DIR/oldJson.json
     local merged_json=$OUTPUT_DIR/mergedJson.json
+    local error_code=0
 
     echo "Downloading previous JSON $jsonLink ..."
     curl -L -o "$old_json" "https://github.com/$GITHUB_REPOSITORY/releases/download/$jsonLink?access_token=$GITHUB_TOKEN" 2>/dev/null
-    if [ $? -ne 0 ]; then echo "ERROR: Download Failed! $?"; exit 1; fi
+    error_code=$?
+    if [ $error_code -ne 0 ]; then
+        echo "ERROR: Download Failed! $error_code"
+        exit 1
+    fi
 
     echo "Creating new JSON ..."
     set +e
@@ -147,7 +178,7 @@ function merge_package_json(){
     set -e
 
     set -v
-    if [ ! -s $merged_json ]; then
+    if [ ! -s "$merged_json" ]; then
         rm -f "$merged_json"
         echo "Nothing to merge"
     else
@@ -188,9 +219,10 @@ else
     done
     # Copy only relevant variant files
     mkdir "$PKG_DIR/variants/"
-    for variant in `cat ${PKG_DIR}/boards.txt | grep "\.variant=" | cut -d= -f2` ; do
+    board_list=$(cat "${PKG_DIR}"/boards.txt | grep "\.variant=" | cut -d= -f2)
+    while IFS= read -r variant; do
         cp -Rf "$GITHUB_WORKSPACE/variants/${variant}"      "$PKG_DIR/variants/"
-    done
+    done <<< "$board_list"
 fi
 cp -f  "$GITHUB_WORKSPACE/CMakeLists.txt"                   "$PKG_DIR/"
 cp -f  "$GITHUB_WORKSPACE/idf_component.yml"                "$PKG_DIR/"
@@ -219,12 +251,8 @@ find "$PKG_DIR" -name '*.git*' -type f -delete
 ##
 RVTC_NAME="riscv32-esp-elf-gcc"
 RVTC_NEW_NAME="esp-rv32"
-X32TC_NAME="xtensa-esp32-elf-gcc"
+X32TC_NAME="xtensa-esp-elf-gcc"
 X32TC_NEW_NAME="esp-x32"
-XS2TC_NAME="xtensa-esp32s2-elf-gcc"
-XS2TC_NEW_NAME="esp-xs2"
-XS3TC_NAME="xtensa-esp32s3-elf-gcc"
-XS3TC_NEW_NAME="esp-xs3"
 
 # Replace tools locations in platform.txt
 echo "Generating platform.txt..."
@@ -233,40 +261,40 @@ sed "s/version=.*/version=$RELEASE_TAG/g" | \
 sed 's/tools\.esp32-arduino-libs\.path\.windows=.*//g' | \
 sed 's/{runtime\.platform\.path}.tools.esp32-arduino-libs/\{runtime.tools.esp32-arduino-libs.path\}/g' | \
 sed 's/{runtime\.platform\.path}.tools.xtensa-esp-elf-gdb/\{runtime.tools.xtensa-esp-elf-gdb.path\}/g' | \
-sed "s/{runtime\.platform\.path}.tools.xtensa-esp32-elf/\\{runtime.tools.$X32TC_NEW_NAME.path\\}/g" | \
-sed "s/{runtime\.platform\.path}.tools.xtensa-esp32s2-elf/\\{runtime.tools.$XS2TC_NEW_NAME.path\\}/g" | \
-sed "s/{runtime\.platform\.path}.tools.xtensa-esp32s3-elf/\\{runtime.tools.$XS3TC_NEW_NAME.path\\}/g" | \
+sed "s/{runtime\.platform\.path}.tools.xtensa-esp-elf/\\{runtime.tools.$X32TC_NEW_NAME.path\\}/g" | \
 sed 's/{runtime\.platform\.path}.tools.riscv32-esp-elf-gdb/\{runtime.tools.riscv32-esp-elf-gdb.path\}/g' | \
 sed "s/{runtime\.platform\.path}.tools.riscv32-esp-elf/\\{runtime.tools.$RVTC_NEW_NAME.path\\}/g" | \
 sed 's/{runtime\.platform\.path}.tools.esptool/\{runtime.tools.esptool_py.path\}/g' | \
-sed 's/{runtime\.platform\.path}.tools.openocd-esp32/\{runtime.tools.openocd-esp32.path\}/g' \
- > "$PKG_DIR/platform.txt"
+sed 's/{runtime\.platform\.path}.tools.openocd-esp32/\{runtime.tools.openocd-esp32.path\}/g' > "$PKG_DIR/platform.txt"
 
-if ! [ -z ${VENDOR} ]; then
+if [ -n "${VENDOR}" ]; then
     # Append vendor name to platform.txt to create a separate section
     sed -i  "/^name=.*/s/$/ ($VENDOR)/" "$PKG_DIR/platform.txt"
 fi
 
 # Add header with version information
 echo "Generating core_version.h ..."
-ver_define=`echo $RELEASE_TAG | tr "[:lower:].\055" "[:upper:]_"`
-ver_hex=`git -C "$GITHUB_WORKSPACE" rev-parse --short=8 HEAD 2>/dev/null`
-echo \#define ARDUINO_ESP32_GIT_VER 0x$ver_hex > "$PKG_DIR/cores/esp32/core_version.h"
-echo \#define ARDUINO_ESP32_GIT_DESC `git -C "$GITHUB_WORKSPACE" describe --tags 2>/dev/null` >> "$PKG_DIR/cores/esp32/core_version.h"
-echo \#define ARDUINO_ESP32_RELEASE_$ver_define >> "$PKG_DIR/cores/esp32/core_version.h"
-echo \#define ARDUINO_ESP32_RELEASE \"$ver_define\" >> "$PKG_DIR/cores/esp32/core_version.h"
+ver_define=$(echo "$RELEASE_TAG" | tr "[:lower:].\055" "[:upper:]_")
+ver_hex=$(git -C "$GITHUB_WORKSPACE" rev-parse --short=8 HEAD 2>/dev/null)
+echo \#define ARDUINO_ESP32_GIT_VER 0x"$ver_hex" > "$PKG_DIR/cores/esp32/core_version.h"
+echo \#define ARDUINO_ESP32_GIT_DESC "$(git -C "$GITHUB_WORKSPACE" describe --tags 2>/dev/null)" >> "$PKG_DIR/cores/esp32/core_version.h"
+echo \#define ARDUINO_ESP32_RELEASE_"$ver_define" >> "$PKG_DIR/cores/esp32/core_version.h"
+echo \#define ARDUINO_ESP32_RELEASE \""$ver_define"\" >> "$PKG_DIR/cores/esp32/core_version.h"
 
 # Compress package folder
 echo "Creating ZIP ..."
 pushd "$OUTPUT_DIR" >/dev/null
 zip -qr "$PACKAGE_ZIP" "$PACKAGE_NAME"
-if [ $? -ne 0 ]; then echo "ERROR: Failed to create $PACKAGE_ZIP ($?)"; exit 1; fi
+if [ $? -ne 0 ]; then
+    echo "ERROR: Failed to create $PACKAGE_ZIP ($?)"
+    exit 1
+fi
 
 # Calculate SHA-256
 echo "Calculating SHA sum ..."
 PACKAGE_PATH="$OUTPUT_DIR/$PACKAGE_ZIP"
-PACKAGE_SHA=`shasum -a 256 "$PACKAGE_ZIP" | cut -f 1 -d ' '`
-PACKAGE_SIZE=`get_file_size "$PACKAGE_ZIP"`
+PACKAGE_SHA=$(shasum -a 256 "$PACKAGE_ZIP" | cut -f 1 -d ' ')
+PACKAGE_SIZE=$(get_file_size "$PACKAGE_ZIP")
 popd >/dev/null
 rm -rf "$PKG_DIR"
 echo "'$PACKAGE_ZIP' Created! Size: $PACKAGE_SIZE, SHA-256: $PACKAGE_SHA"
@@ -274,7 +302,7 @@ echo
 
 # Upload package to release page
 echo "Uploading package to release page ..."
-PACKAGE_URL=`git_safe_upload_asset "$PACKAGE_PATH"`
+PACKAGE_URL=$(git_safe_upload_asset "$PACKAGE_PATH")
 echo "Package Uploaded"
 echo "Download URL: $PACKAGE_URL"
 echo
@@ -282,9 +310,9 @@ echo
 ##
 ## TEMP WORKAROUND FOR RV32 LONG PATH ON WINDOWS
 ##
-RVTC_VERSION=`cat $PACKAGE_JSON_TEMPLATE | jq -r ".packages[0].platforms[0].toolsDependencies[] | select(.name == \"$RVTC_NAME\") | .version" | cut -d '_' -f 2`
+RVTC_VERSION=$(cat "$PACKAGE_JSON_TEMPLATE" | jq -r ".packages[0].platforms[0].toolsDependencies[] | select(.name == \"$RVTC_NAME\") | .version" | cut -d '_' -f 2)
 # RVTC_VERSION=`date -j -f '%Y%m%d' "$RVTC_VERSION" '+%y%m'` # MacOS
-RVTC_VERSION=`date -d "$RVTC_VERSION" '+%y%m'`
+RVTC_VERSION=$(date -d "$RVTC_VERSION" '+%y%m')
 rvtc_jq_arg="\
     (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$RVTC_NAME\")).version = \"$RVTC_VERSION\" |\
     (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$RVTC_NAME\")).name = \"$RVTC_NEW_NAME\" |\
@@ -293,15 +321,7 @@ rvtc_jq_arg="\
     (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$X32TC_NAME\")).version = \"$RVTC_VERSION\" |\
     (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$X32TC_NAME\")).name = \"$X32TC_NEW_NAME\" |\
     (.packages[0].tools[] | select(.name==\"$X32TC_NAME\")).version = \"$RVTC_VERSION\" |\
-    (.packages[0].tools[] | select(.name==\"$X32TC_NAME\")).name = \"$X32TC_NEW_NAME\" |\
-    (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS2TC_NAME\")).version = \"$RVTC_VERSION\" |\
-    (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS2TC_NAME\")).name = \"$XS2TC_NEW_NAME\" |\
-    (.packages[0].tools[] | select(.name==\"$XS2TC_NAME\")).version = \"$RVTC_VERSION\" |\
-    (.packages[0].tools[] | select(.name==\"$XS2TC_NAME\")).name = \"$XS2TC_NEW_NAME\" |\
-    (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS3TC_NAME\")).version = \"$RVTC_VERSION\" |\
-    (.packages[0].platforms[0].toolsDependencies[] | select(.name==\"$XS3TC_NAME\")).name = \"$XS3TC_NEW_NAME\" |\
-    (.packages[0].tools[] | select(.name==\"$XS3TC_NAME\")).version = \"$RVTC_VERSION\" |\
-    (.packages[0].tools[] | select(.name==\"$XS3TC_NAME\")).name = \"$XS3TC_NEW_NAME\""
+    (.packages[0].tools[] | select(.name==\"$X32TC_NAME\")).name = \"$X32TC_NEW_NAME\""
 cat "$PACKAGE_JSON_TEMPLATE" | jq "$rvtc_jq_arg" > "$OUTPUT_DIR/package-rvfix.json"
 PACKAGE_JSON_TEMPLATE="$OUTPUT_DIR/package-rvfix.json"
 
@@ -317,17 +337,20 @@ jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \
     .packages[0].platforms[0].checksum = \"SHA-256:$PACKAGE_SHA\""
 
 # Generate package JSONs
-echo "Genarating $PACKAGE_JSON_DEV ..."
+echo "Generating $PACKAGE_JSON_DEV ..."
 cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV"
 if [ "$RELEASE_PRE" == "false" ]; then
-    echo "Genarating $PACKAGE_JSON_REL ..."
+    echo "Generating $PACKAGE_JSON_REL ..."
     cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL"
 fi
 
 # Figure out the last release or pre-release
 echo "Getting previous releases ..."
-releasesJson=`curl -sH "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$GITHUB_REPOSITORY/releases" 2>/dev/null`
-if [ $? -ne 0 ]; then echo "ERROR: Get Releases Failed! ($?)"; exit 1; fi
+releasesJson=$(curl -sH "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$GITHUB_REPOSITORY/releases" 2>/dev/null)
+if [ $? -ne 0 ]; then
+    echo "ERROR: Get Releases Failed! ($?)"
+    exit 1
+fi
 
 set +e
 prev_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false)) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name")
@@ -347,13 +370,13 @@ echo "Previous (any)release: $prev_any_release"
 echo
 
 # Merge package JSONs with previous releases
-if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then
+if [ -n "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then
     echo "Merging with JSON from $prev_any_release ..."
     merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV"
 fi
 
 if [ "$RELEASE_PRE" == "false" ]; then
-    if [ ! -z "$prev_release" ] && [ "$prev_release" != "null" ]; then
+    if [ -n "$prev_release" ] && [ "$prev_release" != "null" ]; then
         echo "Merging with JSON from $prev_release ..."
         merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL"
     fi
@@ -363,21 +386,30 @@ fi
 
 echo "Installing arduino-cli ..."
 export PATH="/home/runner/bin:$PATH"
-source ./.github/scripts/install-arduino-cli.sh
+source "${SCRIPTS_DIR}/install-arduino-cli.sh"
 
 echo "Testing $PACKAGE_JSON_DEV install ..."
 
 echo "Installing esp32 ..."
 arduino-cli core install esp32:esp32 --additional-urls "file://$OUTPUT_DIR/$PACKAGE_JSON_DEV"
-if [ $? -ne 0 ]; then echo "ERROR: Failed to install esp32 ($?)"; exit 1; fi
+if [ $? -ne 0 ]; then
+    echo "ERROR: Failed to install esp32 ($?)"
+    exit 1
+fi
 
 echo "Compiling example ..."
-arduino-cli compile --fqbn esp32:esp32:esp32 $GITHUB_WORKSPACE/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino
-if [ $? -ne 0 ]; then echo "ERROR: Failed to compile example ($?)"; exit 1; fi
+arduino-cli compile --fqbn esp32:esp32:esp32 "$GITHUB_WORKSPACE"/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino
+if [ $? -ne 0 ]; then
+    echo "ERROR: Failed to compile example ($?)"
+    exit 1
+fi
 
 echo "Uninstalling esp32 ..."
 arduino-cli core uninstall esp32:esp32
-if [ $? -ne 0 ]; then echo "ERROR: Failed to uninstall esp32 ($?)"; exit 1; fi
+if [ $? -ne 0 ]; then
+    echo "ERROR: Failed to uninstall esp32 ($?)"
+    exit 1
+fi
 
 echo "Test successful!"
 
@@ -386,15 +418,24 @@ if [ "$RELEASE_PRE" == "false" ]; then
 
     echo "Installing esp32 ..."
     arduino-cli core install esp32:esp32 --additional-urls "file://$OUTPUT_DIR/$PACKAGE_JSON_REL"
-    if [ $? -ne 0 ]; then echo "ERROR: Failed to install esp32 ($?)"; exit 1; fi
+    if [ $? -ne 0 ]; then
+        echo "ERROR: Failed to install esp32 ($?)"
+        exit 1
+    fi
 
     echo "Compiling example ..."
-    arduino-cli compile --fqbn esp32:esp32:esp32 $GITHUB_WORKSPACE/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino
-    if [ $? -ne 0 ]; then echo "ERROR: Failed to compile example ($?)"; exit 1; fi
+    arduino-cli compile --fqbn esp32:esp32:esp32 "$GITHUB_WORKSPACE"/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino
+    if [ $? -ne 0 ]; then
+        echo "ERROR: Failed to compile example ($?)"
+        exit 1
+    fi
 
     echo "Uninstalling esp32 ..."
     arduino-cli core uninstall esp32:esp32
-    if [ $? -ne 0 ]; then echo "ERROR: Failed to uninstall esp32 ($?)"; exit 1; fi
+    if [ $? -ne 0 ]; then
+        echo "ERROR: Failed to uninstall esp32 ($?)"
+        exit 1
+    fi
 
     echo "Test successful!"
 fi
@@ -402,13 +443,13 @@ fi
 # Upload package JSONs
 
 echo "Uploading $PACKAGE_JSON_DEV ..."
-echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV"`
-echo "Pages URL: "`git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV"`
+echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV")"
+echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV")"
 echo
 if [ "$RELEASE_PRE" == "false" ]; then
     echo "Uploading $PACKAGE_JSON_REL ..."
-    echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL"`
-    echo "Pages URL: "`git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL"`
+    echo "Download URL: $(git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL")"
+    echo "Pages URL: $(git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL")"
     echo
 fi
 
diff --git a/.github/scripts/set_push_chunks.sh b/.github/scripts/set_push_chunks.sh
index 11a93a7159d..047cae6efd8 100644
--- a/.github/scripts/set_push_chunks.sh
+++ b/.github/scripts/set_push_chunks.sh
@@ -11,23 +11,23 @@ elif [[ $LIB_CHANGED == 'true' ]]; then
     echo "Libraries changed. Building only affected sketches."
     if [[ $NETWORKING_CHANGED == 'true' ]]; then
         echo "Networking libraries changed. Building networking related sketches."
-        networking_sketches="$(find libraries/WiFi -name *.ino) "
-        networking_sketches+="$(find libraries/Ethernet -name *.ino) "
-        networking_sketches+="$(find libraries/PPP -name *.ino) "
-        networking_sketches+="$(find libraries/NetworkClientSecure -name *.ino) "
-        networking_sketches+="$(find libraries/WebServer -name *.ino) "
+        networking_sketches="$(find libraries/WiFi -name '*.ino') "
+        networking_sketches+="$(find libraries/Ethernet -name '*.ino') "
+        networking_sketches+="$(find libraries/PPP -name '*.ino') "
+        networking_sketches+="$(find libraries/NetworkClientSecure -name '*.ino') "
+        networking_sketches+="$(find libraries/WebServer -name '*.ino') "
     fi
     if [[ $FS_CHANGED == 'true' ]]; then
         echo "FS libraries changed. Building FS related sketches."
-        fs_sketches="$(find libraries/SD -name *.ino) "
-        fs_sketches+="$(find libraries/SD_MMC -name *.ino) "
-        fs_sketches+="$(find libraries/SPIFFS -name *.ino) "
-        fs_sketches+="$(find libraries/LittleFS -name *.ino) "
-        fs_sketches+="$(find libraries/FFat -name *.ino) "
+        fs_sketches="$(find libraries/SD -name '*.ino') "
+        fs_sketches+="$(find libraries/SD_MMC -name '*.ino') "
+        fs_sketches+="$(find libraries/SPIFFS -name '*.ino') "
+        fs_sketches+="$(find libraries/LittleFS -name '*.ino') "
+        fs_sketches+="$(find libraries/FFat -name '*.ino') "
     fi
     sketches="$networking_sketches $fs_sketches"
     for file in $LIB_FILES; do
-        lib=$(echo $file | awk -F "/" '{print $1"/"$2}')
+        lib=$(echo "$file" | awk -F "/" '{print $1"/"$2}')
         if [[ "$file" == *.ino ]]; then
             # If file ends with .ino, add it to the list of sketches
             echo "Sketch found: $file"
@@ -36,14 +36,14 @@ elif [[ $LIB_CHANGED == 'true' ]]; then
             # If file is inside the src directory, find all sketches in the lib/examples directory
             echo "Library src file found: $file"
             if [[ -d $lib/examples ]]; then
-                lib_sketches=$(find $lib/examples -name *.ino)
+                lib_sketches=$(find "$lib"/examples -name '*.ino')
                 sketches+="$lib_sketches "
                 echo "Library sketches: $lib_sketches"
             fi
         else
             # If file is in a example folder but it is not a sketch, find all sketches in the current directory
             echo "File in example folder found: $file"
-            sketch=$(find $(dirname $file) -name *.ino)
+            sketch=$(find "$(dirname "$file")" -name '*.ino')
             sketches+="$sketch "
             echo "Sketch in example folder: $sketch"
         fi
@@ -53,9 +53,9 @@ fi
 
 if [[ -n $sketches ]]; then
     # Remove duplicates
-    sketches=$(echo $sketches | tr ' ' '\n' | sort | uniq)
+    sketches=$(echo "$sketches" | tr ' ' '\n' | sort | uniq)
     for sketch in $sketches; do
-        echo $sketch >> sketches_found.txt
+        echo "$sketch" >> sketches_found.txt
         chunks_count=$((chunks_count+1))
     done
     echo "Number of sketches found: $chunks_count"
@@ -69,15 +69,17 @@ if [[ -n $sketches ]]; then
 fi
 
 chunks='["0"'
-for i in $(seq 1 $(( $chunks_count - 1 )) ); do
+for i in $(seq 1 $(( chunks_count - 1 )) ); do
     chunks+=",\"$i\""
 done
 chunks+="]"
 
-echo "build_all=$build_all" >> $GITHUB_OUTPUT
-echo "build_libraries=$BUILD_LIBRARIES" >> $GITHUB_OUTPUT
-echo "build_static_sketches=$BUILD_STATIC_SKETCHES" >> $GITHUB_OUTPUT
-echo "build_idf=$BUILD_IDF" >> $GITHUB_OUTPUT
-echo "build_platformio=$BUILD_PLATFORMIO" >> $GITHUB_OUTPUT
-echo "chunk_count=$chunks_count" >> $GITHUB_OUTPUT
-echo "chunks=$chunks" >> $GITHUB_OUTPUT
+{
+    echo "build_all=$build_all"
+    echo "build_libraries=$BUILD_LIBRARIES"
+    echo "build_static_sketches=$BUILD_STATIC_SKETCHES"
+    echo "build_idf=$BUILD_IDF"
+    echo "build_platformio=$BUILD_PLATFORMIO"
+    echo "chunk_count=$chunks_count"
+    echo "chunks=$chunks"
+} >> "$GITHUB_OUTPUT"
diff --git a/.github/scripts/sketch_utils.sh b/.github/scripts/sketch_utils.sh
index e2b2ec0b269..3e6ceb675e9 100755
--- a/.github/scripts/sketch_utils.sh
+++ b/.github/scripts/sketch_utils.sh
@@ -8,10 +8,12 @@ else
     SDKCONFIG_DIR="tools/esp32-arduino-libs"
 fi
 
-function check_requirements(){ # check_requirements <sketchdir> <sdkconfig_path>
+function check_requirements { # check_requirements <sketchdir> <sdkconfig_path>
     local sketchdir=$1
     local sdkconfig_path=$2
     local has_requirements=1
+    local requirements
+    local requirements_or
 
     if [ ! -f "$sdkconfig_path" ] || [ ! -f "$sketchdir/ci.json" ]; then
         echo "ERROR: sdkconfig or ci.json not found" 1>&2
@@ -19,10 +21,10 @@ function check_requirements(){ # check_requirements <sketchdir> <sdkconfig_path>
         # CI will fail and the user will know that the sketch has a problem.
     else
         # Check if the sketch requires any configuration options (AND)
-        local requirements=$(jq -r '.requires[]? // empty' "$sketchdir/ci.json")
+        requirements=$(jq -r '.requires[]? // empty' "$sketchdir/ci.json")
         if [[ "$requirements" != "null" && "$requirements" != "" ]]; then
             for requirement in $requirements; do
-                requirement=$(echo $requirement | xargs)
+                requirement=$(echo "$requirement" | xargs)
                 found_line=$(grep -E "^$requirement" "$sdkconfig_path")
                 if [[ "$found_line" == "" ]]; then
                     has_requirements=0
@@ -31,11 +33,11 @@ function check_requirements(){ # check_requirements <sketchdir> <sdkconfig_path>
         fi
 
         # Check if the sketch requires any configuration options (OR)
-        local requirements_or=$(jq -r '.requires_any[]? // empty' "$sketchdir/ci.json")
+        requirements_or=$(jq -r '.requires_any[]? // empty' "$sketchdir/ci.json")
         if [[ "$requirements_or" != "null" && "$requirements_or" != "" ]]; then
             local found=false
             for requirement in $requirements_or; do
-                requirement=$(echo $requirement | xargs)
+                requirement=$(echo "$requirement" | xargs)
                 found_line=$(grep -E "^$requirement" "$sdkconfig_path")
                 if [[ "$found_line" != "" ]]; then
                     found=true
@@ -51,8 +53,8 @@ function check_requirements(){ # check_requirements <sketchdir> <sdkconfig_path>
     echo $has_requirements
 }
 
-function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [extra-options]
-    while [ ! -z "$1" ]; do
+function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [extra-options]
+    while [ -n "$1" ]; do
         case "$1" in
         -ai )
             shift
@@ -97,10 +99,10 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
         shift
     done
 
-    xtra_opts=$*
+    xtra_opts=("$@")
     len=0
 
-    if [ -z $sketchdir ]; then
+    if [ -z "$sketchdir" ]; then
         echo "ERROR: Sketch directory not provided"
         echo "$USAGE"
         exit 1
@@ -108,8 +110,8 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
 
     # No FQBN was passed, try to get it from other options
 
-    if [ -z $fqbn ]; then
-        if [ -z $target ]; then
+    if [ -z "$fqbn" ]; then
+        if [ -z "$target" ]; then
             echo "ERROR: Unspecified chip"
             echo "$USAGE"
             exit 1
@@ -120,25 +122,25 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
         # precedence.  Note that the following logic also falls to the default
         # parameters if no arguments were passed and no file was found.
 
-        if [ -z $options ] && [ -f $sketchdir/ci.json ]; then
+        if [ -z "$options" ] && [ -f "$sketchdir"/ci.json ]; then
             # The config file could contain multiple FQBNs for one chip.  If
             # that's the case we build one time for every FQBN.
 
-            len=`jq -r --arg target $target '.fqbn[$target] | length' $sketchdir/ci.json`
-            if [ $len -gt 0 ]; then
-                fqbn=`jq -r --arg target $target '.fqbn[$target] | sort' $sketchdir/ci.json`
+            len=$(jq -r --arg target "$target" '.fqbn[$target] | length' "$sketchdir"/ci.json)
+            if [ "$len" -gt 0 ]; then
+                fqbn=$(jq -r --arg target "$target" '.fqbn[$target] | sort' "$sketchdir"/ci.json)
             fi
         fi
 
-        if [ ! -z $options ] || [ $len -eq 0 ]; then
+        if [ -n "$options" ] || [ "$len" -eq 0 ]; then
             # Since we are passing options, we will end up with only one FQBN to
             # build.
 
             len=1
 
-            if [ -f $sketchdir/ci.json ]; then
-                fqbn_append=`jq -r '.fqbn_append' $sketchdir/ci.json`
-                if [ $fqbn_append == "null" ]; then
+            if [ -f "$sketchdir"/ci.json ]; then
+                fqbn_append=$(jq -r '.fqbn_append' "$sketchdir"/ci.json)
+                if [ "$fqbn_append" == "null" ]; then
                     fqbn_append=""
                 fi
             fi
@@ -153,6 +155,7 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
             esp32c3_opts=$(echo "$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g')
             esp32c6_opts=$(echo "$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g')
             esp32h2_opts=$(echo "$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g')
+            esp32p4_opts=$(echo "PSRAM=enabled,USBMode=default,$debug_level,$fqbn_append" | sed 's/^,*//;s/,*$//;s/,\{2,\}/,/g')
 
             # Select the common part of the FQBN based on the target.  The rest will be
             # appended depending on the passed options.
@@ -184,6 +187,14 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
                     [ -n "${options:-$esp32h2_opts}" ] && opt=":${options:-$esp32h2_opts}"
                     fqbn="espressif:esp32:esp32h2$opt"
                 ;;
+                "esp32p4")
+                    [ -n "${options:-$esp32p4_opts}" ] && opt=":${options:-$esp32p4_opts}"
+                    fqbn="espressif:esp32:esp32p4$opt"
+                ;;
+                *)
+                    echo "ERROR: Invalid chip: $target"
+                    exit 1
+                ;;
             esac
 
             # Make it look like a JSON array.
@@ -202,7 +213,7 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
         exit 1
     fi
 
-    # The directory that will hold all the artifcats (the build directory) is
+    # The directory that will hold all the artifacts (the build directory) is
     # provided through:
     #  1. An env variable called ARDUINO_BUILD_DIR.
     #  2. Created at the sketch level as "build" in the case of a single
@@ -210,17 +221,18 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
     #  3. Created at the sketch level as "buildX" where X is the number
     #     of configuration built in case of a multiconfiguration test.
 
-    sketchname=$(basename $sketchdir)
+    sketchname=$(basename "$sketchdir")
+    local has_requirements
 
-    if [ -f $sketchdir/ci.json ]; then
+    if [ -f "$sketchdir"/ci.json ]; then
         # If the target is listed as false, skip the sketch. Otherwise, include it.
-        is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json)
+        is_target=$(jq -r --arg target "$target" '.targets[$target]' "$sketchdir"/ci.json)
         if [[ "$is_target" == "false" ]]; then
             echo "Skipping $sketchname for target $target"
             exit 0
         fi
 
-        local has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig")
+        has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig")
         if [ "$has_requirements" == "0" ]; then
             echo "Target $target does not meet the requirements for $sketchname. Skipping."
             exit 0
@@ -230,7 +242,7 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
     ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
     if [ -n "$ARDUINO_BUILD_DIR" ]; then
         build_dir="$ARDUINO_BUILD_DIR"
-    elif [ $len -eq 1 ]; then
+    elif [ "$len" -eq 1 ]; then
         # build_dir="$sketchdir/build"
         build_dir="$HOME/.arduino/tests/$sketchname/build.tmp"
     fi
@@ -239,51 +251,49 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
     sizes_file="$GITHUB_WORKSPACE/cli_compile_$chunk_index.json"
 
     mkdir -p "$ARDUINO_CACHE_DIR"
-    for i in `seq 0 $(($len - 1))`
-    do
-        if [ $len -ne 1 ]; then
-          # build_dir="$sketchdir/build$i"
-          build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp"
+    for i in $(seq 0 $((len - 1))); do
+        if [ "$len" -ne 1 ]; then
+            # build_dir="$sketchdir/build$i"
+            build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp"
         fi
-        rm -rf $build_dir
-        mkdir -p $build_dir
+        rm -rf "$build_dir"
+        mkdir -p "$build_dir"
 
-        currfqbn=`echo $fqbn | jq -r --argjson i $i '.[$i]'`
+        currfqbn=$(echo "$fqbn" | jq -r --argjson i "$i" '.[$i]')
 
         if [ -f "$ide_path/arduino-cli" ]; then
             echo "Building $sketchname with arduino-cli and FQBN=$currfqbn"
 
-            curroptions=`echo "$currfqbn" | cut -d':' -f4`
-            currfqbn=`echo "$currfqbn" | cut -d':' -f1-3`
-            $ide_path/arduino-cli compile \
+            curroptions=$(echo "$currfqbn" | cut -d':' -f4)
+            currfqbn=$(echo "$currfqbn" | cut -d':' -f1-3)
+            "$ide_path"/arduino-cli compile \
                 --fqbn "$currfqbn" \
                 --board-options "$curroptions" \
                 --warnings "all" \
                 --build-property "compiler.warning_flags.all=-Wall -Werror=all -Wextra" \
-                --build-cache-path "$ARDUINO_CACHE_DIR" \
                 --build-path "$build_dir" \
-                $xtra_opts "${sketchdir}" \
-                2>&1 | tee $output_file
+                "${xtra_opts[@]}" "${sketchdir}" \
+                2>&1 | tee "$output_file"
 
             exit_status=${PIPESTATUS[0]}
-            if [ $exit_status -ne 0 ]; then
+            if [ "$exit_status" -ne 0 ]; then
                 echo "ERROR: Compilation failed with error code $exit_status"
-                exit $exit_status
+                exit "$exit_status"
             fi
 
-            if [ $log_compilation ]; then
+            if [ -n "$log_compilation" ]; then
                 #Extract the program storage space and dynamic memory usage in bytes and percentage in separate variables from the output, just the value without the string
-                flash_bytes=$(grep -oE 'Sketch uses ([0-9]+) bytes' $output_file | awk '{print $3}')
-                flash_percentage=$(grep -oE 'Sketch uses ([0-9]+) bytes \(([0-9]+)%\)' $output_file | awk '{print $5}' | tr -d '(%)')
-                ram_bytes=$(grep -oE 'Global variables use ([0-9]+) bytes' $output_file | awk '{print $4}')
-                ram_percentage=$(grep -oE 'Global variables use ([0-9]+) bytes \(([0-9]+)%\)' $output_file | awk '{print $6}' | tr -d '(%)')
+                flash_bytes=$(grep -oE 'Sketch uses ([0-9]+) bytes' "$output_file" | awk '{print $3}')
+                flash_percentage=$(grep -oE 'Sketch uses ([0-9]+) bytes \(([0-9]+)%\)' "$output_file" | awk '{print $5}' | tr -d '(%)')
+                ram_bytes=$(grep -oE 'Global variables use ([0-9]+) bytes' "$output_file" | awk '{print $4}')
+                ram_percentage=$(grep -oE 'Global variables use ([0-9]+) bytes \(([0-9]+)%\)' "$output_file" | awk '{print $6}' | tr -d '(%)')
 
                 # Extract the directory path excluding the filename
                 directory_path=$(dirname "$sketch")
                 # Define the constant part
                 constant_part="/home/runner/Arduino/hardware/espressif/esp32/libraries/"
-                # Extract the desired substring using sed
-                lib_sketch_name=$(echo "$directory_path" | sed "s|$constant_part||")
+                # Extract the desired substring
+                lib_sketch_name="${directory_path#"$constant_part"}"
                 #append json file where key is fqbn, sketch name, sizes -> extracted values
                 echo "{\"name\": \"$lib_sketch_name\",
                     \"sizes\": [{
@@ -299,15 +309,15 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
             echo "Building $sketchname with arduino-builder and FQBN=$currfqbn"
             echo "Build path = $build_dir"
 
-            $ide_path/arduino-builder -compile -logger=human -core-api-version=10810 \
-                -fqbn=\"$currfqbn\" \
+            "$ide_path"/arduino-builder -compile -logger=human -core-api-version=10810 \
+                -fqbn=\""$currfqbn"\" \
                 -warnings="all" \
                 -tools "$ide_path/tools-builder" \
                 -hardware "$user_path/hardware" \
                 -libraries "$user_path/libraries" \
                 -build-cache "$ARDUINO_CACHE_DIR" \
                 -build-path "$build_dir" \
-                $xtra_opts "${sketchdir}/${sketchname}.ino"
+                "${xtra_opts[@]}" "${sketchdir}/${sketchname}.ino"
 
             exit_status=$?
             if [ $exit_status -ne 0 ]; then
@@ -334,15 +344,16 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
     unset options
 }
 
-function count_sketches(){ # count_sketches <path> [target] [file] [ignore-requirements]
+function count_sketches { # count_sketches <path> [target] [file] [ignore-requirements]
     local path=$1
     local target=$2
     local ignore_requirements=$3
     local file=$4
+    local sketches
 
     if [ $# -lt 1 ]; then
-      echo "ERROR: Illegal number of parameters"
-      echo "USAGE: ${0} count <path> [target]"
+        echo "ERROR: Illegal number of parameters"
+        echo "USAGE: ${0} count <path> [target]"
     fi
 
     rm -rf sketches.txt
@@ -352,42 +363,47 @@ function count_sketches(){ # count_sketches <path> [target] [file] [ignore-requi
     fi
 
     if [ -f "$file" ]; then
-        local sketches=$(cat $file)
+        sketches=$(cat "$file")
     else
-        local sketches=$(find $path -name *.ino | sort)
+        sketches=$(find "$path" -name '*.ino' | sort)
     fi
 
     local sketchnum=0
     for sketch in $sketches; do
-        local sketchdir=$(dirname $sketch)
-        local sketchdirname=$(basename $sketchdir)
-        local sketchname=$(basename $sketch)
+        local sketchdir
+        local sketchdirname
+        local sketchname
+        local has_requirements
+
+        sketchdir=$(dirname "$sketch")
+        sketchdirname=$(basename "$sketchdir")
+        sketchname=$(basename "$sketch")
+
         if [[ "$sketchdirname.ino" != "$sketchname" ]]; then
             continue
         elif [[ -n $target ]] && [[ -f $sketchdir/ci.json ]]; then
             # If the target is listed as false, skip the sketch. Otherwise, include it.
-            is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json)
+            is_target=$(jq -r --arg target "$target" '.targets[$target]' "$sketchdir"/ci.json)
             if [[ "$is_target" == "false" ]]; then
                 continue
             fi
 
             if [ "$ignore_requirements" != "1" ]; then
-                local has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig")
+                has_requirements=$(check_requirements "$sketchdir" "$SDKCONFIG_DIR/$target/sdkconfig")
                 if [ "$has_requirements" == "0" ]; then
                     continue
                 fi
             fi
         fi
-        echo $sketch >> sketches.txt
-        sketchnum=$(($sketchnum + 1))
+        echo "$sketch" >> sketches.txt
+        sketchnum=$((sketchnum + 1))
     done
     return $sketchnum
 }
 
-function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <path> <chunk> <total-chunks> [extra-options]
-
-    local args=""
-    while [ ! -z "$1" ]; do
+function build_sketches { # build_sketches <ide_path> <user_path> <target> <path> <chunk> <total-chunks> [extra-options]
+    local args=()
+    while [ -n "$1" ]; do
         case $1 in
         -ai )
             shift
@@ -400,12 +416,12 @@ function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <pat
         -t )
             shift
             target=$1
-            args+=" -t $target"
+            args+=("-t" "$target")
             ;;
         -fqbn )
             shift
             fqbn=$1
-            args+=" -fqbn $fqbn"
+            args+=("-fqbn" "$fqbn")
             ;;
         -p )
             shift
@@ -434,10 +450,10 @@ function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <pat
         shift
     done
 
-    local xtra_opts=$*
+    local xtra_opts=("$@")
 
     if [ -z "$chunk_index" ] || [ -z "$chunk_max" ]; then
-        echo "ERROR: Invalid chunk paramters"
+        echo "ERROR: Invalid chunk parameters"
         echo "$USAGE"
         exit 1
     fi
@@ -460,13 +476,16 @@ function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <pat
         local sketchcount=$?
     fi
     set -e
-    local sketches=$(cat sketches.txt)
+    local sketches
+    sketches=$(cat sketches.txt)
     rm -rf sketches.txt
 
-    local chunk_size=$(( $sketchcount / $chunk_max ))
-    local all_chunks=$(( $chunk_max * $chunk_size ))
+    local chunk_size
+    local all_chunks
+    chunk_size=$(( sketchcount / chunk_max ))
+    all_chunks=$(( chunk_max * chunk_size ))
     if [ "$all_chunks" -lt "$sketchcount" ]; then
-        chunk_size=$(( $chunk_size + 1 ))
+        chunk_size=$(( chunk_size + 1 ))
     fi
 
     local start_index=0
@@ -475,19 +494,20 @@ function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <pat
         start_index=$chunk_index
         end_index=$sketchcount
     else
-        start_index=$(( $chunk_index * $chunk_size ))
+        start_index=$(( chunk_index * chunk_size ))
         if [ "$sketchcount" -le "$start_index" ]; then
             echo "No sketches to build for $target in this chunk"
             return 0
         fi
 
-        end_index=$(( $(( $chunk_index + 1 )) * $chunk_size ))
+        end_index=$(( $(( chunk_index + 1 )) * chunk_size ))
         if [ "$end_index" -gt "$sketchcount" ]; then
             end_index=$sketchcount
         fi
     fi
 
-    local start_num=$(( $start_index + 1 ))
+    local start_num
+    start_num=$(( start_index + 1 ))
     echo "Found $sketchcount Sketches for target '$target'";
     echo "Chunk Index : $chunk_index"
     echo "Chunk Count : $chunk_max"
@@ -496,14 +516,14 @@ function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <pat
     echo "End Sketch  : $end_index"
 
     #if fqbn is not passed then set it to default for compilation log
-    if [ -z $fqbn ]; then
+    if [ -z "$fqbn" ]; then
         log_fqbn="espressif:esp32:$target"
     else
         log_fqbn=$fqbn
     fi
 
     sizes_file="$GITHUB_WORKSPACE/cli_compile_$chunk_index.json"
-    if [ $log_compilation ]; then
+    if [ -n "$log_compilation" ]; then
         #echo board,target and start of sketches to sizes_file json
         echo "{ \"board\": \"$log_fqbn\",
                 \"target\": \"$target\",
@@ -511,30 +531,34 @@ function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <pat
     fi
 
     local sketchnum=0
-    args+=" -ai $ide_path -au $user_path -i $chunk_index"
-    if [ $log_compilation ]; then
-        args+=" -l $log_compilation"
+    args+=("-ai" "$ide_path" "-au" "$user_path" "-i" "$chunk_index")
+    if [ -n "$log_compilation" ]; then
+        args+=("-l" "$log_compilation")
     fi
     for sketch in $sketches; do
-        local sketchdir=$(dirname $sketch)
-        local sketchdirname=$(basename $sketchdir)
-        sketchnum=$(($sketchnum + 1))
+        local sketchdir
+        local sketchdirname
+
+        sketchdir=$(dirname "$sketch")
+        sketchdirname=$(basename "$sketchdir")
+        sketchnum=$((sketchnum + 1))
+
         if [ "$sketchnum" -le "$start_index" ] \
         || [ "$sketchnum" -gt "$end_index" ]; then
             continue
         fi
         echo ""
         echo "Building Sketch Index $sketchnum - $sketchdirname"
-        build_sketch $args -s $sketchdir $xtra_opts
+        build_sketch "${args[@]}" -s "$sketchdir" "${xtra_opts[@]}"
         local result=$?
         if [ $result -ne 0 ]; then
             return $result
         fi
     done
 
-    if [ $log_compilation ]; then
+    if [ -n "$log_compilation" ]; then
         #remove last comma from json
-        if [ $i -eq $(($len - 1)) ]; then
+        if [ "$i" -eq $((len - 1)) ]; then
             sed -i '$ s/.$//' "$sizes_file"
         fi
         #echo end of sketches sizes_file json
@@ -549,28 +573,28 @@ function build_sketches(){ # build_sketches <ide_path> <user_path> <target> <pat
 USAGE="
 USAGE: ${0} [command] [options]
 Available commands:
-  count: Count sketches.
-  build: Build a sketch.
-  chunk_build: Build a chunk of sketches.
-  check_requirements: Check if target meets sketch requirements.
+    count: Count sketches.
+    build: Build a sketch.
+    chunk_build: Build a chunk of sketches.
+    check_requirements: Check if target meets sketch requirements.
 "
 
 cmd=$1
 shift
-if [ -z $cmd ]; then
+if [ -z "$cmd" ]; then
     echo "ERROR: No command supplied"
     echo "$USAGE"
     exit 2
 fi
 
 case "$cmd" in
-    "count") count_sketches $*
+    "count") count_sketches "$@"
     ;;
-    "build") build_sketch $*
+    "build") build_sketch "$@"
     ;;
-    "chunk_build") build_sketches $*
+    "chunk_build") build_sketches "$@"
     ;;
-    "check_requirements") check_requirements $*
+    "check_requirements") check_requirements "$@"
     ;;
     *)
         echo "ERROR: Unrecognized command"
diff --git a/.github/scripts/tests_build.sh b/.github/scripts/tests_build.sh
index e843e5fdb2d..93342c83299 100755
--- a/.github/scripts/tests_build.sh
+++ b/.github/scripts/tests_build.sh
@@ -3,14 +3,14 @@
 USAGE="
 USAGE:
     ${0} -c -type <test_type> <chunk_build_opts>
-       Example: ${0} -c -type validation -t esp32 -i 0 -m 15
+        Example: ${0} -c -type validation -t esp32 -i 0 -m 15
     ${0} -s sketch_name <build_opts>
-       Example: ${0} -s hello_world -t esp32
+        Example: ${0} -s hello_world -t esp32
     ${0} -clean
-       Remove build and test generated files
+        Remove build and test generated files
 "
 
-function clean(){
+function clean {
     rm -rf tests/.pytest_cache
     find tests/ -type d -name 'build*' -exec rm -rf "{}" \+
     find tests/ -type d -name '__pycache__' -exec rm -rf "{}" \+
@@ -23,7 +23,7 @@ BUILD_CMD=""
 
 chunk_build=0
 
-while [ ! -z "$1" ]; do
+while [ -n "$1" ]; do
     case $1 in
     -c )
         chunk_build=1
@@ -45,25 +45,25 @@ while [ ! -z "$1" ]; do
         exit 0
         ;;
     * )
-      break
-      ;;
+        break
+        ;;
     esac
     shift
 done
 
-source ${SCRIPTS_DIR}/install-arduino-cli.sh
-source ${SCRIPTS_DIR}/install-arduino-core-esp32.sh
+source "${SCRIPTS_DIR}/install-arduino-cli.sh"
+source "${SCRIPTS_DIR}/install-arduino-core-esp32.sh"
 
-args="-ai $ARDUINO_IDE_PATH -au $ARDUINO_USR_PATH"
+args=("-ai" "$ARDUINO_IDE_PATH" "-au" "$ARDUINO_USR_PATH")
 
 if [[ $test_type == "all" ]] || [[ -z $test_type ]]; then
     if [ -n "$sketch" ]; then
-        tmp_sketch_path=$(find tests -name $sketch.ino)
-        test_type=$(basename $(dirname $(dirname "$tmp_sketch_path")))
+        tmp_sketch_path=$(find tests -name "$sketch".ino)
+        test_type=$(basename "$(dirname "$(dirname "$tmp_sketch_path")")")
         echo "Sketch $sketch test type: $test_type"
         test_folder="$PWD/tests/$test_type"
     else
-      test_folder="$PWD/tests"
+        test_folder="$PWD/tests"
     fi
 else
     test_folder="$PWD/tests/$test_type"
@@ -71,11 +71,10 @@ fi
 
 if [ $chunk_build -eq 1 ]; then
     BUILD_CMD="${SCRIPTS_DIR}/sketch_utils.sh chunk_build"
-    args+=" -p $test_folder -i 0 -m 1"
+    args+=("-p" "$test_folder" "-i" "0" "-m" "1")
 else
     BUILD_CMD="${SCRIPTS_DIR}/sketch_utils.sh build"
-    args+=" -s $test_folder/$sketch"
+    args+=("-s" "$test_folder/$sketch")
 fi
 
-${BUILD_CMD} ${args} $*
-
+${BUILD_CMD} "${args[@]}" "$@"
diff --git a/.github/scripts/tests_matrix.sh b/.github/scripts/tests_matrix.sh
index ca0b6eb8684..a8baf2ce275 100644
--- a/.github/scripts/tests_matrix.sh
+++ b/.github/scripts/tests_matrix.sh
@@ -6,21 +6,23 @@ wokwi_types="'validation'"
 qemu_types="'validation'"
 
 if [[ $IS_PR != 'true' ]] || [[ $PERFORMANCE_ENABLED == 'true' ]]; then
-  build_types+=",'performance'"
-  hw_types+=",'performance'"
-  #wokwi_types+=",'performance'"
-  #qemu_types+=",'performance'"
+    build_types+=",'performance'"
+    hw_types+=",'performance'"
+    #wokwi_types+=",'performance'"
+    #qemu_types+=",'performance'"
 fi
 
-targets="'esp32','esp32s2','esp32s3','esp32c3','esp32c6','esp32h2'"
+targets="'esp32','esp32s2','esp32s3','esp32c3','esp32c6','esp32h2','esp32p4'"
 
 mkdir -p info
 
 echo "[$wokwi_types]" > info/wokwi_types.txt
 echo "[$targets]" > info/targets.txt
 
-echo "build-types=[$build_types]" >> $GITHUB_OUTPUT
-echo "hw-types=[$hw_types]" >> $GITHUB_OUTPUT
-echo "wokwi-types=[$wokwi_types]" >> $GITHUB_OUTPUT
-echo "qemu-types=[$qemu_types]" >> $GITHUB_OUTPUT
-echo "targets=[$targets]" >> $GITHUB_OUTPUT
+{
+    echo "build-types=[$build_types]"
+    echo "hw-types=[$hw_types]"
+    echo "wokwi-types=[$wokwi_types]"
+    echo "qemu-types=[$qemu_types]"
+    echo "targets=[$targets]"
+} >> "$GITHUB_OUTPUT"
diff --git a/.github/scripts/tests_run.sh b/.github/scripts/tests_run.sh
index 16b0f2fb500..513fd16b371 100755
--- a/.github/scripts/tests_run.sh
+++ b/.github/scripts/tests_run.sh
@@ -1,126 +1,130 @@
 #!/bin/bash
 
-function run_test() {
+function run_test {
     local target=$1
     local sketch=$2
     local options=$3
     local erase_flash=$4
-    local sketchdir=$(dirname $sketch)
-    local sketchname=$(basename $sketchdir)
+    local sketchdir
+    local sketchname
     local result=0
     local error=0
     local sdkconfig_path
+    local extra_args
 
-    if [ $options -eq 0 ] && [ -f $sketchdir/ci.json ]; then
-        len=`jq -r --arg target $target '.fqbn[$target] | length' $sketchdir/ci.json`
-        if [ $len -eq 0 ]; then
+    sketchdir=$(dirname "$sketch")
+    sketchname=$(basename "$sketchdir")
+
+    if [ "$options" -eq 0 ] && [ -f "$sketchdir"/ci.json ]; then
+        len=$(jq -r --arg target "$target" '.fqbn[$target] | length' "$sketchdir"/ci.json)
+        if [ "$len" -eq 0 ]; then
             len=1
         fi
     else
         len=1
     fi
 
-    if [ $len -eq 1 ]; then
+    if [ "$len" -eq 1 ]; then
         sdkconfig_path="$HOME/.arduino/tests/$sketchname/build.tmp/sdkconfig"
     else
         sdkconfig_path="$HOME/.arduino/tests/$sketchname/build0.tmp/sdkconfig"
     fi
 
-    if [ -f $sketchdir/ci.json ]; then
+    if [ -f "$sketchdir"/ci.json ]; then
         # If the target or platform is listed as false, skip the sketch. Otherwise, include it.
-        is_target=$(jq -r --arg target $target '.targets[$target]' $sketchdir/ci.json)
-        selected_platform=$(jq -r --arg platform $platform '.platforms[$platform]' $sketchdir/ci.json)
+        is_target=$(jq -r --arg target "$target" '.targets[$target]' "$sketchdir"/ci.json)
+        selected_platform=$(jq -r --arg platform "$platform" '.platforms[$platform]' "$sketchdir"/ci.json)
 
         if [[ $is_target == "false" ]] || [[ $selected_platform == "false" ]]; then
-            printf "\033[93mSkipping $sketchname test for $target, platform: $platform\033[0m\n"
+            printf "\033[93mSkipping %s test for %s, platform: %s\033[0m\n" "$sketchname" "$target" "$platform"
             printf "\n\n\n"
             return 0
         fi
     fi
 
-    if [ ! -f $sdkconfig_path ]; then
-        printf "\033[93mSketch $sketchname not built\nMight be due to missing target requirements or build failure\033[0m\n"
+    if [ ! -f "$sdkconfig_path" ]; then
+        printf "\033[93mSketch %s not built\nMight be due to missing target requirements or build failure\033[0m\n" "$sketchname"
         printf "\n\n\n"
         return 0
     fi
 
-    local right_target=$(grep -E "^CONFIG_IDF_TARGET=\"$target\"$" "$sdkconfig_path")
+    local right_target
+    right_target=$(grep -E "^CONFIG_IDF_TARGET=\"$target\"$" "$sdkconfig_path")
     if [ -z "$right_target" ]; then
-        printf "\033[91mError: Sketch $sketchname compiled for different target\n\033[0m\n"
+        printf "\033[91mError: Sketch %s compiled for different target\n\033[0m\n" "$sketchname"
         printf "\n\n\n"
         return 1
     fi
 
-    if [ $len -eq 1 ]; then
-      # build_dir="$sketchdir/build"
-      build_dir="$HOME/.arduino/tests/$sketchname/build.tmp"
-      report_file="$sketchdir/$target/$sketchname.xml"
+    if [ "$len" -eq 1 ]; then
+        # build_dir="$sketchdir/build"
+        build_dir="$HOME/.arduino/tests/$sketchname/build.tmp"
+        report_file="$sketchdir/$target/$sketchname.xml"
     fi
 
-    for i in `seq 0 $(($len - 1))`
-    do
+    for i in $(seq 0 $((len - 1))); do
         fqbn="Default"
 
-        if [ $len -ne 1 ]; then
-            fqbn=`jq -r --arg target $target --argjson i $i '.fqbn[$target] | sort | .[$i]' $sketchdir/ci.json`
-        elif [ -f $sketchdir/ci.json ]; then
-            has_fqbn=`jq -r --arg target $target '.fqbn[$target]' $sketchdir/ci.json`
+        if [ "$len" -ne 1 ]; then
+            fqbn=$(jq -r --arg target "$target" --argjson i "$i" '.fqbn[$target] | sort | .[$i]' "$sketchdir"/ci.json)
+        elif [ -f "$sketchdir"/ci.json ]; then
+            has_fqbn=$(jq -r --arg target "$target" '.fqbn[$target]' "$sketchdir"/ci.json)
             if [ "$has_fqbn" != "null" ]; then
-                fqbn=`jq -r --arg target $target '.fqbn[$target] | .[0]' $sketchdir/ci.json`
+                fqbn=$(jq -r --arg target "$target" '.fqbn[$target] | .[0]' "$sketchdir"/ci.json)
             fi
         fi
 
-        printf "\033[95mRunning test: $sketchname -- Config: $fqbn\033[0m\n"
-        if [ $erase_flash -eq 1 ]; then
-            esptool.py -c $target erase_flash
+        printf "\033[95mRunning test: %s -- Config: %s\033[0m\n" "$sketchname" "$fqbn"
+        if [ "$erase_flash" -eq 1 ]; then
+            esptool.py -c "$target" erase_flash
         fi
 
-        if [ $len -ne 1 ]; then
+        if [ "$len" -ne 1 ]; then
             # build_dir="$sketchdir/build$i"
             build_dir="$HOME/.arduino/tests/$sketchname/build$i.tmp"
             report_file="$sketchdir/$target/$sketchname$i.xml"
         fi
 
         if [ $platform == "wokwi" ]; then
-            extra_args="--target $target --embedded-services arduino,wokwi --wokwi-timeout=$wokwi_timeout"
+            extra_args=("--target" "$target" "--embedded-services" "arduino,wokwi" "--wokwi-timeout=$wokwi_timeout")
             if [[ -f "$sketchdir/scenario.yaml" ]]; then
-                extra_args+=" --wokwi-scenario $sketchdir/scenario.yaml"
+                extra_args+=("--wokwi-scenario" "$sketchdir/scenario.yaml")
             fi
             if [[ -f "$sketchdir/diagram.$target.json" ]]; then
-                extra_args+=" --wokwi-diagram $sketchdir/diagram.$target.json"
+                extra_args+=("--wokwi-diagram" "$sketchdir/diagram.$target.json")
             fi
 
         elif [ $platform == "qemu" ]; then
             PATH=$HOME/qemu/bin:$PATH
-            extra_args="--embedded-services qemu --qemu-image-path $build_dir/$sketchname.ino.merged.bin"
+            extra_args=("--embedded-services" "qemu" "--qemu-image-path" "$build_dir/$sketchname.ino.merged.bin")
 
-            if [ $target == "esp32" ] || [ $target == "esp32s3" ]; then
-                extra_args+=" --qemu-prog-path qemu-system-xtensa --qemu-cli-args=\"-machine $target -m 4M -nographic\""
-            elif [ $target == "esp32c3" ]; then
-                extra_args+=" --qemu-prog-path qemu-system-riscv32 --qemu-cli-args=\"-machine $target -icount 3 -nographic\""
+            if [ "$target" == "esp32" ] || [ "$target" == "esp32s3" ]; then
+                extra_args+=("--qemu-prog-path" "qemu-system-xtensa" "--qemu-cli-args=\"-machine $target -m 4M -nographic\"")
+            elif [ "$target" == "esp32c3" ]; then
+                extra_args+=("--qemu-prog-path" "qemu-system-riscv32" "--qemu-cli-args=\"-machine $target -icount 3 -nographic\"")
             else
-                printf "\033[91mUnsupported QEMU target: $target\033[0m\n"
+                printf "\033[91mUnsupported QEMU target: %s\033[0m\n" "$target"
                 exit 1
             fi
         else
-            extra_args="--embedded-services esp,arduino"
+            extra_args=("--embedded-services" "esp,arduino")
         fi
 
-        rm $sketchdir/diagram.json 2>/dev/null || true
+        rm "$sketchdir"/diagram.json 2>/dev/null || true
 
         result=0
-        printf "\033[95mpytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args\033[0m\n"
-        bash -c "set +e; pytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args; exit \$?" || result=$?
+        printf "\033[95mpytest \"%s/test_%s.py\" --build-dir \"%s\" --junit-xml=\"%s\" %s\033[0m\n" "$sketchdir" "$sketchname" "$build_dir" "$report_file" "${extra_args[*]@Q}"
+        bash -c "set +e; pytest \"$sketchdir/test_$sketchname.py\" --build-dir \"$build_dir\" --junit-xml=\"$report_file\" ${extra_args[*]@Q}; exit \$?" || result=$?
         printf "\n"
         if [ $result -ne 0 ]; then
             result=0
-            printf "\033[95mRetrying test: $sketchname -- Config: $i\033[0m\n"
-            printf "\033[95mpytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args\033[0m\n"
-            bash -c "set +e; pytest $sketchdir/test_$sketchname.py --build-dir $build_dir --junit-xml=$report_file $extra_args; exit \$?" || result=$?
+            printf "\033[95mRetrying test: %s -- Config: %s\033[0m\n" "$sketchname" "$i"
+            printf "\033[95mpytest \"%s/test_%s.py\" --build-dir \"%s\" --junit-xml=\"%s\" %s\033[0m\n" "$sketchdir" "$sketchname" "$build_dir" "$report_file" "${extra_args[*]@Q}"
+            bash -c "set +e; pytest \"$sketchdir/test_$sketchname.py\" --build-dir \"$build_dir\" --junit-xml=\"$report_file\" ${extra_args[*]@Q}; exit \$?" || result=$?
             printf "\n"
             if [ $result -ne 0 ]; then
-              printf "\033[91mFailed test: $sketchname -- Config: $i\033[0m\n\n"
-              error=$result
+                printf "\033[91mFailed test: %s -- Config: %s\033[0m\n\n" "$sketchname" "$i"
+                error=$result
             fi
         fi
     done
@@ -136,13 +140,13 @@ chunk_run=0
 options=0
 erase=0
 
-while [ ! -z "$1" ]; do
+while [ -n "$1" ]; do
     case $1 in
     -c )
         chunk_run=1
         ;;
     -Q )
-        if [ ! -d $QEMU_PATH ]; then
+        if [ ! -d "$QEMU_PATH" ]; then
             echo "QEMU path $QEMU_PATH does not exist"
             exit 1
         fi
@@ -188,98 +192,97 @@ while [ ! -z "$1" ]; do
         test_type=$1
         ;;
     * )
-      break
-      ;;
+        break
+        ;;
     esac
     shift
 done
 
 if [ ! $platform == "qemu" ]; then
-    source ${SCRIPTS_DIR}/install-arduino-ide.sh
+    source "${SCRIPTS_DIR}/install-arduino-ide.sh"
 fi
 
 # If sketch is provided and test type is not, test type is inferred from the sketch path
 if [[ $test_type == "all" ]] || [[ -z $test_type ]]; then
     if [ -n "$sketch" ]; then
-        tmp_sketch_path=$(find tests -name $sketch.ino)
-        test_type=$(basename $(dirname $(dirname "$tmp_sketch_path")))
+        tmp_sketch_path=$(find tests -name "$sketch".ino)
+        test_type=$(basename "$(dirname "$(dirname "$tmp_sketch_path")")")
         echo "Sketch $sketch test type: $test_type"
         test_folder="$PWD/tests/$test_type"
     else
-      test_folder="$PWD/tests"
+        test_folder="$PWD/tests"
     fi
 else
     test_folder="$PWD/tests/$test_type"
 fi
 
 if [ $chunk_run -eq 0 ]; then
-    if [ -z $sketch ]; then
+    if [ -z "$sketch" ]; then
         echo "ERROR: Sketch name is required for single test run"
         exit 1
     fi
-    run_test $target $test_folder/$sketch/$sketch.ino $options $erase
+    run_test "$target" "$test_folder"/"$sketch"/"$sketch".ino $options $erase
     exit $?
 else
-  if [ "$chunk_max" -le 0 ]; then
-      echo "ERROR: Chunks count must be positive number"
-      exit 1
-  fi
-
-  if [ "$chunk_index" -ge "$chunk_max" ] && [ "$chunk_max" -ge 2 ]; then
-      echo "ERROR: Chunk index must be less than chunks count"
-      exit 1
-  fi
-
-  set +e
-  # Ignore requirements as we don't have the libs. The requirements will be checked in the run_test function
-  ${COUNT_SKETCHES} "$test_folder" "$target" "1"
-  sketchcount=$?
-  set -e
-  sketches=$(cat sketches.txt)
-  rm -rf sketches.txt
-
-  chunk_size=$(( $sketchcount / $chunk_max ))
-  all_chunks=$(( $chunk_max * $chunk_size ))
-  if [ "$all_chunks" -lt "$sketchcount" ]; then
-      chunk_size=$(( $chunk_size + 1 ))
-  fi
-
-  start_index=0
-  end_index=0
-  if [ "$chunk_index" -ge "$chunk_max" ]; then
-      start_index=$chunk_index
-      end_index=$sketchcount
-  else
-      start_index=$(( $chunk_index * $chunk_size ))
-      if [ "$sketchcount" -le "$start_index" ]; then
-          exit 0
-      fi
-
-      end_index=$(( $(( $chunk_index + 1 )) * $chunk_size ))
-      if [ "$end_index" -gt "$sketchcount" ]; then
-          end_index=$sketchcount
-      fi
-  fi
-
-  start_num=$(( $start_index + 1 ))
-  sketchnum=0
-  error=0
-
-  for sketch in $sketches; do
-
-      sketchnum=$(($sketchnum + 1))
-      if [ "$sketchnum" -le "$start_index" ] \
-      || [ "$sketchnum" -gt "$end_index" ]; then
-          continue
-      fi
-
-      printf "\033[95mSketch Index $(($sketchnum - 1))\033[0m\n"
-
-      exit_code=0
-      run_test $target $sketch $options $erase || exit_code=$?
-      if [ $exit_code -ne 0 ]; then
-          error=$exit_code
-      fi
-  done
-  exit $error
+    if [ "$chunk_max" -le 0 ]; then
+        echo "ERROR: Chunks count must be positive number"
+        exit 1
+    fi
+
+    if [ "$chunk_index" -ge "$chunk_max" ] && [ "$chunk_max" -ge 2 ]; then
+        echo "ERROR: Chunk index must be less than chunks count"
+        exit 1
+    fi
+
+    set +e
+    # Ignore requirements as we don't have the libs. The requirements will be checked in the run_test function
+    ${COUNT_SKETCHES} "$test_folder" "$target" "1"
+    sketchcount=$?
+    set -e
+    sketches=$(cat sketches.txt)
+    rm -rf sketches.txt
+
+    chunk_size=$(( sketchcount / chunk_max ))
+    all_chunks=$(( chunk_max * chunk_size ))
+    if [ "$all_chunks" -lt "$sketchcount" ]; then
+        chunk_size=$(( chunk_size + 1 ))
+    fi
+
+    start_index=0
+    end_index=0
+    if [ "$chunk_index" -ge "$chunk_max" ]; then
+        start_index=$chunk_index
+        end_index=$sketchcount
+    else
+        start_index=$(( chunk_index * chunk_size ))
+        if [ "$sketchcount" -le "$start_index" ]; then
+            exit 0
+        fi
+
+        end_index=$(( $(( chunk_index + 1 )) * chunk_size ))
+        if [ "$end_index" -gt "$sketchcount" ]; then
+            end_index=$sketchcount
+        fi
+    fi
+
+    sketchnum=0
+    error=0
+
+    for sketch in $sketches; do
+
+        sketchnum=$((sketchnum + 1))
+        if [ "$sketchnum" -le "$start_index" ] \
+        || [ "$sketchnum" -gt "$end_index" ]; then
+            continue
+        fi
+
+        printf "\033[95mSketch Index %s\033[0m\n" "$((sketchnum - 1))"
+
+        exit_code=0
+        run_test "$target" "$sketch" $options $erase || exit_code=$?
+        if [ $exit_code -ne 0 ]; then
+            error=$exit_code
+        fi
+    done
+    exit $error
 fi
diff --git a/.github/scripts/update-version.sh b/.github/scripts/update-version.sh
index cbc31378b15..9a38b27a57a 100755
--- a/.github/scripts/update-version.sh
+++ b/.github/scripts/update-version.sh
@@ -1,20 +1,21 @@
 #!/bin/bash
+# shellcheck disable=SC2002
 
 # For reference: add tools for all boards by replacing one line in each board
 # "[board].upload.tool=esptool_py" to "[board].upload.tool=esptool_py\n[board].upload.tool.default=esptool_py\n[board].upload.tool.network=esp_ota"
 #cat boards.txt | sed "s/\([a-zA-Z0-9_\-]*\)\.upload\.tool\=esptool_py/\1\.upload\.tool\=esptool_py\\n\1\.upload\.tool\.default\=esptool_py\\n\1\.upload\.tool\.network\=esp_ota/"
 
 if [ ! $# -eq 3 ]; then
-	echo "Bad number of arguments: $#" >&2
-	echo "usage: $0 <major> <minor> <patch>" >&2
-	exit 1
+    echo "Bad number of arguments: $#" >&2
+    echo "usage: $0 <major> <minor> <patch>" >&2
+    exit 1
 fi
 
 re='^[0-9]+$'
 if [[ ! $1 =~ $re ]] || [[ ! $2 =~ $re ]] || [[ ! $3 =~ $re ]] ; then
-	echo "error: Not a valid version: $1.$2.$3" >&2
-	echo "usage: $0 <major> <minor> <patch>" >&2
-	exit 1
+    echo "error: Not a valid version: $1.$2.$3" >&2
+    echo "usage: $0 <major> <minor> <patch>" >&2
+    exit 1
 fi
 
 ESP_ARDUINO_VERSION_MAJOR="$1"
@@ -36,11 +37,12 @@ sed "s/#define ESP_ARDUINO_VERSION_MAJOR.*/#define ESP_ARDUINO_VERSION_MAJOR $ES
 sed "s/#define ESP_ARDUINO_VERSION_MINOR.*/#define ESP_ARDUINO_VERSION_MINOR $ESP_ARDUINO_VERSION_MINOR/g" | \
 sed "s/#define ESP_ARDUINO_VERSION_PATCH.*/#define ESP_ARDUINO_VERSION_PATCH $ESP_ARDUINO_VERSION_PATCH/g" > __esp_arduino_version.h && mv __esp_arduino_version.h cores/esp32/esp_arduino_version.h
 
-for lib in `ls libraries`; do
-	if [ -f "libraries/$lib/library.properties" ]; then
-		echo "Updating Library $lib..."
-		cat "libraries/$lib/library.properties" | sed "s/version=.*/version=$ESP_ARDUINO_VERSION/g" > "libraries/$lib/__library.properties" && mv "libraries/$lib/__library.properties" "libraries/$lib/library.properties"
-	fi
+libraries=$(find libraries -maxdepth 1 -mindepth 1 -type d -exec basename {} \;)
+for lib in $libraries; do
+    if [ -f "libraries/$lib/library.properties" ]; then
+        echo "Updating Library $lib..."
+        cat "libraries/$lib/library.properties" | sed "s/version=.*/version=$ESP_ARDUINO_VERSION/g" > "libraries/$lib/__library.properties" && mv "libraries/$lib/__library.properties" "libraries/$lib/library.properties"
+    fi
 done
 
 exit 0
diff --git a/.github/scripts/upload_py_tools.sh b/.github/scripts/upload_py_tools.sh
index 0544bccd710..abe18a50c6e 100755
--- a/.github/scripts/upload_py_tools.sh
+++ b/.github/scripts/upload_py_tools.sh
@@ -1,11 +1,12 @@
 #!/bin/bash
+
 CHANGED_FILES=$1
 echo "Pushing '$CHANGED_FILES' as github-actions[bot]"
 git config --global github.user "github-actions[bot]"
 git config --global user.name "github-actions[bot]"
 git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
 for tool in $CHANGED_FILES; do
-	git add tools/$tool.exe
+    git add tools/"$tool".exe
 done
 git commit -m "change(tools): Push generated binaries to PR"
 git push
diff --git a/.github/workflows/allboards.yml b/.github/workflows/allboards.yml
index 4a2d4349ac3..8c4dadcd03e 100644
--- a/.github/workflows/allboards.yml
+++ b/.github/workflows/allboards.yml
@@ -1,6 +1,6 @@
 name: Boards Test - Remote trigger
 
-# The workflow will run on remote dispath with event-type set to "test-boards"
+# The workflow will run on remote dispatch with event-type set to "test-boards"
 on:
   repository_dispatch:
     types: [test-boards]
@@ -20,8 +20,7 @@ jobs:
           ref: ${{ github.event.client_payload.branch }}
 
       - name: Get boards fqbns
-        run: 
-          bash .github/scripts/find_all_boards.sh
+        run: bash .github/scripts/find_all_boards.sh
 
   setup-chunks:
     needs: find-boards
@@ -43,8 +42,7 @@ jobs:
 
       - id: set-test-chunks
         name: Set Chunks
-        run: 
-          echo "test-chunks<<EOF" >> $GITHUB_OUTPUT
+        run: echo "test-chunks<<EOF" >> $GITHUB_OUTPUT
 
           echo "$( jq -nc '${{ needs.find-boards.outputs.fqbns }} | [_nwise( ${{ needs.find-boards.outputs.board-count }}/15 | ceil)]')" >> $GITHUB_OUTPUT
 
@@ -61,7 +59,7 @@ jobs:
 
     strategy:
       fail-fast: false
-      matrix: 
+      matrix:
         chunk: ${{ fromJSON(needs.setup-chunks.outputs['test-chunks']) }}
 
     steps:
@@ -71,9 +69,8 @@ jobs:
           ref: ${{ github.event.client_payload.branch }}
 
       - name: Echo FQBNS to file
-        run:
-          echo "$FQBN" > fqbns.json
-        env: 
+        run: echo "$FQBN" > fqbns.json
+        env:
           FQBN: ${{ toJSON(matrix.chunk) }}
 
       - name: Compile sketch
@@ -88,5 +85,4 @@ jobs:
           enable-warnings-report: false
           cli-compile-flags: |
             - --warnings="all"
-          sketch-paths:
-            "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino"
+          sketch-paths: "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino"
diff --git a/.github/workflows/boards.yml b/.github/workflows/boards.yml
index a309e4ed2ce..a51c794cfb4 100644
--- a/.github/workflows/boards.yml
+++ b/.github/workflows/boards.yml
@@ -4,9 +4,9 @@ name: Boards Test
 on:
   pull_request:
     paths:
-      - 'boards.txt'
-      - 'libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino'
-      - '.github/workflows/boards.yml'
+      - "boards.txt"
+      - "libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino"
+      - ".github/workflows/boards.yml"
 
 env:
   # It's convenient to set variables for values used multiple times in the workflow
@@ -28,8 +28,7 @@ jobs:
         uses: dcarbone/install-jq-action@v1.0.1
 
       - name: Get board name
-        run:
-          bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{github.base_ref}}
+        run: bash .github/scripts/find_new_boards.sh ${{ github.repository }} ${{github.base_ref}}
 
   test-boards:
     needs: find-boards
@@ -72,7 +71,7 @@ jobs:
             ./tools/openocd-esp32
             ./tools/riscv32-*
             ./tools/xtensa-*
-            
+
       - name: Compile sketch
         uses: P-R-O-C-H-Y/compile-sketches@main
         with:
@@ -85,6 +84,5 @@ jobs:
           cli-compile-flags: |
             - --warnings="all"
           exit-on-fail: true
-          sketch-paths:
-            "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino"
+          sketch-paths: "- ./libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino"
           verbose: true
diff --git a/.github/workflows/build_py_tools.yml b/.github/workflows/build_py_tools.yml
index 37742d15224..48e7f2c82d3 100644
--- a/.github/workflows/build_py_tools.yml
+++ b/.github/workflows/build_py_tools.yml
@@ -3,11 +3,11 @@ name: Build Python Tools
 on:
   pull_request:
     paths:
-      - '.github/workflows/build_py_tools.yml'
-      - 'tools/get.py'
-      - 'tools/espota.py'
-      - 'tools/gen_esp32part.py'
-      - 'tools/gen_insights_package.py'
+      - ".github/workflows/build_py_tools.yml"
+      - "tools/get.py"
+      - "tools/espota.py"
+      - "tools/gen_esp32part.py"
+      - "tools/gen_insights_package.py"
 
 jobs:
   find-changed-tools:
@@ -33,8 +33,8 @@ jobs:
         uses: tj-actions/changed-files@v41
         id: verify-changed-files
         with:
-          fetch_depth: '2'
-          since_last_remote_commit: 'true'
+          fetch_depth: "2"
+          since_last_remote_commit: "true"
           files: |
             tools/get.py
             tools/espota.py
@@ -57,20 +57,20 @@ jobs:
       matrix:
         os: [windows-latest, macos-latest, ubuntu-20.04, ARM]
         include:
-        - os: windows-latest
-          TARGET: win64
-          EXTEN: .exe
-          SEPARATOR: ';'
-        - os: macos-latest
-          TARGET: macos
-          SEPARATOR: ':'
-        - os: ubuntu-20.04
-          TARGET: linux-amd64
-          SEPARATOR: ':'
-        - os: ARM
-          CONTAINER: python:3.8-bullseye
-          TARGET: arm
-          SEPARATOR: ':'
+          - os: windows-latest
+            TARGET: win64
+            EXTEN: .exe
+            SEPARATOR: ";"
+          - os: macos-latest
+            TARGET: macos
+            SEPARATOR: ":"
+          - os: ubuntu-20.04
+            TARGET: linux-amd64
+            SEPARATOR: ":"
+          - os: ARM
+            CONTAINER: python:3.8-bullseye
+            TARGET: arm
+            SEPARATOR: ":"
     container: ${{ matrix.CONTAINER }} # use python container on ARM
     env:
       DISTPATH: pytools-${{ matrix.TARGET }}
diff --git a/.github/workflows/dangerjs.yml b/.github/workflows/dangerjs.yml
index 75c046731f3..f4bdad3c16e 100644
--- a/.github/workflows/dangerjs.yml
+++ b/.github/workflows/dangerjs.yml
@@ -11,14 +11,14 @@ jobs:
   pull-request-style-linter:
     runs-on: ubuntu-latest
     steps:
-    - name: Check out PR head
-      uses: actions/checkout@v4
-      with:
-        ref: ${{ github.event.pull_request.head.sha }}
+      - name: Check out PR head
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ github.event.pull_request.head.sha }}
 
-    - name: DangerJS pull request linter
-      uses: espressif/shared-github-dangerjs@v1
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        rule-max-commits: 'false'
-        commit-messages-min-summary-length: '10'
+      - name: DangerJS pull request linter
+        uses: espressif/shared-github-dangerjs@v1
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          rule-max-commits: "false"
+          commit-messages-min-summary-length: "10"
diff --git a/.github/workflows/docs_build.yml b/.github/workflows/docs_build.yml
index ffa5a0b4580..d2f12e1f7b5 100644
--- a/.github/workflows/docs_build.yml
+++ b/.github/workflows/docs_build.yml
@@ -3,18 +3,17 @@ name: Documentation Build and Deploy CI
 on:
   push:
     branches:
-    - master
-    - release/v2.x
+      - master
+      - release/v2.x
     paths:
-    - 'docs/**'
-    - '.github/workflows/docs_build.yml'
+      - "docs/**"
+      - ".github/workflows/docs_build.yml"
   pull_request:
     paths:
-    - 'docs/**'
-    - '.github/workflows/docs_build.yml'
+      - "docs/**"
+      - ".github/workflows/docs_build.yml"
 
 jobs:
-
   build-docs:
     name: Build ESP-Docs
     runs-on: ubuntu-22.04
@@ -22,25 +21,25 @@ jobs:
       run:
         shell: bash
     steps:
-    - uses: actions/checkout@v4
-      with:
-        submodules: true
-    - uses: actions/setup-python@v5
-      with:
-        cache-dependency-path: docs/requirements.txt
-        cache: 'pip'
-        python-version: '3.10'
-    - name: Build
-      run: |
-        sudo apt update
-        sudo apt install python3-pip python3-setuptools
-        # GitHub CI installs pip3 and setuptools outside the path.
-        # Update the path to include them and run.
-        cd ./docs
-        PATH=/home/runner/.local/bin:$PATH pip3 install -r requirements.txt --prefer-binary
-        PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs -l en
-    - name: Archive Docs
-      uses: actions/upload-artifact@v4
-      with:
-        name: docs
-        path: docs
+      - uses: actions/checkout@v4
+        with:
+          submodules: true
+      - uses: actions/setup-python@v5
+        with:
+          cache-dependency-path: docs/requirements.txt
+          cache: "pip"
+          python-version: "3.10"
+      - name: Build
+        run: |
+          sudo apt update
+          sudo apt install python3-pip python3-setuptools
+          # GitHub CI installs pip3 and setuptools outside the path.
+          # Update the path to include them and run.
+          cd ./docs
+          PATH=/home/runner/.local/bin:$PATH pip3 install -r requirements.txt --prefer-binary
+          PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" build-docs -l en
+      - name: Archive Docs
+        uses: actions/upload-artifact@v4
+        with:
+          name: docs
+          path: docs
diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml
index 5393f7e8a20..b558fd21aa5 100644
--- a/.github/workflows/docs_deploy.yml
+++ b/.github/workflows/docs_deploy.yml
@@ -7,11 +7,11 @@ on:
       - completed
   push:
     branches:
-    - release/v2.x
-    - master
+      - release/v2.x
+      - master
     paths:
-    - 'docs/**'
-    - '.github/workflows/docs_deploy.yml'
+      - "docs/**"
+      - ".github/workflows/docs_deploy.yml"
 
 jobs:
   deploy-prod-docs:
@@ -21,39 +21,39 @@ jobs:
       run:
         shell: bash
     steps:
-    - name: Check if release workflow is successful
-      if: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.conclusion != 'success' }}
-      run: |
-        echo "Release workflow failed. Exiting..."
-        exit 1
-    - uses: actions/checkout@v4
-      with:
-        submodules: true
-    - uses: actions/setup-python@v5
-      with:
-        cache-dependency-path: docs/requirements.txt
-        cache: 'pip'
-        python-version: '3.10'
-    - name: Deploy Documentation
-      env:
-        # Deploy to production server
-        # DOCS_BUILD_DIR: "./docs/_build/"
-        DOCS_DEPLOY_PRIVATEKEY: ${{ secrets.DOCS_KEY }}
-        DOCS_DEPLOY_PATH: ${{ secrets.DOCS_PATH }}
-        DOCS_DEPLOY_SERVER: ${{ secrets.DOCS_SERVER }}
-        DOCS_DEPLOY_SERVER_USER: ${{ secrets.DOCS_USER }}
-        DOCS_DEPLOY_URL_BASE: ${{ secrets.DOCS_URL }}
-      run: |
-        sudo apt update
-        sudo apt install python3-pip python3-setuptools
-        source ./docs/utils.sh
-        add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
-        export GIT_VER=$(git describe --always)
-        echo "PIP install requirements..."
-        pip3 install --user -r ./docs/requirements.txt
-        echo "Building the Docs..."
-        cd ./docs && build-docs -l en
-        echo "Deploy the Docs..."
-        export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/
-        cd $GITHUB_WORKSPACE/docs
-        deploy-docs
+      - name: Check if release workflow is successful
+        if: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.conclusion != 'success' }}
+        run: |
+          echo "Release workflow failed. Exiting..."
+          exit 1
+      - uses: actions/checkout@v4
+        with:
+          submodules: true
+      - uses: actions/setup-python@v5
+        with:
+          cache-dependency-path: docs/requirements.txt
+          cache: "pip"
+          python-version: "3.10"
+      - name: Deploy Documentation
+        env:
+          # Deploy to production server
+          # DOCS_BUILD_DIR: "./docs/_build/"
+          DOCS_DEPLOY_PRIVATEKEY: ${{ secrets.DOCS_KEY }}
+          DOCS_DEPLOY_PATH: ${{ secrets.DOCS_PATH }}
+          DOCS_DEPLOY_SERVER: ${{ secrets.DOCS_SERVER }}
+          DOCS_DEPLOY_SERVER_USER: ${{ secrets.DOCS_USER }}
+          DOCS_DEPLOY_URL_BASE: ${{ secrets.DOCS_URL }}
+        run: |
+          sudo apt update
+          sudo apt install python3-pip python3-setuptools
+          source ./docs/utils.sh
+          add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
+          export GIT_VER=$(git describe --always)
+          echo "PIP install requirements..."
+          pip3 install --user -r ./docs/requirements.txt
+          echo "Building the Docs..."
+          cd ./docs && build-docs -l en
+          echo "Deploy the Docs..."
+          export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/
+          cd $GITHUB_WORKSPACE/docs
+          deploy-docs
diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml
index 5d8e1794a8a..47480e8239a 100644
--- a/.github/workflows/gh-pages.yml
+++ b/.github/workflows/gh-pages.yml
@@ -3,21 +3,20 @@ name: GitHub Pages CI
 on:
   push:
     branches:
-    - master
-    - pages
+      - master
+      - pages
     paths:
-    - 'README.md'
-    - '.github/scripts/on-pages.sh'
-    - '.github/workflows/gh-pages.yml'
+      - "README.md"
+      - ".github/scripts/on-pages.sh"
+      - ".github/workflows/gh-pages.yml"
 
 jobs:
-
   build-pages:
     name: Build GitHub Pages
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v4
-    - name: Copy Files
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      run: bash ./.github/scripts/on-pages.sh
+      - uses: actions/checkout@v4
+      - name: Copy Files
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: bash ./.github/scripts/on-pages.sh
diff --git a/.github/workflows/lib.yml b/.github/workflows/lib.yml
index 894df61f4fd..1197308c921 100644
--- a/.github/workflows/lib.yml
+++ b/.github/workflows/lib.yml
@@ -7,7 +7,7 @@ on:
 
   # Schedule weekly builds on every Sunday at 4 am
   schedule:
-    - cron: '0 4 * * SUN'
+    - cron: "0 4 * * SUN"
 
 concurrency:
   group: libs-${{ github.event.pull_request.number || github.ref }}
@@ -27,7 +27,6 @@ jobs:
       contains(github.event.pull_request.labels.*.name, 'lib_test') ||
       (github.event_name == 'schedule' && github.repository == 'espressif/arduino-esp32')
     runs-on: ubuntu-latest
-
     env:
       REPOSITORY: |
         - source-path: '.'
@@ -42,6 +41,7 @@ jobs:
           - esp32s3
           - esp32c6
           - esp32h2
+          - esp32p4
 
         include:
           - target: esp32
@@ -56,7 +56,8 @@ jobs:
             fqbn: espressif:esp32:esp32c6
           - target: esp32h2
             fqbn: espressif:esp32:esp32h2
-
+          - target: esp32p4
+            fqbn: espressif:esp32:esp32p4
 
     steps:
       # This step makes the contents of the repository available to the workflow
@@ -85,7 +86,7 @@ jobs:
           path: ${{ env.SKETCHES_REPORTS_PATH }}
 
   report-to-file:
-    needs: compile-sketch  # Wait for the compile job to finish to get the data for the report
+    needs: compile-sketch # Wait for the compile job to finish to get the data for the report
     if: github.event_name == 'schedule' # Only run the job when the workflow is triggered by a schedule
     runs-on: ubuntu-latest
     steps:
@@ -94,11 +95,10 @@ jobs:
         uses: actions/checkout@v4
         with:
           token: ${{ env.GITHUB_TOKEN }}
-          fetch-depth: '0'
+          fetch-depth: "0"
 
       - name: Switch branch
-        run:
-          git checkout remotes/origin/gh-pages
+        run: git checkout remotes/origin/gh-pages
 
       # This step is needed to get the size data produced by the compile jobs
       - name: Download sketches reports artifact
@@ -115,8 +115,7 @@ jobs:
           destination-file: ${{ env.RESULT_LIBRARY_TEST_FILE }}
 
       - name: Append file with action URL
-        run:
-          echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_LIBRARY_TEST_FILE }}
+        run: echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_LIBRARY_TEST_FILE }}
 
       - name: Push to github repo
         run: |
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 8257e78c822..dc009e445da 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -37,7 +37,7 @@ jobs:
         uses: actions/setup-python@v5
         with:
           cache-dependency-path: tools/pre-commit/requirements.txt
-          cache: 'pip'
+          cache: "pip"
           python-version: "3.x"
 
       - name: Get Python version hash
diff --git a/.github/workflows/publishlib.yml b/.github/workflows/publishlib.yml
index 7fd932f5309..62393b80915 100644
--- a/.github/workflows/publishlib.yml
+++ b/.github/workflows/publishlib.yml
@@ -47,7 +47,7 @@ jobs:
         uses: juliangruber/read-file-action@v1
         with:
           path: ./artifacts/workflows/pr_num.txt
-    
+
       - name: Report results
         uses: P-R-O-C-H-Y/report-size-deltas@libs
         with:
diff --git a/.github/workflows/publishsizes-2.x.yml b/.github/workflows/publishsizes-2.x.yml
index bdd2fc311e4..ffbd751838c 100644
--- a/.github/workflows/publishsizes-2.x.yml
+++ b/.github/workflows/publishsizes-2.x.yml
@@ -11,11 +11,11 @@ env:
 
 jobs:
   sizes-test-results:
-    name: Sizes Comparsion Results
+    name: Sizes Comparison Results
     runs-on: ubuntu-latest
     steps:
       - name: Checkout code
-        uses: actions/checkout@v4  # This step checks out the repository's code at gh-pages branch
+        uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch
         with:
           ref: gh-pages
 
@@ -41,8 +41,7 @@ jobs:
           destination-file: ${{ env.RESULT_SIZES_TEST_FILE }}
 
       - name: Append file with action URL
-        run:
-          echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_SIZES_TEST_FILE }}
+        run: echo "/ [GitHub Action Link](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}})" >> ${{ env.RESULT_SIZES_TEST_FILE }}
 
       - name: Push to github repo
         run: |
diff --git a/.github/workflows/publishsizes.yml b/.github/workflows/publishsizes.yml
index ce4e94cd5e5..6c6d75eccce 100644
--- a/.github/workflows/publishsizes.yml
+++ b/.github/workflows/publishsizes.yml
@@ -14,7 +14,7 @@ env:
 
 jobs:
   sizes-test-results:
-    name: Sizes Comparsion Results
+    name: Sizes Comparison Results
     runs-on: ubuntu-latest
     if: |
       github.event.workflow_run.event == 'pull_request' &&
@@ -22,7 +22,7 @@ jobs:
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@v4  # This step checks out the repository's code at gh-pages branch
+        uses: actions/checkout@v4 # This step checks out the repository's code at gh-pages branch
         with:
           ref: gh-pages
 
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 82159e1b8a4..4f30bdbb844 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -4,30 +4,30 @@ on:
   workflow_dispatch:
   push:
     branches:
-    - master
-    - release/*
+      - master
+      - release/*
   pull_request:
     paths:
-      - 'cores/**'
-      - 'libraries/**'
-      - '!libraries/**.md'
-      - '!libraries/**.txt'
-      - '!libraries/**.properties'
-      - '!libraries/**.py'
-      - 'package/**'
-      - 'tools/**.py'
-      - 'platform.txt'
-      - 'programmers.txt'
-      - 'idf_component.yml'
-      - 'Kconfig.projbuild'
-      - 'package.json'
-      - 'CMakeLists.txt'
-      - '.github/workflows/push.yml'
-      - '.github/scripts/**'
-      - '!.github/scripts/find_*'
-      - '!.github/scripts/on-release.sh'
-      - '!.github/scripts/tests_*'
-      - '!.github/scripts/upload_*'
+      - "cores/**"
+      - "libraries/**"
+      - "!libraries/**.md"
+      - "!libraries/**.txt"
+      - "!libraries/**.properties"
+      - "!libraries/**.py"
+      - "package/**"
+      - "tools/**.py"
+      - "platform.txt"
+      - "programmers.txt"
+      - "idf_component.yml"
+      - "Kconfig.projbuild"
+      - "package.json"
+      - "CMakeLists.txt"
+      - ".github/workflows/push.yml"
+      - ".github/scripts/**"
+      - "!.github/scripts/find_*"
+      - "!.github/scripts/on-release.sh"
+      - "!.github/scripts/tests_*"
+      - "!.github/scripts/upload_*"
       - "variants/esp32/**/*"
       - "variants/esp32s2/**/*"
       - "variants/esp32s3/**/*"
@@ -49,8 +49,8 @@ jobs:
     runs-on: ubuntu-latest
     if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }}
     steps:
-    - uses: actions/checkout@v4
-    - run: bash ./.github/scripts/check-cmakelists.sh
+      - uses: actions/checkout@v4
+      - run: bash ./.github/scripts/check-cmakelists.sh
 
   gen-chunks:
     name: Generate chunks
@@ -65,16 +65,16 @@ jobs:
       chunk_count: ${{ steps.set-chunks.outputs.chunk_count }}
       chunks: ${{ steps.set-chunks.outputs.chunks }}
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v4
-      with:
-        fetch-depth: 2
+      - name: Checkout repository
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 2
 
-    - name: Get changed files
-      id: changed-files
-      uses: tj-actions/changed-files@v44
-      with:
-        files_yaml: |
+      - name: Get changed files
+        id: changed-files
+        uses: tj-actions/changed-files@v44
+        with:
+          files_yaml: |
             core:
               - '.github/**'
               - '!.github/scripts/install-platformio-esp32.sh'
@@ -115,31 +115,31 @@ jobs:
               - '.github/scripts/install-platformio-esp32.sh'
               - 'tools/platformio-build.py'
 
-    - name: Set chunks
-      id: set-chunks
-      env:
-        LIB_FILES: ${{ steps.changed-files.outputs.libraries_all_changed_files }}
-        IS_PR: ${{ github.event_name == 'pull_request' }}
-        MAX_CHUNKS: ${{ env.MAX_CHUNKS }}
-        BUILD_PLATFORMIO: ${{ steps.changed-files.outputs.platformio_any_changed == 'true' }}
-        BUILD_IDF: ${{ steps.changed-files.outputs.idf_any_changed == 'true' }}
-        BUILD_LIBRARIES: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }}
-        BUILD_STATIC_SKETCHES: ${{ steps.changed-files.outputs.static_sketeches_any_changed == 'true' }}
-        FS_CHANGED: ${{ steps.changed-files.outputs.fs_any_changed == 'true' }}
-        NETWORKING_CHANGED: ${{ steps.changed-files.outputs.networking_any_changed == 'true' }}
-        CORE_CHANGED: ${{ steps.changed-files.outputs.core_any_changed == 'true' }}
-        LIB_CHANGED: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }}
-      run: |
-        bash ./.github/scripts/set_push_chunks.sh
+      - name: Set chunks
+        id: set-chunks
+        env:
+          LIB_FILES: ${{ steps.changed-files.outputs.libraries_all_changed_files }}
+          IS_PR: ${{ github.event_name == 'pull_request' }}
+          MAX_CHUNKS: ${{ env.MAX_CHUNKS }}
+          BUILD_PLATFORMIO: ${{ steps.changed-files.outputs.platformio_any_changed == 'true' }}
+          BUILD_IDF: ${{ steps.changed-files.outputs.idf_any_changed == 'true' }}
+          BUILD_LIBRARIES: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }}
+          BUILD_STATIC_SKETCHES: ${{ steps.changed-files.outputs.static_sketeches_any_changed == 'true' }}
+          FS_CHANGED: ${{ steps.changed-files.outputs.fs_any_changed == 'true' }}
+          NETWORKING_CHANGED: ${{ steps.changed-files.outputs.networking_any_changed == 'true' }}
+          CORE_CHANGED: ${{ steps.changed-files.outputs.core_any_changed == 'true' }}
+          LIB_CHANGED: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }}
+        run: |
+          bash ./.github/scripts/set_push_chunks.sh
 
-    - name: Upload sketches found
-      if: ${{ steps.set-chunks.outputs.build_all == 'false' && steps.set-chunks.outputs.build_libraries == 'true' }}
-      uses: actions/upload-artifact@v4
-      with:
-        name: sketches_found
-        path: sketches_found.txt
-        overwrite: true
-        if-no-files-found: error
+      - name: Upload sketches found
+        if: ${{ steps.set-chunks.outputs.build_all == 'false' && steps.set-chunks.outputs.build_libraries == 'true' }}
+        uses: actions/upload-artifact@v4
+        with:
+          name: sketches_found
+          path: sketches_found.txt
+          overwrite: true
+          if-no-files-found: error
 
   # Ubuntu
   build-arduino-linux:
@@ -153,45 +153,45 @@ jobs:
         chunk: ${{ fromJson(needs.gen-chunks.outputs.chunks) }}
 
     steps:
-    - uses: actions/checkout@v4
-    - uses: actions/setup-python@v5
-      with:
-        python-version: '3.x'
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: "3.x"
 
-    - name: Get libs cache
-      uses: actions/cache@v4
-      with:
-        key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }}
-        path: |
-          ./tools/dist
-          ./tools/esp32-arduino-libs
-          ./tools/esptool
-          ./tools/mk*
-          ./tools/openocd-esp32
-          ./tools/riscv32-*
-          ./tools/xtensa-*
+      - name: Get libs cache
+        uses: actions/cache@v4
+        with:
+          key: libs-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package/package_esp32_index.template.json', 'tools/get.py') }}
+          path: |
+            ./tools/dist
+            ./tools/esp32-arduino-libs
+            ./tools/esptool
+            ./tools/mk*
+            ./tools/openocd-esp32
+            ./tools/riscv32-*
+            ./tools/xtensa-*
 
-    - name: Build all sketches
-      if: ${{ needs.gen-chunks.outputs.build_all == 'true' }}
-      run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ env.MAX_CHUNKS }} 1
+      - name: Build all sketches
+        if: ${{ needs.gen-chunks.outputs.build_all == 'true' }}
+        run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ env.MAX_CHUNKS }} 1
 
-    - name: Download sketches found
-      if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }}
-      uses: actions/download-artifact@v4
-      with:
-        name: sketches_found
+      - name: Download sketches found
+        if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }}
+        uses: actions/download-artifact@v4
+        with:
+          name: sketches_found
 
-    - name: Build selected sketches
-      if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }}
-      run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ needs.gen-chunks.outputs.chunk_count }} 1 sketches_found.txt
+      - name: Build selected sketches
+        if: ${{ needs.gen-chunks.outputs.build_all == 'false' && needs.gen-chunks.outputs.build_libraries == 'true' }}
+        run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} ${{ needs.gen-chunks.outputs.chunk_count }} 1 sketches_found.txt
 
-    #Upload cli compile json as artifact
-    - name: Upload cli compile json
-      uses: actions/upload-artifact@v4
-      with:
-        name: pr_cli_compile_${{ matrix.chunk }}
-        path: cli_compile_${{ matrix.chunk }}.json
-        overwrite: true
+      #Upload cli compile json as artifact
+      - name: Upload cli compile json
+        uses: actions/upload-artifact@v4
+        with:
+          name: pr_cli_compile_${{ matrix.chunk }}
+          path: cli_compile_${{ matrix.chunk }}.json
+          overwrite: true
 
   # Windows and MacOS
   build-arduino-win-mac:
@@ -205,35 +205,35 @@ jobs:
         os: [windows-latest, macOS-latest]
 
     steps:
-    - uses: actions/checkout@v4
-    - uses: actions/setup-python@v5
-      with:
-        python-version: '3.x'
-    - name: Build Sketches
-      run: bash ./.github/scripts/on-push.sh
-
-  # PlatformIO on Windows, Ubuntu and Mac
-  build-platformio:
-    name: PlatformIO on ${{ matrix.os }}
-    needs: gen-chunks
-    if: |
-      needs.gen-chunks.outputs.build_all == 'true' ||
-      needs.gen-chunks.outputs.build_static_sketches == 'true' ||
-      needs.gen-chunks.outputs.build_platformio == 'true'
-    runs-on: ${{ matrix.os }}
-    strategy:
-      fail-fast: false
-      matrix:
-        os: [ubuntu-latest, windows-latest, macOS-latest]
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: "3.x"
+      - name: Build Sketches
+        run: bash ./.github/scripts/on-push.sh
 
-    steps:
-    - uses: actions/checkout@v4
-    - uses: actions/setup-python@v5
-      with:
-        python-version: '3.x'
-    - name: Build Sketches
-      run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO
+  # # PlatformIO on Windows, Ubuntu and Mac
+  # build-platformio:
+  #   name: PlatformIO on ${{ matrix.os }}
+  #   needs: gen-chunks
+  #   if: |
+  #     needs.gen-chunks.outputs.build_all == 'true' ||
+  #     needs.gen-chunks.outputs.build_static_sketches == 'true' ||
+  #     needs.gen-chunks.outputs.build_platformio == 'true'
+  #   runs-on: ${{ matrix.os }}
+  #   strategy:
+  #     fail-fast: false
+  #     matrix:
+  #       os: [ubuntu-latest, windows-latest, macOS-latest]
+  #   steps:
+  #     - uses: actions/checkout@v4
+  #     - uses: actions/setup-python@v5
+  #       with:
+  #         python-version: "3.x"
+  #     - name: Build Sketches
+  #       run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO
 
+  # ESP-IDF component build
   build-esp-idf-component:
     name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
     needs: gen-chunks
@@ -249,8 +249,18 @@ jobs:
         # See https://hub.docker.com/r/espressif/idf/tags and
         # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
         # for details.
-        idf_ver: ["release-v5.1"]
-        idf_target: ["esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2"]
+        idf_ver: ["release-v5.3"]
+        idf_target:
+          [
+            "esp32",
+            "esp32s2",
+            "esp32s3",
+            "esp32c2",
+            "esp32c3",
+            "esp32c6",
+            "esp32h2",
+            "esp32p4"
+          ]
     container: espressif/idf:${{ matrix.idf_ver }}
     steps:
       - name: Check out arduino-esp32 as a component
@@ -275,16 +285,15 @@ jobs:
     if: github.event_name == 'push' && github.ref == 'refs/heads/master'
     runs-on: ubuntu-latest
     steps:
-    # Check out repository
+      # Check out repository
       - name: Checkout repository
         uses: actions/checkout@v4
         with:
           token: ${{secrets.GITHUB_TOKEN}}
-          fetch-depth: '0'
+          fetch-depth: "0"
 
       - name: Switch branch
-        run:
-          git checkout remotes/origin/gh-pages
+        run: git checkout remotes/origin/gh-pages
 
       - name: Download sketches reports artifact
         uses: actions/download-artifact@v4
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f8aa779d994..53a512dd54f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -10,15 +10,15 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v4
-      with:
-        fetch-depth: 0
-    - uses: actions/setup-python@v5
-      with:
-        python-version: '3.x'
-    - run: pip install packaging
-    - run: pip install pyserial
-    - name: Build Release
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      run: bash ./.github/scripts/on-release.sh
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+      - uses: actions/setup-python@v5
+        with:
+          python-version: "3.x"
+      - run: pip install packaging
+      - run: pip install pyserial
+      - name: Build Release
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: bash ./.github/scripts/on-release.sh
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index f57a1925c1c..0db3b98782b 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -16,22 +16,22 @@ on:
   pull_request:
     types: [opened, reopened, closed, synchronize, labeled, unlabeled]
     paths:
-      - '.github/workflows/tests*'
-      - '.github/scripts/*.sh'
-      - '!.github/scripts/check-cmakelists.sh'
-      - '!.github/scripts/find_*'
-      - '!.github/scripts/on-*.sh'
-      - '!.github/scripts/set_push_chunks.sh'
-      - '!.github/scripts/update-version.sh'
-      - '!.github/scripts/upload_py_tools.sh'
-      - 'tests/**'
-      - 'cores/**'
-      - 'libraries/*/src/**.cpp'
-      - 'libraries/*/src/**.h'
-      - 'libraries/*/src/**.c'
-      - 'package/**'
+      - ".github/workflows/tests*"
+      - ".github/scripts/*.sh"
+      - "!.github/scripts/check-cmakelists.sh"
+      - "!.github/scripts/find_*"
+      - "!.github/scripts/on-*.sh"
+      - "!.github/scripts/set_push_chunks.sh"
+      - "!.github/scripts/update-version.sh"
+      - "!.github/scripts/upload_py_tools.sh"
+      - "tests/**"
+      - "cores/**"
+      - "libraries/*/src/**.cpp"
+      - "libraries/*/src/**.h"
+      - "libraries/*/src/**.c"
+      - "package/**"
   schedule:
-    - cron: '0 2 * * *'
+    - cron: "0 2 * * *"
 
 concurrency:
   group: tests-${{ github.event.pull_request.number || github.ref }}
@@ -115,7 +115,7 @@ jobs:
       fail-fast: false
       matrix:
         type: ${{ fromJson(needs.gen-matrix.outputs.qemu-types) }}
-        chip: ['esp32', 'esp32c3']
+        chip: ["esp32", "esp32c3"]
     with:
       type: ${{ matrix.type }}
       chip: ${{ matrix.chip }}
diff --git a/.github/workflows/tests_build.yml b/.github/workflows/tests_build.yml
index 090dfa8136b..7a5a2959657 100644
--- a/.github/workflows/tests_build.yml
+++ b/.github/workflows/tests_build.yml
@@ -5,11 +5,11 @@ on:
     inputs:
       type:
         type: string
-        description: 'Type of tests to build'
+        description: "Type of tests to build"
         required: true
       chip:
         type: string
-        description: 'Chip to build tests for'
+        description: "Chip to build tests for"
         required: true
 
 jobs:
diff --git a/.github/workflows/tests_hw.yml b/.github/workflows/tests_hw.yml
index d7922500f10..76480ed7c0e 100644
--- a/.github/workflows/tests_hw.yml
+++ b/.github/workflows/tests_hw.yml
@@ -5,11 +5,11 @@ on:
     inputs:
       type:
         type: string
-        description: 'Type of tests to run'
+        description: "Type of tests to run"
         required: true
       chip:
         type: string
-        description: 'Chip to run tests for'
+        description: "Chip to run tests for"
         required: true
 
 env:
diff --git a/.github/workflows/tests_qemu.yml b/.github/workflows/tests_qemu.yml
index 0b4ec18e7ac..6675909c9df 100644
--- a/.github/workflows/tests_qemu.yml
+++ b/.github/workflows/tests_qemu.yml
@@ -64,8 +64,8 @@ jobs:
         if: ${{ steps.check-tests.outputs.enabled == 'true' }}
         with:
           cache-dependency-path: tests/requirements.txt
-          cache: 'pip'
-          python-version: '3.x'
+          cache: "pip"
+          python-version: "3.x"
 
       - name: Install Python dependencies
         if: ${{ steps.check-tests.outputs.enabled == 'true' }}
diff --git a/.github/workflows/tests_results.yml b/.github/workflows/tests_results.yml
index f9c572bf546..4ef338a9e16 100644
--- a/.github/workflows/tests_results.yml
+++ b/.github/workflows/tests_results.yml
@@ -18,11 +18,11 @@ jobs:
       github.event.workflow_run.conclusion == 'timed_out'
     runs-on: ubuntu-latest
     permissions:
-        actions: write
-        statuses: write
-        checks: write
-        pull-requests: write
-        contents: write
+      actions: write
+      statuses: write
+      checks: write
+      pull-requests: write
+      contents: write
     steps:
       - uses: actions/checkout@v4
         with:
@@ -139,13 +139,13 @@ jobs:
             core.info(`${name} is ${state}`);
 
       - name: Create output folder
-        if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }}
+        if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled
         run: |
           rm -rf artifacts
           mkdir -p runtime-tests-results
 
       - name: Generate badge
-        if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }}
+        if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled
         uses: jaywcjlove/generated-badges@v1.0.13
         with:
           label: Runtime Tests
@@ -154,7 +154,7 @@ jobs:
           color: ${{ job.status == 'success' && 'green' || 'red' }}
 
       - name: Push badge
-        if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }}
+        if: ${{ !cancelled() && (env.original_event == 'schedule' || env.original_event == 'workflow_dispatch') }} # codespell:ignore cancelled
         run: |
           git config user.name "github-actions[bot]"
           git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
diff --git a/.github/workflows/tests_wokwi.yml b/.github/workflows/tests_wokwi.yml
index a891ca89dfd..f5eb2efcad2 100644
--- a/.github/workflows/tests_wokwi.yml
+++ b/.github/workflows/tests_wokwi.yml
@@ -247,8 +247,8 @@ jobs:
         if: ${{ steps.check-tests.outputs.enabled == 'true' }}
         with:
           cache-dependency-path: tests/requirements.txt
-          cache: 'pip'
-          python-version: '3.x'
+          cache: "pip"
+          python-version: "3.x"
 
       - name: Install dependencies
         if: ${{ steps.check-tests.outputs.enabled == 'true' }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 6a949631bd9..f80261422b0 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -12,8 +12,9 @@ default_language_version:
 
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: "v4.5.0"
+    rev: "v5.0.0"
     hooks:
+      # Generic checks
       - id: check-case-conflict
       - id: check-symlinks
       - id: debug-statements
@@ -25,6 +26,8 @@ repos:
         args: [--fix=lf]
       - id: trailing-whitespace
         args: [--markdown-linebreak-ext=md]
+
+      # JSON formatting
       - id: pretty-format-json
         stages: [manual]
         args: [--autofix]
@@ -35,40 +38,67 @@ repos:
               package\.json$|
               ^package\/.*$
           )
+
   - repo: https://github.com/codespell-project/codespell
     rev: "v2.3.0"
     hooks:
+      # Spell checking
       - id: codespell
         exclude: ^.*\.(svd|SVD)$
+
   - repo: https://github.com/pre-commit/mirrors-clang-format
     rev: "v18.1.3"
     hooks:
+      # C/C++ formatting
       - id: clang-format
         types_or: [c, c++]
         exclude: ^.*\/build_opt\.h$
+
   - repo: https://github.com/psf/black-pre-commit-mirror
-    rev: "22.10.0"
+    rev: "24.10.0"
     hooks:
+      # Python formatting
       - id: black
         types_or: [python]
         args: [--line-length=120] #From the arduino code style. Add as argument rather than creating a new config file.
+
   - repo: https://github.com/PyCQA/flake8
-    rev: "7.0.0"
+    rev: "7.1.1"
     hooks:
+      # Python linting
       - id: flake8
         types_or: [python]
         additional_dependencies:
           - flake8-bugbear
           - flake8-comprehensions
           - flake8-simplify
+
   - repo: https://github.com/pre-commit/mirrors-prettier
     rev: "v3.1.0"
     hooks:
+      # YAML formatting
       - id: prettier
         types_or: [yaml]
+
+  - repo: https://github.com/shellcheck-py/shellcheck-py
+    rev: "v0.10.0.1"
+    hooks:
+      # Bash linting
+      - id: shellcheck
+        types: [shell]
+
+  - repo: https://github.com/openstack/bashate
+    rev: "2.1.1"
+    hooks:
+      # Bash formatting
+      - id: bashate
+        types: [shell]
+        args: ["-i", "E006"] # Ignore E006: Line too long
+
   - repo: https://github.com/errata-ai/vale
-    rev: "v3.0.7"
+    rev: "v3.9.1"
     hooks:
+      # Sync vale styles and lint markdown and reStructuredText
       - id: vale
         name: vale-sync
         language_version: "1.21.6"
diff --git a/.shellcheckrc b/.shellcheckrc
new file mode 100644
index 00000000000..a7612e611a2
--- /dev/null
+++ b/.shellcheckrc
@@ -0,0 +1,11 @@
+# Shellcheck configuration file for ESP32 Arduino core
+
+# Optional checks. https://github.com/koalaman/shellcheck/wiki/optional
+enable=add-default-case,deprecate-which,avoid-nullary-conditions
+
+# Enable search for external sources
+external-sources=true
+
+# Search folder for sourced files.
+# Set to the folder where the original script is located.
+source-path=SCRIPTDIR
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a774deafd23..5ad9d8272ce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,8 +5,8 @@
 #   export ARDUINO_SKIP_IDF_VERSION_CHECK=1
 #   idf.py build
 
-set(min_supported_idf_version "5.1.0")
-set(max_supported_idf_version "5.1.99")
+set(min_supported_idf_version "5.3.0")
+set(max_supported_idf_version "5.4.99")
 set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")
 
 if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}")
@@ -25,7 +25,7 @@ endif()
 set(CORE_SRCS
   cores/esp32/base64.cpp
   cores/esp32/cbuf.cpp
-  cores/esp32/chip-debug-report.cpp
+  cores/esp32/ColorFormat.c
   cores/esp32/esp32-hal-adc.c
   cores/esp32/esp32-hal-bt.c
   cores/esp32/esp32-hal-cpu.c
@@ -42,12 +42,13 @@ set(CORE_SRCS
   cores/esp32/esp32-hal-sigmadelta.c
   cores/esp32/esp32-hal-spi.c
   cores/esp32/esp32-hal-time.c
-  cores/esp32/esp32-hal-timer.c
-  cores/esp32/esp32-hal-tinyusb.c
+  cores/esp32/esp32-hal-timer.c 
   cores/esp32/esp32-hal-touch.c
+  cores/esp32/esp32-hal-touch-ng.c
   cores/esp32/esp32-hal-uart.c
   cores/esp32/esp32-hal-rmt.c
   cores/esp32/Esp.cpp
+  cores/esp32/freertos_stats.cpp
   cores/esp32/FunctionalInterrupt.cpp
   cores/esp32/HardwareSerial.cpp
   cores/esp32/HEXBuilder.cpp
@@ -64,9 +65,6 @@ set(CORE_SRCS
   cores/esp32/StreamString.cpp
   cores/esp32/Tone.cpp
   cores/esp32/HWCDC.cpp
-  cores/esp32/USB.cpp
-  cores/esp32/USBCDC.cpp
-  cores/esp32/USBMSC.cpp
   cores/esp32/FirmwareMSC.cpp
   cores/esp32/firmware_msc_fat.c
   cores/esp32/wiring_pulse.c
@@ -74,72 +72,51 @@ set(CORE_SRCS
   cores/esp32/WMath.cpp
   cores/esp32/WString.cpp
   )
+if(IDF_TARGET MATCHES "esp32s2|esp32s3|esp32p4" AND CONFIG_TINYUSB_ENABLED)
+  list(APPEND CORE_SRCS
+    cores/esp32/esp32-hal-tinyusb.c
+    cores/esp32/USB.cpp
+    cores/esp32/USBCDC.cpp
+    cores/esp32/USBMSC.cpp)
+endif()
 
 set(ARDUINO_ALL_LIBRARIES
   ArduinoOTA
   AsyncUDP
-  BLE
-  BluetoothSerial
   DNSServer
   EEPROM
-  ESP_I2S
-  ESP_NOW
-  ESP_SR
   ESPmDNS
   Ethernet
   FFat
   FS
   HTTPClient
   HTTPUpdate
-  Insights
   LittleFS
   NetBIOS
   Network
-  OpenThread
   PPP
   Preferences
-  RainMaker
   SD_MMC
   SD
-  SimpleBLE
-  SPIFFS
   SPI
   Ticker
   Update
-  USB
   WebServer
-  NetworkClientSecure
   WiFi
-  WiFiProv
   Wire
-  Zigbee
   )
+if(IDF_TARGET MATCHES "esp32s2|esp32s3|esp32p4" AND CONFIG_TINYUSB_ENABLED)
+  list(APPEND ARDUINO_ALL_LIBRARIES USB)
+endif()
 
 set(ARDUINO_LIBRARY_ArduinoOTA_SRCS libraries/ArduinoOTA/src/ArduinoOTA.cpp)
-set(ARDUINO_LIBRARY_ArduinoOTA_REQUIRES esp_https_ota)
 
 set(ARDUINO_LIBRARY_AsyncUDP_SRCS libraries/AsyncUDP/src/AsyncUDP.cpp)
 
-set(ARDUINO_LIBRARY_BluetoothSerial_SRCS
-  libraries/BluetoothSerial/src/BluetoothSerial.cpp
-  libraries/BluetoothSerial/src/BTAddress.cpp
-  libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
-  libraries/BluetoothSerial/src/BTScanResultsSet.cpp)
-
 set(ARDUINO_LIBRARY_DNSServer_SRCS libraries/DNSServer/src/DNSServer.cpp)
 
 set(ARDUINO_LIBRARY_EEPROM_SRCS libraries/EEPROM/src/EEPROM.cpp)
 
-set(ARDUINO_LIBRARY_ESP_I2S_SRCS libraries/ESP_I2S/src/ESP_I2S.cpp)
-
-set(ARDUINO_LIBRARY_ESP_NOW_SRCS
-  libraries/ESP_NOW/src/ESP32_NOW.cpp
-  libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp)
-
-set(ARDUINO_LIBRARY_ESP_SR_SRCS
-  libraries/ESP_SR/src/ESP_SR.cpp
-  libraries/ESP_SR/src/esp32-hal-sr.c)
-
 set(ARDUINO_LIBRARY_ESPmDNS_SRCS libraries/ESPmDNS/src/ESPmDNS.cpp)
 
 set(ARDUINO_LIBRARY_Ethernet_SRCS libraries/Ethernet/src/ETH.cpp)
@@ -154,33 +131,16 @@ set(ARDUINO_LIBRARY_HTTPClient_SRCS libraries/HTTPClient/src/HTTPClient.cpp)
 
 set(ARDUINO_LIBRARY_HTTPUpdate_SRCS libraries/HTTPUpdate/src/HTTPUpdate.cpp)
 
-set(ARDUINO_LIBRARY_Insights_SRCS libraries/Insights/src/Insights.cpp)
-
 set(ARDUINO_LIBRARY_LittleFS_SRCS libraries/LittleFS/src/LittleFS.cpp)
-set(ARDUINO_LIBRARY_LittleFS_REQUIRES joltwallet__littlefs)
 
 set(ARDUINO_LIBRARY_NetBIOS_SRCS libraries/NetBIOS/src/NetBIOS.cpp)
 
-set(ARDUINO_LIBRARY_OpenThread_SRCS
-  libraries/OpenThread/src/OThreadCLI.cpp
-  libraries/OpenThread/src/OThreadCLI_Util.cpp)
-
 set(ARDUINO_LIBRARY_PPP_SRCS
   libraries/PPP/src/PPP.cpp
   libraries/PPP/src/ppp.c)
 
 set(ARDUINO_LIBRARY_Preferences_SRCS libraries/Preferences/src/Preferences.cpp)
 
-set(ARDUINO_LIBRARY_RainMaker_SRCS
-  libraries/RainMaker/src/RMaker.cpp
-  libraries/RainMaker/src/RMakerNode.cpp
-  libraries/RainMaker/src/RMakerParam.cpp
-  libraries/RainMaker/src/RMakerDevice.cpp
-  libraries/RainMaker/src/RMakerType.cpp
-  libraries/RainMaker/src/RMakerQR.cpp
-  libraries/RainMaker/src/RMakerUtils.cpp
-  libraries/RainMaker/src/AppInsights.cpp)
-
 set(ARDUINO_LIBRARY_SD_MMC_SRCS libraries/SD_MMC/src/SD_MMC.cpp)
 
 set(ARDUINO_LIBRARY_SD_SRCS
@@ -188,10 +148,6 @@ set(ARDUINO_LIBRARY_SD_SRCS
   libraries/SD/src/sd_diskio.cpp
   libraries/SD/src/sd_diskio_crc.c)
 
-set(ARDUINO_LIBRARY_SimpleBLE_SRCS libraries/SimpleBLE/src/SimpleBLE.cpp)
-
-set(ARDUINO_LIBRARY_SPIFFS_SRCS libraries/SPIFFS/src/SPIFFS.cpp)
-
 set(ARDUINO_LIBRARY_SPI_SRCS libraries/SPI/src/SPI.cpp)
 
 set(ARDUINO_LIBRARY_Ticker_SRCS libraries/Ticker/src/Ticker.cpp)
@@ -200,36 +156,34 @@ set(ARDUINO_LIBRARY_Update_SRCS
   libraries/Update/src/Updater.cpp
   libraries/Update/src/HttpsOTAUpdate.cpp)
 
-set(ARDUINO_LIBRARY_USB_SRCS
-  libraries/USB/src/USBHID.cpp
-  libraries/USB/src/USBMIDI.cpp
-  libraries/USB/src/USBHIDMouse.cpp
-  libraries/USB/src/USBHIDKeyboard.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_da_DK.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_de_DE.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_en_US.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_es_ES.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_fr_FR.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_hu_HU.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_it_IT.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_pt_BR.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_pt_PT.cpp
-  libraries/USB/src/keyboardLayout/KeyboardLayout_sv_SE.cpp
-  libraries/USB/src/USBHIDGamepad.cpp
-  libraries/USB/src/USBHIDConsumerControl.cpp
-  libraries/USB/src/USBHIDSystemControl.cpp
-  libraries/USB/src/USBHIDVendor.cpp
-  libraries/USB/src/USBVendor.cpp)
+if(IDF_TARGET MATCHES "esp32s2|esp32s3|esp32p4" AND CONFIG_TINYUSB_ENABLED)
+  set(ARDUINO_LIBRARY_USB_SRCS
+    libraries/USB/src/USBHID.cpp
+    libraries/USB/src/USBMIDI.cpp
+    libraries/USB/src/USBHIDMouse.cpp
+    libraries/USB/src/USBHIDKeyboard.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_da_DK.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_de_DE.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_en_US.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_es_ES.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_fr_FR.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_hu_HU.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_it_IT.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_pt_BR.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_pt_PT.cpp
+    libraries/USB/src/keyboardLayout/KeyboardLayout_sv_SE.cpp
+    libraries/USB/src/USBHIDGamepad.cpp
+    libraries/USB/src/USBHIDConsumerControl.cpp
+    libraries/USB/src/USBHIDSystemControl.cpp
+    libraries/USB/src/USBHIDVendor.cpp
+    libraries/USB/src/USBVendor.cpp)
+endif()
 
 set(ARDUINO_LIBRARY_WebServer_SRCS
   libraries/WebServer/src/WebServer.cpp
   libraries/WebServer/src/Parsing.cpp
   libraries/WebServer/src/detail/mimetable.cpp)
 
-set(ARDUINO_LIBRARY_NetworkClientSecure_SRCS
-  libraries/NetworkClientSecure/src/ssl_client.cpp
-  libraries/NetworkClientSecure/src/NetworkClientSecure.cpp)
-
 set(ARDUINO_LIBRARY_Network_SRCS
   libraries/Network/src/NetworkInterface.cpp
   libraries/Network/src/NetworkEvents.cpp
@@ -248,55 +202,8 @@ set(ARDUINO_LIBRARY_WiFi_SRCS
   libraries/WiFi/src/STA.cpp
   libraries/WiFi/src/AP.cpp)
 
-set(ARDUINO_LIBRARY_WiFiProv_SRCS libraries/WiFiProv/src/WiFiProv.cpp)
-
 set(ARDUINO_LIBRARY_Wire_SRCS libraries/Wire/src/Wire.cpp)
 
-set(ARDUINO_LIBRARY_Zigbee_SRCS
-  libraries/Zigbee/src/ZigbeeCore.cpp
-  libraries/Zigbee/src/ZigbeeEP.cpp
-  libraries/Zigbee/src/ZigbeeHandlers.cpp
-  libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp
-  libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp
-  libraries/Zigbee/src/ep/ZigbeeLight.cpp
-  libraries/Zigbee/src/ep/ZigbeeSwitch.cpp
-  libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp
-  libraries/Zigbee/src/ep/ZigbeeThermostat.cpp
-  )
-
-set(ARDUINO_LIBRARY_BLE_SRCS
-  libraries/BLE/src/BLE2901.cpp
-  libraries/BLE/src/BLE2902.cpp
-  libraries/BLE/src/BLE2904.cpp
-  libraries/BLE/src/BLEAddress.cpp
-  libraries/BLE/src/BLEAdvertisedDevice.cpp
-  libraries/BLE/src/BLEAdvertising.cpp
-  libraries/BLE/src/BLEBeacon.cpp
-  libraries/BLE/src/BLECharacteristic.cpp
-  libraries/BLE/src/BLECharacteristicMap.cpp
-  libraries/BLE/src/BLEClient.cpp
-  libraries/BLE/src/BLEDescriptor.cpp
-  libraries/BLE/src/BLEDescriptorMap.cpp
-  libraries/BLE/src/BLEDevice.cpp
-  libraries/BLE/src/BLEEddystoneTLM.cpp
-  libraries/BLE/src/BLEEddystoneURL.cpp
-  libraries/BLE/src/BLEExceptions.cpp
-  libraries/BLE/src/BLEHIDDevice.cpp
-  libraries/BLE/src/BLERemoteCharacteristic.cpp
-  libraries/BLE/src/BLERemoteDescriptor.cpp
-  libraries/BLE/src/BLERemoteService.cpp
-  libraries/BLE/src/BLEScan.cpp
-  libraries/BLE/src/BLESecurity.cpp
-  libraries/BLE/src/BLEServer.cpp
-  libraries/BLE/src/BLEService.cpp
-  libraries/BLE/src/BLEServiceMap.cpp
-  libraries/BLE/src/BLEUtils.cpp
-  libraries/BLE/src/BLEUUID.cpp
-  libraries/BLE/src/BLEValue.cpp
-  libraries/BLE/src/FreeRTOS.cpp
-  libraries/BLE/src/GeneralUtils.cpp
-  )
-
 set(ARDUINO_LIBRARIES_SRCS)
 set(ARDUINO_LIBRARIES_REQUIRES)
 set(ARDUINO_LIBRARIES_INCLUDEDIRS)
@@ -317,15 +224,11 @@ endforeach()
 set(includedirs variants/${CONFIG_ARDUINO_VARIANT}/ cores/esp32/ ${ARDUINO_LIBRARIES_INCLUDEDIRS})
 set(srcs ${CORE_SRCS} ${ARDUINO_LIBRARIES_SRCS})
 set(priv_includes cores/esp32/libb64)
-set(requires spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser espressif__network_provisioning)
-set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support bt esp_hid usb esp_psram ${ARDUINO_LIBRARIES_REQUIRES})
-
-if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_OpenThread)
-  #if(CONFIG_SOC_IEEE802154_SUPPORTED) # Does not work!
-  #if(CONFIG_OPENTHREAD_ENABLED) # Does not work!
-  if(IDF_TARGET STREQUAL "esp32c6" OR IDF_TARGET STREQUAL "esp32h2") # Sadly only this works
-    list(APPEND requires openthread)
-  endif()
+set(requires spi_flash esp_partition mbedtls wpa_supplicant esp_adc esp_eth http_parser esp_ringbuf esp_driver_gptimer esp_driver_usb_serial_jtag driver)
+set(priv_requires fatfs nvs_flash app_update bootloader_support bt esp_hid usb esp_psram ${ARDUINO_LIBRARIES_REQUIRES})
+
+if(IDF_TARGET STREQUAL "esp32p4")
+  list(APPEND requires esp_driver_touch_sens)
 endif()
 
 idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})
@@ -367,9 +270,12 @@ function(maybe_add_component component_name)
     endif()
 endfunction()
 
-if(IDF_TARGET MATCHES "esp32s2|esp32s3" AND CONFIG_TINYUSB_ENABLED)
+if(IDF_TARGET MATCHES "esp32s2|esp32s3|esp32p4" AND CONFIG_TINYUSB_ENABLED)
     maybe_add_component(arduino_tinyusb)
 endif()
 if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ArduinoOTA)
     maybe_add_component(esp_https_ota)
 endif()
+if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_LittleFS)
+    maybe_add_component(joltwallet__littlefs)
+endif()
diff --git a/Kconfig.projbuild b/Kconfig.projbuild
index 2085a11ea7d..9b53fb77e81 100644
--- a/Kconfig.projbuild
+++ b/Kconfig.projbuild
@@ -301,11 +301,6 @@ config ARDUINO_SELECTIVE_SD_MMC
     depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_FS
     default y
 
-config ARDUINO_SELECTIVE_SPIFFS
-    bool "Enable SPIFFS"
-    depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_FS
-    default y
-
 config ARDUINO_SELECTIVE_FFat
     bool "Enable FFat"
     depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_FS
@@ -355,7 +350,6 @@ config ARDUINO_SELECTIVE_ESPmDNS
 config ARDUINO_SELECTIVE_HTTPClient
     bool "Enable HTTPClient"
     depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Network
-    select ARDUINO_SELECTIVE_NetworkClientSecure
     default y
 
 config ARDUINO_SELECTIVE_NetBIOS
@@ -374,29 +368,4 @@ config ARDUINO_SELECTIVE_WiFi
     depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Network
     default y
 
-config ARDUINO_SELECTIVE_NetworkClientSecure
-    bool "Enable NetworkClientSecure"
-    depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Network
-    default y
-
-config ARDUINO_SELECTIVE_WiFiProv
-    bool "Enable WiFiProv"
-    depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Network && ARDUINO_SELECTIVE_WiFi
-    default y
-
-config ARDUINO_SELECTIVE_BLE
-    bool "Enable BLE"
-    depends on ARDUINO_SELECTIVE_COMPILATION
-    default y
-
-config ARDUINO_SELECTIVE_BluetoothSerial
-    bool "Enable BluetoothSerial"
-    depends on ARDUINO_SELECTIVE_COMPILATION
-    default y
-
-config ARDUINO_SELECTIVE_SimpleBLE
-    bool "Enable SimpleBLE"
-    depends on ARDUINO_SELECTIVE_COMPILATION
-    default y
-
 endmenu
diff --git a/README.md b/README.md
index ee1880b8d05..852d51f214e 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,6 @@
-# Arduino core for the ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6 and ESP32-H2
+# Tasmota Platformio Arduino for ESP32, ESP32-P4, ESP32-S2, ESP32-S3, ESP32-C2, ESP32-C3, ESP32-C6 and ESP32-H2
 
-[![Build Status](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml/badge.svg?branch=master&event=push)](https://github.com/espressif/arduino-esp32/actions/workflows/push.yml) [![External Libraries Test](https://github.com/espressif/arduino-esp32/actions/workflows/lib.yml/badge.svg?branch=master&event=schedule)](https://github.com/espressif/arduino-esp32/blob/gh-pages/LIBRARIES_TEST.md) [![Hardware Tests](https://github.com/espressif/arduino-esp32/blob/gh-pages/runtime-tests-results/badge.svg)](https://github.com/espressif/arduino-esp32/actions/workflows/tests_results.yml)
-
-### Need help or have a question? Join the chat at [Gitter](https://gitter.im/espressif/arduino-esp32) or [open a new Discussion](https://github.com/espressif/arduino-esp32/discussions)
-
-## Contents
-
-  - [Development Status](#development-status)
-  - [Development Planning](#development-planning)
-  - [Documentation](#documentation)
-  - [Supported Chips](#supported-chips)
-  - [Decoding exceptions](#decoding-exceptions)
-  - [Issue/Bug report template](#issuebug-report-template)
-  - [Contributing](#contributing)
-
-### Development Status
-
-Latest Stable Release  [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Downloads](https://img.shields.io/github/downloads/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/)
-
-Latest Development Release  [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Release Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/)
-
-### Development Planning
-
-Our Development is fully tracked on this public **[Roadmap 🎉](https://github.com/orgs/espressif/projects/3)**
-
-For even more information you can join our **[Monthly Community Meetings 🔔](https://github.com/espressif/arduino-esp32/discussions/categories/monthly-community-meetings).**
+### [![GitHub Releases](https://img.shields.io/github/downloads/tasmota/arduino-esp32/total?label=downloads)](https://github.com/tasmota/arduino-esp32/releases/latest)
 
 ### Documentation
 
@@ -36,55 +12,21 @@ You can use the [Arduino-ESP32 Online Documentation](https://docs.espressif.com/
 
 ---
 
-**APIs compatibility with ESP8266 and Arduino-CORE (Arduino.cc) is explained [here](https://docs.espressif.com/projects/arduino-esp32/en/latest/libraries.html#apis).**
-
----
-
-* [Getting Started](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html)
-* [Installing (Windows, Linux and macOS)](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html)
-* [Libraries](https://docs.espressif.com/projects/arduino-esp32/en/latest/libraries.html)
-* [Arduino as an ESP-IDF component](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html)
-* [FAQ](https://docs.espressif.com/projects/arduino-esp32/en/latest/faq.html)
-* [Troubleshooting](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html)
-
 ### Supported Chips
 
-Here are the ESP32 series supported by the Arduino-ESP32 project:
+Here are the ESP32 series supported by the Tasmota Arduino-ESP32 project:
 
 | **SoC**  | **Stable** | **Development** |                                           **Datasheet**                                           |
 |----------|:----------:|:---------------:|:-------------------------------------------------------------------------------------------------:|
-| ESP32    |     Yes    |       Yes       |    [ESP32](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf)    |
+| ESP32    |     Yes    |       Yes       | [ESP32](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf)    |
+| ESP32solo1|    Yes    |       Yes       | [ESP32solo1](https://www.espressif.com/sites/default/files/documentation/esp32-solo-1_datasheet_en.pdf)  |
 | ESP32-S2 |     Yes    |       Yes       | [ESP32-S2](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) |
-| ESP32-C3 |     Yes    |       Yes       | [ESP32-C3](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) |
 | ESP32-S3 |     Yes    |       Yes       | [ESP32-S3](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) |
+| ESP32-C2 |     Yes    |       Yes       | [ESP32-C2](https://www.espressif.com/sites/default/files/documentation/esp8684_datasheet_en.pdf)  |
+| ESP32-C3 |     Yes    |       Yes       | [ESP32-C3](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) |
 | ESP32-C6 |     Yes    |       Yes       | [ESP32-C6](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) |
 | ESP32-H2 |     Yes    |       Yes       | [ESP32-H2](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) |
+| ESP32-P4 |     No     |       Yes       | [ESP32-P4](https://www.espressif.com/sites/default/files/documentation/esp32-p4_datasheet_en.pdf) |
 
-> [!NOTE]
-> ESP32-C2 is also supported by Arduino-ESP32 but requires rebuilding the static libraries. This is not trivial and requires a good understanding of the ESP-IDF
-> build system. For more information, see the [Lib Builder documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/lib_builder.html).
 
 For more details visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html#supported-soc-s) documentation page.
-
-### Decoding exceptions
-
-You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
-
-### Issue/Bug report template
-
-Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labeled as [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+).
-
-Finally, if you are sure no one else had the issue, follow the **Issue template** or **Feature request template** while reporting any [new Issue](https://github.com/espressif/arduino-esp32/issues/new/choose).
-
-### External libraries compilation test
-
-We have set-up CI testing for external libraries for ESP32 Arduino core. You can check test results in the file [LIBRARIES_TEST](https://github.com/espressif/arduino-esp32/blob/gh-pages/LIBRARIES_TEST.md).
-For more information and how to add your library to the test see [external library testing](https://docs.espressif.com/projects/arduino-esp32/en/latest/external_libraries_test.html) in the documentation.
-
-### Contributing
-
-We welcome contributions to the Arduino ESP32 project!
-
-See [contributing](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html) in the documentation for more information on how to contribute to the project.
-
-> We would like to have this repository in a polite and friendly atmosphere, so please be kind and respectful to others. For more details, look at [Code of Conduct](https://github.com/espressif/arduino-esp32/blob/master/CODE_OF_CONDUCT.md).
diff --git a/boards.txt b/boards.txt
index 817c7b7441c..9a55e7b0ef9 100644
--- a/boards.txt
+++ b/boards.txt
@@ -161,6 +161,195 @@ esp32c2.menu.EraseFlash.all.upload.erase_cmd=-e
 
 ##############################################################
 
+esp32p4.name=ESP32P4 Dev Module
+
+esp32p4.bootloader.tool=esptool_py
+esp32p4.bootloader.tool.default=esptool_py
+
+esp32p4.upload.tool=esptool_py
+esp32p4.upload.tool.default=esptool_py
+esp32p4.upload.tool.network=esp_ota
+
+esp32p4.upload.maximum_size=1310720
+esp32p4.upload.maximum_data_size=327680
+esp32p4.upload.flags=
+esp32p4.upload.extra_flags=
+esp32p4.upload.use_1200bps_touch=false
+esp32p4.upload.wait_for_upload_port=false
+
+esp32p4.serial.disableDTR=false
+esp32p4.serial.disableRTS=false
+
+esp32p4.build.tarch=riscv32
+esp32p4.build.target=esp
+esp32p4.build.mcu=esp32p4
+esp32p4.build.core=esp32
+esp32p4.build.variant=esp32p4
+esp32p4.build.board=ESP32P4_DEV
+esp32p4.build.bootloader_addr=0x2000
+
+esp32p4.build.usb_mode=0
+esp32p4.build.cdc_on_boot=0
+esp32p4.build.msc_on_boot=0
+esp32p4.build.dfu_on_boot=0
+esp32p4.build.f_cpu=360000000L
+esp32p4.build.flash_size=4MB
+esp32p4.build.flash_freq=80m
+esp32p4.build.img_freq=80m
+esp32p4.build.flash_mode=qio
+esp32p4.build.boot=qio
+esp32p4.build.partitions=default
+esp32p4.build.defines=
+
+## IDE 2.0 Seems to not update the value
+esp32p4.menu.JTAGAdapter.default=Disabled
+esp32p4.menu.JTAGAdapter.default.build.copy_jtag_files=0
+esp32p4.menu.JTAGAdapter.builtin=Integrated USB JTAG
+esp32p4.menu.JTAGAdapter.builtin.build.openocdscript=esp32p4-builtin.cfg
+esp32p4.menu.JTAGAdapter.builtin.build.copy_jtag_files=1
+esp32p4.menu.JTAGAdapter.external=FTDI Adapter
+esp32p4.menu.JTAGAdapter.external.build.openocdscript=esp32p4-ftdi.cfg
+esp32p4.menu.JTAGAdapter.external.build.copy_jtag_files=1
+esp32p4.menu.JTAGAdapter.bridge=ESP USB Bridge
+esp32p4.menu.JTAGAdapter.bridge.build.openocdscript=esp32p4-bridge.cfg
+esp32p4.menu.JTAGAdapter.bridge.build.copy_jtag_files=1
+
+esp32p4.menu.PSRAM.disabled=Disabled
+esp32p4.menu.PSRAM.disabled.build.defines=
+esp32p4.menu.PSRAM.enabled=Enabled
+esp32p4.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
+
+esp32p4.menu.USBMode.default=USB-OTG (TinyUSB)
+esp32p4.menu.USBMode.default.build.usb_mode=0
+esp32p4.menu.USBMode.hwcdc=Hardware CDC and JTAG
+esp32p4.menu.USBMode.hwcdc.build.usb_mode=1
+
+esp32p4.menu.CDCOnBoot.default=Disabled
+esp32p4.menu.CDCOnBoot.default.build.cdc_on_boot=0
+esp32p4.menu.CDCOnBoot.cdc=Enabled
+esp32p4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
+
+esp32p4.menu.MSCOnBoot.default=Disabled
+esp32p4.menu.MSCOnBoot.default.build.msc_on_boot=0
+esp32p4.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode)
+esp32p4.menu.MSCOnBoot.msc.build.msc_on_boot=1
+
+esp32p4.menu.DFUOnBoot.default=Disabled
+esp32p4.menu.DFUOnBoot.default.build.dfu_on_boot=0
+esp32p4.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode)
+esp32p4.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
+
+esp32p4.menu.UploadMode.default=UART0 / Hardware CDC
+esp32p4.menu.UploadMode.default.upload.use_1200bps_touch=false
+esp32p4.menu.UploadMode.default.upload.wait_for_upload_port=false
+esp32p4.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB)
+esp32p4.menu.UploadMode.cdc.upload.use_1200bps_touch=true
+esp32p4.menu.UploadMode.cdc.upload.wait_for_upload_port=true
+
+esp32p4.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
+esp32p4.menu.PartitionScheme.default.build.partitions=default
+esp32p4.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
+esp32p4.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
+esp32p4.menu.PartitionScheme.default_8MB=8M with spiffs (3MB APP/1.5MB SPIFFS)
+esp32p4.menu.PartitionScheme.default_8MB.build.partitions=default_8MB
+esp32p4.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336
+esp32p4.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
+esp32p4.menu.PartitionScheme.minimal.build.partitions=minimal
+esp32p4.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2)
+esp32p4.menu.PartitionScheme.no_fs.build.partitions=no_fs
+esp32p4.menu.PartitionScheme.no_fs.upload.maximum_size=2031616
+esp32p4.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
+esp32p4.menu.PartitionScheme.no_ota.build.partitions=no_ota
+esp32p4.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
+esp32p4.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
+esp32p4.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
+esp32p4.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
+esp32p4.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
+esp32p4.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
+esp32p4.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
+esp32p4.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
+esp32p4.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
+esp32p4.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
+esp32p4.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
+esp32p4.menu.PartitionScheme.huge_app.build.partitions=huge_app
+esp32p4.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
+esp32p4.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
+esp32p4.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
+esp32p4.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
+esp32p4.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FATFS)
+esp32p4.menu.PartitionScheme.fatflash.build.partitions=ffat
+esp32p4.menu.PartitionScheme.fatflash.upload.maximum_size=2097152
+esp32p4.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9.9MB FATFS)
+esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
+esp32p4.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728
+esp32p4.menu.PartitionScheme.custom=Custom
+esp32p4.menu.PartitionScheme.custom.build.partitions=
+esp32p4.menu.PartitionScheme.custom.upload.maximum_size=16777216
+
+## From https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/kconfig.html#config-esp-default-cpu-freq-mhz
+esp32p4.menu.CPUFreq.360=360MHz
+esp32p4.menu.CPUFreq.360.build.f_cpu=360000000L
+esp32p4.menu.CPUFreq.40=40MHz
+esp32p4.menu.CPUFreq.40.build.f_cpu=40000000L
+
+esp32p4.menu.FlashMode.qio=QIO
+esp32p4.menu.FlashMode.qio.build.flash_mode=dio
+esp32p4.menu.FlashMode.qio.build.boot=qio
+esp32p4.menu.FlashMode.dio=DIO
+esp32p4.menu.FlashMode.dio.build.flash_mode=dio
+esp32p4.menu.FlashMode.dio.build.boot=dio
+
+esp32p4.menu.FlashFreq.80=80MHz
+esp32p4.menu.FlashFreq.80.build.flash_freq=80m
+esp32p4.menu.FlashFreq.40=40MHz
+esp32p4.menu.FlashFreq.40.build.flash_freq=40m
+
+esp32p4.menu.FlashSize.4M=4MB (32Mb)
+esp32p4.menu.FlashSize.4M.build.flash_size=4MB
+esp32p4.menu.FlashSize.8M=8MB (64Mb)
+esp32p4.menu.FlashSize.8M.build.flash_size=8MB
+esp32p4.menu.FlashSize.8M.build.partitions=default_8MB
+esp32p4.menu.FlashSize.2M=2MB (16Mb)
+esp32p4.menu.FlashSize.2M.build.flash_size=2MB
+esp32p4.menu.FlashSize.2M.build.partitions=minimal
+esp32p4.menu.FlashSize.16M=16MB (128Mb)
+esp32p4.menu.FlashSize.16M.build.flash_size=16MB
+
+esp32p4.menu.UploadSpeed.921600=921600
+esp32p4.menu.UploadSpeed.921600.upload.speed=921600
+esp32p4.menu.UploadSpeed.115200=115200
+esp32p4.menu.UploadSpeed.115200.upload.speed=115200
+esp32p4.menu.UploadSpeed.256000.windows=256000
+esp32p4.menu.UploadSpeed.256000.upload.speed=256000
+esp32p4.menu.UploadSpeed.230400.windows.upload.speed=256000
+esp32p4.menu.UploadSpeed.230400=230400
+esp32p4.menu.UploadSpeed.230400.upload.speed=230400
+esp32p4.menu.UploadSpeed.460800.linux=460800
+esp32p4.menu.UploadSpeed.460800.macosx=460800
+esp32p4.menu.UploadSpeed.460800.upload.speed=460800
+esp32p4.menu.UploadSpeed.512000.windows=512000
+esp32p4.menu.UploadSpeed.512000.upload.speed=512000
+
+esp32p4.menu.DebugLevel.none=None
+esp32p4.menu.DebugLevel.none.build.code_debug=0
+esp32p4.menu.DebugLevel.error=Error
+esp32p4.menu.DebugLevel.error.build.code_debug=1
+esp32p4.menu.DebugLevel.warn=Warn
+esp32p4.menu.DebugLevel.warn.build.code_debug=2
+esp32p4.menu.DebugLevel.info=Info
+esp32p4.menu.DebugLevel.info.build.code_debug=3
+esp32p4.menu.DebugLevel.debug=Debug
+esp32p4.menu.DebugLevel.debug.build.code_debug=4
+esp32p4.menu.DebugLevel.verbose=Verbose
+esp32p4.menu.DebugLevel.verbose.build.code_debug=5
+
+esp32p4.menu.EraseFlash.none=Disabled
+esp32p4.menu.EraseFlash.none.upload.erase_cmd=
+esp32p4.menu.EraseFlash.all=Enabled
+esp32p4.menu.EraseFlash.all.upload.erase_cmd=-e
+
+##############################################################
+
 esp32h2.name=ESP32H2 Dev Module
 
 esp32h2.bootloader.tool=esptool_py
@@ -342,7 +531,15 @@ esp32h2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_co
 esp32h2.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor)
 esp32h2.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP
 esp32h2.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port
-
+esp32h2.menu.ZigbeeMode.ed_debug=Zigbee ED (end device) - Debug
+esp32h2.menu.ZigbeeMode.ed_debug.build.zigbee_mode=-DZIGBEE_MODE_ED
+esp32h2.menu.ZigbeeMode.ed_debug.build.zigbee_libs=-lesp_zb_api_ed.debug -lesp_zb_cli_command -lzboss_stack.ed.debug -lzboss_port.debug
+esp32h2.menu.ZigbeeMode.zczr_debug=Zigbee ZCZR (coordinator/router) - Debug
+esp32h2.menu.ZigbeeMode.zczr_debug.build.zigbee_mode=-DZIGBEE_MODE_ZCZR
+esp32h2.menu.ZigbeeMode.zczr_debug.build.zigbee_libs=-lesp_zb_api_zczr.debug -lesp_zb_cli_command -lzboss_stack.zczr.debug -lzboss_port.debug
+esp32h2.menu.ZigbeeMode.rcp_debug=Zigbee RCP (radio co-processor) - Debug
+esp32h2.menu.ZigbeeMode.rcp_debug.build.zigbee_mode=-DZIGBEE_MODE_RCP
+esp32h2.menu.ZigbeeMode.rcp_debug.build.zigbee_libs=-lesp_zb_api_rcp.debug -lesp_zb_cli_command -lzboss_stack.rcp.debug -lzboss_port.debug
 
 ##############################################################
 
@@ -534,6 +731,15 @@ esp32c6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_co
 esp32c6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor)
 esp32c6.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP
 esp32c6.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port
+esp32c6.menu.ZigbeeMode.ed_debug=Zigbee ED (end device) - Debug
+esp32c6.menu.ZigbeeMode.ed_debug.build.zigbee_mode=-DZIGBEE_MODE_ED
+esp32c6.menu.ZigbeeMode.ed_debug.build.zigbee_libs=-lesp_zb_api_ed.debug -lesp_zb_cli_command -lzboss_stack.ed.debug -lzboss_port.debug
+esp32c6.menu.ZigbeeMode.zczr_debug=Zigbee ZCZR (coordinator/router) - Debug
+esp32c6.menu.ZigbeeMode.zczr_debug.build.zigbee_mode=-DZIGBEE_MODE_ZCZR
+esp32c6.menu.ZigbeeMode.zczr_debug.build.zigbee_libs=-lesp_zb_api_zczr.debug -lesp_zb_cli_command -lzboss_stack.zczr.debug -lzboss_port.debug
+esp32c6.menu.ZigbeeMode.rcp_debug=Zigbee RCP (radio co-processor) - Debug
+esp32c6.menu.ZigbeeMode.rcp_debug.build.zigbee_mode=-DZIGBEE_MODE_RCP
+esp32c6.menu.ZigbeeMode.rcp_debug.build.zigbee_libs=-lesp_zb_api_rcp.debug -lesp_zb_cli_command -lzboss_stack.rcp.debug -lzboss_port.debug
 
 ##############################################################
 
@@ -47051,3 +47257,457 @@ waveshare_esp32_s3_touch_amoled_191.menu.EraseFlash.all=Enabled
 waveshare_esp32_s3_touch_amoled_191.menu.EraseFlash.all.upload.erase_cmd=-e
 
 ##############################################################
+
+
+Pcbcupid_GLYPH_C3.name=Pcbcupid GLYPH C3
+Pcbcupid_GLYPH_C3.vid.0=0x2886
+Pcbcupid_GLYPH_C3.pid.0=0x0046
+
+Pcbcupid_GLYPH_C3.bootloader.tool=esptool_py
+Pcbcupid_GLYPH_C3.bootloader.tool.default=esptool_py
+
+Pcbcupid_GLYPH_C3.upload.tool=esptool_py
+Pcbcupid_GLYPH_C3.upload.tool.default=esptool_py
+Pcbcupid_GLYPH_C3.upload.tool.network=esp_ota
+
+Pcbcupid_GLYPH_C3.upload.maximum_size=1310720
+Pcbcupid_GLYPH_C3.upload.maximum_data_size=327680
+Pcbcupid_GLYPH_C3.upload.flags=
+Pcbcupid_GLYPH_C3.upload.extra_flags=
+Pcbcupid_GLYPH_C3.upload.use_1200bps_touch=false
+Pcbcupid_GLYPH_C3.upload.wait_for_upload_port=false
+
+Pcbcupid_GLYPH_C3.serial.disableDTR=false
+Pcbcupid_GLYPH_C3.serial.disableRTS=false
+
+Pcbcupid_GLYPH_C3.build.tarch=riscv32
+Pcbcupid_GLYPH_C3.build.target=esp
+Pcbcupid_GLYPH_C3.build.mcu=esp32c3
+Pcbcupid_GLYPH_C3.build.core=esp32
+Pcbcupid_GLYPH_C3.build.variant=Pcbcupid_GLYPH_C3
+Pcbcupid_GLYPH_C3.build.board=PCBCUPID_GLYPHC3
+Pcbcupid_GLYPH_C3.build.bootloader_addr=0x0
+
+Pcbcupid_GLYPH_C3.build.cdc_on_boot=1
+Pcbcupid_GLYPH_C3.build.f_cpu=160000000L
+Pcbcupid_GLYPH_C3.build.flash_size=4MB
+Pcbcupid_GLYPH_C3.build.flash_freq=80m
+Pcbcupid_GLYPH_C3.build.flash_mode=qio
+Pcbcupid_GLYPH_C3.build.boot=qio
+Pcbcupid_GLYPH_C3.build.partitions=default
+Pcbcupid_GLYPH_C3.build.defines=
+
+Pcbcupid_GLYPH_C3.menu.CDCOnBoot.default=Enabled
+Pcbcupid_GLYPH_C3.menu.CDCOnBoot.default.build.cdc_on_boot=1
+Pcbcupid_GLYPH_C3.menu.CDCOnBoot.cdc=Disabled
+Pcbcupid_GLYPH_C3.menu.CDCOnBoot.cdc.build.cdc_on_boot=0
+
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.default.build.partitions=default
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.minimal.build.partitions=minimal
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.no_ota.build.partitions=no_ota
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.huge_app.build.partitions=huge_app
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.rainmaker=RainMaker 4MB
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.rainmaker.build.partitions=rainmaker
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.rainmaker.upload.maximum_size=1966080
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.rainmaker_4MB=RainMaker 4MB No OTA
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.rainmaker_4MB.build.partitions=rainmaker_4MB_no_ota
+Pcbcupid_GLYPH_C3.menu.PartitionScheme.rainmaker_4MB.upload.maximum_size=4038656
+
+Pcbcupid_GLYPH_C3.menu.CPUFreq.160=160MHz (WiFi)
+Pcbcupid_GLYPH_C3.menu.CPUFreq.160.build.f_cpu=160000000L
+Pcbcupid_GLYPH_C3.menu.CPUFreq.80=80MHz (WiFi)
+Pcbcupid_GLYPH_C3.menu.CPUFreq.80.build.f_cpu=80000000L
+Pcbcupid_GLYPH_C3.menu.CPUFreq.40=40MHz
+Pcbcupid_GLYPH_C3.menu.CPUFreq.40.build.f_cpu=40000000L
+Pcbcupid_GLYPH_C3.menu.CPUFreq.20=20MHz
+Pcbcupid_GLYPH_C3.menu.CPUFreq.20.build.f_cpu=20000000L
+Pcbcupid_GLYPH_C3.menu.CPUFreq.10=10MHz
+Pcbcupid_GLYPH_C3.menu.CPUFreq.10.build.f_cpu=10000000L
+
+Pcbcupid_GLYPH_C3.menu.FlashMode.qio=QIO
+Pcbcupid_GLYPH_C3.menu.FlashMode.qio.build.flash_mode=dio
+Pcbcupid_GLYPH_C3.menu.FlashMode.qio.build.boot=qio
+Pcbcupid_GLYPH_C3.menu.FlashMode.dio=DIO
+Pcbcupid_GLYPH_C3.menu.FlashMode.dio.build.flash_mode=dio
+Pcbcupid_GLYPH_C3.menu.FlashMode.dio.build.boot=dio
+
+Pcbcupid_GLYPH_C3.menu.FlashFreq.80=80MHz
+Pcbcupid_GLYPH_C3.menu.FlashFreq.80.build.flash_freq=80m
+Pcbcupid_GLYPH_C3.menu.FlashFreq.40=40MHz
+Pcbcupid_GLYPH_C3.menu.FlashFreq.40.build.flash_freq=40m
+
+Pcbcupid_GLYPH_C3.menu.FlashSize.4M=4MB (32Mb)
+Pcbcupid_GLYPH_C3.menu.FlashSize.4M.build.flash_size=4MB
+
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.921600=921600
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.921600.upload.speed=921600
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.115200=115200
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.115200.upload.speed=115200
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.256000.windows=256000
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.256000.upload.speed=256000
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.230400.windows.upload.speed=256000
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.230400=230400
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.230400.upload.speed=230400
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.460800.linux=460800
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.460800.macosx=460800
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.460800.upload.speed=460800
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.512000.windows=512000
+Pcbcupid_GLYPH_C3.menu.UploadSpeed.512000.upload.speed=512000
+
+Pcbcupid_GLYPH_C3.menu.DebugLevel.none=None
+Pcbcupid_GLYPH_C3.menu.DebugLevel.none.build.code_debug=0
+Pcbcupid_GLYPH_C3.menu.DebugLevel.error=Error
+Pcbcupid_GLYPH_C3.menu.DebugLevel.error.build.code_debug=1
+Pcbcupid_GLYPH_C3.menu.DebugLevel.warn=Warn
+Pcbcupid_GLYPH_C3.menu.DebugLevel.warn.build.code_debug=2
+Pcbcupid_GLYPH_C3.menu.DebugLevel.info=Info
+Pcbcupid_GLYPH_C3.menu.DebugLevel.info.build.code_debug=3
+Pcbcupid_GLYPH_C3.menu.DebugLevel.debug=Debug
+Pcbcupid_GLYPH_C3.menu.DebugLevel.debug.build.code_debug=4
+Pcbcupid_GLYPH_C3.menu.DebugLevel.verbose=Verbose
+Pcbcupid_GLYPH_C3.menu.DebugLevel.verbose.build.code_debug=5
+
+Pcbcupid_GLYPH_C3.menu.EraseFlash.none=Disabled
+Pcbcupid_GLYPH_C3.menu.EraseFlash.none.upload.erase_cmd=
+Pcbcupid_GLYPH_C3.menu.EraseFlash.all=Enabled
+Pcbcupid_GLYPH_C3.menu.EraseFlash.all.upload.erase_cmd=-e
+
+##############################################################
+
+
+Pcbcupid_GLYPH_H2.name=Pcbcupid GLYPH H2
+
+Pcbcupid_GLYPH_H2.bootloader.tool=esptool_py
+Pcbcupid_GLYPH_H2.bootloader.tool.default=esptool_py
+
+Pcbcupid_GLYPH_H2.upload.tool=esptool_py
+Pcbcupid_GLYPH_H2.upload.tool.default=esptool_py
+Pcbcupid_GLYPH_H2.upload.tool.network=esp_ota
+
+Pcbcupid_GLYPH_H2.upload.maximum_size=1310720
+Pcbcupid_GLYPH_H2.upload.maximum_data_size=327680
+Pcbcupid_GLYPH_H2.upload.flags=
+Pcbcupid_GLYPH_H2.upload.extra_flags=
+Pcbcupid_GLYPH_H2.upload.use_1200bps_touch=false
+Pcbcupid_GLYPH_H2.upload.wait_for_upload_port=false
+
+Pcbcupid_GLYPH_H2.serial.disableDTR=false
+Pcbcupid_GLYPH_H2.serial.disableRTS=false
+
+Pcbcupid_GLYPH_H2.build.tarch=riscv32
+Pcbcupid_GLYPH_H2.build.target=esp
+Pcbcupid_GLYPH_H2.build.mcu=esp32h2
+Pcbcupid_GLYPH_H2.build.core=esp32
+Pcbcupid_GLYPH_H2.build.variant=Pcbcupid_GLYPH_H2
+Pcbcupid_GLYPH_H2.build.board=PCBCUPID_GLYPHH2
+Pcbcupid_GLYPH_H2.build.bootloader_addr=0x0
+
+Pcbcupid_GLYPH_H2.build.cdc_on_boot=1
+Pcbcupid_GLYPH_H2.build.f_cpu=96000000L
+Pcbcupid_GLYPH_H2.build.flash_size=4MB
+Pcbcupid_GLYPH_H2.build.flash_freq=64m
+Pcbcupid_GLYPH_H2.build.img_freq=48m
+Pcbcupid_GLYPH_H2.build.flash_mode=qio
+Pcbcupid_GLYPH_H2.build.boot=qio
+Pcbcupid_GLYPH_H2.build.partitions=default
+Pcbcupid_GLYPH_H2.build.defines=
+
+## IDE 2.0 Seems to not update the value
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.default=Disabled
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.default.build.copy_jtag_files=0
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.builtin=Integrated USB JTAG
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.builtin.build.openocdscript=esp32h2-builtin.cfg
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.builtin.build.copy_jtag_files=1
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.external=FTDI Adapter
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.external.build.openocdscript=esp32h2-ftdi.cfg
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.external.build.copy_jtag_files=1
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.bridge=ESP USB Bridge
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.bridge.build.openocdscript=esp32h2-bridge.cfg
+Pcbcupid_GLYPH_H2.menu.JTAGAdapter.bridge.build.copy_jtag_files=1
+
+Pcbcupid_GLYPH_H2.menu.CDCOnBoot.default=Enabled
+Pcbcupid_GLYPH_H2.menu.CDCOnBoot.default.build.cdc_on_boot=1
+Pcbcupid_GLYPH_H2.menu.CDCOnBoot.cdc=Disabled
+Pcbcupid_GLYPH_H2.menu.CDCOnBoot.cdc.build.cdc_on_boot=0
+
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.default.build.partitions=default
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.minimal.build.partitions=minimal
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.no_fs=No FS 4MB (2MB APP x2)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.no_fs.build.partitions=no_fs
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.no_fs.upload.maximum_size=2031616
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.no_ota.build.partitions=no_ota
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.huge_app.build.partitions=huge_app
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.zigbee.build.partitions=zigbee
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.zigbee.upload.maximum_size=1310720
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.custom=Custom
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.custom.build.partitions=
+Pcbcupid_GLYPH_H2.menu.PartitionScheme.custom.upload.maximum_size=16777216
+
+Pcbcupid_GLYPH_H2.menu.FlashMode.qio=QIO
+Pcbcupid_GLYPH_H2.menu.FlashMode.qio.build.flash_mode=dio
+Pcbcupid_GLYPH_H2.menu.FlashMode.qio.build.boot=qio
+Pcbcupid_GLYPH_H2.menu.FlashMode.dio=DIO
+Pcbcupid_GLYPH_H2.menu.FlashMode.dio.build.flash_mode=dio
+Pcbcupid_GLYPH_H2.menu.FlashMode.dio.build.boot=dio
+
+Pcbcupid_GLYPH_H2.menu.FlashFreq.64=64MHz
+Pcbcupid_GLYPH_H2.menu.FlashFreq.64.build.flash_freq=64m
+Pcbcupid_GLYPH_H2.menu.FlashFreq.64.build.img_freq=48m
+#Pcbcupid_GLYPH_H2.menu.FlashFreq.32=32MHz
+#Pcbcupid_GLYPH_H2.menu.FlashFreq.32.build.flash_freq=32m
+#Pcbcupid_GLYPH_H2.menu.FlashFreq.32.build.img_freq=24m
+Pcbcupid_GLYPH_H2.menu.FlashFreq.16=16MHz
+Pcbcupid_GLYPH_H2.menu.FlashFreq.16.build.flash_freq=16m
+Pcbcupid_GLYPH_H2.menu.FlashFreq.16.build.img_freq=12m
+
+Pcbcupid_GLYPH_H2.menu.FlashSize.2M=2MB (16Mb)
+Pcbcupid_GLYPH_H2.menu.FlashSize.2M.build.flash_size=2MB
+Pcbcupid_GLYPH_H2.menu.FlashSize.4M=4MB (32Mb)
+Pcbcupid_GLYPH_H2.menu.FlashSize.4M.build.flash_size=4MB
+
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.921600=921600
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.921600.upload.speed=921600
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.115200=115200
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.115200.upload.speed=115200
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.256000.windows=256000
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.256000.upload.speed=256000
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.230400.windows.upload.speed=256000
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.230400=230400
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.230400.upload.speed=230400
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.460800.linux=460800
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.460800.macosx=460800
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.460800.upload.speed=460800
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.512000.windows=512000
+Pcbcupid_GLYPH_H2.menu.UploadSpeed.512000.upload.speed=512000
+
+Pcbcupid_GLYPH_H2.menu.DebugLevel.none=None
+Pcbcupid_GLYPH_H2.menu.DebugLevel.none.build.code_debug=0
+Pcbcupid_GLYPH_H2.menu.DebugLevel.error=Error
+Pcbcupid_GLYPH_H2.menu.DebugLevel.error.build.code_debug=1
+Pcbcupid_GLYPH_H2.menu.DebugLevel.warn=Warn
+Pcbcupid_GLYPH_H2.menu.DebugLevel.warn.build.code_debug=2
+Pcbcupid_GLYPH_H2.menu.DebugLevel.info=Info
+Pcbcupid_GLYPH_H2.menu.DebugLevel.info.build.code_debug=3
+Pcbcupid_GLYPH_H2.menu.DebugLevel.debug=Debug
+Pcbcupid_GLYPH_H2.menu.DebugLevel.debug.build.code_debug=4
+Pcbcupid_GLYPH_H2.menu.DebugLevel.verbose=Verbose
+Pcbcupid_GLYPH_H2.menu.DebugLevel.verbose.build.code_debug=5
+
+Pcbcupid_GLYPH_H2.menu.EraseFlash.none=Disabled
+Pcbcupid_GLYPH_H2.menu.EraseFlash.none.upload.erase_cmd=
+Pcbcupid_GLYPH_H2.menu.EraseFlash.all=Enabled
+Pcbcupid_GLYPH_H2.menu.EraseFlash.all.upload.erase_cmd=-e
+
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.default=Disabled
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.default.build.zigbee_mode=
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.default.build.zigbee_libs=
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.ed=Zigbee ED (end device)
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router)
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor)
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP
+Pcbcupid_GLYPH_H2.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port
+
+##############################################################
+
+
+Pcbcupid_GLYPH_C6.name=Pcbcupid GLYPH C6
+
+Pcbcupid_GLYPH_C6.bootloader.tool=esptool_py
+Pcbcupid_GLYPH_C6.bootloader.tool.default=esptool_py
+
+Pcbcupid_GLYPH_C6.upload.tool=esptool_py
+Pcbcupid_GLYPH_C6.upload.tool.default=esptool_py
+Pcbcupid_GLYPH_C6.upload.tool.network=esp_ota
+
+Pcbcupid_GLYPH_C6.upload.maximum_size=1310720
+Pcbcupid_GLYPH_C6.upload.maximum_data_size=327680
+Pcbcupid_GLYPH_C6.upload.flags=
+Pcbcupid_GLYPH_C6.upload.extra_flags=
+Pcbcupid_GLYPH_C6.upload.use_1200bps_touch=false
+Pcbcupid_GLYPH_C6.upload.wait_for_upload_port=false
+
+Pcbcupid_GLYPH_C6.serial.disableDTR=false
+Pcbcupid_GLYPH_C6.serial.disableRTS=false
+
+Pcbcupid_GLYPH_C6.build.tarch=riscv32
+Pcbcupid_GLYPH_C6.build.target=esp
+Pcbcupid_GLYPH_C6.build.mcu=esp32c6
+Pcbcupid_GLYPH_C6.build.core=esp32
+Pcbcupid_GLYPH_C6.build.variant=Pcbcupid_GLYPH_C6
+Pcbcupid_GLYPH_C6.build.board=PCBCUPID_GLYPHC6
+Pcbcupid_GLYPH_C6.build.bootloader_addr=0x0
+
+Pcbcupid_GLYPH_C6.build.cdc_on_boot=1
+Pcbcupid_GLYPH_C6.build.f_cpu=160000000L
+Pcbcupid_GLYPH_C6.build.flash_size=4MB
+Pcbcupid_GLYPH_C6.build.flash_freq=80m
+Pcbcupid_GLYPH_C6.build.flash_mode=qio
+Pcbcupid_GLYPH_C6.build.boot=qio
+Pcbcupid_GLYPH_C6.build.partitions=default
+Pcbcupid_GLYPH_C6.build.defines=
+
+## IDE 2.0 Seems to not update the value
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.default=Disabled
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.default.build.copy_jtag_files=0
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.builtin=Integrated USB JTAG
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.builtin.build.openocdscript=esp32c6-builtin.cfg
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.builtin.build.copy_jtag_files=1
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.external=FTDI Adapter
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.external.build.openocdscript=esp32c6-ftdi.cfg
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.external.build.copy_jtag_files=1
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.bridge=ESP USB Bridge
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.bridge.build.openocdscript=esp32c6-bridge.cfg
+Pcbcupid_GLYPH_C6.menu.JTAGAdapter.bridge.build.copy_jtag_files=1
+
+Pcbcupid_GLYPH_C6.menu.CDCOnBoot.cdc=Enabled
+Pcbcupid_GLYPH_C6.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
+Pcbcupid_GLYPH_C6.menu.CDCOnBoot.default=Disabled
+Pcbcupid_GLYPH_C6.menu.CDCOnBoot.default.build.cdc_on_boot=0
+
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.default.build.partitions=default
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.no_ota.build.partitions=no_ota
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.huge_app.build.partitions=huge_app
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.zigbee=Zigbee 4MB with spiffs
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.zigbee.build.partitions=zigbee
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.zigbee.upload.maximum_size=1310720
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr
+Pcbcupid_GLYPH_C6.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720
+
+Pcbcupid_GLYPH_C6.menu.CPUFreq.160=160MHz (WiFi)
+Pcbcupid_GLYPH_C6.menu.CPUFreq.160.build.f_cpu=160000000L
+Pcbcupid_GLYPH_C6.menu.CPUFreq.80=80MHz (WiFi)
+Pcbcupid_GLYPH_C6.menu.CPUFreq.80.build.f_cpu=80000000L
+Pcbcupid_GLYPH_C6.menu.CPUFreq.40=40MHz
+Pcbcupid_GLYPH_C6.menu.CPUFreq.40.build.f_cpu=40000000L
+Pcbcupid_GLYPH_C6.menu.CPUFreq.20=20MHz
+Pcbcupid_GLYPH_C6.menu.CPUFreq.20.build.f_cpu=20000000L
+Pcbcupid_GLYPH_C6.menu.CPUFreq.10=10MHz
+Pcbcupid_GLYPH_C6.menu.CPUFreq.10.build.f_cpu=10000000L
+
+Pcbcupid_GLYPH_C6.menu.FlashMode.qio=QIO
+Pcbcupid_GLYPH_C6.menu.FlashMode.qio.build.flash_mode=dio
+Pcbcupid_GLYPH_C6.menu.FlashMode.qio.build.boot=qio
+Pcbcupid_GLYPH_C6.menu.FlashMode.dio=DIO
+Pcbcupid_GLYPH_C6.menu.FlashMode.dio.build.flash_mode=dio
+Pcbcupid_GLYPH_C6.menu.FlashMode.dio.build.boot=dio
+
+Pcbcupid_GLYPH_C6.menu.FlashFreq.80=80MHz
+Pcbcupid_GLYPH_C6.menu.FlashFreq.80.build.flash_freq=80m
+Pcbcupid_GLYPH_C6.menu.FlashFreq.40=40MHz
+Pcbcupid_GLYPH_C6.menu.FlashFreq.40.build.flash_freq=40m
+
+Pcbcupid_GLYPH_C6.menu.FlashSize.4M=4MB (32Mb)
+Pcbcupid_GLYPH_C6.menu.FlashSize.4M.build.flash_size=4MB
+
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.921600=921600
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.921600.upload.speed=921600
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.115200=115200
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.115200.upload.speed=115200
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.256000.windows=256000
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.256000.upload.speed=256000
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.230400.windows.upload.speed=256000
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.230400=230400
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.230400.upload.speed=230400
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.460800.linux=460800
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.460800.macosx=460800
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.460800.upload.speed=460800
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.512000.windows=512000
+Pcbcupid_GLYPH_C6.menu.UploadSpeed.512000.upload.speed=512000
+
+Pcbcupid_GLYPH_C6.menu.DebugLevel.none=None
+Pcbcupid_GLYPH_C6.menu.DebugLevel.none.build.code_debug=0
+Pcbcupid_GLYPH_C6.menu.DebugLevel.error=Error
+Pcbcupid_GLYPH_C6.menu.DebugLevel.error.build.code_debug=1
+Pcbcupid_GLYPH_C6.menu.DebugLevel.warn=Warn
+Pcbcupid_GLYPH_C6.menu.DebugLevel.warn.build.code_debug=2
+Pcbcupid_GLYPH_C6.menu.DebugLevel.info=Info
+Pcbcupid_GLYPH_C6.menu.DebugLevel.info.build.code_debug=3
+Pcbcupid_GLYPH_C6.menu.DebugLevel.debug=Debug
+Pcbcupid_GLYPH_C6.menu.DebugLevel.debug.build.code_debug=4
+Pcbcupid_GLYPH_C6.menu.DebugLevel.verbose=Verbose
+Pcbcupid_GLYPH_C6.menu.DebugLevel.verbose.build.code_debug=5
+
+Pcbcupid_GLYPH_C6.menu.EraseFlash.none=Disabled
+Pcbcupid_GLYPH_C6.menu.EraseFlash.none.upload.erase_cmd=
+Pcbcupid_GLYPH_C6.menu.EraseFlash.all=Enabled
+Pcbcupid_GLYPH_C6.menu.EraseFlash.all.upload.erase_cmd=-e
+
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.default=Disabled
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.default.build.zigbee_mode=
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.default.build.zigbee_libs=
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.ed=Zigbee ED (end device)
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.ed.build.zigbee_mode=-DZIGBEE_MODE_ED
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.ed.build.zigbee_libs=-lesp_zb_api_ed -lesp_zb_cli_command -lzboss_stack.ed -lzboss_port
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router)
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api_zczr -lesp_zb_cli_command -lzboss_stack.zczr -lzboss_port
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.rcp=Zigbee RCP (radio co-processor)
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.rcp.build.zigbee_mode=-DZIGBEE_MODE_RCP
+Pcbcupid_GLYPH_C6.menu.ZigbeeMode.rcp.build.zigbee_libs=-lesp_zb_api_rcp -lesp_zb_cli_command -lzboss_stack.rcp -lzboss_port
+
+##############################################################
diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h
index 2b115505cff..ab7e497dcf6 100644
--- a/cores/esp32/Arduino.h
+++ b/cores/esp32/Arduino.h
@@ -199,6 +199,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
 #include "Udp.h"
 #include "HardwareSerial.h"
 #include "Esp.h"
+#include "freertos_stats.h"
 
 // Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries
 using std::abs;
diff --git a/cores/esp32/Client.h b/cores/esp32/Client.h
index ab013612401..4ea10d070fb 100644
--- a/cores/esp32/Client.h
+++ b/cores/esp32/Client.h
@@ -26,7 +26,9 @@
 class Client : public Stream {
 public:
   virtual int connect(IPAddress ip, uint16_t port) = 0;
+  virtual int connect(IPAddress ip, uint16_t port, int32_t timeout) = 0;
   virtual int connect(const char *host, uint16_t port) = 0;
+  virtual int connect(const char *host, uint16_t port, int32_t timeout) = 0;
   virtual size_t write(uint8_t) = 0;
   virtual size_t write(const uint8_t *buf, size_t size) = 0;
   virtual int available() = 0;
diff --git a/cores/esp32/ColorFormat.c b/cores/esp32/ColorFormat.c
new file mode 100644
index 00000000000..a01123545b3
--- /dev/null
+++ b/cores/esp32/ColorFormat.c
@@ -0,0 +1,279 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "ColorFormat.h"
+
+#include <math.h>
+
+// define a clamp macro to substitute the std::clamp macro which is available from C++17 onwards
+#define clamp(a, min, max) ((a) < (min) ? (min) : ((a) > (max) ? (max) : (a)))
+
+const espHsvColor_t HSV_BLACK = {0, 0, 0};
+const espHsvColor_t HSV_WHITE = {0, 0, 254};
+const espHsvColor_t HSV_RED = {0, 254, 254};
+const espHsvColor_t HSV_YELLOW = {42, 254, 254};
+const espHsvColor_t HSV_GREEN = {84, 254, 254};
+const espHsvColor_t HSV_CYAN = {127, 254, 254};
+const espHsvColor_t HSV_BLUE = {169, 254, 254};
+const espHsvColor_t HSV_MAGENTA = {211, 254, 254};
+
+const espRgbColor_t RGB_BLACK = {0, 0, 0};
+const espRgbColor_t RGB_WHITE = {255, 255, 255};
+const espRgbColor_t RGB_RED = {255, 0, 0};
+const espRgbColor_t RGB_YELLOW = {255, 255, 0};
+const espRgbColor_t RGB_GREEN = {0, 255, 0};
+const espRgbColor_t RGB_CYAN = {0, 255, 255};
+const espRgbColor_t RGB_BLUE = {0, 0, 255};
+const espRgbColor_t RGB_MAGENTA = {255, 0, 255};
+
+// main color temperature values
+const espCtColor_t COOL_WHITE_COLOR_TEMPERATURE = {142};
+const espCtColor_t DAYLIGHT_WHITE_COLOR_TEMPERATURE = {181};
+const espCtColor_t WHITE_COLOR_TEMPERATURE = {250};
+const espCtColor_t SOFT_WHITE_COLOR_TEMPERATURE = {370};
+const espCtColor_t WARM_WHITE_COLOR_TEMPERATURE = {454};
+
+espRgbColor_t espHsvToRgbColor(uint16_t h, uint8_t s, uint8_t v) {
+  espHsvColor_t hsv = {h, s, v};
+  return espHsvColorToRgbColor(hsv);
+}
+
+espRgbColor_t espHsvColorToRgbColor(espHsvColor_t hsv) {
+  espRgbColor_t rgb;
+
+  uint8_t region, p, q, t;
+  uint32_t h, s, v, remainder;
+
+  if (hsv.s == 0) {
+    rgb.r = rgb.g = rgb.b = hsv.v;
+  } else {
+    h = hsv.h;
+    s = hsv.s;
+    v = hsv.v;
+
+    region = h / 43;
+    remainder = (h - (region * 43)) * 6;
+    p = (v * (255 - s)) >> 8;
+    q = (v * (255 - ((s * remainder) >> 8))) >> 8;
+    t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
+    switch (region) {
+      case 0:  rgb.r = v, rgb.g = t, rgb.b = p; break;
+      case 1:  rgb.r = q, rgb.g = v, rgb.b = p; break;
+      case 2:  rgb.r = p, rgb.g = v, rgb.b = t; break;
+      case 3:  rgb.r = p, rgb.g = q, rgb.b = v; break;
+      case 4:  rgb.r = t, rgb.g = p, rgb.b = v; break;
+      case 5:
+      default: rgb.r = v, rgb.g = p, rgb.b = q; break;
+    }
+  }
+  return rgb;
+}
+
+espHsvColor_t espRgbToHsvColor(uint8_t r, uint8_t g, uint8_t b) {
+  espRgbColor_t rgb = {r, g, b};
+  return espRgbColorToHsvColor(rgb);
+}
+
+espHsvColor_t espRgbColorToHsvColor(espRgbColor_t rgb) {
+  espHsvColor_t hsv;
+  uint8_t rgbMin, rgbMax;
+
+  rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
+  rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
+
+  hsv.v = rgbMax;
+  if (hsv.v == 0) {
+    hsv.h = 0;
+    hsv.s = 0;
+    return hsv;
+  }
+
+  hsv.s = 255 * (rgbMax - rgbMin) / hsv.v;
+  if (hsv.s == 0) {
+    hsv.h = 0;
+    return hsv;
+  }
+  if (rgbMax == rgb.r) {
+    hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
+  } else if (rgbMax == rgb.g) {
+    hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
+  } else {
+    hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
+  }
+  return hsv;
+}
+
+espRgbColor_t espXYColorToRgbColor(uint8_t Level, espXyColor_t xy) {
+  return espXYToRgbColor(Level, xy.x, xy.y);
+}
+
+espRgbColor_t espXYToRgbColor(uint8_t Level, uint16_t current_X, uint16_t current_Y) {
+  // convert xyY color space to RGB
+
+  // https://www.easyrgb.com/en/math.php
+  // https://en.wikipedia.org/wiki/SRGB
+  // refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space
+
+  // The current_X/current_Y attribute contains the current value of the normalized chromaticity value of x/y.
+  // The value of x/y shall be related to the current_X/current_Y attribute by the relationship
+  // x = current_X/65536
+  // y = current_Y/65536
+  // z = 1-x-y
+
+  espRgbColor_t rgb;
+
+  float x, y, z;
+  float X, Y, Z;
+  float r, g, b;
+
+  x = ((float)current_X) / 65535.0f;
+  y = ((float)current_Y) / 65535.0f;
+
+  z = 1.0f - x - y;
+
+  // Calculate XYZ values
+
+  // Y - given brightness in 0 - 1 range
+  Y = ((float)Level) / 254.0f;
+  X = (Y / y) * x;
+  Z = (Y / y) * z;
+
+  // X, Y and Z input refer to a D65/2° standard illuminant.
+  // sR, sG and sB (standard RGB) output range = 0 ÷ 255
+  // convert XYZ to RGB - CIE XYZ to sRGB
+  X = X / 100.0f;
+  Y = Y / 100.0f;
+  Z = Z / 100.0f;
+
+  r = (X * 3.2406f) - (Y * 1.5372f) - (Z * 0.4986f);
+  g = -(X * 0.9689f) + (Y * 1.8758f) + (Z * 0.0415f);
+  b = (X * 0.0557f) - (Y * 0.2040f) + (Z * 1.0570f);
+
+  // apply gamma 2.2 correction
+  r = (r <= 0.0031308f ? 12.92f * r : (1.055f) * pow(r, (1.0f / 2.4f)) - 0.055f);
+  g = (g <= 0.0031308f ? 12.92f * g : (1.055f) * pow(g, (1.0f / 2.4f)) - 0.055f);
+  b = (b <= 0.0031308f ? 12.92f * b : (1.055f) * pow(b, (1.0f / 2.4f)) - 0.055f);
+
+  // Round off
+  r = clamp(r, 0, 1);
+  g = clamp(g, 0, 1);
+  b = clamp(b, 0, 1);
+
+  // these rgb values are in  the range of 0 to 1, convert to limit of HW specific LED
+  rgb.r = (uint8_t)(r * 255);
+  rgb.g = (uint8_t)(g * 255);
+  rgb.b = (uint8_t)(b * 255);
+
+  return rgb;
+}
+
+espXyColor_t espRgbToXYColor(uint8_t r, uint8_t g, uint8_t b) {
+  espRgbColor_t rgb = {r, g, b};
+  return espRgbColorToXYColor(rgb);
+}
+
+espXyColor_t espRgbColorToXYColor(espRgbColor_t rgb) {
+  // convert RGB to xy color space
+
+  // https://www.easyrgb.com/en/math.php
+  // https://en.wikipedia.org/wiki/SRGB
+  // refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space
+
+  espXyColor_t xy;
+
+  float r, g, b;
+  float X, Y, Z;
+  float x, y;
+
+  r = ((float)rgb.r) / 255.0f;
+  g = ((float)rgb.g) / 255.0f;
+  b = ((float)rgb.b) / 255.0f;
+
+  // convert RGB to XYZ - sRGB to CIE XYZ
+  r = (r <= 0.04045f ? r / 12.92f : pow((r + 0.055f) / 1.055f, 2.4f));
+  g = (g <= 0.04045f ? g / 12.92f : pow((g + 0.055f) / 1.055f, 2.4f));
+  b = (b <= 0.04045f ? b / 12.92f : pow((b + 0.055f) / 1.055f, 2.4f));
+
+  // https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d
+  X = r * 0.649926f + g * 0.103455f + b * 0.197109f;
+  Y = r * 0.234327f + g * 0.743075f + b * 0.022598f;
+  Z = r * 0.0000000f + g * 0.053077f + b * 1.035763f;
+
+  // sR, sG and sB (standard RGB) input range = 0 ÷ 255
+  // X, Y and Z output refer to a D65/2° standard illuminant.
+  X = r * 0.4124564f + g * 0.3575761f + b * 0.1804375f;
+  Y = r * 0.2126729f + g * 0.7151522f + b * 0.0721750f;
+  Z = r * 0.0193339f + g * 0.1191920f + b * 0.9503041f;
+
+  // Calculate xy values
+  x = X / (X + Y + Z);
+  y = Y / (X + Y + Z);
+
+  // convert to 0-65535 range
+  xy.x = (uint16_t)(x * 65535);
+  xy.y = (uint16_t)(y * 65535);
+  return xy;
+}
+
+espRgbColor_t espCTToRgbColor(uint16_t ct) {
+  espCtColor_t ctColor = {ct};
+  return espCTColorToRgbColor(ctColor);
+}
+
+espRgbColor_t espCTColorToRgbColor(espCtColor_t ct) {
+  espRgbColor_t rgb = {0, 0, 0};
+  float r, g, b;
+
+  if (ct.ctMireds == 0) {
+    return rgb;
+  }
+  // Algorithm credits to Tanner Helland: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html
+
+  // Convert Mireds to centiKelvins. k = 1,000,000/mired
+  float ctCentiKelvin = 10000 / ct.ctMireds;
+
+  // Red
+  if (ctCentiKelvin <= 66) {
+    r = 255;
+  } else {
+    r = 329.698727446f * pow(ctCentiKelvin - 60, -0.1332047592f);
+  }
+
+  // Green
+  if (ctCentiKelvin <= 66) {
+    g = 99.4708025861f * log(ctCentiKelvin) - 161.1195681661f;
+  } else {
+    g = 288.1221695283f * pow(ctCentiKelvin - 60, -0.0755148492f);
+  }
+
+  // Blue
+  if (ctCentiKelvin >= 66) {
+    b = 255;
+  } else {
+    if (ctCentiKelvin <= 19) {
+      b = 0;
+    } else {
+      b = 138.5177312231 * log(ctCentiKelvin - 10) - 305.0447927307;
+    }
+  }
+  rgb.r = (uint8_t)clamp(r, 0, 255);
+  rgb.g = (uint8_t)clamp(g, 0, 255);
+  rgb.b = (uint8_t)clamp(b, 0, 255);
+
+  return rgb;
+}
diff --git a/cores/esp32/ColorFormat.h b/cores/esp32/ColorFormat.h
new file mode 100644
index 00000000000..0bb87145d16
--- /dev/null
+++ b/cores/esp32/ColorFormat.h
@@ -0,0 +1,70 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct RgbColor_t {
+  uint8_t r;
+  uint8_t g;
+  uint8_t b;
+};
+
+struct HsvColor_t {
+  uint16_t h;
+  uint8_t s;
+  uint8_t v;
+};
+
+struct XyColor_t {
+  uint16_t x;
+  uint16_t y;
+};
+
+struct CtColor_t {
+  uint16_t ctMireds;
+};
+
+typedef struct RgbColor_t espRgbColor_t;
+typedef struct HsvColor_t espHsvColor_t;
+typedef struct XyColor_t espXyColor_t;
+typedef struct CtColor_t espCtColor_t;
+
+espRgbColor_t espXYToRgbColor(uint8_t Level, uint16_t current_X, uint16_t current_Y);
+espRgbColor_t espXYColorToRgb(uint8_t Level, espXyColor_t xy);
+espXyColor_t espRgbColorToXYColor(espRgbColor_t rgb);
+espXyColor_t espRgbToXYColor(uint8_t r, uint8_t g, uint8_t b);
+espRgbColor_t espHsvColorToRgbColor(espHsvColor_t hsv);
+espRgbColor_t espHsvToRgbColor(uint16_t h, uint8_t s, uint8_t v);
+espRgbColor_t espCTColorToRgbColor(espCtColor_t ct);
+espRgbColor_t espCTToRgbColor(uint16_t ct);
+espHsvColor_t espRgbColorToHsvColor(espRgbColor_t rgb);
+espHsvColor_t espRgbToHsvColor(uint8_t r, uint8_t g, uint8_t b);
+
+extern const espHsvColor_t HSV_BLACK, HSV_WHITE, HSV_RED, HSV_YELLOW, HSV_GREEN, HSV_CYAN, HSV_BLUE, HSV_MAGENTA;
+extern const espCtColor_t COOL_WHITE_COLOR_TEMPERATURE, DAYLIGHT_WHITE_COLOR_TEMPERATURE, WHITE_COLOR_TEMPERATURE, SOFT_WHITE_COLOR_TEMPERATURE,
+  WARM_WHITE_COLOR_TEMPERATURE;
+extern const espRgbColor_t RGB_BLACK, RGB_WHITE, RGB_RED, RGB_YELLOW, RGB_GREEN, RGB_CYAN, RGB_BLUE, RGB_MAGENTA;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp
index 483e888f64f..9f90a828b25 100644
--- a/cores/esp32/Esp.cpp
+++ b/cores/esp32/Esp.cpp
@@ -60,6 +60,9 @@ extern "C" {
 #elif CONFIG_IDF_TARGET_ESP32H2
 #include "esp32h2/rom/spi_flash.h"
 #define ESP_FLASH_IMAGE_BASE 0x0000  // Esp32h2 is located at 0x0000
+#elif CONFIG_IDF_TARGET_ESP32P4
+#include "esp32p4/rom/spi_flash.h"
+#define ESP_FLASH_IMAGE_BASE 0x2000  // Esp32p4 is located at 0x2000
 #else
 #error Target CONFIG_IDF_TARGET is not supported
 #endif
@@ -274,7 +277,7 @@ const char *EspClass::getChipModel(void) {
         return "ESP32-D0WD";
       }
     case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5:   return "ESP32-D2WD";
-    case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2:   return "ESP32-PICO-D2";
+    case EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH:    return "ESP32-U4WDH";
     case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4:   return "ESP32-PICO-D4";
     case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302: return "ESP32-PICO-V3-02";
     case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDR2V3: return "ESP32-D0WDR2-V3";
@@ -297,6 +300,7 @@ const char *EspClass::getChipModel(void) {
     case CHIP_ESP32C2: return "ESP32-C2";
     case CHIP_ESP32C6: return "ESP32-C6";
     case CHIP_ESP32H2: return "ESP32-H2";
+    case CHIP_ESP32P4: return "ESP32-P4";
     default:           return "UNKNOWN";
   }
 #endif
@@ -335,6 +339,8 @@ uint32_t EspClass::getFlashChipSpeed(void) {
   return magicFlashChipSpeed(fhdr.spi_speed);
 }
 
+// FIXME for P4
+#if !defined(CONFIG_IDF_TARGET_ESP32P4)
 FlashMode_t EspClass::getFlashChipMode(void) {
 #if CONFIG_IDF_TARGET_ESP32S2
   uint32_t spi_ctrl = REG_READ(PERIPHS_SPI_FLASH_CTRL);
@@ -361,6 +367,7 @@ FlashMode_t EspClass::getFlashChipMode(void) {
   }
   return (FM_DOUT);
 }
+#endif  // if !defined(CONFIG_IDF_TARGET_ESP32P4)
 
 uint32_t EspClass::magicFlashChipSize(uint8_t byte) {
   /*
diff --git a/cores/esp32/FirmwareMSC.h b/cores/esp32/FirmwareMSC.h
index 3eaa184bcd6..cc428bc69b8 100644
--- a/cores/esp32/FirmwareMSC.h
+++ b/cores/esp32/FirmwareMSC.h
@@ -14,7 +14,9 @@
 
 #pragma once
 #include <stdbool.h>
+#if defined __has_include && __has_include("USBMSC.h")
 #include "USBMSC.h"
+#endif
 
 #if CONFIG_TINYUSB_MSC_ENABLED
 
diff --git a/cores/esp32/HWCDC.cpp b/cores/esp32/HWCDC.cpp
index 780e560dcf8..f0411f1d171 100644
--- a/cores/esp32/HWCDC.cpp
+++ b/cores/esp32/HWCDC.cpp
@@ -11,7 +11,9 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+#if defined __has_include && __has_include("USB.h")
 #include "USB.h"
+#endif
 #if SOC_USB_SERIAL_JTAG_SUPPORTED
 
 #include "esp32-hal.h"
@@ -286,14 +288,14 @@ bool HWCDC::deinit(void *busptr) {
   running = true;
   // Setting USB D+ D- pins
   bool retCode = true;
-  retCode &= perimanClearPinBus(USB_DM_GPIO_NUM);
-  retCode &= perimanClearPinBus(USB_DP_GPIO_NUM);
+  retCode &= perimanClearPinBus(USB_INT_PHY0_DM_GPIO_NUM);
+  retCode &= perimanClearPinBus(USB_INT_PHY0_DP_GPIO_NUM);
   if (retCode) {
     // Force the host to re-enumerate (BUS_RESET)
-    pinMode(USB_DM_GPIO_NUM, OUTPUT_OPEN_DRAIN);
-    pinMode(USB_DP_GPIO_NUM, OUTPUT_OPEN_DRAIN);
-    digitalWrite(USB_DM_GPIO_NUM, LOW);
-    digitalWrite(USB_DP_GPIO_NUM, LOW);
+    pinMode(USB_INT_PHY0_DM_GPIO_NUM, OUTPUT_OPEN_DRAIN);
+    pinMode(USB_INT_PHY0_DP_GPIO_NUM, OUTPUT_OPEN_DRAIN);
+    digitalWrite(USB_INT_PHY0_DM_GPIO_NUM, LOW);
+    digitalWrite(USB_INT_PHY0_DP_GPIO_NUM, LOW);
   }
   // release the flag
   running = false;
@@ -323,11 +325,11 @@ void HWCDC::begin(unsigned long baud) {
   // delay(10);  // USB Host has to enumerate it again
 
   // Peripheral Manager setting for USB D+ D- pins
-  uint8_t pin = USB_DM_GPIO_NUM;
+  uint8_t pin = USB_INT_PHY0_DM_GPIO_NUM;
   if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_USB_DM, (void *)this, -1, -1)) {
     goto err;
   }
-  pin = USB_DP_GPIO_NUM;
+  pin = USB_INT_PHY0_DP_GPIO_NUM;
   if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_USB_DP, (void *)this, -1, -1)) {
     goto err;
   }
diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp
index c82cbb43d3b..fb93dad1c47 100644
--- a/cores/esp32/HardwareSerial.cpp
+++ b/cores/esp32/HardwareSerial.cpp
@@ -25,23 +25,37 @@
 
 void serialEvent(void) __attribute__((weak));
 
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
 void serialEvent1(void) __attribute__((weak));
-#endif /* SOC_UART_NUM > 1 */
+#endif /* SOC_UART_HP_NUM > 1 */
 
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
 void serialEvent2(void) __attribute__((weak));
-#endif /* SOC_UART_NUM > 2 */
+#endif /* SOC_UART_HP_NUM > 2 */
+
+#if SOC_UART_HP_NUM > 3
+void serialEvent3(void) __attribute__((weak));
+#endif /* SOC_UART_HP_NUM > 3 */
+
+#if SOC_UART_HP_NUM > 4
+void serialEvent4(void) __attribute__((weak));
+#endif /* SOC_UART_HP_NUM > 4 */
 
 #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
 // There is always Seria0 for UART0
 HardwareSerial Serial0(0);
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
 HardwareSerial Serial1(1);
 #endif
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
 HardwareSerial Serial2(2);
 #endif
+#if SOC_UART_HP_NUM > 3
+HardwareSerial Serial3(3);
+#endif
+#if SOC_UART_HP_NUM > 4
+HardwareSerial Serial4(4);
+#endif
 
 #if HWCDC_SERIAL_IS_DEFINED == 1  // Hardware JTAG CDC Event
 extern void HWCDCSerialEvent(void) __attribute__((weak));
@@ -67,16 +81,26 @@ void serialEventRun(void) {
   if (serialEvent && Serial0.available()) {
     serialEvent();
   }
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
   if (serialEvent1 && Serial1.available()) {
     serialEvent1();
   }
 #endif
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
   if (serialEvent2 && Serial2.available()) {
     serialEvent2();
   }
 #endif
+#if SOC_UART_HP_NUM > 3
+  if (serialEvent3 && Serial3.available()) {
+    serialEvent3();
+  }
+#endif
+#if SOC_UART_HP_NUM > 4
+  if (serialEvent4 && Serial4.available()) {
+    serialEvent4();
+  }
+#endif
 }
 #endif
 
@@ -274,8 +298,8 @@ void HardwareSerial::_uartEventTask(void *args) {
 }
 
 void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd) {
-  if (_uart_nr >= SOC_UART_NUM) {
-    log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_NUM - 1);
+  if (_uart_nr >= SOC_UART_HP_NUM) {
+    log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_HP_NUM - 1);
     return;
   }
 
@@ -289,6 +313,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
   // map logical pins to GPIO numbers
   rxPin = digitalPinToGPIONumber(rxPin);
   txPin = digitalPinToGPIONumber(txPin);
+  int8_t _rxPin = uart_get_RxPin(_uart_nr);
+  int8_t _txPin = uart_get_TxPin(_uart_nr);
+
+  rxPin = rxPin < 0 ? _rxPin : rxPin;
+  txPin = txPin < 0 ? _txPin : txPin;
 
   HSERIAL_MUTEX_LOCK();
   // First Time or after end() --> set default Pins
@@ -304,7 +333,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
           txPin = _txPin < 0 ? (int8_t)SOC_TX0 : _txPin;
         }
         break;
-#if SOC_UART_NUM > 1  // may save some flash bytes...
+#if SOC_UART_HP_NUM > 1  // may save some flash bytes...
       case UART_NUM_1:
         if (rxPin < 0 && txPin < 0) {
           // do not change RX1/TX1 if it has already been set before
@@ -313,18 +342,55 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
         }
         break;
 #endif
-#if SOC_UART_NUM > 2  // may save some flash bytes...
+#if SOC_UART_HP_NUM > 2  // may save some flash bytes...
       case UART_NUM_2:
         if (rxPin < 0 && txPin < 0) {
           // do not change RX2/TX2 if it has already been set before
+#ifdef RX2
           rxPin = _rxPin < 0 ? (int8_t)RX2 : _rxPin;
+#endif
+#ifdef TX2
           txPin = _txPin < 0 ? (int8_t)TX2 : _txPin;
+#endif
+        }
+        break;
+#endif
+#if SOC_UART_HP_NUM > 3  // may save some flash bytes...
+      case UART_NUM_3:
+        if (rxPin < 0 && txPin < 0) {
+          // do not change RX2/TX2 if it has already been set before
+#ifdef RX3
+          rxPin = _rxPin < 0 ? (int8_t)RX3 : _rxPin;
+#endif
+#ifdef TX3
+          txPin = _txPin < 0 ? (int8_t)TX3 : _txPin;
+#endif
+        }
+        break;
+#endif
+#if SOC_UART_HP_NUM > 4  // may save some flash bytes...
+      case UART_NUM_4:
+        if (rxPin < 0 && txPin < 0) {
+          // do not change RX2/TX2 if it has already been set before
+#ifdef RX4
+          rxPin = _rxPin < 0 ? (int8_t)RX4 : _rxPin;
+#endif
+#ifdef TX4
+          txPin = _txPin < 0 ? (int8_t)TX4 : _txPin;
+#endif
         }
         break;
 #endif
     }
   }
 
+  // if no RX/TX pins are defined, it will not start the UART driver
+  if (rxPin < 0 && txPin < 0) {
+    log_e("No RX/TX pins defined. Please set RX/TX pins.");
+    HSERIAL_MUTEX_UNLOCK();
+    return;
+  }
+
   // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified.
   // it will detach previous UART attached pins
 
diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h
index fb9ac9a952b..efe02dd5d52 100644
--- a/cores/esp32/HardwareSerial.h
+++ b/cores/esp32/HardwareSerial.h
@@ -51,7 +51,9 @@
 #include "esp32-hal.h"
 #include "soc/soc_caps.h"
 #include "HWCDC.h"
+#if defined __has_include && __has_include("USBCDC.h")
 #include "USBCDC.h"
+#endif
 
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
@@ -125,6 +127,8 @@ typedef enum {
 #define SOC_RX0 (gpio_num_t)17
 #elif CONFIG_IDF_TARGET_ESP32H2
 #define SOC_RX0 (gpio_num_t)23
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define SOC_RX0 (gpio_num_t)38
 #endif
 #endif
 
@@ -141,12 +145,14 @@ typedef enum {
 #define SOC_TX0 (gpio_num_t)16
 #elif CONFIG_IDF_TARGET_ESP32H2
 #define SOC_TX0 (gpio_num_t)24
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define SOC_TX0 (gpio_num_t)37
 #endif
 #endif
 
 // Default pins for UART1 are arbitrary, and defined here for convenience.
 
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
 #ifndef RX1
 #if CONFIG_IDF_TARGET_ESP32
 #define RX1 (gpio_num_t)26
@@ -162,6 +168,8 @@ typedef enum {
 #define RX1 (gpio_num_t)4
 #elif CONFIG_IDF_TARGET_ESP32H2
 #define RX1 (gpio_num_t)0
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define RX1 (gpio_num_t)11
 #endif
 #endif
 
@@ -180,13 +188,15 @@ typedef enum {
 #define TX1 (gpio_num_t)5
 #elif CONFIG_IDF_TARGET_ESP32H2
 #define TX1 (gpio_num_t)1
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define TX1 (gpio_num_t)10
 #endif
 #endif
-#endif /* SOC_UART_NUM > 1 */
+#endif /* SOC_UART_HP_NUM > 1 */
 
 // Default pins for UART2 are arbitrary, and defined here for convenience.
 
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
 #ifndef RX2
 #if CONFIG_IDF_TARGET_ESP32
 #define RX2 (gpio_num_t)4
@@ -202,7 +212,7 @@ typedef enum {
 #define TX2 (gpio_num_t)20
 #endif
 #endif
-#endif /* SOC_UART_NUM > 2 */
+#endif /* SOC_UART_HP_NUM > 2 */
 
 typedef std::function<void(void)> OnReceiveCb;
 typedef std::function<void(hardwareSerial_error_t)> OnReceiveErrorCb;
@@ -357,12 +367,18 @@ extern void serialEventRun(void) __attribute__((weak));
 #endif  // ARDUINO_USB_CDC_ON_BOOT
 // There is always Seria0 for UART0
 extern HardwareSerial Serial0;
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
 extern HardwareSerial Serial1;
 #endif
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
 extern HardwareSerial Serial2;
 #endif
+#if SOC_UART_HP_NUM > 3
+extern HardwareSerial Serial3;
+#endif
+#if SOC_UART_HP_NUM > 4
+extern HardwareSerial Serial4;
+#endif
 #endif  //!defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
 
 #endif  // HardwareSerial_h
diff --git a/cores/esp32/IPAddress.cpp b/cores/esp32/IPAddress.cpp
index b4fc4c3f7e0..299a625ff27 100644
--- a/cores/esp32/IPAddress.cpp
+++ b/cores/esp32/IPAddress.cpp
@@ -22,6 +22,10 @@
 #include "lwip/netif.h"
 #include "StreamString.h"
 
+#ifndef CONFIG_LWIP_IPV6
+#define IP6_NO_ZONE 0
+#endif
+
 IPAddress::IPAddress() : IPAddress(IPv4) {}
 
 IPAddress::IPAddress(IPType ip_type) {
@@ -201,7 +205,13 @@ bool IPAddress::fromString6(const char *address) {
       colons++;
       acc = 0;
     } else if (c == '%') {
-      _zone = netif_name_to_index(address);
+      // netif_index_to_name crashes on latest esp-idf
+      // _zone = netif_name_to_index(address);
+      // in the interim, we parse the suffix as a zone number
+      while ((*address != '\0') && (!isdigit(*address))) {  // skip all non-digit after '%'
+        address++;
+      }
+      _zone = atol(address) + 1;  // increase by one by convention, so we can have zone '0'
       while (*address != '\0') {
         address++;
       }
@@ -344,12 +354,25 @@ size_t IPAddress::printTo(Print &p, bool includeZone) const {
         n += p.print(':');
       }
     }
-    // add a zone if zone-id is non-zero
+    // add a zone if zone-id is non-zero (causes exception on recent IDF builds)
+    // if (_zone > 0 && includeZone) {
+    //   n += p.print('%');
+    //   char if_name[NETIF_NAMESIZE];
+    //   netif_index_to_name(_zone, if_name);
+    //   n += p.print(if_name);
+    // }
+    // In the interim, we just output the index number
     if (_zone > 0 && includeZone) {
       n += p.print('%');
-      char if_name[NETIF_NAMESIZE];
-      netif_index_to_name(_zone, if_name);
-      n += p.print(if_name);
+      // look for the interface name
+      for (netif *intf = netif_list; intf != nullptr; intf = intf->next) {
+        if (_zone - 1 == intf->num) {
+          n += p.print(intf->name[0]);
+          n += p.print(intf->name[1]);
+          break;
+        }
+      }
+      n += p.print(_zone - 1);
     }
     return n;
   }
@@ -368,6 +391,7 @@ IPAddress::IPAddress(const ip_addr_t *addr) {
 }
 
 void IPAddress::to_ip_addr_t(ip_addr_t *addr) const {
+#if CONFIG_LWIP_IPV6
   if (_type == IPv6) {
     addr->type = IPADDR_TYPE_V6;
     addr->u_addr.ip6.addr[0] = _address.dword[0];
@@ -381,9 +405,13 @@ void IPAddress::to_ip_addr_t(ip_addr_t *addr) const {
     addr->type = IPADDR_TYPE_V4;
     addr->u_addr.ip4.addr = _address.dword[IPADDRESS_V4_DWORD_INDEX];
   }
+#else
+  addr->addr = _address.dword[IPADDRESS_V4_DWORD_INDEX];
+#endif
 }
 
 IPAddress &IPAddress::from_ip_addr_t(const ip_addr_t *addr) {
+#if CONFIG_LWIP_IPV6
   if (addr->type == IPADDR_TYPE_V6) {
     _type = IPv6;
     _address.dword[0] = addr->u_addr.ip6.addr[0];
@@ -394,13 +422,21 @@ IPAddress &IPAddress::from_ip_addr_t(const ip_addr_t *addr) {
     _zone = addr->u_addr.ip6.zone;
 #endif /* LWIP_IPV6_SCOPES */
   } else {
+#endif
     _type = IPv4;
     memset(_address.bytes, 0, sizeof(_address.bytes));
+#if CONFIG_LWIP_IPV6
     _address.dword[IPADDRESS_V4_DWORD_INDEX] = addr->u_addr.ip4.addr;
+#else
+  _address.dword[IPADDRESS_V4_DWORD_INDEX] = addr->addr;
+#endif
+#if CONFIG_LWIP_IPV6
   }
+#endif
   return *this;
 }
 
+#if CONFIG_LWIP_IPV6
 esp_ip6_addr_type_t IPAddress::addr_type() const {
   if (_type != IPv6) {
     return ESP_IP6_ADDR_IS_UNKNOWN;
@@ -409,6 +445,9 @@ esp_ip6_addr_type_t IPAddress::addr_type() const {
   to_ip_addr_t(&addr);
   return esp_netif_ip6_get_addr_type((esp_ip6_addr_t *)(&(addr.u_addr.ip6)));
 }
+#endif
 
+#if CONFIG_LWIP_IPV6
 const IPAddress IN6ADDR_ANY(IPv6);
+#endif
 const IPAddress INADDR_NONE(0, 0, 0, 0);
diff --git a/cores/esp32/IPAddress.h b/cores/esp32/IPAddress.h
index b88aeed3026..923f4dd5ca6 100644
--- a/cores/esp32/IPAddress.h
+++ b/cores/esp32/IPAddress.h
@@ -24,6 +24,7 @@
 #include "WString.h"
 #include "lwip/ip_addr.h"
 #include "esp_netif_ip_addr.h"
+#include "sdkconfig.h"
 
 #define IPADDRESS_V4_BYTES_INDEX 12
 #define IPADDRESS_V4_DWORD_INDEX 3
@@ -115,7 +116,9 @@ class IPAddress : public Printable {
   IPAddress(const ip_addr_t *addr);
   void to_ip_addr_t(ip_addr_t *addr) const;
   IPAddress &from_ip_addr_t(const ip_addr_t *addr);
+#if CONFIG_LWIP_IPV6
   esp_ip6_addr_type_t addr_type() const;
+#endif
   uint8_t zone() const {
     return (type() == IPv6) ? _zone : 0;
   }
diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp
index 2689086013a..795a17dc0b8 100644
--- a/cores/esp32/USBCDC.cpp
+++ b/cores/esp32/USBCDC.cpp
@@ -31,7 +31,7 @@ USBCDC *devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
 static uint16_t load_cdc_descriptor(uint8_t *dst, uint8_t *itf) {
   uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC");
   uint8_t descriptor[TUD_CDC_DESC_LEN] = {// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
-                                          TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64)
+                                          TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, CFG_TUD_ENDOINT_SIZE, 0x03, 0x84, CFG_TUD_ENDOINT_SIZE)
   };
   *itf += 2;
   memcpy(dst, descriptor, TUD_CDC_DESC_LEN);
diff --git a/cores/esp32/USBMSC.cpp b/cores/esp32/USBMSC.cpp
index eeaf3026535..aeb79883f0d 100644
--- a/cores/esp32/USBMSC.cpp
+++ b/cores/esp32/USBMSC.cpp
@@ -24,7 +24,7 @@ extern "C" uint16_t tusb_msc_load_descriptor(uint8_t *dst, uint8_t *itf) {
   uint8_t ep_num = tinyusb_get_free_duplex_endpoint();
   TU_VERIFY(ep_num != 0);
   uint8_t descriptor[TUD_MSC_DESC_LEN] = {// Interface number, string index, EP Out & EP In address, EP size
-                                          TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64)
+                                          TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), CFG_TUD_ENDOINT_SIZE)
   };
   *itf += 1;
   memcpy(dst, descriptor, TUD_MSC_DESC_LEN);
diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp
index 239ae3e97c9..daafef3cab9 100644
--- a/cores/esp32/chip-debug-report.cpp
+++ b/cores/esp32/chip-debug-report.cpp
@@ -64,6 +64,9 @@ static void printPkgVersion(void) {
 #elif CONFIG_IDF_TARGET_ESP32H2
   uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SYS_4_REG, EFUSE_PKG_VERSION);
   chip_report_printf("%lu", pkg_ver);
+#elif CONFIG_IDF_TARGET_ESP32P4
+  uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SYS_2_REG, EFUSE_PKG_VERSION);
+  chip_report_printf("%lu", pkg_ver);
 #else
   chip_report_printf("Unknown");
 #endif
@@ -84,6 +87,7 @@ static void printChipInfo(void) {
     case CHIP_ESP32C3: chip_report_printf("ESP32-C3\n"); break;
     case CHIP_ESP32C6: chip_report_printf("ESP32-C6\n"); break;
     case CHIP_ESP32H2: chip_report_printf("ESP32-H2\n"); break;
+    case CHIP_ESP32P4: chip_report_printf("ESP32-P4\n"); break;
     default:           chip_report_printf("Unknown %d\n", info.model); break;
   }
   printPkgVersion();
@@ -105,6 +109,8 @@ static void printChipInfo(void) {
 static void printFlashInfo(void) {
 #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
 #define ESP_FLASH_IMAGE_BASE 0x1000
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define ESP_FLASH_IMAGE_BASE 0x2000
 #else
 #define ESP_FLASH_IMAGE_BASE 0x0000
 #endif
diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c
index ee9cd02a623..c7cc1f5d556 100644
--- a/cores/esp32/esp32-hal-adc.c
+++ b/cores/esp32/esp32-hal-adc.c
@@ -75,7 +75,7 @@ static bool adcDetachBus(void *pin) {
       if (err != ESP_OK) {
         return false;
       }
-#elif !defined(CONFIG_IDF_TARGET_ESP32H2)
+#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4))
       err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle);
       if (err != ESP_OK) {
         return false;
@@ -127,7 +127,7 @@ esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, i
             log_e("adc_cali_create_scheme_curve_fitting failed with error: %d", err);
             return err;
           }
-#elif !defined(CONFIG_IDF_TARGET_ESP32H2)  //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
+#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4))  //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
           log_d("Deleting ADC_UNIT_%d line cali handle", adc_unit);
           err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle);
           if (err != ESP_OK) {
@@ -310,7 +310,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin) {
       .bitwidth = __analogWidth,
     };
     err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle);
-#elif !defined(CONFIG_IDF_TARGET_ESP32H2)  //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
+#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4))  //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
     adc_cali_line_fitting_config_t cali_config = {
       .unit_id = adc_unit,
       .bitwidth = __analogWidth,
@@ -379,7 +379,7 @@ static bool adcContinuousDetachBus(void *adc_unit_number) {
       if (err != ESP_OK) {
         return false;
       }
-#elif !defined(CONFIG_IDF_TARGET_ESP32H2)
+#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4))
       err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle);
       if (err != ESP_OK) {
         return false;
@@ -552,7 +552,7 @@ bool analogContinuous(const uint8_t pins[], size_t pins_count, uint32_t conversi
       .bitwidth = __adcContinuousWidth,
     };
     err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle);
-#elif !defined(CONFIG_IDF_TARGET_ESP32H2)  //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
+#elif (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4))  //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
     adc_cali_line_fitting_config_t cali_config = {
       .unit_id = adc_unit,
       .bitwidth = __adcContinuousWidth,
diff --git a/cores/esp32/esp32-hal-cpu.c b/cores/esp32/esp32-hal-cpu.c
index 7027c7cad9d..e9baf3613c2 100644
--- a/cores/esp32/esp32-hal-cpu.c
+++ b/cores/esp32/esp32-hal-cpu.c
@@ -19,9 +19,9 @@
 #include "esp_attr.h"
 #include "esp_log.h"
 #include "soc/rtc.h"
-#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2)
+#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)
 #include "soc/rtc_cntl_reg.h"
-#include "soc/apb_ctrl_reg.h"
+#include "soc/syscon_reg.h"
 #endif
 #include "soc/efuse_reg.h"
 #include "esp32-hal.h"
@@ -30,13 +30,13 @@
 #include "esp_system.h"
 #ifdef ESP_IDF_VERSION_MAJOR  // IDF 4+
 #if CONFIG_IDF_TARGET_ESP32   // ESP32/PICO-D4
-#include "freertos/xtensa_timer.h"
+#include "xtensa_timer.h"
 #include "esp32/rom/rtc.h"
 #elif CONFIG_IDF_TARGET_ESP32S2
-#include "freertos/xtensa_timer.h"
+#include "xtensa_timer.h"
 #include "esp32s2/rom/rtc.h"
 #elif CONFIG_IDF_TARGET_ESP32S3
-#include "freertos/xtensa_timer.h"
+#include "xtensa_timer.h"
 #include "esp32s3/rom/rtc.h"
 #elif CONFIG_IDF_TARGET_ESP32C2
 #include "esp32c2/rom/rtc.h"
@@ -46,6 +46,8 @@
 #include "esp32c6/rom/rtc.h"
 #elif CONFIG_IDF_TARGET_ESP32H2
 #include "esp32h2/rom/rtc.h"
+#elif CONFIG_IDF_TARGET_ESP32P4
+#include "esp32p4/rom/rtc.h"
 #else
 #error Target CONFIG_IDF_TARGET is not supported
 #endif
@@ -161,13 +163,13 @@ bool removeApbChangeCallback(void *arg, apb_change_cb_t cb) {
 }
 
 static uint32_t calculateApb(rtc_cpu_freq_config_t *conf) {
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2
-  return APB_CLK_FREQ;
-#else
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
   if (conf->freq_mhz >= 80) {
     return 80 * MHZ;
   }
   return (conf->source_freq_mhz * MHZ) / conf->div;
+#else
+  return APB_CLK_FREQ;
 #endif
 }
 
@@ -177,7 +179,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) {
   rtc_cpu_freq_config_t conf, cconf;
   uint32_t capb, apb;
   //Get XTAL Frequency and calculate min CPU MHz
-#ifndef CONFIG_IDF_TARGET_ESP32H2
+#if (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4))
   rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get();
 #endif
 #if CONFIG_IDF_TARGET_ESP32
@@ -193,7 +195,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) {
     }
   }
 #endif
-#ifndef CONFIG_IDF_TARGET_ESP32H2
+#if (!defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4))
   if (cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 120 && cpu_freq_mhz != 80) {
     if (xtal >= RTC_XTAL_FREQ_40M) {
       log_e("Bad frequency: %u MHz! Options are: 240, 160, 120, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal / 2, xtal / 4);
@@ -235,7 +237,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) {
   }
   //Make the frequency change
   rtc_clk_cpu_freq_set_config_fast(&conf);
-#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2)
+#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)
   if (capb != apb) {
     //Update REF_TICK (uncomment if REF_TICK is different than 1MHz)
     //if(conf.freq_mhz < 80){
@@ -248,11 +250,8 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) {
   }
 #endif
   //Update FreeRTOS Tick Divisor
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
 
-#elif CONFIG_IDF_TARGET_ESP32S3
-
-#else
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
   uint32_t fcpu = (conf.freq_mhz >= 80) ? (conf.freq_mhz * MHZ) : (apb);
   _xt_tick_divisor = fcpu / XT_TICK_PER_SEC;
 #endif
@@ -260,19 +259,27 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz) {
   if (apb_change_callbacks) {
     triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb);
   }
+  // clang-format off
 #ifdef SOC_CLK_APLL_SUPPORTED
   log_d(
     "%s: %u / %u = %u Mhz, APB: %u Hz",
-    (conf.source == RTC_CPU_FREQ_SRC_PLL) ? "PLL"
-                                          : ((conf.source == RTC_CPU_FREQ_SRC_APLL) ? "APLL" : ((conf.source == RTC_CPU_FREQ_SRC_XTAL) ? "XTAL" : "8M")),
+    (conf.source == SOC_CPU_CLK_SRC_PLL) ? "PLL"
+                                          : ((conf.source == SOC_CPU_CLK_SRC_APLL) ? "APLL"
+                                          : ((conf.source == SOC_CPU_CLK_SRC_XTAL) ? "XTAL"
+#ifdef CONFIG_IDF_TARGET_ESP32P4
+                                          : "17.5M")),
+#else
+                                          : "8M")),
+#endif
     conf.source_freq_mhz, conf.div, conf.freq_mhz, apb
   );
 #else
   log_d(
-    "%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == RTC_CPU_FREQ_SRC_PLL) ? "PLL" : ((conf.source == RTC_CPU_FREQ_SRC_XTAL) ? "XTAL" : "17.5M"),
+    "%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == SOC_CPU_CLK_SRC_PLL) ? "PLL" : ((conf.source == SOC_CPU_CLK_SRC_XTAL) ? "XTAL" : "17.5M"),
     conf.source_freq_mhz, conf.div, conf.freq_mhz, apb
   );
 #endif
+  // clang-format on
   return true;
 }
 
diff --git a/cores/esp32/esp32-hal-i2c-slave.c b/cores/esp32/esp32-hal-i2c-slave.c
index edae1e57c92..85eddcdfcf4 100644
--- a/cores/esp32/esp32-hal-i2c-slave.c
+++ b/cores/esp32/esp32-hal-i2c-slave.c
@@ -41,21 +41,40 @@
 #include "esp_intr_alloc.h"
 #include "soc/i2c_reg.h"
 #include "soc/i2c_struct.h"
+#include "soc/periph_defs.h"
 #include "hal/i2c_ll.h"
 #include "hal/clk_gate_ll.h"
 #include "esp32-hal-log.h"
 #include "esp32-hal-i2c-slave.h"
 #include "esp32-hal-periman.h"
+#include "esp_private/periph_ctrl.h"
+
+#if SOC_PERIPH_CLK_CTRL_SHARED
+#define I2C_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
+#else
+#define I2C_CLOCK_SRC_ATOMIC()
+#endif
+
+#if !SOC_RCC_IS_INDEPENDENT
+#define I2C_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
+#else
+#define I2C_RCC_ATOMIC()
+#endif
 
 #define I2C_SLAVE_USE_RX_QUEUE 0  // 1: Queue, 0: RingBuffer
 
-#if SOC_I2C_NUM > 1
+#ifdef CONFIG_IDF_TARGET_ESP32P4
+#define I2C_SCL_IDX(p) ((p == 0) ? I2C0_SCL_PAD_OUT_IDX : ((p == 1) ? I2C1_SCL_PAD_OUT_IDX : 0))
+#define I2C_SDA_IDX(p) ((p == 0) ? I2C0_SDA_PAD_OUT_IDX : ((p == 1) ? I2C1_SDA_PAD_OUT_IDX : 0))
+#else
+#if SOC_HP_I2C_NUM > 1
 #define I2C_SCL_IDX(p) ((p == 0) ? I2CEXT0_SCL_OUT_IDX : ((p == 1) ? I2CEXT1_SCL_OUT_IDX : 0))
 #define I2C_SDA_IDX(p) ((p == 0) ? I2CEXT0_SDA_OUT_IDX : ((p == 1) ? I2CEXT1_SDA_OUT_IDX : 0))
 #else
 #define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX
 #define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX
 #endif
+#endif  // ifdef CONFIG_IDF_TARGET_ESP32P4
 
 #if CONFIG_IDF_TARGET_ESP32
 #define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA
@@ -99,14 +118,14 @@ typedef union {
   uint32_t val;
 } i2c_slave_queue_event_t;
 
-static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = {
+static i2c_slave_struct_t _i2c_bus_array[SOC_HP_I2C_NUM] = {
   {&I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
 #if !CONFIG_DISABLE_HAL_LOCKS
    ,
    NULL
 #endif
   },
-#if SOC_I2C_NUM > 1
+#if SOC_HP_I2C_NUM > 1
   {&I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
 #if !CONFIG_DISABLE_HAL_LOCKS
    ,
@@ -173,19 +192,19 @@ static inline void i2c_ll_stretch_clr(i2c_dev_t *hw) {
 }
 
 static inline bool i2c_ll_slave_addressed(i2c_dev_t *hw) {
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2
-  return hw->sr.slave_addressed;
-#else
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
   return hw->status_reg.slave_addressed;
+#else
+  return hw->sr.slave_addressed;
 #endif
 }
 
 static inline bool i2c_ll_slave_rw(i2c_dev_t *hw)  //not exposed by hal_ll
 {
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2
-  return hw->sr.slave_rw;
-#else
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
   return hw->status_reg.slave_rw;
+#else
+  return hw->sr.slave_rw;
 #endif
 }
 
@@ -210,7 +229,7 @@ static bool i2cSlaveDetachBus(void *bus_i2c_num);
 //=====================================================================================================================
 
 esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void *arg) {
-  if (num >= SOC_I2C_NUM) {
+  if (num >= SOC_HP_I2C_NUM) {
     log_e("Invalid port num: %u", num);
     return ESP_ERR_INVALID_ARG;
   }
@@ -224,7 +243,7 @@ esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_ca
 }
 
 esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) {
-  if (num >= SOC_I2C_NUM) {
+  if (num >= SOC_HP_I2C_NUM) {
     log_e("Invalid port num: %u", num);
     return ESP_ERR_INVALID_ARG;
   }
@@ -306,17 +325,18 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t
     frequency = 100000L;
   }
   frequency = (frequency * 5) / 4;
-
+#if !defined(CONFIG_IDF_TARGET_ESP32P4)
   if (i2c->num == 0) {
     periph_ll_enable_clk_clear_rst(PERIPH_I2C0_MODULE);
-#if SOC_I2C_NUM > 1
+#if SOC_HP_I2C_NUM > 1
   } else {
     periph_ll_enable_clk_clear_rst(PERIPH_I2C1_MODULE);
 #endif
   }
+#endif  // !defined(CONFIG_IDF_TARGET_ESP32P4)
 
   i2c_ll_slave_init(i2c->dev);
-  i2c_ll_set_fifo_mode(i2c->dev, true);
+  i2c_ll_slave_set_fifo_mode(i2c->dev, true);
   i2c_ll_set_slave_addr(i2c->dev, slaveID, false);
   i2c_ll_set_tout(i2c->dev, I2C_LL_MAX_TIMEOUT);
   i2c_slave_set_frequency(i2c, frequency);
@@ -337,15 +357,23 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t
 
   i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
   i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
-  i2c_ll_set_fifo_mode(i2c->dev, true);
+  i2c_ll_slave_set_fifo_mode(i2c->dev, true);
 
   if (!i2c->intr_handle) {
     uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED;
     if (i2c->num == 0) {
+#if !defined(CONFIG_IDF_TARGET_ESP32P4)
       ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
-#if SOC_I2C_NUM > 1
+#else
+      ret = esp_intr_alloc(ETS_I2C0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
+#endif
+#if SOC_HP_I2C_NUM > 1
     } else {
+#if !defined(CONFIG_IDF_TARGET_ESP32P4)
       ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
+#else
+      ret = esp_intr_alloc(ETS_I2C1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
+#endif
 #endif
     }
 
@@ -375,7 +403,7 @@ esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t
 }
 
 esp_err_t i2cSlaveDeinit(uint8_t num) {
-  if (num >= SOC_I2C_NUM) {
+  if (num >= SOC_HP_I2C_NUM) {
     log_e("Invalid port num: %u", num);
     return ESP_ERR_INVALID_ARG;
   }
@@ -398,7 +426,7 @@ esp_err_t i2cSlaveDeinit(uint8_t num) {
 }
 
 size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) {
-  if (num >= SOC_I2C_NUM) {
+  if (num >= SOC_HP_I2C_NUM) {
     log_e("Invalid port num: %u", num);
     return 0;
   }
@@ -515,16 +543,20 @@ static bool i2c_slave_set_frequency(i2c_slave_struct_t *i2c, uint32_t clk_speed)
 
   i2c_hal_clk_config_t clk_cal;
 #if SOC_I2C_SUPPORT_APB
-  i2c_ll_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal);
-  i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/
+  i2c_ll_master_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal);
+  I2C_CLOCK_SRC_ATOMIC() {
+    i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/
+  }
 #elif SOC_I2C_SUPPORT_XTAL
-  i2c_ll_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal);
-  i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_XTAL); /*!< I2C source clock from XTAL, 40M */
+  i2c_ll_master_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal);
+  I2C_CLOCK_SRC_ATOMIC() {
+    i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_XTAL); /*!< I2C source clock from XTAL, 40M */
+  }
 #endif
   i2c_ll_set_txfifo_empty_thr(i2c->dev, a);
   i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a);
-  i2c_ll_set_bus_timing(i2c->dev, &clk_cal);
-  i2c_ll_set_filter(i2c->dev, 3);
+  i2c_ll_master_set_bus_timing(i2c->dev, &clk_cal);
+  i2c_ll_master_set_filter(i2c->dev, 3);
   return true;
 }
 
diff --git a/cores/esp32/esp32-hal-i2c.c b/cores/esp32/esp32-hal-i2c.c
index 419ce66bb9b..359b2161201 100644
--- a/cores/esp32/esp32-hal-i2c.c
+++ b/cores/esp32/esp32-hal-i2c.c
@@ -29,6 +29,19 @@
 #include "hal/i2c_ll.h"
 #include "driver/i2c.h"
 #include "esp32-hal-periman.h"
+#include "esp_private/periph_ctrl.h"
+
+#if SOC_PERIPH_CLK_CTRL_SHARED
+#define I2C_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
+#else
+#define I2C_CLOCK_SRC_ATOMIC()
+#endif
+
+#if !SOC_RCC_IS_INDEPENDENT
+#define I2C_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
+#else
+#define I2C_RCC_ATOMIC()
+#endif
 
 #if SOC_I2C_SUPPORT_APB || SOC_I2C_SUPPORT_XTAL
 #include "esp_private/esp_clk.h"
@@ -388,7 +401,9 @@ esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency) {
       periph_rtc_dig_clk8m_enable();
     }
 #endif
-    i2c_hal_set_bus_timing(&(hal), frequency, i2c_clk_alloc[src_clk].clk, i2c_clk_alloc[src_clk].clk_freq);
+    I2C_CLOCK_SRC_ATOMIC() {
+      i2c_hal_set_bus_timing(&(hal), frequency, i2c_clk_alloc[src_clk].clk, i2c_clk_alloc[src_clk].clk_freq);
+    }
     bus[i2c_num].frequency = frequency;
     //Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2
     i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT);
diff --git a/cores/esp32/esp32-hal-ledc.c b/cores/esp32/esp32-hal-ledc.c
index 7d748f98a56..0a3ec5a60c7 100644
--- a/cores/esp32/esp32-hal-ledc.c
+++ b/cores/esp32/esp32-hal-ledc.c
@@ -323,11 +323,16 @@ bool ledcOutputInvert(uint8_t pin, bool out_invert) {
   ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
   if (bus != NULL) {
     gpio_set_level(pin, out_invert);
+
+#ifdef CONFIG_IDF_TARGET_ESP32P4
+    esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT_PAD_OUT0_IDX + ((bus->channel) % 8), out_invert, 0);
+#else
 #ifdef SOC_LEDC_SUPPORT_HS_MODE
     esp_rom_gpio_connect_out_signal(pin, ((bus->channel / 8 == 0) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX) + ((bus->channel) % 8), out_invert, 0);
 #else
     esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + ((bus->channel) % 8), out_invert, 0);
 #endif
+#endif  // ifdef CONFIG_IDF_TARGET_ESP32P4
     return true;
   }
   return false;
diff --git a/cores/esp32/esp32-hal-matrix.c b/cores/esp32/esp32-hal-matrix.c
index fba044d0c85..7cddb4e04db 100644
--- a/cores/esp32/esp32-hal-matrix.c
+++ b/cores/esp32/esp32-hal-matrix.c
@@ -32,6 +32,8 @@
 #include "esp32c6/rom/gpio.h"
 #elif CONFIG_IDF_TARGET_ESP32H2
 #include "esp32h2/rom/gpio.h"
+#elif CONFIG_IDF_TARGET_ESP32P4
+#include "esp32p4/rom/gpio.h"
 #else
 #error Target CONFIG_IDF_TARGET is not supported
 #endif
diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c
index 86140144613..0bce548bdd2 100644
--- a/cores/esp32/esp32-hal-misc.c
+++ b/cores/esp32/esp32-hal-misc.c
@@ -30,9 +30,9 @@
 #endif  //CONFIG_BT_ENABLED
 #include <sys/time.h>
 #include "soc/rtc.h"
-#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2)
+#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)
 #include "soc/rtc_cntl_reg.h"
-#include "soc/apb_ctrl_reg.h"
+#include "soc/syscon_reg.h"
 #endif
 #include "esp_task_wdt.h"
 #include "esp32-hal.h"
@@ -54,6 +54,8 @@
 #include "esp32c6/rom/rtc.h"
 #elif CONFIG_IDF_TARGET_ESP32H2
 #include "esp32h2/rom/rtc.h"
+#elif CONFIG_IDF_TARGET_ESP32P4
+#include "esp32p4/rom/rtc.h"
 
 #else
 #error Target CONFIG_IDF_TARGET is not supported
@@ -148,14 +150,14 @@ void feedLoopWDT() {
 #endif
 
 void enableCore0WDT() {
-  TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
+  TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCore(0);
   if (idle_0 == NULL || esp_task_wdt_add(idle_0) != ESP_OK) {
     log_e("Failed to add Core 0 IDLE task to WDT");
   }
 }
 
 void disableCore0WDT() {
-  TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
+  TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCore(0);
   if (idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK) {
     log_e("Failed to remove Core 0 IDLE task from WDT");
   }
@@ -163,14 +165,14 @@ void disableCore0WDT() {
 
 #ifndef CONFIG_FREERTOS_UNICORE
 void enableCore1WDT() {
-  TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
+  TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCore(1);
   if (idle_1 == NULL || esp_task_wdt_add(idle_1) != ESP_OK) {
     log_e("Failed to add Core 1 IDLE task to WDT");
   }
 }
 
 void disableCore1WDT() {
-  TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
+  TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCore(1);
   if (idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK) {
     log_e("Failed to remove Core 1 IDLE task from WDT");
   }
@@ -251,7 +253,7 @@ extern bool btInUse();
 #endif
 
 #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
-ESP_SYSTEM_INIT_FN(init_psram_new, BIT(0), 99) {
+ESP_SYSTEM_INIT_FN(init_psram_new, CORE, BIT(0), 99) {
   psramInit();
   return ESP_OK;
 }
diff --git a/cores/esp32/esp32-hal-psram.c b/cores/esp32/esp32-hal-psram.c
index b1b13f53ef3..3c7a51c3343 100644
--- a/cores/esp32/esp32-hal-psram.c
+++ b/cores/esp32/esp32-hal-psram.c
@@ -27,6 +27,8 @@
 #include "esp32s2/rom/cache.h"
 #elif CONFIG_IDF_TARGET_ESP32S3
 #include "esp32s3/rom/cache.h"
+#elif CONFIG_IDF_TARGET_ESP32P4
+#include "esp32p4/rom/cache.h"
 #else
 #error Target CONFIG_IDF_TARGET is not supported
 #endif
@@ -79,7 +81,7 @@ bool psramInit() {
     ESP_EARLY_LOGE(TAG, "PSRAM test failed!");
     return false;
   }
-  ESP_EARLY_LOGI(TAG, "PSRAM enabled");
+  //ESP_EARLY_LOGI(TAG, "PSRAM enabled");
 #endif /* CONFIG_SPIRAM_BOOT_INIT */
   spiramDetected = true;
   return true;
diff --git a/cores/esp32/esp32-hal-psram.h b/cores/esp32/esp32-hal-psram.h
index e82af1342c2..69c1c625157 100644
--- a/cores/esp32/esp32-hal-psram.h
+++ b/cores/esp32/esp32-hal-psram.h
@@ -21,7 +21,8 @@ extern "C" {
 
 #include "sdkconfig.h"
 
-#ifndef BOARD_HAS_PSRAM
+// Clear flags in Arduino IDE when PSRAM is disabled
+#if defined(ESP32_ARDUINO_LIB_BUILDER) && !defined(BOARD_HAS_PSRAM)
 #ifdef CONFIG_SPIRAM_SUPPORT
 #undef CONFIG_SPIRAM_SUPPORT
 #endif
diff --git a/cores/esp32/esp32-hal-spi.c b/cores/esp32/esp32-hal-spi.c
index 857c3d4bb2e..80928309670 100644
--- a/cores/esp32/esp32-hal-spi.c
+++ b/cores/esp32/esp32-hal-spi.c
@@ -22,11 +22,13 @@
 #include "esp_attr.h"
 #include "soc/spi_reg.h"
 #include "soc/spi_struct.h"
+#include "soc/periph_defs.h"
 #include "soc/io_mux_reg.h"
 #include "soc/gpio_sig_map.h"
 #include "soc/rtc.h"
 #include "hal/clk_gate_ll.h"
 #include "esp32-hal-periman.h"
+#include "esp_private/periph_ctrl.h"
 
 #include "esp_system.h"
 #include "esp_intr_alloc.h"
@@ -55,12 +57,15 @@
 #elif CONFIG_IDF_TARGET_ESP32H2
 #include "esp32h2/rom/ets_sys.h"
 #include "esp32h2/rom/gpio.h"
+#elif CONFIG_IDF_TARGET_ESP32P4
+#include "esp32p4/rom/ets_sys.h"
+#include "esp32p4/rom/gpio.h"
 #else
 #error Target CONFIG_IDF_TARGET is not supported
 #endif
 
 struct spi_struct_t {
-  spi_dev_t *dev;
+  volatile spi_dev_t *dev;
 #if !CONFIG_DISABLE_HAL_LOCKS
   SemaphoreHandle_t lock;
 #endif
@@ -96,6 +101,24 @@ struct spi_struct_t {
 #define SPI_FSPI_SS_IDX(n) ((n == 0) ? FSPICS0_OUT_IDX : ((n == 1) ? FSPICS1_OUT_IDX : 0))
 #define SPI_SS_IDX(p, n)   ((p == 0) ? SPI_FSPI_SS_IDX(n) : ((p == 1) ? SPI_HSPI_SS_IDX(n) : 0))
 
+#elif CONFIG_IDF_TARGET_ESP32P4
+// ESP32P4
+#define SPI_COUNT (2)  // SPI2 and SPI3. SPI0 and SPI1 are reserved for flash and PSRAM
+
+#define SPI_CLK_IDX(p)  ((p == 0) ? SPI2_CK_PAD_OUT_IDX : ((p == 1) ? SPI3_CK_PAD_OUT_IDX : 0))
+#define SPI_MISO_IDX(p) ((p == 0) ? SPI2_Q_PAD_OUT_IDX : ((p == 1) ? SPI3_QO_PAD_OUT_IDX : 0))
+#define SPI_MOSI_IDX(p) ((p == 0) ? SPI2_D_PAD_IN_IDX : ((p == 1) ? SPI3_D_PAD_IN_IDX : 0))
+
+#define SPI_HSPI_SS_IDX(n) ((n == 0) ? SPI3_CS_PAD_OUT_IDX : ((n == 1) ? SPI3_CS1_PAD_OUT_IDX : ((n == 2) ? SPI3_CS2_PAD_OUT_IDX : 0)))
+
+#define SPI_FSPI_SS_IDX(n)                                 \
+  ((n == 0) ? SPI2_CS_PAD_OUT_IDX                          \
+            : ((n == 1) ? SPI2_CS1_PAD_OUT_IDX             \
+                        : ((n == 2) ? SPI2_CS2_PAD_OUT_IDX \
+                                    : ((n == 3) ? SPI2_CS3_PAD_OUT_IDX : ((n == 4) ? SPI2_CS4_PAD_OUT_IDX : ((n == 5) ? SPI2_CS5_PAD_OUT_IDX : 0))))))
+
+#define SPI_SS_IDX(p, n) ((p == 0) ? SPI_FSPI_SS_IDX(n) : ((p == 1) ? SPI_HSPI_SS_IDX(n) : 0))
+
 #elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
 // ESP32C3
 #define SPI_COUNT (1)
@@ -125,14 +148,15 @@ struct spi_struct_t {
 #if CONFIG_DISABLE_HAL_LOCKS
 #define SPI_MUTEX_LOCK()
 #define SPI_MUTEX_UNLOCK()
-
+// clang-format off
 static spi_t _spi_bus_array[] = {
 #if CONFIG_IDF_TARGET_ESP32S2
   {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1},
   {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1},
   {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1}
-#elif CONFIG_IDF_TARGET_ESP32S3
-  {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1}
+#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4
+  {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1},
+  {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1}
 #elif CONFIG_IDF_TARGET_ESP32C2
   {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1}
 #elif CONFIG_IDF_TARGET_ESP32C3
@@ -146,6 +170,7 @@ static spi_t _spi_bus_array[] = {
   {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1}
 #endif
 };
+// clang-format on
 #else
 #define SPI_MUTEX_LOCK() \
   do {                   \
@@ -157,7 +182,7 @@ static spi_t _spi_bus_array[] = {
   {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0, -1, -1, -1, -1},
   {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1, -1, -1, -1, -1},
   {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2, -1, -1, -1, -1}
-#elif CONFIG_IDF_TARGET_ESP32S3
+#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4
   {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 1, -1, -1, -1, -1}
 #elif CONFIG_IDF_TARGET_ESP32C2
   {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1}
@@ -369,11 +394,10 @@ void spiEnableSSPins(spi_t *spi, uint8_t ss_mask) {
     return;
   }
   SPI_MUTEX_LOCK();
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-  spi->dev->misc.val &= ~(ss_mask & SPI_SS_MASK_ALL);
-#else
+#if CONFIG_IDF_TARGET_ESP32
   spi->dev->pin.val &= ~(ss_mask & SPI_SS_MASK_ALL);
+#else
+  spi->dev->misc.val &= ~(ss_mask & SPI_SS_MASK_ALL);
 #endif
   SPI_MUTEX_UNLOCK();
 }
@@ -383,11 +407,10 @@ void spiDisableSSPins(spi_t *spi, uint8_t ss_mask) {
     return;
   }
   SPI_MUTEX_LOCK();
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-  spi->dev->misc.val |= (ss_mask & SPI_SS_MASK_ALL);
-#else
+#if CONFIG_IDF_TARGET_ESP32
   spi->dev->pin.val |= (ss_mask & SPI_SS_MASK_ALL);
+#else
+  spi->dev->misc.val |= (ss_mask & SPI_SS_MASK_ALL);
 #endif
   SPI_MUTEX_UNLOCK();
 }
@@ -417,11 +440,10 @@ void spiSSSet(spi_t *spi) {
     return;
   }
   SPI_MUTEX_LOCK();
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-  spi->dev->misc.cs_keep_active = 1;
-#else
+#if CONFIG_IDF_TARGET_ESP32
   spi->dev->pin.cs_keep_active = 1;
+#else
+  spi->dev->misc.cs_keep_active = 1;
 #endif
   SPI_MUTEX_UNLOCK();
 }
@@ -431,11 +453,10 @@ void spiSSClear(spi_t *spi) {
     return;
   }
   SPI_MUTEX_LOCK();
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-  spi->dev->misc.cs_keep_active = 0;
-#else
+#if CONFIG_IDF_TARGET_ESP32
   spi->dev->pin.cs_keep_active = 0;
+#else
+  spi->dev->misc.cs_keep_active = 0;
 #endif
   SPI_MUTEX_UNLOCK();
 }
@@ -460,11 +481,10 @@ uint8_t spiGetDataMode(spi_t *spi) {
   if (!spi) {
     return 0;
   }
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-  bool idleEdge = spi->dev->misc.ck_idle_edge;
-#else
+#if CONFIG_IDF_TARGET_ESP32
   bool idleEdge = spi->dev->pin.ck_idle_edge;
+#else
+  bool idleEdge = spi->dev->misc.ck_idle_edge;
 #endif
   bool outEdge = spi->dev->user.ck_out_edge;
   if (idleEdge) {
@@ -486,39 +506,35 @@ void spiSetDataMode(spi_t *spi, uint8_t dataMode) {
   SPI_MUTEX_LOCK();
   switch (dataMode) {
     case SPI_MODE1:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 0;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 0;
+#else
+      spi->dev->misc.ck_idle_edge = 0;
 #endif
       spi->dev->user.ck_out_edge = 1;
       break;
     case SPI_MODE2:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 1;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 1;
+#else
+      spi->dev->misc.ck_idle_edge = 1;
 #endif
       spi->dev->user.ck_out_edge = 1;
       break;
     case SPI_MODE3:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 1;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 1;
+#else
+      spi->dev->misc.ck_idle_edge = 1;
 #endif
       spi->dev->user.ck_out_edge = 0;
       break;
     case SPI_MODE0:
     default:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 0;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 0;
+#else
+      spi->dev->misc.ck_idle_edge = 0;
 #endif
       spi->dev->user.ck_out_edge = 0;
       break;
@@ -564,11 +580,10 @@ static void spiInitBus(spi_t *spi) {
   spi->dev->slave.trans_done = 0;
 #endif
   spi->dev->slave.val = 0;
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-  spi->dev->misc.val = 0;
-#else
+#if CONFIG_IDF_TARGET_ESP32
   spi->dev->pin.val = 0;
+#else
+  spi->dev->misc.val = 0;
 #endif
   spi->dev->user.val = 0;
   spi->dev->user1.val = 0;
@@ -648,18 +663,18 @@ spi_t *spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t
     DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
     DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
   }
-#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#elif defined(__PERIPH_CTRL_ALLOW_LEGACY_API)
   periph_ll_reset(PERIPH_SPI2_MODULE);
   periph_ll_enable_clk_clear_rst(PERIPH_SPI2_MODULE);
 #endif
 
   SPI_MUTEX_LOCK();
   spiInitBus(spi);
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->clk_gate.clk_en = 1;
   spi->dev->clk_gate.mst_clk_sel = 1;
   spi->dev->clk_gate.mst_clk_active = 1;
-#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2
+#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3)
   spi->dev->dma_conf.tx_seg_trans_clr_en = 1;
   spi->dev->dma_conf.rx_seg_trans_clr_en = 1;
   spi->dev->dma_conf.dma_seg_trans_en = 0;
@@ -670,7 +685,7 @@ spi_t *spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t
   spi->dev->user.doutdin = 1;
   int i;
   for (i = 0; i < 16; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
     spi->dev->data_buf[i].val = 0x00000000;
 #else
     spi->dev->data_buf[i] = 0x00000000;
@@ -697,7 +712,7 @@ void spiWaitReady(spi_t *spi) {
 #if CONFIG_IDF_TARGET_ESP32S2
 #define usr_mosi_dbitlen usr_mosi_bit_len
 #define usr_miso_dbitlen usr_miso_bit_len
-#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#elif !defined(CONFIG_IDF_TARGET_ESP32)
 #define usr_mosi_dbitlen ms_data_bitlen
 #define usr_miso_dbitlen ms_data_bitlen
 #define mosi_dlen        ms_dlen
@@ -718,13 +733,13 @@ void spiWrite(spi_t *spi, const uint32_t *data, uint8_t len) {
   spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
   for (i = 0; i < len; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
     spi->dev->data_buf[i].val = data[i];
 #else
     spi->dev->data_buf[i] = data[i];
 #endif
   }
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -745,20 +760,20 @@ void spiTransfer(spi_t *spi, uint32_t *data, uint8_t len) {
   spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1;
   spi->dev->miso_dlen.usr_miso_dbitlen = (len * 32) - 1;
   for (i = 0; i < len; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
     spi->dev->data_buf[i].val = data[i];
 #else
     spi->dev->data_buf[i] = data[i];
 #endif
   }
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
   for (i = 0; i < len; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
     data[i] = spi->dev->data_buf[i].val;
 #else
     data[i] = spi->dev->data_buf[i];
@@ -776,13 +791,13 @@ void spiWriteByte(spi_t *spi, uint8_t data) {
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
   spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
 
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -798,18 +813,18 @@ uint8_t spiTransferByte(spi_t *spi, uint8_t data) {
   SPI_MUTEX_LOCK();
   spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
   spi->dev->miso_dlen.usr_miso_dbitlen = 7;
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   data = spi->dev->data_buf[0].val & 0xFF;
 #else
   data = spi->dev->data_buf[0] & 0xFF;
@@ -839,12 +854,12 @@ void spiWriteWord(spi_t *spi, uint16_t data) {
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
   spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -863,18 +878,18 @@ uint16_t spiTransferWord(spi_t *spi, uint16_t data) {
   SPI_MUTEX_LOCK();
   spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
   spi->dev->miso_dlen.usr_miso_dbitlen = 15;
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   data = spi->dev->data_buf[0].val;
 #else
   data = spi->dev->data_buf[0];
@@ -898,12 +913,12 @@ void spiWriteLong(spi_t *spi, uint32_t data) {
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
   spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -922,18 +937,18 @@ uint32_t spiTransferLong(spi_t *spi, uint32_t data) {
   SPI_MUTEX_LOCK();
   spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
   spi->dev->miso_dlen.usr_miso_dbitlen = 31;
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   data = spi->dev->data_buf[0].val;
 #else
   data = spi->dev->data_buf[0];
@@ -972,14 +987,14 @@ static void __spiTransferBytes(spi_t *spi, const uint8_t *data, uint8_t *out, ui
   spi->dev->miso_dlen.usr_miso_dbitlen = ((bytes * 8) - 1);
 
   for (i = 0; i < words; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
     spi->dev->data_buf[i].val = wordsBuf[i];  //copy buffer to spi fifo
 #else
     spi->dev->data_buf[i] = wordsBuf[i];  //copy buffer to spi fifo
 #endif
   }
 
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -989,7 +1004,7 @@ static void __spiTransferBytes(spi_t *spi, const uint8_t *data, uint8_t *out, ui
 
   if (out) {
     for (i = 0; i < words; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
       wordsBuf[i] = spi->dev->data_buf[i].val;  //copy spi fifo to buffer
 #else
       wordsBuf[i] = spi->dev->data_buf[i];  //copy spi fifo to buffer
@@ -1061,39 +1076,35 @@ void spiTransaction(spi_t *spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bit
   spi->dev->clock.val = clockDiv;
   switch (dataMode) {
     case SPI_MODE1:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 0;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 0;
+#else
+      spi->dev->misc.ck_idle_edge = 0;
 #endif
       spi->dev->user.ck_out_edge = 1;
       break;
     case SPI_MODE2:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 1;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 1;
+#else
+      spi->dev->misc.ck_idle_edge = 1;
 #endif
       spi->dev->user.ck_out_edge = 1;
       break;
     case SPI_MODE3:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 1;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 1;
+#else
+      spi->dev->misc.ck_idle_edge = 1;
 #endif
       spi->dev->user.ck_out_edge = 0;
       break;
     case SPI_MODE0:
     default:
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 \
-  || CONFIG_IDF_TARGET_ESP32H2
-      spi->dev->misc.ck_idle_edge = 0;
-#else
+#if CONFIG_IDF_TARGET_ESP32
       spi->dev->pin.ck_idle_edge = 0;
+#else
+      spi->dev->misc.ck_idle_edge = 0;
 #endif
       spi->dev->user.ck_out_edge = 0;
       break;
@@ -1105,7 +1116,7 @@ void spiTransaction(spi_t *spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bit
     spi->dev->ctrl.wr_bit_order = 1;
     spi->dev->ctrl.rd_bit_order = 1;
   }
-#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   // Sync new config with hardware, fixes https://github.com/espressif/arduino-esp32/issues/9221
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
@@ -1134,12 +1145,12 @@ void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t *spi, uint8_t data) {
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
   spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -1153,18 +1164,18 @@ uint8_t spiTransferByteNL(spi_t *spi, uint8_t data) {
   }
   spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
   spi->dev->miso_dlen.usr_miso_dbitlen = 7;
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   data = spi->dev->data_buf[0].val & 0xFF;
 #else
   data = spi->dev->data_buf[0] & 0xFF;
@@ -1183,12 +1194,12 @@ void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t *spi, uint16_t data) {
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
   spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -1205,18 +1216,18 @@ uint16_t spiTransferShortNL(spi_t *spi, uint16_t data) {
   }
   spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
   spi->dev->miso_dlen.usr_miso_dbitlen = 15;
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   data = spi->dev->data_buf[0].val & 0xFFFF;
 #else
   data = spi->dev->data_buf[0] & 0xFFFF;
@@ -1238,12 +1249,12 @@ void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t *spi, uint32_t data) {
 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
   spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
@@ -1260,18 +1271,18 @@ uint32_t spiTransferLongNL(spi_t *spi, uint32_t data) {
   }
   spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
   spi->dev->miso_dlen.usr_miso_dbitlen = 31;
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   data = spi->dev->data_buf[0].val;
 #else
   data = spi->dev->data_buf[0];
@@ -1302,13 +1313,13 @@ void spiWriteNL(spi_t *spi, const void *data_in, uint32_t len) {
     spi->dev->miso_dlen.usr_miso_dbitlen = 0;
 #endif
     for (size_t i = 0; i < c_longs; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
       spi->dev->data_buf[i].val = data[i];
 #else
       spi->dev->data_buf[i] = data[i];
 #endif
     }
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
     spi->dev->cmd.update = 1;
     while (spi->dev->cmd.update);
 #endif
@@ -1341,7 +1352,7 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint
     spi->dev->miso_dlen.usr_miso_dbitlen = (c_len * 8) - 1;
     if (data) {
       for (size_t i = 0; i < c_longs; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
         spi->dev->data_buf[i].val = data[i];
 #else
         spi->dev->data_buf[i] = data[i];
@@ -1349,14 +1360,14 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint
       }
     } else {
       for (size_t i = 0; i < c_longs; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
         spi->dev->data_buf[i].val = 0xFFFFFFFF;
 #else
         spi->dev->data_buf[i] = 0xFFFFFFFF;
 #endif
       }
     }
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
     spi->dev->cmd.update = 1;
     while (spi->dev->cmd.update);
 #endif
@@ -1365,13 +1376,13 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint
     if (result) {
       if (c_len & 3) {
         for (size_t i = 0; i < (c_longs - 1); i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
           result[i] = spi->dev->data_buf[i].val;
 #else
           result[i] = spi->dev->data_buf[i];
 #endif
         }
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
         uint32_t last_data = spi->dev->data_buf[c_longs - 1].val;
 #else
         uint32_t last_data = spi->dev->data_buf[c_longs - 1];
@@ -1383,7 +1394,7 @@ void spiTransferBytesNL(spi_t *spi, const void *data_in, uint8_t *data_out, uint
         }
       } else {
         for (size_t i = 0; i < c_longs; i++) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
           result[i] = spi->dev->data_buf[i].val;
 #else
           result[i] = spi->dev->data_buf[i];
@@ -1425,18 +1436,18 @@ void spiTransferBitsNL(spi_t *spi, uint32_t data, uint32_t *out, uint8_t bits) {
 
   spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1);
   spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   spi->dev->data_buf[0].val = data;
 #else
   spi->dev->data_buf[0] = data;
 #endif
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
   spi->dev->cmd.update = 1;
   while (spi->dev->cmd.update);
 #endif
   spi->dev->cmd.usr = 1;
   while (spi->dev->cmd.usr);
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   data = spi->dev->data_buf[0].val;
 #else
   data = spi->dev->data_buf[0];
@@ -1477,34 +1488,34 @@ void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t *spi, const void *data_in, uint32_t
       if (msb) {
         if (l_bytes && i == (c_longs - 1)) {
           if (l_bytes == 2) {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
             MSB_16_SET(spi->dev->data_buf[i].val, data[i]);
 #else
             MSB_16_SET(spi->dev->data_buf[i], data[i]);
 #endif
           } else {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
             spi->dev->data_buf[i].val = data[i] & 0xFF;
 #else
             spi->dev->data_buf[i] = data[i] & 0xFF;
 #endif
           }
         } else {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
           MSB_PIX_SET(spi->dev->data_buf[i].val, data[i]);
 #else
           MSB_PIX_SET(spi->dev->data_buf[i], data[i]);
 #endif
         }
       } else {
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
         spi->dev->data_buf[i].val = data[i];
 #else
         spi->dev->data_buf[i] = data[i];
 #endif
       }
     }
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
     spi->dev->cmd.update = 1;
     while (spi->dev->cmd.update);
 #endif
@@ -1528,7 +1539,7 @@ typedef union {
     uint32_t clkcnt_l : 6; /*it must be equal to spi_clkcnt_N.*/
     uint32_t clkcnt_h : 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
     uint32_t clkcnt_n : 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
     uint32_t clkdiv_pre : 4; /*it is pre-divider of spi_clk.*/
     uint32_t reserved   : 9; /*reserved*/
 #else
@@ -1573,7 +1584,7 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq) {
 
     while (calPreVari++ <= 1) {
       calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
       if (calPre > 0xF) {
         reg.clkdiv_pre = 0xF;
 #else
diff --git a/cores/esp32/esp32-hal-spi.h b/cores/esp32/esp32-hal-spi.h
index a238cada87d..b77abff7854 100644
--- a/cores/esp32/esp32-hal-spi.h
+++ b/cores/esp32/esp32-hal-spi.h
@@ -28,10 +28,7 @@ extern "C" {
 
 #define SPI_HAS_TRANSACTION
 
-#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32S3
-#define FSPI 0
-#define HSPI 1
-#elif CONFIG_IDF_TARGET_ESP32S2
+#ifdef CONFIG_IDF_TARGET_ESP32S2
 #define FSPI 1  //SPI 1 bus. ESP32S2: for external memory only (can use the same data lines but different SS)
 #define HSPI 2  //SPI 2 bus. ESP32S2: external memory or device  - it can be matrixed to any pins
 #define SPI2 2  // Another name for ESP32S2 SPI 2
@@ -40,6 +37,9 @@ extern "C" {
 #define FSPI 1  //SPI 1 bus attached to the flash (can use the same data lines but different SS)
 #define HSPI 2  //SPI 2 bus normally mapped to pins 12 - 15, but can be matrixed to any pins
 #define VSPI 3  //SPI 3 bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins
+#else
+#define FSPI 0
+#define HSPI 1
 #endif
 
 // This defines are not representing the real Divider of the ESP32
diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c
index f7225425913..f83e8b61bd2 100644
--- a/cores/esp32/esp32-hal-tinyusb.c
+++ b/cores/esp32/esp32-hal-tinyusb.c
@@ -10,12 +10,15 @@
 
 #include "soc/soc.h"
 #include "soc/efuse_reg.h"
+#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 #include "soc/rtc_cntl_reg.h"
 #include "soc/usb_struct.h"
 #include "soc/usb_reg.h"
 #include "soc/usb_wrap_reg.h"
 #include "soc/usb_wrap_struct.h"
 #include "soc/usb_periph.h"
+#endif
+
 #include "soc/periph_defs.h"
 #include "soc/timer_group_struct.h"
 #include "soc/system_reg.h"
@@ -34,8 +37,8 @@
 
 #include "esp32-hal.h"
 #include "esp32-hal-periman.h"
-
 #include "esp32-hal-tinyusb.h"
+
 #if CONFIG_IDF_TARGET_ESP32S2
 #include "esp32s2/rom/usb/usb_persist.h"
 #include "esp32s2/rom/usb/usb_dc.h"
@@ -50,6 +53,7 @@
 #include "esp32s3/rom/usb/usb_persist.h"
 #include "esp32s3/rom/usb/usb_dc.h"
 #include "esp32s3/rom/usb/chip_usb_dw_wrapper.h"
+#elif CONFIG_IDF_TARGET_ESP32P4
 #endif
 
 typedef enum {
@@ -127,7 +131,11 @@ esp_err_t init_usb_hal(bool external_phy) {
     .controller = USB_PHY_CTRL_OTG,
     .target = USB_PHY_TARGET_INT,
     .otg_mode = USB_OTG_MODE_DEVICE,
+#if CONFIG_IDF_TARGET_ESP32P4
+    .otg_speed = USB_PHY_SPEED_HIGH,
+#else
     .otg_speed = USB_PHY_SPEED_FULL,
+#endif
     .ext_io_conf = NULL,
     .otg_io_conf = NULL,
   };
@@ -165,7 +173,16 @@ void deinit_usb_hal() {
 
 esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) {
   init_usb_hal(config->external_phy);
-  if (!tusb_init()) {
+  tusb_rhport_init_t tinit;
+  memset(&tinit, 0, sizeof(tusb_rhport_init_t));
+  tinit.role = TUSB_ROLE_DEVICE;
+#if CONFIG_IDF_TARGET_ESP32P4
+  tinit.speed = TUSB_SPEED_HIGH;
+  if (!tusb_init(1, &tinit)) {
+#else
+  tinit.speed = TUSB_SPEED_FULL;
+  if (!tusb_init(0, &tinit)) {
+#endif
     log_e("Can't initialize the TinyUSB stack.");
     return ESP_FAIL;
   }
@@ -275,15 +292,14 @@ enum {
   VENDOR_REQUEST_MICROSOFT = 2
 };
 
-static uint8_t const tinyusb_bos_descriptor[] = {
-  // total length, number of device caps
-  TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
+static uint8_t const tinyusb_bos_descriptor[] = {// total length, number of device caps
+                                                 TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
 
-  // Vendor Code, iLandingPage
-  TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
+                                                 // Vendor Code, iLandingPage
+                                                 TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
 
-  // Microsoft OS 2.0 descriptor
-  TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
+                                                 // Microsoft OS 2.0 descriptor
+                                                 TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
 };
 
 /*
@@ -467,8 +483,10 @@ __attribute__((weak)) void tud_network_init_cb(void) {}
 /*
  * Private API
  * */
+#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 static bool usb_persist_enabled = false;
 static restart_type_t usb_persist_mode = RESTART_NO_PERSIST;
+#endif
 
 #if CONFIG_IDF_TARGET_ESP32S3
 
@@ -549,6 +567,7 @@ static void usb_switch_to_cdc_jtag() {
 }
 #endif
 
+#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 static void IRAM_ATTR usb_persist_shutdown_handler(void) {
   if (usb_persist_mode != RESTART_NO_PERSIST) {
     if (usb_persist_enabled) {
@@ -580,8 +599,10 @@ static void IRAM_ATTR usb_persist_shutdown_handler(void) {
     }
   }
 }
+#endif
 
 void usb_persist_restart(restart_type_t mode) {
+#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
   if (mode < RESTART_TYPE_MAX && esp_register_shutdown_handler(usb_persist_shutdown_handler) == ESP_OK) {
     usb_persist_mode = mode;
 #if CONFIG_IDF_TARGET_ESP32S3
@@ -591,6 +612,7 @@ void usb_persist_restart(restart_type_t mode) {
 #endif
     esp_restart();
   }
+#endif
 }
 
 static bool tinyusb_reserve_in_endpoint(uint8_t endpoint) {
@@ -674,8 +696,13 @@ static inline char nibble_to_hex_char(uint8_t b) {
 
 static void set_usb_serial_num(void) {
   /* Get the MAC address */
+#if CONFIG_IDF_TARGET_ESP32P4
+  const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SYS_0_REG, EFUSE_MAC_0);
+  const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SYS_0_REG, EFUSE_MAC_1);
+#else
   const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0);
   const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1);
+#endif
   uint8_t mac_bytes[6];
   memcpy(mac_bytes, &mac0, 4);
   memcpy(mac_bytes + 4, &mac1, 2);
@@ -794,6 +821,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
     return ESP_FAIL;
   }
 
+#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
   bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA);
 
   //if(usb_did_persist && usb_persist_enabled){
@@ -806,6 +834,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
     periph_ll_reset(PERIPH_USB_MODULE);
     periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE);
   }
+#endif
 
   tinyusb_config_t tusb_cfg = {
     .external_phy = false  // In the most cases you need to use a `false` value
diff --git a/cores/esp32/esp32-hal-tinyusb.h b/cores/esp32/esp32-hal-tinyusb.h
index 9e9d044f80e..0b42760e69f 100644
--- a/cores/esp32/esp32-hal-tinyusb.h
+++ b/cores/esp32/esp32-hal-tinyusb.h
@@ -31,6 +31,14 @@ extern "C" {
 #define USB_ESPRESSIF_VID                0x303A
 #define USB_STRING_DESCRIPTOR_ARRAY_SIZE 10
 
+#ifndef CFG_TUD_ENDOINT_SIZE
+#if CONFIG_IDF_TARGET_ESP32P4
+#define CFG_TUD_ENDOINT_SIZE 512
+#else
+#define CFG_TUD_ENDOINT_SIZE 64
+#endif
+#endif
+
 typedef struct {
   uint16_t vid;
   uint16_t pid;
diff --git a/cores/esp32/esp32-hal-touch-ng.c b/cores/esp32/esp32-hal-touch-ng.c
new file mode 100644
index 00000000000..888a299ec0c
--- /dev/null
+++ b/cores/esp32/esp32-hal-touch-ng.c
@@ -0,0 +1,453 @@
+// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "soc/soc_caps.h"
+
+#if SOC_TOUCH_SENSOR_SUPPORTED
+#if SOC_TOUCH_SENSOR_VERSION == 3  // ESP32P4 for now
+
+#include "driver/touch_sens.h"
+#include "esp32-hal-touch-ng.h"
+#include "esp32-hal-periman.h"
+
+/*
+    Internal Private Touch Data Structure and Functions
+*/
+
+typedef void (*voidFuncPtr)(void);
+typedef void (*voidArgFuncPtr)(void *);
+
+typedef struct {
+  voidFuncPtr fn;
+  bool callWithArgs;
+  void *arg;
+  bool lastStatusIsPressed;
+} TouchInterruptHandle_t;
+
+static TouchInterruptHandle_t __touchInterruptHandlers[SOC_TOUCH_SENSOR_NUM] = {
+  0,
+};
+
+static uint8_t _sample_num = 1;
+static uint32_t _div_num = 1;
+static uint8_t _coarse_freq_tune = 1;
+static uint8_t _fine_freq_tune = 1;
+static uint8_t used_pads = 0;
+
+static uint32_t __touchSleepTime = 256;
+static float __touchMeasureTime = 32.0f;
+
+static touch_sensor_config_t sensor_config;
+
+static bool initialized = false;
+static bool enabled = false;
+static bool running = false;
+static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = {false};
+
+static touch_sensor_handle_t touch_sensor_handle = NULL;
+static touch_channel_handle_t touch_channel_handle[SOC_TOUCH_SENSOR_NUM] = {};
+
+// Active threshold to benchmark ratio. (i.e., touch will be activated when data >= benchmark * (1 + ratio))
+static float s_thresh2bm_ratio = 0.015f;  // 1.5% for all channels
+
+static bool ARDUINO_ISR_ATTR __touchOnActiveISR(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) {
+  uint8_t pad_num = (uint8_t)event->chan_id;
+  __touchInterruptHandlers[pad_num].lastStatusIsPressed = true;
+  if (__touchInterruptHandlers[pad_num].fn) {
+    // keeping backward compatibility with "void cb(void)" and with new "void cb(void *)"
+    if (__touchInterruptHandlers[pad_num].callWithArgs) {
+      ((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg);
+    } else {
+      __touchInterruptHandlers[pad_num].fn();
+    }
+  }
+  return false;
+}
+
+static bool ARDUINO_ISR_ATTR __touchOnInactiveISR(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx) {
+  uint8_t pad_num = (uint8_t)event->chan_id;
+  __touchInterruptHandlers[pad_num].lastStatusIsPressed = false;
+  if (__touchInterruptHandlers[pad_num].fn) {
+    // keeping backward compatibility with "void cb(void)" and with new "void cb(void *)"
+    if (__touchInterruptHandlers[pad_num].callWithArgs) {
+      ((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg);
+    } else {
+      __touchInterruptHandlers[pad_num].fn();
+    }
+  }
+  return false;
+}
+
+bool touchStop() {
+  if (!running) {  // Already stopped
+    return true;
+  }
+  if (touch_sensor_stop_continuous_scanning(touch_sensor_handle) != ESP_OK) {
+    log_e("Touch sensor stop scanning failed!");
+    return false;
+  }
+  running = false;
+  return true;
+}
+
+bool touchDisable() {
+  if (!enabled) {  // Already disabled
+    return true;
+  }
+  if (!running && (touch_sensor_disable(touch_sensor_handle) != ESP_OK)) {
+    log_e("Touch sensor still running or disable failed!");
+    return false;
+  }
+  enabled = false;
+  return true;
+}
+
+bool touchStart() {
+  if (running) {  // Already running
+    return true;
+  }
+  if (enabled && (touch_sensor_start_continuous_scanning(touch_sensor_handle) != ESP_OK)) {
+    log_e("Touch sensor not enabled or failed to start continuous scanning failed!");
+    return false;
+  }
+  running = true;
+  return true;
+}
+
+bool touchEnable() {
+  if (enabled) {  // Already enabled
+    return true;
+  }
+  if (touch_sensor_enable(touch_sensor_handle) != ESP_OK) {
+    log_e("Touch sensor enable failed!");
+    return false;
+  }
+  enabled = true;
+  return true;
+}
+
+bool touchBenchmarkThreshold(uint8_t pad) {
+  if (!touchEnable()) {
+    return false;
+  }
+
+  /* Scan the enabled touch channels for several times, to make sure the initial channel data is stable */
+  for (int i = 0; i < 3; i++) {
+    if (touch_sensor_trigger_oneshot_scanning(touch_sensor_handle, 2000) != ESP_OK) {
+      log_e("Touch sensor trigger oneshot scanning failed!");
+      return false;
+    }
+  }
+
+  /* Disable the touch channel to rollback the state */
+  if (!touchDisable()) {
+    return false;
+  }
+
+  // Reconfigure passed pad with new threshold
+  uint32_t benchmark[_sample_num] = {};
+  if (touch_channel_read_data(touch_channel_handle[pad], TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark) != ESP_OK) {
+    log_e("Touch channel read data failed!");
+    return false;
+  }
+  /* Calculate the proper active thresholds regarding the initial benchmark */
+  touch_channel_config_t chan_cfg = {};
+  for (int i = 0; i < _sample_num; i++) {
+    chan_cfg.active_thresh[i] = (uint32_t)(benchmark[i] * s_thresh2bm_ratio);
+    log_v("Configured [CH %d] sample %d: benchmark = %" PRIu32 ", threshold = %" PRIu32 "\t", pad, i, benchmark[i], chan_cfg.active_thresh[i]);
+  }
+  /* Update the channel configuration */
+  if (touch_sensor_reconfig_channel(touch_channel_handle[pad], &chan_cfg) != ESP_OK) {
+    log_e("Touch sensor threshold reconfig channel failed!");
+    return false;
+  }
+  return true;
+}
+
+static bool touchDetachBus(void *pin) {
+  int8_t pad = digitalPinToTouchChannel((int)(pin - 1));
+  channels_initialized[pad] = false;
+  //disable touch pad and delete the channel
+  touch_sensor_del_channel(touch_channel_handle[pad]);
+  used_pads--;
+  if (used_pads == 0) {
+    touchStop();
+    touchDisable();
+    if (touch_sensor_del_controller(touch_sensor_handle) != ESP_OK)  //deinit touch module, as no pads are used
+    {
+      log_e("Touch module deinit failed!");
+      return false;
+    }
+    initialized = false;
+  }
+  return true;
+}
+
+static void __touchInit() {
+  if (initialized) {
+    return;
+  }
+  // Support only one sample configuration for now
+  touch_sensor_sample_config_t single_sample_cfg = TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(_div_num, _coarse_freq_tune, _fine_freq_tune);
+  touch_sensor_sample_config_t sample_cfg[_sample_num] = {};
+  sample_cfg[0] = single_sample_cfg;
+
+  /* Allocate new touch controller handle */
+  touch_sensor_config_t sens_cfg = {
+    .power_on_wait_us = __touchSleepTime,
+    .meas_interval_us = __touchMeasureTime,
+    .max_meas_time_us = 0,
+    .output_mode = TOUCH_PAD_OUT_AS_CLOCK,
+    .sample_cfg_num = _sample_num,
+    .sample_cfg = sample_cfg,
+  };
+
+  // touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(_sample_num, sample_cfg);
+  if (touch_sensor_new_controller(&sens_cfg, &touch_sensor_handle) != ESP_OK) {
+    goto err;
+  }
+
+  sensor_config = sens_cfg;
+  /* Configure the touch sensor filter */
+  touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG();
+  if (touch_sensor_config_filter(touch_sensor_handle, &filter_cfg) != ESP_OK) {
+    goto err;
+  }
+
+  /* Register the touch sensor on_active and on_inactive callbacks */
+  touch_event_callbacks_t callbacks = {
+    .on_active = __touchOnActiveISR,
+    .on_inactive = __touchOnInactiveISR,
+    .on_measure_done = NULL,
+    .on_scan_done = NULL,
+    .on_timeout = NULL,
+    .on_proximity_meas_done = NULL,
+  };
+  if (touch_sensor_register_callbacks(touch_sensor_handle, &callbacks, NULL) != ESP_OK) {
+    goto err;
+  }
+
+  initialized = true;
+  return;
+err:
+  log_e(" Touch sensor initialization error.");
+  initialized = false;
+  return;
+}
+
+static void __touchChannelInit(int pad) {
+  if (channels_initialized[pad]) {
+    return;
+  }
+
+  // Initial setup with default Threshold
+  __touchInterruptHandlers[pad].fn = NULL;
+
+  touch_channel_config_t chan_cfg = {
+    .active_thresh = {1000}  // default threshold, will be updated after benchmark
+  };
+
+  if (!touchStop() || !touchDisable()) {
+    log_e("Touch sensor stop and disable failed!");
+    return;
+  }
+
+  if (touch_sensor_new_channel(touch_sensor_handle, pad, &chan_cfg, &touch_channel_handle[pad]) != ESP_OK) {
+    log_e("Touch sensor new channel failed!");
+    return;
+  }
+
+  // Benchmark active threshold and reconfigure pad
+  if (!touchBenchmarkThreshold(pad)) {
+    log_e("Touch sensor benchmark threshold failed!");
+    return;
+  }
+
+  channels_initialized[pad] = true;
+  used_pads++;
+
+  if (!touchEnable() || !touchStart()) {
+    log_e("Touch sensor enable and start failed!");
+  }
+}
+
+static touch_value_t __touchRead(uint8_t pin) {
+  int8_t pad = digitalPinToTouchChannel(pin);
+  if (pad < 0) {
+    log_e(" No touch pad on selected pin!");
+    return 0;
+  }
+
+  if (perimanGetPinBus(pin, ESP32_BUS_TYPE_TOUCH) == NULL) {
+    perimanSetBusDeinit(ESP32_BUS_TYPE_TOUCH, touchDetachBus);
+    if (!perimanClearPinBus(pin)) {
+      return 0;
+    }
+    __touchInit();
+    __touchChannelInit(pad);
+
+    if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_TOUCH, (void *)(pin + 1), -1, pad)) {
+      touchDetachBus((void *)(pin + 1));
+      return 0;
+    }
+  }
+
+  uint32_t touch_read[_sample_num] = {};
+  touch_channel_read_data(touch_channel_handle[pad], TOUCH_CHAN_DATA_TYPE_SMOOTH, touch_read);
+  touch_value_t touch_value = touch_read[0];  // only one sample configuration for now
+
+  return touch_value;
+}
+
+static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Args, bool callWithArgs, touch_value_t threshold) {
+  int8_t pad = digitalPinToTouchChannel(pin);
+  if (pad < 0) {
+    log_e(" No touch pad on selected pin!");
+    return;
+  }
+
+  if (userFunc == NULL) {
+    // detach ISR User Call
+    __touchInterruptHandlers[pad].fn = NULL;
+    __touchInterruptHandlers[pad].callWithArgs = false;
+    __touchInterruptHandlers[pad].arg = NULL;
+  } else {
+    // attach ISR User Call
+    __touchInit();
+    __touchChannelInit(pad);
+    __touchInterruptHandlers[pad].fn = userFunc;
+    __touchInterruptHandlers[pad].callWithArgs = callWithArgs;
+    __touchInterruptHandlers[pad].arg = Args;
+  }
+
+  if (threshold != 0) {
+    if (!touchStop() || !touchDisable()) {
+      log_e("Touch sensor stop and disable failed!");
+      return;
+    }
+
+    touch_channel_config_t chan_cfg = {};
+    for (int i = 0; i < _sample_num; i++) {
+      chan_cfg.active_thresh[i] = threshold;
+    }
+
+    if (touch_sensor_reconfig_channel(touch_channel_handle[pad], &chan_cfg) != ESP_OK) {
+      log_e("Touch sensor threshold reconfig channel failed!");
+    }
+
+    if (!touchEnable() || !touchStart()) {
+      log_e("Touch sensor enable and start failed!");
+    }
+  }
+}
+
+// it keeps backwards compatibility
+static void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold) {
+  __touchConfigInterrupt(pin, userFunc, NULL, threshold, false);
+}
+
+// new additional version of the API with User Args
+static void __touchAttachArgsInterrupt(uint8_t pin, void (*userFunc)(void), void *args, touch_value_t threshold) {
+  __touchConfigInterrupt(pin, userFunc, args, threshold, true);
+}
+
+// new additional API to detach touch ISR
+static void __touchDettachInterrupt(uint8_t pin) {
+  __touchConfigInterrupt(pin, NULL, NULL, 0, false);  // userFunc as NULL acts as detaching
+}
+
+// /*
+//     External Public Touch API Functions
+// */
+
+bool touchInterruptGetLastStatus(uint8_t pin) {
+  int8_t pad = digitalPinToTouchChannel(pin);
+  if (pad < 0) {
+    return false;
+  }
+
+  return __touchInterruptHandlers[pad].lastStatusIsPressed;
+}
+
+void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold) {
+  int8_t pad = digitalPinToTouchChannel(pin);
+  if (pad < 0) {
+    log_e(" No touch pad on selected pin!");
+    return;
+  }
+
+  if (perimanGetPinBus(pin, ESP32_BUS_TYPE_TOUCH) == NULL) {
+    perimanSetBusDeinit(ESP32_BUS_TYPE_TOUCH, touchDetachBus);
+    __touchInit();
+    __touchChannelInit(pad);
+    if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_TOUCH, (void *)(pin + 1), -1, pad)) {
+      log_e("Failed to set bus to Peripheral manager");
+      touchDetachBus((void *)(pin + 1));
+      return;
+    }
+  }
+
+  log_v("Touch sensor deep sleep wake-up configuration for pad %d with threshold %d", pad, threshold);
+  if (!touchStop() || !touchDisable()) {
+    log_e("Touch sensor stop and disable failed!");
+    return;
+  }
+
+  touch_sleep_config_t deep_slp_cfg = {
+    .slp_wakeup_lvl = TOUCH_DEEP_SLEEP_WAKEUP,
+    .deep_slp_chan = touch_channel_handle[pad],
+    .deep_slp_thresh = {threshold},
+    .deep_slp_sens_cfg = NULL,  // Use the original touch sensor configuration
+  };
+
+  // Register the deep sleep wake-up
+  if (touch_sensor_config_sleep_wakeup(touch_sensor_handle, &deep_slp_cfg) != ESP_OK) {
+    log_e("Touch sensor deep sleep wake-up failed!");
+    return;
+  }
+
+  if (!touchEnable() || !touchStart()) {
+    log_e("Touch sensor enable and start failed!");
+  }
+}
+
+void touchSetDefaultThreshold(float percentage) {
+  s_thresh2bm_ratio = (float)percentage / 100.0f;
+}
+
+void touchSetTiming(float measure, uint32_t sleep) {
+  if (initialized) {
+    log_e("Touch sensor already initialized. Cannot set cycles.");
+    return;
+  }
+  __touchSleepTime = sleep;
+  __touchMeasureTime = measure;
+}
+
+void touchSetConfig(uint32_t div_num, uint8_t coarse_freq_tune, uint8_t fine_freq_tune) {
+  if (initialized) {
+    log_e("Touch sensor already initialized. Cannot set configuration.");
+    return;
+  }
+  _div_num = div_num;
+  _coarse_freq_tune = coarse_freq_tune;
+  _fine_freq_tune = fine_freq_tune;
+}
+
+extern touch_value_t touchRead(uint8_t) __attribute__((weak, alias("__touchRead")));
+extern void touchAttachInterrupt(uint8_t, voidFuncPtr, touch_value_t) __attribute__((weak, alias("__touchAttachInterrupt")));
+extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value_t) __attribute__((weak, alias("__touchAttachArgsInterrupt")));
+extern void touchDetachInterrupt(uint8_t) __attribute__((weak, alias("__touchDettachInterrupt")));
+
+#endif /* SOC_TOUCH_SENSOR_VERSION == 3 */
+#endif /* SOC_TOUCH_SENSOR_SUPPORTED */
diff --git a/cores/esp32/esp32-hal-touch-ng.h b/cores/esp32/esp32-hal-touch-ng.h
new file mode 100644
index 00000000000..0d4eb79ac58
--- /dev/null
+++ b/cores/esp32/esp32-hal-touch-ng.h
@@ -0,0 +1,91 @@
+/*
+ Arduino.h - Main include file for the Arduino SDK
+ Copyright (c) 2005-2013 Arduino Team.  All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef MAIN_ESP32_HAL_TOUCH_NEW_H_
+#define MAIN_ESP32_HAL_TOUCH_NEW_H_
+
+#include "soc/soc_caps.h"
+#if SOC_TOUCH_SENSOR_SUPPORTED
+#if SOC_TOUCH_SENSOR_VERSION == 3  // ESP32P4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "esp32-hal.h"
+
+typedef uint32_t touch_value_t;
+
+/*
+ * Set time in us that measurement operation takes
+ * The result from touchRead, threshold and detection
+ * accuracy depend on these values.
+ * Note: must be called before setting up touch pads
+ **/
+void touchSetTiming(float measure, uint32_t sleep);
+
+/*
+ * Tune the touch pad frequency.
+ * Note: Must be called before setting up touch pads
+*/
+void touchSetConfig(uint32_t _div_num, uint8_t coarse_freq_tune, uint8_t fine_freq_tune);
+
+/*
+ * Read touch pad value.
+ * You can use this method to chose a good threshold value
+ * to use as value for touchAttachInterrupt.
+ * */
+touch_value_t touchRead(uint8_t pin);
+
+/*
+ * Set function to be called if touch pad value rises by given increment (threshold).
+ * Use touchRead to determine a proper threshold between touched and untouched state.
+ * */
+void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold);
+void touchAttachInterruptArg(uint8_t pin, void (*userFunc)(void *), void *arg, touch_value_t threshold);
+void touchDetachInterrupt(uint8_t pin);
+
+/*
+ * Returns true when the latest ISR status for the Touchpad is that it is touched (Active)
+ * and false when the Touchpad is untoouched (Inactive).
+ * This function can be used in conjunction with ISR User callback in order to take action
+ * as soon as the touchpad is touched and/or released.
+ **/
+bool touchInterruptGetLastStatus(uint8_t pin);
+
+/*
+ * Set the default threshold for touch pads.
+ * The threshold is a percentage of the benchmark value.
+ * The default value is 1.5%.
+ **/
+void touchSetDefaultThreshold(float percentage);
+
+/*
+ * Setup touch pad wake up from deep sleep /light sleep with given threshold.
+ * When light sleep is used, all used touch pads will be able to wake up the chip.
+ **/
+void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOC_TOUCH_SENSOR_VERSION == 3 */
+#endif /* SOC_TOUCH_SENSOR_SUPPORTED */
+#endif /* MAIN_ESP32_HAL_TOUCH_H_ */
diff --git a/cores/esp32/esp32-hal-touch.c b/cores/esp32/esp32-hal-touch.c
index d32b34d0173..701bf6d16c9 100644
--- a/cores/esp32/esp32-hal-touch.c
+++ b/cores/esp32/esp32-hal-touch.c
@@ -14,6 +14,8 @@
 #include "soc/soc_caps.h"
 
 #if SOC_TOUCH_SENSOR_SUPPORTED
+#if SOC_TOUCH_SENSOR_VERSION <= 2  // ESP32, ESP32S2, ESP32S3
+
 #include "driver/touch_sensor.h"
 #include "esp32-hal-touch.h"
 #include "esp32-hal-periman.h"
@@ -22,10 +24,10 @@
     Internal Private Touch Data Structure and Functions
 */
 
-#if SOC_TOUCH_VERSION_1  // ESP32
+#if SOC_TOUCH_SENSOR_VERSION == 1  // ESP32
 static uint16_t __touchSleepCycles = 0x1000;
 static uint16_t __touchMeasureCycles = 0x1000;
-#elif SOC_TOUCH_VERSION_2  // ESP32S2, ESP32S3
+#elif SOC_TOUCH_SENSOR_VERSION == 2  // ESP32S2, ESP32S3
 static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT;
 static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT;
 #endif
@@ -37,7 +39,7 @@ typedef struct {
   voidFuncPtr fn;
   bool callWithArgs;
   void *arg;
-#if SOC_TOUCH_VERSION_2  // Only for ESP32S2 and ESP32S3
+#if SOC_TOUCH_SENSOR_VERSION == 2  // Only for ESP32S2 and ESP32S3
   bool lastStatusIsPressed;
 #endif
 } TouchInterruptHandle_t;
@@ -51,7 +53,7 @@ static bool initialized = false;
 static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = {false};
 
 static void ARDUINO_ISR_ATTR __touchISR(void *arg) {
-#if SOC_TOUCH_VERSION_1  // ESP32
+#if SOC_TOUCH_SENSOR_VERSION == 1  // ESP32
   uint32_t pad_intr = touch_pad_get_status();
   //clear interrupt
   touch_pad_clear_status();
@@ -68,7 +70,7 @@ static void ARDUINO_ISR_ATTR __touchISR(void *arg) {
       }
     }
   }
-#elif SOC_TOUCH_VERSION_2  // ESP32S2, ESP32S3
+#elif SOC_TOUCH_SENSOR_VERSION == 2  // ESP32S2, ESP32S3
   touch_pad_intr_mask_t evt = touch_pad_read_intr_status_mask();
   uint8_t pad_num = touch_pad_get_current_meas_channel();
   if (evt & TOUCH_PAD_INTR_MASK_ACTIVE) {
@@ -93,9 +95,9 @@ static void ARDUINO_ISR_ATTR __touchISR(void *arg) {
 static void __touchSetCycles(uint16_t measure, uint16_t sleep) {
   __touchSleepCycles = sleep;
   __touchMeasureCycles = measure;
-#if SOC_TOUCH_VERSION_1  // ESP32
+#if SOC_TOUCH_SENSOR_VERSION == 1  // ESP32
   touch_pad_set_measurement_clock_cycles(measure);
-#elif SOC_TOUCH_VERSION_2  // ESP32S2, ESP32S3
+#elif SOC_TOUCH_SENSOR_VERSION == 2  // ESP32S2, ESP32S3
   touch_pad_set_charge_discharge_times(measure);
 #endif
   touch_pad_set_measurement_interval(sleep);
@@ -123,7 +125,7 @@ static void __touchInit() {
 
   esp_err_t err = ESP_OK;
 
-#if SOC_TOUCH_VERSION_1  // ESP32
+#if SOC_TOUCH_SENSOR_VERSION == 1  // ESP32
   err = touch_pad_init();
   if (err != ESP_OK) {
     goto err;
@@ -143,8 +145,8 @@ static void __touchInit() {
   if (err != ESP_OK) {
     goto err;
   }
-  touch_pad_intr_enable();  // returns ESP_OK
-#elif SOC_TOUCH_VERSION_2   // ESP32S2, ESP32S3
+  touch_pad_intr_enable();           // returns ESP_OK
+#elif SOC_TOUCH_SENSOR_VERSION == 2  // ESP32S2, ESP32S3
   err = touch_pad_init();
   if (err != ESP_OK) {
     goto err;
@@ -165,7 +167,6 @@ static void __touchInit() {
   touch_pad_fsm_start();                         // returns ESP_OK
   //ISR setup moved to __touchChannelInit
 #endif
-
   initialized = true;
   return;
 err:
@@ -179,11 +180,11 @@ static void __touchChannelInit(int pad) {
     return;
   }
 
-#if SOC_TOUCH_VERSION_1  // ESP32
+#if SOC_TOUCH_SENSOR_VERSION == 1  // ESP32
   // Initial no Threshold and setup
   __touchInterruptHandlers[pad].fn = NULL;
-  touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX);  // returns ESP_OK
-#elif SOC_TOUCH_VERSION_2                              // ESP32S2, ESP32S3
+  touch_pad_config(pad, TOUCH_PAD_THRESHOLD_MAX);  // returns ESP_OK
+#elif SOC_TOUCH_SENSOR_VERSION == 2                // ESP32S2, ESP32S3
   // Initial no Threshold and setup
   __touchInterruptHandlers[pad].fn = NULL;
   touch_pad_config(pad);  // returns ESP_OK
@@ -238,7 +239,7 @@ static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Ar
   if (userFunc == NULL) {
     // detach ISR User Call
     __touchInterruptHandlers[pad].fn = NULL;
-    threshold = SOC_TOUCH_PAD_THRESHOLD_MAX;  // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX
+    threshold = TOUCH_PAD_THRESHOLD_MAX;  // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX
   } else {
     // attach ISR User Call
     __touchInit();
@@ -270,7 +271,7 @@ static void __touchDettachInterrupt(uint8_t pin) {
     External Public Touch API Functions
 */
 
-#if SOC_TOUCH_VERSION_1  // Only for ESP32 SoC
+#if SOC_TOUCH_SENSOR_VERSION == 1  // Only for ESP32 SoC
 void touchInterruptSetThresholdDirection(bool mustbeLower) {
   if (mustbeLower) {
     touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW);
@@ -278,7 +279,7 @@ void touchInterruptSetThresholdDirection(bool mustbeLower) {
     touch_pad_set_trigger_mode(TOUCH_TRIGGER_ABOVE);
   }
 }
-#elif SOC_TOUCH_VERSION_2  // Only for ESP32S2 and ESP32S3
+#elif SOC_TOUCH_SENSOR_VERSION == 2  // Only for ESP32S2 and ESP32S3
 // returns true if touch pad has been and continues pressed and false otherwise
 bool touchInterruptGetLastStatus(uint8_t pin) {
   int8_t pad = digitalPinToTouchChannel(pin);
@@ -307,10 +308,10 @@ void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold) {
       return;
     }
   }
-#if SOC_TOUCH_VERSION_1  // Only for ESP32 SoC
+#if SOC_TOUCH_SENSOR_VERSION == 1  // Only for ESP32 SoC
   touch_pad_set_thresh(pad, threshold);
 
-#elif SOC_TOUCH_VERSION_2
+#elif SOC_TOUCH_SENSOR_VERSION == 2
   touch_pad_sleep_channel_enable(pad, true);
   touch_pad_sleep_set_threshold(pad, threshold);
 
@@ -324,4 +325,5 @@ extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value
 extern void touchDetachInterrupt(uint8_t) __attribute__((weak, alias("__touchDettachInterrupt")));
 extern void touchSetCycles(uint16_t, uint16_t) __attribute__((weak, alias("__touchSetCycles")));
 
+#endif /* SOC_TOUCH_SENSOR_VERSION <= 2 */
 #endif /* SOC_TOUCH_SENSOR_SUPPORTED */
diff --git a/cores/esp32/esp32-hal-touch.h b/cores/esp32/esp32-hal-touch.h
index db33ce3bc6a..4b06c7db766 100644
--- a/cores/esp32/esp32-hal-touch.h
+++ b/cores/esp32/esp32-hal-touch.h
@@ -22,6 +22,7 @@
 
 #include "soc/soc_caps.h"
 #if SOC_TOUCH_SENSOR_SUPPORTED
+#if SOC_TOUCH_SENSOR_VERSION <= 2  // ESP32 ESP32S2 ESP32S3
 
 #ifdef __cplusplus
 extern "C" {
@@ -29,13 +30,13 @@ extern "C" {
 
 #include "esp32-hal.h"
 
-#if !defined(SOC_TOUCH_VERSION_1) && !defined(SOC_TOUCH_VERSION_2)
+#if !SOC_TOUCH_SENSOR_SUPPORTED
 #error Touch IDF driver Not supported!
 #endif
 
-#if SOC_TOUCH_VERSION_1  // ESP32
+#if SOC_TOUCH_SENSOR_VERSION == 1  // ESP32
 typedef uint16_t touch_value_t;
-#elif SOC_TOUCH_VERSION_2  // ESP32S2 ESP32S3
+#elif SOC_TOUCH_SENSOR_VERSION == 2  // ESP32S2 ESP32S3
 typedef uint32_t touch_value_t;
 #endif
 
@@ -71,7 +72,7 @@ void touchDetachInterrupt(uint8_t pin);
  * Default if Lower.
  **/
 
-#if SOC_TOUCH_VERSION_1  // Only for ESP32 SoC
+#if SOC_TOUCH_SENSOR_VERSION == 1  // Only for ESP32 SoC
 void touchInterruptSetThresholdDirection(bool mustbeLower);
 #endif
 
@@ -83,7 +84,7 @@ void touchInterruptSetThresholdDirection(bool mustbeLower);
  * as soon as the touchpad is touched and/or released
  **/
 
-#if SOC_TOUCH_VERSION_2  // Only for ESP32S2 and ESP32S3
+#if SOC_TOUCH_SENSOR_VERSION == 2  // Only for ESP32S2 and ESP32S3
 // returns true if touch pad has been and continues pressed and false otherwise
 bool touchInterruptGetLastStatus(uint8_t pin);
 #endif
@@ -97,5 +98,6 @@ void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold);
 }
 #endif
 
+#endif /* SOC_TOUCH_SENSOR_VERSION <= 2 */
 #endif /* SOC_TOUCH_SENSOR_SUPPORTED */
 #endif /* MAIN_ESP32_HAL_TOUCH_H_ */
diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c
index 9eb117988f6..34a2660e3a3 100644
--- a/cores/esp32/esp32-hal-uart.c
+++ b/cores/esp32/esp32-hal-uart.c
@@ -33,7 +33,8 @@
 #include "hal/gpio_hal.h"
 #include "esp_rom_gpio.h"
 
-static int s_uart_debug_nr = 0;  // UART number for debug output
+static int s_uart_debug_nr = 0;         // UART number for debug output
+#define REF_TICK_BAUDRATE_LIMIT 250000  // this is maximum UART badrate using REF_TICK as clock
 
 struct uart_struct_t {
 
@@ -61,12 +62,18 @@ struct uart_struct_t {
 
 static uart_t _uart_bus_array[] = {
   {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
   {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
 #endif
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
   {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
 #endif
+#if SOC_UART_HP_NUM > 3
+  {3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
+#endif
+#if SOC_UART_HP_NUM > 4
+  {4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
+#endif
 };
 
 #else
@@ -81,12 +88,18 @@ static uart_t _uart_bus_array[] = {
 
 static uart_t _uart_bus_array[] = {
   {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
   {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
 #endif
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
   {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
 #endif
+#if SOC_UART_HP_NUM > 3
+  {NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
+#endif
+#if SOC_UART_HP_NUM > 4
+  {NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
+#endif
 };
 
 #endif
@@ -94,8 +107,8 @@ static uart_t _uart_bus_array[] = {
 // Negative Pin Number will keep it unmodified, thus this function can detach individual pins
 // This function will also unset the pins in the Peripheral Manager and set the pin to -1 after detaching
 static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
-  if (uart_num >= SOC_UART_NUM) {
-    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
+  if (uart_num >= SOC_UART_HP_NUM) {
+    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1);
     return false;
   }
   // get UART information
@@ -181,8 +194,8 @@ static bool _uartDetachBus_RTS(void *busptr) {
 // Attach function for UART
 // connects the IO Pad, set Paripheral Manager and internal UART structure data
 static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
-  if (uart_num >= SOC_UART_NUM) {
-    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
+  if (uart_num >= SOC_UART_HP_NUM) {
+    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1);
     return false;
   }
   // get UART information
@@ -308,8 +321,8 @@ bool uartIsDriverInstalled(uart_t *uart) {
 // Negative Pin Number will keep it unmodified, thus this function can set individual pins
 // When pins are changed, it will detach the previous one
 bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
-  if (uart_num >= SOC_UART_NUM) {
-    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
+  if (uart_num >= SOC_UART_HP_NUM) {
+    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1);
     return false;
   }
   // get UART information
@@ -378,7 +391,7 @@ bool _testUartBegin(
   uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint32_t rx_buffer_size, uint32_t tx_buffer_size, bool inverted,
   uint8_t rxfifo_full_thrhd
 ) {
-  if (uart_nr >= SOC_UART_NUM) {
+  if (uart_nr >= SOC_UART_HP_NUM) {
     return false;  // no new driver has to be installed
   }
   uart_t *uart = &_uart_bus_array[uart_nr];
@@ -400,8 +413,8 @@ uart_t *uartBegin(
   uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint32_t rx_buffer_size, uint32_t tx_buffer_size, bool inverted,
   uint8_t rxfifo_full_thrhd
 ) {
-  if (uart_nr >= SOC_UART_NUM) {
-    log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
+  if (uart_nr >= SOC_UART_HP_NUM) {
+    log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1);
     return NULL;  // no new driver was installed
   }
   uart_t *uart = &_uart_bus_array[uart_nr];
@@ -497,6 +510,8 @@ uart_t *uartBegin(
     log_v("UART%d not installed. Starting installation", uart_nr);
   }
   uart_config_t uart_config;
+  memset(&uart_config, 0, sizeof(uart_config_t));
+  uart_config.flags.backup_before_sleep = false;  // new flag from IDF v5.3
   uart_config.data_bits = (config & 0xc) >> 2;
   uart_config.parity = (config & 0x3);
   uart_config.stop_bits = (config & 0x30) >> 4;
@@ -508,7 +523,7 @@ uart_t *uartBegin(
 #if SOC_UART_SUPPORT_XTAL_CLK
   uart_config.source_clk = UART_SCLK_XTAL;  // valid for C2, S3, C3, C6, H2 and P4
 #elif SOC_UART_SUPPORT_REF_TICK
-  if (baudrate <= 250000) {
+  if (baudrate <= REF_TICK_BAUDRATE_LIMIT) {
     uart_config.source_clk = UART_SCLK_REF_TICK;  // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
   } else {
     uart_config.source_clk = UART_SCLK_APB;  // baudrate may change with the APB Frequency!
@@ -604,8 +619,8 @@ bool uartSetRxFIFOFull(uart_t *uart, uint8_t numBytesFIFOFull) {
 }
 
 void uartEnd(uint8_t uart_num) {
-  if (uart_num >= SOC_UART_NUM) {
-    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
+  if (uart_num >= SOC_UART_HP_NUM) {
+    log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_HP_NUM - 1);
     return;
   }
   // get UART information
@@ -623,7 +638,7 @@ void uartSetRxInvert(uart_t *uart, bool invert) {
   if (uart == NULL) {
     return;
   }
-#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
   // POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
   // IDF or LL set/reset the whole inv_mask!
   // if (invert)
@@ -790,6 +805,10 @@ void uartSetBaudRate(uart_t *uart, uint32_t baud_rate) {
     return;
   }
   UART_MUTEX_LOCK();
+#if !SOC_UART_SUPPORT_XTAL_CLK
+  soc_module_clk_t newClkSrc = baud_rate <= REF_TICK_BAUDRATE_LIMIT ? SOC_MOD_CLK_REF_TICK : SOC_MOD_CLK_APB;
+  uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc);
+#endif
   if (uart_set_baudrate(uart->num, baud_rate) == ESP_OK) {
     uart->_baudrate = baud_rate;
   } else {
@@ -819,28 +838,48 @@ static void ARDUINO_ISR_ATTR uart0_write_char(char c) {
   uart_ll_write_txfifo(&UART0, (const uint8_t *)&c, 1);
 }
 
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
 static void ARDUINO_ISR_ATTR uart1_write_char(char c) {
   while (uart_ll_get_txfifo_len(&UART1) == 0);
   uart_ll_write_txfifo(&UART1, (const uint8_t *)&c, 1);
 }
 #endif
 
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
 static void ARDUINO_ISR_ATTR uart2_write_char(char c) {
   while (uart_ll_get_txfifo_len(&UART2) == 0);
   uart_ll_write_txfifo(&UART2, (const uint8_t *)&c, 1);
 }
 #endif
 
+#if SOC_UART_HP_NUM > 3
+static void ARDUINO_ISR_ATTR uart3_write_char(char c) {
+  while (uart_ll_get_txfifo_len(&UART3) == 0);
+  uart_ll_write_txfifo(&UART3, (const uint8_t *)&c, 1);
+}
+#endif
+
+#if SOC_UART_HP_NUM > 4
+static void ARDUINO_ISR_ATTR uart4_write_char(char c) {
+  while (uart_ll_get_txfifo_len(&UART4) == 0);
+  uart_ll_write_txfifo(&UART4, (const uint8_t *)&c, 1);
+}
+#endif
+
 void uart_install_putc() {
   switch (s_uart_debug_nr) {
     case 0: ets_install_putc1((void (*)(char)) & uart0_write_char); break;
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
     case 1: ets_install_putc1((void (*)(char)) & uart1_write_char); break;
 #endif
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
     case 2: ets_install_putc1((void (*)(char)) & uart2_write_char); break;
+#endif
+#if SOC_UART_HP_NUM > 3
+    case 3: ets_install_putc1((void (*)(char)) & uart3_write_char); break;
+#endif
+#if SOC_UART_HP_NUM > 4
+    case 4: ets_install_putc1((void (*)(char)) & uart4_write_char); break;
 #endif
     default: ets_install_putc1(NULL); break;
   }
@@ -850,7 +889,7 @@ void uart_install_putc() {
 // Routines that take care of UART mode in the HardwareSerial Class code
 // used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips
 bool uartSetMode(uart_t *uart, uart_mode_t mode) {
-  if (uart == NULL || uart->num >= SOC_UART_NUM) {
+  if (uart == NULL || uart->num >= SOC_UART_HP_NUM) {
     return false;
   }
 
@@ -861,7 +900,7 @@ bool uartSetMode(uart_t *uart, uart_mode_t mode) {
 }
 
 void uartSetDebug(uart_t *uart) {
-  if (uart == NULL || uart->num >= SOC_UART_NUM) {
+  if (uart == NULL || uart->num >= SOC_UART_HP_NUM) {
     s_uart_debug_nr = -1;
   } else {
     s_uart_debug_nr = uart->num;
@@ -896,7 +935,7 @@ int log_printfv(const char *format, va_list arg) {
 #endif
 */
 #if (ARDUINO_USB_CDC_ON_BOOT == 1 && ARDUINO_USB_MODE == 0) || CONFIG_IDF_TARGET_ESP32C3 \
-  || ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6) && ARDUINO_USB_CDC_ON_BOOT == 1)
+  || ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4) && ARDUINO_USB_CDC_ON_BOOT == 1)
   vsnprintf(temp, len + 1, format, arg);
   ets_printf("%s", temp);
 #else
@@ -1103,19 +1142,35 @@ unsigned long uartDetectBaudrate(uart_t *uart) {
 */
 
 // gets the right TX or RX SIGNAL, based on the UART number from gpio_sig_map.h
-#if SOC_UART_NUM > 2
+#ifdef CONFIG_IDF_TARGET_ESP32P4
+#define UART_TX_SIGNAL(uartNumber) \
+  (uartNumber == UART_NUM_0        \
+     ? UART0_TXD_PAD_OUT_IDX       \
+     : (uartNumber == UART_NUM_1   \
+          ? UART1_TXD_PAD_OUT_IDX  \
+          : (uartNumber == UART_NUM_2 ? UART2_TXD_PAD_OUT_IDX : (uartNumber == UART_NUM_3 ? UART3_TXD_PAD_OUT_IDX : UART4_TXD_PAD_OUT_IDX))))
+#define UART_RX_SIGNAL(uartNumber) \
+  (uartNumber == UART_NUM_0        \
+     ? UART0_RXD_PAD_IN_IDX        \
+     : (uartNumber == UART_NUM_1   \
+          ? UART1_RXD_PAD_IN_IDX   \
+          : (uartNumber == UART_NUM_2 ? UART2_RXD_PAD_IN_IDX : (uartNumber == UART_NUM_3 ? UART3_RXD_PAD_IN_IDX : UART4_RXD_PAD_IN_IDX))))
+#else
+#if SOC_UART_HP_NUM > 2
 #define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : (uartNumber == UART_NUM_1 ? U1TXD_OUT_IDX : U2TXD_OUT_IDX))
 #define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : (uartNumber == UART_NUM_1 ? U1RXD_IN_IDX : U2RXD_IN_IDX))
 #else
 #define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : U1TXD_OUT_IDX)
 #define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : U1RXD_IN_IDX)
 #endif
+#endif  // ifdef CONFIG_IDF_TARGET_ESP32P4
+
 /*
    This function internally binds defined UARTs TX signal with defined RX pin of any UART (same or different).
    This creates a loop that lets us receive anything we send on the UART without external wires.
 */
 void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) {
-  if (uartNum > SOC_UART_NUM - 1 || !GPIO_IS_VALID_GPIO(rxPin)) {
+  if (uartNum > SOC_UART_HP_NUM - 1 || !GPIO_IS_VALID_GPIO(rxPin)) {
     return;
   }
   esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false);
diff --git a/cores/esp32/esp32-hal.h b/cores/esp32/esp32-hal.h
index 60350ae960b..d0bd4b8bc93 100644
--- a/cores/esp32/esp32-hal.h
+++ b/cores/esp32/esp32-hal.h
@@ -61,6 +61,19 @@ extern "C" {
 #define ARDUINO_EVENT_RUNNING_CORE CONFIG_ARDUINO_EVENT_RUNNING_CORE
 #endif
 
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+static const uint8_t BOOT_PIN = 0;
+#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C61
+static const uint8_t BOOT_PIN = 9;
+#elif CONFIG_IDF_TARGET_ESP32P4
+static const uint8_t BOOT_PIN = 35;
+#elif CONFIG_IDF_TARGET_ESP32C5
+static const uint8_t BOOT_PIN = 28;
+#else
+#error BOOT_PIN not defined for this chip!
+#endif
+#define BOOT_PIN BOOT_PIN
+
 //forward declaration from freertos/portmacro.h
 void vPortYield(void);
 void yield(void);
@@ -74,6 +87,7 @@ void yield(void);
 #include "esp32-hal-uart.h"
 #include "esp32-hal-gpio.h"
 #include "esp32-hal-touch.h"
+#include "esp32-hal-touch-ng.h"
 #include "esp32-hal-dac.h"
 #include "esp32-hal-adc.h"
 #include "esp32-hal-spi.h"
diff --git a/cores/esp32/esp_arduino_version.h b/cores/esp32/esp_arduino_version.h
index d541b534ab4..c2921b95fb8 100644
--- a/cores/esp32/esp_arduino_version.h
+++ b/cores/esp32/esp_arduino_version.h
@@ -21,9 +21,9 @@ extern "C" {
 /** Major version number (X.x.x) */
 #define ESP_ARDUINO_VERSION_MAJOR 3
 /** Minor version number (x.X.x) */
-#define ESP_ARDUINO_VERSION_MINOR 0
+#define ESP_ARDUINO_VERSION_MINOR 1
 /** Patch version number (x.x.X) */
-#define ESP_ARDUINO_VERSION_PATCH 5
+#define ESP_ARDUINO_VERSION_PATCH 0
 
 /**
  * Macro to convert ARDUINO version number into an integer
diff --git a/cores/esp32/freertos_stats.cpp b/cores/esp32/freertos_stats.cpp
new file mode 100644
index 00000000000..50a98bf502b
--- /dev/null
+++ b/cores/esp32/freertos_stats.cpp
@@ -0,0 +1,111 @@
+// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "freertos_stats.h"
+#include "sdkconfig.h"
+
+#if CONFIG_FREERTOS_USE_TRACE_FACILITY
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/portable.h"
+#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */
+
+void printRunningTasks(Print &printer) {
+#if CONFIG_FREERTOS_USE_TRACE_FACILITY
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+#define FREERTOS_TASK_NUMBER_MAX_NUM 256  // RunTime stats for how many Tasks to be stored
+  static configRUN_TIME_COUNTER_TYPE ulRunTimeCounters[FREERTOS_TASK_NUMBER_MAX_NUM];
+  static configRUN_TIME_COUNTER_TYPE ulLastRunTime = 0;
+  configRUN_TIME_COUNTER_TYPE ulCurrentRunTime = 0, ulTaskRunTime = 0;
+#endif
+  configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0;
+  TaskStatus_t *pxTaskStatusArray = NULL;
+  volatile UBaseType_t uxArraySize = 0, x = 0;
+  const char *taskStates[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"};
+
+  // Take a snapshot of the number of tasks in case it changes while this function is executing.
+  uxArraySize = uxTaskGetNumberOfTasks();
+
+  // Allocate a TaskStatus_t structure for each task.
+  pxTaskStatusArray = (TaskStatus_t *)pvPortMalloc(uxArraySize * sizeof(TaskStatus_t));
+
+  if (pxTaskStatusArray != NULL) {
+    // Generate raw status information about each task.
+    uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime);
+
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+    ulCurrentRunTime = ulTotalRunTime - ulLastRunTime;
+    ulLastRunTime = ulTotalRunTime;
+#endif
+    printer.printf(
+      "Tasks: %u"
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+      ", Runtime: %lus, Period: %luus"
+#endif
+      "\n",
+      uxArraySize
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+      ,
+      ulTotalRunTime / 1000000, ulCurrentRunTime
+#endif
+    );
+    printer.printf("Num\t            Name"
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+                   "\tLoad"
+#endif
+                   "\tPrio\t Free"
+#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
+                   "\tCore"
+#endif
+                   "\tState\r\n");
+    for (x = 0; x < uxArraySize; x++) {
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+      if (pxTaskStatusArray[x].xTaskNumber < FREERTOS_TASK_NUMBER_MAX_NUM) {
+        ulTaskRunTime = (pxTaskStatusArray[x].ulRunTimeCounter - ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber]);
+        ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber] = pxTaskStatusArray[x].ulRunTimeCounter;
+        ulTaskRunTime = (ulTaskRunTime * 100) / ulCurrentRunTime;  // in percentage
+      } else {
+        ulTaskRunTime = 0;
+      }
+#endif
+      printer.printf(
+        "%3u\t%16s"
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+        "\t%3lu%%"
+#endif
+        "\t%4u\t%5lu"
+#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
+        "\t%4c"
+#endif
+        "\t%s\r\n",
+        pxTaskStatusArray[x].xTaskNumber, pxTaskStatusArray[x].pcTaskName,
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+        ulTaskRunTime,
+#endif
+        pxTaskStatusArray[x].uxCurrentPriority, pxTaskStatusArray[x].usStackHighWaterMark,
+#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
+        (pxTaskStatusArray[x].xCoreID == tskNO_AFFINITY) ? '*' : ('0' + pxTaskStatusArray[x].xCoreID),
+#endif
+        taskStates[pxTaskStatusArray[x].eCurrentState]
+      );
+    }
+
+    // The array is no longer needed, free the memory it consumes.
+    vPortFree(pxTaskStatusArray);
+    printer.println();
+  }
+#else
+  printer.println("FreeRTOS trace facility is not enabled.");
+#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */
+}
diff --git a/cores/esp32/freertos_stats.h b/cores/esp32/freertos_stats.h
new file mode 100644
index 00000000000..ea9e1a55a21
--- /dev/null
+++ b/cores/esp32/freertos_stats.h
@@ -0,0 +1,28 @@
+// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#ifdef __cplusplus
+
+#include "Print.h"
+
+/*
+ * Executing this function will cause interrupts and
+ * the scheduler to be blocked for some time.
+ * Please use only for debugging purposes.
+ */
+void printRunningTasks(Print &printer);
+
+#endif
diff --git a/cores/esp32/io_pin_remap.h b/cores/esp32/io_pin_remap.h
index 73789a585e3..10f11a5bf4c 100644
--- a/cores/esp32/io_pin_remap.h
+++ b/cores/esp32/io_pin_remap.h
@@ -106,7 +106,7 @@ int8_t gpioNumberToDigitalPin(int8_t gpioNumber);
 #define spiAttachMOSI(spi, mosi)     spiAttachMOSI(spi, digitalPinToGPIONumber(mosi))
 #define spiAttachSS(spi, cs_num, ss) spiAttachSS(spi, cs_num, digitalPinToGPIONumber(ss))
 
-// cores/esp32/esp32-hal-touch.h
+// cores/esp32/esp32-hal-touch.h && cores/esp32/esp32-hal-touch-ng.h
 #define touchInterruptGetLastStatus(pin)                       touchInterruptGetLastStatus(digitalPinToGPIONumber(pin))
 #define touchRead(pin)                                         touchRead(digitalPinToGPIONumber(pin))
 #define touchAttachInterruptArg(pin, userFunc, arg, threshold) touchAttachInterruptArg(digitalPinToGPIONumber(pin), userFunc, arg, threshold)
diff --git a/cores/esp32/main.cpp b/cores/esp32/main.cpp
index 6c4d50a9a84..746d18dc075 100644
--- a/cores/esp32/main.cpp
+++ b/cores/esp32/main.cpp
@@ -10,7 +10,9 @@
 #endif
 #endif
 
+#if defined __has_include && __has_include("chip-debug-report.h")
 #include "chip-debug-report.h"
+#endif
 
 #ifndef ARDUINO_LOOP_STACK_SIZE
 #ifndef CONFIG_ARDUINO_LOOP_STACK_SIZE
@@ -49,20 +51,24 @@ void loopTask(void *pvParameters) {
   // sets UART0 (default console) RX/TX pins as already configured in boot or as defined in variants/pins_arduino.h
   Serial0.setPins(gpioNumberToDigitalPin(SOC_RX0), gpioNumberToDigitalPin(SOC_TX0));
 #endif
+#if defined __has_include && __has_include("chip-debug-report.h")
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
   printBeforeSetupInfo();
 #else
   if (shouldPrintChipDebugReport()) {
     printBeforeSetupInfo();
   }
+#endif
 #endif
   setup();
+#if defined __has_include && __has_include("chip-debug-report.h")
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
   printAfterSetupInfo();
 #else
   if (shouldPrintChipDebugReport()) {
     printAfterSetupInfo();
   }
+#endif
 #endif
   for (;;) {
 #if CONFIG_FREERTOS_UNICORE
diff --git a/docs/_static/logo_pio.png b/docs/_static/logo_pio.png
deleted file mode 100644
index a64c1563964..00000000000
Binary files a/docs/_static/logo_pio.png and /dev/null differ
diff --git a/docs/en/contributing.rst b/docs/en/contributing.rst
index bc3e2e89674..fb7843f1fb6 100644
--- a/docs/en/contributing.rst
+++ b/docs/en/contributing.rst
@@ -178,6 +178,7 @@ Currently, the default FQBNs are:
 * ``espressif:esp32:esp32c3``
 * ``espressif:esp32:esp32c6``
 * ``espressif:esp32:esp32h2``
+* ``espressif:esp32:esp32p4:USBMode=default``
 
 There are two ways to alter the FQBNs used to compile the sketches: by using the ``fqbn`` or ``fqbn_append`` fields in the ``ci.json`` file.
 
@@ -440,6 +441,16 @@ For checking the code style and other code quality checks, we use pre-commit hoo
 These hooks will be automatically run by the CI when a Pull Request is marked as ``Status: Pending Merge``.
 You can check which hooks are being run in the ``.pre-commit-config.yaml`` file.
 
+Currently, we have hooks for the following tasks:
+
+* Formatters for C, C++, Python, Bash, JSON, Markdown and ReStructuredText files;
+* Linters for Python, Bash and prose (spoken language);
+* Checking for spelling errors in the code and documentation;
+* Removing trailing whitespaces and tabs in the code;
+* Checking for the presence of private keys and other sensitive information in the code;
+* Fixing the line endings and end of files (EOF) in the code;
+* And more.
+
 You can read more about the pre-commit hooks in the `pre-commit documentation <https://pre-commit.com/>`_.
 
 If you want to run the pre-commit hooks locally, you first need to install the required dependencies by running:
diff --git a/docs/en/getting_started.rst b/docs/en/getting_started.rst
index c4bd54b246c..8d312317bdf 100644
--- a/docs/en/getting_started.rst
+++ b/docs/en/getting_started.rst
@@ -78,14 +78,13 @@ Supported IDEs
 
 Here is the list of supported IDE for Arduino ESP32 support integration.
 
-+-------------------+-------------------+
-| |arduino-logo|    | |pio-logo|        |
-+-------------------+-------------------+
-| Arduino IDE       | PlatformIO        |
-+-------------------+-------------------+
++-------------------+
+| |arduino-logo|    |
++-------------------+
+| Arduino IDE       |
++-------------------+
 
 .. |arduino-logo| image:: ../_static/logo_arduino.png
-.. |pio-logo| image:: ../_static/logo_pio.png
 
 See `Installing Guides <installing.html>`_ for more details on how to install the Arduino ESP32 support.
 
diff --git a/docs/en/installing.rst b/docs/en/installing.rst
index ec405b3552c..d5392d4b5ec 100644
--- a/docs/en/installing.rst
+++ b/docs/en/installing.rst
@@ -63,92 +63,6 @@ To start the installation process using the Boards Manager, follow these steps:
 
 - Restart Arduino IDE.
 
-Installing using PlatformIO
----------------------------
-
-.. figure:: ../_static/logo_pio.png
-   :align: center
-   :width: 200
-   :figclass: align-center
-
-PlatformIO is a professional collaborative platform for embedded development. It has out-of-the-box support for ESP32 SoCs and allows working with Arduino ESP32 as well as ESP-IDF from Espressif without changing your development environment. PlatformIO includes lots of instruments for the most common development tasks such as debugging, unit testing, and static code analysis.
-
-.. warning:: Integration of the Arduino Core ESP32 project in PlatformIO is maintained by PlatformIO developers. Arduino Core ESP32 Project Team cannot support PlatformIO-specific issues. Please report these issues in official `PlatformIO repositories <https://github.com/platformio>`_.
-
-A detailed overview of the PlatformIO ecosystem and its philosophy can be found in `the official documentation <https://docs.platformio.org/en/latest/core/index.html>`_.
-
-PlatformIO can be used in two flavors:
-
-- `PlatformIO IDE <https://platformio.org/platformio-ide>`_ is a toolset for embedded C/C++ development available on Windows, macOS and Linux platforms
-
-- `PlatformIO Core (CLI) <https://docs.platformio.org/en/latest/core/index.html>`_ is a command-line tool that consists of a multi-platform build system, platform and library managers and other integration components. It can be used with a variety of code development environments and allows integration with cloud platforms and web services
-
-To install PlatformIO, you can follow this Getting Started, provided at `docs.platformio.org`_.
-
-Using the stable code
-*********************
-
-.. note::
-   A detailed overview of supported development boards, examples and frameworks can be found on `the official Espressif32 dev-platform page <https://registry.platformio.org/platforms/platformio/espressif32>`_ in the PlatformIO Registry.
-
-The most reliable and easiest way to get started is to use the latest stable version of the ESP32 development platform that passed all tests/verifications and can be used in production.
-
-Create a new project and select one of the available boards. You can change after by changing the `platformio.ini <https://docs.platformio.org/en/latest/projectconf/index.html>`_ file.
-
-- For ESP32
-
-.. code-block:: bash
-
-   [env:esp32dev]
-   platform = espressif32
-   board = esp32dev
-   framework = arduino
-
-- For ESP32-S2 (ESP32-S2-Saola-1 board)
-
-.. code-block:: bash
-
-   [env:esp32-s2-saola-1]
-   platform = espressif32
-   board = esp32-s2-saola-1
-   framework = arduino
-
-- For ESP32-C3 (ESP32-C3-DevKitM-1 board)
-
-.. code-block:: bash
-
-   [env:esp32-c3-devkitm-1]
-   platform = espressif32
-   board = esp32-c3-devkitm-1
-   framework = arduino
-
-How to update to the latest code
-********************************
-
-To test the latest Arduino ESP32, you need to change your project *platformio.ini* accordingly.
-The following configuration uses the upstream version of the Espressif development platform and the latest Arduino core directly from the Espressif GitHub repository:
-
-.. code-block:: bash
-
-   [env:esp32-c3-devkitm-1]
-   platform = https://github.com/platformio/platform-espressif32.git
-   board = esp32-c3-devkitm-1
-   framework = arduino
-   platform_packages =
-       framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
-
-
-To get more information about PlatformIO, see the following links:
-
-- `PlatformIO Core (CLI) <https://docs.platformio.org/en/latest/core/index.html>`_
-
-- `PlatformIO Home <https://docs.platformio.org/en/latest/home/index.html>`_
-
-- `Tutorials and Examples <https://docs.platformio.org/en/latest/tutorials/index.html>`_
-
-- `Library Management <https://docs.platformio.org/en/latest/librarymanager/index.html>`_
-
-
 Windows (manual installation)
 -----------------------------
 
@@ -360,4 +274,3 @@ Where ``~/Documents/Arduino`` represents your sketch book location as per "Ardui
 - Restart Arduino IDE.
 
 .. _Arduino.cc: https://www.arduino.cc/en/Main/Software
-.. _docs.platformio.org: https://docs.platformio.org/en/latest/integration/ide/pioide.html
diff --git a/docs/en/lib_builder.rst b/docs/en/lib_builder.rst
index a05fd45d584..478becc3350 100644
--- a/docs/en/lib_builder.rst
+++ b/docs/en/lib_builder.rst
@@ -157,6 +157,7 @@ This build command will build for the ESP32-S3 target. You can specify other tar
 * esp32c3
 * esp32c6
 * esp32h2
+* esp32p4
 
 Set Build Type
 ^^^^^^^^^^^^^^
diff --git a/docs/en/tutorials/blink.rst b/docs/en/tutorials/blink.rst
index b5f6a767f8d..f4a53ec945d 100644
--- a/docs/en/tutorials/blink.rst
+++ b/docs/en/tutorials/blink.rst
@@ -7,7 +7,7 @@ Introduction
 
 This is the interactive blink tutorial using `Wokwi`_. For this tutorial, you don't need the ESP32 board or the Arduino toolchain.
 
-.. note:: If you don't want to use this tutorial with the simulation, you can copy and paste the :ref:`blink_example_code` from `Wokwi`_ editor and use it on the `Arduino IDE`_ or `PlatformIO`_.
+.. note:: If you don't want to use this tutorial with the simulation, you can copy and paste the :ref:`blink_example_code` from `Wokwi`_ editor and use it on the `Arduino IDE`.
 
 About this Tutorial
 -------------------
@@ -109,5 +109,4 @@ Resources
 
 .. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
 .. _Wokwi: https://wokwi.com/
-.. _PlatformIO: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#platformio
 .. _Arduino IDE: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#installing-using-boards-manager
diff --git a/docs/utils.sh b/docs/utils.sh
index 84f37489975..3a860ac8a2c 100644
--- a/docs/utils.sh
+++ b/docs/utils.sh
@@ -1,18 +1,19 @@
+#!/bin/bash
 # Bash helper functions for adding SSH keys
 
-function add_ssh_keys() {
-  local key_string="${1}"
-  mkdir -p ~/.ssh
-  chmod 700 ~/.ssh
-  echo -n "${key_string}" >~/.ssh/id_rsa_base64
-  base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 >~/.ssh/id_rsa
-  chmod 600 ~/.ssh/id_rsa
+function add_ssh_keys {
+    local key_string="${1}"
+    mkdir -p ~/.ssh
+    chmod 700 ~/.ssh
+    echo -n "${key_string}" >~/.ssh/id_rsa_base64
+    base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 >~/.ssh/id_rsa
+    chmod 600 ~/.ssh/id_rsa
 }
 
-function add_doc_server_ssh_keys() {
-  local key_string="${1}"
-  local server_url="${2}"
-  local server_user="${3}"
-  add_ssh_keys "${key_string}"
-  echo -e "Host ${server_url}\n\tStrictHostKeyChecking no\n\tUser ${server_user}\n" >>~/.ssh/config
+function add_doc_server_ssh_keys {
+    local key_string="${1}"
+    local server_url="${2}"
+    local server_user="${3}"
+    add_ssh_keys "${key_string}"
+    echo -e "Host ${server_url}\n\tStrictHostKeyChecking no\n\tUser ${server_user}\n" >>~/.ssh/config
 }
diff --git a/idf_component.yml b/idf_component.yml
index abacb442ef2..03c9c96c8ef 100644
--- a/idf_component.yml
+++ b/idf_component.yml
@@ -9,6 +9,7 @@ targets:
   - esp32c3
   - esp32c6
   - esp32h2
+  - esp32p4
 tags:
   - arduino
 files:
@@ -20,6 +21,7 @@ files:
     - "variants/esp32c3/**/*"
     - "variants/esp32c6/**/*"
     - "variants/esp32h2/**/*"
+    - "variants/esp32p4/**/*"
   exclude:
     - "docs/"
     - "docs/**/*"
@@ -42,59 +44,30 @@ files:
     - "platform.txt"
     - "programmers.txt"
 dependencies:
-  idf: ">=5.1,<5.2"
+  idf: ">=5.3,<=5.4"
   # mdns 1.2.1 is necessary to build H2 with no WiFi
   espressif/mdns:
     version: "^1.2.3"
     require: public
   espressif/esp_modem:
     version: "^1.1.0"
-  espressif/network_provisioning:
-    version: "~1.0.0"
-  espressif/esp-zboss-lib:
-    version: "^1.0.1"
     rules:
-      - if: "target != esp32c2"
-  espressif/esp-zigbee-lib:
-    version: "^1.0.1"
-    rules:
-      - if: "target != esp32c2"
+      - if: "target in [esp32, esp32s2, esp32s3, esp32h2, esp32p4]"
   espressif/esp-dsp:
-    version: "^1.3.4"
-    rules:
-      - if: "target != esp32c2"
-  espressif/esp_rainmaker:
-    version: "^1.0.0"
-    rules:
-      - if: "target != esp32c2"
-  espressif/rmaker_common:
-    version: "^1.4.6"
-    rules:
-      - if: "target != esp32c2"
-  espressif/esp_insights:
-    version: "^1.2.1"
+    version: "^1.4.12"
+  espressif/esp_hosted:
+    version: "^0.0.25"
     rules:
-      - if: "target != esp32c2"
-  espressif/qrcode:
-    version: "^0.1.0~1"
+      - if: "target == esp32p4"
+  espressif/esp_wifi_remote:
+    version: "^0.4.1"
     rules:
-      - if: "target != esp32c2"
-  espressif/esp-sr:
-    version: "^1.4.2"
-    rules:
-      - if: "target in [esp32s3]"
-  espressif/libsodium:
-    version: "^1.0.20~1"
-    require: public
-  espressif/esp-modbus:
-    version: "^1.0.15"
-    require: public
+      - if: "target == esp32p4"
   joltwallet/littlefs:
-    version: "^1.10.2"
-  chmorgan/esp-libhelix-mp3:
-    version: "1.0.3"
+    version: "^1.14.1"
+  espressif/esp32-camera:
+    version: "master"
+    git: https://github.com/espressif/esp32-camera.git
     require: public
-examples:
-  - path: ./idf_component_examples/hello_world
-  - path: ./idf_component_examples/hw_cdc_hello_world
-  - path: ./idf_component_examples/esp_matter_light
+    rules:
+      - if: "target in [esp32, esp32s2, esp32s3, esp32p4]"
diff --git a/libraries/ArduinoOTA/library.properties b/libraries/ArduinoOTA/library.properties
index d3d9d08494b..54ad6eafb21 100644
--- a/libraries/ArduinoOTA/library.properties
+++ b/libraries/ArduinoOTA/library.properties
@@ -1,5 +1,5 @@
 name=ArduinoOTA
-version=3.0.5
+version=3.1.0
 author=Ivan Grokhotkov and Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download.
diff --git a/libraries/ArduinoOTA/src/ArduinoOTA.cpp b/libraries/ArduinoOTA/src/ArduinoOTA.cpp
index 9dcf93a1d23..0ab5466ab20 100644
--- a/libraries/ArduinoOTA/src/ArduinoOTA.cpp
+++ b/libraries/ArduinoOTA/src/ArduinoOTA.cpp
@@ -134,10 +134,12 @@ void ArduinoOTAClass::begin() {
     sprintf(tmp, "esp32-%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
     _hostname = tmp;
   }
+#ifdef CONFIG_MDNS_MAX_INTERFACES
   if (_mdnsEnabled) {
     MDNS.begin(_hostname.c_str());
     MDNS.enableArduino(_port, (_password.length() > 0));
   }
+#endif
   _initialized = true;
   _state = OTA_IDLE;
   log_i("OTA server at: %s.local:%u", _hostname.c_str(), _port);
@@ -372,9 +374,11 @@ void ArduinoOTAClass::_runUpdate() {
 void ArduinoOTAClass::end() {
   _initialized = false;
   _udp_ota.stop();
+#ifdef CONFIG_MDNS_MAX_INTERFACES
   if (_mdnsEnabled) {
     MDNS.end();
   }
+#endif
   _state = OTA_IDLE;
   log_i("OTA server stopped.");
 }
diff --git a/libraries/AsyncUDP/library.properties b/libraries/AsyncUDP/library.properties
index ba0cb838673..24457a39b90 100644
--- a/libraries/AsyncUDP/library.properties
+++ b/libraries/AsyncUDP/library.properties
@@ -1,5 +1,5 @@
 name=ESP32 Async UDP
-version=3.0.5
+version=3.1.0
 author=Me-No-Dev
 maintainer=Me-No-Dev
 sentence=Async UDP Library for ESP32
diff --git a/libraries/AsyncUDP/src/AsyncUDP.cpp b/libraries/AsyncUDP/src/AsyncUDP.cpp
index 5549276de44..48714bce5c5 100644
--- a/libraries/AsyncUDP/src/AsyncUDP.cpp
+++ b/libraries/AsyncUDP/src/AsyncUDP.cpp
@@ -328,25 +328,36 @@ AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr,
   pbuf_ref(_pb);
 
   //memcpy(&_remoteIp, raddr, sizeof(ip_addr_t));
+#if CONFIG_LWIP_IPV6
   _remoteIp.type = raddr->type;
   _localIp.type = _remoteIp.type;
+#endif
 
   eth_hdr *eth = NULL;
   udp_hdr *udphdr = (udp_hdr *)(_data - UDP_HLEN);
   _localPort = ntohs(udphdr->dest);
   _remotePort = ntohs(udphdr->src);
 
+#if CONFIG_LWIP_IPV6
   if (_remoteIp.type == IPADDR_TYPE_V4) {
+#endif
     eth = (eth_hdr *)(_data - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR);
     struct ip_hdr *iphdr = (struct ip_hdr *)(_data - UDP_HLEN - IP_HLEN);
+#if CONFIG_LWIP_IPV6
     _localIp.u_addr.ip4.addr = iphdr->dest.addr;
     _remoteIp.u_addr.ip4.addr = iphdr->src.addr;
+#else
+  _localIp.addr = iphdr->dest.addr;
+  _remoteIp.addr = iphdr->src.addr;
+#endif
+#if CONFIG_LWIP_IPV6
   } else {
     eth = (eth_hdr *)(_data - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR);
     struct ip6_hdr *ip6hdr = (struct ip6_hdr *)(_data - UDP_HLEN - IP6_HLEN);
     memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
     memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16);
   }
+#endif
   memcpy(_remoteMac, eth->src.addr, 6);
 
   struct netif *netif = NULL;
@@ -413,36 +424,48 @@ tcpip_adapter_if_t AsyncUDPPacket::interface() {
 }
 
 IPAddress AsyncUDPPacket::localIP() {
+#if CONFIG_LWIP_IPV6
   if (_localIp.type != IPADDR_TYPE_V4) {
     return IPAddress();
   }
   return IPAddress(_localIp.u_addr.ip4.addr);
+#else
+  return IPAddress(_localIp.addr);
+#endif
 }
 
+#if CONFIG_LWIP_IPV6
 IPAddress AsyncUDPPacket::localIPv6() {
   if (_localIp.type != IPADDR_TYPE_V6) {
     return IPAddress(IPv6);
   }
   return IPAddress(IPv6, (const uint8_t *)_localIp.u_addr.ip6.addr, _localIp.u_addr.ip6.zone);
 }
+#endif
 
 uint16_t AsyncUDPPacket::localPort() {
   return _localPort;
 }
 
 IPAddress AsyncUDPPacket::remoteIP() {
+#if CONFIG_LWIP_IPV6
   if (_remoteIp.type != IPADDR_TYPE_V4) {
     return IPAddress();
   }
   return IPAddress(_remoteIp.u_addr.ip4.addr);
+#else
+  return IPAddress(_remoteIp.addr);
+#endif
 }
 
+#if CONFIG_LWIP_IPV6
 IPAddress AsyncUDPPacket::remoteIPv6() {
   if (_remoteIp.type != IPADDR_TYPE_V6) {
     return IPAddress(IPv6);
   }
   return IPAddress(IPv6, (const uint8_t *)_remoteIp.u_addr.ip6.addr, _remoteIp.u_addr.ip6.zone);
 }
+#endif
 
 uint16_t AsyncUDPPacket::remotePort() {
   return _remotePort;
@@ -453,14 +476,22 @@ void AsyncUDPPacket::remoteMac(uint8_t *mac) {
 }
 
 bool AsyncUDPPacket::isIPv6() {
+#if CONFIG_LWIP_IPV6
   return _localIp.type == IPADDR_TYPE_V6;
+#else
+  return false;
+#endif
 }
 
 bool AsyncUDPPacket::isBroadcast() {
+#if CONFIG_LWIP_IPV6
   if (_localIp.type == IPADDR_TYPE_V6) {
     return false;
   }
   uint32_t ip = _localIp.u_addr.ip4.addr;
+#else
+  uint32_t ip = _localIp.addr;
+#endif
   return ip == 0xFFFFFFFF || ip == 0 || (ip & 0xFF000000) == 0xFF000000;
 }
 
@@ -571,6 +602,7 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap
     }
     netif = (struct netif *)nif;
 
+#if CONFIG_LWIP_IPV6
     if (addr->type == IPADDR_TYPE_V4) {
       if (join) {
         if (igmp_joingroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) {
@@ -592,7 +624,19 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap
         }
       }
     }
+#else
+    if (join) {
+      if (igmp_joingroup_netif(netif, (const ip4_addr *)(addr))) {
+        return ESP_ERR_INVALID_STATE;
+      }
+    } else {
+      if (igmp_leavegroup_netif(netif, (const ip4_addr *)(addr))) {
+        return ESP_ERR_INVALID_STATE;
+      }
+    }
+#endif
   } else {
+#if CONFIG_LWIP_IPV6
     if (addr->type == IPADDR_TYPE_V4) {
       if (join) {
         if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) {
@@ -614,6 +658,17 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap
         }
       }
     }
+#else
+    if (join) {
+      if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)(addr))) {
+        return ESP_ERR_INVALID_STATE;
+      }
+    } else {
+      if (igmp_leavegroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)(addr))) {
+        return ESP_ERR_INVALID_STATE;
+      }
+    }
+#endif
   }
   return ESP_OK;
 }
@@ -722,18 +777,24 @@ size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr,
 }
 
 IPAddress AsyncUDP::listenIP() {
+#if CONFIG_LWIP_IPV6
   if (!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V4) {
     return IPAddress();
   }
   return IPAddress(_pcb->remote_ip.u_addr.ip4.addr);
+#else
+  return IPAddress(_pcb->remote_ip.addr);
+#endif
 }
 
+#if CONFIG_LWIP_IPV6
 IPAddress AsyncUDP::listenIPv6() {
   if (!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V6) {
     return IPAddress(IPv6);
   }
   return IPAddress(IPv6, (const uint8_t *)_pcb->remote_ip.u_addr.ip6.addr, _pcb->remote_ip.u_addr.ip6.zone);
 }
+#endif
 
 size_t AsyncUDP::write(const uint8_t *data, size_t len) {
   return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port);
diff --git a/libraries/AsyncUDP/src/AsyncUDP.h b/libraries/AsyncUDP/src/AsyncUDP.h
index 160fb7b1515..cd96d852542 100644
--- a/libraries/AsyncUDP/src/AsyncUDP.h
+++ b/libraries/AsyncUDP/src/AsyncUDP.h
@@ -79,10 +79,14 @@ class AsyncUDPPacket : public Stream {
   tcpip_adapter_if_t interface();
 
   IPAddress localIP();
+#if CONFIG_LWIP_IPV6
   IPAddress localIPv6();
+#endif
   uint16_t localPort();
   IPAddress remoteIP();
+#if CONFIG_LWIP_IPV6
   IPAddress remoteIPv6();
+#endif
   uint16_t remotePort();
   void remoteMac(uint8_t *mac);
 
@@ -146,7 +150,9 @@ class AsyncUDP : public Print {
   size_t broadcast(AsyncUDPMessage &message);
 
   IPAddress listenIP();
+#if CONFIG_LWIP_IPV6
   IPAddress listenIPv6();
+#endif
   bool connected();
   esp_err_t lastErr();
   operator bool();
diff --git a/libraries/BLE/examples/BLE5_extended_scan/ci.json b/libraries/BLE/examples/BLE5_extended_scan/ci.json
index 9f7646a74a6..184cc25a2b0 100644
--- a/libraries/BLE/examples/BLE5_extended_scan/ci.json
+++ b/libraries/BLE/examples/BLE5_extended_scan/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_50_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/BLE5_multi_advertising/ci.json b/libraries/BLE/examples/BLE5_multi_advertising/ci.json
index 9f7646a74a6..184cc25a2b0 100644
--- a/libraries/BLE/examples/BLE5_multi_advertising/ci.json
+++ b/libraries/BLE/examples/BLE5_multi_advertising/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_50_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json
index 9f7646a74a6..184cc25a2b0 100644
--- a/libraries/BLE/examples/BLE5_periodic_advertising/ci.json
+++ b/libraries/BLE/examples/BLE5_periodic_advertising/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_50_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/BLE5_periodic_sync/ci.json b/libraries/BLE/examples/BLE5_periodic_sync/ci.json
index 9f7646a74a6..184cc25a2b0 100644
--- a/libraries/BLE/examples/BLE5_periodic_sync/ci.json
+++ b/libraries/BLE/examples/BLE5_periodic_sync/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_50_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/Beacon_Scanner/ci.json b/libraries/BLE/examples/Beacon_Scanner/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/Beacon_Scanner/ci.json
+++ b/libraries/BLE/examples/Beacon_Scanner/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/Client/ci.json b/libraries/BLE/examples/Client/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/Client/ci.json
+++ b/libraries/BLE/examples/Client/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json
+++ b/libraries/BLE/examples/EddystoneTLM_Beacon/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/EddystoneURL_Beacon/ci.json
+++ b/libraries/BLE/examples/EddystoneURL_Beacon/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/Notify/ci.json b/libraries/BLE/examples/Notify/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/Notify/ci.json
+++ b/libraries/BLE/examples/Notify/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/Scan/ci.json b/libraries/BLE/examples/Scan/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/Scan/ci.json
+++ b/libraries/BLE/examples/Scan/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/Server/ci.json b/libraries/BLE/examples/Server/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/Server/ci.json
+++ b/libraries/BLE/examples/Server/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/Server_multiconnect/ci.json b/libraries/BLE/examples/Server_multiconnect/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/Server_multiconnect/ci.json
+++ b/libraries/BLE/examples/Server_multiconnect/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/UART/ci.json b/libraries/BLE/examples/UART/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/UART/ci.json
+++ b/libraries/BLE/examples/UART/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/Write/ci.json b/libraries/BLE/examples/Write/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/Write/ci.json
+++ b/libraries/BLE/examples/Write/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/examples/iBeacon/ci.json b/libraries/BLE/examples/iBeacon/ci.json
index c23553ec084..abe13a7ebbb 100644
--- a/libraries/BLE/examples/iBeacon/ci.json
+++ b/libraries/BLE/examples/iBeacon/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_SOC_BLE_SUPPORTED=y"
   ]
diff --git a/libraries/BLE/library.properties b/libraries/BLE/library.properties
index 74dbf9c8514..32ad36b5f44 100644
--- a/libraries/BLE/library.properties
+++ b/libraries/BLE/library.properties
@@ -1,5 +1,5 @@
 name=BLE
-version=3.0.5
+version=3.1.0
 author=Neil Kolban <kolban1@kolban.com>
 maintainer=Dariusz Krempa <esp32@esp32.eu.org>
 sentence=BLE functions for ESP32
diff --git a/libraries/BLE/src/BLECharacteristic.cpp b/libraries/BLE/src/BLECharacteristic.cpp
index 1d1bafdda1c..b03d524a6a5 100644
--- a/libraries/BLE/src/BLECharacteristic.cpp
+++ b/libraries/BLE/src/BLECharacteristic.cpp
@@ -279,9 +279,13 @@ void BLECharacteristic::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_ga
 
         log_d(" - Response to write event: New value: handle: %.2x, uuid: %s", getHandle(), getUUID().toString().c_str());
 
+// The call to BLEUtils::buildHexData() doesn't output anything if the log level is not
+// "DEBUG". As it is quite CPU intensive, it is much better to not call it if not needed.
+#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
         char *pHexData = BLEUtils::buildHexData(nullptr, param->write.value, param->write.len);
         log_d(" - Data: length: %d, data: %s", param->write.len, pHexData);
         free(pHexData);
+#endif
 
         if (param->write.need_rsp) {
           esp_gatt_rsp_t rsp;
@@ -390,9 +394,13 @@ void BLECharacteristic::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_ga
           rsp.attr_value.handle = param->read.handle;
           rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
 
+// The call to BLEUtils::buildHexData() doesn't output anything if the log level is not
+// "DEBUG". As it is quite CPU intensive, it is much better to not call it if not needed.
+#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
           char *pHexData = BLEUtils::buildHexData(nullptr, rsp.attr_value.value, rsp.attr_value.len);
           log_d(" - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset);
           free(pHexData);
+#endif
 
           esp_err_t errRc = ::esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
           if (errRc != ESP_OK) {
@@ -471,7 +479,20 @@ void BLECharacteristic::notify(bool is_notification) {
 
   m_pCallbacks->onNotify(this);  // Invoke the notify callback.
 
+  // GeneralUtils::hexDump() doesn't output anything if the log level is not
+  // "VERBOSE". Additionally, it is very CPU intensive, even when it doesn't
+  // output anything! So it is much better to *not* call it at all if not needed.
+  // In a simple program which calls BLECharacteristic::notify() every 50 ms,
+  // the performance gain of this little optimization is 37% in release mode
+  // (-O3) and 57% in debug mode.
+  // Of course, the "#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE" guard
+  // could also be put inside the GeneralUtils::hexDump() function itself. But
+  // it's better to put it here also, as it is clearer (indicating a verbose log
+  // thing) and it allows to remove the "m_value.getValue().c_str()" call, which
+  // is, in itself, quite CPU intensive.
+#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
   GeneralUtils::hexDump((uint8_t *)m_value.getValue().c_str(), m_value.getValue().length());
+#endif
 
   if (getService()->getServer()->getConnectedCount() == 0) {
     log_v("<< notify: No connected clients.");
@@ -624,9 +645,13 @@ void BLECharacteristic::setReadProperty(bool value) {
  * @param [in] length The length of the data in bytes.
  */
 void BLECharacteristic::setValue(uint8_t *data, size_t length) {
+// The call to BLEUtils::buildHexData() doesn't output anything if the log level is not
+// "VERBOSE". As it is quite CPU intensive, it is much better to not call it if not needed.
+#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
   char *pHex = BLEUtils::buildHexData(nullptr, data, length);
   log_v(">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
   free(pHex);
+#endif
   if (length > ESP_GATT_MAX_ATTR_LEN) {
     log_e("Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN);
     return;
diff --git a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json
+++ b/libraries/BluetoothSerial/examples/DiscoverConnect/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json
+++ b/libraries/BluetoothSerial/examples/GetLocalMAC/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBTM/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino
index 343bd79c79b..d184a4ea769 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino
@@ -17,12 +17,6 @@
 #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
 #endif
 
-// Check Simple Secure Pairing
-#if defined(CONFIG_BT_SSP_ENABLED)
-#warning Legacy Pairing is disabled (CONFIG_BT_SSP_ENABLED is enabled. Disable it in menuconfig).
-void setup() {}
-void loop() {}
-#else
 const char *deviceName = "ESP32_Legacy_example";
 
 BluetoothSerial SerialBT;
@@ -62,4 +56,3 @@ void loop() {
     delay(1);  // Feed the watchdog
   }
 }
-#endif
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino
index eb0c05e0038..e5d05eed14e 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino
@@ -22,11 +22,6 @@
 #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
 #endif
 
-// Check Simple Secure Pairing
-#if !defined(CONFIG_BT_SSP_ENABLED)
-#error Simple Secure Pairing for Bluetooth is not available or not enabled.
-#endif
-
 const char *deviceName = "ESP32_SSP_example";
 
 // The following lines defines the method of pairing
diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json
+++ b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json
index 98fda4381b1..b5097688f52 100644
--- a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json
+++ b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires": [
     "CONFIG_BT_SPP_ENABLED=y"
   ]
diff --git a/libraries/BluetoothSerial/library.properties b/libraries/BluetoothSerial/library.properties
index b7595ef3d1f..6db3a01bb19 100644
--- a/libraries/BluetoothSerial/library.properties
+++ b/libraries/BluetoothSerial/library.properties
@@ -1,5 +1,5 @@
 name=BluetoothSerial
-version=3.0.5
+version=3.1.0
 author=Evandro Copercini
 maintainer=Evandro Copercini
 sentence=Simple UART to Classical Bluetooth bridge for ESP32
diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
index bcb94db910f..3d00504c1b1 100644
--- a/libraries/BluetoothSerial/src/BluetoothSerial.cpp
+++ b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
@@ -71,11 +71,9 @@ static esp_bd_addr_t _peer_bd_addr;
 static char _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
 static bool _isRemoteAddressSet;
 static bool _isMaster;
-#ifdef CONFIG_BT_SSP_ENABLED
 static bool _enableSSP;
 static bool _IO_CAP_INPUT;
 static bool _IO_CAP_OUTPUT;
-#endif
 esp_bt_pin_code_t _pin_code = {0};
 uint8_t _pin_code_len = 0;  // Number of valid Bytes in the esp_bt_pin_code_t array
 static esp_spp_sec_t _sec_mask;
@@ -538,7 +536,6 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
         esp_bt_gap_pin_reply(param->pin_req.bda, true, _pin_code_len, _pin_code);
       }
       break;
-#ifdef CONFIG_BT_SSP_ENABLED
     case ESP_BT_GAP_CFM_REQ_EVT:  // Enum 6 - Security Simple Pairing User Confirmation request.
       log_i("ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
       if (confirm_request_callback) {
@@ -549,13 +546,10 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
         esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false);
       }
       break;
-#endif
 
     case ESP_BT_GAP_KEY_NOTIF_EVT:  // Enum 7 - Security Simple Pairing Passkey Notification
       log_i("ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
       break;
-
-#ifdef CONFIG_BT_SSP_ENABLED
     case ESP_BT_GAP_KEY_REQ_EVT:  // Enum 8 - Security Simple Pairing Passkey request
       log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
       if (key_request_callback) {
@@ -566,7 +560,6 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
         esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false);
       }
       break;
-#endif
 
     case ESP_BT_GAP_READ_RSSI_DELTA_EVT:  // Enum 9 - Read rssi event
       log_i("ESP_BT_GAP_READ_RSSI_DELTA_EVT Read rssi event");
@@ -705,9 +698,8 @@ static bool _init_bt(const char *deviceName, bt_mode mode) {
   }
 
   log_i("device name set");
-  esp_bt_dev_set_device_name(deviceName);
+  esp_bt_gap_set_device_name(deviceName);
 
-#ifdef CONFIG_BT_SSP_ENABLED
   if (_enableSSP) {
     log_i("Simple Secure Pairing");
     esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
@@ -723,7 +715,6 @@ static bool _init_bt(const char *deviceName, bt_mode mode) {
     }
     esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
   }
-#endif
 
   // the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack
   esp_bt_cod_t cod;
@@ -894,7 +885,6 @@ void BluetoothSerial::memrelease() {
   esp_bt_mem_release(ESP_BT_MODE_BTDM);
 }
 
-#ifdef CONFIG_BT_SSP_ENABLED
 void BluetoothSerial::onConfirmRequest(ConfirmRequestCb cb) {
   confirm_request_callback = cb;
 }
@@ -906,7 +896,6 @@ void BluetoothSerial::onKeyRequest(KeyRequestCb cb) {
 void BluetoothSerial::respondPasskey(uint32_t passkey) {
   esp_bt_gap_ssp_passkey_reply(current_bd_addr, true, passkey);
 }
-#endif
 
 void BluetoothSerial::onAuthComplete(AuthCompleteCb cb) {
   auth_complete_callback = cb;
@@ -921,7 +910,6 @@ esp_err_t BluetoothSerial::register_callback(esp_spp_cb_t callback) {
   return ESP_OK;
 }
 
-#ifdef CONFIG_BT_SSP_ENABLED
 // Enable Simple Secure Pairing (using generated PIN)
 // This must be called before calling begin, otherwise has no effect!
 void BluetoothSerial::enableSSP() {
@@ -957,8 +945,6 @@ void BluetoothSerial::disableSSP() {
   _enableSSP = false;
 }
 
-#else
-
 bool BluetoothSerial::setPin(const char *pin, uint8_t pin_code_len) {
   if (pin_code_len == 0 || pin_code_len > 16) {
     log_e("PIN code must be 1-16 Bytes long! Called with length %d", pin_code_len);
@@ -968,7 +954,6 @@ bool BluetoothSerial::setPin(const char *pin, uint8_t pin_code_len) {
   memcpy(_pin_code, pin, pin_code_len);
   return (esp_bt_gap_set_pin(ESP_BT_PIN_TYPE_FIXED, _pin_code_len, _pin_code) == ESP_OK);
 }
-#endif
 
 bool BluetoothSerial::connect(String remoteName) {
   bool retval = false;
diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.h b/libraries/BluetoothSerial/src/BluetoothSerial.h
index 6b7ba419e00..d59fbf1f714 100644
--- a/libraries/BluetoothSerial/src/BluetoothSerial.h
+++ b/libraries/BluetoothSerial/src/BluetoothSerial.h
@@ -56,21 +56,16 @@ class BluetoothSerial : public Stream {
   void onData(BluetoothSerialDataCb cb);
   esp_err_t register_callback(esp_spp_cb_t callback);
 
-#ifdef CONFIG_BT_SSP_ENABLED
   void onConfirmRequest(ConfirmRequestCb cb);
   void onKeyRequest(KeyRequestCb cb);
   void respondPasskey(uint32_t passkey);
-#endif
   void onAuthComplete(AuthCompleteCb cb);
   void confirmReply(boolean confirm);
 
-#ifdef CONFIG_BT_SSP_ENABLED
   void enableSSP();
   void enableSSP(bool inputCapability, bool outputCapability);
   void disableSSP();
-#else
   bool setPin(const char *pin, uint8_t pin_code_len);
-#endif
   bool connect(String remoteName);
   bool connect(
     uint8_t remoteAddress[], int channel = 0, esp_spp_sec_t sec_mask = (ESP_SPP_SEC_ENCRYPT | ESP_SPP_SEC_AUTHENTICATE),
diff --git a/libraries/DNSServer/library.properties b/libraries/DNSServer/library.properties
index fc1ce2d9107..077d9237f21 100644
--- a/libraries/DNSServer/library.properties
+++ b/libraries/DNSServer/library.properties
@@ -1,5 +1,5 @@
 name=DNSServer
-version=3.0.5
+version=3.1.0
 author=Kristijan Novoselić
 maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com>
 sentence=A simple DNS server for ESP32.
diff --git a/libraries/EEPROM/library.properties b/libraries/EEPROM/library.properties
index d82b97dcf3d..bf75d618898 100644
--- a/libraries/EEPROM/library.properties
+++ b/libraries/EEPROM/library.properties
@@ -1,5 +1,5 @@
 name=EEPROM
-version=3.0.5
+version=3.1.0
 author=Ivan Grokhotkov
 maintainer=Paolo Becchi <pbecchi@aerobusiness.it>
 sentence=Enables reading and writing data a sequential, addressable FLASH storage
diff --git a/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp b/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp
index af3d38ad544..6b62ee9b6cf 100644
--- a/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp
+++ b/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp
@@ -24,55 +24,6 @@
 #include "esp32-hal-log.h"
 #endif
 
-// Face Detection will not work on boards without (or with disabled) PSRAM
-#ifdef BOARD_HAS_PSRAM
-// Face Recognition takes upward from 15 seconds per frame on chips other than ESP32S3
-// Makes no sense to have it enabled for them
-#if CONFIG_IDF_TARGET_ESP32S3
-#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 1
-#define CONFIG_ESP_FACE_DETECT_ENABLED      1
-#else
-#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0
-#define CONFIG_ESP_FACE_DETECT_ENABLED      0
-#endif
-#else
-#define CONFIG_ESP_FACE_DETECT_ENABLED      0
-#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0
-#endif
-
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-
-#include <vector>
-#include "human_face_detect_msr01.hpp"
-#include "human_face_detect_mnp01.hpp"
-
-#define TWO_STAGE 1 /*<! 1: detect by two-stage which is more accurate but slower(with keypoints). */
-                    /*<! 0: detect by one-stage which is less accurate but faster(without keypoints). */
-
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wstrict-aliasing"
-#include "face_recognition_tool.hpp"
-#include "face_recognition_112_v1_s16.hpp"
-#include "face_recognition_112_v1_s8.hpp"
-#pragma GCC diagnostic error "-Wformat"
-#pragma GCC diagnostic warning "-Wstrict-aliasing"
-
-#define QUANT_TYPE 0  //if set to 1 => very large firmware, very slow, reboots when streaming...
-
-#define FACE_ID_SAVE_NUMBER 7
-#endif
-
-#define FACE_COLOR_WHITE  0x00FFFFFF
-#define FACE_COLOR_BLACK  0x00000000
-#define FACE_COLOR_RED    0x000000FF
-#define FACE_COLOR_GREEN  0x0000FF00
-#define FACE_COLOR_BLUE   0x00FF0000
-#define FACE_COLOR_YELLOW (FACE_COLOR_RED | FACE_COLOR_GREEN)
-#define FACE_COLOR_CYAN   (FACE_COLOR_BLUE | FACE_COLOR_GREEN)
-#define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED)
-#endif
-
 // Enable LED FLASH setting
 #define CONFIG_LED_ILLUMINATOR_ENABLED 1
 
@@ -100,32 +51,6 @@ static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %
 httpd_handle_t stream_httpd = NULL;
 httpd_handle_t camera_httpd = NULL;
 
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-
-static int8_t detection_enabled = 0;
-
-// #if TWO_STAGE
-// static HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
-// static HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
-// #else
-// static HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
-// #endif
-
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-static int8_t recognition_enabled = 0;
-static int8_t is_enrolling = 0;
-
-#if QUANT_TYPE
-// S16 model
-FaceRecognition112V1S16 recognizer;
-#else
-// S8 model
-FaceRecognition112V1S8 recognizer;
-#endif
-#endif
-
-#endif
-
 typedef struct {
   size_t size;   //number of values used for filtering
   size_t index;  //current value index
@@ -166,105 +91,6 @@ static int ra_filter_run(ra_filter_t *filter, int value) {
 }
 #endif
 
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-static void rgb_print(fb_data_t *fb, uint32_t color, const char *str) {
-  fb_gfx_print(fb, (fb->width - (strlen(str) * 14)) / 2, 10, color, str);
-}
-
-static int rgb_printf(fb_data_t *fb, uint32_t color, const char *format, ...) {
-  char loc_buf[64];
-  char *temp = loc_buf;
-  int len;
-  va_list arg;
-  va_list copy;
-  va_start(arg, format);
-  va_copy(copy, arg);
-  len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg);
-  va_end(copy);
-  if (len >= sizeof(loc_buf)) {
-    temp = (char *)malloc(len + 1);
-    if (temp == NULL) {
-      return 0;
-    }
-  }
-  vsnprintf(temp, len + 1, format, arg);
-  va_end(arg);
-  rgb_print(fb, color, temp);
-  if (len > 64) {
-    free(temp);
-  }
-  return len;
-}
-#endif
-static void draw_face_boxes(fb_data_t *fb, std::list<dl::detect::result_t> *results, int face_id) {
-  int x, y, w, h;
-  uint32_t color = FACE_COLOR_YELLOW;
-  if (face_id < 0) {
-    color = FACE_COLOR_RED;
-  } else if (face_id > 0) {
-    color = FACE_COLOR_GREEN;
-  }
-  if (fb->bytes_per_pixel == 2) {
-    //color = ((color >> 8) & 0xF800) | ((color >> 3) & 0x07E0) | (color & 0x001F);
-    color = ((color >> 16) & 0x001F) | ((color >> 3) & 0x07E0) | ((color << 8) & 0xF800);
-  }
-  int i = 0;
-  for (std::list<dl::detect::result_t>::iterator prediction = results->begin(); prediction != results->end(); prediction++, i++) {
-    // rectangle box
-    x = (int)prediction->box[0];
-    y = (int)prediction->box[1];
-    w = (int)prediction->box[2] - x + 1;
-    h = (int)prediction->box[3] - y + 1;
-    if ((x + w) > fb->width) {
-      w = fb->width - x;
-    }
-    if ((y + h) > fb->height) {
-      h = fb->height - y;
-    }
-    fb_gfx_drawFastHLine(fb, x, y, w, color);
-    fb_gfx_drawFastHLine(fb, x, y + h - 1, w, color);
-    fb_gfx_drawFastVLine(fb, x, y, h, color);
-    fb_gfx_drawFastVLine(fb, x + w - 1, y, h, color);
-#if TWO_STAGE
-    // landmarks (left eye, mouth left, nose, right eye, mouth right)
-    int x0, y0, j;
-    for (j = 0; j < 10; j += 2) {
-      x0 = (int)prediction->keypoint[j];
-      y0 = (int)prediction->keypoint[j + 1];
-      fb_gfx_fillRect(fb, x0, y0, 3, 3, color);
-    }
-#endif
-  }
-}
-
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-static int run_face_recognition(fb_data_t *fb, std::list<dl::detect::result_t> *results) {
-  std::vector<int> landmarks = results->front().keypoint;
-  int id = -1;
-
-  Tensor<uint8_t> tensor;
-  tensor.set_element((uint8_t *)fb->data).set_shape({fb->height, fb->width, 3}).set_auto_free(false);
-
-  int enrolled_count = recognizer.get_enrolled_id_num();
-
-  if (enrolled_count < FACE_ID_SAVE_NUMBER && is_enrolling) {
-    id = recognizer.enroll_id(tensor, landmarks, "", true);
-    log_i("Enrolled ID: %d", id);
-    rgb_printf(fb, FACE_COLOR_CYAN, "ID[%u]", id);
-  }
-
-  face_info_t recognize = recognizer.recognize(tensor, landmarks);
-  if (recognize.id >= 0) {
-    rgb_printf(fb, FACE_COLOR_GREEN, "ID[%u]: %.2f", recognize.id, recognize.similarity);
-  } else {
-    rgb_print(fb, FACE_COLOR_RED, "Intruder Alert!");
-  }
-  return recognize.id;
-}
-#endif
-#endif
-
 #if CONFIG_LED_ILLUMINATOR_ENABLED
 void enable_led(bool en) {  // Turn LED On or Off
   int duty = en ? led_duty : 0;
@@ -359,134 +185,28 @@ static esp_err_t capture_handler(httpd_req_t *req) {
   snprintf(ts, 32, "%lld.%06ld", fb->timestamp.tv_sec, fb->timestamp.tv_usec);
   httpd_resp_set_hdr(req, "X-Timestamp", (const char *)ts);
 
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-  size_t out_len, out_width, out_height;
-  uint8_t *out_buf;
-  bool s;
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-  bool detected = false;
-#endif
-  int face_id = 0;
-  if (!detection_enabled || fb->width > 400) {
-#endif
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-    size_t fb_len = 0;
+  size_t fb_len = 0;
 #endif
-    if (fb->format == PIXFORMAT_JPEG) {
+  if (fb->format == PIXFORMAT_JPEG) {
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-      fb_len = fb->len;
+    fb_len = fb->len;
 #endif
-      res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
-    } else {
-      jpg_chunking_t jchunk = {req, 0};
-      res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
-      httpd_resp_send_chunk(req, NULL, 0);
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-      fb_len = jchunk.len;
-#endif
-    }
-    esp_camera_fb_return(fb);
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-    int64_t fr_end = esp_timer_get_time();
-#endif
-    log_i("JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000));
-    return res;
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-  }
-
-  jpg_chunking_t jchunk = {req, 0};
-
-  if (fb->format == PIXFORMAT_RGB565
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-      && !recognition_enabled
-#endif
-  ) {
-#if TWO_STAGE
-    HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
-    HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
-    std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
-    std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
-#else
-    HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
-    std::list<dl::detect::result_t> &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
-#endif
-    if (results.size() > 0) {
-      fb_data_t rfb;
-      rfb.width = fb->width;
-      rfb.height = fb->height;
-      rfb.data = fb->buf;
-      rfb.bytes_per_pixel = 2;
-      rfb.format = FB_RGB565;
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-      detected = true;
-#endif
-      draw_face_boxes(&rfb, &results, face_id);
-    }
-    s = fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 90, jpg_encode_stream, &jchunk);
-    esp_camera_fb_return(fb);
+    res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
   } else {
-    out_len = fb->width * fb->height * 3;
-    out_width = fb->width;
-    out_height = fb->height;
-    out_buf = (uint8_t *)malloc(out_len);
-    if (!out_buf) {
-      log_e("out_buf malloc failed");
-      httpd_resp_send_500(req);
-      return ESP_FAIL;
-    }
-    s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
-    esp_camera_fb_return(fb);
-    if (!s) {
-      free(out_buf);
-      log_e("To rgb888 failed");
-      httpd_resp_send_500(req);
-      return ESP_FAIL;
-    }
-
-    fb_data_t rfb;
-    rfb.width = out_width;
-    rfb.height = out_height;
-    rfb.data = out_buf;
-    rfb.bytes_per_pixel = 3;
-    rfb.format = FB_BGR888;
-
-#if TWO_STAGE
-    HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
-    HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
-    std::list<dl::detect::result_t> &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
-    std::list<dl::detect::result_t> &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates);
-#else
-    HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
-    std::list<dl::detect::result_t> &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
-#endif
-
-    if (results.size() > 0) {
+    jpg_chunking_t jchunk = {req, 0};
+    res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
+    httpd_resp_send_chunk(req, NULL, 0);
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-      detected = true;
+    fb_len = jchunk.len;
 #endif
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-      if (recognition_enabled) {
-        face_id = run_face_recognition(&rfb, &results);
-      }
-#endif
-      draw_face_boxes(&rfb, &results, face_id);
-    }
-
-    s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
-    free(out_buf);
-  }
-
-  if (!s) {
-    log_e("JPEG compression failed");
-    httpd_resp_send_500(req);
-    return ESP_FAIL;
   }
+  esp_camera_fb_return(fb);
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
   int64_t fr_end = esp_timer_get_time();
 #endif
-  log_i("FACE: %uB %ums %s%d", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start) / 1000), detected ? "DETECTED " : "", face_id);
+  log_i("JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000));
   return res;
-#endif
 }
 
 static esp_err_t stream_handler(httpd_req_t *req) {
@@ -496,26 +216,6 @@ static esp_err_t stream_handler(httpd_req_t *req) {
   size_t _jpg_buf_len = 0;
   uint8_t *_jpg_buf = NULL;
   char *part_buf[128];
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-  bool detected = false;
-  int64_t fr_ready = 0;
-  int64_t fr_recognize = 0;
-  int64_t fr_encode = 0;
-  int64_t fr_face = 0;
-  int64_t fr_start = 0;
-#endif
-  int face_id = 0;
-  size_t out_len = 0, out_width = 0, out_height = 0;
-  uint8_t *out_buf = NULL;
-  bool s = false;
-#if TWO_STAGE
-  HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
-  HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
-#else
-  HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
-#endif
-#endif
 
   static int64_t last_frame = 0;
   if (!last_frame) {
@@ -536,13 +236,6 @@ static esp_err_t stream_handler(httpd_req_t *req) {
 #endif
 
   while (true) {
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-    detected = false;
-#endif
-    face_id = 0;
-#endif
-
     fb = esp_camera_fb_get();
     if (!fb) {
       log_e("Camera capture failed");
@@ -550,138 +243,18 @@ static esp_err_t stream_handler(httpd_req_t *req) {
     } else {
       _timestamp.tv_sec = fb->timestamp.tv_sec;
       _timestamp.tv_usec = fb->timestamp.tv_usec;
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-      fr_start = esp_timer_get_time();
-      fr_ready = fr_start;
-      fr_encode = fr_start;
-      fr_recognize = fr_start;
-      fr_face = fr_start;
-#endif
-      if (!detection_enabled || fb->width > 400) {
-#endif
-        if (fb->format != PIXFORMAT_JPEG) {
-          bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
-          esp_camera_fb_return(fb);
-          fb = NULL;
-          if (!jpeg_converted) {
-            log_e("JPEG compression failed");
-            res = ESP_FAIL;
-          }
-        } else {
-          _jpg_buf_len = fb->len;
-          _jpg_buf = fb->buf;
+      if (fb->format != PIXFORMAT_JPEG) {
+        bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
+        esp_camera_fb_return(fb);
+        fb = NULL;
+        if (!jpeg_converted) {
+          log_e("JPEG compression failed");
+          res = ESP_FAIL;
         }
-#if CONFIG_ESP_FACE_DETECT_ENABLED
       } else {
-        if (fb->format == PIXFORMAT_RGB565
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-            && !recognition_enabled
-#endif
-        ) {
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-          fr_ready = esp_timer_get_time();
-#endif
-#if TWO_STAGE
-          std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
-          std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
-#else
-          std::list<dl::detect::result_t> &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
-#endif
-#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-          fr_face = esp_timer_get_time();
-          fr_recognize = fr_face;
-#endif
-          if (results.size() > 0) {
-            fb_data_t rfb;
-            rfb.width = fb->width;
-            rfb.height = fb->height;
-            rfb.data = fb->buf;
-            rfb.bytes_per_pixel = 2;
-            rfb.format = FB_RGB565;
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-            detected = true;
-#endif
-            draw_face_boxes(&rfb, &results, face_id);
-          }
-          s = fmt2jpg(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 80, &_jpg_buf, &_jpg_buf_len);
-          esp_camera_fb_return(fb);
-          fb = NULL;
-          if (!s) {
-            log_e("fmt2jpg failed");
-            res = ESP_FAIL;
-          }
-#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-          fr_encode = esp_timer_get_time();
-#endif
-        } else {
-          out_len = fb->width * fb->height * 3;
-          out_width = fb->width;
-          out_height = fb->height;
-          out_buf = (uint8_t *)malloc(out_len);
-          if (!out_buf) {
-            log_e("out_buf malloc failed");
-            res = ESP_FAIL;
-          } else {
-            s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
-            esp_camera_fb_return(fb);
-            fb = NULL;
-            if (!s) {
-              free(out_buf);
-              log_e("To rgb888 failed");
-              res = ESP_FAIL;
-            } else {
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-              fr_ready = esp_timer_get_time();
-#endif
-
-              fb_data_t rfb;
-              rfb.width = out_width;
-              rfb.height = out_height;
-              rfb.data = out_buf;
-              rfb.bytes_per_pixel = 3;
-              rfb.format = FB_BGR888;
-
-#if TWO_STAGE
-              std::list<dl::detect::result_t> &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
-              std::list<dl::detect::result_t> &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates);
-#else
-              std::list<dl::detect::result_t> &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
-#endif
-
-#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-              fr_face = esp_timer_get_time();
-              fr_recognize = fr_face;
-#endif
-
-              if (results.size() > 0) {
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-                detected = true;
-#endif
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-                if (recognition_enabled) {
-                  face_id = run_face_recognition(&rfb, &results);
-#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-                  fr_recognize = esp_timer_get_time();
-#endif
-                }
-#endif
-                draw_face_boxes(&rfb, &results, face_id);
-              }
-              s = fmt2jpg(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len);
-              free(out_buf);
-              if (!s) {
-                log_e("fmt2jpg failed");
-                res = ESP_FAIL;
-              }
-#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-              fr_encode = esp_timer_get_time();
-#endif
-            }
-          }
-        }
+        _jpg_buf_len = fb->len;
+        _jpg_buf = fb->buf;
       }
-#endif
     }
     if (res == ESP_OK) {
       res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
@@ -707,30 +280,14 @@ static esp_err_t stream_handler(httpd_req_t *req) {
     }
     int64_t fr_end = esp_timer_get_time();
 
-#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
-    int64_t ready_time = (fr_ready - fr_start) / 1000;
-    int64_t face_time = (fr_face - fr_ready) / 1000;
-    int64_t recognize_time = (fr_recognize - fr_face) / 1000;
-    int64_t encode_time = (fr_encode - fr_recognize) / 1000;
-    int64_t process_time = (fr_encode - fr_start) / 1000;
-#endif
-
     int64_t frame_time = fr_end - last_frame;
     frame_time /= 1000;
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
     uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);
 #endif
     log_i(
-      "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)"
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-      ", %u+%u+%u+%u=%u %s%d"
-#endif
-      ,
-      (uint32_t)(_jpg_buf_len), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, avg_frame_time, 1000.0 / avg_frame_time
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-      ,
-      (uint32_t)ready_time, (uint32_t)face_time, (uint32_t)recognize_time, (uint32_t)encode_time, (uint32_t)process_time, (detected) ? "DETECTED " : "", face_id
-#endif
+      "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)", (uint32_t)(_jpg_buf_len), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, avg_frame_time,
+      1000.0 / avg_frame_time
     );
   }
 
@@ -841,28 +398,6 @@ static esp_err_t cmd_handler(httpd_req_t *req) {
       enable_led(true);
     }
   }
-#endif
-
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-  else if (!strcmp(variable, "face_detect")) {
-    detection_enabled = val;
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-    if (!detection_enabled) {
-      recognition_enabled = 0;
-    }
-#endif
-  }
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-  else if (!strcmp(variable, "face_enroll")) {
-    is_enrolling = !is_enrolling;
-    log_i("Enrolling: %s", is_enrolling ? "true" : "false");
-  } else if (!strcmp(variable, "face_recognize")) {
-    recognition_enabled = val;
-    if (recognition_enabled) {
-      detection_enabled = val;
-    }
-  }
-#endif
 #endif
   else {
     log_i("Unknown command: %s", variable);
@@ -947,13 +482,6 @@ static esp_err_t status_handler(httpd_req_t *req) {
   p += sprintf(p, ",\"led_intensity\":%u", led_duty);
 #else
   p += sprintf(p, ",\"led_intensity\":%d", -1);
-#endif
-#if CONFIG_ESP_FACE_DETECT_ENABLED
-  p += sprintf(p, ",\"face_detect\":%u", detection_enabled);
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-  p += sprintf(p, ",\"face_enroll\":%u,", is_enrolling);
-  p += sprintf(p, "\"face_recognize\":%u", recognition_enabled);
-#endif
 #endif
   *p++ = '}';
   *p++ = 0;
@@ -1289,12 +817,6 @@ void startCameraServer() {
 
   ra_filter_init(&ra_filter, 20);
 
-#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
-  recognizer.set_partition(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "fr");
-
-  // load ids from flash partition
-  recognizer.set_ids_from_flash();
-#endif
   log_i("Starting web server on port: '%d'", config.server_port);
   if (httpd_start(&camera_httpd, &config) == ESP_OK) {
     httpd_register_uri_handler(camera_httpd, &index_uri);
diff --git a/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json b/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json
index 25c42144223..cd679adefad 100644
--- a/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json
+++ b/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ci.json
@@ -2,6 +2,7 @@
   "targets": {
     "esp32c3": false,
     "esp32c6": false,
-    "esp32h2": false
+    "esp32h2": false,
+    "esp32p4": false
   }
 }
diff --git a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json
index 1af543242e3..6afa60f44c4 100644
--- a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json
+++ b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/ci.json
@@ -3,6 +3,7 @@
     "esp32c3": false,
     "esp32c6": false,
     "esp32h2": false,
+    "esp32p4": false,
     "esp32s2": false,
     "esp32s3": false
   }
diff --git a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino
index 5aacf1baaf0..9d2b248ba44 100644
--- a/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino
+++ b/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino
@@ -15,9 +15,11 @@ Pranav Cherukupalli <cherukupallip@gmail.com>
 */
 
 #if CONFIG_IDF_TARGET_ESP32
-#define THRESHOLD 40   /* Greater the value, more the sensitivity */
-#else                  //ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted) */
+#define THRESHOLD 40 /* Greater the value, more the sensitivity */
+#elif (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3)
 #define THRESHOLD 5000 /* Lower the value, more the sensitivity */
+#else                  // ESP32-P4 + default for other chips (to be adjusted) */
+#define THRESHOLD 500  /* Lower the value, more the sensitivity */
 #endif
 
 RTC_DATA_ATTR int bootCount = 0;
@@ -88,7 +90,7 @@ void setup() {
   touchSleepWakeUpEnable(T3, THRESHOLD);
   touchSleepWakeUpEnable(T7, THRESHOLD);
 
-#else  //ESP32-S2 + ESP32-S3
+#else  //ESP32-S2 + ESP32-S3 + ESP32-P4
   //Setup sleep wakeup on Touch Pad 3 (GPIO3)
   touchSleepWakeUpEnable(T3, THRESHOLD);
 
diff --git a/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/README.md b/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/README.md
index 7bd44855adc..f48e352dd45 100644
--- a/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/README.md
+++ b/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/README.md
@@ -62,10 +62,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Troubleshooting
 
 ***Important: Make sure you are using a good quality USB cable and that you have a reliable power source***
diff --git a/libraries/ESP32/examples/FreeRTOS/Mutex/README.md b/libraries/ESP32/examples/FreeRTOS/Mutex/README.md
index d1c8c19e3be..435528bd771 100644
--- a/libraries/ESP32/examples/FreeRTOS/Mutex/README.md
+++ b/libraries/ESP32/examples/FreeRTOS/Mutex/README.md
@@ -51,10 +51,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Example Log Output
 
 The expected output of shared variables protected by mutex demonstrates mutually exclusive access from tasks - they do not interrupt each other and do not rewrite the value before the other task has read it back.
diff --git a/libraries/ESP32/examples/FreeRTOS/Queue/README.md b/libraries/ESP32/examples/FreeRTOS/Queue/README.md
index 745ce9e8db6..e81d6741e2a 100644
--- a/libraries/ESP32/examples/FreeRTOS/Queue/README.md
+++ b/libraries/ESP32/examples/FreeRTOS/Queue/README.md
@@ -29,10 +29,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Example Log Output
 
 ```
diff --git a/libraries/ESP32/examples/FreeRTOS/Semaphore/README.md b/libraries/ESP32/examples/FreeRTOS/Semaphore/README.md
index 8f860a52db5..fcb38eed1d6 100644
--- a/libraries/ESP32/examples/FreeRTOS/Semaphore/README.md
+++ b/libraries/ESP32/examples/FreeRTOS/Semaphore/README.md
@@ -35,10 +35,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Example Log Output
 
 ```
diff --git a/libraries/ESP32/examples/RMT/Legacy_RMT_Driver_Compatible/Legacy_RMT_Driver_Compatible.ino b/libraries/ESP32/examples/RMT/Legacy_RMT_Driver_Compatible/Legacy_RMT_Driver_Compatible.ino
index 5744cf884a7..b42fe15f0cd 100644
--- a/libraries/ESP32/examples/RMT/Legacy_RMT_Driver_Compatible/Legacy_RMT_Driver_Compatible.ino
+++ b/libraries/ESP32/examples/RMT/Legacy_RMT_Driver_Compatible/Legacy_RMT_Driver_Compatible.ino
@@ -12,7 +12,6 @@
 // add the file "build_opt.h" to your Arduino project folder with "-DESP32_ARDUINO_NO_RGB_BUILTIN" to use the RMT Legacy driver
 #error "ESP32_ARDUINO_NO_RGB_BUILTIN is not defined, this example is intended to demonstrate the RMT Legacy driver."
 #error "Please add the file 'build_opt.h' with '-DESP32_ARDUINO_NO_RGB_BUILTIN' to your Arduino project folder."
-#error "Another way to disable the RGB_BUILTIN is to define it in the platformio.ini file, for instance: '-D ESP32_ARDUINO_NO_RGB_BUILTIN'"
 
 #else
 
diff --git a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino
index eada1c7ea6b..17e7af290bf 100644
--- a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino
+++ b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino
@@ -21,7 +21,7 @@
  *
  */
 
-#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
 // ESP32 C3 has only 2 channels for RX and 2 for TX, thus MAX RMT_MEM is 128
 #define RMT_TX_PIN 4
 #define RMT_RX_PIN 5
diff --git a/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino b/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino
index 3c9dbb9b12f..0104c6422f2 100644
--- a/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino
+++ b/libraries/ESP32/examples/ResetReason/ResetReason/ResetReason.ino
@@ -26,6 +26,8 @@
 #include "esp32c6/rom/rtc.h"
 #elif CONFIG_IDF_TARGET_ESP32H2
 #include "esp32h2/rom/rtc.h"
+#elif CONFIG_IDF_TARGET_ESP32P4
+#include "esp32p4/rom/rtc.h"
 #else
 #error Target CONFIG_IDF_TARGET is not supported
 #endif
diff --git a/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino b/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino
index eff21a1939e..3c5ff0ba6fc 100644
--- a/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino
+++ b/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino
@@ -11,7 +11,7 @@
  */
 
 // soc/soc_caps.h has information about each SoC target
-// in this example, we use SOC_UART_NUM that goes from 1 to 3,
+// in this example, we use SOC_UART_HP_NUM that goes from 1 to 3,
 // depending on the number of available UARTs in the ESP32xx
 // This makes the code transparent to what SoC is used.
 #include "soc/soc_caps.h"
@@ -24,9 +24,9 @@
 #define TXPIN     5  // GPIO 5 => TX for Serial1 or Serial2
 
 // declare testingSerial (as reference) related to TEST_UART number defined above (only for Serial1 and Serial2)
-#if SOC_UART_NUM > 1 && TEST_UART == 1
+#if SOC_UART_HP_NUM > 1 && TEST_UART == 1
 HardwareSerial &testingSerial = Serial1;
-#elif SOC_UART_NUM > 2 && TEST_UART == 2
+#elif SOC_UART_HP_NUM > 2 && TEST_UART == 2
 HardwareSerial &testingSerial = Serial2;
 #endif
 
@@ -36,11 +36,11 @@ void processOnReceiving(HardwareSerial &mySerial) {
   int8_t uart_num = -1;
   if (&mySerial == &Serial0) {
     uart_num = 0;
-#if SOC_UART_NUM > 1
+#if SOC_UART_HP_NUM > 1
   } else if (&mySerial == &Serial1) {
     uart_num = 1;
 #endif
-#if SOC_UART_NUM > 2
+#if SOC_UART_HP_NUM > 2
   } else if (&mySerial == &Serial2) {
     uart_num = 2;
 #endif
diff --git a/libraries/ESP32/examples/Template/ExampleTemplate/README.md b/libraries/ESP32/examples/Template/ExampleTemplate/README.md
index f5aa7b35e86..91b50967e9e 100644
--- a/libraries/ESP32/examples/Template/ExampleTemplate/README.md
+++ b/libraries/ESP32/examples/Template/ExampleTemplate/README.md
@@ -64,10 +64,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Example/Log Output ==(OPTIONAL)==
 
 ==*Add the log/serial output here!*==
diff --git a/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino b/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino
index 0f0880902fb..3b4e5f0b9e9 100644
--- a/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino
+++ b/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino
@@ -3,7 +3,12 @@ This is an example how to use Touch Intrrerupts
 The bigger the threshold, the more sensible is the touch
 */
 
+#if CONFIG_IDF_TARGET_ESP32P4
+int threshold = 0;  // when 0 is used, the benchmarked value will be used
+#else
 int threshold = 40;
+#endif
+
 bool touch1detected = false;
 bool touch2detected = false;
 
diff --git a/libraries/ESP32/keywords.txt b/libraries/ESP32/keywords.txt
index 6cfd3fcab4c..866e76babd8 100644
--- a/libraries/ESP32/keywords.txt
+++ b/libraries/ESP32/keywords.txt
@@ -6,12 +6,50 @@
 # Datatypes (KEYWORD1)
 #######################################
 
+Serial4	KEYWORD1
+espCtColor_t	KEYWORD1
+espXyColor_t	KEYWORD1
+espHsvColor_t	KEYWORD1
+espRgbColor_t	KEYWORD1
+
 #######################################
 # Methods and Functions (KEYWORD2)
 #######################################
 
+espXYToRgbColor	KEYWORD2
+espXYColorToRgb	KEYWORD2
+espRgbColorToXYColor	KEYWORD2
+espRgbToXYColor	KEYWORD2
+espHsvColorToRgbColor	KEYWORD2
+espHsvToRgbColor	KEYWORD2
+espCTColorToRgbColor	KEYWORD2
+espCTToRgbColor	KEYWORD2
+espRgbColorToHsvColor	KEYWORD2
+espRgbToHsvColor	KEYWORD2
+
 #######################################
 # Constants (LITERAL1)
 #######################################
 
 RGB_BUILTIN	LITERAL1
+HSV_BLACK	LITERAL1
+HSV_WHITE	LITERAL1
+HSV_RED	LITERAL1
+HSV_YELLOW	LITERAL1
+HSV_GREEN	LITERAL1
+HSV_CYAN	LITERAL1
+HSV_BLUE	LITERAL1
+HSV_MAGENTA	LITERAL1
+COOL_WHITE_COLOR_TEMPERATURE	LITERAL1
+DAYLIGHT_WHITE_COLOR_TEMPERATURE	LITERAL1
+WHITE_COLOR_TEMPERATURE	LITERAL1
+SOFT_WHITE_COLOR_TEMPERATURE	LITERAL1
+WARM_WHITE_COLOR_TEMPERATURE	LITERAL1
+RGB_BLACK	LITERAL1
+RGB_WHITE	LITERAL1
+RGB_RED	LITERAL1
+RGB_YELLOW	LITERAL1
+RGB_GREEN	LITERAL1
+RGB_CYAN	LITERAL1
+RGB_BLUE	LITERAL1
+RGB_MAGENTA	LITERAL1
diff --git a/libraries/ESP32/library.properties b/libraries/ESP32/library.properties
index 0f79f5cf010..1bb1ed21750 100644
--- a/libraries/ESP32/library.properties
+++ b/libraries/ESP32/library.properties
@@ -1,5 +1,5 @@
 name=ESP32
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov, Ivan Grokhtkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32 sketches examples
diff --git a/libraries/ESP_I2S/library.properties b/libraries/ESP_I2S/library.properties
index d165941af0f..807f7daeb9d 100644
--- a/libraries/ESP_I2S/library.properties
+++ b/libraries/ESP_I2S/library.properties
@@ -1,5 +1,5 @@
 name=ESP_I2S
-version=3.0.5
+version=3.1.0
 author=me-no-dev
 maintainer=me-no-dev
 sentence=Library for ESP I2S communication
diff --git a/libraries/ESP_I2S/src/ESP_I2S.cpp b/libraries/ESP_I2S/src/ESP_I2S.cpp
index 84050dfa6f8..0ac1e176dc8 100644
--- a/libraries/ESP_I2S/src/ESP_I2S.cpp
+++ b/libraries/ESP_I2S/src/ESP_I2S.cpp
@@ -7,12 +7,17 @@
 
 #include "esp32-hal-periman.h"
 #include "wav_header.h"
+#if ARDUINO_HAS_MP3_DECODER
 #include "mp3dec.h"
+#endif
 
 #define I2S_READ_CHUNK_SIZE 1920
 
-#define I2S_DEFAULT_CFG() \
-  { .id = I2S_NUM_AUTO, .role = I2S_ROLE_MASTER, .dma_desc_num = 6, .dma_frame_num = 240, .auto_clear = true, }
+#define I2S_DEFAULT_CFG()                                                                                                                    \
+  {                                                                                                                                          \
+    .id = I2S_NUM_AUTO, .role = I2S_ROLE_MASTER, .dma_desc_num = 6, .dma_frame_num = 240, .auto_clear = true, .auto_clear_before_cb = false, \
+    .intr_priority = 0                                                                                                                       \
+  }
 
 #define I2S_STD_CHAN_CFG(_sample_rate, _data_bit_width, _slot_mode)                                                                   \
   {                                                                                                                                   \
@@ -803,32 +808,36 @@ bool I2SClass::configureRX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slo
 
 size_t I2SClass::readBytes(char *buffer, size_t size) {
   size_t bytes_read = 0;
+  size_t bytes_to_read = 0;
   size_t total_size = 0;
   last_error = ESP_FAIL;
   if (rx_chan == NULL) {
     return total_size;
   }
   while (total_size < size) {
-    bytes_read = size - total_size;
-    if (rx_transform_buf != NULL && bytes_read > I2S_READ_CHUNK_SIZE) {
-      bytes_read = I2S_READ_CHUNK_SIZE;
+    bytes_read = 0;
+    bytes_to_read = size - total_size;
+    if (rx_transform_buf != NULL && bytes_to_read > I2S_READ_CHUNK_SIZE) {
+      bytes_to_read = I2S_READ_CHUNK_SIZE;
     }
-    I2S_ERROR_CHECK_RETURN(rx_fn(rx_chan, rx_transform_buf, (char *)(buffer + total_size), bytes_read, &bytes_read, _timeout), 0);
+    I2S_ERROR_CHECK_RETURN(rx_fn(rx_chan, rx_transform_buf, (char *)(buffer + total_size), bytes_to_read, &bytes_read, _timeout), 0);
     total_size += bytes_read;
   }
   return total_size;
 }
 
-size_t I2SClass::write(uint8_t *buffer, size_t size) {
+size_t I2SClass::write(const uint8_t *buffer, size_t size) {
   size_t written = 0;
   size_t bytes_sent = 0;
+  size_t bytes_to_send = 0;
   last_error = ESP_FAIL;
   if (tx_chan == NULL) {
     return written;
   }
   while (written < size) {
-    bytes_sent = size - written;
-    esp_err_t err = i2s_channel_write(tx_chan, (char *)(buffer + written), bytes_sent, &bytes_sent, _timeout);
+    bytes_sent = 0;
+    bytes_to_send = size - written;
+    esp_err_t err = i2s_channel_write(tx_chan, (char *)(buffer + written), bytes_to_send, &bytes_sent, _timeout);
     setWriteError(err);
     I2S_ERROR_CHECK_RETURN(err, written);
     written += bytes_sent;
@@ -1007,6 +1016,7 @@ void I2SClass::playWAV(uint8_t *data, size_t len) {
   write(data + WAVE_HEADER_SIZE + data_offset, data_chunk->subchunk_size);
 }
 
+#if ARDUINO_HAS_MP3_DECODER
 bool I2SClass::playMP3(uint8_t *src, size_t src_len) {
   int16_t outBuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP];
   uint8_t *readPtr = NULL;
@@ -1044,5 +1054,6 @@ bool I2SClass::playMP3(uint8_t *src, size_t src_len) {
   MP3FreeDecoder(decoder);
   return true;
 }
+#endif
 
 #endif /* SOC_I2S_SUPPORTED */
diff --git a/libraries/ESP_I2S/src/ESP_I2S.h b/libraries/ESP_I2S/src/ESP_I2S.h
index c83e3815ddb..b5c076bed04 100644
--- a/libraries/ESP_I2S/src/ESP_I2S.h
+++ b/libraries/ESP_I2S/src/ESP_I2S.h
@@ -1,5 +1,9 @@
 #pragma once
 
+#if defined __has_include && __has_include("mp3dec.h")
+#define ARDUINO_HAS_MP3_DECODER 1
+#endif
+
 #include "soc/soc_caps.h"
 #if SOC_I2S_SUPPORTED
 
@@ -62,7 +66,7 @@ class I2SClass : public Stream {
   bool end();
 
   size_t readBytes(char *buffer, size_t size);
-  size_t write(uint8_t *buffer, size_t size);
+  size_t write(const uint8_t *buffer, size_t size);
 
   i2s_chan_handle_t txChan();
   uint32_t txSampleRate();
@@ -85,8 +89,10 @@ class I2SClass : public Stream {
   uint8_t *recordWAV(size_t rec_seconds, size_t *out_size);
   // Play short PCM WAV from memory
   void playWAV(uint8_t *data, size_t len);
+#if ARDUINO_HAS_MP3_DECODER
   // Play short MP3 from memory
   bool playMP3(uint8_t *src, size_t src_len);
+#endif
 
 private:
   esp_err_t last_error;
diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json
index 618e46bd244..36babb82730 100644
--- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json
+++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ci.json
@@ -1,6 +1,5 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json
index 618e46bd244..36babb82730 100644
--- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json
+++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ci.json
@@ -1,6 +1,5 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json
index 618e46bd244..36babb82730 100644
--- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json
+++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ci.json
@@ -1,6 +1,5 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json
index 618e46bd244..36babb82730 100644
--- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json
+++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ci.json
@@ -1,6 +1,5 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/ESP_NOW/library.properties b/libraries/ESP_NOW/library.properties
index 262454bb069..42876f47f95 100644
--- a/libraries/ESP_NOW/library.properties
+++ b/libraries/ESP_NOW/library.properties
@@ -1,5 +1,5 @@
 name=ESP_NOW
-version=3.0.5
+version=3.1.0
 author=me-no-dev
 maintainer=P-R-O-C-H-Y
 sentence=Library for ESP_NOW
diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp
index 69b8ddd96a5..6fd3ff0a0b1 100644
--- a/libraries/ESP_NOW/src/ESP32_NOW.cpp
+++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp
@@ -1,3 +1,8 @@
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support"
+#else
+
 #include "ESP32_NOW.h"
 #include <string.h>
 #include "esp_system.h"
@@ -406,3 +411,5 @@ size_t ESP_NOW_Peer::send(const uint8_t *data, int len) {
 ESP_NOW_Peer::operator bool() const {
   return added;
 }
+
+#endif
diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h
index 1bbcabb2557..efba9243aee 100644
--- a/libraries/ESP_NOW/src/ESP32_NOW.h
+++ b/libraries/ESP_NOW/src/ESP32_NOW.h
@@ -1,5 +1,10 @@
 #pragma once
 
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support"
+#else
+
 #include "esp_wifi_types.h"
 #include "Print.h"
 #include "esp_now.h"
@@ -77,3 +82,5 @@ class ESP_NOW_Peer {
 };
 
 extern ESP_NOW_Class ESP_NOW;
+
+#endif
diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp
index 17740d1331a..5603da2ba13 100644
--- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp
+++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp
@@ -1,3 +1,8 @@
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support"
+#else
+
 #include "ESP32_NOW_Serial.h"
 #include <string.h>
 #include "esp_now.h"
@@ -277,3 +282,5 @@ void ESP_NOW_Serial_Class::onSent(bool success) {
     }
   }
 }
+
+#endif
diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.h b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h
index b1f41456320..7cc43d85ef8 100644
--- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.h
+++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h
@@ -1,5 +1,10 @@
 #pragma once
 
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#warning "ESP-NOW is only supported in SoCs with native Wi-Fi support"
+#else
+
 #include "esp_wifi_types.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
@@ -48,3 +53,5 @@ class ESP_NOW_Serial_Class : public Stream, public ESP_NOW_Peer {
   void onReceive(const uint8_t *data, size_t len, bool broadcast);
   void onSent(bool success);
 };
+
+#endif
diff --git a/libraries/ESP_SR/examples/Basic/ci.json b/libraries/ESP_SR/examples/Basic/ci.json
index c9b0955f8f2..c395378f45e 100644
--- a/libraries/ESP_SR/examples/Basic/ci.json
+++ b/libraries/ESP_SR/examples/Basic/ci.json
@@ -12,6 +12,7 @@
     "esp32c3": false,
     "esp32c6": false,
     "esp32h2": false,
+    "esp32p4": false,
     "esp32s2": false
   }
 }
diff --git a/libraries/ESP_SR/library.properties b/libraries/ESP_SR/library.properties
index 6f0d447d29b..a81cff2fe9d 100644
--- a/libraries/ESP_SR/library.properties
+++ b/libraries/ESP_SR/library.properties
@@ -1,5 +1,5 @@
 name=ESP_SR
-version=3.0.5
+version=3.1.0
 author=me-no-dev
 maintainer=me-no-dev
 sentence=Library for ESP Sound Recognition
diff --git a/libraries/ESPmDNS/library.properties b/libraries/ESPmDNS/library.properties
index 32a2fe24695..4f65114fd0b 100644
--- a/libraries/ESPmDNS/library.properties
+++ b/libraries/ESPmDNS/library.properties
@@ -1,5 +1,5 @@
 name=ESPmDNS
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov, Ivan Grokhtkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32 mDNS Library
diff --git a/libraries/ESPmDNS/src/ESPmDNS.cpp b/libraries/ESPmDNS/src/ESPmDNS.cpp
index 546de43c20a..4c15ed3a5dd 100644
--- a/libraries/ESPmDNS/src/ESPmDNS.cpp
+++ b/libraries/ESPmDNS/src/ESPmDNS.cpp
@@ -39,6 +39,7 @@ License (MIT license):
 #endif
 
 #include "ESPmDNS.h"
+#ifdef CONFIG_MDNS_MAX_INTERFACES
 #include <functional>
 #include "esp_mac.h"
 #include "soc/soc_caps.h"
@@ -391,3 +392,5 @@ String MDNSResponder::txtKey(int idx, int txtIdx) {
 }
 
 MDNSResponder MDNS;
+
+#endif /* CONFIG_MDNS_MAX_INTERFACES */
diff --git a/libraries/ESPmDNS/src/ESPmDNS.h b/libraries/ESPmDNS/src/ESPmDNS.h
index 04ac382cfdc..0336f476efe 100644
--- a/libraries/ESPmDNS/src/ESPmDNS.h
+++ b/libraries/ESPmDNS/src/ESPmDNS.h
@@ -41,6 +41,9 @@ License (MIT license):
 #ifndef ESP32MDNS_H
 #define ESP32MDNS_H
 
+#include "sdkconfig.h"
+#ifdef CONFIG_MDNS_MAX_INTERFACES
+
 #include "Arduino.h"
 #include "mdns.h"
 #include "esp_interface.h"
@@ -125,4 +128,5 @@ class MDNSResponder {
 
 extern MDNSResponder MDNS;
 
+#endif  /* CONFIG_MDNS_MAX_INTERFACES */
 #endif  //ESP32MDNS_H
diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino
index 1453df63434..59a32750bf6 100644
--- a/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino
+++ b/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino
@@ -5,13 +5,21 @@
 
 // Important to be defined BEFORE including ETH.h for ETH.begin() to work.
 // Example RMII LAN8720 (Olimex, etc.)
-#ifndef ETH_PHY_TYPE
-#define ETH_PHY_TYPE  ETH_PHY_LAN8720
+#ifndef ETH_PHY_MDC
+#define ETH_PHY_TYPE ETH_PHY_LAN8720
+#if CONFIG_IDF_TARGET_ESP32
 #define ETH_PHY_ADDR  0
 #define ETH_PHY_MDC   23
 #define ETH_PHY_MDIO  18
 #define ETH_PHY_POWER -1
 #define ETH_CLK_MODE  ETH_CLOCK_GPIO0_IN
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define ETH_PHY_ADDR  0
+#define ETH_PHY_MDC   31
+#define ETH_PHY_MDIO  52
+#define ETH_PHY_POWER 51
+#define ETH_CLK_MODE  EMAC_CLK_EXT_IN
+#endif
 #endif
 
 #include <ETH.h>
diff --git a/libraries/Ethernet/examples/ETH_LAN8720/ci.json b/libraries/Ethernet/examples/ETH_LAN8720/ci.json
index dcdfd06db51..0eab13b8841 100644
--- a/libraries/Ethernet/examples/ETH_LAN8720/ci.json
+++ b/libraries/Ethernet/examples/ETH_LAN8720/ci.json
@@ -1,5 +1,8 @@
 {
   "requires": [
     "CONFIG_ETH_USE_ESP32_EMAC=y"
-  ]
+  ],
+  "targets": {
+    "esp32p4": false
+  }
 }
diff --git a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino
index 3252cd120f4..242281c3997 100644
--- a/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino
+++ b/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino
@@ -5,13 +5,21 @@
 
 #include <ETH.h>
 
-#ifndef ETH_PHY_TYPE
-#define ETH_PHY_TYPE  ETH_PHY_TLK110
+#ifndef ETH_PHY_MDC
+#define ETH_PHY_TYPE ETH_PHY_TLK110
+#if CONFIG_IDF_TARGET_ESP32
 #define ETH_PHY_ADDR  31
 #define ETH_PHY_MDC   23
 #define ETH_PHY_MDIO  18
 #define ETH_PHY_POWER 17
 #define ETH_CLK_MODE  ETH_CLOCK_GPIO0_IN
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define ETH_PHY_ADDR  1
+#define ETH_PHY_MDC   31
+#define ETH_PHY_MDIO  52
+#define ETH_PHY_POWER 51
+#define ETH_CLK_MODE  EMAC_CLK_EXT_IN
+#endif
 #endif
 
 static bool eth_connected = false;
diff --git a/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino b/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino
index d4bc78a1c07..d5d57333a55 100644
--- a/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino
+++ b/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino
@@ -9,7 +9,7 @@
 // Set this to 1 to enable dual Ethernet support
 #define USE_TWO_ETH_PORTS 0
 
-#ifndef ETH_PHY_TYPE
+#ifndef ETH_PHY_CS
 #define ETH_PHY_TYPE ETH_PHY_W5500
 #define ETH_PHY_ADDR 1
 #define ETH_PHY_CS   15
@@ -24,7 +24,7 @@
 
 #if USE_TWO_ETH_PORTS
 // Second port on shared SPI bus
-#ifndef ETH1_PHY_TYPE
+#ifndef ETH1_PHY_CS
 #define ETH1_PHY_TYPE ETH_PHY_W5500
 #define ETH1_PHY_ADDR 1
 #define ETH1_PHY_CS   32
diff --git a/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino b/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino
index 512bb78ff5e..dad54a745b7 100644
--- a/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino
+++ b/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino
@@ -8,7 +8,7 @@
 // Set this to 1 to enable dual Ethernet support
 #define USE_TWO_ETH_PORTS 0
 
-#ifndef ETH_PHY_TYPE
+#ifndef ETH_PHY_CS
 #define ETH_PHY_TYPE     ETH_PHY_W5500
 #define ETH_PHY_ADDR     1
 #define ETH_PHY_CS       15
@@ -22,7 +22,7 @@
 
 #if USE_TWO_ETH_PORTS
 // Second port on shared SPI bus
-#ifndef ETH1_PHY_TYPE
+#ifndef ETH1_PHY_CS
 #define ETH1_PHY_TYPE ETH_PHY_W5500
 #define ETH1_PHY_ADDR 1
 #define ETH1_PHY_CS   32
diff --git a/libraries/Ethernet/library.properties b/libraries/Ethernet/library.properties
index ea92455fe37..70aa24ec4aa 100644
--- a/libraries/Ethernet/library.properties
+++ b/libraries/Ethernet/library.properties
@@ -1,5 +1,5 @@
 name=Ethernet
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Enables network connection (local and Internet) using the ESP32 Ethernet.
diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp
index 4d215d80034..9ba849c0dc8 100644
--- a/libraries/Ethernet/src/ETH.cpp
+++ b/libraries/Ethernet/src/ETH.cpp
@@ -22,6 +22,7 @@
 #define ARDUINO_CORE_BUILD
 
 #include "ETH.h"
+#if CONFIG_ETH_ENABLED
 #include "esp_system.h"
 #include "esp_event.h"
 #include "esp_eth.h"
@@ -30,7 +31,9 @@
 #include "driver/gpio.h"
 #include "driver/spi_master.h"
 #if CONFIG_ETH_USE_ESP32_EMAC
+#if defined __has_include && __has_include("soc/emac_ext_struct.h")
 #include "soc/emac_ext_struct.h"
+#endif /* __has_include("soc/emac_ext_struct.h" */
 #include "soc/rtc.h"
 #endif /* CONFIG_ETH_USE_ESP32_EMAC */
 #include "esp32-hal-periman.h"
@@ -72,6 +75,7 @@ static void onEthConnected(arduino_event_id_t event, arduino_event_info_t info)
       log_e("Could not find ETH interface with that handle!");
       return;
     }
+#if CONFIG_LWIP_IPV6
     if (_ethernets[index]->getStatusBits() & ESP_NETIF_WANT_IP6_BIT) {
       esp_err_t err = esp_netif_create_ip6_linklocal(_ethernets[index]->netif());
       if (err != ESP_OK) {
@@ -80,6 +84,7 @@ static void onEthConnected(arduino_event_id_t event, arduino_event_info_t info)
         log_v("Enabled IPv6 Link Local on %s", _ethernets[index]->desc());
       }
     }
+#endif
   }
 }
 
@@ -147,6 +152,42 @@ void ETHClass::setTaskStackSize(size_t size) {
 }
 
 #if CONFIG_ETH_USE_ESP32_EMAC
+#if CONFIG_IDF_TARGET_ESP32
+#define ETH_EMAC_DEFAULT_CONFIG() ETH_ESP32_EMAC_DEFAULT_CONFIG()
+#elif CONFIG_IDF_TARGET_ESP32P4
+// clang-format off
+#define ETH_EMAC_DEFAULT_CONFIG()                                                  \
+  {                                                                                \
+    .smi_gpio = {.mdc_num = 31, .mdio_num = 52},                                   \
+    .interface = EMAC_DATA_INTERFACE_RMII,                                         \
+    .clock_config = {                                                              \
+      .rmii = {                                                                    \
+        .clock_mode = EMAC_CLK_EXT_IN,                                             \
+        .clock_gpio = (emac_rmii_clock_gpio_t)ETH_RMII_CLK                         \
+      }                                                                            \
+    },                                                                             \
+    .dma_burst_len = ETH_DMA_BURST_LEN_32,                                         \
+    .intr_priority = 0,                                                            \
+    .emac_dataif_gpio = {                                                          \
+      .rmii = {                                                                    \
+        .tx_en_num = ETH_RMII_TX_EN,                                               \
+        .txd0_num = ETH_RMII_TX0,                                                  \
+        .txd1_num = ETH_RMII_TX1,                                                  \
+        .crs_dv_num = ETH_RMII_CRS_DV,                                             \
+        .rxd0_num = ETH_RMII_RX0,                                                  \
+        .rxd1_num = ETH_RMII_RX1_EN                                                \
+      }                                                                            \
+    },                                                                             \
+    .clock_config_out_in = {                                                       \
+      .rmii = {                                                                    \
+        .clock_mode = EMAC_CLK_EXT_IN,                                             \
+        .clock_gpio = (emac_rmii_clock_gpio_t) - 1                                 \
+      }                                                                            \
+    },                                                                             \
+  }
+#endif
+// clang-format on
+
 bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clock_mode) {
   esp_err_t ret = ESP_OK;
   if (_eth_index > 2) {
@@ -170,14 +211,23 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i
   Network.begin();
   _ethernets[_eth_index] = this;
 
-  eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
+#if CONFIG_IDF_TARGET_ESP32
+#undef DEFAULT_RMII_CLK_GPIO
+#define DEFAULT_RMII_CLK_GPIO (emac_rmii_clock_gpio_t)(0)
+#endif
+
+  eth_esp32_emac_config_t mac_config = ETH_EMAC_DEFAULT_CONFIG();
+#if CONFIG_IDF_TARGET_ESP32
   mac_config.clock_config.rmii.clock_mode = (clock_mode) ? EMAC_CLK_OUT : EMAC_CLK_EXT_IN;
   mac_config.clock_config.rmii.clock_gpio = (1 == clock_mode)   ? EMAC_APPL_CLK_OUT_GPIO
                                             : (2 == clock_mode) ? EMAC_CLK_OUT_GPIO
                                             : (3 == clock_mode) ? EMAC_CLK_OUT_180_GPIO
                                                                 : EMAC_CLK_IN_GPIO;
-  mac_config.smi_mdc_gpio_num = digitalPinToGPIONumber(mdc);
-  mac_config.smi_mdio_gpio_num = digitalPinToGPIONumber(mdio);
+#elif CONFIG_IDF_TARGET_ESP32P4
+  mac_config.clock_config.rmii.clock_mode = (emac_rmii_clock_mode_t)clock_mode;
+#endif
+  mac_config.smi_gpio.mdc_num = digitalPinToGPIONumber(mdc);
+  mac_config.smi_gpio.mdio_num = digitalPinToGPIONumber(mdio);
 
   _pin_mcd = digitalPinToGPIONumber(mdc);
   _pin_mdio = digitalPinToGPIONumber(mdio);
@@ -237,6 +287,7 @@ bool ETHClass::begin(eth_phy_type_t type, int32_t phy_addr, int mdc, int mdio, i
     case ETH_PHY_TLK110:  phy = esp_eth_phy_new_ip101(&phy_config); break;
     case ETH_PHY_RTL8201: phy = esp_eth_phy_new_rtl8201(&phy_config); break;
     case ETH_PHY_DP83848: phy = esp_eth_phy_new_dp83848(&phy_config); break;
+    case ETH_PHY_JL1101:  phy = esp_eth_phy_new_jl1101(&phy_config); break;
     case ETH_PHY_KSZ8041: phy = esp_eth_phy_new_ksz80xx(&phy_config); break;
     case ETH_PHY_KSZ8081: phy = esp_eth_phy_new_ksz80xx(&phy_config); break;
     default:              log_e("Unsupported PHY %d", type); break;
@@ -893,7 +944,7 @@ void ETHClass::end(void) {
 #if ETH_SPI_SUPPORTS_CUSTOM
   _spi = NULL;
 #endif
-#if CONFIG_ETH_USE_ESP32_EMAC
+#if (CONFIG_ETH_USE_ESP32_EMAC && !defined(CONFIG_IDF_TARGET_ESP32P4))
   perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_RMII, empty_ethDetachBus);
   perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_CLK, empty_ethDetachBus);
   perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET_MCD, empty_ethDetachBus);
@@ -1007,3 +1058,5 @@ size_t ETHClass::printDriverInfo(Print &out) const {
 }
 
 ETHClass ETH;
+
+#endif /* CONFIG_ETH_ENABLED */
diff --git a/libraries/Ethernet/src/ETH.h b/libraries/Ethernet/src/ETH.h
index 14d2d042614..476c4a7b09c 100644
--- a/libraries/Ethernet/src/ETH.h
+++ b/libraries/Ethernet/src/ETH.h
@@ -18,6 +18,9 @@
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include "sdkconfig.h"
+#if CONFIG_ETH_ENABLED
+
 #ifndef _ETH_H_
 #define _ETH_H_
 
@@ -75,6 +78,7 @@
 
 #if CONFIG_ETH_USE_ESP32_EMAC
 #define ETH_PHY_IP101 ETH_PHY_TLK110
+#if CONFIG_IDF_TARGET_ESP32
 typedef enum {
   ETH_CLOCK_GPIO0_IN,
   ETH_CLOCK_GPIO0_OUT,
@@ -88,6 +92,31 @@ typedef enum {
 #define ETH_RMII_RX0    25
 #define ETH_RMII_RX1_EN 26
 #define ETH_RMII_CRS_DV 27
+#elif CONFIG_IDF_TARGET_ESP32P4
+typedef emac_rmii_clock_mode_t eth_clock_mode_t;
+#include "pins_arduino.h"
+#ifndef ETH_RMII_TX_EN
+#define ETH_RMII_TX_EN 49
+#endif
+#ifndef ETH_RMII_TX0
+#define ETH_RMII_TX0 34
+#endif
+#ifndef ETH_RMII_TX1
+#define ETH_RMII_TX1 35
+#endif
+#ifndef ETH_RMII_RX0
+#define ETH_RMII_RX0 29
+#endif
+#ifndef ETH_RMII_RX1_EN
+#define ETH_RMII_RX1_EN 30
+#endif
+#ifndef ETH_RMII_CRS_DV
+#define ETH_RMII_CRS_DV 28
+#endif
+#ifndef ETH_RMII_CLK
+#define ETH_RMII_CLK 50
+#endif
+#endif
 #endif /* CONFIG_ETH_USE_ESP32_EMAC */
 
 #ifndef ETH_PHY_SPI_FREQ_MHZ
@@ -101,6 +130,7 @@ typedef enum {
   ETH_PHY_LAN8720,
   ETH_PHY_TLK110,
   ETH_PHY_RTL8201,
+  ETH_PHY_JL1101,
   ETH_PHY_DP83848,
   ETH_PHY_KSZ8041,
   ETH_PHY_KSZ8081,
@@ -223,3 +253,4 @@ class ETHClass : public NetworkInterface {
 extern ETHClass ETH;
 
 #endif /* _ETH_H_ */
+#endif /* CONFIG_ETH_ENABLED */
diff --git a/libraries/FFat/library.properties b/libraries/FFat/library.properties
index e01f1e2f2a7..dae11e43aaf 100644
--- a/libraries/FFat/library.properties
+++ b/libraries/FFat/library.properties
@@ -1,5 +1,5 @@
 name=FFat
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov, Ivan Grokhtkov, Larry Bernstone
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32 FAT on Flash File System
diff --git a/libraries/FFat/src/FFat.cpp b/libraries/FFat/src/FFat.cpp
index 506cc70be46..4a2274b2fdb 100644
--- a/libraries/FFat/src/FFat.cpp
+++ b/libraries/FFat/src/FFat.cpp
@@ -46,7 +46,11 @@ bool F_Fat::begin(bool formatOnFail, const char *basePath, uint8_t maxOpenFiles,
   }
 
   esp_vfs_fat_mount_config_t conf = {
-    .format_if_mount_failed = formatOnFail, .max_files = maxOpenFiles, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false
+    .format_if_mount_failed = formatOnFail,
+    .max_files = maxOpenFiles,
+    .allocation_unit_size = CONFIG_WL_SECTOR_SIZE,
+    .disk_status_check_enable = false,
+    .use_one_fat = false
   };
   esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(basePath, partitionLabel, &conf, &_wl_handle);
   if (err) {
@@ -98,7 +102,7 @@ bool F_Fat::format(bool full_wipe, char *partitionLabel) {
   }
   // Now do a mount with format_if_fail (which it will)
   esp_vfs_fat_mount_config_t conf = {
-    .format_if_mount_failed = true, .max_files = 1, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false
+    .format_if_mount_failed = true, .max_files = 1, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, .use_one_fat = false
   };
   result = esp_vfs_fat_spiflash_mount_rw_wl("/format_ffat", partitionLabel, &conf, &temp_handle);
   esp_vfs_fat_spiflash_unmount_rw_wl("/format_ffat", temp_handle);
diff --git a/libraries/FS/library.properties b/libraries/FS/library.properties
index 9bdcdb83573..009383ab0c8 100644
--- a/libraries/FS/library.properties
+++ b/libraries/FS/library.properties
@@ -1,5 +1,5 @@
 name=FS
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov, Ivan Grokhtkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32 File System
diff --git a/libraries/FS/src/vfs_api.cpp b/libraries/FS/src/vfs_api.cpp
index 616f37ac611..a57067c1bbb 100644
--- a/libraries/FS/src/vfs_api.cpp
+++ b/libraries/FS/src/vfs_api.cpp
@@ -96,7 +96,6 @@ FileImplPtr VFSImpl::open(const char *fpath, const char *mode, const bool create
     return std::make_shared<VFSFileImpl>(this, fpath, mode);
   }
 
-  log_e("%s does not exist, no permits for creation", temp);
   free(temp);
   return FileImplPtr();
 }
diff --git a/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino b/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino
index 7f1d1dd3575..d8b66ac19d9 100644
--- a/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino
+++ b/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino
@@ -3,6 +3,12 @@
 /*|TESTED BOARDS: Devkit v1 DOIT, Devkitc v4                 |*/
 /*|CORE: June 2018                                           |*/
 /*|----------------------------------------------------------|*/
+
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#error "WPA-Enterprise is only supported in SoCs with native Wi-Fi support"
+#endif
+
 #include <WiFi.h>
 #include <HTTPClient.h>
 #if __has_include("esp_eap_client.h")
diff --git a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json
index 618e46bd244..04eb62b977a 100644
--- a/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json
+++ b/libraries/HTTPClient/examples/HTTPClientEnterprise/ci.json
@@ -1,6 +1,6 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "fqbn_append": "PartitionScheme=huge_app",
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/HTTPClient/library.properties b/libraries/HTTPClient/library.properties
index 2c1e160efee..203b8929d30 100644
--- a/libraries/HTTPClient/library.properties
+++ b/libraries/HTTPClient/library.properties
@@ -1,5 +1,5 @@
 name=HTTPClient
-version=3.0.5
+version=3.1.0
 author=Markus Sattler
 maintainer=Markus Sattler
 sentence=HTTP Client for ESP32
diff --git a/libraries/HTTPClient/src/HTTPClient.h b/libraries/HTTPClient/src/HTTPClient.h
index 80f6da28599..20d07c723ed 100644
--- a/libraries/HTTPClient/src/HTTPClient.h
+++ b/libraries/HTTPClient/src/HTTPClient.h
@@ -31,6 +31,10 @@
 #define HTTPCLIENT_1_1_COMPATIBLE
 #endif
 
+#ifndef HTTPCLIENT_NOSECURE
+#define HTTPCLIENT_NOSECURE
+#endif
+
 #include <memory>
 #include <Arduino.h>
 #include <NetworkClient.h>
diff --git a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json
index 618e46bd244..cbdd28f773d 100644
--- a/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json
+++ b/libraries/HTTPUpdate/examples/httpUpdateSecure/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires_any": [
     "CONFIG_SOC_WIFI_SUPPORTED=y",
     "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
diff --git a/libraries/HTTPUpdate/library.properties b/libraries/HTTPUpdate/library.properties
index aca3f392795..ac903dd71cf 100644
--- a/libraries/HTTPUpdate/library.properties
+++ b/libraries/HTTPUpdate/library.properties
@@ -1,5 +1,5 @@
 name=HTTPUpdate
-version=3.0.5
+version=3.1.0
 author=Markus Sattler
 maintainer=Markus Sattler
 sentence=Http Update for ESP32
diff --git a/libraries/HTTPUpdateServer/library.properties b/libraries/HTTPUpdateServer/library.properties
index 03f6b299bf9..b26bd2cad7b 100644
--- a/libraries/HTTPUpdateServer/library.properties
+++ b/libraries/HTTPUpdateServer/library.properties
@@ -1,5 +1,5 @@
 name=HTTPUpdateServer
-version=3.0.5
+version=3.1.0
 author=Hristo Kapanakov
 maintainer=
 sentence=Simple HTTP Update server based on the WebServer
diff --git a/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino b/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino
index 52019a703b7..7102dfb19af 100644
--- a/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino
+++ b/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino
@@ -36,6 +36,7 @@ static void smoke_test() {
         Insights.event(TAG, "[count][%d]", count);
       } else {
         log_e("[count][%d] [crash_count][%" PRIu32 "] [excvaddr][0x0f] Crashing...", count, s_reset_count);
+        //ToDo: find better way to crash
         abort();
       }
     }
diff --git a/libraries/Insights/library.properties b/libraries/Insights/library.properties
index a948dbe7ad1..af213a1e70d 100644
--- a/libraries/Insights/library.properties
+++ b/libraries/Insights/library.properties
@@ -1,5 +1,5 @@
 name=ESP Insights
-version=3.0.5
+version=3.1.0
 author=Sanket Wadekar <sanket.wadekar@espressif.com>
 maintainer=Sanket Wadekar <sanket.wadekar@espressif.com>
 sentence=ESP Insights
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/.gitignore b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/.gitignore
deleted file mode 100644
index 653e92272d5..00000000000
--- a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.pio
-.vscode
-mklittlefs.exe
-mklittlefs
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/README.md b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/README.md
deleted file mode 100644
index beed34e92f1..00000000000
--- a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/README.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# How to run on PlatformIO IDE
-
-- Download and extract to this project root a **mklittlefs** executable for your OS [from a zipped binary here](https://github.com/earlephilhower/mklittlefs/releases)
-- Open **LITTLEFS_PlatformIO** folder
-- Run PlatformIO project task: **Upload Filesystem Image**
-- Run PlatformIO project task: **Upload and Monitor**
-- You will see a Serial output like:
-```
---- Miniterm on COM5  115200,8,N,1 ---
---- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
-ets Jun  8 2016 00:22:57
-
-rst:0x1 (POWERON_RESET),boot:0x13 (Snfigsip: 0, SPIWP:0xee
-clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
-mode:DIO, clock div:2
-load:0x3fff0018,len:4
-load:0x3fff001c,len:1044
-load:0x40078000,len:10044
-load:0x40080400,len:5872
-entry 0x400806ac
-Listing directory: /
-  FILE: /file1.txt  SIZE: 3  LAST WRITE: 2020-10-06 15:10:33
-  DIR : /testfolder  LAST WRITE: 2020-10-06 15:10:33
-Creating Dir: /mydir
-Dir created
-Writing file: /mydir/hello2.txt
-- file written
-Listing directory: /
-  FILE: /file1.txt  SIZE: 3  LAST WRITE: 2020-10-06 15:10:33
-  DIR : /mydir  LAST WRITE: 1970-01-01 00:00:00
-Listing directory: /mydir
-  FILE: /mydir/hello2.txt  SIZE: 6  LAST WRITE: 1970-01-01 00:00:00
-  DIR : /testfolder  LAST WRITE: 2020-10-06 15:10:33
-Listing directory: /testfolder
-  FILE: /testfolder/test2.txt  SIZE: 3  LAST WRITE: 2020-10-06 15:10:33
-Deleting file: /mydir/hello2.txt
-- file deleted
-Removing Dir: /mydir
-Dir removed
-Listing directory: /
-  FILE: /file1.txt  SIZE: 3  LAST WRITE: 2020-10-06 15:10:33
-  DIR : /testfolder  LAST WRITE: 2020-10-06 15:10:33
-Listing directory: /testfolder
-  FILE: /testfolder/test2.txt  SIZE: 3  LAST WRITE: 2020-10-06 15:10:33
-Writing file: /hello.txt
-- file written
-Appending to file: /hello.txt
-- message appended
-Reading file: /hello.txt
-- read from file:
-Hello World!
-Renaming file /hello.txt to /foo.txt
-- file renamed
-Reading file: /foo.txt
-- read from file:
-Hello World!
-Deleting file: /foo.txt
-- file deleted
-Testing file I/O with /test.txt
-- writing................................................................
- - 1048576 bytes written in 12006 ms
-- reading................................................................
-- 1048576 bytes read in 547 ms
-Deleting file: /test.txt
-- file deleted
-Test complete
-```
-- If you have a module with more than 4 MB flash, you can uncomment **partitions_custom.csv** in **platformio.ini** and modify the csv file accordingly
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/file1.txt b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/file1.txt
deleted file mode 100644
index 72943a16fb2..00000000000
--- a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/file1.txt
+++ /dev/null
@@ -1 +0,0 @@
-aaa
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt
deleted file mode 100644
index f761ec192d9..00000000000
--- a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt
+++ /dev/null
@@ -1 +0,0 @@
-bbb
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv
deleted file mode 100644
index 97846fa59bb..00000000000
--- a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv
+++ /dev/null
@@ -1,6 +0,0 @@
-# Name,   Type, SubType,  Offset,   Size,  Flags
-ota_0,     app, ota_0,   0x10000,  0x1A0000,
-ota_1,     app, ota_1,          ,  0x1A0000,
-otadata,  data, ota,    0x350000,  0x2000,
-nvs,      data, nvs,            ,  0x6000,
-data,     data, spiffs,         ,  0xA8000,
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/platformio.ini b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/platformio.ini
deleted file mode 100644
index dce1ac84456..00000000000
--- a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/platformio.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-; PlatformIO Project Configuration File
-;
-;   Build options: build flags, source filter
-;   Upload options: custom upload port, speed and extra flags
-;   Library options: dependencies, extra library storages
-;   Advanced options: extra scripting
-;
-; Please visit documentation for the other options and examples
-; https://docs.platformio.org/page/projectconf.html
-
-[platformio]
-default_envs = esp32
-
-[env]
-framework = arduino
-
-[env:esp32]
-platform = espressif32
-board = esp32dev
-board_build.partitions = partitions_custom.csv
-monitor_filters = esp32_exception_decoder
-monitor_speed = 115200
diff --git a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/src/main.cpp b/libraries/LittleFS/examples/LITTLEFS_PlatformIO/src/main.cpp
deleted file mode 100644
index 5ae9e8d7dfc..00000000000
--- a/libraries/LittleFS/examples/LITTLEFS_PlatformIO/src/main.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-#include <Arduino.h>
-#include "FS.h"
-#include <LittleFS.h>
-#include <time.h>
-
-/* You only need to format LittleFS the first time you run a
-   test or else use the LITTLEFS plugin to create a partition
-   https://github.com/lorol/arduino-esp32littlefs-plugin */
-
-#define FORMAT_LITTLEFS_IF_FAILED true
-
-void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
-  Serial.printf("Listing directory: %s\r\n", dirname);
-
-  File root = fs.open(dirname);
-  if (!root) {
-    Serial.println("- failed to open directory");
-    return;
-  }
-  if (!root.isDirectory()) {
-    Serial.println(" - not a directory");
-    return;
-  }
-
-  File file = root.openNextFile();
-  while (file) {
-    if (file.isDirectory()) {
-      Serial.print("  DIR : ");
-
-      Serial.print(file.name());
-      time_t t = file.getLastWrite();
-      struct tm *tmstruct = localtime(&t);
-      Serial.printf(
-        "  LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour,
-        tmstruct->tm_min, tmstruct->tm_sec
-      );
-
-      if (levels) {
-        listDir(fs, file.name(), levels - 1);
-      }
-    } else {
-      Serial.print("  FILE: ");
-      Serial.print(file.name());
-      Serial.print("  SIZE: ");
-
-      Serial.print(file.size());
-      time_t t = file.getLastWrite();
-      struct tm *tmstruct = localtime(&t);
-      Serial.printf(
-        "  LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour,
-        tmstruct->tm_min, tmstruct->tm_sec
-      );
-    }
-    file = root.openNextFile();
-  }
-}
-
-void createDir(fs::FS &fs, const char *path) {
-  Serial.printf("Creating Dir: %s\n", path);
-  if (fs.mkdir(path)) {
-    Serial.println("Dir created");
-  } else {
-    Serial.println("mkdir failed");
-  }
-}
-
-void removeDir(fs::FS &fs, const char *path) {
-  Serial.printf("Removing Dir: %s\n", path);
-  if (fs.rmdir(path)) {
-    Serial.println("Dir removed");
-  } else {
-    Serial.println("rmdir failed");
-  }
-}
-
-void readFile(fs::FS &fs, const char *path) {
-  Serial.printf("Reading file: %s\r\n", path);
-
-  File file = fs.open(path);
-  if (!file || file.isDirectory()) {
-    Serial.println("- failed to open file for reading");
-    return;
-  }
-
-  Serial.println("- read from file:");
-  while (file.available()) {
-    Serial.write(file.read());
-  }
-  file.close();
-}
-
-void writeFile(fs::FS &fs, const char *path, const char *message) {
-  Serial.printf("Writing file: %s\r\n", path);
-
-  File file = fs.open(path, FILE_WRITE);
-  if (!file) {
-    Serial.println("- failed to open file for writing");
-    return;
-  }
-  if (file.print(message)) {
-    Serial.println("- file written");
-  } else {
-    Serial.println("- write failed");
-  }
-  file.close();
-}
-
-void appendFile(fs::FS &fs, const char *path, const char *message) {
-  Serial.printf("Appending to file: %s\r\n", path);
-
-  File file = fs.open(path, FILE_APPEND);
-  if (!file) {
-    Serial.println("- failed to open file for appending");
-    return;
-  }
-  if (file.print(message)) {
-    Serial.println("- message appended");
-  } else {
-    Serial.println("- append failed");
-  }
-  file.close();
-}
-
-void renameFile(fs::FS &fs, const char *path1, const char *path2) {
-  Serial.printf("Renaming file %s to %s\r\n", path1, path2);
-  if (fs.rename(path1, path2)) {
-    Serial.println("- file renamed");
-  } else {
-    Serial.println("- rename failed");
-  }
-}
-
-void deleteFile(fs::FS &fs, const char *path) {
-  Serial.printf("Deleting file: %s\r\n", path);
-  if (fs.remove(path)) {
-    Serial.println("- file deleted");
-  } else {
-    Serial.println("- delete failed");
-  }
-}
-
-// SPIFFS-like write and delete file
-
-// See: https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.cpp#L60
-void writeFile2(fs::FS &fs, const char *path, const char *message) {
-  if (!fs.exists(path)) {
-    if (strchr(path, '/')) {
-      Serial.printf("Create missing folders of: %s\r\n", path);
-      char *pathStr = strdup(path);
-      if (pathStr) {
-        char *ptr = strchr(pathStr, '/');
-        while (ptr) {
-          *ptr = 0;
-          fs.mkdir(pathStr);
-          *ptr = '/';
-          ptr = strchr(ptr + 1, '/');
-        }
-      }
-      free(pathStr);
-    }
-  }
-
-  Serial.printf("Writing file to: %s\r\n", path);
-  File file = fs.open(path, FILE_WRITE);
-  if (!file) {
-    Serial.println("- failed to open file for writing");
-    return;
-  }
-  if (file.print(message)) {
-    Serial.println("- file written");
-  } else {
-    Serial.println("- write failed");
-  }
-  file.close();
-}
-
-// See:  https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.h#L149
-void deleteFile2(fs::FS &fs, const char *path) {
-  Serial.printf("Deleting file and empty folders on path: %s\r\n", path);
-
-  if (fs.remove(path)) {
-    Serial.println("- file deleted");
-  } else {
-    Serial.println("- delete failed");
-  }
-
-  char *pathStr = strdup(path);
-  if (pathStr) {
-    char *ptr = strrchr(pathStr, '/');
-    if (ptr) {
-      Serial.printf("Removing all empty folders on path: %s\r\n", path);
-    }
-    while (ptr) {
-      *ptr = 0;
-      fs.rmdir(pathStr);
-      ptr = strrchr(pathStr, '/');
-    }
-    free(pathStr);
-  }
-}
-
-void testFileIO(fs::FS &fs, const char *path) {
-  Serial.printf("Testing file I/O with %s\r\n", path);
-
-  static uint8_t buf[512];
-  size_t len = 0;
-  File file = fs.open(path, FILE_WRITE);
-  if (!file) {
-    Serial.println("- failed to open file for writing");
-    return;
-  }
-
-  size_t i;
-  Serial.print("- writing");
-  uint32_t start = millis();
-  for (i = 0; i < 2048; i++) {
-    if ((i & 0x001F) == 0x001F) {
-      Serial.print(".");
-    }
-    file.write(buf, 512);
-  }
-  Serial.println("");
-  uint32_t end = millis() - start;
-  Serial.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end);
-  file.close();
-
-  file = fs.open(path);
-  start = millis();
-  end = start;
-  i = 0;
-  if (file && !file.isDirectory()) {
-    len = file.size();
-    size_t flen = len;
-    start = millis();
-    Serial.print("- reading");
-    while (len) {
-      size_t toRead = len;
-      if (toRead > 512) {
-        toRead = 512;
-      }
-      file.read(buf, toRead);
-      if ((i++ & 0x001F) == 0x001F) {
-        Serial.print(".");
-      }
-      len -= toRead;
-    }
-    Serial.println("");
-    end = millis() - start;
-    Serial.printf("- %u bytes read in %u ms\r\n", flen, end);
-    file.close();
-  } else {
-    Serial.println("- failed to open file for reading");
-  }
-}
-
-void setup() {
-  Serial.begin(115200);
-  if (!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED)) {
-    Serial.println("LittleFS Mount Failed");
-    return;
-  }
-
-  listDir(LittleFS, "/", 0);
-  createDir(LittleFS, "/mydir");
-  writeFile(LittleFS, "/mydir/hello2.txt", "Hello2");
-  //writeFile(LittleFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3");
-  writeFile2(LittleFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3");
-  listDir(LittleFS, "/", 3);
-  deleteFile(LittleFS, "/mydir/hello2.txt");
-  //deleteFile(LittleFS, "/mydir/newdir2/newdir3/hello3.txt");
-  deleteFile2(LittleFS, "/mydir/newdir2/newdir3/hello3.txt");
-  removeDir(LittleFS, "/mydir");
-  listDir(LittleFS, "/", 3);
-  writeFile(LittleFS, "/hello.txt", "Hello ");
-  appendFile(LittleFS, "/hello.txt", "World!\r\n");
-  readFile(LittleFS, "/hello.txt");
-  renameFile(LittleFS, "/hello.txt", "/foo.txt");
-  readFile(LittleFS, "/foo.txt");
-  deleteFile(LittleFS, "/foo.txt");
-  testFileIO(LittleFS, "/test.txt");
-  deleteFile(LittleFS, "/test.txt");
-
-  Serial.println("Test complete");
-}
-
-void loop() {}
diff --git a/libraries/LittleFS/library.properties b/libraries/LittleFS/library.properties
index fac629fab31..86c4c43eeca 100644
--- a/libraries/LittleFS/library.properties
+++ b/libraries/LittleFS/library.properties
@@ -1,5 +1,5 @@
 name=LittleFS
-version=3.0.5
+version=3.1.0
 author=
 maintainer=
 sentence=LittleFS for esp32
diff --git a/libraries/LittleFS/src/LittleFS.cpp b/libraries/LittleFS/src/LittleFS.cpp
index e0e71aacf9c..e86caeb74cc 100644
--- a/libraries/LittleFS/src/LittleFS.cpp
+++ b/libraries/LittleFS/src/LittleFS.cpp
@@ -12,18 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "LittleFS.h"
+
+#ifdef CONFIG_LITTLEFS_PAGE_SIZE
 #include "vfs_api.h"
 
 extern "C" {
 #include <sys/unistd.h>
 #include <sys/stat.h>
 #include <dirent.h>
-}
-#include "sdkconfig.h"
-#include "LittleFS.h"
-
-#ifdef CONFIG_LITTLEFS_PAGE_SIZE
-extern "C" {
 #include "esp_littlefs.h"
 }
 
@@ -125,4 +122,4 @@ size_t LittleFSFS::usedBytes() {
 }
 
 LittleFSFS LittleFS;
-#endif
+#endif /* CONFIG_LITTLEFS_PAGE_SIZE */
diff --git a/libraries/LittleFS/src/LittleFS.h b/libraries/LittleFS/src/LittleFS.h
index 47220b30b33..da4ab7d1f6f 100644
--- a/libraries/LittleFS/src/LittleFS.h
+++ b/libraries/LittleFS/src/LittleFS.h
@@ -14,6 +14,10 @@
 #ifndef _LITTLEFS_H_
 #define _LITTLEFS_H_
 
+#include "sdkconfig.h"
+
+#ifdef CONFIG_LITTLEFS_PAGE_SIZE
+
 #include "FS.h"
 
 namespace fs {
@@ -36,4 +40,5 @@ class LittleFSFS : public FS {
 
 extern fs::LittleFSFS LittleFS;
 
+#endif /* CONFIG_LITTLEFS_PAGE_SIZE */
 #endif
diff --git a/libraries/NetBIOS/library.properties b/libraries/NetBIOS/library.properties
index c073252d6f2..42555781f75 100644
--- a/libraries/NetBIOS/library.properties
+++ b/libraries/NetBIOS/library.properties
@@ -1,5 +1,5 @@
 name=NetBIOS
-version=3.0.5
+version=3.1.0
 author=Pablo@xpablo.cz
 maintainer=Hristo Gochkov<hristo@espressif.com>
 sentence=Enables NBNS (NetBIOS) name resolution.
diff --git a/libraries/Network/library.properties b/libraries/Network/library.properties
index 2a80ad844ea..8a1567e68a9 100644
--- a/libraries/Network/library.properties
+++ b/libraries/Network/library.properties
@@ -1,5 +1,5 @@
 name=Networking
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=General network management library.
diff --git a/libraries/Network/src/NetworkClient.cpp b/libraries/Network/src/NetworkClient.cpp
index 067d288bf93..da83597d2c6 100644
--- a/libraries/Network/src/NetworkClient.cpp
+++ b/libraries/Network/src/NetworkClient.cpp
@@ -210,6 +210,7 @@ int NetworkClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms) {
   _timeout = timeout_ms;
   int sockfd = -1;
 
+#if CONFIG_LWIP_IPV6
   if (ip.type() == IPv6) {
     struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr;
     sockfd = socket(AF_INET6, SOCK_STREAM, 0);
@@ -218,12 +219,15 @@ int NetworkClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms) {
     tmpaddr->sin6_port = htons(port);
     tmpaddr->sin6_scope_id = ip.zone();
   } else {
+#endif
     struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr;
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     tmpaddr->sin_family = AF_INET;
     tmpaddr->sin_addr.s_addr = ip;
     tmpaddr->sin_port = htons(port);
+#if CONFIG_LWIP_IPV6
   }
+#endif
   if (sockfd < 0) {
     log_e("socket: %d", errno);
     return 0;
@@ -590,6 +594,7 @@ IPAddress NetworkClient::remoteIP(int fd) const {
     return IPAddress((uint32_t)(s->sin_addr.s_addr));
   }
 
+#if CONFIG_LWIP_IPV6
   // IPv6, but it might be IPv4 mapped address
   if (((struct sockaddr *)&addr)->sa_family == AF_INET6) {
     struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr;
@@ -600,6 +605,7 @@ IPAddress NetworkClient::remoteIP(int fd) const {
     }
   }
   log_e("NetworkClient::remoteIP Not AF_INET or AF_INET6?");
+#endif
   return (IPAddress(0, 0, 0, 0));
 }
 
@@ -630,6 +636,7 @@ IPAddress NetworkClient::localIP(int fd) const {
     return IPAddress((uint32_t)(s->sin_addr.s_addr));
   }
 
+#if CONFIG_LWIP_IPV6
   // IPv6, but it might be IPv4 mapped address
   if (((struct sockaddr *)&addr)->sa_family == AF_INET6) {
     struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr;
@@ -640,6 +647,7 @@ IPAddress NetworkClient::localIP(int fd) const {
     }
   }
   log_e("NetworkClient::localIP Not AF_INET or AF_INET6?");
+#endif
   return (IPAddress(0, 0, 0, 0));
 }
 
diff --git a/libraries/Network/src/NetworkClient.h b/libraries/Network/src/NetworkClient.h
index bdf857e9637..add886146b4 100644
--- a/libraries/Network/src/NetworkClient.h
+++ b/libraries/Network/src/NetworkClient.h
@@ -28,8 +28,6 @@ class NetworkClientRxBuffer;
 
 class ESPLwIPClient : public Client {
 public:
-  virtual int connect(IPAddress ip, uint16_t port, int32_t timeout) = 0;
-  virtual int connect(const char *host, uint16_t port, int32_t timeout) = 0;
   virtual void setConnectionTimeout(uint32_t milliseconds) = 0;
 };
 
diff --git a/libraries/Network/src/NetworkEvents.cpp b/libraries/Network/src/NetworkEvents.cpp
index 5a7e7c49afa..1a7177bae61 100644
--- a/libraries/Network/src/NetworkEvents.cpp
+++ b/libraries/Network/src/NetworkEvents.cpp
@@ -368,7 +368,7 @@ const char *NetworkEvents::eventName(arduino_event_id_t id) {
     case ARDUINO_EVENT_PPP_GOT_IP:       return "PPP_GOT_IP";
     case ARDUINO_EVENT_PPP_LOST_IP:      return "PPP_LOST_IP";
     case ARDUINO_EVENT_PPP_GOT_IP6:      return "PPP_GOT_IP6";
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
     case ARDUINO_EVENT_WIFI_OFF:                 return "WIFI_OFF";
     case ARDUINO_EVENT_WIFI_READY:               return "WIFI_READY";
     case ARDUINO_EVENT_WIFI_SCAN_DONE:           return "SCAN_DONE";
diff --git a/libraries/Network/src/NetworkEvents.h b/libraries/Network/src/NetworkEvents.h
index e134d6816a2..34a54cab092 100644
--- a/libraries/Network/src/NetworkEvents.h
+++ b/libraries/Network/src/NetworkEvents.h
@@ -5,11 +5,14 @@
  */
 #pragma once
 
+#include "sdkconfig.h"
 #include "soc/soc_caps.h"
 #include "esp_err.h"
 #include "esp_event.h"
 #include "esp_netif_types.h"
+#if CONFIG_ETH_ENABLED
 #include "esp_eth_driver.h"
+#endif
 #include <functional>
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
@@ -20,13 +23,15 @@
 #include <mutex>
 #endif  // defined NETWORK_EVENTS_MUTEX &&  SOC_CPU_CORES_NUM > 1
 
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 #include "esp_wifi_types.h"
 #include "esp_smartconfig.h"
+#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
 #include "network_provisioning/network_config.h"
 #endif
+#endif
 
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 constexpr int WIFI_SCANNING_BIT = BIT0;
 constexpr int WIFI_SCAN_DONE_BIT = BIT1;
 #endif
@@ -44,7 +49,7 @@ typedef enum {
   ARDUINO_EVENT_ETH_GOT_IP,
   ARDUINO_EVENT_ETH_LOST_IP,
   ARDUINO_EVENT_ETH_GOT_IP6,
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
   ARDUINO_EVENT_WIFI_OFF = 100,
   ARDUINO_EVENT_WIFI_READY,
   ARDUINO_EVENT_WIFI_SCAN_DONE,
@@ -95,8 +100,10 @@ typedef union {
   ip_event_ap_staipassigned_t wifi_ap_staipassigned;
   ip_event_got_ip_t got_ip;
   ip_event_got_ip6_t got_ip6;
+#if CONFIG_ETH_ENABLED
   esp_eth_handle_t eth_connected;
-#if SOC_WIFI_SUPPORTED
+#endif
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
   wifi_event_sta_scan_done_t wifi_scan_done;
   wifi_event_sta_authmode_change_t wifi_sta_authmode_change;
   wifi_event_sta_connected_t wifi_sta_connected;
@@ -107,8 +114,12 @@ typedef union {
   wifi_event_ap_staconnected_t wifi_ap_staconnected;
   wifi_event_ap_stadisconnected_t wifi_ap_stadisconnected;
   wifi_event_ftm_report_t wifi_ftm_report;
+#endif
+#if SOC_WIFI_SUPPORTED
   wifi_sta_config_t prov_cred_recv;
+#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
   network_prov_wifi_sta_fail_reason_t prov_fail_reason;
+#endif
   smartconfig_event_got_ssid_pswd_t sc_got_ssid_pswd;
 #endif
 } arduino_event_info_t;
@@ -237,7 +248,7 @@ class NetworkEvents {
   friend class ESP_NetworkInterface;
   friend class ETHClass;
   friend class PPPClass;
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
   friend class STAClass;
   friend class APClass;
   friend class WiFiGenericClass;
diff --git a/libraries/Network/src/NetworkInterface.cpp b/libraries/Network/src/NetworkInterface.cpp
index f4bb1d48392..4f310821204 100644
--- a/libraries/Network/src/NetworkInterface.cpp
+++ b/libraries/Network/src/NetworkInterface.cpp
@@ -106,6 +106,7 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void *event_data) {
     } else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
       arduino_event.event_id = ARDUINO_EVENT_ETH_LOST_IP;
     }
+#if CONFIG_LWIP_IPV6
   } else if (event_id == IP_EVENT_GOT_IP6) {
     ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
     esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip);
@@ -115,14 +116,10 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void *event_data) {
       setStatusBits(ESP_NETIF_HAS_LOCAL_IP6_BIT);
     }
 #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
-    char if_name[NETIF_NAMESIZE] = {
-      0,
-    };
-    netif_index_to_name(event->ip6_info.ip.zone, if_name);
     static const char *addr_types[] = {"UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6"};
     log_v(
-      "IF %s Got IPv6: Interface: %d, IP Index: %d, Type: %s, Zone: %d (%s), Address: " IPV6STR, desc(), _interface_id, event->ip_index, addr_types[addr_type],
-      event->ip6_info.ip.zone, if_name, IPV62STR(event->ip6_info.ip)
+      "IF %s Got IPv6: Interface: %d, IP Index: %d, Type: %s, Zone: %d, Address: " IPV6STR, desc(), _interface_id, event->ip_index, addr_types[addr_type],
+      event->ip6_info.ip.zone, IPV62STR(event->ip6_info.ip)
     );
 #endif
     memcpy(&arduino_event.event_info.got_ip6, event_data, sizeof(ip_event_got_ip6_t));
@@ -138,6 +135,7 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void *event_data) {
     } else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
       arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP6;
     }
+#endif /* CONFIG_LWIP_IPV6 */
 #if SOC_WIFI_SUPPORTED
   } else if (event_id == IP_EVENT_AP_STAIPASSIGNED && _interface_id == ESP_NETIF_ID_AP) {
     setStatusBits(ESP_NETIF_HAS_IP_BIT);
@@ -330,6 +328,7 @@ bool NetworkInterface::hasGlobalIPv6() const {
 }
 
 bool NetworkInterface::enableIPv6(bool en) {
+#if CONFIG_LWIP_IPV6
   if (en) {
     setStatusBits(ESP_NETIF_WANT_IP6_BIT);
     if (_esp_netif != NULL && connected()) {
@@ -345,6 +344,9 @@ bool NetworkInterface::enableIPv6(bool en) {
     clearStatusBits(ESP_NETIF_WANT_IP6_BIT);
   }
   return true;
+#else
+  return false;
+#endif
 }
 
 bool NetworkInterface::dnsIP(uint8_t dns_no, IPAddress ip) {
@@ -743,6 +745,7 @@ uint8_t NetworkInterface::subnetCIDR() const {
   return calculateSubnetCIDR(IPAddress(ip.netmask.addr));
 }
 
+#if CONFIG_LWIP_IPV6
 IPAddress NetworkInterface::linkLocalIPv6() const {
   if (_esp_netif == NULL) {
     return IPAddress(IPv6);
@@ -764,6 +767,7 @@ IPAddress NetworkInterface::globalIPv6() const {
   }
   return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
 }
+#endif
 
 size_t NetworkInterface::printTo(Print &out) const {
   size_t bytes = 0;
@@ -838,6 +842,7 @@ size_t NetworkInterface::printTo(Print &out) const {
   bytes += out.print(dnsIP());
   bytes += out.println();
 
+#if CONFIG_LWIP_IPV6
   static const char *types[] = {"UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6"};
   esp_ip6_addr_t if_ip6[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
   int v6addrs = esp_netif_get_all_ip6(_esp_netif, if_ip6);
@@ -849,6 +854,7 @@ size_t NetworkInterface::printTo(Print &out) const {
     bytes += out.print(types[esp_netif_ip6_get_addr_type(&if_ip6[i])]);
     bytes += out.println();
   }
+#endif
 
   return bytes;
 }
diff --git a/libraries/Network/src/NetworkInterface.h b/libraries/Network/src/NetworkInterface.h
index 323cf3bfc72..4f97181d4fd 100644
--- a/libraries/Network/src/NetworkInterface.h
+++ b/libraries/Network/src/NetworkInterface.h
@@ -70,8 +70,10 @@ class NetworkInterface : public Printable {
   IPAddress broadcastIP() const;
   IPAddress networkID() const;
   uint8_t subnetCIDR() const;
+#if CONFIG_LWIP_IPV6
   IPAddress linkLocalIPv6() const;
   IPAddress globalIPv6() const;
+#endif
 
   size_t printTo(Print &out) const;
 
diff --git a/libraries/Network/src/NetworkManager.cpp b/libraries/Network/src/NetworkManager.cpp
index 88059a60562..12276b2e242 100644
--- a/libraries/Network/src/NetworkManager.cpp
+++ b/libraries/Network/src/NetworkManager.cpp
@@ -87,6 +87,7 @@ int NetworkManager::hostByName(const char *aHostname, IPAddress &aResult) {
   memset(&hints, 0, sizeof(hints));
   hints.ai_socktype = SOCK_STREAM;
 
+#if CONFIG_LWIP_IPV6
   // **Workaround**
   // LWIP AF_UNSPEC always prefers IPv4 and doesn't check what network is
   // available. See https://github.com/espressif/esp-idf/issues/13255
@@ -106,22 +107,27 @@ int NetworkManager::hostByName(const char *aHostname, IPAddress &aResult) {
     }
   }
   // **End Workaround**
+#endif
 
   hints.ai_family = AF_UNSPEC;
   err = lwip_getaddrinfo(aHostname, servname, &hints, &res);
 
   if (err == ERR_OK) {
+#if CONFIG_LWIP_IPV6
     if (res->ai_family == AF_INET6) {
       struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
       // As an array of u8_t
       aResult = IPAddress(IPv6, ipv6->sin6_addr.s6_addr);
       log_d("DNS found IPv6 %s", aResult.toString().c_str());
     } else {
+#endif
       struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
       // As a single u32_t
       aResult = IPAddress(ipv4->sin_addr.s_addr);
       log_d("DNS found IPv4 %s", aResult.toString().c_str());
+#if CONFIG_LWIP_IPV6
     }
+#endif
 
     lwip_freeaddrinfo(res);
     return 1;
diff --git a/libraries/Network/src/NetworkServer.cpp b/libraries/Network/src/NetworkServer.cpp
index 4609757255e..ce8ef952ea7 100644
--- a/libraries/Network/src/NetworkServer.cpp
+++ b/libraries/Network/src/NetworkServer.cpp
@@ -46,8 +46,13 @@ NetworkClient NetworkServer::accept() {
     client_sock = _accepted_sockfd;
     _accepted_sockfd = -1;
   } else {
+#if CONFIG_LWIP_IPV6
     struct sockaddr_in6 _client;
     int cs = sizeof(struct sockaddr_in6);
+#else
+    struct sockaddr_in _client;
+    int cs = sizeof(struct sockaddr_in);
+#endif
 #ifdef ESP_IDF_VERSION_MAJOR
     client_sock = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t *)&cs);
 #else
@@ -77,6 +82,7 @@ void NetworkServer::begin(uint16_t port, int enable) {
   if (port) {
     _port = port;
   }
+#if CONFIG_LWIP_IPV6
   struct sockaddr_in6 server;
   sockfd = socket(AF_INET6, SOCK_STREAM, 0);
   if (sockfd < 0) {
@@ -93,6 +99,18 @@ void NetworkServer::begin(uint16_t port, int enable) {
   }
   memset(server.sin6_addr.s6_addr, 0x0, 16);
   server.sin6_port = htons(_port);
+#else
+  struct sockaddr_in server;
+  memset(&server, 0x0, sizeof(sockaddr_in));
+  server.sin_family = AF_INET;
+  sockfd = socket(AF_INET, SOCK_STREAM, 0);
+  if (sockfd < 0) {
+    return;
+  }
+  setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
+  memcpy((uint8_t *)&(server.sin_addr.s_addr), (uint8_t *)&_addr[0], 4);
+  server.sin_port = htons(_port);
+#endif
   if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
     return;
   }
@@ -117,8 +135,13 @@ bool NetworkServer::hasClient() {
   if (_accepted_sockfd >= 0) {
     return true;
   }
+#if CONFIG_LWIP_IPV6
   struct sockaddr_in6 _client;
   int cs = sizeof(struct sockaddr_in6);
+#else
+  struct sockaddr _client;
+  int cs = sizeof(struct sockaddr);
+#endif
 #ifdef ESP_IDF_VERSION_MAJOR
   _accepted_sockfd = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t *)&cs);
 #else
diff --git a/libraries/Network/src/NetworkUdp.cpp b/libraries/Network/src/NetworkUdp.cpp
index 73e0607c5ff..51579910ded 100644
--- a/libraries/Network/src/NetworkUdp.cpp
+++ b/libraries/Network/src/NetworkUdp.cpp
@@ -255,6 +255,7 @@ int NetworkUDP::endPacket() {
       log_e("could not send data: %d", errno);
       return 0;
     }
+#if LWIP_IPV6
   } else {
     struct sockaddr_in6 recipient;
     recipient.sin6_flowinfo = 0;
@@ -267,6 +268,7 @@ int NetworkUDP::endPacket() {
       log_e("could not send data: %d", errno);
       return 0;
     }
+#endif
   }
   return 1;
 }
@@ -336,12 +338,16 @@ int NetworkUDP::parsePacket() {
       remote_ip.from_ip_addr_t(&addr);
     }
     remote_port = ntohs(si_other.sin6_port);
+  } else {
+    remote_ip = ip_addr_any.u_addr.ip4.addr;
+    remote_port = 0;
   }
-#endif  // LWIP_IPV6=1
+#else
   else {
-    remote_ip = ip_addr_any.u_addr.ip4.addr;
+    remote_ip = ip_addr_any.addr;
     remote_port = 0;
   }
+#endif  // LWIP_IPV6=1
   if (len > 0) {
     rx_buffer = new (std::nothrow) cbuf(len);
     rx_buffer->write(buf, len);
diff --git a/libraries/NetworkClientSecure/README.md b/libraries/NetworkClientSecure/README.md
index d028158730d..f83cf246287 100644
--- a/libraries/NetworkClientSecure/README.md
+++ b/libraries/NetworkClientSecure/README.md
@@ -32,25 +32,11 @@ This method is similar to the single root certificate verification above, but it
 root certificates from Mozilla to authenticate against, while the previous method only accepts a single
 certificate for a given server. This allows the client to connect to all public SSL servers.
 
-To use this feature in PlatformIO:
-1. create a certificate bundle as described in the document below, or obtain a pre-built one you trust:
-https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_crt_bundle.html
-(gen_crt_bundle.py can be found in the /tools folder)
-   a. note: the full bundle will take up around 64k of flash space, but has minimal RAM usage, as only
-      the index of the certificates is kept in RAM
-2. Place the bundle under the file name "data/cert/x509_crt_bundle.bin" in your platformio project
-3. add "board_build.embed_files = data/cert/x509_crt_bundle.bin" in your platformio.ini
-4. add the following global declaration in your project:
-   extern const uint8_t rootca_crt_bundle_start[] asm("_binary_data_cert_x509_crt_bundle_bin_start");
-5. before initiating the first SSL connection, call
-   my_client.setCACertBundle(rootca_crt_bundle_start);
-
 To use this feature in Arduino IDE:
 If the Arduino IDE added support for embedding files in the meantime, then follow the instructions above.
-If not, you have three choices:
-1. convert your project to PlatformIO
-2. create a makefile where you can add the idf_component_register() declaration to include the certificate bundle
-3. Store the bundle as a SPIFFS file, but then you have to load it into RAM in runtime and waste 64k of precious memory
+If not, you have two choices:
+1. create a makefile where you can add the idf_component_register() declaration to include the certificate bundle
+2. Store the bundle as a SPIFFS file, but then you have to load it into RAM in runtime and waste 64k of precious memory
 
 Using a root CA cert and client cert/keys
 -----------------------------------------
diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json
index 618e46bd244..cbdd28f773d 100644
--- a/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json
+++ b/libraries/NetworkClientSecure/examples/WiFiClientSecure/ci.json
@@ -1,4 +1,5 @@
 {
+  "fqbn_append": "PartitionScheme=huge_app",
   "requires_any": [
     "CONFIG_SOC_WIFI_SUPPORTED=y",
     "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino
index a7149e05e6e..b9e01d15682 100644
--- a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino
+++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino
@@ -13,6 +13,11 @@
 // Note: this example is outdated and may not work!
 // For more examples see https://github.com/martinius96/ESP32-eduroam
 
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#error "WPA-Enterprise is only supported in SoCs with native Wi-Fi support"
+#endif
+
 #include <WiFi.h>
 #include <NetworkClientSecure.h>
 #if __has_include("esp_eap_client.h")
diff --git a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json
index 618e46bd244..04eb62b977a 100644
--- a/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json
+++ b/libraries/NetworkClientSecure/examples/WiFiClientSecureEnterprise/ci.json
@@ -1,6 +1,6 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "fqbn_append": "PartitionScheme=huge_app",
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/NetworkClientSecure/library.properties b/libraries/NetworkClientSecure/library.properties
index f71bc7ef0d8..d810e852524 100644
--- a/libraries/NetworkClientSecure/library.properties
+++ b/libraries/NetworkClientSecure/library.properties
@@ -1,5 +1,5 @@
 name=NetworkClientSecure
-version=3.0.5
+version=3.1.0
 author=Evandro Luis Copercini
 maintainer=Github Community
 sentence=Enables secure network connection (local and Internet) using the ESP32 built-in WiFi.
diff --git a/libraries/NetworkClientSecure/src/ssl_client.cpp b/libraries/NetworkClientSecure/src/ssl_client.cpp
index 0f93f5cd7fe..19f75673133 100644
--- a/libraries/NetworkClientSecure/src/ssl_client.cpp
+++ b/libraries/NetworkClientSecure/src/ssl_client.cpp
@@ -83,6 +83,7 @@ int start_ssl_client(
 
   fcntl(ssl_client->socket, F_SETFL, fcntl(ssl_client->socket, F_GETFL, 0) | O_NONBLOCK);
   struct sockaddr_storage serv_addr = {};
+#if CONFIG_LWIP_IPV6
   if (domain == AF_INET6) {
     struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serv_addr;
     tmpaddr->sin6_family = AF_INET6;
@@ -92,11 +93,14 @@ int start_ssl_client(
     tmpaddr->sin6_port = htons(port);
     tmpaddr->sin6_scope_id = ip.zone();
   } else {
+#endif
     struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serv_addr;
     tmpaddr->sin_family = AF_INET;
     tmpaddr->sin_addr.s_addr = ip;
     tmpaddr->sin_port = htons(port);
+#if CONFIG_LWIP_IPV6
   }
+#endif
 
   if (timeout <= 0) {
     timeout = 30000;  // Milli seconds.
diff --git a/libraries/OpenThread/library.properties b/libraries/OpenThread/library.properties
index 39c6329725e..19d37749a92 100644
--- a/libraries/OpenThread/library.properties
+++ b/libraries/OpenThread/library.properties
@@ -1,5 +1,5 @@
 name=OpenThread
-version=3.0.5
+version=3.1.0
 author=Rodrigo Garcia | GitHub @SuGlider
 maintainer=Rodrigo Garcia <Rodrigo.Garcia@espressif.com>
 sentence=Library for OpenThread Network on ESP32.
diff --git a/libraries/PPP/library.properties b/libraries/PPP/library.properties
index 47264f1fd8c..e2b290cc893 100644
--- a/libraries/PPP/library.properties
+++ b/libraries/PPP/library.properties
@@ -1,5 +1,5 @@
 name=PPP
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Enables network connection using GSM Modem.
diff --git a/libraries/PPP/src/PPP.cpp b/libraries/PPP/src/PPP.cpp
index ba1ca2e4869..77b70d3969c 100644
--- a/libraries/PPP/src/PPP.cpp
+++ b/libraries/PPP/src/PPP.cpp
@@ -1,12 +1,13 @@
 #define ARDUINO_CORE_BUILD
 #include "PPP.h"
-#if CONFIG_LWIP_PPP_SUPPORT
+#if CONFIG_LWIP_PPP_SUPPORT && ARDUINO_HAS_ESP_MODEM
 #include "esp32-hal-periman.h"
 #include "esp_netif.h"
 #include "esp_netif_ppp.h"
 #include <string>
 #include "driver/uart.h"
 #include "hal/uart_ll.h"
+#include "esp_private/uart_share_hw_ctrl.h"
 
 #define PPP_CMD_MODE_CHECK(x)                                    \
   if (_dce == NULL) {                                            \
@@ -279,7 +280,7 @@ bool PPPClass::begin(ppp_modem_model_t model, uint8_t uart_num, int baud_rate) {
   dte_config.uart_config.flow_control = _flow_ctrl;
   dte_config.uart_config.rx_buffer_size = _rx_buffer_size;
   dte_config.uart_config.tx_buffer_size = _tx_buffer_size;
-  dte_config.uart_config.port_num = _uart_num;
+  dte_config.uart_config.port_num = (uart_port_t)_uart_num;
   dte_config.uart_config.baud_rate = baud_rate;
 
   /* Configure the DCE */
@@ -653,7 +654,10 @@ bool PPPClass::setBaudrate(int baudrate) {
     log_e("uart_get_sclk_freq failed with %d %s", err, esp_err_to_name(err));
     return false;
   }
-  uart_ll_set_baudrate(UART_LL_GET_HW(_uart_num), (uint32_t)baudrate, sclk_freq);
+
+  HP_UART_SRC_CLK_ATOMIC() {
+    uart_ll_set_baudrate(UART_LL_GET_HW(_uart_num), (uint32_t)baudrate, sclk_freq);
+  }
 
   return true;
 }
diff --git a/libraries/PPP/src/PPP.h b/libraries/PPP/src/PPP.h
index 52eed57edbc..b8e1f7ad56f 100644
--- a/libraries/PPP/src/PPP.h
+++ b/libraries/PPP/src/PPP.h
@@ -1,7 +1,11 @@
 #pragma once
 
 #include "sdkconfig.h"
-#if CONFIG_LWIP_PPP_SUPPORT
+#if defined __has_include && __has_include("esp_modem_c_api_types.h")
+#define ARDUINO_HAS_ESP_MODEM 1
+#endif
+
+#if CONFIG_LWIP_PPP_SUPPORT && ARDUINO_HAS_ESP_MODEM
 #include "Network.h"
 #include "esp_modem_c_api_types.h"
 
@@ -109,5 +113,4 @@ class PPPClass : public NetworkInterface {
 };
 
 extern PPPClass PPP;
-
-#endif /* CONFIG_LWIP_PPP_SUPPORT */
+#endif /* CONFIG_LWIP_PPP_SUPPORT && ARDUINO_HAS_ESP_MODEM */
diff --git a/libraries/PPP/src/ppp.c b/libraries/PPP/src/ppp.c
index db8ba0760bd..52896e76c8e 100644
--- a/libraries/PPP/src/ppp.c
+++ b/libraries/PPP/src/ppp.c
@@ -1,5 +1,5 @@
 #include "sdkconfig.h"
-#if CONFIG_LWIP_PPP_SUPPORT
+#if CONFIG_LWIP_PPP_SUPPORT && defined __has_include && __has_include("esp_modem_api.h")
 #include "esp_modem_api.h"
 
 esp_err_t _esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout) {
diff --git a/libraries/Preferences/library.properties b/libraries/Preferences/library.properties
index 1923e59fc40..90cd20d75c3 100644
--- a/libraries/Preferences/library.properties
+++ b/libraries/Preferences/library.properties
@@ -1,5 +1,5 @@
 name=Preferences
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Provides friendly access to ESP32's Non-Volatile Storage
diff --git a/libraries/RainMaker/library.properties b/libraries/RainMaker/library.properties
index cf67e9772e1..0c3e6e26697 100644
--- a/libraries/RainMaker/library.properties
+++ b/libraries/RainMaker/library.properties
@@ -1,5 +1,5 @@
 name=ESP RainMaker
-version=3.0.5
+version=3.1.0
 author=Sweety Mhaiske <switi.mhaiske@espressif.com>
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP RainMaker Support
diff --git a/libraries/SD/library.properties b/libraries/SD/library.properties
index ca73443684f..3fd1a3f8a3e 100644
--- a/libraries/SD/library.properties
+++ b/libraries/SD/library.properties
@@ -1,5 +1,5 @@
 name=SD
-version=3.0.5
+version=3.1.0
 author=Arduino, SparkFun
 maintainer=Arduino <info@arduino.cc>
 sentence=Enables reading and writing on SD cards. For all Arduino boards.
diff --git a/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino b/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino
index 030caae759c..e03f5ceb25e 100644
--- a/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino
+++ b/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino
@@ -14,6 +14,7 @@
  * Connections for     ║   ║   ╔═══╩═║═║═══╗   ║  ║    ║
  * full-sized          ║   ║   ║   ╔═╝ ║   ║   ║  ║    ║
  * SD card             ║   ║   ║   ║   ║   ║   ║  ║    ║
+ * ESP32-P4 Func EV | 40  39  GND  43 3V3 GND  44 43  42  | SLOT 0 (IO_MUX)
  * ESP32-S3 DevKit  | 21  47  GND  39 3V3 GND  40 41  42  |
  * ESP32-S3-USB-OTG | 38  37  GND  36 3V3 GND  35 34  33  |
  * ESP32            |  4   2  GND  14 3V3 GND  15 13  12  |
@@ -42,6 +43,7 @@
 #include "FS.h"
 #include "SD_MMC.h"
 
+#ifdef CONFIG_IDF_TARGET_ESP32S3
 // Default pins for ESP-S3
 // Warning: ESP32-S3-WROOM-2 is using most of the default GPIOs (33-37) to interface with on-board OPI flash.
 //   If the SD_MMC is initialized with default pins it will result in rebooting loop - please
@@ -54,6 +56,7 @@ int d0 = 37;
 int d1 = 38;
 int d2 = 33;
 int d3 = 39;  // GPIO 34 is not broken-out on ESP32-S3-DevKitC-1 v1.1
+#endif
 
 void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
   Serial.printf("Listing directory: %s\n", dirname);
@@ -211,15 +214,16 @@ void testFileIO(fs::FS &fs, const char *path) {
 void setup() {
   Serial.begin(115200);
   /*
-    // If you want to change the pin assignment on ESP32-S3 uncomment this block and the appropriate
+    // If you want to change the pin assignment or you get an error that some pins
+    // are not assigned on ESP32-S3/ESP32-P4 uncomment this block and the appropriate
     // line depending if you want to use 1-bit or 4-bit line.
-    // Please note that ESP32 does not allow pin change and will always fail.
+    // Please note that ESP32 does not allow pin change and setPins() will always fail.
     //if(! SD_MMC.setPins(clk, cmd, d0)){
     //if(! SD_MMC.setPins(clk, cmd, d0, d1, d2, d3)){
-        Serial.println("Pin change failed!");
-        return;
-    }
-    */
+    //    Serial.println("Pin change failed!");
+    //    return;
+    //}
+  */
 
   if (!SD_MMC.begin()) {
     Serial.println("Card Mount Failed");
@@ -262,4 +266,6 @@ void setup() {
   Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));
 }
 
-void loop() {}
+void loop() {
+  delay(10);
+}
diff --git a/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino b/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino
index bd9f150f3e8..d1e933e4f4b 100644
--- a/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino
+++ b/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino
@@ -14,6 +14,7 @@
  * Connections for     ║   ║   ╔═══╩═║═║═══╗   ║  ║    ║
  * full-sized          ║   ║   ║   ╔═╝ ║   ║   ║  ║    ║
  * SD card             ║   ║   ║   ║   ║   ║   ║  ║    ║
+ * ESP32-P4 Func EV | 40  39  GND  43 3V3 GND  44 43  42  | SLOT 0 (IO_MUX)
  * ESP32-S3 DevKit  | 21  47  GND  39 3V3 GND  40 41  42  |
  * ESP32-S3-USB-OTG | 38  37  GND  36 3V3 GND  35 34  33  |
  * ESP32            |  4   2  GND  14 3V3 GND  15 13  12  |
diff --git a/libraries/SD_MMC/library.properties b/libraries/SD_MMC/library.properties
index 176947e4017..94586e8e1ec 100644
--- a/libraries/SD_MMC/library.properties
+++ b/libraries/SD_MMC/library.properties
@@ -1,5 +1,5 @@
 name=SD_MMC
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov, Ivan Grokhtkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32 SDMMC File System
diff --git a/libraries/SD_MMC/src/SD_MMC.cpp b/libraries/SD_MMC/src/SD_MMC.cpp
index 13e5fcf27fc..4a0962ff7e4 100644
--- a/libraries/SD_MMC/src/SD_MMC.cpp
+++ b/libraries/SD_MMC/src/SD_MMC.cpp
@@ -32,10 +32,14 @@
 #include "ff.h"
 #include "esp32-hal-periman.h"
 
+#if SOC_SDMMC_IO_POWER_EXTERNAL
+#include "sd_pwr_ctrl_by_on_chip_ldo.h"
+#endif
+
 using namespace fs;
 
 SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) {
-#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && defined(BOARD_HAS_SDMMC)
+#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && defined(BOARD_HAS_SDMMC) && !defined(CONFIG_IDF_TARGET_ESP32P4)
   _pin_clk = SDMMC_CLK;
   _pin_cmd = SDMMC_CMD;
   _pin_d0 = SDMMC_D0;
@@ -45,7 +49,7 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) {
   _pin_d3 = SDMMC_D3;
 #endif  // BOARD_HAS_1BIT_SDMMC
 
-#elif SOC_SDMMC_USE_IOMUX
+#elif defined(SOC_SDMMC_USE_IOMUX) && defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32)
   _pin_clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK;
   _pin_cmd = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD;
   _pin_d0 = SDMMC_SLOT1_IOMUX_PIN_NUM_D0;
@@ -54,6 +58,31 @@ SDMMCFS::SDMMCFS(FSImplPtr impl) : FS(impl), _card(nullptr) {
   _pin_d2 = SDMMC_SLOT1_IOMUX_PIN_NUM_D2;
   _pin_d3 = SDMMC_SLOT1_IOMUX_PIN_NUM_D3;
 #endif  // BOARD_HAS_1BIT_SDMMC
+
+// ESP32-P4 can use either IOMUX or GPIO matrix
+#elif defined(BOARD_HAS_SDMMC) && defined(CONFIG_IDF_TARGET_ESP32P4)
+#if defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 0)
+  _pin_clk = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK;
+  _pin_cmd = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD;
+  _pin_d0 = SDMMC_SLOT0_IOMUX_PIN_NUM_D0;
+#ifndef BOARD_HAS_1BIT_SDMMC
+  _pin_d1 = SDMMC_SLOT0_IOMUX_PIN_NUM_D1;
+  _pin_d2 = SDMMC_SLOT0_IOMUX_PIN_NUM_D2;
+  _pin_d3 = SDMMC_SLOT0_IOMUX_PIN_NUM_D3;
+#endif  // BOARD_HAS_1BIT_SDMMC
+#else
+  _pin_clk = SDMMC_CLK;
+  _pin_cmd = SDMMC_CMD;
+  _pin_d0 = SDMMC_D0;
+#ifndef BOARD_HAS_1BIT_SDMMC
+  _pin_d1 = SDMMC_D1;
+  _pin_d2 = SDMMC_D2;
+  _pin_d3 = SDMMC_D3;
+#endif  // BOARD_HAS_1BIT_SDMMC
+#endif  // BOARD_SDMMC_SLOT_NO
+#endif
+#if defined(SOC_SDMMC_IO_POWER_EXTERNAL) && defined(BOARD_SDMMC_POWER_CHANNEL)
+  _power_channel = BOARD_SDMMC_POWER_CHANNEL;
 #endif
 }
 
@@ -83,7 +112,7 @@ bool SDMMCFS::setPins(int clk, int cmd, int d0, int d1, int d2, int d3) {
   d2 = digitalPinToGPIONumber(d2);
   d3 = digitalPinToGPIONumber(d3);
 
-#ifdef SOC_SDMMC_USE_GPIO_MATRIX
+#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && !defined(CONFIG_IDF_TARGET_ESP32P4)
   // SoC supports SDMMC pin configuration via GPIO matrix. Save the pins for later use in SDMMCFS::begin.
   _pin_clk = (int8_t)clk;
   _pin_cmd = (int8_t)cmd;
@@ -104,11 +133,42 @@ bool SDMMCFS::setPins(int clk, int cmd, int d0, int d1, int d2, int d3) {
     return false;
   }
   return true;
+#elif defined(CONFIG_IDF_TARGET_ESP32P4)
+#if defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 0)
+  // ESP32-P4 can use either IOMUX or GPIO matrix
+  bool pins_ok =
+    (clk == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_CLK) && (cmd == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_CMD) && (d0 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D0)
+    && (((d1 == -1) && (d2 == -1) && (d3 == -1)) || ((d1 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D1) && (d2 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D2) && (d3 == (int)SDMMC_SLOT0_IOMUX_PIN_NUM_D3)));
+  if (!pins_ok) {
+    log_e("SDMMCFS: specified pins are not supported when using IOMUX (SDMMC SLOT 0).");
+    return false;
+  }
+  return true;
+#else
+  _pin_clk = (int8_t)clk;
+  _pin_cmd = (int8_t)cmd;
+  _pin_d0 = (int8_t)d0;
+  _pin_d1 = (int8_t)d1;
+  _pin_d2 = (int8_t)d2;
+  _pin_d3 = (int8_t)d3;
+  return true;
+#endif
 #else
 #error SoC not supported
 #endif
 }
 
+#ifdef SOC_SDMMC_IO_POWER_EXTERNAL
+bool SDMMCFS::setPowerChannel(int power_channel) {
+  if (_card != nullptr) {
+    log_e("SD_MMC.setPowerChannel must be called before SD_MMC.begin");
+    return false;
+  }
+  _power_channel = power_channel;
+  return true;
+}
+#endif
+
 bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_failed, int sdmmc_frequency, uint8_t maxOpenFiles) {
   if (_card) {
     return true;
@@ -123,7 +183,9 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_
   }
   //mount
   sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
-#ifdef SOC_SDMMC_USE_GPIO_MATRIX
+#if (defined(SOC_SDMMC_USE_GPIO_MATRIX) && !defined(CONFIG_IDF_TARGET_ESP32P4)) \
+  || (defined(CONFIG_IDF_TARGET_ESP32P4) && ((defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 1)) || !defined(BOARD_HAS_SDMMC)))
+  log_d("pin_cmd: %d, pin_clk: %d, pin_d0: %d, pin_d1: %d, pin_d2: %d, pin_d3: %d", _pin_cmd, _pin_clk, _pin_d0, _pin_d1, _pin_d2, _pin_d3);
   // SoC supports SDMMC pin configuration via GPIO matrix.
   // Check that the pins have been set either in the constructor or setPins function.
   if (_pin_cmd == -1 || _pin_clk == -1 || _pin_d0 == -1 || (!mode1bit && (_pin_d1 == -1 || _pin_d2 == -1 || _pin_d3 == -1))) {
@@ -163,7 +225,18 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_
 
   sdmmc_host_t host = SDMMC_HOST_DEFAULT();
   host.flags = SDMMC_HOST_FLAG_4BIT;
+#if defined(CONFIG_IDF_TARGET_ESP32P4) && defined(BOARD_SDMMC_SLOT) && (BOARD_SDMMC_SLOT == 0)
+  host.slot = SDMMC_HOST_SLOT_0;
+  // reconfigure slot_config to remove all pins in order to use IO_MUX
+  slot_config = {
+    .cd = SDMMC_SLOT_NO_CD,
+    .wp = SDMMC_SLOT_NO_WP,
+    .width = 4,
+    .flags = 0,
+  };
+#else
   host.slot = SDMMC_HOST_SLOT_1;
+#endif
   host.max_freq_khz = sdmmc_frequency;
 #ifdef BOARD_HAS_1BIT_SDMMC
   mode1bit = true;
@@ -174,8 +247,40 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_
   }
   _mode1bit = mode1bit;
 
+#ifdef SOC_SDMMC_IO_POWER_EXTERNAL
+  if (_power_channel == -1) {
+    log_i("On-chip power channel specified, use external power for SDMMC");
+  } else {
+    sd_pwr_ctrl_ldo_config_t ldo_config = {
+      .ldo_chan_id = _power_channel,
+    };
+    sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;
+
+    if (sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle) != ESP_OK) {
+      log_e("Failed to create a new on-chip LDO power control driver");
+      return false;
+    }
+    host.pwr_ctrl_handle = pwr_ctrl_handle;
+  }
+#endif
+
+#if defined(BOARD_SDMMC_POWER_PIN)
+#ifndef BOARD_SDMMC_POWER_ON_LEVEL
+#error "BOARD_SDMMC_POWER_ON_LEVEL not defined, please define it in pins_arduino.h"
+#endif
+  pinMode(BOARD_SDMMC_POWER_PIN, OUTPUT);
+  digitalWrite(BOARD_SDMMC_POWER_PIN, !BOARD_SDMMC_POWER_ON_LEVEL);
+  delay(200);
+  digitalWrite(BOARD_SDMMC_POWER_PIN, BOARD_SDMMC_POWER_ON_LEVEL);
+  perimanSetPinBusExtraType(BOARD_SDMMC_POWER_PIN, "SDMMC_POWER");
+#endif
+
   esp_vfs_fat_sdmmc_mount_config_t mount_config = {
-    .format_if_mount_failed = format_if_mount_failed, .max_files = maxOpenFiles, .allocation_unit_size = 0, .disk_status_check_enable = false
+    .format_if_mount_failed = format_if_mount_failed,
+    .max_files = maxOpenFiles,
+    .allocation_unit_size = 0,
+    .disk_status_check_enable = false,
+    .use_one_fat = false
   };
 
   esp_err_t ret = esp_vfs_fat_sdmmc_mount(mountpoint, &host, &slot_config, &mount_config, &_card);
@@ -236,6 +341,9 @@ void SDMMCFS::end() {
       perimanClearPinBus(_pin_d2);
       perimanClearPinBus(_pin_d3);
     }
+#if defined(BOARD_SDMMC_POWER_PIN)
+    perimanClearPinBus(BOARD_SDMMC_POWER_PIN);
+#endif
   }
 }
 
diff --git a/libraries/SD_MMC/src/SD_MMC.h b/libraries/SD_MMC/src/SD_MMC.h
index a2bc12aed64..b6fe13a0d24 100644
--- a/libraries/SD_MMC/src/SD_MMC.h
+++ b/libraries/SD_MMC/src/SD_MMC.h
@@ -44,6 +44,9 @@ class SDMMCFS : public FS {
   int8_t _pin_d1 = -1;
   int8_t _pin_d2 = -1;
   int8_t _pin_d3 = -1;
+#ifdef SOC_SDMMC_IO_POWER_EXTERNAL
+  int8_t _power_channel = -1;
+#endif
   uint8_t _pdrv = 0xFF;
   bool _mode1bit = false;
 
@@ -51,6 +54,9 @@ class SDMMCFS : public FS {
   SDMMCFS(FSImplPtr impl);
   bool setPins(int clk, int cmd, int d0);
   bool setPins(int clk, int cmd, int d0, int d1, int d2, int d3);
+#ifdef SOC_SDMMC_IO_POWER_EXTERNAL
+  bool setPowerChannel(int power_channel);
+#endif
   bool begin(
     const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false, int sdmmc_frequency = BOARD_MAX_SDMMC_FREQ,
     uint8_t maxOpenFiles = 5
diff --git a/libraries/SPI/library.properties b/libraries/SPI/library.properties
index 8d704b2667e..a7a7204db62 100644
--- a/libraries/SPI/library.properties
+++ b/libraries/SPI/library.properties
@@ -1,5 +1,5 @@
 name=SPI
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE.
diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp
index 93c686a0d13..35e52f43e4d 100644
--- a/libraries/SPI/src/SPI.cpp
+++ b/libraries/SPI/src/SPI.cpp
@@ -83,7 +83,7 @@ void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) {
     _miso = (_spi_num == FSPI) ? MISO : -1;
     _mosi = (_spi_num == FSPI) ? MOSI : -1;
     _ss = (_spi_num == FSPI) ? SS : -1;
-#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
+#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4
     _sck = SCK;
     _miso = MISO;
     _mosi = MOSI;
diff --git a/libraries/SPIFFS/library.properties b/libraries/SPIFFS/library.properties
index a901b32effd..132ff5fb7f1 100644
--- a/libraries/SPIFFS/library.properties
+++ b/libraries/SPIFFS/library.properties
@@ -1,5 +1,5 @@
 name=SPIFFS
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov, Ivan Grokhtkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32 SPIFFS File System
diff --git a/libraries/SimpleBLE/library.properties b/libraries/SimpleBLE/library.properties
index ab634e30461..ae28a21c0df 100644
--- a/libraries/SimpleBLE/library.properties
+++ b/libraries/SimpleBLE/library.properties
@@ -1,5 +1,5 @@
 name=SimpleBLE
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Provides really simple BLE advertizer with just on and off
diff --git a/libraries/TFLiteMicro/library.properties b/libraries/TFLiteMicro/library.properties
index 026411cd30e..cde7d21bec1 100644
--- a/libraries/TFLiteMicro/library.properties
+++ b/libraries/TFLiteMicro/library.properties
@@ -1,5 +1,5 @@
 name=TFLite Micro
-version=3.0.5
+version=3.1.0
 author=Sanket Wadekar
 maintainer=Sanket Wadekar
 sentence=TensorFlow Lite for Microcontrollers
diff --git a/libraries/Ticker/library.properties b/libraries/Ticker/library.properties
index 3486c45fb09..d6e9829c6ef 100644
--- a/libraries/Ticker/library.properties
+++ b/libraries/Ticker/library.properties
@@ -1,5 +1,5 @@
 name=Ticker
-version=3.0.5
+version=3.1.0
 author=Bert Melis
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Allows to call functions with a given interval.
diff --git a/libraries/USB/library.properties b/libraries/USB/library.properties
index abfa263769f..752acf3a803 100644
--- a/libraries/USB/library.properties
+++ b/libraries/USB/library.properties
@@ -1,5 +1,5 @@
 name=USB
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32S2 USB Library
diff --git a/libraries/USB/src/USBHID.cpp b/libraries/USB/src/USBHID.cpp
index 75f37ef5df3..1d5d86fb3a3 100644
--- a/libraries/USB/src/USBHID.cpp
+++ b/libraries/USB/src/USBHID.cpp
@@ -206,7 +206,9 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t *dst, uint8_t *itf) {
   uint8_t descriptor[TUD_HID_INOUT_DESC_LEN] = {
     // HID Input & Output descriptor
     // Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
-    TUD_HID_INOUT_DESCRIPTOR(*itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), 64, 1)
+    TUD_HID_INOUT_DESCRIPTOR(
+      *itf, str_index, tinyusb_interface_protocol, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE, 1
+    )
   };
   *itf += 1;
   memcpy(dst, descriptor, TUD_HID_INOUT_DESC_LEN);
diff --git a/libraries/USB/src/USBMIDI.cpp b/libraries/USB/src/USBMIDI.cpp
index cfc40e7b154..8a9571855e1 100644
--- a/libraries/USB/src/USBMIDI.cpp
+++ b/libraries/USB/src/USBMIDI.cpp
@@ -24,7 +24,7 @@ extern "C" uint16_t tusb_midi_load_descriptor(uint8_t *dst, uint8_t *itf) {
   uint8_t ep_out = tinyusb_get_free_out_endpoint();
   TU_VERIFY(ep_out != 0);
   uint8_t descriptor[TUD_MIDI_DESC_LEN] = {
-    TUD_MIDI_DESCRIPTOR(*itf, str_index, ep_out, (uint8_t)(0x80 | ep_in), 64),
+    TUD_MIDI_DESCRIPTOR(*itf, str_index, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE),
   };
   *itf += 2;
   memcpy(dst, descriptor, TUD_MIDI_DESC_LEN);
diff --git a/libraries/USB/src/USBVendor.cpp b/libraries/USB/src/USBVendor.cpp
index 293d5866945..70fac5770ae 100644
--- a/libraries/USB/src/USBVendor.cpp
+++ b/libraries/USB/src/USBVendor.cpp
@@ -24,7 +24,7 @@ esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, i
 
 static USBVendor *_Vendor = NULL;
 static QueueHandle_t rx_queue = NULL;
-static uint8_t USB_VENDOR_ENDPOINT_SIZE = 64;
+static uint16_t USB_VENDOR_ENDPOINT_SIZE = CFG_TUD_ENDOINT_SIZE;
 
 uint16_t tusb_vendor_load_descriptor(uint8_t *dst, uint8_t *itf) {
   uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Vendor");
@@ -68,10 +68,13 @@ extern "C" bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage,
   return false;
 }
 
-USBVendor::USBVendor(uint8_t endpoint_size) : itf(0), cb(NULL) {
+USBVendor::USBVendor(uint16_t endpoint_size) : itf(0), cb(NULL) {
   if (!_Vendor) {
     _Vendor = this;
-    if (endpoint_size <= 64) {
+    if (endpoint_size == 0) {
+      endpoint_size = CFG_TUD_ENDOINT_SIZE;
+    }
+    if (endpoint_size <= CFG_TUD_ENDOINT_SIZE) {
       USB_VENDOR_ENDPOINT_SIZE = endpoint_size;
     }
     tinyusb_enable_interface(USB_INTERFACE_VENDOR, TUD_VENDOR_DESC_LEN, tusb_vendor_load_descriptor);
@@ -97,7 +100,7 @@ size_t USBVendor::setRxBufferSize(size_t rx_queue_len) {
 }
 
 void USBVendor::begin() {
-  setRxBufferSize(256);  //default if not preset
+  setRxBufferSize(512);  //default if not preset
 }
 
 void USBVendor::end() {
diff --git a/libraries/USB/src/USBVendor.h b/libraries/USB/src/USBVendor.h
index e3e22281939..4990e466321 100644
--- a/libraries/USB/src/USBVendor.h
+++ b/libraries/USB/src/USBVendor.h
@@ -74,7 +74,7 @@ class USBVendor : public Stream {
   arduino_usb_vendor_control_request_handler_t cb;
 
 public:
-  USBVendor(uint8_t endpoint_size = 64);
+  USBVendor(uint16_t endpoint_size = 0);
   void begin(void);
   void end(void);
   size_t setRxBufferSize(size_t);
diff --git a/libraries/Update/library.properties b/libraries/Update/library.properties
index 1aece5b163e..9d480986b1e 100644
--- a/libraries/Update/library.properties
+++ b/libraries/Update/library.properties
@@ -1,5 +1,5 @@
 name=Update
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=ESP32 Sketch Update Library
diff --git a/libraries/Update/src/Update.h b/libraries/Update/src/Update.h
index 5832846fd28..67189da2f02 100644
--- a/libraries/Update/src/Update.h
+++ b/libraries/Update/src/Update.h
@@ -7,6 +7,10 @@
 #ifndef ESP32UPDATER_H
 #define ESP32UPDATER_H
 
+#ifndef UPDATE_NOCRYPT
+#define UPDATE_NOCRYPT
+#endif
+
 #include <Arduino.h>
 #include <MD5Builder.h>
 #include <functional>
@@ -63,6 +67,7 @@ class UpdateClass {
     */
   bool begin(size_t size = UPDATE_SIZE_UNKNOWN, int command = U_FLASH, int ledPin = -1, uint8_t ledOn = LOW, const char *label = NULL);
 
+#ifndef UPDATE_NOCRYPT
   /*
      Setup decryption configuration
      Crypt Key is 32bytes(256bits) block of data, use the same key as used to encrypt image file
@@ -71,6 +76,7 @@ class UpdateClass {
      Crypt Mode,    used to select if image files should be decrypted or not
     */
   bool setupCrypt(const uint8_t *cryptKey = 0, size_t cryptAddress = 0, uint8_t cryptConfig = 0xf, int cryptMode = U_AES_DECRYPT_AUTO);
+#endif /* UPDATE_NOCRYPT */
 
   /*
       Writes a buffer to the flash and increments the address
@@ -99,6 +105,7 @@ class UpdateClass {
     */
   bool end(bool evenIfRemaining = false);
 
+#ifndef UPDATE_NOCRYPT
   /*
       sets AES256 key(32 bytes) used for decrypting image file
     */
@@ -122,6 +129,7 @@ class UpdateClass {
   void setCryptConfig(const uint8_t cryptConfig) {
     _cryptCfg = cryptConfig & 0x0f;
   }
+#endif /* UPDATE_NOCRYPT */
 
   /*
       Aborts the running update
@@ -139,7 +147,13 @@ class UpdateClass {
       sets the expected MD5 for the firmware (hexString)
       If calc_post_decryption is true, the update library will calculate the MD5 after the decryption, if false the calculation occurs before the decryption
     */
-  bool setMD5(const char *expected_md5, bool calc_post_decryption = true);
+  bool setMD5(
+    const char *expected_md5
+#ifndef UPDATE_NOCRYPT
+    ,
+    bool calc_post_decryption = true
+#endif /* #ifdef UPDATE_NOCRYPT */
+  );
 
   /*
       returns the MD5 String of the successfully ended firmware
@@ -236,8 +250,10 @@ class UpdateClass {
 private:
   void _reset();
   void _abort(uint8_t err);
+#ifndef UPDATE_NOCRYPT
   void _cryptKeyTweak(size_t cryptAddress, uint8_t *tweaked_key);
   bool _decryptBuffer();
+#endif /* UPDATE_NOCRYPT */
   bool _writeBuffer();
   bool _verifyHeader(uint8_t data);
   bool _verifyEnd();
@@ -245,8 +261,10 @@ class UpdateClass {
   bool _chkDataInBlock(const uint8_t *data, size_t len) const;  // check if block contains any data or is empty
 
   uint8_t _error;
+#ifndef UPDATE_NOCRYPT
   uint8_t *_cryptKey;
   uint8_t *_cryptBuffer;
+#endif /* UPDATE_NOCRYPT */
   uint8_t *_buffer;
   uint8_t *_skipBuffer;
   size_t _bufferLen;
@@ -258,15 +276,19 @@ class UpdateClass {
   const esp_partition_t *_partition;
 
   String _target_md5;
+#ifndef UPDATE_NOCRYPT
   bool _target_md5_decrypted = true;
+#endif /* UPDATE_NOCRYPT */
   MD5Builder _md5;
 
   int _ledPin;
   uint8_t _ledOn;
 
+#ifndef UPDATE_NOCRYPT
   uint8_t _cryptMode;
   size_t _cryptAddress;
   uint8_t _cryptCfg;
+#endif /* UPDATE_NOCRYPT */
 };
 
 #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_UPDATE)
diff --git a/libraries/Update/src/Updater.cpp b/libraries/Update/src/Updater.cpp
index e92f84d4599..3b0c517431d 100644
--- a/libraries/Update/src/Updater.cpp
+++ b/libraries/Update/src/Updater.cpp
@@ -9,7 +9,9 @@
 #include "spi_flash_mmap.h"
 #include "esp_ota_ops.h"
 #include "esp_image_format.h"
+#ifndef UPDATE_NOCRYPT
 #include "mbedtls/aes.h"
+#endif /* UPDATE_NOCRYPT */
 
 static const char *_err2str(uint8_t _error) {
   if (_error == UPDATE_ERROR_OK) {
@@ -38,8 +40,10 @@ static const char *_err2str(uint8_t _error) {
     return ("Bad Argument");
   } else if (_error == UPDATE_ERROR_ABORT) {
     return ("Aborted");
+#ifndef UPDATE_NOCRYPT
   } else if (_error == UPDATE_ERROR_DECRYPT) {
     return ("Decryption error");
+#endif /* UPDATE_NOCRYPT */
   }
   return ("UNKNOWN");
 }
@@ -67,8 +71,17 @@ bool UpdateClass::_enablePartition(const esp_partition_t *partition) {
 }
 
 UpdateClass::UpdateClass()
-  : _error(0), _cryptKey(0), _cryptBuffer(0), _buffer(0), _skipBuffer(0), _bufferLen(0), _size(0), _progress_callback(NULL), _progress(0), _paroffset(0),
-    _command(U_FLASH), _partition(NULL), _cryptMode(U_AES_DECRYPT_AUTO), _cryptAddress(0), _cryptCfg(0xf) {}
+  : _error(0),
+#ifndef UPDATE_NOCRYPT
+    _cryptKey(0), _cryptBuffer(0),
+#endif /* UPDATE_NOCRYPT */
+    _buffer(0), _skipBuffer(0), _bufferLen(0), _size(0), _progress_callback(NULL), _progress(0), _paroffset(0), _command(U_FLASH), _partition(NULL)
+#ifndef UPDATE_NOCRYPT
+    ,
+    _cryptMode(U_AES_DECRYPT_AUTO), _cryptAddress(0), _cryptCfg(0xf)
+#endif /* UPDATE_NOCRYPT */
+{
+}
 
 UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress fn) {
   _progress_callback = fn;
@@ -83,7 +96,9 @@ void UpdateClass::_reset() {
     delete[] _skipBuffer;
   }
 
+#ifndef UPDATE_NOCRYPT
   _cryptBuffer = nullptr;
+#endif /* UPDATE_NOCRYPT */
   _buffer = nullptr;
   _skipBuffer = nullptr;
   _bufferLen = 0;
@@ -175,6 +190,7 @@ bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn, con
   return true;
 }
 
+#ifndef UPDATE_NOCRYPT
 bool UpdateClass::setupCrypt(const uint8_t *cryptKey, size_t cryptAddress, uint8_t cryptConfig, int cryptMode) {
   if (setCryptKey(cryptKey)) {
     if (setCryptMode(cryptMode)) {
@@ -216,6 +232,7 @@ bool UpdateClass::setCryptMode(const int cryptMode) {
   }
   return true;
 }
+#endif /* UPDATE_NOCRYPT */
 
 void UpdateClass::_abort(uint8_t err) {
   _reset();
@@ -226,6 +243,7 @@ void UpdateClass::abort() {
   _abort(UPDATE_ERROR_ABORT);
 }
 
+#ifndef UPDATE_NOCRYPT
 void UpdateClass::_cryptKeyTweak(size_t cryptAddress, uint8_t *tweaked_key) {
   memcpy(tweaked_key, _cryptKey, ENCRYPTED_KEY_SIZE);
   if (_cryptCfg == 0) {
@@ -338,8 +356,10 @@ bool UpdateClass::_decryptBuffer() {
   }
   return true;
 }
+#endif /* UPDATE_NOCRYPT */
 
 bool UpdateClass::_writeBuffer() {
+#ifndef UPDATE_NOCRYPT
   //first bytes of loading image, check to see if loading image needs decrypting
   if (!_progress) {
     _cryptMode &= U_AES_DECRYPT_MODE_MASK;
@@ -360,6 +380,7 @@ bool UpdateClass::_writeBuffer() {
       return false;
     }
   }
+#endif /* UPDATE_NOCRYPT */
   //first bytes of new firmware
   uint8_t skip = 0;
   if (!_progress && _command == U_FLASH) {
@@ -409,9 +430,13 @@ bool UpdateClass::_writeBuffer() {
   if (!_progress && _command == U_FLASH) {
     _buffer[0] = ESP_IMAGE_HEADER_MAGIC;
   }
+#ifndef UPDATE_NOCRYPT
   if (_target_md5_decrypted) {
+#endif /* UPDATE_NOCRYPT */
     _md5.add(_buffer, _bufferLen);
+#ifndef UPDATE_NOCRYPT
   }
+#endif /* UPDATE_NOCRYPT */
   _progress += _bufferLen;
   _bufferLen = 0;
   if (_progress_callback) {
@@ -453,13 +478,21 @@ bool UpdateClass::_verifyEnd() {
   return false;
 }
 
-bool UpdateClass::setMD5(const char *expected_md5, bool calc_post_decryption) {
+bool UpdateClass::setMD5(
+  const char *expected_md5
+#ifndef UPDATE_NOCRYPT
+  ,
+  bool calc_post_decryption
+#endif /* UPDATE_NOCRYPT */
+) {
   if (strlen(expected_md5) != 32) {
     return false;
   }
   _target_md5 = expected_md5;
   _target_md5.toLowerCase();
+#ifndef UPDATE_NOCRYPT
   _target_md5_decrypted = calc_post_decryption;
+#endif /* UPDATE_NOCRYPT */
   return true;
 }
 
@@ -532,12 +565,16 @@ size_t UpdateClass::writeStream(Stream &data) {
     return 0;
   }
 
+#ifndef UPDATE_NOCRYPT
   if (_command == U_FLASH && !_cryptMode) {
+#endif /* UPDATE_NOCRYPT */
     if (!_verifyHeader(data.peek())) {
       _reset();
       return 0;
     }
+#ifndef UPDATE_NOCRYPT
   }
+#endif /* UPDATE_NOCRYPT */
 
   if (_ledPin != -1) {
     pinMode(_ledPin, OUTPUT);
diff --git a/libraries/WebServer/examples/MultiHomedServers/README.md b/libraries/WebServer/examples/MultiHomedServers/README.md
index 83ec6223850..04b96dfbd53 100644
--- a/libraries/WebServer/examples/MultiHomedServers/README.md
+++ b/libraries/WebServer/examples/MultiHomedServers/README.md
@@ -67,10 +67,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Example Log Output
 
 ```
diff --git a/libraries/WebServer/library.properties b/libraries/WebServer/library.properties
index 8985e6f5179..89e35e4713d 100644
--- a/libraries/WebServer/library.properties
+++ b/libraries/WebServer/library.properties
@@ -1,5 +1,5 @@
 name=WebServer
-version=3.0.5
+version=3.1.0
 author=Ivan Grokhotkov
 maintainer=Ivan Grokhtkov <ivan@esp8266.com>
 sentence=Simple web server library
diff --git a/libraries/WebServer/src/WebServer.cpp b/libraries/WebServer/src/WebServer.cpp
index 53c575d2c56..805cc9db167 100644
--- a/libraries/WebServer/src/WebServer.cpp
+++ b/libraries/WebServer/src/WebServer.cpp
@@ -460,7 +460,7 @@ void WebServer::handleClient() {
       case HC_WAIT_CLOSE:
         if (_currentClient.isSSE()) {
           // Never close connection
-          _statusChange = millis();
+          //_statusChange = millis();
         }
         // Wait for client to close the connection
         if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
diff --git a/libraries/WiFi/examples/FTM/FTM_Initiator/README.md b/libraries/WiFi/examples/FTM/FTM_Initiator/README.md
index 3558f75d372..b9c7f8d438d 100644
--- a/libraries/WiFi/examples/FTM/FTM_Initiator/README.md
+++ b/libraries/WiFi/examples/FTM/FTM_Initiator/README.md
@@ -55,10 +55,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or setting the `upload_port` option on the `platformio.ini` file.
-
 ## Log Output
 
 Expected log output:
diff --git a/libraries/WiFi/examples/FTM/FTM_Responder/README.md b/libraries/WiFi/examples/FTM/FTM_Responder/README.md
index feede0867f3..fdcf1ab921b 100644
--- a/libraries/WiFi/examples/FTM/FTM_Responder/README.md
+++ b/libraries/WiFi/examples/FTM/FTM_Responder/README.md
@@ -48,10 +48,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or setting the `upload_port` option on the `platformio.ini` file.
-
 ## Log Output
 
 Expected log output:
diff --git a/libraries/WiFi/examples/WPS/WPS.ino b/libraries/WiFi/examples/WPS/WPS.ino
index fc353dcbfb8..aacdd14ddab 100644
--- a/libraries/WiFi/examples/WPS/WPS.ino
+++ b/libraries/WiFi/examples/WPS/WPS.ino
@@ -14,6 +14,11 @@ Author:
 Pranav Cherukupalli <cherukupallip@gmail.com>
 */
 
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#error "WPS is only supported in SoCs with native Wi-Fi support"
+#endif
+
 #include "WiFi.h"
 #include "esp_wps.h"
 /*
diff --git a/libraries/WiFi/examples/WPS/ci.json b/libraries/WiFi/examples/WPS/ci.json
index 618e46bd244..36babb82730 100644
--- a/libraries/WiFi/examples/WPS/ci.json
+++ b/libraries/WiFi/examples/WPS/ci.json
@@ -1,6 +1,5 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/WiFi/examples/WiFiClient/README.md b/libraries/WiFi/examples/WiFiClient/README.md
index 8b6a5d9caeb..9d3698a543a 100644
--- a/libraries/WiFi/examples/WiFiClient/README.md
+++ b/libraries/WiFi/examples/WiFiClient/README.md
@@ -61,10 +61,6 @@ To get more information about the Espressif boards see [Espressif Development Ki
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Example Log Output
 
 The initial output which is common for all examples can be ignored:
diff --git a/libraries/WiFi/examples/WiFiClientConnect/README.md b/libraries/WiFi/examples/WiFiClientConnect/README.md
index eab02b674ff..939d44c5b76 100644
--- a/libraries/WiFi/examples/WiFiClientConnect/README.md
+++ b/libraries/WiFi/examples/WiFiClientConnect/README.md
@@ -18,10 +18,6 @@ Currently, this example supports the following targets.
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port`` option on the `platformio.ini` file.
-
 ## Example/Log Output
 
 ```
diff --git a/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino b/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino
index 75b7a4dcc06..198f97e2805 100644
--- a/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino
+++ b/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino
@@ -1,3 +1,8 @@
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#error "WPA-Enterprise is only supported in SoCs with native Wi-Fi support"
+#endif
+
 #include <WiFi.h>                      //Wifi library
 #define EAP_IDENTITY "login"           //if connecting from another corporation, use identity@organization.domain in Eduroam
 #define EAP_USERNAME "login"           //oftentimes just a repeat of the identity
diff --git a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json
index 618e46bd244..36babb82730 100644
--- a/libraries/WiFi/examples/WiFiClientEnterprise/ci.json
+++ b/libraries/WiFi/examples/WiFiClientEnterprise/ci.json
@@ -1,6 +1,5 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/WiFi/examples/WiFiScan/README.md b/libraries/WiFi/examples/WiFiScan/README.md
index ec39cc6c639..f1268f21b5c 100644
--- a/libraries/WiFi/examples/WiFiScan/README.md
+++ b/libraries/WiFi/examples/WiFiScan/README.md
@@ -18,10 +18,6 @@ Currently, this example supports the following targets.
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or setting the `upload_port` option on the `platformio.ini` file.
-
 ## Example/Log Output
 
 ```
diff --git a/libraries/WiFi/examples/WiFiScanAsync/README.md b/libraries/WiFi/examples/WiFiScanAsync/README.md
index a557173c10f..26120aaa31c 100644
--- a/libraries/WiFi/examples/WiFiScanAsync/README.md
+++ b/libraries/WiFi/examples/WiFiScanAsync/README.md
@@ -18,10 +18,6 @@ Currently, this example supports the following targets.
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or setting the `upload_port` option on the `platformio.ini` file.
-
 ## Example/Log Output
 
 ```
diff --git a/libraries/WiFi/examples/WiFiScanDualAntenna/README.md b/libraries/WiFi/examples/WiFiScanDualAntenna/README.md
index f7ec7cc3ef9..9a6611149d0 100644
--- a/libraries/WiFi/examples/WiFiScanDualAntenna/README.md
+++ b/libraries/WiFi/examples/WiFiScanDualAntenna/README.md
@@ -17,10 +17,6 @@ This example is compatible with the ESP32-WROOM-DA.
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file.
-
 ## Example/Log Output
 
 ```
diff --git a/libraries/WiFi/examples/WiFiScanTime/README.md b/libraries/WiFi/examples/WiFiScanTime/README.md
index f56ba893925..7be0e05d4fe 100644
--- a/libraries/WiFi/examples/WiFiScanTime/README.md
+++ b/libraries/WiFi/examples/WiFiScanTime/README.md
@@ -18,10 +18,6 @@ Currently, this example supports the following targets.
 * Before Compile/Verify, select the correct board: `Tools -> Board`.
 * Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
 
-#### Using Platform IO
-
-* Select the COM port: `Devices` or setting the `upload_port` option on the `platformio.ini` file.
-
 ## Example/Log Output
 
 ```
diff --git a/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino b/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino
index 6d372bb1098..724355c6a37 100644
--- a/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino
+++ b/libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino
@@ -1,3 +1,8 @@
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#error "SmartConfig is only supported in SoCs with native Wi-Fi support"
+#endif
+
 #include "WiFi.h"
 
 void setup() {
diff --git a/libraries/WiFi/examples/WiFiSmartConfig/ci.json b/libraries/WiFi/examples/WiFiSmartConfig/ci.json
index 618e46bd244..36babb82730 100644
--- a/libraries/WiFi/examples/WiFiSmartConfig/ci.json
+++ b/libraries/WiFi/examples/WiFiSmartConfig/ci.json
@@ -1,6 +1,5 @@
 {
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/WiFi/library.properties b/libraries/WiFi/library.properties
index fa63459c166..925616ea561 100644
--- a/libraries/WiFi/library.properties
+++ b/libraries/WiFi/library.properties
@@ -1,5 +1,5 @@
 name=WiFi
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Enables network connection (local and Internet) using the ESP32 built-in WiFi.
diff --git a/libraries/WiFi/src/AP.cpp b/libraries/WiFi/src/AP.cpp
index a61be662495..b713a6d3901 100644
--- a/libraries/WiFi/src/AP.cpp
+++ b/libraries/WiFi/src/AP.cpp
@@ -7,7 +7,7 @@
 #include "WiFi.h"
 #include "WiFiGeneric.h"
 #include "WiFiAP.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -87,6 +87,7 @@ static void _onApArduinoEvent(arduino_event_t *ev) {
   }
   log_v("Arduino AP Event: %d - %s", ev->event_id, Network.eventName(ev->event_id));
   if (ev->event_id == ARDUINO_EVENT_WIFI_AP_START) {
+#if CONFIG_LWIP_IPV6
     if (_ap_network_if->getStatusBits() & ESP_NETIF_WANT_IP6_BIT) {
       esp_err_t err = esp_netif_create_ip6_linklocal(_ap_network_if->netif());
       if (err != ESP_OK) {
@@ -95,6 +96,7 @@ static void _onApArduinoEvent(arduino_event_t *ev) {
         log_v("Enabled IPv6 Link Local on %s", _ap_network_if->desc());
       }
     }
+#endif
   }
 }
 
diff --git a/libraries/WiFi/src/STA.cpp b/libraries/WiFi/src/STA.cpp
index 443d2621957..547a27d1c47 100644
--- a/libraries/WiFi/src/STA.cpp
+++ b/libraries/WiFi/src/STA.cpp
@@ -6,7 +6,7 @@
 #include "WiFi.h"
 #include "WiFiGeneric.h"
 #include "WiFiSTA.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -118,6 +118,7 @@ static void _onStaArduinoEvent(arduino_event_t *ev) {
     _sta_network_if->_setStatus(WL_STOPPED);
   } else if (ev->event_id == ARDUINO_EVENT_WIFI_STA_CONNECTED) {
     _sta_network_if->_setStatus(WL_IDLE_STATUS);
+#if CONFIG_LWIP_IPV6
     if (_sta_network_if->getStatusBits() & ESP_NETIF_WANT_IP6_BIT) {
       esp_err_t err = esp_netif_create_ip6_linklocal(_sta_network_if->netif());
       if (err != ESP_OK) {
@@ -126,6 +127,7 @@ static void _onStaArduinoEvent(arduino_event_t *ev) {
         log_v("Enabled IPv6 Link Local on %s", _sta_network_if->desc());
       }
     }
+#endif
   } else if (ev->event_id == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
     uint8_t reason = ev->event_info.wifi_sta_disconnected.reason;
     // Reason 0 causes crash, use reason 1 (UNSPECIFIED) instead
@@ -419,6 +421,7 @@ bool STAClass::connect(const char *ssid, const char *passphrase, int32_t channel
   return true;
 }
 
+#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT
 /**
  * Start Wifi connection with a WPA2 Enterprise AP
  * if passphrase is set the most secure supported mode will be automatically selected
@@ -517,6 +520,7 @@ bool STAClass::connect(
 
   return connect(wpa2_ssid, NULL, channel, bssid, tryConnect);  //connect to wifi
 }
+#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */
 
 bool STAClass::disconnect(bool eraseap, unsigned long timeout) {
   if (eraseap) {
diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp
index a854cb0ceb7..7fb0ed16459 100644
--- a/libraries/WiFi/src/WiFi.cpp
+++ b/libraries/WiFi/src/WiFi.cpp
@@ -22,7 +22,7 @@
 
  */
 #include "WiFi.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 extern "C" {
 #include <stdint.h>
diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h
index a823dabd864..ea2efd97697 100644
--- a/libraries/WiFi/src/WiFi.h
+++ b/libraries/WiFi/src/WiFi.h
@@ -22,7 +22,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include <stdint.h>
 
diff --git a/libraries/WiFi/src/WiFiAP.cpp b/libraries/WiFi/src/WiFiAP.cpp
index fac84dc8512..bb15ff44625 100644
--- a/libraries/WiFi/src/WiFiAP.cpp
+++ b/libraries/WiFi/src/WiFiAP.cpp
@@ -25,7 +25,7 @@
 #include "WiFi.h"
 #include "WiFiGeneric.h"
 #include "WiFiAP.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include <stdint.h>
 #include <stdbool.h>
@@ -177,6 +177,7 @@ bool WiFiAPClass::softAPsetHostname(const char *hostname) {
   return AP.setHostname(hostname);
 }
 
+#if CONFIG_LWIP_IPV6
 /**
  * Enable IPv6 on the softAP interface.
  * @return true on success
@@ -193,5 +194,5 @@ bool WiFiAPClass::softAPenableIPv6(bool enable) {
 IPAddress WiFiAPClass::softAPlinkLocalIPv6() {
   return AP.linkLocalIPv6();
 }
-
+#endif
 #endif /* SOC_WIFI_SUPPORTED */
diff --git a/libraries/WiFi/src/WiFiAP.h b/libraries/WiFi/src/WiFiAP.h
index 9acd124c27e..e80f91fa26c 100644
--- a/libraries/WiFi/src/WiFiAP.h
+++ b/libraries/WiFi/src/WiFiAP.h
@@ -23,7 +23,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include "esp_wifi_types.h"
 #include "WiFiType.h"
@@ -100,8 +101,10 @@ class WiFiAPClass {
   IPAddress softAPSubnetMask();
   uint8_t softAPSubnetCIDR();
 
+#if CONFIG_LWIP_IPV6
   bool softAPenableIPv6(bool enable = true);
   IPAddress softAPlinkLocalIPv6();
+#endif
 
   const char *softAPgetHostname();
   bool softAPsetHostname(const char *hostname);
diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp
index 6ddf384d009..40e3b12c687 100644
--- a/libraries/WiFi/src/WiFiGeneric.cpp
+++ b/libraries/WiFi/src/WiFiGeneric.cpp
@@ -24,7 +24,7 @@
 
 #include "WiFi.h"
 #include "WiFiGeneric.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 extern "C" {
 #include <stdint.h>
@@ -39,6 +39,9 @@ extern "C" {
 #include <esp_event.h>
 #include <esp_mac.h>
 #include <esp_netif.h>
+#if SOC_WIFI_SUPPORTED
+#include <esp_phy.h>
+#endif
 #include "lwip/ip_addr.h"
 #include "lwip/opt.h"
 #include "lwip/err.h"
@@ -102,6 +105,7 @@ static void _arduino_event_cb(void *arg, esp_event_base_t event_base, int32_t ev
     arduino_event.event_id = ARDUINO_EVENT_WIFI_FTM_REPORT;
     memcpy(&arduino_event.event_info.wifi_ftm_report, event_data, sizeof(wifi_event_ftm_report_t));
 
+#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
     /*
 	 * SMART CONFIG
 	 * */
@@ -123,6 +127,7 @@ static void _arduino_event_cb(void *arg, esp_event_base_t event_base, int32_t ev
     log_v("SC Send Ack Done");
     arduino_event.event_id = ARDUINO_EVENT_SC_SEND_ACK_DONE;
 
+#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
     /*
 	 * Provisioning
 	 * */
@@ -156,6 +161,8 @@ static void _arduino_event_cb(void *arg, esp_event_base_t event_base, int32_t ev
   } else if (event_base == NETWORK_PROV_EVENT && event_id == NETWORK_PROV_WIFI_CRED_SUCCESS) {
     log_v("Provisioning Success!");
     arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_SUCCESS;
+#endif
+#endif
   }
 
   if (arduino_event.event_id < ARDUINO_EVENT_MAX) {
@@ -169,15 +176,19 @@ static bool initWiFiEvents() {
     return false;
   }
 
+#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
   if (esp_event_handler_instance_register(SC_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb, NULL, NULL)) {
     log_e("event_handler_instance_register for SC_EVENT Failed!");
     return false;
   }
 
+#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
   if (esp_event_handler_instance_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb, NULL, NULL)) {
     log_e("event_handler_instance_register for NETWORK_PROV_EVENT Failed!");
     return false;
   }
+#endif
+#endif
 
   return true;
 }
@@ -188,15 +199,19 @@ static bool deinitWiFiEvents() {
     return false;
   }
 
+#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
   if (esp_event_handler_unregister(SC_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb)) {
     log_e("esp_event_handler_unregister for SC_EVENT Failed!");
     return false;
   }
 
+#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
   if (esp_event_handler_unregister(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &_arduino_event_cb)) {
     log_e("esp_event_handler_unregister for NETWORK_PROV_EVENT Failed!");
     return false;
   }
+#endif
+#endif
 
   return true;
 }
@@ -224,9 +239,57 @@ void WiFiGenericClass::useStaticBuffers(bool bufferMode) {
 extern "C" void phy_bbpll_en_usb(bool en);
 #endif
 
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+extern "C" {
+//#include "esp_hosted.h"
+#include "esp_hosted_transport_config.h"
+extern esp_err_t esp_hosted_init();
+extern esp_err_t esp_hosted_deinit();
+};
+static bool hosted_initialized = false;
+
+static bool wifiHostedInit() {
+  if (!hosted_initialized) {
+    hosted_initialized = true;
+    struct esp_hosted_sdio_config conf = INIT_DEFAULT_HOST_SDIO_CONFIG();
+    conf.pin_clk.pin = CONFIG_ESP_SDIO_PIN_CLK;
+    conf.pin_cmd.pin = CONFIG_ESP_SDIO_PIN_CMD;
+    conf.pin_d0.pin = CONFIG_ESP_SDIO_PIN_D0;
+    conf.pin_d1.pin = CONFIG_ESP_SDIO_PIN_D1;
+    conf.pin_d2.pin = CONFIG_ESP_SDIO_PIN_D2;
+    conf.pin_d3.pin = CONFIG_ESP_SDIO_PIN_D3;
+    //conf.pin_rst.pin = CONFIG_ESP_SDIO_GPIO_RESET_SLAVE;
+    // esp_hosted_sdio_set_config() will fail on second attempt but here temporarily to not cause exception on reinit
+    if (esp_hosted_sdio_set_config(&conf) != ESP_OK || esp_hosted_init() != ESP_OK) {
+      log_e("esp_hosted_init failed!");
+      hosted_initialized = false;
+      return false;
+    }
+    log_v("ESP-HOSTED initialized!");
+  }
+  // Attach pins to PeriMan here
+  // Slave chip model is CONFIG_IDF_SLAVE_TARGET
+  // CONFIG_ESP_SDIO_PIN_CMD
+  // CONFIG_ESP_SDIO_PIN_CLK
+  // CONFIG_ESP_SDIO_PIN_D0
+  // CONFIG_ESP_SDIO_PIN_D1
+  // CONFIG_ESP_SDIO_PIN_D2
+  // CONFIG_ESP_SDIO_PIN_D3
+  // CONFIG_ESP_SDIO_GPIO_RESET_SLAVE
+
+  return true;
+}
+#endif
+
 bool wifiLowLevelInit(bool persistent) {
   if (!lowLevelInitDone) {
     lowLevelInitDone = true;
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+    if (!wifiHostedInit()) {
+      lowLevelInitDone = false;
+      return lowLevelInitDone;
+    }
+#endif
     if (!Network.begin()) {
       lowLevelInitDone = false;
       return lowLevelInitDone;
@@ -290,6 +353,13 @@ static bool wifiLowLevelDeinit() {
       arduino_event_t arduino_event;
       arduino_event.event_id = ARDUINO_EVENT_WIFI_OFF;
       Network.postEvent(&arduino_event);
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+      if (hosted_initialized && esp_hosted_deinit() == ESP_OK) {
+        hosted_initialized = false;
+        log_v("ESP-HOSTED uninitialized!");
+        // detach SDIO pins from PeriMan
+      }
+#endif
     }
   }
   return !lowLevelInitDone;
@@ -369,6 +439,7 @@ void WiFiGenericClass::_eventCallback(arduino_event_t *event) {
   // log_d("Arduino Event: %d - %s", event->event_id, WiFi.eventName(event->event_id));
   if (event->event_id == ARDUINO_EVENT_WIFI_SCAN_DONE) {
     WiFiScanClass::_scanDone();
+#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
   } else if (event->event_id == ARDUINO_EVENT_SC_GOT_SSID_PSWD) {
     WiFi.begin(
       (const char *)event->event_info.sc_got_ssid_pswd.ssid, (const char *)event->event_info.sc_got_ssid_pswd.password, 0,
@@ -377,6 +448,7 @@ void WiFiGenericClass::_eventCallback(arduino_event_t *event) {
   } else if (event->event_id == ARDUINO_EVENT_SC_SEND_ACK_DONE) {
     esp_smartconfig_stop();
     WiFiSTAClass::_smartConfigDone = true;
+#endif
   }
 }
 
@@ -692,10 +764,11 @@ bool WiFiGenericClass::initiateFTM(uint8_t frm_count, uint16_t burst_period, uin
  * @return true on success
  */
 bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2, wifi_rx_ant_t rx_mode, wifi_tx_ant_t tx_mode) {
+#if !CONFIG_ESP_WIFI_REMOTE_ENABLED
 
-  wifi_ant_gpio_config_t wifi_ant_io;
+  esp_phy_ant_gpio_config_t wifi_ant_io;
 
-  if (ESP_OK != esp_wifi_get_ant_gpio(&wifi_ant_io)) {
+  if (ESP_OK != esp_phy_get_ant_gpio(&wifi_ant_io)) {
     log_e("Failed to get antenna configuration");
     return false;
   }
@@ -705,60 +778,60 @@ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2
   wifi_ant_io.gpio_cfg[1].gpio_num = gpio_ant2;
   wifi_ant_io.gpio_cfg[1].gpio_select = 1;
 
-  if (ESP_OK != esp_wifi_set_ant_gpio(&wifi_ant_io)) {
+  if (ESP_OK != esp_phy_set_ant_gpio(&wifi_ant_io)) {
     log_e("Failed to set antenna GPIO configuration");
     return false;
   }
 
   // Set antenna default configuration
-  wifi_ant_config_t ant_config = {
-    .rx_ant_mode = WIFI_ANT_MODE_AUTO,
-    .rx_ant_default = WIFI_ANT_MAX,  // Ignored in AUTO mode
-    .tx_ant_mode = WIFI_ANT_MODE_AUTO,
+  esp_phy_ant_config_t ant_config = {
+    .rx_ant_mode = ESP_PHY_ANT_MODE_AUTO,
+    .rx_ant_default = ESP_PHY_ANT_MAX,  // Ignored in AUTO mode
+    .tx_ant_mode = ESP_PHY_ANT_MODE_AUTO,
     .enabled_ant0 = 1,
     .enabled_ant1 = 2,
   };
 
   switch (rx_mode) {
-    case WIFI_RX_ANT0: ant_config.rx_ant_mode = WIFI_ANT_MODE_ANT0; break;
-    case WIFI_RX_ANT1: ant_config.rx_ant_mode = WIFI_ANT_MODE_ANT1; break;
+    case WIFI_RX_ANT0: ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_ANT0; break;
+    case WIFI_RX_ANT1: ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_ANT1; break;
     case WIFI_RX_ANT_AUTO:
       log_i("TX Antenna will be automatically selected");
-      ant_config.rx_ant_default = WIFI_ANT_ANT0;
-      ant_config.rx_ant_mode = WIFI_ANT_MODE_AUTO;
+      ant_config.rx_ant_default = ESP_PHY_ANT_ANT0;
+      ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
       // Force TX for AUTO if RX is AUTO
-      ant_config.tx_ant_mode = WIFI_ANT_MODE_AUTO;
+      ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
       goto set_ant;
       break;
     default:
       log_e("Invalid default antenna! Falling back to AUTO");
-      ant_config.rx_ant_mode = WIFI_ANT_MODE_AUTO;
+      ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
       break;
   }
 
   switch (tx_mode) {
-    case WIFI_TX_ANT0: ant_config.tx_ant_mode = WIFI_ANT_MODE_ANT0; break;
-    case WIFI_TX_ANT1: ant_config.tx_ant_mode = WIFI_ANT_MODE_ANT1; break;
+    case WIFI_TX_ANT0: ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_ANT0; break;
+    case WIFI_TX_ANT1: ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_ANT1; break;
     case WIFI_TX_ANT_AUTO:
       log_i("RX Antenna will be automatically selected");
-      ant_config.rx_ant_default = WIFI_ANT_ANT0;
-      ant_config.tx_ant_mode = WIFI_ANT_MODE_AUTO;
+      ant_config.rx_ant_default = ESP_PHY_ANT_ANT0;
+      ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
       // Force RX for AUTO if RX is AUTO
-      ant_config.rx_ant_mode = WIFI_ANT_MODE_AUTO;
+      ant_config.rx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
       break;
     default:
       log_e("Invalid default antenna! Falling back to AUTO");
-      ant_config.rx_ant_default = WIFI_ANT_ANT0;
-      ant_config.tx_ant_mode = WIFI_ANT_MODE_AUTO;
+      ant_config.rx_ant_default = ESP_PHY_ANT_ANT0;
+      ant_config.tx_ant_mode = ESP_PHY_ANT_MODE_AUTO;
       break;
   }
 
 set_ant:
-  if (ESP_OK != esp_wifi_set_ant(&ant_config)) {
+  if (ESP_OK != esp_phy_set_ant(&ant_config)) {
     log_e("Failed to set antenna configuration");
     return false;
   }
-
+#endif
   return true;
 }
 
diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h
index 2a5ca812999..ed216229ed4 100644
--- a/libraries/WiFi/src/WiFiGeneric.h
+++ b/libraries/WiFi/src/WiFiGeneric.h
@@ -23,7 +23,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include "esp_err.h"
 #include "esp_event.h"
@@ -32,8 +33,12 @@
 #include "IPAddress.h"
 #include "esp_smartconfig.h"
 #include "esp_netif_types.h"
+#if CONFIG_ETH_ENABLED
 #include "esp_eth_driver.h"
+#endif
+#if CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
 #include "network_provisioning/manager.h"
+#endif
 #include "lwip/ip_addr.h"
 
 #include "Network.h"
diff --git a/libraries/WiFi/src/WiFiMulti.cpp b/libraries/WiFi/src/WiFiMulti.cpp
index a438919f792..c99bef5ac90 100644
--- a/libraries/WiFi/src/WiFiMulti.cpp
+++ b/libraries/WiFi/src/WiFiMulti.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "WiFiMulti.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 #include <limits.h>
 #include <string.h>
 #include <esp32-hal.h>
@@ -251,9 +251,11 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout, bool scanHidden) {
         bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb
       );
 
+#if CONFIG_LWIP_IPV6
       if (ipv6_support == true) {
         WiFi.enableIPv6();
       }
+#endif
       WiFi.disconnect();
       delay(10);
       WiFi.begin(bestNetwork.ssid, (_bAllowOpenAP && bestNetworkSec == WIFI_AUTH_OPEN) ? NULL : bestNetwork.passphrase, bestChannel, bestBSSID);
@@ -318,9 +320,11 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout, bool scanHidden) {
   return status;
 }
 
+#if CONFIG_LWIP_IPV6
 void WiFiMulti::enableIPv6(bool state) {
   ipv6_support = state;
 }
+#endif
 
 void WiFiMulti::markAsFailed(int32_t i) {
   APlist[i].hasFailed = true;
diff --git a/libraries/WiFi/src/WiFiMulti.h b/libraries/WiFi/src/WiFiMulti.h
index 1e11ff13f51..d818f77899f 100644
--- a/libraries/WiFi/src/WiFiMulti.h
+++ b/libraries/WiFi/src/WiFiMulti.h
@@ -26,7 +26,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include "WiFi.h"
 #include <vector>
@@ -46,7 +47,9 @@ class WiFiMulti {
 
   bool addAP(const char *ssid, const char *passphrase = NULL);
   uint8_t run(uint32_t connectTimeout = 5000, bool scanHidden = false);
+#if CONFIG_LWIP_IPV6
   void enableIPv6(bool state);
+#endif
 
   // Force (default: true) to only keep connected or to connect to an AP from the provided WiFiMulti list.
   // When bStrict is false, it will keep the last/current connected AP even if not in the WiFiMulti List.
diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp
index 99c02a4b81d..b956e35ba26 100644
--- a/libraries/WiFi/src/WiFiSTA.cpp
+++ b/libraries/WiFi/src/WiFiSTA.cpp
@@ -25,7 +25,7 @@
 #include "WiFi.h"
 #include "WiFiGeneric.h"
 #include "WiFiSTA.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include <stdint.h>
 #include <stdbool.h>
@@ -63,6 +63,7 @@ wl_status_t WiFiSTAClass::status() {
   return STA.status();
 }
 
+#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT
 wl_status_t WiFiSTAClass::begin(
   const char *wpa2_ssid, wpa2_auth_method_t method, const char *wpa2_identity, const char *wpa2_username, const char *wpa2_password, const char *ca_pem,
   const char *client_crt, const char *client_key, int ttls_phase2_type, int32_t channel, const uint8_t *bssid, bool connect
@@ -77,6 +78,7 @@ wl_status_t WiFiSTAClass::begin(
 
   return STA.status();
 }
+#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */
 
 wl_status_t WiFiSTAClass::begin(const char *ssid, const char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) {
   if (!STA.begin()) {
@@ -386,6 +388,7 @@ int8_t WiFiSTAClass::RSSI(void) {
   return STA.RSSI();
 }
 
+#if CONFIG_LWIP_IPV6
 /**
  * Enable IPv6 on the station interface.
  * Should be called before WiFi.begin()
@@ -411,6 +414,7 @@ IPAddress WiFiSTAClass::linkLocalIPv6() {
 IPAddress WiFiSTAClass::globalIPv6() {
   return STA.globalIPv6();
 }
+#endif
 
 bool WiFiSTAClass::_smartConfigStarted = false;
 bool WiFiSTAClass::_smartConfigDone = false;
diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h
index 2c046c4c4b9..3c8adbd8502 100644
--- a/libraries/WiFi/src/WiFiSTA.h
+++ b/libraries/WiFi/src/WiFiSTA.h
@@ -23,7 +23,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include "WiFiType.h"
 #include "WiFiGeneric.h"
@@ -53,11 +54,13 @@ class STAClass : public NetworkInterface {
 
   bool connect();
   bool connect(const char *ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true);
+#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT
   bool connect(
     const char *wpa2_ssid, wpa2_auth_method_t method, const char *wpa2_identity = NULL, const char *wpa2_username = NULL, const char *wpa2_password = NULL,
     const char *ca_pem = NULL, const char *client_crt = NULL, const char *client_key = NULL, int ttls_phase2_type = -1, int32_t channel = 0,
     const uint8_t *bssid = 0, bool connect = true
   );
+#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */
   bool disconnect(bool eraseap = false, unsigned long timeout = 0);
   bool reconnect();
   bool erase();
@@ -108,6 +111,7 @@ class WiFiSTAClass {
 public:
   STAClass STA;
 
+#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT
   wl_status_t begin(
     const char *wpa2_ssid, wpa2_auth_method_t method, const char *wpa2_identity = NULL, const char *wpa2_username = NULL, const char *wpa2_password = NULL,
     const char *ca_pem = NULL, const char *client_crt = NULL, const char *client_key = NULL, int ttls_phase2_type = -1, int32_t channel = 0,
@@ -123,6 +127,8 @@ class WiFiSTAClass {
       ttls_phase2_type, channel, bssid, connect
     );
   }
+#endif /* CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT */
+
   wl_status_t begin(const char *ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true);
   wl_status_t begin(const String &ssid, const String &passphrase = (const char *)NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true) {
     return begin(ssid.c_str(), passphrase.c_str(), channel, bssid, connect);
@@ -179,9 +185,11 @@ class WiFiSTAClass {
   IPAddress networkID();
   uint8_t subnetCIDR();
 
+#if CONFIG_LWIP_IPV6
   bool enableIPv6(bool en = true);
   IPAddress linkLocalIPv6();
   IPAddress globalIPv6();
+#endif
 
   // ----------------------------------------------------------------------------------------------
   // ---------------------------------------- Smart Config ----------------------------------------
diff --git a/libraries/WiFi/src/WiFiScan.cpp b/libraries/WiFi/src/WiFiScan.cpp
index ffacc57f093..27d9edcc70c 100644
--- a/libraries/WiFi/src/WiFiScan.cpp
+++ b/libraries/WiFi/src/WiFiScan.cpp
@@ -25,7 +25,7 @@
 #include "WiFi.h"
 #include "WiFiGeneric.h"
 #include "WiFiScan.h"
-#if SOC_WIFI_SUPPORTED
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 extern "C" {
 #include <stdint.h>
diff --git a/libraries/WiFi/src/WiFiScan.h b/libraries/WiFi/src/WiFiScan.h
index 0648885292f..7afd26bb76a 100644
--- a/libraries/WiFi/src/WiFiScan.h
+++ b/libraries/WiFi/src/WiFiScan.h
@@ -23,7 +23,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include "WiFiType.h"
 #include "WiFiGeneric.h"
diff --git a/libraries/WiFi/src/WiFiType.h b/libraries/WiFi/src/WiFiType.h
index 1d721d33963..29af9ce2252 100644
--- a/libraries/WiFi/src/WiFiType.h
+++ b/libraries/WiFi/src/WiFiType.h
@@ -22,7 +22,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED
 
 #include "esp_wifi_types.h"
 
diff --git a/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino b/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino
index 59b8bfc359e..76025d75770 100644
--- a/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino
+++ b/libraries/WiFiProv/examples/WiFiProv/WiFiProv.ino
@@ -8,6 +8,11 @@ Note: This sketch takes up a lot of space for the app and may not be able to fla
    - for example "No OTA (2MB APP/2MB SPIFFS)"
 */
 
+#include "sdkconfig.h"
+#if CONFIG_ESP_WIFI_REMOTE_ENABLED
+#error "WiFiProv is only supported in SoCs with native Wi-Fi support"
+#endif
+
 #include "WiFiProv.h"
 #include "WiFi.h"
 
diff --git a/libraries/WiFiProv/examples/WiFiProv/ci.json b/libraries/WiFiProv/examples/WiFiProv/ci.json
index cbdd28f773d..04eb62b977a 100644
--- a/libraries/WiFiProv/examples/WiFiProv/ci.json
+++ b/libraries/WiFiProv/examples/WiFiProv/ci.json
@@ -1,7 +1,6 @@
 {
   "fqbn_append": "PartitionScheme=huge_app",
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/libraries/WiFiProv/library.properties b/libraries/WiFiProv/library.properties
index cbba5a3fbeb..20e27fc5097 100644
--- a/libraries/WiFiProv/library.properties
+++ b/libraries/WiFiProv/library.properties
@@ -1,5 +1,5 @@
 name=WiFiProv
-version=3.0.5
+version=3.1.0
 author=Switi Mhaiske <sweetymhaiske@gmail.com>
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Enables provisioning.
diff --git a/libraries/WiFiProv/src/WiFiProv.cpp b/libraries/WiFiProv/src/WiFiProv.cpp
index f4008d44ded..55fbd473f88 100644
--- a/libraries/WiFiProv/src/WiFiProv.cpp
+++ b/libraries/WiFiProv/src/WiFiProv.cpp
@@ -18,7 +18,8 @@
 
 */
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED && CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
 
 #include <stdio.h>
 #include <stdint.h>
diff --git a/libraries/WiFiProv/src/WiFiProv.h b/libraries/WiFiProv/src/WiFiProv.h
index 44dda82ad0e..a4a3397ed06 100644
--- a/libraries/WiFiProv/src/WiFiProv.h
+++ b/libraries/WiFiProv/src/WiFiProv.h
@@ -20,7 +20,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_WIFI_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_WIFI_SUPPORTED && CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
 
 #include "WiFi.h"
 #include "HardwareSerial.h"
diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties
index 2d4ef887e34..a2d79eee81b 100644
--- a/libraries/Wire/library.properties
+++ b/libraries/Wire/library.properties
@@ -1,5 +1,5 @@
 name=Wire
-version=3.0.5
+version=3.1.0
 author=Hristo Gochkov
 maintainer=Hristo Gochkov <hristo@espressif.com>
 sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For esp8266 boards.
diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp
index 8ac0c25595d..24b0eb7c0a3 100644
--- a/libraries/Wire/src/Wire.cpp
+++ b/libraries/Wire/src/Wire.cpp
@@ -646,8 +646,8 @@ void TwoWire::onRequestService(uint8_t num, void *arg) {
 #endif /* SOC_I2C_SUPPORT_SLAVE */
 
 TwoWire Wire = TwoWire(0);
-#if SOC_I2C_NUM > 1
+#if SOC_HP_I2C_NUM > 1
 TwoWire Wire1 = TwoWire(1);
-#endif /* SOC_I2C_NUM */
+#endif /* SOC_HP_I2C_NUM */
 
 #endif /* SOC_I2C_SUPPORTED */
diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h
index cf720d48234..45f30c81ffc 100644
--- a/libraries/Wire/src/Wire.h
+++ b/libraries/Wire/src/Wire.h
@@ -144,9 +144,9 @@ class TwoWire : public HardwareI2C {
 };
 
 extern TwoWire Wire;
-#if SOC_I2C_NUM > 1
+#if SOC_HP_I2C_NUM > 1
 extern TwoWire Wire1;
-#endif /* SOC_I2C_NUM */
+#endif /* SOC_HP_I2C_NUM */
 
 #endif /* SOC_I2C_SUPPORTED */
 #endif /* TwoWire_h */
diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino
index c03d26d3aba..7ff7a020632 100644
--- a/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino
+++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmable_Light/Zigbee_Color_Dimmable_Light.ino
@@ -41,6 +41,10 @@ ZigbeeColorDimmableLight zbColorLight = ZigbeeColorDimmableLight(ZIGBEE_LIGHT_EN
 
 /********************* RGB LED functions **************************/
 void setRGBLight(bool state, uint8_t red, uint8_t green, uint8_t blue, uint8_t level) {
+  if (!state) {
+    rgbLedWrite(LED_PIN, 0, 0, 0);
+    return;
+  }
   float brightness = (float)level / 255;
   rgbLedWrite(LED_PIN, red * brightness, green * brightness, blue * brightness);
 }
@@ -60,6 +64,11 @@ void identify(uint16_t time) {
 
 /********************* Arduino functions **************************/
 void setup() {
+  Serial.begin(115200);
+  while (!Serial) {
+    delay(10);
+  }
+
   // Init RMT and leave light OFF
   rgbLedWrite(LED_PIN, 0, 0, 0);
 
@@ -76,12 +85,21 @@ void setup() {
   zbColorLight.setManufacturerAndModel("Espressif", "ZBColorLightBulb");
 
   // Add endpoint to Zigbee Core
-  log_d("Adding ZigbeeLight endpoint to Zigbee Core");
+  Serial.println("Adding ZigbeeLight endpoint to Zigbee Core");
   Zigbee.addEndpoint(&zbColorLight);
 
-  // When all EPs are registered, start Zigbee. By default acts as ZIGBEE_END_DEVICE
-  log_d("Calling Zigbee.begin()");
-  Zigbee.begin();
+  // When all EPs are registered, start Zigbee in End Device mode
+  if (!Zigbee.begin()) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
+  }
+  Serial.println("Connecting to network");
+  while (!Zigbee.connected()) {
+    Serial.print(".");
+    delay(100);
+  }
+  Serial.println();
 }
 
 void loop() {
@@ -94,10 +112,13 @@ void loop() {
       delay(50);
       if ((millis() - startTime) > 3000) {
         // If key pressed for more than 3secs, factory reset Zigbee and reboot
-        Serial.printf("Resetting Zigbee to factory settings, reboot.\n");
+        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
+        delay(1000);
         Zigbee.factoryReset();
       }
     }
+    // Increase blightness by 50 every time the button is pressed
+    zbColorLight.setLightLevel(zbColorLight.getLightLevel() + 50);
   }
   delay(100);
 }
diff --git a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino
index 6d6c7b163dd..15e120a1dbd 100644
--- a/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino
+++ b/libraries/Zigbee/examples/Zigbee_Color_Dimmer_Switch/Zigbee_Color_Dimmer_Switch.ino
@@ -46,7 +46,6 @@ ZigbeeColorDimmerSwitch zbSwitch = ZigbeeColorDimmerSwitch(SWITCH_ENDPOINT_NUMBE
 
 /********************* Arduino functions **************************/
 void setup() {
-
   Serial.begin(115200);
   while (!Serial) {
     delay(10);
@@ -68,11 +67,15 @@ void setup() {
   Zigbee.setRebootOpenNetwork(180);
 
   //When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode
-  Zigbee.begin(ZIGBEE_COORDINATOR);
+  if (!Zigbee.begin(ZIGBEE_COORDINATOR)) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
+  }
 
   Serial.println("Waiting for Light to bound to the switch");
   //Wait for switch to bound to a light:
-  while (!zbSwitch.isBound()) {
+  while (!zbSwitch.bound()) {
     Serial.printf(".");
     delay(500);
   }
@@ -142,6 +145,6 @@ void loop() {
   static uint32_t last_print = 0;
   if (millis() - last_print > 30000) {
     last_print = millis();
-    zbSwitch.printBoundDevices();
+    zbSwitch.printBoundDevices(Serial);
   }
 }
diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino b/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino
index 30e3cd2d109..92c59044cae 100644
--- a/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino
+++ b/libraries/Zigbee/examples/Zigbee_On_Off_Light/Zigbee_On_Off_Light.ino
@@ -45,6 +45,10 @@ void setLED(bool value) {
 
 /********************* Arduino functions **************************/
 void setup() {
+  Serial.begin(115200);
+  while (!Serial) {
+    delay(10);
+  }
   // Init LED and turn it OFF (if LED_PIN == RGB_BUILTIN, the rgbLedWrite() will be used under the hood)
   pinMode(LED_PIN, OUTPUT);
   digitalWrite(LED_PIN, LOW);
@@ -59,12 +63,21 @@ void setup() {
   zbLight.onLightChange(setLED);
 
   //Add endpoint to Zigbee Core
-  log_d("Adding ZigbeeLight endpoint to Zigbee Core");
+  Serial.println("Adding ZigbeeLight endpoint to Zigbee Core");
   Zigbee.addEndpoint(&zbLight);
 
   // When all EPs are registered, start Zigbee. By default acts as ZIGBEE_END_DEVICE
-  log_d("Calling Zigbee.begin()");
-  Zigbee.begin();
+  if (!Zigbee.begin()) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
+  }
+  Serial.println("Connecting to network");
+  while (!Zigbee.connected()) {
+    Serial.print(".");
+    delay(100);
+  }
+  Serial.println();
 }
 
 void loop() {
@@ -77,10 +90,13 @@ void loop() {
       delay(50);
       if ((millis() - startTime) > 3000) {
         // If key pressed for more than 3secs, factory reset Zigbee and reboot
-        Serial.printf("Resetting Zigbee to factory settings, reboot.\n");
+        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
+        delay(1000);
         Zigbee.factoryReset();
       }
     }
+    // Toggle light by pressing the button
+    zbLight.setLight(!zbLight.getLightState());
   }
   delay(100);
 }
diff --git a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino
index 69cf6654a41..e12b8aaf9ea 100644
--- a/libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino
+++ b/libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino
@@ -70,6 +70,7 @@ ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER);
 static void onZbButton(SwitchData *button_func_pair) {
   if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) {
     // Send toggle command to the light
+    Serial.println("Toggling light");
     zbSwitch.lightToggle();
   }
 }
@@ -93,7 +94,6 @@ static void enableGpioInterrupt(bool enabled) {
 
 /********************* Arduino functions **************************/
 void setup() {
-
   Serial.begin(115200);
   while (!Serial) {
     delay(10);
@@ -106,7 +106,7 @@ void setup() {
   zbSwitch.allowMultipleBinding(true);
 
   //Add endpoint to Zigbee Core
-  log_d("Adding ZigbeeSwitch endpoint to Zigbee Core");
+  Serial.println("Adding ZigbeeSwitch endpoint to Zigbee Core");
   Zigbee.addEndpoint(&zbSwitch);
 
   //Open network for 180 seconds after boot
@@ -118,34 +118,36 @@ void setup() {
     /* create a queue to handle gpio event from isr */
     gpio_evt_queue = xQueueCreate(10, sizeof(SwitchData));
     if (gpio_evt_queue == 0) {
-      log_e("Queue was not created and must not be used");
-      while (1);
+      Serial.println("Queue creating failed, rebooting...");
+      ESP.restart();
     }
     attachInterruptArg(buttonFunctionPair[i].pin, onGpioInterrupt, (void *)(buttonFunctionPair + i), FALLING);
   }
 
   // When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode
-  log_d("Calling Zigbee.begin()");
-  Zigbee.begin(ZIGBEE_COORDINATOR);
+  if (!Zigbee.begin(ZIGBEE_COORDINATOR)) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
+  }
 
   Serial.println("Waiting for Light to bound to the switch");
   //Wait for switch to bound to a light:
-  while (!zbSwitch.isBound()) {
+  while (!zbSwitch.bound()) {
     Serial.printf(".");
     delay(500);
   }
 
-  // Optional: read manufacturer and model name from the bound light
+  // Optional: List all bound devices and read manufacturer and model name
   std::list<zb_device_params_t *> boundLights = zbSwitch.getBoundDevices();
-  //List all bound lights
   for (const auto &device : boundLights) {
-    Serial.printf("Device on endpoint %d, short address: 0x%x\n", device->endpoint, device->short_addr);
+    Serial.printf("Device on endpoint %d, short address: 0x%x\r\n", device->endpoint, device->short_addr);
     Serial.printf(
-      "IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", device->ieee_addr[0], device->ieee_addr[1], device->ieee_addr[2], device->ieee_addr[3],
-      device->ieee_addr[4], device->ieee_addr[5], device->ieee_addr[6], device->ieee_addr[7]
+      "IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4],
+      device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0]
     );
-    Serial.printf("Light manufacturer: %s", zbSwitch.readManufacturer(device->endpoint, device->short_addr));
-    Serial.printf("Light model: %s", zbSwitch.readModel(device->endpoint, device->short_addr));
+    Serial.printf("Light manufacturer: %s\r\n", zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr));
+    Serial.printf("Light model: %s\r\n", zbSwitch.readModel(device->endpoint, device->short_addr, device->ieee_addr));
   }
 
   Serial.println();
@@ -188,6 +190,6 @@ void loop() {
   static uint32_t lastPrint = 0;
   if (millis() - lastPrint > 10000) {
     lastPrint = millis();
-    zbSwitch.printBoundDevices();
+    zbSwitch.printBoundDevices(Serial);
   }
 }
diff --git a/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino b/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino
index 7d59fb2907d..c3a74e0aee5 100644
--- a/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino
+++ b/libraries/Zigbee/examples/Zigbee_Scan_Networks/Zigbee_Scan_Networks.ino
@@ -32,7 +32,7 @@
 #include "Zigbee.h"
 
 #ifdef ZIGBEE_MODE_ZCZR
-zigbee_role_t role = ZIGBEE_ROUTER;  // or can be ZIGBEE_COORDINATOR, but it wont scan itself
+zigbee_role_t role = ZIGBEE_ROUTER;  // or can be ZIGBEE_COORDINATOR, but it won't scan itself
 #else
 zigbee_role_t role = ZIGBEE_END_DEVICE;
 #endif
@@ -81,14 +81,13 @@ void setup() {
   }
 
   // Initialize Zigbee stack without any EPs just for scanning
-  Zigbee.begin(role);
-
-  // Waint until Zigbee stack is ready
-  while (!Zigbee.isStarted()) {
-    delay(100);
+  if (!Zigbee.begin(role)) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
   }
 
-  Serial.println("Setup done");
+  Serial.println("Setup done, starting Zigbee network scan...");
   // Start Zigbee Network Scan with default parameters (all channels, scan time 5)
   Zigbee.scanNetworks();
 }
@@ -98,7 +97,7 @@ void loop() {
   int16_t ZigbeeScanStatus = Zigbee.scanComplete();
   if (ZigbeeScanStatus < 0) {  // it is busy scanning or got an error
     if (ZigbeeScanStatus == ZB_SCAN_FAILED) {
-      Serial.println("WiFi Scan has failed. Starting again.");
+      Serial.println("Zigbee scan has failed. Starting again.");
       Zigbee.scanNetworks();
     }
     // other option is status ZB_SCAN_RUNNING - just wait.
diff --git a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino
index 530995a8427..0c2f9b56690 100644
--- a/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino
+++ b/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino
@@ -27,7 +27,7 @@
  */
 
 #ifndef ZIGBEE_MODE_ED
-#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"
+#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
 #endif
 
 #include "Zigbee.h"
@@ -56,14 +56,19 @@ void meausureAndSleep() {
   zbTempSensor.reportTemperature();
   zbTempSensor.reportHumidity();
 
-  log_d("Temperature: %.2f°C, Humidity: %.2f%", temperature, humidity);
+  Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity);
 
   // Put device to deep sleep
+  Serial.println("Going to sleep now");
   esp_deep_sleep_start();
 }
 
 /********************* Arduino functions **************************/
 void setup() {
+  Serial.begin(115200);
+  while (!Serial) {
+    delay(10);
+  }
   // Init button switch
   pinMode(BUTTON_PIN, INPUT_PULLUP);
 
@@ -94,14 +99,20 @@ void setup() {
   zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000;
 
   // When all EPs are registered, start Zigbee in End Device mode
-  Zigbee.begin(&zigbeeConfig, false);
-
-  // Wait for Zigbee to start
-  while (!Zigbee.isStarted()) {
+  if (!Zigbee.begin(&zigbeeConfig, false)) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
+  }
+  Serial.println("Connecting to network");
+  while (!Zigbee.connected()) {
+    Serial.print(".");
     delay(100);
   }
+  Serial.println();
+  Serial.println("Successfully connected to Zigbee network");
 
-  // Delay 5s to allow establishing connection with coordinator, needed for sleepy devices
+  // Delay 5s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices
   delay(5000);
 }
 
@@ -115,6 +126,8 @@ void loop() {
       delay(50);
       if ((millis() - startTime) > 3000) {
         // If key pressed for more than 3secs, factory reset Zigbee and reboot
+        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
+        delay(1000);
         Zigbee.factoryReset();
       }
     }
diff --git a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino
index c5ca00decd6..255b074265e 100644
--- a/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino
+++ b/libraries/Zigbee/examples/Zigbee_Temperature_Sensor/Zigbee_Temperature_Sensor.ino
@@ -27,7 +27,7 @@
  */
 
 #ifndef ZIGBEE_MODE_ED
-#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"
+#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
 #endif
 
 #include "Zigbee.h"
@@ -42,7 +42,7 @@ static void temp_sensor_value_update(void *arg) {
   for (;;) {
     // Read temperature sensor value
     float tsens_value = temperatureRead();
-    log_v("Temperature sensor value: %.2f°C", tsens_value);
+    Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value);
     // Update temperature value in Temperature sensor EP
     zbTempSensor.setTemperature(tsens_value);
     delay(1000);
@@ -51,12 +51,10 @@ static void temp_sensor_value_update(void *arg) {
 
 /********************* Arduino functions **************************/
 void setup() {
-
   Serial.begin(115200);
   while (!Serial) {
     delay(10);
   }
-
   // Init button switch
   pinMode(BUTTON_PIN, INPUT_PULLUP);
 
@@ -72,8 +70,21 @@ void setup() {
   // Add endpoint to Zigbee Core
   Zigbee.addEndpoint(&zbTempSensor);
 
+  Serial.println("Starting Zigbee...");
   // When all EPs are registered, start Zigbee in End Device mode
-  Zigbee.begin();
+  if (!Zigbee.begin()) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
+  } else {
+    Serial.println("Zigbee started successfully!");
+  }
+  Serial.println("Connecting to network");
+  while (!Zigbee.connected()) {
+    Serial.print(".");
+    delay(100);
+  }
+  Serial.println();
 
   // Start Temperature sensor reading task
   xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL);
@@ -96,7 +107,8 @@ void loop() {
       delay(50);
       if ((millis() - startTime) > 3000) {
         // If key pressed for more than 3secs, factory reset Zigbee and reboot
-        Serial.printf("Resetting Zigbee to factory settings, reboot.\n");
+        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
+        delay(1000);
         Zigbee.factoryReset();
       }
     }
diff --git a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino
index 565d9e64919..df02f891794 100644
--- a/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino
+++ b/libraries/Zigbee/examples/Zigbee_Thermostat/Zigbee_Thermostat.ino
@@ -80,19 +80,22 @@ void setup() {
   Zigbee.setRebootOpenNetwork(180);
 
   // When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode
-  Zigbee.begin(ZIGBEE_COORDINATOR);
-
-  Serial.println("Waiting for Temperature sensor to bound to the switch");
+  if (!Zigbee.begin(ZIGBEE_COORDINATOR)) {
+    Serial.println("Zigbee failed to start!");
+    Serial.println("Rebooting...");
+    ESP.restart();
+  }
 
-  //Wait for switch to bound to a light:
-  while (!zbThermostat.isBound()) {
+  Serial.println("Waiting for Temperature sensor to bound to the thermostat");
+  while (!zbThermostat.bound()) {
     Serial.printf(".");
     delay(500);
   }
 
+  Serial.println();
+
   // Get temperature sensor configuration
   zbThermostat.getSensorSettings();
-  Serial.println();
 }
 
 void loop() {
diff --git a/libraries/Zigbee/keywords.txt b/libraries/Zigbee/keywords.txt
index 53ce5fffe2a..40e5dcec004 100644
--- a/libraries/Zigbee/keywords.txt
+++ b/libraries/Zigbee/keywords.txt
@@ -30,14 +30,20 @@ zigbee_scan_result_t	KEYWORD1
 #######################################
 
 # ZigbeeCore
-isStarted	KEYWORD2
+begin	KEYWORD2
+started	KEYWORD2
+connected	KEYWORD2
+getRole	KEYWORD2
 addEndpoint	KEYWORD2
 setRadioConfig	KEYWORD2
-setHostConfig	KEYWORD2
 getRadioConfig	KEYWORD2
+setHostConfig	KEYWORD2
 getHostConfig	KEYWORD2
 setPrimaryChannelMask	KEYWORD2
+setScanDuration	KEYWORD2
+getScanDuration	KEYWORD2
 setRebootOpenNetwork	KEYWORD2
+openNetwork	KEYWORD2
 scanNetworks	KEYWORD2
 scanComplete	KEYWORD2
 getScanResult	KEYWORD2
@@ -45,21 +51,33 @@ scanDelete	KEYWORD2
 factoryReset	KEYWORD2
 
 # Common ZigbeeEP
+setEpConfig	KEYWORD2
 setVersion	KEYWORD2
-setManufacturerAndModel	KEYWORD2
-is_bound	KEYWORD2
+getEndpoint	KEYWORD2
 printBoundDevices	KEYWORD2
+getBoundDevices	KEYWORD2
+bound	KEYWORD2
 allowMultipleBinding	KEYWORD2
+setManufacturerAndModel	KEYWORD2
+setPowerSource	KEYWORD2
+setBatteryPercentage	KEYWORD2
+reportBatteryPercentage	KEYWORD2
+readManufacturer	KEYWORD2
+readModel	KEYWORD2
+onIdentify	KEYWORD2
 
 # ZigbeeLight + ZigbeeColorDimmableLight
-setOnOff	KEYWORD2
-sceneControl	KEYWORD2
-setOnOffTime	KEYWORD2
-setOffWaitTime	KEYWORD2
-setLevel	KEYWORD2
-setColor	KEYWORD2
-setColorSaturation	KEYWORD2
-setColorHue	KEYWORD2
+onLightChange	KEYWORD2
+restoreLight	KEYWORD2
+setLight	KEYWORD2
+setLightState	KEYWORD2
+setLightLevel	KEYWORD2
+setLightColor	KEYWORD2
+getLightState	KEYWORD2
+getLightLevel	KEYWORD2
+getLightRed	KEYWORD2
+getLightGreen	KEYWORD2
+getLightBlue	KEYWORD2
 
 # ZigbeeSwitch + ZigbeeColorDimmerSwitch
 lightToggle	KEYWORD2
@@ -70,22 +88,23 @@ lightOnWithTimedOff	KEYWORD2
 lightOnWithSceneRecall	KEYWORD2
 setLightLevel	KEYWORD2
 setLightColor	KEYWORD2
-setLightColorSaturation	KEYWORD2
-setLightColorHue	KEYWORD2
 
-# ZigbeeTempSensor
+# ZigbeeTempSensor + humidity
 setTemperature	KEYWORD2
 setMinMaxValue	KEYWORD2
 setTolerance	KEYWORD2
 setReporting	KEYWORD2
 reportTemperature	KEYWORD2
+addHumiditySensor	KEYWORD2
+setHumidity	KEYWORD2
+setHumidityReporting	KEYWORD2
+reportHumidity	KEYWORD2
 
 # ZigbeeThermostat
-temperatureRead	KEYWORD2
-temperatureMin	KEYWORD2
-temperatureMax	KEYWORD2
-temperatureTolerance	KEYWORD2
+onTempRecieve	KEYWORD2
+onConfigRecieve	KEYWORD2
 getTemperature	KEYWORD2
+getSensorSettings	KEYWORD2
 setTemperatureReporting	KEYWORD2
 
 #######################################
diff --git a/libraries/Zigbee/src/ZigbeeCore.cpp b/libraries/Zigbee/src/ZigbeeCore.cpp
index 31f9ab1910f..b1dc6211362 100644
--- a/libraries/Zigbee/src/ZigbeeCore.cpp
+++ b/libraries/Zigbee/src/ZigbeeCore.cpp
@@ -1,11 +1,13 @@
 /* Zigbee Core Functions */
 
 #include "ZigbeeCore.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "ZigbeeHandlers.cpp"
 #include "Arduino.h"
 
+#define ZB_INIT_TIMEOUT 30000  // 30 seconds
+
 extern "C" void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr);
 static bool edBatteryPowered = false;
 
@@ -17,6 +19,14 @@ ZigbeeCore::ZigbeeCore() {
   _open_network = 0;
   _scan_status = ZB_SCAN_FAILED;
   _started = false;
+  _connected = false;
+  _scan_duration = 4;  // maximum scan duration
+  if (!lock) {
+    lock = xSemaphoreCreateBinary();
+    if (lock == NULL) {
+      log_e("Semaphore creation failed");
+    }
+  }
 }
 ZigbeeCore::~ZigbeeCore() {}
 
@@ -25,10 +35,14 @@ static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id,
 
 bool ZigbeeCore::begin(esp_zb_cfg_t *role_cfg, bool erase_nvs) {
   if (!zigbeeInit(role_cfg, erase_nvs)) {
+    log_e("ZigbeeCore begin failed");
     return false;
   }
   _role = (zigbee_role_t)role_cfg->esp_zb_role;
-  return true;
+  if (xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) {
+    log_e("ZigbeeCore begin timeout");
+  }
+  return started();
 }
 
 bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) {
@@ -57,7 +71,10 @@ bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) {
     }
     default: log_e("Invalid Zigbee Role"); return false;
   }
-  return status;
+  if (!status || xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) {
+    log_e("ZigbeeCore begin failed or timeout");
+  }
+  return started();
 }
 
 void ZigbeeCore::addEndpoint(ZigbeeEP *ep) {
@@ -74,6 +91,8 @@ void ZigbeeCore::addEndpoint(ZigbeeEP *ep) {
 }
 
 static void esp_zb_task(void *pvParameters) {
+  esp_zb_bdb_set_scan_duration(Zigbee.getScanDuration());
+
   /* initialize Zigbee stack */
   ESP_ERROR_CHECK(esp_zb_start(false));
 
@@ -162,12 +181,20 @@ void ZigbeeCore::setPrimaryChannelMask(uint32_t mask) {
   _primary_channel_mask = mask;
 }
 
+void ZigbeeCore::setScanDuration(uint8_t duration) {
+  if (duration < 1 || duration > 4) {
+    log_e("Invalid scan duration, must be between 1 and 4");
+    return;
+  }
+  _scan_duration = duration;
+}
+
 void ZigbeeCore::setRebootOpenNetwork(uint8_t time) {
   _open_network = time;
 }
 
 void ZigbeeCore::openNetwork(uint8_t time) {
-  if (isStarted()) {
+  if (started()) {
     log_v("Opening network for joining for %d seconds", time);
     esp_zb_bdb_open_network(time);
   }
@@ -203,21 +230,25 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
           } else {
             log_i("Start network steering");
             esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
+            Zigbee._started = true;
+            xSemaphoreGive(Zigbee.lock);
           }
-          //-----------------
-
         } else {
           log_i("Device rebooted");
           Zigbee._started = true;
+          xSemaphoreGive(Zigbee.lock);
           if ((zigbee_role_t)Zigbee.getRole() == ZIGBEE_COORDINATOR && Zigbee._open_network > 0) {
             log_i("Opening network for joining for %d seconds", Zigbee._open_network);
             esp_zb_bdb_open_network(Zigbee._open_network);
+          } else {
+            Zigbee._connected = true;
           }
+          Zigbee.searchBindings();
         }
       } else {
         /* commissioning failed */
-        log_e("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status));
-        esp_restart();
+        log_w("Commissioning failed, trying again...", esp_err_to_name(err_status));
+        esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_INITIALIZATION, 500);
       }
       break;
     case ESP_ZB_BDB_SIGNAL_FORMATION:  // Coordinator
@@ -243,6 +274,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
           log_i("Network steering started");
         }
         Zigbee._started = true;
+        xSemaphoreGive(Zigbee.lock);
       } else {
         if (err_status == ESP_OK) {
           esp_zb_ieee_addr_t extended_pan_id;
@@ -252,7 +284,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
             extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4], extended_pan_id[3], extended_pan_id[2], extended_pan_id[1],
             extended_pan_id[0], esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address()
           );
-          Zigbee._started = true;
+          Zigbee._connected = true;
         } else {
           log_i("Network steering was not successful (status: %s)", esp_err_to_name(err_status));
           esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
@@ -278,10 +310,9 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
             Bit 6 – Security capability
             Bit 7 – Reserved
         */
-
         // for each endpoint in the list call the findEndpoint function if not bounded or allowed to bind multiple devices
         for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
-          if (!(*it)->isBound() || (*it)->epAllowMultipleBinding()) {
+          if (!(*it)->bound() || (*it)->epAllowMultipleBinding()) {
             (*it)->findEndpoint(&cmd_req);
           }
         }
@@ -298,6 +329,12 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
         }
       }
       break;
+    case ESP_ZB_ZDO_SIGNAL_LEAVE:  // End Device + Router
+      // Device was removed from the network, factory reset the device
+      if ((zigbee_role_t)Zigbee.getRole() != ZIGBEE_COORDINATOR) {
+        Zigbee.factoryReset();
+      }
+      break;
     default: log_v("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); break;
   }
 }
@@ -335,7 +372,7 @@ void ZigbeeCore::scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t co
 }
 
 void ZigbeeCore::scanNetworks(u_int32_t channel_mask, u_int8_t scan_duration) {
-  if (!isStarted()) {
+  if (!started()) {
     log_e("Zigbee stack is not started, cannot scan networks");
     return;
   }
@@ -360,6 +397,75 @@ void ZigbeeCore::scanDelete() {
   _scan_status = ZB_SCAN_FAILED;
 }
 
+// Recall bounded devices from the binding table after reboot
+void ZigbeeCore::bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx) {
+  bool done = true;
+  esp_zb_zdo_mgmt_bind_param_t *req = (esp_zb_zdo_mgmt_bind_param_t *)user_ctx;
+  esp_zb_zdp_status_t zdo_status = (esp_zb_zdp_status_t)table_info->status;
+  log_d("Binding table callback for address 0x%04x with status %d", req->dst_addr, zdo_status);
+  if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
+    // Print binding table log simple
+    log_d("Binding table info: total %d, index %d, count %d", table_info->total, table_info->index, table_info->count);
+
+    if (table_info->total == 0) {
+      log_d("No binding table entries found");
+      free(req);
+      return;
+    }
+
+    esp_zb_zdo_binding_table_record_t *record = table_info->record;
+    for (int i = 0; i < table_info->count; i++) {
+      log_d(
+        "Binding table record: src_endp %d, dst_endp %d, cluster_id 0x%04x, dst_addr_mode %d", record->src_endp, record->dst_endp, record->cluster_id,
+        record->dst_addr_mode
+      );
+
+      zb_device_params_t *device = (zb_device_params_t *)calloc(1, sizeof(zb_device_params_t));
+      device->endpoint = record->dst_endp;
+      if (record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT || record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT) {
+        device->short_addr = record->dst_address.addr_short;
+      } else {  //ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT
+        memcpy(device->ieee_addr, record->dst_address.addr_long, sizeof(esp_zb_ieee_addr_t));
+      }
+
+      // Add to list of bound devices of proper endpoint
+      for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
+        if ((*it)->getEndpoint() == record->src_endp) {
+          (*it)->addBoundDevice(device);
+          log_d(
+            "Device bound to EP %d -> device endpoint: %d, short addr: 0x%04x, ieee addr: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", record->src_endp,
+            device->endpoint, device->short_addr, device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3],
+            device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0]
+          );
+        }
+      }
+      record = record->next;
+    }
+
+    // Continue reading the binding table
+    if (table_info->index + table_info->count < table_info->total) {
+      /* There are unreported binding table entries, request for them. */
+      req->start_index = table_info->index + table_info->count;
+      esp_zb_zdo_binding_table_req(req, bindingTableCb, req);
+      done = false;
+    }
+  }
+
+  if (done) {
+    // Print bound devices
+    log_d("Filling bounded devices finished");
+    free(req);
+  }
+}
+
+void ZigbeeCore::searchBindings() {
+  esp_zb_zdo_mgmt_bind_param_t *mb_req = (esp_zb_zdo_mgmt_bind_param_t *)malloc(sizeof(esp_zb_zdo_mgmt_bind_param_t));
+  mb_req->dst_addr = esp_zb_get_short_address();
+  mb_req->start_index = 0;
+  log_d("Requesting binding table for address 0x%04x", mb_req->dst_addr);
+  esp_zb_zdo_binding_table_req(mb_req, bindingTableCb, (void *)mb_req);
+}
+
 // Function to convert enum value to string
 const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) {
   switch (deviceId) {
@@ -407,4 +513,4 @@ const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceI
 
 ZigbeeCore Zigbee = ZigbeeCore();
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ZigbeeCore.h b/libraries/Zigbee/src/ZigbeeCore.h
index 1044a9c737c..6729b7cc9f4 100644
--- a/libraries/Zigbee/src/ZigbeeCore.h
+++ b/libraries/Zigbee/src/ZigbeeCore.h
@@ -3,7 +3,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_IEEE802154_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "esp_zigbee_core.h"
 #include "zdo/esp_zigbee_zdo_common.h"
@@ -65,17 +66,22 @@ class ZigbeeCore {
   esp_zb_host_config_t _host_config;
   uint32_t _primary_channel_mask;
   int16_t _scan_status;
+  uint8_t _scan_duration;
 
   esp_zb_ep_list_t *_zb_ep_list;
   zigbee_role_t _role;
   bool _started;
+  bool _connected;
 
   uint8_t _open_network;
   zigbee_scan_result_t *_scan_result;
+  SemaphoreHandle_t lock;
 
   bool zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs);
   static void scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor);
   const char *getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId);
+  void searchBindings();
+  static void bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx);
 
 public:
   ZigbeeCore();
@@ -87,9 +93,12 @@ class ZigbeeCore {
   bool begin(esp_zb_cfg_t *role_cfg, bool erase_nvs = false);
   // bool end();
 
-  bool isStarted() {
+  bool started() {
     return _started;
   }
+  bool connected() {
+    return _connected;
+  }
   zigbee_role_t getRole() {
     return _role;
   }
@@ -103,7 +112,12 @@ class ZigbeeCore {
   void setHostConfig(esp_zb_host_config_t config);
   esp_zb_host_config_t getHostConfig();
 
-  void setPrimaryChannelMask(uint32_t mask);
+  void setPrimaryChannelMask(uint32_t mask);  // By default all channels are scanned (11-26) -> mask 0x07FFF800
+  void setScanDuration(uint8_t duration);     // Can be set from 1 - 4. 1 is fastest, 4 is slowest
+  uint8_t getScanDuration() {
+    return _scan_duration;
+  }
+
   void setRebootOpenNetwork(uint8_t time);
   void openNetwork(uint8_t time);
 
@@ -122,4 +136,4 @@ class ZigbeeCore {
 
 extern ZigbeeCore Zigbee;
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ZigbeeEP.cpp b/libraries/Zigbee/src/ZigbeeEP.cpp
index 8597f4404c2..dbfe8596268 100644
--- a/libraries/Zigbee/src/ZigbeeEP.cpp
+++ b/libraries/Zigbee/src/ZigbeeEP.cpp
@@ -2,11 +2,13 @@
 
 #include "ZigbeeEP.h"
 
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "esp_zigbee_cluster.h"
 #include "zcl/esp_zigbee_zcl_power_config.h"
 
+#define ZB_CMD_TIMEOUT 10000  // 10 seconds
+
 bool ZigbeeEP::_is_bound = false;
 bool ZigbeeEP::_allow_multiple_binding = false;
 
@@ -19,14 +21,12 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) {
   _ep_config.endpoint = 0;
   _cluster_list = nullptr;
   _on_identify = nullptr;
-#if !CONFIG_DISABLE_HAL_LOCKS
   if (!lock) {
     lock = xSemaphoreCreateBinary();
     if (lock == NULL) {
       log_e("Semaphore creation failed");
     }
   }
-#endif
 }
 
 ZigbeeEP::~ZigbeeEP() {}
@@ -104,7 +104,7 @@ void ZigbeeEP::reportBatteryPercentage() {
   esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
   report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
   report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID;
-  report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
+  report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
   report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG;
   report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
 
@@ -114,13 +114,20 @@ void ZigbeeEP::reportBatteryPercentage() {
   log_v("Battery percentage reported");
 }
 
-char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) {
+char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
   /* Read peer Manufacture Name & Model Identifier */
   esp_zb_zcl_read_attr_cmd_t read_req;
-  read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
+
+  if (short_addr != 0) {
+    read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
+    read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
+  } else {
+    read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+  }
+
   read_req.zcl_basic_cmd.src_endpoint = _endpoint;
   read_req.zcl_basic_cmd.dst_endpoint = endpoint;
-  read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
   read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
 
   uint16_t attributes[] = {
@@ -132,22 +139,31 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) {
   // clear read manufacturer
   _read_manufacturer = nullptr;
 
+  esp_zb_lock_acquire(portMAX_DELAY);
   esp_zb_zcl_read_attr_cmd_req(&read_req);
+  esp_zb_lock_release();
 
   //Wait for response or timeout
-  if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
+  if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
     log_e("Error while reading manufacturer");
   }
   return _read_manufacturer;
 }
 
-char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) {
+char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
   /* Read peer Manufacture Name & Model Identifier */
   esp_zb_zcl_read_attr_cmd_t read_req;
-  read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
+
+  if (short_addr != 0) {
+    read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
+    read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
+  } else {
+    read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+  }
+
   read_req.zcl_basic_cmd.src_endpoint = _endpoint;
   read_req.zcl_basic_cmd.dst_endpoint = endpoint;
-  read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
   read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
 
   uint16_t attributes[] = {
@@ -159,11 +175,12 @@ char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) {
   // clear read model
   _read_model = nullptr;
 
+  esp_zb_lock_acquire(portMAX_DELAY);
   esp_zb_zcl_read_attr_cmd_req(&read_req);
+  esp_zb_lock_release();
 
   //Wait for response or timeout
-  //Semaphore take
-  if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
+  if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
     log_e("Error while reading model");
   }
   return _read_model;
@@ -173,8 +190,23 @@ void ZigbeeEP::printBoundDevices() {
   log_i("Bound devices:");
   for ([[maybe_unused]]
        const auto &device : _bound_devices) {
-    log_i("Device on endpoint %d, short address: 0x%x", device->endpoint, device->short_addr);
-    print_ieee_addr(device->ieee_addr);
+    log_i(
+      "Device on endpoint %d, short address: 0x%x, ieee address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", device->endpoint, device->short_addr,
+      device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1],
+      device->ieee_addr[0]
+    );
+  }
+}
+
+void ZigbeeEP::printBoundDevices(Print &print) {
+  print.println("Bound devices:");
+  for ([[maybe_unused]]
+       const auto &device : _bound_devices) {
+    print.printf(
+      "Device on endpoint %d, short address: 0x%x, ieee address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n", device->endpoint, device->short_addr,
+      device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1],
+      device->ieee_addr[0]
+    );
   }
 }
 
@@ -210,4 +242,4 @@ void ZigbeeEP::zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message) {
   }
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ZigbeeEP.h b/libraries/Zigbee/src/ZigbeeEP.h
index 3a86617e2f4..522c84620ff 100644
--- a/libraries/Zigbee/src/ZigbeeEP.h
+++ b/libraries/Zigbee/src/ZigbeeEP.h
@@ -3,14 +3,12 @@
 #pragma once
 
 #include "ZigbeeCore.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include <Arduino.h>
 
 /* Useful defines */
 #define ZB_ARRAY_LENTH(arr) (sizeof(arr) / sizeof(arr[0]))
-#define print_ieee_addr(addr) \
-  log_i("IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7])
 #define XYZ_TO_RGB(X, Y, Z, r, g, b)                                \
   {                                                                 \
     r = (float)(3.240479 * (X) - 1.537150 * (Y) - 0.498535 * (Z));  \
@@ -69,11 +67,13 @@ class ZigbeeEP {
   }
 
   void printBoundDevices();
+  void printBoundDevices(Print &print);
+
   std::list<zb_device_params_t *> getBoundDevices() const {
     return _bound_devices;
   }
 
-  static bool isBound() {
+  static bool bound() {
     return _is_bound;
   }
   static void allowMultipleBinding(bool bind) {
@@ -87,8 +87,8 @@ class ZigbeeEP {
   void reportBatteryPercentage();
 
   // Methods to read manufacturer and model name from selected endpoint and short address
-  char *readManufacturer(uint8_t endpoint, uint16_t short_addr);
-  char *readModel(uint8_t endpoint, uint16_t short_addr);
+  char *readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
+  char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
 
   bool epAllowMultipleBinding() {
     return _allow_multiple_binding;
@@ -108,7 +108,6 @@ class ZigbeeEP {
   }
 
 private:
-  static bool _allow_multiple_binding;
   char *_read_manufacturer;
   char *_read_model;
   void (*_on_identify)(uint16_t time);
@@ -119,11 +118,16 @@ class ZigbeeEP {
   esp_zb_endpoint_config_t _ep_config;
   esp_zb_cluster_list_t *_cluster_list;
   static bool _is_bound;
+  static bool _allow_multiple_binding;
   std::list<zb_device_params_t *> _bound_devices;
   SemaphoreHandle_t lock;
   zb_power_source_t _power_source;
 
+  void addBoundDevice(zb_device_params_t *device) {
+    _bound_devices.push_back(device);
+    _is_bound = true;
+  }
   friend class ZigbeeCore;
 };
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ZigbeeHandlers.cpp b/libraries/Zigbee/src/ZigbeeHandlers.cpp
index 9522b0ba1a8..881d7ca0c37 100644
--- a/libraries/Zigbee/src/ZigbeeHandlers.cpp
+++ b/libraries/Zigbee/src/ZigbeeHandlers.cpp
@@ -2,7 +2,7 @@
 #include "ZigbeeCore.h"
 #include "Arduino.h"
 
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 // forward declaration of all implemented handlers
 static esp_err_t zb_attribute_set_handler(const esp_zb_zcl_set_attr_value_message_t *message);
@@ -138,4 +138,4 @@ static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_m
   return ESP_OK;
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp
index 841d9c7f122..f034daba54a 100644
--- a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp
+++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp
@@ -1,5 +1,5 @@
 #include "ZigbeeColorDimmableLight.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 ZigbeeColorDimmableLight::ZigbeeColorDimmableLight(uint8_t endpoint) : ZigbeeEP(endpoint) {
   _device_id = ESP_ZB_HA_COLOR_DIMMABLE_LIGHT_DEVICE_ID;
@@ -47,6 +47,24 @@ void ZigbeeColorDimmableLight::calculateRGB(uint16_t x, uint16_t y, uint8_t &red
   blue = (uint8_t)(b * (float)255);
 }
 
+void ZigbeeColorDimmableLight::calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y) {
+  // Convert RGB to XYZ
+  float r = (float)red / 255.0f;
+  float g = (float)green / 255.0f;
+  float b = (float)blue / 255.0f;
+
+  float X, Y, Z;
+  RGB_TO_XYZ(r, g, b, X, Y, Z);
+
+  // Convert XYZ to xy chromaticity coordinates
+  float color_x = X / (X + Y + Z);
+  float color_y = Y / (X + Y + Z);
+
+  // Convert normalized xy to 16-bit values
+  x = (uint16_t)(color_x * 65535.0f);
+  y = (uint16_t)(color_y * 65535.0f);
+}
+
 //set attribute method -> method overridden in child class
 void ZigbeeColorDimmableLight::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {
   //check the data and call right method
@@ -109,4 +127,48 @@ void ZigbeeColorDimmableLight::lightChanged() {
   }
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+void ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue) {
+  //Update all attributes
+  _current_state = state;
+  _current_level = level;
+  _current_red = red;
+  _current_green = green;
+  _current_blue = blue;
+  lightChanged();
+
+  log_v("Updating on/off light state to %d", state);
+  /* Update light clusters */
+  esp_zb_lock_acquire(portMAX_DELAY);
+  //set on/off state
+  esp_zb_zcl_set_attribute_val(
+    _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false
+  );
+  //set level
+  esp_zb_zcl_set_attribute_val(
+    _endpoint, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, &_current_level, false
+  );
+  //set color
+  uint16_t color_x, color_y;
+  calculateXY(red, green, blue, color_x, color_y);
+  esp_zb_zcl_set_attribute_val(
+    _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_X_ID, &color_x, false
+  );
+  esp_zb_zcl_set_attribute_val(
+    _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID, &color_y, false
+  );
+  esp_zb_lock_release();
+}
+
+void ZigbeeColorDimmableLight::setLightState(bool state) {
+  setLight(state, _current_level, _current_red, _current_green, _current_blue);
+}
+
+void ZigbeeColorDimmableLight::setLightLevel(uint8_t level) {
+  setLight(_current_state, level, _current_red, _current_green, _current_blue);
+}
+
+void ZigbeeColorDimmableLight::setLightColor(uint8_t red, uint8_t green, uint8_t blue) {
+  setLight(_current_state, _current_level, red, green, blue);
+}
+
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h
index 992c2573654..9fa59dcfffc 100644
--- a/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h
+++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h
@@ -3,7 +3,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_IEEE802154_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "ZigbeeEP.h"
 #include "ha/esp_zigbee_ha_standard.h"
@@ -20,9 +21,31 @@ class ZigbeeColorDimmableLight : public ZigbeeEP {
     lightChanged();
   }
 
+  void setLightState(bool state);
+  void setLightLevel(uint8_t level);
+  void setLightColor(uint8_t red, uint8_t green, uint8_t blue);
+  void setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue);
+
+  bool getLightState() {
+    return _current_state;
+  }
+  uint8_t getLightLevel() {
+    return _current_level;
+  }
+  uint8_t getLightRed() {
+    return _current_red;
+  }
+  uint8_t getLightGreen() {
+    return _current_green;
+  }
+  uint8_t getLightBlue() {
+    return _current_blue;
+  }
+
 private:
   void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override;
   void calculateRGB(uint16_t x, uint16_t y, uint8_t &red, uint8_t &green, uint8_t &blue);
+  void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y);
 
   uint16_t getCurrentColorX();
   uint16_t getCurrentColorY();
@@ -38,4 +61,4 @@ class ZigbeeColorDimmableLight : public ZigbeeEP {
   uint16_t _current_blue;
 };
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp
index d9a9e1c1014..4fd492a5477 100644
--- a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp
+++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp
@@ -1,5 +1,5 @@
 #include "ZigbeeColorDimmerSwitch.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 // Initialize the static instance pointer
 ZigbeeColorDimmerSwitch *ZigbeeColorDimmerSwitch::_instance = nullptr;
@@ -98,10 +98,10 @@ void ZigbeeColorDimmerSwitch::lightToggle() {
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
-    log_i("Sending 'light toggle' command");
-    //esp_zb_lock_acquire(portMAX_DELAY);
+    log_v("Sending 'light toggle' command");
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
-    //esp_zb_lock_release();
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -114,7 +114,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint16_t group_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
-    log_i("Sending 'light toggle' command to group address 0x%x", group_addr);
+    log_v("Sending 'light toggle' command to group address 0x%x", group_addr);
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -131,7 +131,27 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr)
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
-    log_i("Sending 'light toggle' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'light toggle' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    esp_zb_zcl_on_off_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    log_v(
+      "Sending 'light toggle' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5],
+      ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -146,7 +166,7 @@ void ZigbeeColorDimmerSwitch::lightOn() {
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
-    log_i("Sending 'light on' command");
+    log_v("Sending 'light on' command");
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -162,7 +182,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint16_t group_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
-    log_i("Sending 'light on' command to group address 0x%x", group_addr);
+    log_v("Sending 'light on' command to group address 0x%x", group_addr);
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -179,7 +199,27 @@ void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
-    log_i("Sending 'light on' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'light on' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    esp_zb_zcl_on_off_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    log_v(
+      "Sending 'light on' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5],
+      ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -194,7 +234,7 @@ void ZigbeeColorDimmerSwitch::lightOff() {
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
-    log_i("Sending 'light off' command");
+    log_v("Sending 'light off' command");
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -210,7 +250,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint16_t group_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
-    log_i("Sending 'light off' command to group address 0x%x", group_addr);
+    log_v("Sending 'light off' command to group address 0x%x", group_addr);
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -227,7 +267,27 @@ void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
-    log_i("Sending 'light off' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'light off' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    esp_zb_zcl_on_off_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    log_v(
+      "Sending 'light off' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5],
+      ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -243,7 +303,7 @@ void ZigbeeColorDimmerSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effe
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.effect_id = effect_id;
     cmd_req.effect_variant = effect_variant;
-    log_i("Sending 'light off with effect' command");
+    log_v("Sending 'light off with effect' command");
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_off_with_effect_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -257,7 +317,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithSceneRecall() {
     esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req;
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
-    log_i("Sending 'light on with scene recall' command");
+    log_v("Sending 'light on with scene recall' command");
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -274,7 +334,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16
     cmd_req.on_off_control = on_off_control;  //TODO: Test how it works, then maybe change API
     cmd_req.on_time = time_on;
     cmd_req.off_wait_time = time_off;
-    log_i("Sending 'light on with time off' command");
+    log_v("Sending 'light on with time off' command");
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_on_with_timed_off_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -290,7 +350,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level) {
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.level = level;
     cmd_req.transition_time = 0xffff;
-    log_i("Sending 'set light level' command");
+    log_v("Sending 'set light level' command");
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -307,7 +367,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint16_t group_addr)
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
     cmd_req.level = level;
     cmd_req.transition_time = 0xffff;
-    log_i("Sending 'set light level' command to group address 0x%x", group_addr);
+    log_v("Sending 'set light level' command to group address 0x%x", group_addr);
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -325,7 +385,28 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, uin
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
     cmd_req.level = level;
     cmd_req.transition_time = 0xffff;
-    log_i("Sending 'set light level' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'set light level' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    esp_zb_zcl_move_to_level_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    cmd_req.level = level;
+    cmd_req.transition_time = 0xffff;
+    log_v(
+      "Sending 'set light level' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6],
+      ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_level_move_to_level_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -346,7 +427,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
     cmd_req.color_x = color_x;
     cmd_req.color_y = color_y;
     cmd_req.transition_time = 0;
-    log_i("Sending 'set light color' command");
+    log_v("Sending 'set light color' command");
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -368,7 +449,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
     cmd_req.color_x = color_x;
     cmd_req.color_y = color_y;
     cmd_req.transition_time = 0;
-    log_i("Sending 'set light color' command to group address 0x%x", group_addr);
+    log_v("Sending 'set light color' command to group address 0x%x", group_addr);
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -391,7 +472,33 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
     cmd_req.color_x = color_x;
     cmd_req.color_y = color_y;
     cmd_req.transition_time = 0;
-    log_i("Sending 'set light color' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'set light color' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    //Convert RGB to XY
+    uint16_t color_x, color_y;
+    calculateXY(red, green, blue, color_x, color_y);
+
+    esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    cmd_req.color_x = color_x;
+    cmd_req.color_y = color_y;
+    cmd_req.transition_time = 0;
+    log_v(
+      "Sending 'set light color' command to endpoint %d,  ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6],
+      ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
     esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_color_move_to_color_cmd_req(&cmd_req);
     esp_zb_lock_release();
@@ -400,4 +507,4 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
   }
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h
index 2263f3235ca..8e2a4d9e1a3 100644
--- a/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h
+++ b/libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h
@@ -3,7 +3,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_IEEE802154_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "ZigbeeEP.h"
 #include "ha/esp_zigbee_ha_standard.h"
@@ -17,14 +18,17 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP {
   void lightToggle();
   void lightToggle(uint16_t group_addr);
   void lightToggle(uint8_t endpoint, uint16_t short_addr);
+  void lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
   void lightOn();
   void lightOn(uint16_t group_addr);
   void lightOn(uint8_t endpoint, uint16_t short_addr);
+  void lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
   void lightOff();
   void lightOff(uint16_t group_addr);
   void lightOff(uint8_t endpoint, uint16_t short_addr);
+  void lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
   void lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant);
   void lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off);
@@ -33,18 +37,12 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP {
   void setLightLevel(uint8_t level);
   void setLightLevel(uint8_t level, uint16_t group_addr);
   void setLightLevel(uint8_t level, uint8_t endpoint, uint16_t short_addr);
+  void setLightLevel(uint8_t level, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
   void setLightColor(uint8_t red, uint8_t green, uint8_t blue);
   void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint16_t group_addr);
   void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, uint16_t short_addr);
-
-  void setLightColorSaturation(uint8_t value);
-  void setLightColorSaturation(uint8_t value, uint16_t group_addr);
-  void setLightColorSaturation(uint8_t value, uint8_t endpoint, uint16_t short_addr);
-
-  void setLightColorHue(uint8_t value);
-  void setLightColorHue(uint8_t value, uint16_t group_addr);
-  void setLightColorHue(uint8_t value, uint8_t endpoint, uint16_t short_addr);
+  void setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
 private:
   // save instance of the class in order to use it in static functions
@@ -57,4 +55,4 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP {
   void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y);
 };
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.cpp b/libraries/Zigbee/src/ep/ZigbeeLight.cpp
index 1f59cd82325..100efe34a86 100644
--- a/libraries/Zigbee/src/ep/ZigbeeLight.cpp
+++ b/libraries/Zigbee/src/ep/ZigbeeLight.cpp
@@ -1,5 +1,5 @@
 #include "ZigbeeLight.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 ZigbeeLight::ZigbeeLight(uint8_t endpoint) : ZigbeeEP(endpoint) {
   _device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID;
@@ -33,4 +33,17 @@ void ZigbeeLight::lightChanged() {
   }
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+void ZigbeeLight::setLight(bool state) {
+  _current_state = state;
+  lightChanged();
+
+  log_v("Updating on/off light state to %d", state);
+  /* Update on/off light state */
+  esp_zb_lock_acquire(portMAX_DELAY);
+  esp_zb_zcl_set_attribute_val(
+    _endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false
+  );
+  esp_zb_lock_release();
+}
+
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeLight.h b/libraries/Zigbee/src/ep/ZigbeeLight.h
index 32e4e8c9bdc..9b8fc409d4a 100644
--- a/libraries/Zigbee/src/ep/ZigbeeLight.h
+++ b/libraries/Zigbee/src/ep/ZigbeeLight.h
@@ -3,7 +3,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_IEEE802154_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "ZigbeeEP.h"
 #include "ha/esp_zigbee_ha_standard.h"
@@ -13,13 +14,20 @@ class ZigbeeLight : public ZigbeeEP {
   ZigbeeLight(uint8_t endpoint);
   ~ZigbeeLight();
 
-  // Use tp set a cb function to be called on light change
+  // Use to set a cb function to be called on light change
   void onLightChange(void (*callback)(bool)) {
     _on_light_change = callback;
   }
+  // Use to restore light state
   void restoreLight() {
     lightChanged();
   }
+  // Use to control light state
+  void setLight(bool state);
+  // Use to get light state
+  bool getLightState() {
+    return _current_state;
+  }
 
 private:
   void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override;
@@ -30,4 +38,4 @@ class ZigbeeLight : public ZigbeeEP {
   bool _current_state;
 };
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp
index 17f0b6703c9..f6b36d7f0d4 100644
--- a/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp
+++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.cpp
@@ -1,5 +1,5 @@
 #include "ZigbeeSwitch.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 // Initialize the static instance pointer
 ZigbeeSwitch *ZigbeeSwitch::_instance = nullptr;
@@ -59,7 +59,6 @@ void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {
     .num_out_clusters = 1,
     .cluster_list = cluster_list,
   };
-
   esp_zb_zdo_match_cluster(&on_off_req, findCb, &_endpoint);
 }
 
@@ -70,8 +69,10 @@ void ZigbeeSwitch::lightToggle() {
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
-    log_i("Sending 'light toggle' command");
+    log_v("Sending 'light toggle' command");
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -84,8 +85,10 @@ void ZigbeeSwitch::lightToggle(uint16_t group_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
-    log_i("Sending 'light toggle' command to group address 0x%x", group_addr);
+    log_v("Sending 'light toggle' command to group address 0x%x", group_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -99,8 +102,30 @@ void ZigbeeSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
-    log_i("Sending 'light toggle' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'light toggle' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    esp_zb_zcl_on_off_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    log_v(
+      "Sending 'light toggle' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5],
+      ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -112,8 +137,10 @@ void ZigbeeSwitch::lightOn() {
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
-    log_i("Sending 'light on' command");
+    log_v("Sending 'light on' command");
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -126,8 +153,10 @@ void ZigbeeSwitch::lightOn(uint16_t group_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
-    log_i("Sending 'light on' command to group address 0x%x", group_addr);
+    log_v("Sending 'light on' command to group address 0x%x", group_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -141,8 +170,30 @@ void ZigbeeSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
-    log_i("Sending 'light on' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'light on' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    esp_zb_zcl_on_off_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    log_v(
+      "Sending 'light on' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5],
+      ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -154,8 +205,10 @@ void ZigbeeSwitch::lightOff() {
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
-    log_i("Sending 'light off' command");
+    log_v("Sending 'light off' command");
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -168,8 +221,10 @@ void ZigbeeSwitch::lightOff(uint16_t group_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
-    log_i("Sending 'light off' command to group address 0x%x", group_addr);
+    log_v("Sending 'light off' command to group address 0x%x", group_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -183,8 +238,30 @@ void ZigbeeSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) {
     cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
     cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
-    log_i("Sending 'light off' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    log_v("Sending 'light off' command to endpoint %d, address 0x%x", endpoint, short_addr);
+    esp_zb_lock_acquire(portMAX_DELAY);
+    esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
+  } else {
+    log_e("Light not bound");
+  }
+}
+
+void ZigbeeSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
+  if (_is_bound) {
+    esp_zb_zcl_on_off_cmd_t cmd_req;
+    cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
+    cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
+    cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
+    cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
+    memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
+    log_v(
+      "Sending 'light off' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5],
+      ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
+    );
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -197,8 +274,10 @@ void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant)
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
     cmd_req.effect_id = effect_id;
     cmd_req.effect_variant = effect_variant;
-    log_i("Sending 'light off with effect' command");
+    log_v("Sending 'light off with effect' command");
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_off_with_effect_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -209,8 +288,10 @@ void ZigbeeSwitch::lightOnWithSceneRecall() {
     esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req;
     cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
     cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
-    log_i("Sending 'light on with scene recall' command");
+    log_v("Sending 'light on with scene recall' command");
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
@@ -223,11 +304,13 @@ void ZigbeeSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on,
     cmd_req.on_off_control = on_off_control;  //TODO: Test how it works, then maybe change API
     cmd_req.on_time = time_on;
     cmd_req.off_wait_time = time_off;
-    log_i("Sending 'light on with time off' command");
+    log_v("Sending 'light on with time off' command");
+    esp_zb_lock_acquire(portMAX_DELAY);
     esp_zb_zcl_on_off_on_with_timed_off_cmd_req(&cmd_req);
+    esp_zb_lock_release();
   } else {
     log_e("Light not bound");
   }
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeSwitch.h b/libraries/Zigbee/src/ep/ZigbeeSwitch.h
index bbc6c0a91dc..62264641378 100644
--- a/libraries/Zigbee/src/ep/ZigbeeSwitch.h
+++ b/libraries/Zigbee/src/ep/ZigbeeSwitch.h
@@ -3,7 +3,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_IEEE802154_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "ZigbeeEP.h"
 #include "ha/esp_zigbee_ha_standard.h"
@@ -17,14 +18,17 @@ class ZigbeeSwitch : public ZigbeeEP {
   void lightToggle();
   void lightToggle(uint16_t group_addr);
   void lightToggle(uint8_t endpoint, uint16_t short_addr);
+  void lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
   void lightOn();
   void lightOn(uint16_t group_addr);
   void lightOn(uint8_t endpoint, uint16_t short_addr);
+  void lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
   void lightOff();
   void lightOff(uint16_t group_addr);
   void lightOff(uint8_t endpoint, uint16_t short_addr);
+  void lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
 
   void lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant);
   void lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off);
@@ -39,4 +43,4 @@ class ZigbeeSwitch : public ZigbeeEP {
   static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
 };
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp
index a20f6255746..3dfac0489dd 100644
--- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp
+++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.cpp
@@ -1,5 +1,5 @@
 #include "ZigbeeTempSensor.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 ZigbeeTempSensor::ZigbeeTempSensor(uint8_t endpoint) : ZigbeeEP(endpoint) {
   _device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID;
@@ -60,7 +60,9 @@ void ZigbeeTempSensor::setReporting(uint16_t min_interval, uint16_t max_interval
       },
     .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC,
   };
+  esp_zb_lock_acquire(portMAX_DELAY);
   esp_zb_zcl_update_reporting_info(&reporting_info);
+  esp_zb_lock_release();
 }
 
 void ZigbeeTempSensor::setTemperature(float temperature) {
@@ -80,7 +82,7 @@ void ZigbeeTempSensor::reportTemperature() {
   esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
   report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
   report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
-  report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
+  report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
   report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
   report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
 
@@ -121,7 +123,7 @@ void ZigbeeTempSensor::reportHumidity() {
   esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
   report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
   report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID;
-  report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
+  report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
   report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT;
   report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
 
@@ -158,7 +160,9 @@ void ZigbeeTempSensor::setHumidityReporting(uint16_t min_interval, uint16_t max_
       },
     .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC,
   };
+  esp_zb_lock_acquire(portMAX_DELAY);
   esp_zb_zcl_update_reporting_info(&reporting_info);
+  esp_zb_lock_release();
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h
index 0f2040ff917..d868034280d 100644
--- a/libraries/Zigbee/src/ep/ZigbeeTempSensor.h
+++ b/libraries/Zigbee/src/ep/ZigbeeTempSensor.h
@@ -3,7 +3,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_IEEE802154_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "ZigbeeEP.h"
 #include "ha/esp_zigbee_ha_standard.h"
@@ -41,4 +42,4 @@ class ZigbeeTempSensor : public ZigbeeEP {
   void reportHumidity();
 };
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp
index b9805a37a19..4610e087563 100644
--- a/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp
+++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.cpp
@@ -1,5 +1,5 @@
 #include "ZigbeeThermostat.h"
-#if SOC_IEEE802154_SUPPORTED
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 static float zb_s16_to_temperature(int16_t value) {
   return 1.0 * value / 100;
@@ -185,7 +185,7 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m
   int16_t report_change = (int16_t)delta * 100;
   esp_zb_zcl_config_report_record_t records[] = {
     {
-      .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV,
+      .direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND,
       .attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
       .attrType = ESP_ZB_ZCL_ATTR_TYPE_S16,
       .min_interval = min_interval,
@@ -202,4 +202,4 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m
   esp_zb_lock_release();
 }
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/libraries/Zigbee/src/ep/ZigbeeThermostat.h b/libraries/Zigbee/src/ep/ZigbeeThermostat.h
index 7d63cd9f726..fe797ffd7b6 100644
--- a/libraries/Zigbee/src/ep/ZigbeeThermostat.h
+++ b/libraries/Zigbee/src/ep/ZigbeeThermostat.h
@@ -3,7 +3,8 @@
 #pragma once
 
 #include "soc/soc_caps.h"
-#if SOC_IEEE802154_SUPPORTED
+#include "sdkconfig.h"
+#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
 
 #include "ZigbeeEP.h"
 #include "ha/esp_zigbee_ha_standard.h"
@@ -61,4 +62,4 @@ class ZigbeeThermostat : public ZigbeeEP {
   void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) override;
 };
 
-#endif  //SOC_IEEE802154_SUPPORTED
+#endif  //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
diff --git a/package.json b/package.json
index 6dbb69ad305..e13a446bd98 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "framework-arduinoespressif32",
-  "version": "3.0.5",
-  "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-S and ESP32-C series of SoCs",
+  "version": "3.1.0",
+  "description": "Arduino Wiring-based Framework for the Espressif ESP32, ESP32-P4, ESP32-S and ESP32-C series of SoCs",
   "keywords": [
     "framework",
     "arduino",
diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json
index 751617ee152..6b5a6370a4f 100644
--- a/package/package_esp32_index.template.json
+++ b/package/package_esp32_index.template.json
@@ -42,47 +42,37 @@
             {
               "packager": "esp32",
               "name": "esp32-arduino-libs",
-              "version": "idf-release_v5.1-33fbade6"
+              "version": "idf-release_v5.3-a0f798cf"
             },
             {
               "packager": "esp32",
-              "name": "xtensa-esp32-elf-gcc",
-              "version": "esp-12.2.0_20230208"
-            },
-            {
-              "packager": "esp32",
-              "name": "xtensa-esp32s2-elf-gcc",
-              "version": "esp-12.2.0_20230208"
-            },
-            {
-              "packager": "esp32",
-              "name": "xtensa-esp32s3-elf-gcc",
-              "version": "esp-12.2.0_20230208"
+              "name": "xtensa-esp-elf-gcc",
+              "version": "esp-13.2.0_20240530"
             },
             {
               "packager": "esp32",
               "name": "xtensa-esp-elf-gdb",
-              "version": "12.1_20231023"
+              "version": "14.2_20240403"
             },
             {
               "packager": "esp32",
               "name": "riscv32-esp-elf-gcc",
-              "version": "esp-12.2.0_20230208"
+              "version": "esp-13.2.0_20240530"
             },
             {
               "packager": "esp32",
               "name": "riscv32-esp-elf-gdb",
-              "version": "12.1_20231023"
+              "version": "14.2_20240403"
             },
             {
               "packager": "esp32",
               "name": "openocd-esp32",
-              "version": "v0.12.0-esp32-20240821"
+              "version": "v0.12.0-esp32-20241016"
             },
             {
               "packager": "esp32",
               "name": "esptool_py",
-              "version": "4.6"
+              "version": "4.9.dev1"
             },
             {
               "packager": "esp32",
@@ -105,545 +95,421 @@
       "tools": [
         {
           "name": "esp32-arduino-libs",
-          "version": "idf-release_v5.1-33fbade6",
+          "version": "idf-release_v5.3-a0f798cf",
           "systems": [
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             },
             {
               "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             },
             {
               "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
-            },
-            {
-              "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             },
-            {
-              "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
-            },
-            {
-              "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
-            },
-            {
-              "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "archiveFileName": "esp32-arduino-libs-idf-release_v5.1-33fbade6.zip",
-              "checksum": "SHA-256:578f325fa9fca635d9c6c3b19726cb26077751e3155b677317bde2e0b371df7d",
-              "size": "309285463"
-            }
-          ]
-        },
-        {
-          "name": "xtensa-esp32-elf-gcc",
-          "version": "esp-12.2.0_20230208",
-          "systems": [
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:e8d35938385447cf9c34735fee2a3b2b61cca6be07db77a45856a1c2a347e423",
-              "size": "111766903"
-            },
-            {
-              "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:569988acfc2673369f222037c64bac96990cee08cebeebc4f8860e0d984f8bd9",
-              "size": "106473247"
-            },
-            {
-              "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "checksum": "SHA-256:6a844f16021e936cc9b87b203978356f57ab2144554f6f2a0f73ffa3d3d316c5",
-              "size": "105576049"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             },
             {
               "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "checksum": "SHA-256:743d6f03a89329bb09f9550d27fcab677f5cf06b4720793bbcef7883a932681d",
-              "size": "114870843"
-            },
-            {
-              "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:4d32d764e984f3a570aacfb2f4957619540fb4629534d969b2e83997901334c3",
-              "size": "119424029"
-            },
-            {
-              "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:dc8fa7f4933bf5cb08e83bacce6160cc9dfe93d7aad1e8f92599bb81ff5b2e28",
-              "size": "106136827"
-            },
-            {
-              "host": "i686-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "checksum": "SHA-256:62bb6428d107ed3f44c212c77ecf24804b74c97327b0f0ad2029c656c6dbd6ee",
-              "size": "130847086"
-            },
-            {
-              "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp32-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "checksum": "SHA-256:8febfe4a6476efc69012390106c8c660a14418f025137b0513670c72124339cf",
-              "size": "134985117"
-            }
-          ]
-        },
-        {
-          "name": "xtensa-esp32s2-elf-gcc",
-          "version": "esp-12.2.0_20230208",
-          "systems": [
-            {
-              "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:2ff838520a5003d2768b275f5bb5ead69dd2388c3b7cd9043cb59891ba43147f",
-              "size": "112199211"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             },
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:6d79d5b14fc7129a9b8208d54e19b05dedb565f50f7a96264c9df84b06ad3be0",
-              "size": "106953064"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             },
             {
               "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "checksum": "SHA-256:e5bd03b6ad19179b015a93ada9992adc3610036ebf6aeb0835a09c9aadb50a14",
-              "size": "106026829"
-            },
-            {
-              "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "checksum": "SHA-256:fb45943557b2d201bbb1bdc7514a1872f9bb96c2dfb48b95abdba281cc792f75",
-              "size": "115288662"
-            },
-            {
-              "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:e965236cb80e45282d16f40184af183e013b63b177bd1884736c463eac636564",
-              "size": "119711811"
-            },
-            {
-              "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:78a55eec18650b21378d97494989ffe208748e0f49bb2b2d6756b264e1863919",
-              "size": "106540817"
-            },
-            {
-              "host": "i686-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "checksum": "SHA-256:1e6dac5162ab75f94b88c47ebeabb6600c652fb4f615ed07c1724d037c02fd19",
-              "size": "131273859"
-            },
-            {
-              "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s2-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp32s2-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "checksum": "SHA-256:8a785cc4e0838cebe404f82c0ead7a0f9ac5fabc660a742e33a41ddac6326cc1",
-              "size": "135373049"
+              "url": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.3/esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "archiveFileName": "esp32-arduino-libs-idf-release_v5.3-a0f798cf.zip",
+              "checksum": "SHA-256:f552d02ecef616389f1d0c973cb270718a192e6258db426656cd5965db3c6ed0",
+              "size": "339750940"
             }
           ]
         },
         {
-          "name": "xtensa-esp32s3-elf-gcc",
-          "version": "esp-12.2.0_20230208",
+          "name": "xtensa-esp-elf-gcc",
+          "version": "esp-13.2.0_20240530",
           "systems": [
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:61495ffe575e00c6998ae7274ff917658c04bded62ece0937c7042d6dcbf46de",
-              "size": "111971129"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:bce77e8480701d5a90545369d1b5848f6048eb39c0022d2446d1e33a8e127490",
+              "size": "208911713"
             },
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:9008d395be46fcfe68c7de6edc850fc1595f28323a28e7922e5c085bd310cb90",
-              "size": "106616800"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:7c9e3c1adc733d042ed87b92daa1d6396e1b441c1755f1fa14cb88855719ba88",
+              "size": "202519931"
             },
             {
               "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "checksum": "SHA-256:568857bdac7dea389dffc7fbc6871b4af299150a8ecf1bf965f224d2a1655edb",
-              "size": "105700326"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz",
+              "checksum": "SHA-256:d6955e8ea6af91574bf9213b92f32ca09eb8640103446b7fa19a63cfeeec5421",
+              "size": "202206516"
             },
             {
               "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "checksum": "SHA-256:d122738bcc6c2f52d05fa89b2fb1afe6a7894cda8a07a1879aca867a31507ed0",
-              "size": "115098400"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz",
+              "checksum": "SHA-256:3666ee74ecb693ee6488f11469802630a7b0d32608184045a4f35cb413f59e3d",
+              "size": "213304863"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:7defcddb98788b0991416ad2e0cb6a3b248b8030f22d5d76b8832117cc1494ca",
-              "size": "119883189"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz",
+              "checksum": "SHA-256:948cf57b6eecc898b5f70e06ad08ba88c08b627be570ec631dfcd72f6295194a",
+              "size": "221357024"
             },
             {
               "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:b59e076f8e4b9ca99535d449f9fc4cbb443188051dce4ad934e38f16b095f8d9",
-              "size": "106464677"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz",
+              "checksum": "SHA-256:6f03fdf0cc14a7f3900ee59977f62e8626d8b7c208506e52f1fd883ac223427a",
+              "size": "199689745"
             },
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "checksum": "SHA-256:3ddf51774817e815e5d41c312a90c1159226978fb45fd0d4f7085c567f8b73ab",
-              "size": "131134034"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-i686-w64-mingw32_hotfix.zip",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-i686-w64-mingw32_hotfix.zip",
+              "checksum": "SHA-256:d6b227c50e3c8e21d62502b3140e5ab74a4cb502c2b4169c36238b9858a8fb88",
+              "size": "266042967"
             },
             {
               "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/xtensa-esp32s3-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp32s3-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "checksum": "SHA-256:1d15ca65e3508388a86d8bed3048c46d07538f5bc88d3e4296f9c03152087cd1",
-              "size": "135381926"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-w64-mingw32_hotfix.zip",
+              "archiveFileName": "xtensa-esp-elf-13.2.0_20240530-x86_64-w64-mingw32_hotfix.zip",
+              "checksum": "SHA-256:155ee97b531236e6a7c763395c68ca793e55e74d2cb4d38a23057a153e01e7d0",
+              "size": "269831985"
             }
           ]
         },
         {
           "name": "xtensa-esp-elf-gdb",
-          "version": "12.1_20231023",
+          "version": "14.2_20240403",
           "systems": [
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:d0743ec43cd92c35452a9097f7863281de4e72f04120d63cfbcf9d591a373529",
-              "size": "36942094"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:9d68472d4cba5cf8c2b79d94f86f92c828e76a632bd1e6be5e7706e5b304d36e",
+              "size": "31010320"
             },
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:bc1fac0366c6a08e26c45896ca21c8c90efc2cdd431b8ba084e8772e15502d0e",
-              "size": "37134601"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:bdabc3217994815fc311c4e16e588b78f6596b5ad4ffa46c80b40e982cfb1e66",
+              "size": "30954580"
             },
             {
               "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz",
-              "checksum": "SHA-256:25efc51d52b71f097ccec763c5c885c8f5026b432fec4b5badd6a5f36fe34d04",
-              "size": "34579556"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz",
+              "checksum": "SHA-256:d54b8d703ba897b28c627da3d27106a3906dd01ba298778a67064710bc33c76d",
+              "size": "28697281"
             },
             {
               "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz",
-              "checksum": "SHA-256:e0af0b3b4a6b29a843cd5f47e331a966d9258f7d825b4656c6251490f71b05b2",
-              "size": "35676578"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz",
+              "checksum": "SHA-256:64d3bc992ed8fdec383d49e8b803ac494605a38117c8293db8da055037de96b0",
+              "size": "29890994"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz",
-              "checksum": "SHA-256:bd146fd99a52b2d71c7ce0f62b9e18f3423d6cae7b2b2c954046b0dd7a23142f",
-              "size": "52863941"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz",
+              "checksum": "SHA-256:023e74b3fda793da4bc0509b02de776ee0dad6efaaac17bef5916fb7dc9c26b9",
+              "size": "44446611"
             },
             {
               "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz",
-              "checksum": "SHA-256:5edc76565bf9d2fadf24e443ddf3df7567354f336a65d4af5b2ee805cdfcec24",
-              "size": "33504923"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz",
+              "checksum": "SHA-256:ea757c6bf8c25238f6d2fdcc6bbab25a1b00608a0f9e19b7ddd2f37ddbdc3fb1",
+              "size": "37021423"
             },
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip",
-              "checksum": "SHA-256:ea4f3ee6b95ad1ad2e07108a21a50037a3e64a420cdeb34b2ba95d612faed898",
-              "size": "31068749"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip",
+              "checksum": "SHA-256:322e8d9b700dc32d8158e3dc55fb85ec55de48d0bb7789375ee39a28d5d655e2",
+              "size": "26302466"
             },
             {
               "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/xtensa-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip",
-              "archiveFileName": "xtensa-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip",
-              "checksum": "SHA-256:13bb97f39173948d1cfb6e651d9b335ea9d52f1fdd0dda1eda3a2d23d8c63644",
-              "size": "33514906"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/xtensa-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip",
+              "archiveFileName": "xtensa-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip",
+              "checksum": "SHA-256:a27a2fe20f192f8e0a51b8936428b4e1cf8935cfe008ee445cc49f6fc7f6db2e",
+              "size": "28366035"
             }
           ]
         },
         {
           "name": "riscv32-esp-elf-gcc",
-          "version": "esp-12.2.0_20230208",
+          "version": "esp-13.2.0_20240530",
           "systems": [
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-x86_64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:1eb0d65990547ee9706b90406600cbc3638814d5feb7c1f7b44bb5416478a5bd",
-              "size": "257615266"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:e7fbfffbb19dcd3764a9848a141bf44e19ad0b48e0bd1515912345c26fe52fba",
+              "size": "294346758"
             },
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-aarch64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:921fcdc170c7fe5d6a0a30470ed1875c8926d910c19739fc950c8d1836e4c1c5",
-              "size": "253094184"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:a178a895b807ed2e87d5d62153c36a6aae048581f527c0eb152f0a02b8de9571",
+              "size": "288374597"
             },
             {
               "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-arm-linux-gnueabi.tar.gz",
-              "checksum": "SHA-256:f66e06312b58251c2121c1b1df1102565708573b86b2a9fe0c03ea1b0e9a7511",
-              "size": "252558021"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.gz",
+              "checksum": "SHA-256:4a2f176d0f5bc8a70645975e2a08ea94145fb69b7225c5cdcbd6024a4836aaf5",
+              "size": "287737495"
             },
             {
               "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-i686-linux-gnu.tar.gz",
-              "checksum": "SHA-256:8abcac0331ef8973d1c705e77523364ebec7e98b37640d4a1d036912f3cbe946",
-              "size": "261248375"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.gz",
+              "checksum": "SHA-256:7a6f02f1b2effafb18600bbf602818f6923fd320f000fb8659f34acbfda8812f",
+              "size": "299138540"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-x86_64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:76a334bc75a4e3891c222c84d7968817f2d0699d2976fc2a1658e56395283bec",
-              "size": "268987133"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.gz",
+              "checksum": "SHA-256:a193b4f025d0d836b0a9d9cbe760af1c53e53af66fc332fe98952bc4c456dd9a",
+              "size": "305025700"
             },
             {
               "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-aarch64-apple-darwin.tar.gz",
-              "checksum": "SHA-256:f30571945b257a10a26901bba3c5892e07c192aacf9ed6e8fcd11ca36ed827d2",
-              "size": "252159713"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.gz",
+              "checksum": "SHA-256:7082dd2e2123dea5609a24092d19ac6612ae7e219df1d298de6b2f64cb4af0df",
+              "size": "285458443"
             },
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-i686-w64-mingw32.zip",
-              "checksum": "SHA-256:a5dfbb6dbf6fc6c6ea9beb2723af059ba3c5b2c86c2f0dc3b21afdc7bb229bf5",
-              "size": "324863847"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-i686-w64-mingw32.zip",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-i686-w64-mingw32.zip",
+              "checksum": "SHA-256:590bfb10576702639825581cc00c445da6e577012840a787137417e80d15f46d",
+              "size": "366573064"
             },
             {
               "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-12.2.0_20230208/riscv32-esp-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "archiveFileName": "riscv32-esp-elf-12.2.0_20230208-x86_64-w64-mingw32.zip",
-              "checksum": "SHA-256:9deae9e0013b2f7bbf017f9c8135755bfa89522f337c7dca35872bf12ec08176",
-              "size": "328092732"
+              "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-w64-mingw32.zip",
+              "archiveFileName": "riscv32-esp-elf-13.2.0_20240530-x86_64-w64-mingw32.zip",
+              "checksum": "SHA-256:413eb9f6adf8fdaf25544d014c850fc09eb38bb93a2fc5ebd107ab1b0de1bb3a",
+              "size": "369820297"
             }
           ]
         },
         {
           "name": "riscv32-esp-elf-gdb",
-          "version": "12.1_20231023",
+          "version": "14.2_20240403",
           "systems": [
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-x86_64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:2c78b806be176b1e449e07ff83429d38dfc39a13f89a127ac1ffa6c1230537a0",
-              "size": "36630145"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-x86_64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:ce004bc0bbd71b246800d2d13b239218b272a38bd528e316f21f1af2db8a4b13",
+              "size": "30707431"
             },
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-aarch64-linux-gnu.tar.gz",
-              "checksum": "SHA-256:33f80117c8777aaff9179e27953e41764c5c46b3c576dc96a37ecc7a368807ec",
-              "size": "36980143"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-aarch64-linux-gnu.tar.gz",
+              "checksum": "SHA-256:ba10f2866c61410b88c65957274280b1a62e3bed05131654ed9b6758efe18e55",
+              "size": "30824065"
             },
             {
               "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-arm-linux-gnueabi.tar.gz",
-              "checksum": "SHA-256:292e6ec0a9381c1480bbadf5caae25e86428b68fb5d030c9be7deda5e7f070e0",
-              "size": "34950318"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-arm-linux-gnueabi.tar.gz",
+              "checksum": "SHA-256:88539db5d987f28827efac7e26080a2803b9b539342ccd2963ccfdd56d7f08f7",
+              "size": "29000575"
             },
             {
               "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-i586-linux-gnu.tar.gz",
-              "checksum": "SHA-256:68a25fbcfc6371ec4dbe503ec92211977eb2006f0c29e67dbce6b93c70c6b7ec",
-              "size": "35801607"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-i586-linux-gnu.tar.gz",
+              "checksum": "SHA-256:0e628ee37438ab6ba05eb889a76d09e50cb98e0020a16b8e2b935c5cf19b4ed2",
+              "size": "29947521"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-x86_64-apple-darwin14.tar.gz",
-              "checksum": "SHA-256:322c722e6c12225ed8cd97f95a0375105756dc5113d369958ce0858ad1a90257",
-              "size": "52618688"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-x86_64-apple-darwin14.tar.gz",
+              "checksum": "SHA-256:8f6bda832d70dad5860a639d55aba4237bd10cbac9f4822db1eece97357b34a9",
+              "size": "44196117"
             },
             {
               "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-aarch64-apple-darwin21.1.tar.gz",
-              "checksum": "SHA-256:c2224b3a8d02451c530cf004c29653292d963a1b4021b4b472b862b6dbe97e0b",
-              "size": "33149392"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-aarch64-apple-darwin21.1.tar.gz",
+              "checksum": "SHA-256:d88b6116e86456c8480ce9bc95aed375a35c0d091f1da0a53b86be0e6ef3d320",
+              "size": "36794404"
             },
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-i686-w64-mingw32.zip",
-              "checksum": "SHA-256:4b42149a99dd87ee7e6dde25c99bad966c7f964253fa8f771593d7cef69f5602",
-              "size": "31635103"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-i686-w64-mingw32.zip",
+              "checksum": "SHA-256:d6e7ce05805b0d8d4dd138ad239b98a1adf8da98941867d60760eb1ae5361730",
+              "size": "26486295"
             },
             {
               "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v12.1_20231023/riscv32-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip",
-              "archiveFileName": "riscv32-esp-elf-gdb-12.1_20231023-x86_64-w64-mingw32.zip",
-              "checksum": "SHA-256:728231546ad5006d34463f972658b2a89e52f660a42abab08a29bedd4a8046ad",
-              "size": "33400816"
+              "url": "https://github.com/espressif/binutils-gdb/releases/download/esp-gdb-v14.2_20240403/riscv32-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip",
+              "archiveFileName": "riscv32-esp-elf-gdb-14.2_20240403-x86_64-w64-mingw32.zip",
+              "checksum": "SHA-256:5c9f211dc46daf6b96fad09d709284a0f0186fef8947d9f6edd6bca5b5ad4317",
+              "size": "27942579"
             }
           ]
         },
         {
           "name": "openocd-esp32",
-          "version": "v0.12.0-esp32-20240821",
+          "version": "v0.12.0-esp32-20241016",
           "systems": [
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-amd64-0.12.0-esp32-20240821.tar.gz",
-              "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20240821.tar.gz",
-              "checksum": "SHA-256:f8c68541fa38307bc0c0763b7e1e3fe4e943d5d45da07d817a73b492e103b652",
-              "size": "2373094"
+              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-amd64-0.12.0-esp32-20241016.tar.gz",
+              "archiveFileName": "openocd-esp32-linux-amd64-0.12.0-esp32-20241016.tar.gz",
+              "checksum": "SHA-256:e82b0f036dc99244bead5f09a86e91bb2365cbcd1122ac68261e5647942485df",
+              "size": "2398717"
             },
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-arm64-0.12.0-esp32-20240821.tar.gz",
-              "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20240821.tar.gz",
-              "checksum": "SHA-256:4d6e263d84e447354dc685848557d6c284dda7fe007ee451f729a7edfa7baad7",
-              "size": "2251272"
+              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-arm64-0.12.0-esp32-20241016.tar.gz",
+              "archiveFileName": "openocd-esp32-linux-arm64-0.12.0-esp32-20241016.tar.gz",
+              "checksum": "SHA-256:8f8daf5bd22ec5d2fa9257b0862ec33da18ee677e023fb9a9eb17f74ce208c76",
+              "size": "2271584"
             },
             {
               "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-linux-armel-0.12.0-esp32-20240821.tar.gz",
-              "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20240821.tar.gz",
-              "checksum": "SHA-256:9d45679f2c4cf450d5e2350047cf57bb76dde2487d30cebce0a72c9173b5c45b",
-              "size": "2390074"
+              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-linux-armel-0.12.0-esp32-20241016.tar.gz",
+              "archiveFileName": "openocd-esp32-linux-armel-0.12.0-esp32-20241016.tar.gz",
+              "checksum": "SHA-256:bc9c020ecf20e2000f76cffa44305fd5bc44d2e688ea78cce423399d33f19767",
+              "size": "2414206"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-macos-0.12.0-esp32-20240821.tar.gz",
-              "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20240821.tar.gz",
-              "checksum": "SHA-256:565c8fabc5f19a6e7a0864a294d74b307eec30b9291d16d3fc90e273f0330cb4",
-              "size": "2485320"
+              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-macos-0.12.0-esp32-20241016.tar.gz",
+              "archiveFileName": "openocd-esp32-macos-0.12.0-esp32-20241016.tar.gz",
+              "checksum": "SHA-256:02a2dffe801a2d005fa9e614d80ff8173395b2cb0b5d3118d0229d094a9946a7",
+              "size": "2508089"
             },
             {
               "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-macos-arm64-0.12.0-esp32-20240821.tar.gz",
-              "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20240821.tar.gz",
-              "checksum": "SHA-256:68c5c7cf3d15b9810939a5edabc6ff2c9f4fc32262de91fc292a180bc5cc0637",
-              "size": "2530336"
+              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-macos-arm64-0.12.0-esp32-20241016.tar.gz",
+              "archiveFileName": "openocd-esp32-macos-arm64-0.12.0-esp32-20241016.tar.gz",
+              "checksum": "SHA-256:c382f9e884d6565cb6089bff5f200f4810994667d885f062c3d3c5625a0fa9d6",
+              "size": "2552569"
             },
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-win32-0.12.0-esp32-20240821.zip",
-              "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20240821.zip",
-              "checksum": "SHA-256:463fc2903ddaf03f86ff50836c5c63cc696550b0446140159eddfd2e85570c5d",
-              "size": "2916409"
+              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-win32-0.12.0-esp32-20241016.zip",
+              "archiveFileName": "openocd-esp32-win32-0.12.0-esp32-20241016.zip",
+              "checksum": "SHA-256:3b5d615e0a72cc771a45dd469031312d5881c01d7b6bc9edb29b8b6bda8c2e90",
+              "size": "2946244"
             },
             {
               "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20240821/openocd-esp32-win64-0.12.0-esp32-20240821.zip",
-              "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20240821.zip",
-              "checksum": "SHA-256:550f57369f1f1f6cc600b5dffa3378fd6164d8ea8db7c567cf41091771f090cb",
-              "size": "2916408"
+              "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20241016/openocd-esp32-win64-0.12.0-esp32-20241016.zip",
+              "archiveFileName": "openocd-esp32-win64-0.12.0-esp32-20241016.zip",
+              "checksum": "SHA-256:5e7b2fd1947d3a8625f6a11db7a2340cf2f41ff4c61284c022c7d7c32b18780a",
+              "size": "2946244"
             }
           ]
         },
         {
           "name": "esptool_py",
-          "version": "4.6",
+          "version": "4.9.dev1",
           "systems": [
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz",
-              "archiveFileName": "esptool-v4.6-src.tar.gz",
-              "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a",
-              "size": "99141"
+              "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC2/esptool-v4.9.dev1-linux-amd64.tar.gz",
+              "archiveFileName": "esptool-v4.9.dev1-linux-amd64.tar.gz",
+              "checksum": "SHA-256:21f6c2155f0ec9e5b475c8a4bf59803d8cfb4d74f4e488a80f97da3d77542bba",
+              "size": "64632960"
             },
             {
-              "host": "i686-pc-linux-gnu",
-              "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz",
-              "archiveFileName": "esptool-v4.6-src.tar.gz",
-              "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a",
-              "size": "99141"
+              "host": "arm-linux-gnueabihf",
+              "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC2/esptool-v4.9.dev1-linux-arm32.tar.gz",
+              "archiveFileName": "esptool-v4.9.dev1-linux-arm32.tar.gz",
+              "checksum": "SHA-256:818477f10814b2bd82078fc6695663ac84220d3947722ce1880a6c867d5c2997",
+              "size": "46042432"
             },
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz",
-              "archiveFileName": "esptool-v4.6-src.tar.gz",
-              "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a",
-              "size": "99141"
-            },
-            {
-              "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-src.tar.gz",
-              "archiveFileName": "esptool-v4.6-src.tar.gz",
-              "checksum": "SHA-256:22f9bad0cd1cea14e554ac1f4a6d8f67415ff7029a66ce9130756276e7264e5a",
-              "size": "99141"
+              "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC2/esptool-v4.9.dev1-linux-arm64.tar.gz",
+              "archiveFileName": "esptool-v4.9.dev1-linux-arm64.tar.gz",
+              "checksum": "SHA-256:b377a130a4dca58f3a31c66ed0b9858cc057c998741222cccdb6e5a724651a1f",
+              "size": "54459357"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-macos.tar.gz",
-              "archiveFileName": "esptool-v4.6-macos.tar.gz",
-              "checksum": "SHA-256:885ec69fcffdcb9e7c6eacd2589f13a45ce6bcb6742bea368ec3a73bcca6dd59",
-              "size": "5851297"
+              "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC2/esptool-v4.9.dev1-macos-amd64.tar.gz",
+              "archiveFileName": "esptool-v4.9.dev1-macos-amd64.tar.gz",
+              "checksum": "SHA-256:25cc246b20230afc287ffdfe95f57b3fab23cec88a6dde3b5092ec05926b5431",
+              "size": "32386336"
             },
             {
-              "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-win64.zip",
-              "archiveFileName": "esptool-v4.6-win64.zip",
-              "checksum": "SHA-256:c7c68cd1aa520cbfce488ff6a77818ece272272eb012831b9d9ab1280a7c393f",
-              "size": "6638480"
+              "host": "arm64-apple-darwin",
+              "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC2/esptool-v4.9.dev1-macos-arm64.tar.gz",
+              "archiveFileName": "esptool-v4.9.dev1-macos-arm64.tar.gz",
+              "checksum": "SHA-256:b845d678db1d1559d82894e68366683a7fc3809371a5f5def67c30c9dee15912",
+              "size": "29841092"
             },
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esptool-v4.6-win64.zip",
-              "archiveFileName": "esptool-v4.6-win64.zip",
-              "checksum": "SHA-256:c7c68cd1aa520cbfce488ff6a77818ece272272eb012831b9d9ab1280a7c393f",
-              "size": "6638480"
+              "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC2/esptool-v4.9.dev1-win64.zip",
+              "archiveFileName": "esptool-v4.9.dev1-win64.zip",
+              "checksum": "SHA-256:f649a212e086b06ca6ee595feffd7a4706696ea43a2cd1a4f49352829e8ac96e",
+              "size": "35812159"
+            },
+            {
+              "host": "x86_64-mingw32",
+              "url": "https://github.com/espressif/arduino-esp32/releases/download/3.1.0-RC2/esptool-v4.9.dev1-win64.zip",
+              "archiveFileName": "esptool-v4.9.dev1-win64.zip",
+              "checksum": "SHA-256:f649a212e086b06ca6ee595feffd7a4706696ea43a2cd1a4f49352829e8ac96e",
+              "size": "35812159"
             }
           ]
         },
diff --git a/platform.txt b/platform.txt
index d1c3fb3a3dd..b075e539866 100644
--- a/platform.txt
+++ b/platform.txt
@@ -1,18 +1,15 @@
 name=ESP32 Arduino
-version=3.0.5
+version=3.1.0
 
 tools.esp32-arduino-libs.path={runtime.platform.path}/tools/esp32-arduino-libs
 tools.esp32-arduino-libs.path.windows={runtime.platform.path}\tools\esp32-arduino-libs
-tools.xtensa-esp32-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp32-elf
-tools.xtensa-esp32s2-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp32s2-elf
-tools.xtensa-esp32s3-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp32s3-elf
+tools.xtensa-esp-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp-elf
 tools.xtensa-esp-elf-gdb.path={runtime.platform.path}/tools/xtensa-esp-elf-gdb
 tools.riscv32-esp-elf-gcc.path={runtime.platform.path}/tools/riscv32-esp-elf
 tools.riscv32-esp-elf-gdb.path={runtime.platform.path}/tools/riscv32-esp-elf-gdb
 
 tools.esptool_py.path={runtime.platform.path}/tools/esptool
 tools.esptool_py.cmd=esptool
-tools.esptool_py.cmd.linux=esptool.py
 tools.esptool_py.cmd.windows=esptool.exe
 
 tools.esptool_py.network_cmd=python3 "{runtime.platform.path}/tools/espota.py" -r
@@ -27,7 +24,7 @@ tools.gen_esp32part.cmd.windows="{runtime.platform.path}\tools\gen_esp32part.exe
 tools.gen_insights_pkg.cmd=python3 "{runtime.platform.path}"/tools/gen_insights_package.py
 tools.gen_insights_pkg.cmd.windows="{runtime.platform.path}\tools\gen_insights_package.exe"
 
-compiler.path={tools.{build.tarch}-{build.target}-elf-gcc.path}/bin/
+compiler.path={tools.{build.tarch}-esp-elf-gcc.path}/bin/
 compiler.prefix={build.tarch}-{build.target}-elf-
 
 compiler.sdk.path={tools.esp32-arduino-libs.path}/{build.mcu}
@@ -52,10 +49,10 @@ compiler.common_werror_flags=-Werror=return-type
 
 # Compile Flags
 compiler.cpreprocessor.flags="@{compiler.sdk.path}/flags/defines" "-I{build.source.path}" -iprefix "{compiler.sdk.path}/include/" "@{compiler.sdk.path}/flags/includes" "-I{compiler.sdk.path}/{build.memory_type}/include"
-compiler.c.flags="@{compiler.sdk.path}/flags/c_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags}
-compiler.cpp.flags="@{compiler.sdk.path}/flags/cpp_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags}
-compiler.S.flags="@{compiler.sdk.path}/flags/S_flags" {compiler.warning_flags} {compiler.optimization_flags}
-compiler.c.elf.flags="@{compiler.sdk.path}/flags/ld_flags" "@{compiler.sdk.path}/flags/ld_scripts"
+compiler.c.flags=-MMD -c "@{compiler.sdk.path}/flags/c_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags}
+compiler.cpp.flags=-MMD -c "@{compiler.sdk.path}/flags/cpp_flags" {compiler.warning_flags} {compiler.optimization_flags} {compiler.common_werror_flags}
+compiler.S.flags=-MMD -c -x assembler-with-cpp "@{compiler.sdk.path}/flags/S_flags" {compiler.warning_flags} {compiler.optimization_flags}
+compiler.c.elf.flags="-Wl,--Map={build.path}/{build.project_name}.map" "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-L{compiler.sdk.path}/{build.memory_type}" "-Wl,--wrap=esp_panic_handler" "@{compiler.sdk.path}/flags/ld_flags" "@{compiler.sdk.path}/flags/ld_scripts"
 compiler.c.elf.libs="@{compiler.sdk.path}/flags/ld_libs"
 compiler.ar.flags=cr
 
@@ -69,10 +66,10 @@ compiler.ar.cmd={compiler.prefix}gcc-ar
 compiler.size.cmd={compiler.prefix}size
 
 # These can be overridden in platform.local.txt
-compiler.c.extra_flags=-MMD -c
-compiler.cpp.extra_flags=-MMD -c
-compiler.S.extra_flags=-MMD -c -x assembler-with-cpp
-compiler.c.elf.extra_flags="-Wl,--Map={build.path}/{build.project_name}.map" "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-L{compiler.sdk.path}/{build.memory_type}" "-Wl,--wrap=esp_panic_handler"
+compiler.c.extra_flags=
+compiler.cpp.extra_flags=
+compiler.S.extra_flags=
+compiler.c.elf.extra_flags=
 compiler.ar.extra_flags=
 compiler.objcopy.eep.extra_flags=
 compiler.elf2hex.extra_flags=
@@ -86,6 +83,7 @@ build.extra_flags.esp32c2=-DARDUINO_USB_CDC_ON_BOOT=0
 build.extra_flags.esp32c3=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot}
 build.extra_flags.esp32c6=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot}
 build.extra_flags.esp32h2=-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot}
+build.extra_flags.esp32p4=-DARDUINO_USB_MODE={build.usb_mode} -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} -DARDUINO_USB_MSC_ON_BOOT={build.msc_on_boot} -DARDUINO_USB_DFU_ON_BOOT={build.dfu_on_boot}
 
 # This can be overriden in boards.txt
 build.zigbee_mode=
@@ -123,7 +121,6 @@ recipe.hooks.prebuild.3.pattern.windows=cmd /c if not exist "{build.path}\partit
 # Check if custom bootloader exist: source > variant > build.boot
 recipe.hooks.prebuild.4.pattern_args=--chip {build.mcu} elf2image --flash_mode {build.flash_mode} --flash_freq {build.img_freq} --flash_size {build.flash_size} -o
 recipe.hooks.prebuild.4.pattern=/usr/bin/env bash -c "[ -f "{build.source.path}"/bootloader.bin ] && cp -f "{build.source.path}"/bootloader.bin "{build.path}"/{build.project_name}.bootloader.bin || ( [ -f "{build.variant.path}"/{build.custom_bootloader}.bin ] && cp "{build.variant.path}"/{build.custom_bootloader}.bin "{build.path}"/{build.project_name}.bootloader.bin || "{tools.esptool_py.path}"/{tools.esptool_py.cmd} {recipe.hooks.prebuild.4.pattern_args} "{build.path}"/{build.project_name}.bootloader.bin "{compiler.sdk.path}"/bin/bootloader_{build.boot}_{build.boot_freq}.elf )"
-recipe.hooks.prebuild.4.pattern.linux=/usr/bin/env bash -c "[ -f "{build.source.path}"/bootloader.bin ] && cp -f "{build.source.path}"/bootloader.bin "{build.path}"/{build.project_name}.bootloader.bin || ( [ -f "{build.variant.path}"/{build.custom_bootloader}.bin ] && cp "{build.variant.path}"/{build.custom_bootloader}.bin "{build.path}"/{build.project_name}.bootloader.bin || python3 "{tools.esptool_py.path}"/{tools.esptool_py.cmd} {recipe.hooks.prebuild.4.pattern_args} "{build.path}"/{build.project_name}.bootloader.bin "{compiler.sdk.path}"/bin/bootloader_{build.boot}_{build.boot_freq}.elf )"
 recipe.hooks.prebuild.4.pattern.windows=cmd /c IF EXIST "{build.source.path}\bootloader.bin" ( COPY /y "{build.source.path}\bootloader.bin" "{build.path}\{build.project_name}.bootloader.bin" ) ELSE ( IF EXIST "{build.variant.path}\{build.custom_bootloader}.bin" ( COPY "{build.variant.path}\{build.custom_bootloader}.bin" "{build.path}\{build.project_name}.bootloader.bin" ) ELSE ( "{tools.esptool_py.path}\{tools.esptool_py.cmd}" {recipe.hooks.prebuild.4.pattern_args} "{build.path}\{build.project_name}.bootloader.bin" "{compiler.sdk.path}\bin\bootloader_{build.boot}_{build.boot_freq}.elf" ) )
 
 # Check if custom build options exist in the sketch folder
@@ -168,7 +165,6 @@ recipe.objcopy.partitions.bin.pattern={tools.gen_esp32part.cmd} -q "{build.path}
 ## Create bin
 recipe.objcopy.bin.pattern_args=--chip {build.mcu} elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.img_freq}" --flash_size "{build.flash_size}" --elf-sha256-offset 0xb0 -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf"
 recipe.objcopy.bin.pattern="{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.objcopy.bin.pattern_args}
-recipe.objcopy.bin.pattern.linux=python3 "{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.objcopy.bin.pattern_args}
 
 ## Create Insights Firmware Package
 recipe.hooks.objcopy.postobjcopy.1.pattern_args={build.path} {build.project_name} "{build.source.path}"
@@ -182,7 +178,6 @@ recipe.hooks.objcopy.postobjcopy.2.pattern.windows=cmd /c if exist "{build.path}
 # Create merged binary
 recipe.hooks.objcopy.postobjcopy.3.pattern_args=--chip {build.mcu} merge_bin -o "{build.path}/{build.project_name}.merged.bin" --fill-flash-size {build.flash_size} --flash_mode keep --flash_freq keep --flash_size keep {build.bootloader_addr} "{build.path}/{build.project_name}.bootloader.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin" 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x10000 "{build.path}/{build.project_name}.bin"
 recipe.hooks.objcopy.postobjcopy.3.pattern="{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.hooks.objcopy.postobjcopy.3.pattern_args}
-recipe.hooks.objcopy.postobjcopy.3.pattern.linux=python3 "{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.hooks.objcopy.postobjcopy.3.pattern_args}
 
 ## Save bin
 recipe.output.tmp_file={build.project_name}.bin
@@ -292,7 +287,6 @@ tools.esptool_py.upload.params.verbose=
 tools.esptool_py.upload.params.quiet=
 tools.esptool_py.upload.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset write_flash {upload.erase_cmd} -z --flash_mode keep --flash_freq keep --flash_size keep {build.bootloader_addr} "{build.path}/{build.project_name}.bootloader.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin" 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x10000 "{build.path}/{build.project_name}.bin" {upload.extra_flags}
 tools.esptool_py.upload.pattern="{path}/{cmd}" {upload.pattern_args}
-tools.esptool_py.upload.pattern.linux=python3 "{path}/{cmd}" {upload.pattern_args}
 
 ## Program Application
 ## -------------------
@@ -300,7 +294,6 @@ tools.esptool_py.program.params.verbose=
 tools.esptool_py.program.params.quiet=
 tools.esptool_py.program.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset write_flash -z --flash_mode keep --flash_freq keep --flash_size keep 0x10000 "{build.path}/{build.project_name}.bin"
 tools.esptool_py.program.pattern="{path}/{cmd}" {program.pattern_args}
-tools.esptool_py.program.pattern.linux=python3 "{path}/{cmd}" {program.pattern_args}
 
 ## Erase Chip (before burning the bootloader)
 ## ------------------------------------------
@@ -309,7 +302,6 @@ tools.esptool_py.erase.params.verbose=
 tools.esptool_py.erase.params.quiet=
 tools.esptool_py.erase.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset erase_flash
 tools.esptool_py.erase.pattern="{path}/{cmd}" {erase.pattern_args}
-tools.esptool_py.erase.pattern.linux=python3 "{path}/{cmd}" {erase.pattern_args}
 
 ## Burn Bootloader
 ## ---------------
diff --git a/tests/performance/psramspeed/test_psramspeed.py b/tests/performance/psramspeed/test_psramspeed.py
index 8d051580799..9e96e158504 100644
--- a/tests/performance/psramspeed/test_psramspeed.py
+++ b/tests/performance/psramspeed/test_psramspeed.py
@@ -74,7 +74,7 @@ def test_psramspeed(dut, request):
         sums[(test, size, impl)]["time_sum"] += time
 
     avg_results = {}
-    for (test, size, impl) in sums:
+    for test, size, impl in sums:
         rate_avg = round(sums[(test, size, impl)]["rate_sum"] / runs, 2)
         time_avg = round(sums[(test, size, impl)]["time_sum"] / runs, 2)
         LOGGER.info(
diff --git a/tests/performance/ramspeed/test_ramspeed.py b/tests/performance/ramspeed/test_ramspeed.py
index b4c3cee7f9b..dbe1670d329 100644
--- a/tests/performance/ramspeed/test_ramspeed.py
+++ b/tests/performance/ramspeed/test_ramspeed.py
@@ -74,7 +74,7 @@ def test_ramspeed(dut, request):
         sums[(test, size, impl)]["time_sum"] += time
 
     avg_results = {}
-    for (test, size, impl) in sums:
+    for test, size, impl in sums:
         rate_avg = round(sums[(test, size, impl)]["rate_sum"] / runs, 2)
         time_avg = round(sums[(test, size, impl)]["time_sum"] / runs, 2)
         LOGGER.info(
diff --git a/tests/requirements.txt b/tests/requirements.txt
index a7df8928665..cef0bf17881 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,7 +1,7 @@
 cryptography==43.0.1
 --only-binary cryptography
 pytest-cov==5.0.0
-pytest-embedded-serial-esp==1.11.8
-pytest-embedded-arduino==1.11.8
-pytest-embedded-wokwi==1.11.8
-pytest-embedded-qemu==1.11.8
+pytest-embedded-serial-esp==1.12.0
+pytest-embedded-arduino==1.12.0
+pytest-embedded-wokwi==1.12.0
+pytest-embedded-qemu==1.12.0
diff --git a/tests/validation/periman/ci.json b/tests/validation/periman/ci.json
index accee2b2135..22ff71c54ff 100644
--- a/tests/validation/periman/ci.json
+++ b/tests/validation/periman/ci.json
@@ -2,5 +2,8 @@
   "platforms": {
     "qemu": false,
     "wokwi": false
+  },
+  "targets": {
+    "esp32p4": false
   }
 }
diff --git a/tests/validation/touch/touch.ino b/tests/validation/touch/touch.ino
index 60f6e7f7966..97aac8a65e6 100644
--- a/tests/validation/touch/touch.ino
+++ b/tests/validation/touch/touch.ino
@@ -2,6 +2,10 @@
 #include "soc/soc_caps.h"
 #include "driver/touch_pad.h"
 
+#if SOC_TOUCH_SENSOR_VERSION == 3
+#include "hal/touch_sensor_ll.h"
+#endif
+
 #if CONFIG_IDF_TARGET_ESP32
 
 #define TEST_TOUCH_CHANNEL (9)
@@ -15,11 +19,7 @@ uint8_t TOUCH_GPIOS[] = {4, 2, 15, 13, 12, 14, 27, 33, 32};
 
 #define NO_TOUCH_GPIO 25
 
-#define RELEASED_VALUE      75  //75+ read value to pass test
-#define PRESSED_VALUE       20  //20- read value to pass test
-#define INTERRUPT_THRESHOLD 40
-
-#else  //ESP32S2 and ESP32S3
+#elif (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3)
 
 #define TEST_TOUCH_CHANNEL (12)  //14
 static touch_pad_t touch_list[TEST_TOUCH_CHANNEL] = {
@@ -33,7 +33,25 @@ uint8_t TOUCH_GPIOS[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 /*,13,14*/};
 
 #define NO_TOUCH_GPIO 17
 
-#if CONFIG_IDF_TARGET_ESP32S2
+#else  //ESP32P4
+
+#define TEST_TOUCH_CHANNEL (5)  //14
+static touch_pad_t touch_list[TEST_TOUCH_CHANNEL] = {
+  TOUCH_PAD_NUM0, TOUCH_PAD_NUM1, TOUCH_PAD_NUM2,
+  TOUCH_PAD_NUM3, TOUCH_PAD_NUM4, /* TOUCH_PAD_NUM5, TOUCH_PAD_NUM6,
+  TOUCH_PAD_NUM7, TOUCH_PAD_NUM8, TOUCH_PAD_NUM9, TOUCH_PAD_NUM10, TOUCH_PAD_NUM11, TOUCH_PAD_NUM12, TOUCH_PAD_NUM13*/
+};
+
+uint8_t TOUCH_GPIOS[] = {2, 3, 4, 5, 6 /*, 7, 8, 9, 10, 11, 12 ,13, 14, 15*/};
+
+#define NO_TOUCH_GPIO 17
+#endif
+
+#if CONFIG_IDF_TARGET_ESP32
+#define RELEASED_VALUE      75  //75+ read value to pass test
+#define PRESSED_VALUE       20  //20- read value to pass test
+#define INTERRUPT_THRESHOLD 40
+#elif CONFIG_IDF_TARGET_ESP32S2
 #define RELEASED_VALUE      10000  //10000- read value to pass test
 #define PRESSED_VALUE       42000  //40000+ read value to pass test
 #define INTERRUPT_THRESHOLD 30000
@@ -41,12 +59,13 @@ uint8_t TOUCH_GPIOS[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 /*,13,14*/};
 #define RELEASED_VALUE      25000  //25000- read value to pass test
 #define PRESSED_VALUE       90000  //90000+ read value to pass test
 #define INTERRUPT_THRESHOLD 80000
+#elif CONFIG_IDF_TARGET_ESP32P4
+#define PRESSED_VALUE_DIFFERENCE 200  //200+ read value difference against the unpressed value
+#define INTERRUPT_THRESHOLD      0    // Use benchmarked threshold
 #else
 #error Test not currently supported on this chip. Please adjust and try again!
 #endif
 
-#endif
-
 bool touch1detected = false;
 bool touch2detected = false;
 
@@ -59,17 +78,25 @@ void gotTouch2() {
 }
 
 /*
- * Change the slope to get larger value from touch sensor.
+ * Change the slope to get larger value from touch sensor. (Capacitor for ESP32P4)
  */
 static void test_press_fake(touch_pad_t pad_num) {
+#if SOC_TOUCH_SENSOR_VERSION <= 2
   touch_pad_set_cnt_mode(pad_num, TOUCH_PAD_SLOPE_1, TOUCH_PAD_TIE_OPT_DEFAULT);
+#else
+  touch_ll_set_internal_capacitor(0x7f);
+#endif
 }
 
 /*
- * Change the slope to get smaller value from touch sensor.
+ * Change the slope to get smaller value from touch sensor. (Capacitor for ESP32P4)
  */
 static void test_release_fake(touch_pad_t pad_num) {
+#if SOC_TOUCH_SENSOR_VERSION <= 2
   touch_pad_set_cnt_mode(pad_num, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
+#else
+  touch_ll_set_internal_capacitor(0);
+#endif
 }
 
 /* These functions are intended to be called before and after each test. */
@@ -87,6 +114,7 @@ void tearDown(void) {
  */
 void test_touch_read(void) {
 
+#if SOC_TOUCH_SENSOR_VERSION <= 2
   //TEST RELEASE STATE
   for (int i = 0; i < sizeof(TOUCH_GPIOS); i++) {
 #ifdef CONFIG_IDF_TARGET_ESP32
@@ -109,6 +137,29 @@ void test_touch_read(void) {
     TEST_ASSERT_GREATER_THAN(PRESSED_VALUE, touchRead(TOUCH_GPIOS[k]));
 #endif
   }
+#else  //TOUCH V3
+  //TEST RELEASE STATE
+  touch_value_t touch_unpressed[sizeof(TOUCH_GPIOS)];
+  for (int i = 0; i < sizeof(TOUCH_GPIOS); i++) {
+    touch_unpressed[i] = touchRead(TOUCH_GPIOS[i]);
+  }
+
+  // TEST PRESS STATE
+  for (int j = 0; j < TEST_TOUCH_CHANNEL; j++) {
+    test_press_fake(touch_list[j]);
+  }
+  delay(100);
+
+  touch_value_t touch_pressed[sizeof(TOUCH_GPIOS)];
+  for (int k = 0; k < sizeof(TOUCH_GPIOS); k++) {
+    touch_pressed[k] = touchRead(TOUCH_GPIOS[k]);
+  }
+
+  // COMPARE PRESSED > UNPRESSED
+  for (int l = 0; l < sizeof(TOUCH_GPIOS); l++) {
+    TEST_ASSERT_GREATER_THAN((touch_unpressed[l] + PRESSED_VALUE_DIFFERENCE), touch_pressed[l]);
+  }
+#endif
 }
 
 void test_touch_interrtupt(void) {
@@ -146,4 +197,6 @@ void setup() {
   UNITY_END();
 }
 
-void loop() {}
+void loop() {
+  delay(10);
+}
diff --git a/tests/validation/uart/diagram.esp32.json b/tests/validation/uart/diagram.esp32.json
new file mode 100644
index 00000000000..a31c06d8313
--- /dev/null
+++ b/tests/validation/uart/diagram.esp32.json
@@ -0,0 +1,24 @@
+{
+  "version": 1,
+  "author": "lucasssvaz",
+  "editor": "wokwi",
+  "parts": [
+    {
+      "type": "board-esp32-devkit-c-v4",
+      "id": "esp",
+      "attrs": { "cpuFrequency": "40" }
+    }
+  ],
+  "connections": [
+    [
+      "esp:TX",
+      "$serialMonitor:RX",
+      ""
+    ],
+    [
+      "esp:RX",
+      "$serialMonitor:TX",
+      ""
+    ]
+  ]
+}
diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino
index 527d28241d9..27bd95da7f8 100644
--- a/tests/validation/uart/uart.ino
+++ b/tests/validation/uart/uart.ino
@@ -2,25 +2,20 @@
  *
  * This test is using UART0 (Serial) only for reporting test status and helping with the auto
  * baudrate detection test.
- * UART1 (Serial1) and UART2 (Serial2), where available, are used for testing.
+ * The other serials are used for testing.
  */
 
-#include <unity.h>
-#include "HardwareSerial.h"
-#include "esp_rom_gpio.h"
-#include "Wire.h"
-
 // Default pins:
-//          |  Name   | ESP32 | S2 | S3 | C3 | C6 | H2 |
-// UART0 RX | SOC_RX0 |   3   | 44 | 44 | 20 | 17 | 23 |
-// UART0 TX | SOC_TX0 |   1   | 43 | 43 | 21 | 16 | 24 |
-// UART1 RX |   RX1   |  26   |  4 | 15 | 18 |  4 |  0 |
-// UART1 TX |   TX1   |  27   |  5 | 16 | 19 |  5 |  1 |
-// UART2 RX |   RX2   |   4   | -- | 19 | -- | -- | -- |
-// UART2 TX |   TX2   |  25   | -- | 20 | -- | -- | -- |
+//          |  Name   | ESP32 | S2 | S3 | C3 | C6 | H2 | P4 |
+// UART0 RX | SOC_RX0 |   3   | 44 | 44 | 20 | 17 | 23 | 38 |
+// UART0 TX | SOC_TX0 |   1   | 43 | 43 | 21 | 16 | 24 | 37 |
+// UART1 RX |   RX1   |  26   |  4 | 15 | 18 |  4 |  0 | 11 |
+// UART1 TX |   TX1   |  27   |  5 | 16 | 19 |  5 |  1 | 10 |
+// UART2 RX |   RX2   |   4   | -- | 19 | -- | -- | -- | -- |
+// UART2 TX |   TX2   |  25   | -- | 20 | -- | -- | -- | -- |
 
 /*
- * For 2 UARTS:
+ * For each UART:
  *
  *           terminal
  *          |       ^
@@ -30,111 +25,95 @@
  *        report status
  *              |
  *         TX <---> RX
- *            UART1
- *
- * For 3 UARTS:
- *
- *     =====terminal======
- *      ^  |       ^    ^
- *      |  v UART0 |    |
- *      |  RX    TX     |
- *      |               |
- *      ^ report status ^
- *      |               |
- *      | TX ---> RX    |
- *  UART2 RX <--- TX UART1
- *
+ *            UARTx
  */
 
-#if SOC_UART_NUM == 2
-// Used for the pin swap test
-#define NEW_RX1 9
-#define NEW_TX1 10
-#endif
+#include <vector>
+#include <unity.h>
+#include "HardwareSerial.h"
+#include "esp_rom_gpio.h"
+#include "Wire.h"
 
-/* Utility global variables */
+/* Utility defines */
 
-static String recv_msg = "";
-static int peeked_char = -1;
+#define TEST_UART_NUM (uart_test_configs.size())
 
-/* Utility functions */
+/* Utility classes */
 
-extern int8_t uart_get_RxPin(uint8_t uart_num);
-extern int8_t uart_get_TxPin(uint8_t uart_num);
+class UARTTestConfig {
+public:
+  int uart_num;
+  HardwareSerial &serial;
+  int peeked_char;
+  int8_t default_rx_pin;
+  int8_t default_tx_pin;
+  String recv_msg;
 
-// This function starts all the available test UARTs
-void start_serial(unsigned long baudrate = 115200) {
-#if SOC_UART_NUM >= 2
-  Serial1.begin(baudrate);
-  while (!Serial1) {
-    delay(10);
-  }
-#endif
+  UARTTestConfig(int num, HardwareSerial &serial_ref, int8_t rx_pin, int8_t tx_pin)
+    : uart_num(num), serial(serial_ref), peeked_char(-1), default_rx_pin(rx_pin), default_tx_pin(tx_pin), recv_msg("") {}
 
-#if SOC_UART_NUM >= 3
-  Serial2.begin(baudrate);
-  while (!Serial2) {
-    delay(10);
+  void begin(unsigned long baudrate) {
+    serial.begin(baudrate, SERIAL_8N1, default_rx_pin, default_tx_pin);
+    while (!serial) {
+      delay(10);
+    }
   }
-#endif
-}
-
-// This function stops all the available test UARTs
-void stop_serial(bool hard_stop = false) {
-#if SOC_UART_NUM >= 2
-  Serial1.end(/*hard_stop*/);
-#endif
 
-#if SOC_UART_NUM >= 3
-  Serial2.end(/*hard_stop*/);
-#endif
-}
+  void end() {
+    serial.end();
+  }
 
-// This function transmits a message and checks if it was received correctly
-void transmit_and_check_msg(const String msg_append, bool perform_assert = true) {
-  delay(100);  // Wait for some settings changes to take effect
-#if SOC_UART_NUM == 2
-  Serial1.print("Hello from Serial1 (UART1) >>> via loopback >>> Serial1 (UART1) " + msg_append);
-  Serial1.flush();
-  delay(100);
-  if (perform_assert) {
-    TEST_ASSERT_EQUAL_STRING(("Hello from Serial1 (UART1) >>> via loopback >>> Serial1 (UART1) " + msg_append).c_str(), recv_msg.c_str());
+  void reset_buffers() {
+    recv_msg = "";
+    peeked_char = -1;
   }
-#elif SOC_UART_NUM == 3
-  Serial1.print("Hello from Serial1 (UART1) >>> to >>> Serial2 (UART2) " + msg_append);
-  Serial1.flush();
-  delay(100);
-  if (perform_assert) {
-    TEST_ASSERT_EQUAL_STRING(("Hello from Serial1 (UART1) >>> to >>> Serial2 (UART2) " + msg_append).c_str(), recv_msg.c_str());
+
+  void transmit_and_check_msg(const String &msg_append, bool perform_assert = true) {
+    reset_buffers();
+    delay(100);
+    serial.print("Hello from Serial" + String(uart_num) + " " + msg_append);
+    serial.flush();
+    delay(100);
+    if (perform_assert) {
+      TEST_ASSERT_EQUAL_STRING(("Hello from Serial" + String(uart_num) + " " + msg_append).c_str(), recv_msg.c_str());
+      log_d("UART%d received message: %s\n", uart_num, recv_msg.c_str());
+    }
   }
 
-  Serial2.print("Hello from Serial2 (UART2) >>> to >>> Serial1 (UART1) " + msg_append);
-  Serial2.flush();
-  delay(100);
-  if (perform_assert) {
-    TEST_ASSERT_EQUAL_STRING(("Hello from Serial2 (UART2) >>> to >>> Serial1 (UART1) " + msg_append).c_str(), recv_msg.c_str());
+  void onReceive() {
+    char c;
+    size_t available = serial.available();
+    if (peeked_char == -1) {
+      peeked_char = serial.peek();
+    }
+    while (available--) {
+      c = (char)serial.read();
+      recv_msg += c;
+    }
   }
-#else
-  log_d("No UARTs available for transmission");
-  TEST_FAIL();
-#endif
-}
+};
+
+/* Utility global variables */
+
+[[maybe_unused]]
+static const int NEW_RX1 = 9;
+[[maybe_unused]]
+static const int NEW_TX1 = 10;
+std::vector<UARTTestConfig *> uart_test_configs;
+
+/* Utility functions */
+
+extern "C" int8_t uart_get_RxPin(uint8_t uart_num);
+extern "C" int8_t uart_get_TxPin(uint8_t uart_num);
 
 /* Tasks */
 
 // This task is used to send a message after a delay to test the auto baudrate detection
 void task_delayed_msg(void *pvParameters) {
-  HardwareSerial *selected_serial;
-
-#if SOC_UART_NUM == 2
-  selected_serial = &Serial;
-#elif SOC_UART_NUM == 3
-  selected_serial = &Serial1;
-#endif
-
+  HardwareSerial &selected_serial = uart_test_configs.size() == 1 ? Serial : Serial1;
   delay(2000);
-  selected_serial->println("Hello from Serial1 to detect baudrate");
-  selected_serial->flush();
+  selected_serial.println("Hello to detect baudrate");
+  selected_serial.flush();
   vTaskDelete(NULL);
 }
 
@@ -142,67 +121,23 @@ void task_delayed_msg(void *pvParameters) {
 
 // This function is automatically called by unity before each test is run
 void setUp(void) {
-  start_serial(115200);
-#if SOC_UART_NUM == 2
-  log_d("Setup internal loop-back from and back to Serial1 (UART1) TX >> Serial1 (UART1) RX");
-
-  Serial1.onReceive([]() {
-    onReceive_cb(Serial1);
-  });
-  uart_internal_loopback(1, RX1);
-#elif SOC_UART_NUM == 3
-  log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)");
-
-  Serial1.onReceive([]() {
-    onReceive_cb(Serial1);
-  });
-  Serial2.onReceive([]() {
-    onReceive_cb(Serial2);
-  });
-  uart_internal_loopback(1, RX2);
-  uart_internal_loopback(2, RX1);
-#endif
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    //log_d("Setup internal loop-back from and back to UART%d TX >> UART%d RX", config.uart_num, config.uart_num);
+    config.begin(115200);
+    config.serial.onReceive([&config]() {
+      config.onReceive();
+    });
+    uart_internal_loopback(config.uart_num, uart_get_RxPin(config.uart_num));
+  }
 }
 
 // This function is automatically called by unity after each test is run
 void tearDown(void) {
-  stop_serial();
-}
-
-/* Callback functions */
-
-// This is a callback function that will be activated on UART RX events
-void onReceive_cb(HardwareSerial &selected_serial) {
-  int uart_num = -1;
-  char c;
-
-  (void)uart_num;  // Avoid compiler warning when debug level is set to none
-
-  if (&selected_serial == &Serial) {
-    uart_num = 0;
-#if SOC_UART_NUM >= 2
-  } else if (&selected_serial == &Serial1) {
-    uart_num = 1;
-#endif
-#if SOC_UART_NUM >= 3
-  } else if (&selected_serial == &Serial2) {
-    uart_num = 2;
-#endif
-  }
-
-  recv_msg = "";
-  size_t available = selected_serial.available();
-
-  if (available != 0) {
-    peeked_char = selected_serial.peek();
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    config.end();
   }
-
-  while (available--) {
-    c = (char)selected_serial.read();
-    recv_msg += c;
-  }
-
-  log_d("UART %d received message: %s\n", uart_num, recv_msg.c_str());
 }
 
 /* Test functions */
@@ -211,40 +146,33 @@ void onReceive_cb(HardwareSerial &selected_serial) {
 void basic_transmission_test(void) {
   log_d("Performing basic transmission test");
 
-  transmit_and_check_msg("");
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    config.transmit_and_check_msg("");
+  }
 
   Serial.println("Basic transmission test successful");
 }
 
 // This test checks if the baudrate can be changed and if the message can be transmitted and received correctly after the change
 void change_baudrate_test(void) {
-  //Test first using the updateBaudRate method and then using the begin method
-  log_d("Changing baudrate to 9600");
-
-  //Baudrate error should be within 2% of the target baudrate
-  Serial1.updateBaudRate(9600);
-  TEST_ASSERT_UINT_WITHIN(192, 9600, Serial1.baudRate());
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    log_d("Changing baudrate of UART%d to 9600", config.uart_num);
 
-#if SOC_UART_NUM == 3
-  Serial2.updateBaudRate(9600);
-  TEST_ASSERT_UINT_WITHIN(192, 9600, Serial2.baudRate());
-#endif
-
-  log_d("Sending string using 9600 baudrate");
-  transmit_and_check_msg("using 9600 baudrate");
+    //Baudrate error should be within 2% of the target baudrate
+    config.serial.updateBaudRate(9600);
+    TEST_ASSERT_UINT_WITHIN(192, 9600, config.serial.baudRate());
 
-  log_d("Changing baudrate back to 115200");
-  start_serial(115200);
+    log_d("Sending string on UART%d using 9600 baudrate", config.uart_num);
+    config.transmit_and_check_msg("using 9600 baudrate");
 
-  //Baudrate error should be within 2% of the target baudrate
-  TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial1.baudRate());
+    config.serial.begin(115200);
+    TEST_ASSERT_UINT_WITHIN(2304, 115200, config.serial.baudRate());
 
-#if SOC_UART_NUM == 3
-  TEST_ASSERT_UINT_WITHIN(2304, 115200, Serial2.baudRate());
-#endif
-
-  log_d("Sending string using 115200 baudrate");
-  transmit_and_check_msg("using 115200 baudrate");
+    log_d("Sending string on UART%d using 115200 baudrate", config.uart_num);
+    config.transmit_and_check_msg("using 115200 baudrate");
+  }
 
   Serial.println("Change baudrate test successful");
 }
@@ -261,7 +189,7 @@ void resize_buffers_test(void) {
   ret = Serial1.setTxBufferSize(256);
   TEST_ASSERT_EQUAL(0, ret);
 
-  stop_serial();
+  Serial1.end();
 
   log_d("Trying to resize RX buffer while stopped.");
   ret = Serial1.setRxBufferSize(256);
@@ -277,7 +205,12 @@ void resize_buffers_test(void) {
 // This test checks if the begin function can be called when the UART is already running
 void begin_when_running_test(void) {
   log_d("Trying to set up serial twice");
-  start_serial(115200);
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    // Calling twice should not crash
+    config.begin(115200);
+    config.begin(115200);
+  }
   Serial.println("Begin when running test successful");
 }
 
@@ -285,9 +218,12 @@ void begin_when_running_test(void) {
 void end_when_stopped_test(void) {
   log_d("Trying to end serial twice");
 
-  // Calling end(true) twice should not crash
-  stop_serial(true);
-  stop_serial(true);
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    // Calling twice should not crash
+    config.end();
+    config.end();
+  }
 
   Serial.println("End when stopped test successful");
 }
@@ -311,7 +247,7 @@ void enabled_uart_calls_test(void) {
   TEST_ASSERT_EQUAL(true, boolean_ret);
 
   log_d("Checking if Serial 1 is peekable while running");
-  TEST_ASSERT_GREATER_OR_EQUAL(0, peeked_char);
+  TEST_ASSERT_GREATER_OR_EQUAL(0, uart_test_configs[0]->peeked_char);
 
   log_d("Checking if Serial 1 can read bytes while running");
   integer_ret = Serial1.readBytes(test_buf, 1);
@@ -347,7 +283,10 @@ void disabled_uart_calls_test(void) {
   int integer_ret;
   uint8_t test_buf[1];
 
-  stop_serial();
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    config.end();
+  }
 
   log_d("Checking if Serial 1 can set the RX timeout when stopped");
   boolean_ret = Serial1.setRxTimeout(1);
@@ -415,44 +354,35 @@ void disabled_uart_calls_test(void) {
 
 // This test checks if the pins can be changed and if the message can be transmitted and received correctly after the change
 void change_pins_test(void) {
-  //stop_serial();
-
   log_d("Disabling UART loopback");
 
-#if SOC_UART_NUM == 2
-  esp_rom_gpio_connect_out_signal(SOC_RX0, SIG_GPIO_OUT_IDX, false, false);
-#elif SOC_UART_NUM == 3
-  esp_rom_gpio_connect_out_signal(RX1, SIG_GPIO_OUT_IDX, false, false);
-  esp_rom_gpio_connect_out_signal(RX2, SIG_GPIO_OUT_IDX, false, false);
-#endif
-
-  log_d("Swapping UART pins");
-
-#if SOC_UART_NUM == 2
-  Serial1.setPins(NEW_RX1, NEW_TX1);
-  TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(1));
-  TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(1));
-#elif SOC_UART_NUM == 3
-  Serial1.setPins(RX2, TX2);
-  Serial2.setPins(RX1, TX1);
-  TEST_ASSERT_EQUAL(RX2, uart_get_RxPin(1));
-  TEST_ASSERT_EQUAL(TX2, uart_get_TxPin(1));
-  TEST_ASSERT_EQUAL(RX1, uart_get_RxPin(2));
-  TEST_ASSERT_EQUAL(TX1, uart_get_TxPin(2));
-#endif
-
-  start_serial(115200);
-
-  log_d("Re-enabling UART loopback");
-
-#if SOC_UART_NUM == 2
-  uart_internal_loopback(1, NEW_RX1);
-#elif SOC_UART_NUM == 3
-  uart_internal_loopback(1, RX1);
-  uart_internal_loopback(2, RX2);
-#endif
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    esp_rom_gpio_connect_out_signal(config.default_rx_pin, SIG_GPIO_OUT_IDX, false, false);
+  }
 
-  transmit_and_check_msg("using new pins");
+  log_d("Swapping UART pins and testing transmission");
+
+  if (TEST_UART_NUM == 1) {
+    UARTTestConfig &config = *uart_test_configs[0];
+    config.serial.setPins(NEW_RX1, NEW_TX1);
+    TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(config.uart_num));
+    TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(config.uart_num));
+
+    uart_internal_loopback(config.uart_num, NEW_RX1);
+    config.transmit_and_check_msg("using new pins");
+  } else {
+    for (int i = 0; i < TEST_UART_NUM; i++) {
+      UARTTestConfig &config = *uart_test_configs[i];
+      UARTTestConfig &next_uart = *uart_test_configs[(i + 1) % TEST_UART_NUM];
+      config.serial.setPins(next_uart.default_rx_pin, next_uart.default_tx_pin);
+      TEST_ASSERT_EQUAL(uart_get_RxPin(config.uart_num), next_uart.default_rx_pin);
+      TEST_ASSERT_EQUAL(uart_get_TxPin(config.uart_num), next_uart.default_tx_pin);
+
+      uart_internal_loopback(config.uart_num, next_uart.default_rx_pin);
+      config.transmit_and_check_msg("using new pins");
+    }
+  }
 
   Serial.println("Change pins test successful");
 }
@@ -467,12 +397,15 @@ void auto_baudrate_test(void) {
 
   log_d("Stopping test serial. Using Serial2 for ESP32 and Serial1 for ESP32-S2.");
 
-#if SOC_UART_NUM == 2
-  selected_serial = &Serial1;
-  uart_internal_loopback(0, RX1);
-#elif SOC_UART_NUM == 3
-  selected_serial = &Serial2;
+  if (TEST_UART_NUM == 1) {
+    selected_serial = &Serial1;
+    uart_internal_loopback(0, RX1);
+  } else {
+#ifdef RX2
+    selected_serial = &Serial2;
+    uart_internal_loopback(1, RX2);
 #endif
+  }
 
   //selected_serial->end(false);
 
@@ -485,10 +418,10 @@ void auto_baudrate_test(void) {
   selected_serial->begin(0);
   baudrate = selected_serial->baudRate();
 
-#if SOC_UART_NUM == 2
-  Serial.end();
-  Serial.begin(115200);
-#endif
+  if (TEST_UART_NUM == 1) {
+    Serial.end();
+    Serial.begin(115200);
+  }
 
   TEST_ASSERT_UINT_WITHIN(2304, 115200, baudrate);
 
@@ -502,32 +435,23 @@ void periman_test(void) {
 
   log_d("Setting up I2C on the same pins as UART");
 
-  Wire.begin(RX1, TX1);
-
-#if SOC_UART_NUM == 3
-  Wire1.begin(RX2, TX2);
-#endif
-
-  recv_msg = "";
-
-  log_d("Trying to send message using UART with I2C enabled");
-  transmit_and_check_msg("while used by I2C", false);
-  TEST_ASSERT_EQUAL_STRING("", recv_msg.c_str());
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    Wire.begin(config.default_rx_pin, config.default_tx_pin);
+    config.recv_msg = "";
 
-  log_d("Disabling I2C and re-enabling UART");
+    log_d("Trying to send message using UART%d with I2C enabled", config.uart_num);
+    config.transmit_and_check_msg("while used by I2C", false);
+    TEST_ASSERT_EQUAL_STRING("", config.recv_msg.c_str());
 
-  Serial1.setPins(RX1, TX1);
+    log_d("Disabling I2C and re-enabling UART%d", config.uart_num);
 
-#if SOC_UART_NUM == 3
-  Serial2.setPins(RX2, TX2);
-  uart_internal_loopback(1, RX2);
-  uart_internal_loopback(2, RX1);
-#elif SOC_UART_NUM == 2
-  uart_internal_loopback(1, RX1);
-#endif
+    config.serial.setPins(config.default_rx_pin, config.default_tx_pin);
+    uart_internal_loopback(config.uart_num, config.default_rx_pin);
 
-  log_d("Trying to send message using UART with I2C disabled");
-  transmit_and_check_msg("while I2C is disabled");
+    log_d("Trying to send message using UART%d with I2C disabled", config.uart_num);
+    config.transmit_and_check_msg("while I2C is disabled");
+  }
 
   Serial.println("Peripheral manager test successful");
 }
@@ -543,8 +467,11 @@ void change_cpu_frequency_test(void) {
 
   Serial.updateBaudRate(115200);
 
-  log_d("Trying to send message with the new CPU frequency");
-  transmit_and_check_msg("with new CPU frequency");
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    log_d("Trying to send message with the new CPU frequency on UART%d", config.uart_num);
+    config.transmit_and_check_msg("with new CPU frequency");
+  }
 
   log_d("Changing CPU frequency back to %dMHz", old_freq);
   Serial.flush();
@@ -552,8 +479,11 @@ void change_cpu_frequency_test(void) {
 
   Serial.updateBaudRate(115200);
 
-  log_d("Trying to send message with the original CPU frequency");
-  transmit_and_check_msg("with the original CPU frequency");
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    log_d("Trying to send message with the original CPU frequency on UART%d", config.uart_num);
+    config.transmit_and_check_msg("with the original CPU frequency");
+  }
 
   Serial.println("Change CPU frequency test successful");
 }
@@ -565,30 +495,39 @@ void setup() {
   while (!Serial) {
     delay(10);
   }
-  log_d("SOC_UART_NUM = %d", SOC_UART_NUM);
-
-  // Begin needs to be called before setting up the loopback because it creates the serial object
-  start_serial(115200);
-
-#if SOC_UART_NUM == 2
-  log_d("Setup internal loop-back from and back to Serial1 (UART1) TX >> Serial1 (UART1) RX");
-
-  Serial1.onReceive([]() {
-    onReceive_cb(Serial1);
-  });
-  uart_internal_loopback(1, RX1);
-#elif SOC_UART_NUM == 3
-  log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)");
-
-  Serial1.onReceive([]() {
-    onReceive_cb(Serial1);
-  });
-  Serial2.onReceive([]() {
-    onReceive_cb(Serial2);
-  });
-  uart_internal_loopback(1, RX2);
-  uart_internal_loopback(2, RX1);
+
+  uart_test_configs = {
+#if SOC_UART_HP_NUM >= 2 && defined(RX1) && defined(TX1)
+    // inverting RX1<->TX1 because ESP32-P4 has a problem with loopback on RX1 :: GPIO11 <-- UART_TX SGINAL
+    new UARTTestConfig(1, Serial1, TX1, RX1),
+#endif
+#if SOC_UART_HP_NUM >= 3 && defined(RX2) && defined(TX2)
+    new UARTTestConfig(2, Serial2, RX2, TX2),
+#endif
+#if SOC_UART_HP_NUM >= 4 && defined(RX3) && defined(TX3)
+    new UARTTestConfig(3, Serial3, RX3, TX3),
 #endif
+#if SOC_UART_HP_NUM >= 5 && defined(RX4) && defined(TX4)
+    new UARTTestConfig(4, Serial4, RX4, TX4)
+#endif
+  };
+
+  if (TEST_UART_NUM == 0) {
+    log_e("This test requires at least one UART besides UART0 configured");
+    abort();
+  }
+
+  log_d("TEST_UART_NUM = %d", TEST_UART_NUM);
+
+  for (auto *ref : uart_test_configs) {
+    UARTTestConfig &config = *ref;
+    config.begin(115200);
+    log_d("Setup internal loop-back from and back to UART%d TX >> UART%d RX", config.uart_num, config.uart_num);
+    config.serial.onReceive([&config]() {
+      config.onReceive();
+    });
+    uart_internal_loopback(config.uart_num, uart_get_RxPin(config.uart_num));
+  }
 
   log_d("Setup done. Starting tests");
 
diff --git a/tests/validation/wifi/ci.json b/tests/validation/wifi/ci.json
index 94819d60efc..36e91b221cb 100644
--- a/tests/validation/wifi/ci.json
+++ b/tests/validation/wifi/ci.json
@@ -21,8 +21,7 @@
     "hardware": false,
     "qemu": false
   },
-  "requires_any": [
-    "CONFIG_SOC_WIFI_SUPPORTED=y",
-    "CONFIG_ESP_WIFI_REMOTE_ENABLED=y"
+  "requires": [
+    "CONFIG_SOC_WIFI_SUPPORTED=y"
   ]
 }
diff --git a/tools/add_lib.sh b/tools/add_lib.sh
index 4ec73c4f7f7..9760f8114c6 100755
--- a/tools/add_lib.sh
+++ b/tools/add_lib.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
+
 HELP="This script help to add library when using arduino-esp32 as an ESP-IDF component
 The script accepts up to three arguments:
 -n  NEW: URL address to new library on GIThub (cannot be combined with -e)
@@ -26,119 +27,126 @@ n_param=""
 
 # Parse the command-line arguments using getopts
 while getopts "he:l:n:" opt; do
-  case $opt in
-    h)
-      echo "$HELP"
-      exit 0
-      ;;
-    e)
-      #e_param="$OPTARG"
-      e_param="${OPTARG/#~/$HOME}"
-      ;;
-    l)
-      #l_param="$OPTARG"
-      l_param="${OPTARG/#~/$HOME}"
-      ;;
-    n)
-      n_param=$OPTARG
-      ;;
-    \?)
-      echo "Invalid option: -$OPTARG" >&2
-      echo $HELP
-      exit 1
-      ;;
-    :)
-      echo "Option -$OPTARG requires an argument." >&2
-      echo $HELP
-      exit 1
-      ;;
-  esac
+    case $opt in
+        h)
+            echo "$HELP"
+            exit 0
+            ;;
+        e)
+            #e_param="$OPTARG"
+            e_param="${OPTARG/#~/$HOME}"
+            ;;
+        l)
+            #l_param="$OPTARG"
+            l_param="${OPTARG/#~/$HOME}"
+            ;;
+        n)
+            n_param=$OPTARG
+            ;;
+        \?)
+            echo "Invalid option: -$OPTARG" >&2
+            echo "$HELP"
+            exit 1
+            ;;
+        :)
+            echo "Option -$OPTARG requires an argument." >&2
+            echo "$HELP"
+            exit 1
+            ;;
+        *)
+            echo "Invalid option: -$OPTARG" >&2
+            echo "$HELP"
+            exit 1
+            ;;
+    esac
 done
 
 # No parameter check
 if [[ -z "$e_param" ]] && [[ -z "$l_param" ]] && [[ -z "$n_param" ]]; then
-  echo "Error: No parameters" >&2
-  echo "$HELP"
-  exit 1
+    echo "Error: No parameters" >&2
+    echo "$HELP"
+    exit 1
 fi
 
 # Only local path check (not permitted)
-if [[ -z "$e_param" ]] && [[ ! -z "$l_param" ]] && [[ -z "$n_param" ]]; then
-  echo "Error: -l parameter must be paired with -e or -n" >&2
-  echo "$HELP"
-  exit 1
+if [[ -z "$e_param" ]] && [[ -n "$l_param" ]] && [[ -z "$n_param" ]]; then
+    echo "Error: -l parameter must be paired with -e or -n" >&2
+    echo "$HELP"
+    exit 1
 fi
 
 # Invalid combination check
-if [[ ! -z $e_param ]] && [[ ! -z $n_param ]]; then
-  echo "ERROR: Cannot combine -n with -e" >&2
-  echo "$HELP"
-  exit 1
+if [[ -n $e_param ]] && [[ -n $n_param ]]; then
+    echo "ERROR: Cannot combine -n with -e" >&2
+    echo "$HELP"
+    exit 1
 fi
 
 # Check existing lib
-if [[ ! -z "$e_param" ]]; then
-  if  [[ ! -d "${e_param/#~/$HOME}" ]]; then # this works!
-    echo "Error: existing library parameter - path does not exist" >&2
-    exit 1
-  fi
+if [[ -n "$e_param" ]]; then
+    if  [[ ! -d "${e_param/#~/$HOME}" ]]; then # this works!
+        echo "Error: existing library parameter - path does not exist" >&2
+        exit 1
+    fi
 fi
 
 LIBRARY=""
 
 # Only existing library was supplied
-if [[ ! -z $e_param ]] && [[ -z $l_param ]] && [[ -z $n_param ]]; then
-  LIBRARY=$e_param
+if [[ -n $e_param ]] && [[ -z $l_param ]] && [[ -z $n_param ]]; then
+    LIBRARY=$e_param
 fi
 
 # Install new lib
-if [ ! -z $n_param ]; then
-  INSTALL_TARGET=""
-  if [ -z $l_param ]; then
-    # If local path for project is not supplied - use as INSTALL_TARGET Arduino libraries path
-    INSTALL_TARGET=$ARDUINO_LIBS_PATH/$(basename "$n_param")
-  else
-    INSTALL_TARGET=$l_param/components/$(basename "$n_param")
-    if [ ! -d "$l_param/components" ]; then
-      echo "Folder components does not exist yet: mkdir -p "$l_param/components""
-      mkdir -p "$l_param/components"
+if [ -n "$n_param" ]; then
+    INSTALL_TARGET=""
+    if [ -z "$l_param" ]; then
+        # If local path for project is not supplied - use as INSTALL_TARGET Arduino libraries path
+        INSTALL_TARGET=$ARDUINO_LIBS_PATH/$(basename "$n_param")
+    else
+        INSTALL_TARGET=$l_param/components/$(basename "$n_param")
+        if [ ! -d "$l_param/components" ]; then
+            echo "Folder components does not exist yet: mkdir -p \"$l_param/components\""
+            mkdir -p "$l_param/components"
+        fi
     fi
-  fi
-  # clone the new lib
-  echo "Cloning: git clone --recursive $n_param $INSTALL_TARGET"
-  git clone --recursive $n_param $INSTALL_TARGET
-  LIBRARY=$INSTALL_TARGET
+    # clone the new lib
+    echo "Cloning: git clone --recursive $n_param $INSTALL_TARGET"
+    git clone --recursive "$n_param" "$INSTALL_TARGET"
+    LIBRARY=$INSTALL_TARGET
 fi
 
 # Copy existing lib to local project
-if [[ ! -z $e_param ]] && [[ ! -z $l_param ]]; then
-  if [ ! -d "$l_param/components" ]; then
-    echo "Folder components does not exist yet: mkdir -p "$l_param/components""
-    mkdir -p "$l_param/components"
-  fi
-  echo "Copy from $e_param to $l_param"
-  echo "cp -r $e_param $l_param/components/$(basename "$e_param")"
-  cp -r $e_param $l_param/components/$(basename "$e_param")
-  LIBRARY=$l_param/components/$(basename "$e_param")
+if [[ -n $e_param ]] && [[ -n $l_param ]]; then
+    if [ ! -d "$l_param/components" ]; then
+        echo "Folder components does not exist yet: mkdir -p \"$l_param/components\""
+        mkdir -p "$l_param/components"
+    fi
+    echo "Copy from $e_param to $l_param"
+    echo "cp -r $e_param $l_param/components/\"$(basename "$e_param")\""
+    cp -r "$e_param" "$l_param"/components/"$(basename "$e_param")"
+    LIBRARY=$l_param/components/"$(basename "$e_param")"
 fi
 
 
 if [ -z "$LIBRARY" ]; then
-  echo "ERROR: No library path" >&2
-  exit 1
+    echo "ERROR: No library path" >&2
+    exit 1
 fi
 
 # 1. get the source list:
-FILES=$(find $LIBRARY -name '*.c' -o -name '*.cpp' |  xargs -I{} basename {})
+FILES=$(find "$LIBRARY" -print0 -name '*.c' -o -name '*.cpp' | xargs -0 -I{} basename {})
 
 # Fresh start
-if [ -f $LIBRARY/CMakeLists.txt ]; then
-  rm $LIBRARY/CMakeLists.txt
-  touch $LIBRARY/CMakeLists.txt
+if [ -f "$LIBRARY"/CMakeLists.txt ]; then
+    rm "$LIBRARY"/CMakeLists.txt
+    touch "$LIBRARY"/CMakeLists.txt
 fi
 
 # Generate CMakeLists.txt
-echo "idf_component_register(SRCS $(echo $FILES | sed -e 's/ /" "/g' | sed -e 's/^/"/' -e 's/$/"/')" >> $LIBRARY/CMakeLists.txt
-echo "                       INCLUDE_DIRS \".\"" >> $LIBRARY/CMakeLists.txt
-echo "                       REQUIRES \"arduino-esp32\"" >> $LIBRARY/CMakeLists.txt
-echo "                       )" >> $LIBRARY/CMakeLists.txt
+{
+    echo "idf_component_register(SRCS $(echo "$FILES" | sed -e 's/ /" "/g' | sed -e 's/^/"/' -e 's/$/"/')"
+    echo "                       INCLUDE_DIRS \".\""
+    echo "                       REQUIRES \"arduino-esp32\""
+    echo "                       )"
+} >> "$LIBRARY"/CMakeLists.txt
diff --git a/tools/gen_esp32part.exe b/tools/gen_esp32part.exe
index 51c1959ac74..5bd12c6360d 100644
Binary files a/tools/gen_esp32part.exe and b/tools/gen_esp32part.exe differ
diff --git a/tools/gen_esp32part.py b/tools/gen_esp32part.py
index 4ba0ee59517..ffa740a36e0 100755
--- a/tools/gen_esp32part.py
+++ b/tools/gen_esp32part.py
@@ -529,7 +529,7 @@ def to_binary(self):
     def to_csv(self, simple_formatting=False):
         def addr_format(a, include_sizes):
             if not simple_formatting and include_sizes:
-                for (val, suffix) in [(0x100000, "M"), (0x400, "K")]:
+                for val, suffix in [(0x100000, "M"), (0x400, "K")]:
                     if a % val == 0:
                         return "%d%s" % (a // val, suffix)
             return "0x%x" % a
diff --git a/tools/get.exe b/tools/get.exe
index 671b1507b0b..4a5e209cacf 100644
Binary files a/tools/get.exe and b/tools/get.exe differ
diff --git a/tools/get.py b/tools/get.py
index 1e1e392473c..058c69badb1 100755
--- a/tools/get.py
+++ b/tools/get.py
@@ -177,6 +177,7 @@ def is_latest_version(destination, dirname, rename_to, cfile, checksum):
 
 
 def unpack(filename, destination, force_extract, checksum):  # noqa: C901
+    sys_name = platform.system()
     dirname = ""
     cfile = None  # Compressed file
     file_is_corrupted = False
@@ -223,6 +224,8 @@ def unpack(filename, destination, force_extract, checksum):  # noqa: C901
     rename_to = re.match(r"^([a-z][^\-]*\-*)+", dirname).group(0).strip("-")
     if rename_to == dirname and dirname.startswith("esp32-arduino-libs-"):
         rename_to = "esp32-arduino-libs"
+    elif rename_to == dirname and dirname.startswith("esptool-"):
+        rename_to = "esptool"
 
     if not force_extract:
         if is_latest_version(destination, dirname, rename_to, cfile, checksum):
@@ -256,6 +259,11 @@ def unpack(filename, destination, force_extract, checksum):  # noqa: C901
         print("Renaming {0} to {1} ...".format(dirname, rename_to))
         shutil.move(dirname, rename_to)
 
+    # Add execute permission to esptool on non-Windows platforms
+    if rename_to.startswith("esptool") and "CYGWIN_NT" not in sys_name and "Windows" not in sys_name:
+        st = os.stat(os.path.join(destination, rename_to, "esptool"))
+        os.chmod(os.path.join(destination, rename_to, "esptool"), st.st_mode | 0o111)
+
     with open(os.path.join(destination, rename_to, ".package_checksum"), "w") as f:
         f.write(checksum)
 
diff --git a/tools/platformio-build.py b/tools/pioarduino-build.py
similarity index 88%
rename from tools/platformio-build.py
rename to tools/pioarduino-build.py
index 1ece3afddff..9b688a0cdbe 100644
--- a/tools/platformio-build.py
+++ b/tools/pioarduino-build.py
@@ -22,7 +22,7 @@
 http://arduino.cc/en/Reference/HomePage
 """
 
-# Extends: https://github.com/platformio/platform-espressif32/blob/develop/builder/main.py
+# Extends: https://github.com/tasmota/platform-espressif32/blob/develop/builder/main.py
 
 from os.path import abspath, basename, isdir, isfile, join
 from copy import deepcopy
@@ -35,7 +35,7 @@
 partitions_name = board_config.get("build.partitions", board_config.get("build.arduino.partitions", ""))
 
 FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
-FRAMEWORK_LIBS_DIR = platform.get_package_dir("framework-arduinoespressif32-libs")
+FRAMEWORK_LIBS_DIR = join(FRAMEWORK_DIR, "tools", "esp32-arduino-libs")
 assert isdir(FRAMEWORK_DIR)
 
 
@@ -160,7 +160,7 @@ def add_tinyuf2_extra_image():
     join(
         FRAMEWORK_LIBS_DIR,
         build_mcu,
-        "platformio-build.py",
+        "pioarduino-build.py",
     )
 )
 
@@ -184,9 +184,15 @@ def add_tinyuf2_extra_image():
 libs = []
 
 variants_dir = join(FRAMEWORK_DIR, "variants")
+try:
+    build_variants_dir = join(board_config.get("build.variants_dir"))
+except Exception:
+    build_variants_dir = ""
 
 if "build.variants_dir" in board_config:
-    variants_dir = join("$PROJECT_DIR", board_config.get("build.variants_dir"))
+    if len(build_variants_dir) > 1:
+        variants_dir = join("$PROJECT_DIR", board_config.get("build.variants_dir"))
+
 
 if "build.variant" in board_config:
     env.Append(CPPPATH=[join(variants_dir, board_config.get("build.variant"))])
@@ -209,17 +215,26 @@ def add_tinyuf2_extra_image():
 # Process framework extra images
 #
 
+# Tasmota places extra images "safeboot" in custom variants folder in project directory
+build_name = join(board_config.get("name"))
+if len(build_variants_dir) > 1:
+    EXTRA_IMG_DIR = join(variants_dir)
+else:
+    EXTRA_IMG_DIR = FRAMEWORK_DIR
+    if "tasmota" in build_name.lower():
+        EXTRA_IMG_DIR = join(EXTRA_IMG_DIR, "variants", "tasmota")
+
 env.Append(
     LIBSOURCE_DIRS=[join(FRAMEWORK_DIR, "libraries")],
     FLASH_EXTRA_IMAGES=[
         (
-            "0x1000" if build_mcu in ("esp32", "esp32s2") else "0x0000",
+            "0x1000" if build_mcu in ["esp32", "esp32s2"] else ("0x2000" if build_mcu in ["esp32p4"] else "0x0000"),
             get_bootloader_image(variants_dir),
         ),
         ("0x8000", join(env.subst("$BUILD_DIR"), "partitions.bin")),
         ("0xe000", join(FRAMEWORK_DIR, "tools", "partitions", "boot_app0.bin")),
     ]
-    + [(offset, join(FRAMEWORK_DIR, img)) for offset, img in board_config.get("upload.arduino.flash_extra_images", [])],
+    + [(offset, join(EXTRA_IMG_DIR, img)) for offset, img in board_config.get("upload.arduino.flash_extra_images", [])],
 )
 
 # Add an extra UF2 image if the 'TinyUF2' partition is selected
diff --git a/variants/Pcbcupid_GLYPH_C3/pins_arduino.h b/variants/Pcbcupid_GLYPH_C3/pins_arduino.h
new file mode 100644
index 00000000000..653c2c48828
--- /dev/null
+++ b/variants/Pcbcupid_GLYPH_C3/pins_arduino.h
@@ -0,0 +1,43 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include <stdint.h>
+
+// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino
+static const uint8_t LED_BUILTIN = 1;
+#define BUILTIN_LED LED_BUILTIN  // backward compatibility
+#define LED_BUILTIN LED_BUILTIN  // allow testing #ifdef LED_BUILTIN
+
+//MSR Used in on-board battery measurement
+static const uint8_t BAT_MEASURE = 0;
+#define MSR BAT_MEASURE
+
+static const uint8_t TX = 21;
+static const uint8_t RX = 20;
+
+static const uint8_t SDA = 4;
+static const uint8_t SCL = 5;
+
+static const uint8_t SS = 3;
+static const uint8_t MOSI = 6;
+static const uint8_t MISO = 7;
+static const uint8_t SCK = 10;
+
+static const uint8_t A0 = 0;
+static const uint8_t A1 = 1;
+static const uint8_t A2 = 2;
+static const uint8_t A3 = 3;
+
+static const uint8_t D0 = 0;
+static const uint8_t D1 = 1;
+static const uint8_t D2 = 2;
+static const uint8_t D3 = 3;
+static const uint8_t D4 = 4;
+static const uint8_t D5 = 5;
+static const uint8_t D6 = 6;
+static const uint8_t D7 = 7;
+static const uint8_t D8 = 8;
+static const uint8_t D9 = 9;
+static const uint8_t D10 = 10;
+
+#endif /* Pins_Arduino_h */
diff --git a/variants/Pcbcupid_GLYPH_C6/pins_arduino.h b/variants/Pcbcupid_GLYPH_C6/pins_arduino.h
new file mode 100644
index 00000000000..f06fb151244
--- /dev/null
+++ b/variants/Pcbcupid_GLYPH_C6/pins_arduino.h
@@ -0,0 +1,52 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include <stdint.h>
+
+// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino
+static const uint8_t LED_BUILTIN = 14;
+#define BUILTIN_LED LED_BUILTIN  // backward compatibility
+#define LED_BUILTIN LED_BUILTIN  // allow testing #ifdef LED_BUILTIN
+
+//MSR Used in on-board battery measurement
+static const uint8_t BAT_MEASURE = 0;
+#define MSR BAT_MEASURE
+
+static const uint8_t TX = 16;
+static const uint8_t RX = 17;
+
+static const uint8_t SDA = 4;
+static const uint8_t SCL = 5;
+
+static const uint8_t SS = 20;
+static const uint8_t MOSI = 22;
+static const uint8_t MISO = 23;
+static const uint8_t SCK = 21;
+
+static const uint8_t A0 = 0;
+static const uint8_t A1 = 1;
+static const uint8_t A2 = 2;
+static const uint8_t A3 = 3;
+
+static const uint8_t D0 = 0;
+static const uint8_t D1 = 1;
+static const uint8_t D2 = 2;
+static const uint8_t D3 = 3;
+static const uint8_t D4 = 4;
+static const uint8_t D5 = 5;
+static const uint8_t D6 = 6;
+static const uint8_t D7 = 7;
+static const uint8_t D8 = 8;
+static const uint8_t D9 = 9;
+static const uint8_t D14 = 14;
+static const uint8_t D15 = 15;
+static const uint8_t D16 = 16;
+static const uint8_t D17 = 17;
+static const uint8_t D18 = 18;
+static const uint8_t D19 = 19;
+static const uint8_t D20 = 20;
+static const uint8_t D21 = 21;
+static const uint8_t D22 = 22;
+static const uint8_t D23 = 23;
+
+#endif /* Pins_Arduino_h */
diff --git a/variants/Pcbcupid_GLYPH_H2/pins_arduino.h b/variants/Pcbcupid_GLYPH_H2/pins_arduino.h
new file mode 100644
index 00000000000..20a385a9817
--- /dev/null
+++ b/variants/Pcbcupid_GLYPH_H2/pins_arduino.h
@@ -0,0 +1,44 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include <stdint.h>
+
+// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino
+static const uint8_t LED_BUILTIN = 0;
+#define BUILTIN_LED LED_BUILTIN  // backward compatibility
+#define LED_BUILTIN LED_BUILTIN  // allow testing #ifdef LED_BUILTIN
+
+//MSR Used in on-board battery measurement
+static const uint8_t BAT_MEASURE = 1;
+#define MSR BAT_MEASURE
+
+static const uint8_t TX = 24;
+static const uint8_t RX = 23;
+
+static const uint8_t SDA = 4;
+static const uint8_t SCL = 5;
+
+static const uint8_t SS = 3;
+static const uint8_t MOSI = 22;
+static const uint8_t MISO = 25;
+static const uint8_t SCK = 11;
+
+static const uint8_t A1 = 1;
+static const uint8_t A2 = 2;
+static const uint8_t A3 = 3;
+
+static const uint8_t D0 = 0;
+static const uint8_t D1 = 1;
+static const uint8_t D2 = 2;
+static const uint8_t D3 = 3;
+static const uint8_t D4 = 4;
+static const uint8_t D5 = 5;
+static const uint8_t D8 = 8;
+static const uint8_t D9 = 9;
+static const uint8_t D10 = 10;
+static const uint8_t D11 = 11;
+static const uint8_t D12 = 12;
+static const uint8_t D13 = 13;
+static const uint8_t D14 = 14;
+
+#endif /* Pins_Arduino_h */
diff --git a/variants/esp32p4/pins_arduino.h b/variants/esp32p4/pins_arduino.h
new file mode 100644
index 00000000000..a7a5568adf3
--- /dev/null
+++ b/variants/esp32p4/pins_arduino.h
@@ -0,0 +1,85 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include <stdint.h>
+#include "soc/soc_caps.h"
+
+// BOOT_MODE 35
+// BOOT_MODE2 36 pullup
+
+static const uint8_t TX = 37;
+static const uint8_t RX = 38;
+
+static const uint8_t SDA = 13;
+static const uint8_t SCL = 12;
+
+// Use GPIOs 36 or lower on the P4 DevKit to avoid LDO power issues with high numbered GPIOs.
+static const uint8_t SS = 26;
+static const uint8_t MOSI = 32;
+static const uint8_t MISO = 33;
+static const uint8_t SCK = 36;
+
+static const uint8_t A0 = 16;
+static const uint8_t A1 = 17;
+static const uint8_t A2 = 18;
+static const uint8_t A3 = 19;
+static const uint8_t A4 = 20;
+static const uint8_t A5 = 21;
+static const uint8_t A6 = 22;
+static const uint8_t A7 = 23;
+static const uint8_t A8 = 49;
+static const uint8_t A9 = 50;
+static const uint8_t A10 = 51;
+static const uint8_t A11 = 52;
+static const uint8_t A12 = 53;
+static const uint8_t A13 = 54;
+
+static const uint8_t T0 = 2;
+static const uint8_t T1 = 3;
+static const uint8_t T2 = 4;
+static const uint8_t T3 = 5;
+static const uint8_t T4 = 6;
+static const uint8_t T5 = 7;
+static const uint8_t T6 = 8;
+static const uint8_t T7 = 9;
+static const uint8_t T8 = 10;
+static const uint8_t T9 = 11;
+static const uint8_t T10 = 12;
+static const uint8_t T11 = 13;
+static const uint8_t T12 = 14;
+static const uint8_t T13 = 15;
+
+/* ESP32-P4 EV Function board specific definitions */
+//ETH
+#define ETH_PHY_TYPE    ETH_PHY_TLK110
+#define ETH_PHY_ADDR    1
+#define ETH_PHY_MDC     31
+#define ETH_PHY_MDIO    52
+#define ETH_PHY_POWER   51
+#define ETH_RMII_TX_EN  49
+#define ETH_RMII_TX0    34
+#define ETH_RMII_TX1    35
+#define ETH_RMII_RX0    29
+#define ETH_RMII_RX1_EN 30
+#define ETH_RMII_CRS_DV 28
+#define ETH_RMII_CLK    50
+#define ETH_CLK_MODE    EMAC_CLK_EXT_IN
+
+//SDMMC
+#define BOARD_HAS_SDMMC
+#define BOARD_SDMMC_SLOT           0
+#define BOARD_SDMMC_POWER_CHANNEL  4
+#define BOARD_SDMMC_POWER_PIN      45
+#define BOARD_SDMMC_POWER_ON_LEVEL LOW
+
+//WIFI - ESP32C6
+#define BOARD_HAS_SDIO_ESP_HOSTED
+#define BOARD_SDIO_ESP_HOSTED_CLK   18
+#define BOARD_SDIO_ESP_HOSTED_CMD   19
+#define BOARD_SDIO_ESP_HOSTED_D0    14
+#define BOARD_SDIO_ESP_HOSTED_D1    15
+#define BOARD_SDIO_ESP_HOSTED_D2    16
+#define BOARD_SDIO_ESP_HOSTED_D3    17
+#define BOARD_SDIO_ESP_HOSTED_RESET 54
+
+#endif /* Pins_Arduino_h */