mirror of
https://github.com/esphome/esphome.git
synced 2025-11-05 01:21:50 +00:00
Compare commits
5 Commits
qualify_mi
...
2025.10.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a478b9070 | ||
|
|
a32a1d11fb | ||
|
|
daeb8ef88c | ||
|
|
febee437d6 | ||
|
|
de2f475dbd |
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.10.2
|
PROJECT_NUMBER = 2025.10.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
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ void HDC1080Component::setup() {
|
|||||||
|
|
||||||
// if configuration fails - there is a problem
|
// if configuration fails - there is a problem
|
||||||
if (this->write_register(HDC1080_CMD_CONFIGURATION, config, 2) != i2c::ERROR_OK) {
|
if (this->write_register(HDC1080_CMD_CONFIGURATION, config, 2) != i2c::ERROR_OK) {
|
||||||
this->mark_failed();
|
ESP_LOGW(TAG, "Failed to configure HDC1080");
|
||||||
|
this->status_set_warning();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,13 @@ uint32_t ESP8266UartComponent::get_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266UartComponent::setup() {
|
void ESP8266UartComponent::setup() {
|
||||||
|
if (this->rx_pin_) {
|
||||||
|
this->rx_pin_->setup();
|
||||||
|
}
|
||||||
|
if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
|
||||||
|
this->tx_pin_->setup();
|
||||||
|
}
|
||||||
|
|
||||||
// Use Arduino HardwareSerial UARTs if all used pins match the ones
|
// Use Arduino HardwareSerial UARTs if all used pins match the ones
|
||||||
// preconfigured by the platform. For example if RX disabled but TX pin
|
// preconfigured by the platform. For example if RX disabled but TX pin
|
||||||
// is 1 we still want to use Serial.
|
// is 1 we still want to use Serial.
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/gpio.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "soc/gpio_num.h"
|
||||||
|
|
||||||
#ifdef USE_LOGGER
|
#ifdef USE_LOGGER
|
||||||
#include "esphome/components/logger/logger.h"
|
#include "esphome/components/logger/logger.h"
|
||||||
@@ -104,6 +107,13 @@ void IDFUARTComponent::load_settings(bool dump_config) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->rx_pin_) {
|
||||||
|
this->rx_pin_->setup();
|
||||||
|
}
|
||||||
|
if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
|
||||||
|
this->tx_pin_->setup();
|
||||||
|
}
|
||||||
|
|
||||||
int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
|
int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
|
||||||
int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
|
int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
|
||||||
int8_t flow_control = this->flow_control_pin_ != nullptr ? this->flow_control_pin_->get_pin() : -1;
|
int8_t flow_control = this->flow_control_pin_ != nullptr ? this->flow_control_pin_->get_pin() : -1;
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ uint16_t LibreTinyUARTComponent::get_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LibreTinyUARTComponent::setup() {
|
void LibreTinyUARTComponent::setup() {
|
||||||
|
if (this->rx_pin_) {
|
||||||
|
this->rx_pin_->setup();
|
||||||
|
}
|
||||||
|
if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
|
||||||
|
this->tx_pin_->setup();
|
||||||
|
}
|
||||||
|
|
||||||
int8_t tx_pin = tx_pin_ == nullptr ? -1 : tx_pin_->get_pin();
|
int8_t tx_pin = tx_pin_ == nullptr ? -1 : tx_pin_->get_pin();
|
||||||
int8_t rx_pin = rx_pin_ == nullptr ? -1 : rx_pin_->get_pin();
|
int8_t rx_pin = rx_pin_ == nullptr ? -1 : rx_pin_->get_pin();
|
||||||
bool tx_inverted = tx_pin_ != nullptr && tx_pin_->is_inverted();
|
bool tx_inverted = tx_pin_ != nullptr && tx_pin_->is_inverted();
|
||||||
|
|||||||
@@ -52,6 +52,13 @@ uint16_t RP2040UartComponent::get_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RP2040UartComponent::setup() {
|
void RP2040UartComponent::setup() {
|
||||||
|
if (this->rx_pin_) {
|
||||||
|
this->rx_pin_->setup();
|
||||||
|
}
|
||||||
|
if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
|
||||||
|
this->tx_pin_->setup();
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t config = get_config();
|
uint16_t config = get_config();
|
||||||
|
|
||||||
constexpr uint32_t valid_tx_uart_0 = __bitset({0, 12, 16, 28});
|
constexpr uint32_t valid_tx_uart_0 = __bitset({0, 12, 16, 28});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from enum import Enum
|
|||||||
|
|
||||||
from esphome.enum import StrEnum
|
from esphome.enum import StrEnum
|
||||||
|
|
||||||
__version__ = "2025.10.2"
|
__version__ = "2025.10.3"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||||
|
|||||||
@@ -224,36 +224,37 @@ def resolve_ip_address(
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
# Process hosts
|
# Process hosts
|
||||||
cached_addresses: list[str] = []
|
|
||||||
uncached_hosts: list[str] = []
|
uncached_hosts: list[str] = []
|
||||||
has_cache = address_cache is not None
|
|
||||||
|
|
||||||
for h in hosts:
|
for h in hosts:
|
||||||
if is_ip_address(h):
|
if is_ip_address(h):
|
||||||
if has_cache:
|
_add_ip_addresses_to_addrinfo([h], port, res)
|
||||||
# If we have a cache, treat IPs as cached
|
|
||||||
cached_addresses.append(h)
|
|
||||||
else:
|
|
||||||
# If no cache, pass IPs through to resolver with hostnames
|
|
||||||
uncached_hosts.append(h)
|
|
||||||
elif address_cache and (cached := address_cache.get_addresses(h)):
|
elif address_cache and (cached := address_cache.get_addresses(h)):
|
||||||
# Found in cache
|
_add_ip_addresses_to_addrinfo(cached, port, res)
|
||||||
cached_addresses.extend(cached)
|
|
||||||
else:
|
else:
|
||||||
# Not cached, need to resolve
|
# Not cached, need to resolve
|
||||||
if address_cache and address_cache.has_cache():
|
if address_cache and address_cache.has_cache():
|
||||||
_LOGGER.info("Host %s not in cache, will need to resolve", h)
|
_LOGGER.info("Host %s not in cache, will need to resolve", h)
|
||||||
uncached_hosts.append(h)
|
uncached_hosts.append(h)
|
||||||
|
|
||||||
# Process cached addresses (includes direct IPs and cached lookups)
|
|
||||||
_add_ip_addresses_to_addrinfo(cached_addresses, port, res)
|
|
||||||
|
|
||||||
# If we have uncached hosts (only non-IP hostnames), resolve them
|
# If we have uncached hosts (only non-IP hostnames), resolve them
|
||||||
if uncached_hosts:
|
if uncached_hosts:
|
||||||
|
from aioesphomeapi.host_resolver import AddrInfo as AioAddrInfo
|
||||||
|
|
||||||
|
from esphome.core import EsphomeError
|
||||||
from esphome.resolver import AsyncResolver
|
from esphome.resolver import AsyncResolver
|
||||||
|
|
||||||
resolver = AsyncResolver(uncached_hosts, port)
|
resolver = AsyncResolver(uncached_hosts, port)
|
||||||
|
addr_infos: list[AioAddrInfo] = []
|
||||||
|
try:
|
||||||
addr_infos = resolver.resolve()
|
addr_infos = resolver.resolve()
|
||||||
|
except EsphomeError as err:
|
||||||
|
if not res:
|
||||||
|
# No pre-resolved addresses available, DNS resolution is fatal
|
||||||
|
raise
|
||||||
|
_LOGGER.info("%s (using %d already resolved IP addresses)", err, len(res))
|
||||||
|
|
||||||
# Convert aioesphomeapi AddrInfo to our format
|
# Convert aioesphomeapi AddrInfo to our format
|
||||||
for addr_info in addr_infos:
|
for addr_info in addr_infos:
|
||||||
sockaddr = addr_info.sockaddr
|
sockaddr = addr_info.sockaddr
|
||||||
|
|||||||
@@ -454,9 +454,27 @@ def test_resolve_ip_address_mixed_list() -> None:
|
|||||||
# Mix of IP and hostname - should use async resolver
|
# Mix of IP and hostname - should use async resolver
|
||||||
result = helpers.resolve_ip_address(["192.168.1.100", "test.local"], 6053)
|
result = helpers.resolve_ip_address(["192.168.1.100", "test.local"], 6053)
|
||||||
|
|
||||||
|
assert len(result) == 2
|
||||||
|
assert result[0][4][0] == "192.168.1.100"
|
||||||
|
assert result[1][4][0] == "192.168.1.200"
|
||||||
|
MockResolver.assert_called_once_with(["test.local"], 6053)
|
||||||
|
mock_resolver.resolve.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_ip_address_mixed_list_fail() -> None:
|
||||||
|
"""Test resolving a mix of IPs and hostnames with resolve failed."""
|
||||||
|
with patch("esphome.resolver.AsyncResolver") as MockResolver:
|
||||||
|
mock_resolver = MockResolver.return_value
|
||||||
|
mock_resolver.resolve.side_effect = EsphomeError(
|
||||||
|
"Error resolving IP address: [test.local]"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mix of IP and hostname - should use async resolver
|
||||||
|
result = helpers.resolve_ip_address(["192.168.1.100", "test.local"], 6053)
|
||||||
|
|
||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
assert result[0][4][0] == "192.168.1.200"
|
assert result[0][4][0] == "192.168.1.100"
|
||||||
MockResolver.assert_called_once_with(["192.168.1.100", "test.local"], 6053)
|
MockResolver.assert_called_once_with(["test.local"], 6053)
|
||||||
mock_resolver.resolve.assert_called_once()
|
mock_resolver.resolve.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user