mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
docs(architecture): update architecture documentation with Calculator Pattern details and sensor organization
This commit is contained in:
parent
a962289682
commit
3d1b6a64fc
1 changed files with 63 additions and 15 deletions
|
|
@ -197,17 +197,46 @@ For detailed cache behavior, see [Caching Strategy](./caching-strategy.md).
|
|||
| **Coordinator** | `coordinator.py` | Update orchestration, cache management, absolute-time scheduling with boundary tolerance |
|
||||
| **Data Transformer** | `coordinator/data_transformation.py` | Price enrichment (averages, ratings, differences) |
|
||||
| **Period Calculator** | `coordinator/periods.py` | Best/peak price period calculation with relaxation |
|
||||
| **Sensors** | `sensor/` | 120+ entities for prices, levels, ratings, statistics |
|
||||
| **Sensors** | `sensor/` | 80+ entities for prices, levels, ratings, statistics |
|
||||
| **Binary Sensors** | `binary_sensor/` | Period indicators (best/peak price active) |
|
||||
| **Services** | `services.py` | Custom service endpoints (get_price, ApexCharts) |
|
||||
|
||||
### Sensor Architecture (Calculator Pattern)
|
||||
|
||||
The sensor platform uses **Calculator Pattern** for clean separation of concerns (refactored Nov 2025):
|
||||
|
||||
| Component | Files | Lines | Responsibility |
|
||||
|-----------|-------|-------|----------------|
|
||||
| **Entity Class** | `sensor/core.py` | 909 | Entity lifecycle, coordinator, delegates to calculators |
|
||||
| **Calculators** | `sensor/calculators/` | 1,838 | Business logic (8 specialized calculators) |
|
||||
| **Attributes** | `sensor/attributes/` | 1,209 | State presentation (8 specialized modules) |
|
||||
| **Routing** | `sensor/value_getters.py` | 276 | Centralized sensor → calculator mapping |
|
||||
| **Chart Export** | `sensor/chart_data.py` | 144 | Service call handling, YAML parsing |
|
||||
| **Helpers** | `sensor/helpers.py` | 188 | Aggregation functions, utilities |
|
||||
|
||||
**Calculator Package** (`sensor/calculators/`):
|
||||
- `base.py` - Abstract BaseCalculator with coordinator access
|
||||
- `interval.py` - Single interval calculations (current/next/previous)
|
||||
- `rolling_hour.py` - 5-interval rolling windows
|
||||
- `daily_stat.py` - Calendar day min/max/avg statistics
|
||||
- `window_24h.py` - Trailing/leading 24h windows
|
||||
- `volatility.py` - Price volatility analysis
|
||||
- `trend.py` - Complex trend analysis with caching
|
||||
- `timing.py` - Best/peak price period timing
|
||||
- `metadata.py` - Home/metering metadata
|
||||
|
||||
**Benefits:**
|
||||
- 58% reduction in core.py (2,170 → 909 lines)
|
||||
- Clear separation: Calculators (logic) vs Attributes (presentation)
|
||||
- Independent testability for each calculator
|
||||
- Easy to add sensors: Choose calculation pattern, add to routing
|
||||
|
||||
### Helper Utilities
|
||||
|
||||
| Utility | File | Purpose |
|
||||
|---------|------|---------|
|
||||
| **Price Utils** | `price_utils.py` | Rating calculation, enrichment, level aggregation |
|
||||
| **Average Utils** | `average_utils.py` | Trailing/leading 24h average calculations |
|
||||
| **Sensor Helpers** | `sensor/helpers.py` | Interval detection with smart boundary tolerance (±2s) |
|
||||
| **Price Utils** | `utils/price.py` | Rating calculation, enrichment, level aggregation |
|
||||
| **Average Utils** | `utils/average.py` | Trailing/leading 24h average calculations |
|
||||
| **Entity Utils** | `entity_utils/` | Shared icon/color/attribute logic |
|
||||
| **Translations** | `const.py` | Translation loading and caching |
|
||||
|
||||
|
|
@ -224,7 +253,7 @@ For detailed cache behavior, see [Caching Strategy](./caching-strategy.md).
|
|||
|
||||
### 2. Price Data Enrichment
|
||||
|
||||
All quarter-hourly price intervals get augmented:
|
||||
All quarter-hourly price intervals get augmented via `utils/price.py`:
|
||||
|
||||
```python
|
||||
# Original from Tibber API
|
||||
|
|
@ -234,7 +263,7 @@ All quarter-hourly price intervals get augmented:
|
|||
"level": "NORMAL"
|
||||
}
|
||||
|
||||
# After enrichment (price_utils.py)
|
||||
# After enrichment (utils/price.py)
|
||||
{
|
||||
"startsAt": "2025-11-03T14:00:00+01:00",
|
||||
"total": 0.2534,
|
||||
|
|
@ -248,26 +277,45 @@ All quarter-hourly price intervals get augmented:
|
|||
### 3. Quarter-Hour Precision
|
||||
|
||||
- **API polling**: Every 15 minutes (coordinator fetch cycle)
|
||||
- **Entity updates**: On 00/15/30/45-minute boundaries via `_schedule_quarter_hour_refresh()`
|
||||
- **Entity updates**: On 00/15/30/45-minute boundaries via `coordinator/listeners.py`
|
||||
- **Timer scheduling**: Uses `async_track_utc_time_change(minute=[0, 15, 30, 45], second=0)`
|
||||
- HA may trigger ±few milliseconds before/after exact boundary
|
||||
- Smart boundary tolerance (±2 seconds) handles scheduling jitter
|
||||
- Smart boundary tolerance (±2 seconds) handles scheduling jitter in `sensor/helpers.py`
|
||||
- If HA schedules at 14:59:58 → rounds to 15:00:00 (shows new interval data)
|
||||
- If HA restarts at 14:59:30 → stays at 14:45:00 (shows current interval data)
|
||||
- **Absolute time tracking**: Timer plans for **all future boundaries** (not relative delays)
|
||||
- Prevents double-updates (if triggered at 14:59:58, next trigger is 15:15:00, not 15:00:00)
|
||||
- **Result**: Current price sensors update without waiting for next API poll
|
||||
|
||||
### 4. Unified Sensor Handlers
|
||||
### 4. Calculator Pattern (Sensor Platform)
|
||||
|
||||
Sensors organized by **calculation method** (post-refactoring Nov 2025):
|
||||
Sensors organized by **calculation method** (refactored Nov 2025):
|
||||
|
||||
- **Interval-based**: `_get_interval_value(offset, type)` - current/next/previous
|
||||
- **Rolling hour**: `_get_rolling_hour_value(offset, type)` - 5-interval windows
|
||||
- **Daily stats**: `_get_daily_stat_value(day, stat_func)` - calendar day min/max/avg
|
||||
- **24h windows**: `_get_24h_window_value(stat_func)` - trailing/leading statistics
|
||||
**Unified Handler Methods** (`sensor/core.py`):
|
||||
- `_get_interval_value(offset, type)` - current/next/previous intervals
|
||||
- `_get_rolling_hour_value(offset, type)` - 5-interval rolling windows
|
||||
- `_get_daily_stat_value(day, stat_func)` - calendar day min/max/avg
|
||||
- `_get_24h_window_value(stat_func)` - trailing/leading statistics
|
||||
|
||||
Single implementation, minimal code duplication.
|
||||
**Routing** (`sensor/value_getters.py`):
|
||||
- Single source of truth mapping 80+ entity keys to calculator methods
|
||||
- Organized by calculation type (Interval, Rolling Hour, Daily Stats, etc.)
|
||||
|
||||
**Calculators** (`sensor/calculators/`):
|
||||
- Each calculator inherits from `BaseCalculator` with coordinator access
|
||||
- Focused responsibility: `IntervalCalculator`, `TrendCalculator`, etc.
|
||||
- Complex logic isolated (e.g., `TrendCalculator` has internal caching)
|
||||
|
||||
**Attributes** (`sensor/attributes/`):
|
||||
- Separate from business logic, handles state presentation
|
||||
- Builds extra_state_attributes dicts for entity classes
|
||||
- Unified builders: `build_sensor_attributes()`, `build_extra_state_attributes()`
|
||||
|
||||
**Benefits:**
|
||||
- Minimal code duplication across 80+ sensors
|
||||
- Clear separation of concerns (calculation vs presentation)
|
||||
- Easy to extend: Add sensor → choose pattern → add to routing
|
||||
- Independent testability for each component
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue