Reduce memory required for sensor entities (#9201)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
J. Nick Koston 2025-06-26 01:15:59 +02:00 committed by GitHub
parent 6d0c6329ad
commit 17497eec43
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 49 additions and 11 deletions

View File

@ -23,16 +23,22 @@ std::string state_class_to_string(StateClass state_class) {
Sensor::Sensor() : state(NAN), raw_state(NAN) {} Sensor::Sensor() : state(NAN), raw_state(NAN) {}
int8_t Sensor::get_accuracy_decimals() { int8_t Sensor::get_accuracy_decimals() {
if (this->accuracy_decimals_.has_value()) if (this->sensor_flags_.has_accuracy_override)
return *this->accuracy_decimals_; return this->accuracy_decimals_;
return 0; return 0;
} }
void Sensor::set_accuracy_decimals(int8_t accuracy_decimals) { this->accuracy_decimals_ = accuracy_decimals; } void Sensor::set_accuracy_decimals(int8_t accuracy_decimals) {
this->accuracy_decimals_ = accuracy_decimals;
this->sensor_flags_.has_accuracy_override = true;
}
void Sensor::set_state_class(StateClass state_class) { this->state_class_ = state_class; } void Sensor::set_state_class(StateClass state_class) {
this->state_class_ = state_class;
this->sensor_flags_.has_state_class_override = true;
}
StateClass Sensor::get_state_class() { StateClass Sensor::get_state_class() {
if (this->state_class_.has_value()) if (this->sensor_flags_.has_state_class_override)
return *this->state_class_; return this->state_class_;
return StateClass::STATE_CLASS_NONE; return StateClass::STATE_CLASS_NONE;
} }

View File

@ -80,9 +80,9 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
* state changes to the database when they are published, even if the state is the * state changes to the database when they are published, even if the state is the
* same as before. * same as before.
*/ */
bool get_force_update() const { return force_update_; } bool get_force_update() const { return sensor_flags_.force_update; }
/// Set force update mode. /// Set force update mode.
void set_force_update(bool force_update) { force_update_ = force_update; } void set_force_update(bool force_update) { sensor_flags_.force_update = force_update; }
/// Add a filter to the filter chain. Will be appended to the back. /// Add a filter to the filter chain. Will be appended to the back.
void add_filter(Filter *filter); void add_filter(Filter *filter);
@ -155,9 +155,17 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
Filter *filter_list_{nullptr}; ///< Store all active filters. Filter *filter_list_{nullptr}; ///< Store all active filters.
optional<int8_t> accuracy_decimals_; ///< Accuracy in decimals override // Group small members together to avoid padding
optional<StateClass> state_class_{STATE_CLASS_NONE}; ///< State class override int8_t accuracy_decimals_{-1}; ///< Accuracy in decimals (-1 = not set)
bool force_update_{false}; ///< Force update mode StateClass state_class_{STATE_CLASS_NONE}; ///< State class (STATE_CLASS_NONE = not set)
// Bit-packed flags for sensor-specific settings
struct SensorFlags {
uint8_t has_accuracy_override : 1;
uint8_t has_state_class_override : 1;
uint8_t force_update : 1;
uint8_t reserved : 5; // Reserved for future use
} sensor_flags_{};
}; };
} // namespace sensor } // namespace sensor

View File

@ -8,5 +8,8 @@ sensor:
name: Test Sensor name: Test Sensor
id: test_sensor id: test_sensor
unit_of_measurement: °C unit_of_measurement: °C
accuracy_decimals: 2
state_class: measurement
force_update: true
lambda: return 42.0; lambda: return 42.0;
update_interval: 0.1s update_interval: 0.1s

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio import asyncio
import aioesphomeapi
from aioesphomeapi import EntityState from aioesphomeapi import EntityState
import pytest import pytest
@ -47,3 +48,23 @@ async def test_host_mode_with_sensor(
# Verify the sensor state # Verify the sensor state
assert test_sensor_state.state == 42.0 assert test_sensor_state.state == 42.0
assert len(states) > 0, "No states received" assert len(states) > 0, "No states received"
# Verify the optimized fields are working correctly
# Get entity info to check accuracy_decimals, state_class, etc.
entities, _ = await client.list_entities_services()
sensor_info: aioesphomeapi.SensorInfo | None = None
for entity in entities:
if isinstance(entity, aioesphomeapi.SensorInfo):
sensor_info = entity
break
assert sensor_info is not None, "Sensor entity info not found"
assert sensor_info.accuracy_decimals == 2, (
f"Expected accuracy_decimals=2, got {sensor_info.accuracy_decimals}"
)
assert sensor_info.state_class == 1, (
f"Expected state_class=1 (measurement), got {sensor_info.state_class}"
)
assert sensor_info.force_update is True, (
f"Expected force_update=True, got {sensor_info.force_update}"
)