mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
11 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
60e05e0815 |
refactor(currency)!: rename major/minor to base/subunit currency terminology
Complete terminology migration from confusing "major/minor" to clearer
"base/subunit" currency naming throughout entire codebase, translations,
documentation, tests, and services.
BREAKING CHANGES:
1. **Service API Parameters Renamed**:
- `get_chartdata`: `minor_currency` → `subunit_currency`
- `get_apexcharts_yaml`: Updated service_data references from
`minor_currency: true` to `subunit_currency: true`
- All automations/scripts using these parameters MUST be updated
2. **Configuration Option Key Changed**:
- Config entry option: Display mode setting now uses new terminology
- Internal key: `currency_display_mode` values remain "base"/"subunit"
- User-facing labels updated in all 5 languages (de, en, nb, nl, sv)
3. **Sensor Entity Key Renamed**:
- `current_interval_price_major` → `current_interval_price_base`
- Entity ID changes: `sensor.tibber_home_current_interval_price_major`
→ `sensor.tibber_home_current_interval_price_base`
- Energy Dashboard configurations MUST update entity references
4. **Function Signatures Changed**:
- `format_price_unit_major()` → `format_price_unit_base()`
- `format_price_unit_minor()` → `format_price_unit_subunit()`
- `get_price_value()`: Parameter `in_euro` deprecated in favor of
`config_entry` (backward compatible for now)
5. **Translation Keys Renamed**:
- All language files: Sensor translation key
`current_interval_price_major` → `current_interval_price_base`
- Service parameter descriptions updated in all languages
- Selector options updated: Display mode dropdown values
Changes by Category:
**Core Code (Python)**:
- const.py: Renamed all format_price_unit_*() functions, updated docstrings
- entity_utils/helpers.py: Updated get_price_value() with config-driven
conversion and backward-compatible in_euro parameter
- sensor/__init__.py: Added display mode filtering for base currency sensor
- sensor/core.py:
* Implemented suggested_display_precision property for dynamic decimal places
* Updated native_unit_of_measurement to use get_display_unit_string()
* Updated all price conversion calls to use config_entry parameter
- sensor/definitions.py: Renamed entity key and updated all
suggested_display_precision values (2 decimals for most sensors)
- sensor/calculators/*.py: Updated all price conversion calls (8 calculators)
- sensor/helpers.py: Updated aggregate_price_data() signature with config_entry
- sensor/attributes/future.py: Updated future price attributes conversion
**Services**:
- services/chartdata.py: Renamed parameter minor_currency → subunit_currency
throughout (53 occurrences), updated metadata calculation
- services/apexcharts.py: Updated service_data references in generated YAML
- services/formatters.py: Renamed parameter use_minor_currency →
use_subunit_currency in aggregate_hourly_exact() and get_period_data()
- sensor/chart_metadata.py: Updated default parameter name
**Translations (5 Languages)**:
- All /translations/*.json:
* Added new config step "display_settings" with comprehensive explanations
* Renamed current_interval_price_major → current_interval_price_base
* Updated service parameter descriptions (subunit_currency)
* Added selector.currency_display_mode.options with translated labels
- All /custom_translations/*.json:
* Renamed sensor description keys
* Updated chart_metadata usage_tips references
**Documentation**:
- docs/user/docs/actions.md: Updated parameter table and feature list
- docs/user/versioned_docs/version-v0.21.0/actions.md: Backported changes
**Tests**:
- Updated 7 test files with renamed parameters and conversion logic:
* test_connect_segments.py: Renamed minor/major to subunit/base
* test_period_data_format.py: Updated period price conversion tests
* test_avg_none_fallback.py: Fixed tuple unpacking for new return format
* test_best_price_e2e.py: Added config_entry parameter to all calls
* test_cache_validity.py: Fixed cache data structure (price_info key)
* test_coordinator_shutdown.py: Added repair_manager mock
* test_midnight_turnover.py: Added config_entry parameter
* test_peak_price_e2e.py: Added config_entry parameter, fixed price_avg → price_mean
* test_percentage_calculations.py: Added config_entry mock
**Coordinator/Period Calculation**:
- coordinator/periods.py: Added config_entry parameter to
calculate_periods_with_relaxation() calls (2 locations)
Migration Guide:
1. **Update Service Calls in Automations/Scripts**:
\`\`\`yaml
# Before:
service: tibber_prices.get_chartdata
data:
minor_currency: true
# After:
service: tibber_prices.get_chartdata
data:
subunit_currency: true
\`\`\`
2. **Update Energy Dashboard Configuration**:
- Settings → Dashboards → Energy
- Replace sensor entity:
`sensor.tibber_home_current_interval_price_major` →
`sensor.tibber_home_current_interval_price_base`
3. **Review Integration Configuration**:
- Settings → Devices & Services → Tibber Prices → Configure
- New "Currency Display Settings" step added
- Default mode depends on currency (EUR → subunit, Scandinavian → base)
Rationale:
The "major/minor" terminology was confusing and didn't clearly communicate:
- **Major** → Unclear if this means "primary" or "large value"
- **Minor** → Easily confused with "less important" rather than "smaller unit"
New terminology is precise and self-explanatory:
- **Base currency** → Standard ISO currency (€, kr, $, £)
- **Subunit currency** → Fractional unit (ct, øre, ¢, p)
This aligns with:
- International terminology (ISO 4217 standard)
- Banking/financial industry conventions
- User expectations from payment processing systems
Impact: Aligns currency terminology with international standards. Users must
update service calls, automations, and Energy Dashboard configuration after
upgrade.
Refs: User feedback session (December 2025) identified terminology confusion
|
||
|
|
981fb08a69 |
refactor(price_info): price data handling to use unified interval retrieval
- Introduced `get_intervals_for_day_offsets` helper to streamline access to price intervals for yesterday, today, and tomorrow. - Updated various components to replace direct access to `priceInfo` with the new helper, ensuring a flat structure for price intervals. - Adjusted calculations and data processing methods to accommodate the new data structure. - Enhanced documentation to reflect changes in caching strategy and data structure. |
||
|
|
0fd98554ae |
refactor(entity): switch description content based on extended_descriptions
Changed description attribute behavior from "add separate long_description attribute" to "switch description content" when CONF_EXTENDED_DESCRIPTIONS is enabled. OLD: description always shown, long_description added as separate attribute NEW: description content switches between short and long based on config Implementation: - Check extended_descriptions flag BEFORE loading translation - Load "long_description" key if enabled, fallback to "description" if missing - Assign loaded content to "description" attribute (same key always) - usage_tips remains separate attribute (only when extended=true) - Updated both sync (entities) and async (services) versions Added PLR0912 noqa: Branch complexity justified by feature requirements (extended check + fallback logic + position handling). Impact: Users see more detailed descriptions when extended mode enabled, without attribute clutter. Fallback ensures robustness if long_description missing in translations. |
||
|
|
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.
|
||
|
|
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. |
||
|
|
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. |
||
|
|
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". |
||
|
|
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.
|
||
|
|
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
|
||
|
|
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. |
||
|
|
fa40c00f67 | refactor(sensors): Transform sensor platform into package |