mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-30 13:23:41 +00:00
refactor: Adjust suggested display precision for future average price sensors and add timestamp attributes for next average calculations
This commit is contained in:
parent
ac100216ee
commit
32e429624e
1 changed files with 62 additions and 9 deletions
|
|
@ -318,7 +318,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 1h Average Price",
|
name="Next 1h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=True,
|
entity_registry_enabled_default=True,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
|
|
@ -327,7 +327,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 2h Average Price",
|
name="Next 2h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=True,
|
entity_registry_enabled_default=True,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
|
|
@ -336,7 +336,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 3h Average Price",
|
name="Next 3h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=True,
|
entity_registry_enabled_default=True,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
|
|
@ -345,7 +345,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 4h Average Price",
|
name="Next 4h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=True,
|
entity_registry_enabled_default=True,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
|
|
@ -354,7 +354,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 5h Average Price",
|
name="Next 5h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=True,
|
entity_registry_enabled_default=True,
|
||||||
),
|
),
|
||||||
# Disabled by default: 6h, 8h, 12h (advanced use cases)
|
# Disabled by default: 6h, 8h, 12h (advanced use cases)
|
||||||
|
|
@ -364,7 +364,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 6h Average Price",
|
name="Next 6h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
|
|
@ -373,7 +373,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 8h Average Price",
|
name="Next 8h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
|
|
@ -382,7 +382,7 @@ FUTURE_AVERAGE_SENSORS = (
|
||||||
name="Next 12h Average Price",
|
name="Next 12h Average Price",
|
||||||
icon="mdi:chart-line",
|
icon="mdi:chart-line",
|
||||||
device_class=SensorDeviceClass.MONETARY,
|
device_class=SensorDeviceClass.MONETARY,
|
||||||
suggested_display_precision=2,
|
suggested_display_precision=1,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -1433,6 +1433,10 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
||||||
attributes["data_available"] = False
|
attributes["data_available"] = False
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Add timestamp attribute (first future interval)
|
||||||
|
if future_prices:
|
||||||
|
attributes["timestamp"] = future_prices[0]["interval_start"]
|
||||||
|
|
||||||
attributes["intervals"] = future_prices
|
attributes["intervals"] = future_prices
|
||||||
attributes["data_available"] = True
|
attributes["data_available"] = True
|
||||||
|
|
||||||
|
|
@ -1660,6 +1664,8 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
||||||
"leading_price_max",
|
"leading_price_max",
|
||||||
]:
|
]:
|
||||||
self._add_average_price_attributes(attributes)
|
self._add_average_price_attributes(attributes)
|
||||||
|
elif key.startswith("next_avg_"):
|
||||||
|
self._add_next_avg_attributes(attributes)
|
||||||
elif any(pattern in key for pattern in ["_price_today", "_price_tomorrow", "rating", "data_timestamp"]):
|
elif any(pattern in key for pattern in ["_price_today", "_price_tomorrow", "rating", "data_timestamp"]):
|
||||||
self._add_statistics_attributes(attributes)
|
self._add_statistics_attributes(attributes)
|
||||||
elif key == "price_forecast":
|
elif key == "price_forecast":
|
||||||
|
|
@ -1772,7 +1778,12 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
||||||
price_info = self.coordinator.data.get("priceInfo", {})
|
price_info = self.coordinator.data.get("priceInfo", {})
|
||||||
now = dt_util.now()
|
now = dt_util.now()
|
||||||
|
|
||||||
if key == "price_rating":
|
if key == "data_timestamp":
|
||||||
|
# For data_timestamp sensor, use the latest timestamp (same as the sensor value)
|
||||||
|
latest_timestamp = self._get_data_timestamp()
|
||||||
|
if latest_timestamp:
|
||||||
|
attributes["timestamp"] = latest_timestamp.isoformat()
|
||||||
|
elif key == "price_rating":
|
||||||
interval_data = find_price_data_for_interval(price_info, now)
|
interval_data = find_price_data_for_interval(price_info, now)
|
||||||
attributes["timestamp"] = interval_data["startsAt"] if interval_data else None
|
attributes["timestamp"] = interval_data["startsAt"] if interval_data else None
|
||||||
if hasattr(self, "_last_rating_difference") and self._last_rating_difference is not None:
|
if hasattr(self, "_last_rating_difference") and self._last_rating_difference is not None:
|
||||||
|
|
@ -1843,6 +1854,48 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
||||||
attributes["timestamp"] = intervals_in_window[0].get("startsAt")
|
attributes["timestamp"] = intervals_in_window[0].get("startsAt")
|
||||||
attributes["interval_count"] = len(intervals_in_window)
|
attributes["interval_count"] = len(intervals_in_window)
|
||||||
|
|
||||||
|
def _add_next_avg_attributes(self, attributes: dict) -> None:
|
||||||
|
"""Add attributes for next N hours average price sensors."""
|
||||||
|
key = self.entity_description.key
|
||||||
|
now = dt_util.now()
|
||||||
|
|
||||||
|
# Extract hours from sensor key (e.g., "next_avg_3h" -> 3)
|
||||||
|
try:
|
||||||
|
hours = int(key.replace("next_avg_", "").replace("h", ""))
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get next interval start time (this is where the calculation begins)
|
||||||
|
next_interval_start = now + timedelta(minutes=MINUTES_PER_INTERVAL)
|
||||||
|
|
||||||
|
# Calculate the end of the time window
|
||||||
|
window_end = next_interval_start + timedelta(hours=hours)
|
||||||
|
|
||||||
|
# Get all price intervals
|
||||||
|
price_info = self.coordinator.data.get("priceInfo", {})
|
||||||
|
today_prices = price_info.get("today", [])
|
||||||
|
tomorrow_prices = price_info.get("tomorrow", [])
|
||||||
|
all_prices = today_prices + tomorrow_prices
|
||||||
|
|
||||||
|
if not all_prices:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Find all intervals in the window
|
||||||
|
intervals_in_window = []
|
||||||
|
for price_data in all_prices:
|
||||||
|
starts_at = dt_util.parse_datetime(price_data["startsAt"])
|
||||||
|
if starts_at is None:
|
||||||
|
continue
|
||||||
|
starts_at = dt_util.as_local(starts_at)
|
||||||
|
if next_interval_start <= starts_at < window_end:
|
||||||
|
intervals_in_window.append(price_data)
|
||||||
|
|
||||||
|
# Add timestamp attribute (start of next interval - where calculation begins)
|
||||||
|
if intervals_in_window:
|
||||||
|
attributes["timestamp"] = intervals_in_window[0].get("startsAt")
|
||||||
|
attributes["interval_count"] = len(intervals_in_window)
|
||||||
|
attributes["hours"] = hours
|
||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
"""Force a refresh when homeassistant.update_entity is called."""
|
"""Force a refresh when homeassistant.update_entity is called."""
|
||||||
await self.coordinator.async_request_refresh()
|
await self.coordinator.async_request_refresh()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue