Arduino core 3.2.1

This commit is contained in:
Jason2866
2025-07-03 17:12:25 +02:00
parent da5cb384a5
commit 9bf8b3f10a
76 changed files with 493576 additions and 1697 deletions
+20 -8
View File
@@ -1,4 +1,4 @@
name: CI Examples name: CI Examples Arduino IDF 5.4.x based
on: on:
workflow_dispatch: # Manually start a workflow workflow_dispatch: # Manually start a workflow
@@ -12,7 +12,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-24.04, windows-2022, macos-15] os: [ubuntu-latest, windows-latest, macos-15]
example: example:
- "examples/arduino-blink" - "examples/arduino-blink"
- "examples/arduino-rmt-blink" - "examples/arduino-rmt-blink"
@@ -20,10 +20,10 @@ jobs:
- "examples/arduino-wifiscan" - "examples/arduino-wifiscan"
- "examples/arduino-zigbee-light" - "examples/arduino-zigbee-light"
- "examples/arduino-zigbee-switch" - "examples/arduino-zigbee-switch"
- "examples/tasmota" - "examples/arduino-NimBLE-ext_client"
- "examples/espidf-arduino-h2zero-BLE_scan"
#- "examples/espidf-arduino-matter-light"
- "examples/arduino-matter-light" - "examples/arduino-matter-light"
- "examples/tasmota"
- "examples/espidf-arduino-matter-light"
- "examples/espidf-arduino-blink" - "examples/espidf-arduino-blink"
- "examples/espidf-arduino-littlefs" - "examples/espidf-arduino-littlefs"
- "examples/espidf-blink" - "examples/espidf-blink"
@@ -37,6 +37,15 @@ jobs:
- "examples/espidf-ulp" - "examples/espidf-ulp"
- "examples/espidf-ulp-riscv" - "examples/espidf-ulp-riscv"
- "examples/espidf-ulp-lp" - "examples/espidf-ulp-lp"
exclude:
- os: windows-latest
example: "examples/espidf-ulp"
- os: windows-latest
example: "examples/espidf-ulp-lp"
- os: windows-latest
example: "examples/espidf-ulp-riscv"
- os: windows-latest
example: "examples/espidf-arduino-matter-light"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -48,13 +57,16 @@ jobs:
python-version: "3.13" python-version: "3.13"
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip pip install uv
pip install wheel uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.18.zip
pip install -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.18.zip
pio pkg install --global --platform file://. pio pkg install --global --platform file://.
- name: git clone Tasmota and add to examples - name: git clone Tasmota and add to examples
if: "matrix.example == 'examples/tasmota'"
run: | run: |
git clone -b development --depth 1 https://github.com/arendst/Tasmota.git examples/tasmota git clone -b development --depth 1 https://github.com/arendst/Tasmota.git examples/tasmota
cp examples/tasmota_platformio_override.ini examples/tasmota/platformio_override.ini cp examples/tasmota_platformio_override.ini examples/tasmota/platformio_override.ini
- name: Build examples - name: Build examples
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: pio run -d ${{ matrix.example }} run: pio run -d ${{ matrix.example }}
+4 -3
View File
@@ -4,12 +4,13 @@
[![Discord](https://img.shields.io/discord/1263397951829708871.svg?logo=discord&logoColor=white&color=5865F2&label=Discord)](https://discord.gg/Nutz9crnZr) [![Discord](https://img.shields.io/discord/1263397951829708871.svg?logo=discord&logoColor=white&color=5865F2&label=Discord)](https://discord.gg/Nutz9crnZr)
[![GitHub Releases](https://img.shields.io/github/downloads/pioarduino/platform-espressif32/total?label=downloads)](https://github.com/pioarduino/platform-espressif32/releases/latest) [![GitHub Releases](https://img.shields.io/github/downloads/pioarduino/platform-espressif32/total?label=downloads)](https://github.com/pioarduino/platform-espressif32/releases/latest)
ESP32 is a series of low-cost, low-power system on a chip microcontrollers with integrated Wi-Fi and Bluetooth. ESP32 integrates an antenna switch, RF balun, power amplifier, low-noise receive amplifier, filters, and power management modules. Espressif Systems is a privately held, fabless semiconductor company renowned for delivering cost-effective wireless communication microcontrollers. Their innovative solutions are widely adopted in mobile devices and Internet of Things (IoT) applications around the globe.
## General
* Issues with boards (wrong / missing). All issues caused from boards will not be fixed from the maintainer(s). A PR needs to be provided against branch `develop` to solve. * Issues with boards (wrong / missing). All issues caused from boards will not be fixed from the maintainer(s). A PR needs to be provided against branch `develop` to solve.
* No support for the Arduino Nora Nano board, issues needs to be solved by the community * No support for the Arduino Nora Nano board, issues needs to be solved by the community
## IDE Preparation ## IDE Preparation
- [Download and install Microsoft Visual Studio Code](https://code.visualstudio.com/). pioarduino IDE is on top of it. - [Download and install Microsoft Visual Studio Code](https://code.visualstudio.com/). pioarduino IDE is on top of it.
- Open the extension manager. - Open the extension manager.
- Search for the `pioarduino ide` extension. - Search for the `pioarduino ide` extension.
@@ -24,7 +25,7 @@ ESP32 is a series of low-cost, low-power system on a chip microcontrollers with
The Wiki is AI generated and insane detailed and accurate. The Wiki is AI generated and insane detailed and accurate.
### Stable Arduino ### Stable Arduino
currently espressif Arduino 3.2.0 and IDF 5.4.1 currently espressif Arduino 3.2.1 and IDF 5.4.2
```ini ```ini
[env:stable] [env:stable]
+2 -2
View File
@@ -42,7 +42,7 @@
"platforms": [ "platforms": [
"espressif32" "espressif32"
], ],
"name": "Espressif ESP32-S3-DevKitC-1-N16R8V (16 MB Flash Quad, 16 MB PSRAM Octal)", "name": "Espressif ESP32-S3-DevKitC-1-N16R16V (16 MB Flash Quad, 16 MB PSRAM Octal)",
"upload": { "upload": {
"flash_size": "16MB", "flash_size": "16MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
@@ -52,4 +52,4 @@
}, },
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html", "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html",
"vendor": "Espressif" "vendor": "Espressif"
} }
+1 -1
View File
@@ -42,7 +42,7 @@
"platforms": [ "platforms": [
"espressif32" "espressif32"
], ],
"name": "Espressif ESP32-S3-DevKitC-1-N8R8 (16 MB Flash Quad, 2 MB PSRAM Quad)", "name": "Espressif ESP32-S3-DevKitC-1-N16R2 (16 MB Flash Quad, 2 MB PSRAM Quad)",
"upload": { "upload": {
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
+1 -1
View File
@@ -42,7 +42,7 @@
"platforms": [ "platforms": [
"espressif32" "espressif32"
], ],
"name": "Espressif ESP32-S3-DevKitC-1-N8R8 (4 MB Flash Quad, 2 MB PSRAM Quad)", "name": "Espressif ESP32-S3-DevKitC-1-N4R2 (4 MB Flash Quad, 2 MB PSRAM Quad)",
"upload": { "upload": {
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
+1 -1
View File
@@ -42,7 +42,7 @@
"platforms": [ "platforms": [
"espressif32" "espressif32"
], ],
"name": "Espressif ESP32-S3-DevKitC-1-N8R8 (4 MB Flash Quad, 8 MB PSRAM Octal)", "name": "Espressif ESP32-S3-DevKitC-1-N4R8 (4 MB Flash Quad, 8 MB PSRAM Octal)",
"upload": { "upload": {
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
+1 -1
View File
@@ -42,7 +42,7 @@
"platforms": [ "platforms": [
"espressif32" "espressif32"
], ],
"name": "Espressif ESP32-S3-DevKitC-1-N8R8 (8 MB Flash Quad, 2 MB PSRAM quad)", "name": "Espressif ESP32-S3-DevKitC-1-N8R2 (8 MB Flash Quad, 2 MB PSRAM quad)",
"upload": { "upload": {
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
+42
View File
@@ -0,0 +1,42 @@
{
"build": {
"arduino": {
"memory_type": "qio_opi",
"partitions": "default_8MB.csv"
},
"core": "esp32",
"extra_flags": [
"-DARDUINO_M5Stack_ATOMS3U",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"mcu": "esp32s3",
"variant": "m5stack_atoms3"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "M5Stack AtomS3U",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.m5stack.com/en/core/AtomS3U",
"vendor": "M5Stack"
}
-2
View File
@@ -41,8 +41,6 @@
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 8388608, "maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },
+49
View File
@@ -0,0 +1,49 @@
{
"build": {
"arduino":{
"partitions": "default_8MB.csv",
"memory_type": "qio_qspi"
},
"core": "esp32",
"extra_flags": [
"-DARDUINO_EDGES3[D]",
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0X303A",
"0x82DC"
]
],
"mcu": "esp32s3",
"variant": "um_edges3_d"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Unexpected Maker EDGES3[D]",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 460800
},
"url": "https://unexpectedmaker.com/",
"vendor": "Unexpected Maker"
}
-2
View File
@@ -36,8 +36,6 @@
"flash_size": "16MB", "flash_size": "16MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 16777216, "maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 921600 "speed": 921600
}, },
-2
View File
@@ -36,8 +36,6 @@
"flash_size": "4MB", "flash_size": "4MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 4194304, "maximum_size": 4194304,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 921600 "speed": 921600
}, },
-2
View File
@@ -41,8 +41,6 @@
"flash_size": "16MB", "flash_size": "16MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 16777216, "maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },
-2
View File
@@ -41,8 +41,6 @@
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 8388608, "maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },
-2
View File
@@ -41,8 +41,6 @@
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 8388608, "maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },
-2
View File
@@ -41,8 +41,6 @@
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 8388608, "maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },
-2
View File
@@ -41,8 +41,6 @@
"flash_size": "16MB", "flash_size": "16MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 16777216, "maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },
-2
View File
@@ -36,8 +36,6 @@
"flash_size": "4MB", "flash_size": "4MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 4194304, "maximum_size": 4194304,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 921600 "speed": 921600
}, },
+49
View File
@@ -0,0 +1,49 @@
{
"build": {
"arduino": {
"partitions": "default_16MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_SQUIXL",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0x303A",
"0x82DF"
]
],
"mcu": "esp32s3",
"variant": "um_squixl"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Unexpected Maker SQUiXL",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 460800
},
"url": "https://unexpectedmaker.com/shop/squixl",
"vendor": "Unexpected Maker"
}
-2
View File
@@ -37,8 +37,6 @@
"flash_size": "4MB", "flash_size": "4MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 4194304, "maximum_size": 4194304,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 921600 "speed": 921600
}, },
-2
View File
@@ -41,8 +41,6 @@
"flash_size": "8MB", "flash_size": "8MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 8388608, "maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },
+3 -3
View File
@@ -110,14 +110,14 @@ env.Append(
" ".join( " ".join(
[ [
"riscv32-esp-elf-objcopy" "riscv32-esp-elf-objcopy"
if mcu in ("esp32c2","esp32c3","esp32c6","esp32h2","esp32p4") if mcu in ("esp32c2","esp32c3","esp32c5","esp32c6","esp32h2","esp32p4")
else "xtensa-%s-elf-objcopy" % mcu, else "xtensa-%s-elf-objcopy" % mcu,
"--input-target", "--input-target",
"binary", "binary",
"--output-target", "--output-target",
"elf32-littleriscv" if mcu in ("esp32c2","esp32c3","esp32c6","esp32h2","esp32p4") else "elf32-xtensa-le", "elf32-littleriscv" if mcu in ("esp32c2","esp32c3","esp32c5","esp32c6","esp32h2","esp32p4") else "elf32-xtensa-le",
"--binary-architecture", "--binary-architecture",
"riscv" if mcu in ("esp32c2","esp32c3","esp32c6","esp32h2","esp32p4") else "xtensa", "riscv" if mcu in ("esp32c2","esp32c3","esp32c5","esp32c6","esp32h2","esp32p4") else "xtensa",
"--rename-section", "--rename-section",
".data=.rodata.embedded", ".data=.rodata.embedded",
"$SOURCE", "$SOURCE",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+271 -185
View File
@@ -40,22 +40,22 @@ from SCons.Script import (
DefaultEnvironment, DefaultEnvironment,
) )
from platformio import fs, __version__ from platformio import fs
from platformio.compat import IS_WINDOWS from platformio.compat import IS_WINDOWS
from platformio.proc import exec_command from platformio.proc import exec_command
from platformio.builder.tools.piolib import ProjectAsLibBuilder from platformio.builder.tools.piolib import ProjectAsLibBuilder
from platformio.project.config import ProjectConfig from platformio.project.config import ProjectConfig
from platformio.package.version import get_original_version, pepver_to_semver from platformio.package.version import get_original_version, pepver_to_semver
# Added to avoid conflicts between installed Python packages from
# the IDF virtual environment and PlatformIO Core
# Note: This workaround can be safely deleted when PlatformIO 6.1.7 is released
if os.environ.get("PYTHONPATH"):
del os.environ["PYTHONPATH"]
env = DefaultEnvironment() env = DefaultEnvironment()
env.SConscript("_embed_files.py", exports="env") env.SConscript("_embed_files.py", exports="env")
# remove maybe existing old map file in project root
map_file = os.path.join(env.subst("$PROJECT_DIR"), env.subst("$PROGNAME") + ".map")
if os.path.exists(map_file):
os.remove(map_file)
def install_standard_python_deps(): def install_standard_python_deps():
def _get_installed_standard_pip_packages(): def _get_installed_standard_pip_packages():
result = {} result = {}
@@ -83,7 +83,10 @@ def install_standard_python_deps():
deps = { deps = {
"wheel": ">=0.35.1", "wheel": ">=0.35.1",
"rich-click": ">=1.8.6", "rich-click": ">=1.8.6",
"PyYAML": ">=6.0.2" "PyYAML": ">=6.0.2",
"intelhex": ">=2.3.0",
"rich": ">=14.0.0",
"esp-idf-size": ">=1.6.1"
} }
installed_packages = _get_installed_standard_pip_packages() installed_packages = _get_installed_standard_pip_packages()
@@ -100,7 +103,7 @@ def install_standard_python_deps():
env.Execute( env.Execute(
env.VerboseAction( env.VerboseAction(
( (
'"$PYTHONEXE" -m pip install -U ' '"$PYTHONEXE" -m pip install -U -q -q -q '
+ " ".join( + " ".join(
[ [
'"%s%s"' % (p, deps[p]) '"%s%s"' % (p, deps[p])
@@ -147,18 +150,20 @@ TOOLCHAIN_DIR = platform.get_package_dir(
assert os.path.isdir(FRAMEWORK_DIR) assert os.path.isdir(FRAMEWORK_DIR)
assert os.path.isdir(TOOLCHAIN_DIR) assert os.path.isdir(TOOLCHAIN_DIR)
if ( def create_silent_action(action_func):
["espidf"] == env.get("PIOFRAMEWORK") """Create a silent SCons action that suppresses output"""
and semantic_version.Version.coerce(__version__) silent_action = env.Action(action_func)
<= semantic_version.Version("6.1.10") silent_action.strfunction = lambda target, source, env: ''
and "__debug" in COMMAND_LINE_TARGETS return silent_action
):
print("Warning! Debugging an IDF project requires PlatformIO Core >= 6.1.11!")
# Arduino framework as a component is not compatible with ESP-IDF >5.3
if "arduino" in env.subst("$PIOFRAMEWORK"): if "arduino" in env.subst("$PIOFRAMEWORK"):
ARDUINO_FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32") ARDUINO_FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
ARDUINO_FRMWRK_LIB_DIR = platform.get_package_dir("framework-arduinoespressif32-libs") ARDUINO_FRMWRK_LIB_DIR = platform.get_package_dir("framework-arduinoespressif32-libs")
if mcu == "esp32c2":
ARDUINO_FRMWRK_C2_LIB_DIR = join(ARDUINO_FRMWRK_LIB_DIR, mcu)
if not os.path.exists(ARDUINO_FRMWRK_C2_LIB_DIR):
ARDUINO_C2_DIR = join(platform.get_package_dir("framework-arduino-c2-skeleton-lib"),mcu)
shutil.copytree(ARDUINO_C2_DIR, ARDUINO_FRMWRK_C2_LIB_DIR, dirs_exist_ok=True)
# Possible package names in 'package@version' format is not compatible with CMake # Possible package names in 'package@version' format is not compatible with CMake
if "@" in os.path.basename(ARDUINO_FRAMEWORK_DIR): if "@" in os.path.basename(ARDUINO_FRAMEWORK_DIR):
new_path = os.path.join( new_path = os.path.join(
@@ -168,6 +173,7 @@ if "arduino" in env.subst("$PIOFRAMEWORK"):
os.rename(ARDUINO_FRAMEWORK_DIR, new_path) os.rename(ARDUINO_FRAMEWORK_DIR, new_path)
ARDUINO_FRAMEWORK_DIR = new_path ARDUINO_FRAMEWORK_DIR = new_path
assert ARDUINO_FRAMEWORK_DIR and os.path.isdir(ARDUINO_FRAMEWORK_DIR) assert ARDUINO_FRAMEWORK_DIR and os.path.isdir(ARDUINO_FRAMEWORK_DIR)
arduino_libs_mcu = join(platform.get_package_dir("framework-arduinoespressif32-libs"),mcu)
BUILD_DIR = env.subst("$BUILD_DIR") BUILD_DIR = env.subst("$BUILD_DIR")
PROJECT_DIR = env.subst("$PROJECT_DIR") PROJECT_DIR = env.subst("$PROJECT_DIR")
@@ -178,6 +184,18 @@ SDKCONFIG_PATH = os.path.expandvars(board.get(
os.path.join(PROJECT_DIR, "sdkconfig.%s" % env.subst("$PIOENV")), os.path.join(PROJECT_DIR, "sdkconfig.%s" % env.subst("$PIOENV")),
)) ))
def contains_path_traversal(url):
"""Check for Path Traversal patterns"""
dangerous_patterns = [
'../', '..\\', # Standard Path Traversal
'%2e%2e%2f', '%2e%2e%5c', # URL-encoded
'..%2f', '..%5c', # Mixed
'%252e%252e%252f', # Double encoded
]
url_lower = url.lower()
return any(pattern in url_lower for pattern in dangerous_patterns)
# #
# generate modified Arduino IDF sdkconfig, applying settings from "custom_sdkconfig" # generate modified Arduino IDF sdkconfig, applying settings from "custom_sdkconfig"
# #
@@ -192,180 +210,208 @@ if "espidf.custom_sdkconfig" in board:
flag_custom_sdkonfig = True flag_custom_sdkonfig = True
def HandleArduinoIDFsettings(env): def HandleArduinoIDFsettings(env):
"""
Handles Arduino IDF settings configuration with custom sdkconfig support.
"""
def get_MD5_hash(phrase): def get_MD5_hash(phrase):
"""Generate MD5 hash for checksum validation."""
import hashlib import hashlib
return hashlib.md5((phrase).encode('utf-8')).hexdigest()[:16] return hashlib.md5(phrase.encode('utf-8')).hexdigest()[:16]
def custom_sdkconfig_file(string): def load_custom_sdkconfig_file():
if not config.has_option("env:"+env["PIOENV"], "custom_sdkconfig"): """Load custom sdkconfig from file or URL if specified."""
if not config.has_option("env:" + env["PIOENV"], "custom_sdkconfig"):
return "" return ""
sdkconfig_entrys = env.GetProjectOption("custom_sdkconfig").splitlines()
for file in sdkconfig_entrys: sdkconfig_entries = env.GetProjectOption("custom_sdkconfig").splitlines()
if "http" in file and "://" in file:
response = requests.get(file.split(" ")[0]) for file_entry in sdkconfig_entries:
if response.ok: # Handle HTTP/HTTPS URLs
target = str(response.content.decode('utf-8')) if "http" in file_entry and "://" in file_entry:
url = file_entry.split(" ")[0]
# Path Traversal protection
if contains_path_traversal(url):
print(f"Path Traversal detected: {url} check your URL path")
else: else:
print("Failed to download:", file) try:
return "" response = requests.get(file_entry.split(" ")[0], timeout=10)
return target if response.ok:
if "file://" in file: return response.content.decode('utf-8')
file_path = join(PROJECT_DIR,file.lstrip("file://").split(os.path.sep)[-1]) except requests.RequestException as e:
print(f"Error downloading {file_entry}: {e}")
except UnicodeDecodeError as e:
print(f"Error decoding response from {file_entry}: {e}")
return ""
# Handle local files
if "file://" in file_entry:
file_ref = file_entry[7:] if file_entry.startswith("file://") else file_entry
filename = os.path.basename(file_ref)
file_path = join(PROJECT_DIR, filename)
if os.path.exists(file_path): if os.path.exists(file_path):
with open(file_path, 'r') as file: try:
target = file.read() with open(file_path, 'r') as f:
return f.read()
except IOError as e:
print(f"Error reading file {file_path}: {e}")
return ""
else: else:
print("File not found:", file_path) print("File not found, check path:", file_path)
return "" return ""
return target
return "" return ""
def extract_flag_name(line):
"""Extract flag name from sdkconfig line."""
line = line.strip()
if line.startswith("#") and "is not set" in line:
return line.split(" ")[1]
elif not line.startswith("#") and "=" in line:
return line.split("=")[0]
return None
custom_sdk_config_flags = "" def build_idf_config_flags():
board_idf_config_flags = "" """Build complete IDF configuration flags from all sources."""
sdkconfig_file_flags = "" flags = []
custom_sdkconfig_file_str = ""
# Add board-specific flags first
if "espidf.custom_sdkconfig" in board:
board_flags = board.get("espidf.custom_sdkconfig", [])
if board_flags:
flags.extend(board_flags)
# Add custom sdkconfig file content
custom_file_content = load_custom_sdkconfig_file()
if custom_file_content:
flags.append(custom_file_content)
# Add project-level custom sdkconfig
if config.has_option("env:" + env["PIOENV"], "custom_sdkconfig"):
custom_flags = env.GetProjectOption("custom_sdkconfig").rstrip("\n")
if custom_flags:
flags.append(custom_flags)
return "\n".join(flags) + "\n" if flags else ""
if config.has_option("env:"+env["PIOENV"], "custom_sdkconfig"): def add_flash_configuration(config_flags):
flag_custom_sdkonfig = True """Add flash frequency and mode configuration."""
custom_sdk_config_flags = (env.GetProjectOption("custom_sdkconfig").rstrip("\n")) + "\n"
custom_sdkconfig_file_str = custom_sdkconfig_file(sdkconfig_file_flags)
if "espidf.custom_sdkconfig" in board:
board_idf_config_flags = ('\n'.join([element for element in board.get("espidf.custom_sdkconfig", "")])).rstrip("\n") + "\n"
flag_custom_sdkonfig = True
if flag_custom_sdkonfig == True: # TDOO duplicated
print("*** Add \"custom_sdkconfig\" settings to IDF sdkconfig.defaults ***")
idf_config_flags = custom_sdk_config_flags
if custom_sdkconfig_file_str != "":
sdkconfig_file_flags = custom_sdkconfig_file_str + "\n"
idf_config_flags = sdkconfig_file_flags + idf_config_flags
idf_config_flags = board_idf_config_flags + idf_config_flags
if flash_frequency != "80m": if flash_frequency != "80m":
idf_config_flags = idf_config_flags + "# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set\n" config_flags += "# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set\n"
esptool_flashfreq_y = "CONFIG_ESPTOOLPY_FLASHFREQ_%s=y\n" % flash_frequency.upper() config_flags += f"CONFIG_ESPTOOLPY_FLASHFREQ_{flash_frequency.upper()}=y\n"
esptool_flashfreq_M = "CONFIG_ESPTOOLPY_FLASHFREQ=\"%s\"\n" % flash_frequency config_flags += f"CONFIG_ESPTOOLPY_FLASHFREQ=\"{flash_frequency}\"\n"
idf_config_flags = idf_config_flags + esptool_flashfreq_y + esptool_flashfreq_M
if flash_mode != "qio": if flash_mode != "qio":
idf_config_flags = idf_config_flags + "# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set\n" config_flags += "# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set\n"
esptool_flashmode = "CONFIG_ESPTOOLPY_FLASHMODE_%s=y\n" % flash_mode.upper()
if esptool_flashmode not in idf_config_flags: flash_mode_flag = f"CONFIG_ESPTOOLPY_FLASHMODE_{flash_mode.upper()}=y\n"
idf_config_flags = idf_config_flags + esptool_flashmode if flash_mode_flag not in config_flags:
if mcu in ("esp32") and "CONFIG_FREERTOS_UNICORE=y" in idf_config_flags: config_flags += flash_mode_flag
idf_config_flags = idf_config_flags + "# CONFIG_SPIRAM is not set\n"
# ESP32 specific SPIRAM configuration
if mcu == "esp32" and "CONFIG_FREERTOS_UNICORE=y" in config_flags:
config_flags += "# CONFIG_SPIRAM is not set\n"
return config_flags
idf_config_flags = idf_config_flags.splitlines() def write_sdkconfig_file(idf_config_flags, checksum_source):
sdkconfig_src = join(ARDUINO_FRMWRK_LIB_DIR,mcu,"sdkconfig") if "arduino" not in env.subst("$PIOFRAMEWORK"):
print("Error: Arduino framework required for sdkconfig processing")
def get_flag(line): return
if line.startswith("#") and "is not set" in line: """Write the final sdkconfig.defaults file with checksum."""
return line.split(" ")[1] sdkconfig_src = join(arduino_libs_mcu, "sdkconfig")
elif not line.startswith("#") and len(line.split("=")) > 1: sdkconfig_dst = join(PROJECT_DIR, "sdkconfig.defaults")
return line.split("=")[0]
else: # Generate checksum for validation (maintains original logic)
return None checksum = get_MD5_hash(checksum_source.strip() + mcu)
with open(sdkconfig_src) as src: with open(sdkconfig_src, 'r', encoding='utf-8') as src, open(sdkconfig_dst, 'w', encoding='utf-8') as dst:
sdkconfig_dst = os.path.join(PROJECT_DIR, "sdkconfig.defaults") # Write checksum header (critical for compilation decision logic)
dst = open(sdkconfig_dst,"w") dst.write(f"# TASMOTA__{checksum}\n")
dst.write("# TASMOTA__"+ get_MD5_hash(''.join(custom_sdk_config_flags).strip() + mcu) +"\n")
while line := src.readline(): processed_flags = set()
flag = get_flag(line)
if flag is None: # Process each line from source sdkconfig
for line in src:
flag_name = extract_flag_name(line)
if flag_name is None:
dst.write(line) dst.write(line)
else: continue
no_match = True
for item in idf_config_flags: # Check if we have a custom replacement for this flag
if flag == get_flag(item.replace("\'", "")): flag_replaced = False
dst.write(item.replace("\'", "")+"\n") for custom_flag in idf_config_flags[:]: # Create copy for safe removal
no_match = False custom_flag_name = extract_flag_name(custom_flag.replace("'", ""))
print("Replace:",line,"with:",item.replace("\'", ""))
idf_config_flags.remove(item) if flag_name == custom_flag_name:
if no_match: cleaned_flag = custom_flag.replace("'", "")
dst.write(line) dst.write(cleaned_flag + "\n")
for item in idf_config_flags: # are there new flags? print(f"Replace: {line.strip()} with: {cleaned_flag}")
print("Add:",item.replace("\'", "")) idf_config_flags.remove(custom_flag)
dst.write(item.replace("\'", "")+"\n") processed_flags.add(custom_flag_name)
dst.close() flag_replaced = True
return break
else:
if not flag_replaced:
dst.write(line)
# Add any remaining new flags
for remaining_flag in idf_config_flags:
cleaned_flag = remaining_flag.replace("'", "")
print(f"Add: {cleaned_flag}")
dst.write(cleaned_flag + "\n")
# Main execution logic
has_custom_config = (
config.has_option("env:" + env["PIOENV"], "custom_sdkconfig") or
"espidf.custom_sdkconfig" in board
)
if not has_custom_config:
return return
print("*** Add \"custom_sdkconfig\" settings to IDF sdkconfig.defaults ***")
# Build complete configuration
idf_config_flags = build_idf_config_flags()
idf_config_flags = add_flash_configuration(idf_config_flags)
# Convert to list for processing
idf_config_list = [line for line in idf_config_flags.splitlines() if line.strip()]
# Write final configuration file with checksum
custom_sdk_config_flags = ""
if config.has_option("env:" + env["PIOENV"], "custom_sdkconfig"):
custom_sdk_config_flags = env.GetProjectOption("custom_sdkconfig").rstrip("\n") + "\n"
write_sdkconfig_file(idf_config_list, custom_sdk_config_flags)
def HandleCOMPONENTsettings(env): def HandleCOMPONENTsettings(env):
if flag_custom_component_add == True or flag_custom_component_remove == True: # todo remove duplicated from component_manager import ComponentManager
import yaml component_manager = ComponentManager(env)
from yaml import SafeLoader
print("*** \"custom_component\" is used to select managed idf components ***")
if flag_custom_component_remove == True:
idf_custom_component_remove = env.GetProjectOption("custom_component_remove").splitlines()
else:
idf_custom_component_remove = ""
if flag_custom_component_add == True:
idf_custom_component_add = env.GetProjectOption("custom_component_add").splitlines()
else:
idf_custom_component_add = ""
# search "idf_component.yml" file if flag_custom_component_add or flag_custom_component_remove:
try: # 1.st in Arduino framework actions = [action for flag, action in [
idf_component_yml_src = os.path.join(ARDUINO_FRAMEWORK_DIR, "idf_component.yml") (flag_custom_component_add, "select"),
shutil.copy(join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml"),join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml.orig")) (flag_custom_component_remove, "deselect")
yml_file_dir = idf_component_yml_src ] if flag]
except: # 2.nd Project source action_text = " and ".join(actions)
try: print(f"*** \"custom_component\" is used to {action_text} managed idf components ***")
idf_component_yml_src = os.path.join(PROJECT_SRC_DIR, "idf_component.yml")
shutil.copy(join(PROJECT_SRC_DIR,"idf_component.yml"),join(PROJECT_SRC_DIR,"idf_component.yml.orig"))
yml_file_dir = idf_component_yml_src
except: # no idf_component.yml in Project source -> create
idf_component_yml_src = os.path.join(PROJECT_SRC_DIR, "idf_component.yml")
yml_file_dir = idf_component_yml_src
idf_component_yml_str = """
dependencies:
idf: \">=5.1\"
"""
idf_component_yml = yaml.safe_load(idf_component_yml_str)
with open(idf_component_yml_src, 'w',) as f :
yaml.dump(idf_component_yml,f)
yaml_file=open(idf_component_yml_src,"r") component_manager.handle_component_settings(
idf_component=yaml.load(yaml_file, Loader=SafeLoader) add_components=flag_custom_component_add,
idf_component_str=json.dumps(idf_component) # convert to json string remove_components=flag_custom_component_remove
idf_component_json=json.loads(idf_component_str) # convert string to json dict )
if idf_custom_component_remove != "":
for entry in idf_custom_component_remove:
# checking if the entry exists before removing
if entry in idf_component_json["dependencies"]:
print("*** Removing component:",entry)
del idf_component_json["dependencies"][entry]
if idf_custom_component_add != "":
for entry in idf_custom_component_add:
if len(str(entry)) > 4: # too short or empty entry
# add new entrys to json
if "@" in entry:
idf_comp_entry = str(entry.split("@")[0]).replace(" ", "")
idf_comp_vers = str(entry.split("@")[1]).replace(" ", "")
else:
idf_comp_entry = str(entry).replace(" ", "")
idf_comp_vers = "*"
if idf_comp_entry not in idf_component_json["dependencies"]:
print("*** Adding component:", idf_comp_entry, idf_comp_vers)
new_entry = {idf_comp_entry: {"version": idf_comp_vers}}
idf_component_json["dependencies"].update(new_entry)
idf_component_yml_file = open(yml_file_dir,"w")
yaml.dump(idf_component_json, idf_component_yml_file)
idf_component_yml_file.close()
# print("JSON from modified idf_component.yml:")
# print(json.dumps(idf_component_json))
return return
return return
if flag_custom_component_add == True or flag_custom_component_remove == True: if "arduino" in env.subst("$PIOFRAMEWORK"):
HandleCOMPONENTsettings(env) HandleCOMPONENTsettings(env)
if flag_custom_sdkonfig == True and "arduino" in env.subst("$PIOFRAMEWORK"): if flag_custom_sdkonfig == True and "arduino" in env.subst("$PIOFRAMEWORK") and "espidf" not in env.subst("$PIOFRAMEWORK"):
HandleArduinoIDFsettings(env) HandleArduinoIDFsettings(env)
LIB_SOURCE = os.path.join(ProjectConfig.get_instance().get("platformio", "platforms_dir"), "espressif32", "builder", "build_lib") LIB_SOURCE = os.path.join(ProjectConfig.get_instance().get("platformio", "platforms_dir"), "espressif32", "builder", "build_lib")
if not bool(os.path.exists(os.path.join(PROJECT_DIR, ".dummy"))): if not bool(os.path.exists(os.path.join(PROJECT_DIR, ".dummy"))):
@@ -397,7 +443,6 @@ def get_project_lib_includes(env):
return paths return paths
def is_cmake_reconfigure_required(cmake_api_reply_dir): def is_cmake_reconfigure_required(cmake_api_reply_dir):
cmake_cache_file = os.path.join(BUILD_DIR, "CMakeCache.txt") cmake_cache_file = os.path.join(BUILD_DIR, "CMakeCache.txt")
cmake_txt_files = [ cmake_txt_files = [
@@ -536,6 +581,8 @@ def populate_idf_env_vars(idf_env):
if "IDF_TOOLS_PATH" in idf_env: if "IDF_TOOLS_PATH" in idf_env:
del idf_env["IDF_TOOLS_PATH"] del idf_env["IDF_TOOLS_PATH"]
idf_env["ESP_ROM_ELF_DIR"] = platform.get_package_dir("tool-esp-rom-elfs")
def get_target_config(project_configs, target_index, cmake_api_reply_dir): def get_target_config(project_configs, target_index, cmake_api_reply_dir):
target_json = project_configs.get("targets")[target_index].get("jsonFile", "") target_json = project_configs.get("targets")[target_index].get("jsonFile", "")
@@ -595,6 +642,8 @@ def extract_defines(compile_group):
define_string = define_string.strip() define_string = define_string.strip()
if "=" in define_string: if "=" in define_string:
define, value = define_string.split("=", maxsplit=1) define, value = define_string.split("=", maxsplit=1)
if define == "OPENTHREAD_BUILD_DATETIME":
return None
if any(char in value for char in (' ', '<', '>')): if any(char in value for char in (' ', '<', '>')):
value = f'"{value}"' value = f'"{value}"'
elif '"' in value and not value.startswith("\\"): elif '"' in value and not value.startswith("\\"):
@@ -1531,11 +1580,10 @@ def install_python_deps():
# https://github.com/platformio/platformio-core/issues/4614 # https://github.com/platformio/platformio-core/issues/4614
"urllib3": "<2", "urllib3": "<2",
# https://github.com/platformio/platform-espressif32/issues/635 # https://github.com/platformio/platform-espressif32/issues/635
"cryptography": "~=41.0.1", "cryptography": "~=44.0.0",
"future": ">=0.18.3",
"pyparsing": ">=3.1.0,<4", "pyparsing": ">=3.1.0,<4",
"idf-component-manager": "~=2.0.1", "idf-component-manager": "~=2.0.1",
"esp-idf-kconfig": ">=2.5.0" "esp-idf-kconfig": "~=2.5.0"
} }
if sys_platform.system() == "Darwin" and "arm" in sys_platform.machine().lower(): if sys_platform.system() == "Darwin" and "arm" in sys_platform.machine().lower():
@@ -1556,7 +1604,7 @@ def install_python_deps():
env.Execute( env.Execute(
env.VerboseAction( env.VerboseAction(
( (
'"%s" -m pip install -U ' % python_exe_path '"%s" -m pip install -U -q -q -q ' % python_exe_path
+ " ".join(['"%s%s"' % (p, deps[p]) for p in packages_to_install]) + " ".join(['"%s%s"' % (p, deps[p]) for p in packages_to_install])
), ),
"Installing ESP-IDF's Python dependencies", "Installing ESP-IDF's Python dependencies",
@@ -1566,7 +1614,7 @@ def install_python_deps():
if IS_WINDOWS and "windows-curses" not in installed_packages: if IS_WINDOWS and "windows-curses" not in installed_packages:
env.Execute( env.Execute(
env.VerboseAction( env.VerboseAction(
'"%s" -m pip install windows-curses' % python_exe_path, '"%s" -m pip install -q -q -q windows-curses' % python_exe_path,
"Installing windows-curses package", "Installing windows-curses package",
) )
) )
@@ -1786,18 +1834,36 @@ if "arduino" in env.subst("$PIOFRAMEWORK"):
LIBSOURCE_DIRS=[os.path.join(ARDUINO_FRAMEWORK_DIR, "libraries")] LIBSOURCE_DIRS=[os.path.join(ARDUINO_FRAMEWORK_DIR, "libraries")]
) )
# Set ESP-IDF version environment variables (needed for proper Kconfig processing)
framework_version = get_framework_version()
major_version = framework_version.split('.')[0] + '.' + framework_version.split('.')[1]
os.environ["ESP_IDF_VERSION"] = major_version
# Configure CMake arguments with ESP-IDF version
extra_cmake_args = [
"-DIDF_TARGET=" + idf_variant,
"-DPYTHON_DEPS_CHECKED=1",
"-DEXTRA_COMPONENT_DIRS:PATH=" + ";".join(extra_components),
"-DPYTHON=" + get_python_exe(),
"-DSDKCONFIG=" + SDKCONFIG_PATH,
f"-DESP_IDF_VERSION={major_version}",
f"-DESP_IDF_VERSION_MAJOR={framework_version.split('.')[0]}",
f"-DESP_IDF_VERSION_MINOR={framework_version.split('.')[1]}",
]
# This will add the linker flag for the map file
extra_cmake_args.append(
f'-DCMAKE_EXE_LINKER_FLAGS=-Wl,-Map={os.path.join(BUILD_DIR, env.subst("$PROGNAME") + ".map")}'
)
# Add any extra args from board config
extra_cmake_args += click.parser.split_arg_string(board.get("build.cmake_extra_args", ""))
print("Reading CMake configuration...") print("Reading CMake configuration...")
project_codemodel = get_cmake_code_model( project_codemodel = get_cmake_code_model(
PROJECT_DIR, PROJECT_DIR,
BUILD_DIR, BUILD_DIR,
[ extra_cmake_args
"-DIDF_TARGET=" + idf_variant,
"-DPYTHON_DEPS_CHECKED=1",
"-DEXTRA_COMPONENT_DIRS:PATH=" + ";".join(extra_components),
"-DPYTHON=" + get_python_exe(),
"-DSDKCONFIG=" + SDKCONFIG_PATH,
]
+ click.parser.split_arg_string(board.get("build.cmake_extra_args", "")),
) )
# At this point the sdkconfig file should be generated by the underlying build system # At this point the sdkconfig file should be generated by the underlying build system
@@ -1973,7 +2039,7 @@ env.Prepend(
( (
board.get( board.get(
"upload.bootloader_offset", "upload.bootloader_offset",
"0x1000" if mcu in ["esp32", "esp32s2"] else ("0x2000" if mcu in ["esp32p4"] else "0x0"), "0x1000" if mcu in ["esp32", "esp32s2"] else ("0x2000" if mcu in ["esp32c5", "esp32p4"] else "0x0"),
), ),
os.path.join("$BUILD_DIR", "bootloader.bin"), os.path.join("$BUILD_DIR", "bootloader.bin"),
), ),
@@ -2063,6 +2129,15 @@ extra_elf2bin_flags = "--elf-sha256-offset 0xb0"
# For chips that support configurable MMU page size feature # For chips that support configurable MMU page size feature
# If page size is configured to values other than the default "64KB" in menuconfig, # If page size is configured to values other than the default "64KB" in menuconfig,
mmu_page_size = "64KB" mmu_page_size = "64KB"
if sdk_config.get("MMU_PAGE_SIZE_8KB", False):
mmu_page_size = "8KB"
elif sdk_config.get("MMU_PAGE_SIZE_16KB", False):
mmu_page_size = "16KB"
elif sdk_config.get("MMU_PAGE_SIZE_32KB", False):
mmu_page_size = "32KB"
else:
mmu_page_size = "64KB"
if sdk_config.get("SOC_MMU_PAGE_SIZE_CONFIGURABLE", False): if sdk_config.get("SOC_MMU_PAGE_SIZE_CONFIGURABLE", False):
if board_flash_size == "2MB": if board_flash_size == "2MB":
mmu_page_size = "32KB" mmu_page_size = "32KB"
@@ -2091,7 +2166,7 @@ if os.path.isdir(ulp_dir) and os.listdir(ulp_dir) and mcu not in ("esp32c2", "es
# Compile Arduino IDF sources # Compile Arduino IDF sources
# #
if "arduino" in env.get("PIOFRAMEWORK") and "espidf" not in env.get("PIOFRAMEWORK"): if ("arduino" in env.subst("$PIOFRAMEWORK")) and ("espidf" not in env.subst("$PIOFRAMEWORK")):
def idf_lib_copy(source, target, env): def idf_lib_copy(source, target, env):
env_build = join(env["PROJECT_BUILD_DIR"],env["PIOENV"]) env_build = join(env["PROJECT_BUILD_DIR"],env["PIOENV"])
sdkconfig_h_path = join(env_build,"config","sdkconfig.h") sdkconfig_h_path = join(env_build,"config","sdkconfig.h")
@@ -2147,9 +2222,14 @@ if "arduino" in env.get("PIOFRAMEWORK") and "espidf" not in env.get("PIOFRAMEWOR
print("*** Original Arduino \"idf_component.yml\" restored ***") print("*** Original Arduino \"idf_component.yml\" restored ***")
except: except:
print("*** Original Arduino \"idf_component.yml\" couldnt be restored ***") print("*** Original Arduino \"idf_component.yml\" couldnt be restored ***")
env.AddPostAction("checkprogsize", idf_lib_copy) # Restore original pioarduino-build.py
from component_manager import ComponentManager
component_manager = ComponentManager(env)
component_manager.restore_pioarduino_build_py()
silent_action = create_silent_action(idf_lib_copy)
env.AddPostAction("checkprogsize", silent_action)
if "espidf" in env.get("PIOFRAMEWORK") and (flag_custom_component_add == True or flag_custom_component_remove == True): if "espidf" in env.subst("$PIOFRAMEWORK") and (flag_custom_component_add == True or flag_custom_component_remove == True):
def idf_custom_component(source, target, env): def idf_custom_component(source, target, env):
try: try:
shutil.copy(join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml.orig"),join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml")) shutil.copy(join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml.orig"),join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml"))
@@ -2163,8 +2243,14 @@ if "espidf" in env.get("PIOFRAMEWORK") and (flag_custom_component_add == True or
os.remove(join(PROJECT_SRC_DIR,"idf_component.yml")) os.remove(join(PROJECT_SRC_DIR,"idf_component.yml"))
print("*** pioarduino generated \"idf_component.yml\" removed ***") print("*** pioarduino generated \"idf_component.yml\" removed ***")
except: except:
print("*** \"idf_component.yml\" couldnt be removed ***") print("*** no custom \"idf_component.yml\" found for removing ***")
env.AddPostAction("checkprogsize", idf_custom_component) if "arduino" in env.subst("$PIOFRAMEWORK"):
# Restore original pioarduino-build.py, only used with Arduino
from component_manager import ComponentManager
component_manager = ComponentManager(env)
component_manager.restore_pioarduino_build_py()
silent_action = create_silent_action(idf_custom_component)
env.AddPostAction("checkprogsize", silent_action)
# #
# Process OTA partition and image # Process OTA partition and image
# #
@@ -2219,7 +2305,7 @@ def _parse_size(value):
partitions_csv = env.subst("$PARTITIONS_TABLE_CSV") partitions_csv = env.subst("$PARTITIONS_TABLE_CSV")
result = [] result = []
next_offset = 0 next_offset = 0
bound = int(board.get("upload.offset_address", "0x10000"), 16) # default 0x10000 bound = 0x10000
with open(partitions_csv) as fp: with open(partitions_csv) as fp:
for line in fp.readlines(): for line in fp.readlines():
line = line.strip() line = line.strip()
+1 -1
View File
@@ -37,7 +37,7 @@ def prepare_ulp_env_vars(env):
toolchain_path = platform.get_package_dir( toolchain_path = platform.get_package_dir(
"toolchain-xtensa-esp-elf" "toolchain-xtensa-esp-elf"
if idf_variant not in ("esp32c6", "esp32p4") if idf_variant not in ("esp32c5","esp32c6", "esp32p4")
else "toolchain-riscv32-esp" else "toolchain-riscv32-esp"
) )
+333 -127
View File
@@ -12,31 +12,47 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import locale
import os
import re import re
import shlex
import subprocess
import sys import sys
from os.path import isfile, join from os.path import isfile, join
from SCons.Script import ( from SCons.Script import (
ARGUMENTS, COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default, ARGUMENTS,
DefaultEnvironment) COMMAND_LINE_TARGETS,
AlwaysBuild,
Builder,
Default,
DefaultEnvironment,
)
from platformio.project.helpers import get_project_dir
from platformio.util import get_serial_ports from platformio.util import get_serial_ports
# Initialize environment and configuration
env = DefaultEnvironment() env = DefaultEnvironment()
platform = env.PioPlatform() platform = env.PioPlatform()
projectconfig = env.GetProjectConfig()
terminal_cp = locale.getpreferredencoding().lower()
# # Framework directory path
# Helpers
#
FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32") FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
def BeforeUpload(target, source, env): def BeforeUpload(target, source, env):
"""
Prepare the environment before uploading firmware.
Handles port detection and special upload configurations.
"""
upload_options = {} upload_options = {}
if "BOARD" in env: if "BOARD" in env:
upload_options = env.BoardConfig().get("upload", {}) upload_options = env.BoardConfig().get("upload", {})
env.AutodetectUploadPort() if not env.subst("$UPLOAD_PORT"):
env.AutodetectUploadPort()
before_ports = get_serial_ports() before_ports = get_serial_ports()
if upload_options.get("use_1200bps_touch", False): if upload_options.get("use_1200bps_touch", False):
@@ -47,6 +63,10 @@ def BeforeUpload(target, source, env):
def _get_board_memory_type(env): def _get_board_memory_type(env):
"""
Determine the memory type configuration for the board.
Returns the appropriate memory type string based on board configuration.
"""
board_config = env.BoardConfig() board_config = env.BoardConfig()
default_type = "%s_%s" % ( default_type = "%s_%s" % (
board_config.get("build.flash_mode", "dio"), board_config.get("build.flash_mode", "dio"),
@@ -62,24 +82,33 @@ def _get_board_memory_type(env):
), ),
) )
def _normalize_frequency(frequency): def _normalize_frequency(frequency):
"""
Convert frequency value to normalized string format (e.g., "40m").
Removes 'L' suffix and converts to MHz format.
"""
frequency = str(frequency).replace("L", "") frequency = str(frequency).replace("L", "")
return str(int(int(frequency) / 1000000)) + "m" return str(int(int(frequency) / 1000000)) + "m"
def _get_board_f_flash(env): def _get_board_f_flash(env):
"""Get the flash frequency for the board."""
frequency = env.subst("$BOARD_F_FLASH") frequency = env.subst("$BOARD_F_FLASH")
return _normalize_frequency(frequency) return _normalize_frequency(frequency)
def _get_board_f_image(env): def _get_board_f_image(env):
"""Get the image frequency for the board, fallback to flash frequency."""
board_config = env.BoardConfig() board_config = env.BoardConfig()
if "build.f_image" in board_config: if "build.f_image" in board_config:
return _normalize_frequency(board_config.get("build.f_image")) return _normalize_frequency(board_config.get("build.f_image"))
return _get_board_f_flash(env) return _get_board_f_flash(env)
def _get_board_f_boot(env): def _get_board_f_boot(env):
"""Get the boot frequency for the board, fallback to flash frequency."""
board_config = env.BoardConfig() board_config = env.BoardConfig()
if "build.f_boot" in board_config: if "build.f_boot" in board_config:
return _normalize_frequency(board_config.get("build.f_boot")) return _normalize_frequency(board_config.get("build.f_boot"))
@@ -88,10 +117,11 @@ def _get_board_f_boot(env):
def _get_board_flash_mode(env): def _get_board_flash_mode(env):
if _get_board_memory_type(env) in ( """
"opi_opi", Determine the appropriate flash mode for the board.
"opi_qspi", Handles special cases for OPI memory types.
): """
if _get_board_memory_type(env) in ("opi_opi", "opi_qspi"):
return "dout" return "dout"
mode = env.subst("$BOARD_FLASH_MODE") mode = env.subst("$BOARD_FLASH_MODE")
@@ -101,6 +131,10 @@ def _get_board_flash_mode(env):
def _get_board_boot_mode(env): def _get_board_boot_mode(env):
"""
Determine the boot mode for the board.
Handles special cases for OPI memory types.
"""
memory_type = env.BoardConfig().get("build.arduino.memory_type", "") memory_type = env.BoardConfig().get("build.arduino.memory_type", "")
build_boot = env.BoardConfig().get("build.boot", "$BOARD_FLASH_MODE") build_boot = env.BoardConfig().get("build.boot", "$BOARD_FLASH_MODE")
if memory_type in ("opi_opi", "opi_qspi"): if memory_type in ("opi_opi", "opi_qspi"):
@@ -109,6 +143,10 @@ def _get_board_boot_mode(env):
def _parse_size(value): def _parse_size(value):
"""
Parse size values from various formats (int, hex, K/M suffixes).
Returns the size in bytes as an integer.
"""
if isinstance(value, int): if isinstance(value, int):
return value return value
elif value.isdigit(): elif value.isdigit():
@@ -122,16 +160,23 @@ def _parse_size(value):
def _parse_partitions(env): def _parse_partitions(env):
"""
Parse the partition table CSV file and return partition information.
Also sets the application offset for the environment.
"""
partitions_csv = env.subst("$PARTITIONS_TABLE_CSV") partitions_csv = env.subst("$PARTITIONS_TABLE_CSV")
if not isfile(partitions_csv): if not isfile(partitions_csv):
sys.stderr.write("Could not find the file %s with partitions " sys.stderr.write(
"table.\n" % partitions_csv) "Could not find the file %s with partitions table.\n"
% partitions_csv
)
env.Exit(1) env.Exit(1)
return return
result = [] result = []
next_offset = 0 next_offset = 0
app_offset = int(board.get("upload.offset_address", "0x10000"), 16) # default 0x10000 app_offset = 0x10000 # Default address for firmware
with open(partitions_csv) as fp: with open(partitions_csv) as fp:
for line in fp.readlines(): for line in fp.readlines():
line = line.strip() line = line.strip()
@@ -148,25 +193,34 @@ def _parse_partitions(env):
"subtype": tokens[2], "subtype": tokens[2],
"offset": tokens[3] or calculated_offset, "offset": tokens[3] or calculated_offset,
"size": tokens[4], "size": tokens[4],
"flags": tokens[5] if len(tokens) > 5 else None "flags": tokens[5] if len(tokens) > 5 else None,
} }
result.append(partition) result.append(partition)
next_offset = _parse_size(partition["offset"]) next_offset = _parse_size(partition["offset"])
if (partition["subtype"] == "ota_0"): if partition["subtype"] == "ota_0":
app_offset = next_offset app_offset = next_offset
next_offset = next_offset + _parse_size(partition["size"]) next_offset = next_offset + _parse_size(partition["size"])
# Configure application partition offset # Configure application partition offset
env.Replace(ESP32_APP_OFFSET=str(hex(app_offset))) env.Replace(ESP32_APP_OFFSET=str(hex(app_offset)))
# Propagate application offset to debug configurations # Propagate application offset to debug configurations
env["INTEGRATION_EXTRA_DATA"].update({"application_offset": str(hex(app_offset))}) env["INTEGRATION_EXTRA_DATA"].update(
{"application_offset": str(hex(app_offset))}
)
return result return result
def _update_max_upload_size(env): def _update_max_upload_size(env):
"""
Update the maximum upload size based on partition table configuration.
Prioritizes user-specified partition names.
"""
if not env.get("PARTITIONS_TABLE_CSV"): if not env.get("PARTITIONS_TABLE_CSV"):
return return
sizes = { sizes = {
p["subtype"]: _parse_size(p["size"]) for p in _parse_partitions(env) p["subtype"]: _parse_size(p["size"])
for p in _parse_partitions(env)
if p["type"] in ("0", "app") if p["type"] in ("0", "app")
} }
@@ -177,12 +231,15 @@ def _update_max_upload_size(env):
if custom_app_partition_name: if custom_app_partition_name:
selected_partition = partitions.get(custom_app_partition_name, {}) selected_partition = partitions.get(custom_app_partition_name, {})
if selected_partition: if selected_partition:
board.update("upload.maximum_size", _parse_size(selected_partition["size"])) board.update(
"upload.maximum_size", _parse_size(selected_partition["size"])
)
return return
else: else:
print( print(
"Warning! Selected partition `%s` is not available in the partition " \ "Warning! Selected partition `%s` is not available in the "
"table! Default partition will be used!" % custom_app_partition_name "partition table! Default partition will be used!"
% custom_app_partition_name
) )
for p in partitions.values(): for p in partitions.values():
@@ -191,20 +248,23 @@ def _update_max_upload_size(env):
break break
def _to_unix_slashes(path): def _to_unix_slashes(path):
"""Convert Windows-style backslashes to Unix-style forward slashes."""
return path.replace("\\", "/") return path.replace("\\", "/")
#
# Filesystem helpers
#
def fetch_fs_size(env): def fetch_fs_size(env):
"""
Extract filesystem size and offset information from partition table.
Sets FS_START, FS_SIZE, FS_PAGE, and FS_BLOCK environment variables.
"""
fs = None fs = None
for p in _parse_partitions(env): for p in _parse_partitions(env):
if p["type"] == "data" and p["subtype"] in ("spiffs", "fat", "littlefs"): if p["type"] == "data" and p["subtype"] in (
"spiffs",
"fat",
"littlefs",
):
fs = p fs = p
if not fs: if not fs:
sys.stderr.write( sys.stderr.write(
@@ -213,6 +273,7 @@ def fetch_fs_size(env):
) )
env.Exit(1) env.Exit(1)
return return
env["FS_START"] = _parse_size(fs["offset"]) env["FS_START"] = _parse_size(fs["offset"])
env["FS_SIZE"] = _parse_size(fs["size"]) env["FS_SIZE"] = _parse_size(fs["size"])
env["FS_PAGE"] = int("0x100", 16) env["FS_PAGE"] = int("0x100", 16)
@@ -226,20 +287,37 @@ def fetch_fs_size(env):
def __fetch_fs_size(target, source, env): def __fetch_fs_size(target, source, env):
"""Wrapper function for fetch_fs_size to be used as SCons emitter."""
fetch_fs_size(env) fetch_fs_size(env)
return (target, source) return (target, source)
def check_lib_archive_exists():
"""
Check if lib_archive is set in platformio.ini configuration.
Returns True if found, False otherwise.
"""
for section in projectconfig.sections():
if "lib_archive" in projectconfig.options(section):
return True
return False
# Initialize board configuration and MCU settings
board = env.BoardConfig() board = env.BoardConfig()
mcu = board.get("build.mcu", "esp32") mcu = board.get("build.mcu", "esp32")
toolchain_arch = "xtensa-%s" % mcu toolchain_arch = "xtensa-%s" % mcu
filesystem = board.get("build.filesystem", "spiffs") filesystem = board.get("build.filesystem", "littlefs")
if mcu in ("esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4"):
# Set toolchain architecture for RISC-V based ESP32 variants
if mcu in ("esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32h2", "esp32p4"):
toolchain_arch = "riscv32-esp" toolchain_arch = "riscv32-esp"
# Initialize integration extra data if not present
if "INTEGRATION_EXTRA_DATA" not in env: if "INTEGRATION_EXTRA_DATA" not in env:
env["INTEGRATION_EXTRA_DATA"] = {} env["INTEGRATION_EXTRA_DATA"] = {}
# Configure build tools and environment variables
env.Replace( env.Replace(
__get_board_boot_mode=_get_board_boot_mode, __get_board_boot_mode=_get_board_boot_mode,
__get_board_f_flash=_get_board_f_flash, __get_board_f_flash=_get_board_f_flash,
@@ -247,7 +325,6 @@ env.Replace(
__get_board_f_boot=_get_board_f_boot, __get_board_f_boot=_get_board_f_boot,
__get_board_flash_mode=_get_board_flash_mode, __get_board_flash_mode=_get_board_flash_mode,
__get_board_memory_type=_get_board_memory_type, __get_board_memory_type=_get_board_memory_type,
AR="%s-elf-gcc-ar" % toolchain_arch, AR="%s-elf-gcc-ar" % toolchain_arch,
AS="%s-elf-as" % toolchain_arch, AS="%s-elf-as" % toolchain_arch,
CC="%s-elf-gcc" % toolchain_arch, CC="%s-elf-gcc" % toolchain_arch,
@@ -255,7 +332,14 @@ env.Replace(
GDB=join( GDB=join(
platform.get_package_dir( platform.get_package_dir(
"tool-riscv32-esp-elf-gdb" "tool-riscv32-esp-elf-gdb"
if mcu in ("esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4") if mcu in (
"esp32c2",
"esp32c3",
"esp32c5",
"esp32c6",
"esp32h2",
"esp32p4",
)
else "tool-xtensa-esp-elf-gdb" else "tool-xtensa-esp-elf-gdb"
) )
or "", or "",
@@ -265,20 +349,14 @@ env.Replace(
OBJCOPY=join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"), OBJCOPY=join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"),
RANLIB="%s-elf-gcc-ranlib" % toolchain_arch, RANLIB="%s-elf-gcc-ranlib" % toolchain_arch,
SIZETOOL="%s-elf-size" % toolchain_arch, SIZETOOL="%s-elf-size" % toolchain_arch,
ARFLAGS=["rc"], ARFLAGS=["rc"],
SIZEPROGREGEXP=r"^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|"
SIZEPROGREGEXP=r"^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|\.flash\.text|\.flash\.rodata|)\s+([0-9]+).*", r"\.flash\.text|\.flash\.rodata|)\s+([0-9]+).*",
SIZEDATAREGEXP=r"^(?:\.dram0\.data|\.dram0\.bss|\.noinit)\s+([0-9]+).*", SIZEDATAREGEXP=r"^(?:\.dram0\.data|\.dram0\.bss|\.noinit)\s+([0-9]+).*",
SIZECHECKCMD="$SIZETOOL -A -d $SOURCES", SIZECHECKCMD="$SIZETOOL -A -d $SOURCES",
SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES", SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES",
ERASEFLAGS=["--chip", mcu, "--port", '"$UPLOAD_PORT"'],
ERASEFLAGS=[ ERASECMD='"$PYTHONEXE" "$OBJCOPY" $ERASEFLAGS erase-flash',
"--chip", mcu,
"--port", '"$UPLOAD_PORT"'
],
ERASECMD='"$PYTHONEXE" "$OBJCOPY" $ERASEFLAGS erase_flash',
# mkspiffs package contains two different binaries for IDF and Arduino # mkspiffs package contains two different binaries for IDF and Arduino
MKFSTOOL="mk%s" % filesystem MKFSTOOL="mk%s" % filesystem
+ ( + (
@@ -293,46 +371,61 @@ env.Replace(
if filesystem == "spiffs" if filesystem == "spiffs"
else "" else ""
), ),
# Legacy `ESP32_SPIFFS_IMAGE_NAME` is used as the second fallback value for # Legacy `ESP32_SPIFFS_IMAGE_NAME` is used as the second fallback value
# backward compatibility # for backward compatibility
ESP32_FS_IMAGE_NAME=env.get( ESP32_FS_IMAGE_NAME=env.get(
"ESP32_FS_IMAGE_NAME", env.get("ESP32_SPIFFS_IMAGE_NAME", filesystem) "ESP32_FS_IMAGE_NAME",
env.get("ESP32_SPIFFS_IMAGE_NAME", filesystem),
),
ESP32_APP_OFFSET=env.get("INTEGRATION_EXTRA_DATA").get(
"application_offset"
), ),
ESP32_APP_OFFSET=env.get("INTEGRATION_EXTRA_DATA").get("application_offset"),
ARDUINO_LIB_COMPILE_FLAG="Inactive", ARDUINO_LIB_COMPILE_FLAG="Inactive",
PROGSUFFIX=".elf",
PROGSUFFIX=".elf"
) )
# Check if lib_archive is set in platformio.ini and set it to False
# if not found. This makes weak defs in framework and libs possible.
if not check_lib_archive_exists():
env_section = "env:" + env["PIOENV"]
projectconfig.set(env_section, "lib_archive", "False")
# Allow user to override via pre:script # Allow user to override via pre:script
if env.get("PROGNAME", "program") == "program": if env.get("PROGNAME", "program") == "program":
env.Replace(PROGNAME="firmware") env.Replace(PROGNAME="firmware")
# Configure build actions and builders
env.Append( env.Append(
BUILDERS=dict( BUILDERS=dict(
ElfToBin=Builder( ElfToBin=Builder(
action=env.VerboseAction(" ".join([ action=env.VerboseAction(
'"$PYTHONEXE" "$OBJCOPY"', " ".join(
"--chip", mcu, "elf2image", [
"--flash_mode", "${__get_board_flash_mode(__env__)}", '"$PYTHONEXE" "$OBJCOPY"',
"--flash_freq", "${__get_board_f_image(__env__)}", "--chip",
"--flash_size", board.get("upload.flash_size", "4MB"), mcu,
"-o", "$TARGET", "$SOURCES" "elf2image",
]), "Building $TARGET"), "--flash-mode",
suffix=".bin" "${__get_board_flash_mode(__env__)}",
"--flash-freq",
"${__get_board_f_image(__env__)}",
"--flash-size",
board.get("upload.flash_size", "4MB"),
"-o",
"$TARGET",
"$SOURCES",
]
),
"Building $TARGET",
),
suffix=".bin",
), ),
DataToBin=Builder( DataToBin=Builder(
action=env.VerboseAction( action=env.VerboseAction(
" ".join( " ".join(
['"$MKFSTOOL"', "-c", "$SOURCES", "-s", "$FS_SIZE"] ['"$MKFSTOOL"', "-c", "$SOURCES", "-s", "$FS_SIZE"]
+ ( + (
[ ["-p", "$FS_PAGE", "-b", "$FS_BLOCK"]
"-p",
"$FS_PAGE",
"-b",
"$FS_BLOCK",
]
if filesystem in ("littlefs", "spiffs") if filesystem in ("littlefs", "spiffs")
else [] else []
) )
@@ -347,9 +440,76 @@ env.Append(
) )
) )
# Load framework-specific configuration
if not env.get("PIOFRAMEWORK"): if not env.get("PIOFRAMEWORK"):
env.SConscript("frameworks/_bare.py", exports="env") env.SConscript("frameworks/_bare.py", exports="env")
def firmware_metrics(target, source, env):
"""
Custom target to run esp-idf-size with support for command line parameters
Usage: pio run -t metrics -- [esp-idf-size arguments]
"""
if terminal_cp != "utf-8":
print("Firmware metrics can not be shown. Set the terminal codepage to \"utf-8\"")
return
map_file = os.path.join(env.subst("$BUILD_DIR"), env.subst("$PROGNAME") + ".map")
if not os.path.isfile(map_file):
# map file can be in project dir
map_file = os.path.join(get_project_dir(), env.subst("$PROGNAME") + ".map")
if not os.path.isfile(map_file):
print(f"Error: Map file not found: {map_file}")
print("Make sure the project is built first with 'pio run'")
return
try:
import subprocess
import sys
import shlex
cmd = [env.subst("$PYTHONEXE"), "-m", "esp_idf_size", "--ng"]
# Parameters from platformio.ini
extra_args = env.GetProjectOption("custom_esp_idf_size_args", "")
if extra_args:
cmd.extend(shlex.split(extra_args))
# Command Line Parameter, after --
cli_args = []
if "--" in sys.argv:
dash_index = sys.argv.index("--")
if dash_index + 1 < len(sys.argv):
cli_args = sys.argv[dash_index + 1:]
cmd.extend(cli_args)
# Add CLI arguments before the map file
if cli_args:
cmd.extend(cli_args)
# Map-file as last argument
cmd.append(map_file)
# Debug-Info if wanted
if env.GetProjectOption("custom_esp_idf_size_verbose", False):
print(f"Running command: {' '.join(cmd)}")
# Call esp-idf-size
result = subprocess.run(cmd, check=False, capture_output=False)
if result.returncode != 0:
print(f"Warning: esp-idf-size exited with code {result.returncode}")
except ImportError:
print("Error: esp-idf-size module not found.")
print("Install with: pip install esp-idf-size")
except FileNotFoundError:
print("Error: Python executable not found.")
print("Check your Python installation.")
except Exception as e:
print(f"Error: Failed to run firmware metrics: {e}")
print("Make sure esp-idf-size is installed: pip install esp-idf-size")
# #
# Target: Build executable and linkable firmware or FS image # Target: Build executable and linkable firmware or FS image
# #
@@ -364,6 +524,10 @@ if "nobuild" in COMMAND_LINE_TARGETS:
target_firm = join("$BUILD_DIR", "${PROGNAME}.bin") target_firm = join("$BUILD_DIR", "${PROGNAME}.bin")
else: else:
target_elf = env.BuildProgram() target_elf = env.BuildProgram()
silent_action = env.Action(firmware_metrics)
# Hack to silence scons command output
silent_action.strfunction = lambda target, source, env: ""
env.AddPostAction(target_elf, silent_action)
if set(["buildfs", "uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS): if set(["buildfs", "uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
target_firm = env.DataToBin( target_firm = env.DataToBin(
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR" join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR"
@@ -371,26 +535,27 @@ else:
env.NoCache(target_firm) env.NoCache(target_firm)
AlwaysBuild(target_firm) AlwaysBuild(target_firm)
else: else:
target_firm = env.ElfToBin( target_firm = env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf)
join("$BUILD_DIR", "${PROGNAME}"), target_elf)
env.Depends(target_firm, "checkprogsize") env.Depends(target_firm, "checkprogsize")
env.AddPlatformTarget("buildfs", target_firm, target_firm, "Build Filesystem Image") # Configure platform targets
env.AddPlatformTarget(
"buildfs", target_firm, target_firm, "Build Filesystem Image"
)
AlwaysBuild(env.Alias("nobuild", target_firm)) AlwaysBuild(env.Alias("nobuild", target_firm))
target_buildprog = env.Alias("buildprog", target_firm, target_firm) target_buildprog = env.Alias("buildprog", target_firm, target_firm)
# update max upload size based on CSV file # Update max upload size based on CSV file
if env.get("PIOMAINPROG"): if env.get("PIOMAINPROG"):
env.AddPreAction( env.AddPreAction(
"checkprogsize", "checkprogsize",
env.VerboseAction( env.VerboseAction(
lambda source, target, env: _update_max_upload_size(env), lambda source, target, env: _update_max_upload_size(env),
"Retrieving maximum program size $SOURCES")) "Retrieving maximum program size $SOURCES",
),
)
#
# Target: Print binary size # Target: Print binary size
#
target_size = env.AddPlatformTarget( target_size = env.AddPlatformTarget(
"size", "size",
target_elf, target_elf,
@@ -399,25 +564,25 @@ target_size = env.AddPlatformTarget(
"Calculate program size", "Calculate program size",
) )
#
# Target: Upload firmware or FS image # Target: Upload firmware or FS image
#
upload_protocol = env.subst("$UPLOAD_PROTOCOL") upload_protocol = env.subst("$UPLOAD_PROTOCOL")
debug_tools = board.get("debug.tools", {}) debug_tools = board.get("debug.tools", {})
upload_actions = [] upload_actions = []
# Compatibility with old OTA configurations # Compatibility with old OTA configurations
if (upload_protocol != "espota" if upload_protocol != "espota" and re.match(
and re.match(r"\"?((([0-9]{1,3}\.){3}[0-9]{1,3})|[^\\/]+\.local)\"?$", r"\"?((([0-9]{1,3}\.){3}[0-9]{1,3})|[^\\/]+\.local)\"?$",
env.get("UPLOAD_PORT", ""))): env.get("UPLOAD_PORT", ""),
):
upload_protocol = "espota" upload_protocol = "espota"
sys.stderr.write( sys.stderr.write(
"Warning! We have just detected `upload_port` as IP address or host " "Warning! We have just detected `upload_port` as IP address or host "
"name of ESP device. `upload_protocol` is switched to `espota`.\n" "name of ESP device. `upload_protocol` is switched to `espota`.\n"
"Please specify `upload_protocol = espota` in `platformio.ini` " "Please specify `upload_protocol = espota` in `platformio.ini` "
"project configuration file.\n") "project configuration file.\n"
)
# Configure upload protocol: ESP OTA
if upload_protocol == "espota": if upload_protocol == "espota":
if not env.subst("$UPLOAD_PORT"): if not env.subst("$UPLOAD_PORT"):
sys.stderr.write( sys.stderr.write(
@@ -425,32 +590,45 @@ if upload_protocol == "espota":
"using `upload_port` for build environment or use " "using `upload_port` for build environment or use "
"global `--upload-port` option.\n" "global `--upload-port` option.\n"
"See https://docs.platformio.org/page/platforms/" "See https://docs.platformio.org/page/platforms/"
"espressif32.html#over-the-air-ota-update\n") "espressif32.html#over-the-air-ota-update\n"
)
env.Replace( env.Replace(
UPLOADER=join(FRAMEWORK_DIR,"tools", "espota.py"), UPLOADER=join(FRAMEWORK_DIR, "tools", "espota.py"),
UPLOADERFLAGS=["--debug", "--progress", "-i", "$UPLOAD_PORT"], UPLOADERFLAGS=["--debug", "--progress", "-i", "$UPLOAD_PORT"],
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS -f $SOURCE' UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS -f $SOURCE',
) )
if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS): if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
env.Append(UPLOADERFLAGS=["--spiffs"]) env.Append(UPLOADERFLAGS=["--spiffs"])
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")] upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
# Configure upload protocol: esptool
elif upload_protocol == "esptool": elif upload_protocol == "esptool":
env.Replace( env.Replace(
UPLOADER=join( UPLOADER=join(
platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"), platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"
),
UPLOADERFLAGS=[ UPLOADERFLAGS=[
"--chip", mcu, "--chip",
"--port", '"$UPLOAD_PORT"', mcu,
"--baud", "$UPLOAD_SPEED", "--port",
"--before", board.get("upload.before_reset", "default_reset"), '"$UPLOAD_PORT"',
"--after", board.get("upload.after_reset", "hard_reset"), "--baud",
"write_flash", "-z", "$UPLOAD_SPEED",
"--flash_mode", "${__get_board_flash_mode(__env__)}", "--before",
"--flash_freq", "${__get_board_f_image(__env__)}", board.get("upload.before_reset", "default-reset"),
"--flash_size", "detect" "--after",
board.get("upload.after_reset", "hard-reset"),
"write-flash",
"-z",
"--flash-mode",
"${__get_board_flash_mode(__env__)}",
"--flash-freq",
"${__get_board_f_image(__env__)}",
"--flash-size",
"detect",
], ],
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $ESP32_APP_OFFSET $SOURCE' UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS '
"$ESP32_APP_OFFSET $SOURCE",
) )
for image in env.get("FLASH_EXTRA_IMAGES", []): for image in env.get("FLASH_EXTRA_IMAGES", []):
env.Append(UPLOADERFLAGS=[image[0], env.subst(image[1])]) env.Append(UPLOADERFLAGS=[image[0], env.subst(image[1])])
@@ -458,27 +636,36 @@ elif upload_protocol == "esptool":
if "uploadfs" in COMMAND_LINE_TARGETS: if "uploadfs" in COMMAND_LINE_TARGETS:
env.Replace( env.Replace(
UPLOADERFLAGS=[ UPLOADERFLAGS=[
"--chip", mcu, "--chip",
"--port", '"$UPLOAD_PORT"', mcu,
"--baud", "$UPLOAD_SPEED", "--port",
"--before", board.get("upload.before_reset", "default_reset"), '"$UPLOAD_PORT"',
"--after", board.get("upload.after_reset", "hard_reset"), "--baud",
"write_flash", "-z", "$UPLOAD_SPEED",
"--flash_mode", "${__get_board_flash_mode(__env__)}", "--before",
"--flash_freq", "${__get_board_f_image(__env__)}", board.get("upload.before_reset", "default-reset"),
"--flash_size", "detect", "--after",
"$FS_START" board.get("upload.after_reset", "hard-reset"),
"write-flash",
"-z",
"--flash-mode",
"${__get_board_flash_mode(__env__)}",
"--flash-freq",
"${__get_board_f_image(__env__)}",
"--flash-size",
"detect",
"$FS_START",
], ],
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $SOURCE', UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $SOURCE',
) )
upload_actions = [ upload_actions = [
env.VerboseAction(BeforeUpload, "Looking for upload port..."), env.VerboseAction(BeforeUpload, "Looking for upload port..."),
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE") env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE"),
] ]
# Configure upload protocol: DFU
elif upload_protocol == "dfu": elif upload_protocol == "dfu":
hwids = board.get("build.hwids", [["0x2341", "0x0070"]]) hwids = board.get("build.hwids", [["0x2341", "0x0070"]])
vid = hwids[0][0] vid = hwids[0][0]
pid = hwids[0][1] pid = hwids[0][1]
@@ -493,17 +680,18 @@ elif upload_protocol == "dfu":
"-d", "-d",
",".join(["%s:%s" % (hwid[0], hwid[1]) for hwid in hwids]), ",".join(["%s:%s" % (hwid[0], hwid[1]) for hwid in hwids]),
"-Q", "-Q",
"-D" "-D",
], ],
UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS "$SOURCE"', UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS "$SOURCE"',
) )
# Configure upload protocol: Debug tools (OpenOCD)
elif upload_protocol in debug_tools: elif upload_protocol in debug_tools:
_parse_partitions(env) _parse_partitions(env)
openocd_args = ["-d%d" % (2 if int(ARGUMENTS.get("PIOVERBOSE", 0)) else 1)] openocd_args = ["-d%d" % (2 if int(ARGUMENTS.get("PIOVERBOSE", 0)) else 1)]
openocd_args.extend( openocd_args.extend(
debug_tools.get(upload_protocol).get("server").get("arguments", [])) debug_tools.get(upload_protocol).get("server").get("arguments", [])
)
openocd_args.extend( openocd_args.extend(
[ [
"-c", "-c",
@@ -531,7 +719,9 @@ elif upload_protocol in debug_tools:
f.replace( f.replace(
"$PACKAGE_DIR", "$PACKAGE_DIR",
_to_unix_slashes( _to_unix_slashes(
platform.get_package_dir("tool-openocd-esp32") or "")) platform.get_package_dir("tool-openocd-esp32") or ""
),
)
for f in openocd_args for f in openocd_args
] ]
env.Replace( env.Replace(
@@ -541,55 +731,71 @@ elif upload_protocol in debug_tools:
) )
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")] upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
# custom upload tool # Configure upload protocol: Custom
elif upload_protocol == "custom": elif upload_protocol == "custom":
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")] upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
else: else:
sys.stderr.write("Warning! Unknown upload protocol %s\n" % upload_protocol) sys.stderr.write("Warning! Unknown upload protocol %s\n" % upload_protocol)
# Register upload targets
env.AddPlatformTarget("upload", target_firm, upload_actions, "Upload") env.AddPlatformTarget("upload", target_firm, upload_actions, "Upload")
env.AddPlatformTarget("uploadfs", target_firm, upload_actions, "Upload Filesystem Image")
env.AddPlatformTarget( env.AddPlatformTarget(
"uploadfsota", target_firm, upload_actions, "Upload Filesystem Image OTA") "uploadfs", target_firm, upload_actions, "Upload Filesystem Image"
)
env.AddPlatformTarget(
"uploadfsota",
target_firm,
upload_actions,
"Upload Filesystem Image OTA",
)
#
# Target: Erase Flash and Upload # Target: Erase Flash and Upload
#
env.AddPlatformTarget( env.AddPlatformTarget(
"erase_upload", "erase_upload",
target_firm, target_firm,
[ [
env.VerboseAction(BeforeUpload, "Looking for upload port..."), env.VerboseAction(BeforeUpload, "Looking for upload port..."),
env.VerboseAction("$ERASECMD", "Erasing..."), env.VerboseAction("$ERASECMD", "Erasing..."),
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE") env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE"),
], ],
"Erase Flash and Upload", "Erase Flash and Upload",
) )
#
# Target: Erase Flash # Target: Erase Flash
#
env.AddPlatformTarget( env.AddPlatformTarget(
"erase", "erase",
None, None,
[ [
env.VerboseAction(BeforeUpload, "Looking for upload port..."), env.VerboseAction(BeforeUpload, "Looking for upload port..."),
env.VerboseAction("$ERASECMD", "Erasing...") env.VerboseAction("$ERASECMD", "Erasing..."),
], ],
"Erase Flash", "Erase Flash",
) )
# # Register Custom Target for firmware metrics
# Override memory inspection behavior env.AddCustomTarget(
# name="metrics",
dependencies="$BUILD_DIR/${PROGNAME}.elf",
actions=firmware_metrics,
title="Firmware Size Metrics",
description="Analyze firmware size using esp-idf-size "
"(supports CLI args after --)",
always_build=True,
)
# Additional Target without Build-Dependency when already compiled
env.AddCustomTarget(
name="metrics-only",
dependencies=None,
actions=firmware_metrics,
title="Firmware Size Metrics (No Build)",
description="Analyze firmware size without building first",
always_build=True,
)
# Override memory inspection behavior
env.SConscript("sizedata.py", exports="env") env.SConscript("sizedata.py", exports="env")
# # Set default targets
# Default targets
#
Default([target_buildprog, target_size]) Default([target_buildprog, target_size])
@@ -0,0 +1,5 @@
# NimBLE_extended_client example using h2zero Arduino NimBLE stack
BLE 5 client example, using the great [h2zero NimBLE](https://github.com/h2zero/NimBLE-Arduino) implementation.
Thx @h2zero for the great BLE library.
@@ -0,0 +1,53 @@
; 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
[env]
platform = espressif32
framework = arduino
monitor_speed = 115200
build_flags =
'-DCONFIG_BT_NIMBLE_EXT_ADV=1'
lib_deps =
https://github.com/h2zero/NimBLE-Arduino
lib_ignore =
BLE
BluetoothSerial
SimpleBLE
WiFiProv
custom_component_remove =
espressif/esp_hosted
espressif/esp_wifi_remote
espressif/esp-dsp
espressif/network_provisioning
espressif/esp_rainmaker
espressif/rmaker_common
espressif/esp_insights
espressif/esp_diag_data_store
espressif/esp_diagnostics
espressif/libsodium
espressif/esp-modbus
espressif/esp-cbor
espressif/esp-sr
espressif/esp32-camera
[env:esp32s3]
board = esp32-s3-devkitc-1
[env:esp32c2]
board = esp32-c2-devkitm-1
[env:esp32c3]
board = esp32-c3-devkitm-1
[env:esp32c6]
board = esp32-c6-devkitm-1
[env:esp32h2]
board = esp32-h2-devkitm-1
@@ -0,0 +1,150 @@
/** NimBLE Extended Client Demo:
*
* Demonstrates the Bluetooth 5.x client capabilities.
*
* Created: on April 2 2022
* Author: H2zero
*
*/
#include <Arduino.h>
#include <NimBLEDevice.h>
#if !CONFIG_BT_NIMBLE_EXT_ADV
# error Must enable extended advertising, see nimconfig.h file.
#endif
#define SERVICE_UUID "ABCD"
#define CHARACTERISTIC_UUID "1234"
static const NimBLEAdvertisedDevice* advDevice;
static bool doConnect = false;
static uint32_t scanTime = 10 * 1000; // In milliseconds, 0 = scan forever
/** Define the PHY's to use when connecting to peer devices, can be 1, 2, or all 3 (default).*/
static uint8_t connectPhys = BLE_GAP_LE_PHY_CODED_MASK | BLE_GAP_LE_PHY_1M_MASK /*| BLE_GAP_LE_PHY_2M_MASK */;
/** Define a class to handle the callbacks for client connection events */
class ClientCallbacks : public NimBLEClientCallbacks {
void onConnect(NimBLEClient* pClient) override { Serial.printf("Connected\n"); };
void onDisconnect(NimBLEClient* pClient, int reason) override {
Serial.printf("%s Disconnected, reason = %d - Starting scan\n", pClient->getPeerAddress().toString().c_str(), reason);
NimBLEDevice::getScan()->start(scanTime);
}
} clientCallbacks;
/** Define a class to handle the callbacks when advertisements are received */
class scanCallbacks : public NimBLEScanCallbacks {
void onResult(const NimBLEAdvertisedDevice* advertisedDevice) override {
Serial.printf("Advertised Device found: %s\n", advertisedDevice->toString().c_str());
if (advertisedDevice->isAdvertisingService(NimBLEUUID("ABCD"))) {
Serial.printf("Found Our Service\n");
doConnect = true;
/** Save the device reference in a global for the client to use*/
advDevice = advertisedDevice;
/** stop scan before connecting */
NimBLEDevice::getScan()->stop();
}
}
/** Callback to process the results of the completed scan or restart it */
void onScanEnd(const NimBLEScanResults& results, int rc) override { Serial.printf("Scan Ended\n"); }
} scanCallbacks;
/** Handles the provisioning of clients and connects / interfaces with the server */
bool connectToServer() {
NimBLEClient* pClient = nullptr;
pClient = NimBLEDevice::createClient();
pClient->setClientCallbacks(&clientCallbacks, false);
/**
* Set the PHY's to use for this connection. This is a bitmask that represents the PHY's:
* * 0x01 BLE_GAP_LE_PHY_1M_MASK
* * 0x02 BLE_GAP_LE_PHY_2M_MASK
* * 0x04 BLE_GAP_LE_PHY_CODED_MASK
* Combine these with OR ("|"), eg BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK;
*/
pClient->setConnectPhy(connectPhys);
/** Set how long we are willing to wait for the connection to complete (milliseconds), default is 30000. */
pClient->setConnectTimeout(10 * 1000);
if (!pClient->connect(advDevice)) {
/** Created a client but failed to connect, don't need to keep it as it has no data */
NimBLEDevice::deleteClient(pClient);
Serial.printf("Failed to connect, deleted client\n");
return false;
}
Serial.printf("Connected to: %s RSSI: %d\n", pClient->getPeerAddress().toString().c_str(), pClient->getRssi());
/** Now we can read/write/subscribe the characteristics of the services we are interested in */
NimBLERemoteService* pSvc = nullptr;
NimBLERemoteCharacteristic* pChr = nullptr;
pSvc = pClient->getService(SERVICE_UUID);
if (pSvc) {
pChr = pSvc->getCharacteristic(CHARACTERISTIC_UUID);
if (pChr) {
if (pChr->canRead()) {
std::string value = pChr->readValue();
Serial.printf("Characteristic value: %s\n", value.c_str());
}
}
} else {
Serial.printf("ABCD service not found.\n");
}
NimBLEDevice::deleteClient(pClient);
Serial.printf("Done with this device!\n");
return true;
}
void setup() {
Serial.begin(115200);
Serial.printf("Starting NimBLE Client\n");
/** Initialize NimBLE and set the device name */
NimBLEDevice::init("NimBLE Extended Client");
/** Create aNimBLE Scan instance and set the callbacks for scan events */
NimBLEScan* pScan = NimBLEDevice::getScan();
pScan->setScanCallbacks(&scanCallbacks);
/** Set scan interval (how often) and window (how long) in milliseconds */
pScan->setInterval(97);
pScan->setWindow(67);
/**
* Active scan will gather scan response data from advertisers
* but will use more energy from both devices
*/
pScan->setActiveScan(true);
/**
* Start scanning for advertisers for the scan time specified (in milliseconds) 0 = forever
* Optional callback for when scanning stops.
*/
pScan->start(scanTime);
Serial.printf("Scanning for peripherals\n");
}
void loop() {
/** Loop here until we find a device we want to connect to */
if (doConnect) {
if (connectToServer()) {
Serial.printf("Success!, scanning for more!\n");
} else {
Serial.printf("Failed to connect, starting scan\n");
}
doConnect = false;
NimBLEDevice::getScan()->start(scanTime);
}
delay(10);
}
+24 -1
View File
@@ -12,6 +12,10 @@ platform = espressif32
framework = arduino framework = arduino
board = esp32-solo1 board = esp32-solo1
build_flags = -DLED_BUILTIN=2 build_flags = -DLED_BUILTIN=2
lib_ignore = wifi
spiffs
NetworkClientSecure
custom_component_remove = custom_component_remove =
espressif/esp_hosted espressif/esp_hosted
espressif/esp_wifi_remote espressif/esp_wifi_remote
@@ -31,6 +35,9 @@ platform = espressif32
framework = arduino framework = arduino
board = esp32-c2-devkitm-1 board = esp32-c2-devkitm-1
monitor_speed = 115200 monitor_speed = 115200
lib_ignore = wifi
spiffs
NetworkClientSecure
custom_component_remove = espressif/esp_hosted custom_component_remove = espressif/esp_hosted
espressif/esp_wifi_remote espressif/esp_wifi_remote
espressif/esp-dsp espressif/esp-dsp
@@ -43,12 +50,16 @@ custom_component_remove = espressif/esp_hosted
espressif/esp_diagnostics espressif/esp_diagnostics
espressif/esp_rainmaker espressif/esp_rainmaker
espressif/rmaker_common espressif/rmaker_common
custom_component_add = espressif/cmake_utilities @ 0.*
[env:esp32-s3-arduino_nano_esp32] [env:esp32-s3-arduino_nano_esp32]
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = arduino_nano_esp32 board = arduino_nano_esp32
monitor_speed = 115200 monitor_speed = 115200
lib_ignore = wifi
spiffs
NetworkClientSecure
custom_component_remove = espressif/esp_hosted custom_component_remove = espressif/esp_hosted
espressif/esp_wifi_remote espressif/esp_wifi_remote
espressif/esp-dsp espressif/esp-dsp
@@ -67,6 +78,9 @@ custom_component_remove = espressif/esp_hosted
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = esp32s3_120_16_8-qio_opi board = esp32s3_120_16_8-qio_opi
lib_ignore =
spiffs
NetworkClientSecure
custom_sdkconfig = CONFIG_SPIRAM_MODE_OCT=y custom_sdkconfig = CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_120M=y CONFIG_SPIRAM_SPEED_120M=y
CONFIG_LCD_RGB_ISR_IRAM_SAFE=y CONFIG_LCD_RGB_ISR_IRAM_SAFE=y
@@ -87,13 +101,16 @@ custom_component_remove = espressif/esp_hosted
espressif/esp_diagnostics espressif/esp_diagnostics
espressif/esp_rainmaker espressif/esp_rainmaker
espressif/rmaker_common espressif/rmaker_common
custom_component_add = lvgl/lvgl @ ^9.2.2
[env:esp32-c6-devkitc-1] [env:esp32-c6-devkitc-1]
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
build_type = debug
board = esp32-c6-devkitc-1 board = esp32-c6-devkitc-1
monitor_speed = 115200 monitor_speed = 115200
lib_ignore = wifi
spiffs
NetworkClientSecure
custom_component_remove = espressif/esp_hosted custom_component_remove = espressif/esp_hosted
espressif/esp_wifi_remote espressif/esp_wifi_remote
espressif/mdns espressif/mdns
@@ -106,6 +123,9 @@ platform = espressif32
framework = arduino framework = arduino
board = esp32-h2-devkitm-1 board = esp32-h2-devkitm-1
monitor_speed = 115200 monitor_speed = 115200
lib_ignore =
spiffs
NetworkClientSecure
custom_component_remove = espressif/esp_hosted custom_component_remove = espressif/esp_hosted
espressif/esp_wifi_remote espressif/esp_wifi_remote
espressif/mdns espressif/mdns
@@ -118,6 +138,9 @@ platform = espressif32
framework = arduino framework = arduino
board = esp32-p4 board = esp32-p4
build_flags = -DLED_BUILTIN=2 build_flags = -DLED_BUILTIN=2
lib_ignore = wifi
spiffs
NetworkClientSecure
monitor_speed = 115200 monitor_speed = 115200
custom_component_remove = espressif/esp_hosted custom_component_remove = espressif/esp_hosted
espressif/esp_wifi_remote espressif/esp_wifi_remote
+12
View File
@@ -2,6 +2,9 @@
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = esp32-s2-saola-1 board = esp32-s2-saola-1
lib_ignore = wifi
spiffs
NetworkClientSecure
build_flags = -DBUILTIN_RGBLED_PIN=18 build_flags = -DBUILTIN_RGBLED_PIN=18
-DNR_OF_LEDS=1 -DNR_OF_LEDS=1
@@ -9,6 +12,9 @@ build_flags = -DBUILTIN_RGBLED_PIN=18
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
lib_ignore = wifi
spiffs
NetworkClientSecure
build_flags = -DBUILTIN_RGBLED_PIN=48 build_flags = -DBUILTIN_RGBLED_PIN=48
-DNR_OF_LEDS=1 -DNR_OF_LEDS=1
@@ -16,6 +22,9 @@ build_flags = -DBUILTIN_RGBLED_PIN=48
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = esp32-c3-devkitm-1 board = esp32-c3-devkitm-1
lib_ignore = wifi
spiffs
NetworkClientSecure
build_flags = -DBUILTIN_RGBLED_PIN=8 build_flags = -DBUILTIN_RGBLED_PIN=8
-DNR_OF_LEDS=1 -DNR_OF_LEDS=1
@@ -23,5 +32,8 @@ build_flags = -DBUILTIN_RGBLED_PIN=8
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = esp32-c6-devkitm-1 board = esp32-c6-devkitm-1
lib_ignore = wifi
spiffs
NetworkClientSecure
build_flags = -DBUILTIN_RGBLED_PIN=8 build_flags = -DBUILTIN_RGBLED_PIN=8
-DNR_OF_LEDS=1 -DNR_OF_LEDS=1
+48
View File
@@ -12,3 +12,51 @@ platform = espressif32
framework = arduino framework = arduino
board = esp-wrover-kit board = esp-wrover-kit
monitor_speed = 115200 monitor_speed = 115200
[env:esp32-s2]
platform = espressif32
framework = arduino
board = esp32-s2-saola-1
upload_protocol = esp-prog
monitor_speed = 115200
check_tool = clangtidy
[env:esp32-s3]
platform = espressif32
framework = arduino
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
monitor_speed = 115200
check_tool = cppcheck
[env:esp32-c2]
platform = espressif32
framework = arduino
board = esp32-c2-devkitm-1
upload_protocol = esp-prog
monitor_speed = 115200
check_tool = clangtidy
custom_component_remove =
espressif/esp-dsp
espressif/network_provisioning
espressif/esp-zboss-lib
espressif/esp-zigbee-lib
espressif/esp_rainmaker
espressif/esp-sr
espressif/esp-modbus
espressif/esp32-camera
[env:esp32-c3]
platform = espressif32
framework = arduino
board = esp32-c3-devkitm-1
upload_protocol = esp-builtin
monitor_speed = 115200
check_tool = pvs-studio
[env:esp32-c6]
platform = espressif32
framework = arduino
board = esp32-c6-devkitm-1
upload_protocol = esp-builtin
monitor_speed = 115200
@@ -1,2 +0,0 @@
.pio
.vscode
@@ -1,4 +0,0 @@
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_definitions(ARDUINO_ARCH_ESP32=1)
project(Arduino_IDF_BLE_scan)
@@ -1,7 +0,0 @@
# Arduino_IDF_BLE_scan example using 3rd party NimBLE stack
BLE scan example, using the great h2zero NimBLE implementation. The needed NimBLE lib is loaded via the IDF component manager -> `idf_component.yml`.
Mandantory not to forget to switch Arduino included BLE libs.
Done in `sdkconfig.defaults`
Thx @h2zero for the great BLE library.
@@ -1,27 +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
[env]
platform = espressif32
framework = arduino, espidf
monitor_speed = 115200
board_build.embed_txtfiles =
managed_components/espressif__esp_insights/server_certs/https_server.crt
managed_components/espressif__esp_rainmaker/server_certs/rmaker_mqtt_server.crt
managed_components/espressif__esp_rainmaker/server_certs/rmaker_claim_service_server.crt
managed_components/espressif__esp_rainmaker/server_certs/rmaker_ota_server.crt
lib_ignore =
BLE
BluetoothSerial
SimpleBLE
WiFiProv
[env:esp32]
board = esp32dev
@@ -1,34 +0,0 @@
# CONFIG_AUTOSTART_ARDUINO is not set
# CONFIG_WS2812_LED_ENABLE is not set
CONFIG_FREERTOS_HZ=1000
CONFIG_MBEDTLS_PSK_MODES=y
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
# Override some defaults so BT stack is enabled
# in this example
#
# BT config
#
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=n
CONFIG_BT_NIMBLE_ENABLED=y
#
# Arduino Configuration
#
#
# Disable all Arduino included BLE libraries
#
CONFIG_ARDUINO_SELECTIVE_COMPILATION=y
# CONFIG_ARDUINO_SELECTIVE_WiFiProv is not set
# CONFIG_ARDUINO_SELECTIVE_BLE is not set
# CONFIG_ARDUINO_SELECTIVE_BluetoothSerial is not set
# CONFIG_ARDUINO_SELECTIVE_SimpleBLE is not set
# end of Arduino Configuration
@@ -1,6 +0,0 @@
# This file was automatically generated for projects
# without default 'CMakeLists.txt' file.
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
idf_component_register(SRCS ${app_sources})
@@ -1,41 +0,0 @@
dependencies:
# Required IDF version
idf: ">=4.4"
esp-nimble-cpp:
git: https://github.com/h2zero/esp-nimble-cpp.git
version: 877a29a8b1d0022c5e8f67ba8b879316e67b6c3d
# # Defining a dependency from the registry:
# # https://components.espressif.com/component/example/cmp
# example/cmp: "^3.3.3" # Automatically update minor releases
#
# # Other ways to define dependencies
#
# # For components maintained by Espressif only name can be used.
# # Same as `espressif/cmp`
# component: "~1.0.0" # Automatically update bugfix releases
#
# # Or in a longer form with extra parameters
# component2:
# version: ">=2.0.0"
#
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect for the `main` component.
# # All dependencies of `main` are public by default.
# public: true
#
# # For components hosted on non-default registry:
# service_url: "https://componentregistry.company.com"
#
# # For components in git repository:
# test_component:
# path: test_component
# git: ssh://git@gitlab.com/user/components.git
#
# # For test projects during component development
# # components can be used from a local directory
# # with relative or absolute path
# some_local_component:
# path: ../../projects/component
@@ -1,54 +0,0 @@
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
Ported to Arduino ESP32 by Evandro Copercini
Refactored back to IDF by H2zero
*/
/** NimBLE differences highlighted in comment blocks **/
/*******original********
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
***********************/
#include <Arduino.h>
#include <NimBLEDevice.h>
extern "C"{void app_main(void);}
int scanTime = 5 * 1000; // In milliseconds, 0 = scan forever
BLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice* advertisedDevice) {
printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
}
};
void scanTask (void * parameter){
for(;;) {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->getResults(scanTime, false);
printf("Devices found: %d\n", foundDevices.getCount());
printf("Scan done!\n");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
vTaskDelay(2000/portTICK_PERIOD_MS); // Delay a second between loops.
}
vTaskDelete(NULL);
}
void app_main(void) {
printf("Scanning...\n");
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setScanCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // less or equal setInterval value
xTaskCreate(scanTask, "scanTask", 5000, NULL, 1, NULL);
}
@@ -1,10 +1,14 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16.0) cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(PROJECT_VER "1.0") set(PROJECT_VER "1.0")
set(PROJECT_VER_NUMBER 1) set(PROJECT_VER_NUMBER 1)
project(matter-light) # This should be done before using the IDF_TARGET variable.
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(espidf_arduino_matter_light)
# WARNING: This is just an example for using key for decrypting the encrypted OTA image # WARNING: This is just an example for using key for decrypting the encrypted OTA image
# Please do not use it as is. # Please do not use it as is.
@@ -16,8 +20,8 @@ if(CONFIG_IDF_TARGET_ESP32C2)
include(relinker) include(relinker)
endif() endif()
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H" APPEND) idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++2a;-Os;-DCHIP_HAVE_CONFIG_H" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND) idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND)
# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various # For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various
# flags that depend on -Wformat # flags that depend on -Wformat
idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND) idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND)
+9 -12
View File
@@ -1,14 +1,12 @@
| Supported Targets | ESP32-S3 | ESP32-C3 | ESP32-C6 | | Supported Targets | ESP32-C3 | ESP32-C6 |
| ----------------- | -------- | -------- | -------- | | ----------------- | -------- | -------- |
# Managed Component Light # Managed Component Light
This example is configured by default to work with the ESP32-S3, which has the RGB LED GPIO set as pin 48 and the BOOT button on GPIO 0. This example is configured by default to work with the ESP32-C6, which has the RGB LED GPIO set as pin 8 and the BOOT button on GPIO 9.
This example creates a Color Temperature Light device using the esp_matter component downloaded from the [Espressif Component Registry](https://components.espressif.com/) instead of an extra component locally, so the example can work without setting up the esp-matter environment. This example creates a Color Temperature Light device using the esp_matter component automatically downloaded from the [Espressif Component Registry](https://components.espressif.com/). See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about matter.
See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware.
The code is based on the Arduino API and uses Arduino as an IDF Component. The code is based on the Arduino API and uses Arduino as an IDF Component.
@@ -27,8 +25,8 @@ There is no QR Code to be used when the Smartphone APP wants to add the Matter D
Please enter the code manually: `34970112332` Please enter the code manually: `34970112332`
The devboard has a built-in LED that will be used as the Matter Light. The devboard has a built-in LED that will be used as the Matter Light.
The default setting of the code uses pin 48 for the ESP32-S3. The default setting of the code uses pin 8 for the ESP32-C6,
Please change it in `main/matter_accessory_driver.h` or in the `sdkconfig.defaults.<SOC>` file. Please change it in `main/matter_accessory_driver.h` or in the `sdkconfig.defaults` file.
## LED Status and Factory Mode ## LED Status and Factory Mode
@@ -53,10 +51,9 @@ Holding the BOOT button pressed for more than 10 seconds and then releasing it w
## Building the Application using WiFi and Matter ## Building the Application using WiFi and Matter
Use ESP-IDF 5.1.4 from https://github.com/espressif/esp-idf/tree/release/v5.1 This example has been tested with Arduino Core 3.2.0. It should work with newer versions too.
This example has been tested with Arduino Core 3.0.4
There is a configuration file for these SoC: esp32s3, esp32c3, esp32c6. There is a configuration file for these SoCs: esp32c3, esp32c6.
Those are the tested devices that have a WS2812 RGB LED and can run BLE, WiFi and Matter. Those are the tested devices that have a WS2812 RGB LED and can run BLE, WiFi and Matter.
In case it is necessary to change the Button Pin or the REG LED Pin, please use the `menuconfig` and change the Menu Option `Light Matter Accessory` In case it is necessary to change the Button Pin or the REG LED Pin, please use the `menuconfig` and change the Menu Option `Light Matter Accessory`
@@ -64,5 +61,5 @@ In case it is necessary to change the Button Pin or the REG LED Pin, please use
## Using OpenThread with Matter ## Using OpenThread with Matter
This is possible with the ESP32-C6. This is possible with the ESP32-C6.
It is neessasy to have a Thread Border Routed in the Matter Environment. Check you matter hardware provider. It is necessary to have a Thread Border Router in the Matter Environment. Check your Matter hardware provider.
@@ -3,100 +3,40 @@ menu "Light Matter Accessory"
config BUTTON_PIN config BUTTON_PIN
int int
prompt "Button 1 GPIO" prompt "Button 1 GPIO"
default ENV_GPIO_BOOT_BUTTON default 9 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6
default 0
range -1 ENV_GPIO_IN_RANGE_MAX range -1 ENV_GPIO_IN_RANGE_MAX
help help
The GPIO pin for button that will be used to turn on/off the Matter Light. It shall be connected to a push button. It can use the BOOT button of the development board. The GPIO pin for button that will be used to turn on/off the Matter Light. It shall be connected to a push button. It can use the BOOT button of the development board.
endmenu endmenu
menu "LEDs" menu "LEDs"
config WS2812_PIN config WS2812_PIN
int int
prompt "WS2812 RGB LED GPIO" prompt "WS2812 RGB LED GPIO"
default ENV_GPIO_RGB_LED default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6
default 48
range -1 ENV_GPIO_OUT_RANGE_MAX range -1 ENV_GPIO_OUT_RANGE_MAX
help help
The GPIO pin for the Matter Light that will be driven by RMT. It shall be connected to one single WS2812 RGB LED. The GPIO pin for the Matter Light that will be driven by RMT. It shall be connected to one single WS2812 RGB LED.
endmenu endmenu
# TARGET CONFIGURATION config ENV_GPIO_RANGE_MIN
if IDF_TARGET_ESP32C3 int
config ENV_GPIO_RANGE_MIN default 0
int
default 0
config ENV_GPIO_RANGE_MAX config ENV_GPIO_RANGE_MAX
int int
default 19 default 19 if IDF_TARGET_ESP32C3
# GPIOs 20/21 are always used by UART in examples default 30 if IDF_TARGET_ESP32C6
default 48
config ENV_GPIO_IN_RANGE_MAX config ENV_GPIO_IN_RANGE_MAX
int int
default ENV_GPIO_RANGE_MAX default ENV_GPIO_RANGE_MAX
config ENV_GPIO_OUT_RANGE_MAX config ENV_GPIO_OUT_RANGE_MAX
int int
default ENV_GPIO_RANGE_MAX default ENV_GPIO_RANGE_MAX
config ENV_GPIO_BOOT_BUTTON
int
default 9
config ENV_GPIO_RGB_LED
int
default 8
endif
if IDF_TARGET_ESP32C6
config ENV_GPIO_RANGE_MIN
int
default 0
config ENV_GPIO_RANGE_MAX
int
default 30
# GPIOs 16/17 are always used by UART in examples
config ENV_GPIO_IN_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_OUT_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_BOOT_BUTTON
int
default 9
config ENV_GPIO_RGB_LED
int
default 8
endif
if IDF_TARGET_ESP32S3
config ENV_GPIO_RANGE_MIN
int
default 0
config ENV_GPIO_RANGE_MAX
int
default 48
config ENV_GPIO_IN_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_OUT_RANGE_MAX
int
default ENV_GPIO_RANGE_MAX
config ENV_GPIO_BOOT_BUTTON
int
default 0
config ENV_GPIO_RGB_LED
int
default 48
endif
endmenu endmenu
@@ -13,235 +13,225 @@
#include "builtinLED.h" #include "builtinLED.h"
typedef struct { typedef struct {
uint16_t hue; uint16_t hue;
uint8_t saturation; uint8_t saturation;
} HS_color_t; } HS_color_t;
static const HS_color_t temperatureTable[] = { static const HS_color_t temperatureTable[] = {
{4, 100}, {8, 100}, {11, 100}, {14, 100}, {16, 100}, {18, 100}, {20, 100}, {22, 100}, {24, 100}, {25, 100}, {4, 100}, {8, 100}, {11, 100}, {14, 100}, {16, 100}, {18, 100}, {20, 100}, {22, 100}, {24, 100}, {25, 100}, {27, 100}, {28, 100}, {30, 100}, {31, 100},
{27, 100}, {28, 100}, {30, 100}, {31, 100}, {31, 95}, {30, 89}, {30, 85}, {29, 80}, {29, 76}, {29, 73}, {31, 95}, {30, 89}, {30, 85}, {29, 80}, {29, 76}, {29, 73}, {29, 69}, {28, 66}, {28, 63}, {28, 60}, {28, 57}, {28, 54}, {28, 52}, {27, 49},
{29, 69}, {28, 66}, {28, 63}, {28, 60}, {28, 57}, {28, 54}, {28, 52}, {27, 49}, {27, 47}, {27, 45}, {27, 47}, {27, 45}, {27, 43}, {27, 41}, {27, 39}, {27, 37}, {27, 35}, {27, 33}, {27, 31}, {27, 30}, {27, 28}, {27, 26}, {27, 25}, {27, 23},
{27, 43}, {27, 41}, {27, 39}, {27, 37}, {27, 35}, {27, 33}, {27, 31}, {27, 30}, {27, 28}, {27, 26}, {27, 22}, {27, 21}, {27, 19}, {27, 18}, {27, 17}, {27, 15}, {28, 14}, {28, 13}, {28, 12}, {29, 10}, {29, 9}, {30, 8}, {31, 7}, {32, 6},
{27, 25}, {27, 23}, {27, 22}, {27, 21}, {27, 19}, {27, 18}, {27, 17}, {27, 15}, {28, 14}, {28, 13}, {34, 5}, {36, 4}, {41, 3}, {49, 2}, {0, 0}, {294, 2}, {265, 3}, {251, 4}, {242, 5}, {237, 6}, {233, 7}, {231, 8}, {229, 9}, {228, 10},
{28, 12}, {29, 10}, {29, 9}, {30, 8}, {31, 7}, {32, 6}, {34, 5}, {36, 4}, {41, 3}, {49, 2}, {227, 11}, {226, 11}, {226, 12}, {225, 13}, {225, 13}, {224, 14}, {224, 14}, {224, 15}, {224, 15}, {223, 16}, {223, 16}, {223, 17}, {223, 17}, {223, 17},
{0, 0}, {294, 2}, {265, 3}, {251, 4}, {242, 5}, {237, 6}, {233, 7}, {231, 8}, {229, 9}, {228, 10}, {222, 18}, {222, 18}, {222, 19}, {222, 19}, {222, 19}, {222, 19}, {222, 20}, {222, 20}, {222, 20}, {222, 21}, {222, 21}
{227, 11}, {226, 11}, {226, 12}, {225, 13}, {225, 13}, {224, 14}, {224, 14}, {224, 15}, {224, 15}, {223, 16},
{223, 16}, {223, 17}, {223, 17}, {223, 17}, {222, 18}, {222, 18}, {222, 19}, {222, 19}, {222, 19}, {222, 19},
{222, 20}, {222, 20}, {222, 20}, {222, 21}, {222, 21}
}; };
/* step brightness table: gamma = 2.3 */ /* step brightness table: gamma = 2.3 */
static const uint8_t gamma_table[MAX_PROGRESS] = { static const uint8_t gamma_table[MAX_PROGRESS] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8,
2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20,
5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 21, 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 39, 40, 40,
10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 86, 87, 88, 89, 91, 92, 93, 95, 96, 97, 99, 100, 101, 103, 104,
26, 27, 28, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37, 105, 107, 108, 110, 111, 112, 114, 115, 117, 118, 120, 121, 123, 124, 126, 128, 129, 131, 132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 149,
38, 39, 40, 40, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 150, 152, 154, 156, 157, 159, 161, 163, 164, 166, 168, 170, 172, 174, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 226, 228, 230, 232, 234, 236, 239, 241, 243, 245, 248, 250, 252, 255,
68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 86,
87, 88, 89, 91, 92, 93, 95, 96, 97, 99, 100, 101, 103, 104, 105, 107,
108, 110, 111, 112, 114, 115, 117, 118, 120, 121, 123, 124, 126, 128, 129, 131,
132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 156, 157,
159, 161, 163, 164, 166, 168, 170, 172, 174, 175, 177, 179, 181, 183, 185, 187,
189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219,
221, 223, 226, 228, 230, 232, 234, 236, 239, 241, 243, 245, 248, 250, 252, 255,
}; };
BuiltInLED::BuiltInLED() { BuiltInLED::BuiltInLED() {
pin_number = (uint8_t) -1; // no pin number pin_number = (uint8_t)-1; // no pin number
state = false; // LED is off state = false; // LED is off
hsv_color.value = 0; // black color hsv_color.value = 0; // black color
} }
BuiltInLED::~BuiltInLED(){ BuiltInLED::~BuiltInLED() {
end(); end();
} }
led_indicator_color_hsv_t BuiltInLED::rgb2hsv(led_indicator_color_rgb_t rgb) { led_indicator_color_hsv_t BuiltInLED::rgb2hsv(led_indicator_color_rgb_t rgb) {
led_indicator_color_hsv_t hsv; led_indicator_color_hsv_t hsv;
uint8_t minRGB, maxRGB; uint8_t minRGB, maxRGB;
uint8_t delta; uint8_t delta;
minRGB = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b); minRGB = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
maxRGB = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b); maxRGB = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
hsv.value = 0; hsv.value = 0;
hsv.v = maxRGB; hsv.v = maxRGB;
delta = maxRGB - minRGB; delta = maxRGB - minRGB;
if (delta == 0) { if (delta == 0) {
hsv.h = 0; hsv.h = 0;
hsv.s = 0; hsv.s = 0;
} else {
hsv.s = delta * 255 / maxRGB;
if (rgb.r == maxRGB) {
hsv.h = (60 * (rgb.g - rgb.b) / delta + 360) % 360;
} else if (rgb.g == maxRGB) {
hsv.h = (60 * (rgb.b - rgb.r) / delta + 120);
} else { } else {
hsv.s = delta * 255 / maxRGB; hsv.h = (60 * (rgb.r - rgb.g) / delta + 240);
if (rgb.r == maxRGB) {
hsv.h = (60 * (rgb.g - rgb.b) / delta + 360) % 360;
} else if (rgb.g == maxRGB) {
hsv.h = (60 * (rgb.b - rgb.r) / delta + 120);
} else {
hsv.h = (60 * (rgb.r - rgb.g) / delta + 240);
}
} }
return hsv; }
return hsv;
} }
led_indicator_color_rgb_t BuiltInLED::hsv2rgb(led_indicator_color_hsv_t hsv) { led_indicator_color_rgb_t BuiltInLED::hsv2rgb(led_indicator_color_hsv_t hsv) {
led_indicator_color_rgb_t rgb; led_indicator_color_rgb_t rgb;
uint8_t rgb_max = hsv.v; uint8_t rgb_max = hsv.v;
uint8_t rgb_min = rgb_max * (255 - hsv.s) / 255.0f; uint8_t rgb_min = rgb_max * (255 - hsv.s) / 255.0f;
uint8_t i = hsv.h / 60; uint8_t i = hsv.h / 60;
uint8_t diff = hsv.h % 60; uint8_t diff = hsv.h % 60;
// RGB adjustment amount by hue // RGB adjustment amount by hue
uint8_t rgb_adj = (rgb_max - rgb_min) * diff / 60; uint8_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
rgb.value = 0; rgb.value = 0;
switch (i) { switch (i) {
case 0: case 0:
rgb.r = rgb_max; rgb.r = rgb_max;
rgb.g = rgb_min + rgb_adj; rgb.g = rgb_min + rgb_adj;
rgb.b = rgb_min; rgb.b = rgb_min;
break; break;
case 1: case 1:
rgb.r = rgb_max - rgb_adj; rgb.r = rgb_max - rgb_adj;
rgb.g = rgb_max; rgb.g = rgb_max;
rgb.b = rgb_min; rgb.b = rgb_min;
break; break;
case 2: case 2:
rgb.r = rgb_min; rgb.r = rgb_min;
rgb.g = rgb_max; rgb.g = rgb_max;
rgb.b = rgb_min + rgb_adj; rgb.b = rgb_min + rgb_adj;
break; break;
case 3: case 3:
rgb.r = rgb_min; rgb.r = rgb_min;
rgb.g = rgb_max - rgb_adj; rgb.g = rgb_max - rgb_adj;
rgb.b = rgb_max; rgb.b = rgb_max;
break; break;
case 4: case 4:
rgb.r = rgb_min + rgb_adj; rgb.r = rgb_min + rgb_adj;
rgb.g = rgb_min; rgb.g = rgb_min;
rgb.b = rgb_max; rgb.b = rgb_max;
break; break;
default: default:
rgb.r = rgb_max; rgb.r = rgb_max;
rgb.g = rgb_min; rgb.g = rgb_min;
rgb.b = rgb_max - rgb_adj; rgb.b = rgb_max - rgb_adj;
break; break;
} }
// gamma correction // gamma correction
rgb.r = gamma_table[rgb.r]; rgb.r = gamma_table[rgb.r];
rgb.g = gamma_table[rgb.g]; rgb.g = gamma_table[rgb.g];
rgb.b = gamma_table[rgb.b]; rgb.b = gamma_table[rgb.b];
return rgb; return rgb;
} }
void BuiltInLED::begin(uint8_t pin){ void BuiltInLED::begin(uint8_t pin) {
if (pin < NUM_DIGITAL_PINS) { if (pin < NUM_DIGITAL_PINS) {
pin_number = pin; pin_number = pin;
log_i("Initializing pin %d", pin); log_i("Initializing pin %d", pin);
} else {
log_e("Invalid pin (%d) number", pin);
}
}
void BuiltInLED::end() {
state = false;
write(); // turn off the LED
if (pin_number < NUM_DIGITAL_PINS) {
if (!rmtDeinit(pin_number)) {
log_e("Failed to deinitialize RMT");
}
}
}
void BuiltInLED::on() {
state = true;
}
void BuiltInLED::off() {
state = false;
}
void BuiltInLED::toggle() {
state = !state;
}
bool BuiltInLED::getState() {
return state;
}
bool BuiltInLED::write() {
led_indicator_color_rgb_t rgb_color = getRGB();
log_d("Writing to pin %d with state = %s", pin_number, state ? "ON" : "OFF");
log_d("HSV: %d, %d, %d", hsv_color.h, hsv_color.s, hsv_color.v);
log_d("RGB: %d, %d, %d", rgb_color.r, rgb_color.g, rgb_color.b);
if (pin_number < NUM_DIGITAL_PINS) {
if (state) {
rgbLedWrite(pin_number, rgb_color.r, rgb_color.g, rgb_color.b);
} else { } else {
log_e("Invalid pin (%d) number", pin); rgbLedWrite(pin_number, 0, 0, 0);
}
}
void BuiltInLED::end(){
state = false;
write(); // turn off the LED
if (pin_number < NUM_DIGITAL_PINS) {
if (!rmtDeinit(pin_number)) {
log_e("Failed to deinitialize RMT");
}
} }
return true;
} else {
log_e("Invalid pin (%d) number", pin_number);
return false;
}
} }
void BuiltInLED::on(){ void BuiltInLED::setBrightness(uint8_t brightness) {
state = true; hsv_color.v = brightness;
} }
void BuiltInLED::off(){ uint8_t BuiltInLED::getBrightness() {
state = false; return hsv_color.v;
} }
void BuiltInLED::toggle(){ void BuiltInLED::setHSV(led_indicator_color_hsv_t hsv) {
state = !state; if (hsv.h > MAX_HUE) {
hsv.h = MAX_HUE;
}
hsv_color.value = hsv.value;
} }
bool BuiltInLED::getState(){ led_indicator_color_hsv_t BuiltInLED::getHSV() {
return state; return hsv_color;
} }
bool BuiltInLED::write(){ void BuiltInLED::setRGB(led_indicator_color_rgb_t rgb_color) {
led_indicator_color_rgb_t rgb_color = getRGB(); hsv_color = rgb2hsv(rgb_color);
log_d("Writing to pin %d with state = %s", pin_number, state ? "ON" : "OFF"); }
log_d("HSV: %d, %d, %d", hsv_color.h, hsv_color.s, hsv_color.v);
log_d("RGB: %d, %d, %d", rgb_color.r, rgb_color.g, rgb_color.b); led_indicator_color_rgb_t BuiltInLED::getRGB() {
if(pin_number < NUM_DIGITAL_PINS){ return hsv2rgb(hsv_color);
if (state) { }
rgbLedWrite(pin_number, rgb_color.r, rgb_color.g, rgb_color.b);
} else { void BuiltInLED::setTemperature(uint32_t temperature) {
rgbLedWrite(pin_number, 0, 0, 0); uint16_t hue;
} uint8_t saturation;
return true;
log_d("Requested Temperature: %ld", temperature);
//hsv_color.v = gamma_table[((temperature >> 25) & 0x7F)];
temperature &= 0xFFFFFF;
if (temperature < 600) {
hue = 0;
saturation = 100;
} else {
if (temperature > 10000) {
hue = 222;
saturation = 21 + (temperature - 10000) * 41 / 990000;
} else { } else {
log_e("Invalid pin (%d) number", pin_number); temperature -= 600;
return false; temperature /= 100;
hue = temperatureTable[temperature].hue;
saturation = temperatureTable[temperature].saturation;
} }
}
saturation = (saturation * 255) / 100;
// brightness is not changed
hsv_color.h = hue;
hsv_color.s = saturation;
log_d("Calculated Temperature: %ld, Hue: %d, Saturation: %d, Brightness: %d", temperature, hue, saturation, hsv_color.v);
} }
void BuiltInLED::setBrightness(uint8_t brightness){
hsv_color.v = brightness;
}
uint8_t BuiltInLED::getBrightness(){
return hsv_color.v;
}
void BuiltInLED::setHSV(led_indicator_color_hsv_t hsv){
if (hsv.h > MAX_HUE) {
hsv.h = MAX_HUE;
}
hsv_color.value = hsv.value;
}
led_indicator_color_hsv_t BuiltInLED::getHSV(){
return hsv_color;
}
void BuiltInLED::setRGB(led_indicator_color_rgb_t rgb_color){
hsv_color = rgb2hsv(rgb_color);
}
led_indicator_color_rgb_t BuiltInLED::getRGB(){
return hsv2rgb(hsv_color);
}
void BuiltInLED::setTemperature(uint32_t temperature){
uint16_t hue;
uint8_t saturation;
log_d("Requested Temperature: %ld", temperature);
//hsv_color.v = gamma_table[((temperature >> 25) & 0x7F)];
temperature &= 0xFFFFFF;
if (temperature < 600) {
hue = 0;
saturation = 100;
} else {
if (temperature > 10000) {
hue = 222;
saturation = 21 + (temperature - 10000) * 41 / 990000;
} else {
temperature -= 600;
temperature /= 100;
hue = temperatureTable[temperature].hue;
saturation = temperatureTable[temperature].saturation;
}
}
saturation = (saturation * 255) / 100;
// brightness is not changed
hsv_color.h = hue;
hsv_color.s = saturation;
log_d("Calculated Temperature: %ld, Hue: %d, Saturation: %d, Brightness: %d", temperature, hue, saturation, hsv_color.v);
}
@@ -14,61 +14,61 @@
#include <Arduino.h> #include <Arduino.h>
#define MAX_HUE 360 #define MAX_HUE 360
#define MAX_SATURATION 255 #define MAX_SATURATION 255
#define MAX_BRIGHTNESS 255 #define MAX_BRIGHTNESS 255
#define MAX_PROGRESS 256 #define MAX_PROGRESS 256
typedef struct { typedef struct {
union { union {
struct { struct {
uint32_t v: 8; /*!< Brightness/Value of the LED. 0-255 */ uint32_t v : 8; /*!< Brightness/Value of the LED. 0-255 */
uint32_t s: 8; /*!< Saturation of the LED. 0-255 */ uint32_t s : 8; /*!< Saturation of the LED. 0-255 */
uint32_t h: 9; /*!< Hue of the LED. 0-360 */ uint32_t h : 9; /*!< Hue of the LED. 0-360 */
};
uint32_t value; /*!< IHSV value of the LED. */
}; };
uint32_t value; /*!< IHSV value of the LED. */
};
} led_indicator_color_hsv_t; } led_indicator_color_hsv_t;
typedef struct { typedef struct {
union { union {
struct { struct {
uint32_t r: 8; /*!< Red component of the LED color. Range: 0-255. */ uint32_t r : 8; /*!< Red component of the LED color. Range: 0-255. */
uint32_t g: 8; /*!< Green component of the LED color. Range: 0-255. */ uint32_t g : 8; /*!< Green component of the LED color. Range: 0-255. */
uint32_t b: 8; /*!< Blue component of the LED color. Range: 0-255. */ uint32_t b : 8; /*!< Blue component of the LED color. Range: 0-255. */
};
uint32_t value; /*!< Combined RGB value of the LED color. */
}; };
uint32_t value; /*!< Combined RGB value of the LED color. */
};
} led_indicator_color_rgb_t; } led_indicator_color_rgb_t;
class BuiltInLED { class BuiltInLED {
private: private:
uint8_t pin_number; uint8_t pin_number;
bool state; bool state;
led_indicator_color_hsv_t hsv_color; led_indicator_color_hsv_t hsv_color;
public: public:
BuiltInLED(); BuiltInLED();
~BuiltInLED(); ~BuiltInLED();
static led_indicator_color_hsv_t rgb2hsv(led_indicator_color_rgb_t rgb_value); static led_indicator_color_hsv_t rgb2hsv(led_indicator_color_rgb_t rgb_value);
static led_indicator_color_rgb_t hsv2rgb(led_indicator_color_hsv_t hsv); static led_indicator_color_rgb_t hsv2rgb(led_indicator_color_hsv_t hsv);
void begin(uint8_t pin); void begin(uint8_t pin);
void end(); void end();
void on(); void on();
void off(); void off();
void toggle(); void toggle();
bool getState(); bool getState();
bool write(); bool write();
void setBrightness(uint8_t brightness); void setBrightness(uint8_t brightness);
uint8_t getBrightness(); uint8_t getBrightness();
void setHSV(led_indicator_color_hsv_t hsv); void setHSV(led_indicator_color_hsv_t hsv);
led_indicator_color_hsv_t getHSV(); led_indicator_color_hsv_t getHSV();
void setRGB(led_indicator_color_rgb_t color); void setRGB(led_indicator_color_rgb_t color);
led_indicator_color_rgb_t getRGB(); led_indicator_color_rgb_t getRGB();
void setTemperature(uint32_t temperature); void setTemperature(uint32_t temperature);
}; };
@@ -1,6 +1,6 @@
dependencies: dependencies:
espressif/esp_matter: espressif/esp_matter:
version: "^1.3.0" version: ">=1.4.0"
espressif/cmake_utilities: espressif/cmake_utilities:
version: "0.*" version: "0.*"
rules: rules:
@@ -11,85 +11,79 @@
#include "matter_accessory_driver.h" #include "matter_accessory_driver.h"
/* Do any conversions/remapping for the actual value here */ /* Do any conversions/remapping for the actual value here */
esp_err_t light_accessory_set_power(void *led, uint8_t val) esp_err_t light_accessory_set_power(void *led, uint8_t val) {
{ BuiltInLED *builtinLED = (BuiltInLED *)led;
BuiltInLED *builtinLED = (BuiltInLED *) led; esp_err_t err = ESP_OK;
esp_err_t err = ESP_OK; if (val) {
if (val) { builtinLED->on();
builtinLED->on(); } else {
} else { builtinLED->off();
builtinLED->off(); }
} if (!builtinLED->write()) {
if (!builtinLED->write()) { err = ESP_FAIL;
err = ESP_FAIL; }
} log_i("LED set power: %d", val);
log_i("LED set power: %d", val); return err;
return err;
} }
esp_err_t light_accessory_set_brightness(void *led, uint8_t val) esp_err_t light_accessory_set_brightness(void *led, uint8_t val) {
{ esp_err_t err = ESP_OK;
esp_err_t err = ESP_OK; BuiltInLED *builtinLED = (BuiltInLED *)led;
BuiltInLED *builtinLED = (BuiltInLED *) led; int value = REMAP_TO_RANGE(val, MATTER_BRIGHTNESS, STANDARD_BRIGHTNESS);
int value = REMAP_TO_RANGE(val, MATTER_BRIGHTNESS, STANDARD_BRIGHTNESS);
builtinLED->setBrightness(value); builtinLED->setBrightness(value);
if (!builtinLED->write()) { if (!builtinLED->write()) {
err = ESP_FAIL; err = ESP_FAIL;
} }
log_i("LED set brightness: %d", value); log_i("LED set brightness: %d", value);
return err; return err;
} }
esp_err_t light_accessory_set_hue(void *led, uint8_t val) esp_err_t light_accessory_set_hue(void *led, uint8_t val) {
{ esp_err_t err = ESP_OK;
esp_err_t err = ESP_OK; BuiltInLED *builtinLED = (BuiltInLED *)led;
BuiltInLED *builtinLED = (BuiltInLED *) led; int value = REMAP_TO_RANGE(val, MATTER_HUE, STANDARD_HUE);
int value = REMAP_TO_RANGE(val, MATTER_HUE, STANDARD_HUE); led_indicator_color_hsv_t hsv = builtinLED->getHSV();
led_indicator_color_hsv_t hsv = builtinLED->getHSV(); hsv.h = value;
hsv.h = value; builtinLED->setHSV(hsv);
builtinLED->setHSV(hsv); if (!builtinLED->write()) {
if (!builtinLED->write()) { err = ESP_FAIL;
err = ESP_FAIL; }
} log_i("LED set hue: %d", value);
log_i("LED set hue: %d", value); return err;
return err;
} }
esp_err_t light_accessory_set_saturation(void *led, uint8_t val) esp_err_t light_accessory_set_saturation(void *led, uint8_t val) {
{ esp_err_t err = ESP_OK;
esp_err_t err = ESP_OK; BuiltInLED *builtinLED = (BuiltInLED *)led;
BuiltInLED *builtinLED = (BuiltInLED *) led; int value = REMAP_TO_RANGE(val, MATTER_SATURATION, STANDARD_SATURATION);
int value = REMAP_TO_RANGE(val, MATTER_SATURATION, STANDARD_SATURATION); led_indicator_color_hsv_t hsv = builtinLED->getHSV();
led_indicator_color_hsv_t hsv = builtinLED->getHSV(); hsv.s = value;
hsv.s = value; builtinLED->setHSV(hsv);
builtinLED->setHSV(hsv); if (!builtinLED->write()) {
if (!builtinLED->write()) { err = ESP_FAIL;
err = ESP_FAIL; }
} log_i("LED set saturation: %d", value);
log_i("LED set saturation: %d", value); return err;
return err;
} }
esp_err_t light_accessory_set_temperature(void *led, uint16_t val) esp_err_t light_accessory_set_temperature(void *led, uint16_t val) {
{ esp_err_t err = ESP_OK;
esp_err_t err = ESP_OK; BuiltInLED *builtinLED = (BuiltInLED *)led;
BuiltInLED *builtinLED = (BuiltInLED *) led; uint32_t value = REMAP_TO_RANGE_INVERSE(val, STANDARD_TEMPERATURE_FACTOR);
uint32_t value = REMAP_TO_RANGE_INVERSE(val, STANDARD_TEMPERATURE_FACTOR); builtinLED->setTemperature(value);
builtinLED->setTemperature(value); if (!builtinLED->write()) {
if (!builtinLED->write()) { err = ESP_FAIL;
err = ESP_FAIL; }
} log_i("LED set temperature: %ld", value);
log_i("LED set temperature: %ld", value); return err;
return err;
} }
app_driver_handle_t light_accessory_init() app_driver_handle_t light_accessory_init() {
{ /* Initialize led */
/* Initialize led */ static BuiltInLED builtinLED;
static BuiltInLED builtinLED;
const uint8_t pin = WS2812_PIN; // set your board WS2812b pin here const uint8_t pin = WS2812_PIN; // set your board WS2812b pin here
builtinLED.begin(pin); builtinLED.begin(pin);
return (app_driver_handle_t) &builtinLED; return (app_driver_handle_t)&builtinLED;
} }
@@ -3,9 +3,9 @@
// set your board WS2812b pin here (e.g. 48 is the default pin for the ESP32-S3 devkit) // set your board WS2812b pin here (e.g. 48 is the default pin for the ESP32-S3 devkit)
#ifndef CONFIG_WS2812_PIN #ifndef CONFIG_WS2812_PIN
#define WS2812_PIN 48 // ESP32-S3 DevKitC built-in LED #define WS2812_PIN 48 // ESP32-S3 DevKitC built-in LED
#else #else
#define WS2812_PIN CONFIG_WS2812_PIN // From sdkconfig.defaults.<soc> #define WS2812_PIN CONFIG_WS2812_PIN // From sdkconfig.defaults.<soc>
#endif #endif
#ifndef RGB_BUILTIN #ifndef RGB_BUILTIN
@@ -14,34 +14,34 @@
// Set your board button pin here (e.g. 0 is the default pin for the ESP32-S3 devkit) // Set your board button pin here (e.g. 0 is the default pin for the ESP32-S3 devkit)
#ifndef CONFIG_BUTTON_PIN #ifndef CONFIG_BUTTON_PIN
#define BUTTON_PIN 0 // ESP32-S3 DevKitC built-in button #define BUTTON_PIN 0 // ESP32-S3 DevKitC built-in button
#else #else
#define BUTTON_PIN CONFIG_BUTTON_PIN // From sdkconfig.defaults.<soc> #define BUTTON_PIN CONFIG_BUTTON_PIN // From sdkconfig.defaults.<soc>
#endif #endif
/** Standard max values (used for remapping attributes) */ /** Standard max values (used for remapping attributes) */
#define STANDARD_BRIGHTNESS 255 #define STANDARD_BRIGHTNESS 255
#define STANDARD_HUE 360 #define STANDARD_HUE 360
#define STANDARD_SATURATION 255 #define STANDARD_SATURATION 255
#define STANDARD_TEMPERATURE_FACTOR 1000000 #define STANDARD_TEMPERATURE_FACTOR 1000000
/** Matter max values (used for remapping attributes) */ /** Matter max values (used for remapping attributes) */
#define MATTER_BRIGHTNESS 254 #define MATTER_BRIGHTNESS 254
#define MATTER_HUE 254 #define MATTER_HUE 254
#define MATTER_SATURATION 254 #define MATTER_SATURATION 254
#define MATTER_TEMPERATURE_FACTOR 1000000 #define MATTER_TEMPERATURE_FACTOR 1000000
/** Default attribute values used during initialization */ /** Default attribute values used during initialization */
#define DEFAULT_POWER true #define DEFAULT_POWER true
#define DEFAULT_BRIGHTNESS 64 #define DEFAULT_BRIGHTNESS 64
#define DEFAULT_HUE 128 #define DEFAULT_HUE 128
#define DEFAULT_SATURATION 254 #define DEFAULT_SATURATION 254
typedef void *app_driver_handle_t; typedef void *app_driver_handle_t;
esp_err_t light_accessory_set_power(void *led, uint8_t val); esp_err_t light_accessory_set_power(void *led, uint8_t val);
esp_err_t light_accessory_set_brightness(void *led, uint8_t val); esp_err_t light_accessory_set_brightness(void *led, uint8_t val);
esp_err_t light_accessory_set_hue(void *led, uint8_t val); esp_err_t light_accessory_set_hue(void *led, uint8_t val);
esp_err_t light_accessory_set_saturation(void *led, uint8_t val); esp_err_t light_accessory_set_saturation(void *led, uint8_t val);
esp_err_t light_accessory_set_temperature(void *led, uint16_t val); esp_err_t light_accessory_set_temperature(void *led, uint16_t val);
app_driver_handle_t light_accessory_init(); app_driver_handle_t light_accessory_init();
@@ -20,24 +20,18 @@
#include <platform/ESP32/OpenthreadLauncher.h> #include <platform/ESP32/OpenthreadLauncher.h>
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
{ \ { .radio_mode = RADIO_MODE_NATIVE, }
.radio_mode = RADIO_MODE_NATIVE, \
}
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \ { .host_connection_mode = HOST_CONNECTION_MODE_NONE, }
.host_connection_mode = HOST_CONNECTION_MODE_NONE, \
}
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \ { .storage_partition_name = "nvs", .netif_queue_size = 10, .task_queue_size = 10, }
.storage_partition_name = "nvs", .netif_queue_size = 10, .task_queue_size = 10, \
}
#endif #endif
// set your board button pin here // set your board button pin here
const uint8_t button_gpio = BUTTON_PIN; // GPIO BOOT Button const uint8_t button_gpio = BUTTON_PIN; // GPIO BOOT Button
uint16_t light_endpoint_id = 0; uint16_t light_endpoint_id = 0;
@@ -54,290 +48,259 @@ extern const char decryption_key_end[] asm("_binary_esp_image_encryption_key_pem
static const char *s_decryption_key = decryption_key_start; static const char *s_decryption_key = decryption_key_start;
static const uint16_t s_decryption_key_len = decryption_key_end - decryption_key_start; static const uint16_t s_decryption_key_len = decryption_key_end - decryption_key_start;
#endif // CONFIG_ENABLE_ENCRYPTED_OTA #endif // CONFIG_ENABLE_ENCRYPTED_OTA
bool isAccessoryCommissioned() { bool isAccessoryCommissioned() {
return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0; return chip::Server::GetInstance().GetFabricTable().FabricCount() > 0;
} }
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
bool isWifiConnected() { bool isWifiConnected() {
return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected(); return chip::DeviceLayer::ConnectivityMgr().IsWiFiStationConnected();
} }
#endif #endif
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
bool isThreadConnected() { bool isThreadConnected() {
return chip::DeviceLayer::ConnectivityMgr().IsThreadAttached(); return chip::DeviceLayer::ConnectivityMgr().IsThreadAttached();
} }
#endif #endif
static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) {
{ switch (event->Type) {
switch (event->Type) {
case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged: case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged:
log_i("Interface %s Address changed", log_i(
event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned ? "Interface %s Address changed", event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned ? "IPv4" : "IPV6"
"IPv4" : "IPV6" ); );
break; break;
case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: case chip::DeviceLayer::DeviceEventType::kCommissioningComplete: log_i("Commissioning complete"); break;
log_i("Commissioning complete");
break;
case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired: log_i("Commissioning failed, fail safe timer expired"); break;
log_i("Commissioning failed, fail safe timer expired");
break;
case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted: log_i("Commissioning session started"); break;
log_i("Commissioning session started");
break;
case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped: log_i("Commissioning session stopped"); break;
log_i("Commissioning session stopped");
break;
case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened: log_i("Commissioning window opened"); break;
log_i("Commissioning window opened");
break;
case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed: log_i("Commissioning window closed"); break;
log_i("Commissioning window closed");
break;
case chip::DeviceLayer::DeviceEventType::kFabricRemoved: case chip::DeviceLayer::DeviceEventType::kFabricRemoved:
{ {
log_i("Fabric removed successfully"); log_i("Fabric removed successfully");
if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0) {
{ chip::CommissioningWindowManager &commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager();
chip::CommissioningWindowManager & commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager(); constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds);
constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds); if (!commissionMgr.IsCommissioningWindowOpen()) {
if (!commissionMgr.IsCommissioningWindowOpen()) /* After removing last fabric, this example does not remove the Wi-Fi credentials
{
/* After removing last fabric, this example does not remove the Wi-Fi credentials
* and still has IP connectivity so, only advertising on DNS-SD. * and still has IP connectivity so, only advertising on DNS-SD.
*/ */
CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds, CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds, chip::CommissioningWindowAdvertisement::kDnssdOnly);
chip::CommissioningWindowAdvertisement::kDnssdOnly); if (err != CHIP_NO_ERROR) {
if (err != CHIP_NO_ERROR) log_e("Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format());
{ }
log_e("Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format());
}
}
}
break;
} }
}
case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: break;
log_i("Fabric will be removed");
break;
case chip::DeviceLayer::DeviceEventType::kFabricUpdated:
log_i("Fabric is updated");
break;
case chip::DeviceLayer::DeviceEventType::kFabricCommitted:
log_i("Fabric is committed");
break;
case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized:
log_i("BLE deinitialized and memory reclaimed");
break;
default:
break;
}
}
esp_err_t matter_light_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id,
uint32_t attribute_id, esp_matter_attr_val_t *val)
{
esp_err_t err = ESP_OK;
if (endpoint_id == light_endpoint_id) {
void *led = (void *)driver_handle;
if (cluster_id == OnOff::Id) {
if (attribute_id == OnOff::Attributes::OnOff::Id) {
err = light_accessory_set_power(led, val->val.b);
}
} else if (cluster_id == LevelControl::Id) {
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
err = light_accessory_set_brightness(led, val->val.u8);
}
} else if (cluster_id == ColorControl::Id) {
if (attribute_id == ColorControl::Attributes::CurrentHue::Id) {
err = light_accessory_set_hue(led, val->val.u8);
} else if (attribute_id == ColorControl::Attributes::CurrentSaturation::Id) {
err = light_accessory_set_saturation(led, val->val.u8);
} else if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) {
err = light_accessory_set_temperature(led, val->val.u16);
}
}
}
return err;
}
esp_err_t matter_light_set_defaults(uint16_t endpoint_id)
{
esp_err_t err = ESP_OK;
void *led = endpoint::get_priv_data(endpoint_id);
node_t *node = node::get();
endpoint_t *endpoint = endpoint::get(node, endpoint_id);
cluster_t *cluster = NULL;
attribute_t *attribute = NULL;
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
/* Setting brightness */
cluster = cluster::get(endpoint, LevelControl::Id);
attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_brightness(led, val.val.u8);
/* Setting color */
cluster = cluster::get(endpoint, ColorControl::Id);
attribute = attribute::get(cluster, ColorControl::Attributes::ColorMode::Id);
attribute::get_val(attribute, &val);
if (val.val.u8 == (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation) {
/* Setting hue */
attribute = attribute::get(cluster, ColorControl::Attributes::CurrentHue::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_hue(led, val.val.u8);
/* Setting saturation */
attribute = attribute::get(cluster, ColorControl::Attributes::CurrentSaturation::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_saturation(led, val.val.u8);
} else if (val.val.u8 == (uint8_t)ColorControl::ColorMode::kColorTemperature) {
/* Setting temperature */
attribute = attribute::get(cluster, ColorControl::Attributes::ColorTemperatureMireds::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_temperature(led, val.val.u16);
} else {
log_e("Color mode not supported");
} }
/* Setting power */ case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved: log_i("Fabric will be removed"); break;
cluster = cluster::get(endpoint, OnOff::Id);
attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_power(led, val.val.b);
return err; case chip::DeviceLayer::DeviceEventType::kFabricUpdated: log_i("Fabric is updated"); break;
case chip::DeviceLayer::DeviceEventType::kFabricCommitted: log_i("Fabric is committed"); break;
case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized: log_i("BLE deinitialized and memory reclaimed"); break;
default: break;
}
} }
void button_driver_init() esp_err_t matter_light_attribute_update(
{ app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val
/* Initialize button */ ) {
pinMode(button_gpio, INPUT_PULLUP); esp_err_t err = ESP_OK;
if (endpoint_id == light_endpoint_id) {
void *led = (void *)driver_handle;
if (cluster_id == OnOff::Id) {
if (attribute_id == OnOff::Attributes::OnOff::Id) {
err = light_accessory_set_power(led, val->val.b);
}
} else if (cluster_id == LevelControl::Id) {
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
err = light_accessory_set_brightness(led, val->val.u8);
}
} else if (cluster_id == ColorControl::Id) {
if (attribute_id == ColorControl::Attributes::CurrentHue::Id) {
err = light_accessory_set_hue(led, val->val.u8);
} else if (attribute_id == ColorControl::Attributes::CurrentSaturation::Id) {
err = light_accessory_set_saturation(led, val->val.u8);
} else if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) {
err = light_accessory_set_temperature(led, val->val.u16);
}
}
}
return err;
}
esp_err_t matter_light_set_defaults(uint16_t endpoint_id) {
esp_err_t err = ESP_OK;
void *led = endpoint::get_priv_data(endpoint_id);
node_t *node = node::get();
endpoint_t *endpoint = endpoint::get(node, endpoint_id);
cluster_t *cluster = NULL;
attribute_t *attribute = NULL;
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
/* Setting brightness */
cluster = cluster::get(endpoint, LevelControl::Id);
attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_brightness(led, val.val.u8);
/* Setting color */
cluster = cluster::get(endpoint, ColorControl::Id);
attribute = attribute::get(cluster, ColorControl::Attributes::ColorMode::Id);
attribute::get_val(attribute, &val);
if (val.val.u8 == (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation) {
/* Setting hue */
attribute = attribute::get(cluster, ColorControl::Attributes::CurrentHue::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_hue(led, val.val.u8);
/* Setting saturation */
attribute = attribute::get(cluster, ColorControl::Attributes::CurrentSaturation::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_saturation(led, val.val.u8);
} else if (val.val.u8 == (uint8_t)ColorControl::ColorMode::kColorTemperature) {
/* Setting temperature */
attribute = attribute::get(cluster, ColorControl::Attributes::ColorTemperatureMireds::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_temperature(led, val.val.u16);
} else {
log_e("Color mode not supported");
}
/* Setting power */
cluster = cluster::get(endpoint, OnOff::Id);
attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id);
attribute::get_val(attribute, &val);
err |= light_accessory_set_power(led, val.val.b);
return err;
}
void button_driver_init() {
/* Initialize button */
pinMode(button_gpio, INPUT_PULLUP);
} }
// This callback is called for every attribute update. The callback implementation shall // This callback is called for every attribute update. The callback implementation shall
// handle the desired attributes and return an appropriate error code. If the attribute // handle the desired attributes and return an appropriate error code. If the attribute
// is not of your interest, please do not return an error code and strictly return ESP_OK. // is not of your interest, please do not return an error code and strictly return ESP_OK.
static esp_err_t app_attribute_update_cb(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, static esp_err_t app_attribute_update_cb(
uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data
{ ) {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
if (type == PRE_UPDATE) { if (type == PRE_UPDATE) {
/* Driver update */ /* Driver update */
app_driver_handle_t driver_handle = (app_driver_handle_t)priv_data; app_driver_handle_t driver_handle = (app_driver_handle_t)priv_data;
err = matter_light_attribute_update(driver_handle, endpoint_id, cluster_id, attribute_id, val); err = matter_light_attribute_update(driver_handle, endpoint_id, cluster_id, attribute_id, val);
} }
return err; return err;
} }
// This callback is invoked when clients interact with the Identify Cluster. // This callback is invoked when clients interact with the Identify Cluster.
// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light). // In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light).
static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id, static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id, uint8_t effect_variant, void *priv_data) {
uint8_t effect_variant, void *priv_data) log_i("Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant);
{ return ESP_OK;
log_i("Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant);
return ESP_OK;
} }
void setup() void setup() {
{ esp_err_t err = ESP_OK;
esp_err_t err = ESP_OK;
/* Initialize driver */ /* Initialize driver */
app_driver_handle_t light_handle = light_accessory_init(); app_driver_handle_t light_handle = light_accessory_init();
button_driver_init(); button_driver_init();
/* Create a Matter node and add the mandatory Root Node device type on endpoint 0 */ /* Create a Matter node and add the mandatory Root Node device type on endpoint 0 */
node::config_t node_config; node::config_t node_config;
// node handle can be used to add/modify other endpoints. // node handle can be used to add/modify other endpoints.
node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb); node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb);
if (node == nullptr) { if (node == nullptr) {
log_e("Failed to create Matter node"); log_e("Failed to create Matter node");
abort(); abort();
} }
extended_color_light::config_t light_config; extended_color_light::config_t light_config;
light_config.on_off.on_off = DEFAULT_POWER; light_config.on_off.on_off = DEFAULT_POWER;
light_config.on_off.lighting.start_up_on_off = nullptr; light_config.on_off.lighting.start_up_on_off = nullptr;
light_config.level_control.current_level = DEFAULT_BRIGHTNESS; light_config.level_control.current_level = DEFAULT_BRIGHTNESS;
light_config.level_control.lighting.start_up_current_level = DEFAULT_BRIGHTNESS; light_config.level_control.lighting.start_up_current_level = DEFAULT_BRIGHTNESS;
light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature; light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature;
light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature; light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature;
light_config.color_control.color_temperature.startup_color_temperature_mireds = nullptr; light_config.color_control.color_temperature.startup_color_temperature_mireds = nullptr;
// endpoint handles can be used to add/modify clusters. // endpoint handles can be used to add/modify clusters.
endpoint_t *endpoint = extended_color_light::create(node, &light_config, ENDPOINT_FLAG_NONE, light_handle); endpoint_t *endpoint = extended_color_light::create(node, &light_config, ENDPOINT_FLAG_NONE, light_handle);
if (endpoint == nullptr) { if (endpoint == nullptr) {
log_e("Failed to create extended color light endpoint"); log_e("Failed to create extended color light endpoint");
abort(); abort();
} }
light_endpoint_id = endpoint::get_id(endpoint); light_endpoint_id = endpoint::get_id(endpoint);
log_i("Light created with endpoint_id %d", light_endpoint_id); log_i("Light created with endpoint_id %d", light_endpoint_id);
/* Mark deferred persistence for some attributes that might be changed rapidly */ /* Mark deferred persistence for some attributes that might be changed rapidly */
cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id); cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id);
attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id); attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id);
attribute::set_deferred_persistence(current_level_attribute); attribute::set_deferred_persistence(current_level_attribute);
cluster_t *color_control_cluster = cluster::get(endpoint, ColorControl::Id); cluster_t *color_control_cluster = cluster::get(endpoint, ColorControl::Id);
attribute_t *current_x_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::CurrentX::Id); attribute_t *current_x_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::CurrentX::Id);
attribute::set_deferred_persistence(current_x_attribute); attribute::set_deferred_persistence(current_x_attribute);
attribute_t *current_y_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::CurrentY::Id); attribute_t *current_y_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::CurrentY::Id); // codespell:ignore
attribute::set_deferred_persistence(current_y_attribute); attribute::set_deferred_persistence(current_y_attribute);
attribute_t *color_temp_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::ColorTemperatureMireds::Id); attribute_t *color_temp_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::ColorTemperatureMireds::Id);
attribute::set_deferred_persistence(color_temp_attribute); attribute::set_deferred_persistence(color_temp_attribute);
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
/* Set OpenThread platform config */ /* Set OpenThread platform config */
esp_openthread_platform_config_t config = { esp_openthread_platform_config_t config = {
.radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(), .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(), .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(), .port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
}; };
set_openthread_platform_config(&config); set_openthread_platform_config(&config);
#endif #endif
/* Matter start */ /* Matter start */
err = esp_matter::start(app_event_cb); err = esp_matter::start(app_event_cb);
if (err != ESP_OK) { if (err != ESP_OK) {
log_e("Failed to start Matter, err:%d", err); log_e("Failed to start Matter, err:%d", err);
abort(); abort();
} }
#if CONFIG_ENABLE_ENCRYPTED_OTA #if CONFIG_ENABLE_ENCRYPTED_OTA
err = esp_matter_ota_requestor_encrypted_init(s_decryption_key, s_decryption_key_len); err = esp_matter_ota_requestor_encrypted_init(s_decryption_key, s_decryption_key_len);
if (err != ESP_OK) { if (err != ESP_OK) {
log_e("Failed to initialized the encrypted OTA, err: %d", err); log_e("Failed to initialized the encrypted OTA, err: %d", err);
abort(); abort();
} }
#endif // CONFIG_ENABLE_ENCRYPTED_OTA #endif // CONFIG_ENABLE_ENCRYPTED_OTA
#if CONFIG_ENABLE_CHIP_SHELL #if CONFIG_ENABLE_CHIP_SHELL
esp_matter::console::diagnostics_register_commands(); esp_matter::console::diagnostics_register_commands();
esp_matter::console::wifi_register_commands(); esp_matter::console::wifi_register_commands();
#if CONFIG_OPENTHREAD_CLI #if CONFIG_OPENTHREAD_CLI
esp_matter::console::otcli_register_commands(); esp_matter::console::otcli_register_commands();
#endif #endif
esp_matter::console::init(); esp_matter::console::init();
#endif #endif
} }
@@ -346,10 +309,10 @@ void loop() {
static bool button_state = false; static bool button_state = false;
static bool started = false; static bool started = false;
if(!isAccessoryCommissioned()) { if (!isAccessoryCommissioned()) {
log_w("Accessory not commissioned yet. Waiting for commissioning."); log_w("Accessory not commissioned yet. Waiting for commissioning.");
#ifdef RGB_BUILTIN #ifdef RGB_BUILTIN
rgbLedWrite(RGB_BUILTIN, 48, 0, 20); // Purple indicates accessory not commissioned rgbLedWrite(RGB_BUILTIN, 48, 0, 20); // Purple indicates accessory not commissioned
#endif #endif
delay(5000); delay(5000);
return; return;
@@ -359,7 +322,7 @@ void loop() {
if (!isWifiConnected()) { if (!isWifiConnected()) {
log_w("Wi-Fi not connected yet. Waiting for connection."); log_w("Wi-Fi not connected yet. Waiting for connection.");
#ifdef RGB_BUILTIN #ifdef RGB_BUILTIN
rgbLedWrite(RGB_BUILTIN, 48, 20, 0); // Orange indicates accessory not connected to Wi-Fi rgbLedWrite(RGB_BUILTIN, 48, 20, 0); // Orange indicates accessory not connected to Wi-Fi
#endif #endif
delay(5000); delay(5000);
return; return;
@@ -370,7 +333,7 @@ void loop() {
if (!isThreadConnected()) { if (!isThreadConnected()) {
log_w("Thread not connected yet. Waiting for connection."); log_w("Thread not connected yet. Waiting for connection.");
#ifdef RGB_BUILTIN #ifdef RGB_BUILTIN
rgbLedWrite(RGB_BUILTIN, 0, 20, 48); // Blue indicates accessory not connected to Trhead rgbLedWrite(RGB_BUILTIN, 0, 20, 48); // Blue indicates accessory not connected to Trhead
#endif #endif
delay(5000); delay(5000);
return; return;
@@ -389,10 +352,10 @@ void loop() {
// Check if the button is pressed and toggle the light right away // Check if the button is pressed and toggle the light right away
if (digitalRead(button_gpio) == LOW && !button_state) { if (digitalRead(button_gpio) == LOW && !button_state) {
// deals with button debounce // deals with button debounce
button_time_stamp = millis(); // record the time while the button is pressed. button_time_stamp = millis(); // record the time while the button is pressed.
button_state = true; // pressed. button_state = true; // pressed.
// Toggle button is pressed - toggle the light // Toggle button is pressed - toggle the light
log_i("Toggle button pressed"); log_i("Toggle button pressed");
endpoint_t *endpoint = endpoint::get(node::get(), light_endpoint_id); endpoint_t *endpoint = endpoint::get(node::get(), light_endpoint_id);
@@ -408,14 +371,14 @@ void loop() {
// Check if the button is released and handle the factory reset // Check if the button is released and handle the factory reset
uint32_t time_diff = millis() - button_time_stamp; uint32_t time_diff = millis() - button_time_stamp;
if (button_state && time_diff > 100 && digitalRead(button_gpio) == HIGH) { if (button_state && time_diff > 100 && digitalRead(button_gpio) == HIGH) {
button_state = false; // released. It can be pressed again after 100ms debounce. button_state = false; // released. It can be pressed again after 100ms debounce.
// Factory reset is triggered if the button is pressed for more than 10 seconds // Factory reset is triggered if the button is pressed for more than 10 seconds
if (time_diff > 10000) { if (time_diff > 10000) {
log_i("Factory reset triggered. Light will retored to factory settings."); log_i("Factory reset triggered. Light will restored to factory settings.");
esp_matter::factory_reset(); esp_matter::factory_reset();
} }
} }
delay(50); // WDT is happier with a delay delay(50); // WDT is happier with a delay
} }
@@ -17,10 +17,16 @@ platform = espressif32
framework = arduino, espidf framework = arduino, espidf
board_build.partitions = partitions.csv board_build.partitions = partitions.csv
monitor_speed = 115200 monitor_speed = 115200
build_unflags =
-std=c++17
-std=gnu++2b
build_flags =
-std=gnu++2a
-Wno-missing-field-initializers
[env:esp32s3] [env:esp32c6]
board = esp32-s3-devkitc-1 board = esp32-c6-devkitc-1
board_build.embed_txtfiles = board_build.embed_txtfiles =
managed_components/espressif__esp_insights/server_certs/https_server.crt managed_components/espressif__esp_insights/server_certs/https_server.crt
managed_components/espressif__esp_rainmaker/server_certs/rmaker_mqtt_server.crt managed_components/espressif__esp_rainmaker/server_certs/rmaker_mqtt_server.crt
@@ -1,3 +1,5 @@
CONFIG_IDF_TARGET="esp32c6"
# Arduino Settings # Arduino Settings
CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y CONFIG_AUTOSTART_ARDUINO=y
@@ -6,9 +8,17 @@ CONFIG_AUTOSTART_ARDUINO=y
# Boot Messages - Log level # Boot Messages - Log level
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
# Arduino Log Level # Arduino Log Level
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_VERBOSE=y CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
# IDF Log Level # IDF Log Level
CONFIG_LOG_DEFAULT_LEVEL_WARN=y CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
# Default to 921600 baud when flashing and monitoring device
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
#enable BT #enable BT
CONFIG_BT_ENABLED=y CONFIG_BT_ENABLED=y
@@ -17,6 +27,11 @@ CONFIG_BT_NIMBLE_ENABLED=y
#disable BT connection reattempt #disable BT connection reattempt
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
# NIMBLE
CONFIG_BT_NIMBLE_EXT_ADV=n
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y
#enable lwip ipv6 autoconfig #enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y CONFIG_LWIP_IPV6_AUTOCONFIG=y
@@ -28,16 +43,17 @@ CONFIG_PARTITION_TABLE_OFFSET=0xC000
# Disable chip shell # Disable chip shell
CONFIG_ENABLE_CHIP_SHELL=n CONFIG_ENABLE_CHIP_SHELL=n
# Enable OTA Requester
CONFIG_ENABLE_OTA_REQUESTOR=n
#enable lwIP route hooks #enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# Button
CONFIG_BUTTON_PERIOD_TIME_MS=20
CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000
# disable softap by default # disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
CONFIG_ENABLE_WIFI_STATION=y
CONFIG_ENABLE_WIFI_AP=n
# Disable DS Peripheral # Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
@@ -52,15 +68,23 @@ CONFIG_MBEDTLS_HKDF_C=y
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1) # unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
# libsodium
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
# ESP32-S3-DevKitC-1 Settings # FreeRTOS should use legacy API
CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y
# Use minimal mDNS
CONFIG_USE_MINIMAL_MDNS=y
CONFIG_ENABLE_EXTENDED_DISCOVERY=y
# ESP32-C6-DevKit Settings
# Buttons # Buttons
CONFIG_BSP_BUTTONS_NUM=1 CONFIG_BUTTON_PIN=9
CONFIG_BSP_BUTTON_1_TYPE_GPIO=y
CONFIG_BSP_BUTTON_1_GPIO=0
CONFIG_BSP_BUTTON_1_LEVEL=0
# LEDs # LEDs
CONFIG_BSP_LEDS_NUM=1 CONFIG_WS2812_PIN=8
CONFIG_BSP_LED_TYPE_RGB=y # max GPIO
CONFIG_BSP_LED_RGB_GPIO=48 CONFIG_ENV_GPIO_RANGE_MIN=0
CONFIG_BSP_LED_RGB_BACKEND_RMT=y CONFIG_ENV_GPIO_RANGE_MAX=30
CONFIG_ENV_GPIO_IN_RANGE_MAX=30
CONFIG_ENV_GPIO_OUT_RANGE_MAX=30
@@ -5,7 +5,7 @@ CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y CONFIG_AUTOSTART_ARDUINO=y
# Log Levels # Log Levels
# Boot Messages - Log level # Boot Messages - Log level
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
# Arduino Log Level # Arduino Log Level
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
@@ -56,7 +56,7 @@ CONFIG_LWIP_MULTICAST_PING=y
CONFIG_USE_MINIMAL_MDNS=n CONFIG_USE_MINIMAL_MDNS=n
CONFIG_ENABLE_EXTENDED_DISCOVERY=y CONFIG_ENABLE_EXTENDED_DISCOVERY=y
# Enable OTA Requestor # Enable OTA Requester
CONFIG_ENABLE_OTA_REQUESTOR=n CONFIG_ENABLE_OTA_REQUESTOR=n
# Disable STA and AP for ESP32C6 # Disable STA and AP for ESP32C6
@@ -77,4 +77,3 @@ CONFIG_MRP_MAX_RETRANS=3
# Enable HKDF in mbedtls # Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y CONFIG_MBEDTLS_HKDF_C=y
@@ -1,64 +0,0 @@
CONFIG_IDF_TARGET="esp32c3"
# Arduino Settings
CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y
# Log Levels
# Boot Messages - Log level
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
# Arduino Log Level
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
# IDF Log Level
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
# Default to 921600 baud when flashing and monitoring device
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
#enable BT
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
#disable BT connection reattempt
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
#enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# Use a custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
# Disable chip shell
CONFIG_ENABLE_CHIP_SHELL=n
# Enable OTA Requestor
CONFIG_ENABLE_OTA_REQUESTOR=n
#enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
CONFIG_ENABLE_WIFI_STATION=y
CONFIG_ENABLE_WIFI_AP=n
# Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Use compact attribute storage mode
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
@@ -1,68 +1,5 @@
CONFIG_IDF_TARGET="esp32c6" CONFIG_IDF_TARGET="esp32c6"
# Arduino Settings
CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y
# Log Levels
# Boot Messages - Log level
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
# Arduino Log Level
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
# IDF Log Level
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
# Default to 921600 baud when flashing and monitoring device
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
#enable BT
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
#disable BT connection reattempt
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
#enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# Use a custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
# Disable chip shell
CONFIG_ENABLE_CHIP_SHELL=n
# Enable OTA Requestor
CONFIG_ENABLE_OTA_REQUESTOR=n
#enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
CONFIG_ENABLE_WIFI_STATION=y
CONFIG_ENABLE_WIFI_AP=n
# Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Use compact attribute storage mode
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
# libsodium # libsodium
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
@@ -1,64 +0,0 @@
CONFIG_IDF_TARGET="esp32s3"
# Arduino Settings
CONFIG_FREERTOS_HZ=1000
CONFIG_AUTOSTART_ARDUINO=y
# Log Levels
# Boot Messages - Log level
CONFIG_BOOTLOADER_LOG_LEVEL_ERROR=y
# Arduino Log Level
CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO=y
# IDF Log Level
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
# Default to 921600 baud when flashing and monitoring device
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
#enable BT
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
#disable BT connection reattempt
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
#enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# Use a custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
# Disable chip shell
CONFIG_ENABLE_CHIP_SHELL=n
# Enable OTA Requestor
CONFIG_ENABLE_OTA_REQUESTOR=n
#enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
CONFIG_ENABLE_WIFI_STATION=y
CONFIG_ENABLE_WIFI_AP=n
# Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Use compact attribute storage mode
CONFIG_ESP_MATTER_NVS_USE_COMPACT_ATTR_STORAGE=y
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
+10 -1
View File
@@ -13,7 +13,6 @@ framework = espidf
board = esp32dev board = esp32dev
monitor_speed = 115200 monitor_speed = 115200
build_flags = build_flags =
; https://docs.espressif.com/projects/esp-idf/en/latest/get-started/get-started-wrover-kit.html#rgb-led
-D CONFIG_BLINK_GPIO=2 -D CONFIG_BLINK_GPIO=2
-D CONFIG_BLINK_LED_GPIO=2 -D CONFIG_BLINK_LED_GPIO=2
-D CONFIG_BLINK_PERIOD=1000 -D CONFIG_BLINK_PERIOD=1000
@@ -37,3 +36,13 @@ build_flags =
-D CONFIG_BLINK_GPIO=2 -D CONFIG_BLINK_GPIO=2
-D CONFIG_BLINK_LED_GPIO=2 -D CONFIG_BLINK_LED_GPIO=2
-D CONFIG_BLINK_PERIOD=1000 -D CONFIG_BLINK_PERIOD=1000
[env:esp32-p4]
platform = espressif32
framework = espidf
board = esp32-p4
monitor_speed = 115200
build_flags =
-D CONFIG_BLINK_GPIO=2
-D CONFIG_BLINK_LED_GPIO=2
-D CONFIG_BLINK_PERIOD=1000
@@ -18,3 +18,6 @@ board_build.embed_txtfiles =
[env:esp-wrover-kit] [env:esp-wrover-kit]
board = esp-wrover-kit board = esp-wrover-kit
build_flags =
-D SHOW_METRICS
+5 -3
View File
@@ -29,13 +29,15 @@ lib_ignore = ${env:tasmota32_base.lib_ignore}
NetworkClientSecure NetworkClientSecure
Zigbee Zigbee
custom_sdkconfig = https://raw.githubusercontent.com/pioarduino/sdkconfig/refs/heads/main/sdkconfig_tasmota_esp32 custom_sdkconfig = https://raw.githubusercontent.com/pioarduino/sdkconfig/refs/heads/main/sdkconfig_tasmota_esp32
'# CONFIG_BT_ENABLED is not set'
'# CONFIG_BT_NIMBLE_ENABLED is not set'
'# CONFIG_BT_CONTROLLER_ENABLED is not set'
CONFIG_BT_CONTROLLER_DISABLED=y
'# CONFIG_ETH_USE_ESP32_EMAC is not set' '# CONFIG_ETH_USE_ESP32_EMAC is not set'
'# CONFIG_ETH_PHY_INTERFACE_RMII is not set' '# CONFIG_ETH_PHY_INTERFACE_RMII is not set'
'# CONFIG_ETH_RMII_CLK_INPUT is not set' '# CONFIG_ETH_RMII_CLK_INPUT is not set'
'# CONFIG_ETH_RMII_CLK_IN_GPIO is not set' '# CONFIG_ETH_RMII_CLK_IN_GPIO is not set'
custom_component_remove = espressif/esp_hosted custom_component_remove =
espressif/esp_wifi_remote
espressif/esp-dsp
espressif/network_provisioning espressif/network_provisioning
espressif/esp-zboss-lib espressif/esp-zboss-lib
espressif/esp-zigbee-lib espressif/esp-zigbee-lib
+45572
View File
File diff suppressed because it is too large Load Diff
+21108
View File
File diff suppressed because it is too large Load Diff
+34807
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+70756
View File
File diff suppressed because it is too large Load Diff
+53987
View File
File diff suppressed because it is too large Load Diff
+133701
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+46655
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+69011
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -32,7 +32,7 @@ IS_WINDOWS = sys.platform.startswith("win")
class Esp32ExceptionDecoder(DeviceMonitorFilterBase): class Esp32ExceptionDecoder(DeviceMonitorFilterBase):
NAME = "esp32_exception_decoder" NAME = "esp32_exception_decoder"
ADDR_PATTERN = re.compile(r"((?:0x[0-9a-fA-F]{8}[: ]?)+)\s?$") ADDR_PATTERN = re.compile(r"((?:0x[0-9a-fA-F]{8}[: ]?)+)")
ADDR_SPLIT = re.compile(r"[ :]") ADDR_SPLIT = re.compile(r"[ :]")
PREFIX_RE = re.compile(r"^ *") PREFIX_RE = re.compile(r"^ *")
+89 -40
View File
@@ -6,19 +6,19 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"keywords": [ "keywords": [
"dev-platform", "dev-platform",
"Wi-Fi", "WiFi",
"Bluetooth", "Bluetooth",
"Xtensa", "Xtensa",
"RISC-V" "RISC-V"
], ],
"engines": { "engines": {
"platformio": ">=6.1.16" "platformio": ">=6.1.18"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/pioarduino/platform-espressif32.git" "url": "https://github.com/pioarduino/platform-espressif32.git"
}, },
"version": "54.03.20", "version": "54.03.21",
"frameworks": { "frameworks": {
"arduino": { "arduino": {
"script": "builder/frameworks/arduino.py" "script": "builder/frameworks/arduino.py"
@@ -33,114 +33,163 @@
"type": "framework", "type": "framework",
"optional": true, "optional": true,
"owner": "espressif", "owner": "espressif",
"version": "https://github.com/espressif/arduino-esp32/releases/download/3.2.0/esp32-3.2.0.zip" "version": "https://github.com/espressif/arduino-esp32/releases/download/3.2.1/esp32-3.2.1.zip"
}, },
"framework-arduinoespressif32-libs": { "framework-arduinoespressif32-libs": {
"type": "framework", "type": "framework",
"optional": true, "optional": true,
"owner": "espressif", "owner": "espressif",
"version": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-2f7dcd86-v1.zip" "version": "https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.4/esp32-arduino-libs-idf-release_v5.4-858a988d-v1.zip"
}, },
"framework-arduino-c2-skeleton-lib": { "framework-arduino-c2-skeleton-lib": {
"type": "framework", "type": "framework",
"optional": true, "optional": true,
"owner": "espressif", "owner": "espressif",
"version": "https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/c2_arduino_compile_skeleton.zip" "version": "https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/c2_arduino_compile_skeleton.zip"
}, },
"framework-espidf": { "framework-espidf": {
"type": "framework", "type": "framework",
"optional": true, "optional": true,
"owner": "pioarduino", "owner": "pioarduino",
"version": "https://github.com/pioarduino/esp-idf/releases/download/v5.4.1/esp-idf-v5.4.1.zip" "version": "https://github.com/pioarduino/esp-idf/releases/download/v5.4.2/esp-idf-v5.4.2.zip"
}, },
"toolchain-xtensa-esp-elf": { "toolchain-xtensa-esp-elf": {
"type": "toolchain", "type": "toolchain",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "14.2.0+20241119" "package-version": "14.2.0+20241119",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/xtensa-esp-elf-14.2.0_20241119.zip"
}, },
"toolchain-riscv32-esp": { "toolchain-riscv32-esp": {
"type": "toolchain", "type": "toolchain",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "14.2.0+20241119" "package-version": "14.2.0+20241119",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/riscv32-esp-elf-14.2.0_20241119.zip"
}, },
"toolchain-esp32ulp": { "toolchain-esp32ulp": {
"type": "toolchain", "type": "toolchain",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "~1.23800.0" "package-version": "2.38.0+20240113",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/esp32ulp-elf-2.38_20240113.zip"
}, },
"tool-xtensa-esp-elf-gdb": { "tool-xtensa-esp-elf-gdb": {
"type": "debugger", "type": "debugger",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "14.2.0+20240403" "package-version": "16.2.0+20250324",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/xtensa-esp-gdb-v16.2_20250324.zip"
}, },
"tool-riscv32-esp-elf-gdb": { "tool-riscv32-esp-elf-gdb": {
"type": "debugger", "type": "debugger",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "14.2.0+20240403" "package-version": "16.2.0+20250324",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/riscv32-esp-gdb-v16.2_20250324.zip"
}, },
"tool-esptoolpy": { "tool-esptoolpy": {
"type": "uploader", "type": "uploader",
"optional": false,
"owner": "pioarduino", "owner": "pioarduino",
"version": "https://github.com/pioarduino/esptool/releases/download/v4.8.9/esptool.zip" "version": "https://github.com/pioarduino/esptool/releases/download/v5.0.0-dev1/esptool.zip"
},
"tl-install": {
"type": "tool",
"optional": false,
"owner": "pioarduino",
"version": "https://github.com/pioarduino/esp_install/releases/download/v5.0.0/esp_install-v5.0.0.zip"
}, },
"tool-dfuutil-arduino": { "tool-dfuutil-arduino": {
"type": "uploader", "type": "uploader",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "~1.11.0" "package-version": "1.11.0",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/dfuutil-arduino-v1.11.0.zip"
}, },
"tool-openocd-esp32": { "tool-openocd-esp32": {
"type": "debugger", "type": "debugger",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "~2.1100.0" "package-version": "2.1200.20250422",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/openocd-v0.12.0-esp32-20250422.zip"
}, },
"tool-mklittlefs": { "tool-mklittlefs": {
"type": "uploader", "type": "uploader",
"owner": "tasmota", "optional": true,
"version": "^3.2.0" "owner": "pioarduino",
"package-version": "3.2.0",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/mklittlefs-3.2.0.zip"
}, },
"tool-mkfatfs": { "tool-mklittlefs-4.0.0": {
"type": "uploader", "type": "uploader",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "~2.0.0" "package-version": "4.0.0",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/mklittlefs-4.0.0.zip"
}, },
"tool-mkspiffs": { "tool-mkspiffs": {
"type": "uploader", "type": "uploader",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "~2.230.0" "package-version": "2.230.0",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/mkspiffs-v2.230.0.zip"
},
"tool-mkfatfs": {
"type": "uploader",
"optional": true,
"owner": "pioarduino",
"package-version": "2.0.1",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/mkfatfs-v2.0.1.zip"
}, },
"tool-cppcheck": { "tool-cppcheck": {
"type": "tool",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "~1.21100" "package-version": "2.11.0+230717",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/cppcheck-v2.11.0-230717.zip"
}, },
"tool-clangtidy": { "tool-clangtidy": {
"type": "tool",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "^1.190100.0" "package-version": "18.1.1",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/clangtidy-v18.1.1.zip"
}, },
"tool-pvs-studio": { "tool-pvs-studio": {
"type": "tool",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "^7.18.0" "package-version": "7.36.91321",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/pvs-studio-v7.36.91321.zip"
}, },
"tool-cmake": { "tool-cmake": {
"type": "tool",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "~3.30.2" "package-version": "3.30.2",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/cmake-3.30.2.zip"
},
"tool-esp-rom-elfs": {
"type": "tool",
"optional": true,
"owner": "pioarduino",
"package-version": "2024.10.11",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/esp-rom-elfs-20241011.zip"
}, },
"tool-ninja": { "tool-ninja": {
"type": "tool",
"optional": true, "optional": true,
"owner": "platformio", "owner": "pioarduino",
"version": "^1.7.0" "package-version": "1.10.2",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/ninja-1.10.2.zip"
},
"tool-scons": {
"type": "tool",
"optional": true,
"owner": "pioarduino",
"package-version": "4.40801.0",
"version": "https://github.com/pioarduino/registry/releases/download/0.0.1/scons-4.8.1.zip"
} }
} }
} }
+499 -111
View File
@@ -13,109 +13,490 @@
# limitations under the License. # limitations under the License.
import os import os
import urllib import contextlib
import sys
import json import json
import re
import requests import requests
import subprocess
import sys
import shutil
import logging
from typing import Optional, Dict, List, Any
from platformio.public import PlatformBase, to_unix_path from platformio.public import PlatformBase, to_unix_path
from platformio.proc import get_pythonexe_path
from platformio.project.config import ProjectConfig
from platformio.package.manager.tool import ToolPackageManager
# Constants
RETRY_LIMIT = 3
SUBPROCESS_TIMEOUT = 300
MKLITTLEFS_VERSION_320 = "3.2.0"
MKLITTLEFS_VERSION_400 = "4.0.0"
DEFAULT_DEBUG_SPEED = "5000"
DEFAULT_APP_OFFSET = "0x10000"
# MCUs that support ESP-builtin debug
ESP_BUILTIN_DEBUG_MCUS = frozenset([
"esp32c3", "esp32c5", "esp32c6", "esp32s3", "esp32h2", "esp32p4"
])
# MCU configuration mapping
MCU_TOOLCHAIN_CONFIG = {
"xtensa": {
"mcus": frozenset(["esp32", "esp32s2", "esp32s3"]),
"toolchains": ["toolchain-xtensa-esp-elf"],
"debug_tools": ["tool-xtensa-esp-elf-gdb"]
},
"riscv": {
"mcus": frozenset([
"esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32h2", "esp32p4"
]),
"toolchains": ["toolchain-riscv32-esp"],
"debug_tools": ["tool-riscv32-esp-elf-gdb"]
}
}
COMMON_IDF_PACKAGES = [
"tool-cmake",
"tool-ninja",
"tool-scons",
"tool-esp-rom-elfs"
]
CHECK_PACKAGES = [
"tool-cppcheck",
"tool-clangtidy",
"tool-pvs-studio"
]
# System-specific configuration
IS_WINDOWS = sys.platform.startswith("win") IS_WINDOWS = sys.platform.startswith("win")
# Set Platformio env var to use windows_amd64 for all windows architectures # Set Platformio env var to use windows_amd64 for all windows architectures
# only windows_amd64 native espressif toolchains are available # only windows_amd64 native espressif toolchains are available
# needs platformio core >= 6.1.16b2 or pioarduino core 6.1.16+test # needs platformio/pioarduino core >= 6.1.17
if IS_WINDOWS: if IS_WINDOWS:
os.environ["PLATFORMIO_SYSTEM_TYPE"] = "windows_amd64" os.environ["PLATFORMIO_SYSTEM_TYPE"] = "windows_amd64"
# Global variables
python_exe = get_pythonexe_path()
pm = ToolPackageManager()
# Configure logger
logger = logging.getLogger(__name__)
def safe_file_operation(operation_func):
"""Decorator for safe filesystem operations with error handling."""
def wrapper(*args, **kwargs):
try:
return operation_func(*args, **kwargs)
except (OSError, IOError, FileNotFoundError) as e:
logger.error(f"Filesystem error in {operation_func.__name__}: {e}")
return False
except Exception as e:
logger.error(f"Unexpected error in {operation_func.__name__}: {e}")
raise # Re-raise unexpected exceptions
return wrapper
@safe_file_operation
def safe_remove_directory(path: str) -> bool:
"""Safely remove directories with error handling."""
if os.path.exists(path) and os.path.isdir(path):
shutil.rmtree(path)
logger.debug(f"Directory removed: {path}")
return True
@safe_file_operation
def safe_copy_file(src: str, dst: str) -> bool:
"""Safely copy files with error handling."""
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copyfile(src, dst)
logger.debug(f"File copied: {src} -> {dst}")
return True
class Espressif32Platform(PlatformBase): class Espressif32Platform(PlatformBase):
def configure_default_packages(self, variables, targets): """ESP32 platform implementation for PlatformIO with optimized toolchain management."""
if not variables.get("board"):
return super().configure_default_packages(variables, targets)
board_config = self.board_config(variables.get("board")) def __init__(self, *args, **kwargs):
mcu = variables.get("board_build.mcu", board_config.get("build.mcu", "esp32")) """Initialize the ESP32 platform with caching mechanisms."""
board_sdkconfig = variables.get("board_espidf.custom_sdkconfig", board_config.get("espidf.custom_sdkconfig", "")) super().__init__(*args, **kwargs)
core_variant_board = ''.join(variables.get("board_build.extra_flags", board_config.get("build.extra_flags", ""))) self._packages_dir = None
core_variant_board = core_variant_board.replace("-D", " ") self._tools_cache = {}
core_variant_build = (''.join(variables.get("build_flags", []))).replace("-D", " ") self._mcu_config_cache = {}
frameworks = variables.get("pioframework", [])
if "arduino" in frameworks: @property
self.packages["framework-arduinoespressif32"]["optional"] = False def packages_dir(self) -> str:
self.packages["framework-arduinoespressif32-libs"]["optional"] = False """Get cached packages directory path."""
if self._packages_dir is None:
config = ProjectConfig.get_instance()
self._packages_dir = config.get("platformio", "packages_dir")
return self._packages_dir
if variables.get("custom_sdkconfig") is not None or len(str(board_sdkconfig)) > 3: def _get_tool_paths(self, tool_name: str) -> Dict[str, str]:
"""Get centralized path calculation for tools with caching."""
if tool_name not in self._tools_cache:
tool_path = os.path.join(self.packages_dir, tool_name)
self._tools_cache[tool_name] = {
'tool_path': tool_path,
'package_path': os.path.join(tool_path, "package.json"),
'tools_json_path': os.path.join(tool_path, "tools.json"),
'piopm_path': os.path.join(tool_path, ".piopm"),
'idf_tools_path': os.path.join(
self.packages_dir, "tl-install", "tools", "idf_tools.py"
)
}
return self._tools_cache[tool_name]
def _check_tool_status(self, tool_name: str) -> Dict[str, bool]:
"""Check the installation status of a tool."""
paths = self._get_tool_paths(tool_name)
return {
'has_idf_tools': os.path.exists(paths['idf_tools_path']),
'has_tools_json': os.path.exists(paths['tools_json_path']),
'has_piopm': os.path.exists(paths['piopm_path']),
'tool_exists': os.path.exists(paths['tool_path'])
}
def _run_idf_tools_install(self, tools_json_path: str, idf_tools_path: str) -> bool:
"""Execute idf_tools.py install command with timeout and error handling."""
cmd = [
python_exe,
idf_tools_path,
"--quiet",
"--non-interactive",
"--tools-json",
tools_json_path,
"install"
]
try:
result = subprocess.run(
cmd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=SUBPROCESS_TIMEOUT,
check=False
)
if result.returncode != 0:
logger.error("idf_tools.py installation failed")
return False
logger.debug("idf_tools.py executed successfully")
return True
except subprocess.TimeoutExpired:
logger.error(f"Timeout in idf_tools.py after {SUBPROCESS_TIMEOUT}s")
return False
except (subprocess.SubprocessError, OSError) as e:
logger.error(f"Error in idf_tools.py: {e}")
return False
def _check_tool_version(self, tool_name: str) -> bool:
"""Check if the installed tool version matches the required version."""
paths = self._get_tool_paths(tool_name)
try:
with open(paths['package_path'], 'r', encoding='utf-8') as f:
package_data = json.load(f)
required_version = self.packages.get(tool_name, {}).get("package-version")
installed_version = package_data.get("version")
if not required_version:
logger.debug(f"No version check required for {tool_name}")
return True
if not installed_version:
logger.warning(f"Installed version for {tool_name} unknown")
return False
version_match = required_version == installed_version
if not version_match:
logger.info(
f"Version mismatch for {tool_name}: "
f"{installed_version} != {required_version}"
)
return version_match
except (json.JSONDecodeError, FileNotFoundError) as e:
logger.error(f"Error reading package data for {tool_name}: {e}")
return False
def install_tool(self, tool_name: str, retry_count: int = 0) -> bool:
"""Install a tool with optimized retry mechanism."""
if retry_count >= RETRY_LIMIT:
logger.error(
f"Installation of {tool_name} failed after {RETRY_LIMIT} attempts"
)
return False
self.packages[tool_name]["optional"] = False
paths = self._get_tool_paths(tool_name)
status = self._check_tool_status(tool_name)
# Case 1: New installation with idf_tools
if status['has_idf_tools'] and status['has_tools_json']:
return self._install_with_idf_tools(tool_name, paths)
# Case 2: Tool already installed, version check
if (status['has_idf_tools'] and status['has_piopm'] and
not status['has_tools_json']):
return self._handle_existing_tool(tool_name, paths, retry_count)
logger.debug(f"Tool {tool_name} already configured")
return True
def _install_with_idf_tools(self, tool_name: str, paths: Dict[str, str]) -> bool:
"""Install tool using idf_tools.py installation method."""
if not self._run_idf_tools_install(
paths['tools_json_path'], paths['idf_tools_path']
):
return False
# Copy tool files
tools_path_default = os.path.join(
os.path.expanduser("~"), ".platformio"
)
target_package_path = os.path.join(
tools_path_default, "tools", tool_name, "package.json"
)
if not safe_copy_file(paths['package_path'], target_package_path):
return False
safe_remove_directory(paths['tool_path'])
tl_path = f"file://{os.path.join(tools_path_default, 'tools', tool_name)}"
pm.install(tl_path)
logger.info(f"Tool {tool_name} successfully installed")
return True
def _handle_existing_tool(
self, tool_name: str, paths: Dict[str, str], retry_count: int
) -> bool:
"""Handle already installed tools with version checking."""
if self._check_tool_version(tool_name):
# Version matches, use tool
self.packages[tool_name]["version"] = paths['tool_path']
self.packages[tool_name]["optional"] = False
logger.debug(f"Tool {tool_name} found with correct version")
return True
# Wrong version, reinstall
logger.info(f"Reinstalling {tool_name} due to version mismatch")
safe_remove_directory(paths['tool_path'])
return self.install_tool(tool_name, retry_count + 1)
def _configure_arduino_framework(self, frameworks: List[str]) -> None:
"""Configure Arduino framework with dynamic library URL fetching."""
if "arduino" not in frameworks:
return
self.packages["framework-arduinoespressif32"]["optional"] = False
self.packages["framework-arduinoespressif32-libs"]["optional"] = False
def _configure_espidf_framework(
self, frameworks: List[str], variables: Dict, board_config: Dict, mcu: str
) -> None:
"""Configure ESP-IDF framework based on custom sdkconfig settings."""
custom_sdkconfig = variables.get("custom_sdkconfig")
board_sdkconfig = variables.get(
"board_espidf.custom_sdkconfig",
board_config.get("espidf.custom_sdkconfig", "")
)
if custom_sdkconfig is not None or len(str(board_sdkconfig)) > 3:
frameworks.append("espidf") frameworks.append("espidf")
self.packages["framework-espidf"]["optional"] = False self.packages["framework-espidf"]["optional"] = False
if mcu == "esp32c2": if mcu == "esp32c2":
self.packages["framework-arduino-c2-skeleton-lib"]["optional"] = False self.packages["framework-arduino-c2-skeleton-lib"]["optional"] = False
# Enable check tools only when "check_tool" is active def _get_mcu_config(self, mcu: str) -> Optional[Dict]:
for p in self.packages: """Get MCU configuration with optimized caching and search."""
if p in ("tool-cppcheck", "tool-clangtidy", "tool-pvs-studio"): if mcu in self._mcu_config_cache:
self.packages[p]["optional"] = False if str(variables.get("check_tool")).strip("['']") in p else True return self._mcu_config_cache[mcu]
if "buildfs" in targets: for _, config in MCU_TOOLCHAIN_CONFIG.items():
filesystem = variables.get("board_build.filesystem", "littlefs") if mcu in config["mcus"]:
if filesystem == "littlefs": # Dynamically add ULP toolchain
self.packages["tool-mklittlefs"]["optional"] = False result = config.copy()
elif filesystem == "fatfs": result["ulp_toolchain"] = ["toolchain-esp32ulp"]
self.packages["tool-mkfatfs"]["optional"] = False if mcu != "esp32":
else: result["ulp_toolchain"].append("toolchain-riscv32-esp")
self.packages["tool-mkspiffs"]["optional"] = False self._mcu_config_cache[mcu] = result
if variables.get("upload_protocol"): return result
self.packages["tool-openocd-esp32"]["optional"] = False return None
if os.path.isdir("ulp"):
self.packages["toolchain-esp32ulp"]["optional"] = False
if "downloadfs" in targets: def _needs_debug_tools(self, variables: Dict, targets: List[str]) -> bool:
filesystem = variables.get("board_build.filesystem", "littlefs") """Check if debug tools are needed based on build configuration."""
if filesystem == "littlefs": return bool(
# Use Tasmota mklittlefs v4.0.0 to unpack, older version is incompatible variables.get("build_type") or
self.packages["tool-mklittlefs"]["version"] = "~4.0.0" "debug" in targets or
variables.get("upload_protocol")
)
def _configure_mcu_toolchains(
self, mcu: str, variables: Dict, targets: List[str]
) -> None:
"""Configure MCU-specific toolchains with optimized installation."""
mcu_config = self._get_mcu_config(mcu)
if not mcu_config:
logger.warning(f"Unknown MCU: {mcu}")
return
# Install base toolchains
for toolchain in mcu_config["toolchains"]:
self.install_tool(toolchain)
# ULP toolchain if ULP directory exists
if mcu_config.get("ulp_toolchain") and os.path.isdir("ulp"):
for toolchain in mcu_config["ulp_toolchain"]:
self.install_tool(toolchain)
# Debug tools when needed
if self._needs_debug_tools(variables, targets):
for debug_tool in mcu_config["debug_tools"]:
self.install_tool(debug_tool)
self.install_tool("tool-openocd-esp32")
def _configure_installer(self) -> None:
"""Configure the ESP-IDF tools installer."""
installer_path = os.path.join(
self.packages_dir, "tl-install", "tools", "idf_tools.py"
)
if os.path.exists(installer_path):
self.packages["tl-install"]["optional"] = True
def _install_common_idf_packages(self) -> None:
"""Install common ESP-IDF packages required for all builds."""
for package in COMMON_IDF_PACKAGES:
self.install_tool(package)
def _configure_check_tools(self, variables: Dict) -> None:
"""Configure static analysis and check tools based on configuration."""
check_tools = variables.get("check_tool", [])
if not check_tools:
return
for package in CHECK_PACKAGES:
if any(tool in package for tool in check_tools):
self.install_tool(package)
def _ensure_mklittlefs_version(self) -> None:
"""Ensure correct mklittlefs version is installed."""
piopm_path = os.path.join(self.packages_dir, "tool-mklittlefs", ".piopm")
if os.path.exists(piopm_path):
try:
with open(piopm_path, 'r', encoding='utf-8') as f:
package_data = json.load(f)
if package_data.get('version') != MKLITTLEFS_VERSION_320:
os.remove(piopm_path)
logger.info("Outdated mklittlefs version removed")
except (json.JSONDecodeError, KeyError) as e:
logger.error(f"Error reading mklittlefs package data: {e}")
def _setup_mklittlefs_for_download(self) -> None:
"""Setup mklittlefs for download functionality with version 4.0.0."""
mklittlefs_dir = os.path.join(self.packages_dir, "tool-mklittlefs")
mklittlefs400_dir = os.path.join(
self.packages_dir, "tool-mklittlefs-4.0.0"
)
# Ensure mklittlefs 3.2.0 is installed
if not os.path.exists(mklittlefs_dir):
self.install_tool("tool-mklittlefs")
if os.path.exists(os.path.join(mklittlefs_dir, "tools.json")):
self.install_tool("tool-mklittlefs")
# Install mklittlefs 4.0.0
if not os.path.exists(mklittlefs400_dir):
self.install_tool("tool-mklittlefs-4.0.0")
if os.path.exists(os.path.join(mklittlefs400_dir, "tools.json")):
self.install_tool("tool-mklittlefs-4.0.0")
# Copy mklittlefs 4.0.0 over 3.2.0
if os.path.exists(mklittlefs400_dir):
package_src = os.path.join(mklittlefs_dir, "package.json")
package_dst = os.path.join(mklittlefs400_dir, "package.json")
safe_copy_file(package_src, package_dst)
shutil.copytree(mklittlefs400_dir, mklittlefs_dir, dirs_exist_ok=True)
self.packages.pop("tool-mkfatfs", None)
def _handle_littlefs_tool(self, for_download: bool) -> None:
"""Handle LittleFS tool installation with special download configuration."""
if for_download:
self._setup_mklittlefs_for_download()
else:
self._ensure_mklittlefs_version()
self.install_tool("tool-mklittlefs")
def _install_filesystem_tool(self, filesystem: str, for_download: bool = False) -> None:
"""Install filesystem-specific tools based on the filesystem type."""
tool_mapping = {
"default": lambda: self._handle_littlefs_tool(for_download),
"fatfs": lambda: self.install_tool("tool-mkfatfs"),
"spiffs": lambda: self.install_tool("tool-mkspiffs")
}
handler = tool_mapping.get(filesystem, tool_mapping["default"])
handler()
def _handle_dfuutil_tool(self, variables: Dict, for_download: bool = False) -> None:
"""Install dfuutil tool for Arduino Nano ESP32 board."""
# Currently only Arduino Nano ESP32 uses the dfuutil tool as uploader # Currently only Arduino Nano ESP32 uses the dfuutil tool as uploader
if variables.get("board") == "arduino_nano_esp32": if variables.get("board") == "arduino_nano_esp32":
self.packages["tool-dfuutil-arduino"]["optional"] = False self.install_tool("tool-dfuutil-arduino")
else:
del self.packages["tool-dfuutil-arduino"]
# Starting from v12, Espressif's toolchains are shipped without def _configure_filesystem_tools(self, variables: Dict, targets: List[str]) -> None:
# bundled GDB. Instead, it's distributed as separate packages for Xtensa """Configure filesystem tools based on build targets and filesystem type."""
# and RISC-V targets. filesystem = variables.get("board_build.filesystem", "littlefs")
for gdb_package in ("tool-xtensa-esp-elf-gdb", "tool-riscv32-esp-elf-gdb"):
self.packages[gdb_package]["optional"] = False
# if IS_WINDOWS:
# Note: On Windows GDB v12 is not able to
# launch a GDB server in pipe mode while v11 works fine
# self.packages[gdb_package]["version"] = "~11.2.0"
# Common packages for IDF and mixed Arduino+IDF projects if any(target in targets for target in ["buildfs", "uploadfs"]):
if "espidf" in frameworks: self._install_filesystem_tool(filesystem, for_download=False)
self.packages["toolchain-esp32ulp"]["optional"] = False
for p in self.packages:
if p in ("tool-scons", "tool-cmake", "tool-ninja"):
self.packages[p]["optional"] = False
# elif p in ("tool-mconf", "tool-idf") and IS_WINDOWS:
# self.packages[p]["optional"] = False
if mcu in ("esp32", "esp32s2", "esp32s3"): if "downloadfs" in targets:
self.packages["toolchain-xtensa-esp-elf"]["optional"] = False self._install_filesystem_tool(filesystem, for_download=True)
else:
self.packages.pop("toolchain-xtensa-esp-elf", None)
if mcu in ("esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4"): def configure_default_packages(self, variables: Dict, targets: List[str]) -> Any:
if mcu in ("esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4"): """Main configuration method with optimized package management."""
self.packages.pop("toolchain-esp32ulp", None) if not variables.get("board"):
# RISC-V based toolchain for ESP32C3, ESP32C6 ESP32S2, ESP32S3 ULP return super().configure_default_packages(variables, targets)
self.packages["toolchain-riscv32-esp"]["optional"] = False
# Base configuration
board_config = self.board_config(variables.get("board"))
mcu = variables.get("board_build.mcu", board_config.get("build.mcu", "esp32"))
frameworks = list(variables.get("pioframework", [])) # Create copy
try:
# Configuration steps
self._configure_installer()
self._configure_arduino_framework(frameworks)
self._configure_espidf_framework(frameworks, variables, board_config, mcu)
self._configure_mcu_toolchains(mcu, variables, targets)
if "espidf" in frameworks:
self._install_common_idf_packages()
self._configure_check_tools(variables)
self._configure_filesystem_tools(variables, targets)
self._handle_dfuutil_tool(variables)
logger.info("Package configuration completed successfully")
except Exception as e:
logger.error(f"Error in package configuration: {type(e).__name__}: {e}")
# Don't re-raise to maintain compatibility
return super().configure_default_packages(variables, targets) return super().configure_default_packages(variables, targets)
def get_boards(self, id_=None): def get_boards(self, id_=None):
"""Get board configuration with dynamic options."""
result = super().get_boards(id_) result = super().get_boards(id_)
if not result: if not result:
return result return result
@@ -127,13 +508,14 @@ class Espressif32Platform(PlatformBase):
return result return result
def _add_dynamic_options(self, board): def _add_dynamic_options(self, board):
# upload protocols """Add dynamic board options for upload protocols and debug tools."""
# Upload protocols
if not board.get("upload.protocols", []): if not board.get("upload.protocols", []):
board.manifest["upload"]["protocols"] = ["esptool", "espota"] board.manifest["upload"]["protocols"] = ["esptool", "espota"]
if not board.get("upload.protocol", ""): if not board.get("upload.protocol", ""):
board.manifest["upload"]["protocol"] = "esptool" board.manifest["upload"]["protocol"] = "esptool"
# debug tools # Debug tools
debug = board.manifest.get("debug", {}) debug = board.manifest.get("debug", {})
non_debug_protocols = ["esptool", "espota"] non_debug_protocols = ["esptool", "espota"]
supported_debug_tools = [ supported_debug_tools = [
@@ -147,17 +529,21 @@ class Espressif32Platform(PlatformBase):
"olimex-arm-usb-ocd-h", "olimex-arm-usb-ocd-h",
"olimex-arm-usb-ocd", "olimex-arm-usb-ocd",
"olimex-jtag-tiny", "olimex-jtag-tiny",
"tumpa", "tumpa"
] ]
# A special case for the Kaluga board that has a separate interface config # Special configuration for Kaluga board
if board.id == "esp32-s2-kaluga-1": if board.id == "esp32-s2-kaluga-1":
supported_debug_tools.append("ftdi") supported_debug_tools.append("ftdi")
if board.get("build.mcu", "") in ("esp32c3", "esp32c6", "esp32s3", "esp32h2"):
# ESP-builtin for certain MCUs
mcu = board.get("build.mcu", "")
if mcu in ESP_BUILTIN_DEBUG_MCUS:
supported_debug_tools.append("esp-builtin") supported_debug_tools.append("esp-builtin")
upload_protocol = board.manifest.get("upload", {}).get("protocol") upload_protocol = board.manifest.get("upload", {}).get("protocol")
upload_protocols = board.manifest.get("upload", {}).get("protocols", []) upload_protocols = board.manifest.get("upload", {}).get("protocols", [])
if debug: if debug:
upload_protocols.extend(supported_debug_tools) upload_protocols.extend(supported_debug_tools)
if upload_protocol and upload_protocol not in upload_protocols: if upload_protocol and upload_protocol not in upload_protocols:
@@ -167,37 +553,13 @@ class Espressif32Platform(PlatformBase):
if "tools" not in debug: if "tools" not in debug:
debug["tools"] = {} debug["tools"] = {}
# Debug tool configuration
for link in upload_protocols: for link in upload_protocols:
if link in non_debug_protocols or link in debug["tools"]: if link in non_debug_protocols or link in debug["tools"]:
continue continue
if link in ("jlink", "cmsis-dap"): openocd_interface = self._get_openocd_interface(link, board)
openocd_interface = link server_args = self._get_debug_server_args(openocd_interface, debug)
elif link in ("esp-prog", "ftdi"):
if board.id == "esp32-s2-kaluga-1":
openocd_interface = "ftdi/esp32s2_kaluga_v1"
else:
openocd_interface = "ftdi/esp32_devkitj_v1"
elif link == "esp-bridge":
openocd_interface = "esp_usb_bridge"
elif link == "esp-builtin":
openocd_interface = "esp_usb_jtag"
else:
openocd_interface = "ftdi/" + link
server_args = [
"-s",
"$PACKAGE_DIR/share/openocd/scripts",
"-f",
"interface/%s.cfg" % openocd_interface,
"-f",
"%s/%s"
% (
("target", debug.get("openocd_target"))
if "openocd_target" in debug
else ("board", debug.get("openocd_board"))
),
]
debug["tools"][link] = { debug["tools"][link] = {
"server": { "server": {
@@ -229,14 +591,43 @@ class Espressif32Platform(PlatformBase):
board.manifest["debug"] = debug board.manifest["debug"] = debug
return board return board
def _get_openocd_interface(self, link: str, board) -> str:
"""Determine OpenOCD interface configuration for debug link."""
if link in ("jlink", "cmsis-dap"):
return link
if link in ("esp-prog", "ftdi"):
if board.id == "esp32-s2-kaluga-1":
return "ftdi/esp32s2_kaluga_v1"
return "ftdi/esp32_devkitj_v1"
if link == "esp-bridge":
return "esp_usb_bridge"
if link == "esp-builtin":
return "esp_usb_jtag"
return f"ftdi/{link}"
def _get_debug_server_args(self, openocd_interface: str, debug: Dict) -> List[str]:
"""Generate debug server arguments for OpenOCD configuration."""
if 'openocd_target' in debug:
config_type = 'target'
config_name = debug.get('openocd_target')
else:
config_type = 'board'
config_name = debug.get('openocd_board')
return [
"-s", "$PACKAGE_DIR/share/openocd/scripts",
"-f", f"interface/{openocd_interface}.cfg",
"-f", f"{config_type}/{config_name}.cfg"
]
def configure_debug_session(self, debug_config): def configure_debug_session(self, debug_config):
"""Configure debug session with flash image loading."""
build_extra_data = debug_config.build_data.get("extra", {}) build_extra_data = debug_config.build_data.get("extra", {})
flash_images = build_extra_data.get("flash_images", []) flash_images = build_extra_data.get("flash_images", [])
if "openocd" in (debug_config.server or {}).get("executable", ""): if "openocd" in (debug_config.server or {}).get("executable", ""):
debug_config.server["arguments"].extend( debug_config.server["arguments"].extend([
["-c", "adapter speed %s" % (debug_config.speed or "5000")] "-c", f"adapter speed {debug_config.speed or DEFAULT_DEBUG_SPEED}"
) ])
ignore_conds = [ ignore_conds = [
debug_config.load_cmds != ["load"], debug_config.load_cmds != ["load"],
@@ -248,16 +639,13 @@ class Espressif32Platform(PlatformBase):
return return
load_cmds = [ load_cmds = [
'monitor program_esp "{{{path}}}" {offset} verify'.format( f'monitor program_esp "{to_unix_path(item["path"])}" '
path=to_unix_path(item["path"]), offset=item["offset"] f'{item["offset"]} verify'
)
for item in flash_images for item in flash_images
] ]
load_cmds.append( load_cmds.append(
'monitor program_esp "{%s.bin}" %s verify' f'monitor program_esp '
% ( f'"{to_unix_path(debug_config.build_data["prog_path"][:-4])}.bin" '
to_unix_path(debug_config.build_data["prog_path"][:-4]), f'{build_extra_data.get("application_offset", DEFAULT_APP_OFFSET)} verify'
build_extra_data.get("application_offset", "0x10000"),
)
) )
debug_config.load_cmds = load_cmds debug_config.load_cmds = load_cmds