1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-14 06:38:17 +00:00

Merge branch 'dev' into defaults2

This commit is contained in:
tomaszduda23 2025-01-25 14:08:38 +01:00 committed by GitHub
commit adb3c8bb86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
78 changed files with 735 additions and 645 deletions

View File

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

View File

@ -133,6 +133,7 @@ esphome/components/ens160_i2c/* @latonita
esphome/components/ens160_spi/* @latonita
esphome/components/ens210/* @itn3rd77
esphome/components/es7210/* @kahrendt
esphome/components/es7243e/* @kbx81
esphome/components/es8156/* @kbx81
esphome/components/es8311/* @kahrendt @kroimon
esphome/components/esp32/* @esphome/core

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_CONFIG = 0x01;
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111; // 3300_SPS for ADS1015
void ADS1115Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
uint16_t value;
@ -43,9 +41,9 @@ void ADS1115Component::setup() {
config |= 0b0000000100000000;
}
// Set data rate - 860 samples per second (we're in singleshot mode)
// Set data rate - 860 samples per second
// 0bxxxxxxxx100xxxxx
config |= ADS1115_DATA_RATE_860_SPS << 5;
config |= ADS1115_860SPS << 5;
// Set comparator mode - hysteresis
// 0bxxxxxxxxxxx0xxxx
@ -77,7 +75,7 @@ void ADS1115Component::dump_config() {
}
}
float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain,
ADS1115Resolution resolution) {
ADS1115Resolution resolution, ADS1115Samplerate samplerate) {
uint16_t config = this->prev_config_;
// Multiplexer
// 0bxBBBxxxxxxxxxxxx
@ -89,6 +87,11 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
config &= 0b1111000111111111;
config |= (gain & 0b111) << 9;
// Sample rate
// 0bxxxxxxxxBBBxxxxx
config &= 0b1111111100011111;
config |= (samplerate & 0b111) << 5;
if (!this->continuous_mode_) {
// Start conversion
config |= 0b1000000000000000;
@ -101,8 +104,54 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
}
this->prev_config_ = config;
// about 1.2 ms with 860 samples per second
delay(2);
// 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);
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
// to ensure conversion is taking place with the correct settings

View File

@ -33,6 +33,17 @@ enum ADS1115Resolution {
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 {
public:
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; }
/// 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:
uint16_t prev_config_{0};

View File

@ -5,6 +5,7 @@ from esphome.const import (
CONF_GAIN,
CONF_MULTIPLEXER,
CONF_RESOLUTION,
CONF_SAMPLE_RATE,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
UNIT_VOLT,
@ -43,6 +44,17 @@ RESOLUTION = {
"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", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
@ -64,6 +76,9 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
RESOLUTION, upper=True, space="_"
),
cv.Optional(CONF_SAMPLE_RATE, default="860"): cv.enum(
SAMPLERATE, string=True
),
}
)
.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_gain(config[CONF_GAIN]))
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";
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() {
@ -24,6 +24,7 @@ void ADS1115Sensor::dump_config() {
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_);
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_);
ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_);
ESP_LOGCONFIG(TAG, " Sample rate: %u", this->samplerate_);
}
} // namespace ads1115

View File

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

View File

@ -19,6 +19,7 @@ from .boards import BK72XX_BOARD_PINS, BK72XX_BOARDS
CODEOWNERS = ["@kuba2k2"]
AUTO_LOAD = ["libretiny"]
IS_TARGET_PLATFORM = True
COMPONENT_DATA = LibreTinyComponent(
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
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.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()
),
}
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'
)
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
from esphome.components import climate
from esphome.const import CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomClimateConstructor = custom_ns.class_("CustomClimateConstructor")
CONF_CLIMATES = "climates"
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),
}
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'
)
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
from esphome.components import cover
from esphome.const import CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomCoverConstructor = custom_ns.class_("CustomCoverConstructor")
CONF_COVERS = "covers"
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),
}
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'
)
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
from esphome.components import light
from esphome.const import CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomLightOutputConstructor = custom_ns.class_("CustomLightOutputConstructor")
CONF_LIGHTS = "lights"
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),
}
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'
)
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
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")
CustomFloatOutputConstructor = custom_ns.class_("CustomFloatOutputConstructor")
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,
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'
)
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
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.Schema(
{
cv.GenerateID(): cv.declare_id(CustomSensorConstructor),
cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_SENSORS): cv.ensure_list(sensor.sensor_schema()),
}
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'
)
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
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.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)),
}
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'
)
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
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.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()
),
}
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'
)
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
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
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(
'The "custom" component has been removed. Consider conversion to an external component.\nhttps://esphome.io/guides/contributing#a-note-about-custom-components'
)
async def to_code(config):
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

@ -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);
while (it != NULL) {
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,
partition->address, partition->size);
ESP_LOGCONFIG(TAG, " %-12s %-4d %-8d 0x%08" PRIX32 " 0x%08" PRIX32, partition->label, partition->type,
partition->subtype, partition->address, partition->size);
it = esp_partition_next(it);
}
esp_partition_iterator_release(it);

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -72,9 +72,9 @@ void MQTTClimateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCo
// max_temp
root[MQTT_MAX_TEMP] = traits.get_visual_max_temperature();
// 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
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
root[MQTT_TEMPERATURE_UNIT] = "C";

View File

@ -52,6 +52,14 @@ class Format:
pass
class BMPFormat(Format):
def __init__(self):
super().__init__("BMP")
def actions(self):
cg.add_define("USE_ONLINE_IMAGE_BMP_SUPPORT")
class PNGFormat(Format):
def __init__(self):
super().__init__("PNG")
@ -62,7 +70,13 @@ class PNGFormat(Format):
# New formats can be added here.
IMAGE_FORMATS = {x.image_type: x for x in (PNGFormat(),)}
IMAGE_FORMATS = {
x.image_type: x
for x in (
BMPFormat(),
PNGFormat(),
)
}
OnlineImage = online_image_ns.class_("OnlineImage", cg.PollingComponent, Image_)

View File

@ -0,0 +1,101 @@
#include "bmp_image.h"
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
#include "esphome/components/display/display.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace online_image {
static const char *const TAG = "online_image.bmp";
int HOT BmpDecoder::decode(uint8_t *buffer, size_t size) {
size_t index = 0;
if (this->current_index_ == 0 && index == 0 && size > 14) {
/**
* BMP file format:
* 0-1: Signature (BM)
* 2-5: File size
* 6-9: Reserved
* 10-13: Pixel data offset
*
* Integer values are stored in little-endian format.
*/
// Check if the file is a BMP image
if (buffer[0] != 'B' || buffer[1] != 'M') {
ESP_LOGE(TAG, "Not a BMP file");
return DECODE_ERROR_INVALID_TYPE;
}
this->download_size_ = encode_uint32(buffer[5], buffer[4], buffer[3], buffer[2]);
this->data_offset_ = encode_uint32(buffer[13], buffer[12], buffer[11], buffer[10]);
this->current_index_ = 14;
index = 14;
}
if (this->current_index_ == 14 && index == 14 && size > this->data_offset_) {
/**
* BMP DIB header:
* 14-17: DIB header size
* 18-21: Image width
* 22-25: Image height
* 26-27: Number of color planes
* 28-29: Bits per pixel
* 30-33: Compression method
* 34-37: Image data size
* 38-41: Horizontal resolution
* 42-45: Vertical resolution
* 46-49: Number of colors in the color table
*/
this->width_ = encode_uint32(buffer[21], buffer[20], buffer[19], buffer[18]);
this->height_ = encode_uint32(buffer[25], buffer[24], buffer[23], buffer[22]);
this->bits_per_pixel_ = encode_uint16(buffer[29], buffer[28]);
this->compression_method_ = encode_uint32(buffer[33], buffer[32], buffer[31], buffer[30]);
this->image_data_size_ = encode_uint32(buffer[37], buffer[36], buffer[35], buffer[34]);
this->color_table_entries_ = encode_uint32(buffer[49], buffer[48], buffer[47], buffer[46]);
switch (this->bits_per_pixel_) {
case 1:
this->width_bytes_ = (this->width_ % 8 == 0) ? (this->width_ / 8) : (this->width_ / 8 + 1);
break;
default:
ESP_LOGE(TAG, "Unsupported bits per pixel: %d", this->bits_per_pixel_);
return DECODE_ERROR_UNSUPPORTED_FORMAT;
}
if (this->compression_method_ != 0) {
ESP_LOGE(TAG, "Unsupported compression method: %d", this->compression_method_);
return DECODE_ERROR_UNSUPPORTED_FORMAT;
}
if (!this->set_size(this->width_, this->height_)) {
return DECODE_ERROR_OUT_OF_MEMORY;
}
this->current_index_ = this->data_offset_;
index = this->data_offset_;
}
while (index < size) {
size_t paint_index = this->current_index_ - this->data_offset_;
uint8_t current_byte = buffer[index];
for (uint8_t i = 0; i < 8; i++) {
size_t x = (paint_index * 8) % this->width_ + i;
size_t y = (this->height_ - 1) - (paint_index / this->width_bytes_);
Color c = (current_byte & (1 << (7 - i))) ? display::COLOR_ON : display::COLOR_OFF;
this->draw(x, y, 1, 1, c);
}
this->current_index_++;
index++;
}
this->decoded_bytes_ += size;
return size;
};
} // namespace online_image
} // namespace esphome
#endif // USE_ONLINE_IMAGE_BMP_SUPPORT

View File

@ -0,0 +1,40 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
#include "image_decoder.h"
namespace esphome {
namespace online_image {
/**
* @brief Image decoder specialization for PNG images.
*/
class BmpDecoder : public ImageDecoder {
public:
/**
* @brief Construct a new BMP Decoder object.
*
* @param display The image to decode the stream into.
*/
BmpDecoder(OnlineImage *image) : ImageDecoder(image) {}
int HOT decode(uint8_t *buffer, size_t size) override;
protected:
size_t current_index_{0};
ssize_t width_{0};
ssize_t height_{0};
uint16_t bits_per_pixel_{0};
uint32_t compression_method_{0};
uint32_t image_data_size_{0};
uint32_t color_table_entries_{0};
size_t width_bytes_{0};
size_t data_offset_{0};
};
} // namespace online_image
} // namespace esphome
#endif // USE_ONLINE_IMAGE_BMP_SUPPORT

View File

@ -8,10 +8,11 @@ namespace online_image {
static const char *const TAG = "online_image.decoder";
void ImageDecoder::set_size(int width, int height) {
this->image_->resize_(width, height);
bool ImageDecoder::set_size(int width, int height) {
bool resized = this->image_->resize_(width, height);
this->x_scale_ = static_cast<double>(this->image_->buffer_width_) / width;
this->y_scale_ = static_cast<double>(this->image_->buffer_height_) / height;
return resized;
}
void ImageDecoder::draw(int x, int y, int w, int h, const Color &color) {

View File

@ -4,6 +4,12 @@
namespace esphome {
namespace online_image {
enum DecodeError : int {
DECODE_ERROR_INVALID_TYPE = -1,
DECODE_ERROR_UNSUPPORTED_FORMAT = -2,
DECODE_ERROR_OUT_OF_MEMORY = -3,
};
class OnlineImage;
/**
@ -24,7 +30,7 @@ class ImageDecoder {
*
* @param download_size The total number of bytes that need to be downloaded for the image.
*/
virtual void prepare(uint32_t download_size) { this->download_size_ = download_size; }
virtual void prepare(size_t download_size) { this->download_size_ = download_size; }
/**
* @brief Decode a part of the image. It will try reading from the buffer.
@ -45,8 +51,9 @@ class ImageDecoder {
*
* @param width The image's width.
* @param height The image's height.
* @return true if the image was resized, false otherwise.
*/
void set_size(int width, int height);
bool set_size(int width, int height);
/**
* @brief Fill a rectangle on the display_buffer using the defined color.
@ -68,8 +75,8 @@ class ImageDecoder {
OnlineImage *image_;
// Initializing to 1, to ensure it is distinguishable from initial "decoded_bytes_".
// Will be overwritten anyway once the download size is known.
uint32_t download_size_ = 1;
uint32_t decoded_bytes_ = 0;
size_t download_size_ = 1;
size_t decoded_bytes_ = 0;
double x_scale_ = 1.0;
double y_scale_ = 1.0;
};

View File

@ -6,6 +6,9 @@ static const char *const TAG = "online_image";
#include "image_decoder.h"
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
#include "bmp_image.h"
#endif
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
#include "png_image.h"
#endif
@ -118,9 +121,14 @@ void OnlineImage::update() {
ESP_LOGD(TAG, "Starting download");
size_t total_size = this->downloader_->content_length;
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
if (this->format_ == ImageFormat::BMP) {
this->decoder_ = make_unique<BmpDecoder>(this);
}
#endif // ONLINE_IMAGE_BMP_SUPPORT
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
if (this->format_ == ImageFormat::PNG) {
this->decoder_ = esphome::make_unique<PngDecoder>(this);
this->decoder_ = make_unique<PngDecoder>(this);
}
#endif // ONLINE_IMAGE_PNG_SUPPORT

View File

@ -1,10 +1,10 @@
#pragma once
#include "esphome/components/http_request/http_request.h"
#include "esphome/components/image/image.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include "esphome/components/http_request/http_request.h"
#include "esphome/components/image/image.h"
#include "image_decoder.h"
@ -27,6 +27,8 @@ enum ImageFormat {
JPEG,
/** PNG format. */
PNG,
/** BMP format. */
BMP,
};
/**
@ -146,7 +148,7 @@ class OnlineImage : public PollingComponent,
*/
int buffer_height_;
friend void ImageDecoder::set_size(int width, int height);
friend bool ImageDecoder::set_size(int width, int height);
friend void ImageDecoder::draw(int x, int y, int w, int h, const Color &color);
};

View File

@ -41,7 +41,7 @@ static void draw_callback(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, ui
decoder->draw(x, y, w, h, color);
}
void PngDecoder::prepare(uint32_t download_size) {
void PngDecoder::prepare(size_t download_size) {
ImageDecoder::prepare(download_size);
pngle_set_user_data(this->pngle_, this);
pngle_set_init_callback(this->pngle_, init_callback);
@ -51,7 +51,7 @@ void PngDecoder::prepare(uint32_t download_size) {
int HOT PngDecoder::decode(uint8_t *buffer, size_t size) {
if (!this->pngle_) {
ESP_LOGE(TAG, "PNG decoder engine not initialized!");
return -1;
return DECODE_ERROR_OUT_OF_MEMORY;
}
if (size < 256 && size < this->download_size_ - this->decoded_bytes_) {
ESP_LOGD(TAG, "Waiting for data");

View File

@ -21,7 +21,7 @@ class PngDecoder : public ImageDecoder {
PngDecoder(OnlineImage *image) : ImageDecoder(image), pngle_(pngle_new()) {}
~PngDecoder() override { pngle_destroy(this->pngle_); }
void prepare(uint32_t download_size) override;
void prepare(size_t download_size) override;
int HOT decode(uint8_t *buffer, size_t size) override;
protected:

View File

@ -75,6 +75,8 @@ void PulseMeterSensor::loop() {
case MeterState::RUNNING: {
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_);
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);
} break;
}

View File

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

View File

@ -19,6 +19,8 @@ from .boards import RTL87XX_BOARD_PINS, RTL87XX_BOARDS
CODEOWNERS = ["@kuba2k2"]
AUTO_LOAD = ["libretiny"]
IS_TARGET_PLATFORM = True
COMPONENT_DATA = LibreTinyComponent(
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 "esphome/core/log.h"
#include <cinttypes>
#include <utility>
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.
void MR60BHA2Component::dump_config() {
ESP_LOGCONFIG(TAG, "MR60BHA2:");
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "People Exist Binary Sensor", this->has_target_binary_sensor_);
#endif
#ifdef USE_SENSOR
LOG_SENSOR(" ", "Breath Rate Sensor", this->breath_rate_sensor_);
LOG_SENSOR(" ", "Heart Rate Sensor", this->heart_rate_sensor_);
LOG_SENSOR(" ", "Distance Sensor", this->distance_sensor_);
LOG_SENSOR(" ", "Target Number Sensor", this->num_targets_sensor_);
#endif
}
@ -94,7 +99,8 @@ bool MR60BHA2Component::validate_message_() {
uint16_t frame_type = encode_uint16(data[5], data[6]);
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;
}
@ -144,6 +150,18 @@ void MR60BHA2Component::process_frame_(uint16_t frame_id, uint16_t frame_type, c
}
}
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:
if (this->heart_rate_sensor_ != nullptr && length >= 4) {
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;
case DISTANCE_TYPE_BUFFER:
if (!data[0]) {
if (data[0] != 0) {
if (this->distance_sensor_ != nullptr && length >= 8) {
uint32_t current_distance_int = encode_uint32(data[7], data[6], data[5], data[4]);
float distance_float;
@ -164,6 +182,12 @@ void MR60BHA2Component::process_frame_(uint16_t frame_id, uint16_t frame_type, c
}
}
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:
break;
}

View File

@ -1,6 +1,9 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif
@ -12,37 +15,23 @@
namespace esphome {
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 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 DISTANCE_TYPE_BUFFER = 0x0A16;
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,
};
static const uint16_t PRINT_CLOUD_BUFFER = 0x0A04;
class MR60BHA2Component : public Component,
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
SUB_SENSOR(breath_rate);
SUB_SENSOR(heart_rate);
SUB_SENSOR(distance);
SUB_SENSOR(num_targets);
#endif
public:

View File

@ -7,6 +7,7 @@ from esphome.const import (
ICON_HEART_PULSE,
ICON_PULSE,
ICON_SIGNAL,
ICON_COUNTER,
STATE_CLASS_MEASUREMENT,
UNIT_BEATS_PER_MINUTE,
UNIT_CENTIMETER,
@ -18,12 +19,13 @@ DEPENDENCIES = ["seeed_mr60bha2"]
CONF_BREATH_RATE = "breath_rate"
CONF_HEART_RATE = "heart_rate"
CONF_NUM_TARGETS = "num_targets"
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_MR60BHA2_ID): cv.use_id(MR60BHA2Component),
cv.Optional(CONF_BREATH_RATE): sensor.sensor_schema(
accuracy_decimals=2,
accuracy_decimals=0,
state_class=STATE_CLASS_MEASUREMENT,
icon=ICON_PULSE,
),
@ -40,6 +42,9 @@ CONFIG_SCHEMA = cv.Schema(
accuracy_decimals=2,
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):
sens = await sensor.new_sensor(distance_config)
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) {
// Clock starts out at idle level
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++) {
uint8_t shift;

View File

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

View File

@ -15,15 +15,6 @@ PLATFORM_LIBRETINY_OLDSTYLE = "libretiny"
PLATFORM_RP2040 = "rp2040"
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"}
HEADER_FILE_EXTENSIONS = {".h", ".hpp", ".tcc"}

View File

@ -1,6 +1,7 @@
import logging
import multiprocessing
import os
from pathlib import Path
from esphome import automation
import esphome.codegen as cg
@ -28,7 +29,6 @@ from esphome.const import (
CONF_TRIGGER_ID,
CONF_VERSION,
KEY_CORE,
TARGET_PLATFORMS,
__version__ as ESPHOME_VERSION,
)
from esphome.core import CORE, coroutine_with_priority
@ -174,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):
conf = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME])
@ -187,12 +211,16 @@ def preload_core_config(config, result):
conf[CONF_BUILD_PATH] = os.path.join(build_path, CORE.name)
CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH])
target_platforms = [key for key in TARGET_PLATFORMS if key in config]
target_platforms = []
for domain, _ in config.items():
if _is_target_platform(domain):
target_platforms += [domain]
if not target_platforms:
raise cv.Invalid(
"Platform missing. You must include one of the available platform keys: "
+ ", ".join(TARGET_PLATFORMS),
+ ", ".join(_list_target_platforms()),
[CONF_ESPHOME],
)
if len(target_platforms) > 1:
@ -202,6 +230,7 @@ def preload_core_config(config, result):
)
config[CONF_ESPHOME] = conf
return target_platforms[0]
def include_file(path, basename):

View File

@ -60,6 +60,7 @@
#define USE_NETWORK
#define USE_NEXTION_TFT_UPLOAD
#define USE_NUMBER
#define USE_ONLINE_IMAGE_BMP_SUPPORT
#define USE_ONLINE_IMAGE_PNG_SUPPORT
#define USE_OTA
#define USE_OTA_PASSWORD

View File

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

View File

@ -10,4 +10,5 @@ sensor:
- platform: ads1115
multiplexer: A0_A1
gain: 1.024
sample_rate: 128
id: ads1115_sensor

View File

@ -10,4 +10,5 @@ sensor:
- platform: ads1115
multiplexer: A0_A1
gain: 1.024
sample_rate: 128
id: ads1115_sensor

View File

@ -10,4 +10,5 @@ sensor:
- platform: ads1115
multiplexer: A0_A1
gain: 1.024
sample_rate: 128
id: ads1115_sensor

View File

@ -10,4 +10,5 @@ sensor:
- platform: ads1115
multiplexer: A0_A1
gain: 1.024
sample_rate: 128
id: ads1115_sensor

View File

@ -10,4 +10,5 @@ sensor:
- platform: ads1115
multiplexer: A0_A1
gain: 1.024
sample_rate: 128
id: ads1115_sensor

View File

@ -10,4 +10,5 @@ sensor:
- platform: ads1115
multiplexer: A0_A1
gain: 1.024
sample_rate: 128
id: ads1115_sensor

View File

@ -0,0 +1,14 @@
esphome:
on_boot:
then:
- audio_adc.set_mic_gain: 0db
- audio_adc.set_mic_gain: !lambda 'return 4;'
i2c:
- id: i2c_es7243e
scl: ${scl_pin}
sda: ${sda_pin}
audio_adc:
- platform: es7243e
id: es7243e_adc

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO16
sda_pin: GPIO17
<<: !include common.yaml

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO16
sda_pin: GPIO17
<<: !include common.yaml

View File

@ -26,6 +26,10 @@ online_image:
format: PNG
type: RGB
transparency: chroma_key
- id: online_binary_bmp
url: https://samples-files.com/samples/images/bmp/480-360-sample.bmp
format: BMP
type: BINARY
# Check the set_url action
esphome:

View File

@ -9,6 +9,11 @@ uart:
seeed_mr60bha2:
id: my_seeed_mr60bha2
binary_sensor:
- platform: seeed_mr60bha2
has_target:
name: "Person Information"
sensor:
- platform: seeed_mr60bha2
breath_rate:
@ -17,3 +22,5 @@ sensor:
name: "Real-time heart rate"
distance:
name: "Distance to detection object"
num_targets:
name: "Target Number"