From 1d8423edd802f8cb8de213c1020e1b36b769e3dc Mon Sep 17 00:00:00 2001 From: cociweb Date: Tue, 13 Oct 2026 20:14:43 +0200 Subject: [PATCH] [es8388] Add initial option configuration for DAC output and ADC input mic (#16342) Co-authored-by: J. Nick Koston --- esphome/components/es8388/es8388.cpp | 40 +++++++++++------ esphome/components/es8388/es8388.h | 15 ++++++- esphome/components/es8388/select/__init__.py | 46 ++++++++++++++++++-- esphome/core/defines.h | 1 + tests/components/es8388/common.yaml | 4 ++ 5 files changed, 87 insertions(+), 19 deletions(-) diff --git a/esphome/components/es8388/es8388.cpp b/esphome/components/es8388/es8388.cpp index b57949ccd0a..56ee1ac4a59 100644 --- a/esphome/components/es8388/es8388.cpp +++ b/esphome/components/es8388/es8388.cpp @@ -111,24 +111,36 @@ void ES8388::setup() { // Power on ADC, Enable LIN&RIN, Power off MICBIAS, set int1lp to low power mode ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCPOWER, 0x09)); -#ifdef USE_SELECT +#ifdef USE_ES8388_SELECT if (this->dac_output_select_ != nullptr) { - auto dac_power = this->get_dac_power(); - if (dac_power.has_value()) { - if (this->dac_output_select_->has_index(dac_power.value())) { - this->dac_output_select_->publish_state(dac_power.value()); - } else { - ESP_LOGW(TAG, "Unknown DAC output power value: %d", dac_power.value()); + if (this->dac_output_initial_.has_value()) { + const DacOutputLine line = this->dac_output_initial_.value(); + ES8388_ERROR_FAILED(this->set_dac_output(line)); + this->dac_output_select_->publish_state(static_cast(line)); + } else { + auto dac_power = this->get_dac_power(); + if (dac_power.has_value()) { + if (this->dac_output_select_->has_index(dac_power.value())) { + this->dac_output_select_->publish_state(dac_power.value()); + } else { + ESP_LOGW(TAG, "Unknown DAC output power value: %d", dac_power.value()); + } } } } if (this->adc_input_mic_select_ != nullptr) { - auto mic_input = this->get_mic_input(); - if (mic_input.has_value()) { - if (this->adc_input_mic_select_->has_index(mic_input.value())) { - this->adc_input_mic_select_->publish_state(mic_input.value()); - } else { - ESP_LOGW(TAG, "Unknown ADC input mic value: %d", mic_input.value()); + if (this->adc_input_mic_initial_.has_value()) { + const AdcInputMicLine line = this->adc_input_mic_initial_.value(); + ES8388_ERROR_FAILED(this->set_adc_input_mic(line)); + this->adc_input_mic_select_->publish_state(static_cast(line)); + } else { + auto mic_input = this->get_mic_input(); + if (mic_input.has_value()) { + if (this->adc_input_mic_select_->has_index(mic_input.value())) { + this->adc_input_mic_select_->publish_state(mic_input.value()); + } else { + ESP_LOGW(TAG, "Unknown ADC input mic value: %d", mic_input.value()); + } } } } @@ -138,7 +150,7 @@ void ES8388::setup() { void ES8388::dump_config() { ESP_LOGCONFIG(TAG, "ES8388 Audio Codec:"); LOG_I2C_DEVICE(this); -#ifdef USE_SELECT +#ifdef USE_ES8388_SELECT LOG_SELECT(" ", "DacOutputSelect", this->dac_output_select_); LOG_SELECT(" ", "ADCInputMicSelect", this->adc_input_mic_select_); #endif diff --git a/esphome/components/es8388/es8388.h b/esphome/components/es8388/es8388.h index b01acb69c1e..b55538c94f8 100644 --- a/esphome/components/es8388/es8388.h +++ b/esphome/components/es8388/es8388.h @@ -5,7 +5,7 @@ #include "esphome/components/audio_dac/audio_dac.h" #include "esphome/components/i2c/i2c.h" #include "esphome/core/component.h" -#ifdef USE_SELECT +#ifdef USE_ES8388_SELECT #include "esphome/components/select/select.h" #endif @@ -26,7 +26,7 @@ enum AdcInputMicLine : uint8_t { }; class ES8388 final : public audio_dac::AudioDac, public Component, public i2c::I2CDevice { -#ifdef USE_SELECT +#ifdef USE_ES8388_SELECT SUB_SELECT(dac_output) SUB_SELECT(adc_input_mic) #endif @@ -68,11 +68,22 @@ class ES8388 final : public audio_dac::AudioDac, public Component, public i2c::I bool set_dac_output(DacOutputLine line); bool set_adc_input_mic(AdcInputMicLine line); +#ifdef USE_ES8388_SELECT + /// Line to apply in setup() instead of keeping what the codec reports. + void set_dac_output_initial(DacOutputLine line) { this->dac_output_initial_ = line; } + void set_adc_input_mic_initial(AdcInputMicLine line) { this->adc_input_mic_initial_ = line; } +#endif + protected: /// @brief Mutes or unmutes the DAC audio out /// @param mute_state True to mute, false to unmute /// @return True if successful and false otherwise bool set_mute_state_(bool mute_state); + +#ifdef USE_ES8388_SELECT + optional dac_output_initial_{}; + optional adc_input_mic_initial_{}; +#endif }; } // namespace esphome::es8388 diff --git a/esphome/components/es8388/select/__init__.py b/esphome/components/es8388/select/__init__.py index 62ddd6cb38a..f0e3f5b7c89 100644 --- a/esphome/components/es8388/select/__init__.py +++ b/esphome/components/es8388/select/__init__.py @@ -1,7 +1,11 @@ import esphome.codegen as cg from esphome.components import select import esphome.config_validation as cv -from esphome.const import ENTITY_CATEGORY_CONFIG, ICON_CHIP # noqa: F401 +from esphome.const import ( + CONF_INITIAL_OPTION, + ENTITY_CATEGORY_CONFIG, + ICON_CHIP, # noqa: F401 +) from esphome.types import ConfigType from ..audio_dac import CONF_ES8388_ID, ES8388, es8388_ns @@ -9,6 +13,21 @@ from ..audio_dac import CONF_ES8388_ID, ES8388, es8388_ns CONF_DAC_OUTPUT = "dac_output" CONF_ADC_INPUT_MIC = "adc_input_mic" +DacOutputLine = es8388_ns.enum("DacOutputLine") +DAC_OUTPUT_OPTIONS = { + "LINE1": DacOutputLine.DAC_OUTPUT_LINE1, + "LINE2": DacOutputLine.DAC_OUTPUT_LINE2, + "BOTH": DacOutputLine.DAC_OUTPUT_BOTH, +} +DAC_OUTPUT_OPTION_NAMES = list(DAC_OUTPUT_OPTIONS) +AdcInputMicLine = es8388_ns.enum("AdcInputMicLine") +ADC_INPUT_MIC_OPTIONS = { + "LINE1": AdcInputMicLine.ADC_INPUT_MIC_LINE1, + "LINE2": AdcInputMicLine.ADC_INPUT_MIC_LINE2, + "DIFFERENCE": AdcInputMicLine.ADC_INPUT_MIC_DIFFERENCE, +} +ADC_INPUT_MIC_OPTION_NAMES = list(ADC_INPUT_MIC_OPTIONS) + DacOutputSelect = es8388_ns.class_("DacOutputSelect", select.Select) ADCInputMicSelect = es8388_ns.class_("ADCInputMicSelect", select.Select) @@ -19,24 +38,45 @@ CONFIG_SCHEMA = cv.All( DacOutputSelect, entity_category=ENTITY_CATEGORY_CONFIG, icon=ICON_CHIP, + ).extend( + { + cv.Optional(CONF_INITIAL_OPTION): cv.enum( + DAC_OUTPUT_OPTIONS, upper=True + ), + } ), cv.Optional(CONF_ADC_INPUT_MIC): select.select_schema( ADCInputMicSelect, entity_category=ENTITY_CATEGORY_CONFIG, icon=ICON_CHIP, + ).extend( + { + cv.Optional(CONF_INITIAL_OPTION): cv.enum( + ADC_INPUT_MIC_OPTIONS, upper=True + ), + } ), } ) async def to_code(config: ConfigType) -> None: + cg.add_define("USE_ES8388_SELECT") hub = await cg.get_variable(config[CONF_ES8388_ID]) selects = select.sub_selects(config, parent=hub) await selects( - CONF_DAC_OUTPUT, hub.set_dac_output_select, options=["LINE1", "LINE2", "BOTH"] + CONF_DAC_OUTPUT, hub.set_dac_output_select, options=DAC_OUTPUT_OPTION_NAMES ) await selects( CONF_ADC_INPUT_MIC, hub.set_adc_input_mic_select, - options=["LINE1", "LINE2", "DIFFERENCE"], + options=ADC_INPUT_MIC_OPTION_NAMES, ) + if ( + initial := config.get(CONF_DAC_OUTPUT, {}).get(CONF_INITIAL_OPTION) + ) is not None: + cg.add(hub.set_dac_output_initial(initial)) + if ( + initial := config.get(CONF_ADC_INPUT_MIC, {}).get(CONF_INITIAL_OPTION) + ) is not None: + cg.add(hub.set_adc_input_mic_initial(initial)) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index d9b12fdddb1..08f1e31d6c2 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -72,6 +72,7 @@ #define USE_ENTITY_DEVICE_CLASS #define USE_ENTITY_ICON #define USE_ENTITY_UNIT_OF_MEASUREMENT +#define USE_ES8388_SELECT #define USE_ESP32_BLE_PSRAM #define USE_ESP32_CAMERA_JPEG_CONVERSION #define USE_ESP32_HOSTED diff --git a/tests/components/es8388/common.yaml b/tests/components/es8388/common.yaml index cc7465ab935..aa08b9b0470 100644 --- a/tests/components/es8388/common.yaml +++ b/tests/components/es8388/common.yaml @@ -17,5 +17,9 @@ select: es8388_id: es8388_parent dac_output: name: "DAC Output" + id: es8388_test_dac_output_select + initial_option: BOTH adc_input_mic: name: "ADC Input MIC" + id: es8388_test_adc_input_mic_select + initial_option: LINE2