Commit graph

259 commits

Author SHA1 Message Date
Julian Pawlowski
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
2025-12-11 08:26:30 +00:00
Julian Pawlowski
ddc092a3a4 fix(statistics): handle None median value in price statistics calculation 2025-12-09 18:36:37 +00:00
Julian Pawlowski
284a7f4291 fix(periods): Periods are now correctly recalculated after tomorrow prices became available. 2025-12-09 16:57:57 +00:00
Julian Pawlowski
51a99980df feat(sensors)!: add configurable median/mean display for average sensors
Add user-configurable option to choose between median and arithmetic mean
as the displayed value for all 14 average price sensors, with the alternate
value exposed as attribute.

BREAKING CHANGE: Average sensor default changed from arithmetic mean to
median. Users who rely on arithmetic mean behavior may use the price_mean attribue now, or must manually reconfigure
via Settings → Devices & Services → Tibber Prices → Configure → General
Settings → "Average Sensor Display" → Select "Arithmetic Mean" to get this as sensor state.

Affected sensors (14 total):
- Daily averages: average_price_today, average_price_tomorrow
- 24h windows: trailing_price_average, leading_price_average
- Rolling hour: current_hour_average_price, next_hour_average_price
- Future forecasts: next_avg_3h, next_avg_6h, next_avg_9h, next_avg_12h

Implementation:
- All average calculators now return (mean, median) tuples
- User preference controls which value appears in sensor state
- Alternate value automatically added to attributes
- Period statistics (best_price/peak_price) extended with both values

Technical changes:
- New config option: CONF_AVERAGE_SENSOR_DISPLAY (default: "median")
- Calculator functions return tuples: (avg, median)
- Attribute builders: add_alternate_average_attribute() helper function
- Period statistics: price_avg → price_mean + price_median
- Translations: Updated all 5 languages (de, en, nb, nl, sv)
- Documentation: AGENTS.md, period-calculation.md, recorder-optimization.md

Migration path:
Users can switch back to arithmetic mean via:
Settings → Integrations → Tibber Prices → Configure
→ General Settings → "Average Sensor Display" → "Arithmetic Mean"

Impact: Median is more resistant to price spikes, providing more stable
automation triggers. Statistical analysis from coordinator still uses
arithmetic mean (e.g., trailing_avg_24h for rating calculations).

Co-developed-with: GitHub Copilot <copilot@github.com>
2025-12-08 17:53:40 +00:00
Julian Pawlowski
99d7c97868 fix(translations): update home not found messages for clarity in multiple languages 2025-12-07 20:57:53 +00:00
Julian Pawlowski
b8bd4670d9 chore(release): bump version to 0.21.0 2025-12-07 20:52:11 +00:00
Julian Pawlowski
83be54d5ad feat(coordinator): implement repairs system for proactive user notifications
Add repair notification system with three auto-clearing repair types:
- Tomorrow data missing (after 18:00)
- API rate limit exceeded (3+ consecutive errors)
- Home not found in Tibber account

Includes:
- coordinator/repairs.py: Complete TibberPricesRepairManager implementation
- Enhanced API error handling with explicit 5xx handling
- Translations for 5 languages (EN, DE, NB, NL, SV)
- Developer documentation in docs/developer/docs/repairs-system.md

Impact: Users receive actionable notifications for important issues instead
of only seeing stale data in logs.
2025-12-07 20:51:43 +00:00
Julian Pawlowski
98512672ae feat(lifecycle): implement HA entity best practices for state management
Implemented comprehensive entity lifecycle patterns following Home Assistant
best practices for proper state management and history tracking.
Changes:
- entity.py: Added available property to base class
  - Returns False when coordinator has no data or last_update_success=False
  - Prevents entities from showing stale data during errors
  - Auth failures trigger reauth flow via ConfigEntryAuthFailed

- sensor/core.py: Added state restore and background task handling
  - Changed inheritance: SensorEntity → RestoreSensor
  - Restore native_value from SensorExtraStoredData in async_added_to_hass()
  - Chart sensors restore response data from attributes
  - Converted blocking service calls to background tasks using hass.async_create_task()
  - Eliminates 194ms setup warning by making async_added_to_hass non-blocking

- binary_sensor/core.py: Added state restore and force_update
  - Changed inheritance: BinarySensorEntity → RestoreEntity + BinarySensorEntity
  - Restore is_on state in async_added_to_hass()
  - Added available property override for connection sensor (always True)
  - Added force_update property for connection sensor to track all state changes
  - Other binary sensors use base available logic

- AGENTS.md: Documented entity lifecycle patterns in Common Pitfalls
  - Added "Entity Lifecycle & State Management" section
  - Documents available, state restore, and force_update patterns
  - Explains why each pattern matters for proper HA integration

Impact: Entities no longer show stale data during errors, history has no gaps
after HA restart, connection state changes are properly tracked, and config
entry setup completes in <200ms (under HA threshold).

All patterns verified against HA developer documentation:
https://developers.home-assistant.io/docs/core/entity/
2025-12-07 17:24:41 +00:00
Julian Pawlowski
763a6b76b9 perf(entities): exclude non-essential attributes from recorder history
Implement _unrecorded_attributes in both sensor and binary_sensor
entities to prevent Home Assistant Recorder database bloat.

Excluded attributes (60-85% size reduction per state):
- Descriptions/help text (static, large strings)
- Large nested structures (periods, trend_attributes, chart data)
- Frequently changing diagnostics (icon_color, cache_age)
- Static/rarely changing config (currency, resolution)
- Temporary/time-bound data (next_api_poll, last_*)
- Redundant/derived data (price_spread, diff_%)

Kept for history analysis:
- timestamp (always first), all price values
- Period timing (start, end, duration_minutes)
- Price statistics (avg, min, max)
- Boolean status flags, relaxation_active

Impact: Reduces attribute size from ~3-8 KB to ~0.5-1.5 KB per state
change. Expected savings: ~1 GB per month for typical installation.

See: https://developers.home-assistant.io/docs/core/entity/#excluding-state-attributes-from-recorder-history
2025-12-07 16:57:40 +00:00
Julian Pawlowski
6241f47012 fix(translations): ensure newline at end of translation files for consistency 2025-12-07 15:17:21 +00:00
Julian Pawlowski
07c01dea01 refactor(i18n): normalize enum values and improve translation consistency
Unified enum representation across all translation files and improved
consistency of localization patterns.

Key changes:
- Replaced uppercase enum constants (VERY_CHEAP, LOW, RISING) with
  localized lowercase values (sehr günstig, niedrig, steigend) across
  all languages in both translations/ and custom_translations/
- Removed **bold** markdown from sensor attributes (custom_translations/)
  as it doesn't render in extra_state_attributes UI
- Preserved **bold** in Config Flow descriptions (translations/) where
  markdown is properly rendered
- Corrected German formality: "Sie" → "du" throughout all descriptions
- Completed missing Config Flow translations in Dutch, Swedish, and
  Norwegian (~45 fields: period_settings, flexibility_settings,
  relaxation_and_target_periods sections)
- Fixed chart_data_export and chart_metadata sensor classification
  (moved from binary_sensor to sensor as they are ENUM type)
- Corrected sensor placement in custom_translations/ (all 5 languages)

Files changed: 10 (5 translations/ + 5 custom_translations/)
Lines: +203, -222

Impact: All 5 languages now use consistent, properly formatted
localized enum values. Config Flow UI displays correctly formatted
examples with bold highlighting. Sensor attributes show clean text
without raw markdown syntax. German uses informal "du" tone throughout.
2025-12-07 14:21:53 +00:00
Julian Pawlowski
86afea9cce docs: Update README with example screenshots. 2025-12-05 21:37:31 +00:00
Julian Pawlowski
afb8ac2327 doc: Add comprehensive chart examples and screenshots for tibber_prices integration
- Created a new documentation file `chart-examples.md` detailing various chart configurations available through the `tibber_prices.get_apexcharts_yaml` action.
- Included descriptions, dependencies, and YAML generation examples for four chart modes: Today's Prices, Rolling 48h Window, and Rolling Window Auto-Zoom.
- Added a section on dynamic Y-axis scaling and best price period highlights.
- Established prerequisites for using the charts, including required cards and customization tips.
- Introduced a new `README.md` in the images/charts directory to document available chart screenshots and guidelines for capturing them.
2025-12-05 21:15:52 +00:00
Julian Pawlowski
f92fc3b444 refactor(services): remove gradient_stop, use fixed 50% gradient
Implementation flaw discovered: gradient_stop calculated as
`(avg - min) / (max - min)` for combined data produces one value
applied to ALL series. Each series (VERY_CHEAP, NORMAL, VERY_EXPENSIVE)
has different min/max ranges, so the same gradient stop position
represents a different absolute price in each series.

Example failure case:
- VERY_CHEAP: 10-20 ct → 50% at 15 ct (below overall avg!)
- VERY_EXPENSIVE: 40-50 ct → 50% at 45 ct (above overall avg!)

Conclusion: Gradient shows middle of each series range, not average
price position.

Solution: Fixed 50% gradient purely for visual appeal. Semantic
information provided by:
- Series colors (CHEAP/NORMAL/EXPENSIVE)
- Grid lines (implicitly show average)
- Dynamic Y-axis bounds (optimal scaling via chart_metadata sensor)

Changes:
- sensor/chart_metadata.py: Remove gradient_stop extraction
- services/get_apexcharts_yaml.py: Fixed gradient at [50, 100]
- custom_translations/*.json: Remove gradient_stop references

Impact: Honest visualization with no false semantic signals. Feature
was never released, clean removal without migration.
2025-12-05 20:51:30 +00:00
Julian Pawlowski
6922e52368 feat(sensors): add chart_metadata sensor for lightweight chart configuration
Implemented new chart_metadata diagnostic sensor that provides essential
chart configuration values (yaxis_min, yaxis_max, gradient_stop) as
attributes, enabling dynamic chart configuration without requiring
async service calls in templates.

Sensor implementation:
- New chart_metadata.py module with metadata-only service calls
- Automatically calls get_chartdata with metadata="only" parameter
- Refreshes on coordinator updates (new price data or user data)
- State values: "pending", "ready", "error"
- Enabled by default (critical for chart features)

ApexCharts YAML generator integration:
- Checks for chart_metadata sensor availability before generation
- Uses template variables to read sensor attributes dynamically
- Fallback to fixed values (gradient_stop=50%) if sensor unavailable
- Creates separate notifications for two independent issues:
  1. Chart metadata sensor disabled (reduced functionality warning)
  2. Required custom cards missing (YAML won't work warning)
- Both notifications explain YAML generation context and provide
  complete fix instructions with regeneration requirement

Configuration:
- Supports configuration.yaml: tibber_prices.chart_metadata_config
- Optional parameters: day, minor_currency, resolution
- Defaults to minor_currency=True for ApexCharts compatibility

Translation additions:
- Entity name and state translations (all 5 languages)
- Notification messages for sensor unavailable and missing cards
- best_price_period_name for tooltip formatter

Binary sensor improvements:
- tomorrow_data_available now enabled by default (critical for automations)
- data_lifecycle_status now enabled by default (critical for debugging)

Impact: Users get dynamic chart configuration with optimized Y-axis scaling
and gradient positioning without manual calculations. ApexCharts YAML
generation now provides clear, actionable notifications when issues occur,
ensuring users understand why functionality is limited and how to fix it.
2025-12-05 20:30:54 +00:00
Julian Pawlowski
ac6f1e0955 chore(release): bump version to 0.20.0 2025-12-05 18:14:32 +00:00
Julian Pawlowski
c8e9f7ec2a feat(apexcharts): add server-side metadata with dynamic yaxis and gradient
Implemented comprehensive metadata calculation for chart data export service
with automatic Y-axis scaling and gradient positioning based on actual price
statistics.

Changes:
- Added 'metadata' parameter to get_chartdata service (include/only/none)
- Implemented _calculate_metadata() with per-day price statistics
  * min/max/avg/median prices
  * avg_position and median_position (0-1 scale for gradient stops)
  * yaxis_suggested bounds (floor(min)-1, ceil(max)+1)
  * time_range with day boundaries
  * currency info with symbol and unit
- Integrated metadata into rolling_window modes via config-template-card
  * Pre-calculated yaxis bounds (no async issues in templates)
  * Dynamic gradient stops based on avg_position
  * Server-side calculation ensures consistency

Visual refinements:
- Best price overlay opacity reduced to 0.05 (ultra-subtle green hint)
- Stroke width increased to 1.5 for better visibility
- Gradient opacity adjusted to 0.45 with "light" shade
- Marker configuration: size 0, hover size 2, strokeWidth 1
- Header display: Only show LOW/HIGH rating_levels (min/max prices)
  * Conditional logic excludes NORMAL and level types
  * Entity state shows meaningful extrema values
- NOW marker label removed for rolling_window_autozoom mode
  * Static position at 120min lookback makes label misleading

Code cleanup:
- Removed redundant all_series_config (server-side data formatting)
- Currency names capitalized (Cents, Øre, Öre, Pence)

Translation updates:
- Added metadata selector translations (de, en, nb, nl, sv)
- Added metadata field description in services
- Synchronized all language files

Impact: Users get dynamic Y-axis scaling based on actual price data,
eliminating manual configuration. Rolling window charts automatically
adjust axis bounds and gradient positioning. Header shows only
meaningful extreme values (daily min/max). All data transformation
happens server-side for optimal performance and consistency.
2025-12-05 18:14:18 +00:00
Julian Pawlowski
2f1929fbdc chore(release): bump version to 0.19.0 2025-12-04 14:39:16 +00:00
Julian Pawlowski
c9a7dcdae7 feat(services): add rolling window options with auto-zoom for ApexCharts
Added two new rolling window options for get_apexcharts_yaml service to provide
flexible dynamic chart visualization:

- rolling_window: Fixed 48h window that automatically shifts between
  yesterday+today and today+tomorrow based on data availability
- rolling_window_autozoom: Same as rolling_window but with progressive zoom-in
  (2h lookback + remaining time until midnight, updates every 15min)

Implementation changes:
- Updated service schema validation to accept new day options
- Added entity mapping patterns for both rolling modes
- Implemented minute-based graph_span calculation with quarter-hour alignment
- Added config-template-card integration for dynamic span updates
- Used current_interval_price sensor as 15-minute update trigger
- Unified data loading: both rolling modes omit day parameter for dynamic selection
- Applied ternary operator pattern for cleaner day_param logic
- Made grid lines more subtle (borderColor #f5f5f5, strokeDashArray 0)

Translation updates:
- Added selector options in all 5 languages (de, en, nb, nl, sv)
- Updated field descriptions to include default behavior and new options
- Documented that rolling window is default when day parameter omitted

Documentation updates:
- Updated user docs (actions.md, automation-examples.md) with new options
- Added detailed explanation of day parameter options
- Included examples for both rolling_window and rolling_window_autozoom modes

Impact: Users can now create auto-adapting ApexCharts that show 48h rolling
windows with optional progressive zoom throughout the day. Requires
config-template-card for dynamic behavior.
2025-12-04 14:39:00 +00:00
Julian Pawlowski
1386407df8 fix(translations): update descriptions and names for clarity in multiple language files 2025-12-04 12:41:11 +00:00
Julian Pawlowski
c28c33dade chore(release): bump version to 0.18.1 2025-12-03 14:21:06 +00:00
Julian Pawlowski
6e0310ef7c fix(services): correct period data format for ApexCharts visualization
Period data in array_of_arrays format now generates proper segment structure
for stepline charts. Each period produces 2-3 data points depending on
insert_nulls parameter:

1. Start time with price (begin period)
2. End time with price (hold price level)
3. End time with NULL (terminate segment, only if insert_nulls='segments'/'all')

This enables ApexCharts to correctly display periods as continuous blocks with
clean gaps between them. Previously only start point was generated, causing
periods to render as single points instead of continuous segments.

Changes:
- formatters.py: Updated get_period_data() to generate 2-3 points per period
- formatters.py: Added insert_nulls parameter to control NULL termination
- get_chartdata.py: Pass insert_nulls parameter to get_period_data()
- get_apexcharts_yaml.py: Set insert_nulls='segments' for period overlay
- get_apexcharts_yaml.py: Preserve NULL values in data_generator mapping
- get_apexcharts_yaml.py: Store original price for potential tooltip access
- tests: Added comprehensive period data format tests

Impact: Best price and peak price period overlays now display correctly as
continuous blocks with proper segment separation in ApexCharts cards.
2025-12-03 14:20:46 +00:00
Julian Pawlowski
a2d664e120 chore(release): bump version to 0.18.0 2025-12-03 13:36:04 +00:00
Julian Pawlowski
d7b129efec chore(release): bump version to 0.17.1 2025-12-03 13:16:06 +00:00
Julian Pawlowski
8893b31f21 fix(binary_sensor): restore push updates from coordinator
Binary sensor _handle_coordinator_update() was empty, blocking all push updates
from coordinator. This prevented binary sensors from reflecting state changes
immediately after API fetch or error conditions.

Changes:
- Implement _handle_coordinator_update() to call async_write_ha_state()
- All binary sensors now receive push updates when coordinator has new data

Binary sensors affected:
- tomorrow_data_available: Now reflects data availability immediately after API fetch
- connection: Now shows disconnected state immediately on auth/API errors
- chart_data_export: Now updates chart data when price data changes
- peak_price_period, best_price_period: Get push updates when periods change
- data_lifecycle_status: Gets push updates on status changes

Impact: Binary sensors update in real-time instead of waiting for next timer
cycle or user interaction. Fixes stale state issue where tomorrow_data_available
remained off despite data being available, and connection sensor not reflecting
authentication failures immediately.
2025-12-03 13:14:26 +00:00
Julian Pawlowski
a1ab98d666 refactor(config_flow): reorganize options flow steps with section structure
Restructured 5 options flow steps (current_interval_price_rating, best_price,
peak_price, price_trend, volatility) to use Home Assistant's sections feature
for better UI organization and logical grouping.

Changes:
- current_interval_price_rating: Single section "price_rating_thresholds"
- best_price: Three sections (period_settings, flexibility_settings,
  relaxation_and_target_periods)
- peak_price: Three sections (period_settings, flexibility_settings,
  relaxation_and_target_periods)
- price_trend: Single section "price_trend_thresholds"
- volatility: Single section "volatility_thresholds"

Each section includes name, description, data fields, and data_description
fields following HA translation schema requirements.

Updated all 5 language files (de, en, nb, nl, sv) with new section structure
while preserving existing field descriptions and translations.

Impact: Options flow now displays configuration fields in collapsible,
logically grouped sections with clear section headers, improving UX for
complex multi-parameter configuration steps. No functional changes to
configuration logic or validation.
2025-12-02 20:23:31 +00:00
Julian Pawlowski
3098144db2 chore(release): bump version to 0.17.0 2025-12-02 19:00:54 +00:00
Julian Pawlowski
3977d5e329 fix(coordinator): add _is_fetching flag and fix tomorrow data detection
Implement _is_fetching flag to show "refreshing" status during API calls,
and fix needs_tomorrow_data() to recognize single-home cache format.

Changes:
- Set _is_fetching flag before API call, reset after completion (core.py)
- Fix needs_tomorrow_data() to check for "price_info" key instead of "homes"
- Remove redundant "homes" check in should_update_price_data()
- Improve logging: change debug to info for tomorrow data checks

Lifecycle status now correctly transitions after 13:00 when tomorrow data
is missing: cached → searching_tomorrow → refreshing → fresh → cached

Impact: Users will see accurate lifecycle status and tomorrow's electricity
prices will automatically load when available after 13:00, fixing issue
since v0.14.0 where prices weren't fetched without manual HA restart.
2025-12-02 19:00:20 +00:00
Julian Pawlowski
d6ae931918 feat(services): add new services and icons for enhanced functionality and user experience 2025-12-02 18:46:15 +00:00
Julian Pawlowski
97db134ed5 feat(services): add icons to service definitions for better visibility 2025-12-02 17:16:44 +00:00
github-actions[bot]
ae6f0780fd chore(release): sync manifest.json with tag v0.16.1 2025-12-02 16:49:44 +00:00
Julian Pawlowski
b78ddeaf43 feat(docs): update get_apexcharts_yaml service descriptions to clarify limitations and customization options 2025-12-02 16:47:36 +00:00
Julian Pawlowski
0a44dd7f12 chore(release): bump version to 0.16.0 2025-12-01 23:48:36 +00:00
Julian Pawlowski
e156dfb061 feat(services): add rolling 48h window support to chart services
Add dynamic rolling window mode to get_chartdata and get_apexcharts_yaml
services that automatically adapts to data availability.

When 'day' parameter is omitted, services return 48-hour window:
- With tomorrow data (after ~13:00): today + tomorrow
- Without tomorrow data: yesterday + today

Changes:
- Implement rolling window logic in get_chartdata using has_tomorrow_data()
- Generate config-template-card wrapper in get_apexcharts_yaml for dynamic
  ApexCharts span.offset based on tomorrow_data_available binary sensor
- Update service descriptions in services.yaml
- Add rolling window descriptions to all translations (de, en, nb, nl, sv)
- Document rolling window mode in docs/user/services.md
- Add ApexCharts examples with prerequisites in docs/user/automation-examples.md

BREAKING CHANGE: get_apexcharts_yaml rolling window mode requires
config-template-card in addition to apexcharts-card for dynamic offset
calculation.

Impact: Users can create auto-adapting 48h price charts without manual day
selection. Fixed day views (day: today/yesterday/tomorrow) still work with
apexcharts-card only.
2025-12-01 23:46:09 +00:00
Julian Pawlowski
cf8d9ba8e8 feat(apexcharts): add highlight option for best price periods in chart 2025-12-01 21:51:39 +00:00
Julian Pawlowski
f70ac9cff6 feat(services): improve ApexCharts segment visualization and fix header display
Simplifies the connect_segments implementation to use a unified bridge-point
approach for all price transitions (up/down/same). Previously used
direction-dependent logic (hold vs connect points) which was unnecessarily
complex.

Changes:
- get_chartdata.py: Bridge points now always use next interval's price at
  boundary timestamp, creating smooth visual connection between segments
- get_chartdata.py: Trailing NULL removal now conditional on insert_nulls mode
  ('segments' removes for header fix, 'all' preserves intentional gaps)
- get_apexcharts_yaml.py: Enable connect_segments by default, activate
  show_states for header min/max display
- get_apexcharts_yaml.py: Remove extrema series (not compatible with
  data_generator approach - ApexCharts requires entity time-series data)
- tests: Move test_connect_segments.py to tests/services/ to mirror source
  structure

Impact: ApexCharts cards now show clean visual connections between price level
segments with proper header statistics display. Trailing NULLs no longer cause
"N/A" in headers for filtered data. Test organization improved for
maintainability.
2025-12-01 11:14:27 +00:00
Copilot
49628f3394
Add connect_segments parameter and fix ApexCharts header N/A display (#46)
* Initial plan

* Add connect_segments parameter to get_chartdata service for visual segment connections

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>

* Address code review feedback: fix test logic and correct misleading comment

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>

* Integrate PR45: Remove trailing null values for proper ApexCharts header display

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>

* Add connect_segments translations for de, nb, nl, sv languages

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>

* Changes before error encountered

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>

* Fix hassfest validation: Move time_units from translations to custom_translations

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>
2025-12-01 03:19:52 +01:00
Julian Pawlowski
b306a491e0 refactor(translations): unify time unit translations across multiple languages 2025-11-30 17:25:58 +00:00
Julian Pawlowski
2320520ed9 chore(release): bump version to 0.15.0 2025-11-30 16:43:21 +00:00
Julian Pawlowski
412cecc126 refactor(cache): enhance cache validation to support new structure and invalidate old format 2025-11-30 16:42:41 +00:00
Julian Pawlowski
6f93bb8288 refactor(formatters, get_chartdata): serialize datetime objects to ISO format in data points 2025-11-30 15:07:18 +00:00
Julian Pawlowski
7c0000039e refactor(config_flow): disable subentry flow temporarily due to incomplete time-travel feature 2025-11-26 14:36:08 +00:00
Julian Pawlowski
3c69807c05 refactor(logging): use details logger for verbose period calculation logs
Moved verbose debug logging to separate _LOGGER_DETAILS logger:
- core.py: Outlier flex capping messages
- outlier_filtering.py: Spike detection, context validation, smoothing details
- period_building.py: Level filter details, gap tolerance info
- relaxation.py: Per-phase iteration details, filter combination attempts

Pattern: Main _LOGGER for high-level progress, _LOGGER_DETAILS for step-by-step

Benefits:
- Users can disable verbose logs via logger configuration
- Main DEBUG log stays readable (high-level flow)
- Details available when needed for troubleshooting

Added:
- period_overlap.py: Docstring for extend_period_if_adjacent()

Impact: Cleaner log output by default. Enable details logger
(homeassistant.components.tibber_prices.coordinator.period_handlers.details)
for deep debugging.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
9ae618fff9 refactor(config_flow): rename TibberPricesFlowHandler to TibberPricesConfigFlowHandler
Renamed main config flow handler class for clarity:
- TibberPricesFlowHandler → TibberPricesConfigFlowHandler

Updated imports in:
- config_flow.py (import alias)
- config_flow_handlers/__init__.py (exports)

Reason: More explicit name distinguishes from OptionsFlowHandler and
SubentryFlowHandler. Follows naming convention of other flow handlers.

Impact: No functional changes, improved code readability.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
6338f51527 refactor(services): rename service modules to match service names
Renamed service modules for consistency with service identifiers:
- apexcharts.py → get_apexcharts_yaml.py
- chartdata.py → get_chartdata.py
- Added: get_price.py (new service module)

Naming convention: Module names now match service names directly
(tibber_prices.get_apexcharts_yaml → get_apexcharts_yaml.py)

Impact: Improved code organization, easier to locate service implementations.
No functional changes.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
b6f5f1678f feat(services): add fetch_price_info_range service and update schema
Added new service for fetching historical/future price data:
- fetch_price_info_range: Query prices for arbitrary date ranges
- Supports start_time and end_time parameters
- Returns structured price data via service response
- Uses interval pool for efficient data retrieval

Service definition:
- services.yaml: Added fetch_price_info_range with date selectors
- services/__init__.py: Implemented handler with validation
- Response format: {"priceInfo": [...], "currency": "..."}

Schema updates:
- config_flow_handlers/schemas.py: Convert days slider to IntSelector
  (was NumberSelector with float, caused "2.0 Tage" display issue)

Impact: Users can fetch price data for custom date ranges programmatically.
Config flow displays clean integer values for day offsets.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
44f6ae2c5e feat(interval-pool): add intelligent interval caching and memory optimization
Implemented interval pool architecture for efficient price data management:

Core Components:
- IntervalPool: Central storage with timestamp-based index
- FetchGroupCache: Protected range management (day-before-yesterday to tomorrow)
- IntervalFetcher: Gap detection and optimized API queries
- TimestampIndex: O(1) lookup for price intervals

Key Features:
- Deduplication: Touch intervals instead of duplicating (memory efficient)
- GC cleanup: Removes dead intervals no longer referenced by index
- Gap detection: Only fetches missing ranges, reuses cached data
- Protected range: Keeps yesterday/today/tomorrow, purges older data
- Resolution support: Handles hourly (pre-Oct 2025) and quarter-hourly data

Integration:
- TibberPricesApiClient: Uses interval pool for all range queries
- DataUpdateCoordinator: Retrieves data from pool instead of direct API
- Transparent: No changes required in sensor/service layers

Performance Benefits:
- Reduces API calls by 70% (reuses overlapping intervals)
- Memory footprint: ~10KB per home (protects 384 intervals max)
- Lookup time: O(1) timestamp-based index

Breaking Changes: None (backward compatible integration layer)

Impact: Significantly reduces Tibber API load while maintaining data
freshness. Memory-efficient storage prevents unbounded growth.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
e04e38d09f refactor(logging): remove verbose debug logging from price enrichment
Removed excessive debug logging in enrich_price_info_with_differences():
- Deleted per-interval "Processing" messages (cluttered logs)
- Kept boundary INFO messages (enrichment start/skip counts)
- Removed unused variable expected_intervals_24h
- Removed unused parameter day_label from _process_price_interval()

Impact: Cleaner logs, no functional changes. Reduces log volume during
price data processing.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
2449c28a88 feat(i18n): localize time offset descriptions and config flow strings
Added complete localization support for time offset descriptions:
- Convert hardcoded English strings "(X days ago)" to translatable keys
- Add time_units translations (day/days, hour/hours, minute/minutes, ago, now)
- Support singular/plural forms in all 5 languages (de, en, nb, nl, sv)
- German: Proper Dativ case "Tagen" with preposition "vor"
- Compact format for mixed offsets: "7 Tagen - 02:30"

Config flow improvements:
- Replace hardcoded "Enter new API token" with translated "Add new Tibber account API token"
- Use get_translation() for account_choice dropdown labels
- Fix SelectOptionDict usage (no mixing with translation_key parameter)
- Convert days slider from float to int (prevents "2.0 Tage" display)
- DurationSelector: default {"hours": 0, "minutes": 0} to fix validation errors

Translation keys added:
- selector.account_choice.options.new_token
- time_units (day, days, hour, hours, minute, minutes, ago, now)
- config.step.time_offset_description guidance text

Impact: Config flow works fully translated in all 5 languages with proper grammar.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
7e47ef5995 docs: fix attribute names in AGENTS.md examples
Updated attribute ordering documentation to use correct names:
- "periods" → "pricePeriods" (matches code since refactoring)
- "intervals" → "priceInfo" (flat list structure)

Impact: Documentation now matches actual code structure.
2025-11-24 16:26:23 +00:00