mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
refactor(sensors): rename current price sensors for clarity
Renamed internal sensor keys to be more explicit about their temporal scope: - current_price → current_interval_price - price_level → current_interval_price_level - price_rating → current_interval_price_rating This naming makes it clearer that these sensors represent the current 15-minute interval, distinguishing them from hourly averages and other time-based calculations. Updated across all components: - Sensor entity descriptions and handlers (sensor.py) - Time-sensitive entity keys list (coordinator.py) - Config flow step IDs (config_flow.py) - Translation keys in all 5 languages (de, en, nb, nl, sv) - Custom translations (entity descriptions, usage tips) - Price level/rating lookups (const.py, sensor.py) - Documentation examples (AGENTS.md, README.md) Impact: Sensor entity IDs remain unchanged due to translation_key system. Existing automations continue to work. Only internal code references and translation structures updated for consistency.
This commit is contained in:
parent
c4f36d04de
commit
7737dccd49
17 changed files with 199 additions and 178 deletions
31
AGENTS.md
31
AGENTS.md
|
|
@ -1150,14 +1150,16 @@ We use **Ruff** (which replaces Black, Flake8, isort, and more) as our sole lint
|
|||
**Critical principle:** Logs must enable logic tracing without reading code. Each log message should make the current state and decision-making process crystal clear.
|
||||
|
||||
**Why good logging matters beyond debugging:**
|
||||
- Clear logs become the foundation for good documentation (see "Documentation Writing Strategy")
|
||||
- If you spend hours making logs explain the logic, that clarity transfers directly to user docs
|
||||
- Logs show state transitions and decisions that users need to understand
|
||||
- Pattern: Good hierarchical logs → Easy to extract examples and explanations for documentation
|
||||
|
||||
- Clear logs become the foundation for good documentation (see "Documentation Writing Strategy")
|
||||
- If you spend hours making logs explain the logic, that clarity transfers directly to user docs
|
||||
- Logs show state transitions and decisions that users need to understand
|
||||
- Pattern: Good hierarchical logs → Easy to extract examples and explanations for documentation
|
||||
|
||||
**Log Level Strategy:**
|
||||
|
||||
- **INFO Level** - User-facing results and high-level progress:
|
||||
|
||||
- Compact 1-line summaries (no multi-line blocks)
|
||||
- Important results only (success/failure outcomes)
|
||||
- No indentation (scannability)
|
||||
|
|
@ -1165,6 +1167,7 @@ We use **Ruff** (which replaces Black, Flake8, isort, and more) as our sole lint
|
|||
- Example: `"Day 2025-11-11: Success after 1 relaxation phase (2 periods)"`
|
||||
|
||||
- **DEBUG Level** - Detailed execution trace:
|
||||
|
||||
- Full context headers with all relevant configuration
|
||||
- Step-by-step progression through logic
|
||||
- Hierarchical indentation to show call depth/logic structure
|
||||
|
|
@ -1201,10 +1204,11 @@ _LOGGER.debug("%sExtended baseline period from %s to %s", INDENT_L4, old_end, ne
|
|||
```
|
||||
|
||||
**Why indentation?**
|
||||
- Makes call stack and decision tree visible at a glance
|
||||
- Enables quick problem localization (which phase/step failed?)
|
||||
- Shows parent-child relationships between operations
|
||||
- Distinguishes between sequential steps vs nested logic
|
||||
|
||||
- Makes call stack and decision tree visible at a glance
|
||||
- Enables quick problem localization (which phase/step failed?)
|
||||
- Shows parent-child relationships between operations
|
||||
- Distinguishes between sequential steps vs nested logic
|
||||
|
||||
**Configuration Context:**
|
||||
|
||||
|
|
@ -1328,6 +1332,7 @@ When writing or updating user-facing documentation (`docs/user/`), follow these
|
|||
Understanding **how** good documentation emerges is as important as knowing what makes it good:
|
||||
|
||||
- **Live Understanding vs. Code Analysis**
|
||||
|
||||
- ✅ **DO:** Write docs during/after active development
|
||||
- When implementing complex logic, document it while the "why" is fresh
|
||||
- Use real examples from debugging sessions (actual logs, real data)
|
||||
|
|
@ -1338,6 +1343,7 @@ Understanding **how** good documentation emerges is as important as knowing what
|
|||
- No user perspective: What's actually confusing?
|
||||
|
||||
- **User Feedback Loop**
|
||||
|
||||
- Key insight: Documentation improves when users question it
|
||||
- Pattern:
|
||||
1. User asks: "Does this still match the code?"
|
||||
|
|
@ -1347,16 +1353,19 @@ Understanding **how** good documentation emerges is as important as knowing what
|
|||
- Why it works: User questions force critical thinking, real confusion points get addressed
|
||||
|
||||
- **Log-Driven Documentation**
|
||||
|
||||
- Observation: When logs explain logic clearly, documentation becomes easier
|
||||
- Why: Logs show state transitions ("Baseline insufficient → Starting relaxation"), decisions ("Replaced period X with larger Y"), and are already written for humans
|
||||
- Pattern: If you spent hours making logs clear → use that clarity in documentation too
|
||||
|
||||
- **Concrete Examples > Abstract Descriptions**
|
||||
|
||||
- ✅ **Good:** "Day 2025-11-11 found 2 periods at flex=12.0% +volatility_any (stopped early, no need to try higher flex)"
|
||||
- ❌ **Bad:** "The relaxation algorithm uses a configurable threshold multiplier with filter combination strategies"
|
||||
- Use real data from debug sessions, show actual attribute values, demonstrate with timeline diagrams
|
||||
|
||||
- **Context Accumulation in Long Sessions**
|
||||
|
||||
- Advantage: AI builds mental model incrementally, sees evolution of logic (not just final state), understands trade-offs
|
||||
- Disadvantage of short sessions: Cold start every time, missing "why" context, documentation becomes spec-writing
|
||||
- Lesson: Complex documentation benefits from focused, uninterrupted work with accumulated context
|
||||
|
|
@ -1406,7 +1415,7 @@ name = 'tibber_prices' # Ruff will change to double quotes
|
|||
```python
|
||||
# ✅ Always use trailing commas in multi-line structures
|
||||
SENSOR_TYPES = [
|
||||
"current_price",
|
||||
"current_interval_price",
|
||||
"min_price",
|
||||
"max_price", # ← Trailing comma
|
||||
]
|
||||
|
|
@ -1421,7 +1430,7 @@ def calculate_average(
|
|||
|
||||
# ❌ Missing trailing comma
|
||||
SENSOR_TYPES = [
|
||||
"current_price",
|
||||
"current_interval_price",
|
||||
"min_price",
|
||||
"max_price" # Ruff will add trailing comma
|
||||
]
|
||||
|
|
@ -1483,7 +1492,7 @@ df = (
|
|||
|
||||
```python
|
||||
# ✅ Annotate function signatures (public functions)
|
||||
def get_current_price(coordinator: DataUpdateCoordinator) -> float:
|
||||
def get_current_interval_price(coordinator: DataUpdateCoordinator) -> float:
|
||||
"""Get current price from coordinator."""
|
||||
return coordinator.data["priceInfo"]["today"][0]["total"]
|
||||
|
||||
|
|
|
|||
142
README.md
142
README.md
|
|
@ -14,10 +14,10 @@ A Home Assistant integration that provides advanced price information and rating
|
|||
|
||||
## 📖 Documentation
|
||||
|
||||
- **[User Guide](docs/user/)** - Installation, configuration, and usage guides
|
||||
- **[Period Calculation](docs/user/period-calculation.md)** - How Best/Peak Price periods are calculated
|
||||
- **[Developer Guide](docs/development/)** - Contributing, architecture, and release process
|
||||
- **[Changelog](https://github.com/jpawlowski/hass.tibber_prices/releases)** - Release history and notes
|
||||
- **[User Guide](docs/user/)** - Installation, configuration, and usage guides
|
||||
- **[Period Calculation](docs/user/period-calculation.md)** - How Best/Peak Price periods are calculated
|
||||
- **[Developer Guide](docs/development/)** - Contributing, architecture, and release process
|
||||
- **[Changelog](https://github.com/jpawlowski/hass.tibber_prices/releases)** - Release history and notes
|
||||
|
||||
## ✨ Features
|
||||
|
||||
|
|
@ -44,6 +44,7 @@ Click the button below to open the integration directly in HACS:
|
|||
[](https://my.home-assistant.io/redirect/hacs_repository/?owner=jpawlowski&repository=hass.tibber_prices&category=integration)
|
||||
|
||||
Then:
|
||||
|
||||
1. Click "Download" to install the integration
|
||||
2. **Restart Home Assistant** (required after installation)
|
||||
|
||||
|
|
@ -60,6 +61,7 @@ Click the button below to open the configuration dialog:
|
|||
[](https://my.home-assistant.io/redirect/config_flow_start/?domain=tibber_prices)
|
||||
|
||||
This will guide you through:
|
||||
|
||||
1. Enter your Tibber API token ([get one here](https://developer.tibber.com/settings/access-token))
|
||||
2. Select your Tibber home
|
||||
3. Configure price thresholds (optional)
|
||||
|
|
@ -73,9 +75,9 @@ This will guide you through:
|
|||
|
||||
### Step 3: Start Using!
|
||||
|
||||
- 30+ sensors are now available (key sensors enabled by default)
|
||||
- Configure additional sensors in **Settings** → **Devices & Services** → **Tibber Price Information & Ratings** → **Entities**
|
||||
- Use sensors in automations, dashboards, and scripts
|
||||
- 30+ sensors are now available (key sensors enabled by default)
|
||||
- Configure additional sensors in **Settings** → **Devices & Services** → **Tibber Price Information & Ratings** → **Entities**
|
||||
- Use sensors in automations, dashboards, and scripts
|
||||
|
||||
📖 **[Full Installation Guide →](docs/user/installation.md)**
|
||||
|
||||
|
|
@ -87,66 +89,66 @@ The integration provides **30+ sensors** across different categories. Key sensor
|
|||
|
||||
### Core Price Sensors (Enabled by Default)
|
||||
|
||||
| Entity | Description |
|
||||
| ----------------------------- | ------------------------------------------------- |
|
||||
| Current Electricity Price | Current 15-minute interval price |
|
||||
| Next Interval Price | Price for the next 15-minute interval |
|
||||
| Current Hour Average Price | Average of current hour's 4 intervals |
|
||||
| Next Hour Average Price | Average of next hour's 4 intervals |
|
||||
| Current Price Level | API classification (VERY_CHEAP to VERY_EXPENSIVE) |
|
||||
| Next Interval Price Level | Price level for next interval |
|
||||
| Current Hour Price Level | Price level for current hour average |
|
||||
| Next Hour Price Level | Price level for next hour average |
|
||||
| Entity | Description |
|
||||
| -------------------------- | ------------------------------------------------- |
|
||||
| Current Electricity Price | Current 15-minute interval price |
|
||||
| Next Interval Price | Price for the next 15-minute interval |
|
||||
| Current Hour Average Price | Average of current hour's 4 intervals |
|
||||
| Next Hour Average Price | Average of next hour's 4 intervals |
|
||||
| Current Price Level | API classification (VERY_CHEAP to VERY_EXPENSIVE) |
|
||||
| Next Interval Price Level | Price level for next interval |
|
||||
| Current Hour Price Level | Price level for current hour average |
|
||||
| Next Hour Price Level | Price level for next hour average |
|
||||
|
||||
### Statistical Sensors (Enabled by Default)
|
||||
|
||||
| Entity | Description |
|
||||
| ------------------------------ | -------------------------------------------- |
|
||||
| Today's Lowest Price | Minimum price for today |
|
||||
| Today's Highest Price | Maximum price for today |
|
||||
| Today's Average Price | Mean price across today's intervals |
|
||||
| Tomorrow's Lowest Price | Minimum price for tomorrow (when available) |
|
||||
| Tomorrow's Highest Price | Maximum price for tomorrow (when available) |
|
||||
| Tomorrow's Average Price | Mean price for tomorrow (when available) |
|
||||
| Leading 24h Average Price | Average of next 24 hours from now |
|
||||
| Leading 24h Minimum Price | Lowest price in next 24 hours |
|
||||
| Leading 24h Maximum Price | Highest price in next 24 hours |
|
||||
| Entity | Description |
|
||||
| ------------------------- | ------------------------------------------- |
|
||||
| Today's Lowest Price | Minimum price for today |
|
||||
| Today's Highest Price | Maximum price for today |
|
||||
| Today's Average Price | Mean price across today's intervals |
|
||||
| Tomorrow's Lowest Price | Minimum price for tomorrow (when available) |
|
||||
| Tomorrow's Highest Price | Maximum price for tomorrow (when available) |
|
||||
| Tomorrow's Average Price | Mean price for tomorrow (when available) |
|
||||
| Leading 24h Average Price | Average of next 24 hours from now |
|
||||
| Leading 24h Minimum Price | Lowest price in next 24 hours |
|
||||
| Leading 24h Maximum Price | Highest price in next 24 hours |
|
||||
|
||||
### Price Rating Sensors (Enabled by Default)
|
||||
|
||||
| Entity | Description |
|
||||
| --------------------------- | ---------------------------------------------------------- |
|
||||
| Current Price Rating | % difference from 24h trailing average (current interval) |
|
||||
| Next Interval Price Rating | % difference from 24h trailing average (next interval) |
|
||||
| Current Hour Price Rating | % difference for current hour average |
|
||||
| Next Hour Price Rating | % difference for next hour average |
|
||||
| Entity | Description |
|
||||
| -------------------------- | --------------------------------------------------------- |
|
||||
| Current Price Rating | % difference from 24h trailing average (current interval) |
|
||||
| Next Interval Price Rating | % difference from 24h trailing average (next interval) |
|
||||
| Current Hour Price Rating | % difference for current hour average |
|
||||
| Next Hour Price Rating | % difference for next hour average |
|
||||
|
||||
> **How ratings work**: Compares each interval to the average of the previous 96 intervals (24 hours). Positive values mean prices are above average, negative means below average.
|
||||
|
||||
### Binary Sensors (Enabled by Default)
|
||||
|
||||
| Entity | Description |
|
||||
| -------------------------- | -------------------------------------------------------------- |
|
||||
| Peak Price Period | ON when in a detected peak price period ([how it works](docs/user/period-calculation.md)) |
|
||||
| Best Price Period | ON when in a detected best price period ([how it works](docs/user/period-calculation.md)) |
|
||||
| Tibber API Connection | Connection status to Tibber API |
|
||||
| Tomorrow's Data Available | Whether tomorrow's price data is available |
|
||||
| Entity | Description |
|
||||
| ------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| Peak Price Period | ON when in a detected peak price period ([how it works](docs/user/period-calculation.md)) |
|
||||
| Best Price Period | ON when in a detected best price period ([how it works](docs/user/period-calculation.md)) |
|
||||
| Tibber API Connection | Connection status to Tibber API |
|
||||
| Tomorrow's Data Available | Whether tomorrow's price data is available |
|
||||
|
||||
### Diagnostic Sensors (Enabled by Default)
|
||||
|
||||
| Entity | Description |
|
||||
| ----------------- | ------------------------------------------ |
|
||||
| Data Expiration | Timestamp when current data expires |
|
||||
| Price Forecast | Formatted list of upcoming price intervals |
|
||||
| Entity | Description |
|
||||
| --------------- | ------------------------------------------ |
|
||||
| Data Expiration | Timestamp when current data expires |
|
||||
| Price Forecast | Formatted list of upcoming price intervals |
|
||||
|
||||
### Additional Sensors (Disabled by Default)
|
||||
|
||||
The following sensors are available but disabled by default. Enable them in `Settings > Devices & Services > Tibber Price Information & Ratings > Entities`:
|
||||
|
||||
- **Previous Interval Price** & **Previous Interval Price Level**: Historical data for the last 15-minute interval
|
||||
- **Previous Interval Price Rating**: Rating for the previous interval
|
||||
- **Trailing 24h Average Price**: Average of the past 24 hours from now
|
||||
- **Trailing 24h Minimum/Maximum Price**: Min/max in the past 24 hours
|
||||
- **Previous Interval Price** & **Previous Interval Price Level**: Historical data for the last 15-minute interval
|
||||
- **Previous Interval Price Rating**: Rating for the previous interval
|
||||
- **Trailing 24h Average Price**: Average of the past 24 hours from now
|
||||
- **Trailing 24h Minimum/Maximum Price**: Min/max in the past 24 hours
|
||||
|
||||
> **Note**: All monetary sensors use minor currency units (ct/kWh, øre/kWh, ¢/kWh, p/kWh) automatically based on your Tibber account's currency. Supported: EUR, NOK, SEK, DKK, USD, GBP.
|
||||
|
||||
|
|
@ -186,7 +188,7 @@ automation:
|
|||
- alias: "Notify on Very Expensive Electricity"
|
||||
trigger:
|
||||
- platform: state
|
||||
entity_id: sensor.tibber_current_price_level
|
||||
entity_id: sensor.tibber_current_interval_price_level
|
||||
to: "VERY_EXPENSIVE"
|
||||
action:
|
||||
- service: notify.mobile_app
|
||||
|
|
@ -204,14 +206,14 @@ automation:
|
|||
- alias: "Reduce Heating During High Price Ratings"
|
||||
trigger:
|
||||
- platform: numeric_state
|
||||
entity_id: sensor.tibber_current_price_rating
|
||||
above: 20 # More than 20% above 24h average
|
||||
entity_id: sensor.tibber_current_interval_price_rating
|
||||
above: 20 # More than 20% above 24h average
|
||||
action:
|
||||
- service: climate.set_temperature
|
||||
target:
|
||||
entity_id: climate.living_room
|
||||
data:
|
||||
temperature: 19 # Lower target temperature
|
||||
temperature: 19 # Lower target temperature
|
||||
```
|
||||
|
||||
### Smart EV Charging Based on Tomorrow's Prices
|
||||
|
|
@ -227,8 +229,8 @@ automation:
|
|||
to: "on"
|
||||
condition:
|
||||
- condition: numeric_state
|
||||
entity_id: sensor.tibber_current_price_rating
|
||||
below: -15 # At least 15% below average
|
||||
entity_id: sensor.tibber_current_interval_price_rating
|
||||
below: -15 # At least 15% below average
|
||||
- condition: numeric_state
|
||||
entity_id: sensor.ev_battery_level
|
||||
below: 80
|
||||
|
|
@ -273,15 +275,18 @@ automation:
|
|||
Every sensor includes rich attributes beyond just the state value. These attributes provide context, timestamps, and additional data useful for automations and templates.
|
||||
|
||||
**Standard attributes available on most sensors:**
|
||||
- `timestamp` - ISO 8601 timestamp for the data point
|
||||
- `description` - Brief explanation of what the sensor represents
|
||||
- `level_id` and `level_value` - For price level sensors (e.g., `VERY_CHEAP` = -2)
|
||||
|
||||
- `timestamp` - ISO 8601 timestamp for the data point
|
||||
- `description` - Brief explanation of what the sensor represents
|
||||
- `level_id` and `level_value` - For price level sensors (e.g., `VERY_CHEAP` = -2)
|
||||
|
||||
**Extended descriptions** (enable in integration options):
|
||||
- `long_description` - Detailed explanation of the sensor's purpose
|
||||
- `usage_tips` - Practical suggestions for using the sensor in automations
|
||||
|
||||
- `long_description` - Detailed explanation of the sensor's purpose
|
||||
- `usage_tips` - Practical suggestions for using the sensor in automations
|
||||
|
||||
**Example - Current Price sensor attributes:**
|
||||
|
||||
```yaml
|
||||
timestamp: "2025-11-03T14:15:00+01:00"
|
||||
description: "The current electricity price per kWh"
|
||||
|
|
@ -290,14 +295,15 @@ usage_tips: "Use this to track prices or to create automations that run when ele
|
|||
```
|
||||
|
||||
**Example template using attributes:**
|
||||
|
||||
```yaml
|
||||
template:
|
||||
- sensor:
|
||||
- name: "Price Status"
|
||||
state: >
|
||||
{% set price = states('sensor.tibber_current_electricity_price') | float %}
|
||||
{% set timestamp = state_attr('sensor.tibber_current_electricity_price', 'timestamp') %}
|
||||
Price at {{ timestamp }}: {{ price }} ct/kWh
|
||||
- sensor:
|
||||
- name: "Price Status"
|
||||
state: >
|
||||
{% set price = states('sensor.tibber_current_electricity_price') | float %}
|
||||
{% set timestamp = state_attr('sensor.tibber_current_electricity_price', 'timestamp') %}
|
||||
Price at {{ timestamp }}: {{ price }} ct/kWh
|
||||
```
|
||||
|
||||
📖 **[View all sensors and attributes →](docs/user/sensors.md)**
|
||||
|
|
@ -325,9 +331,9 @@ Contributions are welcome! Please read the [Contributing Guidelines](CONTRIBUTIN
|
|||
|
||||
### For Contributors
|
||||
|
||||
- **[Developer Setup](docs/development/setup.md)** - Get started with DevContainer
|
||||
- **[Architecture Guide](docs/development/architecture.md)** - Understand the codebase
|
||||
- **[Release Management](docs/development/release-management.md)** - Release process and versioning
|
||||
- **[Developer Setup](docs/development/setup.md)** - Get started with DevContainer
|
||||
- **[Architecture Guide](docs/development/architecture.md)** - Understand the codebase
|
||||
- **[Release Management](docs/development/release-management.md)** - Release process and versioning
|
||||
|
||||
## 🤖 Development Note
|
||||
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ class TibberPricesOptionsFlowHandler(OptionsFlow):
|
|||
_TOTAL_STEPS: ClassVar[int] = 6
|
||||
_STEP_INFO: ClassVar[dict[str, int]] = {
|
||||
"init": 1,
|
||||
"price_rating": 2,
|
||||
"current_interval_price_rating": 2,
|
||||
"volatility": 3,
|
||||
"best_price": 4,
|
||||
"peak_price": 5,
|
||||
|
|
@ -553,7 +553,7 @@ class TibberPricesOptionsFlowHandler(OptionsFlow):
|
|||
return await self.async_step_volatility()
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="price_rating",
|
||||
step_id="current_interval_price_rating",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
|
|
@ -592,7 +592,7 @@ class TibberPricesOptionsFlowHandler(OptionsFlow):
|
|||
),
|
||||
}
|
||||
),
|
||||
description_placeholders=self._get_step_description_placeholders("price_rating"),
|
||||
description_placeholders=self._get_step_description_placeholders("current_interval_price_rating"),
|
||||
)
|
||||
|
||||
async def async_step_best_price(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
|
||||
|
|
@ -666,7 +666,7 @@ class TibberPricesOptionsFlowHandler(OptionsFlow):
|
|||
SelectSelectorConfig(
|
||||
options=BEST_PRICE_MAX_LEVEL_OPTIONS,
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
translation_key="price_level",
|
||||
translation_key="current_interval_price_level",
|
||||
),
|
||||
),
|
||||
vol.Optional(
|
||||
|
|
@ -817,7 +817,7 @@ class TibberPricesOptionsFlowHandler(OptionsFlow):
|
|||
SelectSelectorConfig(
|
||||
options=PEAK_PRICE_MIN_LEVEL_OPTIONS,
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
translation_key="price_level",
|
||||
translation_key="current_interval_price_level",
|
||||
),
|
||||
),
|
||||
vol.Optional(
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ PRICE_LEVEL_COLOR_MAPPING = {
|
|||
}
|
||||
|
||||
# Icon mapping for current price sensors (dynamic icons based on price level)
|
||||
# Used by current_price and current_hour_average sensors
|
||||
# Used by current_interval_price and current_hour_average sensors
|
||||
# Icon shows price level (cheap/normal/expensive), icon_color reinforces with color
|
||||
PRICE_LEVEL_CASH_ICON_MAPPING = {
|
||||
PRICE_LEVEL_VERY_CHEAP: "mdi:cash-multiple", # Many coins (save a lot!)
|
||||
|
|
@ -667,7 +667,9 @@ async def async_get_price_level_translation(
|
|||
The localized price level if found, None otherwise
|
||||
|
||||
"""
|
||||
return await async_get_translation(hass, ["sensor", "price_level", "price_levels", level], language)
|
||||
return await async_get_translation(
|
||||
hass, ["sensor", "current_interval_price_level", "price_levels", level], language
|
||||
)
|
||||
|
||||
|
||||
def get_price_level_translation(
|
||||
|
|
@ -687,7 +689,7 @@ def get_price_level_translation(
|
|||
The localized price level if found in cache, None otherwise
|
||||
|
||||
"""
|
||||
return get_translation(["sensor", "price_level", "price_levels", level], language)
|
||||
return get_translation(["sensor", "current_interval_price_level", "price_levels", level], language)
|
||||
|
||||
|
||||
async def async_get_home_type_translation(
|
||||
|
|
|
|||
|
|
@ -107,11 +107,11 @@ TOMORROW_DATA_CHECK_HOUR = 13
|
|||
TIME_SENSITIVE_ENTITY_KEYS = frozenset(
|
||||
{
|
||||
# Current/next/previous price sensors
|
||||
"current_price",
|
||||
"current_interval_price",
|
||||
"next_interval_price",
|
||||
"previous_interval_price",
|
||||
# Current/next/previous price levels
|
||||
"price_level",
|
||||
"current_interval_price_level",
|
||||
"next_interval_price_level",
|
||||
"previous_interval_price_level",
|
||||
# Rolling hour calculations (5-interval windows)
|
||||
|
|
@ -120,7 +120,7 @@ TIME_SENSITIVE_ENTITY_KEYS = frozenset(
|
|||
"current_hour_price_level",
|
||||
"next_hour_price_level",
|
||||
# Current/next/previous price ratings
|
||||
"price_rating",
|
||||
"current_interval_price_rating",
|
||||
"next_interval_price_rating",
|
||||
"previous_interval_price_rating",
|
||||
"current_hour_price_rating",
|
||||
|
|
@ -222,7 +222,7 @@ class TibberPricesDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||
"""
|
||||
Listen for time-sensitive updates that occur every quarter-hour.
|
||||
|
||||
Time-sensitive entities (like current_price, next_interval_price, etc.) should use this
|
||||
Time-sensitive entities (like current_interval_price, next_interval_price, etc.) should use this
|
||||
method instead of async_add_listener to receive updates at quarter-hour boundaries.
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"description": "Der aktuelle Strompreis pro kWh",
|
||||
"long_description": "Zeigt den aktuellen Preis pro kWh von deinem Tibber-Abonnement an",
|
||||
"usage_tips": "Nutze dies, um Preise zu verfolgen oder Automatisierungen zu erstellen, die bei günstigem Strom ausgeführt werden"
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
"long_description": "Zeigt den höchsten Preis pro kWh für die nächsten 24 Stunden (vorlaufendes Maximum) von deinem Tibber-Abonnement an. Dies bietet den höchsten erwarteten Preis in den nächsten 24 Stunden basierend auf Prognosedaten.",
|
||||
"usage_tips": "Nutze dies, um den Betrieb von Geräten während kommender Spitzenpreiszeiten zu vermeiden."
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"description": "Die aktuelle Preislevelklassifikation",
|
||||
"long_description": "Zeigt die Klassifizierung von Tibber für den aktuellen Preis im Vergleich zu historischen Preisen an",
|
||||
"usage_tips": "Nutze dies, um Automatisierungen auf Basis des relativen Preisniveaus anstelle der absoluten Preise zu erstellen"
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
"long_description": "Zeigt das mediane Preisniveau über 5 Intervalle, die eine Stunde voraus zentriert sind. Hilft bei der Verbrauchsplanung basierend auf kommenden Preistrends statt momentanen zukünftigen Preisen.",
|
||||
"usage_tips": "Nutze dies, um Aktivitäten für die nächste Stunde basierend auf einer geglätteten Preisniveau-Prognose zu planen."
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"description": "Wie sich der Preis des aktuellen Intervalls mit historischen Daten vergleicht",
|
||||
"long_description": "Zeigt, wie sich der Preis des aktuellen Intervalls im Vergleich zu historischen Preisdaten als Prozentsatz verhält",
|
||||
"usage_tips": "Ein positiver Prozentsatz bedeutet, dass der aktuelle Preis überdurchschnittlich ist, negativ bedeutet unterdurchschnittlich"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"description": "The current electricity price per kWh",
|
||||
"long_description": "Shows the current price per kWh from your Tibber subscription",
|
||||
"usage_tips": "Use this to track prices or to create automations that run when electricity is cheap"
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
"long_description": "Shows the maximum price per kWh from the next 24 hours (leading maximum) from your Tibber subscription. This provides the highest price expected in the next 24 hours based on forecast data.",
|
||||
"usage_tips": "Use this to avoid running appliances during upcoming peak price periods."
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"description": "The current price level classification",
|
||||
"long_description": "Shows Tibber's classification of the current price compared to historical prices",
|
||||
"usage_tips": "Use this to create automations based on relative price levels rather than absolute prices"
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
"long_description": "Shows the median price level across 5 intervals centered one hour ahead. Helps plan consumption based on upcoming price trends rather than instantaneous future prices.",
|
||||
"usage_tips": "Use to schedule activities for the next hour based on a smoothed price level forecast."
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"description": "How the current interval's price compares to historical data",
|
||||
"long_description": "Shows how the current interval's price compares to historical price data as a percentage",
|
||||
"usage_tips": "A positive percentage means the current price is above average, negative means below average"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"description": "Den nåværende elektrisitetsprisen per kWh",
|
||||
"long_description": "Viser nåværende pris per kWh fra ditt Tibber-abonnement",
|
||||
"usage_tips": "Bruk dette til å spore priser eller lage automatiseringer som kjører når strøm er billig"
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
"long_description": "Viser maksimumsprisen per kWh fra de neste 24 timene (fremtidsrettet maksimum) fra ditt Tibber-abonnement. Dette gir den høyeste prisen forventet i de neste 24 timene basert på prognosedata.",
|
||||
"usage_tips": "Bruk dette til å unngå å kjøre apparater i kommende topprisperioder."
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"description": "Den nåværende prisnivåklassifiseringen",
|
||||
"long_description": "Viser Tibbers klassifisering av nåværende pris sammenlignet med historiske priser",
|
||||
"usage_tips": "Bruk dette til å lage automatiseringer basert på relative prisnivåer i stedet for absolutte priser"
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
"long_description": "Viser median prisnivå på tvers av 5 intervaller sentrert en time frem. Hjelper med å planlegge forbruk basert på kommende pristrender i stedet for øyeblikkelige fremtidige priser.",
|
||||
"usage_tips": "Bruk for å planlegge aktiviteter for neste time basert på en utjevnet prisnivåprognose."
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"description": "Hvordan nåværende intervalls pris sammenlignes med historiske data",
|
||||
"long_description": "Viser hvordan nåværende intervalls pris sammenlignes med historiske prisdata som en prosentandel",
|
||||
"usage_tips": "En positiv prosentandel betyr at nåværende pris er over gjennomsnittet, negativ betyr under gjennomsnittet"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"description": "De huidige elektriciteitsprijs per kWh",
|
||||
"long_description": "Toont de huidige prijs per kWh van uw Tibber-abonnement",
|
||||
"usage_tips": "Gebruik dit om prijzen bij te houden of om automatiseringen te maken die worden uitgevoerd wanneer elektriciteit goedkoop is"
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
"long_description": "Toont de maximumprijs per kWh van de komende 24 uur (vooruitlopend maximum) van uw Tibber-abonnement. Dit geeft de hoogste prijs die wordt verwacht in de komende 24 uur op basis van prognosegegevens.",
|
||||
"usage_tips": "Gebruik dit om te voorkomen dat u apparaten draait tijdens aanstaande piekprijsperioden."
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"description": "De huidige prijsniveauclassificatie",
|
||||
"long_description": "Toont de classificatie van Tibber van de huidige prijs vergeleken met historische prijzen",
|
||||
"usage_tips": "Gebruik dit om automatiseringen te maken op basis van relatieve prijsniveaus in plaats van absolute prijzen"
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
"long_description": "Toont het mediane prijsniveau over 5 intervallen gecentreerd één uur vooruit. Helpt verbruik te plannen op basis van aanstaande prijstrends in plaats van momentane toekomstige prijzen.",
|
||||
"usage_tips": "Gebruik om activiteiten voor het volgende uur te plannen op basis van een vloeiende prijsniveauprognose."
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"description": "Hoe de prijs van het huidige interval zich verhoudt tot historische gegevens",
|
||||
"long_description": "Toont hoe de prijs van het huidige interval zich verhoudt tot historische prijsgegevens als een percentage",
|
||||
"usage_tips": "Een positief percentage betekent dat de huidige prijs boven het gemiddelde ligt, negatief betekent onder het gemiddelde"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"description": "Det nuvarande elpriset per kWh",
|
||||
"long_description": "Visar nuvarande pris per kWh från ditt Tibber-abonnemang",
|
||||
"usage_tips": "Använd detta för att spåra priser eller skapa automationer som körs när el är billig"
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
"long_description": "Visar maximipriset per kWh från nästa 24 timmar (framåtblickande maximum) från ditt Tibber-abonnemang. Detta ger det högsta priset som förväntas nästa 24 timmar baserat på prognosdata.",
|
||||
"usage_tips": "Använd detta för att undvika att köra apparater under kommande toppprisperioder."
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"description": "Den nuvarande prisnivåklassificeringen",
|
||||
"long_description": "Visar Tibbers klassificering av nuvarande pris jämfört med historiska priser",
|
||||
"usage_tips": "Använd detta för att skapa automationer baserade på relativa prisnivåer istället för absoluta priser"
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
"long_description": "Visar median prisnivå över 5 intervaller centrerade en timme framåt. Hjälper att planera konsumtion baserat på kommande pristrender istället för ögonblickliga framtida priser.",
|
||||
"usage_tips": "Använd för att schemalägga aktiviteter för nästa timme baserat på en utjämnad prisnivåprognos."
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"description": "Hur nuvarande intervalls pris jämförs med historiska data",
|
||||
"long_description": "Visar hur nuvarande intervalls pris jämförs med historiska prisdata som en procentsats",
|
||||
"usage_tips": "En positiv procentsats betyder att nuvarande pris är över genomsnittet, negativ betyder under genomsnittet"
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ def calculate_trailing_average_for_interval(
|
|||
|
||||
|
||||
def calculate_difference_percentage(
|
||||
current_price: float,
|
||||
current_interval_price: float,
|
||||
trailing_average: float | None,
|
||||
) -> float | None:
|
||||
"""
|
||||
|
|
@ -158,7 +158,7 @@ def calculate_difference_percentage(
|
|||
This mimics the API's "difference" field from priceRating endpoint.
|
||||
|
||||
Args:
|
||||
current_price: The current interval's price
|
||||
current_interval_price: The current interval's price
|
||||
trailing_average: The 24-hour trailing average price
|
||||
|
||||
Returns:
|
||||
|
|
@ -169,7 +169,7 @@ def calculate_difference_percentage(
|
|||
if trailing_average is None or trailing_average == 0:
|
||||
return None
|
||||
|
||||
return ((current_price - trailing_average) / trailing_average) * 100
|
||||
return ((current_interval_price - trailing_average) / trailing_average) * 100
|
||||
|
||||
|
||||
def calculate_rating_level(
|
||||
|
|
@ -238,9 +238,9 @@ def _process_price_interval(
|
|||
return
|
||||
|
||||
starts_at = dt_util.as_local(starts_at)
|
||||
current_price = price_interval.get("total")
|
||||
current_interval_price = price_interval.get("total")
|
||||
|
||||
if current_price is None:
|
||||
if current_interval_price is None:
|
||||
return
|
||||
|
||||
# Calculate trailing average
|
||||
|
|
@ -248,7 +248,7 @@ def _process_price_interval(
|
|||
|
||||
# Calculate and set the difference and rating_level
|
||||
if trailing_avg is not None:
|
||||
difference = calculate_difference_percentage(float(current_price), trailing_avg)
|
||||
difference = calculate_difference_percentage(float(current_interval_price), trailing_avg)
|
||||
price_interval["difference"] = difference
|
||||
|
||||
# Calculate rating_level based on difference
|
||||
|
|
@ -486,7 +486,7 @@ def aggregate_period_ratings(
|
|||
|
||||
|
||||
def calculate_price_trend(
|
||||
current_price: float,
|
||||
current_interval_price: float,
|
||||
future_average: float,
|
||||
threshold_rising: float = 5.0,
|
||||
threshold_falling: float = -5.0,
|
||||
|
|
@ -495,7 +495,7 @@ def calculate_price_trend(
|
|||
Calculate price trend by comparing current price with future average.
|
||||
|
||||
Args:
|
||||
current_price: Current interval price
|
||||
current_interval_price: Current interval price
|
||||
future_average: Average price of future intervals
|
||||
threshold_rising: Percentage threshold for rising trend (positive, default 5%)
|
||||
threshold_falling: Percentage threshold for falling trend (negative, default -5%)
|
||||
|
|
@ -506,12 +506,12 @@ def calculate_price_trend(
|
|||
difference_percentage: % change from current to future ((future - current) / current * 100)
|
||||
|
||||
"""
|
||||
if current_price == 0:
|
||||
if current_interval_price == 0:
|
||||
# Avoid division by zero
|
||||
return "stable", 0.0
|
||||
|
||||
# Calculate percentage difference from current to future
|
||||
diff_pct = ((future_average - current_price) / current_price) * 100
|
||||
diff_pct = ((future_average - current_interval_price) / current_interval_price) * 100
|
||||
|
||||
# Determine trend based on thresholds
|
||||
# threshold_falling is negative, so we compare with it directly
|
||||
|
|
|
|||
|
|
@ -80,8 +80,8 @@ MIN_HOURS_FOR_LATER_HALF = 3 # Minimum hours needed to calculate later half ave
|
|||
# Main price sensors that users will typically use in automations
|
||||
PRICE_SENSORS = (
|
||||
SensorEntityDescription(
|
||||
key="current_price",
|
||||
translation_key="current_price",
|
||||
key="current_interval_price",
|
||||
translation_key="current_interval_price",
|
||||
name="Current Electricity Price",
|
||||
icon="mdi:cash", # Dynamic: will show cash-multiple/plus/cash/minus/remove based on level
|
||||
device_class=SensorDeviceClass.MONETARY,
|
||||
|
|
@ -124,8 +124,8 @@ PRICE_SENSORS = (
|
|||
# import timing issues with Home Assistant's entity platform initialization.
|
||||
# Keep in sync with PRICE_LEVEL_OPTIONS in const.py!
|
||||
SensorEntityDescription(
|
||||
key="price_level",
|
||||
translation_key="price_level",
|
||||
key="current_interval_price_level",
|
||||
translation_key="current_interval_price_level",
|
||||
name="Current Price Level",
|
||||
icon="mdi:gauge",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
|
|
@ -314,8 +314,8 @@ VOLATILITY_SENSORS = (
|
|||
# Keep in sync with PRICE_RATING_OPTIONS in const.py!
|
||||
RATING_SENSORS = (
|
||||
SensorEntityDescription(
|
||||
key="price_rating",
|
||||
translation_key="price_rating",
|
||||
key="current_interval_price_rating",
|
||||
translation_key="current_interval_price_rating",
|
||||
name="Current Price Rating",
|
||||
icon="mdi:star-outline",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
|
|
@ -620,13 +620,13 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
# Map sensor keys to their handler methods
|
||||
handlers = {
|
||||
# Price level sensors
|
||||
"price_level": self._get_price_level_value,
|
||||
"current_interval_price_level": self._get_price_level_value,
|
||||
"next_interval_price_level": lambda: self._get_interval_level_value(interval_offset=1),
|
||||
"previous_interval_price_level": lambda: self._get_interval_level_value(interval_offset=-1),
|
||||
"current_hour_price_level": lambda: self._get_rolling_hour_level_value(hour_offset=0),
|
||||
"next_hour_price_level": lambda: self._get_rolling_hour_level_value(hour_offset=1),
|
||||
# Price sensors
|
||||
"current_price": lambda: self._get_interval_price_value(interval_offset=0, in_euro=False),
|
||||
"current_interval_price": lambda: self._get_interval_price_value(interval_offset=0, in_euro=False),
|
||||
"next_interval_price": lambda: self._get_interval_price_value(interval_offset=1, in_euro=False),
|
||||
"previous_interval_price": lambda: self._get_interval_price_value(interval_offset=-1, in_euro=False),
|
||||
# Rolling hour average (5 intervals: 2 before + current + 2 after)
|
||||
|
|
@ -692,7 +692,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
decimals=2,
|
||||
),
|
||||
# Rating sensors
|
||||
"price_rating": lambda: self._get_rating_value(rating_type="current"),
|
||||
"current_interval_price_rating": lambda: self._get_rating_value(rating_type="current"),
|
||||
"next_interval_price_rating": lambda: self._get_interval_rating_value(interval_offset=1),
|
||||
"previous_interval_price_rating": lambda: self._get_interval_rating_value(interval_offset=-1),
|
||||
"current_hour_price_rating": lambda: self._get_rolling_hour_rating_value(hour_offset=0),
|
||||
|
|
@ -1115,11 +1115,11 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
if (
|
||||
translations
|
||||
and "sensor" in translations
|
||||
and "price_rating" in translations["sensor"]
|
||||
and "price_levels" in translations["sensor"]["price_rating"]
|
||||
and level in translations["sensor"]["price_rating"]["price_levels"]
|
||||
and "current_interval_price_rating" in translations["sensor"]
|
||||
and "price_levels" in translations["sensor"]["current_interval_price_rating"]
|
||||
and level in translations["sensor"]["current_interval_price_rating"]["price_levels"]
|
||||
):
|
||||
return translations["sensor"]["price_rating"]["price_levels"][level]
|
||||
return translations["sensor"]["current_interval_price_rating"]["price_levels"][level]
|
||||
# Fallback to English if not found
|
||||
if language != "en":
|
||||
en_cache_key = f"{DOMAIN}_translations_en"
|
||||
|
|
@ -1127,11 +1127,11 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
if (
|
||||
en_translations
|
||||
and "sensor" in en_translations
|
||||
and "price_rating" in en_translations
|
||||
and "price_levels" in en_translations["sensor"]["price_rating"]
|
||||
and level in en_translations["sensor"]["price_rating"]["price_levels"]
|
||||
and "current_interval_price_rating" in en_translations
|
||||
and "price_levels" in en_translations["sensor"]["current_interval_price_rating"]
|
||||
and level in en_translations["sensor"]["current_interval_price_rating"]["price_levels"]
|
||||
):
|
||||
return en_translations["sensor"]["price_rating"]["price_levels"][level]
|
||||
return en_translations["sensor"]["current_interval_price_rating"]["price_levels"][level]
|
||||
return level
|
||||
|
||||
def _get_rating_value(self, *, rating_type: str) -> str | None:
|
||||
|
|
@ -1285,7 +1285,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
if not current_interval or "total" not in current_interval:
|
||||
return None
|
||||
|
||||
current_price = float(current_interval["total"])
|
||||
current_interval_price = float(current_interval["total"])
|
||||
current_starts_at = dt_util.parse_datetime(current_interval["startsAt"])
|
||||
if current_starts_at is None:
|
||||
return None
|
||||
|
|
@ -1311,7 +1311,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
|
||||
# Calculate trend with configured thresholds
|
||||
trend_state, diff_pct = calculate_price_trend(
|
||||
current_price, future_avg, threshold_rising=threshold_rising, threshold_falling=threshold_falling
|
||||
current_interval_price, future_avg, threshold_rising=threshold_rising, threshold_falling=threshold_falling
|
||||
)
|
||||
|
||||
# Determine icon color based on trend state
|
||||
|
|
@ -1340,8 +1340,8 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
self._trend_attributes[f"second_half_{hours}h_avg"] = round(later_half_avg * 100, 2)
|
||||
|
||||
# Calculate incremental change: how much does the later half differ from current?
|
||||
if current_price > 0:
|
||||
later_half_diff = ((later_half_avg - current_price) / current_price) * 100
|
||||
if current_interval_price > 0:
|
||||
later_half_diff = ((later_half_avg - current_interval_price) / current_interval_price) * 100
|
||||
self._trend_attributes[f"second_half_{hours}h_diff_from_current_%"] = round(later_half_diff, 1)
|
||||
|
||||
# Cache the trend value for consistency
|
||||
|
|
@ -1711,7 +1711,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
if not self.coordinator.data or not self._value_getter:
|
||||
return None
|
||||
# For price_level, ensure we return the translated value as state
|
||||
if self.entity_description.key == "price_level":
|
||||
if self.entity_description.key == "current_interval_price_level":
|
||||
return self._get_price_level_value()
|
||||
return self._value_getter()
|
||||
except (KeyError, ValueError, TypeError) as ex:
|
||||
|
|
@ -1771,11 +1771,11 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
"""
|
||||
Get icon for current price sensors (dynamic based on price level).
|
||||
|
||||
Only current_price and current_hour_average have dynamic icons.
|
||||
Only current_interval_price and current_hour_average have dynamic icons.
|
||||
Other price sensors (next/previous) use static icons from entity description.
|
||||
"""
|
||||
# Only current price sensors get dynamic icons
|
||||
if key == "current_price":
|
||||
if key == "current_interval_price":
|
||||
level = self._get_price_level_for_sensor(key)
|
||||
if level:
|
||||
return PRICE_LEVEL_CASH_ICON_MAPPING.get(level.upper())
|
||||
|
|
@ -1790,7 +1790,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
def _get_level_sensor_icon(self, key: str, value: Any) -> str | None:
|
||||
"""Get icon for price level sensors."""
|
||||
if key not in [
|
||||
"price_level",
|
||||
"current_interval_price_level",
|
||||
"next_interval_price_level",
|
||||
"previous_interval_price_level",
|
||||
"current_hour_price_level",
|
||||
|
|
@ -1803,7 +1803,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
def _get_rating_sensor_icon(self, key: str, value: Any) -> str | None:
|
||||
"""Get icon for price rating sensors."""
|
||||
if key not in [
|
||||
"price_rating",
|
||||
"current_interval_price_rating",
|
||||
"next_interval_price_rating",
|
||||
"previous_interval_price_rating",
|
||||
"current_hour_price_rating",
|
||||
|
|
@ -1830,7 +1830,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
|
||||
# Map sensor key to interval offset
|
||||
offset_map = {
|
||||
"current_price": 0,
|
||||
"current_interval_price": 0,
|
||||
"next_interval_price": 1,
|
||||
"previous_interval_price": -1,
|
||||
}
|
||||
|
|
@ -1988,8 +1988,8 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
|
||||
# Group sensors by type and delegate to specific handlers
|
||||
if key in [
|
||||
"current_price",
|
||||
"price_level",
|
||||
"current_interval_price",
|
||||
"current_interval_price_level",
|
||||
"next_interval_price",
|
||||
"previous_interval_price",
|
||||
"current_hour_average",
|
||||
|
|
@ -2003,7 +2003,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
"current_hour_price_rating",
|
||||
"next_hour_price_rating",
|
||||
]:
|
||||
self._add_current_price_attributes(attributes)
|
||||
self._add_current_interval_price_attributes(attributes)
|
||||
elif key in [
|
||||
"trailing_price_average",
|
||||
"leading_price_average",
|
||||
|
|
@ -2022,7 +2022,11 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
elif key.endswith("_volatility"):
|
||||
self._add_volatility_attributes(attributes)
|
||||
# For price_level, add the original level as attribute
|
||||
if key == "price_level" and hasattr(self, "_last_price_level") and self._last_price_level is not None:
|
||||
if (
|
||||
key == "current_interval_price_level"
|
||||
and hasattr(self, "_last_price_level")
|
||||
and self._last_price_level is not None
|
||||
):
|
||||
attributes["level_id"] = self._last_price_level
|
||||
except (KeyError, ValueError, TypeError) as ex:
|
||||
self.coordinator.logger.exception(
|
||||
|
|
@ -2035,8 +2039,8 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
else:
|
||||
return attributes if attributes else None
|
||||
|
||||
def _add_current_price_attributes(self, attributes: dict) -> None:
|
||||
"""Add attributes for current price sensors."""
|
||||
def _add_current_interval_price_attributes(self, attributes: dict) -> None:
|
||||
"""Add attributes for current interval price sensors."""
|
||||
key = self.entity_description.key
|
||||
price_info = self.coordinator.data.get("priceInfo", {}) if self.coordinator.data else {}
|
||||
now = dt_util.now()
|
||||
|
|
@ -2085,7 +2089,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
attributes["timestamp"] = current_interval_data["startsAt"] if current_interval_data else None
|
||||
|
||||
# Add icon_color for price sensors (based on their price level)
|
||||
if key in ["current_price", "next_interval_price", "previous_interval_price"]:
|
||||
if key in ["current_interval_price", "next_interval_price", "previous_interval_price"]:
|
||||
# For interval-based price sensors, get level from interval_data
|
||||
if interval_data and "level" in interval_data:
|
||||
level = interval_data["level"]
|
||||
|
|
@ -2115,7 +2119,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
if level_value and isinstance(level_value, str):
|
||||
self._add_price_level_attributes(attributes, level_value.upper())
|
||||
# For current price level sensor
|
||||
elif key == "price_level":
|
||||
elif key == "current_interval_price_level":
|
||||
current_interval_data = self._get_current_interval_data()
|
||||
if current_interval_data and "level" in current_interval_data:
|
||||
self._add_price_level_attributes(attributes, current_interval_data["level"])
|
||||
|
|
@ -2149,7 +2153,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
if rating_value and isinstance(rating_value, str):
|
||||
self._add_price_rating_attributes(attributes, rating_value.upper())
|
||||
# For current price rating sensor
|
||||
elif key == "price_rating":
|
||||
elif key == "current_interval_price_rating":
|
||||
current_interval_data = self._get_current_interval_data()
|
||||
if current_interval_data and "rating_level" in current_interval_data:
|
||||
self._add_price_rating_attributes(attributes, current_interval_data["rating_level"])
|
||||
|
|
@ -2201,7 +2205,7 @@ class TibberPricesSensor(TibberPricesEntity, SensorEntity):
|
|||
latest_timestamp = self._get_data_timestamp()
|
||||
if latest_timestamp:
|
||||
attributes["timestamp"] = latest_timestamp.isoformat()
|
||||
elif key == "price_rating":
|
||||
elif key == "current_interval_price_rating":
|
||||
interval_data = find_price_data_for_interval(price_info, now)
|
||||
attributes["timestamp"] = interval_data["startsAt"] if interval_data else None
|
||||
if hasattr(self, "_last_rating_difference") and self._last_rating_difference is not None:
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
},
|
||||
"submit": "Weiter zu Schritt 2"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"title": "Preisbewertungs-Schwellwerte",
|
||||
"description": "{step_progress}\n\nKonfiguration der Schwellwerte für Preisbewertungsstufen (niedrig/normal/hoch) basierend auf dem Vergleich mit dem gleitenden 24-Stunden-Durchschnitt.",
|
||||
"data": {
|
||||
|
|
@ -183,7 +183,7 @@
|
|||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"name": "Aktueller Strompreis"
|
||||
},
|
||||
"next_interval_price": {
|
||||
|
|
@ -198,7 +198,7 @@
|
|||
"next_hour_average": {
|
||||
"name": "Nächster Stunden-Durchschnittspreis"
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"name": "Aktuelles Preisniveau",
|
||||
"state": {
|
||||
"very_cheap": "Sehr günstig",
|
||||
|
|
@ -284,7 +284,7 @@
|
|||
"leading_price_max": {
|
||||
"name": "Vorlaufender 24h-Höchstpreis"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"name": "Aktuelle Preisbewertung",
|
||||
"state": {
|
||||
"low": "Niedrig",
|
||||
|
|
@ -507,7 +507,7 @@
|
|||
"very_high": "Sehr hoch"
|
||||
}
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"options": {
|
||||
"any": "Beliebig",
|
||||
"very_cheap": "Sehr günstig",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
},
|
||||
"submit": "Next to Step 2"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"title": "Price Rating Thresholds",
|
||||
"description": "{step_progress}\n\nConfigure thresholds for price rating levels (low/normal/high) based on comparison with trailing 24-hour average.",
|
||||
"data": {
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"name": "Current Electricity Price"
|
||||
},
|
||||
"next_interval_price": {
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
"next_hour_average": {
|
||||
"name": "Next Hour Average Price"
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"name": "Current Price Level",
|
||||
"state": {
|
||||
"very_cheap": "Very Cheap",
|
||||
|
|
@ -280,7 +280,7 @@
|
|||
"leading_price_max": {
|
||||
"name": "Leading 24h Maximum Price"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"name": "Current Price Rating",
|
||||
"state": {
|
||||
"low": "Low",
|
||||
|
|
@ -503,7 +503,7 @@
|
|||
"very_high": "Very high"
|
||||
}
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"options": {
|
||||
"any": "Any",
|
||||
"very_cheap": "Very cheap",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
},
|
||||
"submit": "Neste til steg 2"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"title": "Prisvurderingsterskler",
|
||||
"description": "{step_progress}\n\nKonfigurer terskler for prisvurderingsnivåer (lav/normal/høy) basert på sammenligning med 24-timers glidende gjennomsnitt.",
|
||||
"data": {
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"name": "Nåværende strømpris"
|
||||
},
|
||||
"next_interval_price": {
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
"next_hour_average": {
|
||||
"name": "Neste timepris gjennomsnitt"
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"name": "Nåværende prisnivå",
|
||||
"state": {
|
||||
"very_cheap": "Veldig billig",
|
||||
|
|
@ -280,7 +280,7 @@
|
|||
"leading_price_max": {
|
||||
"name": "Fremtidig 24t maksimumspris"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"name": "Nåværende prisvurdering",
|
||||
"state": {
|
||||
"low": "Lav",
|
||||
|
|
@ -503,7 +503,7 @@
|
|||
"very_high": "Svært høy"
|
||||
}
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"options": {
|
||||
"any": "Alle",
|
||||
"very_cheap": "Svært billig",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
},
|
||||
"submit": "Volgende naar stap 2"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"title": "Prijsbeoordelingsdrempels",
|
||||
"description": "{step_progress}\n\nConfigureer drempels voor prijsbeoordelingsniveaus (laag/normaal/hoog) op basis van vergelijking met het voortschrijdend 24-uurs gemiddelde.",
|
||||
"data": {
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"name": "Huidige elektriciteitsprijs"
|
||||
},
|
||||
"next_interval_price": {
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
"next_hour_average": {
|
||||
"name": "Volgend uurgemiddelde prijs"
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"name": "Huidig prijsniveau",
|
||||
"state": {
|
||||
"very_cheap": "Zeer goedkoop",
|
||||
|
|
@ -280,7 +280,7 @@
|
|||
"leading_price_max": {
|
||||
"name": "Vooruitlopend 24u maximumprijs"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"name": "Huidige prijsbeoordeling",
|
||||
"state": {
|
||||
"low": "Laag",
|
||||
|
|
@ -503,7 +503,7 @@
|
|||
"very_high": "Zeer hoog"
|
||||
}
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"options": {
|
||||
"any": "Alle",
|
||||
"very_cheap": "Zeer goedkoop",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
},
|
||||
"submit": "Nästa till steg 2"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"title": "Prisvärderingströsklar",
|
||||
"description": "{step_progress}\n\nKonfigurera trösklar för prisvärderingsnivåer (låg/normal/hög) baserat på jämförelse med rullande 24-timmars genomsnitt.",
|
||||
"data": {
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"current_price": {
|
||||
"current_interval_price": {
|
||||
"name": "Nuvarande elpris"
|
||||
},
|
||||
"next_interval_price": {
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
"next_hour_average": {
|
||||
"name": "Nästa timgenomsnitt pris"
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"name": "Nuvarande prisnivå",
|
||||
"state": {
|
||||
"very_cheap": "Mycket billigt",
|
||||
|
|
@ -280,7 +280,7 @@
|
|||
"leading_price_max": {
|
||||
"name": "Framåtblickande 24t maximumpris"
|
||||
},
|
||||
"price_rating": {
|
||||
"current_interval_price_rating": {
|
||||
"name": "Nuvarande prisvärdering",
|
||||
"state": {
|
||||
"low": "Låg",
|
||||
|
|
@ -503,7 +503,7 @@
|
|||
"very_high": "Mycket hög"
|
||||
}
|
||||
},
|
||||
"price_level": {
|
||||
"current_interval_price_level": {
|
||||
"options": {
|
||||
"any": "Alla",
|
||||
"very_cheap": "Mycket billigt",
|
||||
|
|
|
|||
Loading…
Reference in a new issue