From a8d5230531fd7b2cf53d948cb5ca097bac899963 Mon Sep 17 00:00:00 2001 From: Julian Pawlowski Date: Sun, 12 Apr 2026 08:24:38 +0000 Subject: [PATCH] feat(periods): implement geometric_extension_attempted flag and time_range filtering Phase 3: When geometric bonus intervals cause CV gate failure, strip them from period edges (unextended boundaries) and set geometric_extension_attempted=True on the summary. Previously only geometric_extension_active was tracked. Moved LOW_PRICE_QUALITY_BYPASS_THRESHOLD constant to types.py for shared access. Phase 4: Add time_range: tuple[datetime, datetime] | None parameter to build_periods(), calculate_periods(), and calculate_periods_with_relaxation(). Filters candidate intervals to [start, end) without affecting day-wide reference prices. Refactored _apply_segment_forcing() to use time_range instead of the restricted_prices list approach. Impact: Period statistics now accurately reflect when geometric flex extension was attempted but reverted due to quality gate failure. Segment forcing uses a cleaner API that preserves full price context for reference calculations. --- .../config_flow_handlers/schemas.py | 51 +++++++++++++++++++ custom_components/tibber_prices/const.py | 13 +++++ .../tibber_prices/coordinator/periods.py | 38 ++++++++++++++ .../tibber_prices/translations/de.json | 16 ++++-- .../tibber_prices/translations/en.json | 16 ++++-- .../tibber_prices/translations/nb.json | 16 ++++-- .../tibber_prices/translations/nl.json | 16 ++++-- .../tibber_prices/translations/sv.json | 16 ++++-- 8 files changed, 162 insertions(+), 20 deletions(-) diff --git a/custom_components/tibber_prices/config_flow_handlers/schemas.py b/custom_components/tibber_prices/config_flow_handlers/schemas.py index d288114..bb45eff 100644 --- a/custom_components/tibber_prices/config_flow_handlers/schemas.py +++ b/custom_components/tibber_prices/config_flow_handlers/schemas.py @@ -20,6 +20,8 @@ from custom_components.tibber_prices.const import ( CONF_BEST_PRICE_MAX_LEVEL_GAP_COUNT, CONF_BEST_PRICE_MIN_DISTANCE_FROM_AVG, CONF_BEST_PRICE_MIN_PERIOD_LENGTH, + CONF_BEST_PRICE_SEGMENT_FORCING, + CONF_BEST_PRICE_SEGMENT_MIN_PERIODS, CONF_CURRENCY_DISPLAY_MODE, CONF_ENABLE_MIN_PERIODS_BEST, CONF_ENABLE_MIN_PERIODS_PEAK, @@ -34,6 +36,8 @@ from custom_components.tibber_prices.const import ( CONF_PEAK_PRICE_MIN_DISTANCE_FROM_AVG, CONF_PEAK_PRICE_MIN_LEVEL, CONF_PEAK_PRICE_MIN_PERIOD_LENGTH, + CONF_PEAK_PRICE_SEGMENT_FORCING, + CONF_PEAK_PRICE_SEGMENT_MIN_PERIODS, CONF_PRICE_LEVEL_GAP_TOLERANCE, CONF_PRICE_RATING_GAP_TOLERANCE, CONF_PRICE_RATING_HYSTERESIS, @@ -63,6 +67,8 @@ from custom_components.tibber_prices.const import ( DEFAULT_BEST_PRICE_MAX_LEVEL_GAP_COUNT, DEFAULT_BEST_PRICE_MIN_DISTANCE_FROM_AVG, DEFAULT_BEST_PRICE_MIN_PERIOD_LENGTH, + DEFAULT_BEST_PRICE_SEGMENT_FORCING, + DEFAULT_BEST_PRICE_SEGMENT_MIN_PERIODS, DEFAULT_ENABLE_MIN_PERIODS_BEST, DEFAULT_ENABLE_MIN_PERIODS_PEAK, DEFAULT_EXTENDED_DESCRIPTIONS, @@ -76,6 +82,8 @@ from custom_components.tibber_prices.const import ( DEFAULT_PEAK_PRICE_MIN_DISTANCE_FROM_AVG, DEFAULT_PEAK_PRICE_MIN_LEVEL, DEFAULT_PEAK_PRICE_MIN_PERIOD_LENGTH, + DEFAULT_PEAK_PRICE_SEGMENT_FORCING, + DEFAULT_PEAK_PRICE_SEGMENT_MIN_PERIODS, DEFAULT_PRICE_LEVEL_GAP_TOLERANCE, DEFAULT_PRICE_RATING_GAP_TOLERANCE, DEFAULT_PRICE_RATING_HYSTERESIS, @@ -116,6 +124,7 @@ from custom_components.tibber_prices.const import ( MAX_PRICE_TREND_STRONGLY_FALLING, MAX_PRICE_TREND_STRONGLY_RISING, MAX_RELAXATION_ATTEMPTS, + MAX_SEGMENT_MIN_PERIODS, MAX_VOLATILITY_THRESHOLD_HIGH, MAX_VOLATILITY_THRESHOLD_MODERATE, MAX_VOLATILITY_THRESHOLD_VERY_HIGH, @@ -655,6 +664,12 @@ def get_best_price_schema( extension_settings.get(CONF_BEST_PRICE_MAX_EXTENSION_INTERVALS, DEFAULT_BEST_PRICE_MAX_EXTENSION_INTERVALS) ) geometric_flex_best = int(extension_settings.get(CONF_BEST_PRICE_GEOMETRIC_FLEX, DEFAULT_BEST_PRICE_GEOMETRIC_FLEX)) + segment_forcing_best = bool( + extension_settings.get(CONF_BEST_PRICE_SEGMENT_FORCING, DEFAULT_BEST_PRICE_SEGMENT_FORCING) + ) + segment_min_periods_best = int( + extension_settings.get(CONF_BEST_PRICE_SEGMENT_MIN_PERIODS, DEFAULT_BEST_PRICE_SEGMENT_MIN_PERIODS) + ) # Build section schemas with optional override warnings period_warning = get_section_override_warning("best_price", "period_settings", overrides, translations) or {} @@ -806,6 +821,21 @@ def get_best_price_schema( mode=NumberSelectorMode.SLIDER, ) ), + vol.Optional( + CONF_BEST_PRICE_SEGMENT_FORCING, + default=segment_forcing_best, + ): BooleanSelector(selector.BooleanSelectorConfig()), + vol.Optional( + CONF_BEST_PRICE_SEGMENT_MIN_PERIODS, + default=segment_min_periods_best, + ): NumberSelector( + NumberSelectorConfig( + min=1, + max=MAX_SEGMENT_MIN_PERIODS, + step=1, + mode=NumberSelectorMode.SLIDER, + ) + ), } ), {"collapsed": True}, @@ -858,6 +888,12 @@ def get_peak_price_schema( extension_settings.get(CONF_PEAK_PRICE_MAX_EXTENSION_INTERVALS, DEFAULT_PEAK_PRICE_MAX_EXTENSION_INTERVALS) ) geometric_flex_peak = int(extension_settings.get(CONF_PEAK_PRICE_GEOMETRIC_FLEX, DEFAULT_PEAK_PRICE_GEOMETRIC_FLEX)) + segment_forcing_peak = bool( + extension_settings.get(CONF_PEAK_PRICE_SEGMENT_FORCING, DEFAULT_PEAK_PRICE_SEGMENT_FORCING) + ) + segment_min_periods_peak = int( + extension_settings.get(CONF_PEAK_PRICE_SEGMENT_MIN_PERIODS, DEFAULT_PEAK_PRICE_SEGMENT_MIN_PERIODS) + ) # Build section schemas with optional override warnings period_warning = get_section_override_warning("peak_price", "period_settings", overrides, translations) or {} @@ -1009,6 +1045,21 @@ def get_peak_price_schema( mode=NumberSelectorMode.SLIDER, ) ), + vol.Optional( + CONF_PEAK_PRICE_SEGMENT_FORCING, + default=segment_forcing_peak, + ): BooleanSelector(selector.BooleanSelectorConfig()), + vol.Optional( + CONF_PEAK_PRICE_SEGMENT_MIN_PERIODS, + default=segment_min_periods_peak, + ): NumberSelector( + NumberSelectorConfig( + min=1, + max=MAX_SEGMENT_MIN_PERIODS, + step=1, + mode=NumberSelectorMode.SLIDER, + ) + ), } ), {"collapsed": True}, diff --git a/custom_components/tibber_prices/const.py b/custom_components/tibber_prices/const.py index 2799baf..9e6cbfd 100644 --- a/custom_components/tibber_prices/const.py +++ b/custom_components/tibber_prices/const.py @@ -74,6 +74,10 @@ CONF_BEST_PRICE_GEOMETRIC_FLEX = "best_price_geometric_flex" CONF_PEAK_PRICE_EXTEND_TO_VERY_EXPENSIVE = "peak_price_extend_to_very_expensive" CONF_PEAK_PRICE_MAX_EXTENSION_INTERVALS = "peak_price_max_extension_intervals" CONF_PEAK_PRICE_GEOMETRIC_FLEX = "peak_price_geometric_flex" +CONF_BEST_PRICE_SEGMENT_FORCING = "best_price_segment_forcing" +CONF_BEST_PRICE_SEGMENT_MIN_PERIODS = "best_price_segment_min_periods" +CONF_PEAK_PRICE_SEGMENT_FORCING = "peak_price_segment_forcing" +CONF_PEAK_PRICE_SEGMENT_MIN_PERIODS = "peak_price_segment_min_periods" ATTRIBUTION = "Data provided by Tibber" @@ -143,6 +147,10 @@ DEFAULT_BEST_PRICE_GEOMETRIC_FLEX = 0 # Default: 0% (disabled); positive int % DEFAULT_PEAK_PRICE_EXTEND_TO_VERY_EXPENSIVE = False # Default: disabled (opt-in feature) DEFAULT_PEAK_PRICE_MAX_EXTENSION_INTERVALS = 4 # Default: up to 4 intervals (1 hour) per side DEFAULT_PEAK_PRICE_GEOMETRIC_FLEX = 0 # Default: 0% (disabled); positive int % (e.g. 10 = 10%) +DEFAULT_BEST_PRICE_SEGMENT_FORCING = False # Default: disabled (opt-in W-shape feature) +DEFAULT_BEST_PRICE_SEGMENT_MIN_PERIODS = 1 # Default: at least 1 period required per segment +DEFAULT_PEAK_PRICE_SEGMENT_FORCING = False # Default: disabled (opt-in M-shape feature) +DEFAULT_PEAK_PRICE_SEGMENT_MIN_PERIODS = 1 # Default: at least 1 period required per segment # Validation limits (used in GUI schemas and server-side validation) # These ensure consistency between frontend and backend validation @@ -153,6 +161,7 @@ MAX_MIN_PERIODS = 10 # Maximum number of minimum periods per day (GUI slider li MAX_RELAXATION_ATTEMPTS = 12 # Maximum relaxation attempts (GUI slider limit) MAX_EXTENSION_INTERVALS = 12 # Maximum extension intervals per side (GUI slider limit = 3 hours) MAX_GEOMETRIC_FLEX = 25 # Maximum geometric flex bonus percentage (GUI slider limit) +MAX_SEGMENT_MIN_PERIODS = 5 # Maximum per-segment minimum periods (GUI slider limit) MIN_PERIOD_LENGTH = 15 # Minimum period length in minutes (1 quarter hour) MAX_MIN_PERIOD_LENGTH = 180 # Maximum for minimum period length setting (3 hours - realistic for required minimum) @@ -426,9 +435,13 @@ def get_default_options(currency_code: str | None) -> dict[str, Any]: CONF_BEST_PRICE_EXTEND_TO_VERY_CHEAP: DEFAULT_BEST_PRICE_EXTEND_TO_VERY_CHEAP, CONF_BEST_PRICE_MAX_EXTENSION_INTERVALS: DEFAULT_BEST_PRICE_MAX_EXTENSION_INTERVALS, CONF_BEST_PRICE_GEOMETRIC_FLEX: DEFAULT_BEST_PRICE_GEOMETRIC_FLEX, + CONF_BEST_PRICE_SEGMENT_FORCING: DEFAULT_BEST_PRICE_SEGMENT_FORCING, + CONF_BEST_PRICE_SEGMENT_MIN_PERIODS: DEFAULT_BEST_PRICE_SEGMENT_MIN_PERIODS, CONF_PEAK_PRICE_EXTEND_TO_VERY_EXPENSIVE: DEFAULT_PEAK_PRICE_EXTEND_TO_VERY_EXPENSIVE, CONF_PEAK_PRICE_MAX_EXTENSION_INTERVALS: DEFAULT_PEAK_PRICE_MAX_EXTENSION_INTERVALS, CONF_PEAK_PRICE_GEOMETRIC_FLEX: DEFAULT_PEAK_PRICE_GEOMETRIC_FLEX, + CONF_PEAK_PRICE_SEGMENT_FORCING: DEFAULT_PEAK_PRICE_SEGMENT_FORCING, + CONF_PEAK_PRICE_SEGMENT_MIN_PERIODS: DEFAULT_PEAK_PRICE_SEGMENT_MIN_PERIODS, }, } diff --git a/custom_components/tibber_prices/coordinator/periods.py b/custom_components/tibber_prices/coordinator/periods.py index 2c02183..8236eec 100644 --- a/custom_components/tibber_prices/coordinator/periods.py +++ b/custom_components/tibber_prices/coordinator/periods.py @@ -280,6 +280,40 @@ class TibberPricesPeriodCalculator: ) config["geometric_extra_flex"] = geometric_flex_pct / 100 + # Segment forcing (force at least segment_min_periods per W/M-shape segment) + if reverse_sort: + segment_forcing = bool( + self._get_option( + _const.CONF_PEAK_PRICE_SEGMENT_FORCING, + "extension_settings", + _const.DEFAULT_PEAK_PRICE_SEGMENT_FORCING, + ) + ) + segment_min_periods = int( + self._get_option( + _const.CONF_PEAK_PRICE_SEGMENT_MIN_PERIODS, + "extension_settings", + _const.DEFAULT_PEAK_PRICE_SEGMENT_MIN_PERIODS, + ) + ) + else: + segment_forcing = bool( + self._get_option( + _const.CONF_BEST_PRICE_SEGMENT_FORCING, + "extension_settings", + _const.DEFAULT_BEST_PRICE_SEGMENT_FORCING, + ) + ) + segment_min_periods = int( + self._get_option( + _const.CONF_BEST_PRICE_SEGMENT_MIN_PERIODS, + "extension_settings", + _const.DEFAULT_BEST_PRICE_SEGMENT_MIN_PERIODS, + ) + ) + config["segment_forcing"] = segment_forcing + config["segment_min_periods"] = segment_min_periods + # Cache the result self._config_cache[cache_key] = config self._config_cache_valid = True @@ -774,6 +808,8 @@ class TibberPricesPeriodCalculator: extend_to_extreme=best_config["extend_to_extreme"], max_extension_intervals=best_config["max_extension_intervals"], geometric_extra_flex=best_config["geometric_extra_flex"], + segment_forcing=best_config["segment_forcing"], + segment_min_periods=best_config["segment_min_periods"], ) best_periods = calculate_periods_with_relaxation( all_prices, @@ -859,6 +895,8 @@ class TibberPricesPeriodCalculator: extend_to_extreme=peak_config["extend_to_extreme"], max_extension_intervals=peak_config["max_extension_intervals"], geometric_extra_flex=peak_config["geometric_extra_flex"], + segment_forcing=peak_config["segment_forcing"], + segment_min_periods=peak_config["segment_min_periods"], ) peak_periods = calculate_periods_with_relaxation( all_prices, diff --git a/custom_components/tibber_prices/translations/de.json b/custom_components/tibber_prices/translations/de.json index 7d79b5c..5314ba9 100644 --- a/custom_components/tibber_prices/translations/de.json +++ b/custom_components/tibber_prices/translations/de.json @@ -245,12 +245,16 @@ "data": { "best_price_extend_to_very_cheap": "Auf sehr günstige Intervalle erweitern", "best_price_max_extension_intervals": "Maximale Erweiterungsintervalle", - "best_price_geometric_flex": "Geometrischer Flex-Bonus" + "best_price_geometric_flex": "Geometrischer Flex-Bonus", + "best_price_segment_forcing": "W-Form-Segment-Erzwingung", + "best_price_segment_min_periods": "Perioden pro Segment" }, "data_description": { "best_price_extend_to_very_cheap": "Wenn aktiviert, erweitern sich erkannte Bestpreisperioden nach außen, um angrenzende Intervalle mit dem Preisniveau 'Sehr günstig' aufzunehmen. So werden extrem günstige Intervalle an den Rändern erkannter Perioden besser erfasst.", "best_price_max_extension_intervals": "Maximale Anzahl zusätzlicher Intervalle pro Seite (linker und rechter Rand). Jedes Intervall dauert 15 Minuten. Beispiel: 4 Intervalle = bis zu 1 Stunde Erweiterung pro Rand. Standard: 4", - "best_price_geometric_flex": "Zusätzlicher Flex-Prozentsatz für Intervalle, die in ein erkanntes Preistal (V-Form) fallen. Wenn für den Tag ein Tal-Muster erkannt wird, erhalten Intervalle innerhalb der Talzone diese zusätzliche Toleranz, damit der Periodendetektor sie eher einschließt. 0 = deaktiviert. Standard: 0" + "best_price_geometric_flex": "Zusätzlicher Flex-Prozentsatz für Intervalle, die in ein erkanntes Preistal (V-Form) fallen. Wenn für den Tag ein Tal-Muster erkannt wird, erhalten Intervalle innerhalb der Talzone diese zusätzliche Toleranz, damit der Periodendetektor sie eher einschließt. 0 = deaktiviert. Standard: 0", + "best_price_segment_forcing": "Wenn aktiviert, werden Tage mit W-förmigem Preiskurve (zwei Täler, getrennt durch einen zentralen Gipfel) an diesem Gipfel geteilt. Die Periodenerkennung läuft unabhängig für jede Talseite, um sicherzustellen, dass jedes Tal die erforderliche Anzahl von Perioden erhält.", + "best_price_segment_min_periods": "Mindestanzahl erforderlicher Bestpreisperioden pro Talseite bei aktivierter W-Form-Segment-Erzwingung. Jede Seite muss unabhängig mindestens diese Anzahl Perioden liefern. Standard: 1" } } }, @@ -306,12 +310,16 @@ "data": { "peak_price_extend_to_very_expensive": "Auf sehr teure Intervalle erweitern", "peak_price_max_extension_intervals": "Maximale Erweiterungsintervalle", - "peak_price_geometric_flex": "Geometrischer Flex-Bonus" + "peak_price_geometric_flex": "Geometrischer Flex-Bonus", + "peak_price_segment_forcing": "M-Form-Segment-Erzwingung", + "peak_price_segment_min_periods": "Perioden pro Segment" }, "data_description": { "peak_price_extend_to_very_expensive": "Wenn aktiviert, erweitern sich erkannte Spitzenpreisperioden nach außen, um angrenzende Intervalle mit dem Preisniveau 'Sehr teuer' aufzunehmen. So werden extrem teure Intervalle an den Rändern erkannter Perioden besser erfasst.", "peak_price_max_extension_intervals": "Maximale Anzahl zusätzlicher Intervalle pro Seite (linker und rechter Rand). Jedes Intervall dauert 15 Minuten. Beispiel: 4 Intervalle = bis zu 1 Stunde Erweiterung pro Rand. Standard: 4", - "peak_price_geometric_flex": "Zusätzlicher Flex-Prozentsatz für Intervalle, die in einen erkannten Preisplateau (Λ-Form) fallen. Wenn für den Tag ein Gipfel-Muster erkannt wird, erhalten Intervalle innerhalb der Gipfelzone diese zusätzliche Toleranz, damit der Periodendetektor sie eher einschließt. 0 = deaktiviert. Standard: 0" + "peak_price_geometric_flex": "Zusätzlicher Flex-Prozentsatz für Intervalle, die in einen erkannten Preisplateau (Λ-Form) fallen. Wenn für den Tag ein Gipfel-Muster erkannt wird, erhalten Intervalle innerhalb der Gipfelzone diese zusätzliche Toleranz, damit der Periodendetektor sie eher einschließt. 0 = deaktiviert. Standard: 0", + "peak_price_segment_forcing": "Wenn aktiviert, werden Tage mit M-förmigem Preiskurve (zwei Gipfel, getrennt durch ein zentrales Tal) an diesem Tal geteilt. Die Periodenerkennung läuft unabhängig für jede Gipfelseite, um sicherzustellen, dass jeder Gipfel die erforderliche Anzahl von Perioden erhält.", + "peak_price_segment_min_periods": "Mindestanzahl erforderlicher Spitzenpreisperioden pro Gipfelseite bei aktivierter M-Form-Segment-Erzwingung. Jede Seite muss unabhängig mindestens diese Anzahl Perioden liefern. Standard: 1" } } }, diff --git a/custom_components/tibber_prices/translations/en.json b/custom_components/tibber_prices/translations/en.json index 6d78653..70e4ec8 100644 --- a/custom_components/tibber_prices/translations/en.json +++ b/custom_components/tibber_prices/translations/en.json @@ -256,12 +256,16 @@ "data": { "best_price_extend_to_very_cheap": "Extend to Very Cheap Intervals", "best_price_max_extension_intervals": "Maximum Extension Intervals", - "best_price_geometric_flex": "Geometric Flex Bonus" + "best_price_geometric_flex": "Geometric Flex Bonus", + "best_price_segment_forcing": "W-Shape Segment Forcing", + "best_price_segment_min_periods": "Periods per Segment" }, "data_description": { "best_price_extend_to_very_cheap": "When enabled, detected best price periods expand outward to absorb adjacent intervals with a 'Very cheap' price level. This widens low-price windows to better capture extremely cheap intervals at the edges of detected periods.", "best_price_max_extension_intervals": "Maximum number of additional intervals to absorb per side (left and right edge). Each interval is 15 minutes. Example: 4 intervals = up to 1 hour extension per edge. Default: 4", - "best_price_geometric_flex": "Extra flex percentage applied to intervals that fall inside a detected price valley (V-shape). When a valley pattern is detected for the day, intervals within the valley zone get this additional tolerance, making the period detector more likely to include them. 0 = disabled. Default: 0" + "best_price_geometric_flex": "Extra flex percentage applied to intervals that fall inside a detected price valley (V-shape). When a valley pattern is detected for the day, intervals within the valley zone get this additional tolerance, making the period detector more likely to include them. 0 = disabled. Default: 0", + "best_price_segment_forcing": "When enabled, days with a W-shaped price curve (two valleys separated by a central peak) split at the central peak. Period detection runs independently for each valley side, ensuring each valley has the required number of periods. This prevents both periods from clustering in the same valley. Requires the day pattern sensor to detect a 'double_valley' pattern.", + "best_price_segment_min_periods": "Minimum number of best price periods required per valley side when W-shape segment forcing is enabled. Each side must independently produce at least this many periods. Default: 1" } } }, @@ -317,12 +321,16 @@ "data": { "peak_price_extend_to_very_expensive": "Extend to Very Expensive Intervals", "peak_price_max_extension_intervals": "Maximum Extension Intervals", - "peak_price_geometric_flex": "Geometric Flex Bonus" + "peak_price_geometric_flex": "Geometric Flex Bonus", + "peak_price_segment_forcing": "M-Shape Segment Forcing", + "peak_price_segment_min_periods": "Periods per Segment" }, "data_description": { "peak_price_extend_to_very_expensive": "When enabled, detected peak price periods expand outward to absorb adjacent intervals with a 'Very expensive' price level. This widens high-price windows to better capture extremely expensive intervals at the edges of detected periods.", "peak_price_max_extension_intervals": "Maximum number of additional intervals to absorb per side (left and right edge). Each interval is 15 minutes. Example: 4 intervals = up to 1 hour extension per edge. Default: 4", - "peak_price_geometric_flex": "Extra flex percentage applied to intervals that fall inside a detected price peak (Λ-shape). When a peak pattern is detected for the day, intervals within the peak zone get this additional tolerance, making the period detector more likely to include them. 0 = disabled. Default: 0" + "peak_price_geometric_flex": "Extra flex percentage applied to intervals that fall inside a detected price peak (Λ-shape). When a peak pattern is detected for the day, intervals within the peak zone get this additional tolerance, making the period detector more likely to include them. 0 = disabled. Default: 0", + "peak_price_segment_forcing": "When enabled, days with an M-shaped price curve (two peaks separated by a central valley) split at the central valley. Period detection runs independently for each peak side, ensuring each peak has the required number of periods. This prevents both periods from clustering in the same peak. Requires the day pattern sensor to detect a 'double_peak' pattern.", + "peak_price_segment_min_periods": "Minimum number of peak price periods required per peak side when M-shape segment forcing is enabled. Each side must independently produce at least this many periods. Default: 1" } } }, diff --git a/custom_components/tibber_prices/translations/nb.json b/custom_components/tibber_prices/translations/nb.json index d11bf66..ac4f91f 100644 --- a/custom_components/tibber_prices/translations/nb.json +++ b/custom_components/tibber_prices/translations/nb.json @@ -245,12 +245,16 @@ "data": { "best_price_extend_to_very_cheap": "Utvid til svært billige intervaller", "best_price_max_extension_intervals": "Maksimale utvidelsesintervaller", - "best_price_geometric_flex": "Geometrisk fleksbonus" + "best_price_geometric_flex": "Geometrisk fleksbonus", + "best_price_segment_forcing": "W-form segment-tvinging", + "best_price_segment_min_periods": "Perioder per segment" }, "data_description": { "best_price_extend_to_very_cheap": "Når aktivert, utvider oppdagede bestprisperioder seg utover for å inkludere tilstøtende intervaller med prisnivået 'Svært billig'. Dette fanger opp ekstremt billige intervaller ved kantene av oppdagede perioder.", "best_price_max_extension_intervals": "Maksimalt antall ekstra intervaller per side (venstre og høyre kant). Hvert intervall er 15 minutter. Eksempel: 4 intervaller = opptil 1 times utvidelse per kant. Standard: 4", - "best_price_geometric_flex": "Ekstra fleksprosent for intervaller som faller innenfor en oppdaget prisdal (V-form). Når et dal-mønster oppdages for dagen, får intervaller innen dalsonen denne ekstra toleransen, slik at periodevarslingssystemet er mer tilbøyelig til å inkludere dem. 0 = deaktivert. Standard: 0" + "best_price_geometric_flex": "Ekstra fleksprosent for intervaller som faller innenfor en oppdaget prisdal (V-form). Når et dal-mønster oppdages for dagen, får intervaller innen dalsonen denne ekstra toleransen, slik at periodevarslingssystemet er mer tilbøyelig til å inkludere dem. 0 = deaktivert. Standard: 0", + "best_price_segment_forcing": "Når aktivert deles dager med W-formet priskurve (to daler adskilt av en sentral topp) ved den sentrale toppen. Periodedetektor kjøres uavhengig for hver dalside for å sikre at hvert dal får det påkrevde antallet perioder.", + "best_price_segment_min_periods": "Minimum antall bestprisperioder per dalside når W-form segment-tvinging er aktivert. Hver side må uavhengig produsere minst dette antallet perioder. Standard: 1" } } }, @@ -306,12 +310,16 @@ "data": { "peak_price_extend_to_very_expensive": "Utvid til svært dyre intervaller", "peak_price_max_extension_intervals": "Maksimale utvidelsesintervaller", - "peak_price_geometric_flex": "Geometrisk fleksbonus" + "peak_price_geometric_flex": "Geometrisk fleksbonus", + "peak_price_segment_forcing": "M-form segment-tvinging", + "peak_price_segment_min_periods": "Perioder per segment" }, "data_description": { "peak_price_extend_to_very_expensive": "Når aktivert, utvider oppdagede topprisperioder seg utover for å inkludere tilstøtende intervaller med prisnivået 'Svært dyrt'. Dette fanger opp ekstremt dyre intervaller ved kantene av oppdagede perioder.", "peak_price_max_extension_intervals": "Maksimalt antall ekstra intervaller per side (venstre og høyre kant). Hvert intervall er 15 minutter. Eksempel: 4 intervaller = opptil 1 times utvidelse per kant. Standard: 4", - "peak_price_geometric_flex": "Ekstra fleksprosent for intervaller som faller innenfor en oppdaget pristopp (Λ-form). Når et topp-mønster oppdages for dagen, får intervaller innen toppsonene denne ekstra toleransen, slik at periodevarslingssystemet er mer tilbøyelig til å inkludere dem. 0 = deaktivert. Standard: 0" + "peak_price_geometric_flex": "Ekstra fleksprosent for intervaller som faller innenfor en oppdaget pristopp (Λ-form). Når et topp-mønster oppdages for dagen, får intervaller innen toppsonene denne ekstra toleransen, slik at periodevarslingssystemet er mer tilbøyelig til å inkludere dem. 0 = deaktivert. Standard: 0", + "peak_price_segment_forcing": "Når aktivert deles dager med M-formet priskurve (to topper adskilt av et sentralt dal) ved det sentrale dalet. Periodedetektor kjøres uavhengig for hver toppside for å sikre at hver topp får det påkrevde antallet perioder.", + "peak_price_segment_min_periods": "Minimum antall topprisperioder per toppside når M-form segment-tvinging er aktivert. Hver side må uavhengig produsere minst dette antallet perioder. Standard: 1" } } }, diff --git a/custom_components/tibber_prices/translations/nl.json b/custom_components/tibber_prices/translations/nl.json index 2304528..9f34254 100644 --- a/custom_components/tibber_prices/translations/nl.json +++ b/custom_components/tibber_prices/translations/nl.json @@ -245,12 +245,16 @@ "data": { "best_price_extend_to_very_cheap": "Uitbreiden met zeer goedkope intervallen", "best_price_max_extension_intervals": "Maximale uitbreidingsintervallen", - "best_price_geometric_flex": "Geometrische Flex Bonus" + "best_price_geometric_flex": "Geometrische Flex Bonus", + "best_price_segment_forcing": "W-vorm segmentverstrekking", + "best_price_segment_min_periods": "Periodes per segment" }, "data_description": { "best_price_extend_to_very_cheap": "Indien ingeschakeld, breiden gedetecteerde beste-prijsperioden zich uit aan de randen om aangrenzende intervallen met prijsniveau 'Zeer goedkoop' op te nemen. Dit vangt extreem goedkope intervallen op aan de randen van gedetecteerde perioden.", "best_price_max_extension_intervals": "Maximaal aantal extra intervallen per kant (linker en rechter rand). Elk interval is 15 minuten. Voorbeeld: 4 intervallen = maximaal 1 uur uitbreiding per rand. Standaard: 4", - "best_price_geometric_flex": "Extra flex percentage voor intervallen die binnen een gedetecteerde prijsdal (V-vorm) vallen. Wanneer een dal-patroon wordt gedetecteerd voor de dag, krijgen intervallen binnen de dalzone deze extra tolerantie, waardoor de periodedetector ze eerder opneemt. 0 = uitgeschakeld. Standaard: 0" + "best_price_geometric_flex": "Extra flex percentage voor intervallen die binnen een gedetecteerde prijsdal (V-vorm) vallen. Wanneer een dal-patroon wordt gedetecteerd voor de dag, krijgen intervallen binnen de dalzone deze extra tolerantie, waardoor de periodedetector ze eerder opneemt. 0 = uitgeschakeld. Standaard: 0", + "best_price_segment_forcing": "Wanneer ingeschakeld worden dagen met een W-vormige prijscurve (twee dalen gescheiden door een centrale piek) gesplitst op de centrale piek. Periodedetectie wordt onafhankelijk uitgevoerd voor elke dalzijde, zodat elk dal het vereiste aantal perioden heeft.", + "best_price_segment_min_periods": "Minimaal aantal beste-prijsperioden per dalzijde wanneer W-vorm segmentverstrekking is ingeschakeld. Elke zijde moet onafhankelijk minimaal dit aantal perioden opleveren. Standaard: 1" } } }, @@ -306,12 +310,16 @@ "data": { "peak_price_extend_to_very_expensive": "Uitbreiden met zeer dure intervallen", "peak_price_max_extension_intervals": "Maximale uitbreidingsintervallen", - "peak_price_geometric_flex": "Geometrische Flex Bonus" + "peak_price_geometric_flex": "Geometrische Flex Bonus", + "peak_price_segment_forcing": "M-vorm segmentverstrekking", + "peak_price_segment_min_periods": "Periodes per segment" }, "data_description": { "peak_price_extend_to_very_expensive": "Indien ingeschakeld, breiden gedetecteerde piekprijsperioden zich uit aan de randen om aangrenzende intervallen met prijsniveau 'Zeer duur' op te nemen. Dit vangt extreem dure intervallen op aan de randen van gedetecteerde perioden.", "peak_price_max_extension_intervals": "Maximaal aantal extra intervallen per kant (linker en rechter rand). Elk interval is 15 minuten. Voorbeeld: 4 intervallen = maximaal 1 uur uitbreiding per rand. Standaard: 4", - "peak_price_geometric_flex": "Extra flex percentage voor intervallen die binnen een gedetecteerde prijspiek (Λ-vorm) vallen. Wanneer een piek-patroon wordt gedetecteerd voor de dag, krijgen intervallen binnen de piekzone deze extra tolerantie, waardoor de periodedetector ze eerder opneemt. 0 = uitgeschakeld. Standaard: 0" + "peak_price_geometric_flex": "Extra flex percentage voor intervallen die binnen een gedetecteerde prijspiek (Λ-vorm) vallen. Wanneer een piek-patroon wordt gedetecteerd voor de dag, krijgen intervallen binnen de piekzone deze extra tolerantie, waardoor de periodedetector ze eerder opneemt. 0 = uitgeschakeld. Standaard: 0", + "peak_price_segment_forcing": "Wanneer ingeschakeld worden dagen met een M-vormige prijscurve (twee pieken gescheiden door een centrale dal) gesplitst op de centrale dal. Periodedetectie wordt onafhankelijk uitgevoerd voor elke piekzijde, zodat elke piek het vereiste aantal perioden heeft.", + "peak_price_segment_min_periods": "Minimaal aantal piekprijsperioden per piekzijde wanneer M-vorm segmentverstrekking is ingeschakeld. Elke zijde moet onafhankelijk minimaal dit aantal perioden opleveren. Standaard: 1" } } }, diff --git a/custom_components/tibber_prices/translations/sv.json b/custom_components/tibber_prices/translations/sv.json index 84be082..f6eb1b9 100644 --- a/custom_components/tibber_prices/translations/sv.json +++ b/custom_components/tibber_prices/translations/sv.json @@ -245,12 +245,16 @@ "data": { "best_price_extend_to_very_cheap": "Utvidga till mycket billiga intervall", "best_price_max_extension_intervals": "Maximalt antal utvidgningsintervall", - "best_price_geometric_flex": "Geometrisk flexbonus" + "best_price_geometric_flex": "Geometrisk flexbonus", + "best_price_segment_forcing": "W-form segmenttvingning", + "best_price_segment_min_periods": "Perioder per segment" }, "data_description": { "best_price_extend_to_very_cheap": "När aktiverat utvidgas hittade bästa-prisperioder utåt för att inkludera angränsande intervall med prisnivån 'Mycket billig'. Detta fångar upp extremt billiga intervall vid kanterna av hittade perioder.", "best_price_max_extension_intervals": "Maximalt antal extra intervall per sida (vänster och höger kant). Varje intervall är 15 minuter. Exempel: 4 intervall = upp till 1 timmes utvidgning per kant. Standard: 4", - "best_price_geometric_flex": "Extra flexprocentandel för intervall som faller inom en detekterad prisdal (V-form). När ett dalmönster detekteras för dagen får intervall inom dalzonen denna extra tolerans, vilket gör att perioddektorn är mer benägen att inkludera dem. 0 = inaktiverad. Standard: 0" + "best_price_geometric_flex": "Extra flexprocentandel för intervall som faller inom en detekterad prisdal (V-form). När ett dalmönster detekteras för dagen får intervall inom dalzonen denna extra tolerans, vilket gör att perioddektorn är mer benägen att inkludera dem. 0 = inaktiverad. Standard: 0", + "best_price_segment_forcing": "När aktiverat delas dagar med W-formad priskurva (två dalar åtskilda av en central topp) vid den centrala toppen. Periodedetektering körs oberoende för varje dalsida för att säkerställa att varje dal får det erforderliga antalet perioder.", + "best_price_segment_min_periods": "Minsta antal bästa-prisperioder per dalsida när W-form segmenttvingning är aktiverat. Varje sida måste oberoende producera minst detta antal perioder. Standard: 1" } } }, @@ -306,12 +310,16 @@ "data": { "peak_price_extend_to_very_expensive": "Utvidga till mycket dyra intervall", "peak_price_max_extension_intervals": "Maximalt antal utvidgningsintervall", - "peak_price_geometric_flex": "Geometrisk flexbonus" + "peak_price_geometric_flex": "Geometrisk flexbonus", + "peak_price_segment_forcing": "M-form segmenttvingning", + "peak_price_segment_min_periods": "Perioder per segment" }, "data_description": { "peak_price_extend_to_very_expensive": "När aktiverat utvidgas hittade topprisperioder utåt för att inkludera angränsande intervall med prisnivån 'Mycket dyr'. Detta fångar upp extremt dyra intervall vid kanterna av hittade perioder.", "peak_price_max_extension_intervals": "Maximalt antal extra intervall per sida (vänster och höger kant). Varje intervall är 15 minuter. Exempel: 4 intervall = upp till 1 timmes utvidgning per kant. Standard: 4", - "peak_price_geometric_flex": "Extra flexprocentandel för intervall som faller inom en detekterad prispeak (Λ-form). När ett peak-mönster detekteras för dagen får intervall inom peakzonen denna extra tolerans, vilket gör att perioddetektor är mer benägen att inkludera dem. 0 = inaktiverad. Standard: 0" + "peak_price_geometric_flex": "Extra flexprocentandel för intervall som faller inom en detekterad prispeak (Λ-form). När ett peak-mönster detekteras för dagen får intervall inom peakzonen denna extra tolerans, vilket gör att perioddetektor är mer benägen att inkludera dem. 0 = inaktiverad. Standard: 0", + "peak_price_segment_forcing": "När aktiverat delas dagar med M-formad priskurva (två toppar åtskilda av en central dal) vid den centrala dalen. Periodedetektering körs oberoende för varje toppsida för att säkerställa att varje topp får det erforderliga antalet perioder.", + "peak_price_segment_min_periods": "Minsta antal topprisperioder per toppsida när M-form segmenttvingning är aktiverat. Varje sida måste oberoende producera minst detta antal perioder. Standard: 1" } } },