mirror of
https://github.com/esphome/esphome.git
synced 2026-01-19 17:46:23 -07:00
119 lines
4.8 KiB
Markdown
119 lines
4.8 KiB
Markdown
# add_on_state_callback Usage Analysis
|
|
|
|
## Summary
|
|
|
|
After the Controller Registry migration (PR #11772), `add_on_state_callback` is still widely used in the codebase, but for **legitimate reasons** - components that genuinely need per-entity state tracking.
|
|
|
|
## Usage Breakdown
|
|
|
|
### 1. **MQTT Components** (~17 uses)
|
|
**Purpose:** Per-entity MQTT configuration requires callbacks
|
|
- Each MQTT component instance needs to publish to custom topics with custom QoS/retain settings
|
|
- Cannot use Controller pattern due to per-entity configuration overhead
|
|
- Examples: `mqtt_sensor.cpp`, `mqtt_climate.cpp`, `mqtt_number.cpp`, etc.
|
|
|
|
```cpp
|
|
this->sensor_->add_on_state_callback([this](float state) {
|
|
this->publish_state(state);
|
|
});
|
|
```
|
|
|
|
### 2. **Copy Components** (~10 uses)
|
|
**Purpose:** Mirror state from one entity to another
|
|
- Each copy instance tracks a different source entity
|
|
- Legitimate use of callbacks for entity-to-entity synchronization
|
|
- Examples: `copy_sensor.cpp`, `copy_fan.cpp`, `copy_select.cpp`, etc.
|
|
|
|
```cpp
|
|
source_->add_on_state_callback([this](const std::string &value) {
|
|
this->publish_state(value);
|
|
});
|
|
```
|
|
|
|
### 3. **Derivative Sensors** (~5-7 uses)
|
|
**Purpose:** Compute derived values from source sensors
|
|
- **integration_sensor:** Integrates sensor values over time
|
|
- **total_daily_energy:** Tracks cumulative energy
|
|
- **combination:** Combines multiple sensor values
|
|
- **graph:** Samples sensor data for display
|
|
- **duty_time:** Tracks on-time duration
|
|
- **ntc/absolute_humidity/resistance:** Mathematical transformations
|
|
|
|
```cpp
|
|
this->sensor_->add_on_state_callback([this](float state) {
|
|
this->process_sensor_value_(state);
|
|
});
|
|
```
|
|
|
|
### 4. **Climate/Cover with Sensors** (~10-15 uses)
|
|
**Purpose:** External sensors providing feedback to control loops
|
|
- **feedback_cover:** Binary sensors for open/close/obstacle detection
|
|
- **bang_bang/pid/thermostat:** External temperature sensors for climate control
|
|
- **climate_ir (toshiba/yashima/heatpumpir):** Temperature sensors for IR climate
|
|
|
|
```cpp
|
|
this->sensor_->add_on_state_callback([this](float state) {
|
|
this->current_temperature = state;
|
|
// Trigger control loop update
|
|
});
|
|
```
|
|
|
|
### 5. **Entity Base Classes** (~10-15 definitions)
|
|
**Purpose:** Provide the callback interface for all entities
|
|
- Not actual usage, just the method definitions
|
|
- Examples: `sensor.cpp::add_on_state_callback()`, `climate.cpp::add_on_state_callback()`, etc.
|
|
|
|
### 6. **Automation Trigger Classes** (~15-20 definitions)
|
|
**Purpose:** User-defined YAML automations need callbacks
|
|
- Files like `sensor/automation.h`, `climate/automation.h`
|
|
- Implement triggers like `on_value:`, `on_state:`
|
|
- Cannot be migrated - this is user-facing automation functionality
|
|
|
|
### 7. **Miscellaneous** (~5-10 uses)
|
|
- **voice_assistant/micro_wake_word:** State coordination
|
|
- **esp32_improv:** Provisioning state tracking
|
|
- **http_request/update:** Update status monitoring
|
|
- **switch/binary_sensor:** Cross-component dependencies
|
|
- **OTA callbacks:** OTA state monitoring
|
|
|
|
## Key Insights
|
|
|
|
### What's NOT Using Callbacks Anymore ✅
|
|
**API Server and WebServer** - migrated to Controller Registry
|
|
- **Before:** Each entity had 2 callbacks (API + WebServer) = ~32 bytes overhead
|
|
- **After:** Zero per-entity overhead = saves ~32 bytes per entity
|
|
|
|
### What SHOULD Keep Using Callbacks ✅
|
|
All the above categories have legitimate reasons:
|
|
|
|
1. **Per-entity configuration:** MQTT needs custom topics/QoS per entity
|
|
2. **Entity-to-entity relationships:** Copy components, derivative sensors
|
|
3. **Control loop feedback:** Climate/cover with external sensors
|
|
4. **User-defined automations:** YAML triggers configured by users
|
|
5. **Component dependencies:** Components that genuinely depend on other entities
|
|
|
|
## Memory Impact
|
|
|
|
**Per Sensor (ESP32):**
|
|
- Empty callback infrastructure: **~16 bytes** (unique_ptr + empty vector)
|
|
- With one callback (e.g., MQTT): **~32 bytes** (16 + std::function)
|
|
- With multiple callbacks: **~32 + 16n bytes** (where n = additional callbacks)
|
|
|
|
**Typical scenarios:**
|
|
- Sensor with **only API/WebServer:** ~16 bytes (no callbacks registered)
|
|
- Sensor with **MQTT:** ~32 bytes (one callback)
|
|
- Sensor with **MQTT + automation:** ~48 bytes (two callbacks)
|
|
- Sensor with **copy + total_daily_energy + graph:** ~64 bytes (three callbacks)
|
|
|
|
## Conclusion
|
|
|
|
The callback system is still heavily used (~103 occurrences) but for **appropriate reasons**:
|
|
- Components with per-entity state/configuration (MQTT, Copy)
|
|
- Sensor processing chains (derivatives, transformations)
|
|
- Control loops with external feedback (climate, covers)
|
|
- User-defined automations (cannot be removed)
|
|
|
|
The Controller Registry successfully eliminated wasteful callbacks for **stateless global handlers** (API/WebServer), saving ~32 bytes per entity for those use cases.
|
|
|
|
**No further callback elimination opportunities** exist without fundamentally changing ESPHome's architecture or breaking user-facing features.
|