mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
Implemented multi-phase filter relaxation system to ensure minimum number
of best-price and peak-price periods are found, even on days with unusual
price patterns.
New configuration options per period type (best/peak):
- enable_min_periods_{best|peak}: Toggle feature on/off
- min_periods_{best|peak}: Target number of periods (default: 2)
- relaxation_step_{best|peak}: Step size for threshold increase (default: 25%)
Relaxation phases (applied sequentially until target reached):
1. Flex threshold increase (up to 4 steps, e.g., 15% → 18.75% → 22.5% → ...)
2. Volatility filter bypass + continued flex increase
3. All filters off + continued flex increase
Changes to period calculation:
- New calculate_periods_with_relaxation() wrapper function
- filter_periods_by_volatility() now applies post-calculation filtering
- _resolve_period_overlaps() merges baseline + relaxed periods intelligently
- Relaxed periods marked with relaxation_level, relaxation_threshold_* attributes
- Overlap detection prevents double-counting same intervals
Binary sensor attribute ordering improvements:
- Added helper methods for consistent attribute priority
- Relaxation info grouped in priority 6 (after detail attributes)
- Only shown when period was actually relaxed (relaxation_active=true)
Translation updates:
- Added UI labels + descriptions for 6 new config options (all 5 languages)
- Explained relaxation concept with examples in data_description fields
- Clarified volatility filter now applies per-period, not per-day
Impact: Users can configure integration to guarantee minimum number of
periods per day. System automatically relaxes filters when needed while
preserving baseline periods found with strict filters. Particularly useful
for automation reliability on days with flat pricing or unusual patterns.
Fixes edge case where no periods were found despite prices varying enough
for meaningful optimization decisions.
514 lines
23 KiB
JSON
514 lines
23 KiB
JSON
{
|
|
"config": {
|
|
"step": {
|
|
"user": {
|
|
"description": "Set up Tibber Price Information & Ratings.\n\nTo generate an API access token, visit https://developer.tibber.com.",
|
|
"data": {
|
|
"access_token": "API access token"
|
|
},
|
|
"submit": "Validate Token"
|
|
},
|
|
"select_home": {
|
|
"description": "Select a home to fetch price information and ratings.",
|
|
"data": {
|
|
"home_id": "Home"
|
|
},
|
|
"title": "Pick a Home",
|
|
"submit": "Select Home"
|
|
},
|
|
"finish": {
|
|
"description": "Select a home to fetch price information and ratings.",
|
|
"data": {
|
|
"home_id": "Home ID"
|
|
},
|
|
"title": "Pick a home",
|
|
"submit": "Select Home"
|
|
},
|
|
"reauth_confirm": {
|
|
"title": "Reauthenticate Tibber Price Integration",
|
|
"description": "The access token for Tibber is no longer valid. Please enter a new API access token to continue using this integration.\n\nTo generate a new API access token, visit https://developer.tibber.com.",
|
|
"data": {
|
|
"access_token": "API access token"
|
|
},
|
|
"submit": "Update Token"
|
|
}
|
|
},
|
|
"error": {
|
|
"auth": "The Tibber Access Token is invalid.",
|
|
"connection": "Unable to connect to Tibber. Please check your internet connection.",
|
|
"unknown": "Unexpected error",
|
|
"cannot_connect": "Failed to connect",
|
|
"invalid_access_token": "Invalid access token",
|
|
"missing_homes": "The new access token does not have access to all configured homes. Please use an access token that has access to the same Tibber homes."
|
|
},
|
|
"abort": {
|
|
"already_configured": "Integration is already configured",
|
|
"entry_not_found": "Tibber configuration entry not found.",
|
|
"setup_complete": "Setup complete! You can change additional options for Tibber Prices in the integration's options after closing this dialog.",
|
|
"reauth_successful": "Reauthentication successful. The integration has been updated with the new access token."
|
|
}
|
|
},
|
|
"common": {
|
|
"step_progress": "Step {step_num} of {total_steps}"
|
|
},
|
|
"config_subentries": {
|
|
"home": {
|
|
"initiate_flow": {
|
|
"user": "Add Tibber Home"
|
|
},
|
|
"title": "Add Tibber Home",
|
|
"step": {
|
|
"user": {
|
|
"title": "Add Tibber Home",
|
|
"description": "Select a home to add to your Tibber integration.\n\n**Note:** After adding this home, you can add additional homes from the integration's context menu by selecting \"Add Tibber Home\".",
|
|
"data": {
|
|
"home_id": "Home"
|
|
}
|
|
}
|
|
},
|
|
"error": {
|
|
"api_error": "Failed to fetch homes from Tibber API"
|
|
},
|
|
"abort": {
|
|
"no_parent_entry": "Parent entry not found",
|
|
"no_access_token": "No access token available",
|
|
"home_not_found": "Selected home not found",
|
|
"api_error": "Failed to fetch homes from Tibber API",
|
|
"no_available_homes": "No additional homes available to add. All homes from your Tibber account have already been added."
|
|
}
|
|
}
|
|
},
|
|
"options": {
|
|
"step": {
|
|
"init": {
|
|
"title": "General Settings",
|
|
"description": "{step_progress}\n\nConfigure general settings for Tibber Price Information & Ratings.\n\nUser: {user_login}",
|
|
"data": {
|
|
"extended_descriptions": "Show extended descriptions in entity attributes"
|
|
},
|
|
"submit": "Next to Step 2"
|
|
},
|
|
"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": {
|
|
"price_rating_threshold_low": "Low Rating Threshold (below trailing average)",
|
|
"price_rating_threshold_high": "High Rating Threshold (above trailing average)"
|
|
},
|
|
"submit": "Next to Step 3"
|
|
},
|
|
"best_price": {
|
|
"title": "Best Price Period Settings",
|
|
"description": "{step_progress}\n\nConfigure settings for the Best Price Period binary sensor. This sensor is active during periods with the lowest electricity prices.",
|
|
"data": {
|
|
"best_price_min_period_length": "Minimum Period Length",
|
|
"best_price_flex": "Flexibility: Maximum above minimum price",
|
|
"best_price_min_distance_from_avg": "Minimum Distance: Required below daily average",
|
|
"best_price_min_volatility": "Minimum Volatility Filter",
|
|
"best_price_max_level": "Price Level Filter (Optional)",
|
|
"enable_min_periods_best": "Try to Achieve Minimum Period Count",
|
|
"min_periods_best": "Minimum Periods Required",
|
|
"relaxation_step_best": "Filter Relaxation Step Size"
|
|
},
|
|
"data_description": {
|
|
"best_price_min_volatility": "Only show best price periods when the period's internal price volatility (spread within the period) meets or exceeds this level. Default: 'Low' (show periods with any volatility level) - allows finding cheap periods even if prices are stable. Select 'Moderate'/'High' to only show periods with significant price variations, which may indicate more dynamic pricing opportunities.",
|
|
"best_price_max_level": "Only show best price periods if they contain intervals with price levels ≤ selected value. For example, selecting 'Cheap' means the period must have at least one 'VERY_CHEAP' or 'CHEAP' interval. This ensures 'best price' periods are not just relatively cheap for the day, but actually cheap in absolute terms. Select 'Any' to show best prices regardless of their absolute price level.",
|
|
"enable_min_periods_best": "When enabled, filters will be gradually relaxed if not enough periods are found. This attempts to reach the desired minimum number of periods, which may include less optimal time windows as best-price periods.",
|
|
"min_periods_best": "Minimum number of best price periods to aim for per day. Filters will be relaxed step-by-step to try achieving this count. Only active when 'Try to Achieve Minimum Period Count' is enabled. Default: 1",
|
|
"relaxation_step_best": "Percentage of the original flexibility threshold to add per relaxation step. For example: with 15% flexibility and 25% step size, filters will try 15%, 18.75%, 22.5%, etc. Higher values mean faster relaxation but less precision."
|
|
},
|
|
"submit": "Next to Step 5"
|
|
},
|
|
"peak_price": {
|
|
"title": "Peak Price Period Settings",
|
|
"description": "{step_progress}\n\nConfigure settings for the Peak Price Period binary sensor. This sensor is active during periods with the highest electricity prices.",
|
|
"data": {
|
|
"peak_price_min_period_length": "Minimum Period Length",
|
|
"peak_price_flex": "Flexibility: Maximum below maximum price (negative value)",
|
|
"peak_price_min_distance_from_avg": "Minimum Distance: Required above daily average",
|
|
"peak_price_min_volatility": "Minimum Volatility Filter",
|
|
"peak_price_min_level": "Price Level Filter (Optional)",
|
|
"enable_min_periods_peak": "Try to Achieve Minimum Period Count",
|
|
"min_periods_peak": "Minimum Periods Required",
|
|
"relaxation_step_peak": "Filter Relaxation Step Size"
|
|
},
|
|
"data_description": {
|
|
"peak_price_min_volatility": "Only show peak price periods when the period's internal price volatility (spread within the period) meets or exceeds this level. Default: 'Low' (show periods with any volatility level) - allows identifying expensive periods even if prices are stable. Select 'Moderate'/'High' to only show periods with significant price variations, which may indicate more urgent need to avoid these times.",
|
|
"peak_price_min_level": "Only show peak price periods if they contain intervals with price levels ≥ selected value. For example, selecting 'Expensive' means the period must have at least one 'EXPENSIVE' or 'VERY_EXPENSIVE' interval. This ensures 'peak price' periods are not just relatively expensive for the day, but actually expensive in absolute terms. Select 'Any' to show peak prices regardless of their absolute price level.",
|
|
"enable_min_periods_peak": "When enabled, filters will be gradually relaxed if not enough periods are found. This attempts to reach the desired minimum number of periods to ensure you're warned about expensive periods even on days with unusual price patterns.",
|
|
"min_periods_peak": "Minimum number of peak price periods to aim for per day. Filters will be relaxed step-by-step to try achieving this count. Only active when 'Try to Achieve Minimum Period Count' is enabled. Default: 1",
|
|
"relaxation_step_peak": "Percentage of the original flexibility threshold to add per relaxation step. For example: with -15% flexibility and 25% step size, filters will try -15%, -18.75%, -22.5%, etc. Higher values mean faster relaxation but less precision."
|
|
},
|
|
"submit": "Next to Step 6"
|
|
},
|
|
"price_trend": {
|
|
"title": "Price Trend Thresholds",
|
|
"description": "{step_progress}\n\nConfigure thresholds for price trend sensors. These sensors compare the current price with the average of the next N hours to determine if prices are rising, falling, or stable.",
|
|
"data": {
|
|
"price_trend_threshold_rising": "Rising Threshold (above current price)",
|
|
"price_trend_threshold_falling": "Falling Threshold (below current price, negative value)"
|
|
},
|
|
"submit": "Complete Configuration"
|
|
},
|
|
"volatility": {
|
|
"title": "Price Volatility Thresholds",
|
|
"description": "{step_progress}\n\nConfigure thresholds for volatility classification. Volatility measures price variation (spread between min/max) in minor currency units. These thresholds are used by volatility sensors and period filters.",
|
|
"data": {
|
|
"volatility_threshold_moderate": "Moderate Threshold (spread ≥ this value)",
|
|
"volatility_threshold_high": "High Threshold (spread ≥ this value)",
|
|
"volatility_threshold_very_high": "Very High Threshold (spread ≥ this value)"
|
|
},
|
|
"submit": "Next to Step 4"
|
|
}
|
|
},
|
|
"error": {
|
|
"auth": "The Tibber Access Token is invalid.",
|
|
"connection": "Unable to connect to Tibber. Please check your internet connection.",
|
|
"unknown": "An unexpected error occurred. Please check the logs for details.",
|
|
"cannot_connect": "Failed to connect",
|
|
"invalid_access_token": "Invalid access token",
|
|
"different_home": "The access token is not valid for the home ID this integration is configured for."
|
|
},
|
|
"abort": {
|
|
"entry_not_found": "Tibber configuration entry not found."
|
|
}
|
|
},
|
|
"entity": {
|
|
"sensor": {
|
|
"current_price": {
|
|
"name": "Current Electricity Price"
|
|
},
|
|
"next_interval_price": {
|
|
"name": "Next Price"
|
|
},
|
|
"previous_interval_price": {
|
|
"name": "Previous Electricity Price"
|
|
},
|
|
"current_hour_average": {
|
|
"name": "Current Hour Average Price"
|
|
},
|
|
"next_hour_average": {
|
|
"name": "Next Hour Average Price"
|
|
},
|
|
"price_level": {
|
|
"name": "Current Price Level",
|
|
"state": {
|
|
"very_cheap": "Very Cheap",
|
|
"cheap": "Cheap",
|
|
"normal": "Normal",
|
|
"expensive": "Expensive",
|
|
"very_expensive": "Very Expensive"
|
|
}
|
|
},
|
|
"next_interval_price_level": {
|
|
"name": "Next Price Level",
|
|
"state": {
|
|
"very_cheap": "Very Cheap",
|
|
"cheap": "Cheap",
|
|
"normal": "Normal",
|
|
"expensive": "Expensive",
|
|
"very_expensive": "Very Expensive"
|
|
}
|
|
},
|
|
"previous_interval_price_level": {
|
|
"name": "Previous Price Level",
|
|
"state": {
|
|
"very_cheap": "Very Cheap",
|
|
"cheap": "Cheap",
|
|
"normal": "Normal",
|
|
"expensive": "Expensive",
|
|
"very_expensive": "Very Expensive"
|
|
}
|
|
},
|
|
"current_hour_price_level": {
|
|
"name": "Current Hour Price Level",
|
|
"state": {
|
|
"very_cheap": "Very Cheap",
|
|
"cheap": "Cheap",
|
|
"normal": "Normal",
|
|
"expensive": "Expensive",
|
|
"very_expensive": "Very Expensive"
|
|
}
|
|
},
|
|
"next_hour_price_level": {
|
|
"name": "Next Hour Price Level",
|
|
"state": {
|
|
"very_cheap": "Very Cheap",
|
|
"cheap": "Cheap",
|
|
"normal": "Normal",
|
|
"expensive": "Expensive",
|
|
"very_expensive": "Very Expensive"
|
|
}
|
|
},
|
|
"lowest_price_today": {
|
|
"name": "Today's Lowest Price"
|
|
},
|
|
"highest_price_today": {
|
|
"name": "Today's Highest Price"
|
|
},
|
|
"average_price_today": {
|
|
"name": "Today's Average Price"
|
|
},
|
|
"lowest_price_tomorrow": {
|
|
"name": "Tomorrow's Lowest Price"
|
|
},
|
|
"highest_price_tomorrow": {
|
|
"name": "Tomorrow's Highest Price"
|
|
},
|
|
"average_price_tomorrow": {
|
|
"name": "Tomorrow's Average Price"
|
|
},
|
|
"trailing_price_average": {
|
|
"name": "Trailing 24h Average Price"
|
|
},
|
|
"leading_price_average": {
|
|
"name": "Leading 24h Average Price"
|
|
},
|
|
"trailing_price_min": {
|
|
"name": "Trailing 24h Minimum Price"
|
|
},
|
|
"trailing_price_max": {
|
|
"name": "Trailing 24h Maximum Price"
|
|
},
|
|
"leading_price_min": {
|
|
"name": "Leading 24h Minimum Price"
|
|
},
|
|
"leading_price_max": {
|
|
"name": "Leading 24h Maximum Price"
|
|
},
|
|
"price_rating": {
|
|
"name": "Current Price Rating",
|
|
"state": {
|
|
"low": "Low",
|
|
"normal": "Normal",
|
|
"high": "High"
|
|
}
|
|
},
|
|
"next_interval_price_rating": {
|
|
"name": "Next Price Rating",
|
|
"state": {
|
|
"low": "Low",
|
|
"normal": "Normal",
|
|
"high": "High"
|
|
}
|
|
},
|
|
"previous_interval_price_rating": {
|
|
"name": "Previous Price Rating",
|
|
"state": {
|
|
"low": "Low",
|
|
"normal": "Normal",
|
|
"high": "High"
|
|
}
|
|
},
|
|
"current_hour_price_rating": {
|
|
"name": "Current Hour Price Rating",
|
|
"state": {
|
|
"low": "Low",
|
|
"normal": "Normal",
|
|
"high": "High"
|
|
}
|
|
},
|
|
"next_hour_price_rating": {
|
|
"name": "Next Hour Price Rating",
|
|
"state": {
|
|
"low": "Low",
|
|
"normal": "Normal",
|
|
"high": "High"
|
|
}
|
|
},
|
|
"next_avg_1h": {
|
|
"name": "Next 1h Average Price"
|
|
},
|
|
"next_avg_2h": {
|
|
"name": "Next 2h Average Price"
|
|
},
|
|
"next_avg_3h": {
|
|
"name": "Next 3h Average Price"
|
|
},
|
|
"next_avg_4h": {
|
|
"name": "Next 4h Average Price"
|
|
},
|
|
"next_avg_5h": {
|
|
"name": "Next 5h Average Price"
|
|
},
|
|
"next_avg_6h": {
|
|
"name": "Next 6h Average Price"
|
|
},
|
|
"next_avg_8h": {
|
|
"name": "Next 8h Average Price"
|
|
},
|
|
"next_avg_12h": {
|
|
"name": "Next 12h Average Price"
|
|
},
|
|
"price_trend_1h": {
|
|
"name": "Price Trend (1h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"price_trend_2h": {
|
|
"name": "Price Trend (2h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"price_trend_3h": {
|
|
"name": "Price Trend (3h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"price_trend_4h": {
|
|
"name": "Price Trend (4h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"price_trend_5h": {
|
|
"name": "Price Trend (5h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"price_trend_6h": {
|
|
"name": "Price Trend (6h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"price_trend_8h": {
|
|
"name": "Price Trend (8h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"price_trend_12h": {
|
|
"name": "Price Trend (12h)",
|
|
"state": {
|
|
"rising": "Rising",
|
|
"falling": "Falling",
|
|
"stable": "Stable"
|
|
}
|
|
},
|
|
"daily_rating": {
|
|
"name": "Daily Price Rating"
|
|
},
|
|
"monthly_rating": {
|
|
"name": "Monthly Price Rating"
|
|
},
|
|
"data_timestamp": {
|
|
"name": "Price Data Expiration"
|
|
},
|
|
"today_volatility": {
|
|
"name": "Today's Price Volatility",
|
|
"state": {
|
|
"low": "Low",
|
|
"moderate": "Moderate",
|
|
"high": "High",
|
|
"very_high": "Very High"
|
|
}
|
|
},
|
|
"tomorrow_volatility": {
|
|
"name": "Tomorrow's Price Volatility",
|
|
"state": {
|
|
"low": "Low",
|
|
"moderate": "Moderate",
|
|
"high": "High",
|
|
"very_high": "Very High"
|
|
}
|
|
},
|
|
"next_24h_volatility": {
|
|
"name": "Next 24h Price Volatility",
|
|
"state": {
|
|
"low": "Low",
|
|
"moderate": "Moderate",
|
|
"high": "High",
|
|
"very_high": "Very High"
|
|
}
|
|
},
|
|
"today_tomorrow_volatility": {
|
|
"name": "Today+Tomorrow Price Volatility",
|
|
"state": {
|
|
"low": "Low",
|
|
"moderate": "Moderate",
|
|
"high": "High",
|
|
"very_high": "Very High"
|
|
}
|
|
},
|
|
"price_forecast": {
|
|
"name": "Price Forecast"
|
|
}
|
|
},
|
|
"binary_sensor": {
|
|
"peak_price_period": {
|
|
"name": "Peak Price Period"
|
|
},
|
|
"best_price_period": {
|
|
"name": "Best Price Period"
|
|
},
|
|
"connection": {
|
|
"name": "Tibber API Connection"
|
|
},
|
|
"tomorrow_data_available": {
|
|
"name": "Tomorrow's Data Available"
|
|
}
|
|
}
|
|
},
|
|
"issues": {
|
|
"new_homes_available": {
|
|
"title": "New Tibber homes detected",
|
|
"description": "We detected {count} new home(s) on your Tibber account: {homes}. You can add them to Home Assistant through the Tibber integration configuration."
|
|
},
|
|
"homes_removed": {
|
|
"title": "Tibber homes removed",
|
|
"description": "We detected that {count} home(s) have been removed from your Tibber account: {homes}. Please review your Tibber integration configuration."
|
|
}
|
|
},
|
|
"services": {
|
|
"refresh_user_data": {
|
|
"name": "Refresh User Data",
|
|
"description": "Forces a refresh of the user data (homes, profile information) from the Tibber API. This can be useful after making changes to your Tibber account or when troubleshooting connectivity issues.",
|
|
"fields": {
|
|
"entry_id": {
|
|
"name": "Entry ID",
|
|
"description": "The config entry ID for the Tibber integration."
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"selector": {
|
|
"volatility": {
|
|
"options": {
|
|
"low": "Low",
|
|
"moderate": "Moderate",
|
|
"high": "High",
|
|
"very_high": "Very high"
|
|
}
|
|
},
|
|
"price_level": {
|
|
"options": {
|
|
"any": "Any",
|
|
"very_cheap": "Very cheap",
|
|
"cheap": "Cheap",
|
|
"normal": "Normal",
|
|
"expensive": "Expensive",
|
|
"very_expensive": "Very expensive"
|
|
}
|
|
}
|
|
},
|
|
"title": "Tibber Price Information & Ratings"
|
|
}
|