Moved Chart Data Export sensor configuration from config flow textarea
to configuration.yaml for better maintainability and consistency with
Home Assistant standards.
Changes:
- __init__.py: Added async_setup() with CONFIG_SCHEMA for tibber_prices.chart_export
- const.py: Added DATA_CHART_CONFIG constant for hass.data storage
- options_flow.py: Simplified chart_data_export step to info-only page
- schemas.py: get_chart_data_export_schema() returns empty schema (no input fields)
- sensor/chart_data.py: Reads config from hass.data instead of config_entry.options
- All 5 translation files: Updated chart_data_export description with:
- Clear heading: "📊 Chart Data Export Sensor"
- Intro line explaining sensor purpose
- Legacy warning (⚠️) recommending service use
- Two valid use cases (✅): attribute-only tools, auto-updating data
- One discouraged use case (❌): automations should use service directly
- 3-step activation instructions
- YAML configuration example with all parameters
- Correct default behavior: today+tomorrow, 15-minute intervals, prices only
Impact: Users configure chart export in configuration.yaml instead of UI.
Sensor remains disabled by default (diagnostic sensor). Config flow shows
prominent info page guiding users toward service usage while keeping
sensor available for legacy dashboard tools that only read attributes.
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.