mirror of
https://github.com/esphome/esphome.git
synced 2024-12-25 06:54:52 +01:00
Latest developments
This commit is contained in:
parent
0c7470d296
commit
22868cc05b
3 changed files with 232 additions and 70 deletions
|
@ -1,15 +1,48 @@
|
||||||
|
from esphome import automation
|
||||||
|
from esphome.automation import maybe_simple_id
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
|
||||||
from esphome.components import i2c
|
from esphome.components import i2c
|
||||||
from esphome.const import CONF_ID
|
from esphome.const import CONF_ID
|
||||||
|
from esphome.util import Registry
|
||||||
|
|
||||||
|
CONF_ES8388_ID = "es8388_id"
|
||||||
|
|
||||||
|
CONF_PRESET = "preset"
|
||||||
|
CONF_INIT_INSTRUCTIONS = "init_instructions"
|
||||||
|
CONF_MACROS = "macros"
|
||||||
|
CONF_INSTRUCTIONS = "instructions"
|
||||||
|
|
||||||
|
ES8388_MACROS = Registry()
|
||||||
|
|
||||||
es8388_ns = cg.esphome_ns.namespace("es8388")
|
es8388_ns = cg.esphome_ns.namespace("es8388")
|
||||||
ES8388Component = es8388_ns.class_("ES8388Component", cg.Component, i2c.I2CDevice)
|
ES8388Component = es8388_ns.class_("ES8388Component", cg.Component, i2c.I2CDevice)
|
||||||
|
Presets = es8388_ns.enum("ES8388Preset")
|
||||||
|
Macro = es8388_ns.class_("Macro")
|
||||||
|
MacroAction = es8388_ns.class_("ES8388MacroAction", automation.Action)
|
||||||
|
|
||||||
|
ES8388_PRESETS = {
|
||||||
|
"raspiaudio_muse_luxe": Presets.RASPIAUDIO_MUSE_LUXE,
|
||||||
|
"raspiaudio_radio": Presets.RASPIAUDIO_RADIO,
|
||||||
|
}
|
||||||
|
|
||||||
|
def validate_instruction_list():
|
||||||
|
return cv.ensure_list(
|
||||||
|
cv.Length(min=2, max=2),
|
||||||
|
cv.ensure_list(int)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
cv.Schema({cv.GenerateID(): cv.declare_id(ES8388Component)})
|
cv.Schema({
|
||||||
|
cv.GenerateID(): cv.declare_id(ES8388Component),
|
||||||
|
cv.Optional(CONF_PRESET): cv.enum(ES8388_PRESETS, lower=True),
|
||||||
|
cv.Optional(CONF_INIT_INSTRUCTIONS): validate_instruction_list(),
|
||||||
|
cv.Optional(CONF_MACROS): cv.ensure_list({
|
||||||
|
cv.Required(CONF_ID): cv.string,
|
||||||
|
cv.Required(CONF_INSTRUCTIONS): validate_instruction_list(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
.extend(i2c.i2c_device_schema(0x10))
|
.extend(i2c.i2c_device_schema(0x10))
|
||||||
.extend(cv.COMPONENT_SCHEMA)
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
)
|
)
|
||||||
|
@ -19,3 +52,31 @@ async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await i2c.register_i2c_device(var, config)
|
await i2c.register_i2c_device(var, config)
|
||||||
|
if CONF_PRESET in config:
|
||||||
|
cg.add(var.set_preset(config[CONF_PRESET]))
|
||||||
|
if CONF_INIT_INSTRUCTIONS in config:
|
||||||
|
cg.add(var.set_init_instructions(config[CONF_INIT_INSTRUCTIONS]))
|
||||||
|
if CONF_MACROS in config:
|
||||||
|
for macro in config[CONF_MACROS]:
|
||||||
|
ES8388_MACROS.register(macro[CONF_ID], Macro, {
|
||||||
|
cv.Required(CONF_ID): cv.declare_id(Macro),
|
||||||
|
cv.Required(CONF_INSTRUCTIONS): validate_instruction_list(),
|
||||||
|
})
|
||||||
|
cg.add(var.register_macro(macro[CONF_ID], macro[CONF_INSTRUCTIONS]))
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"es8388.execute_macro",
|
||||||
|
MacroAction,
|
||||||
|
maybe_simple_id(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_ES8388_ID): cv.use_id(ES8388Component),
|
||||||
|
cv.Required(CONF_ID): cv.string,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def execute_macro_to_code(config, action_id, template_arg, args):
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
|
await cg.register_parented(var, config[CONF_ES8388_ID])
|
||||||
|
|
||||||
|
cg.add(var.set_id(config[CONF_ID]))
|
||||||
|
return var
|
|
@ -7,19 +7,120 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace es8388 {
|
namespace es8388 {
|
||||||
|
|
||||||
|
static const char *const TAG = "es8388";
|
||||||
|
|
||||||
#define ES8388_CLK_MODE_SLAVE 0
|
#define ES8388_CLK_MODE_SLAVE 0
|
||||||
#define ES8388_CLK_MODE_MASTER 1
|
#define ES8388_CLK_MODE_MASTER 1
|
||||||
|
|
||||||
void ES8388Component::setup() {
|
void ES8388Component::setup() {
|
||||||
int zerooo = 0;
|
|
||||||
int val = 2 / zerooo;
|
|
||||||
ESP_LOGW("ES8388", "Writing I2C registers");
|
|
||||||
|
|
||||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 1);
|
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 1);
|
||||||
// WRITE_PERI_REG(PIN_CTRL, READ_PERI_REG(PIN_CTRL) & 0xFFFFFFF0);
|
// WRITE_PERI_REG(PIN_CTRL, READ_PERI_REG(PIN_CTRL) & 0xFFFFFFF0);
|
||||||
|
|
||||||
this->setup_raspiaudio_radio();
|
switch (this->preset_) {
|
||||||
|
case ES8388Preset::RASPIAUDIO_MUSE_LUXE:
|
||||||
|
this->setup_raspiaudio_muse_luxe();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ES8388Preset::RASPIAUDIO_RADIO:
|
||||||
|
this->setup_raspiaudio_radio();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!this->init_instructions_.empty()) {
|
||||||
|
for (std::array<uint8_t, 2> instruction : this->init_instructions_) {
|
||||||
|
if (this->write_byte(instruction[0], instruction[1]))
|
||||||
|
ESP_LOGW(TAG, "Error writing I2C instructions to ES8388: %#04x, %#04x", instruction[0], instruction[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ES8388Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "ES8388:");
|
||||||
|
if (this->preset_) {
|
||||||
|
ESP_LOGCONFIG(TAG, " Preset loaded: %#04x", this->preset_);
|
||||||
|
} else {
|
||||||
|
if (!this->init_instructions_.empty()) {
|
||||||
|
ESP_LOGCONFIG(TAG, " %d initialization instructions found", this->init_instructions_.size());
|
||||||
|
} else {
|
||||||
|
ESP_LOGCONFIG(TAG, " No initialization instructions found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ES8388Component::setup_raspiaudio_muse_luxe() {
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
// mute
|
||||||
|
error = error || not this->write_byte(0x19, 0x04);
|
||||||
|
|
||||||
|
// powerup
|
||||||
|
error = error || not this->write_byte(0x01, 0x50); // LPVrefBuf - low power
|
||||||
|
error = error || not this->write_byte(0x02, 0x00); // power up DAC/ADC without resetting DMS, DEM, filters & serial
|
||||||
|
|
||||||
|
// set CLK mode to slave
|
||||||
|
error = error || not this->write_byte(0x08, 0x00);
|
||||||
|
|
||||||
|
// DAC powerdown
|
||||||
|
error = error || not this->write_byte(0x04, 0xC0);
|
||||||
|
// vmidsel/500k ADC/DAC idem
|
||||||
|
error = error || not this->write_byte(0x00, 0x12);
|
||||||
|
|
||||||
|
// i2s 16 bits
|
||||||
|
error = error || not this->write_byte(0x17, 0x18);
|
||||||
|
// sample freq 256
|
||||||
|
error = error || not this->write_byte(0x18, 0x02);
|
||||||
|
// LIN2/RIN2 for mixer
|
||||||
|
error = error || not this->write_byte(0x26, 0x00);
|
||||||
|
// left DAC to left mixer
|
||||||
|
error = error || not this->write_byte(0x27, 0x90);
|
||||||
|
// right DAC to right mixer
|
||||||
|
error = error || not this->write_byte(0x2A, 0x90);
|
||||||
|
// DACLRC ADCLRC idem
|
||||||
|
error = error || not this->write_byte(0x2B, 0x80);
|
||||||
|
error = error || not this->write_byte(0x2D, 0x00);
|
||||||
|
// DAC volume max
|
||||||
|
error = error || not this->write_byte(0x1B, 0x00);
|
||||||
|
error = error || not this->write_byte(0x1A, 0x00);
|
||||||
|
|
||||||
|
// ADC poweroff
|
||||||
|
error = error || not this->write_byte(0x03, 0xFF);
|
||||||
|
// ADC amp 24dB
|
||||||
|
error = error || not this->write_byte(0x09, 0x88);
|
||||||
|
// LINPUT1/RINPUT1
|
||||||
|
error = error || not this->write_byte(0x0A, 0x00);
|
||||||
|
// ADC mono left
|
||||||
|
error = error || not this->write_byte(0x0B, 0x02);
|
||||||
|
// i2S 16b
|
||||||
|
error = error || not this->write_byte(0x0C, 0x0C);
|
||||||
|
// MCLK 256
|
||||||
|
error = error || not this->write_byte(0x0D, 0x02);
|
||||||
|
// ADC Volume
|
||||||
|
error = error || not this->write_byte(0x10, 0x00);
|
||||||
|
error = error || not this->write_byte(0x11, 0x00);
|
||||||
|
// ALC OFF
|
||||||
|
error = error || not this->write_byte(0x03, 0x09);
|
||||||
|
error = error || not this->write_byte(0x2B, 0x80);
|
||||||
|
|
||||||
|
error = error || not this->write_byte(0x02, 0xF0);
|
||||||
|
delay(1);
|
||||||
|
error = error || not this->write_byte(0x02, 0x00);
|
||||||
|
// DAC power-up LOUT1/ROUT1 enabled
|
||||||
|
error = error || not this->write_byte(0x04, 0x30);
|
||||||
|
error = error || not this->write_byte(0x03, 0x00);
|
||||||
|
// DAC volume max
|
||||||
|
error = error || not this->write_byte(0x2E, 0x1C);
|
||||||
|
error = error || not this->write_byte(0x2F, 0x1C);
|
||||||
|
// unmute
|
||||||
|
error = error || not this->write_byte(0x19, 0x00);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
ESP_LOGE(TAG, "Error writing I2C registers for preset Raspiaudio Muse Luxe");
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "I2C registers written successfully for preset Raspiaudio Muse Luxe");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ES8388Component::setup_raspiaudio_radio() {
|
void ES8388Component::setup_raspiaudio_radio() {
|
||||||
|
@ -119,74 +220,31 @@ void ES8388Component::setup_raspiaudio_radio() {
|
||||||
error = error || not this->write_byte(49, 33);
|
error = error || not this->write_byte(49, 33);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
ESP_LOGE("ES8388", "Error writing I2C registers!");
|
ESP_LOGE(TAG, "Error writing I2C registers for preset Raspiaudio Radio");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW("ES8388", "I2C registers written successfully");
|
ESP_LOGD(TAG, "I2C registers written successfully for preset Raspiaudio Radio");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ES8388Component::setup_raspiaudio_muse_luxe() {
|
void ES8388Component::register_macro(std::string name, Instructions instructions) {
|
||||||
// mute
|
Macro macro;
|
||||||
this->mute();
|
macro.name = name;
|
||||||
|
macro.instructions = instructions;
|
||||||
|
this->macros_[name] = macro;
|
||||||
|
}
|
||||||
|
|
||||||
// powerup
|
void ES8388Component::execute_macro(std::string name) {
|
||||||
this->powerup();
|
if (this->macros_.count(name) == 0) {
|
||||||
this->clock_mode(ES8388_CLK_MODE_SLAVE);
|
ESP_LOGE(TAG, "Unable to execute macro `%s`: not found", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool error = false;
|
ESP_LOGD(TAG, "Calling ES8388 macro `%s` with %d I2C instructions", name, this->macros_[name].instructions.size());
|
||||||
|
|
||||||
// DAC powerdown
|
for (std::array<uint8_t, 2> instruction : this->macros_[name].instructions) {
|
||||||
this->powerdown_dac();
|
if (this->write_byte(instruction[0], instruction[1]))
|
||||||
// vmidsel/500k ADC/DAC idem
|
ESP_LOGW(TAG, "Error writing I2C instructions to ES8388: %#04x, %#04x", instruction[0], instruction[1]);
|
||||||
error = error || not this->write_byte(0x00, 0x12);
|
}
|
||||||
|
|
||||||
// i2s 16 bits
|
|
||||||
error = error || not this->write_byte(0x17, 0x18);
|
|
||||||
// sample freq 256
|
|
||||||
error = error || not this->write_byte(0x18, 0x02);
|
|
||||||
// LIN2/RIN2 for mixer
|
|
||||||
error = error || not this->write_byte(0x26, 0x00);
|
|
||||||
// left DAC to left mixer
|
|
||||||
error = error || not this->write_byte(0x27, 0x90);
|
|
||||||
// right DAC to right mixer
|
|
||||||
error = error || not this->write_byte(0x2A, 0x90);
|
|
||||||
// DACLRC ADCLRC idem
|
|
||||||
error = error || not this->write_byte(0x2B, 0x80);
|
|
||||||
error = error || not this->write_byte(0x2D, 0x00);
|
|
||||||
// DAC volume max
|
|
||||||
error = error || not this->write_byte(0x1B, 0x00);
|
|
||||||
error = error || not this->write_byte(0x1A, 0x00);
|
|
||||||
|
|
||||||
// ADC poweroff
|
|
||||||
error = error || not this->write_byte(0x03, 0xFF);
|
|
||||||
// ADC amp 24dB
|
|
||||||
error = error || not this->write_byte(0x09, 0x88);
|
|
||||||
// LINPUT1/RINPUT1
|
|
||||||
error = error || not this->write_byte(0x0A, 0x00);
|
|
||||||
// ADC mono left
|
|
||||||
error = error || not this->write_byte(0x0B, 0x02);
|
|
||||||
// i2S 16b
|
|
||||||
error = error || not this->write_byte(0x0C, 0x0C);
|
|
||||||
// MCLK 256
|
|
||||||
error = error || not this->write_byte(0x0D, 0x02);
|
|
||||||
// ADC Volume
|
|
||||||
error = error || not this->write_byte(0x10, 0x00);
|
|
||||||
error = error || not this->write_byte(0x11, 0x00);
|
|
||||||
// ALC OFF
|
|
||||||
error = error || not this->write_byte(0x03, 0x09);
|
|
||||||
error = error || not this->write_byte(0x2B, 0x80);
|
|
||||||
|
|
||||||
error = error || not this->write_byte(0x02, 0xF0);
|
|
||||||
delay(1);
|
|
||||||
error = error || not this->write_byte(0x02, 0x00);
|
|
||||||
// DAC power-up LOUT1/ROUT1 enabled
|
|
||||||
error = error || not this->write_byte(0x04, 0x30);
|
|
||||||
error = error || not this->write_byte(0x03, 0x00);
|
|
||||||
// DAC volume max
|
|
||||||
error = error || not this->write_byte(0x2E, 0x1C);
|
|
||||||
error = error || not this->write_byte(0x2F, 0x1C);
|
|
||||||
// unmute
|
|
||||||
error = error || not this->write_byte(0x19, 0x00);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ES8388Component::powerup_dac() { this->write_byte(0x04, 0x3B); }
|
void ES8388Component::powerup_dac() { this->write_byte(0x04, 0x3B); }
|
||||||
|
|
|
@ -1,19 +1,35 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "esphome/components/i2c/i2c.h"
|
#include "esphome/components/i2c/i2c.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace es8388 {
|
namespace es8388 {
|
||||||
|
|
||||||
|
enum ES8388Preset : uint8_t { NONE = 0x00, RASPIAUDIO_MUSE_LUXE = 0x01, RASPIAUDIO_RADIO = 0x02 };
|
||||||
|
typedef std::vector<std::array<uint8_t, 2>> Instructions;
|
||||||
|
struct Macro {
|
||||||
|
std::string name;
|
||||||
|
Instructions instructions;
|
||||||
|
};
|
||||||
|
typedef std::map<std::string, Macro> Macros;
|
||||||
|
|
||||||
class ES8388Component : public Component, public i2c::I2CDevice {
|
class ES8388Component : public Component, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void setup_raspiaudio_radio();
|
void dump_config() override;
|
||||||
void setup_raspiaudio_muse_luxe();
|
|
||||||
|
|
||||||
float get_setup_priority() const override { return setup_priority::LATE - 1; }
|
float get_setup_priority() const override { return setup_priority::LATE - 1; }
|
||||||
|
|
||||||
|
void set_preset(ES8388Preset preset) { this->preset_ = preset; }
|
||||||
|
void set_init_instructions(Instructions instructions) { this->init_instructions_ = instructions; }
|
||||||
|
void register_macro(std::string name, Instructions instructions);
|
||||||
|
void execute_macro(std::string name);
|
||||||
|
|
||||||
void powerup_dac();
|
void powerup_dac();
|
||||||
// void powerup_adc();
|
// void powerup_adc();
|
||||||
void powerup();
|
void powerup();
|
||||||
|
@ -25,6 +41,33 @@ class ES8388Component : public Component, public i2c::I2CDevice {
|
||||||
void clock_mode(uint8_t mode);
|
void clock_mode(uint8_t mode);
|
||||||
|
|
||||||
void mute();
|
void mute();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setup_raspiaudio_radio();
|
||||||
|
void setup_raspiaudio_muse_luxe();
|
||||||
|
ES8388Preset preset_;
|
||||||
|
Instructions init_instructions_;
|
||||||
|
Macros macros_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class ES8388MacroAction : public Action<Ts...>, public Parented<ES8388Component> {
|
||||||
|
public:
|
||||||
|
// TEMPLATABLE_VALUE(int8_t, hw_frontend_reset)
|
||||||
|
TEMPLATABLE_VALUE(std::string, macro_id)
|
||||||
|
// TEMPLATABLE_VALUE(int, sensing_distance)
|
||||||
|
// TEMPLATABLE_VALUE(int, poweron_selfcheck_time)
|
||||||
|
// TEMPLATABLE_VALUE(int, power_consumption)
|
||||||
|
// TEMPLATABLE_VALUE(int, protect_time)
|
||||||
|
// TEMPLATABLE_VALUE(int, trigger_base)
|
||||||
|
// TEMPLATABLE_VALUE(int, trigger_keep)
|
||||||
|
// TEMPLATABLE_VALUE(int, stage_gain)
|
||||||
|
|
||||||
|
void play(Ts... x) {
|
||||||
|
if (this->macro_id_.has_value()) {
|
||||||
|
std::string macro_id = this->macro_.value(x...);
|
||||||
|
this->parent_->execute_macro(macro_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace es8388
|
} // namespace es8388
|
||||||
|
|
Loading…
Reference in a new issue