diff --git a/CODEOWNERS b/CODEOWNERS index c7423e9eae..dade427a45 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -139,6 +139,7 @@ esphome/components/es7210/* @kahrendt esphome/components/es7243e/* @kbx81 esphome/components/es8156/* @kbx81 esphome/components/es8311/* @kahrendt @kroimon +esphome/components/es8388/* @P4uLT esphome/components/esp32/* @esphome/core esphome/components/esp32_ble/* @Rapsssito @jesserockz esphome/components/esp32_ble_client/* @jesserockz diff --git a/esphome/components/es8388/__init__.py b/esphome/components/es8388/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/es8388/audio_dac.py b/esphome/components/es8388/audio_dac.py new file mode 100644 index 0000000000..77e07b2e01 --- /dev/null +++ b/esphome/components/es8388/audio_dac.py @@ -0,0 +1,26 @@ +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 + +CODEOWNERS = ["@P4uLT"] +CONF_ES8388_ID = "es8388_id" + +es8388_ns = cg.esphome_ns.namespace("es8388") + +ES8388 = es8388_ns.class_("ES8388", AudioDac, cg.Component, i2c.I2CDevice) + +DEPENDENCIES = ["i2c"] + +CONFIG_SCHEMA = ( + cv.Schema({cv.GenerateID(): cv.declare_id(ES8388)}) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x10)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es8388/es8388.cpp b/esphome/components/es8388/es8388.cpp new file mode 100644 index 0000000000..e550a95f45 --- /dev/null +++ b/esphome/components/es8388/es8388.cpp @@ -0,0 +1,289 @@ +#include "es8388.h" + +#include +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace es8388 { + +static const char *const TAG = "es8388"; + +// Mark the component as failed; use only in setup +#define ES8388_ERROR_FAILED(func) \ + if (!(func)) { \ + this->mark_failed(); \ + return; \ + } + +// Return false; use outside of setup +#define ES8388_ERROR_CHECK(func) \ + if (!(func)) { \ + return false; \ + } + +void ES8388::setup() { + ESP_LOGCONFIG(TAG, "Setting up ES8388..."); + + // mute DAC + this->set_mute_state_(true); + + // I2S worker mode + ES8388_ERROR_FAILED(this->write_byte(ES8388_MASTERMODE, 0x00)); + + /* Chip Control and Power Management */ + ES8388_ERROR_FAILED(this->write_byte(ES8388_CONTROL2, 0x50)); + // normal all and power up all + ES8388_ERROR_FAILED(this->write_byte(ES8388_CHIPPOWER, 0x00)); + + // vmidsel/500k + // EnRef=0,Play&Record Mode,(0x17-both of mic&play) + ES8388_ERROR_FAILED(this->write_byte(ES8388_CONTROL1, 0x12)); + + // i2s 16 bits + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL1, 0x18)); + // sample freq 256 + // DACFsMode,SINGLE SPEED; DACFsRatio,256 + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL2, 0x02)); + // 0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2 + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL16, 0x00)); + // only left DAC to left mixer enable 0db + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL17, 0x90)); + // only right DAC to right mixer enable 0db + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL20, 0x90)); + // set internal ADC and DAC use the same LRCK clock, ADC LRCK as internal LRCK + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL21, 0x80)); + // vroi=0 - 1.5k VREF to analog output resistance (default) + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL23, 0x00)); + + // power down adc and line in + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCPOWER, 0xFF)); + + //@nightdav + ES8388_ERROR_FAILED( + this->write_byte(ES8388_ADCCONTROL1, 0x00)); // +21dB : recommended value for ALC & voice recording + + // set to Mono Right + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL3, 0x02)); + + // I2S 16 Bits length and I2S serial audio data format + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL4, 0x0d)); + // ADCFsMode,singel SPEED,RATIO=256 + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL5, 0x02)); + + // ADC Volume + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL8, 0x00)); + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL9, 0x00)); + + //@nightDav + // ALC Config (as recommended by ES8388 user guide for voice recording) + + // Reg 0x12 = 0xe2 (ALC enable, PGA Max. Gain=23.5dB, Min. Gain=0dB) + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL10, 0xe2)); + + // Reg 0x13 = 0xa0 (ALC Target=-1.5dB, ALC Hold time =0 mS) + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL11, 0xa0)); + // Reg 0x14 = 0x12(Decay time =820uS , Attack time = 416 uS) + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL12, 0x12)); + + // Reg 0x15 = 0x06(ALC mode) + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL13, 0x06)); + + // Reg 0x16 = 0xc3(nose gate = -40.5dB, NGG = 0x01(mute ADC)) + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL14, 0xc3)); + + // Power on ADC + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL21, 0x80)); + + // Start state machine + ES8388_ERROR_FAILED(this->write_byte(ES8388_CHIPPOWER, 0xF0)); + delay(1); + ES8388_ERROR_FAILED(this->write_byte(ES8388_CHIPPOWER, 0x00)); + + // DAC volume max + // Set initial volume + // this->set_volume(0.75); // 0.75 = 0xBF = 0dB + + this->set_mute_state_(false); + + // unmute ADC with fade in + ES8388_ERROR_FAILED(this->write_byte(ES8388_ADCCONTROL7, 0x60)); + // unmute DAC with fade in + ES8388_ERROR_FAILED(this->write_byte(ES8388_DACCONTROL3, 0x20)); + + // 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 + if (this->dac_output_select_ != nullptr) { + auto dac_power = this->get_dac_power(); + if (dac_power.has_value()) { + auto dac_power_str = this->dac_output_select_->at(dac_power.value()); + if (dac_power_str.has_value()) { + this->dac_output_select_->publish_state(dac_power_str.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()) { + auto mic_input_str = this->adc_input_mic_select_->at(mic_input.value()); + if (mic_input_str.has_value()) { + this->adc_input_mic_select_->publish_state(mic_input_str.value()); + } else { + ESP_LOGW(TAG, "Unknown ADC input mic value: %d", mic_input.value()); + } + } + } +#endif +} + +void ES8388::dump_config() { + ESP_LOGCONFIG(TAG, "ES8388 Audio Codec:"); + LOG_I2C_DEVICE(this); +#ifdef USE_SELECT + LOG_SELECT(" ", "DacOutputSelect", this->dac_output_select_); + LOG_SELECT(" ", "ADCInputMicSelect", this->adc_input_mic_select_); +#endif + + if (this->is_failed()) { + ESP_LOGCONFIG(TAG, " Failed to initialize"); + return; + } +} + +bool ES8388::set_volume(float volume) { + volume = clamp(volume, 0.0f, 1.0f); + uint8_t value = remap(volume, 0.0f, 1.0f, -96, 0); + ESP_LOGD(TAG, "Setting ES8388_DACCONTROL4 / ES8388_DACCONTROL5 to 0x%02X (volume: %f)", value, volume); + ES8388_ERROR_CHECK(this->write_byte(ES8388_DACCONTROL4, value)); + ES8388_ERROR_CHECK(this->write_byte(ES8388_DACCONTROL5, value)); + + return true; +} + +float ES8388::volume() { + uint8_t value; + ES8388_ERROR_CHECK(this->read_byte(ES8388_DACCONTROL4, &value)); + return remap(value, -96, 0, 0.0f, 1.0f); +} + +bool ES8388::set_mute_state_(bool mute_state) { + uint8_t value = 0; + + this->is_muted_ = mute_state; + + ES8388_ERROR_CHECK(this->read_byte(ES8388_DACCONTROL3, &value)); + ESP_LOGV(TAG, "Read ES8388_DACCONTROL3: 0x%02X", value); + + if (mute_state) { + value = 0x3C; + } + + ESP_LOGV(TAG, "Setting ES8388_DACCONTROL3 to 0x%02X (muted: %s)", value, YESNO(mute_state)); + return this->write_byte(ES8388_DACCONTROL3, value); +} + +// Set dac power output +bool ES8388::set_dac_output(DacOutputLine line) { + uint8_t reg_out1 = 0; + uint8_t reg_out2 = 0; + uint8_t dac_power = 0; + + // 0x00: -30dB , 0x1E: 0dB + switch (line) { + case DAC_OUTPUT_LINE1: + reg_out1 = 0x1E; + dac_power = ES8388_DAC_OUTPUT_LOUT1_ROUT1; + break; + case DAC_OUTPUT_LINE2: + reg_out2 = 0x1E; + dac_power = ES8388_DAC_OUTPUT_LOUT2_ROUT2; + break; + case DAC_OUTPUT_BOTH: + reg_out1 = 0x1E; + reg_out2 = 0x1E; + dac_power = ES8388_DAC_OUTPUT_BOTH; + break; + default: + ESP_LOGE(TAG, "Unknown DAC output line: %d", line); + return false; + }; + + ESP_LOGV(TAG, "Setting ES8388_DACPOWER to 0x%02X", dac_power); + ESP_LOGV(TAG, "Setting ES8388_DACCONTROL24 / ES8388_DACCONTROL25 to 0x%02X", reg_out1); + ESP_LOGV(TAG, "Setting ES8388_DACCONTROL26 / ES8388_DACCONTROL27 to 0x%02X", reg_out2); + + ES8388_ERROR_CHECK(this->write_byte(ES8388_DACCONTROL24, reg_out1)); // LOUT1VOL + ES8388_ERROR_CHECK(this->write_byte(ES8388_DACCONTROL25, reg_out1)); // ROUT1VOL + ES8388_ERROR_CHECK(this->write_byte(ES8388_DACCONTROL26, reg_out2)); // LOUT2VOL + ES8388_ERROR_CHECK(this->write_byte(ES8388_DACCONTROL27, reg_out2)); // ROUT1VOL + + return this->write_byte(ES8388_DACPOWER, dac_power); +} + +optional ES8388::get_dac_power() { + uint8_t dac_power; + if (!this->read_byte(ES8388_DACPOWER, &dac_power)) { + this->status_momentary_warning("Failed to read ES8388_DACPOWER"); + return {}; + } + switch (dac_power) { + case ES8388_DAC_OUTPUT_LOUT1_ROUT1: + return DAC_OUTPUT_LINE1; + case ES8388_DAC_OUTPUT_LOUT2_ROUT2: + return DAC_OUTPUT_LINE2; + case ES8388_DAC_OUTPUT_BOTH: + return DAC_OUTPUT_BOTH; + default: + return {}; + } +} + +// Set ADC input MIC +bool ES8388::set_adc_input_mic(AdcInputMicLine line) { + uint8_t mic_input = 0; + + switch (line) { + case ADC_INPUT_MIC_LINE1: + mic_input = ES8388_ADC_INPUT_LINPUT1_RINPUT1; + break; + case ADC_INPUT_MIC_LINE2: + mic_input = ES8388_ADC_INPUT_LINPUT2_RINPUT2; + break; + case ADC_INPUT_MIC_DIFFERENCE: + mic_input = ES8388_ADC_INPUT_DIFFERENCE; + break; + default: + ESP_LOGE(TAG, "Unknown ADC input mic line: %d", line); + return false; + } + + ESP_LOGV(TAG, "Setting ES8388_ADCCONTROL2 to 0x%02X", mic_input); + ES8388_ERROR_CHECK(this->write_byte(ES8388_ADCCONTROL2, mic_input)); + + return true; +} + +optional ES8388::get_mic_input() { + uint8_t mic_input; + if (!this->read_byte(ES8388_ADCCONTROL2, &mic_input)) { + this->status_momentary_warning("Failed to read ES8388_ADCCONTROL2"); + return {}; + } + switch (mic_input) { + case ES8388_ADC_INPUT_LINPUT1_RINPUT1: + return ADC_INPUT_MIC_LINE1; + case ES8388_ADC_INPUT_LINPUT2_RINPUT2: + return ADC_INPUT_MIC_LINE2; + case ES8388_ADC_INPUT_DIFFERENCE: + return ADC_INPUT_MIC_DIFFERENCE; + default: + return {}; + }; +} + +} // namespace es8388 +} // namespace esphome diff --git a/esphome/components/es8388/es8388.h b/esphome/components/es8388/es8388.h new file mode 100644 index 0000000000..45944f68bd --- /dev/null +++ b/esphome/components/es8388/es8388.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include "esphome/components/audio_dac/audio_dac.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" +#ifdef USE_SELECT +#include "esphome/components/select/select.h" +#endif + +#include "es8388_const.h" + +namespace esphome { +namespace es8388 { + +enum DacOutputLine : uint8_t { + DAC_OUTPUT_LINE1, + DAC_OUTPUT_LINE2, + DAC_OUTPUT_BOTH, +}; + +enum AdcInputMicLine : uint8_t { + ADC_INPUT_MIC_LINE1, + ADC_INPUT_MIC_LINE2, + ADC_INPUT_MIC_DIFFERENCE, +}; + +class ES8388 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice { +#ifdef USE_SELECT + SUB_SELECT(dac_output) + SUB_SELECT(adc_input_mic) +#endif + + public: + ///////////////////////// + // Component overrides // + ///////////////////////// + + void setup() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void dump_config() override; + + //////////////////////// + // AudioDac overrides // + //////////////////////// + + /// @brief Writes the volume out to the DAC + /// @param volume floating point between 0.0 and 1.0 + /// @return True if successful and false otherwise + bool set_volume(float volume) override; + + /// @brief Gets the current volume out from the DAC + /// @return floating point between 0.0 and 1.0 + float volume() override; + + /// @brief Disables mute for audio out + /// @return True if successful and false otherwise + bool set_mute_off() override { return this->set_mute_state_(false); } + + /// @brief Enables mute for audio out + /// @return True if successful and false otherwise + bool set_mute_on() override { return this->set_mute_state_(true); } + + bool is_muted() override { return this->is_muted_; } + + optional get_dac_power(); + optional get_mic_input(); + + bool set_dac_output(DacOutputLine line); + bool set_adc_input_mic(AdcInputMicLine line); + + 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); +}; + +} // namespace es8388 +} // namespace esphome diff --git a/esphome/components/es8388/es8388_const.h b/esphome/components/es8388/es8388_const.h new file mode 100644 index 0000000000..2a51f078bc --- /dev/null +++ b/esphome/components/es8388/es8388_const.h @@ -0,0 +1,83 @@ +#pragma once +#include + +namespace esphome { +namespace es8388 { + +/* ES8388 register */ +static const uint8_t ES8388_CONTROL1 = 0x00; +static const uint8_t ES8388_CONTROL2 = 0x01; + +static const uint8_t ES8388_CHIPPOWER = 0x02; + +static const uint8_t ES8388_ADCPOWER = 0x03; +static const uint8_t ES8388_DACPOWER = 0x04; + +static const uint8_t ES8388_CHIPLOPOW1 = 0x05; +static const uint8_t ES8388_CHIPLOPOW2 = 0x06; + +static const uint8_t ES8388_ANAVOLMANAG = 0x07; + +static const uint8_t ES8388_MASTERMODE = 0x08; + +/* ADC */ +static const uint8_t ES8388_ADCCONTROL1 = 0x09; +static const uint8_t ES8388_ADCCONTROL2 = 0x0a; +static const uint8_t ES8388_ADCCONTROL3 = 0x0b; +static const uint8_t ES8388_ADCCONTROL4 = 0x0c; +static const uint8_t ES8388_ADCCONTROL5 = 0x0d; +static const uint8_t ES8388_ADCCONTROL6 = 0x0e; +static const uint8_t ES8388_ADCCONTROL7 = 0x0f; +static const uint8_t ES8388_ADCCONTROL8 = 0x10; +static const uint8_t ES8388_ADCCONTROL9 = 0x11; +static const uint8_t ES8388_ADCCONTROL10 = 0x12; +static const uint8_t ES8388_ADCCONTROL11 = 0x13; +static const uint8_t ES8388_ADCCONTROL12 = 0x14; +static const uint8_t ES8388_ADCCONTROL13 = 0x15; +static const uint8_t ES8388_ADCCONTROL14 = 0x16; +/* DAC */ +static const uint8_t ES8388_DACCONTROL1 = 0x17; +static const uint8_t ES8388_DACCONTROL2 = 0x18; +static const uint8_t ES8388_DACCONTROL3 = 0x19; +static const uint8_t ES8388_DACCONTROL4 = 0x1a; +static const uint8_t ES8388_DACCONTROL5 = 0x1b; +static const uint8_t ES8388_DACCONTROL6 = 0x1c; +static const uint8_t ES8388_DACCONTROL7 = 0x1d; +static const uint8_t ES8388_DACCONTROL8 = 0x1e; +static const uint8_t ES8388_DACCONTROL9 = 0x1f; +static const uint8_t ES8388_DACCONTROL10 = 0x20; +static const uint8_t ES8388_DACCONTROL11 = 0x21; +static const uint8_t ES8388_DACCONTROL12 = 0x22; +static const uint8_t ES8388_DACCONTROL13 = 0x23; +static const uint8_t ES8388_DACCONTROL14 = 0x24; +static const uint8_t ES8388_DACCONTROL15 = 0x25; +static const uint8_t ES8388_DACCONTROL16 = 0x26; +static const uint8_t ES8388_DACCONTROL17 = 0x27; +static const uint8_t ES8388_DACCONTROL18 = 0x28; +static const uint8_t ES8388_DACCONTROL19 = 0x29; +static const uint8_t ES8388_DACCONTROL20 = 0x2a; +static const uint8_t ES8388_DACCONTROL21 = 0x2b; +static const uint8_t ES8388_DACCONTROL22 = 0x2c; +static const uint8_t ES8388_DACCONTROL23 = 0x2d; +static const uint8_t ES8388_DACCONTROL24 = 0x2e; +static const uint8_t ES8388_DACCONTROL25 = 0x2f; +static const uint8_t ES8388_DACCONTROL26 = 0x30; +static const uint8_t ES8388_DACCONTROL27 = 0x31; +static const uint8_t ES8388_DACCONTROL28 = 0x32; +static const uint8_t ES8388_DACCONTROL29 = 0x33; +static const uint8_t ES8388_DACCONTROL30 = 0x34; + +static const uint8_t ES8388_DAC_OUTPUT_NONE = 0xC0; // ALL DAC DOWN + +static const uint8_t ES8388_DAC_OUTPUT_LOUT1_ROUT1 = 0x30; +static const uint8_t ES8388_DAC_OUTPUT_LOUT2_ROUT2 = 0x0C; +static const uint8_t ES8388_DAC_OUTPUT_BOTH = 0x3C; + +static const uint8_t ES8388_ADC_INPUT_LINPUT1_RINPUT1 = 0x00; +static const uint8_t ES8388_ADC_INPUT_MIC1 = 0x05; +static const uint8_t ES8388_ADC_INPUT_MIC2 = 0x06; +static const uint8_t ES8388_ADC_INPUT_LINPUT2_RINPUT2 = 0x50; +static const uint8_t ES8388_ADC_INPUT_DIFFERENCE = 0xf0; + +} // namespace es8388 +} // namespace esphome diff --git a/esphome/components/es8388/select/__init__.py b/esphome/components/es8388/select/__init__.py new file mode 100644 index 0000000000..068d9f9fb8 --- /dev/null +++ b/esphome/components/es8388/select/__init__.py @@ -0,0 +1,47 @@ +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 ..audio_dac import CONF_ES8388_ID, ES8388, es8388_ns + +CONF_DAC_OUTPUT = "dac_output" +CONF_ADC_INPUT_MIC = "adc_input_mic" + +DacOutputSelect = es8388_ns.class_("DacOutputSelect", select.Select) +ADCInputMicSelect = es8388_ns.class_("ADCInputMicSelect", select.Select) + +CONFIG_SCHEMA = cv.All( + { + cv.GenerateID(CONF_ES8388_ID): cv.use_id(ES8388), + cv.Optional(CONF_DAC_OUTPUT): select.select_schema( + DacOutputSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_CHIP, + ), + cv.Optional(CONF_ADC_INPUT_MIC): select.select_schema( + ADCInputMicSelect, + entity_category=ENTITY_CATEGORY_CONFIG, + icon=ICON_CHIP, + ), + } +) + + +async def to_code(config): + parent = await cg.get_variable(config[CONF_ES8388_ID]) + if dac_output_config := config.get(CONF_DAC_OUTPUT): + s = await select.new_select( + dac_output_config, + options=["LINE1", "LINE2", "BOTH"], + ) + await cg.register_parented(s, parent) + cg.add(parent.set_dac_output_select(s)) + + if adc_input_mic_config := config.get(CONF_ADC_INPUT_MIC): + s = await select.new_select( + adc_input_mic_config, + options=["LINE1", "LINE2", "DIFFERENCE"], + ) + await cg.register_parented(s, parent) + cg.add(parent.set_adc_input_mic_select(s)) diff --git a/esphome/components/es8388/select/adc_input_mic_select.cpp b/esphome/components/es8388/select/adc_input_mic_select.cpp new file mode 100644 index 0000000000..5fab5b8a92 --- /dev/null +++ b/esphome/components/es8388/select/adc_input_mic_select.cpp @@ -0,0 +1,12 @@ +#include "adc_input_mic_select.h" + +namespace esphome { +namespace es8388 { + +void ADCInputMicSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_adc_input_mic(static_cast(this->index_of(value).value())); +} + +} // namespace es8388 +} // namespace esphome diff --git a/esphome/components/es8388/select/adc_input_mic_select.h b/esphome/components/es8388/select/adc_input_mic_select.h new file mode 100644 index 0000000000..8d035525ef --- /dev/null +++ b/esphome/components/es8388/select/adc_input_mic_select.h @@ -0,0 +1,15 @@ +#pragma once + +#include "esphome/components/es8388/es8388.h" +#include "esphome/components/select/select.h" + +namespace esphome { +namespace es8388 { + +class ADCInputMicSelect : public select::Select, public Parented { + protected: + void control(const std::string &value) override; +}; + +} // namespace es8388 +} // namespace esphome diff --git a/esphome/components/es8388/select/dac_output_select.cpp b/esphome/components/es8388/select/dac_output_select.cpp new file mode 100644 index 0000000000..268b5f290c --- /dev/null +++ b/esphome/components/es8388/select/dac_output_select.cpp @@ -0,0 +1,12 @@ +#include "dac_output_select.h" + +namespace esphome { +namespace es8388 { + +void DacOutputSelect::control(const std::string &value) { + this->publish_state(value); + this->parent_->set_dac_output(static_cast(this->index_of(value).value())); +} + +} // namespace es8388 +} // namespace esphome diff --git a/esphome/components/es8388/select/dac_output_select.h b/esphome/components/es8388/select/dac_output_select.h new file mode 100644 index 0000000000..fccae9fc19 --- /dev/null +++ b/esphome/components/es8388/select/dac_output_select.h @@ -0,0 +1,15 @@ +#pragma once + +#include "esphome/components/es8388/es8388.h" +#include "esphome/components/select/select.h" + +namespace esphome { +namespace es8388 { + +class DacOutputSelect : public select::Select, public Parented { + protected: + void control(const std::string &value) override; +}; + +} // namespace es8388 +} // namespace esphome diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 455b404e32..2336ec8fd6 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -95,6 +95,7 @@ // Feature flags which do not work for zephyr #ifndef USE_ZEPHYR +#define USE_AUDIO_DAC #define USE_AUDIO_FLAC_SUPPORT #define USE_AUDIO_MP3_SUPPORT #define USE_API diff --git a/tests/components/es8388/common.yaml b/tests/components/es8388/common.yaml new file mode 100644 index 0000000000..6a63de5aa1 --- /dev/null +++ b/tests/components/es8388/common.yaml @@ -0,0 +1,25 @@ +esphome: + on_boot: + then: + - audio_dac.mute_off: + - audio_dac.mute_on: + + - audio_dac.set_volume: + volume: 50% + +i2c: + - id: i2c_es8388 + scl: ${scl_pin} + sda: ${sda_pin} + +audio_dac: + - platform: es8388 + id: es8388_parent + +select: + - platform: es8388 + es8388_id: es8388_parent + dac_output: + name: "DAC Output" + adc_input_mic: + name: "ADC Input MIC" diff --git a/tests/components/es8388/test.esp32-ard.yaml b/tests/components/es8388/test.esp32-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/es8388/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/es8388/test.esp32-c3-ard.yaml b/tests/components/es8388/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8388/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/es8388/test.esp32-c3-idf.yaml b/tests/components/es8388/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8388/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/es8388/test.esp32-idf.yaml b/tests/components/es8388/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/es8388/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/es8388/test.esp8266-ard.yaml b/tests/components/es8388/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8388/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml