Commit graph

374 commits

Author SHA1 Message Date
Julian Pawlowski
b461e89f08 fix(setup): improve conditional checks for optional package installations 2025-11-21 11:14:00 +00:00
dependabot[bot]
5a77734ec5
chore(deps): bump actions/checkout from 5.0.1 to 6.0.0 (#32) 2025-11-20 23:13:16 +01: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
294da3960c fix(translations): correct typo in price trend title in German localization 2025-11-20 13:00:21 +00:00
Julian Pawlowski
b8a502672b refactor(config_flow): unify translation structure across all languages
Standardized config flow translations (nb, nl, sv) to match German/English
format with minimal field labels and comprehensive data_descriptions.

Changes across Norwegian, Dutch, and Swedish translations:
- Updated step_progress format: **{step_progress}** → _{step_progress}_
- Made all step descriptions bold with **text** formatting
- Simplified field labels (removed verbose explanations)
- Added data_description for price_rating (low/high thresholds)
- Added data_description for price_trend (rising/falling thresholds)
- Added data_description for volatility (moderate/high/very high thresholds)
- Ensured all steps have: emojis, italic step_progress, separator (---)
- Added missing emoji to Swedish price_rating step (📊)

Impact: All 5 languages now have consistent UX with minimal, scannable
field labels and detailed optional descriptions accessible via ⓘ icon.
Users get cleaner config flow with better clarity.
2025-11-20 12:59:12 +00:00
Julian Pawlowski
46fcdb8ba3 docs(period-calculation): update default thresholds for Best Price and Peak Price periods 2025-11-20 11:52:15 +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
07f5990e06 docs(guidelines): update naming conventions for public and private classes 2025-11-20 10:29:45 +00:00
Julian Pawlowski
5ff61b6d5c feat(setup): add optional pyright installation and create type-check script 2025-11-20 10:10:33 +00:00
Julian Pawlowski
781286216a fix(devcontainer): suppress unused import and variable warnings in Python analysis 2025-11-20 09:44:59 +00:00
Julian Pawlowski
821131dbe9 fix(devcontainer): add custom_components/tibber_prices to Python analysis include 2025-11-20 09:30:32 +00:00
Julian Pawlowski
d6761186f1 chore(release): bump version to 0.11.1 2025-11-19 20:55:44 +00:00
Julian Pawlowski
ced6dcf104 fix(coordinator): sync cached_user_data after API call for new integrations
When adding a new integration (no existing cache), metadata sensors
(grid_company, estimated_annual_consumption, etc.) were marked as
unavailable because coordinator._cached_user_data remained None even
after successful API call.

Root cause: update_user_data_if_needed() stored user data in
_data_fetcher.cached_user_data, but the sync back to coordinator
only happened during _load_cache() (before the API call).

Solution: Added explicit sync of cached_user_data after
handle_main_entry_update() completes, ensuring metadata is available
when sensors first access get_user_homes().

Changes:
- coordinator/core.py: Sync _cached_user_data after main entry update
- __init__.py: Kept preload cache call (helps with HA restarts)

Impact: Metadata sensors now show values immediately on fresh integration
setup, without requiring a second update cycle or manual sensor activation.
2025-11-19 20:55:13 +00:00
Julian Pawlowski
2cbb35afd2 chore(release): bump version to 0.11.0 2025-11-19 20:18:37 +00:00
Julian Pawlowski
457fa7c03f refactor(periods): merge adjacent periods and remove is_extension logic
BREAKING CHANGE: Period overlap resolution now merges adjacent/overlapping periods
instead of marking them as extensions. This simplifies automation logic and provides
clearer period boundaries for users.

Previous Behavior:
- Adjacent periods created by relaxation were marked with is_extension=true
- Multiple short periods instead of one continuous period
- Complex logic needed to determine actual period length in automations

New Behavior:
- Adjacent/overlapping periods are merged into single continuous periods
- Newer period's relaxation attributes override older period's
- Simpler automation: one period = one continuous time window

Changes:
- Period Overlap Resolution (new file: period_overlap.py):
  * Added merge_adjacent_periods() to combine periods and preserve attributes
  * Rewrote resolve_period_overlaps() with simplified merge logic
  * Removed split_period_by_overlaps() (no longer needed)
  * Removed is_extension marking logic
  * Removed unused parameters: min_period_length, baseline_periods

- Relaxation Strategy (relaxation.py):
  * Removed all is_extension filtering from period counting
  * Simplified standalone counting to just len(periods)
  * Changed from period_merging import to period_overlap import
  * Added MAX_FLEX_HARD_LIMIT constant (0.50)
  * Improved debug logging for merged periods

- Code Quality:
  * Fixed all remaining linter errors (N806, PLR2004, PLR0912)
  * Extracted magic values to module-level constants:
    - FLEX_SCALING_THRESHOLD = 0.20
    - SCALE_FACTOR_WARNING_THRESHOLD = 0.8
    - MAX_FLEX_HARD_LIMIT = 0.50
  * Added appropriate noqa comments for unavoidable patterns

- Configuration (from previous work in this session):
  * Removed CONF_RELAXATION_STEP_BEST, CONF_RELAXATION_STEP_PEAK
  * Hard-coded 3% relaxation increment for reliability
  * Optimized defaults: RELAXATION_ATTEMPTS 8→11, ENABLE_MIN_PERIODS False→True,
    MIN_PERIODS undefined→2
  * Removed relaxation_step UI fields from config flow
  * Updated all 5 translation files

- Documentation:
  * Updated period_handlers/__init__.py: period_merging → period_overlap
  * No user-facing docs changes needed (already described continuous periods)

Rationale - Period Merging:
User experience was complicated by fragmented periods:
- Automations had to check multiple adjacent periods
- Binary sensors showed ON/OFF transitions within same cheap time
- No clear way to determine actual continuous period length

With merging:
- One continuous cheap time = one period
- Binary sensor clearly ON during entire period
- Attributes show merge history via merged_from dict
- Relaxation info preserved from newest/highest flex period

Rationale - Hard-Coded Relaxation Increment:
The configurable relaxation_step parameter proved problematic:
- High base flex + high step → rapid explosion (40% base + 10% step → 100% in 6 steps)
- Users don't understand the multiplicative nature
- 3% increment provides optimal balance: 11 attempts to reach 50% hard cap

Impact:
- Existing installations: Periods may appear longer (merged instead of split)
- Automations benefit from simpler logic (no is_extension checks needed)
- Custom relaxation_step values will use new 3% increment
- Users may need to adjust relaxation_attempts if they relied on high step sizes
2025-11-19 20:16:58 +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
b3f91a67ce chore(release): bump version to 0.10.1 2025-11-18 22:19:00 +00:00
Julian Pawlowski
3d1b6a64fc docs(architecture): update architecture documentation with Calculator Pattern details and sensor organization 2025-11-18 21:29:07 +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
df075ae56a docs(AGENTS): update documentation metadata and guidelines for code examples 2025-11-18 20:08:25 +00:00
Julian Pawlowski
b5a0854cee docs(coordinator): enhance package docstring with detailed overview and components 2025-11-18 20:08:09 +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
ac24f6a8cb refactor(services): split monolithic services.py into package
Split services.py (1,097 lines) into modular package (6 files, ~200-600 lines each):

Structure:
- services/__init__.py: Service registration (70 lines)
- services/helpers.py: Entry validation (55 lines)
- services/formatters.py: Data transformation (380 lines)
- services/chartdata.py: Chart data export handler (600 lines)
- services/apexcharts.py: ApexCharts YAML generator (240 lines)
- services/refresh_user_data.py: User data refresh (110 lines)

Benefits:
- Clear separation of concerns (helpers, formatters, handlers)
- Each service isolated and independently testable
- Consistent handler naming (handle_* pattern)
- Better code reuse through formatters module

All services working identically (get_chartdata, get_apexcharts_yaml,
refresh_user_data). Updated __init__.py to import from services package.

Impact: Improved maintainability, reduced max file size from 1,097
to 600 lines. Architecture quality improved from 7.5/10 to ~8.5/10.
2025-11-18 20:07:05 +00:00
Julian Pawlowski
d52eb6b788 refactor(utils): create utils package and consolidate constants
Reorganized utility modules into structured package:
- average_utils.py → utils/average.py
- price_utils.py → utils/price.py
- Created utils/__init__.py with clean exports

Moved MINUTES_PER_INTERVAL to const.py (centralized constant
management), with re-exports in utils modules for backward
compatibility during migration.

Added comprehensive package docstring explaining scope:
- Pure data transformation functions (stateless)
- No HA entity/coordinator dependencies
- Clear separation from entity_utils/ (entity-specific logic)

Impact: Cleaner module structure, easier navigation. Follows
file organization policy from AGENTS.md (keep root clean).
2025-11-18 20:06:46 +00:00
Julian Pawlowski
d828f754be Merge branch 'chore/refactoring' into main
Complete refactoring of module structure and documentation:

- Resolved circular import dependencies
- Split monolithic files into organized packages (api/, coordinator/)
- Added comprehensive architecture and timer documentation
- Implemented smart boundary tolerance for quarter-hour rounding
- Enhanced midnight turnover coordination
- All lint checks passing

This merge brings significant improvements to code maintainability and
documentation quality while maintaining full backward compatibility.
2025-11-18 17:32:54 +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
dependabot[bot]
3f90de0c0a
chore(deps): bump actions/checkout from 5.0.0 to 5.0.1 (#29) 2025-11-18 08:56:11 +01:00
Julian Pawlowski
21b444c16d chore(release): bump version to 0.10.0 2025-11-17 04:11:45 +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
e17f59c283 chore(release): bump version to 0.11.0 2025-11-17 03:14:19 +00:00
Julian Pawlowski
38ce1c4c50 feat(chart_export): add Chart Data Export diagnostic sensor
Added optional diagnostic binary sensor that exposes get_chartdata
service results as entity attributes for legacy dashboard tools.

Key features:
- Entity: binary_sensor.tibber_home_NAME_chart_data_export
- Configurable via Options Flow Step 7 (YAML parameters)
- Calls get_chartdata service with user configuration
- Exposes response as attributes for chart cards
- Disabled by default (opt-in)
- Auto-refreshes on coordinator updates
- Manual refresh via homeassistant.update_entity

Implementation details:
- Added chart_data_export entity description to definitions.py
- Implemented state/attribute logic in binary_sensor/core.py
- Added YAML configuration schema in schemas.py
- Added validation in options_flow.py (Step 7)
- Service call validation with detailed error messages
- Attribute ordering: metadata first, descriptions next, service data last
- Dynamic icon mapping (database-export/database-alert)

Translations:
- Added chart_data_export_config to all 5 languages
- Added Step 7 descriptions with legacy warning
- Added invalid_yaml_syntax/invalid_yaml_structure error messages
- Added custom_translations for sensor descriptions

Documentation:
- Added Chart Data Export section to sensors.md
- Added comprehensive service guide to services.md
- Migration path from sensor to service
- Configuration instructions via Options Flow

Impact: Provides backward compatibility for dashboard tools that can
only read entity attributes (e.g., older ApexCharts versions). New
integrations should use tibber_prices.get_chartdata service directly.
2025-11-17 03:14:02 +00:00
Julian Pawlowski
0bf810f0d5 chore(release): bump version to 0.10.0 2025-11-16 23:52:57 +00:00
Julian Pawlowski
fb70f29ac9 feat(services): rewrite ApexCharts service for modern workflow
Complete overhaul of the ApexCharts integration service layer to support
modern chart card workflows with flexible data formatting and filtering.

Replaced services:
- Removed: get_price, get_apexcharts_data (legacy, entity-based)
- Added: get_chartdata (flexible data service)
- Improved: get_apexcharts_yaml (now uses get_chartdata internally)

New get_chartdata service features:
- Multiple output formats (array_of_objects, array_of_arrays)
- Customizable field names for chart compatibility
- Resolution options (15-min intervals, hourly averages)
- Advanced filtering (level_filter, rating_level_filter)
- NULL insertion modes (none, segments, all) for clean gaps
- Minor currency support (cents/øre) with custom rounding
- Optional fields (level, rating_level, average)
- Multi-day support (yesterday/today/tomorrow)

Enhanced get_apexcharts_yaml service:
- Direct entry_id parameter (no entity_id lookup needed)
- Uses get_chartdata with WebSocket API (data_generator)
- Improved ApexCharts configuration:
  * Gradient fill (70% opacity → 20%)
  * Grid styling with dashed lines
  * Zoom & Pan tools (animations disabled for performance)
  * Optimized legend (top-left, compact markers)
  * Y-axis auto-scaling (min: 0 for visibility, supports negative prices)
  * 2 decimal places (improved precision)
  * Browser locale formatting (automatic comma/point)
  * insert_nulls='segments' for clean gaps between levels
- Multi-language support (translated titles, series names)
- Day selection (yesterday/today/tomorrow with correct span config)

Service translations:
- Added comprehensive field descriptions (all 5 languages: de, en, nb, nl, sv)
- Selector translations for all options (day, resolution, output_format, etc.)
- ApexCharts title translations in custom_translations/

Technical improvements:
- Hourly aggregation uses exact 4-interval windows (:00/:15/:30/:45)
- Level/rating aggregation follows sensor logic (aggregate_level_data, aggregate_rating_data)
- Midnight extension for last interval of filtered data (seamless day transitions)
- Case-insensitive filter matching (normalized to uppercase)
- Ruff complexity fixed (extracted _get_level_translation helper)

Impact: Users can now generate production-ready ApexCharts YAML with a single
service call, or use get_chartdata flexibly with any chart card (ApexCharts,
Plotly, Mini Graph, etc.). Supports complex filtering scenarios (e.g., "show
only LOW rating periods") with clean visual gaps. Full multi-language support.
2025-11-16 23:52:36 +00:00
Julian Pawlowski
7bc83ed3e2 chore(dev): remove IntelliCode extension from devcontainer configuration 2025-11-16 18:15:00 +00:00
Julian Pawlowski
329f96f2f4 chore(dev): enhance sync-hac script to clean up broken symlinks and report changes 2025-11-16 18:13:29 +00:00
Julian Pawlowski
60c3b72932 chore(dev): add HACS installation and sync scripts for testing
Added scripts to install HACS in DevContainer for testing the
integration alongside other HACS components.

Changes:
- scripts/setup: Automatically install HACS and create symlink
- scripts/sync-hacs: Sync HACS-installed integrations via symlinks
- .gitignore: Ignore custom_components/* except tibber_prices

HACS installs to config/custom_components/, symlinks in
custom_components/ make integrations visible to Home Assistant.

Impact: Developers can test with other integrations. No user changes.
2025-11-16 18:05:14 +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
6389249020 refactor(translations): update terminology for price period settings in German translations 2025-11-16 10:29:30 +00:00
Julian Pawlowski
3c69ca6f75 feat(release): remove version tag prefix from release titles
HACS automatically displays the version number before release titles,
causing duplication when version tags are included in the title.

Changes:
- scripts/generate-release-notes: All backends now generate intelligent
  titles without version prefix (git-cliff, manual, and copilot)
- scripts/generate-release-notes: Added smart title generation based on
  commit analysis (feat/fix counts) for git-cliff and manual backends
- scripts/generate-release-notes: Unified section headers to use ### (H3)
  instead of ## (H2) for consistency across all backends
- scripts/generate-release-notes: Auto-update feature now uses extracted
  title without prepending version tag
- .github/workflows/release.yml: Extract title directly from generated
  release notes (first line with "# ") instead of manual construction
- .github/workflows/release.yml: Removed redundant "Generate release title"
  step

Before (HACS): v0.9.0: v0.9.0 - New Features
After (HACS):  v0.9.0: Multi-Home Support & Diagnostic Sensors

Impact: Release titles in HACS are now cleaner with single version display
and more descriptive titles generated intelligently from commit content.
All three backends (copilot, git-cliff, manual) produce consistent output
with H1 title followed by H3 sections.
2025-11-16 00:26:34 +00:00
Julian Pawlowski
4508e69ffd chore(release): bump version to 0.9.0 2025-11-16 00:12:20 +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
dae0b43971 refactor(translations): enhance clarity of price labels in German, Norwegian, Dutch, and Swedish 2025-11-15 21:35:44 +00:00
Julian Pawlowski
c3c98a4b63 refactor(translations): simplify price start time labels in multiple languages 2025-11-15 21:23:26 +00:00
Julian Pawlowski
a2c1edb876 refactor(translations): improve clarity of price labels in multiple languages 2025-11-15 21:18:19 +00:00
Julian Pawlowski
ac2ce5d9cf refactor(translations): update price labels for clarity and consistency across multiple languages 2025-11-15 21:01:26 +00:00