[packet_transport] Use FixedVector and parent pointer to enable inline Callback storage (#14946)

This commit is contained in:
J. Nick Koston
2026-03-22 12:41:54 -10:00
committed by GitHub
parent 84727b1f71
commit 2c06464f7b
5 changed files with 39 additions and 12 deletions
@@ -177,13 +177,19 @@ async def register_packet_transport(var, config):
cg.add(var.set_provider_encryption(name, hash_encryption_key(encryption)))
is_provider = False
for sens_conf in config.get(CONF_SENSORS, ()):
sensors = config.get(CONF_SENSORS, ())
binary_sensors = config.get(CONF_BINARY_SENSORS, ())
if sensors:
cg.add(var.set_sensor_count(len(sensors)))
if binary_sensors:
cg.add(var.set_binary_sensor_count(len(binary_sensors)))
for sens_conf in sensors:
is_provider = True
sens_id = sens_conf[CONF_ID]
sensor = await cg.get_variable(sens_id)
bcst_id = sens_conf.get(CONF_BROADCAST_ID, sens_id.id)
cg.add(var.add_sensor(bcst_id, sensor))
for sens_conf in config.get(CONF_BINARY_SENSORS, ()):
for sens_conf in binary_sensors:
is_provider = True
sens_id = sens_conf[CONF_ID]
sensor = await cg.get_variable(sens_id)
@@ -221,16 +221,20 @@ void PacketTransport::setup() {
}
#ifdef USE_SENSOR
for (auto &sensor : this->sensors_) {
sensor.sensor->add_on_state_callback([this, &sensor](float x) {
this->updated_ = true;
// [&sensor] is safe: sensor refers to a FixedVector element that never reallocates,
// so the reference remains valid for the component's lifetime.
sensor.sensor->add_on_state_callback([&sensor](float x) {
sensor.parent->updated_ = true;
sensor.updated = true;
});
}
#endif
#ifdef USE_BINARY_SENSOR
for (auto &sensor : this->binary_sensors_) {
sensor.sensor->add_on_state_callback([this, &sensor](bool value) {
this->updated_ = true;
// [&sensor] is safe: sensor refers to a FixedVector element that never reallocates,
// so the reference remains valid for the component's lifetime.
sensor.sensor->add_on_state_callback([&sensor](bool value) {
sensor.parent->updated_ = true;
sensor.updated = true;
});
}
@@ -548,11 +552,11 @@ void PacketTransport::dump_config() {
" Ping-pong: %s",
this->platform_name_, YESNO(this->is_encrypted_()), YESNO(this->ping_pong_enable_));
#ifdef USE_SENSOR
for (auto sensor : this->sensors_)
for (const auto &sensor : this->sensors_)
ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.id);
#endif
#ifdef USE_BINARY_SENSOR
for (auto sensor : this->binary_sensors_)
for (const auto &sensor : this->binary_sensors_)
ESP_LOGCONFIG(TAG, " Binary Sensor: %s", sensor.id);
#endif
for (const auto &host : this->providers_) {
@@ -1,6 +1,7 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
@@ -37,11 +38,14 @@ struct Provider {
#endif
};
class PacketTransport;
#ifdef USE_SENSOR
struct Sensor {
sensor::Sensor *sensor;
const char *id;
bool updated;
PacketTransport *parent;
};
#endif
#ifdef USE_BINARY_SENSOR
@@ -49,6 +53,7 @@ struct BinarySensor {
binary_sensor::BinarySensor *sensor;
const char *id;
bool updated;
PacketTransport *parent;
};
#endif
@@ -60,8 +65,9 @@ class PacketTransport : public PollingComponent {
void dump_config() override;
#ifdef USE_SENSOR
void set_sensor_count(size_t count) { this->sensors_.init(count); }
void add_sensor(const char *id, sensor::Sensor *sensor) {
Sensor st{sensor, id, true};
Sensor st{sensor, id, true, this};
this->sensors_.push_back(st);
}
void add_remote_sensor(const char *hostname, const char *remote_id, sensor::Sensor *sensor) {
@@ -70,8 +76,9 @@ class PacketTransport : public PollingComponent {
}
#endif
#ifdef USE_BINARY_SENSOR
void set_binary_sensor_count(size_t count) { this->binary_sensors_.init(count); }
void add_binary_sensor(const char *id, binary_sensor::BinarySensor *sensor) {
BinarySensor st{sensor, id, true};
BinarySensor st{sensor, id, true, this};
this->binary_sensors_.push_back(st);
}
@@ -141,11 +148,11 @@ class PacketTransport : public PollingComponent {
std::vector<uint8_t> encryption_key_{};
#ifdef USE_SENSOR
std::vector<Sensor> sensors_{};
FixedVector<Sensor> sensors_{};
string_map_t<string_map_t<sensor::Sensor *>> remote_sensors_{};
#endif
#ifdef USE_BINARY_SENSOR
std::vector<BinarySensor> binary_sensors_{};
FixedVector<BinarySensor> binary_sensors_{};
string_map_t<string_map_t<binary_sensor::BinarySensor *>> remote_binary_sensors_{};
#endif
@@ -5,6 +5,7 @@ namespace esphome::packet_transport::testing {
TEST(PacketTransportBinarySensorTest, AddBinarySensor) {
TestablePacketTransport transport;
binary_sensor::BinarySensor bs;
transport.set_binary_sensor_count(1);
transport.add_binary_sensor("motion", &bs);
ASSERT_EQ(transport.binary_sensors_.size(), 1u);
EXPECT_STREQ(transport.binary_sensors_[0].id, "motion");
@@ -24,6 +25,7 @@ TEST(PacketTransportBinarySensorTest, UnencryptedBinarySensorRoundTrip) {
encoder.init_for_test("sender");
binary_sensor::BinarySensor local_bs;
local_bs.state = true;
encoder.set_binary_sensor_count(1);
encoder.add_binary_sensor("motion", &local_bs);
encoder.send_data_(true);
@@ -46,11 +48,13 @@ TEST(PacketTransportBinarySensorTest, MultipleSensorsRoundTrip) {
sensor::Sensor s1, s2;
s1.state = 10.0f;
s2.state = 20.0f;
encoder.set_sensor_count(2);
encoder.add_sensor("s1", &s1);
encoder.add_sensor("s2", &s2);
binary_sensor::BinarySensor bs1;
bs1.state = true;
encoder.set_binary_sensor_count(1);
encoder.add_binary_sensor("bs1", &bs1);
encoder.send_data_(true);
@@ -5,6 +5,7 @@ namespace esphome::packet_transport::testing {
TEST(PacketTransportSensorTest, AddSensor) {
TestablePacketTransport transport;
sensor::Sensor s;
transport.set_sensor_count(1);
transport.add_sensor("temp", &s);
ASSERT_EQ(transport.sensors_.size(), 1u);
EXPECT_STREQ(transport.sensors_[0].id, "temp");
@@ -26,6 +27,7 @@ TEST(PacketTransportSensorTest, UnencryptedSensorRoundTrip) {
encoder.init_for_test("sender");
sensor::Sensor local_sensor;
local_sensor.state = 42.5f;
encoder.set_sensor_count(1);
encoder.add_sensor("temp", &local_sensor);
encoder.send_data_(true);
@@ -53,6 +55,7 @@ TEST(PacketTransportSensorTest, EncryptedSensorRoundTrip) {
encoder.set_encryption_key(key);
sensor::Sensor local_sensor;
local_sensor.state = 99.9f;
encoder.set_sensor_count(1);
encoder.add_sensor("temp", &local_sensor);
encoder.send_data_(true);
@@ -77,6 +80,7 @@ TEST(PacketTransportSensorTest, SendDataOnlyUpdated) {
sensor::Sensor s1, s2;
s1.state = 1.0f;
s2.state = 2.0f;
encoder.set_sensor_count(2);
encoder.add_sensor("s1", &s1);
encoder.add_sensor("s2", &s2);
@@ -111,6 +115,7 @@ TEST(PacketTransportSensorTest, PingKeyIncludedInTransmittedPacket) {
responder.set_encryption_key(key);
sensor::Sensor local_sensor;
local_sensor.state = 77.7f;
responder.set_sensor_count(1);
responder.add_sensor("temp", &local_sensor);
// Requester sends a MAGIC_PING that the responder processes
@@ -148,6 +153,7 @@ TEST(PacketTransportSensorTest, MissingPingKeyBlocksSensorData) {
responder.set_encryption_key(key);
sensor::Sensor local_sensor;
local_sensor.state = 77.7f;
responder.set_sensor_count(1);
responder.add_sensor("temp", &local_sensor);
responder.send_data_(true);
ASSERT_EQ(responder.sent_packets.size(), 1u);