Compare commits

..

13 Commits

Author SHA1 Message Date
J. Nick Koston
14be8253ab Merge branch 'dev' into esp32_compile_time 2026-01-28 18:21:55 -10:00
J. Nick Koston
74c84c8747 [esp32] Add advanced sdkconfig options to reduce build time and binary size (#13611) 2026-01-28 18:20:39 -10:00
rwrozelle
3e9a6c582e [mdns] Do not broadcast registration when using openthread component (#13592) 2026-01-28 18:16:59 -10:00
J. Nick Koston
d91ebd2113 test 2026-01-28 18:04:27 -10:00
Keith Burzinski
084113926c [es8156] Add bits_per_sample validation, comment code (#13612) 2026-01-28 22:03:50 -06:00
J. Nick Koston
a10cc04e3b add user escape hatch 2026-01-28 17:52:00 -10:00
J. Nick Koston
06ae11e002 address bot comemnt 2026-01-28 17:49:29 -10:00
J. Nick Koston
a5f60750c2 [tx20] Eliminate heap allocations in wind sensor (#13298) 2026-01-29 16:07:41 +13:00
J. Nick Koston
183081cfbc some stragglers 2026-01-28 13:56:45 -10:00
Clyde Stubbs
a382383d83 [workflows] Add deprecation check (#13584) 2026-01-29 12:08:45 +13:00
J. Nick Koston
cd96c1fe18 rename 2026-01-28 13:07:37 -10:00
J. Nick Koston
fd564352c8 lcd 2026-01-28 13:03:59 -10:00
J. Nick Koston
52d0f1cc68 reduce esp32 compile times 2026-01-28 11:51:40 -10:00
29 changed files with 506 additions and 45 deletions

View File

@@ -3,6 +3,7 @@ module.exports = {
BOT_COMMENT_MARKER: '<!-- auto-label-pr-bot -->',
CODEOWNERS_MARKER: '<!-- codeowners-request -->',
TOO_BIG_MARKER: '<!-- too-big-request -->',
DEPRECATED_COMPONENT_MARKER: '<!-- deprecated-component-request -->',
MANAGED_LABELS: [
'new-component',
@@ -27,6 +28,7 @@ module.exports = {
'breaking-change',
'developer-breaking-change',
'code-quality',
'deprecated-component'
],
DOCS_PR_PATTERNS: [

View File

@@ -251,6 +251,76 @@ async function detectPRTemplateCheckboxes(context) {
return labels;
}
// Strategy: Deprecated component detection
async function detectDeprecatedComponents(github, context, changedFiles) {
const labels = new Set();
const deprecatedInfo = [];
const { owner, repo } = context.repo;
// Compile regex once for better performance
const componentFileRegex = /^esphome\/components\/([^\/]+)\//;
// Get files that are modified or added in components directory
const componentFiles = changedFiles.filter(file => componentFileRegex.test(file));
if (componentFiles.length === 0) {
return { labels, deprecatedInfo };
}
// Extract unique component names using the same regex
const components = new Set();
for (const file of componentFiles) {
const match = file.match(componentFileRegex);
if (match) {
components.add(match[1]);
}
}
// Get PR head to fetch files from the PR branch
const prNumber = context.payload.pull_request.number;
// Check each component's __init__.py for DEPRECATED_COMPONENT constant
for (const component of components) {
const initFile = `esphome/components/${component}/__init__.py`;
try {
// Fetch file content from PR head using GitHub API
const { data: fileData } = await github.rest.repos.getContent({
owner,
repo,
path: initFile,
ref: `refs/pull/${prNumber}/head`
});
// Decode base64 content
const content = Buffer.from(fileData.content, 'base64').toString('utf8');
// Look for DEPRECATED_COMPONENT = "message" or DEPRECATED_COMPONENT = 'message'
// Support single quotes, double quotes, and triple quotes (for multiline)
const doubleQuoteMatch = content.match(/DEPRECATED_COMPONENT\s*=\s*"""([\s\S]*?)"""/s) ||
content.match(/DEPRECATED_COMPONENT\s*=\s*"((?:[^"\\]|\\.)*)"/);
const singleQuoteMatch = content.match(/DEPRECATED_COMPONENT\s*=\s*'''([\s\S]*?)'''/s) ||
content.match(/DEPRECATED_COMPONENT\s*=\s*'((?:[^'\\]|\\.)*)'/);
const deprecatedMatch = doubleQuoteMatch || singleQuoteMatch;
if (deprecatedMatch) {
labels.add('deprecated-component');
deprecatedInfo.push({
component: component,
message: deprecatedMatch[1].trim()
});
console.log(`Found deprecated component: ${component}`);
}
} catch (error) {
// Only log if it's not a simple "file not found" error (404)
if (error.status !== 404) {
console.log(`Error reading ${initFile}:`, error.message);
}
}
}
return { labels, deprecatedInfo };
}
// Strategy: Requirements detection
async function detectRequirements(allLabels, prFiles, context) {
const labels = new Set();
@@ -298,5 +368,6 @@ module.exports = {
detectCodeOwner,
detectTests,
detectPRTemplateCheckboxes,
detectDeprecatedComponents,
detectRequirements
};

View File

@@ -11,6 +11,7 @@ const {
detectCodeOwner,
detectTests,
detectPRTemplateCheckboxes,
detectDeprecatedComponents,
detectRequirements
} = require('./detectors');
const { handleReviews } = require('./reviews');
@@ -112,6 +113,7 @@ module.exports = async ({ github, context }) => {
codeOwnerLabels,
testLabels,
checkboxLabels,
deprecatedResult
] = await Promise.all([
detectMergeBranch(context),
detectComponentPlatforms(changedFiles, apiData),
@@ -124,8 +126,13 @@ module.exports = async ({ github, context }) => {
detectCodeOwner(github, context, changedFiles),
detectTests(changedFiles),
detectPRTemplateCheckboxes(context),
detectDeprecatedComponents(github, context, changedFiles)
]);
// Extract deprecated component info
const deprecatedLabels = deprecatedResult.labels;
const deprecatedInfo = deprecatedResult.deprecatedInfo;
// Combine all labels
const allLabels = new Set([
...branchLabels,
@@ -139,6 +146,7 @@ module.exports = async ({ github, context }) => {
...codeOwnerLabels,
...testLabels,
...checkboxLabels,
...deprecatedLabels
]);
// Detect requirements based on all other labels
@@ -169,7 +177,7 @@ module.exports = async ({ github, context }) => {
console.log('Computed labels:', finalLabels.join(', '));
// Handle reviews
await handleReviews(github, context, finalLabels, originalLabelCount, prFiles, totalAdditions, totalDeletions, MAX_LABELS, TOO_BIG_THRESHOLD);
await handleReviews(github, context, finalLabels, originalLabelCount, deprecatedInfo, prFiles, totalAdditions, totalDeletions, MAX_LABELS, TOO_BIG_THRESHOLD);
// Apply labels
await applyLabels(github, context, finalLabels);

View File

@@ -2,12 +2,29 @@ const {
BOT_COMMENT_MARKER,
CODEOWNERS_MARKER,
TOO_BIG_MARKER,
DEPRECATED_COMPONENT_MARKER
} = require('./constants');
// Generate review messages
function generateReviewMessages(finalLabels, originalLabelCount, prFiles, totalAdditions, totalDeletions, prAuthor, MAX_LABELS, TOO_BIG_THRESHOLD) {
function generateReviewMessages(finalLabels, originalLabelCount, deprecatedInfo, prFiles, totalAdditions, totalDeletions, prAuthor, MAX_LABELS, TOO_BIG_THRESHOLD) {
const messages = [];
// Deprecated component message
if (finalLabels.includes('deprecated-component') && deprecatedInfo && deprecatedInfo.length > 0) {
let message = `${DEPRECATED_COMPONENT_MARKER}\n### ⚠️ Deprecated Component\n\n`;
message += `Hey there @${prAuthor},\n`;
message += `This PR modifies one or more deprecated components. Please be aware:\n\n`;
for (const info of deprecatedInfo) {
message += `#### Component: \`${info.component}\`\n`;
message += `${info.message}\n\n`;
}
message += `Consider migrating to the recommended alternative if applicable.`;
messages.push(message);
}
// Too big message
if (finalLabels.includes('too-big')) {
const testAdditions = prFiles
@@ -54,14 +71,14 @@ function generateReviewMessages(finalLabels, originalLabelCount, prFiles, totalA
}
// Handle reviews
async function handleReviews(github, context, finalLabels, originalLabelCount, prFiles, totalAdditions, totalDeletions, MAX_LABELS, TOO_BIG_THRESHOLD) {
async function handleReviews(github, context, finalLabels, originalLabelCount, deprecatedInfo, prFiles, totalAdditions, totalDeletions, MAX_LABELS, TOO_BIG_THRESHOLD) {
const { owner, repo } = context.repo;
const pr_number = context.issue.number;
const prAuthor = context.payload.pull_request.user.login;
const reviewMessages = generateReviewMessages(finalLabels, originalLabelCount, prFiles, totalAdditions, totalDeletions, prAuthor, MAX_LABELS, TOO_BIG_THRESHOLD);
const reviewMessages = generateReviewMessages(finalLabels, originalLabelCount, deprecatedInfo, prFiles, totalAdditions, totalDeletions, prAuthor, MAX_LABELS, TOO_BIG_THRESHOLD);
const hasReviewableLabels = finalLabels.some(label =>
['too-big', 'needs-codeowners'].includes(label)
['too-big', 'needs-codeowners', 'deprecated-component'].includes(label)
);
const { data: reviews } = await github.rest.pulls.listReviews({

View File

@@ -2,7 +2,7 @@ import logging
import esphome.codegen as cg
from esphome.components import sensor, voltage_sampler
from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32 import get_esp32_variant, include_idf_component
from esphome.components.nrf52.const import AIN_TO_GPIO, EXTRA_ADC
from esphome.components.zephyr import (
zephyr_add_overlay,
@@ -118,6 +118,9 @@ async def to_code(config):
cg.add(var.set_sampling_mode(config[CONF_SAMPLING_MODE]))
if CORE.is_esp32:
# Re-enable ESP-IDF's ADC driver (excluded by default to save compile time)
include_idf_component("esp_adc")
if attenuation := config.get(CONF_ATTENUATION):
if attenuation == "auto":
cg.add(var.set_autorange(cg.global_ns.true))

View File

@@ -1,5 +1,5 @@
import esphome.codegen as cg
from esphome.components.esp32 import add_idf_component
from esphome.components.esp32 import add_idf_component, include_idf_component
import esphome.config_validation as cv
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_NUM_CHANNELS, CONF_SAMPLE_RATE
import esphome.final_validate as fv
@@ -166,6 +166,9 @@ def final_validate_audio_schema(
async def to_code(config):
# Re-enable ESP-IDF's HTTP client (excluded by default to save compile time)
include_idf_component("esp_http_client")
add_idf_component(
name="esphome/esp-audio-libs",
ref="2.0.3",

View File

@@ -15,7 +15,7 @@ from esphome.const import (
CONF_UPDATE_INTERVAL,
SCHEDULER_DONT_RUN,
)
from esphome.core import CoroPriority, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -222,3 +222,8 @@ async def display_is_displaying_page_to_code(config, condition_id, template_arg,
async def to_code(config):
cg.add_global(display_ns.using)
cg.add_define("USE_DISPLAY")
if CORE.is_esp32:
# Re-enable ESP-IDF's LCD driver (excluded by default to save compile time)
from esphome.components.esp32 import include_idf_component
include_idf_component("esp_lcd")

View File

@@ -2,11 +2,14 @@ import esphome.codegen as cg
from esphome.components import i2c
from esphome.components.audio_dac import AudioDac
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID
import esphome.final_validate as fv
CODEOWNERS = ["@kbx81"]
DEPENDENCIES = ["i2c"]
CONF_AUDIO_DAC = "audio_dac"
es8156_ns = cg.esphome_ns.namespace("es8156")
ES8156 = es8156_ns.class_("ES8156", AudioDac, cg.Component, i2c.I2CDevice)
@@ -21,6 +24,29 @@ CONFIG_SCHEMA = (
)
def _final_validate(config):
full_config = fv.full_config.get()
# Check all speaker configurations for ones that reference this es8156
speaker_configs = full_config.get("speaker", [])
for speaker_config in speaker_configs:
audio_dac_id = speaker_config.get(CONF_AUDIO_DAC)
if (
audio_dac_id is not None
and audio_dac_id == config[CONF_ID]
and (bits_per_sample := speaker_config.get(CONF_BITS_PER_SAMPLE))
is not None
and bits_per_sample > 24
):
raise cv.Invalid(
f"ES8156 does not support more than 24 bits per sample. "
f"The speaker referencing this audio_dac has bits_per_sample set to {bits_per_sample}."
)
FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)

View File

@@ -17,24 +17,61 @@ static const char *const TAG = "es8156";
}
void ES8156::setup() {
// REG02 MODE CONFIG 1: Enable software mode for I2C control of volume/mute
// Bit 2: SOFT_MODE_SEL=1 (software mode enabled)
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG02_SCLK_MODE, 0x04));
// Analog system configuration (active-low power down bits, active-high enables)
// REG20 ANALOG SYSTEM: Configure analog signal path
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG20_ANALOG_SYS1, 0x2A));
// REG21 ANALOG SYSTEM: VSEL=0x1C (bias level ~120%), normal VREF ramp speed
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG21_ANALOG_SYS2, 0x3C));
// REG22 ANALOG SYSTEM: Line out mode (HPSW=0), OUT_MUTE=0 (not muted)
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG22_ANALOG_SYS3, 0x00));
// REG24 ANALOG SYSTEM: Low power mode for VREFBUF, HPCOM, DACVRP; DAC normal power
// Bits 2:0 = 0x07: LPVREFBUF=1, LPHPCOM=1, LPDACVRP=1, LPDAC=0
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG24_ANALOG_LP, 0x07));
// REG23 ANALOG SYSTEM: Lowest bias (IBIAS_SW=0), VMIDLVL=VDDA/2, normal impedance
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG23_ANALOG_SYS4, 0x00));
// Timing and interface configuration
// REG0A/0B TIME CONTROL: Fast state machine transitions
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0A_TIME_CONTROL1, 0x01));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0B_TIME_CONTROL2, 0x01));
// REG11 SDP INTERFACE CONFIG: Default I2S format (24-bit, I2S mode)
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG11_DAC_SDP, 0x00));
// REG19 EQ CONTROL 1: EQ disabled (EQ_ON=0), EQ_BAND_NUM=2
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG19_EQ_CONTROL1, 0x20));
// REG0D P2S CONTROL: Parallel-to-serial converter settings
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0D_P2S_CONTROL, 0x14));
// REG09 MISC CONTROL 2: Default settings
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG09_MISC_CONTROL2, 0x00));
// REG18 MISC CONTROL 3: Stereo channel routing, no inversion
// Bits 5:4 CHN_CROSS: 0=L→L/R→R, 1=L to both, 2=R to both, 3=swap L/R
// Bits 3:2: LCH_INV/RCH_INV channel inversion
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG18_MISC_CONTROL3, 0x00));
// REG08 CLOCK OFF: Enable all internal clocks (0x3F = all clock gates open)
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG08_CLOCK_ON_OFF, 0x3F));
// REG00 RESET CONTROL: Reset sequence
// First: RST_DIG=1 (assert digital reset)
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x02));
// Then: CSM_ON=1 (enable chip state machine), RST_DIG=1
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x03));
// REG25 ANALOG SYSTEM: Power up analog blocks
// VMIDSEL=2 (normal VMID operation), PDN_ANA=0, ENREFR=0, ENHPCOM=0
// PDN_DACVREFGEN=0, PDN_VREFBUF=0, PDN_DAC=0 (all enabled)
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG25_ANALOG_SYS5, 0x20));
}

View File

@@ -53,6 +53,7 @@ from .const import ( # noqa
KEY_BOARD,
KEY_COMPONENTS,
KEY_ESP32,
KEY_EXCLUDE_COMPONENTS,
KEY_EXTRA_BUILD_FILES,
KEY_FLASH_SIZE,
KEY_FULL_CERT_BUNDLE,
@@ -86,6 +87,7 @@ IS_TARGET_PLATFORM = True
CONF_ASSERTION_LEVEL = "assertion_level"
CONF_COMPILER_OPTIMIZATION = "compiler_optimization"
CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES = "enable_idf_experimental_features"
CONF_INCLUDE_IDF_COMPONENTS = "include_idf_components"
CONF_ENABLE_LWIP_ASSERT = "enable_lwip_assert"
CONF_ENABLE_OTA_ROLLBACK = "enable_ota_rollback"
CONF_EXECUTE_FROM_PSRAM = "execute_from_psram"
@@ -114,6 +116,36 @@ COMPILER_OPTIMIZATIONS = {
"SIZE": "CONFIG_COMPILER_OPTIMIZATION_SIZE",
}
# ESP-IDF components excluded by default to reduce compile time.
# Components can be re-enabled by calling include_idf_component() in to_code().
#
# Cannot be excluded (dependencies of required components):
# - "console": espressif/mdns unconditionally depends on it
# - "sdmmc": driver -> esp_driver_sdmmc -> sdmmc dependency chain
DEFAULT_EXCLUDED_IDF_COMPONENTS = (
"cmock", # Unit testing mock framework - ESPHome doesn't use IDF's testing
"esp_adc", # ADC driver - only needed by adc component
"esp_driver_i2s", # I2S driver - only needed by i2s_audio component
"esp_driver_rmt", # RMT driver - only needed by remote_transmitter/receiver, neopixelbus
"esp_driver_touch_sens", # Touch sensor driver - only needed by esp32_touch
"esp_eth", # Ethernet driver - only needed by ethernet component
"esp_hid", # HID host/device support - ESPHome doesn't implement HID functionality
"esp_http_client", # HTTP client - only needed by http_request component
"esp_https_ota", # ESP-IDF HTTPS OTA - ESPHome has its own OTA implementation
"esp_https_server", # HTTPS server - ESPHome has its own web server
"esp_lcd", # LCD controller drivers - only needed by display component
"esp_local_ctrl", # Local control over HTTPS/BLE - ESPHome has native API
"espcoredump", # Core dump support - ESPHome has its own debug component
"fatfs", # FAT filesystem - ESPHome doesn't use filesystem storage
"mqtt", # ESP-IDF MQTT library - ESPHome has its own MQTT implementation
"perfmon", # Xtensa performance monitor - ESPHome has its own debug component
"protocomm", # Protocol communication for provisioning - unused by ESPHome
"spiffs", # SPIFFS filesystem - ESPHome doesn't use filesystem storage (IDF only)
"unity", # Unit testing framework - ESPHome doesn't use IDF's testing
"wear_levelling", # Flash wear levelling for fatfs - unused since fatfs unused
"wifi_provisioning", # WiFi provisioning - ESPHome uses its own improv implementation
)
# ESP32 (original) chip revision options
# Setting minimum revision to 3.0 or higher:
# - Reduces flash size by excluding workaround code for older chip bugs
@@ -203,6 +235,9 @@ def set_core_data(config):
)
CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS] = {}
CORE.data[KEY_ESP32][KEY_COMPONENTS] = {}
# Initialize with default exclusions - components can call include_idf_component()
# to re-enable any they need
CORE.data[KEY_ESP32][KEY_EXCLUDE_COMPONENTS] = set(DEFAULT_EXCLUDED_IDF_COMPONENTS)
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse(
config[CONF_FRAMEWORK][CONF_VERSION]
)
@@ -328,6 +363,28 @@ def add_idf_component(
}
def exclude_idf_component(name: str) -> None:
"""Exclude an ESP-IDF component from the build.
This reduces compile time by skipping components that are not needed.
The component will be passed to ESP-IDF's EXCLUDE_COMPONENTS cmake variable.
Note: Components that are dependencies of other required components
cannot be excluded - ESP-IDF will still build them.
"""
CORE.data[KEY_ESP32][KEY_EXCLUDE_COMPONENTS].add(name)
def include_idf_component(name: str) -> None:
"""Remove an ESP-IDF component from the exclusion list.
Call this from components that need an ESP-IDF component that is
excluded by default in DEFAULT_EXCLUDED_IDF_COMPONENTS. This ensures the
component will be built when needed.
"""
CORE.data[KEY_ESP32][KEY_EXCLUDE_COMPONENTS].discard(name)
def add_extra_script(stage: str, filename: str, path: Path):
"""Add an extra script to the project."""
key = f"{stage}:{filename}"
@@ -672,11 +729,25 @@ CONF_RINGBUF_IN_IRAM = "ringbuf_in_iram"
CONF_HEAP_IN_IRAM = "heap_in_iram"
CONF_LOOP_TASK_STACK_SIZE = "loop_task_stack_size"
CONF_USE_FULL_CERTIFICATE_BUNDLE = "use_full_certificate_bundle"
CONF_DISABLE_DEBUG_STUBS = "disable_debug_stubs"
CONF_DISABLE_OCD_AWARE = "disable_ocd_aware"
CONF_DISABLE_USB_SERIAL_JTAG_SECONDARY = "disable_usb_serial_jtag_secondary"
CONF_DISABLE_DEV_NULL_VFS = "disable_dev_null_vfs"
CONF_DISABLE_MBEDTLS_PEER_CERT = "disable_mbedtls_peer_cert"
CONF_DISABLE_MBEDTLS_PKCS7 = "disable_mbedtls_pkcs7"
CONF_DISABLE_REGI2C_IN_IRAM = "disable_regi2c_in_iram"
CONF_DISABLE_FATFS = "disable_fatfs"
# VFS requirement tracking
# Components that need VFS features can call require_vfs_select() or require_vfs_dir()
KEY_VFS_SELECT_REQUIRED = "vfs_select_required"
KEY_VFS_DIR_REQUIRED = "vfs_dir_required"
# Feature requirement tracking - components can call require_* functions to re-enable
# These are stored in CORE.data[KEY_ESP32] dict
KEY_USB_SERIAL_JTAG_SECONDARY_REQUIRED = "usb_serial_jtag_secondary_required"
KEY_MBEDTLS_PEER_CERT_REQUIRED = "mbedtls_peer_cert_required"
KEY_MBEDTLS_PKCS7_REQUIRED = "mbedtls_pkcs7_required"
KEY_FATFS_REQUIRED = "fatfs_required"
def require_vfs_select() -> None:
@@ -709,6 +780,43 @@ def require_full_certificate_bundle() -> None:
CORE.data[KEY_ESP32][KEY_FULL_CERT_BUNDLE] = True
def require_usb_serial_jtag_secondary() -> None:
"""Mark that USB Serial/JTAG secondary console is required by a component.
Call this from components (e.g., logger) that need USB Serial/JTAG console output.
This prevents CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG from being disabled.
"""
CORE.data[KEY_ESP32][KEY_USB_SERIAL_JTAG_SECONDARY_REQUIRED] = True
def require_mbedtls_peer_cert() -> None:
"""Mark that mbedTLS peer certificate retention is required by a component.
Call this from components that need access to the peer certificate after
the TLS handshake is complete. This prevents CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
from being disabled.
"""
CORE.data[KEY_ESP32][KEY_MBEDTLS_PEER_CERT_REQUIRED] = True
def require_mbedtls_pkcs7() -> None:
"""Mark that mbedTLS PKCS#7 support is required by a component.
Call this from components that need PKCS#7 certificate validation.
This prevents CONFIG_MBEDTLS_PKCS7_C from being disabled.
"""
CORE.data[KEY_ESP32][KEY_MBEDTLS_PKCS7_REQUIRED] = True
def require_fatfs() -> None:
"""Mark that FATFS support is required by a component.
Call this from components that use FATFS (e.g., SD card, storage components).
This prevents FATFS from being disabled when disable_fatfs is set.
"""
CORE.data[KEY_ESP32][KEY_FATFS_REQUIRED] = True
def _parse_idf_component(value: str) -> ConfigType:
"""Parse IDF component shorthand syntax like 'owner/component^version'"""
# Match operator followed by version-like string (digit or *)
@@ -793,6 +901,19 @@ FRAMEWORK_SCHEMA = cv.Schema(
cv.Optional(
CONF_USE_FULL_CERTIFICATE_BUNDLE, default=False
): cv.boolean,
cv.Optional(CONF_INCLUDE_IDF_COMPONENTS, default=[]): cv.ensure_list(
cv.string_strict
),
cv.Optional(CONF_DISABLE_DEBUG_STUBS, default=True): cv.boolean,
cv.Optional(CONF_DISABLE_OCD_AWARE, default=True): cv.boolean,
cv.Optional(
CONF_DISABLE_USB_SERIAL_JTAG_SECONDARY, default=True
): cv.boolean,
cv.Optional(CONF_DISABLE_DEV_NULL_VFS, default=True): cv.boolean,
cv.Optional(CONF_DISABLE_MBEDTLS_PEER_CERT, default=True): cv.boolean,
cv.Optional(CONF_DISABLE_MBEDTLS_PKCS7, default=True): cv.boolean,
cv.Optional(CONF_DISABLE_REGI2C_IN_IRAM, default=True): cv.boolean,
cv.Optional(CONF_DISABLE_FATFS, default=True): cv.boolean,
}
),
cv.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list(
@@ -982,6 +1103,19 @@ def _configure_lwip_max_sockets(conf: dict) -> None:
add_idf_sdkconfig_option("CONFIG_LWIP_MAX_SOCKETS", max_sockets)
@coroutine_with_priority(CoroPriority.FINAL)
async def _write_exclude_components() -> None:
"""Write EXCLUDE_COMPONENTS cmake arg after all components have registered exclusions."""
if KEY_ESP32 not in CORE.data:
return
excluded = CORE.data[KEY_ESP32].get(KEY_EXCLUDE_COMPONENTS)
if excluded:
exclude_list = ";".join(sorted(excluded))
cg.add_platformio_option(
"board_build.cmake_extra_args", f"-DEXCLUDE_COMPONENTS={exclude_list}"
)
@coroutine_with_priority(CoroPriority.FINAL)
async def _add_yaml_idf_components(components: list[ConfigType]):
"""Add IDF components from YAML config with final priority to override code-added components."""
@@ -1195,6 +1329,11 @@ async def to_code(config):
# Apply LWIP optimization settings
advanced = conf[CONF_ADVANCED]
# Re-include any IDF components the user explicitly requested
for component_name in advanced.get(CONF_INCLUDE_IDF_COMPONENTS, []):
include_idf_component(component_name)
# DHCP server: only disable if explicitly set to false
# WiFi component handles its own optimization when AP mode is not used
# When using Arduino with Ethernet, DHCP server functions must be available
@@ -1316,6 +1455,61 @@ async def to_code(config):
add_idf_sdkconfig_option(f"CONFIG_LOG_DEFAULT_LEVEL_{conf[CONF_LOG_LEVEL]}", True)
# Disable OpenOCD debug stubs to save code size
# These are used for on-chip debugging with OpenOCD/JTAG, rarely needed for ESPHome
if advanced[CONF_DISABLE_DEBUG_STUBS]:
add_idf_sdkconfig_option("CONFIG_ESP_DEBUG_STUBS_ENABLE", False)
# Disable OCD-aware exception handlers
# When enabled, the panic handler detects JTAG debugger and halts instead of resetting
# Most ESPHome users don't use JTAG debugging
if advanced[CONF_DISABLE_OCD_AWARE]:
add_idf_sdkconfig_option("CONFIG_ESP_DEBUG_OCDAWARE", False)
# Disable USB Serial/JTAG secondary console
# Components like logger can call require_usb_serial_jtag_secondary() to re-enable
if CORE.data[KEY_ESP32].get(KEY_USB_SERIAL_JTAG_SECONDARY_REQUIRED, False):
add_idf_sdkconfig_option("CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG", True)
elif advanced[CONF_DISABLE_USB_SERIAL_JTAG_SECONDARY]:
add_idf_sdkconfig_option("CONFIG_ESP_CONSOLE_SECONDARY_NONE", True)
# Disable /dev/null VFS initialization
# ESPHome doesn't typically need /dev/null
if advanced[CONF_DISABLE_DEV_NULL_VFS]:
add_idf_sdkconfig_option("CONFIG_VFS_INITIALIZE_DEV_NULL", False)
# Disable keeping peer certificate after TLS handshake
# Saves ~4KB heap per connection, but prevents certificate inspection after handshake
# Components that need it can call require_mbedtls_peer_cert()
if CORE.data[KEY_ESP32].get(KEY_MBEDTLS_PEER_CERT_REQUIRED, False):
add_idf_sdkconfig_option("CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE", True)
elif advanced[CONF_DISABLE_MBEDTLS_PEER_CERT]:
add_idf_sdkconfig_option("CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE", False)
# Disable PKCS#7 support in mbedTLS
# Only needed for specific certificate validation scenarios
# Components that need it can call require_mbedtls_pkcs7()
if CORE.data[KEY_ESP32].get(KEY_MBEDTLS_PKCS7_REQUIRED, False):
# Component called require_mbedtls_pkcs7() - enable regardless of user setting
add_idf_sdkconfig_option("CONFIG_MBEDTLS_PKCS7_C", True)
elif advanced[CONF_DISABLE_MBEDTLS_PKCS7]:
add_idf_sdkconfig_option("CONFIG_MBEDTLS_PKCS7_C", False)
# Disable regi2c control functions in IRAM
# Only needed if using analog peripherals (ADC, DAC, etc.) from ISRs while cache is disabled
if advanced[CONF_DISABLE_REGI2C_IN_IRAM]:
add_idf_sdkconfig_option("CONFIG_ESP_REGI2C_CTRL_FUNC_IN_IRAM", False)
# Disable FATFS support
# Components that need FATFS (SD card, etc.) can call require_fatfs()
if CORE.data[KEY_ESP32].get(KEY_FATFS_REQUIRED, False):
# Component called require_fatfs() - enable regardless of user setting
add_idf_sdkconfig_option("CONFIG_FATFS_LFN_NONE", False)
add_idf_sdkconfig_option("CONFIG_FATFS_VOLUME_COUNT", 2)
elif advanced[CONF_DISABLE_FATFS]:
add_idf_sdkconfig_option("CONFIG_FATFS_LFN_NONE", True)
add_idf_sdkconfig_option("CONFIG_FATFS_VOLUME_COUNT", 0)
for name, value in conf[CONF_SDKCONFIG_OPTIONS].items():
add_idf_sdkconfig_option(name, RawSdkconfigValue(value))
@@ -1324,6 +1518,11 @@ async def to_code(config):
if conf[CONF_COMPONENTS]:
CORE.add_job(_add_yaml_idf_components, conf[CONF_COMPONENTS])
# Write EXCLUDE_COMPONENTS at FINAL priority after all components have had
# a chance to call include_idf_component() to re-enable components they need.
# Default exclusions are added in set_core_data() during config validation.
CORE.add_job(_write_exclude_components)
APP_PARTITION_SIZES = {
"2MB": 0x0C0000, # 768 KB

View File

@@ -6,6 +6,7 @@ KEY_FLASH_SIZE = "flash_size"
KEY_VARIANT = "variant"
KEY_SDKCONFIG_OPTIONS = "sdkconfig_options"
KEY_COMPONENTS = "components"
KEY_EXCLUDE_COMPONENTS = "exclude_components"
KEY_REPO = "repo"
KEY_REF = "ref"
KEY_REFRESH = "refresh"

View File

@@ -5,6 +5,7 @@ from esphome import pins
import esphome.codegen as cg
from esphome.components import esp32, light
from esphome.components.const import CONF_USE_PSRAM
from esphome.components.esp32 import include_idf_component
import esphome.config_validation as cv
from esphome.const import (
CONF_CHIPSET,
@@ -129,6 +130,9 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
# Re-enable ESP-IDF's RMT driver (excluded by default to save compile time)
include_idf_component("esp_driver_rmt")
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
await light.register_light(var, config)
await cg.register_component(var, config)

View File

@@ -6,6 +6,7 @@ from esphome.components.esp32 import (
VARIANT_ESP32S3,
get_esp32_variant,
gpio,
include_idf_component,
)
import esphome.config_validation as cv
from esphome.const import (
@@ -266,6 +267,9 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
# Re-enable ESP-IDF's touch sensor driver (excluded by default to save compile time)
include_idf_component("esp_driver_touch_sens")
touch = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(touch, config)

View File

@@ -14,6 +14,7 @@ from esphome.components.esp32 import (
add_idf_component,
add_idf_sdkconfig_option,
get_esp32_variant,
include_idf_component,
)
from esphome.components.network import ip_address_literal
from esphome.components.spi import CONF_INTERFACE_INDEX, get_spi_interface
@@ -419,6 +420,9 @@ async def to_code(config):
# Also disable WiFi/BT coexistence since WiFi is disabled
add_idf_sdkconfig_option("CONFIG_SW_COEXIST_ENABLE", False)
# Re-enable ESP-IDF's Ethernet driver (excluded by default to save compile time)
include_idf_component("esp_eth")
if config[CONF_TYPE] == "LAN8670":
# Add LAN867x 10BASE-T1S PHY support component
add_idf_component(name="espressif/lan867x", ref="2.0.0")

View File

@@ -155,6 +155,9 @@ async def to_code(config):
cg.add(var.set_watchdog_timeout(timeout_ms))
if CORE.is_esp32:
# Re-enable ESP-IDF's HTTP client (excluded by default to save compile time)
esp32.include_idf_component("esp_http_client")
cg.add(var.set_buffer_size_rx(config[CONF_BUFFER_SIZE_RX]))
cg.add(var.set_buffer_size_tx(config[CONF_BUFFER_SIZE_TX]))
cg.add(var.set_verify_ssl(config[CONF_VERIFY_SSL]))

View File

@@ -90,14 +90,16 @@ void HttpRequestUpdate::update_task(void *params) {
UPDATE_RETURN;
}
size_t read_index = container->get_bytes_read();
size_t content_length = container->content_length;
container->end();
container.reset(); // Release ownership of the container's shared_ptr
bool valid = false;
{ // Scope to ensure JsonDocument is destroyed before deallocating buffer
valid = json::parse_json(data, read_index, [this_update](JsonObject root) -> bool {
{ // Ensures the response string falls out of scope and deallocates before the task ends
std::string response((char *) data, read_index);
allocator.deallocate(data, container->content_length);
container->end();
container.reset(); // Release ownership of the container's shared_ptr
valid = json::parse_json(response, [this_update](JsonObject root) -> bool {
if (!root[ESPHOME_F("name")].is<const char *>() || !root[ESPHOME_F("version")].is<const char *>() ||
!root[ESPHOME_F("builds")].is<JsonArray>()) {
ESP_LOGE(TAG, "Manifest does not contain required fields");
@@ -135,7 +137,6 @@ void HttpRequestUpdate::update_task(void *params) {
return false;
});
}
allocator.deallocate(data, content_length);
if (!valid) {
ESP_LOGE(TAG, "Failed to parse JSON from %s", this_update->source_url_.c_str());
@@ -156,12 +157,17 @@ void HttpRequestUpdate::update_task(void *params) {
}
}
{ // Ensures the current version string falls out of scope and deallocates before the task ends
std::string current_version;
#ifdef ESPHOME_PROJECT_VERSION
this_update->update_info_.current_version = ESPHOME_PROJECT_VERSION;
current_version = ESPHOME_PROJECT_VERSION;
#else
this_update->update_info_.current_version = ESPHOME_VERSION;
current_version = ESPHOME_VERSION;
#endif
this_update->update_info_.current_version = current_version;
}
bool trigger_update_available = false;
if (this_update->update_info_.latest_version.empty() ||

View File

@@ -1,6 +1,11 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components.esp32 import (
add_idf_sdkconfig_option,
get_esp32_variant,
include_idf_component,
)
from esphome.components.esp32.const import (
VARIANT_ESP32,
VARIANT_ESP32C3,
VARIANT_ESP32C5,
@@ -10,8 +15,6 @@ from esphome.components.esp32 import (
VARIANT_ESP32P4,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
add_idf_sdkconfig_option,
get_esp32_variant,
)
import esphome.config_validation as cv
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE
@@ -272,6 +275,10 @@ FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
# Re-enable ESP-IDF's I2S driver (excluded by default to save compile time)
include_idf_component("esp_driver_i2s")
if use_legacy():
cg.add_define("USE_I2S_LEGACY")

View File

@@ -25,13 +25,8 @@ std::string build_json(const json_build_t &f) {
}
bool parse_json(const std::string &data, const json_parse_t &f) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
return parse_json(reinterpret_cast<const uint8_t *>(data.c_str()), data.size(), f);
}
bool parse_json(const uint8_t *data, size_t len, const json_parse_t &f) {
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
JsonDocument doc = parse_json(data, len);
JsonDocument doc = parse_json(reinterpret_cast<const uint8_t *>(data.c_str()), data.size());
if (doc.overflowed() || doc.isNull())
return false;
return f(doc.as<JsonObject>());

View File

@@ -50,8 +50,6 @@ std::string build_json(const json_build_t &f);
/// Parse a JSON string and run the provided json parse function if it's valid.
bool parse_json(const std::string &data, const json_parse_t &f);
/// Parse JSON from raw bytes and run the provided json parse function if it's valid.
bool parse_json(const uint8_t *data, size_t len, const json_parse_t &f);
/// Parse a JSON string and return the root JsonDocument (or an unbound object on error)
JsonDocument parse_json(const uint8_t *data, size_t len);

View File

@@ -12,6 +12,10 @@ namespace esphome::mdns {
static const char *const TAG = "mdns";
static void register_esp32(MDNSComponent *comp, StaticVector<MDNSService, MDNS_SERVICE_COUNT> &services) {
#ifdef USE_OPENTHREAD
// OpenThread handles service registration via SRP client
// Services are compiled by MDNSComponent::compile_records_() and consumed by OpenThreadSrpComponent
#else
esp_err_t err = mdns_init();
if (err != ESP_OK) {
ESP_LOGW(TAG, "Init failed: %s", esp_err_to_name(err));
@@ -41,13 +45,16 @@ static void register_esp32(MDNSComponent *comp, StaticVector<MDNSService, MDNS_S
ESP_LOGW(TAG, "Failed to register service %s: %s", MDNS_STR_ARG(service.service_type), esp_err_to_name(err));
}
}
#endif
}
void MDNSComponent::setup() { this->setup_buffers_and_register_(register_esp32); }
void MDNSComponent::on_shutdown() {
#ifndef USE_OPENTHREAD
mdns_free();
delay(40); // Allow the mdns packets announcing service removal to be sent
#endif
}
} // namespace esphome::mdns

View File

@@ -4,7 +4,7 @@ from esphome import automation
from esphome.automation import Condition
import esphome.codegen as cg
from esphome.components import logger, socket
from esphome.components.esp32 import add_idf_sdkconfig_option
from esphome.components.esp32 import add_idf_sdkconfig_option, include_idf_component
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv
from esphome.const import (
@@ -360,6 +360,8 @@ async def to_code(config):
# This enables low-latency MQTT event processing instead of waiting for select() timeout
if CORE.is_esp32:
socket.require_wake_loop_threadsafe()
# Re-enable ESP-IDF's mqtt component (excluded by default to save compile time)
include_idf_component("mqtt")
cg.add_define("USE_MQTT")
cg.add_global(mqtt_ns.using)

View File

@@ -1,7 +1,12 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components import light
from esphome.components.esp32 import VARIANT_ESP32C3, VARIANT_ESP32S3, get_esp32_variant
from esphome.components.esp32 import (
VARIANT_ESP32C3,
VARIANT_ESP32S3,
get_esp32_variant,
include_idf_component,
)
import esphome.config_validation as cv
from esphome.const import (
CONF_CHANNEL,
@@ -205,6 +210,10 @@ async def to_code(config):
has_white = "W" in config[CONF_TYPE]
method = config[CONF_METHOD]
# Re-enable ESP-IDF's RMT driver if using RMT method (excluded by default)
if CORE.is_esp32 and method[CONF_TYPE] == METHOD_ESP32_RMT:
include_idf_component("esp_driver_rmt")
method_template = METHODS[method[CONF_TYPE]].to_code(
method, config[CONF_VARIANT], config[CONF_INVERT]
)

View File

@@ -177,6 +177,8 @@ async def to_code(config):
cg.add_define("USE_NEXTION_TFT_UPLOAD")
cg.add(var.set_tft_url(config[CONF_TFT_URL]))
if CORE.is_esp32:
# Re-enable ESP-IDF's HTTP client (excluded by default to save compile time)
esp32.include_idf_component("esp_http_client")
esp32.add_idf_sdkconfig_option("CONFIG_ESP_TLS_INSECURE", True)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY", True

View File

@@ -170,6 +170,9 @@ CONFIG_SCHEMA = remote_base.validate_triggers(
async def to_code(config):
pin = await cg.gpio_pin_expression(config[CONF_PIN])
if CORE.is_esp32:
# Re-enable ESP-IDF's RMT driver (excluded by default to save compile time)
esp32.include_idf_component("esp_driver_rmt")
var = cg.new_Pvariable(config[CONF_ID], pin)
cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS]))
cg.add(var.set_receive_symbols(config[CONF_RECEIVE_SYMBOLS]))

View File

@@ -112,6 +112,9 @@ async def digital_write_action_to_code(config, action_id, template_arg, args):
async def to_code(config):
pin = await cg.gpio_pin_expression(config[CONF_PIN])
if CORE.is_esp32:
# Re-enable ESP-IDF's RMT driver (excluded by default to save compile time)
esp32.include_idf_component("esp_driver_rmt")
var = cg.new_Pvariable(config[CONF_ID], pin)
cg.add(var.set_rmt_symbols(config[CONF_RMT_SYMBOLS]))
cg.add(var.set_non_blocking(config[CONF_NON_BLOCKING]))

View File

@@ -2,7 +2,7 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <vector>
#include <array>
namespace esphome {
namespace tx20 {
@@ -45,25 +45,25 @@ std::string Tx20Component::get_wind_cardinal_direction() const { return this->wi
void Tx20Component::decode_and_publish_() {
ESP_LOGVV(TAG, "Decode Tx20");
std::string string_buffer;
std::string string_buffer_2;
std::vector<bool> bit_buffer;
std::array<bool, MAX_BUFFER_SIZE> bit_buffer{};
size_t bit_pos = 0;
bool current_bit = true;
// Cap at MAX_BUFFER_SIZE - 1 to prevent out-of-bounds access (buffer_index can exceed MAX_BUFFER_SIZE in ISR)
const int max_buffer_index =
std::min(static_cast<int>(this->store_.buffer_index), static_cast<int>(MAX_BUFFER_SIZE - 1));
for (int i = 1; i <= this->store_.buffer_index; i++) {
string_buffer_2 += to_string(this->store_.buffer[i]) + ", ";
for (int i = 1; i <= max_buffer_index; i++) {
uint8_t repeat = this->store_.buffer[i] / TX20_BIT_TIME;
// ignore segments at the end that were too short
string_buffer.append(repeat, current_bit ? '1' : '0');
bit_buffer.insert(bit_buffer.end(), repeat, current_bit);
for (uint8_t j = 0; j < repeat && bit_pos < MAX_BUFFER_SIZE; j++) {
bit_buffer[bit_pos++] = current_bit;
}
current_bit = !current_bit;
}
current_bit = !current_bit;
if (string_buffer.length() < MAX_BUFFER_SIZE) {
uint8_t remain = MAX_BUFFER_SIZE - string_buffer.length();
string_buffer_2 += to_string(remain) + ", ";
string_buffer.append(remain, current_bit ? '1' : '0');
bit_buffer.insert(bit_buffer.end(), remain, current_bit);
size_t bits_before_padding = bit_pos;
while (bit_pos < MAX_BUFFER_SIZE) {
bit_buffer[bit_pos++] = current_bit;
}
uint8_t tx20_sa = 0;
@@ -108,8 +108,24 @@ void Tx20Component::decode_and_publish_() {
// 2. Check received checksum matches calculated checksum
// 3. Check that Wind Direction matches Wind Direction (Inverted)
// 4. Check that Wind Speed matches Wind Speed (Inverted)
ESP_LOGVV(TAG, "BUFFER %s", string_buffer_2.c_str());
ESP_LOGVV(TAG, "Decoded bits %s", string_buffer.c_str());
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
// Build debug strings from completed data
char debug_buf[320]; // buffer values: max 40 entries * 7 chars each
size_t debug_pos = 0;
for (int i = 1; i <= max_buffer_index; i++) {
debug_pos = buf_append_printf(debug_buf, sizeof(debug_buf), debug_pos, "%u, ", this->store_.buffer[i]);
}
if (bits_before_padding < MAX_BUFFER_SIZE) {
buf_append_printf(debug_buf, sizeof(debug_buf), debug_pos, "%zu, ", MAX_BUFFER_SIZE - bits_before_padding);
}
char bits_buf[MAX_BUFFER_SIZE + 1];
for (size_t i = 0; i < MAX_BUFFER_SIZE; i++) {
bits_buf[i] = bit_buffer[i] ? '1' : '0';
}
bits_buf[MAX_BUFFER_SIZE] = '\0';
ESP_LOGVV(TAG, "BUFFER %s", debug_buf);
ESP_LOGVV(TAG, "Decoded bits %s", bits_buf);
#endif
if (tx20_sa == 4) {
if (chk == tx20_sd) {

View File

@@ -8,6 +8,16 @@ esp32:
enable_lwip_bridge_interface: true
disable_libc_locks_in_iram: false # Test explicit opt-out of RAM optimization
use_full_certificate_bundle: false # Test CMN bundle (default)
include_idf_components:
- freertos # Test escape hatch (freertos is always included anyway)
disable_debug_stubs: true
disable_ocd_aware: true
disable_usb_serial_jtag_secondary: true
disable_dev_null_vfs: true
disable_mbedtls_peer_cert: true
disable_mbedtls_pkcs7: true
disable_regi2c_in_iram: true
disable_fatfs: true
wifi:
ssid: MySSID

View File

@@ -10,6 +10,14 @@ esp32:
ref: 2.7.0
advanced:
enable_idf_experimental_features: yes
disable_debug_stubs: true
disable_ocd_aware: true
disable_usb_serial_jtag_secondary: true
disable_dev_null_vfs: true
disable_mbedtls_peer_cert: true
disable_mbedtls_pkcs7: true
disable_regi2c_in_iram: true
disable_fatfs: true
ota:
platform: esphome

View File

@@ -5,6 +5,14 @@ esp32:
advanced:
execute_from_psram: true
disable_libc_locks_in_iram: true # Test default RAM optimization enabled
disable_debug_stubs: true
disable_ocd_aware: true
disable_usb_serial_jtag_secondary: true
disable_dev_null_vfs: true
disable_mbedtls_peer_cert: true
disable_mbedtls_pkcs7: true
disable_regi2c_in_iram: true
disable_fatfs: true
psram:
mode: octal