Merge branch 'dev' into gpio-pin-validation-override

This commit is contained in:
David Pitman 2025-01-22 16:42:44 -08:00 committed by GitHub
commit b8835b658d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
127 changed files with 1320 additions and 1000 deletions

View File

@ -46,7 +46,7 @@ runs:
- name: Build and push to ghcr by digest - name: Build and push to ghcr by digest
id: build-ghcr id: build-ghcr
uses: docker/build-push-action@v6.11.0 uses: docker/build-push-action@v6.12.0
env: env:
DOCKER_BUILD_SUMMARY: false DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false DOCKER_BUILD_RECORD_UPLOAD: false
@ -72,7 +72,7 @@ runs:
- name: Build and push to dockerhub by digest - name: Build and push to dockerhub by digest
id: build-dockerhub id: build-dockerhub
uses: docker/build-push-action@v6.11.0 uses: docker/build-push-action@v6.12.0
env: env:
DOCKER_BUILD_SUMMARY: false DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false DOCKER_BUILD_RECORD_UPLOAD: false

View File

@ -17,7 +17,7 @@ jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v9.0.0 - uses: actions/stale@v9.1.0
with: with:
days-before-pr-stale: 90 days-before-pr-stale: 90
days-before-pr-close: 7 days-before-pr-close: 7
@ -37,7 +37,7 @@ jobs:
close-issues: close-issues:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v9.0.0 - uses: actions/stale@v9.1.0
with: with:
days-before-pr-stale: -1 days-before-pr-stale: -1
days-before-pr-close: -1 days-before-pr-close: -1

View File

@ -11,14 +11,6 @@ repos:
args: [--fix] args: [--fix]
# Run the formatter. # Run the formatter.
- id: ruff-format - id: ruff-format
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.4.2
hooks:
- id: black
args:
- --safe
- --quiet
files: ^((esphome|script|tests)/.+)?[^/]+\.py$
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 6.1.0 rev: 6.1.0
hooks: hooks:
@ -53,6 +45,6 @@ repos:
hooks: hooks:
- id: pylint - id: pylint
name: pylint name: pylint
entry: script/run-in-env.sh pylint entry: python script/run-in-env pylint
language: script language: system
types: [python] types: [python]

View File

@ -49,6 +49,7 @@ esphome/components/atc_mithermometer/* @ahpohl
esphome/components/atm90e26/* @danieltwagner esphome/components/atm90e26/* @danieltwagner
esphome/components/atm90e32/* @circuitsetup @descipher esphome/components/atm90e32/* @circuitsetup @descipher
esphome/components/audio/* @kahrendt esphome/components/audio/* @kahrendt
esphome/components/audio_adc/* @kbx81
esphome/components/audio_dac/* @kbx81 esphome/components/audio_dac/* @kbx81
esphome/components/axs15231/* @clydebarrow esphome/components/axs15231/* @clydebarrow
esphome/components/b_parasite/* @rbaron esphome/components/b_parasite/* @rbaron
@ -132,6 +133,8 @@ esphome/components/ens160_i2c/* @latonita
esphome/components/ens160_spi/* @latonita esphome/components/ens160_spi/* @latonita
esphome/components/ens210/* @itn3rd77 esphome/components/ens210/* @itn3rd77
esphome/components/es7210/* @kahrendt esphome/components/es7210/* @kahrendt
esphome/components/es7243e/* @kbx81
esphome/components/es8156/* @kbx81
esphome/components/es8311/* @kahrendt @kroimon esphome/components/es8311/* @kahrendt @kroimon
esphome/components/esp32/* @esphome/core esphome/components/esp32/* @esphome/core
esphome/components/esp32_ble/* @Rapsssito @jesserockz esphome/components/esp32_ble/* @Rapsssito @jesserockz
@ -339,7 +342,6 @@ esphome/components/radon_eye_rd200/* @jeffeb3
esphome/components/rc522/* @glmnet esphome/components/rc522/* @glmnet
esphome/components/rc522_i2c/* @glmnet esphome/components/rc522_i2c/* @glmnet
esphome/components/rc522_spi/* @glmnet esphome/components/rc522_spi/* @glmnet
esphome/components/resistance_sampler/* @jesserockz
esphome/components/restart/* @esphome/core esphome/components/restart/* @esphome/core
esphome/components/rf_bridge/* @jesserockz esphome/components/rf_bridge/* @jesserockz
esphome/components/rgbct/* @jesserockz esphome/components/rgbct/* @jesserockz

View File

@ -9,8 +9,6 @@ static const char *const TAG = "ads1115";
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00; static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01; static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111; // 3300_SPS for ADS1015
void ADS1115Component::setup() { void ADS1115Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADS1115..."); ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
uint16_t value; uint16_t value;
@ -43,9 +41,9 @@ void ADS1115Component::setup() {
config |= 0b0000000100000000; config |= 0b0000000100000000;
} }
// Set data rate - 860 samples per second (we're in singleshot mode) // Set data rate - 860 samples per second
// 0bxxxxxxxx100xxxxx // 0bxxxxxxxx100xxxxx
config |= ADS1115_DATA_RATE_860_SPS << 5; config |= ADS1115_860SPS << 5;
// Set comparator mode - hysteresis // Set comparator mode - hysteresis
// 0bxxxxxxxxxxx0xxxx // 0bxxxxxxxxxxx0xxxx
@ -77,7 +75,7 @@ void ADS1115Component::dump_config() {
} }
} }
float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain,
ADS1115Resolution resolution) { ADS1115Resolution resolution, ADS1115Samplerate samplerate) {
uint16_t config = this->prev_config_; uint16_t config = this->prev_config_;
// Multiplexer // Multiplexer
// 0bxBBBxxxxxxxxxxxx // 0bxBBBxxxxxxxxxxxx
@ -89,6 +87,11 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
config &= 0b1111000111111111; config &= 0b1111000111111111;
config |= (gain & 0b111) << 9; config |= (gain & 0b111) << 9;
// Sample rate
// 0bxxxxxxxxBBBxxxxx
config &= 0b1111111100011111;
config |= (samplerate & 0b111) << 5;
if (!this->continuous_mode_) { if (!this->continuous_mode_) {
// Start conversion // Start conversion
config |= 0b1000000000000000; config |= 0b1000000000000000;
@ -101,8 +104,54 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
} }
this->prev_config_ = config; this->prev_config_ = config;
// about 1.2 ms with 860 samples per second // Delay calculated as: ceil((1000/SPS)+.5)
if (resolution == ADS1015_12_BITS) {
switch (samplerate) {
case ADS1115_8SPS:
delay(9);
break;
case ADS1115_16SPS:
delay(5);
break;
case ADS1115_32SPS:
delay(3);
break;
case ADS1115_64SPS:
case ADS1115_128SPS:
delay(2); delay(2);
break;
default:
delay(1);
break;
}
} else {
switch (samplerate) {
case ADS1115_8SPS:
delay(126); // NOLINT
break;
case ADS1115_16SPS:
delay(63); // NOLINT
break;
case ADS1115_32SPS:
delay(32);
break;
case ADS1115_64SPS:
delay(17);
break;
case ADS1115_128SPS:
delay(9);
break;
case ADS1115_250SPS:
delay(5);
break;
case ADS1115_475SPS:
delay(3);
break;
case ADS1115_860SPS:
delay(2);
break;
}
}
// in continuous mode, conversion will always be running, rely on the delay // in continuous mode, conversion will always be running, rely on the delay
// to ensure conversion is taking place with the correct settings // to ensure conversion is taking place with the correct settings

View File

@ -33,6 +33,17 @@ enum ADS1115Resolution {
ADS1015_12_BITS = 12, ADS1015_12_BITS = 12,
}; };
enum ADS1115Samplerate {
ADS1115_8SPS = 0b000,
ADS1115_16SPS = 0b001,
ADS1115_32SPS = 0b010,
ADS1115_64SPS = 0b011,
ADS1115_128SPS = 0b100,
ADS1115_250SPS = 0b101,
ADS1115_475SPS = 0b110,
ADS1115_860SPS = 0b111
};
class ADS1115Component : public Component, public i2c::I2CDevice { class ADS1115Component : public Component, public i2c::I2CDevice {
public: public:
void setup() override; void setup() override;
@ -42,7 +53,8 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
/// Helper method to request a measurement from a sensor. /// Helper method to request a measurement from a sensor.
float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution); float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution,
ADS1115Samplerate samplerate);
protected: protected:
uint16_t prev_config_{0}; uint16_t prev_config_{0};

View File

@ -5,6 +5,7 @@ from esphome.const import (
CONF_GAIN, CONF_GAIN,
CONF_MULTIPLEXER, CONF_MULTIPLEXER,
CONF_RESOLUTION, CONF_RESOLUTION,
CONF_SAMPLE_RATE,
DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_VOLT, UNIT_VOLT,
@ -43,6 +44,17 @@ RESOLUTION = {
"12_BITS": ADS1115Resolution.ADS1015_12_BITS, "12_BITS": ADS1115Resolution.ADS1015_12_BITS,
} }
ADS1115Samplerate = ads1115_ns.enum("ADS1115Samplerate")
SAMPLERATE = {
"8": ADS1115Samplerate.ADS1115_8SPS,
"16": ADS1115Samplerate.ADS1115_16SPS,
"32": ADS1115Samplerate.ADS1115_32SPS,
"64": ADS1115Samplerate.ADS1115_64SPS,
"128": ADS1115Samplerate.ADS1115_128SPS,
"250": ADS1115Samplerate.ADS1115_250SPS,
"475": ADS1115Samplerate.ADS1115_475SPS,
"860": ADS1115Samplerate.ADS1115_860SPS,
}
ADS1115Sensor = ads1115_ns.class_( ADS1115Sensor = ads1115_ns.class_(
"ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler "ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
@ -64,6 +76,9 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum( cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
RESOLUTION, upper=True, space="_" RESOLUTION, upper=True, space="_"
), ),
cv.Optional(CONF_SAMPLE_RATE, default="860"): cv.enum(
SAMPLERATE, string=True
),
} }
) )
.extend(cv.polling_component_schema("60s")) .extend(cv.polling_component_schema("60s"))
@ -79,3 +94,4 @@ async def to_code(config):
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER])) cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
cg.add(var.set_gain(config[CONF_GAIN])) cg.add(var.set_gain(config[CONF_GAIN]))
cg.add(var.set_resolution(config[CONF_RESOLUTION])) cg.add(var.set_resolution(config[CONF_RESOLUTION]))
cg.add(var.set_samplerate(config[CONF_SAMPLE_RATE]))

View File

@ -8,7 +8,7 @@ namespace ads1115 {
static const char *const TAG = "ads1115.sensor"; static const char *const TAG = "ads1115.sensor";
float ADS1115Sensor::sample() { float ADS1115Sensor::sample() {
return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_); return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
} }
void ADS1115Sensor::update() { void ADS1115Sensor::update() {
@ -24,6 +24,7 @@ void ADS1115Sensor::dump_config() {
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_); ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_);
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_); ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_);
ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_); ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_);
ESP_LOGCONFIG(TAG, " Sample rate: %u", this->samplerate_);
} }
} // namespace ads1115 } // namespace ads1115

View File

@ -21,6 +21,7 @@ class ADS1115Sensor : public sensor::Sensor,
void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; } void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
void set_gain(ADS1115Gain gain) { this->gain_ = gain; } void set_gain(ADS1115Gain gain) { this->gain_ = gain; }
void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; } void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; }
void set_samplerate(ADS1115Samplerate samplerate) { this->samplerate_ = samplerate; }
float sample() override; float sample() override;
void dump_config() override; void dump_config() override;
@ -29,6 +30,7 @@ class ADS1115Sensor : public sensor::Sensor,
ADS1115Multiplexer multiplexer_; ADS1115Multiplexer multiplexer_;
ADS1115Gain gain_; ADS1115Gain gain_;
ADS1115Resolution resolution_; ADS1115Resolution resolution_;
ADS1115Samplerate samplerate_;
}; };
} // namespace ads1115 } // namespace ads1115

View File

@ -0,0 +1,41 @@
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MIC_GAIN
from esphome.core import coroutine_with_priority
CODEOWNERS = ["@kbx81"]
IS_PLATFORM_COMPONENT = True
audio_adc_ns = cg.esphome_ns.namespace("audio_adc")
AudioAdc = audio_adc_ns.class_("AudioAdc")
SetMicGainAction = audio_adc_ns.class_("SetMicGainAction", automation.Action)
SET_MIC_GAIN_ACTION_SCHEMA = cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(AudioAdc),
cv.Required(CONF_MIC_GAIN): cv.templatable(cv.decibel),
},
key=CONF_MIC_GAIN,
)
@automation.register_action(
"audio_adc.set_mic_gain", SetMicGainAction, SET_MIC_GAIN_ACTION_SCHEMA
)
async def audio_adc_set_mic_gain_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config.get(CONF_MIC_GAIN), args, float)
cg.add(var.set_mic_gain(template_))
return var
@coroutine_with_priority(100.0)
async def to_code(config):
cg.add_define("USE_AUDIO_ADC")
cg.add_global(audio_adc_ns.using)

View File

@ -0,0 +1,17 @@
#pragma once
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace audio_adc {
class AudioAdc {
public:
virtual bool set_mic_gain(float mic_gain) = 0;
virtual float mic_gain() = 0;
};
} // namespace audio_adc
} // namespace esphome

View File

@ -0,0 +1,23 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "audio_adc.h"
namespace esphome {
namespace audio_adc {
template<typename... Ts> class SetMicGainAction : public Action<Ts...> {
public:
explicit SetMicGainAction(AudioAdc *audio_adc) : audio_adc_(audio_adc) {}
TEMPLATABLE_VALUE(float, mic_gain)
void play(Ts... x) override { this->audio_adc_->set_mic_gain(this->mic_gain_.value(x...)); }
protected:
AudioAdc *audio_adc_;
};
} // namespace audio_adc
} // namespace esphome

View File

@ -19,6 +19,7 @@ from .boards import BK72XX_BOARD_PINS, BK72XX_BOARDS
CODEOWNERS = ["@kuba2k2"] CODEOWNERS = ["@kuba2k2"]
AUTO_LOAD = ["libretiny"] AUTO_LOAD = ["libretiny"]
IS_TARGET_PLATFORM = True
COMPONENT_DATA = LibreTinyComponent( COMPONENT_DATA = LibreTinyComponent(
name=COMPONENT_BK72XX, name=COMPONENT_BK72XX,

View File

@ -1,3 +0,0 @@
import esphome.codegen as cg
custom_ns = cg.esphome_ns.namespace("custom")

View File

@ -1,31 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import binary_sensor
from esphome.const import CONF_BINARY_SENSORS, CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomBinarySensorConstructor = custom_ns.class_("CustomBinarySensorConstructor") CONFIG_SCHEMA = cv.invalid(
'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomBinarySensorConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_BINARY_SENSORS): cv.ensure_list(
binary_sensor.binary_sensor_schema()
),
}
) )
async def to_code(config):
template_ = await cg.process_lambda(
config[CONF_LAMBDA],
[],
return_type=cg.std_vector.template(binary_sensor.BinarySensorPtr),
)
rhs = CustomBinarySensorConstructor(template_)
custom = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_BINARY_SENSORS]):
rhs = custom.Pget_binary_sensor(i)
await binary_sensor.register_binary_sensor(rhs, conf)

View File

@ -1,16 +0,0 @@
#include "custom_binary_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace custom {
static const char *const TAG = "custom.binary_sensor";
void CustomBinarySensorConstructor::dump_config() {
for (auto *child : this->binary_sensors_) {
LOG_BINARY_SENSOR("", "Custom Binary Sensor", child);
}
}
} // namespace custom
} // namespace esphome

View File

@ -1,26 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomBinarySensorConstructor : public Component {
public:
CustomBinarySensorConstructor(const std::function<std::vector<binary_sensor::BinarySensor *>()> &init) {
this->binary_sensors_ = init();
}
binary_sensor::BinarySensor *get_binary_sensor(int i) { return this->binary_sensors_[i]; }
void dump_config() override;
protected:
std::vector<binary_sensor::BinarySensor *> binary_sensors_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,30 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import climate
from esphome.const import CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomClimateConstructor = custom_ns.class_("CustomClimateConstructor") CONFIG_SCHEMA = cv.invalid(
CONF_CLIMATES = "climates" 'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomClimateConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_CLIMATES): cv.ensure_list(climate.CLIMATE_SCHEMA),
}
) )
async def to_code(config):
template_ = await cg.process_lambda(
config[CONF_LAMBDA],
[],
return_type=cg.std_vector.template(climate.Climate.operator("ptr")),
)
rhs = CustomClimateConstructor(template_)
custom = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_CLIMATES]):
rhs = custom.Pget_climate(i)
await climate.register_climate(rhs, conf)

View File

@ -1,22 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/climate/climate.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomClimateConstructor {
public:
CustomClimateConstructor(const std::function<std::vector<climate::Climate *>()> &init) { this->climates_ = init(); }
climate::Climate *get_climate(int i) { return this->climates_[i]; }
protected:
std::vector<climate::Climate *> climates_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,30 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import cover
from esphome.const import CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomCoverConstructor = custom_ns.class_("CustomCoverConstructor") CONFIG_SCHEMA = cv.invalid(
CONF_COVERS = "covers" 'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomCoverConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_COVERS): cv.ensure_list(cover.COVER_SCHEMA),
}
) )
async def to_code(config):
template_ = await cg.process_lambda(
config[CONF_LAMBDA],
[],
return_type=cg.std_vector.template(cover.Cover.operator("ptr")),
)
rhs = CustomCoverConstructor(template_)
custom = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_COVERS]):
rhs = custom.Pget_cover(i)
await cover.register_cover(rhs, conf)

View File

@ -1,21 +0,0 @@
#pragma once
#include "esphome/components/cover/cover.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomCoverConstructor {
public:
CustomCoverConstructor(const std::function<std::vector<cover::Cover *>()> &init) { this->covers_ = init(); }
cover::Cover *get_cover(int i) { return this->covers_[i]; }
protected:
std::vector<cover::Cover *> covers_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,30 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import light
from esphome.const import CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomLightOutputConstructor = custom_ns.class_("CustomLightOutputConstructor") CONFIG_SCHEMA = cv.invalid(
CONF_LIGHTS = "lights" 'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomLightOutputConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_LIGHTS): cv.ensure_list(light.ADDRESSABLE_LIGHT_SCHEMA),
}
) )
async def to_code(config):
template_ = await cg.process_lambda(
config[CONF_LAMBDA],
[],
return_type=cg.std_vector.template(light.LightOutput.operator("ptr")),
)
rhs = CustomLightOutputConstructor(template_)
custom = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_LIGHTS]):
rhs = custom.Pget_light(i)
await light.register_light(rhs, conf)

View File

@ -1,24 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/light/light_output.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomLightOutputConstructor {
public:
CustomLightOutputConstructor(const std::function<std::vector<light::LightOutput *>()> &init) {
this->outputs_ = init();
}
light::LightOutput *get_light(int i) { return this->outputs_[i]; }
protected:
std::vector<light::LightOutput *> outputs_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,61 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_OUTPUTS, CONF_TYPE, CONF_BINARY
from .. import custom_ns
CustomBinaryOutputConstructor = custom_ns.class_("CustomBinaryOutputConstructor") CONFIG_SCHEMA = cv.invalid(
CustomFloatOutputConstructor = custom_ns.class_("CustomFloatOutputConstructor") 'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONF_FLOAT = "float"
CONFIG_SCHEMA = cv.typed_schema(
{
CONF_BINARY: cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomBinaryOutputConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_OUTPUTS): cv.ensure_list(
output.BINARY_OUTPUT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(output.BinaryOutput),
}
) )
),
}
),
CONF_FLOAT: cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomFloatOutputConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_OUTPUTS): cv.ensure_list(
output.FLOAT_OUTPUT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(output.FloatOutput),
}
)
),
}
),
},
lower=True,
)
async def to_code(config):
type = config[CONF_TYPE]
if type == "binary":
ret_type = output.BinaryOutputPtr
klass = CustomBinaryOutputConstructor
else:
ret_type = output.FloatOutputPtr
klass = CustomFloatOutputConstructor
template_ = await cg.process_lambda(
config[CONF_LAMBDA], [], return_type=cg.std_vector.template(ret_type)
)
rhs = klass(template_)
custom = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_OUTPUTS]):
out = cg.Pvariable(conf[CONF_ID], custom.get_output(i))
await output.register_output(out, conf)

View File

@ -1,37 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/output/binary_output.h"
#include "esphome/components/output/float_output.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomBinaryOutputConstructor {
public:
CustomBinaryOutputConstructor(const std::function<std::vector<output::BinaryOutput *>()> &init) {
this->outputs_ = init();
}
output::BinaryOutput *get_output(int i) { return this->outputs_[i]; }
protected:
std::vector<output::BinaryOutput *> outputs_;
};
class CustomFloatOutputConstructor {
public:
CustomFloatOutputConstructor(const std::function<std::vector<output::FloatOutput *>()> &init) {
this->outputs_ = init();
}
output::FloatOutput *get_output(int i) { return this->outputs_[i]; }
protected:
std::vector<output::FloatOutput *> outputs_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,27 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_SENSORS
from .. import custom_ns
CustomSensorConstructor = custom_ns.class_("CustomSensorConstructor") CONFIG_SCHEMA = cv.invalid(
'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomSensorConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_SENSORS): cv.ensure_list(sensor.sensor_schema()),
}
) )
async def to_code(config):
template_ = await cg.process_lambda(
config[CONF_LAMBDA], [], return_type=cg.std_vector.template(sensor.SensorPtr)
)
rhs = CustomSensorConstructor(template_)
var = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_SENSORS]):
sens = cg.Pvariable(conf[CONF_ID], var.get_sensor(i))
await sensor.register_sensor(sens, conf)

View File

@ -1,16 +0,0 @@
#include "custom_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace custom {
static const char *const TAG = "custom.sensor";
void CustomSensorConstructor::dump_config() {
for (auto *child : this->sensors_) {
LOG_SENSOR("", "Custom Sensor", child);
}
}
} // namespace custom
} // namespace esphome

View File

@ -1,24 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomSensorConstructor : public Component {
public:
CustomSensorConstructor(const std::function<std::vector<sensor::Sensor *>()> &init) { this->sensors_ = init(); }
sensor::Sensor *get_sensor(int i) { return this->sensors_[i]; }
void dump_config() override;
protected:
std::vector<sensor::Sensor *> sensors_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,27 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import switch
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_SWITCHES
from .. import custom_ns
CustomSwitchConstructor = custom_ns.class_("CustomSwitchConstructor") CONFIG_SCHEMA = cv.invalid(
'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomSwitchConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_SWITCHES): cv.ensure_list(switch.switch_schema(switch.Switch)),
}
) )
async def to_code(config):
template_ = await cg.process_lambda(
config[CONF_LAMBDA], [], return_type=cg.std_vector.template(switch.SwitchPtr)
)
rhs = CustomSwitchConstructor(template_)
var = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_SWITCHES]):
switch_ = cg.Pvariable(conf[CONF_ID], var.get_switch(i))
await switch.register_switch(switch_, conf)

View File

@ -1,16 +0,0 @@
#include "custom_switch.h"
#include "esphome/core/log.h"
namespace esphome {
namespace custom {
static const char *const TAG = "custom.switch";
void CustomSwitchConstructor::dump_config() {
for (auto *child : this->switches_) {
LOG_SWITCH("", "Custom Switch", child);
}
}
} // namespace custom
} // namespace esphome

View File

@ -1,24 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/switch/switch.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomSwitchConstructor : public Component {
public:
CustomSwitchConstructor(const std::function<std::vector<switch_::Switch *>()> &init) { this->switches_ = init(); }
switch_::Switch *get_switch(int i) { return this->switches_[i]; }
void dump_config() override;
protected:
std::vector<switch_::Switch *> switches_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,32 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import text_sensor
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_TEXT_SENSORS
from .. import custom_ns
CustomTextSensorConstructor = custom_ns.class_("CustomTextSensorConstructor") CONFIG_SCHEMA = cv.invalid(
'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomTextSensorConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_TEXT_SENSORS): cv.ensure_list(
text_sensor.text_sensor_schema()
),
}
) )
async def to_code(config):
template_ = await cg.process_lambda(
config[CONF_LAMBDA],
[],
return_type=cg.std_vector.template(text_sensor.TextSensorPtr),
)
rhs = CustomTextSensorConstructor(template_)
var = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_TEXT_SENSORS]):
text = cg.Pvariable(conf[CONF_ID], var.get_text_sensor(i))
await text_sensor.register_text_sensor(text, conf)

View File

@ -1,16 +0,0 @@
#include "custom_text_sensor.h"
#include "esphome/core/log.h"
namespace esphome {
namespace custom {
static const char *const TAG = "custom.text_sensor";
void CustomTextSensorConstructor::dump_config() {
for (auto *child : this->text_sensors_) {
LOG_TEXT_SENSOR("", "Custom Text Sensor", child);
}
}
} // namespace custom
} // namespace esphome

View File

@ -1,26 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/text_sensor/text_sensor.h"
#include <vector>
namespace esphome {
namespace custom {
class CustomTextSensorConstructor : public Component {
public:
CustomTextSensorConstructor(const std::function<std::vector<text_sensor::TextSensor *>()> &init) {
this->text_sensors_ = init();
}
text_sensor::TextSensor *get_text_sensor(int i) { return this->text_sensors_[i]; }
void dump_config() override;
protected:
std::vector<text_sensor::TextSensor *> text_sensors_;
};
} // namespace custom
} // namespace esphome

View File

@ -1,31 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_COMPONENTS, CONF_ID, CONF_LAMBDA
custom_component_ns = cg.esphome_ns.namespace("custom_component")
CustomComponentConstructor = custom_component_ns.class_("CustomComponentConstructor")
MULTI_CONF = True MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(CustomComponentConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Optional(CONF_COMPONENTS): cv.ensure_list(
cv.Schema({cv.GenerateID(): cv.declare_id(cg.Component)}).extend(
cv.COMPONENT_SCHEMA
)
),
}
)
CONFIG_SCHEMA = cv.invalid(
async def to_code(config): 'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
template_ = await cg.process_lambda(
config[CONF_LAMBDA], [], return_type=cg.std_vector.template(cg.ComponentPtr)
) )
rhs = CustomComponentConstructor(template_)
var = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config.get(CONF_COMPONENTS, [])):
comp = cg.Pvariable(conf[CONF_ID], var.get_component(i))
await cg.register_component(comp, conf)

View File

@ -1,28 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/application.h"
#include <vector>
namespace esphome {
namespace custom_component {
class CustomComponentConstructor {
public:
CustomComponentConstructor(const std::function<std::vector<Component *>()> &init) {
this->components_ = init();
for (auto *comp : this->components_) {
App.register_component(comp);
}
}
Component *get_component(int i) const { return this->components_[i]; }
protected:
std::vector<Component *> components_;
};
} // namespace custom_component
} // namespace esphome

View File

@ -298,6 +298,12 @@ void DalyBmsComponent::decode_data_(std::vector<uint8_t> data) {
if (this->cell_16_voltage_sensor_) { if (this->cell_16_voltage_sensor_) {
this->cell_16_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000); this->cell_16_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
} }
if (this->cell_17_voltage_sensor_) {
this->cell_17_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
}
if (this->cell_18_voltage_sensor_) {
this->cell_18_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
}
break; break;
} }
break; break;

View File

@ -54,6 +54,8 @@ class DalyBmsComponent : public PollingComponent, public uart::UARTDevice {
SUB_SENSOR(cell_14_voltage) SUB_SENSOR(cell_14_voltage)
SUB_SENSOR(cell_15_voltage) SUB_SENSOR(cell_15_voltage)
SUB_SENSOR(cell_16_voltage) SUB_SENSOR(cell_16_voltage)
SUB_SENSOR(cell_17_voltage)
SUB_SENSOR(cell_18_voltage)
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR

View File

@ -52,6 +52,8 @@ CONF_CELL_13_VOLTAGE = "cell_13_voltage"
CONF_CELL_14_VOLTAGE = "cell_14_voltage" CONF_CELL_14_VOLTAGE = "cell_14_voltage"
CONF_CELL_15_VOLTAGE = "cell_15_voltage" CONF_CELL_15_VOLTAGE = "cell_15_voltage"
CONF_CELL_16_VOLTAGE = "cell_16_voltage" CONF_CELL_16_VOLTAGE = "cell_16_voltage"
CONF_CELL_17_VOLTAGE = "cell_17_voltage"
CONF_CELL_18_VOLTAGE = "cell_18_voltage"
ICON_CURRENT_DC = "mdi:current-dc" ICON_CURRENT_DC = "mdi:current-dc"
ICON_BATTERY_OUTLINE = "mdi:battery-outline" ICON_BATTERY_OUTLINE = "mdi:battery-outline"
ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up" ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up"
@ -92,6 +94,8 @@ TYPES = [
CONF_CELL_14_VOLTAGE, CONF_CELL_14_VOLTAGE,
CONF_CELL_15_VOLTAGE, CONF_CELL_15_VOLTAGE,
CONF_CELL_16_VOLTAGE, CONF_CELL_16_VOLTAGE,
CONF_CELL_17_VOLTAGE,
CONF_CELL_18_VOLTAGE,
] ]
CELL_VOLTAGE_SCHEMA = sensor.sensor_schema( CELL_VOLTAGE_SCHEMA = sensor.sensor_schema(
@ -212,6 +216,8 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_CELL_14_VOLTAGE): CELL_VOLTAGE_SCHEMA, cv.Optional(CONF_CELL_14_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_15_VOLTAGE): CELL_VOLTAGE_SCHEMA, cv.Optional(CONF_CELL_15_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_16_VOLTAGE): CELL_VOLTAGE_SCHEMA, cv.Optional(CONF_CELL_16_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_17_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_18_VOLTAGE): CELL_VOLTAGE_SCHEMA,
} }
).extend(cv.COMPONENT_SCHEMA) ).extend(cv.COMPONENT_SCHEMA)
) )

View File

@ -35,8 +35,8 @@ void DebugComponent::log_partition_info_() {
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
while (it != NULL) { while (it != NULL) {
const esp_partition_t *partition = esp_partition_get(it); const esp_partition_t *partition = esp_partition_get(it);
ESP_LOGCONFIG(TAG, " %-12s %-4d %-8d 0x%08X 0x%08X", partition->label, partition->type, partition->subtype, ESP_LOGCONFIG(TAG, " %-12s %-4d %-8d 0x%08" PRIX32 " 0x%08" PRIX32, partition->label, partition->type,
partition->address, partition->size); partition->subtype, partition->address, partition->size);
it = esp_partition_next(it); it = esp_partition_next(it);
} }
esp_partition_iterator_release(it); esp_partition_iterator_release(it);

View File

@ -1,67 +0,0 @@
import esphome.codegen as cg
from esphome.components import i2c
import esphome.config_validation as cv
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID, CONF_MIC_GAIN, CONF_SAMPLE_RATE
CODEOWNERS = ["@kahrendt"]
DEPENDENCIES = ["i2c"]
es7210_ns = cg.esphome_ns.namespace("es7210")
ES7210 = es7210_ns.class_("ES7210", cg.Component, i2c.I2CDevice)
es7210_bits_per_sample = es7210_ns.enum("ES7210BitsPerSample")
ES7210_BITS_PER_SAMPLE_ENUM = {
16: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_16,
24: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_24,
32: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_32,
}
es7210_mic_gain = es7210_ns.enum("ES7210MicGain")
ES7210_MIC_GAIN_ENUM = {
"0DB": es7210_mic_gain.ES7210_MIC_GAIN_0DB,
"3DB": es7210_mic_gain.ES7210_MIC_GAIN_3DB,
"6DB": es7210_mic_gain.ES7210_MIC_GAIN_6DB,
"9DB": es7210_mic_gain.ES7210_MIC_GAIN_9DB,
"12DB": es7210_mic_gain.ES7210_MIC_GAIN_12DB,
"15DB": es7210_mic_gain.ES7210_MIC_GAIN_15DB,
"18DB": es7210_mic_gain.ES7210_MIC_GAIN_18DB,
"21DB": es7210_mic_gain.ES7210_MIC_GAIN_21DB,
"24DB": es7210_mic_gain.ES7210_MIC_GAIN_24DB,
"27DB": es7210_mic_gain.ES7210_MIC_GAIN_27DB,
"30DB": es7210_mic_gain.ES7210_MIC_GAIN_30DB,
"33DB": es7210_mic_gain.ES7210_MIC_GAIN_33DB,
"34.5DB": es7210_mic_gain.ES7210_MIC_GAIN_34_5DB,
"36DB": es7210_mic_gain.ES7210_MIC_GAIN_36DB,
"37.5DB": es7210_mic_gain.ES7210_MIC_GAIN_37_5DB,
}
_validate_bits = cv.float_with_unit("bits", "bit")
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ES7210),
cv.Optional(CONF_BITS_PER_SAMPLE, default="16bit"): cv.All(
_validate_bits, cv.enum(ES7210_BITS_PER_SAMPLE_ENUM)
),
cv.Optional(CONF_MIC_GAIN, default="24DB"): cv.enum(
ES7210_MIC_GAIN_ENUM, upper=True
),
cv.Optional(CONF_SAMPLE_RATE, default=16000): cv.int_range(min=1),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x40))
)
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)
cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
cg.add(var.set_mic_gain(config[CONF_MIC_GAIN]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))

View File

@ -0,0 +1,51 @@
import esphome.codegen as cg
from esphome.components import i2c
from esphome.components.audio_adc import AudioAdc
import esphome.config_validation as cv
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID, CONF_MIC_GAIN, CONF_SAMPLE_RATE
CODEOWNERS = ["@kahrendt"]
DEPENDENCIES = ["i2c"]
es7210_ns = cg.esphome_ns.namespace("es7210")
ES7210 = es7210_ns.class_("ES7210", AudioAdc, cg.Component, i2c.I2CDevice)
es7210_bits_per_sample = es7210_ns.enum("ES7210BitsPerSample")
ES7210_BITS_PER_SAMPLE_ENUM = {
16: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_16,
24: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_24,
32: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_32,
}
ES7210_MIC_GAINS = [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 34.5, 36, 37.5]
_validate_bits = cv.float_with_unit("bits", "bit")
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ES7210),
cv.Optional(CONF_BITS_PER_SAMPLE, default="16bit"): cv.All(
_validate_bits, cv.enum(ES7210_BITS_PER_SAMPLE_ENUM)
),
cv.Optional(CONF_MIC_GAIN, default="24db"): cv.All(
cv.decibel, cv.one_of(*ES7210_MIC_GAINS)
),
cv.Optional(CONF_SAMPLE_RATE, default=16000): cv.int_range(min=1),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x40))
)
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)
cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
cg.add(var.set_mic_gain(config[CONF_MIC_GAIN]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))

View File

@ -25,12 +25,12 @@ static const size_t MCLK_DIV_FRE = 256;
} }
void ES7210::dump_config() { void ES7210::dump_config() {
ESP_LOGCONFIG(TAG, "ES7210 ADC:"); ESP_LOGCONFIG(TAG, "ES7210 audio ADC:");
ESP_LOGCONFIG(TAG, " Bits Per Sample: %" PRIu8, this->bits_per_sample_); ESP_LOGCONFIG(TAG, " Bits Per Sample: %" PRIu8, this->bits_per_sample_);
ESP_LOGCONFIG(TAG, " Sample Rate: %" PRIu32, this->sample_rate_); ESP_LOGCONFIG(TAG, " Sample Rate: %" PRIu32, this->sample_rate_);
if (this->is_failed()) { if (this->is_failed()) {
ESP_LOGCONFIG(TAG, " Failed to initialize!"); ESP_LOGE(TAG, " Failed to initialize");
return; return;
} }
} }
@ -84,6 +84,16 @@ void ES7210::setup() {
// Enable device // Enable device
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x71)); ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x71));
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x41)); ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x41));
this->setup_complete_ = true;
}
bool ES7210::set_mic_gain(float mic_gain) {
this->mic_gain_ = clamp<float>(mic_gain, ES7210_MIC_GAIN_MIN, ES7210_MIC_GAIN_MAX);
if (this->setup_complete_) {
return this->configure_mic_gain_();
}
return true;
} }
bool ES7210::configure_sample_rate_() { bool ES7210::configure_sample_rate_() {
@ -122,9 +132,11 @@ bool ES7210::configure_sample_rate_() {
return true; return true;
} }
bool ES7210::configure_mic_gain_() { bool ES7210::configure_mic_gain_() {
for (int i = 0; i < 4; ++i) { auto regv = this->es7210_gain_reg_value_(this->mic_gain_);
this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43 + i, 0x10, 0x00); for (uint8_t i = 0; i < 4; ++i) {
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43 + i, 0x10, 0x00));
} }
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0xff)); ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0xff));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0xff)); ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0xff));
@ -133,29 +145,44 @@ bool ES7210::configure_mic_gain_() {
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0x00)); ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43, 0x10, 0x10)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43, 0x0f, this->mic_gain_)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43, 0x0f, regv));
// Configure mic 2 // Configure mic 2
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0x00)); ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC2_GAIN_REG44, 0x10, 0x10)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC2_GAIN_REG44, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC2_GAIN_REG44, 0x0f, this->mic_gain_)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC2_GAIN_REG44, 0x0f, regv));
// Configure mic 3 // Configure mic 3
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0x00)); ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC3_GAIN_REG45, 0x10, 0x10)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC3_GAIN_REG45, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC3_GAIN_REG45, 0x0f, this->mic_gain_)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC3_GAIN_REG45, 0x0f, regv));
// Configure mic 4 // Configure mic 4
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0x00)); ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC4_GAIN_REG46, 0x10, 0x10)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC4_GAIN_REG46, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC4_GAIN_REG46, 0x0f, this->mic_gain_)); ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC4_GAIN_REG46, 0x0f, regv));
return true; return true;
} }
uint8_t ES7210::es7210_gain_reg_value_(float mic_gain) {
// reg: 12 - 34.5dB, 13 - 36dB, 14 - 37.5dB
mic_gain += 0.5;
if (mic_gain <= 33.0) {
return (uint8_t) mic_gain / 3;
}
if (mic_gain < 36.0) {
return 12;
}
if (mic_gain < 37.0) {
return 13;
}
return 14;
}
bool ES7210::configure_i2s_format_() { bool ES7210::configure_i2s_format_() {
// Configure bits per sample // Configure bits per sample
uint8_t reg_val = 0; uint8_t reg_val = 0;

View File

@ -1,8 +1,11 @@
#pragma once #pragma once
#include "esphome/components/audio_adc/audio_adc.h"
#include "esphome/components/i2c/i2c.h" #include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "es7210_const.h"
namespace esphome { namespace esphome {
namespace es7210 { namespace es7210 {
@ -14,25 +17,7 @@ enum ES7210BitsPerSample : uint8_t {
ES7210_BITS_PER_SAMPLE_32 = 32, ES7210_BITS_PER_SAMPLE_32 = 32,
}; };
enum ES7210MicGain : uint8_t { class ES7210 : public audio_adc::AudioAdc, public Component, public i2c::I2CDevice {
ES7210_MIC_GAIN_0DB = 0,
ES7210_MIC_GAIN_3DB,
ES7210_MIC_GAIN_6DB,
ES7210_MIC_GAIN_9DB,
ES7210_MIC_GAIN_12DB,
ES7210_MIC_GAIN_15DB,
ES7210_MIC_GAIN_18DB,
ES7210_MIC_GAIN_21DB,
ES7210_MIC_GAIN_24DB,
ES7210_MIC_GAIN_27DB,
ES7210_MIC_GAIN_30DB,
ES7210_MIC_GAIN_33DB,
ES7210_MIC_GAIN_34_5DB,
ES7210_MIC_GAIN_36DB,
ES7210_MIC_GAIN_37_5DB,
};
class ES7210 : public Component, public i2c::I2CDevice {
/* Class for configuring an ES7210 ADC for microphone input. /* Class for configuring an ES7210 ADC for microphone input.
* Based on code from: * Based on code from:
* - https://github.com/espressif/esp-bsp/ (accessed 20241219) * - https://github.com/espressif/esp-bsp/ (accessed 20241219)
@ -44,9 +29,11 @@ class ES7210 : public Component, public i2c::I2CDevice {
void dump_config() override; void dump_config() override;
void set_bits_per_sample(ES7210BitsPerSample bits_per_sample) { this->bits_per_sample_ = bits_per_sample; } void set_bits_per_sample(ES7210BitsPerSample bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }
void set_mic_gain(ES7210MicGain mic_gain) { this->mic_gain_ = mic_gain; } bool set_mic_gain(float mic_gain) override;
void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; } void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; }
float mic_gain() override { return this->mic_gain_; };
protected: protected:
/// @brief Updates an I2C registry address by modifying the current state /// @brief Updates an I2C registry address by modifying the current state
/// @param reg_addr I2C register address /// @param reg_addr I2C register address
@ -55,14 +42,20 @@ class ES7210 : public Component, public i2c::I2CDevice {
/// @return True if successful, false otherwise /// @return True if successful, false otherwise
bool es7210_update_reg_bit_(uint8_t reg_addr, uint8_t update_bits, uint8_t data); bool es7210_update_reg_bit_(uint8_t reg_addr, uint8_t update_bits, uint8_t data);
/// @brief Convert floating point mic gain value to register value
/// @param mic_gain Gain value to convert
/// @return Corresponding register value for specified gain
uint8_t es7210_gain_reg_value_(float mic_gain);
bool configure_i2s_format_(); bool configure_i2s_format_();
bool configure_mic_gain_(); bool configure_mic_gain_();
bool configure_sample_rate_(); bool configure_sample_rate_();
bool setup_complete_{false};
bool enable_tdm_{false}; // TDM is unsupported in ESPHome as of version 2024.12 bool enable_tdm_{false}; // TDM is unsupported in ESPHome as of version 2024.12
ES7210MicGain mic_gain_; float mic_gain_{0};
ES7210BitsPerSample bits_per_sample_; ES7210BitsPerSample bits_per_sample_{ES7210_BITS_PER_SAMPLE_16};
uint32_t sample_rate_; uint32_t sample_rate_{0};
}; };
} // namespace es7210 } // namespace es7210

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "es7210.h" #include <cinttypes>
namespace esphome { namespace esphome {
namespace es7210 { namespace es7210 {
@ -42,7 +42,7 @@ static const uint8_t ES7210_MIC12_POWER_REG4B = 0x4B; /* MICBias & ADC & PGA Pow
static const uint8_t ES7210_MIC34_POWER_REG4C = 0x4C; static const uint8_t ES7210_MIC34_POWER_REG4C = 0x4C;
/* /*
* Clock coefficient structer * Clock coefficient structure
*/ */
struct ES7210Coefficient { struct ES7210Coefficient {
uint32_t mclk; // mclk frequency uint32_t mclk; // mclk frequency
@ -122,5 +122,8 @@ static const ES7210Coefficient ES7210_COEFFICIENTS[] = {
{19200000, 96000, 0x01, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, 0xc8}, {19200000, 96000, 0x01, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, 0xc8},
}; };
static const float ES7210_MIC_GAIN_MIN = 0.0;
static const float ES7210_MIC_GAIN_MAX = 37.5;
} // namespace es7210 } // namespace es7210
} // namespace esphome } // namespace esphome

View File

View File

@ -0,0 +1,34 @@
import esphome.codegen as cg
from esphome.components import i2c
from esphome.components.audio_adc import AudioAdc
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MIC_GAIN
CODEOWNERS = ["@kbx81"]
DEPENDENCIES = ["i2c"]
es7243e_ns = cg.esphome_ns.namespace("es7243e")
ES7243E = es7243e_ns.class_("ES7243E", AudioAdc, cg.Component, i2c.I2CDevice)
ES7243E_MIC_GAINS = [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 34.5, 36, 37.5]
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ES7243E),
cv.Optional(CONF_MIC_GAIN, default="24db"): cv.All(
cv.decibel, cv.one_of(*ES7243E_MIC_GAINS)
),
}
)
.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)
cg.add(var.set_mic_gain(config[CONF_MIC_GAIN]))

View File

@ -0,0 +1,125 @@
#include "es7243e.h"
#include "es7243e_const.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include <cinttypes>
namespace esphome {
namespace es7243e {
static const char *const TAG = "es7243e";
// Mark the component as failed; use only in setup
#define ES7243E_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(); \
return; \
}
// Return false; use outside of setup
#define ES7243E_ERROR_CHECK(func) \
if (!(func)) { \
return false; \
}
void ES7243E::dump_config() {
ESP_LOGCONFIG(TAG, "ES7243E audio ADC:");
if (this->is_failed()) {
ESP_LOGE(TAG, " Failed to initialize");
return;
}
}
void ES7243E::setup() {
ESP_LOGCONFIG(TAG, "Setting up ES7243E...");
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG01, 0x3A));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_RESET_REG00, 0x80));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_TEST_MODE_REGF9, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG04, 0x02));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG04, 0x01));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_TEST_MODE_REGF9, 0x01));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_RESET_REG00, 0x1E));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG01, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG02, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG03, 0x20));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG04, 0x01));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ADC_CTRL_REG0D, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG05, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG06, 0x03)); // SCLK=MCLK/4
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG07, 0x00)); // LRCK=MCLK/256
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG08, 0xFF)); // LRCK=MCLK/256
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG09, 0xCA));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_SDP_REG0A, 0x85));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_SDP_REG0B, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ADC_CTRL_REG0E, 0xBF));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ADC_CTRL_REG0F, 0x80));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ADC_CTRL_REG14, 0x0C));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ADC_CTRL_REG15, 0x0C));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG17, 0x02));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG18, 0x26));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG19, 0x77));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG1A, 0xF4));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG1B, 0x66));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG1C, 0x44));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG1E, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG1F, 0x0C));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG20, 0x1A)); // PGA gain +30dB
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG21, 0x1A));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_RESET_REG00, 0x80));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG01, 0x3A));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG16, 0x3F));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG16, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_TEST_MODE_REGF9, 0x00));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG04, 0x01));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG17, 0x01));
ES7243E_ERROR_FAILED(this->configure_mic_gain_());
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_RESET_REG00, 0x80));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG01, 0x3A));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG16, 0x3F));
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_ANALOG_REG16, 0x00));
this->setup_complete_ = true;
}
bool ES7243E::set_mic_gain(float mic_gain) {
this->mic_gain_ = clamp<float>(mic_gain, 0, 37.5);
if (this->setup_complete_) {
return this->configure_mic_gain_();
}
return true;
}
bool ES7243E::configure_mic_gain_() {
auto regv = this->es7243e_gain_reg_value_(this->mic_gain_);
ES7243E_ERROR_CHECK(this->write_byte(ES7243E_ANALOG_REG20, 0x10 | regv));
ES7243E_ERROR_CHECK(this->write_byte(ES7243E_ANALOG_REG21, 0x10 | regv));
return true;
}
uint8_t ES7243E::es7243e_gain_reg_value_(float mic_gain) {
// reg: 12 - 34.5dB, 13 - 36dB, 14 - 37.5dB
mic_gain += 0.5;
if (mic_gain <= 33.0) {
return (uint8_t) mic_gain / 3;
}
if (mic_gain < 36.0) {
return 12;
}
if (mic_gain < 37.0) {
return 13;
}
return 14;
}
} // namespace es7243e
} // namespace esphome

View File

@ -0,0 +1,37 @@
#pragma once
#include "esphome/components/audio_adc/audio_adc.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
namespace esphome {
namespace es7243e {
class ES7243E : public audio_adc::AudioAdc, public Component, public i2c::I2CDevice {
/* Class for configuring an ES7243E ADC for microphone input.
* Based on code from:
* - https://github.com/espressif/esp-adf/ (accessed 20250116)
*/
public:
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
bool set_mic_gain(float mic_gain) override;
float mic_gain() override { return this->mic_gain_; };
protected:
/// @brief Convert floating point mic gain value to register value
/// @param mic_gain Gain value to convert
/// @return Corresponding register value for specified gain
uint8_t es7243e_gain_reg_value_(float mic_gain);
bool configure_mic_gain_();
bool setup_complete_{false};
float mic_gain_{0};
};
} // namespace es7243e
} // namespace esphome

View File

@ -0,0 +1,54 @@
#pragma once
#include <cinttypes>
namespace esphome {
namespace es7243e {
// ES7243E register addresses
static const uint8_t ES7243E_RESET_REG00 = 0x00; // Reset control
static const uint8_t ES7243E_CLOCK_MGR_REG01 = 0x01; // MCLK/BCLK/ADCCLK/Analog clocks on/off
static const uint8_t ES7243E_CLOCK_MGR_REG02 = 0x02; // MCLK & BCLK configuration, source selection
static const uint8_t ES7243E_CLOCK_MGR_REG03 = 0x03; // ADC Over-sample rate control
static const uint8_t ES7243E_CLOCK_MGR_REG04 = 0x04; // Pre-divide/Pre-multiplication
static const uint8_t ES7243E_CLOCK_MGR_REG05 = 0x05; // CF/DSP clock divider
static const uint8_t ES7243E_CLOCK_MGR_REG06 = 0x06; // BCLK divider at master mode
static const uint8_t ES7243E_CLOCK_MGR_REG07 = 0x07; // BCLK/LRCK/SDOUT tri-state control/LRCK divider bit 11->8
static const uint8_t ES7243E_CLOCK_MGR_REG08 = 0x08; // Master LRCK divider bit 7 to bit 0
static const uint8_t ES7243E_CLOCK_MGR_REG09 = 0x09; // SEL S1/Timer for S1
static const uint8_t ES7243E_SDP_REG0A = 0x0A; // SEL S3/Timer for S3
static const uint8_t ES7243E_SDP_REG0B = 0x0B; // SDP out mute control/I2S/left-justify case/word length/format
static const uint8_t ES7243E_SDP_REG0C = 0x0C; // NFS flag at slot0/LSB/TDM mode selection
static const uint8_t ES7243E_ADC_CTRL_REG0D = 0x0D; // data mux/pol. inv./ram clear on lrck/mclk active/gain scale up
static const uint8_t ES7243E_ADC_CTRL_REG0E = 0x0E; // volume control
static const uint8_t ES7243E_ADC_CTRL_REG0F = 0x0F; // offset freeze/auto level control/automute control/VC ramp rate
static const uint8_t ES7243E_ADC_CTRL_REG10 = 0x10; // automute noise gate/detection
static const uint8_t ES7243E_ADC_CTRL_REG11 = 0x11; // automute SDP control/out gain select
static const uint8_t ES7243E_ADC_CTRL_REG12 = 0x12; // controls for automute PDN_PGA/MOD/reset/digital circuit
static const uint8_t ES7243E_ADC_CTRL_REG13 = 0x13; // ALC rate selection/ALC target level
static const uint8_t ES7243E_ADC_CTRL_REG14 = 0x14; // ADCHPF stage1 coeff
static const uint8_t ES7243E_ADC_CTRL_REG15 = 0x15; // ADCHPF stage2 coeff
static const uint8_t ES7243E_ANALOG_REG16 = 0x16; // power-down/reset
static const uint8_t ES7243E_ANALOG_REG17 = 0x17; // VMIDSEL
static const uint8_t ES7243E_ANALOG_REG18 = 0x18; // ADC/ADCFL bias
static const uint8_t ES7243E_ANALOG_REG19 = 0x19; // PGA1/PGA2 bias
static const uint8_t ES7243E_ANALOG_REG1A = 0x1A; // ADCI1/ADCI23 bias
static const uint8_t ES7243E_ANALOG_REG1B = 0x1B; // ADCSM/ADCCM bias
static const uint8_t ES7243E_ANALOG_REG1C = 0x1C; // ADCVRP/ADCCPP bias
static const uint8_t ES7243E_ANALOG_REG1D = 0x1D; // low power bits
static const uint8_t ES7243E_ANALOG_REG1E = 0x1E; // low power bits
static const uint8_t ES7243E_ANALOG_REG1F = 0x1F; // ADC_DMIC_ON/REFSEL/VX2OFF/VX1SEL/VMIDLVL
static const uint8_t ES7243E_ANALOG_REG20 = 0x20; // select MIC1 as PGA1 input/PGA1 gain
static const uint8_t ES7243E_ANALOG_REG21 = 0x21; // select MIC2 as PGA1 input/PGA2 gain
static const uint8_t ES7243E_TEST_MODE_REGF7 = 0xF7;
static const uint8_t ES7243E_TEST_MODE_REGF8 = 0xF8;
static const uint8_t ES7243E_TEST_MODE_REGF9 = 0xF9;
static const uint8_t ES7243E_I2C_CONF_REGFA = 0xFA; // I2C signals retime/reset registers to default
static const uint8_t ES7243E_FLAG_REGFC = 0xFC; // CSM flag/ADC automute flag (RO)
static const uint8_t ES7243E_CHIP_ID1_REGFD = 0xFD; // chip ID 1, reads 0x7A (RO)
static const uint8_t ES7243E_CHIP_ID2_REGFE = 0xFE; // chip ID 2, reads 0x43 (RO)
static const uint8_t ES7243E_CHIP_VERSION_REGFF = 0xFF; // chip version, reads 0x00 (RO)
} // namespace es7243e
} // namespace esphome

View File

View File

@ -0,0 +1,27 @@
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 = ["@kbx81"]
DEPENDENCIES = ["i2c"]
es8156_ns = cg.esphome_ns.namespace("es8156")
ES8156 = es8156_ns.class_("ES8156", AudioDac, cg.Component, i2c.I2CDevice)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ES8156),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x08))
)
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)

View File

@ -0,0 +1,87 @@
#include "es8156.h"
#include "es8156_const.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include <cinttypes>
namespace esphome {
namespace es8156 {
static const char *const TAG = "es8156";
// Mark the component as failed; use only in setup
#define ES8156_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(); \
return; \
}
void ES8156::setup() {
ESP_LOGCONFIG(TAG, "Setting up ES8156...");
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG02_SCLK_MODE, 0x04));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG20_ANALOG_SYS1, 0x2A));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG21_ANALOG_SYS2, 0x3C));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG22_ANALOG_SYS3, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG24_ANALOG_LP, 0x07));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG23_ANALOG_SYS4, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0A_TIME_CONTROL1, 0x01));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0B_TIME_CONTROL2, 0x01));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG11_DAC_SDP, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG19_EQ_CONTROL1, 0x20));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0D_P2S_CONTROL, 0x14));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG09_MISC_CONTROL2, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG18_MISC_CONTROL3, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG08_CLOCK_ON_OFF, 0x3F));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x02));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x03));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG25_ANALOG_SYS5, 0x20));
}
void ES8156::dump_config() {
ESP_LOGCONFIG(TAG, "ES8156 Audio Codec:");
if (this->is_failed()) {
ESP_LOGCONFIG(TAG, " Failed to initialize");
return;
}
}
bool ES8156::set_volume(float volume) {
volume = clamp(volume, 0.0f, 1.0f);
uint8_t reg = remap<uint8_t, float>(volume, 0.0f, 1.0f, 0, 255);
ESP_LOGV(TAG, "Setting ES8156_REG14_VOLUME_CONTROL to %u (volume: %f)", reg, volume);
return this->write_byte(ES8156_REG14_VOLUME_CONTROL, reg);
}
float ES8156::volume() {
uint8_t reg;
this->read_byte(ES8156_REG14_VOLUME_CONTROL, &reg);
return remap<float, uint8_t>(reg, 0, 255, 0.0f, 1.0f);
}
bool ES8156::set_mute_state_(bool mute_state) {
uint8_t reg13;
this->is_muted_ = mute_state;
if (!this->read_byte(ES8156_REG13_DAC_MUTE, &reg13)) {
return false;
}
ESP_LOGV(TAG, "Read ES8156_REG13_DAC_MUTE: %u", reg13);
if (mute_state) {
reg13 |= BIT(1) | BIT(2);
} else {
reg13 &= ~(BIT(1) | BIT(2));
}
ESP_LOGV(TAG, "Setting ES8156_REG13_DAC_MUTE to %u (muted: %s)", reg13, YESNO(mute_state));
return this->write_byte(ES8156_REG13_DAC_MUTE, reg13);
}
} // namespace es8156
} // namespace esphome

View File

@ -0,0 +1,51 @@
#pragma once
#include "esphome/components/audio_dac/audio_dac.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
namespace esphome {
namespace es8156 {
class ES8156 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice {
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_; }
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 es8156
} // namespace esphome

View File

@ -0,0 +1,68 @@
#pragma once
#include "es8156.h"
namespace esphome {
namespace es8156 {
/* ES8156 register addresses */
/*
* RESET Control
*/
static const uint8_t ES8156_REG00_RESET = 0x00;
/*
* Clock Managerment
*/
static const uint8_t ES8156_REG01_MAINCLOCK_CTL = 0x01;
static const uint8_t ES8156_REG02_SCLK_MODE = 0x02;
static const uint8_t ES8156_REG03_LRCLK_DIV_H = 0x03;
static const uint8_t ES8156_REG04_LRCLK_DIV_L = 0x04;
static const uint8_t ES8156_REG05_SCLK_DIV = 0x05;
static const uint8_t ES8156_REG06_NFS_CONFIG = 0x06;
static const uint8_t ES8156_REG07_MISC_CONTROL1 = 0x07;
static const uint8_t ES8156_REG08_CLOCK_ON_OFF = 0x08;
static const uint8_t ES8156_REG09_MISC_CONTROL2 = 0x09;
static const uint8_t ES8156_REG0A_TIME_CONTROL1 = 0x0a;
static const uint8_t ES8156_REG0B_TIME_CONTROL2 = 0x0b;
/*
* System Control
*/
static const uint8_t ES8156_REG0C_CHIP_STATUS = 0x0c;
static const uint8_t ES8156_REG0D_P2S_CONTROL = 0x0d;
static const uint8_t ES8156_REG10_DAC_OSR_COUNTER = 0x10;
/*
* SDP Control
*/
static const uint8_t ES8156_REG11_DAC_SDP = 0x11;
static const uint8_t ES8156_REG12_AUTOMUTE_SET = 0x12;
static const uint8_t ES8156_REG13_DAC_MUTE = 0x13;
static const uint8_t ES8156_REG14_VOLUME_CONTROL = 0x14;
/*
* ALC Control
*/
static const uint8_t ES8156_REG15_ALC_CONFIG1 = 0x15;
static const uint8_t ES8156_REG16_ALC_CONFIG2 = 0x16;
static const uint8_t ES8156_REG17_ALC_CONFIG3 = 0x17;
static const uint8_t ES8156_REG18_MISC_CONTROL3 = 0x18;
static const uint8_t ES8156_REG19_EQ_CONTROL1 = 0x19;
static const uint8_t ES8156_REG1A_EQ_CONTROL2 = 0x1a;
/*
* Analog System Control
*/
static const uint8_t ES8156_REG20_ANALOG_SYS1 = 0x20;
static const uint8_t ES8156_REG21_ANALOG_SYS2 = 0x21;
static const uint8_t ES8156_REG22_ANALOG_SYS3 = 0x22;
static const uint8_t ES8156_REG23_ANALOG_SYS4 = 0x23;
static const uint8_t ES8156_REG24_ANALOG_LP = 0x24;
static const uint8_t ES8156_REG25_ANALOG_SYS5 = 0x25;
/*
* Chip Information
*/
static const uint8_t ES8156_REGFC_I2C_PAGESEL = 0xFC;
static const uint8_t ES8156_REGFD_CHIPID1 = 0xFD;
static const uint8_t ES8156_REGFE_CHIPID0 = 0xFE;
static const uint8_t ES8156_REGFF_CHIP_VERSION = 0xFF;
} // namespace es8156
} // namespace esphome

View File

@ -64,6 +64,7 @@ from .gpio import esp32_pin_to_code # noqa
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
AUTO_LOAD = ["preferences"] AUTO_LOAD = ["preferences"]
IS_TARGET_PLATFORM = True
CONF_RELEASE = "release" CONF_RELEASE = "release"

View File

@ -52,7 +52,12 @@ void ESP32TouchComponent::setup() {
} }
#endif #endif
#if ESP_IDF_VERSION_MAJOR >= 5
touch_pad_set_measurement_clock_cycles(this->meas_cycle_);
touch_pad_set_measurement_interval(this->sleep_cycle_);
#else
touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_); touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_);
#endif
touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_); touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_);
for (auto *child : this->children_) { for (auto *child : this->children_) {

View File

@ -34,6 +34,7 @@ from .gpio import PinInitialState, add_pin_initial_states_array
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
AUTO_LOAD = ["preferences"] AUTO_LOAD = ["preferences"]
IS_TARGET_PLATFORM = True
def set_core_data(config): def set_core_data(config):

View File

@ -17,6 +17,7 @@ from .gpio import host_pin_to_code # noqa
CODEOWNERS = ["@esphome/core", "@clydebarrow"] CODEOWNERS = ["@esphome/core", "@clydebarrow"]
AUTO_LOAD = ["network", "preferences"] AUTO_LOAD = ["network", "preferences"]
IS_TARGET_PLATFORM = True
def set_core_data(config): def set_core_data(config):

View File

@ -12,6 +12,8 @@
#include "esp_crt_bundle.h" #include "esp_crt_bundle.h"
#endif #endif
#include "esp_task_wdt.h"
namespace esphome { namespace esphome {
namespace http_request { namespace http_request {
@ -117,11 +119,11 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::start(std::string url, std::strin
return nullptr; return nullptr;
} }
App.feed_wdt(); container->feed_wdt();
container->content_length = esp_http_client_fetch_headers(client); container->content_length = esp_http_client_fetch_headers(client);
App.feed_wdt(); container->feed_wdt();
container->status_code = esp_http_client_get_status_code(client); container->status_code = esp_http_client_get_status_code(client);
App.feed_wdt(); container->feed_wdt();
if (is_success(container->status_code)) { if (is_success(container->status_code)) {
container->duration_ms = millis() - start; container->duration_ms = millis() - start;
return container; return container;
@ -151,11 +153,11 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::start(std::string url, std::strin
return nullptr; return nullptr;
} }
App.feed_wdt(); container->feed_wdt();
container->content_length = esp_http_client_fetch_headers(client); container->content_length = esp_http_client_fetch_headers(client);
App.feed_wdt(); container->feed_wdt();
container->status_code = esp_http_client_get_status_code(client); container->status_code = esp_http_client_get_status_code(client);
App.feed_wdt(); container->feed_wdt();
if (is_success(container->status_code)) { if (is_success(container->status_code)) {
container->duration_ms = millis() - start; container->duration_ms = millis() - start;
return container; return container;
@ -185,8 +187,9 @@ int HttpContainerIDF::read(uint8_t *buf, size_t max_len) {
return 0; return 0;
} }
App.feed_wdt(); this->feed_wdt();
int read_len = esp_http_client_read(this->client_, (char *) buf, bufsize); int read_len = esp_http_client_read(this->client_, (char *) buf, bufsize);
this->feed_wdt();
this->bytes_read_ += read_len; this->bytes_read_ += read_len;
this->duration_ms += (millis() - start); this->duration_ms += (millis() - start);
@ -201,6 +204,13 @@ void HttpContainerIDF::end() {
esp_http_client_cleanup(this->client_); esp_http_client_cleanup(this->client_);
} }
void HttpContainerIDF::feed_wdt() {
// Tests to see if the executing task has a watchdog timer attached
if (esp_task_wdt_status(nullptr) == ESP_OK) {
App.feed_wdt();
}
}
} // namespace http_request } // namespace http_request
} // namespace esphome } // namespace esphome

View File

@ -18,6 +18,9 @@ class HttpContainerIDF : public HttpContainer {
int read(uint8_t *buf, size_t max_len) override; int read(uint8_t *buf, size_t max_len) override;
void end() override; void end() override;
/// @brief Feeds the watchdog timer if the executing task has one attached
void feed_wdt();
protected: protected:
esp_http_client_handle_t client_; esp_http_client_handle_t client_;
}; };

View File

@ -9,6 +9,13 @@
namespace esphome { namespace esphome {
namespace http_request { namespace http_request {
// The update function runs in a task only on ESP32s.
#ifdef USE_ESP32
#define UPDATE_RETURN vTaskDelete(nullptr) // Delete the current update task
#else
#define UPDATE_RETURN return
#endif
static const char *const TAG = "http_request.update"; static const char *const TAG = "http_request.update";
static const size_t MAX_READ_SIZE = 256; static const size_t MAX_READ_SIZE = 256;
@ -29,45 +36,57 @@ void HttpRequestUpdate::setup() {
} }
void HttpRequestUpdate::update() { void HttpRequestUpdate::update() {
auto container = this->request_parent_->get(this->source_url_); #ifdef USE_ESP32
xTaskCreate(HttpRequestUpdate::update_task, "update_task", 8192, (void *) this, 1, &this->update_task_handle_);
#else
this->update_task(this);
#endif
}
void HttpRequestUpdate::update_task(void *params) {
HttpRequestUpdate *this_update = (HttpRequestUpdate *) params;
auto container = this_update->request_parent_->get(this_update->source_url_);
if (container == nullptr || container->status_code != HTTP_STATUS_OK) { if (container == nullptr || container->status_code != HTTP_STATUS_OK) {
std::string msg = str_sprintf("Failed to fetch manifest from %s", this->source_url_.c_str()); std::string msg = str_sprintf("Failed to fetch manifest from %s", this_update->source_url_.c_str());
this->status_set_error(msg.c_str()); this_update->status_set_error(msg.c_str());
return; UPDATE_RETURN;
} }
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE); ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
uint8_t *data = allocator.allocate(container->content_length); uint8_t *data = allocator.allocate(container->content_length);
if (data == nullptr) { if (data == nullptr) {
std::string msg = str_sprintf("Failed to allocate %d bytes for manifest", container->content_length); std::string msg = str_sprintf("Failed to allocate %d bytes for manifest", container->content_length);
this->status_set_error(msg.c_str()); this_update->status_set_error(msg.c_str());
container->end(); container->end();
return; UPDATE_RETURN;
} }
size_t read_index = 0; size_t read_index = 0;
while (container->get_bytes_read() < container->content_length) { while (container->get_bytes_read() < container->content_length) {
int read_bytes = container->read(data + read_index, MAX_READ_SIZE); int read_bytes = container->read(data + read_index, MAX_READ_SIZE);
App.feed_wdt();
yield(); yield();
read_index += read_bytes; read_index += read_bytes;
} }
bool valid = false;
{ // Ensures the response string falls out of scope and deallocates before the task ends
std::string response((char *) data, read_index); std::string response((char *) data, read_index);
allocator.deallocate(data, container->content_length); allocator.deallocate(data, container->content_length);
container->end(); container->end();
container.reset(); // Release ownership of the container's shared_ptr
bool valid = json::parse_json(response, [this](JsonObject root) -> bool { valid = json::parse_json(response, [this_update](JsonObject root) -> bool {
if (!root.containsKey("name") || !root.containsKey("version") || !root.containsKey("builds")) { if (!root.containsKey("name") || !root.containsKey("version") || !root.containsKey("builds")) {
ESP_LOGE(TAG, "Manifest does not contain required fields"); ESP_LOGE(TAG, "Manifest does not contain required fields");
return false; return false;
} }
this->update_info_.title = root["name"].as<std::string>(); this_update->update_info_.title = root["name"].as<std::string>();
this->update_info_.latest_version = root["version"].as<std::string>(); this_update->update_info_.latest_version = root["version"].as<std::string>();
for (auto build : root["builds"].as<JsonArray>()) { for (auto build : root["builds"].as<JsonArray>()) {
if (!build.containsKey("chipFamily")) { if (!build.containsKey("chipFamily")) {
@ -84,38 +103,40 @@ void HttpRequestUpdate::update() {
ESP_LOGE(TAG, "Manifest does not contain required fields"); ESP_LOGE(TAG, "Manifest does not contain required fields");
return false; return false;
} }
this->update_info_.firmware_url = ota["path"].as<std::string>(); this_update->update_info_.firmware_url = ota["path"].as<std::string>();
this->update_info_.md5 = ota["md5"].as<std::string>(); this_update->update_info_.md5 = ota["md5"].as<std::string>();
if (ota.containsKey("summary")) if (ota.containsKey("summary"))
this->update_info_.summary = ota["summary"].as<std::string>(); this_update->update_info_.summary = ota["summary"].as<std::string>();
if (ota.containsKey("release_url")) if (ota.containsKey("release_url"))
this->update_info_.release_url = ota["release_url"].as<std::string>(); this_update->update_info_.release_url = ota["release_url"].as<std::string>();
return true; return true;
} }
} }
return false; return false;
}); });
}
if (!valid) { if (!valid) {
std::string msg = str_sprintf("Failed to parse JSON from %s", this->source_url_.c_str()); std::string msg = str_sprintf("Failed to parse JSON from %s", this_update->source_url_.c_str());
this->status_set_error(msg.c_str()); this_update->status_set_error(msg.c_str());
return; UPDATE_RETURN;
} }
// Merge source_url_ and this->update_info_.firmware_url // Merge source_url_ and this_update->update_info_.firmware_url
if (this->update_info_.firmware_url.find("http") == std::string::npos) { if (this_update->update_info_.firmware_url.find("http") == std::string::npos) {
std::string path = this->update_info_.firmware_url; std::string path = this_update->update_info_.firmware_url;
if (path[0] == '/') { if (path[0] == '/') {
std::string domain = this->source_url_.substr(0, this->source_url_.find('/', 8)); std::string domain = this_update->source_url_.substr(0, this_update->source_url_.find('/', 8));
this->update_info_.firmware_url = domain + path; this_update->update_info_.firmware_url = domain + path;
} else { } else {
std::string domain = this->source_url_.substr(0, this->source_url_.rfind('/') + 1); std::string domain = this_update->source_url_.substr(0, this_update->source_url_.rfind('/') + 1);
this->update_info_.firmware_url = domain + path; this_update->update_info_.firmware_url = domain + path;
} }
} }
{ // Ensures the current version string falls out of scope and deallocates before the task ends
std::string current_version; std::string current_version;
#ifdef ESPHOME_PROJECT_VERSION #ifdef ESPHOME_PROJECT_VERSION
current_version = ESPHOME_PROJECT_VERSION; current_version = ESPHOME_PROJECT_VERSION;
@ -123,19 +144,23 @@ void HttpRequestUpdate::update() {
current_version = ESPHOME_VERSION; current_version = ESPHOME_VERSION;
#endif #endif
this->update_info_.current_version = current_version; this_update->update_info_.current_version = current_version;
if (this->update_info_.latest_version.empty() || this->update_info_.latest_version == update_info_.current_version) {
this->state_ = update::UPDATE_STATE_NO_UPDATE;
} else {
this->state_ = update::UPDATE_STATE_AVAILABLE;
} }
this->update_info_.has_progress = false; if (this_update->update_info_.latest_version.empty() ||
this->update_info_.progress = 0.0f; this_update->update_info_.latest_version == this_update->update_info_.current_version) {
this_update->state_ = update::UPDATE_STATE_NO_UPDATE;
} else {
this_update->state_ = update::UPDATE_STATE_AVAILABLE;
}
this->status_clear_error(); this_update->update_info_.has_progress = false;
this->publish_state(); this_update->update_info_.progress = 0.0f;
this_update->status_clear_error();
this_update->publish_state();
UPDATE_RETURN;
} }
void HttpRequestUpdate::perform(bool force) { void HttpRequestUpdate::perform(bool force) {

View File

@ -7,6 +7,10 @@
#include "esphome/components/http_request/ota/ota_http_request.h" #include "esphome/components/http_request/ota/ota_http_request.h"
#include "esphome/components/update/update_entity.h" #include "esphome/components/update/update_entity.h"
#ifdef USE_ESP32
#include <freertos/FreeRTOS.h>
#endif
namespace esphome { namespace esphome {
namespace http_request { namespace http_request {
@ -29,6 +33,11 @@ class HttpRequestUpdate : public update::UpdateEntity, public PollingComponent {
HttpRequestComponent *request_parent_; HttpRequestComponent *request_parent_;
OtaHttpRequestComponent *ota_parent_; OtaHttpRequestComponent *ota_parent_;
std::string source_url_; std::string source_url_;
static void update_task(void *params);
#ifdef USE_ESP32
TaskHandle_t update_task_handle_{nullptr};
#endif
}; };
} // namespace http_request } // namespace http_request

View File

@ -282,7 +282,7 @@ IMAGE_TYPE = {
TransparencyType = image_ns.enum("TransparencyType") TransparencyType = image_ns.enum("TransparencyType")
CONF_USE_TRANSPARENCY = "use_transparency" CONF_TRANSPARENCY = "transparency"
# If the MDI file cannot be downloaded within this time, abort. # If the MDI file cannot be downloaded within this time, abort.
IMAGE_DOWNLOAD_TIMEOUT = 30 # seconds IMAGE_DOWNLOAD_TIMEOUT = 30 # seconds
@ -417,7 +417,7 @@ def validate_type(image_types):
def validate_settings(value): def validate_settings(value):
type = value[CONF_TYPE] type = value[CONF_TYPE]
transparency = value[CONF_USE_TRANSPARENCY].lower() transparency = value[CONF_TRANSPARENCY].lower()
allow_config = IMAGE_TYPE[type].allow_config allow_config = IMAGE_TYPE[type].allow_config
if transparency not in allow_config: if transparency not in allow_config:
raise cv.Invalid( raise cv.Invalid(
@ -458,9 +458,7 @@ BASE_SCHEMA = cv.Schema(
IMAGE_SCHEMA = BASE_SCHEMA.extend( IMAGE_SCHEMA = BASE_SCHEMA.extend(
{ {
cv.Required(CONF_TYPE): validate_type(IMAGE_TYPE), cv.Required(CONF_TYPE): validate_type(IMAGE_TYPE),
cv.Optional( cv.Optional(CONF_TRANSPARENCY, default=CONF_OPAQUE): validate_transparency(),
CONF_USE_TRANSPARENCY, default=CONF_OPAQUE
): validate_transparency(),
} }
) )
@ -476,7 +474,7 @@ def typed_image_schema(image_type):
BASE_SCHEMA.extend( BASE_SCHEMA.extend(
{ {
cv.Optional( cv.Optional(
CONF_USE_TRANSPARENCY, default=t CONF_TRANSPARENCY, default=t
): validate_transparency((t,)), ): validate_transparency((t,)),
cv.Optional(CONF_TYPE, default=image_type): validate_type( cv.Optional(CONF_TYPE, default=image_type): validate_type(
(image_type,) (image_type,)
@ -494,7 +492,7 @@ def typed_image_schema(image_type):
BASE_SCHEMA.extend( BASE_SCHEMA.extend(
{ {
cv.Optional( cv.Optional(
CONF_USE_TRANSPARENCY, default=CONF_OPAQUE CONF_TRANSPARENCY, default=CONF_OPAQUE
): validate_transparency(), ): validate_transparency(),
cv.Optional(CONF_TYPE, default=image_type): validate_type( cv.Optional(CONF_TYPE, default=image_type): validate_type(
(image_type,) (image_type,)
@ -556,7 +554,7 @@ async def write_image(config, all_frames=False):
else Image.Dither.FLOYDSTEINBERG else Image.Dither.FLOYDSTEINBERG
) )
type = config[CONF_TYPE] type = config[CONF_TYPE]
transparency = config[CONF_USE_TRANSPARENCY] transparency = config[CONF_TRANSPARENCY]
invert_alpha = config[CONF_INVERT_ALPHA] invert_alpha = config[CONF_INVERT_ALPHA]
frame_count = 1 frame_count = 1
if all_frames: if all_frames:

View File

@ -47,6 +47,7 @@ from .const import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@kuba2k2"] CODEOWNERS = ["@kuba2k2"]
AUTO_LOAD = ["preferences"] AUTO_LOAD = ["preferences"]
IS_TARGET_PLATFORM = True
def _detect_variant(value): def _detect_variant(value):

View File

@ -186,6 +186,8 @@ CONFIG_SCHEMA = cv.All(
esp32_s3_idf=USB_SERIAL_JTAG, esp32_s3_idf=USB_SERIAL_JTAG,
esp32_c3_arduino=USB_CDC, esp32_c3_arduino=USB_CDC,
esp32_c3_idf=USB_SERIAL_JTAG, esp32_c3_idf=USB_SERIAL_JTAG,
esp32_c6_arduino=USB_CDC,
esp32_c6_idf=USB_SERIAL_JTAG,
rp2040=USB_CDC, rp2040=USB_CDC,
bk72xx=DEFAULT, bk72xx=DEFAULT,
rtl87xx=DEFAULT, rtl87xx=DEFAULT,

View File

@ -72,9 +72,9 @@ void MQTTClimateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCo
// max_temp // max_temp
root[MQTT_MAX_TEMP] = traits.get_visual_max_temperature(); root[MQTT_MAX_TEMP] = traits.get_visual_max_temperature();
// target_temp_step // target_temp_step
root[MQTT_TARGET_TEMPERATURE_STEP] = traits.get_visual_target_temperature_step(); root[MQTT_TARGET_TEMPERATURE_STEP] = roundf(traits.get_visual_target_temperature_step() * 10) * 0.1;
// current_temp_step // current_temp_step
root[MQTT_CURRENT_TEMPERATURE_STEP] = traits.get_visual_current_temperature_step(); root[MQTT_CURRENT_TEMPERATURE_STEP] = roundf(traits.get_visual_current_temperature_step() * 10) * 0.1;
// temperature units are always coerced to Celsius internally // temperature units are always coerced to Celsius internally
root[MQTT_TEMPERATURE_UNIT] = "C"; root[MQTT_TEMPERATURE_UNIT] = "C";

View File

@ -2,7 +2,7 @@ from math import log
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import sensor, resistance_sampler from esphome.components import sensor
from esphome.const import ( from esphome.const import (
CONF_CALIBRATION, CONF_CALIBRATION,
CONF_REFERENCE_RESISTANCE, CONF_REFERENCE_RESISTANCE,
@ -15,8 +15,6 @@ from esphome.const import (
UNIT_CELSIUS, UNIT_CELSIUS,
) )
AUTO_LOAD = ["resistance_sampler"]
ntc_ns = cg.esphome_ns.namespace("ntc") ntc_ns = cg.esphome_ns.namespace("ntc")
NTC = ntc_ns.class_("NTC", cg.Component, sensor.Sensor) NTC = ntc_ns.class_("NTC", cg.Component, sensor.Sensor)
@ -126,7 +124,7 @@ CONFIG_SCHEMA = (
) )
.extend( .extend(
{ {
cv.Required(CONF_SENSOR): cv.use_id(resistance_sampler.ResistanceSampler), cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
cv.Required(CONF_CALIBRATION): process_calibration, cv.Required(CONF_CALIBRATION): process_calibration,
} }
) )

View File

@ -5,7 +5,7 @@ import esphome.codegen as cg
from esphome.components.http_request import CONF_HTTP_REQUEST_ID, HttpRequestComponent from esphome.components.http_request import CONF_HTTP_REQUEST_ID, HttpRequestComponent
from esphome.components.image import ( from esphome.components.image import (
CONF_INVERT_ALPHA, CONF_INVERT_ALPHA,
CONF_USE_TRANSPARENCY, CONF_TRANSPARENCY,
IMAGE_SCHEMA, IMAGE_SCHEMA,
Image_, Image_,
get_image_type_enum, get_image_type_enum,
@ -168,7 +168,7 @@ async def to_code(config):
url = config[CONF_URL] url = config[CONF_URL]
width, height = config.get(CONF_RESIZE, (0, 0)) width, height = config.get(CONF_RESIZE, (0, 0))
transparent = get_transparency_enum(config[CONF_USE_TRANSPARENCY]) transparent = get_transparency_enum(config[CONF_TRANSPARENCY])
var = cg.new_Pvariable( var = cg.new_Pvariable(
config[CONF_ID], config[CONF_ID],

View File

@ -100,7 +100,7 @@ class DownloadBuffer {
void reset() { this->unread_ = 0; } void reset() { this->unread_ = 0; }
protected: protected:
ExternalRAMAllocator<uint8_t> allocator_; RAMAllocator<uint8_t> allocator_{};
uint8_t *buffer_; uint8_t *buffer_;
size_t size_; size_t size_;
/** Total number of downloaded bytes not yet read. */ /** Total number of downloaded bytes not yet read. */

View File

@ -83,8 +83,7 @@ class OnlineImage : public PollingComponent,
protected: protected:
bool validate_url_(const std::string &url); bool validate_url_(const std::string &url);
using Allocator = ExternalRAMAllocator<uint8_t>; RAMAllocator<uint8_t> allocator_{};
Allocator allocator_{Allocator::Flags::ALLOW_FAILURE};
uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); } uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); }
int get_buffer_size_(int width, int height) const { return (this->get_bpp() * width + 7u) / 8u * height; } int get_buffer_size_(int width, int height) const { return (this->get_bpp() * width + 7u) / 8u * height; }

View File

@ -75,6 +75,8 @@ void PulseMeterSensor::loop() {
case MeterState::RUNNING: { case MeterState::RUNNING: {
uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_; uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_;
float pulse_width_us = delta_us / float(this->get_->count_); float pulse_width_us = delta_us / float(this->get_->count_);
ESP_LOGV(TAG, "New pulse, delta: %" PRIu32 " µs, count: %" PRIu32 ", width: %.5f µs", delta_us,
this->get_->count_, pulse_width_us);
this->publish_state((60.0f * 1000000.0f) / pulse_width_us); this->publish_state((60.0f * 1000000.0f) / pulse_width_us);
} break; } break;
} }

View File

@ -1,8 +1,7 @@
#pragma once #pragma once
#include "esphome/components/resistance_sampler/resistance_sampler.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
namespace esphome { namespace esphome {
namespace resistance { namespace resistance {
@ -12,7 +11,7 @@ enum ResistanceConfiguration {
DOWNSTREAM, DOWNSTREAM,
}; };
class ResistanceSensor : public Component, public sensor::Sensor, resistance_sampler::ResistanceSampler { class ResistanceSensor : public Component, public sensor::Sensor {
public: public:
void set_sensor(Sensor *sensor) { sensor_ = sensor; } void set_sensor(Sensor *sensor) { sensor_ = sensor; }
void set_configuration(ResistanceConfiguration configuration) { configuration_ = configuration; } void set_configuration(ResistanceConfiguration configuration) { configuration_ = configuration; }

View File

@ -1,6 +1,6 @@
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 sensor, resistance_sampler from esphome.components import sensor
from esphome.const import ( from esphome.const import (
CONF_REFERENCE_VOLTAGE, CONF_REFERENCE_VOLTAGE,
CONF_SENSOR, CONF_SENSOR,
@ -9,15 +9,8 @@ from esphome.const import (
ICON_FLASH, ICON_FLASH,
) )
AUTO_LOAD = ["resistance_sampler"]
resistance_ns = cg.esphome_ns.namespace("resistance") resistance_ns = cg.esphome_ns.namespace("resistance")
ResistanceSensor = resistance_ns.class_( ResistanceSensor = resistance_ns.class_("ResistanceSensor", cg.Component, sensor.Sensor)
"ResistanceSensor",
cg.Component,
sensor.Sensor,
resistance_sampler.ResistanceSampler,
)
CONF_CONFIGURATION = "configuration" CONF_CONFIGURATION = "configuration"
CONF_RESISTOR = "resistor" CONF_RESISTOR = "resistor"

View File

@ -1,6 +0,0 @@
import esphome.codegen as cg
resistance_sampler_ns = cg.esphome_ns.namespace("resistance_sampler")
ResistanceSampler = resistance_sampler_ns.class_("ResistanceSampler")
CODEOWNERS = ["@jesserockz"]

View File

@ -1,10 +0,0 @@
#pragma once
namespace esphome {
namespace resistance_sampler {
/// Abstract interface to mark components that provide resistance values.
class ResistanceSampler {};
} // namespace resistance_sampler
} // namespace esphome

View File

@ -27,6 +27,7 @@ from .gpio import rp2040_pin_to_code # noqa
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@jesserockz"] CODEOWNERS = ["@jesserockz"]
AUTO_LOAD = ["preferences"] AUTO_LOAD = ["preferences"]
IS_TARGET_PLATFORM = True
def set_core_data(config): def set_core_data(config):

View File

@ -19,6 +19,8 @@ from .boards import RTL87XX_BOARD_PINS, RTL87XX_BOARDS
CODEOWNERS = ["@kuba2k2"] CODEOWNERS = ["@kuba2k2"]
AUTO_LOAD = ["libretiny"] AUTO_LOAD = ["libretiny"]
IS_TARGET_PLATFORM = True
COMPONENT_DATA = LibreTinyComponent( COMPONENT_DATA = LibreTinyComponent(
name=COMPONENT_RTL87XX, name=COMPONENT_RTL87XX,

View File

@ -0,0 +1,25 @@
import esphome.codegen as cg
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.const import (
DEVICE_CLASS_OCCUPANCY,
CONF_HAS_TARGET,
)
from . import CONF_MR60BHA2_ID, MR60BHA2Component
DEPENDENCIES = ["seeed_mr60bha2"]
CONFIG_SCHEMA = {
cv.GenerateID(CONF_MR60BHA2_ID): cv.use_id(MR60BHA2Component),
cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema(
device_class=DEVICE_CLASS_OCCUPANCY, icon="mdi:motion-sensor"
),
}
async def to_code(config):
mr60bha2_component = await cg.get_variable(config[CONF_MR60BHA2_ID])
if has_target_config := config.get(CONF_HAS_TARGET):
sens = await binary_sensor.new_binary_sensor(has_target_config)
cg.add(mr60bha2_component.set_has_target_binary_sensor(sens))

View File

@ -1,6 +1,7 @@
#include "seeed_mr60bha2.h" #include "seeed_mr60bha2.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes>
#include <utility> #include <utility>
namespace esphome { namespace esphome {
@ -12,10 +13,14 @@ static const char *const TAG = "seeed_mr60bha2";
// items in an easy-to-read format, including the configuration key-value pairs. // items in an easy-to-read format, including the configuration key-value pairs.
void MR60BHA2Component::dump_config() { void MR60BHA2Component::dump_config() {
ESP_LOGCONFIG(TAG, "MR60BHA2:"); ESP_LOGCONFIG(TAG, "MR60BHA2:");
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "People Exist Binary Sensor", this->has_target_binary_sensor_);
#endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
LOG_SENSOR(" ", "Breath Rate Sensor", this->breath_rate_sensor_); LOG_SENSOR(" ", "Breath Rate Sensor", this->breath_rate_sensor_);
LOG_SENSOR(" ", "Heart Rate Sensor", this->heart_rate_sensor_); LOG_SENSOR(" ", "Heart Rate Sensor", this->heart_rate_sensor_);
LOG_SENSOR(" ", "Distance Sensor", this->distance_sensor_); LOG_SENSOR(" ", "Distance Sensor", this->distance_sensor_);
LOG_SENSOR(" ", "Target Number Sensor", this->num_targets_sensor_);
#endif #endif
} }
@ -94,7 +99,8 @@ bool MR60BHA2Component::validate_message_() {
uint16_t frame_type = encode_uint16(data[5], data[6]); uint16_t frame_type = encode_uint16(data[5], data[6]);
if (frame_type != BREATH_RATE_TYPE_BUFFER && frame_type != HEART_RATE_TYPE_BUFFER && if (frame_type != BREATH_RATE_TYPE_BUFFER && frame_type != HEART_RATE_TYPE_BUFFER &&
frame_type != DISTANCE_TYPE_BUFFER) { frame_type != DISTANCE_TYPE_BUFFER && frame_type != PEOPLE_EXIST_TYPE_BUFFER &&
frame_type != PRINT_CLOUD_BUFFER) {
return false; return false;
} }
@ -144,6 +150,18 @@ void MR60BHA2Component::process_frame_(uint16_t frame_id, uint16_t frame_type, c
} }
} }
break; break;
case PEOPLE_EXIST_TYPE_BUFFER:
if (this->has_target_binary_sensor_ != nullptr && length >= 2) {
uint16_t has_target_int = encode_uint16(data[1], data[0]);
this->has_target_binary_sensor_->publish_state(has_target_int);
if (has_target_int == 0) {
this->breath_rate_sensor_->publish_state(0.0);
this->heart_rate_sensor_->publish_state(0.0);
this->distance_sensor_->publish_state(0.0);
this->num_targets_sensor_->publish_state(0);
}
}
break;
case HEART_RATE_TYPE_BUFFER: case HEART_RATE_TYPE_BUFFER:
if (this->heart_rate_sensor_ != nullptr && length >= 4) { if (this->heart_rate_sensor_ != nullptr && length >= 4) {
uint32_t current_heart_rate_int = encode_uint32(data[3], data[2], data[1], data[0]); uint32_t current_heart_rate_int = encode_uint32(data[3], data[2], data[1], data[0]);
@ -155,7 +173,7 @@ void MR60BHA2Component::process_frame_(uint16_t frame_id, uint16_t frame_type, c
} }
break; break;
case DISTANCE_TYPE_BUFFER: case DISTANCE_TYPE_BUFFER:
if (!data[0]) { if (data[0] != 0) {
if (this->distance_sensor_ != nullptr && length >= 8) { if (this->distance_sensor_ != nullptr && length >= 8) {
uint32_t current_distance_int = encode_uint32(data[7], data[6], data[5], data[4]); uint32_t current_distance_int = encode_uint32(data[7], data[6], data[5], data[4]);
float distance_float; float distance_float;
@ -164,6 +182,12 @@ void MR60BHA2Component::process_frame_(uint16_t frame_id, uint16_t frame_type, c
} }
} }
break; break;
case PRINT_CLOUD_BUFFER:
if (this->num_targets_sensor_ != nullptr && length >= 4) {
uint32_t current_num_targets_int = encode_uint32(data[3], data[2], data[1], data[0]);
this->num_targets_sensor_->publish_state(current_num_targets_int);
}
break;
default: default:
break; break;
} }

View File

@ -1,6 +1,9 @@
#pragma once #pragma once
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#endif #endif
@ -12,37 +15,23 @@
namespace esphome { namespace esphome {
namespace seeed_mr60bha2 { namespace seeed_mr60bha2 {
static const uint8_t DATA_BUF_MAX_SIZE = 12;
static const uint8_t FRAME_BUF_MAX_SIZE = 21;
static const uint8_t LEN_TO_HEAD_CKSUM = 8;
static const uint8_t LEN_TO_DATA_FRAME = 9;
static const uint8_t FRAME_HEADER_BUFFER = 0x01; static const uint8_t FRAME_HEADER_BUFFER = 0x01;
static const uint16_t BREATH_RATE_TYPE_BUFFER = 0x0A14; static const uint16_t BREATH_RATE_TYPE_BUFFER = 0x0A14;
static const uint16_t PEOPLE_EXIST_TYPE_BUFFER = 0x0F09;
static const uint16_t HEART_RATE_TYPE_BUFFER = 0x0A15; static const uint16_t HEART_RATE_TYPE_BUFFER = 0x0A15;
static const uint16_t DISTANCE_TYPE_BUFFER = 0x0A16; static const uint16_t DISTANCE_TYPE_BUFFER = 0x0A16;
static const uint16_t PRINT_CLOUD_BUFFER = 0x0A04;
enum FrameLocation {
LOCATE_FRAME_HEADER,
LOCATE_ID_FRAME1,
LOCATE_ID_FRAME2,
LOCATE_LENGTH_FRAME_H,
LOCATE_LENGTH_FRAME_L,
LOCATE_TYPE_FRAME1,
LOCATE_TYPE_FRAME2,
LOCATE_HEAD_CKSUM_FRAME, // Header checksum: [from the first byte to the previous byte of the HEAD_CKSUM bit]
LOCATE_DATA_FRAME,
LOCATE_DATA_CKSUM_FRAME, // Data checksum: [from the first to the previous byte of the DATA_CKSUM bit]
LOCATE_PROCESS_FRAME,
};
class MR60BHA2Component : public Component, class MR60BHA2Component : public Component,
public uart::UARTDevice { // The class name must be the name defined by text_sensor.py public uart::UARTDevice { // The class name must be the name defined by text_sensor.py
#ifdef USE_BINARY_SENSOR
SUB_BINARY_SENSOR(has_target);
#endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
SUB_SENSOR(breath_rate); SUB_SENSOR(breath_rate);
SUB_SENSOR(heart_rate); SUB_SENSOR(heart_rate);
SUB_SENSOR(distance); SUB_SENSOR(distance);
SUB_SENSOR(num_targets);
#endif #endif
public: public:

View File

@ -7,6 +7,7 @@ from esphome.const import (
ICON_HEART_PULSE, ICON_HEART_PULSE,
ICON_PULSE, ICON_PULSE,
ICON_SIGNAL, ICON_SIGNAL,
ICON_COUNTER,
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_BEATS_PER_MINUTE, UNIT_BEATS_PER_MINUTE,
UNIT_CENTIMETER, UNIT_CENTIMETER,
@ -18,12 +19,13 @@ DEPENDENCIES = ["seeed_mr60bha2"]
CONF_BREATH_RATE = "breath_rate" CONF_BREATH_RATE = "breath_rate"
CONF_HEART_RATE = "heart_rate" CONF_HEART_RATE = "heart_rate"
CONF_NUM_TARGETS = "num_targets"
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(CONF_MR60BHA2_ID): cv.use_id(MR60BHA2Component), cv.GenerateID(CONF_MR60BHA2_ID): cv.use_id(MR60BHA2Component),
cv.Optional(CONF_BREATH_RATE): sensor.sensor_schema( cv.Optional(CONF_BREATH_RATE): sensor.sensor_schema(
accuracy_decimals=2, accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
icon=ICON_PULSE, icon=ICON_PULSE,
), ),
@ -40,6 +42,9 @@ CONFIG_SCHEMA = cv.Schema(
accuracy_decimals=2, accuracy_decimals=2,
icon=ICON_SIGNAL, icon=ICON_SIGNAL,
), ),
cv.Optional(CONF_NUM_TARGETS): sensor.sensor_schema(
icon=ICON_COUNTER,
),
} }
) )
@ -55,3 +60,6 @@ async def to_code(config):
if distance_config := config.get(CONF_DISTANCE): if distance_config := config.get(CONF_DISTANCE):
sens = await sensor.new_sensor(distance_config) sens = await sensor.new_sensor(distance_config)
cg.add(mr60bha2_component.set_distance_sensor(sens)) cg.add(mr60bha2_component.set_distance_sensor(sens))
if num_targets_config := config.get(CONF_NUM_TARGETS):
sens = await sensor.new_sensor(num_targets_config)
cg.add(mr60bha2_component.set_num_targets_sensor(sens))

View File

@ -88,7 +88,7 @@ void SPIDelegateBitBash::write(uint16_t data, size_t num_bits) { this->transfer_
uint16_t SPIDelegateBitBash::transfer_(uint16_t data, size_t num_bits) { uint16_t SPIDelegateBitBash::transfer_(uint16_t data, size_t num_bits) {
// Clock starts out at idle level // Clock starts out at idle level
this->clk_pin_->digital_write(clock_polarity_); this->clk_pin_->digital_write(clock_polarity_);
uint8_t out_data = 0; uint16_t out_data = 0;
for (uint8_t i = 0; i != num_bits; i++) { for (uint8_t i = 0; i != num_bits; i++) {
uint8_t shift; uint8_t shift;

View File

@ -11,7 +11,7 @@ CONFIG_SCHEMA = text_sensor.text_sensor_schema(
UptimeTextSensor, UptimeTextSensor,
icon=ICON_TIMER, icon=ICON_TIMER,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC, entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
).extend(cv.polling_component_schema("60s")) ).extend(cv.polling_component_schema("30s"))
async def to_code(config): async def to_code(config):

View File

@ -9,34 +9,51 @@ namespace uptime {
static const char *const TAG = "uptime.sensor"; static const char *const TAG = "uptime.sensor";
void UptimeTextSensor::setup() { this->last_ms_ = millis(); } void UptimeTextSensor::setup() {
this->last_ms_ = millis();
if (this->last_ms_ < 60 * 1000)
this->last_ms_ = 0;
this->update();
}
void UptimeTextSensor::update() { void UptimeTextSensor::update() {
const auto now = millis(); auto now = millis();
// get whole seconds since last update. Note that even if the millis count has overflowed between updates, // get whole seconds since last update. Note that even if the millis count has overflowed between updates,
// the difference will still be correct due to the way twos-complement arithmetic works. // the difference will still be correct due to the way twos-complement arithmetic works.
const uint32_t delta = (now - this->last_ms_) / 1000; uint32_t delta = now - this->last_ms_;
if (delta == 0) this->last_ms_ = now - delta % 1000; // save remainder for next update
return; delta /= 1000;
// set last_ms_ to the last second boundary
this->last_ms_ = now - (now % 1000);
this->uptime_ += delta; this->uptime_ += delta;
auto uptime = this->uptime_; auto uptime = this->uptime_;
unsigned days = uptime / (24 * 3600); unsigned interval = this->get_update_interval() / 1000;
unsigned seconds = uptime % (24 * 3600); std::string buffer{};
unsigned hours = seconds / 3600; // display from the largest unit that corresponds to the update interval, drop larger units that are zero.
seconds %= 3600; while (true) { // enable use of break for early exit
unsigned minutes = seconds / 60; unsigned remainder = uptime % 60;
seconds %= 60; uptime /= 60;
if (days != 0) { if (interval < 30) {
this->publish_state(str_sprintf("%dd%dh%dm%ds", days, hours, minutes, seconds)); buffer.insert(0, str_sprintf("%us", remainder));
} else if (hours != 0) { if (uptime == 0)
this->publish_state(str_sprintf("%dh%dm%ds", hours, minutes, seconds)); break;
} else if (minutes != 0) {
this->publish_state(str_sprintf("%dm%ds", minutes, seconds));
} else {
this->publish_state(str_sprintf("%ds", seconds));
} }
remainder = uptime % 60;
uptime /= 60;
if (interval < 1800) {
buffer.insert(0, str_sprintf("%um", remainder));
if (uptime == 0)
break;
}
remainder = uptime % 24;
uptime /= 24;
if (interval < 12 * 3600) {
buffer.insert(0, str_sprintf("%uh", remainder));
if (uptime == 0)
break;
}
buffer.insert(0, str_sprintf("%ud", (unsigned) uptime));
break;
}
this->publish_state(buffer);
} }
float UptimeTextSensor::get_setup_priority() const { return setup_priority::HARDWARE; } float UptimeTextSensor::get_setup_priority() const { return setup_priority::HARDWARE; }

View File

@ -17,8 +17,8 @@ class UptimeTextSensor : public text_sensor::TextSensor, public PollingComponent
float get_setup_priority() const override; float get_setup_priority() const override;
protected: protected:
uint64_t uptime_{0}; uint32_t uptime_{0}; // uptime in seconds, will overflow after 136 years
uint64_t last_ms_{0}; uint32_t last_ms_{0};
}; };
} // namespace uptime } // namespace uptime

View File

@ -72,7 +72,8 @@ void WaveshareEPaper2P13InV3::write_buffer_(uint8_t cmd, int top, int bottom) {
this->set_window_(top, bottom); this->set_window_(top, bottom);
this->command(cmd); this->command(cmd);
this->start_data_(); this->start_data_();
auto width_bytes = this->get_width_internal() / 8;
auto width_bytes = this->get_width_controller() / 8;
this->write_array(this->buffer_ + top * width_bytes, (bottom - top) * width_bytes); this->write_array(this->buffer_ + top * width_bytes, (bottom - top) * width_bytes);
this->end_data_(); this->end_data_();
} }
@ -162,7 +163,8 @@ void WaveshareEPaper2P13InV3::display() {
} }
} }
int WaveshareEPaper2P13InV3::get_width_internal() { return 128; } int WaveshareEPaper2P13InV3::get_width_controller() { return 128; }
int WaveshareEPaper2P13InV3::get_width_internal() { return 122; }
int WaveshareEPaper2P13InV3::get_height_internal() { return 250; } int WaveshareEPaper2P13InV3::get_height_internal() { return 250; }

View File

@ -811,6 +811,7 @@ class WaveshareEPaper2P13InV3 : public WaveshareEPaper {
void initialize() override; void initialize() override;
protected: protected:
int get_width_controller() override;
int get_width_internal() override; int get_width_internal() override;
int get_height_internal() override; int get_height_internal() override;
uint32_t idle_timeout_() override; uint32_t idle_timeout_() override;

View File

@ -22,7 +22,6 @@ from esphome.const import (
CONF_PACKAGES, CONF_PACKAGES,
CONF_PLATFORM, CONF_PLATFORM,
CONF_SUBSTITUTIONS, CONF_SUBSTITUTIONS,
TARGET_PLATFORMS,
) )
from esphome.core import CORE, DocumentRange, EsphomeError from esphome.core import CORE, DocumentRange, EsphomeError
import esphome.core.config as core_config import esphome.core.config as core_config
@ -833,7 +832,7 @@ def validate_config(
result[CONF_ESPHOME] = config[CONF_ESPHOME] result[CONF_ESPHOME] = config[CONF_ESPHOME]
result.add_output_path([CONF_ESPHOME], CONF_ESPHOME) result.add_output_path([CONF_ESPHOME], CONF_ESPHOME)
try: try:
core_config.preload_core_config(config, result) target_platform = core_config.preload_core_config(config, result)
except vol.Invalid as err: except vol.Invalid as err:
result.add_error(err) result.add_error(err)
return result return result
@ -845,9 +844,9 @@ def validate_config(
cv.All(cv.version_number, cv.validate_esphome_version)(min_version) cv.All(cv.version_number, cv.validate_esphome_version)(min_version)
# First run platform validation steps # First run platform validation steps
for key in TARGET_PLATFORMS: result.add_validation_step(
if key in config: LoadValidationStep(target_platform, config[target_platform])
result.add_validation_step(LoadValidationStep(key, config[key])) )
result.run_validation_steps() result.run_validation_steps()
if result.errors: if result.errors:

View File

@ -15,15 +15,6 @@ PLATFORM_LIBRETINY_OLDSTYLE = "libretiny"
PLATFORM_RP2040 = "rp2040" PLATFORM_RP2040 = "rp2040"
PLATFORM_RTL87XX = "rtl87xx" PLATFORM_RTL87XX = "rtl87xx"
TARGET_PLATFORMS = [
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_HOST,
PLATFORM_LIBRETINY_OLDSTYLE,
PLATFORM_RP2040,
PLATFORM_RTL87XX,
]
SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"} SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"}
HEADER_FILE_EXTENSIONS = {".h", ".hpp", ".tcc"} HEADER_FILE_EXTENSIONS = {".h", ".hpp", ".tcc"}

View File

@ -1,21 +1,17 @@
import logging import logging
import multiprocessing import multiprocessing
import os import os
import re from pathlib import Path
from esphome import automation from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ARDUINO_VERSION,
CONF_AREA, CONF_AREA,
CONF_BOARD,
CONF_BOARD_FLASH_MODE,
CONF_BUILD_PATH, CONF_BUILD_PATH,
CONF_COMMENT, CONF_COMMENT,
CONF_COMPILE_PROCESS_LIMIT, CONF_COMPILE_PROCESS_LIMIT,
CONF_ESPHOME, CONF_ESPHOME,
CONF_FRAMEWORK,
CONF_FRIENDLY_NAME, CONF_FRIENDLY_NAME,
CONF_INCLUDES, CONF_INCLUDES,
CONF_LIBRARIES, CONF_LIBRARIES,
@ -30,13 +26,9 @@ from esphome.const import (
CONF_PLATFORMIO_OPTIONS, CONF_PLATFORMIO_OPTIONS,
CONF_PRIORITY, CONF_PRIORITY,
CONF_PROJECT, CONF_PROJECT,
CONF_SOURCE,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_TYPE,
CONF_VERSION, CONF_VERSION,
KEY_CORE, KEY_CORE,
PLATFORM_ESP8266,
TARGET_PLATFORMS,
__version__ as ESPHOME_VERSION, __version__ as ESPHOME_VERSION,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
@ -44,7 +36,6 @@ from esphome.helpers import copy_file_if_changed, get_str_env, walk_files
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
BUILD_FLASH_MODES = ["qio", "qout", "dio", "dout"]
StartupTrigger = cg.esphome_ns.class_( StartupTrigger = cg.esphome_ns.class_(
"StartupTrigger", cg.Component, automation.Trigger.template() "StartupTrigger", cg.Component, automation.Trigger.template()
) )
@ -58,8 +49,6 @@ ProjectUpdateTrigger = cg.esphome_ns.class_(
"ProjectUpdateTrigger", cg.Component, automation.Trigger.template(cg.std_string) "ProjectUpdateTrigger", cg.Component, automation.Trigger.template(cg.std_string)
) )
VERSION_REGEX = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(?:[ab]\d+)?$")
VALID_INCLUDE_EXTS = {".h", ".hpp", ".tcc", ".ino", ".cpp", ".c"} VALID_INCLUDE_EXTS = {".h", ".hpp", ".tcc", ".ino", ".cpp", ".c"}
@ -111,7 +100,6 @@ else:
_compile_process_limit_default = cv.UNDEFINED _compile_process_limit_default = cv.UNDEFINED
CONF_ESP8266_RESTORE_FROM_FLASH = "esp8266_restore_from_flash"
CONFIG_SCHEMA = cv.All( CONFIG_SCHEMA = cv.All(
cv.Schema( cv.Schema(
{ {
@ -175,14 +163,9 @@ PRELOAD_CONFIG_SCHEMA = cv.Schema(
{ {
cv.Required(CONF_NAME): cv.valid_name, cv.Required(CONF_NAME): cv.valid_name,
cv.Optional(CONF_BUILD_PATH): cv.string, cv.Optional(CONF_BUILD_PATH): cv.string,
# Compat options, these were moved to target-platform specific sections cv.Optional(CONF_PLATFORM): cv.invalid(
# but we'll keep these around for a long time because every config would "Please remove the `platform` key from the [esphome] block and use the correct platform component. This style of configuration has now been removed."
# be impacted ),
cv.Optional(CONF_PLATFORM): cv.one_of(*TARGET_PLATFORMS, lower=True),
cv.Optional(CONF_BOARD): cv.string_strict,
cv.Optional(CONF_ESP8266_RESTORE_FROM_FLASH): cv.valid,
cv.Optional(CONF_BOARD_FLASH_MODE): cv.valid,
cv.Optional(CONF_ARDUINO_VERSION): cv.valid,
cv.Optional(CONF_MIN_VERSION, default=ESPHOME_VERSION): cv.All( cv.Optional(CONF_MIN_VERSION, default=ESPHOME_VERSION): cv.All(
cv.version_number, cv.validate_esphome_version cv.version_number, cv.validate_esphome_version
), ),
@ -191,7 +174,31 @@ PRELOAD_CONFIG_SCHEMA = cv.Schema(
) )
def preload_core_config(config, result): def _is_target_platform(name):
from esphome.loader import get_component
try:
if get_component(name, True).is_target_platform:
return True
except KeyError:
pass
return False
def _list_target_platforms():
target_platforms = []
root = Path(__file__).parents[1]
for path in (root / "components").iterdir():
if not path.is_dir():
continue
if not (path / "__init__.py").is_file():
continue
if _is_target_platform(path.name):
target_platforms += [path.name]
return target_platforms
def preload_core_config(config, result) -> str:
with cv.prepend_path(CONF_ESPHOME): with cv.prepend_path(CONF_ESPHOME):
conf = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME]) conf = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME])
@ -204,63 +211,26 @@ def preload_core_config(config, result):
conf[CONF_BUILD_PATH] = os.path.join(build_path, CORE.name) conf[CONF_BUILD_PATH] = os.path.join(build_path, CORE.name)
CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH]) CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH])
has_oldstyle = CONF_PLATFORM in conf target_platforms = []
newstyle_found = [key for key in TARGET_PLATFORMS if key in config]
oldstyle_opts = [
CONF_ESP8266_RESTORE_FROM_FLASH,
CONF_BOARD_FLASH_MODE,
CONF_ARDUINO_VERSION,
CONF_BOARD,
]
if not has_oldstyle and not newstyle_found: for domain, _ in config.items():
if _is_target_platform(domain):
target_platforms += [domain]
if not target_platforms:
raise cv.Invalid( raise cv.Invalid(
"Platform missing. You must include one of the available platform keys: " "Platform missing. You must include one of the available platform keys: "
+ ", ".join(TARGET_PLATFORMS), + ", ".join(_list_target_platforms()),
[CONF_ESPHOME], [CONF_ESPHOME],
) )
if has_oldstyle and newstyle_found: if len(target_platforms) > 1:
raise cv.Invalid( raise cv.Invalid(
f"Please remove the `platform` key from the [esphome] block. You're already using the new style with the [{conf[CONF_PLATFORM]}] block", f"Found multiple target platform blocks: {', '.join(target_platforms)}. Only one is allowed.",
[CONF_ESPHOME, CONF_PLATFORM], [target_platforms[0]],
)
if len(newstyle_found) > 1:
raise cv.Invalid(
f"Found multiple target platform blocks: {', '.join(newstyle_found)}. Only one is allowed.",
[newstyle_found[0]],
)
if newstyle_found:
# Convert to newstyle
for key in oldstyle_opts:
if key in conf:
raise cv.Invalid(
f"Please move {key} to the [{newstyle_found[0]}] block.",
[CONF_ESPHOME, key],
) )
if has_oldstyle:
plat = conf.pop(CONF_PLATFORM)
plat_conf = {}
if CONF_ESP8266_RESTORE_FROM_FLASH in conf:
plat_conf["restore_from_flash"] = conf.pop(CONF_ESP8266_RESTORE_FROM_FLASH)
if CONF_BOARD_FLASH_MODE in conf:
plat_conf[CONF_BOARD_FLASH_MODE] = conf.pop(CONF_BOARD_FLASH_MODE)
if CONF_ARDUINO_VERSION in conf:
plat_conf[CONF_FRAMEWORK] = {}
if plat != PLATFORM_ESP8266:
plat_conf[CONF_FRAMEWORK][CONF_TYPE] = "arduino"
try:
if conf[CONF_ARDUINO_VERSION] not in ("recommended", "latest", "dev"):
cv.Version.parse(conf[CONF_ARDUINO_VERSION])
plat_conf[CONF_FRAMEWORK][CONF_VERSION] = conf.pop(CONF_ARDUINO_VERSION)
except ValueError:
plat_conf[CONF_FRAMEWORK][CONF_SOURCE] = conf.pop(CONF_ARDUINO_VERSION)
if CONF_BOARD in conf:
plat_conf[CONF_BOARD] = conf.pop(CONF_BOARD)
# Insert generated target platform config to main config
config[plat] = plat_conf
config[CONF_ESPHOME] = conf config[CONF_ESPHOME] = conf
return target_platforms[0]
def include_file(path, basename): def include_file(path, basename):

View File

@ -120,7 +120,7 @@
#endif #endif
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
#define USE_ESP_IDF_VERSION_CODE VERSION_CODE(4, 4, 2) #define USE_ESP_IDF_VERSION_CODE VERSION_CODE(5, 1, 5)
#endif #endif
#if defined(USE_ESP32_VARIANT_ESP32S2) #if defined(USE_ESP32_VARIANT_ESP32S2)

View File

@ -52,6 +52,10 @@ class ComponentManifest:
def is_platform_component(self) -> bool: def is_platform_component(self) -> bool:
return getattr(self.module, "IS_PLATFORM_COMPONENT", False) return getattr(self.module, "IS_PLATFORM_COMPONENT", False)
@property
def is_target_platform(self) -> bool:
return getattr(self.module, "IS_TARGET_PLATFORM", False)
@property @property
def config_schema(self) -> Optional[Any]: def config_schema(self) -> Optional[Any]:
return getattr(self.module, "CONFIG_SCHEMA", None) return getattr(self.module, "CONFIG_SCHEMA", None)
@ -169,13 +173,15 @@ def install_custom_components_meta_finder():
install_meta_finder(custom_components_dir) install_meta_finder(custom_components_dir)
def _lookup_module(domain): def _lookup_module(domain, exception):
if domain in _COMPONENT_CACHE: if domain in _COMPONENT_CACHE:
return _COMPONENT_CACHE[domain] return _COMPONENT_CACHE[domain]
try: try:
module = importlib.import_module(f"esphome.components.{domain}") module = importlib.import_module(f"esphome.components.{domain}")
except ImportError as e: except ImportError as e:
if exception:
raise
if "No module named" in str(e): if "No module named" in str(e):
_LOGGER.info( _LOGGER.info(
"Unable to import component %s: %s", domain, str(e), exc_info=False "Unable to import component %s: %s", domain, str(e), exc_info=False
@ -184,6 +190,8 @@ def _lookup_module(domain):
_LOGGER.error("Unable to import component %s:", domain, exc_info=True) _LOGGER.error("Unable to import component %s:", domain, exc_info=True)
return None return None
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
if exception:
raise
_LOGGER.error("Unable to load component %s:", domain, exc_info=True) _LOGGER.error("Unable to load component %s:", domain, exc_info=True)
return None return None
@ -192,14 +200,14 @@ def _lookup_module(domain):
return manif return manif
def get_component(domain): def get_component(domain, exception=False):
assert "." not in domain assert "." not in domain
return _lookup_module(domain) return _lookup_module(domain, exception)
def get_platform(domain, platform): def get_platform(domain, platform):
full = f"{platform}.{domain}" full = f"{platform}.{domain}"
return _lookup_module(full) return _lookup_module(full, False)
_COMPONENT_CACHE = {} _COMPONENT_CACHE = {}

53
script/run-in-env Normal file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
import os
from pathlib import Path
import subprocess
import sys
def find_and_activate_virtualenv():
try:
# Get the top-level directory of the git repository
my_path = subprocess.check_output(
["git", "rev-parse", "--show-toplevel"], text=True
).strip()
except subprocess.CalledProcessError:
print(
"Error: Not a git repository or unable to determine the top-level directory.",
file=sys.stderr,
)
sys.exit(1)
# Check for virtual environments
for venv in ["venv", ".venv", "."]:
activate_path = (
Path(my_path)
/ venv
/ ("Scripts" if os.name == "nt" else "bin")
/ "activate"
)
if activate_path.exists():
# Activate the virtual environment by updating PATH
env = os.environ.copy()
venv_bin_dir = activate_path.parent
env["PATH"] = f"{venv_bin_dir}{os.pathsep}{env['PATH']}"
env["VIRTUAL_ENV"] = str(venv_bin_dir.parent)
print(f"Activated virtual environment: {venv_bin_dir.parent}")
# Execute the remaining arguments in the new environment
if len(sys.argv) > 1:
subprocess.run(sys.argv[1:], env=env, check=False)
else:
print(
"No command provided to run in the virtual environment.",
file=sys.stderr,
)
return
print("No virtual environment found.", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
find_and_activate_virtualenv()

View File

@ -1,13 +0,0 @@
#!/usr/bin/env sh
set -eu
my_path=$(git rev-parse --show-toplevel)
for venv in venv .venv .; do
if [ -f "${my_path}/${venv}/bin/activate" ]; then
. "${my_path}/${venv}/bin/activate"
break
fi
done
exec "$@"

View File

@ -1,7 +1,8 @@
--- ---
esphome: esphome:
name: test name: test
platform: ESP8266
esp8266:
board: d1_mini_lite board: d1_mini_lite
binary_sensor: binary_sensor:

View File

@ -1,7 +1,8 @@
--- ---
esphome: esphome:
name: test name: test
platform: ESP8266
esp8266:
board: d1_mini_lite board: d1_mini_lite
wifi: wifi:

View File

@ -1,7 +1,8 @@
--- ---
esphome: esphome:
name: test name: test
platform: ESP32
esp32:
board: nodemcu-32s board: nodemcu-32s
deep_sleep: deep_sleep:

View File

@ -1,7 +1,8 @@
--- ---
esphome: esphome:
name: test name: test
platform: ESP32
esp32:
board: nodemcu-32s board: nodemcu-32s
deep_sleep: deep_sleep:

View File

@ -1,7 +1,8 @@
--- ---
esphome: esphome:
name: test name: test
platform: ESP8266
esp8266:
board: d1_mini_lite board: d1_mini_lite
sensor: sensor:

Some files were not shown because too many files have changed in this diff Show More