mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-30 21:33:39 +00:00
BREAKING CHANGE: Period overlap resolution now merges adjacent/overlapping periods
instead of marking them as extensions. This simplifies automation logic and provides
clearer period boundaries for users.
Previous Behavior:
- Adjacent periods created by relaxation were marked with is_extension=true
- Multiple short periods instead of one continuous period
- Complex logic needed to determine actual period length in automations
New Behavior:
- Adjacent/overlapping periods are merged into single continuous periods
- Newer period's relaxation attributes override older period's
- Simpler automation: one period = one continuous time window
Changes:
- Period Overlap Resolution (new file: period_overlap.py):
* Added merge_adjacent_periods() to combine periods and preserve attributes
* Rewrote resolve_period_overlaps() with simplified merge logic
* Removed split_period_by_overlaps() (no longer needed)
* Removed is_extension marking logic
* Removed unused parameters: min_period_length, baseline_periods
- Relaxation Strategy (relaxation.py):
* Removed all is_extension filtering from period counting
* Simplified standalone counting to just len(periods)
* Changed from period_merging import to period_overlap import
* Added MAX_FLEX_HARD_LIMIT constant (0.50)
* Improved debug logging for merged periods
- Code Quality:
* Fixed all remaining linter errors (N806, PLR2004, PLR0912)
* Extracted magic values to module-level constants:
- FLEX_SCALING_THRESHOLD = 0.20
- SCALE_FACTOR_WARNING_THRESHOLD = 0.8
- MAX_FLEX_HARD_LIMIT = 0.50
* Added appropriate noqa comments for unavoidable patterns
- Configuration (from previous work in this session):
* Removed CONF_RELAXATION_STEP_BEST, CONF_RELAXATION_STEP_PEAK
* Hard-coded 3% relaxation increment for reliability
* Optimized defaults: RELAXATION_ATTEMPTS 8→11, ENABLE_MIN_PERIODS False→True,
MIN_PERIODS undefined→2
* Removed relaxation_step UI fields from config flow
* Updated all 5 translation files
- Documentation:
* Updated period_handlers/__init__.py: period_merging → period_overlap
* No user-facing docs changes needed (already described continuous periods)
Rationale - Period Merging:
User experience was complicated by fragmented periods:
- Automations had to check multiple adjacent periods
- Binary sensors showed ON/OFF transitions within same cheap time
- No clear way to determine actual continuous period length
With merging:
- One continuous cheap time = one period
- Binary sensor clearly ON during entire period
- Attributes show merge history via merged_from dict
- Relaxation info preserved from newest/highest flex period
Rationale - Hard-Coded Relaxation Increment:
The configurable relaxation_step parameter proved problematic:
- High base flex + high step → rapid explosion (40% base + 10% step → 100% in 6 steps)
- Users don't understand the multiplicative nature
- 3% increment provides optimal balance: 11 attempts to reach 50% hard cap
Impact:
- Existing installations: Periods may appear longer (merged instead of split)
- Automations benefit from simpler logic (no is_extension checks needed)
- Custom relaxation_step values will use new 3% increment
- Users may need to adjust relaxation_attempts if they relied on high step sizes
883 lines
42 KiB
JSON
883 lines
42 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.",
|
||
"invalid_yaml_syntax": "Invalid YAML syntax. Please check indentation, colons, and special characters.",
|
||
"invalid_yaml_structure": "YAML must be a dictionary/object (key: value pairs), not a list or plain text.",
|
||
"service_call_failed": "Service call validation failed: {error_detail}"
|
||
},
|
||
"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"
|
||
},
|
||
"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": {
|
||
"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_max_level": "Price Level Filter (Optional)",
|
||
"best_price_max_level_gap_count": "Level Filter Gap Tolerance",
|
||
"enable_min_periods_best": "Try to Achieve Minimum Period Count",
|
||
"min_periods_best": "Minimum Periods Required",
|
||
"relaxation_attempts_best": "Relaxation Attempts"
|
||
},
|
||
"data_description": {
|
||
"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.",
|
||
"best_price_max_level_gap_count": "Maximum number of consecutive intervals allowed that deviate by exactly one level step from the required level. For example: with 'Cheap' filter and gap count 1, a sequence 'CHEAP, CHEAP, NORMAL, CHEAP' is accepted (NORMAL is one step above CHEAP). This prevents periods from being split by occasional level deviations. Default: 0 (strict filtering, no tolerance).",
|
||
"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_attempts_best": "How many flex levels (attempts) to try before giving up. Each attempt runs all filter combinations at the new flex level. More attempts increase the chance of finding additional periods at the cost of longer processing time."
|
||
},
|
||
"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_level": "Price Level Filter (Optional)",
|
||
"peak_price_max_level_gap_count": "Level Filter Gap Tolerance",
|
||
"enable_min_periods_peak": "Try to Achieve Minimum Period Count",
|
||
"min_periods_peak": "Minimum Periods Required",
|
||
"relaxation_attempts_peak": "Relaxation Attempts"
|
||
},
|
||
"data_description": {
|
||
"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.",
|
||
"peak_price_max_level_gap_count": "Maximum number of consecutive intervals allowed that deviate by exactly one level step from the required level. For example: with 'Expensive' filter and gap count 2, a sequence 'EXPENSIVE, NORMAL, NORMAL, EXPENSIVE' is accepted (NORMAL is one step below EXPENSIVE). This prevents periods from being split by occasional level deviations. Default: 0 (strict filtering, no tolerance).",
|
||
"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_attempts_peak": "How many flex levels (attempts) to try before giving up. Each attempt runs all filter combinations at the new flex level. More attempts increase the chance of finding additional peak periods at the cost of longer processing time."
|
||
},
|
||
"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": "Next to Step 7"
|
||
},
|
||
"chart_data_export": {
|
||
"title": "Chart Data Export",
|
||
"description": "{step_progress}\n\n**⚠️ This step is optional** and only relevant if you plan to enable the **Chart Data Export** diagnostic sensor.\n\n**⚠️ IMPORTANT: Legacy Feature**\nThis sensor exists for **backwards compatibility** with tools that can only read entity attributes (e.g., older ApexCharts versions). **For new integrations, use the `tibber_prices.get_chartdata` service directly** - it's more flexible, efficient, and the recommended Home Assistant approach.\n\n**When to use this sensor:**\n- ✅ Your dashboard tool can ONLY read attributes (not call services)\n- ✅ You need static data that updates automatically\n- ❌ NOT recommended for new integrations that support service calls\n\n**What is this sensor?**\nThis sensor calls the `tibber_prices.get_chartdata` service with your custom YAML parameters and exposes the result as entity attributes.\n\n**How to use it:**\n1. **Complete this configuration** (or leave empty for service defaults)\n2. Go to **Settings → Devices & Services → Tibber Prices**\n3. Click on your home → Find **'Chart Data Export'** in the **Diagnostic** section\n4. Enable the sensor - it will automatically call the service with your configuration\n5. Use the sensor's attributes in your dashboard cards\n\n**Configuration guide:**\n1. Test your service call in **Developer Tools → Services → `tibber_prices.get_chartdata`**\n2. Copy the YAML from the `data:` section (without `entry_id`)\n3. Paste it below (use **Shift+Enter** or **Ctrl+Enter** for new lines, NOT just Enter)\n\n**Example YAML:**\n```yaml\nday:\n - today\n - tomorrow\ninclude_level: true\ninclude_rating_level: true\n```\n\n**Note:** Leave empty to use service defaults or skip this feature if you don't need the sensor.",
|
||
"data": {
|
||
"chart_data_config": "Service Configuration (YAML)"
|
||
},
|
||
"data_description": {
|
||
"chart_data_config": "YAML configuration for get_chartdata service. Supported parameters: day (list of yesterday/today/tomorrow), resolution (interval/hourly), output_format, include_level, include_rating_level, include_average, and many more. See service documentation for full list. Leave empty to use service defaults (today, interval resolution, array of objects)."
|
||
},
|
||
"submit": "Complete Configuration"
|
||
},
|
||
"volatility": {
|
||
"title": "Price Volatility Thresholds",
|
||
"description": "{step_progress}\n\nConfigure thresholds for volatility classification. Volatility measures relative price variation using the coefficient of variation (CV = standard deviation / mean × 100%). These thresholds are percentage values that work across all price levels.\n\nUsed by:\n• Volatility sensors (classification)\n• Trend sensors (adaptive threshold adjustment: <moderate = more sensitive, ≥high = less sensitive)",
|
||
"data": {
|
||
"volatility_threshold_moderate": "Moderate Threshold (CV ≥ this %, e.g., 15)",
|
||
"volatility_threshold_high": "High Threshold (CV ≥ this %, e.g., 30)",
|
||
"volatility_threshold_very_high": "Very High Threshold (CV ≥ this %, e.g., 50)"
|
||
},
|
||
"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_interval_price": {
|
||
"name": "Current Electricity Price"
|
||
},
|
||
"current_interval_price_major": {
|
||
"name": "Current Electricity Price (Energy Dashboard)"
|
||
},
|
||
"next_interval_price": {
|
||
"name": "Next Electricity Price"
|
||
},
|
||
"previous_interval_price": {
|
||
"name": "Previous Electricity Price"
|
||
},
|
||
"current_hour_average_price": {
|
||
"name": "⌀ Hourly Price Current"
|
||
},
|
||
"next_hour_average_price": {
|
||
"name": "⌀ Hourly Price Next"
|
||
},
|
||
"current_interval_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": "⌀ Price Today"
|
||
},
|
||
"lowest_price_tomorrow": {
|
||
"name": "Tomorrow's Lowest Price"
|
||
},
|
||
"highest_price_tomorrow": {
|
||
"name": "Tomorrow's Highest Price"
|
||
},
|
||
"average_price_tomorrow": {
|
||
"name": "⌀ Price Tomorrow"
|
||
},
|
||
"yesterday_price_level": {
|
||
"name": "Yesterday's Price Level",
|
||
"state": {
|
||
"very_cheap": "Very Cheap",
|
||
"cheap": "Cheap",
|
||
"normal": "Normal",
|
||
"expensive": "Expensive",
|
||
"very_expensive": "Very Expensive"
|
||
}
|
||
},
|
||
"today_price_level": {
|
||
"name": "Today's Price Level",
|
||
"state": {
|
||
"very_cheap": "Very Cheap",
|
||
"cheap": "Cheap",
|
||
"normal": "Normal",
|
||
"expensive": "Expensive",
|
||
"very_expensive": "Very Expensive"
|
||
}
|
||
},
|
||
"tomorrow_price_level": {
|
||
"name": "Tomorrow's Price Level",
|
||
"state": {
|
||
"very_cheap": "Very Cheap",
|
||
"cheap": "Cheap",
|
||
"normal": "Normal",
|
||
"expensive": "Expensive",
|
||
"very_expensive": "Very Expensive"
|
||
}
|
||
},
|
||
"yesterday_price_rating": {
|
||
"name": "Yesterday's Price Rating",
|
||
"state": {
|
||
"low": "Low",
|
||
"normal": "Normal",
|
||
"high": "High"
|
||
}
|
||
},
|
||
"today_price_rating": {
|
||
"name": "Today's Price Rating",
|
||
"state": {
|
||
"low": "Low",
|
||
"normal": "Normal",
|
||
"high": "High"
|
||
}
|
||
},
|
||
"tomorrow_price_rating": {
|
||
"name": "Tomorrow's Price Rating",
|
||
"state": {
|
||
"low": "Low",
|
||
"normal": "Normal",
|
||
"high": "High"
|
||
}
|
||
},
|
||
"trailing_price_average": {
|
||
"name": "⌀ Price Trailing 24h"
|
||
},
|
||
"leading_price_average": {
|
||
"name": "⌀ Price Leading 24h"
|
||
},
|
||
"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"
|
||
},
|
||
"current_interval_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": "⌀ Price Next 1h"
|
||
},
|
||
"next_avg_2h": {
|
||
"name": "⌀ Price Next 2h"
|
||
},
|
||
"next_avg_3h": {
|
||
"name": "⌀ Price Next 3h"
|
||
},
|
||
"next_avg_4h": {
|
||
"name": "⌀ Price Next 4h"
|
||
},
|
||
"next_avg_5h": {
|
||
"name": "⌀ Price Next 5h"
|
||
},
|
||
"next_avg_6h": {
|
||
"name": "⌀ Price Next 6h"
|
||
},
|
||
"next_avg_8h": {
|
||
"name": "⌀ Price Next 8h"
|
||
},
|
||
"next_avg_12h": {
|
||
"name": "⌀ Price Next 12h"
|
||
},
|
||
"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"
|
||
}
|
||
},
|
||
"current_price_trend": {
|
||
"name": "Current Price Trend",
|
||
"state": {
|
||
"rising": "Rising",
|
||
"falling": "Falling",
|
||
"stable": "Stable"
|
||
}
|
||
},
|
||
"next_price_trend_change": {
|
||
"name": "Next Price Trend Change"
|
||
},
|
||
"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"
|
||
}
|
||
},
|
||
"best_price_end_time": {
|
||
"name": "Best Price End"
|
||
},
|
||
"best_price_period_duration": {
|
||
"name": "Best Price Duration"
|
||
},
|
||
"best_price_remaining_minutes": {
|
||
"name": "Best Price Remaining Time"
|
||
},
|
||
"best_price_progress": {
|
||
"name": "Best Price Progress"
|
||
},
|
||
"best_price_next_start_time": {
|
||
"name": "Best Price Start"
|
||
},
|
||
"best_price_next_in_minutes": {
|
||
"name": "Best Price Starts In"
|
||
},
|
||
"peak_price_end_time": {
|
||
"name": "Peak Price End"
|
||
},
|
||
"peak_price_period_duration": {
|
||
"name": "Peak Price Duration"
|
||
},
|
||
"peak_price_remaining_minutes": {
|
||
"name": "Peak Price Remaining Time"
|
||
},
|
||
"peak_price_progress": {
|
||
"name": "Peak Price Progress"
|
||
},
|
||
"peak_price_next_start_time": {
|
||
"name": "Peak Price Start"
|
||
},
|
||
"peak_price_next_in_minutes": {
|
||
"name": "Peak Price Starts In"
|
||
},
|
||
"price_forecast": {
|
||
"name": "Price Forecast"
|
||
},
|
||
"home_type": {
|
||
"name": "Home Type",
|
||
"state": {
|
||
"apartment": "Apartment",
|
||
"rowhouse": "Rowhouse",
|
||
"house": "House",
|
||
"cottage": "Cottage"
|
||
}
|
||
},
|
||
"home_size": {
|
||
"name": "Home Size"
|
||
},
|
||
"main_fuse_size": {
|
||
"name": "Main Fuse Size"
|
||
},
|
||
"number_of_residents": {
|
||
"name": "Number of Residents"
|
||
},
|
||
"primary_heating_source": {
|
||
"name": "Primary Heating Source",
|
||
"state": {
|
||
"air2air_heatpump": "Air-to-Air Heat Pump",
|
||
"air2water_heatpump": "Air-to-Water Heat Pump",
|
||
"boiler": "Boiler",
|
||
"central_heating": "Central Heating",
|
||
"district_heating": "District Heating",
|
||
"district": "District Heating",
|
||
"electric_boiler": "Electric Boiler",
|
||
"electricity": "Electricity",
|
||
"floor": "Floor Heating",
|
||
"gas": "Gas",
|
||
"ground_heatpump": "Ground Heat Pump",
|
||
"ground": "Ground Heat Pump",
|
||
"oil": "Oil",
|
||
"other": "Other",
|
||
"waste": "Waste Heat"
|
||
}
|
||
},
|
||
"grid_company": {
|
||
"name": "Grid Company"
|
||
},
|
||
"grid_area_code": {
|
||
"name": "Grid Area Code"
|
||
},
|
||
"price_area_code": {
|
||
"name": "Price Area Code"
|
||
},
|
||
"consumption_ean": {
|
||
"name": "Consumption EAN"
|
||
},
|
||
"production_ean": {
|
||
"name": "Production EAN"
|
||
},
|
||
"energy_tax_type": {
|
||
"name": "Energy Tax Type"
|
||
},
|
||
"vat_type": {
|
||
"name": "VAT Type"
|
||
},
|
||
"estimated_annual_consumption": {
|
||
"name": "Estimated Annual Consumption"
|
||
},
|
||
"subscription_status": {
|
||
"name": "Subscription Status",
|
||
"state": {
|
||
"running": "Running",
|
||
"ended": "Ended",
|
||
"pending": "Pending",
|
||
"unknown": "Unknown"
|
||
}
|
||
},
|
||
"chart_data_export": {
|
||
"name": "Chart Data Export",
|
||
"state": {
|
||
"pending": "Pending",
|
||
"ready": "Ready",
|
||
"error": "Error"
|
||
}
|
||
}
|
||
},
|
||
"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"
|
||
},
|
||
"has_ventilation_system": {
|
||
"name": "Has Ventilation System"
|
||
},
|
||
"realtime_consumption_enabled": {
|
||
"name": "Realtime Consumption Enabled"
|
||
}
|
||
}
|
||
},
|
||
"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": {
|
||
"get_apexcharts_yaml": {
|
||
"name": "Get ApexCharts Card YAML",
|
||
"description": "Returns a ready-to-copy YAML snippet for an ApexCharts card visualizing Tibber Prices for the selected day. Use this to easily add a pre-configured chart to your dashboard. The YAML will use the get_chartdata service for data.",
|
||
"fields": {
|
||
"entry_id": {
|
||
"name": "Entry ID",
|
||
"description": "The config entry ID for the Tibber integration."
|
||
},
|
||
"day": {
|
||
"name": "Day",
|
||
"description": "Which day to visualize (yesterday, today, or tomorrow)."
|
||
},
|
||
"level_type": {
|
||
"name": "Level Type",
|
||
"description": "Select which price level classification to visualize: 'rating_level' (low/normal/high based on your configured thresholds) or 'level' (Tibber API levels: very cheap/cheap/normal/expensive/very expensive)."
|
||
}
|
||
}
|
||
},
|
||
"get_chartdata": {
|
||
"name": "Get Chart Data",
|
||
"description": "Returns price data in a simple chart-friendly format compatible with the Tibber Core integration output structure. Perfect for use with popular chart cards like ha-price-timeline-card, ApexCharts Card, Plotly Graph Card, Mini Graph Card, or the built-in History Graph Card. Field names and data structure can be customized to match your specific chart requirements.",
|
||
"fields": {
|
||
"entry_id": {
|
||
"name": "Entry ID",
|
||
"description": "The config entry ID for the Tibber integration."
|
||
},
|
||
"day": {
|
||
"name": "Day",
|
||
"description": "Which day(s) to fetch prices for. You can select multiple days. If not specified, returns all available data (today + tomorrow if available)."
|
||
},
|
||
"resolution": {
|
||
"name": "Resolution",
|
||
"description": "Time resolution for the returned data. Options: 'interval' (default, 15-minute intervals, 96 points per day), 'hourly' (hourly averages, 24 points per day)."
|
||
},
|
||
"output_format": {
|
||
"name": "Output Format",
|
||
"description": "Output format for the returned data. Options: 'array_of_objects' (default, array of objects with customizable field names), 'array_of_arrays' (array of [timestamp, price] arrays with trailing null point for stepline charts)."
|
||
},
|
||
"array_fields": {
|
||
"name": "Array Fields (Array of Arrays only)",
|
||
"description": "[ONLY FOR Array of Arrays FORMAT] Define which fields to include. Use field names in curly braces, separated by commas. Available fields: start_time, price_per_kwh, level, rating_level, average. Fields will be automatically enabled even if include_* options are not set. Leave empty for default (timestamp and price only)."
|
||
},
|
||
"minor_currency": {
|
||
"name": "Minor Currency",
|
||
"description": "Return prices in minor currency units (cents for EUR, øre for NOK/SEK) instead of major currency units. Disabled by default."
|
||
},
|
||
"round_decimals": {
|
||
"name": "Round Decimals",
|
||
"description": "Number of decimal places to round prices to (0-10). If not specified, uses default precision (4 decimals for major currency, 2 for minor currency)."
|
||
},
|
||
"include_level": {
|
||
"name": "Include Level (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Include the Tibber price level field (VERY_CHEAP, CHEAP, NORMAL, EXPENSIVE, VERY_EXPENSIVE) in each data point."
|
||
},
|
||
"include_rating_level": {
|
||
"name": "Include Rating Level (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Include the calculated rating level field (LOW, NORMAL, HIGH) based on your configured thresholds in each data point."
|
||
},
|
||
"include_average": {
|
||
"name": "Include Average (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Include the daily average price in each data point for comparison."
|
||
},
|
||
"level_filter": {
|
||
"name": "Level Filter",
|
||
"description": "Filter intervals to include only specific Tibber price levels (VERY_CHEAP, CHEAP, NORMAL, EXPENSIVE, VERY_EXPENSIVE). If not specified, all levels are included."
|
||
},
|
||
"rating_level_filter": {
|
||
"name": "Rating Level Filter",
|
||
"description": "Filter intervals to include only specific rating levels (LOW, NORMAL, HIGH). If not specified, all rating levels are included."
|
||
},
|
||
"period_filter": {
|
||
"name": "Period Filter",
|
||
"description": "Filter intervals to include only those within Best Price or Peak Price periods. Options: 'best_price' (only intervals in Best Price periods), 'peak_price' (only intervals in Peak Price periods). If not specified, all intervals are included. This uses the precomputed period data from binary sensors."
|
||
},
|
||
"insert_nulls": {
|
||
"name": "Insert NULL Values",
|
||
"description": "Control NULL value insertion for filtered data. 'none' (default): No NULL values, only matching intervals. 'segments': Add NULL points at segment boundaries for clean gaps in charts (recommended for stepline charts). 'all': Insert NULL for all timestamps where filter doesn't match (useful for continuous time series visualization)."
|
||
},
|
||
"add_trailing_null": {
|
||
"name": "Add Trailing Null Point",
|
||
"description": "[BOTH FORMATS] Add a final data point with null values (except timestamp) at the end. Some chart libraries need this to prevent extrapolation/interpolation to the viewport edge when using stepline rendering. Leave disabled unless your chart requires it."
|
||
},
|
||
"start_time_field": {
|
||
"name": "Start Time Field Name (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Custom name for the start time field in the output. Defaults to 'start_time' if not specified."
|
||
},
|
||
"end_time_field": {
|
||
"name": "End Time Field Name (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Custom name for the end time field in the output. Defaults to 'end_time' if not specified. Only used with period_filter."
|
||
},
|
||
"price_field": {
|
||
"name": "Price Field Name (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Custom name for the price field in the output. Defaults to 'price_per_kwh' if not specified."
|
||
},
|
||
"level_field": {
|
||
"name": "Level Field Name (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Custom name for the level field in the output. Defaults to 'level' if not specified. Only used when include_level is enabled."
|
||
},
|
||
"rating_level_field": {
|
||
"name": "Rating Level Field Name (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Custom name for the rating_level field in the output. Defaults to 'rating_level' if not specified. Only used when include_rating_level is enabled."
|
||
},
|
||
"average_field": {
|
||
"name": "Average Field Name (Array of Objects only)",
|
||
"description": "[ONLY FOR Array of Objects FORMAT] Custom name for the average field in the output. Defaults to 'average' if not specified. Only used when include_average is enabled."
|
||
},
|
||
"data_key": {
|
||
"name": "Data Key (both formats)",
|
||
"description": "[BOTH FORMATS] Custom name for the top-level data key in the response. Defaults to 'data' if not specified. For ApexCharts compatibility with Array of Arrays, use 'points'."
|
||
}
|
||
}
|
||
},
|
||
"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": {
|
||
"day": {
|
||
"options": {
|
||
"yesterday": "Yesterday",
|
||
"today": "Today",
|
||
"tomorrow": "Tomorrow"
|
||
}
|
||
},
|
||
"resolution": {
|
||
"options": {
|
||
"interval": "Interval (15 min)",
|
||
"hourly": "Hourly"
|
||
}
|
||
},
|
||
"output_format": {
|
||
"options": {
|
||
"array_of_objects": "Array of Objects",
|
||
"array_of_arrays": "Array of Arrays"
|
||
}
|
||
},
|
||
"level_type": {
|
||
"options": {
|
||
"rating_level": "Rating Level (low/normal/high)",
|
||
"level": "Tibber Level (very cheap to very expensive)"
|
||
}
|
||
},
|
||
"level_filter": {
|
||
"options": {
|
||
"very_cheap": "Very cheap",
|
||
"cheap": "Cheap",
|
||
"normal": "Normal",
|
||
"expensive": "Expensive",
|
||
"very_expensive": "Very expensive"
|
||
}
|
||
},
|
||
"rating_level_filter": {
|
||
"options": {
|
||
"low": "Low",
|
||
"normal": "Normal",
|
||
"high": "High"
|
||
}
|
||
},
|
||
"insert_nulls": {
|
||
"options": {
|
||
"none": "None",
|
||
"segments": "Segments",
|
||
"all": "All"
|
||
}
|
||
},
|
||
"period_filter": {
|
||
"options": {
|
||
"best_price": "Best Price Periods",
|
||
"peak_price": "Peak Price Periods"
|
||
}
|
||
},
|
||
"volatility": {
|
||
"options": {
|
||
"low": "Low",
|
||
"moderate": "Moderate",
|
||
"high": "High",
|
||
"very_high": "Very high"
|
||
}
|
||
},
|
||
"current_interval_price_level": {
|
||
"options": {
|
||
"any": "Any",
|
||
"very_cheap": "Very cheap",
|
||
"cheap": "Cheap",
|
||
"normal": "Normal",
|
||
"expensive": "Expensive",
|
||
"very_expensive": "Very expensive"
|
||
}
|
||
}
|
||
},
|
||
"title": "Tibber Price Information & Ratings"
|
||
}
|