mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-30 21:33:39 +00:00
4 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0a4af0de2f |
feat(sensor): convert timing sensors to hour-based display with minute attributes
Convert best_price and peak_price timing sensors to display in hours (UI-friendly)
while retaining minute values in attributes (automation-friendly). This improves
readability in dashboards by using Home Assistant's automatic duration formatting
"1 h 35 min" instead of decimal "1.58 h".
BREAKING CHANGE: State unit changed from minutes to hours for 6 timing sensors.
Affected sensors:
* best_price_period_duration, best_price_remaining_minutes, best_price_next_in_minutes
* peak_price_period_duration, peak_price_remaining_minutes, peak_price_next_in_minutes
Migration guide for users:
- If your automations use {{ state_attr(..., 'remaining_time') }} or similar:
No action needed - attribute values remain in minutes
- If your automations use {{ states('sensor.best_price_remaining_minutes') }} directly:
Update to use the minute attribute instead: {{ state_attr('sensor.best_price_remaining_minutes', 'remaining_minutes') }}
- If your dashboards display the state value:
Values now show as "1 h 35 min" instead of "95" - this is the intended improvement
- If your templates do math with the state: multiply by 60 to convert hours back to minutes
Before: remaining * 60
After: remaining_minutes (use attribute directly)
Implementation details:
- Timing sensors now use device_class=DURATION, unit=HOURS, precision=2
- State values converted from minutes to hours via _minutes_to_hours()
- New minute-precision attributes added for automation compatibility:
* period_duration_minutes (for checking if period is long enough)
* remaining_minutes (for countdown-based automation logic)
* next_in_minutes (for time-to-event automation triggers)
- Translation improvements across all 5 languages (en, de, nb, nl, sv):
* Descriptions now clarify state in hours vs attributes in minutes
* Long descriptions explain dual-format architecture
* Usage tips updated to reference minute attributes for automations
* All translation files synchronized (fixed order, removed duplicates)
- Type safety: Added type assertions (cast) for timing calculator results to
satisfy Pyright type checking (handles both float and datetime return types)
Home Assistant now automatically formats these durations as "1 h 35 min" for improved
UX, matching the behavior of battery.remaining_time and other duration sensors.
Rationale for breaking change:
The previous minute-based state was unintuitive for users ("95 minutes" doesn't
immediately convey "1.5 hours") and didn't match Home Assistant's standard duration
formatting. The new hour-based state with minute attributes provides:
- Better UX: Automatic "1 h 35 min" formatting in UI
- Full automation compatibility: Minute attributes for all calculation needs
- Consistency: Matches HA's duration sensor pattern (battery, timer, etc.)
Impact: Timing sensors now display in human-readable hours with full backward
compatibility via minute attributes. Users relying on direct state access must
migrate to minute attributes (simple change, documented above).
|
||
|
|
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. |
||
|
|
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. |