mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-05-28 18:43:40 +00:00
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.
1059 lines
45 KiB
Python
1059 lines
45 KiB
Python
"""
|
|
Sensor entity definitions for Tibber Prices.
|
|
|
|
This module contains all SensorEntityDescription definitions organized by
|
|
calculation method. Sensor definitions are declarative and independent of
|
|
the implementation logic.
|
|
|
|
Organization by calculation pattern:
|
|
1. Interval-based: Time offset from current interval
|
|
2. Rolling hour: 5-interval aggregation windows
|
|
3. Daily statistics: Calendar day min/max/avg
|
|
4. 24h windows: Trailing/leading statistics
|
|
5. Future forecast: N-hour windows from next interval
|
|
6. Volatility: Price variation analysis
|
|
7. Best/Peak Price timing: Period-based time tracking
|
|
8. Diagnostic: System metadata
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from homeassistant.components.sensor import (
|
|
SensorDeviceClass,
|
|
SensorEntityDescription,
|
|
SensorStateClass,
|
|
)
|
|
from homeassistant.const import (
|
|
PERCENTAGE,
|
|
EntityCategory,
|
|
UnitOfArea,
|
|
UnitOfElectricCurrent,
|
|
UnitOfEnergy,
|
|
UnitOfTime,
|
|
)
|
|
|
|
# ============================================================================
|
|
# SENSOR DEFINITIONS - Grouped by calculation method
|
|
# ============================================================================
|
|
#
|
|
# Sensors are organized by HOW they calculate values, not WHAT they display.
|
|
# This groups sensors that share common logic and enables code reuse through
|
|
# unified handler methods.
|
|
#
|
|
# Calculation patterns:
|
|
# 1. Interval-based: Use time offset from current interval
|
|
# 2. Rolling hour: Aggregate 5-interval window (2 before + center + 2 after)
|
|
# 3. Daily statistics: Min/max/avg within calendar day boundaries
|
|
# 4. 24h windows: Trailing/leading from current interval
|
|
# 5. Future forecast: N-hour windows starting from next interval
|
|
# 6. Volatility: Statistical analysis of price variation
|
|
# 7. Best/Peak Price timing: Period-based time tracking (requires minute updates)
|
|
# 8. Diagnostic: System information and metadata
|
|
# ============================================================================
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 1. INTERVAL-BASED SENSORS (offset: -1, 0, +1 from current interval)
|
|
# ----------------------------------------------------------------------------
|
|
# All use find_price_data_for_interval() with time offset
|
|
# Shared handler: _get_interval_value(interval_offset, value_type)
|
|
|
|
INTERVAL_PRICE_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="current_interval_price",
|
|
translation_key="current_interval_price",
|
|
icon="mdi:cash", # Dynamic: shows cash-multiple/plus/cash/minus/remove based on price level
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="current_interval_price_base",
|
|
translation_key="current_interval_price_base",
|
|
icon="mdi:cash", # Dynamic: shows cash-multiple/plus/cash/minus/remove based on price level
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None for Energy Dashboard
|
|
suggested_display_precision=4, # More precision for base currency (e.g., 0.2534 EUR/kWh)
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_interval_price",
|
|
translation_key="next_interval_price",
|
|
icon="mdi:cash", # Dynamic: shows cash-multiple/plus/cash/minus/remove based on price level
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future value: historical chart not useful
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="previous_interval_price",
|
|
translation_key="previous_interval_price",
|
|
icon="mdi:cash-refund", # Static: arrow back indicates "past"
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Past snapshot: historical chart not useful
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=2,
|
|
),
|
|
)
|
|
|
|
# NOTE: Enum options are defined inline (not imported from const.py) to avoid
|
|
# import timing issues with Home Assistant's entity platform initialization.
|
|
# Keep in sync with PRICE_LEVEL_OPTIONS in const.py!
|
|
INTERVAL_LEVEL_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="current_interval_price_level",
|
|
translation_key="current_interval_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on level value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_interval_price_level",
|
|
translation_key="next_interval_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on level value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
),
|
|
SensorEntityDescription(
|
|
key="previous_interval_price_level",
|
|
translation_key="previous_interval_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on level value
|
|
entity_registry_enabled_default=False,
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
),
|
|
)
|
|
|
|
# NOTE: Enum options are defined inline (not imported from const.py) to avoid
|
|
# import timing issues with Home Assistant's entity platform initialization.
|
|
# Keep in sync with PRICE_RATING_OPTIONS in const.py!
|
|
INTERVAL_RATING_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="current_interval_price_rating",
|
|
translation_key="current_interval_price_rating",
|
|
icon="mdi:thumbs-up-down", # Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on rating value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
entity_registry_enabled_default=False, # Level is more commonly used
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_interval_price_rating",
|
|
translation_key="next_interval_price_rating",
|
|
icon="mdi:thumbs-up-down", # Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on rating value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
entity_registry_enabled_default=False, # Level is more commonly used
|
|
),
|
|
SensorEntityDescription(
|
|
key="previous_interval_price_rating",
|
|
translation_key="previous_interval_price_rating",
|
|
icon="mdi:thumbs-up-down", # Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on rating value
|
|
entity_registry_enabled_default=False,
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 2. ROLLING HOUR SENSORS (5-interval window: 2 before + center + 2 after)
|
|
# ----------------------------------------------------------------------------
|
|
# All aggregate data from rolling 5-interval window around a specific hour
|
|
# Shared handler: _get_rolling_hour_value(hour_offset, value_type)
|
|
|
|
ROLLING_HOUR_PRICE_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="current_hour_average_price",
|
|
translation_key="current_hour_average_price",
|
|
icon="mdi:cash", # Dynamic: shows cash-multiple/plus/cash/minus/remove based on aggregated price level
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Rolling derived value: historical chart not useful
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_hour_average_price",
|
|
translation_key="next_hour_average_price",
|
|
icon="mdi:cash-fast", # Dynamic: shows cash-multiple/plus/cash/minus/remove based on aggregated price level
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future derived value: historical chart not useful
|
|
suggested_display_precision=2,
|
|
),
|
|
)
|
|
|
|
# NOTE: Enum options are defined inline (not imported from const.py) to avoid
|
|
# import timing issues with Home Assistant's entity platform initialization.
|
|
# Keep in sync with PRICE_LEVEL_OPTIONS in const.py!
|
|
ROLLING_HOUR_LEVEL_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="current_hour_price_level",
|
|
translation_key="current_hour_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on aggregated level value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_hour_price_level",
|
|
translation_key="next_hour_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on aggregated level value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
),
|
|
)
|
|
|
|
# NOTE: Enum options are defined inline (not imported from const.py) to avoid
|
|
# import timing issues with Home Assistant's entity platform initialization.
|
|
# Keep in sync with PRICE_RATING_OPTIONS in const.py!
|
|
ROLLING_HOUR_RATING_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="current_hour_price_rating",
|
|
translation_key="current_hour_price_rating",
|
|
# Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on aggregated rating value
|
|
icon="mdi:thumbs-up-down",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
entity_registry_enabled_default=False, # Level is more commonly used
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_hour_price_rating",
|
|
translation_key="next_hour_price_rating",
|
|
# Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on aggregated rating value
|
|
icon="mdi:thumbs-up-down",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
entity_registry_enabled_default=False, # Level is more commonly used
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 3. DAILY STATISTICS SENSORS (min/max/avg for calendar day boundaries)
|
|
# ----------------------------------------------------------------------------
|
|
# Calculate statistics for specific calendar days (today/tomorrow)
|
|
|
|
DAILY_STAT_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="lowest_price_today",
|
|
translation_key="lowest_price_today",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Daily snapshot: stays constant most of the day
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="highest_price_today",
|
|
translation_key="highest_price_today",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Daily snapshot: stays constant most of the day
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="average_price_today",
|
|
translation_key="average_price_today",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # Keep TOTAL: useful to track daily avg over weeks/months
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="lowest_price_tomorrow",
|
|
translation_key="lowest_price_tomorrow",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future data: historical chart not useful
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="highest_price_tomorrow",
|
|
translation_key="highest_price_tomorrow",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future data: historical chart not useful
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="average_price_tomorrow",
|
|
translation_key="average_price_tomorrow",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future data: historical chart not useful
|
|
suggested_display_precision=2,
|
|
),
|
|
)
|
|
|
|
# NOTE: Enum options are defined inline (not imported from const.py) to avoid
|
|
# import timing issues with Home Assistant's entity platform initialization.
|
|
# Keep in sync with PRICE_LEVEL_OPTIONS in const.py!
|
|
DAILY_LEVEL_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="yesterday_price_level",
|
|
translation_key="yesterday_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on daily level value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="today_price_level",
|
|
translation_key="today_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on daily level value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
),
|
|
SensorEntityDescription(
|
|
key="tomorrow_price_level",
|
|
translation_key="tomorrow_price_level",
|
|
icon="mdi:gauge", # Dynamic: shows gauge/gauge-empty/gauge-low/gauge-full based on daily level value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["very_cheap", "cheap", "normal", "expensive", "very_expensive"],
|
|
),
|
|
)
|
|
|
|
# NOTE: Enum options are defined inline (not imported from const.py) to avoid
|
|
# import timing issues with Home Assistant's entity platform initialization.
|
|
# Keep in sync with PRICE_RATING_OPTIONS in const.py!
|
|
DAILY_RATING_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="yesterday_price_rating",
|
|
translation_key="yesterday_price_rating",
|
|
# Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on daily rating value
|
|
icon="mdi:thumbs-up-down",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="today_price_rating",
|
|
translation_key="today_price_rating",
|
|
# Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on daily rating value
|
|
icon="mdi:thumbs-up-down",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
entity_registry_enabled_default=False, # Level is more commonly used
|
|
),
|
|
SensorEntityDescription(
|
|
key="tomorrow_price_rating",
|
|
translation_key="tomorrow_price_rating",
|
|
# Dynamic: shows thumbs-up/thumbs-up-down/thumbs-down based on daily rating value
|
|
icon="mdi:thumbs-up-down",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "normal", "high"],
|
|
entity_registry_enabled_default=False, # Level is more commonly used
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 4. 24H WINDOW SENSORS (trailing/leading from current interval)
|
|
# ----------------------------------------------------------------------------
|
|
# Calculate statistics over sliding 24-hour windows
|
|
|
|
WINDOW_24H_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="trailing_price_average",
|
|
translation_key="trailing_price_average",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Rolling window: value shifts every 15min, history chart misleading
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="leading_price_average",
|
|
translation_key="leading_price_average",
|
|
icon="mdi:chart-line-variant",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Rolling window: value shifts every 15min, history chart misleading
|
|
entity_registry_enabled_default=False, # Advanced use case
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="trailing_price_min",
|
|
translation_key="trailing_price_min",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Rolling window: value shifts every 15min, history chart misleading
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="trailing_price_max",
|
|
translation_key="trailing_price_max",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Rolling window: value shifts every 15min, history chart misleading
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="leading_price_min",
|
|
translation_key="leading_price_min",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Rolling window: value shifts every 15min, history chart misleading
|
|
entity_registry_enabled_default=False, # Advanced use case
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="leading_price_max",
|
|
translation_key="leading_price_max",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Rolling window: value shifts every 15min, history chart misleading
|
|
entity_registry_enabled_default=False, # Advanced use case
|
|
suggested_display_precision=2,
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 5. FUTURE FORECAST SENSORS (N-hour windows starting from next interval)
|
|
# ----------------------------------------------------------------------------
|
|
# Calculate averages and trends for upcoming time windows
|
|
|
|
FUTURE_MEAN_SENSORS = (
|
|
# Default enabled: 1h-5h
|
|
SensorEntityDescription(
|
|
key="next_avg_1h",
|
|
translation_key="next_avg_1h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_2h",
|
|
translation_key="next_avg_2h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_3h",
|
|
translation_key="next_avg_3h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_4h",
|
|
translation_key="next_avg_4h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_5h",
|
|
translation_key="next_avg_5h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
# Disabled by default: 6h, 8h, 12h (advanced use cases)
|
|
SensorEntityDescription(
|
|
key="next_avg_6h",
|
|
translation_key="next_avg_6h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_8h",
|
|
translation_key="next_avg_8h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_12h",
|
|
translation_key="next_avg_12h",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=None, # Future forecast: historical chart not useful
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
)
|
|
|
|
FUTURE_TREND_SENSORS = (
|
|
# Current trend sensor (what is the trend right now, valid until next change?)
|
|
SensorEntityDescription(
|
|
key="current_price_trend",
|
|
translation_key="current_price_trend",
|
|
icon="mdi:trending-up", # Dynamic: trending-up/trending-down/trending-neutral based on current trend
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
# Next trend change sensor (when will trend change?)
|
|
SensorEntityDescription(
|
|
key="next_price_trend_change",
|
|
translation_key="next_price_trend_change",
|
|
icon="mdi:clock-alert", # Dynamic: trending-up/trending-down/trending-neutral based on direction
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
state_class=None, # Timestamp: no statistics
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
# Trend change countdown sensor (how long until trend changes?)
|
|
SensorEntityDescription(
|
|
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.MINUTES,
|
|
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
|
state_class=None, # Countdown timer: no statistics
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
# Price outlook forecast sensors (is the average of the next Xh cheaper/more expensive than now?)
|
|
# Default enabled: 1h-5h
|
|
SensorEntityDescription(
|
|
key="price_outlook_1h",
|
|
translation_key="price_outlook_1h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_outlook_2h",
|
|
translation_key="price_outlook_2h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_outlook_3h",
|
|
translation_key="price_outlook_3h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_outlook_4h",
|
|
translation_key="price_outlook_4h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_outlook_5h",
|
|
translation_key="price_outlook_5h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
# Disabled by default: 6h, 8h, 12h
|
|
SensorEntityDescription(
|
|
key="price_outlook_6h",
|
|
translation_key="price_outlook_6h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_outlook_8h",
|
|
translation_key="price_outlook_8h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_outlook_12h",
|
|
translation_key="price_outlook_12h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 5b. PRICE TRAJECTORY SENSORS (first-half vs second-half window comparison)
|
|
# ----------------------------------------------------------------------------
|
|
# These sensors reveal turning points: is the price rising or falling WITHIN
|
|
# the window? Complements price_outlook_Xh sensors.
|
|
#
|
|
# Example at a price minimum (12:00):
|
|
# - price_outlook_4h: "strongly_falling" (Ø next 4h is below current high)
|
|
# - price_trajectory_4h: "rising" (second half avg > first half avg)
|
|
# → Combined: act now, reversal is coming within the window.
|
|
#
|
|
# Coverage starts at 2h (minimum for meaningful first/second half split).
|
|
# Default enabled: 2h-5h
|
|
|
|
PRICE_TRAJECTORY_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="price_trajectory_2h",
|
|
translation_key="price_trajectory_2h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_trajectory_3h",
|
|
translation_key="price_trajectory_3h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_trajectory_4h",
|
|
translation_key="price_trajectory_4h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_trajectory_5h",
|
|
translation_key="price_trajectory_5h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
# Disabled by default: 6h, 8h, 12h
|
|
SensorEntityDescription(
|
|
key="price_trajectory_6h",
|
|
translation_key="price_trajectory_6h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_trajectory_8h",
|
|
translation_key="price_trajectory_8h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_trajectory_12h",
|
|
translation_key="price_trajectory_12h",
|
|
icon="mdi:trending-up", # Dynamic: shows trending-up/trending-down/trending-neutral based on trend value
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["strongly_falling", "falling", "stable", "rising", "strongly_rising"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 6. VOLATILITY SENSORS (coefficient of variation analysis)
|
|
# ----------------------------------------------------------------------------
|
|
# NOTE: Enum options are defined inline (not imported from const.py) to avoid
|
|
# import timing issues with Home Assistant's entity platform initialization.
|
|
# Keep in sync with VOLATILITY_OPTIONS in const.py!
|
|
|
|
VOLATILITY_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="today_volatility",
|
|
translation_key="today_volatility",
|
|
# Dynamic: shows chart-bell-curve/chart-gantt/finance based on volatility level
|
|
icon="mdi:chart-bell-curve-cumulative",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "moderate", "high", "very_high"],
|
|
),
|
|
SensorEntityDescription(
|
|
key="tomorrow_volatility",
|
|
translation_key="tomorrow_volatility",
|
|
# Dynamic: shows chart-bell-curve/chart-gantt/finance based on volatility level
|
|
icon="mdi:chart-bell-curve-cumulative",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "moderate", "high", "very_high"],
|
|
entity_registry_enabled_default=False, # Today's volatility is usually sufficient
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_24h_volatility",
|
|
translation_key="next_24h_volatility",
|
|
# Dynamic: shows chart-bell-curve/chart-gantt/finance based on volatility level
|
|
icon="mdi:chart-bell-curve-cumulative",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "moderate", "high", "very_high"],
|
|
entity_registry_enabled_default=False, # Advanced use case
|
|
),
|
|
SensorEntityDescription(
|
|
key="today_tomorrow_volatility",
|
|
translation_key="today_tomorrow_volatility",
|
|
# Dynamic: shows chart-bell-curve/chart-gantt/finance based on volatility level
|
|
icon="mdi:chart-bell-curve-cumulative",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
state_class=None, # Enum values: no statistics
|
|
options=["low", "moderate", "high", "very_high"],
|
|
entity_registry_enabled_default=False, # Advanced use case
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# 7. BEST/PEAK PRICE TIMING SENSORS (period-based time tracking)
|
|
# ----------------------------------------------------------------------------
|
|
# These sensors track time relative to best_price/peak_price binary sensor periods.
|
|
# They require minute-by-minute updates via async_track_time_interval.
|
|
#
|
|
# When period is active (binary_sensor ON):
|
|
# - end_time: Timestamp when current period ends
|
|
# - remaining_minutes: Minutes until period ends
|
|
# - progress: Percentage of period completed (0-100%)
|
|
#
|
|
# When period is inactive (binary_sensor OFF):
|
|
# - next_start_time: Timestamp when next period starts
|
|
# - next_in_minutes: Minutes until next period starts
|
|
#
|
|
# All return None/Unknown when no period is active/scheduled.
|
|
|
|
BEST_PRICE_TIMING_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="best_price_end_time",
|
|
translation_key="best_price_end_time",
|
|
icon="mdi:clock-end",
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
state_class=None, # Timestamps: no statistics
|
|
),
|
|
SensorEntityDescription(
|
|
key="best_price_period_duration",
|
|
translation_key="best_price_period_duration",
|
|
icon="mdi:timer",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
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,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="best_price_remaining_minutes",
|
|
translation_key="best_price_remaining_minutes",
|
|
icon="mdi:timer-sand",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_unit_of_measurement=UnitOfTime.MINUTES,
|
|
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
|
state_class=None, # Countdown timers excluded from statistics
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="best_price_progress",
|
|
translation_key="best_price_progress",
|
|
icon="mdi:percent", # Dynamic: mdi:percent-0 to mdi:percent-100
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
state_class=None, # Progress counter: no statistics
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="best_price_next_start_time",
|
|
translation_key="best_price_next_start_time",
|
|
icon="mdi:clock-start",
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
state_class=None, # Timestamps: no statistics
|
|
),
|
|
SensorEntityDescription(
|
|
key="best_price_next_in_minutes",
|
|
translation_key="best_price_next_in_minutes",
|
|
icon="mdi:timer-outline",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
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,
|
|
),
|
|
)
|
|
|
|
PEAK_PRICE_TIMING_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="peak_price_end_time",
|
|
translation_key="peak_price_end_time",
|
|
icon="mdi:clock-end",
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
state_class=None, # Timestamps: no statistics
|
|
),
|
|
SensorEntityDescription(
|
|
key="peak_price_period_duration",
|
|
translation_key="peak_price_period_duration",
|
|
icon="mdi:timer",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
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,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="peak_price_remaining_minutes",
|
|
translation_key="peak_price_remaining_minutes",
|
|
icon="mdi:timer-sand",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_unit_of_measurement=UnitOfTime.MINUTES,
|
|
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
|
state_class=None, # Countdown timers excluded from statistics
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="peak_price_progress",
|
|
translation_key="peak_price_progress",
|
|
icon="mdi:percent", # Dynamic: mdi:percent-0 to mdi:percent-100
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
state_class=None, # Progress counter: no statistics
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="peak_price_next_start_time",
|
|
translation_key="peak_price_next_start_time",
|
|
icon="mdi:clock-start",
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
state_class=None, # Timestamps: no statistics
|
|
),
|
|
SensorEntityDescription(
|
|
key="peak_price_next_in_minutes",
|
|
translation_key="peak_price_next_in_minutes",
|
|
icon="mdi:timer-outline",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
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,
|
|
),
|
|
)
|
|
|
|
# 8. DIAGNOSTIC SENSORS (data availability and metadata)
|
|
# ----------------------------------------------------------------------------
|
|
|
|
DIAGNOSTIC_SENSORS = (
|
|
SensorEntityDescription(
|
|
key="data_lifecycle_status",
|
|
translation_key="data_lifecycle_status",
|
|
icon="mdi:database-sync",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=["cached", "fresh", "refreshing", "searching_tomorrow", "turnover_pending", "error"],
|
|
state_class=None, # Status value: no statistics
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=True, # Critical for debugging
|
|
),
|
|
# Home metadata from user data
|
|
SensorEntityDescription(
|
|
key="home_type",
|
|
translation_key="home_type",
|
|
icon="mdi:home-variant",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=["apartment", "rowhouse", "house", "cottage"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="home_size",
|
|
translation_key="home_size",
|
|
icon="mdi:ruler-square",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
native_unit_of_measurement=UnitOfArea.SQUARE_METERS,
|
|
state_class=None, # Static user metadata: no statistics useful
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="main_fuse_size",
|
|
translation_key="main_fuse_size",
|
|
icon="mdi:fuse",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
|
device_class=SensorDeviceClass.CURRENT,
|
|
state_class=None, # Static user metadata: no statistics useful
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="number_of_residents",
|
|
translation_key="number_of_residents",
|
|
icon="mdi:account-group",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
state_class=None, # Static user metadata: no statistics useful
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="primary_heating_source",
|
|
translation_key="primary_heating_source",
|
|
icon="mdi:heating-coil",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=[
|
|
"air2air_heatpump",
|
|
"air2water_heatpump",
|
|
"boiler",
|
|
"central_heating",
|
|
"district_heating",
|
|
"district_heating",
|
|
"district",
|
|
"electric_boiler",
|
|
"electricity",
|
|
"floor",
|
|
"gas",
|
|
"ground_heatpump",
|
|
"ground",
|
|
"oil",
|
|
"other",
|
|
"waste",
|
|
],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
# Metering point data
|
|
SensorEntityDescription(
|
|
key="grid_company",
|
|
translation_key="grid_company",
|
|
icon="mdi:transmission-tower",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
),
|
|
SensorEntityDescription(
|
|
key="grid_area_code",
|
|
translation_key="grid_area_code",
|
|
icon="mdi:map-marker",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="price_area_code",
|
|
translation_key="price_area_code",
|
|
icon="mdi:currency-eur",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="consumption_ean",
|
|
translation_key="consumption_ean",
|
|
icon="mdi:barcode",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="production_ean",
|
|
translation_key="production_ean",
|
|
icon="mdi:solar-power",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="energy_tax_type",
|
|
translation_key="energy_tax_type",
|
|
icon="mdi:cash",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="vat_type",
|
|
translation_key="vat_type",
|
|
icon="mdi:percent",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="estimated_annual_consumption",
|
|
translation_key="estimated_annual_consumption",
|
|
icon="mdi:lightning-bolt",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
|
|
device_class=SensorDeviceClass.ENERGY,
|
|
state_class=None, # Static Tibber estimate, not an actual accumulating counter
|
|
suggested_display_precision=0,
|
|
),
|
|
# Subscription data
|
|
SensorEntityDescription(
|
|
key="subscription_status",
|
|
translation_key="subscription_status",
|
|
icon="mdi:file-document-check",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=["running", "ended", "pending", "unknown"],
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="chart_data_export",
|
|
translation_key="chart_data_export",
|
|
icon="mdi:database-export",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=["pending", "ready", "error"],
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False, # Opt-in
|
|
),
|
|
SensorEntityDescription(
|
|
key="chart_metadata",
|
|
translation_key="chart_metadata",
|
|
icon="mdi:chart-box-outline",
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=["pending", "ready", "error"],
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=True, # Critical for chart features
|
|
),
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# COMBINED SENSOR DEFINITIONS
|
|
# ----------------------------------------------------------------------------
|
|
|
|
ENTITY_DESCRIPTIONS = (
|
|
*INTERVAL_PRICE_SENSORS,
|
|
*INTERVAL_LEVEL_SENSORS,
|
|
*INTERVAL_RATING_SENSORS,
|
|
*ROLLING_HOUR_PRICE_SENSORS,
|
|
*ROLLING_HOUR_LEVEL_SENSORS,
|
|
*ROLLING_HOUR_RATING_SENSORS,
|
|
*DAILY_STAT_SENSORS,
|
|
*DAILY_LEVEL_SENSORS,
|
|
*DAILY_RATING_SENSORS,
|
|
*WINDOW_24H_SENSORS,
|
|
*FUTURE_MEAN_SENSORS,
|
|
*FUTURE_TREND_SENSORS,
|
|
*PRICE_TRAJECTORY_SENSORS,
|
|
*VOLATILITY_SENSORS,
|
|
*BEST_PRICE_TIMING_SENSORS,
|
|
*PEAK_PRICE_TIMING_SENSORS,
|
|
*DIAGNOSTIC_SENSORS,
|
|
)
|