[i2s_audio] Add ESP32-S31 support (#20115)

Co-authored-by: cosmicDustOfLightLength <cosmicDustOfLightLength@example.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
cosmicDustOfLightLength
2026-10-19 00:07:52 +00:00
committed by GitHub
co-authored by cosmicDustOfLightLength J. Nick Koston
parent 84ce39e493
commit e6ad995c8e
6 changed files with 97 additions and 1 deletions
+2
View File
@@ -17,6 +17,7 @@ from esphome.components.esp32.const import (
VARIANT_ESP32P4,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
VARIANT_ESP32S31,
)
from esphome.components.microphone import DOMAIN as MICROPHONE_DOMAIN
from esphome.config_helpers import filter_source_files_from_defines
@@ -98,6 +99,7 @@ I2S_PORTS = {
VARIANT_ESP32P4: 3,
VARIANT_ESP32S2: 1,
VARIANT_ESP32S3: 2,
VARIANT_ESP32S31: 2,
}
i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t")
@@ -38,7 +38,12 @@ I2SAudioMicrophone = i2s_audio_ns.class_(
)
INTERNAL_ADC_VARIANTS = [esp32.VARIANT_ESP32]
PDM_VARIANTS = [esp32.VARIANT_ESP32, esp32.VARIANT_ESP32S3, esp32.VARIANT_ESP32P4]
PDM_VARIANTS = [
esp32.VARIANT_ESP32,
esp32.VARIANT_ESP32S3,
esp32.VARIANT_ESP32P4,
esp32.VARIANT_ESP32S31,
]
i2s_pdm_dsr_t = cg.global_ns.enum("i2s_pdm_dsr_t")
I2S_PDM_DSR = {
@@ -0,0 +1,68 @@
"""Tests for the per-variant limits of i2s_audio: port count and PDM support."""
import pytest
from esphome import config_validation as cv
from esphome.components import i2s_audio
from esphome.components.esp32 import KEY_VARIANT
from esphome.components.esp32.const import (
VARIANT_ESP32C3,
VARIANT_ESP32S2,
VARIANT_ESP32S31,
)
from esphome.components.i2s_audio import microphone
from esphome.const import CONF_ID, PlatformFramework
from esphome.core import ID
from esphome.types import ConfigType
from tests.component_tests.types import SetCoreConfigCallable
CONF_FULL_DUPLEX = i2s_audio.CONF_FULL_DUPLEX
def _set_variant(
set_core_config: SetCoreConfigCallable, variant: str, buses: int
) -> None:
set_core_config(
PlatformFramework.ESP32_IDF,
platform_data={KEY_VARIANT: variant},
full_config={
i2s_audio.DOMAIN: [
{CONF_ID: ID(f"bus_{n}"), CONF_FULL_DUPLEX: False} for n in range(buses)
]
},
)
def test_esp32s31_has_two_i2s_ports(set_core_config: SetCoreConfigCallable) -> None:
_set_variant(set_core_config, VARIANT_ESP32S31, buses=2)
i2s_audio._final_validate({})
def test_esp32s31_rejects_a_third_bus(set_core_config: SetCoreConfigCallable) -> None:
_set_variant(set_core_config, VARIANT_ESP32S31, buses=3)
with pytest.raises(cv.Invalid, match="Only 2 I2S audio ports"):
i2s_audio._final_validate({})
def _pdm_microphone(pdm: bool) -> ConfigType:
return {
microphone.CONF_ADC_TYPE: "external",
microphone.CONF_PDM: pdm,
}
def test_esp32s31_supports_pdm_microphones(
set_core_config: SetCoreConfigCallable,
) -> None:
_set_variant(set_core_config, VARIANT_ESP32S31, buses=1)
microphone._validate_esp32_variant(_pdm_microphone(True))
@pytest.mark.parametrize("variant", [VARIANT_ESP32S2, VARIANT_ESP32C3])
def test_pdm_rejected_where_the_soc_has_none(
set_core_config: SetCoreConfigCallable, variant: str
) -> None:
_set_variant(set_core_config, variant, buses=1)
with pytest.raises(cv.Invalid, match="does not support PDM"):
microphone._validate_esp32_variant(_pdm_microphone(True))
microphone._validate_esp32_variant(_pdm_microphone(False))
@@ -0,0 +1,7 @@
substitutions:
i2s_bclk_pin: GPIO5
i2s_lrclk_pin: GPIO4
i2s_mclk_pin: GPIO15
packages:
i2s_audio: !include common.yaml
@@ -0,0 +1,7 @@
substitutions:
i2s_din_pin1: GPIO6
i2s_din_pin2: GPIO7
packages:
i2s_audio: !include ../../test_build_components/common/i2s_audio/esp32-s31-idf.yaml
microphone: !include common-pdm.yaml
@@ -0,0 +1,7 @@
substitutions:
i2s_dout_pin: GPIO10
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-s31-idf.yaml
i2s_audio: !include ../../test_build_components/common/i2s_audio/esp32-s31-idf.yaml
speaker: !include common.yaml