Merge remote-tracking branch 'upstream/dev' into setup_heap_stats

# Conflicts:
#	esphome/core/defines.h
This commit is contained in:
J. Nick Koston
2026-02-23 12:04:56 -06:00
137 changed files with 1553 additions and 590 deletions

View File

@@ -213,6 +213,7 @@ esphome/components/hbridge/light/* @DotNetDann
esphome/components/hbridge/switch/* @dwmw2
esphome/components/hc8/* @omartijn
esphome/components/hdc2010/* @optimusprimespace @ssieb
esphome/components/hdc302x/* @joshuasing
esphome/components/he60r/* @clydebarrow
esphome/components/heatpumpir/* @rob-deutsch
esphome/components/hitachi_ac424/* @sourabhjaiswal

View File

@@ -92,10 +92,7 @@ void AbsoluteHumidityComponent::loop() {
// Calculate absolute humidity
const float absolute_humidity = vapor_density(es, hr, temperature_k);
ESP_LOGD(TAG,
"Saturation vapor pressure %f kPa\n"
"Publishing absolute humidity %f g/m³",
es, absolute_humidity);
ESP_LOGD(TAG, "Saturation vapor pressure %f kPa, absolute humidity %f g/m³", es, absolute_humidity);
// Publish absolute humidity
this->status_clear_warning();

View File

@@ -67,10 +67,8 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
case ESP_GATTC_SEARCH_CMPL_EVT: {
auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
if (chr == nullptr) {
ESP_LOGW(TAG,
"[%s] No control service found at device, not an Anova..?\n"
"[%s] Note, this component does not currently support Anova Nano.",
this->get_name().c_str(), this->get_name().c_str());
ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str());
ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str());
break;
}
this->char_handle_ = chr->handle;

View File

@@ -233,8 +233,8 @@ def _consume_api_sockets(config: ConfigType) -> ConfigType:
# API needs 1 listening socket + typically 3 concurrent client connections
# (not max_connections, which is the upper limit rarely reached)
sockets_needed = 1 + 3
socket.consume_sockets(sockets_needed, "api")(config)
socket.consume_sockets(3, "api")(config)
socket.consume_sockets(1, "api", socket.SocketType.TCP_LISTEN)(config)
return config

View File

@@ -1346,9 +1346,8 @@ uint16_t APIConnection::try_send_water_heater_state(EntityBase *entity, APIConne
resp.target_temperature_low = wh->get_target_temperature_low();
resp.target_temperature_high = wh->get_target_temperature_high();
resp.state = wh->get_state();
resp.key = wh->get_object_id_hash();
return encode_message_to_buffer(resp, WaterHeaterStateResponse::MESSAGE_TYPE, conn, remaining_size);
return fill_and_encode_entity_state(wh, resp, WaterHeaterStateResponse::MESSAGE_TYPE, conn, remaining_size);
}
uint16_t APIConnection::try_send_water_heater_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) {
auto *wh = static_cast<water_heater::WaterHeater *>(entity);

View File

@@ -307,9 +307,9 @@ void AS3935Component::tune_antenna() {
uint8_t tune_val = this->read_capacitance();
ESP_LOGI(TAG,
"Starting antenna tuning\n"
"Division Ratio is set to: %d\n"
"Internal Capacitor is set to: %d\n"
"Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio",
" Division Ratio is set to: %d\n"
" Internal Capacitor is set to: %d\n"
" Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio",
div_ratio, tune_val);
this->display_oscillator(true, ANTFREQ);
}

View File

@@ -77,14 +77,14 @@ void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); }
bool AT581XComponent::i2c_write_config() {
ESP_LOGCONFIG(TAG,
"Writing new config for AT581X\n"
"Frequency: %dMHz\n"
"Sensing distance: %d\n"
"Power: %dµA\n"
"Gain: %d\n"
"Trigger base time: %dms\n"
"Trigger keep time: %dms\n"
"Protect time: %dms\n"
"Self check time: %dms",
" Frequency: %dMHz\n"
" Sensing distance: %d\n"
" Power: %dµA\n"
" Gain: %d\n"
" Trigger base time: %dms\n"
" Trigger keep time: %dms\n"
" Protect time: %dms\n"
" Self check time: %dms",
this->freq_, this->delta_, this->power_, this->gain_, this->trigger_base_time_ms_,
this->trigger_keep_time_ms_, this->protect_time_ms_, this->self_check_time_ms_);

View File

@@ -562,6 +562,7 @@ async def setup_binary_sensor_core_(var, config):
if inverted := config.get(CONF_INVERTED):
cg.add(var.set_inverted(inverted))
if filters_config := config.get(CONF_FILTERS):
cg.add_define("USE_BINARY_SENSOR_FILTER")
filters = await cg.build_registry_list(FILTER_REGISTRY, filters_config)
cg.add(var.add_filters(filters))

View File

@@ -29,10 +29,8 @@ void MultiClickTrigger::on_state_(bool state) {
// Start matching
MultiClickTriggerEvent evt = this->timing_[0];
if (evt.state == state) {
ESP_LOGV(TAG,
"START min=%" PRIu32 " max=%" PRIu32 "\n"
"Multi Click: Starting multi click action!",
evt.min_length, evt.max_length);
ESP_LOGV(TAG, "START min=%" PRIu32 " max=%" PRIu32, evt.min_length, evt.max_length);
ESP_LOGV(TAG, "Multi Click: Starting multi click action!");
this->at_index_ = 1;
if (this->timing_.size() == 1 && evt.max_length == 4294967294UL) {
this->set_timeout(MULTICLICK_TRIGGER_ID, evt.min_length, [this]() { this->trigger_(); });

View File

@@ -18,11 +18,15 @@ void log_binary_sensor(const char *tag, const char *prefix, const char *type, Bi
}
void BinarySensor::publish_state(bool new_state) {
#ifdef USE_BINARY_SENSOR_FILTER
if (this->filter_list_ == nullptr) {
#endif
this->send_state_internal(new_state);
#ifdef USE_BINARY_SENSOR_FILTER
} else {
this->filter_list_->input(new_state);
}
#endif
}
void BinarySensor::publish_initial_state(bool new_state) {
this->invalidate_state();
@@ -47,6 +51,7 @@ bool BinarySensor::set_new_state(const optional<bool> &new_state) {
return false;
}
#ifdef USE_BINARY_SENSOR_FILTER
void BinarySensor::add_filter(Filter *filter) {
filter->parent_ = this;
if (this->filter_list_ == nullptr) {
@@ -63,6 +68,7 @@ void BinarySensor::add_filters(std::initializer_list<Filter *> filters) {
this->add_filter(filter);
}
}
#endif // USE_BINARY_SENSOR_FILTER
bool BinarySensor::is_status_binary_sensor() const { return false; }
} // namespace esphome::binary_sensor

View File

@@ -2,7 +2,9 @@
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
#ifdef USE_BINARY_SENSOR_FILTER
#include "esphome/components/binary_sensor/filter.h"
#endif
#include <initializer_list>
@@ -45,8 +47,10 @@ class BinarySensor : public StatefulEntityBase<bool>, public EntityBase_DeviceCl
*/
void publish_initial_state(bool new_state);
#ifdef USE_BINARY_SENSOR_FILTER
void add_filter(Filter *filter);
void add_filters(std::initializer_list<Filter *> filters);
#endif
// ========== INTERNAL METHODS ==========
// (In most use cases you won't need these)
@@ -60,7 +64,9 @@ class BinarySensor : public StatefulEntityBase<bool>, public EntityBase_DeviceCl
bool state{};
protected:
#ifdef USE_BINARY_SENSOR_FILTER
Filter *filter_list_{nullptr};
#endif
bool set_new_state(const optional<bool> &new_state) override;
};

View File

@@ -1,3 +1,6 @@
#include "esphome/core/defines.h"
#ifdef USE_BINARY_SENSOR_FILTER
#include "filter.h"
#include "binary_sensor.h"
@@ -142,3 +145,5 @@ optional<bool> SettleFilter::new_value(bool value) {
float SettleFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
} // namespace esphome::binary_sensor
#endif // USE_BINARY_SENSOR_FILTER

View File

@@ -1,5 +1,8 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_BINARY_SENSOR_FILTER
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
@@ -138,3 +141,5 @@ class SettleFilter : public Filter, public Component {
};
} // namespace esphome::binary_sensor
#endif // USE_BINARY_SENSOR_FILTER

View File

@@ -182,7 +182,10 @@ void BL0940::recalibrate_() {
ESP_LOGD(TAG,
"Recalibrated reference values:\n"
"Voltage: %f\n, Current: %f\n, Power: %f\n, Energy: %f\n",
" Voltage: %f\n"
" Current: %f\n"
" Power: %f\n"
" Energy: %f",
this->voltage_reference_cal_, this->current_reference_cal_, this->power_reference_cal_,
this->energy_reference_cal_);
}

View File

@@ -7,6 +7,7 @@
#include "esphome/core/preferences.h"
#include "esphome/core/defines.h"
#include <map>
#include <queue>
#ifdef USE_BSEC
#include <bsec.h>

View File

@@ -76,13 +76,15 @@ def _final_validate(config: ConfigType) -> ConfigType:
# Register socket needs for DNS server and additional HTTP connections
# - 1 UDP socket for DNS server
# - 3 additional TCP sockets for captive portal detection probes + configuration requests
# - 3 TCP sockets for captive portal detection probes + configuration requests
# OS captive portal detection makes multiple probe requests that stay in TIME_WAIT.
# Need headroom for actual user configuration requests.
# LRU purging will reclaim idle sockets to prevent exhaustion from repeated attempts.
# The listening socket is registered by web_server_base (shared HTTP server).
from esphome.components import socket
socket.consume_sockets(4, "captive_portal")(config)
socket.consume_sockets(3, "captive_portal")(config)
socket.consume_sockets(1, "captive_portal", socket.SocketType.UDP)(config)
return config

View File

@@ -9,6 +9,7 @@ from esphome.const import (
CONF_DATA,
CONF_FREQUENCY,
CONF_ID,
CONF_OUTPUT_POWER,
CONF_VALUE,
CONF_WAIT_TIME,
)
@@ -22,7 +23,6 @@ ns = cg.esphome_ns.namespace("cc1101")
CC1101Component = ns.class_("CC1101Component", cg.Component, spi.SPIDevice)
# Config keys
CONF_OUTPUT_POWER = "output_power"
CONF_RX_ATTENUATION = "rx_attenuation"
CONF_DC_BLOCKING_FILTER = "dc_blocking_filter"
CONF_IF_FREQUENCY = "if_frequency"

View File

@@ -124,9 +124,11 @@ bool CH422GComponent::write_outputs_() {
float CH422GComponent::get_setup_priority() const { return setup_priority::IO; }
#ifdef USE_LOOP_PRIORITY
// Run our loop() method very early in the loop, so that we cache read values
// before other components call our digital_read() method.
float CH422GComponent::get_loop_priority() const { return 9.0f; } // Just after WIFI
#endif
void CH422GGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) ^ this->inverted_; }

View File

@@ -23,7 +23,9 @@ class CH422GComponent : public Component, public i2c::I2CDevice {
void pin_mode(uint8_t pin, gpio::Flags flags);
float get_setup_priority() const override;
#ifdef USE_LOOP_PRIORITY
float get_loop_priority() const override;
#endif
void dump_config() override;
protected:

View File

@@ -129,9 +129,11 @@ bool CH423Component::write_outputs_() {
float CH423Component::get_setup_priority() const { return setup_priority::IO; }
#ifdef USE_LOOP_PRIORITY
// Run our loop() method very early in the loop, so that we cache read values
// before other components call our digital_read() method.
float CH423Component::get_loop_priority() const { return 9.0f; } // Just after WIFI
#endif
void CH423GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
bool CH423GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) ^ this->inverted_; }

View File

@@ -22,7 +22,9 @@ class CH423Component : public Component, public i2c::I2CDevice {
void pin_mode(uint8_t pin, gpio::Flags flags);
float get_setup_priority() const override;
#ifdef USE_LOOP_PRIORITY
float get_loop_priority() const override;
#endif
void dump_config() override;
protected:

View File

@@ -148,14 +148,14 @@ void CurrentBasedCover::dump_config() {
}
ESP_LOGCONFIG(TAG,
" Close Duration: %.1fs\n"
"Obstacle Rollback: %.1f%%",
" Obstacle Rollback: %.1f%%",
this->close_duration_ / 1e3f, this->obstacle_rollback_ * 100);
if (this->max_duration_ != UINT32_MAX) {
ESP_LOGCONFIG(TAG, "Maximum duration: %.1fs", this->max_duration_ / 1e3f);
ESP_LOGCONFIG(TAG, " Maximum duration: %.1fs", this->max_duration_ / 1e3f);
}
ESP_LOGCONFIG(TAG,
"Start sensing delay: %.1fs\n"
"Malfunction detection: %s",
" Start sensing delay: %.1fs\n"
" Malfunction detection: %s",
this->start_sensing_delay_ / 1e3f, YESNO(this->malfunction_detection_));
}

View File

@@ -79,7 +79,6 @@ const char *DebugComponent::get_reset_reason_(std::span<char, RESET_REASON_BUFFE
} else {
snprintf(buf, size, "unknown source");
}
ESP_LOGD(TAG, "Reset Reason: %s", buf);
return buf;
}
@@ -107,7 +106,6 @@ const char *DebugComponent::get_wakeup_cause_(std::span<char, RESET_REASON_BUFFE
} else {
wake_reason = "unknown source";
}
ESP_LOGD(TAG, "Wakeup Reason: %s", wake_reason);
// Return the static string directly - no need to copy to buffer
return wake_reason;
}
@@ -172,7 +170,6 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
}
uint32_t flash_size = ESP.getFlashChipSize() / 1024; // NOLINT
uint32_t flash_speed = ESP.getFlashChipSpeed() / 1000000; // NOLINT
ESP_LOGD(TAG, "Flash Chip: Size=%" PRIu32 "kB Speed=%" PRIu32 "MHz Mode=%s", flash_size, flash_speed, flash_mode);
pos = buf_append_printf(buf, size, pos, "|Flash: %" PRIu32 "kB Speed:%" PRIu32 "MHz Mode:%s", flash_size, flash_speed,
flash_mode);
#endif
@@ -194,39 +191,46 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
if (info.features != 0) {
pos = buf_append_printf(buf, size, pos, "%sOther:0x%" PRIx32, first_feature ? "" : ", ", info.features);
}
ESP_LOGD(TAG, "Chip: Model=%s, Cores=%u, Revision=%u", model, info.cores, info.revision);
pos = buf_append_printf(buf, size, pos, " Cores:%u Revision:%u", info.cores, info.revision);
uint32_t cpu_freq_mhz = arch_get_cpu_freq_hz() / 1000000;
ESP_LOGD(TAG, "CPU Frequency: %" PRIu32 " MHz", cpu_freq_mhz);
pos = buf_append_printf(buf, size, pos, "|CPU Frequency: %" PRIu32 " MHz", cpu_freq_mhz);
// Framework detection
#ifdef USE_ARDUINO
ESP_LOGD(TAG, "Framework: Arduino");
pos = buf_append_printf(buf, size, pos, "|Framework: Arduino");
#elif defined(USE_ESP32)
ESP_LOGD(TAG, "Framework: ESP-IDF");
pos = buf_append_printf(buf, size, pos, "|Framework: ESP-IDF");
#else
ESP_LOGW(TAG, "Framework: UNKNOWN");
pos = buf_append_printf(buf, size, pos, "|Framework: UNKNOWN");
#endif
ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
pos = buf_append_printf(buf, size, pos, "|ESP-IDF: %s", esp_get_idf_version());
uint8_t mac[6];
get_mac_address_raw(mac);
ESP_LOGD(TAG, "EFuse MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
pos = buf_append_printf(buf, size, pos, "|EFuse MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3],
mac[4], mac[5]);
char reason_buffer[RESET_REASON_BUFFER_SIZE];
const char *reset_reason = get_reset_reason_(std::span<char, RESET_REASON_BUFFER_SIZE>(reason_buffer));
pos = buf_append_printf(buf, size, pos, "|Reset: %s", reset_reason);
const char *wakeup_cause = get_wakeup_cause_(std::span<char, RESET_REASON_BUFFER_SIZE>(reason_buffer));
uint8_t mac[6];
get_mac_address_raw(mac);
ESP_LOGD(TAG,
"ESP32 debug info:\n"
" Chip: %s\n"
" Cores: %u\n"
" Revision: %u\n"
" CPU Frequency: %" PRIu32 " MHz\n"
" ESP-IDF Version: %s\n"
" EFuse MAC: %02X:%02X:%02X:%02X:%02X:%02X\n"
" Reset Reason: %s\n"
" Wakeup Cause: %s",
model, info.cores, info.revision, cpu_freq_mhz, esp_get_idf_version(), mac[0], mac[1], mac[2], mac[3],
mac[4], mac[5], reset_reason, wakeup_cause);
#if defined(USE_ARDUINO)
ESP_LOGD(TAG, " Flash: Size=%" PRIu32 "kB Speed=%" PRIu32 "MHz Mode=%s", flash_size, flash_speed, flash_mode);
#endif
// Framework detection
#ifdef USE_ARDUINO
ESP_LOGD(TAG, " Framework: Arduino");
pos = buf_append_printf(buf, size, pos, "|Framework: Arduino");
#else
ESP_LOGD(TAG, " Framework: ESP-IDF");
pos = buf_append_printf(buf, size, pos, "|Framework: ESP-IDF");
#endif
pos = buf_append_printf(buf, size, pos, "|ESP-IDF: %s", esp_get_idf_version());
pos = buf_append_printf(buf, size, pos, "|EFuse MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3],
mac[4], mac[5]);
pos = buf_append_printf(buf, size, pos, "|Reset: %s", reset_reason);
pos = buf_append_printf(buf, size, pos, "|Wakeup: %s", wakeup_cause);
return pos;

View File

@@ -128,14 +128,16 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
// NOLINTEND(readability-static-accessed-through-instance)
ESP_LOGD(TAG,
"Chip ID: 0x%08" PRIX32 "\n"
"SDK Version: %s\n"
"Core Version: %s\n"
"Boot Version=%u Mode=%u\n"
"CPU Frequency: %u\n"
"Flash Chip ID=0x%08" PRIX32 "\n"
"Reset Reason: %s\n"
"Reset Info: %s",
"ESP8266 debug info:\n"
" Chip ID: 0x%08" PRIX32 "\n"
" SDK Version: %s\n"
" Core Version: %s\n"
" Boot Version: %u\n"
" Boot Mode: %u\n"
" CPU Frequency: %u\n"
" Flash Chip ID: 0x%08" PRIX32 "\n"
" Reset Reason: %s\n"
" Reset Info: %s",
chip_id, sdk_version, get_core_version_str(core_version_buffer), boot_version, boot_mode, cpu_freq,
flash_chip_id, reset_reason, get_reset_info_str(reset_info_buffer, resetInfo.reason));

View File

@@ -27,12 +27,14 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
uint32_t mac_id = lt_cpu_get_mac_id();
ESP_LOGD(TAG,
"LibreTiny Version: %s\n"
"Chip: %s (%04x) @ %u MHz\n"
"Chip ID: 0x%06" PRIX32 "\n"
"Board: %s\n"
"Flash: %" PRIu32 " KiB / RAM: %" PRIu32 " KiB\n"
"Reset Reason: %s",
"LibreTiny debug info:\n"
" Version: %s\n"
" Chip: %s (%04x) @ %u MHz\n"
" Chip ID: 0x%06" PRIX32 "\n"
" Board: %s\n"
" Flash: %" PRIu32 " KiB\n"
" RAM: %" PRIu32 " KiB\n"
" Reset Reason: %s",
lt_get_version(), lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz(), mac_id,
lt_get_board_code(), flash_kib, ram_kib, reset_reason);

View File

@@ -79,13 +79,13 @@ static void fa_cb(const struct flash_area *fa, void *user_data) {
void DebugComponent::log_partition_info_() {
#if CONFIG_FLASH_MAP_LABELS
ESP_LOGCONFIG(TAG, "ID | Device | Device Name "
"| Label | Offset | Size\n"
"--------------------------------------------"
"| Label | Offset | Size");
ESP_LOGCONFIG(TAG, "--------------------------------------------"
"-----------------------------------------------");
#else
ESP_LOGCONFIG(TAG, "ID | Device | Device Name "
"| Offset | Size\n"
"-----------------------------------------"
"| Offset | Size");
ESP_LOGCONFIG(TAG, "-----------------------------------------"
"------------------------------");
#endif
flash_area_foreach(fa_cb, nullptr);
@@ -284,11 +284,12 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
char mac_pretty[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
get_mac_address_pretty_into_buffer(mac_pretty);
ESP_LOGD(TAG,
"Code page size: %u, code size: %u, device id: 0x%08x%08x\n"
"Encryption root: 0x%08x%08x%08x%08x, Identity Root: 0x%08x%08x%08x%08x\n"
"Device address type: %s, address: %s\n"
"Part code: nRF%x, version: %c%c%c%c, package: %s\n"
"RAM: %ukB, Flash: %ukB, production test: %sdone",
"nRF debug info:\n"
" Code page size: %u, code size: %u, device id: 0x%08x%08x\n"
" Encryption root: 0x%08x%08x%08x%08x, Identity Root: 0x%08x%08x%08x%08x\n"
" Device address type: %s, address: %s\n"
" Part code: nRF%x, version: %c%c%c%c, package: %s\n"
" RAM: %ukB, Flash: %ukB, production test: %sdone",
NRF_FICR->CODEPAGESIZE, NRF_FICR->CODESIZE, NRF_FICR->DEVICEID[1], NRF_FICR->DEVICEID[0], NRF_FICR->ER[0],
NRF_FICR->ER[1], NRF_FICR->ER[2], NRF_FICR->ER[3], NRF_FICR->IR[0], NRF_FICR->IR[1], NRF_FICR->IR[2],
NRF_FICR->IR[3], (NRF_FICR->DEVICEADDRTYPE & 0x1 ? "Random" : "Public"), mac_pretty, NRF_FICR->INFO.PART,
@@ -299,23 +300,22 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
(NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) == UICR_PSELRESET_CONNECT_Connected
<< UICR_PSELRESET_CONNECT_Pos;
ESP_LOGD(
TAG, "GPIO as NFC pins: %s, GPIO as nRESET pin: %s",
TAG, " GPIO as NFC pins: %s, GPIO as nRESET pin: %s",
YESNO((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)),
YESNO(n_reset_enabled));
if (n_reset_enabled) {
uint8_t port = (NRF_UICR->PSELRESET[0] & UICR_PSELRESET_PORT_Msk) >> UICR_PSELRESET_PORT_Pos;
uint8_t pin = (NRF_UICR->PSELRESET[0] & UICR_PSELRESET_PIN_Msk) >> UICR_PSELRESET_PIN_Pos;
ESP_LOGD(TAG, "nRESET port P%u.%02u", port, pin);
ESP_LOGD(TAG, " nRESET port P%u.%02u", port, pin);
}
#ifdef USE_BOOTLOADER_MCUBOOT
ESP_LOGD(TAG, "bootloader: mcuboot");
ESP_LOGD(TAG, " Bootloader: mcuboot");
#else
ESP_LOGD(TAG, "bootloader: Adafruit, version %u.%u.%u", (BOOTLOADER_VERSION_REGISTER >> 16) & 0xFF,
ESP_LOGD(TAG, " Bootloader: Adafruit, version %u.%u.%u", (BOOTLOADER_VERSION_REGISTER >> 16) & 0xFF,
(BOOTLOADER_VERSION_REGISTER >> 8) & 0xFF, BOOTLOADER_VERSION_REGISTER & 0xFF);
ESP_LOGD(TAG,
"MBR bootloader addr 0x%08x, UICR bootloader addr 0x%08x\n"
"MBR param page addr 0x%08x, UICR param page addr 0x%08x",
read_mem_u32(MBR_BOOTLOADER_ADDR), NRF_UICR->NRFFW[0], read_mem_u32(MBR_PARAM_PAGE_ADDR),
ESP_LOGD(TAG, " MBR bootloader addr 0x%08x, UICR bootloader addr 0x%08x", read_mem_u32(MBR_BOOTLOADER_ADDR),
NRF_UICR->NRFFW[0]);
ESP_LOGD(TAG, " MBR param page addr 0x%08x, UICR param page addr 0x%08x", read_mem_u32(MBR_PARAM_PAGE_ADDR),
NRF_UICR->NRFFW[1]);
if (is_sd_present()) {
uint32_t const sd_id = sd_id_get();
@@ -326,7 +326,7 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
ver[1] = (sd_version - ver[0] * 1000000) / 1000;
ver[2] = (sd_version - ver[0] * 1000000 - ver[1] * 1000);
ESP_LOGD(TAG, "SoftDevice: S%u %u.%u.%u", sd_id, ver[0], ver[1], ver[2]);
ESP_LOGD(TAG, " SoftDevice: S%u %u.%u.%u", sd_id, ver[0], ver[1], ver[2]);
#ifdef USE_SOFTDEVICE_ID
#ifdef USE_SOFTDEVICE_VERSION
if (USE_SOFTDEVICE_ID != sd_id || USE_SOFTDEVICE_VERSION != ver[0]) {
@@ -352,10 +352,8 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
}
return res;
};
ESP_LOGD(TAG,
"NRFFW %s\n"
"NRFHW %s",
uicr(NRF_UICR->NRFFW, 13).c_str(), uicr(NRF_UICR->NRFHW, 12).c_str());
ESP_LOGD(TAG, " NRFFW %s", uicr(NRF_UICR->NRFFW, 13).c_str());
ESP_LOGD(TAG, " NRFHW %s", uicr(NRF_UICR->NRFHW, 12).c_str());
return pos;
}

View File

@@ -40,9 +40,11 @@ void DeepSleepComponent::loop() {
this->begin_sleep();
}
#ifdef USE_LOOP_PRIORITY
float DeepSleepComponent::get_loop_priority() const {
return -100.0f; // run after everything else is ready
}
#endif
void DeepSleepComponent::set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; }

View File

@@ -113,7 +113,9 @@ class DeepSleepComponent : public Component {
void setup() override;
void dump_config() override;
void loop() override;
#ifdef USE_LOOP_PRIORITY
float get_loop_priority() const override;
#endif
float get_setup_priority() const override;
/// Helper to enter deep sleep mode

View File

@@ -187,18 +187,18 @@ uint8_t DetRangeCfgCommand::on_message(std::string &message) {
} else if (message == "Done") {
ESP_LOGI(TAG,
"Updated detection area config:\n"
"Detection area 1 from %.02fm to %.02fm.",
" Detection area 1 from %.02fm to %.02fm.",
this->min1_, this->max1_);
if (this->min2_ >= 0 && this->max2_ >= 0) {
ESP_LOGI(TAG, "Detection area 2 from %.02fm to %.02fm.", this->min2_, this->max2_);
ESP_LOGI(TAG, " Detection area 2 from %.02fm to %.02fm.", this->min2_, this->max2_);
}
if (this->min3_ >= 0 && this->max3_ >= 0) {
ESP_LOGI(TAG, "Detection area 3 from %.02fm to %.02fm.", this->min3_, this->max3_);
ESP_LOGI(TAG, " Detection area 3 from %.02fm to %.02fm.", this->min3_, this->max3_);
}
if (this->min4_ >= 0 && this->max4_ >= 0) {
ESP_LOGI(TAG, "Detection area 4 from %.02fm to %.02fm.", this->min4_, this->max4_);
ESP_LOGI(TAG, " Detection area 4 from %.02fm to %.02fm.", this->min4_, this->max4_);
}
ESP_LOGD(TAG, "Used command: %s", this->cmd_.c_str());
ESP_LOGD(TAG, " Used command: %s", this->cmd_.c_str());
return 1; // Command done
}
return 0; // Command not done yet.
@@ -222,10 +222,10 @@ uint8_t SetLatencyCommand::on_message(std::string &message) {
} else if (message == "Done") {
ESP_LOGI(TAG,
"Updated output latency config:\n"
"Signal that someone was detected is delayed by %.03f s.\n"
"Signal that nobody is detected anymore is delayed by %.03f s.",
" Signal that someone was detected is delayed by %.03f s.\n"
" Signal that nobody is detected anymore is delayed by %.03f s.",
this->delay_after_detection_, this->delay_after_disappear_);
ESP_LOGD(TAG, "Used command: %s", this->cmd_.c_str());
ESP_LOGD(TAG, " Used command: %s", this->cmd_.c_str());
return 1; // Command done
}
return 0; // Command not done yet

View File

@@ -153,10 +153,7 @@ void EmmetiClimate::reverse_add_(T val, size_t len, esphome::remote_base::Remote
bool EmmetiClimate::check_checksum_(uint8_t checksum) {
uint8_t expected = this->gen_checksum_();
ESP_LOGV(TAG,
"Expected checksum: %X\n"
"Checksum received: %X",
expected, checksum);
ESP_LOGV(TAG, "Expected checksum: %X, Checksum received: %X", expected, checksum);
return checksum == expected;
}
@@ -266,10 +263,7 @@ bool EmmetiClimate::on_receive(remote_base::RemoteReceiveData data) {
}
}
ESP_LOGD(TAG,
"Swing: %d\n"
"Sleep: %d",
(curr_state.bitmap >> 1) & 0x01, (curr_state.bitmap >> 2) & 0x01);
ESP_LOGD(TAG, "Swing: %d, Sleep: %d", (curr_state.bitmap >> 1) & 0x01, (curr_state.bitmap >> 2) & 0x01);
for (size_t pos = 0; pos < 4; pos++) {
if (data.expect_item(EMMETI_BIT_MARK, EMMETI_ONE_SPACE)) {
@@ -295,13 +289,8 @@ bool EmmetiClimate::on_receive(remote_base::RemoteReceiveData data) {
}
}
ESP_LOGD(TAG,
"Turbo: %d\n"
"Light: %d\n"
"Tree: %d\n"
"Blow: %d",
(curr_state.bitmap >> 3) & 0x01, (curr_state.bitmap >> 4) & 0x01, (curr_state.bitmap >> 5) & 0x01,
(curr_state.bitmap >> 6) & 0x01);
ESP_LOGD(TAG, "Turbo: %d, Light: %d, Tree: %d, Blow: %d", (curr_state.bitmap >> 3) & 0x01,
(curr_state.bitmap >> 4) & 0x01, (curr_state.bitmap >> 5) & 0x01, (curr_state.bitmap >> 6) & 0x01);
uint16_t control_data = 0;
for (size_t pos = 0; pos < 11; pos++) {

View File

@@ -152,12 +152,13 @@ void ENS160Component::update() {
// verbose status logging
ESP_LOGV(TAG,
"Status: ENS160 STATAS bit 0x%x\n"
"Status: ENS160 STATER bit 0x%x\n"
"Status: ENS160 VALIDITY FLAG 0x%02x\n"
"Status: ENS160 NEWDAT bit 0x%x\n"
"Status: ENS160 NEWGPR bit 0x%x",
(ENS160_DATA_STATUS_STATAS & (status_value)) == ENS160_DATA_STATUS_STATAS,
"ENS160 Status Register: 0x%02x\n"
" STATAS bit 0x%x\n"
" STATER bit 0x%x\n"
" VALIDITY FLAG 0x%02x\n"
" NEWDAT bit 0x%x\n"
" NEWGPR bit 0x%x",
status_value, (ENS160_DATA_STATUS_STATAS & (status_value)) == ENS160_DATA_STATUS_STATAS,
(ENS160_DATA_STATUS_STATER & (status_value)) == ENS160_DATA_STATUS_STATER,
(ENS160_DATA_STATUS_VALIDITY & status_value) >> 2,
(ENS160_DATA_STATUS_NEWDAT & (status_value)) == ENS160_DATA_STATUS_NEWDAT,

View File

@@ -209,9 +209,10 @@ bool ES8388::set_dac_output(DacOutputLine line) {
};
ESP_LOGV(TAG,
"Setting ES8388_DACPOWER to 0x%02X\n"
"Setting ES8388_DACCONTROL24 / ES8388_DACCONTROL25 to 0x%02X\n"
"Setting ES8388_DACCONTROL26 / ES8388_DACCONTROL27 to 0x%02X",
"DAC output config:\n"
" DACPOWER: 0x%02X\n"
" DACCONTROL24/25: 0x%02X\n"
" DACCONTROL26/27: 0x%02X",
dac_power, reg_out1, reg_out2);
ES8388_ERROR_CHECK(this->write_byte(ES8388_DACCONTROL24, reg_out1)); // LOUT1VOL

View File

@@ -1258,21 +1258,15 @@ def _configure_lwip_max_sockets(conf: dict) -> None:
This function runs in to_code() after all components have registered their socket needs.
User-provided sdkconfig_options take precedence.
"""
from esphome.components.socket import KEY_SOCKET_CONSUMERS
from esphome.components.socket import get_socket_counts
# Check if user manually specified CONFIG_LWIP_MAX_SOCKETS
user_max_sockets = conf[CONF_SDKCONFIG_OPTIONS].get("CONFIG_LWIP_MAX_SOCKETS")
socket_consumers: dict[str, int] = CORE.data.get(KEY_SOCKET_CONSUMERS, {})
total_sockets = sum(socket_consumers.values())
# Early return if no sockets registered and no user override
if total_sockets == 0 and user_max_sockets is None:
return
components_list = ", ".join(
f"{name}={count}" for name, count in sorted(socket_consumers.items())
)
# CONFIG_LWIP_MAX_SOCKETS is a single VFS socket pool shared by all socket
# types (TCP clients, TCP listeners, and UDP). Include all three counts.
sc = get_socket_counts()
total_sockets = sc.tcp + sc.udp + sc.tcp_listen
# User specified their own value - respect it but warn if insufficient
if user_max_sockets is not None:
@@ -1281,22 +1275,23 @@ def _configure_lwip_max_sockets(conf: dict) -> None:
user_max_sockets,
)
# Warn if user's value is less than what components need
if total_sockets > 0:
user_sockets_int = 0
with contextlib.suppress(ValueError, TypeError):
user_sockets_int = int(user_max_sockets)
user_sockets_int = 0
with contextlib.suppress(ValueError, TypeError):
user_sockets_int = int(user_max_sockets)
if user_sockets_int < total_sockets:
_LOGGER.warning(
"CONFIG_LWIP_MAX_SOCKETS is set to %d but your configuration "
"needs %d sockets (registered: %s). You may experience socket "
"exhaustion errors. Consider increasing to at least %d.",
user_sockets_int,
total_sockets,
components_list,
total_sockets,
)
if user_sockets_int < total_sockets:
_LOGGER.warning(
"CONFIG_LWIP_MAX_SOCKETS is set to %d but your configuration "
"needs %d sockets (%d TCP + %d UDP + %d TCP_LISTEN). You may "
"experience socket exhaustion errors. Consider increasing to "
"at least %d.",
user_sockets_int,
total_sockets,
sc.tcp,
sc.udp,
sc.tcp_listen,
total_sockets,
)
# User's value already added via sdkconfig_options processing
return
@@ -1305,11 +1300,19 @@ def _configure_lwip_max_sockets(conf: dict) -> None:
max_sockets = max(DEFAULT_MAX_SOCKETS, total_sockets)
log_level = logging.INFO if max_sockets > DEFAULT_MAX_SOCKETS else logging.DEBUG
sock_min = " (min)" if max_sockets > total_sockets else ""
_LOGGER.log(
log_level,
"Setting CONFIG_LWIP_MAX_SOCKETS to %d (registered: %s)",
"Setting CONFIG_LWIP_MAX_SOCKETS to %d%s "
"(TCP=%d [%s], UDP=%d [%s], TCP_LISTEN=%d [%s])",
max_sockets,
components_list,
sock_min,
sc.tcp,
sc.tcp_details,
sc.udp,
sc.udp_details,
sc.tcp_listen,
sc.tcp_listen_details,
)
add_idf_sdkconfig_option("CONFIG_LWIP_MAX_SOCKETS", max_sockets)

View File

@@ -423,10 +423,8 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
for (auto &svc : this->services_) {
char uuid_buf[espbt::UUID_STR_LEN];
svc->uuid.to_str(uuid_buf);
ESP_LOGV(TAG,
"[%d] [%s] Service UUID: %s\n"
"[%d] [%s] start_handle: 0x%x end_handle: 0x%x",
this->connection_index_, this->address_str_, uuid_buf, this->connection_index_, this->address_str_,
ESP_LOGV(TAG, "[%d] [%s] Service UUID: %s", this->connection_index_, this->address_str_, uuid_buf);
ESP_LOGV(TAG, "[%d] [%s] start_handle: 0x%x end_handle: 0x%x", this->connection_index_, this->address_str_,
svc->start_handle, svc->end_handle);
}
#endif

View File

@@ -20,8 +20,10 @@ def _consume_camera_web_server_sockets(config: ConfigType) -> ConfigType:
from esphome.components import socket
# Each camera web server instance needs 1 listening socket + 2 client connections
sockets_needed = 3
socket.consume_sockets(sockets_needed, "esp32_camera_web_server")(config)
socket.consume_sockets(2, "esp32_camera_web_server")(config)
socket.consume_sockets(1, "esp32_camera_web_server", socket.SocketType.TCP_LISTEN)(
config
)
return config

View File

@@ -106,11 +106,12 @@ void Esp32HostedUpdate::setup() {
esp_app_desc_t *app_desc = (esp_app_desc_t *) (this->firmware_data_ + app_desc_offset);
if (app_desc->magic_word == ESP_APP_DESC_MAGIC_WORD) {
ESP_LOGD(TAG,
"Firmware version: %s\n"
"Project name: %s\n"
"Build date: %s\n"
"Build time: %s\n"
"IDF version: %s",
"ESP32 Hosted firmware:\n"
" Firmware version: %s\n"
" Project name: %s\n"
" Build date: %s\n"
" Build time: %s\n"
" IDF version: %s",
app_desc->version, app_desc->project_name, app_desc->date, app_desc->time, app_desc->idf_ver);
this->update_info_.latest_version = app_desc->version;
if (this->update_info_.latest_version != this->update_info_.current_version) {

View File

@@ -97,8 +97,9 @@ def _consume_ota_sockets(config: ConfigType) -> ConfigType:
"""Register socket needs for OTA component."""
from esphome.components import socket
# OTA needs 1 listening socket (client connections are temporary during updates)
socket.consume_sockets(1, "ota")(config)
# OTA needs 1 listening socket. The active transfer connection during an update
# uses a TCP PCB from the general pool, covered by MIN_TCP_SOCKETS headroom.
socket.consume_sockets(1, "ota", socket.SocketType.TCP_LISTEN)(config)
return config

View File

@@ -21,11 +21,9 @@ void ESPNowTransport::setup() {
return;
}
ESP_LOGI(TAG,
"Registering ESP-NOW handlers\n"
"Peer address: %02X:%02X:%02X:%02X:%02X:%02X",
this->peer_address_[0], this->peer_address_[1], this->peer_address_[2], this->peer_address_[3],
this->peer_address_[4], this->peer_address_[5]);
ESP_LOGI(TAG, "Registering ESP-NOW handlers, peer: %02X:%02X:%02X:%02X:%02X:%02X", this->peer_address_[0],
this->peer_address_[1], this->peer_address_[2], this->peer_address_[3], this->peer_address_[4],
this->peer_address_[5]);
// Register received handler
this->parent_->register_received_handler(this);

View File

@@ -866,10 +866,7 @@ void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister regi
}
#endif
ESP_LOGD(TAG,
"Writing to PHY Register Address: 0x%02" PRIX32 "\n"
"Writing to PHY Register Value: 0x%04" PRIX32,
register_data.address, register_data.value);
ESP_LOGD(TAG, "Writing PHY reg 0x%02" PRIX32 " = 0x%04" PRIX32, register_data.address, register_data.value);
err = mac->write_phy_reg(mac, this->phy_addr_, register_data.address, register_data.value);
ESPHL_ERROR_CHECK(err, "Writing PHY Register failed");

View File

@@ -150,9 +150,9 @@ void EzoPMP::read_command_result_() {
if (current_char == '\0') {
ESP_LOGV(TAG,
"Read Response from device: %s\n"
"First Component: %s\n"
"Second Component: %s\n"
"Third Component: %s",
" First Component: %s\n"
" Second Component: %s\n"
" Third Component: %s",
(char *) response_buffer, (char *) first_parameter_buffer, (char *) second_parameter_buffer,
(char *) third_parameter_buffer);

View File

@@ -97,10 +97,10 @@ void GCJA5Component::parse_data_() {
ESP_LOGI(TAG,
"GCJA5 Status\n"
"Overall Status : %i\n"
"PD Status : %i\n"
"LD Status : %i\n"
"Fan Status : %i",
" Overall Status : %i\n"
" PD Status : %i\n"
" LD Status : %i\n"
" Fan Status : %i",
(status >> 6) & 0x03, (status >> 4) & 0x03, (status >> 2) & 0x03, (status >> 0) & 0x03);
}
}

View File

@@ -38,13 +38,13 @@ void GraphicalDisplayMenu::setup() {
void GraphicalDisplayMenu::dump_config() {
ESP_LOGCONFIG(TAG,
"Graphical Display Menu\n"
"Has Display: %s\n"
"Popup Mode: %s\n"
"Advanced Drawing Mode: %s\n"
"Has Font: %s\n"
"Mode: %s\n"
"Active: %s\n"
"Menu items:",
" Has Display: %s\n"
" Popup Mode: %s\n"
" Advanced Drawing Mode: %s\n"
" Has Font: %s\n"
" Mode: %s\n"
" Active: %s\n"
" Menu items:",
YESNO(this->display_ != nullptr), YESNO(this->display_ != nullptr), YESNO(this->display_ == nullptr),
YESNO(this->font_ != nullptr),
this->mode_ == display_menu_base::MENU_MODE_ROTARY ? "Rotary" : "Joystick", YESNO(this->active_));

View File

@@ -1,6 +1,7 @@
#pragma once
#include <chrono>
#include <queue>
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif

View File

@@ -0,0 +1 @@
CODEOWNERS = ["@joshuasing"]

View File

@@ -0,0 +1,171 @@
#include "hdc302x.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::hdc302x {
static const char *const TAG = "hdc302x.sensor";
// Commands (per datasheet Table 7-4)
static const uint8_t HDC302X_CMD_SOFT_RESET[2] = {0x30, 0xa2};
static const uint8_t HDC302X_CMD_CLEAR_STATUS_REGISTER[2] = {0x30, 0x41};
static const uint8_t HDC302X_CMD_TRIGGER_MSB = 0x24;
static const uint8_t HDC302X_CMD_HEATER_ENABLE[2] = {0x30, 0x6d};
static const uint8_t HDC302X_CMD_HEATER_DISABLE[2] = {0x30, 0x66};
static const uint8_t HDC302X_CMD_HEATER_CONFIGURE[2] = {0x30, 0x6e};
void HDC302XComponent::setup() {
// Soft reset the device
if (this->write(HDC302X_CMD_SOFT_RESET, 2) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR("Soft reset failed"));
return;
}
// Delay SensorRR (reset ready), per datasheet, 6.5.
delay(3);
// Clear status register
if (this->write(HDC302X_CMD_CLEAR_STATUS_REGISTER, 2) != i2c::ERROR_OK) {
this->mark_failed(LOG_STR("Clear status failed"));
return;
}
}
void HDC302XComponent::dump_config() {
ESP_LOGCONFIG(TAG,
"HDC302x:\n"
" Heater: %s",
this->heater_active_ ? "active" : "inactive");
LOG_I2C_DEVICE(this);
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Temperature", this->temp_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
void HDC302XComponent::update() {
uint8_t cmd[] = {
HDC302X_CMD_TRIGGER_MSB,
this->power_mode_,
};
if (this->write(cmd, 2) != i2c::ERROR_OK) {
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
// Read data after ADC conversion has completed
this->set_timeout(this->conversion_delay_ms_(), [this]() { this->read_data_(); });
}
void HDC302XComponent::start_heater(uint16_t power, uint32_t duration_ms) {
if (!this->disable_heater_()) {
ESP_LOGD(TAG, "Heater disable before start failed");
}
if (!this->configure_heater_(power) || !this->enable_heater_()) {
ESP_LOGW(TAG, "Heater start failed");
return;
}
this->heater_active_ = true;
this->cancel_timeout("heater_off");
if (duration_ms > 0) {
this->set_timeout("heater_off", duration_ms, [this]() { this->stop_heater(); });
}
}
void HDC302XComponent::stop_heater() {
this->cancel_timeout("heater_off");
if (!this->disable_heater_()) {
ESP_LOGW(TAG, "Heater stop failed");
}
this->heater_active_ = false;
}
bool HDC302XComponent::enable_heater_() {
if (this->write(HDC302X_CMD_HEATER_ENABLE, 2) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Enable heater failed");
return false;
}
return true;
}
bool HDC302XComponent::configure_heater_(uint16_t power_level) {
if (power_level > 0x3fff) {
ESP_LOGW(TAG, "Heater power 0x%04x exceeds max 0x3fff", power_level);
return false;
}
// Heater current level config.
uint8_t config[] = {
static_cast<uint8_t>((power_level >> 8) & 0xff), // MSB
static_cast<uint8_t>(power_level & 0xff) // LSB
};
// Configure level of heater current (per datasheet 7.5.7.8).
uint8_t cmd[] = {
HDC302X_CMD_HEATER_CONFIGURE[0], HDC302X_CMD_HEATER_CONFIGURE[1], config[0], config[1],
crc8(config, 2, 0xff, 0x31, true),
};
if (this->write(cmd, sizeof(cmd)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Configure heater failed");
return false;
}
return true;
}
bool HDC302XComponent::disable_heater_() {
if (this->write(HDC302X_CMD_HEATER_DISABLE, 2) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Disable heater failed");
return false;
}
return true;
}
void HDC302XComponent::read_data_() {
uint8_t buf[6];
if (this->read(buf, 6) != i2c::ERROR_OK) {
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
// Check checksums
if (crc8(buf, 2, 0xff, 0x31, true) != buf[2] || crc8(buf + 3, 2, 0xff, 0x31, true) != buf[5]) {
this->status_set_warning(LOG_STR("Read data: invalid CRC"));
return;
}
this->status_clear_warning();
if (this->temp_sensor_ != nullptr) {
uint16_t raw_t = encode_uint16(buf[0], buf[1]);
// Calculate temperature in Celsius per datasheet section 7.3.3.
float temp = -45 + 175 * (float(raw_t) / 65535.0f);
this->temp_sensor_->publish_state(temp);
}
if (this->humidity_sensor_ != nullptr) {
uint16_t raw_rh = encode_uint16(buf[3], buf[4]);
// Calculate RH% per datasheet section 7.3.3.
float humidity = 100 * (float(raw_rh) / 65535.0f);
this->humidity_sensor_->publish_state(humidity);
}
}
uint32_t HDC302XComponent::conversion_delay_ms_() {
// ADC conversion delay per datasheet, Table 7-5. - Trigger on Demand
switch (this->power_mode_) {
case HDC302XPowerMode::BALANCED:
return 8;
case HDC302XPowerMode::LOW_POWER:
return 5;
case HDC302XPowerMode::ULTRA_LOW_POWER:
return 4;
case HDC302XPowerMode::HIGH_ACCURACY:
default:
return 13;
}
}
} // namespace esphome::hdc302x

View File

@@ -0,0 +1,68 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome::hdc302x {
enum HDC302XPowerMode : uint8_t {
HIGH_ACCURACY = 0x00,
BALANCED = 0x0b,
LOW_POWER = 0x16,
ULTRA_LOW_POWER = 0xff,
};
/**
HDC302x Temperature and humidity sensor.
Datasheet:
https://www.ti.com/lit/ds/symlink/hdc3020.pdf
*/
class HDC302XComponent : public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
void update() override;
void start_heater(uint16_t power, uint32_t duration_ms);
void stop_heater();
void set_temp_sensor(sensor::Sensor *temp_sensor) { this->temp_sensor_ = temp_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
void set_power_mode(HDC302XPowerMode power_mode) { this->power_mode_ = power_mode; }
protected:
sensor::Sensor *temp_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
HDC302XPowerMode power_mode_{HDC302XPowerMode::HIGH_ACCURACY};
bool heater_active_{false};
bool enable_heater_();
bool configure_heater_(uint16_t power_level);
bool disable_heater_();
void read_data_();
uint32_t conversion_delay_ms_();
};
template<typename... Ts> class HeaterOnAction : public Action<Ts...>, public Parented<HDC302XComponent> {
public:
TEMPLATABLE_VALUE(uint16_t, power)
TEMPLATABLE_VALUE(uint32_t, duration)
void play(const Ts &...x) override {
auto power_val = this->power_.value(x...);
auto duration_val = this->duration_.value(x...);
this->parent_->start_heater(power_val, duration_val);
}
};
template<typename... Ts> class HeaterOffAction : public Action<Ts...>, public Parented<HDC302XComponent> {
public:
void play(const Ts &...x) override { this->parent_->stop_heater(); }
};
} // namespace esphome::hdc302x

View File

@@ -0,0 +1,135 @@
from esphome import automation
from esphome.automation import maybe_simple_id
import esphome.codegen as cg
from esphome.components import i2c, sensor
import esphome.config_validation as cv
from esphome.const import (
CONF_DURATION,
CONF_HUMIDITY,
CONF_ID,
CONF_POWER,
CONF_POWER_MODE,
CONF_TEMPERATURE,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_PERCENT,
)
DEPENDENCIES = ["i2c"]
hdc302x_ns = cg.esphome_ns.namespace("hdc302x")
HDC302XComponent = hdc302x_ns.class_(
"HDC302XComponent", cg.PollingComponent, i2c.I2CDevice
)
HDC302XPowerMode = hdc302x_ns.enum("HDC302XPowerMode")
POWER_MODE_OPTIONS = {
"HIGH_ACCURACY": HDC302XPowerMode.HIGH_ACCURACY,
"BALANCED": HDC302XPowerMode.BALANCED,
"LOW_POWER": HDC302XPowerMode.LOW_POWER,
"ULTRA_LOW_POWER": HDC302XPowerMode.ULTRA_LOW_POWER,
}
# Actions
HeaterOnAction = hdc302x_ns.class_("HeaterOnAction", automation.Action)
HeaterOffAction = hdc302x_ns.class_("HeaterOffAction", automation.Action)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(HDC302XComponent),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=2,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_POWER_MODE, default="HIGH_ACCURACY"): cv.enum(
POWER_MODE_OPTIONS, upper=True
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x44)) # Default address per datasheet, Table 7-2.
)
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)
if temp_config := config.get(CONF_TEMPERATURE):
sens = await sensor.new_sensor(temp_config)
cg.add(var.set_temp_sensor(sens))
if humidity_config := config.get(CONF_HUMIDITY):
sens = await sensor.new_sensor(humidity_config)
cg.add(var.set_humidity_sensor(sens))
cg.add(var.set_power_mode(config[CONF_POWER_MODE]))
# HDC302x heater power configs, per datasheet Table 7-15.
HDC302X_HEATER_POWER_MAP = {
"QUARTER": 0x009F,
"HALF": 0x03FF,
"FULL": 0x3FFF,
}
def heater_power_value(value):
"""Accept enum names or raw uint16 values"""
if isinstance(value, cv.Lambda):
return value
if isinstance(value, str):
upper = value.upper()
if upper in HDC302X_HEATER_POWER_MAP:
return HDC302X_HEATER_POWER_MAP[upper]
raise cv.Invalid(
f"Unknown heater power preset: {value}. Use QUARTER, HALF, FULL, or a raw value 0-16383"
)
return cv.int_range(min=0, max=0x3FFF)(value)
HDC302X_ACTION_SCHEMA = maybe_simple_id({cv.GenerateID(): cv.use_id(HDC302XComponent)})
HDC302X_HEATER_ON_ACTION_SCHEMA = maybe_simple_id(
{
cv.GenerateID(): cv.use_id(HDC302XComponent),
cv.Optional(CONF_POWER, default="QUARTER"): cv.templatable(heater_power_value),
cv.Optional(CONF_DURATION, default="5s"): cv.templatable(
cv.positive_time_period_milliseconds
),
}
)
@automation.register_action(
"hdc302x.heater_on", HeaterOnAction, HDC302X_HEATER_ON_ACTION_SCHEMA
)
async def hdc302x_heater_on_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
template_ = await cg.templatable(config[CONF_POWER], args, cg.uint16)
cg.add(var.set_power(template_))
template_ = await cg.templatable(config[CONF_DURATION], args, cg.uint32)
cg.add(var.set_duration(template_))
return var
@automation.register_action(
"hdc302x.heater_off", HeaterOffAction, HDC302X_ACTION_SCHEMA
)
async def hdc302x_heater_off_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var

View File

@@ -35,10 +35,7 @@ uint8_t HONEYWELLABPSensor::readsensor_() {
pressure_count_ = ((uint16_t) (buf_[0]) << 8 & 0x3F00) | ((uint16_t) (buf_[1]) & 0xFF);
// 11 - bit temperature is all of byte 2 (lowest 8 bits) and the first three bits of byte 3
temperature_count_ = (((uint16_t) (buf_[2]) << 3) & 0x7F8) | (((uint16_t) (buf_[3]) >> 5) & 0x7);
ESP_LOGV(TAG,
"Sensor pressure_count_ %d\n"
"Sensor temperature_count_ %d",
pressure_count_, temperature_count_);
ESP_LOGV(TAG, "Sensor pressure_count_ %d, temperature_count_ %d", pressure_count_, temperature_count_);
}
return status_;
}

View File

@@ -330,38 +330,72 @@ class HttpRequestComponent : public Component {
void set_follow_redirects(bool follow_redirects) { this->follow_redirects_ = follow_redirects; }
void set_redirect_limit(uint16_t limit) { this->redirect_limit_ = limit; }
std::shared_ptr<HttpContainer> get(const std::string &url) { return this->start(url, "GET", "", {}); }
std::shared_ptr<HttpContainer> get(const std::string &url, const std::list<Header> &request_headers) {
std::shared_ptr<HttpContainer> get(const std::string &url) {
return this->start(url, "GET", "", std::vector<Header>{});
}
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers) {
return this->start(url, "GET", "", request_headers);
}
std::shared_ptr<HttpContainer> get(const std::string &url, const std::list<Header> &request_headers,
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url, "GET", "", request_headers, lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body) {
return this->start(url, "POST", body, {});
return this->start(url, "POST", body, std::vector<Header>{});
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
const std::list<Header> &request_headers) {
const std::vector<Header> &request_headers) {
return this->start(url, "POST", body, request_headers);
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
std::shared_ptr<HttpContainer> get(const std::string &url, const std::list<Header> &request_headers) {
return this->get(url, std::vector<Header>(request_headers.begin(), request_headers.end()));
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
std::shared_ptr<HttpContainer> get(const std::string &url, const std::list<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
return this->get(url, std::vector<Header>(request_headers.begin(), request_headers.end()), collect_headers);
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
const std::list<Header> &request_headers) {
return this->post(url, body, std::vector<Header>(request_headers.begin(), request_headers.end()));
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
return this->post(url, body, std::vector<Header>(request_headers.begin(), request_headers.end()), collect_headers);
}
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers) {
// Call perform() directly to avoid ambiguity with the deprecated overloads
return this->perform(url, method, body, request_headers, {});
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers) {
// Call perform() directly to avoid ambiguity with the std::set overload
return this->perform(url, method, body, request_headers, {});
return this->start(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()));
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass collect_headers as std::vector<std::string> instead of std::set. Removed in 2027.1.0.",
"2026.7.0")
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::set<std::string> &collect_headers) {
std::vector<std::string> lower;
lower.reserve(collect_headers.size());
@@ -371,15 +405,39 @@ class HttpRequestComponent : public Component {
return this->perform(url, method, body, request_headers, lower);
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list, and collect_headers as "
"std::vector<std::string> instead of std::set. Removed in 2027.1.0.",
"2026.7.0")
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::set<std::string> &collect_headers) {
std::vector<std::string> lower;
lower.reserve(collect_headers.size());
for (const auto &h : collect_headers) {
lower.push_back(str_lower_case(h));
}
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()), lower);
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()),
lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
return this->perform(url, method, body, request_headers, lower_case_collect_headers);
}
protected:
virtual std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method,
const std::string &body, const std::list<Header> &request_headers,
const std::string &body, const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) = 0;
const char *useragent_{nullptr};
bool follow_redirects_{};
@@ -436,13 +494,10 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
auto f = std::bind(&HttpRequestSendAction<Ts...>::encode_json_func_, this, x..., std::placeholders::_1);
body = json::build_json(f);
}
std::list<Header> request_headers;
for (const auto &item : this->request_headers_) {
auto val = item.second;
Header header;
header.name = item.first;
header.value = val.value(x...);
request_headers.push_back(header);
std::vector<Header> request_headers;
request_headers.reserve(this->request_headers_.size());
for (const auto &[key, val] : this->request_headers_) {
request_headers.push_back({key, val.value(x...)});
}
auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, request_headers,

View File

@@ -26,7 +26,7 @@ static constexpr int ESP8266_SSL_ERR_OOM = -1000;
std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &url, const std::string &method,
const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
this->status_momentary_error("failed", 1000);

View File

@@ -49,7 +49,7 @@ class HttpContainerArduino : public HttpContainer {
class HttpRequestArduino : public HttpRequestComponent {
protected:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) override;
};

View File

@@ -18,7 +18,7 @@ static const char *const TAG = "http_request.host";
std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url, const std::string &method,
const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
this->status_momentary_error("failed", 1000);

View File

@@ -19,7 +19,7 @@ class HttpContainerHost : public HttpContainer {
class HttpRequestHost : public HttpRequestComponent {
public:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) override;
void set_ca_path(const char *ca_path) { this->ca_path_ = ca_path; }

View File

@@ -54,7 +54,7 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, const std::string &method,
const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
this->status_momentary_error("failed", 1000);

View File

@@ -37,7 +37,7 @@ class HttpRequestIDF : public HttpRequestComponent {
protected:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<Header> &request_headers,
const std::vector<std::string> &lower_case_collect_headers) override;
// if zero ESP-IDF will use DEFAULT_HTTP_BUF_SIZE
uint16_t buffer_size_rx_{};

View File

@@ -105,8 +105,7 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
// we will compute MD5 on the fly for verification -- Arduino OTA seems to ignore it
md5_receive.init();
ESP_LOGV(TAG, "MD5Digest initialized\n"
"OTA backend begin");
ESP_LOGV(TAG, "MD5Digest initialized, OTA backend begin");
auto backend = ota::make_ota_backend();
auto error_code = backend->begin(container->content_length);
if (error_code != ota::OTA_RESPONSE_OK) {

View File

@@ -362,10 +362,8 @@ bool INA2XX::configure_shunt_() {
ESP_LOGW(TAG, "Shunt value too high");
}
this->shunt_cal_ &= 0x7FFF;
ESP_LOGV(TAG,
"Given Rshunt=%f Ohm and Max_current=%.3f\n"
"New CURRENT_LSB=%f, SHUNT_CAL=%u",
this->shunt_resistance_ohm_, this->max_current_a_, this->current_lsb_, this->shunt_cal_);
ESP_LOGV(TAG, "Rshunt=%f Ohm, max current=%.3f A, current LSB=%f, shunt cal=%u", this->shunt_resistance_ohm_,
this->max_current_a_, this->current_lsb_, this->shunt_cal_);
return this->write_unsigned_16_(RegisterMap::REG_SHUNT_CAL, this->shunt_cal_);
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <queue>
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
#include "esphome/core/component.h"

View File

@@ -489,11 +489,8 @@ bool LD2410Component::handle_ack_data_() {
this->out_pin_level_ = this->buffer_data_[12];
const auto *light_function_str = find_str(LIGHT_FUNCTIONS_BY_UINT, this->light_function_);
const auto *out_pin_level_str = find_str(OUT_PIN_LEVELS_BY_UINT, this->out_pin_level_);
ESP_LOGV(TAG,
"Light function: %s\n"
"Light threshold: %u\n"
"Out pin level: %s",
light_function_str, this->light_threshold_, out_pin_level_str);
ESP_LOGV(TAG, "Light function: %s, threshold: %u, out pin level: %s", light_function_str, this->light_threshold_,
out_pin_level_str);
#ifdef USE_SELECT
if (this->light_function_select_ != nullptr) {
this->light_function_select_->publish_state(light_function_str);

View File

@@ -530,10 +530,7 @@ bool LD2412Component::handle_ack_data_() {
this->light_function_ = this->buffer_data_[10];
this->light_threshold_ = this->buffer_data_[11];
const auto *light_function_str = find_str(LIGHT_FUNCTIONS_BY_UINT, this->light_function_);
ESP_LOGV(TAG,
"Light function: %s\n"
"Light threshold: %u",
light_function_str, this->light_threshold_);
ESP_LOGV(TAG, "Light function: %s, threshold: %u", light_function_str, this->light_threshold_);
#ifdef USE_SELECT
if (this->light_function_select_ != nullptr) {
this->light_function_select_->publish_state(light_function_str);

View File

@@ -130,10 +130,8 @@ void LEDCOutput::setup() {
}
int hpoint = ledc_angle_to_htop(this->phase_angle_, this->bit_depth_);
ESP_LOGV(TAG,
"Configured frequency %f with a bit depth of %u bits\n"
"Angle of %.1f° results in hpoint %u",
this->frequency_, this->bit_depth_, this->phase_angle_, hpoint);
ESP_LOGV(TAG, "Configured frequency %f with bit depth %u, angle %.1f° hpoint %u", this->frequency_, this->bit_depth_,
this->phase_angle_, hpoint);
ledc_channel_config_t chan_conf{};
chan_conf.gpio_num = this->pin_->get_pin();

View File

@@ -275,6 +275,146 @@ BASE_SCHEMA.add_extra(_detect_variant)
BASE_SCHEMA.add_extra(_update_core_data)
def _configure_lwip(config: dict) -> None:
"""Configure lwIP options for LibreTiny platforms.
The BK/RTL/LN SDKs each ship different lwIP defaults. BK72XX defaults are
wildly oversized for ESPHome's IoT use case, causing OOM on BK7231N.
RTL87XX and LN882H have more conservative defaults but still need tuning
for ESPHome's socket usage patterns.
See https://github.com/esphome/esphome/issues/14095
Comparison of SDK defaults vs ESPHome targets (TCP_MSS=1460 on all LT):
Setting ESP8266 ESP32 BK SDK RTL SDK LN SDK New
────────────────────────────────────────────────────────────────────────────
TCP_SND_BUF 2×MSS 4×MSS 10×MSS 5×MSS 7×MSS 4×MSS
TCP_WND 4×MSS 4×MSS 3/10×MSS 2×MSS 3×MSS 4×MSS
MEM_LIBC_MALLOC 1 1 0 0 1 1
MEMP_MEM_MALLOC 1 1 0 0 0 1
MEM_SIZE N/A* N/A* 16/32KB 5KB N/A* N/A* BK
PBUF_POOL_SIZE 10 16 3/10 20 20 10 BK
MAX_SOCKETS_TCP 5 16 12 —** —** dynamic
MAX_SOCKETS_UDP 4 16 22 —** —** dynamic
TCP_SND_QUEUELEN ~8 17 20 20 35 17
MEMP_NUM_TCP_SEG 10 16 40 20 =qlen 17
MEMP_NUM_TCP_PCB 5 16 12 10 8 =TCP
MEMP_NUM_TCP_PCB_LISTEN 4 16 4 5 3 dynamic
MEMP_NUM_UDP_PCB 4 16 25*** 7**** 7**** =UDP
MEMP_NUM_NETCONN 0 10 38 4***** =sum =sum
MEMP_NUM_NETBUF 0 2 16 2***** 8 4
MEMP_NUM_TCPIP_MSG_INPKT 4 8 16 8***** 12 8
* ESP8266/ESP32/LN882H use MEM_LIBC_MALLOC=1 (system heap, no dedicated pool).
ESP8266/ESP32 also use MEMP_MEM_MALLOC=1 (MEMP pools from heap, not static).
** RTL/LN SDKs don't define MAX_SOCKETS_TCP/UDP (LibreTiny-specific).
*** BK LT overlay: MAX_SOCKETS_UDP+2+1 = 25.
**** RTL/LN LT overlay overrides to flat 7.
***** Not defined in RTL SDK — lwIP opt.h defaults shown.
"dynamic" = auto-calculated from component socket registrations via
socket.get_socket_counts() with minimums of 8 TCP / 6 UDP.
"""
from esphome.components.socket import (
MIN_TCP_LISTEN_SOCKETS,
MIN_TCP_SOCKETS,
MIN_UDP_SOCKETS,
get_socket_counts,
)
sc = get_socket_counts()
# Apply platform minimums — ensure headroom for ESPHome's needs
tcp_sockets = max(MIN_TCP_SOCKETS, sc.tcp)
udp_sockets = max(MIN_UDP_SOCKETS, sc.udp)
# Listening sockets — registered by components (api, ota, web_server_base, etc.)
# Not all components register yet, so ensure a minimum for baseline operation.
listening_tcp = max(MIN_TCP_LISTEN_SOCKETS, sc.tcp_listen)
# TCP_SND_BUF: ESPAsyncWebServer allocates malloc(tcp_sndbuf()) per
# response chunk. At 10×MSS=14.6KB (BK default) this causes OOM (#14095).
# 4×MSS=5,840 matches ESP32. RTL(5×) and LN(7×) are close already.
tcp_snd_buf = "(4*TCP_MSS)" # BK: 10×MSS, RTL: 5×MSS, LN: 7×MSS
# TCP_WND: receive window. 4×MSS matches ESP32.
# RTL SDK uses only 2×MSS; increasing to 4× is safe and improves throughput.
tcp_wnd = "(4*TCP_MSS)" # BK: 10×MSS, RTL: 2×MSS, LN: 3×MSS
# TCP_SND_QUEUELEN: max pbufs queued for send buffer
# ESP-IDF formula: (4 * TCP_SND_BUF + (TCP_MSS - 1)) / TCP_MSS
# With 4×MSS: (4*5840 + 1459) / 1460 = 17 — match ESP32
tcp_snd_queuelen = 17 # BK: 20, RTL: 20, LN: 35
# MEMP_NUM_TCP_SEG: segment pool, must be >= TCP_SND_QUEUELEN (lwIP sanity check)
memp_num_tcp_seg = tcp_snd_queuelen # BK: 40, RTL: 20, LN: =qlen
lwip_opts: list[str] = [
# Disable statistics — not needed for production, saves RAM
"LWIP_STATS=0", # BK: 1, RTL: 0 already, LN: 0 already
"MEM_STATS=0",
"MEMP_STATS=0",
# TCP send buffer — 4×MSS matches ESP32
f"TCP_SND_BUF={tcp_snd_buf}",
# TCP receive window — 4×MSS matches ESP32
f"TCP_WND={tcp_wnd}",
# Socket counts — auto-calculated from component registrations
f"MAX_SOCKETS_TCP={tcp_sockets}",
f"MAX_SOCKETS_UDP={udp_sockets}",
# Listening sockets — BK SDK uses this to derive MEMP_NUM_TCP_PCB_LISTEN;
# RTL/LN don't use it, but we set MEMP_NUM_TCP_PCB_LISTEN explicitly below.
f"MAX_LISTENING_SOCKETS_TCP={listening_tcp}",
# Queued segment limits — derived from 4×MSS buffer size
f"TCP_SND_QUEUELEN={tcp_snd_queuelen}",
f"MEMP_NUM_TCP_SEG={memp_num_tcp_seg}", # must be >= queuelen
# PCB pools — active connections + listening sockets
f"MEMP_NUM_TCP_PCB={tcp_sockets}", # BK: 12, RTL: 10, LN: 8
f"MEMP_NUM_TCP_PCB_LISTEN={listening_tcp}", # BK: =MAX_LISTENING, RTL: 5, LN: 3
# UDP PCB pool — includes wifi.lwip_internal (DHCP + DNS)
f"MEMP_NUM_UDP_PCB={udp_sockets}", # BK: 25, RTL/LN: 7 via LT
# Netconn pool — each socket (active + listening) needs a netconn
f"MEMP_NUM_NETCONN={tcp_sockets + udp_sockets + listening_tcp}",
# Netbuf pool
"MEMP_NUM_NETBUF=4", # BK: 16, RTL: 2 (opt.h), LN: 8
# Inbound message pool
"MEMP_NUM_TCPIP_MSG_INPKT=8", # BK: 16, RTL: 8 (opt.h), LN: 12
]
# Use system heap for all lwIP allocations on all LibreTiny platforms.
# - MEM_LIBC_MALLOC=1: Use system heap instead of dedicated lwIP heap.
# LN882H already ships with this. BK SDK defaults to a 16/32KB dedicated
# pool that fragments during OTA. RTL SDK defaults to a 5KB pool.
# All three SDKs wire malloc → pvPortMalloc (FreeRTOS thread-safe heap).
# - MEMP_MEM_MALLOC=1: Allocate MEMP pools from heap on demand instead
# of static arrays. Saves ~20KB RAM on BK72XX. Safe because WiFi
# receive paths run in task context, not ISR context. ESP32 and ESP8266
# both ship with MEMP_MEM_MALLOC=1.
lwip_opts.append("MEM_LIBC_MALLOC=1")
lwip_opts.append("MEMP_MEM_MALLOC=1")
# BK72XX-specific: PBUF_POOL_SIZE override
# BK SDK "reduced plan" sets this to only 3 — too few for multiple
# concurrent connections (API + web_server + OTA). BK default plan
# uses 10; match that. RTL(20) and LN(20) need no override.
# With MEMP_MEM_MALLOC=1, this is a max count (allocated on demand).
if CORE.is_bk72xx:
lwip_opts.append("PBUF_POOL_SIZE=10")
tcp_min = " (min)" if tcp_sockets > sc.tcp else ""
udp_min = " (min)" if udp_sockets > sc.udp else ""
listen_min = " (min)" if listening_tcp > sc.tcp_listen else ""
_LOGGER.info(
"Configuring lwIP: TCP=%d%s [%s], UDP=%d%s [%s], TCP_LISTEN=%d%s [%s]",
tcp_sockets,
tcp_min,
sc.tcp_details,
udp_sockets,
udp_min,
sc.udp_details,
listening_tcp,
listen_min,
sc.tcp_listen_details,
)
cg.add_platformio_option("custom_options.lwip", lwip_opts)
# pylint: disable=use-dict-literal
async def component_to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
@@ -389,11 +529,12 @@ async def component_to_code(config):
"custom_options.sys_config#h", _BK7231N_SYS_CONFIG_OPTIONS
)
# Disable LWIP statistics to save RAM - not needed in production
# Must explicitly disable all sub-stats to avoid redefinition warnings
cg.add_platformio_option(
"custom_options.lwip",
["LWIP_STATS=0", "MEM_STATS=0", "MEMP_STATS=0"],
)
# Tune lwIP for ESPHome's actual needs.
# The SDK defaults (TCP_SND_BUF=10*MSS, MAX_SOCKETS_TCP=12, MEM_SIZE=32KB)
# are wildly oversized for an IoT device. ESPAsyncWebServer allocates
# malloc(tcp_sndbuf()) per response chunk — at 14.6KB this causes silent
# OOM on memory-constrained chips like BK7231N.
# See https://github.com/esphome/esphome/issues/14095
_configure_lwip(config)
await cg.register_component(var, config)

View File

@@ -329,10 +329,11 @@ async def to_code(config):
level = config[CONF_LEVEL]
CORE.data.setdefault(CONF_LOGGER, {})[CONF_LEVEL] = level
initial_level = LOG_LEVELS[config.get(CONF_INITIAL_LEVEL, level)]
tx_buffer_size = config[CONF_TX_BUFFER_SIZE]
cg.add_define("ESPHOME_LOGGER_TX_BUFFER_SIZE", tx_buffer_size)
log = cg.new_Pvariable(
config[CONF_ID],
baud_rate,
config[CONF_TX_BUFFER_SIZE],
)
if CORE.is_esp32:
cg.add(log.create_pthread_key())

View File

@@ -75,18 +75,13 @@ struct LogBuffer {
*p++ = ':';
// Format line number without modulo operations
// Format line number using subtraction loops (no division - important for ESP8266 which lacks hardware divider)
if (line > 999) [[unlikely]] {
int thousands = line / 1000;
*p++ = '0' + thousands;
line -= thousands * 1000;
write_digit(p, line, 1000);
}
int hundreds = line / 100;
int remainder = line - hundreds * 100;
int tens = remainder / 10;
*p++ = '0' + hundreds;
*p++ = '0' + tens;
*p++ = '0' + (remainder - tens * 10);
write_digit(p, line, 100);
write_digit(p, line, 10);
*p++ = '0' + line;
*p++ = ']';
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR) || defined(USE_HOST)
@@ -162,6 +157,15 @@ struct LogBuffer {
this->process_vsnprintf_result_(vsnprintf_P(this->current_(), this->remaining_(), format, args));
}
#endif
// Extract one decimal digit via subtraction (no division - important for ESP8266)
static inline void ESPHOME_ALWAYS_INLINE write_digit(char *&p, int &value, int divisor) {
char d = '0';
while (value >= divisor) {
d++;
value -= divisor;
}
*p++ = d;
}
// Write ANSI color escape sequence to buffer, updates pointer in place
// Caller is responsible for ensuring buffer has sufficient space
void write_ansi_color_(char *&p, uint8_t level) {

View File

@@ -152,10 +152,7 @@ inline uint8_t Logger::level_for(const char *tag) {
return this->current_level_;
}
Logger::Logger(uint32_t baud_rate, size_t tx_buffer_size) : baud_rate_(baud_rate), tx_buffer_size_(tx_buffer_size) {
// add 1 to buffer size for null terminator
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - allocated once, never freed
this->tx_buffer_ = new char[this->tx_buffer_size_ + 1];
Logger::Logger(uint32_t baud_rate) : baud_rate_(baud_rate) {
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
this->main_task_ = xTaskGetCurrentTaskHandle();
#elif defined(USE_ZEPHYR)
@@ -196,7 +193,7 @@ void Logger::process_messages_() {
uint16_t text_length;
while (this->log_buffer_->borrow_message_main_loop(message, text_length)) {
const char *thread_name = message->thread_name[0] != '\0' ? message->thread_name : nullptr;
LogBuffer buf{this->tx_buffer_, this->tx_buffer_size_};
LogBuffer buf{this->tx_buffer_, ESPHOME_LOGGER_TX_BUFFER_SIZE};
this->format_buffered_message_and_notify_(message->level, message->tag, message->line, thread_name,
message->text_data(), text_length, buf);
// Release the message to allow other tasks to use it as soon as possible

View File

@@ -143,7 +143,7 @@ enum UARTSelection : uint8_t {
*/
class Logger : public Component {
public:
explicit Logger(uint32_t baud_rate, size_t tx_buffer_size);
explicit Logger(uint32_t baud_rate);
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
void init_log_buffer(size_t total_buffer_size);
#endif
@@ -281,7 +281,7 @@ class Logger : public Component {
inline void HOT log_message_to_buffer_and_send_(bool &recursion_guard, uint8_t level, const char *tag, int line,
FormatType format, va_list args, const char *thread_name) {
RecursionGuard guard(recursion_guard);
LogBuffer buf{this->tx_buffer_, this->tx_buffer_size_};
LogBuffer buf{this->tx_buffer_, ESPHOME_LOGGER_TX_BUFFER_SIZE};
#ifdef USE_STORE_LOG_STR_IN_FLASH
if constexpr (std::is_same_v<FormatType, const __FlashStringHelper *>) {
this->format_log_to_buffer_with_terminator_P_(level, tag, line, format, args, buf);
@@ -312,7 +312,6 @@ class Logger : public Component {
// Group 4-byte aligned members first
uint32_t baud_rate_;
char *tx_buffer_{nullptr};
#if defined(USE_ARDUINO) && !defined(USE_ESP32)
Stream *hw_serial_{nullptr};
#endif
@@ -354,7 +353,6 @@ class Logger : public Component {
#endif
// Group smaller types together at the end
uint16_t tx_buffer_size_{0};
uint8_t current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_ZEPHYR)
UARTSelection uart_{UART_SELECTION_UART0};
@@ -371,6 +369,9 @@ class Logger : public Component {
bool global_recursion_guard_{false}; // Simple global recursion guard for single-task platforms
#endif
// Large buffer placed last to keep frequently-accessed member offsets small
char tx_buffer_[ESPHOME_LOGGER_TX_BUFFER_SIZE + 1]; // +1 for null terminator
// --- get_thread_name_ overloads (per-platform) ---
#if defined(USE_ESP32) || defined(USE_LIBRETINY)

View File

@@ -89,16 +89,16 @@ void Logger::pre_setup() {
switch (this->uart_) {
case UART_SELECTION_UART0:
this->uart_num_ = UART_NUM_0;
init_uart(this->uart_num_, baud_rate_, tx_buffer_size_);
init_uart(this->uart_num_, baud_rate_, ESPHOME_LOGGER_TX_BUFFER_SIZE);
break;
case UART_SELECTION_UART1:
this->uart_num_ = UART_NUM_1;
init_uart(this->uart_num_, baud_rate_, tx_buffer_size_);
init_uart(this->uart_num_, baud_rate_, ESPHOME_LOGGER_TX_BUFFER_SIZE);
break;
#ifdef USE_ESP32_VARIANT_ESP32
case UART_SELECTION_UART2:
this->uart_num_ = UART_NUM_2;
init_uart(this->uart_num_, baud_rate_, tx_buffer_size_);
init_uart(this->uart_num_, baud_rate_, ESPHOME_LOGGER_TX_BUFFER_SIZE);
break;
#endif
#ifdef USE_LOGGER_USB_CDC

View File

@@ -5,8 +5,8 @@ namespace esphome::logger {
void HOT Logger::write_msg_(const char *msg, uint16_t len) {
static constexpr size_t TIMESTAMP_LEN = 10; // "[HH:MM:SS]"
// tx_buffer_size_ defaults to 512, so 768 covers default + headroom
char buffer[TIMESTAMP_LEN + 768];
static constexpr size_t HEADROOM = 128; // Extra space for ANSI codes, newline, etc.
char buffer[TIMESTAMP_LEN + ESPHOME_LOGGER_TX_BUFFER_SIZE + HEADROOM];
time_t rawtime;
time(&rawtime);

View File

@@ -146,11 +146,11 @@ void MAX6956::dump_config() {
if (brightness_mode_ == MAX6956CURRENTMODE::GLOBAL) {
ESP_LOGCONFIG(TAG,
"current mode: global\n"
"global brightness: %u",
" Current mode: global\n"
" Brightness: %u",
global_brightness_);
} else {
ESP_LOGCONFIG(TAG, "current mode: segment");
ESP_LOGCONFIG(TAG, " Current mode: segment");
}
}

View File

@@ -56,7 +56,7 @@ def _consume_mdns_sockets(config: ConfigType) -> ConfigType:
from esphome.components import socket
# mDNS needs 2 sockets (IPv4 + IPv6 multicast)
socket.consume_sockets(2, "mdns")(config)
socket.consume_sockets(2, "mdns", socket.SocketType.UDP)(config)
return config

View File

@@ -165,10 +165,7 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) {
case MQTT_EVENT_ERROR:
ESP_LOGE(TAG, "MQTT_EVENT_ERROR");
if (event.error_handle.error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
ESP_LOGE(TAG,
"Last error code reported from esp-tls: 0x%x\n"
"Last tls stack error number: 0x%x\n"
"Last captured errno : %d (%s)",
ESP_LOGE(TAG, "Last esp-tls error: 0x%x, tls stack error: 0x%x, socket errno: %d (%s)",
event.error_handle.esp_tls_last_esp_err, event.error_handle.esp_tls_stack_err,
event.error_handle.esp_transport_sock_errno, strerror(event.error_handle.esp_transport_sock_errno));
} else if (event.error_handle.error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {

View File

@@ -61,7 +61,9 @@ struct IPAddress {
IPAddress(const std::string &in_address) { inet_aton(in_address.c_str(), &ip_addr_); }
IPAddress(const ip_addr_t *other_ip) { ip_addr_ = *other_ip; }
// Remove before 2026.8.0
ESPDEPRECATED("Use str_to() instead. Removed in 2026.8.0", "2026.2.0")
ESPDEPRECATED(
"str() is deprecated: use 'char buf[IP_ADDRESS_BUFFER_SIZE]; ip.str_to(buf);' instead. Removed in 2026.8.0",
"2026.2.0")
std::string str() const {
char buf[IP_ADDRESS_BUFFER_SIZE];
this->str_to(buf);
@@ -150,7 +152,9 @@ struct IPAddress {
bool is_ip6() const { return IP_IS_V6(&ip_addr_); }
bool is_multicast() const { return ip_addr_ismulticast(&ip_addr_); }
// Remove before 2026.8.0
ESPDEPRECATED("Use str_to() instead. Removed in 2026.8.0", "2026.2.0")
ESPDEPRECATED(
"str() is deprecated: use 'char buf[IP_ADDRESS_BUFFER_SIZE]; ip.str_to(buf);' instead. Removed in 2026.8.0",
"2026.2.0")
std::string str() const {
char buf[IP_ADDRESS_BUFFER_SIZE];
this->str_to(buf);

View File

@@ -25,11 +25,7 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) {
uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1;
ESP_LOGD(TAG, "Range start: %" PRIu32, range_start);
if (range_size <= 0 or range_end <= range_start) {
ESP_LOGE(TAG, "Invalid range");
ESP_LOGD(TAG,
"Range end: %" PRIu32 "\n"
"Range size: %" PRIu32,
range_end, range_size);
ESP_LOGE(TAG, "Invalid range end: %" PRIu32 ", size: %" PRIu32, range_end, range_size);
return -1;
}
@@ -138,11 +134,7 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) {
}
bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
ESP_LOGD(TAG,
"TFT upload requested\n"
"Exit reparse: %s\n"
"URL: %s",
YESNO(exit_reparse), this->tft_url_.c_str());
ESP_LOGD(TAG, "TFT upload requested, exit reparse: %s, URL: %s", YESNO(exit_reparse), this->tft_url_.c_str());
if (this->connection_state_.is_updating_) {
ESP_LOGW(TAG, "Upload in progress");
@@ -172,10 +164,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate);
// Define the configuration for the HTTP client
ESP_LOGV(TAG,
"Init HTTP client\n"
"Heap: %" PRIu32,
EspClass::getFreeHeap());
ESP_LOGV(TAG, "Init HTTP client, heap: %" PRIu32, EspClass::getFreeHeap());
HTTPClient http_client;
http_client.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along
@@ -262,10 +251,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
this->reset_(false);
delay(250); // NOLINT
ESP_LOGV(TAG,
"Heap: %" PRIu32 "\n"
"Upload cmd: %s",
EspClass::getFreeHeap(), command);
ESP_LOGV(TAG, "Heap: %" PRIu32 ", upload cmd: %s", EspClass::getFreeHeap(), command);
this->send_command_(command);
if (baud_rate != this->original_baud_rate_) {

View File

@@ -27,11 +27,7 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r
uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1;
ESP_LOGD(TAG, "Range start: %" PRIu32, range_start);
if (range_size <= 0 or range_end <= range_start) {
ESP_LOGD(TAG,
"Range end: %" PRIu32 "\n"
"Range size: %" PRIu32,
range_end, range_size);
ESP_LOGE(TAG, "Invalid range");
ESP_LOGE(TAG, "Invalid range end: %" PRIu32 ", size: %" PRIu32, range_end, range_size);
return -1;
}
@@ -159,11 +155,7 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r
}
bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
ESP_LOGD(TAG,
"TFT upload requested\n"
"Exit reparse: %s\n"
"URL: %s",
YESNO(exit_reparse), this->tft_url_.c_str());
ESP_LOGD(TAG, "TFT upload requested, exit reparse: %s, URL: %s", YESNO(exit_reparse), this->tft_url_.c_str());
if (this->connection_state_.is_updating_) {
ESP_LOGW(TAG, "Upload in progress");
@@ -193,10 +185,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate);
// Define the configuration for the HTTP client
ESP_LOGV(TAG,
"Init HTTP client\n"
"Heap: %" PRIu32,
esp_get_free_heap_size());
ESP_LOGV(TAG, "Init HTTP client, heap: %" PRIu32, esp_get_free_heap_size());
esp_http_client_config_t config = {
.url = this->tft_url_.c_str(),
.cert_pem = nullptr,
@@ -220,10 +209,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
}
// Perform the HTTP request
ESP_LOGV(TAG,
"Check connection\n"
"Heap: %" PRIu32,
esp_get_free_heap_size());
ESP_LOGV(TAG, "Check connection, heap: %" PRIu32, esp_get_free_heap_size());
err = esp_http_client_perform(http_client);
if (err != ESP_OK) {
ESP_LOGE(TAG, "HTTP failed: %s", esp_err_to_name(err));
@@ -232,10 +218,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
}
// Check the HTTP Status Code
ESP_LOGV(TAG,
"Check status\n"
"Heap: %" PRIu32,
esp_get_free_heap_size());
ESP_LOGV(TAG, "Check status, heap: %" PRIu32, esp_get_free_heap_size());
int status_code = esp_http_client_get_status_code(http_client);
if (status_code != 200 && status_code != 206) {
ESP_LOGE(TAG, "HTTP request failed with status %d", status_code);
@@ -344,8 +327,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
ESP_LOGV(TAG, "Heap: %" PRIu32 " left: %" PRIu32, esp_get_free_heap_size(), this->content_length_);
}
ESP_LOGD(TAG, "TFT upload complete\n"
"Close HTTP");
ESP_LOGD(TAG, "TFT upload complete, closing HTTP");
esp_http_client_close(http_client);
esp_http_client_cleanup(http_client);
ESP_LOGV(TAG, "Connection closed");

View File

@@ -49,7 +49,7 @@ void OnlineImage::update() {
ESP_LOGD(TAG, "Updating image from %s", this->url_.c_str());
std::list<http_request::Header> headers;
std::vector<http_request::Header> headers;
// Add caching headers if we have them
if (!this->etag_.empty()) {

View File

@@ -35,9 +35,9 @@ void OpenThreadComponent::dump_config() {
#elif CONFIG_OPENTHREAD_MTD
ESP_LOGCONFIG(TAG, " Device Type: MTD");
// TBD: Synchronized Sleepy End Device
if (this->poll_period > 0) {
if (this->poll_period_ > 0) {
ESP_LOGCONFIG(TAG, " Device is configured as Sleepy End Device (SED)");
uint32_t duration = this->poll_period / 1000;
uint32_t duration = this->poll_period_ / 1000;
ESP_LOGCONFIG(TAG, " Poll Period: %" PRIu32 "s", duration);
} else {
ESP_LOGCONFIG(TAG, " Device is configured as Minimal End Device (MED)");

View File

@@ -36,22 +36,22 @@ class OpenThreadComponent : public Component {
const char *get_use_address() const;
void set_use_address(const char *use_address);
#if CONFIG_OPENTHREAD_MTD
void set_poll_period(uint32_t poll_period) { this->poll_period = poll_period; }
void set_poll_period(uint32_t poll_period) { this->poll_period_ = poll_period; }
#endif
protected:
std::optional<otIp6Address> get_omr_address_(InstanceLock &lock);
std::function<void()> factory_reset_external_callback_;
#if CONFIG_OPENTHREAD_MTD
uint32_t poll_period_{0};
#endif
bool teardown_started_{false};
bool teardown_complete_{false};
std::function<void()> factory_reset_external_callback_;
private:
// Stores a pointer to a string literal (static storage duration).
// ONLY set from Python-generated code with string literals - never dynamic strings.
const char *use_address_{""};
#if CONFIG_OPENTHREAD_MTD
uint32_t poll_period{0};
#endif
};
extern OpenThreadComponent *global_openthread_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

View File

@@ -81,9 +81,11 @@ void OpenThreadComponent::ot_main() {
// Initialize the OpenThread stack
// otLoggingSetLevel(OT_LOG_LEVEL_DEBG);
ESP_ERROR_CHECK(esp_openthread_init(&config));
// Fetch OT instance once to avoid repeated call into OT stack
otInstance *instance = esp_openthread_get_instance();
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance()));
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(instance));
#endif
#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
@@ -104,34 +106,34 @@ void OpenThreadComponent::ot_main() {
esp_cli_custom_command_init();
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
ESP_LOGD(TAG, "Thread Version: %" PRIu16, otThreadGetVersion());
otLinkModeConfig link_mode_config{};
#if CONFIG_OPENTHREAD_FTD
link_mode_config.mRxOnWhenIdle = true;
link_mode_config.mDeviceType = true;
link_mode_config.mNetworkData = true;
#elif CONFIG_OPENTHREAD_MTD
if (this->poll_period > 0) {
if (otLinkSetPollPeriod(esp_openthread_get_instance(), this->poll_period) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set OpenThread pollperiod.");
if (this->poll_period_ > 0) {
if (otLinkSetPollPeriod(instance, this->poll_period_) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set pollperiod");
}
uint32_t link_polling_period = otLinkGetPollPeriod(esp_openthread_get_instance());
ESP_LOGD(TAG, "Link Polling Period: %" PRIu32, link_polling_period);
ESP_LOGD(TAG, "Link Polling Period: %" PRIu32, otLinkGetPollPeriod(instance));
}
link_mode_config.mRxOnWhenIdle = this->poll_period == 0;
link_mode_config.mRxOnWhenIdle = this->poll_period_ == 0;
link_mode_config.mDeviceType = false;
link_mode_config.mNetworkData = false;
#endif
if (otThreadSetLinkMode(esp_openthread_get_instance(), link_mode_config) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set OpenThread linkmode.");
if (otThreadSetLinkMode(instance, link_mode_config) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set linkmode");
}
link_mode_config = otThreadGetLinkMode(esp_openthread_get_instance());
ESP_LOGD(TAG,
"Link Mode Device Type: %s\n"
"Link Mode Network Data: %s\n"
"Link Mode RX On When Idle: %s",
link_mode_config.mDeviceType ? "true" : "false", link_mode_config.mNetworkData ? "true" : "false",
link_mode_config.mRxOnWhenIdle ? "true" : "false");
#ifdef ESPHOME_LOG_HAS_DEBUG // Fetch link mode from OT only when DEBUG
link_mode_config = otThreadGetLinkMode(instance);
ESP_LOGD(TAG, "Link Mode Device Type: %s, Network Data: %s, RX On When Idle: %s",
TRUEFALSE(link_mode_config.mDeviceType), TRUEFALSE(link_mode_config.mNetworkData),
TRUEFALSE(link_mode_config.mRxOnWhenIdle));
#endif
// Run the main loop
#if CONFIG_OPENTHREAD_CLI
@@ -142,13 +144,12 @@ void OpenThreadComponent::ot_main() {
#ifndef USE_OPENTHREAD_FORCE_DATASET
// Check if openthread has a valid dataset from a previous execution
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
otError error = otDatasetGetActiveTlvs(instance, &dataset);
if (error != OT_ERROR_NONE) {
// Make sure the length is 0 so we fallback to the configuration
dataset.mLength = 0;
} else {
ESP_LOGI(TAG, "Found OpenThread-managed dataset, ignoring esphome configuration\n"
"(set force_dataset: true to override)");
ESP_LOGI(TAG, "Found existing dataset, ignoring config (force_dataset: true to override)");
}
#endif

View File

@@ -25,7 +25,7 @@ class OpenThreadInstancePollingComponent : public PollingComponent {
virtual void update_instance(otInstance *instance) = 0;
};
class IPAddressOpenThreadInfo : public PollingComponent, public text_sensor::TextSensor {
class IPAddressOpenThreadInfo final : public PollingComponent, public text_sensor::TextSensor {
public:
void update() override {
std::optional<otIp6Address> address = openthread::global_openthread_component->get_omr_address();
@@ -48,7 +48,7 @@ class IPAddressOpenThreadInfo : public PollingComponent, public text_sensor::Tex
std::string last_ip_;
};
class RoleOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
class RoleOpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
public:
void update_instance(otInstance *instance) override {
otDeviceRole role = otThreadGetDeviceRole(instance);
@@ -64,7 +64,7 @@ class RoleOpenThreadInfo : public OpenThreadInstancePollingComponent, public tex
otDeviceRole last_role_;
};
class Rloc16OpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
class Rloc16OpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
public:
void update_instance(otInstance *instance) override {
uint16_t rloc16 = otThreadGetRloc16(instance);
@@ -75,14 +75,13 @@ class Rloc16OpenThreadInfo : public OpenThreadInstancePollingComponent, public t
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
uint16_t last_rloc16_;
};
class ExtAddrOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
class ExtAddrOpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
public:
void update_instance(otInstance *instance) override {
const auto *extaddr = otLinkGetExtendedAddress(instance);
@@ -93,14 +92,13 @@ class ExtAddrOpenThreadInfo : public OpenThreadInstancePollingComponent, public
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
std::array<uint8_t, 8> last_extaddr_{};
};
class Eui64OpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
class Eui64OpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
public:
void update_instance(otInstance *instance) override {
otExtAddress addr;
@@ -113,14 +111,13 @@ class Eui64OpenThreadInfo : public OpenThreadInstancePollingComponent, public te
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
std::array<uint8_t, 8> last_eui64_{};
};
class ChannelOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
class ChannelOpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor {
public:
void update_instance(otInstance *instance) override {
uint8_t channel = otLinkGetChannel(instance);
@@ -131,7 +128,6 @@ class ChannelOpenThreadInfo : public OpenThreadInstancePollingComponent, public
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
@@ -153,7 +149,7 @@ class DatasetOpenThreadInfo : public OpenThreadInstancePollingComponent {
virtual void update_dataset(otOperationalDataset *dataset) = 0;
};
class NetworkNameOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
class NetworkNameOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
public:
void update_dataset(otOperationalDataset *dataset) override {
if (this->last_network_name_ != dataset->mNetworkName.m8) {
@@ -161,14 +157,13 @@ class NetworkNameOpenThreadInfo : public DatasetOpenThreadInfo, public text_sens
this->publish_state(this->last_network_name_);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
std::string last_network_name_;
};
class NetworkKeyOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
class NetworkKeyOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
public:
void update_dataset(otOperationalDataset *dataset) override {
if (!std::equal(this->last_key_.begin(), this->last_key_.end(), dataset->mNetworkKey.m8)) {
@@ -178,14 +173,13 @@ class NetworkKeyOpenThreadInfo : public DatasetOpenThreadInfo, public text_senso
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
std::array<uint8_t, 16> last_key_{};
};
class PanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
class PanIdOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
public:
void update_dataset(otOperationalDataset *dataset) override {
uint16_t panid = dataset->mPanId;
@@ -196,14 +190,13 @@ class PanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::Te
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
uint16_t last_panid_;
};
class ExtPanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
class ExtPanIdOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor {
public:
void update_dataset(otOperationalDataset *dataset) override {
if (!std::equal(this->last_extpanid_.begin(), this->last_extpanid_.end(), dataset->mExtendedPanId.m8)) {
@@ -214,7 +207,6 @@ class ExtPanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor:
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:

View File

@@ -122,8 +122,10 @@ bool PCA9554Component::write_register_(uint8_t reg, uint16_t value) {
float PCA9554Component::get_setup_priority() const { return setup_priority::IO; }
#ifdef USE_LOOP_PRIORITY
// Run our loop() method early to invalidate cache before any other components access the pins
float PCA9554Component::get_loop_priority() const { return 9.0f; } // Just after WIFI
#endif
void PCA9554GPIOPin::setup() { pin_mode(flags_); }
void PCA9554GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }

View File

@@ -23,7 +23,9 @@ class PCA9554Component : public Component,
float get_setup_priority() const override;
#ifdef USE_LOOP_PRIORITY
float get_loop_priority() const override;
#endif
void dump_config() override;

View File

@@ -99,8 +99,10 @@ bool PCF8574Component::write_gpio_() {
}
float PCF8574Component::get_setup_priority() const { return setup_priority::IO; }
#ifdef USE_LOOP_PRIORITY
// Run our loop() method early to invalidate cache before any other components access the pins
float PCF8574Component::get_loop_priority() const { return 9.0f; } // Just after WIFI
#endif
void PCF8574GPIOPin::setup() { pin_mode(flags_); }
void PCF8574GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }

View File

@@ -26,7 +26,9 @@ class PCF8574Component : public Component,
void pin_mode(uint8_t pin, gpio::Flags flags);
float get_setup_priority() const override;
#ifdef USE_LOOP_PRIORITY
float get_loop_priority() const override;
#endif
void dump_config() override;

View File

@@ -144,9 +144,10 @@ bool PI4IOE5V6408Component::write_gpio_modes_() {
}
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
ESP_LOGV(TAG,
"Wrote GPIO modes: 0b" BYTE_TO_BINARY_PATTERN "\n"
"Wrote GPIO pullup/pulldown: 0b" BYTE_TO_BINARY_PATTERN "\n"
"Wrote GPIO pull enable: 0b" BYTE_TO_BINARY_PATTERN,
"Wrote GPIO config:\n"
" modes: 0b" BYTE_TO_BINARY_PATTERN "\n"
" pullup/pulldown: 0b" BYTE_TO_BINARY_PATTERN "\n"
" pull enable: 0b" BYTE_TO_BINARY_PATTERN,
BYTE_TO_BINARY(this->mode_mask_), BYTE_TO_BINARY(this->pull_up_down_mask_),
BYTE_TO_BINARY(this->pull_enable_mask_));
#endif

View File

@@ -748,8 +748,7 @@ esphome::optional<bool> Pipsolar::get_bit_(std::string bits, uint8_t bit_pos) {
}
void Pipsolar::dump_config() {
ESP_LOGCONFIG(TAG, "Pipsolar:\n"
"enabled polling commands:");
ESP_LOGCONFIG(TAG, "Pipsolar enabled polling commands:");
for (auto &enabled_polling_command : this->enabled_polling_commands_) {
if (enabled_polling_command.length != 0) {
ESP_LOGCONFIG(TAG, "%s", enabled_polling_command.command);

View File

@@ -31,10 +31,7 @@ void PN532::setup() {
this->mark_failed();
return;
}
ESP_LOGD(TAG,
"Found chip PN5%02X\n"
"Firmware ver. %d.%d",
version_data[0], version_data[1], version_data[2]);
ESP_LOGD(TAG, "Found chip PN5%02X, Firmware v%d.%d", version_data[0], version_data[1], version_data[2]);
if (!this->write_command_({
PN532_COMMAND_SAMCONFIGURATION,

View File

@@ -243,9 +243,7 @@ uint8_t PN7150::reset_core_(const bool reset_config, const bool power) {
return nfc::STATUS_FAILED;
}
ESP_LOGD(TAG,
"Configuration %s\n"
"NCI version: %s",
ESP_LOGD(TAG, "Configuration %s, NCI version: %s",
rx.get_message()[nfc::NCI_PKT_PAYLOAD_OFFSET + 2] ? "reset" : "retained",
rx.get_message()[nfc::NCI_PKT_PAYLOAD_OFFSET + 1] == 0x20 ? "2.0" : "1.0");
@@ -274,11 +272,12 @@ uint8_t PN7150::init_core_() {
uint8_t flash_minor_version = rx.get_message()[19 + rx.get_message()[8]];
ESP_LOGD(TAG,
"Manufacturer ID: 0x%02X\n"
"Hardware version: 0x%02X\n"
"ROM code version: 0x%02X\n"
"FLASH major version: 0x%02X\n"
"FLASH minor version: 0x%02X",
"PN7150 chip info:\n"
" Manufacturer ID: 0x%02X\n"
" Hardware version: 0x%02X\n"
" ROM code version: 0x%02X\n"
" FLASH major version: 0x%02X\n"
" FLASH minor version: 0x%02X",
manf_id, hw_version, rom_code_version, flash_major_version, flash_minor_version);
return rx.get_simple_status_response();

View File

@@ -265,10 +265,7 @@ uint8_t PN7160::reset_core_(const bool reset_config, const bool power) {
return nfc::STATUS_FAILED;
}
ESP_LOGD(TAG,
"Configuration %s\n"
"NCI version: %s\n"
"Manufacturer ID: 0x%02X",
ESP_LOGD(TAG, "Configuration %s, NCI version: %s, Manufacturer ID: 0x%02X",
rx.get_message()[4] ? "reset" : "retained", rx.get_message()[5] == 0x20 ? "2.0" : "1.0",
rx.get_message()[6]);
rx.get_message().erase(rx.get_message().begin(), rx.get_message().begin() + 8);
@@ -301,11 +298,12 @@ uint8_t PN7160::init_core_() {
char feat_buf[nfc::FORMAT_BYTES_BUFFER_SIZE];
ESP_LOGD(TAG,
"Hardware version: %u\n"
"ROM code version: %u\n"
"FLASH major version: %u\n"
"FLASH minor version: %u\n"
"Features: %s",
"PN7160 chip info:\n"
" Hardware version: %u\n"
" ROM code version: %u\n"
" FLASH major version: %u\n"
" FLASH minor version: %u\n"
" Features: %s",
hw_version, rom_code_version, flash_major_version, flash_minor_version,
nfc::format_bytes_to(feat_buf, features));

View File

@@ -128,15 +128,14 @@ bool QMP6988Component::get_calibration_data_() {
qmp6988_data_.qmp6988_cali.COE_bp3 = (int16_t) encode_uint16(a_data_uint8_tr[16], a_data_uint8_tr[17]);
ESP_LOGV(TAG,
"<-----------calibration data-------------->\n"
"COE_a0[%d] COE_a1[%d] COE_a2[%d] COE_b00[%d]",
"Calibration data:\n"
" COE_a0[%d] COE_a1[%d] COE_a2[%d] COE_b00[%d]\n"
" COE_bt1[%d] COE_bt2[%d] COE_bp1[%d] COE_b11[%d]\n"
" COE_bp2[%d] COE_b12[%d] COE_b21[%d] COE_bp3[%d]",
qmp6988_data_.qmp6988_cali.COE_a0, qmp6988_data_.qmp6988_cali.COE_a1, qmp6988_data_.qmp6988_cali.COE_a2,
qmp6988_data_.qmp6988_cali.COE_b00);
ESP_LOGV(TAG, "COE_bt1[%d] COE_bt2[%d] COE_bp1[%d] COE_b11[%d]\r\n", qmp6988_data_.qmp6988_cali.COE_bt1,
qmp6988_data_.qmp6988_cali.COE_bt2, qmp6988_data_.qmp6988_cali.COE_bp1, qmp6988_data_.qmp6988_cali.COE_b11);
ESP_LOGV(TAG, "COE_bp2[%d] COE_b12[%d] COE_b21[%d] COE_bp3[%d]\r\n", qmp6988_data_.qmp6988_cali.COE_bp2,
qmp6988_data_.qmp6988_cali.COE_b00, qmp6988_data_.qmp6988_cali.COE_bt1, qmp6988_data_.qmp6988_cali.COE_bt2,
qmp6988_data_.qmp6988_cali.COE_bp1, qmp6988_data_.qmp6988_cali.COE_b11, qmp6988_data_.qmp6988_cali.COE_bp2,
qmp6988_data_.qmp6988_cali.COE_b12, qmp6988_data_.qmp6988_cali.COE_b21, qmp6988_data_.qmp6988_cali.COE_bp3);
ESP_LOGV(TAG, "<-----------calibration data-------------->\r\n");
qmp6988_data_.ik.a0 = qmp6988_data_.qmp6988_cali.COE_a0; // 20Q4
qmp6988_data_.ik.b00 = qmp6988_data_.qmp6988_cali.COE_b00; // 20Q4
@@ -153,14 +152,13 @@ bool QMP6988Component::get_calibration_data_() {
qmp6988_data_.ik.b21 = 13836L * (int64_t) qmp6988_data_.qmp6988_cali.COE_b21 + 79333336L; // 29Q60
qmp6988_data_.ik.bp3 = 2915L * (int64_t) qmp6988_data_.qmp6988_cali.COE_bp3 + 157155561L; // 28Q65
ESP_LOGV(TAG,
"<----------- int calibration data -------------->\n"
"a0[%d] a1[%d] a2[%d] b00[%d]",
qmp6988_data_.ik.a0, qmp6988_data_.ik.a1, qmp6988_data_.ik.a2, qmp6988_data_.ik.b00);
ESP_LOGV(TAG, "bt1[%lld] bt2[%lld] bp1[%lld] b11[%lld]\r\n", qmp6988_data_.ik.bt1, qmp6988_data_.ik.bt2,
qmp6988_data_.ik.bp1, qmp6988_data_.ik.b11);
ESP_LOGV(TAG, "bp2[%lld] b12[%lld] b21[%lld] bp3[%lld]\r\n", qmp6988_data_.ik.bp2, qmp6988_data_.ik.b12,
"Int calibration data:\n"
" a0[%d] a1[%d] a2[%d] b00[%d]\n"
" bt1[%lld] bt2[%lld] bp1[%lld] b11[%lld]\n"
" bp2[%lld] b12[%lld] b21[%lld] bp3[%lld]",
qmp6988_data_.ik.a0, qmp6988_data_.ik.a1, qmp6988_data_.ik.a2, qmp6988_data_.ik.b00, qmp6988_data_.ik.bt1,
qmp6988_data_.ik.bt2, qmp6988_data_.ik.bp1, qmp6988_data_.ik.b11, qmp6988_data_.ik.bp2, qmp6988_data_.ik.b12,
qmp6988_data_.ik.b21, qmp6988_data_.ik.bp3);
ESP_LOGV(TAG, "<----------- int calibration data -------------->\r\n");
return true;
}

View File

@@ -104,10 +104,7 @@ void ProntoProtocol::send_pronto_(RemoteTransmitData *dst, const std::vector<uin
uint16_t intros = 2 * data[2];
uint16_t repeats = 2 * data[3];
ESP_LOGD(TAG,
"Send Pronto: intros=%d\n"
"Send Pronto: repeats=%d",
intros, repeats);
ESP_LOGD(TAG, "Send Pronto: intros=%d, repeats=%d", intros, repeats);
if (NUMBERS_IN_PREAMBLE + intros + repeats != data.size()) { // inconsistent sizes
ESP_LOGE(TAG, "Inconsistent data, not sending");
return;

View File

@@ -51,13 +51,11 @@ void SafeModeComponent::dump_config() {
#if defined(USE_ESP32) && defined(USE_OTA_ROLLBACK)
const esp_partition_t *last_invalid = esp_ota_get_last_invalid_partition();
if (last_invalid != nullptr) {
ESP_LOGW(TAG,
"OTA rollback detected! Rolled back from partition '%s'\n"
"The device reset before the boot was marked successful",
last_invalid->label);
ESP_LOGW(TAG, "OTA rollback detected! Rolled back from partition '%s'", last_invalid->label);
ESP_LOGW(TAG, "The device reset before the boot was marked successful");
if (esp_reset_reason() == ESP_RST_BROWNOUT) {
ESP_LOGW(TAG, "Last reset was due to brownout - check your power supply!\n"
"See https://esphome.io/guides/faq.html#brownout-detector-was-triggered");
ESP_LOGW(TAG, "Last reset was due to brownout - check your power supply!");
ESP_LOGW(TAG, "See https://esphome.io/guides/faq.html#brownout-detector-was-triggered");
}
}
#endif

View File

@@ -903,6 +903,7 @@ async def setup_sensor_core_(var, config):
if config[CONF_FORCE_UPDATE]:
cg.add(var.set_force_update(True))
if config.get(CONF_FILTERS): # must exist and not be empty
cg.add_define("USE_SENSOR_FILTER")
filters = await build_filters(config[CONF_FILTERS])
cg.add(var.set_filters(filters))

View File

@@ -1,3 +1,6 @@
#include "esphome/core/defines.h"
#ifdef USE_SENSOR_FILTER
#include "filter.h"
#include <cmath>
#include "esphome/core/application.h"
@@ -580,3 +583,5 @@ void StreamingMovingAverageFilter::reset_batch() {
}
} // namespace esphome::sensor
#endif // USE_SENSOR_FILTER

View File

@@ -1,6 +1,8 @@
#pragma once
#include <queue>
#include "esphome/core/defines.h"
#ifdef USE_SENSOR_FILTER
#include <utility>
#include <vector>
#include "esphome/core/automation.h"
@@ -638,3 +640,5 @@ class StreamingMovingAverageFilter : public StreamingFilter {
};
} // namespace esphome::sensor
#endif // USE_SENSOR_FILTER

View File

@@ -68,11 +68,15 @@ void Sensor::publish_state(float state) {
ESP_LOGV(TAG, "'%s': Received new state %f", this->name_.c_str(), state);
#ifdef USE_SENSOR_FILTER
if (this->filter_list_ == nullptr) {
#endif
this->internal_send_state_to_frontend(state);
#ifdef USE_SENSOR_FILTER
} else {
this->filter_list_->input(state);
}
#endif
}
void Sensor::add_on_state_callback(std::function<void(float)> &&callback) { this->callback_.add(std::move(callback)); }
@@ -80,6 +84,7 @@ void Sensor::add_on_raw_state_callback(std::function<void(float)> &&callback) {
this->raw_callback_.add(std::move(callback));
}
#ifdef USE_SENSOR_FILTER
void Sensor::add_filter(Filter *filter) {
// inefficient, but only happens once on every sensor setup and nobody's going to have massive amounts of
// filters
@@ -109,6 +114,7 @@ void Sensor::clear_filters() {
}
this->filter_list_ = nullptr;
}
#endif // USE_SENSOR_FILTER
float Sensor::get_state() const { return this->state; }
float Sensor::get_raw_state() const { return this->raw_state; }

View File

@@ -4,13 +4,17 @@
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifdef USE_SENSOR_FILTER
#include "esphome/components/sensor/filter.h"
#endif
#include <initializer_list>
#include <memory>
namespace esphome::sensor {
class Sensor;
void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *obj);
#define LOG_SENSOR(prefix, type, obj) log_sensor(TAG, prefix, LOG_STR_LITERAL(type), obj)
@@ -67,6 +71,7 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
/// Set force update mode.
void set_force_update(bool force_update) { sensor_flags_.force_update = force_update; }
#ifdef USE_SENSOR_FILTER
/// Add a filter to the filter chain. Will be appended to the back.
void add_filter(Filter *filter);
@@ -87,6 +92,7 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
/// Clear the entire filter chain.
void clear_filters();
#endif
/// Getter-syntax for .state.
float get_state() const;
@@ -130,7 +136,9 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
LazyCallbackManager<void(float)> raw_callback_; ///< Storage for raw state callbacks.
LazyCallbackManager<void(float)> callback_; ///< Storage for filtered state callbacks.
#ifdef USE_SENSOR_FILTER
Filter *filter_list_{nullptr}; ///< Store all active filters.
#endif
// Group small members together to avoid padding
int8_t accuracy_decimals_{-1}; ///< Accuracy in decimals (-1 = not set)

View File

@@ -326,7 +326,7 @@ void Sim800LComponent::parse_cmd_(std::string message) {
if (ok || message.compare(0, 6, "+CMGL:") == 0) {
ESP_LOGD(TAG,
"Received SMS from: %s\n"
"%s",
" %s",
this->sender_.c_str(), this->message_.c_str());
this->sms_received_callback_.call(this->message_, this->sender_);
this->state_ = STATE_RECEIVED_SMS;

View File

@@ -1,9 +1,14 @@
from collections.abc import Callable, MutableMapping
from dataclasses import dataclass
from enum import StrEnum
import logging
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.core import CORE
_LOGGER = logging.getLogger(__name__)
CODEOWNERS = ["@esphome/core"]
CONF_IMPLEMENTATION = "implementation"
@@ -13,33 +18,110 @@ IMPLEMENTATION_BSD_SOCKETS = "bsd_sockets"
# Socket tracking infrastructure
# Components register their socket needs and platforms read this to configure appropriately
KEY_SOCKET_CONSUMERS = "socket_consumers"
KEY_SOCKET_CONSUMERS_TCP = "socket_consumers_tcp"
KEY_SOCKET_CONSUMERS_UDP = "socket_consumers_udp"
KEY_SOCKET_CONSUMERS_TCP_LISTEN = "socket_consumers_tcp_listen"
# Recommended minimum socket counts.
# Platforms should apply these (or their own) on top of get_socket_counts().
# These cover minimal configs (e.g. api-only without web_server).
# When web_server is present, its 5 registered sockets push past the TCP minimum.
MIN_TCP_SOCKETS = 8
MIN_UDP_SOCKETS = 6
# Minimum listening sockets — at least api + ota baseline.
MIN_TCP_LISTEN_SOCKETS = 2
# Wake loop threadsafe support tracking
KEY_WAKE_LOOP_THREADSAFE_REQUIRED = "wake_loop_threadsafe_required"
class SocketType(StrEnum):
TCP = "tcp"
UDP = "udp"
TCP_LISTEN = "tcp_listen"
_SOCKET_TYPE_KEYS = {
SocketType.TCP: KEY_SOCKET_CONSUMERS_TCP,
SocketType.UDP: KEY_SOCKET_CONSUMERS_UDP,
SocketType.TCP_LISTEN: KEY_SOCKET_CONSUMERS_TCP_LISTEN,
}
def consume_sockets(
value: int, consumer: str
value: int, consumer: str, socket_type: SocketType = SocketType.TCP
) -> Callable[[MutableMapping], MutableMapping]:
"""Register socket usage for a component.
Args:
value: Number of sockets needed by the component
consumer: Name of the component consuming the sockets
socket_type: Type of socket (SocketType.TCP, SocketType.UDP, or SocketType.TCP_LISTEN)
Returns:
A validator function that records the socket usage
"""
typed_key = _SOCKET_TYPE_KEYS[socket_type]
def _consume_sockets(config: MutableMapping) -> MutableMapping:
consumers: dict[str, int] = CORE.data.setdefault(KEY_SOCKET_CONSUMERS, {})
consumers: dict[str, int] = CORE.data.setdefault(typed_key, {})
consumers[consumer] = consumers.get(consumer, 0) + value
return config
return _consume_sockets
def _format_consumers(consumers: dict[str, int]) -> str:
"""Format consumer dict as 'name=count, ...' or 'none'."""
if not consumers:
return "none"
return ", ".join(f"{name}={count}" for name, count in sorted(consumers.items()))
@dataclass(frozen=True)
class SocketCounts:
"""Socket counts and component details for platform configuration."""
tcp: int
udp: int
tcp_listen: int
tcp_details: str
udp_details: str
tcp_listen_details: str
def get_socket_counts() -> SocketCounts:
"""Return socket counts and component details for platform configuration.
Platforms call this during code generation to configure lwIP socket limits.
All components will have registered their needs by then.
Platforms should apply their own minimums on top of these values.
"""
tcp_consumers = CORE.data.get(KEY_SOCKET_CONSUMERS_TCP, {})
udp_consumers = CORE.data.get(KEY_SOCKET_CONSUMERS_UDP, {})
tcp_listen_consumers = CORE.data.get(KEY_SOCKET_CONSUMERS_TCP_LISTEN, {})
tcp = sum(tcp_consumers.values())
udp = sum(udp_consumers.values())
tcp_listen = sum(tcp_listen_consumers.values())
tcp_details = _format_consumers(tcp_consumers)
udp_details = _format_consumers(udp_consumers)
tcp_listen_details = _format_consumers(tcp_listen_consumers)
_LOGGER.debug(
"Socket counts: TCP=%d (%s), UDP=%d (%s), TCP_LISTEN=%d (%s)",
tcp,
tcp_details,
udp,
udp_details,
tcp_listen,
tcp_listen_details,
)
return SocketCounts(
tcp, udp, tcp_listen, tcp_details, udp_details, tcp_listen_details
)
def require_wake_loop_threadsafe() -> None:
"""Mark that wake_loop_threadsafe support is required by a component.
@@ -66,7 +148,7 @@ def require_wake_loop_threadsafe() -> None:
CORE.data[KEY_WAKE_LOOP_THREADSAFE_REQUIRED] = True
cg.add_define("USE_WAKE_LOOP_THREADSAFE")
# Consume 1 socket for the shared wake notification socket
consume_sockets(1, "socket.wake_loop_threadsafe")({})
consume_sockets(1, "socket.wake_loop_threadsafe", SocketType.UDP)({})
CONFIG_SCHEMA = cv.Schema(

View File

@@ -93,10 +93,7 @@ bool SonoffD1Output::read_command_(uint8_t *cmd, size_t &len) {
if (this->read_array(cmd, 6)) {
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
char hex_buf[format_hex_pretty_size(6)];
ESP_LOGV(TAG,
"[%04d] Reading from dimmer:\n"
"[%04d] %s",
this->write_count_, this->write_count_, format_hex_pretty_to(hex_buf, cmd, 6));
ESP_LOGV(TAG, "[%04d] Reading from dimmer: %s", this->write_count_, format_hex_pretty_to(hex_buf, cmd, 6));
#endif
if (cmd[0] != 0xAA || cmd[1] != 0x55) {
@@ -190,10 +187,7 @@ bool SonoffD1Output::write_command_(uint8_t *cmd, const size_t len, bool needs_a
do {
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
char hex_buf[format_hex_pretty_size(SONOFF_D1_MAX_CMD_SIZE)];
ESP_LOGV(TAG,
"[%04d] Writing to the dimmer:\n"
"[%04d] %s",
this->write_count_, this->write_count_, format_hex_pretty_to(hex_buf, cmd, len));
ESP_LOGV(TAG, "[%04d] Writing to the dimmer: %s", this->write_count_, format_hex_pretty_to(hex_buf, cmd, len));
#endif
this->write_array(cmd, len);
this->write_count_++;

View File

@@ -6,6 +6,7 @@
#include "esphome/components/microphone/microphone_source.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/ring_buffer.h"

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