Commit graph

24 commits

Author SHA1 Message Date
Julian Pawlowski
2d0febdab3 fix(binary_sensor): remove 6-hour lookahead limit for period icons
Simplified _has_future_periods() to check for ANY future periods instead
of limiting to 6-hour window. This ensures icons show 'waiting' state
whenever periods are scheduled, not just within artificial time limit.

Also added pragmatic fallback in timing calculator _find_next_period():
when skip_current=True but only one future period exists, return it
anyway instead of showing 'unknown'. This prevents timing sensors from
showing unknown during active periods.

Changes:
- binary_sensor/definitions.py: Removed PERIOD_LOOKAHEAD_HOURS constant
- binary_sensor/core.py: Simplified _has_future_periods() logic
- sensor/calculators/timing.py: Added pragmatic fallback for single period

Impact: Better user experience - icons always show future periods, timing
sensors show values even during edge cases.
2025-11-22 13:04:17 +00:00
Julian Pawlowski
48d6e2580a refactor(coordinator): remove redundant lifecycle callback system
Removed custom lifecycle callback push-update mechanism after confirming
it was redundant with Home Assistant's built-in DataUpdateCoordinator
pattern.

Root cause analysis showed HA's async_update_listeners() is called
synchronously (no await) immediately after _async_update_data() returns,
making separate lifecycle callbacks unnecessary.

Changes:
- coordinator/core.py: Removed lifecycle callback methods and notifications
- sensor/core.py: Removed lifecycle callback registration and cleanup
- sensor/attributes/lifecycle.py: Removed next_tomorrow_check attribute
- sensor/calculators/lifecycle.py: Removed get_next_tomorrow_check_time()

Impact: Simplified coordinator pattern, no user-visible changes. Standard
HA coordinator mechanism provides same immediate update guarantee without
custom callback complexity.
2025-11-22 13:01:17 +00:00
Julian Pawlowski
9c3c094305 fix(calculations): handle negative electricity prices correctly
Fixed multiple calculation issues with negative prices (Norway/Germany
renewable surplus scenarios):

Bug #6: Rating threshold validation with dead code
- Added threshold validation (low >= high) with warning
- Returns NORMAL as fallback for misconfigured thresholds

Bug #7: Min/Max functions returning 0.0 instead of None
- Changed default from 0.0 to None when window is empty
- Prevents misinterpretation (0.0 looks like price with negatives)

Bug #9: Period price diff percentage wrong sign with negative reference
- Use abs(ref_price) in percentage calculation
- Correct percentage direction for negative prices

Bug #10: Trend diff percentage wrong sign with negative current price
- Use abs(current_interval_price) in percentage calculation
- Correct trend direction when prices cross zero

Bug #11: later_half_diff calculation failed for negative prices
- Changed condition from `if current_interval_price > 0` to `!= 0`
- Use abs(current_interval_price) for percentage

Changes:
- utils/price.py: Add threshold validation, use abs() in percentages
- utils/average.py: Return None instead of 0.0 for empty windows
- period_statistics.py: Use abs() for reference prices
- trend.py: Use abs() for current prices, fix zero-check condition
- tests: 95+ new tests covering negative/zero/mixed price scenarios

Impact: All calculations work correctly with negative electricity prices.
Percentages show correct direction regardless of sign.
2025-11-22 04:45:23 +00:00
Julian Pawlowski
215ac02302 feat(sensors): add lifecycle callback for chart_data_export sensor
chart_data_export now registers lifecycle callback for immediate
updates when coordinator data changes ("fresh" lifecycle state).
Previously only updated via polling intervals.

Changes:
- Register callback in sensor constructor (when entity_key matches)
- Callback triggers async_write_ha_state() on "fresh" lifecycle
- 5 new tests covering callback registration and triggering

Impact: Chart data export updates immediately on API data arrival,
enabling real-time dashboard updates without polling delay.
2025-11-22 04:44:38 +00:00
Julian Pawlowski
49866f26fa fix(coordinator): use coordinator update timestamp for cache validity
Cache validity now checks _last_coordinator_update (within 30min)
instead of _api_calls_today counter. Fixes false "stale" status
when coordinator runs every 15min but cache validation was only
checking API call counter.

Bug #1: Cache validity shows "stale" at 05:57 AM
Bug #2: Cache age calculation incorrect after midnight turnover
Bug #3: get_cache_validity inconsistent with cache_age sensor

Changes:
- Coordinator: Use _last_coordinator_update for cache validation
- Lifecycle: Extract cache validation to dedicated helper function
- Tests: 7 new tests covering midnight scenarios and edge cases

Impact: Cache validity sensor now accurately reflects coordinator
activity, not just explicit API calls. Correctly handles midnight
turnover without false "stale" status.
2025-11-22 04:44:22 +00:00
Julian Pawlowski
189d3ba84d feat(sensor): add data lifecycle diagnostic sensor with push updates
Add comprehensive data_lifecycle_status sensor showing real-time cache
vs fresh API data status with 6 states and 13+ detailed attributes.

Key features:
- 6 lifecycle states: cached, fresh, refreshing, searching_tomorrow,
  turnover_pending, error
- Push-update system for instant state changes (refreshing→fresh→error)
- Quarter-hour polling for turnover_pending detection at 23:45
- Accurate next_api_poll prediction using Timer #1 offset tracking
- Tomorrow prediction with actual timer schedule (not fixed 13:00)
- 13+ formatted attributes: cache_age, data_completeness, api_calls_today,
  next_api_poll, etc.

Implementation:
- sensor/calculators/lifecycle.py: New calculator with state logic
- sensor/attributes/lifecycle.py: Attribute builders with formatting
- coordinator/core.py: Lifecycle tracking + callback system (+16 lines)
- sensor/core.py: Push callback registration (+3 lines)
- coordinator/constants.py: Added to TIME_SENSITIVE_ENTITY_KEYS
- Translations: All 5 languages (de, en, nb, nl, sv)

Timing optimization:
- Extended turnover warning: 5min → 15min (catches 23:45 quarter boundary)
- No minute-timer needed: quarter-hour updates + push = optimal
- Push-updates: <1sec latency for refreshing/fresh/error states
- Timer offset tracking: Accurate tomorrow predictions

Removed obsolete sensors:
- data_timestamp (replaced by lifecycle attributes)
- price_forecast (never implemented, removed from definitions)

Impact: Users can monitor data freshness, API call patterns, cache age,
and understand integration behavior. Perfect for troubleshooting and
visibility into when data updates occur.
2025-11-20 15:12:41 +00:00
Julian Pawlowski
02935c8d72 fix(data_fetching): enhance user data update logic and return status
fix(core): refresh chart data on coordinator updates
2025-11-20 13:48:26 +00:00
Julian Pawlowski
e950737478 feat(chart_export): migrate sensor config from UI to configuration.yaml
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.
2025-11-20 13:41:26 +00:00
Julian Pawlowski
c2b9908e69 refactor(naming): complete class naming convention alignment
Renamed 25 public classes + 1 Enum to include TibberPrices prefix
following Home Assistant integration naming standards.

All classes now follow pattern: TibberPrices{SemanticPurpose}
No package hierarchy in names (import path is namespace).

Key changes:
- Coordinator module: DataFetcher, DataTransformer, ListenerManager,
  PeriodCalculator, TimeService (203 usages), CacheData
- Config flow: CannotConnectError, InvalidAuthError
- Entity utils: IconContext
- Sensor calculators: BaseCalculator + 8 subclasses
- Period handlers: 5 NamedTuples (PeriodConfig, PeriodData,
  PeriodStatistics, ThresholdConfig, IntervalCriteria)
- Period handlers: SpikeCandidateContext (dataclass → NamedTuple)
- API: QueryType Enum

Documentation updates:
- AGENTS.md: Added Pyright code generation guidelines
- planning/class-naming-refactoring-plan.md: Complete execution log

Quality metrics:
- 0 Pyright errors (strict type checking)
- 0 Ruff errors (linting + formatting)
- All hassfest checks passed
- 79 files validated

Impact: Aligns with HA Core standards (TibberDataCoordinator pattern).
No user-facing changes - internal refactor only.
2025-11-20 11:22:53 +00:00
Julian Pawlowski
625bc222ca refactor(coordinator): centralize time operations through TimeService
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.
2025-11-19 18:36:12 +00:00
Julian Pawlowski
a962289682 refactor(sensor): implement Calculator Pattern with specialized modules
Massive refactoring of sensor platform reducing core.py from 2,170 to 909
lines (58% reduction). Extracted business logic into specialized calculators
and attribute builders following separation of concerns principles.

Changes:
- Created sensor/calculators/ package (8 specialized calculators, 1,838 lines):
  * 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 (640 lines)
  * timing.py: Best/peak price period timing
  * metadata.py: Home/metering metadata

- Created sensor/attributes/ package (8 specialized modules, 1,209 lines):
  * Modules match calculator types for consistent organization
  * __init__.py: Routing logic + unified builders
  * Handles state presentation separately from business logic

- Created sensor/chart_data.py (144 lines):
  * Extracted chart data export functionality from entity class
  * YAML parsing, service calls, metadata formatting

- Created sensor/value_getters.py (276 lines):
  * Centralized handler mapping for all 80+ sensor types
  * Single source of truth for sensor routing

- Extended sensor/helpers.py (+88 lines):
  * Added aggregate_window_data() unified aggregator
  * Added get_hourly_price_value() for backward compatibility
  * Consolidated sensor-specific helper functions

- Refactored sensor/core.py (909 lines, was 2,170):
  * Instantiates all calculators in __init__
  * Delegates value calculations to appropriate calculator
  * Uses unified handler methods via value_getters mapping
  * Minimal platform-specific logic remains (icon callbacks, entity lifecycle)

- Deleted sensor/attributes.py (1,106 lines):
  * Functionality split into attributes/ package (8 modules)

- Updated AGENTS.md:
  * Documented Calculator Pattern architecture
  * Added guidance for adding new sensors with calculation groups
  * Updated file organization with new package structure

Architecture Benefits:
- Clear separation: Calculators (business logic) vs Attributes (presentation)
- Improved testability: Each calculator independently testable
- Better maintainability: 21 focused modules vs monolithic file
- Easy extensibility: Add sensors by choosing calculation pattern
- Reusable components: Calculators and attribute builders shared across sensors

Impact: Significantly improved code organization and maintainability while
preserving all functionality. All 80+ sensor types continue working with
cleaner, more modular architecture. Developer experience improved with
logical file structure and clear separation of concerns.
2025-11-18 21:25:55 +00:00
Julian Pawlowski
5ab7703d90 fix(imports): update imports after utils package reorganization
Updated all imports to reflect new module structure:

1. Utils package imports:
   - average_utils → utils.average
   - price_utils → utils.price
   - Added MINUTES_PER_INTERVAL imports from const.py

2. Entity utils imports:
   - Added entity_utils.helpers imports where needed
   - Fixed find_rolling_hour_center_index import paths
   - Added get_price_value import in binary_sensor

3. Type imports:
   - Added coordinator/period_handlers/types.py MINUTES_PER_INTERVAL
     re-export (with noqa:F401) for period handler modules

4. Platform imports:
   - Updated sensor platform imports (utils.average, utils.price)
   - Updated binary_sensor imports (entity_utils helpers)
   - Updated coordinator imports (utils packages)

All import paths validated:
✓ Integration loads successfully
✓ All service handlers importable
✓ No circular dependencies
✓ Lint checks passing

Impact: Clean import structure, no breaking changes to functionality.
All sensors and services work identically to before.
2025-11-18 20:07:28 +00:00
Julian Pawlowski
4876a2cc29 refactor(entity_utils): extract shared helpers from sensor platform
Created entity_utils/helpers.py with platform-agnostic utility functions:
- get_price_value(): Price unit conversion (major/minor currency)
- translate_level(): Price level translation
- translate_rating_level(): Rating level translation
- find_rolling_hour_center_index(): Rolling hour window calculations

These functions moved from sensor/helpers.py as they are used by both
sensor and binary_sensor platforms. Remaining sensor/helpers.py now
contains only sensor-specific helpers (aggregate_price_data, etc.).

Updated imports:
- sensor/core.py: Import from entity_utils instead of sensor.helpers
- entity_utils/icons.py: Fixed find_rolling_hour_center_index import
- binary_sensor platforms: Can now use shared helpers

Added clear docstrings explaining:
- entity_utils/helpers.py: Platform-agnostic utilities
- sensor/helpers.py: Sensor-specific aggregation functions

Impact: Better code reuse, clearer responsibility boundaries between
platform-specific and shared utilities.
2025-11-18 20:07:17 +00:00
Julian Pawlowski
c316d5deef refactor: resolve circular imports and enhance documentation
This commit completes multiple refactoring efforts and documentation improvements:

Code Structure Changes:
- Move round_to_nearest_quarter_hour() from sensor/helpers.py to average_utils.py
- Resolve circular import between price_utils.py and sensor/helpers.py
- Split api.py into api/ package (client.py, queries.py, exceptions.py, helpers.py)
- Split coordinator.py into coordinator/ package (core.py, cache.py, listeners.py, etc.)
- Move period_utils/ to coordinator/period_handlers/ for better organization
- All lint checks passing (no PLC0415 local import warnings)

Documentation Additions:
- Add docs/development/architecture.md with Mermaid diagrams (end-to-end flow, cache coordination)
- Add docs/development/timer-architecture.md (comprehensive 3-timer system documentation)
- Add docs/development/caching-strategy.md (4-layer cache system with invalidation logic)
- Update docs/development/README.md with cross-references
- Update AGENTS.md with new module structure and patterns

Smart Boundary Tolerance:
- Implement ±2 second tolerance for quarter-hour rounding
- Prevents premature interval switching during HA restarts (14:59:30 stays at 14:45)
- Enables boundary snapping for timer jitter (14:59:58 → 15:00)

Atomic Midnight Coordination:
- Add _check_midnight_turnover_needed() for race-free midnight handling
- Coordinate Timer #1 (HA DataUpdateCoordinator) with Timer #2 (quarter-hour refresh)
- Whoever runs first performs turnover, other skips gracefully

Timer Optimization:
- Change timer scheduling from second=1 to second=0 (absolute-time scheduling)
- Document load distribution rationale (unsynchronized API polling prevents thundering herd)
- Comprehensive explanation of 3 independent timers and their coordination

Impact: Cleaner code structure with resolved circular dependencies, comprehensive
documentation of timer and caching systems, and improved reliability during
boundary conditions and midnight turnovers. All changes are developer-facing
improvements with no user-visible behavior changes.
2025-11-18 17:32:36 +00:00
Julian Pawlowski
ef983d0a99 feat(sensor): migrate chart_data_export from binary_sensor to sensor platform
Migrated chart_data_export from binary_sensor to sensor to enable
compatibility with dashboard integrations (ApexCharts, etc.) that
require sensor entities for data selection.

Changes:
- Moved chart_data_export from binary_sensor/ to sensor/ platform
- Changed from boolean state (ON/OFF) to ENUM states ("pending", "ready", "error")
- Maintained all functionality: service call, attribute structure, caching
- Updated translations in all 5 languages (de, en, nb, nl, sv)
- Updated user documentation (sensors.md, services.md)
- Removed all chart_data_export code from binary_sensor platform

Technical details:
- State: "pending" (before first call), "ready" (data available), "error" (service failed)
- Attributes: timestamp + error (metadata) → descriptions → service response data
- Cache (_chart_data_response) bridges async service call and sync property access
- Service call: Triggered on async_added_to_hass() and async_update()

Impact: Dashboard integrations can now select chart_data_export sensor
in their entity pickers. No breaking changes for existing users - entity ID
changes from binary_sensor.* to sensor.*, but functionality identical.
2025-11-17 04:11:10 +00:00
Julian Pawlowski
3a9ba55dd3 feat(sensors): improve price trend sensors with temporal context
Enhanced current_price_trend and next_price_trend_change sensors with
consistent temporal information and fixed trend calculation logic.

Changes:
- Fixed trend calculation order: Calculate final trend state (momentum +
  future outlook) BEFORE scanning for next change, ensuring consistency
  between current_price_trend state and next_price_trend_change from_direction
- Added TIME_SENSITIVE_ENTITY_KEYS registration for both trend sensors
  to enable automatic 15-minute boundary updates (Timer #2)
- Removed redundant timestamp field from _trend_change_attributes (was
  duplicate of sensor state)
- Added timestamp attribute (current interval) to both sensors as first
  attribute for temporal reference
- Implemented _find_trend_start_time() to scan backward and determine
  when current trend began
- Added trend_duration_minutes to current_price_trend showing how long
  current trend has been active
- Added from_direction to current_price_trend showing previous trend
  state (enables detection of valleys/plateaus)
- Added minutes_until_change to next_price_trend_change showing time
  until trend changes
- Removed redundant attributes: valid_until, duration_hours,
  duration_minutes from current_price_trend (can be derived from
  next_price_trend_change sensor)
- Removed redundant next_direction from current_price_trend (available
  in next_price_trend_change sensor)

current_price_trend attributes:
- timestamp: Current interval (calculation basis)
- from_direction: Previous trend state (e.g., "stable" → "falling" = starting decline)
- trend_duration_minutes: How long current trend has been active

next_price_trend_change attributes:
- timestamp: Current interval (calculation basis)
- from_direction: Current trend state (should match current_price_trend state)
- direction: Target trend state
- minutes_until_change: Time until change occurs
- current_price_now, price_at_change, avg_after_change, trend_diff_%

Impact: Users can now detect important transitions (valleys: falling→stable,
plateaus: rising→stable) and understand trend context. Both sensors update
automatically every 15 minutes with consistent information.
2025-11-16 17:09:16 +00:00
Julian Pawlowski
76dc488bb5 feat(sensors): add momentum-based trend detection with two new sensors
Added intelligent price trend analysis combining historical momentum
(weighted 1h lookback) with future outlook for more accurate trend
recognition. Introduced two complementary sensors for comprehensive
trend monitoring.

New sensors:
- current_price_trend: Shows active trend direction with duration
- next_price_trend_change: Predicts when trend will reverse

Momentum analysis (historical perspective):
- Weighted 1h lookback (4 × 15-min intervals)
- Linear weight progression [0.5, 0.75, 1.0, 1.25]
- ±3% threshold for momentum classification
- Recognizes ongoing trends earlier than future-only analysis

Two-phase trend calculation:
- Phase 1: Calculate momentum from weighted trailing average
- Phase 2: Validate with volatility-adaptive future comparison
- Combines both for final trend determination (rising/falling/stable)
- Centralized in _calculate_trend_info() with 60s cache

Volatility-adaptive thresholds:
- Existing trend sensors (1h-12h) now use adaptive thresholds
- calculate_price_trend() adjusted by market volatility:
  * LOW volatility (<15% CV): factor 0.6 → more sensitive (e.g., 3%→1.8%)
  * MODERATE volatility (15-30%): factor 1.0 → baseline (3%)
  * HIGH volatility (≥30%): factor 1.4 → less sensitive (e.g., 3%→4.2%)
- Uses same coefficient of variation as volatility sensors
- Ensures mathematical consistency across integration

Default threshold reduction:
- Rising/falling thresholds: 5% → 3% (more responsive)
- Momentum-based detection enables lower thresholds without noise
- Adaptive adjustment compensates during high volatility

Architectural improvements:
- Centralized calculation: Single source of truth for both sensors
- Eliminates Henne-Ei problem (duplicate calculations)
- 60-second cache per coordinator update
- Shared helper methods: _calculate_momentum(), _combine_momentum_with_future()

Translation updates (all 5 languages):
- Documented momentum feature in custom_translations (de/en/nb/nl/sv)
- Explained "recognizes ongoing trends earlier" advantage
- Added sensor names and state options to standard translations
- Updated volatility threshold descriptions (clarify usage by trend sensors)

Files changed:
- custom_components/tibber_prices/sensor/core.py (930 lines added)
  * New: _calculate_momentum(), _combine_momentum_with_future()
  * New: _calculate_trend_info() (centralized with cache)
  * New: _get_current_trend_value(), _get_next_trend_change_value()
  * Modified: _get_price_trend_value() (volatility-adaptive thresholds)
- custom_components/tibber_prices/sensor/definitions.py
  * Added: current_price_trend (ENUM sensor)
  * Added: next_price_trend_change (TIMESTAMP sensor)
- custom_components/tibber_prices/sensor/attributes.py
  * New: _add_cached_trend_attributes() helper
  * Support for current_trend_attributes, trend_change_attributes
- custom_components/tibber_prices/price_utils.py (178 lines added)
  * New: _calculate_lookahead_volatility_factor()
  * Modified: calculate_price_trend() with volatility adjustment
  * Added: VOLATILITY_FACTOR_* constants (0.6/1.0/1.4)
- custom_components/tibber_prices/entity_utils/icons.py
  * Added: Dynamic icon handling for next_price_trend_change
- custom_components/tibber_prices/const.py
  * Changed: DEFAULT_PRICE_TREND_THRESHOLD_RISING/FALLING (5→3%)
- custom_components/tibber_prices/translations/*.json (5 files)
  * Added: Sensor names, state options, descriptions
- custom_components/tibber_prices/custom_translations/*.json (5 files)
  * Added: Long descriptions with momentum feature explanation

Impact: Users get significantly more accurate trend detection that
understands they're ALREADY in a trend, not just predicting future
changes. Momentum-based approach recognizes ongoing movements 15-60
minutes earlier. Adaptive thresholds prevent false signals during
volatile periods. Two complementary sensors enable both status display
(current trend) and event-based automation (when will it change).
Perfect for use cases like "charge EV when next trend change shows
falling prices" or dashboard badges showing "Rising for 2.5h".
2025-11-16 12:49:43 +00:00
Julian Pawlowski
63442dae1d feat(api): add multi-home support and diagnostic sensors
API Client:
- Changed async_get_price_info() to accept home_ids parameter
- Implemented _get_price_info_for_specific_homes() using GraphQL aliases
  (home0: home(id: "abc") { ... }) for efficient multi-home queries
- Extended async_get_viewer_details() with comprehensive home metadata
  (owner, address, meteringPointData, subscription, features)
- Removed deprecated async_get_data() method (combined query no longer needed)
- Updated _is_data_empty() to handle aliased response structure

Coordinator:
- Added _get_configured_home_ids() to collect all active config entries
- Modified _fetch_all_homes_data() to only query configured homes
- Added refresh_user_data() forcing user data refresh (bypasses cache)
- Improved get_user_profile() with detailed user info (name, login, accountType)
- Fixed get_user_homes() to extract from viewer object

Binary Sensors:
- Added has_ventilation_system sensor (home metadata)
- Added realtime_consumption_enabled sensor (features check)
- Refactored state getter mapping to dictionary pattern

Diagnostic Sensors (12 new):
- Home metadata: home_type, home_size, main_fuse_size, number_of_residents,
  primary_heating_source
- Metering point: grid_company, grid_area_code, price_area_code,
  consumption_ean, production_ean, energy_tax_type, vat_type,
  estimated_annual_consumption
- Subscription: subscription_status
- Added available property override to hide diagnostic sensors with no data

Config Flow:
- Fixed subentry flow to exclude parent home_id from available homes
- Added debug logging for home title generation

Entity:
- Made attribution translatable (get_translation("attribution"))
- Removed hardcoded user name suffix from subentry device names

Impact: Enables multi-home setups with dedicated subentries. Each home gets
its own set of sensors and only configured homes are queried (reduces API
load). New diagnostic sensors provide comprehensive home metadata from Tibber
API. Users can track ventilation systems, heating types, metering point info,
and subscription status.
2025-11-16 00:11:56 +00:00
Julian Pawlowski
4e64cf7598 refactor(sensors): optimize default entity activation for better UX
Adjusted entity_registry_enabled_default flags to reduce initial entity
count while keeping most useful sensors active by default.

Changes:
- Disabled rating sensors (current/next interval, hourly, daily) - Level
  sensors provide better granularity (5 levels vs 3) for automations
- Disabled leading 24h window sensors (avg/min/max) - Advanced use case,
  overlaps with tomorrow statistics
- Disabled additional volatility sensors (tomorrow, next_24h,
  today_tomorrow) - Today's volatility sufficient for typical use cases

Rationale:
- Price level sensors (5 states: very_cheap → very_expensive) are more
  commonly used than rating sensors (3 states: low → high)
- Leading 24h windows overlap with tomorrow daily statistics which have
  clearer boundaries
- Single volatility indicator (today) covers most automation needs

Impact: Reduces default active entities from ~65 to ~50 while maintaining
all essential functionality. Advanced users can enable additional sensors
as needed. Improves initial setup experience by focusing on most relevant
sensors.
2025-11-15 21:47:09 +00:00
Julian Pawlowski
d06ae63075 feat(sensors): add Energy Dashboard price sensor and period duration sensors
Added dedicated sensor for Home Assistant's Energy Dashboard integration and
new sensors to track total period duration for best/peak price periods.

New Sensors:
- current_interval_price_major: Shows price in major currency (EUR/kWh, NOK/kWh)
  instead of minor units (ct/kWh, øre/kWh) for Energy Dashboard compatibility
- best_price_period_duration: Total length of current/next best price period
- peak_price_period_duration: Total length of current/next peak price period

Changes:
- sensor/definitions.py: Added 3 new sensor definitions with proper device_class,
  state_class, and suggested_display_precision
- sensor/core.py: Extended native_unit_of_measurement property to return major
  currency unit for Energy Dashboard sensor while keeping minor units for others
- sensor/core.py: Added _calc_period_duration() method to calculate period lengths
- sensor/core.py: Added handler mappings for new duration sensors
- const.py: Imported format_price_unit_major() for currency formatting
- translations/*.json: Added entity names for all 5 languages (de, en, nb, nl, sv)
- custom_translations/*.json: Added descriptions, long_descriptions, and usage_tips
  for all new sensors in all 5 languages

Technical Details:
- Energy Dashboard sensor uses 4 decimal precision (0.2534 EUR/kWh) vs 2 decimals
  for regular price sensors (25.34 ct/kWh)
- Duration sensors return minutes (UnitOfTime.MINUTES) with 0 decimal precision
- Duration sensors disabled by default (less commonly needed than end time)
- All MONETARY sensors now have explicit state_class=SensorStateClass.TOTAL
- All ENUM/TIMESTAMP sensors have explicit state_class=None for clarity

Impact: Users can now add electricity prices to Energy Dashboard for automatic
cost calculation. Duration sensors help users plan appliance usage by showing
how long cheap/expensive periods last. All price statistics now properly tracked
by Home Assistant's recorder.
2025-11-15 20:38:21 +00:00
Julian Pawlowski
decca432df feat(sensors): add timing sensors for best_price and peak_price periods
Added 10 new timing sensors (5 for best_price, 5 for peak_price) to track
period timing and progress:

Timestamp sensors (quarter-hour updates):
- best_price_end_time / peak_price_end_time
  Shows when current/next period ends (always useful reference time)
- best_price_next_start_time / peak_price_next_start_time
  Shows when next period starts (even during active periods)

Countdown sensors (minute updates):
- best_price_remaining_minutes / peak_price_remaining_minutes
  Minutes left in current period (0 when inactive)
- best_price_next_in_minutes / peak_price_next_in_minutes
  Minutes until next period starts
- best_price_progress / peak_price_progress
  Progress percentage through current period (0-100%)

Smart fallback behavior:
- Sensors always show useful values (no 'Unknown' during normal operation)
- Timestamp sensors show current OR next period end/start times
- Countdown sensors return 0 when no period is active
- Grace period: Progress stays at 100% for 60 seconds after period ends

Dynamic visual feedback:
- Progress icons differentiate 3 states at 0%:
  * No data: mdi:help-circle-outline (gray)
  * Waiting for next period: mdi:timer-pause-outline
  * Period just started: mdi:circle-outline
- Progress 1-99%: mdi:circle-slice-1 to mdi:circle-slice-8 (pie chart)
- Timer icons based on urgency (alert/timer/timer-sand/timer-outline)
- Dynamic colors: green (best_price), orange/red (peak_price), gray (disabled)
- icon_color attribute for UI styling

Implementation details:
- Dual update mechanism: quarter-hour (timestamps) + minute (countdowns)
- Period state callbacks: Check if period is currently active
- IconContext dataclass: Reduced function parameters from 6 to 3
- Unit constants: UnitOfTime.MINUTES, PERCENTAGE from homeassistant.const
- Complete translations for 5 languages (de, en, nb, nl, sv)

Impact: Users can now build sophisticated automations based on period timing
('start dishwasher if remaining_minutes > 60'), display countdowns in
dashboards, and get clear visual feedback about period states. All sensors
provide meaningful values at all times, making automation logic simpler.
2025-11-15 17:12:55 +00:00
Julian Pawlowski
22165d038d feat(sensors): add timestamp attributes and enhance icon system
Added timestamp attributes to all sensors and enhanced the dynamic icon
system for comprehensive price sensor coverage with rolling hour support.

TIMESTAMP ATTRIBUTES:

Core Changes:
- sensor/attributes.py:
  * Enhanced add_average_price_attributes() to track extreme intervals
    for min/max sensors and add appropriate timestamps
  * Added _update_extreme_interval() helper to reduce complexity
  * Extended add_volatility_type_attributes() with timestamp logic for
    all 4 volatility types (today/tomorrow/today_tomorrow/next_24h)
  * Fixed current_interval_price timestamp assignment (use interval_data)

Timestamp Logic:
- Interval-based sensors: Use startsAt of specific 15-minute interval
- Min/Max sensors: Use startsAt of interval with extreme price
- Average sensors: Use startsAt of first interval in window
- Volatility sensors: Use midnight (00:00) for calendar day sensors,
  current time for rolling 24h window
- Daily sensors: Already used fallback to midnight (verified)

ICON SYSTEM ENHANCEMENTS:

Major Extensions:
- entity_utils/icons.py:
  * Created get_rolling_hour_price_level_for_icon() implementing
    5-interval window aggregation matching sensor calculation logic
  * Extended get_price_sensor_icon() coverage from 1 to 4 sensors:
    - current_interval_price (existing)
    - next_interval_price (NEW - dynamic instead of static)
    - current_hour_average_price (NEW - uses rolling hour aggregation)
    - next_hour_average_price (NEW - uses rolling hour aggregation)
  * Added imports for aggregate_level_data and find_rolling_hour_center_index

Documentation:
- sensor/definitions.py:
  * Updated 30+ sensor descriptions with detailed icon behavior comments
  * Changed next_interval_price from static to dynamic icon
  * Documented dynamic vs static icons for all sensor types
  * Added clear icon mapping source documentation

SENSOR KEY RENAMING:

Renamed for clarity (current_hour_average → current_hour_average_price):
- sensor/core.py: Updated value getters and cached data lookup
- sensor/definitions.py: Updated entity descriptions
- sensor/attributes.py: Updated key references in attribute builders
- coordinator.py: Updated TIME_SENSITIVE_ENTITY_KEYS set
- const.py: Updated comment documentation

Translation Updates:
- custom_translations/*.json (5 files): Updated sensor keys
- translations/*.json (5 files): Updated sensor keys

Impact:
- All sensors now have timestamp attribute showing applicable time/interval
- Icon system provides richer visual feedback for more sensor types
- Consistent sensor naming improves code readability
- Users get temporal context for all sensor values
- Dynamic icons adapt to price conditions across more sensors
2025-11-15 15:31:43 +00:00
Julian Pawlowski
e18d653233 feat(sensors): add daily aggregated price level and rating sensors
Added 6 new sensors for yesterday/today/tomorrow aggregated price
levels and ratings, following the same calculation logic as existing
current/next interval sensors.

New sensors:
- yesterday_price_level, today_price_level, tomorrow_price_level
- yesterday_price_rating, today_price_rating, tomorrow_price_rating

Implementation details:
- Added DAILY_LEVEL_SENSORS and DAILY_RATING_SENSORS in sensor/definitions.py
- Implemented _get_daily_aggregated_value() in sensor/core.py using
  existing aggregate_level_data() and aggregate_rating_data() helpers
- Extended icon support in entity_utils/icons.py for dynamic icons
- Added icon_color attributes in sensor/attributes.py with helper
  functions _get_day_key_from_sensor_key() and _add_fallback_timestamp()
- Complete translations in all 5 languages (de, en, nb, nl, sv):
  * Standard translations: sensor names
  * Custom translations: description, long_description, usage_tips

Impact: Users can now see aggregated daily price levels and ratings
for yesterday, today, and tomorrow at a glance, making it easier to
compare overall price situations across days and plan energy consumption
accordingly. Sensors use same aggregation logic as hourly sensors for
consistency.
2025-11-15 13:31:44 +00:00
Julian Pawlowski
fa40c00f67 refactor(sensors): Transform sensor platform into package 2025-11-15 11:46:54 +00:00