mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
Complete terminology migration from confusing "major/minor" to clearer
"base/subunit" currency naming throughout entire codebase, translations,
documentation, tests, and services.
BREAKING CHANGES:
1. **Service API Parameters Renamed**:
- `get_chartdata`: `minor_currency` → `subunit_currency`
- `get_apexcharts_yaml`: Updated service_data references from
`minor_currency: true` to `subunit_currency: true`
- All automations/scripts using these parameters MUST be updated
2. **Configuration Option Key Changed**:
- Config entry option: Display mode setting now uses new terminology
- Internal key: `currency_display_mode` values remain "base"/"subunit"
- User-facing labels updated in all 5 languages (de, en, nb, nl, sv)
3. **Sensor Entity Key Renamed**:
- `current_interval_price_major` → `current_interval_price_base`
- Entity ID changes: `sensor.tibber_home_current_interval_price_major`
→ `sensor.tibber_home_current_interval_price_base`
- Energy Dashboard configurations MUST update entity references
4. **Function Signatures Changed**:
- `format_price_unit_major()` → `format_price_unit_base()`
- `format_price_unit_minor()` → `format_price_unit_subunit()`
- `get_price_value()`: Parameter `in_euro` deprecated in favor of
`config_entry` (backward compatible for now)
5. **Translation Keys Renamed**:
- All language files: Sensor translation key
`current_interval_price_major` → `current_interval_price_base`
- Service parameter descriptions updated in all languages
- Selector options updated: Display mode dropdown values
Changes by Category:
**Core Code (Python)**:
- const.py: Renamed all format_price_unit_*() functions, updated docstrings
- entity_utils/helpers.py: Updated get_price_value() with config-driven
conversion and backward-compatible in_euro parameter
- sensor/__init__.py: Added display mode filtering for base currency sensor
- sensor/core.py:
* Implemented suggested_display_precision property for dynamic decimal places
* Updated native_unit_of_measurement to use get_display_unit_string()
* Updated all price conversion calls to use config_entry parameter
- sensor/definitions.py: Renamed entity key and updated all
suggested_display_precision values (2 decimals for most sensors)
- sensor/calculators/*.py: Updated all price conversion calls (8 calculators)
- sensor/helpers.py: Updated aggregate_price_data() signature with config_entry
- sensor/attributes/future.py: Updated future price attributes conversion
**Services**:
- services/chartdata.py: Renamed parameter minor_currency → subunit_currency
throughout (53 occurrences), updated metadata calculation
- services/apexcharts.py: Updated service_data references in generated YAML
- services/formatters.py: Renamed parameter use_minor_currency →
use_subunit_currency in aggregate_hourly_exact() and get_period_data()
- sensor/chart_metadata.py: Updated default parameter name
**Translations (5 Languages)**:
- All /translations/*.json:
* Added new config step "display_settings" with comprehensive explanations
* Renamed current_interval_price_major → current_interval_price_base
* Updated service parameter descriptions (subunit_currency)
* Added selector.currency_display_mode.options with translated labels
- All /custom_translations/*.json:
* Renamed sensor description keys
* Updated chart_metadata usage_tips references
**Documentation**:
- docs/user/docs/actions.md: Updated parameter table and feature list
- docs/user/versioned_docs/version-v0.21.0/actions.md: Backported changes
**Tests**:
- Updated 7 test files with renamed parameters and conversion logic:
* test_connect_segments.py: Renamed minor/major to subunit/base
* test_period_data_format.py: Updated period price conversion tests
* test_avg_none_fallback.py: Fixed tuple unpacking for new return format
* test_best_price_e2e.py: Added config_entry parameter to all calls
* test_cache_validity.py: Fixed cache data structure (price_info key)
* test_coordinator_shutdown.py: Added repair_manager mock
* test_midnight_turnover.py: Added config_entry parameter
* test_peak_price_e2e.py: Added config_entry parameter, fixed price_avg → price_mean
* test_percentage_calculations.py: Added config_entry mock
**Coordinator/Period Calculation**:
- coordinator/periods.py: Added config_entry parameter to
calculate_periods_with_relaxation() calls (2 locations)
Migration Guide:
1. **Update Service Calls in Automations/Scripts**:
\`\`\`yaml
# Before:
service: tibber_prices.get_chartdata
data:
minor_currency: true
# After:
service: tibber_prices.get_chartdata
data:
subunit_currency: true
\`\`\`
2. **Update Energy Dashboard Configuration**:
- Settings → Dashboards → Energy
- Replace sensor entity:
`sensor.tibber_home_current_interval_price_major` →
`sensor.tibber_home_current_interval_price_base`
3. **Review Integration Configuration**:
- Settings → Devices & Services → Tibber Prices → Configure
- New "Currency Display Settings" step added
- Default mode depends on currency (EUR → subunit, Scandinavian → base)
Rationale:
The "major/minor" terminology was confusing and didn't clearly communicate:
- **Major** → Unclear if this means "primary" or "large value"
- **Minor** → Easily confused with "less important" rather than "smaller unit"
New terminology is precise and self-explanatory:
- **Base currency** → Standard ISO currency (€, kr, $, £)
- **Subunit currency** → Fractional unit (ct, øre, ¢, p)
This aligns with:
- International terminology (ISO 4217 standard)
- Banking/financial industry conventions
- User expectations from payment processing systems
Impact: Aligns currency terminology with international standards. Users must
update service calls, automations, and Energy Dashboard configuration after
upgrade.
Refs: User feedback session (December 2025) identified terminology confusion
1040 lines
42 KiB
Python
1040 lines
42 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_AVG_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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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=["rising", "falling", "stable"],
|
|
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.MINUTES,
|
|
state_class=None, # Changes with each period: no statistics
|
|
suggested_display_precision=0,
|
|
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",
|
|
native_unit_of_measurement=UnitOfTime.MINUTES,
|
|
state_class=None, # Countdown timer: no statistics
|
|
suggested_display_precision=0,
|
|
),
|
|
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",
|
|
native_unit_of_measurement=UnitOfTime.MINUTES,
|
|
state_class=None, # Countdown timer: no statistics
|
|
suggested_display_precision=0,
|
|
),
|
|
)
|
|
|
|
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.MINUTES,
|
|
state_class=None, # Changes with each period: no statistics
|
|
suggested_display_precision=0,
|
|
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",
|
|
native_unit_of_measurement=UnitOfTime.MINUTES,
|
|
state_class=None, # Countdown timer: no statistics
|
|
suggested_display_precision=0,
|
|
),
|
|
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",
|
|
native_unit_of_measurement=UnitOfTime.MINUTES,
|
|
state_class=None, # Countdown timer: no statistics
|
|
suggested_display_precision=0,
|
|
),
|
|
)
|
|
|
|
# 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_AVG_SENSORS,
|
|
*FUTURE_TREND_SENSORS,
|
|
*VOLATILITY_SENSORS,
|
|
*BEST_PRICE_TIMING_SENSORS,
|
|
*PEAK_PRICE_TIMING_SENSORS,
|
|
*DIAGNOSTIC_SENSORS,
|
|
)
|