mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-05-28 18:43:40 +00:00
feat(sensors)!: use native minutes for all duration sensors
Changed native_unit_of_measurement from HOURS to MINUTES for all 7 duration sensors. HA auto-converts to hours for display via suggested_unit_of_measurement=HOURS. Sensors affected: - next_price_trend_change_in - 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 Removed _minutes_to_hours() conversion function — calculator values (minutes) are now passed through directly. BREAKING CHANGE: State values for all duration sensors change from hours to minutes (e.g. 1.5 → 90). The display unit remains hours (suggested_unit_of_measurement). Automations using numeric state comparisons must be updated (multiply old thresholds by 60). Impact: Users with automations comparing duration sensor states numerically need to update thresholds. Dashboard display is unchanged for new installations. Existing installations retain their configured display unit but the underlying numeric value changes.
This commit is contained in:
parent
b1b41be9aa
commit
faa3b2b71a
2 changed files with 28 additions and 48 deletions
|
|
@ -519,11 +519,11 @@ FUTURE_TREND_SENSORS = (
|
|||
),
|
||||
# Trend change countdown sensor (how long until trend changes?)
|
||||
SensorEntityDescription(
|
||||
key="trend_change_in_minutes",
|
||||
translation_key="trend_change_in_minutes",
|
||||
key="next_price_trend_change_in",
|
||||
translation_key="next_price_trend_change_in",
|
||||
icon="mdi:timer-outline",
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
native_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
state_class=None, # Countdown timer: no statistics
|
||||
suggested_display_precision=2,
|
||||
|
|
@ -766,7 +766,7 @@ BEST_PRICE_TIMING_SENSORS = (
|
|||
translation_key="best_price_period_duration",
|
||||
icon="mdi:timer",
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
native_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
state_class=None, # Duration not needed in long-term statistics
|
||||
suggested_display_precision=2,
|
||||
|
|
@ -777,7 +777,7 @@ BEST_PRICE_TIMING_SENSORS = (
|
|||
translation_key="best_price_remaining_minutes",
|
||||
icon="mdi:timer-sand",
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
native_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
state_class=None, # Countdown timers excluded from statistics
|
||||
suggested_display_precision=2,
|
||||
|
|
@ -802,7 +802,7 @@ BEST_PRICE_TIMING_SENSORS = (
|
|||
translation_key="best_price_next_in_minutes",
|
||||
icon="mdi:timer-outline",
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
native_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
state_class=None, # Next-start timers excluded from statistics
|
||||
suggested_display_precision=2,
|
||||
|
|
@ -822,7 +822,7 @@ PEAK_PRICE_TIMING_SENSORS = (
|
|||
translation_key="peak_price_period_duration",
|
||||
icon="mdi:timer",
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
native_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
state_class=None, # Duration not needed in long-term statistics
|
||||
suggested_display_precision=2,
|
||||
|
|
@ -833,7 +833,7 @@ PEAK_PRICE_TIMING_SENSORS = (
|
|||
translation_key="peak_price_remaining_minutes",
|
||||
icon="mdi:timer-sand",
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
native_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
state_class=None, # Countdown timers excluded from statistics
|
||||
suggested_display_precision=2,
|
||||
|
|
@ -858,7 +858,7 @@ PEAK_PRICE_TIMING_SENSORS = (
|
|||
translation_key="peak_price_next_in_minutes",
|
||||
icon="mdi:timer-outline",
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
native_unit_of_measurement=UnitOfTime.MINUTES,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
state_class=None, # Next-start timers excluded from statistics
|
||||
suggested_display_precision=2,
|
||||
|
|
|
|||
|
|
@ -70,14 +70,6 @@ def get_value_getter_mapping( # noqa: PLR0913 - needs all calculators as parame
|
|||
Dictionary mapping entity keys to their value getter callables.
|
||||
|
||||
"""
|
||||
|
||||
def _minutes_to_hours(value: float | None) -> float | None:
|
||||
"""Convert minutes to hours for duration-oriented sensors."""
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
return value / 60
|
||||
|
||||
return {
|
||||
# ================================================================
|
||||
# INTERVAL-BASED SENSORS - via IntervalCalculator
|
||||
|
|
@ -205,7 +197,7 @@ def get_value_getter_mapping( # noqa: PLR0913 - needs all calculators as parame
|
|||
# Current and next trend change sensors
|
||||
"current_price_trend": trend_calculator.get_current_trend_value,
|
||||
"next_price_trend_change": trend_calculator.get_next_trend_change_value,
|
||||
"trend_change_in_minutes": lambda: _minutes_to_hours(trend_calculator.get_trend_change_in_minutes_value()),
|
||||
"next_price_trend_change_in": trend_calculator.get_trend_change_in_minutes_value,
|
||||
# Price outlook sensors (current price vs average of next Xh)
|
||||
"price_outlook_1h": lambda: trend_calculator.get_price_outlook_value(hours=1),
|
||||
"price_outlook_2h": lambda: trend_calculator.get_price_outlook_value(hours=2),
|
||||
|
|
@ -260,17 +252,13 @@ def get_value_getter_mapping( # noqa: PLR0913 - needs all calculators as parame
|
|||
"best_price_end_time": lambda: timing_calculator.get_period_timing_value(
|
||||
period_type="best_price", value_type="end_time"
|
||||
),
|
||||
"best_price_period_duration": lambda: _minutes_to_hours(
|
||||
cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="best_price", value_type="period_duration"),
|
||||
)
|
||||
"best_price_period_duration": lambda: cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="best_price", value_type="period_duration"),
|
||||
),
|
||||
"best_price_remaining_minutes": lambda: _minutes_to_hours(
|
||||
cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="best_price", value_type="remaining_minutes"),
|
||||
)
|
||||
"best_price_remaining_minutes": lambda: cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="best_price", value_type="remaining_minutes"),
|
||||
),
|
||||
"best_price_progress": lambda: timing_calculator.get_period_timing_value(
|
||||
period_type="best_price", value_type="progress"
|
||||
|
|
@ -278,27 +266,21 @@ def get_value_getter_mapping( # noqa: PLR0913 - needs all calculators as parame
|
|||
"best_price_next_start_time": lambda: timing_calculator.get_period_timing_value(
|
||||
period_type="best_price", value_type="next_start_time"
|
||||
),
|
||||
"best_price_next_in_minutes": lambda: _minutes_to_hours(
|
||||
cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="best_price", value_type="next_in_minutes"),
|
||||
)
|
||||
"best_price_next_in_minutes": lambda: cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="best_price", value_type="next_in_minutes"),
|
||||
),
|
||||
# Peak Price timing sensors
|
||||
"peak_price_end_time": lambda: timing_calculator.get_period_timing_value(
|
||||
period_type="peak_price", value_type="end_time"
|
||||
),
|
||||
"peak_price_period_duration": lambda: _minutes_to_hours(
|
||||
cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="peak_price", value_type="period_duration"),
|
||||
)
|
||||
"peak_price_period_duration": lambda: cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="peak_price", value_type="period_duration"),
|
||||
),
|
||||
"peak_price_remaining_minutes": lambda: _minutes_to_hours(
|
||||
cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="peak_price", value_type="remaining_minutes"),
|
||||
)
|
||||
"peak_price_remaining_minutes": lambda: cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="peak_price", value_type="remaining_minutes"),
|
||||
),
|
||||
"peak_price_progress": lambda: timing_calculator.get_period_timing_value(
|
||||
period_type="peak_price", value_type="progress"
|
||||
|
|
@ -306,11 +288,9 @@ def get_value_getter_mapping( # noqa: PLR0913 - needs all calculators as parame
|
|||
"peak_price_next_start_time": lambda: timing_calculator.get_period_timing_value(
|
||||
period_type="peak_price", value_type="next_start_time"
|
||||
),
|
||||
"peak_price_next_in_minutes": lambda: _minutes_to_hours(
|
||||
cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="peak_price", value_type="next_in_minutes"),
|
||||
)
|
||||
"peak_price_next_in_minutes": lambda: cast(
|
||||
"float | None",
|
||||
timing_calculator.get_period_timing_value(period_type="peak_price", value_type="next_in_minutes"),
|
||||
),
|
||||
# Chart data export sensor
|
||||
"chart_data_export": get_chart_data_export_value,
|
||||
|
|
|
|||
Loading…
Reference in a new issue