mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
Introduce TimeService as single source of truth for all datetime operations, replacing direct dt_util calls throughout the codebase. This establishes consistent time context across update cycles and enables future time-travel testing capability. Core changes: - NEW: coordinator/time_service.py with timezone-aware datetime API - Coordinator now creates TimeService per update cycle, passes to calculators - Timer callbacks (#2, #3) inject TimeService into entity update flow - All sensor calculators receive TimeService via coordinator reference - Attribute builders accept time parameter for timestamp calculations Key patterns replaced: - dt_util.now() → time.now() (single reference time per cycle) - dt_util.parse_datetime() + as_local() → time.get_interval_time() - Manual interval arithmetic → time.get_interval_offset_time() - Manual day boundaries → time.get_day_boundaries() - round_to_nearest_quarter_hour() → time.round_to_nearest_quarter() Import cleanup: - Removed dt_util imports from ~30 files (calculators, attributes, utils) - Restricted dt_util to 3 modules: time_service.py (operations), api/client.py (rate limiting), entity_utils/icons.py (cosmetic updates) - datetime/timedelta only for TYPE_CHECKING (type hints) or duration arithmetic Interval resolution abstraction: - Removed hardcoded MINUTES_PER_INTERVAL constant from 10+ files - New methods: time.minutes_to_intervals(), time.get_interval_duration() - Supports future 60-minute resolution (legacy data) via TimeService config Timezone correctness: - API timestamps (startsAt) already localized by data transformation - TimeService operations preserve HA user timezone throughout - DST transitions handled via get_expected_intervals_for_day() (future use) Timestamp ordering preserved: - Attribute builders generate default timestamp (rounded quarter) - Sensors override when needed (next interval, daily midnight, etc.) - Platform ensures timestamp stays FIRST in attribute dict Timer integration: - Timer #2 (quarter-hour): Creates TimeService, calls _handle_time_sensitive_update(time) - Timer #3 (30-second): Creates TimeService, calls _handle_minute_update(time) - Consistent time reference for all entities in same update batch Time-travel readiness: - TimeService.with_reference_time() enables time injection (not yet used) - All calculations use time.now() → easy to simulate past/future states - Foundation for debugging period calculations with historical data Impact: Eliminates timestamp drift within update cycles (previously 60+ independent dt_util.now() calls could differ by milliseconds). Establishes architecture for time-based testing and debugging features.
61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
"""
|
|
Pure data transformation utilities for Tibber Prices integration.
|
|
|
|
This package contains stateless, pure functions for data processing:
|
|
- Time-window calculations (trailing/leading averages, min/max)
|
|
- Price enrichment (differences, volatility, rating levels)
|
|
- Statistical analysis (aggregation, trends)
|
|
|
|
These functions operate on raw data structures (dicts, lists) and do NOT depend on:
|
|
- Home Assistant entities or state management
|
|
- Configuration entries or coordinators
|
|
- Translation systems or UI-specific logic
|
|
|
|
For entity-specific utilities (icons, colors, attributes), see entity_utils/ package.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .average import (
|
|
calculate_current_leading_avg,
|
|
calculate_current_leading_max,
|
|
calculate_current_leading_min,
|
|
calculate_current_trailing_avg,
|
|
calculate_current_trailing_max,
|
|
calculate_current_trailing_min,
|
|
calculate_next_n_hours_avg,
|
|
)
|
|
from .price import (
|
|
aggregate_period_levels,
|
|
aggregate_period_ratings,
|
|
aggregate_price_levels,
|
|
aggregate_price_rating,
|
|
calculate_difference_percentage,
|
|
calculate_price_trend,
|
|
calculate_rating_level,
|
|
calculate_trailing_average_for_interval,
|
|
calculate_volatility_level,
|
|
enrich_price_info_with_differences,
|
|
find_price_data_for_interval,
|
|
)
|
|
|
|
__all__ = [
|
|
"aggregate_period_levels",
|
|
"aggregate_period_ratings",
|
|
"aggregate_price_levels",
|
|
"aggregate_price_rating",
|
|
"calculate_current_leading_avg",
|
|
"calculate_current_leading_max",
|
|
"calculate_current_leading_min",
|
|
"calculate_current_trailing_avg",
|
|
"calculate_current_trailing_max",
|
|
"calculate_current_trailing_min",
|
|
"calculate_difference_percentage",
|
|
"calculate_next_n_hours_avg",
|
|
"calculate_price_trend",
|
|
"calculate_rating_level",
|
|
"calculate_trailing_average_for_interval",
|
|
"calculate_volatility_level",
|
|
"enrich_price_info_with_differences",
|
|
"find_price_data_for_interval",
|
|
]
|