mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
Extends trend sensors from 3-level (rising/stable/falling) to 5-level scale (strongly_rising/rising/stable/falling/strongly_falling) for finer granularity. Changes: - Add PRICE_TREND_MAPPING with integer values (-2, -1, 0, +1, +2) matching PRICE_LEVEL_MAPPING pattern for consistent automation comparisons - Add configurable thresholds for strongly_rising (default: 6%) and strongly_falling (default: -6%) independent from base thresholds - Update calculate_price_trend() to return 3-tuple: (trend_state, diff_pct, trend_value) - Add trend_value attribute to all trend sensors for numeric comparisons - Update sensor entity descriptions with 5-level options - Add validation with cross-checks (strongly_rising > rising, etc.) - Update icons: chevron-double-up/down for strong trends, trending-up/down for normal Files changed: - const.py: PRICE_TREND_* constants, PRICE_TREND_MAPPING, config constants - utils/price.py: Extended calculate_price_trend() signature and return value - sensor/calculators/trend.py: Pass new thresholds, handle 3-tuple return - sensor/definitions.py: 5-level options for all 9 trend sensors - sensor/core.py: 5-level icon mapping - entity_utils/icons.py: 5-level trend icons - config_flow_handlers/: validators, schemas, options_flow for new settings - translations/*.json: Labels and error messages (en, de, nb, sv, nl) - tests/test_percentage_calculations.py: Updated for 3-tuple return Impact: Users get more nuanced trend information for automation decisions. New trend_value attribute enables numeric comparisons (e.g., > 0 for any rise). Existing automations using "rising"/"falling"/"stable" continue to work.
1044 lines
43 KiB
Python
1044 lines
43 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",
|
|
name="Current Electricity 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",
|
|
name="Current Electricity Price (Energy Dashboard)",
|
|
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",
|
|
name="Next 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="previous_interval_price",
|
|
translation_key="previous_interval_price",
|
|
name="Previous Electricity Price",
|
|
icon="mdi:cash-refund", # Static: arrow back indicates "past"
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
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",
|
|
name="Current 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",
|
|
name="Next 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",
|
|
name="Previous 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",
|
|
name="Current 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",
|
|
name="Next 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",
|
|
name="Previous 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",
|
|
name="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=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_hour_average_price",
|
|
translation_key="next_hour_average_price",
|
|
name="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=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
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",
|
|
name="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",
|
|
name="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",
|
|
name="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",
|
|
name="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",
|
|
name="Today's Lowest Price",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="highest_price_today",
|
|
translation_key="highest_price_today",
|
|
name="Today's Highest Price",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="average_price_today",
|
|
translation_key="average_price_today",
|
|
name="Today's Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="lowest_price_tomorrow",
|
|
translation_key="lowest_price_tomorrow",
|
|
name="Tomorrow's Lowest Price",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="highest_price_tomorrow",
|
|
translation_key="highest_price_tomorrow",
|
|
name="Tomorrow's Highest Price",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="average_price_tomorrow",
|
|
translation_key="average_price_tomorrow",
|
|
name="Tomorrow's Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
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",
|
|
name="Yesterday's 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",
|
|
name="Today's 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",
|
|
name="Tomorrow's 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",
|
|
name="Yesterday's 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",
|
|
name="Today's 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",
|
|
name="Tomorrow's 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",
|
|
name="Trailing 24h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="leading_price_average",
|
|
translation_key="leading_price_average",
|
|
name="Leading 24h Average Price",
|
|
icon="mdi:chart-line-variant",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
entity_registry_enabled_default=False, # Advanced use case
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="trailing_price_min",
|
|
translation_key="trailing_price_min",
|
|
name="Trailing 24h Minimum Price",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="trailing_price_max",
|
|
translation_key="trailing_price_max",
|
|
name="Trailing 24h Maximum Price",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="leading_price_min",
|
|
translation_key="leading_price_min",
|
|
name="Leading 24h Minimum Price",
|
|
icon="mdi:arrow-collapse-down",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
entity_registry_enabled_default=False, # Advanced use case
|
|
suggested_display_precision=2,
|
|
),
|
|
SensorEntityDescription(
|
|
key="leading_price_max",
|
|
translation_key="leading_price_max",
|
|
name="Leading 24h Maximum Price",
|
|
icon="mdi:arrow-collapse-up",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
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",
|
|
name="Next 1h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_2h",
|
|
translation_key="next_avg_2h",
|
|
name="Next 2h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_3h",
|
|
translation_key="next_avg_3h",
|
|
name="Next 3h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_4h",
|
|
translation_key="next_avg_4h",
|
|
name="Next 4h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=True,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_5h",
|
|
translation_key="next_avg_5h",
|
|
name="Next 5h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
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",
|
|
name="Next 6h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_8h",
|
|
translation_key="next_avg_8h",
|
|
name="Next 8h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
suggested_display_precision=2,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="next_avg_12h",
|
|
translation_key="next_avg_12h",
|
|
name="Next 12h Average Price",
|
|
icon="mdi:chart-line",
|
|
device_class=SensorDeviceClass.MONETARY,
|
|
state_class=SensorStateClass.TOTAL, # MONETARY requires TOTAL or None
|
|
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",
|
|
name="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",
|
|
name="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,
|
|
),
|
|
# Price trend forecast sensors (will prices be higher/lower in X hours?)
|
|
# Default enabled: 1h-5h
|
|
SensorEntityDescription(
|
|
key="price_trend_1h",
|
|
translation_key="price_trend_1h",
|
|
name="Price Trend (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_trend_2h",
|
|
translation_key="price_trend_2h",
|
|
name="Price Trend (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_trend_3h",
|
|
translation_key="price_trend_3h",
|
|
name="Price Trend (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_trend_4h",
|
|
translation_key="price_trend_4h",
|
|
name="Price Trend (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_trend_5h",
|
|
translation_key="price_trend_5h",
|
|
name="Price Trend (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_trend_6h",
|
|
translation_key="price_trend_6h",
|
|
name="Price Trend (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_trend_8h",
|
|
translation_key="price_trend_8h",
|
|
name="Price Trend (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_trend_12h",
|
|
translation_key="price_trend_12h",
|
|
name="Price Trend (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",
|
|
name="Today's Price 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",
|
|
name="Tomorrow's Price 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",
|
|
name="Next 24h Price 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",
|
|
name="Today + Tomorrow Price 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",
|
|
name="Best Price Period End",
|
|
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",
|
|
name="Best Price Period Duration",
|
|
icon="mdi:timer",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_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",
|
|
name="Best Price Remaining Time",
|
|
icon="mdi:timer-sand",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_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",
|
|
name="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",
|
|
name="Best Price Next Period Start",
|
|
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",
|
|
name="Best Price Starts In",
|
|
icon="mdi:timer-outline",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_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",
|
|
name="Peak Price Period End",
|
|
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",
|
|
name="Peak Price Period Duration",
|
|
icon="mdi:timer",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_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",
|
|
name="Peak Price Remaining Time",
|
|
icon="mdi:timer-sand",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_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",
|
|
name="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",
|
|
name="Peak Price Next Period Start",
|
|
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",
|
|
name="Peak Price Starts In",
|
|
icon="mdi:timer-outline",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_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",
|
|
name="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",
|
|
name="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",
|
|
name="Home Size",
|
|
icon="mdi:ruler-square",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
native_unit_of_measurement=UnitOfArea.SQUARE_METERS,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="main_fuse_size",
|
|
translation_key="main_fuse_size",
|
|
name="Main Fuse Size",
|
|
icon="mdi:fuse",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
|
device_class=SensorDeviceClass.CURRENT,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="number_of_residents",
|
|
translation_key="number_of_residents",
|
|
name="Number of Residents",
|
|
icon="mdi:account-group",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
entity_registry_enabled_default=False,
|
|
suggested_display_precision=0,
|
|
),
|
|
SensorEntityDescription(
|
|
key="primary_heating_source",
|
|
translation_key="primary_heating_source",
|
|
name="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",
|
|
name="Grid Company",
|
|
icon="mdi:transmission-tower",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
),
|
|
SensorEntityDescription(
|
|
key="grid_area_code",
|
|
translation_key="grid_area_code",
|
|
name="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",
|
|
name="Price Area Code",
|
|
icon="mdi:currency-eur",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="consumption_ean",
|
|
translation_key="consumption_ean",
|
|
name="Consumption EAN",
|
|
icon="mdi:barcode",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="production_ean",
|
|
translation_key="production_ean",
|
|
name="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",
|
|
name="Energy Tax Type",
|
|
icon="mdi:cash",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="vat_type",
|
|
translation_key="vat_type",
|
|
name="VAT Type",
|
|
icon="mdi:percent",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
SensorEntityDescription(
|
|
key="estimated_annual_consumption",
|
|
translation_key="estimated_annual_consumption",
|
|
name="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=SensorStateClass.TOTAL,
|
|
suggested_display_precision=0,
|
|
),
|
|
# Subscription data
|
|
SensorEntityDescription(
|
|
key="subscription_status",
|
|
translation_key="subscription_status",
|
|
name="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",
|
|
name="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",
|
|
name="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,
|
|
*VOLATILITY_SENSORS,
|
|
*BEST_PRICE_TIMING_SENSORS,
|
|
*PEAK_PRICE_TIMING_SENSORS,
|
|
*DIAGNOSTIC_SENSORS,
|
|
)
|