diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index 3d5ec97a633..4abc807ee3d 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -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") diff --git a/esphome/components/i2s_audio/microphone/__init__.py b/esphome/components/i2s_audio/microphone/__init__.py index c2173172372..2ff709dbd1c 100644 --- a/esphome/components/i2s_audio/microphone/__init__.py +++ b/esphome/components/i2s_audio/microphone/__init__.py @@ -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 = { diff --git a/tests/component_tests/i2s_audio/test_variants.py b/tests/component_tests/i2s_audio/test_variants.py new file mode 100644 index 00000000000..3c5245565fa --- /dev/null +++ b/tests/component_tests/i2s_audio/test_variants.py @@ -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)) diff --git a/tests/components/i2s_audio/test.esp32-s31-idf.yaml b/tests/components/i2s_audio/test.esp32-s31-idf.yaml new file mode 100644 index 00000000000..6457440bb4e --- /dev/null +++ b/tests/components/i2s_audio/test.esp32-s31-idf.yaml @@ -0,0 +1,7 @@ +substitutions: + i2s_bclk_pin: GPIO5 + i2s_lrclk_pin: GPIO4 + i2s_mclk_pin: GPIO15 + +packages: + i2s_audio: !include common.yaml diff --git a/tests/components/microphone/test.esp32-s31-idf.yaml b/tests/components/microphone/test.esp32-s31-idf.yaml new file mode 100644 index 00000000000..00f535b1692 --- /dev/null +++ b/tests/components/microphone/test.esp32-s31-idf.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 diff --git a/tests/components/speaker/test.esp32-s31-idf.yaml b/tests/components/speaker/test.esp32-s31-idf.yaml new file mode 100644 index 00000000000..00a41ac969b --- /dev/null +++ b/tests/components/speaker/test.esp32-s31-idf.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