mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 23:37:34 +00:00
Merge branch 'dev' into deprecate-sensor-raw-state
This commit is contained in:
@@ -18,12 +18,6 @@ void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
|
||||
void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
|
||||
#endif
|
||||
|
||||
// set_use_address() is guaranteed to be called during component setup by Python code generation,
|
||||
// so use_address_ will always be valid when get_use_address() is called - no fallback needed.
|
||||
const char *EthernetComponent::get_use_address() const { return this->use_address_; }
|
||||
|
||||
void EthernetComponent::set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
|
||||
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||
void EthernetComponent::notify_ip_state_listeners_() {
|
||||
auto ips = this->get_ip_addresses();
|
||||
|
||||
@@ -103,8 +103,8 @@ class EthernetComponent final : public Component {
|
||||
|
||||
network::IPAddresses get_ip_addresses();
|
||||
network::IPAddress get_dns_address(uint8_t num);
|
||||
const char *get_use_address() const;
|
||||
void set_use_address(const char *use_address);
|
||||
const char *get_use_address() const { return this->use_address_; }
|
||||
void set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
void get_eth_mac_address_raw(uint8_t *mac);
|
||||
// Remove before 2026.9.0
|
||||
ESPDEPRECATED("Use get_eth_mac_address_pretty_into_buffer() instead. Removed in 2026.9.0", "2026.3.0")
|
||||
|
||||
@@ -42,29 +42,5 @@ network::IPAddresses get_ip_addresses() {
|
||||
return {};
|
||||
}
|
||||
|
||||
const char *get_use_address() {
|
||||
// Global component pointers are guaranteed to be set by component constructors when USE_* is defined
|
||||
#ifdef USE_ETHERNET
|
||||
return ethernet::global_eth_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#ifdef USE_MODEM
|
||||
return modem::global_modem_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIFI
|
||||
return wifi::global_wifi_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENTHREAD
|
||||
return openthread::global_openthread_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ETHERNET) && !defined(USE_MODEM) && !defined(USE_WIFI) && !defined(USE_OPENTHREAD)
|
||||
// Fallback when no network component is defined (e.g., host platform)
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace esphome::network
|
||||
#endif
|
||||
|
||||
@@ -54,7 +54,29 @@ ESPHOME_ALWAYS_INLINE inline bool is_connected() {
|
||||
/// Return whether the network is disabled (only wifi for now)
|
||||
bool is_disabled();
|
||||
/// Get the active network hostname
|
||||
const char *get_use_address();
|
||||
ESPHOME_ALWAYS_INLINE inline const char *get_use_address() {
|
||||
// Global component pointers are guaranteed to be set by component constructors when USE_* is defined
|
||||
#ifdef USE_ETHERNET
|
||||
return ethernet::global_eth_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#ifdef USE_MODEM
|
||||
return modem::global_modem_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIFI
|
||||
return wifi::global_wifi_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENTHREAD
|
||||
return openthread::global_openthread_component->get_use_address();
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ETHERNET) && !defined(USE_MODEM) && !defined(USE_WIFI) && !defined(USE_OPENTHREAD)
|
||||
// Fallback when no network component is defined (e.g., host platform)
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
IPAddresses get_ip_addresses();
|
||||
|
||||
} // namespace esphome::network
|
||||
|
||||
@@ -257,11 +257,5 @@ void OpenThreadComponent::on_factory_reset(std::function<void()> callback) {
|
||||
ESP_LOGD(TAG, "Waiting on Confirmation Removal SRP Host and Services");
|
||||
}
|
||||
|
||||
// set_use_address() is guaranteed to be called during component setup by Python code generation,
|
||||
// so use_address_ will always be valid when get_use_address() is called - no fallback needed.
|
||||
const char *OpenThreadComponent::get_use_address() const { return this->use_address_; }
|
||||
|
||||
void OpenThreadComponent::set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
|
||||
} // namespace esphome::openthread
|
||||
#endif
|
||||
|
||||
@@ -37,8 +37,8 @@ class OpenThreadComponent : public Component {
|
||||
void on_factory_reset(std::function<void()> callback);
|
||||
void defer_factory_reset_external_callback();
|
||||
|
||||
const char *get_use_address() const;
|
||||
void set_use_address(const char *use_address);
|
||||
const char *get_use_address() const { return this->use_address_; }
|
||||
void set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
#if CONFIG_OPENTHREAD_MTD
|
||||
void set_poll_period(uint32_t poll_period) { this->poll_period_ = poll_period; }
|
||||
#endif
|
||||
|
||||
@@ -891,10 +891,6 @@ network::IPAddress WiFiComponent::get_dns_address(int num) {
|
||||
return this->wifi_dns_ip_(num);
|
||||
return {};
|
||||
}
|
||||
// set_use_address() is guaranteed to be called during component setup by Python code generation,
|
||||
// so use_address_ will always be valid when get_use_address() is called - no fallback needed.
|
||||
const char *WiFiComponent::get_use_address() const { return this->use_address_; }
|
||||
void WiFiComponent::set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
|
||||
#ifdef USE_WIFI_AP
|
||||
void WiFiComponent::setup_ap_config_() {
|
||||
|
||||
@@ -481,8 +481,8 @@ class WiFiComponent final : public Component {
|
||||
|
||||
network::IPAddress get_dns_address(int num);
|
||||
network::IPAddresses get_ip_addresses();
|
||||
const char *get_use_address() const;
|
||||
void set_use_address(const char *use_address);
|
||||
const char *get_use_address() const { return this->use_address_; }
|
||||
void set_use_address(const char *use_address) { this->use_address_ = use_address; }
|
||||
|
||||
const wifi_scan_vector_t<WiFiScanResult> &get_scan_result() const { return scan_result_; }
|
||||
|
||||
|
||||
@@ -166,7 +166,13 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
|
||||
item->component = component;
|
||||
item->set_name(name_type, static_name, hash_or_id);
|
||||
item->type = type;
|
||||
item->callback = std::move(func);
|
||||
// Use destroy + placement-new instead of move-assignment.
|
||||
// GCC's std::function::operator=(function&&) does a full swap dance even when the
|
||||
// target is empty. Since recycled/new items always have an empty callback, we can
|
||||
// destroy the empty one (no-op) and move-construct directly, saving ~40 bytes of
|
||||
// swap/destructor code on Xtensa.
|
||||
item->callback.~function();
|
||||
new (&item->callback) std::function<void()>(std::move(func));
|
||||
// Reset remove flag - recycled items may have been cancelled (remove=true) in previous use
|
||||
this->set_item_removed_(item, false);
|
||||
item->is_retry = is_retry;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
manifest.enable_codegen()
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
|
||||
namespace esphome::binary_sensor::benchmarks {
|
||||
|
||||
static constexpr int kInnerIterations = 2000;
|
||||
|
||||
// Benchmark: publish_state with alternating values (forces state change every time)
|
||||
static void BinarySensorPublish_Alternating(benchmark::State &state) {
|
||||
BinarySensor sensor;
|
||||
|
||||
// First publish to establish initial state
|
||||
sensor.publish_initial_state(false);
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < kInnerIterations; i++) {
|
||||
sensor.publish_state(i % 2 == 0);
|
||||
}
|
||||
benchmark::DoNotOptimize(sensor.state);
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
||||
}
|
||||
BENCHMARK(BinarySensorPublish_Alternating);
|
||||
|
||||
// Benchmark: publish_state with same value (tests dedup fast path)
|
||||
static void BinarySensorPublish_NoChange(benchmark::State &state) {
|
||||
BinarySensor sensor;
|
||||
|
||||
sensor.publish_initial_state(true);
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < kInnerIterations; i++) {
|
||||
sensor.publish_state(true);
|
||||
}
|
||||
benchmark::DoNotOptimize(sensor.state);
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
||||
}
|
||||
BENCHMARK(BinarySensorPublish_NoChange);
|
||||
|
||||
// Benchmark: publish_state with a callback registered
|
||||
static void BinarySensorPublish_WithCallback(benchmark::State &state) {
|
||||
BinarySensor sensor;
|
||||
|
||||
int callback_count = 0;
|
||||
sensor.add_on_state_callback([&callback_count](bool) { callback_count++; });
|
||||
|
||||
sensor.publish_initial_state(false);
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < kInnerIterations; i++) {
|
||||
sensor.publish_state(i % 2 == 0);
|
||||
}
|
||||
benchmark::DoNotOptimize(callback_count);
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
||||
}
|
||||
BENCHMARK(BinarySensorPublish_WithCallback);
|
||||
|
||||
} // namespace esphome::binary_sensor::benchmarks
|
||||
@@ -0,0 +1 @@
|
||||
binary_sensor:
|
||||
@@ -0,0 +1,12 @@
|
||||
import esphome.codegen as cg
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# Sensor filter benchmarks need USE_SENSOR_FILTER defined.
|
||||
# We use a custom to_code instead of enable_codegen() to avoid
|
||||
# pulling in the full sensor component setup.
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_SENSOR_FILTER")
|
||||
|
||||
manifest.to_code = to_code
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/sensor/filter.h"
|
||||
|
||||
namespace esphome::sensor::benchmarks {
|
||||
|
||||
static constexpr int kInnerIterations = 2000;
|
||||
|
||||
// Benchmark: sensor publish through a SlidingWindowMovingAverageFilter (window=5, send_every=1)
|
||||
static void SensorFilter_SlidingWindowAvg(benchmark::State &state) {
|
||||
Sensor sensor;
|
||||
|
||||
// Create filter: window_size=5, send_every=1, send_first_at=1
|
||||
auto *filter = new SlidingWindowMovingAverageFilter(5, 1, 1);
|
||||
sensor.add_filter(filter);
|
||||
|
||||
float value = 0.0f;
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < kInnerIterations; i++) {
|
||||
sensor.publish_state(value);
|
||||
value += 0.1f;
|
||||
if (value > 1000.0f)
|
||||
value = 0.0f;
|
||||
}
|
||||
benchmark::DoNotOptimize(sensor.state);
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
||||
}
|
||||
BENCHMARK(SensorFilter_SlidingWindowAvg);
|
||||
|
||||
// Benchmark: sensor publish through ExponentialMovingAverageFilter
|
||||
static void SensorFilter_ExponentialMovingAvg(benchmark::State &state) {
|
||||
Sensor sensor;
|
||||
|
||||
// alpha=0.1, send_every=1, send_first_at=1
|
||||
auto *filter = new ExponentialMovingAverageFilter(0.1f, 1, 1);
|
||||
sensor.add_filter(filter);
|
||||
|
||||
float value = 0.0f;
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < kInnerIterations; i++) {
|
||||
sensor.publish_state(value);
|
||||
value += 0.1f;
|
||||
if (value > 1000.0f)
|
||||
value = 0.0f;
|
||||
}
|
||||
benchmark::DoNotOptimize(sensor.state);
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
||||
}
|
||||
BENCHMARK(SensorFilter_ExponentialMovingAvg);
|
||||
|
||||
// Benchmark: sensor publish through a chain of 3 filters (offset + multiply + sliding window)
|
||||
static void SensorFilter_Chain3(benchmark::State &state) {
|
||||
Sensor sensor;
|
||||
|
||||
sensor.add_filters({
|
||||
new OffsetFilter(1.0f),
|
||||
new MultiplyFilter(2.0f),
|
||||
new SlidingWindowMovingAverageFilter(5, 1, 1),
|
||||
});
|
||||
|
||||
float value = 0.0f;
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < kInnerIterations; i++) {
|
||||
sensor.publish_state(value);
|
||||
value += 0.1f;
|
||||
if (value > 1000.0f)
|
||||
value = 0.0f;
|
||||
}
|
||||
benchmark::DoNotOptimize(sensor.state);
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
||||
}
|
||||
BENCHMARK(SensorFilter_Chain3);
|
||||
|
||||
} // namespace esphome::sensor::benchmarks
|
||||
@@ -0,0 +1 @@
|
||||
sensor:
|
||||
Reference in New Issue
Block a user