mirror of
https://github.com/esphome/esphome.git
synced 2025-09-28 16:12:24 +01:00
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 2025.8.2
|
PROJECT_NUMBER = 2025.8.3
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
@@ -1135,7 +1135,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const {
|
|||||||
dump_field(out, "string_", this->string_);
|
dump_field(out, "string_", this->string_);
|
||||||
dump_field(out, "int_", this->int_);
|
dump_field(out, "int_", this->int_);
|
||||||
for (const auto it : this->bool_array) {
|
for (const auto it : this->bool_array) {
|
||||||
dump_field(out, "bool_array", it, 4);
|
dump_field(out, "bool_array", static_cast<bool>(it), 4);
|
||||||
}
|
}
|
||||||
for (const auto &it : this->int_array) {
|
for (const auto &it : this->int_array) {
|
||||||
dump_field(out, "int_array", it, 4);
|
dump_field(out, "int_array", it, 4);
|
||||||
|
@@ -40,6 +40,7 @@ from esphome.cpp_generator import RawExpression
|
|||||||
import esphome.final_validate as fv
|
import esphome.final_validate as fv
|
||||||
from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed
|
from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed
|
||||||
from esphome.types import ConfigType
|
from esphome.types import ConfigType
|
||||||
|
from esphome.writer import clean_cmake_cache
|
||||||
|
|
||||||
from .boards import BOARDS, STANDARD_BOARDS
|
from .boards import BOARDS, STANDARD_BOARDS
|
||||||
from .const import ( # noqa
|
from .const import ( # noqa
|
||||||
@@ -840,6 +841,9 @@ async def to_code(config):
|
|||||||
if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]:
|
if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]:
|
||||||
cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC")
|
cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC")
|
||||||
|
|
||||||
|
for clean_var in ("IDF_PATH", "IDF_TOOLS_PATH"):
|
||||||
|
os.environ.pop(clean_var, None)
|
||||||
|
|
||||||
add_extra_script(
|
add_extra_script(
|
||||||
"post",
|
"post",
|
||||||
"post_build.py",
|
"post_build.py",
|
||||||
@@ -1079,7 +1083,11 @@ def _write_idf_component_yml():
|
|||||||
contents = yaml_util.dump({"dependencies": dependencies})
|
contents = yaml_util.dump({"dependencies": dependencies})
|
||||||
else:
|
else:
|
||||||
contents = ""
|
contents = ""
|
||||||
write_file_if_changed(yml_path, contents)
|
if write_file_if_changed(yml_path, contents):
|
||||||
|
dependencies_lock = CORE.relative_build_path("dependencies.lock")
|
||||||
|
if os.path.isfile(dependencies_lock):
|
||||||
|
os.remove(dependencies_lock)
|
||||||
|
clean_cmake_cache()
|
||||||
|
|
||||||
|
|
||||||
# Called by writer.py
|
# Called by writer.py
|
||||||
|
@@ -47,9 +47,9 @@ ErrorCode I2CDevice::write_register(uint8_t a_register, const uint8_t *data, siz
|
|||||||
|
|
||||||
ErrorCode I2CDevice::write_register16(uint16_t a_register, const uint8_t *data, size_t len) const {
|
ErrorCode I2CDevice::write_register16(uint16_t a_register, const uint8_t *data, size_t len) const {
|
||||||
std::vector<uint8_t> v(len + 2);
|
std::vector<uint8_t> v(len + 2);
|
||||||
v.push_back(a_register >> 8);
|
v[0] = a_register >> 8;
|
||||||
v.push_back(a_register);
|
v[1] = a_register;
|
||||||
v.insert(v.end(), data, data + len);
|
std::copy(data, data + len, v.begin() + 2);
|
||||||
return bus_->write_readv(this->address_, v.data(), v.size(), nullptr, 0);
|
return bus_->write_readv(this->address_, v.data(), v.size(), nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -122,7 +122,7 @@ uint8_t Mcp4461Component::get_status_register_() {
|
|||||||
uint8_t addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_STATUS);
|
uint8_t addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_STATUS);
|
||||||
uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::READ);
|
uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::READ);
|
||||||
uint16_t buf;
|
uint16_t buf;
|
||||||
if (!this->read_byte_16(reg, &buf)) {
|
if (!this->read_16_(reg, &buf)) {
|
||||||
this->error_code_ = MCP4461_STATUS_REGISTER_ERROR;
|
this->error_code_ = MCP4461_STATUS_REGISTER_ERROR;
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -148,6 +148,20 @@ void Mcp4461Component::read_status_register_to_log() {
|
|||||||
((status_register_value >> 3) & 0x01), ((status_register_value >> 2) & 0x01),
|
((status_register_value >> 3) & 0x01), ((status_register_value >> 2) & 0x01),
|
||||||
((status_register_value >> 1) & 0x01), ((status_register_value >> 0) & 0x01));
|
((status_register_value >> 1) & 0x01), ((status_register_value >> 0) & 0x01));
|
||||||
}
|
}
|
||||||
|
bool Mcp4461Component::read_16_(uint8_t address, uint16_t *buf) {
|
||||||
|
// read 16 bits and convert from big endian to host,
|
||||||
|
// Do this as two separate operations to ensure a stop condition between the write and read
|
||||||
|
i2c::ErrorCode err = this->write(&address, 1);
|
||||||
|
if (err != i2c::ERROR_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
err = this->read(reinterpret_cast<uint8_t *>(buf), 2);
|
||||||
|
if (err != i2c::ERROR_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*buf = convert_big_endian(*buf);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t Mcp4461Component::get_wiper_address_(uint8_t wiper) {
|
uint8_t Mcp4461Component::get_wiper_address_(uint8_t wiper) {
|
||||||
uint8_t addr;
|
uint8_t addr;
|
||||||
@@ -198,14 +212,14 @@ uint16_t Mcp4461Component::get_wiper_level_(Mcp4461WiperIdx wiper) {
|
|||||||
|
|
||||||
uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) {
|
uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) {
|
||||||
uint8_t addr = this->get_wiper_address_(wiper_idx);
|
uint8_t addr = this->get_wiper_address_(wiper_idx);
|
||||||
uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::INCREMENT);
|
uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::READ);
|
||||||
if (wiper_idx > 3) {
|
if (wiper_idx > 3) {
|
||||||
if (!this->is_eeprom_ready_for_writing_(true)) {
|
if (!this->is_eeprom_ready_for_writing_(true)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint16_t buf = 0;
|
uint16_t buf = 0;
|
||||||
if (!(this->read_byte_16(reg, &buf))) {
|
if (!(this->read_16_(reg, &buf))) {
|
||||||
this->error_code_ = MCP4461_STATUS_I2C_ERROR;
|
this->error_code_ = MCP4461_STATUS_I2C_ERROR;
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
ESP_LOGW(TAG, "Error fetching %swiper %u value", (wiper_idx > 3) ? "nonvolatile " : "", wiper_idx);
|
ESP_LOGW(TAG, "Error fetching %swiper %u value", (wiper_idx > 3) ? "nonvolatile " : "", wiper_idx);
|
||||||
@@ -392,7 +406,7 @@ uint8_t Mcp4461Component::get_terminal_register_(Mcp4461TerminalIdx terminal_con
|
|||||||
: static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON1);
|
: static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON1);
|
||||||
reg |= static_cast<uint8_t>(Mcp4461Commands::READ);
|
reg |= static_cast<uint8_t>(Mcp4461Commands::READ);
|
||||||
uint16_t buf;
|
uint16_t buf;
|
||||||
if (this->read_byte_16(reg, &buf)) {
|
if (this->read_16_(reg, &buf)) {
|
||||||
return static_cast<uint8_t>(buf & 0x00ff);
|
return static_cast<uint8_t>(buf & 0x00ff);
|
||||||
} else {
|
} else {
|
||||||
this->error_code_ = MCP4461_STATUS_I2C_ERROR;
|
this->error_code_ = MCP4461_STATUS_I2C_ERROR;
|
||||||
@@ -517,7 +531,7 @@ uint16_t Mcp4461Component::get_eeprom_value(Mcp4461EepromLocation location) {
|
|||||||
if (!this->is_eeprom_ready_for_writing_(true)) {
|
if (!this->is_eeprom_ready_for_writing_(true)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!this->read_byte_16(reg, &buf)) {
|
if (!this->read_16_(reg, &buf)) {
|
||||||
this->error_code_ = MCP4461_STATUS_I2C_ERROR;
|
this->error_code_ = MCP4461_STATUS_I2C_ERROR;
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
ESP_LOGW(TAG, "Error fetching EEPROM location value");
|
ESP_LOGW(TAG, "Error fetching EEPROM location value");
|
||||||
|
@@ -96,6 +96,7 @@ class Mcp4461Component : public Component, public i2c::I2CDevice {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Mcp4461Wiper;
|
friend class Mcp4461Wiper;
|
||||||
|
bool read_16_(uint8_t address, uint16_t *buf);
|
||||||
void update_write_protection_status_();
|
void update_write_protection_status_();
|
||||||
uint8_t get_wiper_address_(uint8_t wiper);
|
uint8_t get_wiper_address_(uint8_t wiper);
|
||||||
uint16_t read_wiper_level_(uint8_t wiper);
|
uint16_t read_wiper_level_(uint8_t wiper);
|
||||||
|
@@ -16,7 +16,6 @@ DriverChip(
|
|||||||
lane_bit_rate="750Mbps",
|
lane_bit_rate="750Mbps",
|
||||||
swap_xy=cv.UNDEFINED,
|
swap_xy=cv.UNDEFINED,
|
||||||
color_order="RGB",
|
color_order="RGB",
|
||||||
reset_pin=27,
|
|
||||||
initsequence=[
|
initsequence=[
|
||||||
(0x30, 0x00), (0xF7, 0x49, 0x61, 0x02, 0x00), (0x30, 0x01), (0x04, 0x0C), (0x05, 0x00), (0x06, 0x00),
|
(0x30, 0x00), (0xF7, 0x49, 0x61, 0x02, 0x00), (0x30, 0x01), (0x04, 0x0C), (0x05, 0x00), (0x06, 0x00),
|
||||||
(0x0B, 0x11), (0x17, 0x00), (0x20, 0x04), (0x1F, 0x05), (0x23, 0x00), (0x25, 0x19), (0x28, 0x18), (0x29, 0x04), (0x2A, 0x01),
|
(0x0B, 0x11), (0x17, 0x00), (0x20, 0x04), (0x1F, 0x05), (0x23, 0x00), (0x25, 0x19), (0x28, 0x18), (0x29, 0x04), (0x2A, 0x01),
|
||||||
|
@@ -4,7 +4,7 @@ from enum import Enum
|
|||||||
|
|
||||||
from esphome.enum import StrEnum
|
from esphome.enum import StrEnum
|
||||||
|
|
||||||
__version__ = "2025.8.2"
|
__version__ = "2025.8.3"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||||
|
@@ -423,7 +423,7 @@ async def _add_automations(config):
|
|||||||
DATETIME_SUBTYPES = {"date", "time", "datetime"}
|
DATETIME_SUBTYPES = {"date", "time", "datetime"}
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(-100.0)
|
@coroutine_with_priority(-1000.0)
|
||||||
async def _add_platform_defines() -> None:
|
async def _add_platform_defines() -> None:
|
||||||
# Generate compile-time defines for platforms that have actual entities
|
# Generate compile-time defines for platforms that have actual entities
|
||||||
# Only add USE_* and count defines when there are entities
|
# Only add USE_* and count defines when there are entities
|
||||||
|
@@ -310,6 +310,10 @@ def clean_build():
|
|||||||
if os.path.isdir(piolibdeps):
|
if os.path.isdir(piolibdeps):
|
||||||
_LOGGER.info("Deleting %s", piolibdeps)
|
_LOGGER.info("Deleting %s", piolibdeps)
|
||||||
shutil.rmtree(piolibdeps)
|
shutil.rmtree(piolibdeps)
|
||||||
|
dependencies_lock = CORE.relative_build_path("dependencies.lock")
|
||||||
|
if os.path.isfile(dependencies_lock):
|
||||||
|
_LOGGER.info("Deleting %s", dependencies_lock)
|
||||||
|
os.remove(dependencies_lock)
|
||||||
|
|
||||||
|
|
||||||
GITIGNORE_CONTENT = """# Gitignore settings for ESPHome
|
GITIGNORE_CONTENT = """# Gitignore settings for ESPHome
|
||||||
|
@@ -1059,7 +1059,9 @@ def _generate_array_dump_content(
|
|||||||
# Check if underlying type can use dump_field
|
# Check if underlying type can use dump_field
|
||||||
if ti.can_use_dump_field():
|
if ti.can_use_dump_field():
|
||||||
# For types that have dump_field overloads, use them with extra indent
|
# For types that have dump_field overloads, use them with extra indent
|
||||||
o += f' dump_field(out, "{name}", {ti.dump_field_value("it")}, 4);\n'
|
# std::vector<bool> iterators return proxy objects, need explicit cast
|
||||||
|
value_expr = "static_cast<bool>(it)" if is_bool else ti.dump_field_value("it")
|
||||||
|
o += f' dump_field(out, "{name}", {value_expr}, 4);\n'
|
||||||
else:
|
else:
|
||||||
# For complex types (messages, bytes), use the old pattern
|
# For complex types (messages, bytes), use the old pattern
|
||||||
o += f' out.append(" {name}: ");\n'
|
o += f' out.append(" {name}: ");\n'
|
||||||
|
@@ -4,7 +4,7 @@ esphome:
|
|||||||
host:
|
host:
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
level: DEBUG
|
level: VERY_VERBOSE
|
||||||
|
|
||||||
api:
|
api:
|
||||||
actions:
|
actions:
|
||||||
|
@@ -8,6 +8,7 @@ import pytest
|
|||||||
|
|
||||||
from esphome import config_validation as cv, core
|
from esphome import config_validation as cv, core
|
||||||
from esphome.const import CONF_AREA, CONF_AREAS, CONF_DEVICES
|
from esphome.const import CONF_AREA, CONF_AREAS, CONF_DEVICES
|
||||||
|
from esphome.core import config
|
||||||
from esphome.core.config import Area, validate_area_config
|
from esphome.core.config import Area, validate_area_config
|
||||||
|
|
||||||
from .common import load_config_from_fixture
|
from .common import load_config_from_fixture
|
||||||
@@ -223,3 +224,24 @@ def test_device_duplicate_id(
|
|||||||
# Check for the specific error message from IDPassValidationStep
|
# Check for the specific error message from IDPassValidationStep
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert "ID duplicate_device redefined!" in captured.out
|
assert "ID duplicate_device redefined!" in captured.out
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_platform_defines_priority() -> None:
|
||||||
|
"""Test that _add_platform_defines runs after globals.
|
||||||
|
|
||||||
|
This ensures the fix for issue #10431 where sensor counts were incorrect
|
||||||
|
when lambdas were present. The function must run at a lower priority than
|
||||||
|
globals (-100.0) to ensure all components (including those using globals
|
||||||
|
in lambdas) have registered their entities before the count defines are
|
||||||
|
generated.
|
||||||
|
|
||||||
|
Regression test for https://github.com/esphome/esphome/issues/10431
|
||||||
|
"""
|
||||||
|
# Import globals to check its priority
|
||||||
|
from esphome.components.globals import to_code as globals_to_code
|
||||||
|
|
||||||
|
# _add_platform_defines must run AFTER globals (lower priority number = runs later)
|
||||||
|
assert config._add_platform_defines.priority < globals_to_code.priority, (
|
||||||
|
f"_add_platform_defines priority ({config._add_platform_defines.priority}) must be lower than "
|
||||||
|
f"globals priority ({globals_to_code.priority}) to fix issue #10431 (sensor count bug with lambdas)"
|
||||||
|
)
|
||||||
|
Reference in New Issue
Block a user