"use strict";(globalThis.webpackChunkdocs_split_user=globalThis.webpackChunkdocs_split_user||[]).push([[406],{8171:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>o,contentTitle:()=>a,default:()=>h,frontMatter:()=>l,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"period-calculation","title":"Period Calculation","description":"Learn how Best Price and Peak Price periods work, and how to configure them for your needs.","source":"@site/docs/period-calculation.md","sourceDirName":".","slug":"/period-calculation","permalink":"/hass.tibber_prices/user/period-calculation","draft":false,"unlisted":false,"editUrl":"https://github.com/jpawlowski/hass.tibber_prices/tree/main/docs/user/docs/period-calculation.md","tags":[],"version":"current","lastUpdatedAt":1764985026000,"frontMatter":{},"sidebar":"tutorialSidebar","previous":{"title":"Sensors","permalink":"/hass.tibber_prices/user/sensors"},"next":{"title":"Dynamic Icons","permalink":"/hass.tibber_prices/user/dynamic-icons"}}');var r=n(4848),t=n(8453);const l={},a="Period Calculation",o={},d=[{value:"Table of Contents",id:"table-of-contents",level:2},{value:"Quick Start",id:"quick-start",level:2},{value:"What Are Price Periods?",id:"what-are-price-periods",level:3},{value:"Default Behavior",id:"default-behavior",level:3},{value:"Example Timeline",id:"example-timeline",level:3},{value:"How It Works",id:"how-it-works",level:2},{value:"The Basic Idea",id:"the-basic-idea",level:3},{value:"Step-by-Step Process",id:"step-by-step-process",level:3},{value:"1. Define the Search Range (Flexibility)",id:"1-define-the-search-range-flexibility",level:4},{value:"2. Ensure Quality (Distance from Average)",id:"2-ensure-quality-distance-from-average",level:4},{value:"3. Check Duration",id:"3-check-duration",level:4},{value:"4. Apply Optional Filters",id:"4-apply-optional-filters",level:4},{value:"5. Automatic Price Spike Smoothing",id:"5-automatic-price-spike-smoothing",level:4},{value:"Visual Example",id:"visual-example",level:3},{value:"Configuration Guide",id:"configuration-guide",level:2},{value:"Basic Settings",id:"basic-settings",level:3},{value:"Flexibility",id:"flexibility",level:4},{value:"Minimum Period Length",id:"minimum-period-length",level:4},{value:"Distance from Average",id:"distance-from-average",level:4},{value:"Optional Filters",id:"optional-filters",level:3},{value:"Level Filter (Absolute Quality)",id:"level-filter-absolute-quality",level:4},{value:"Gap Tolerance (for Level Filter)",id:"gap-tolerance-for-level-filter",level:4},{value:"Tweaking Strategy: What to Adjust First?",id:"tweaking-strategy-what-to-adjust-first",level:3},{value:"1. Start with Relaxation (Easiest)",id:"1-start-with-relaxation-easiest",level:4},{value:"2. Adjust Period Length (Simple)",id:"2-adjust-period-length-simple",level:4},{value:"3. Fine-tune Flexibility (Moderate)",id:"3-fine-tune-flexibility-moderate",level:4},{value:"4. Adjust Distance from Average (Advanced)",id:"4-adjust-distance-from-average-advanced",level:4},{value:"5. Enable Level Filter (Expert)",id:"5-enable-level-filter-expert",level:4},{value:"Common Mistakes to Avoid",id:"common-mistakes-to-avoid",level:3},{value:"Understanding Relaxation",id:"understanding-relaxation",level:2},{value:"What Is Relaxation?",id:"what-is-relaxation",level:3},{value:"How to Enable",id:"how-to-enable",level:3},{value:"Why Relaxation Is Better Than Manual Tweaking",id:"why-relaxation-is-better-than-manual-tweaking",level:3},{value:"How It Works (Adaptive Matrix)",id:"how-it-works-adaptive-matrix",level:3},{value:"Phase Matrix",id:"phase-matrix",level:4},{value:"Choosing the Number of Attempts",id:"choosing-the-number-of-attempts",level:3},{value:"Per-Day Independence",id:"per-day-independence",level:4},{value:"Common Scenarios",id:"common-scenarios",level:2},{value:"Scenario 1: Simple Best Price (Default)",id:"scenario-1-simple-best-price-default",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"No Periods Found",id:"no-periods-found",level:3},{value:"Periods Split Into Small Pieces",id:"periods-split-into-small-pieces",level:3},{value:"Understanding Sensor Attributes",id:"understanding-sensor-attributes",level:3},{value:"Midnight Price Classification Changes",id:"midnight-price-classification-changes",level:3},{value:"Advanced Topics",id:"advanced-topics",level:2},{value:"Quick Reference",id:"quick-reference",level:3},{value:"Price Levels Reference",id:"price-levels-reference",level:3}];function c(e){const i={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components},{Details:n}=i;return n||function(e,i){throw new Error("Expected "+(i?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(i.header,{children:(0,r.jsx)(i.h1,{id:"period-calculation",children:"Period Calculation"})}),"\n",(0,r.jsx)(i.p,{children:"Learn how Best Price and Peak Price periods work, and how to configure them for your needs."}),"\n",(0,r.jsx)(i.h2,{id:"table-of-contents",children:"Table of Contents"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#quick-start",children:"Quick Start"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#how-it-works",children:"How It Works"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#configuration-guide",children:"Configuration Guide"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#understanding-relaxation",children:"Understanding Relaxation"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#common-scenarios",children:"Common Scenarios"})}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.a,{href:"#troubleshooting",children:"Troubleshooting"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#no-periods-found",children:"No Periods Found"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#periods-split-into-small-pieces",children:"Periods Split Into Small Pieces"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#midnight-price-classification-changes",children:"Midnight Price Classification Changes"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#advanced-topics",children:"Advanced Topics"})}),"\n"]}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsx)(i.h2,{id:"quick-start",children:"Quick Start"}),"\n",(0,r.jsx)(i.h3,{id:"what-are-price-periods",children:"What Are Price Periods?"}),"\n",(0,r.jsxs)(i.p,{children:["The integration finds time windows when electricity is especially ",(0,r.jsx)(i.strong,{children:"cheap"})," (Best Price) or ",(0,r.jsx)(i.strong,{children:"expensive"})," (Peak Price):"]}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Best Price Periods"})," \ud83d\udfe2 - When to run your dishwasher, charge your EV, or heat water"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Peak Price Periods"})," \ud83d\udd34 - When to reduce consumption or defer non-essential loads"]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"default-behavior",children:"Default Behavior"}),"\n",(0,r.jsx)(i.p,{children:"Out of the box, the integration:"}),"\n",(0,r.jsxs)(i.ol,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Best Price"}),": Finds cheapest 1-hour+ windows that are at least 5% below the daily average"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Peak Price"}),": Finds most expensive 30-minute+ windows that are at least 5% above the daily average"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Relaxation"}),": Automatically loosens filters if not enough periods are found"]}),"\n"]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Most users don't need to change anything!"})," The defaults work well for typical use cases."]}),"\n",(0,r.jsxs)(n,{children:[(0,r.jsx)("summary",{children:"\u2139\ufe0f Why do Best Price and Peak Price have different defaults?"}),(0,r.jsxs)(i.p,{children:["The integration sets different ",(0,r.jsx)(i.strong,{children:"initial defaults"})," because the features serve different purposes:"]}),(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Best Price (60 min, 15% flex):"})}),(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"Longer duration ensures appliances can complete their cycles"}),"\n",(0,r.jsx)(i.li,{children:"Stricter flex (15%) focuses on genuinely cheap times"}),"\n",(0,r.jsx)(i.li,{children:"Use case: Running dishwasher, EV charging, water heating"}),"\n"]}),(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Peak Price (30 min, 20% flex):"})}),(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"Shorter duration acceptable for early warnings"}),"\n",(0,r.jsx)(i.li,{children:"More flexible (20%) catches price spikes earlier"}),"\n",(0,r.jsx)(i.li,{children:"Use case: Alerting to expensive periods, even brief ones"}),"\n"]}),(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"You can adjust all these values"})," in the configuration if the defaults don't fit your use case. The asymmetric defaults simply provide good starting points for typical scenarios."]})]}),"\n",(0,r.jsx)(i.h3,{id:"example-timeline",children:"Example Timeline"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"00:00 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 Best Price Period (cheap prices)\n04:00 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 Normal\n08:00 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 Peak Price Period (expensive prices)\n12:00 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 Normal\n16:00 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 Peak Price Period (expensive prices)\n20:00 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 Best Price Period (cheap prices)\n"})}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsx)(i.h2,{id:"how-it-works",children:"How It Works"}),"\n",(0,r.jsx)(i.h3,{id:"the-basic-idea",children:"The Basic Idea"}),"\n",(0,r.jsxs)(i.p,{children:["Each day, the integration analyzes all 96 quarter-hourly price intervals and identifies ",(0,r.jsx)(i.strong,{children:"continuous time ranges"})," that meet specific criteria."]}),"\n",(0,r.jsx)(i.p,{children:"Think of it like this:"}),"\n",(0,r.jsxs)(i.ol,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Find potential windows"})," - Times close to the daily MIN (Best Price) or MAX (Peak Price)"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Filter by quality"})," - Ensure they're meaningfully different from average"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Check duration"})," - Must be long enough to be useful"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Apply preferences"})," - Optional: only show stable prices, avoid mediocre times"]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"step-by-step-process",children:"Step-by-Step Process"}),"\n",(0,r.jsx)(i.h4,{id:"1-define-the-search-range-flexibility",children:"1. Define the Search Range (Flexibility)"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Best Price:"})," How much MORE than the daily minimum can a price be?"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Daily MIN: 20 ct/kWh\nFlexibility: 15% (default)\n\u2192 Search for times \u2264 23 ct/kWh (20 + 15%)\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Peak Price:"})," How much LESS than the daily maximum can a price be?"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Daily MAX: 40 ct/kWh\nFlexibility: -15% (default)\n\u2192 Search for times \u2265 34 ct/kWh (40 - 15%)\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Why flexibility?"})," Prices rarely stay at exactly MIN/MAX. Flexibility lets you capture realistic time windows."]}),"\n",(0,r.jsx)(i.h4,{id:"2-ensure-quality-distance-from-average",children:"2. Ensure Quality (Distance from Average)"}),"\n",(0,r.jsx)(i.p,{children:"Periods must be meaningfully different from the daily average:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Daily AVG: 30 ct/kWh\nMinimum distance: 5% (default)\n\nBest Price: Must be \u2264 28.5 ct/kWh (30 - 5%)\nPeak Price: Must be \u2265 31.5 ct/kWh (30 + 5%)\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Why?"}),' This prevents marking mediocre times as "best" just because they\'re slightly below average.']}),"\n",(0,r.jsx)(i.h4,{id:"3-check-duration",children:"3. Check Duration"}),"\n",(0,r.jsx)(i.p,{children:"Periods must be long enough to be practical:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Default: 60 minutes minimum\n\n45-minute period \u2192 Discarded\n90-minute period \u2192 Kept \u2713\n"})}),"\n",(0,r.jsx)(i.h4,{id:"4-apply-optional-filters",children:"4. Apply Optional Filters"}),"\n",(0,r.jsx)(i.p,{children:"You can optionally require:"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Absolute quality"}),' (level filter) - "Only show if prices are CHEAP/EXPENSIVE (not just below/above average)"']}),"\n"]}),"\n",(0,r.jsx)(i.h4,{id:"5-automatic-price-spike-smoothing",children:"5. Automatic Price Spike Smoothing"}),"\n",(0,r.jsx)(i.p,{children:"Isolated price spikes are automatically detected and smoothed to prevent unnecessary period fragmentation:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Original prices: 18, 19, 35, 20, 19 ct \u2190 35 ct is an isolated outlier\nSmoothed: 18, 19, 19, 20, 19 ct \u2190 Spike replaced with trend prediction\n\nResult: Continuous period 00:00-01:15 instead of split periods\n"})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Important:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"Original prices are always preserved (min/max/avg show real values)"}),"\n",(0,r.jsx)(i.li,{children:"Smoothing only affects which intervals are combined into periods"}),"\n",(0,r.jsxs)(i.li,{children:["The attribute ",(0,r.jsx)(i.code,{children:"period_interval_smoothed_count"})," shows if smoothing was active"]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"visual-example",children:"Visual Example"}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Timeline for a typical day:"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Hour: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23\nPrice: 18 19 20 28 29 30 35 34 33 32 30 28 25 24 26 28 30 32 31 22 21 20 19 18\n\nDaily MIN: 18 ct | Daily MAX: 35 ct | Daily AVG: 26 ct\n\nBest Price (15% flex = \u226420.7 ct):\n \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\n 00:00-03:00 (3h) 19:00-24:00 (5h)\n\nPeak Price (-15% flex = \u226529.75 ct):\n \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\n 06:00-11:00 (5h)\n"})}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsx)(i.h2,{id:"configuration-guide",children:"Configuration Guide"}),"\n",(0,r.jsx)(i.h3,{id:"basic-settings",children:"Basic Settings"}),"\n",(0,r.jsx)(i.h4,{id:"flexibility",children:"Flexibility"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"What:"})," How far from MIN/MAX to search for periods\n",(0,r.jsx)(i.strong,{children:"Default:"})," 15% (Best Price), -15% (Peak Price)\n",(0,r.jsx)(i.strong,{children:"Range:"})," 0-100%"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_flex: 15 # Can be up to 15% more expensive than daily MIN\npeak_price_flex: -15 # Can be up to 15% less expensive than daily MAX\n"})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"When to adjust:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Increase (20-25%)"})," \u2192 Find more/longer periods"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Decrease (5-10%)"})," \u2192 Find only the very best/worst times"]}),"\n"]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"\ud83d\udca1 Tip:"})," Very high flexibility (>30%) is rarely useful. ",(0,r.jsx)(i.strong,{children:"Recommendation:"})," Start with 15-20% and enable relaxation \u2013 it adapts automatically to each day's price pattern."]}),"\n",(0,r.jsx)(i.h4,{id:"minimum-period-length",children:"Minimum Period Length"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"What:"})," How long a period must be to show it\n",(0,r.jsx)(i.strong,{children:"Default:"})," 60 minutes (Best Price), 30 minutes (Peak Price)\n",(0,r.jsx)(i.strong,{children:"Range:"})," 15-240 minutes"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_min_period_length: 60\npeak_price_min_period_length: 30\n"})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"When to adjust:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Increase (90-120 min)"})," \u2192 Only show longer periods (e.g., for heat pump cycles)"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Decrease (30-45 min)"})," \u2192 Show shorter windows (e.g., for quick tasks)"]}),"\n"]}),"\n",(0,r.jsx)(i.h4,{id:"distance-from-average",children:"Distance from Average"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"What:"})," How much better than average a period must be\n",(0,r.jsx)(i.strong,{children:"Default:"})," 5%\n",(0,r.jsx)(i.strong,{children:"Range:"})," 0-20%"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_min_distance_from_avg: 5\npeak_price_min_distance_from_avg: 5\n"})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"When to adjust:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Increase (5-10%)"})," \u2192 Only show clearly better times"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Decrease (0-1%)"})," \u2192 Show any time below/above average"]}),"\n"]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"\u2139\ufe0f Note:"})," Both flexibility and distance filters must be satisfied. When using high flexibility values (>30%), the distance filter may become the limiting factor. For best results, use moderate flexibility (15-20%) with relaxation enabled."]}),"\n",(0,r.jsx)(i.h3,{id:"optional-filters",children:"Optional Filters"}),"\n",(0,r.jsx)(i.h4,{id:"level-filter-absolute-quality",children:"Level Filter (Absolute Quality)"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"What:"})," Only show periods with CHEAP/EXPENSIVE intervals (not just below/above average)\n",(0,r.jsx)(i.strong,{children:"Default:"})," ",(0,r.jsx)(i.code,{children:"any"})," (disabled)\n",(0,r.jsx)(i.strong,{children:"Options:"})," ",(0,r.jsx)(i.code,{children:"any"})," | ",(0,r.jsx)(i.code,{children:"cheap"})," | ",(0,r.jsx)(i.code,{children:"very_cheap"})," (Best Price) | ",(0,r.jsx)(i.code,{children:"expensive"})," | ",(0,r.jsx)(i.code,{children:"very_expensive"})," (Peak Price)"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_max_level: any # Show any period below average\nbest_price_max_level: cheap # Only show if at least one interval is CHEAP\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Use case:"}),' "Only notify me when prices are objectively cheap/expensive"']}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"\u2139\ufe0f Volatility Thresholds:"})," The level filter also supports volatility-based levels (",(0,r.jsx)(i.code,{children:"volatility_low"}),", ",(0,r.jsx)(i.code,{children:"volatility_medium"}),", ",(0,r.jsx)(i.code,{children:"volatility_high"}),"). These use ",(0,r.jsx)(i.strong,{children:"fixed internal thresholds"})," (LOW < 10%, MEDIUM < 20%, HIGH \u2265 20%) that are separate from the sensor volatility thresholds you configure in the UI. This separation ensures that changing sensor display preferences doesn't affect period calculation behavior."]}),"\n",(0,r.jsx)(i.h4,{id:"gap-tolerance-for-level-filter",children:"Gap Tolerance (for Level Filter)"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"What:"}),' Allow some "mediocre" intervals within an otherwise good period\n',(0,r.jsx)(i.strong,{children:"Default:"})," 0 (strict)\n",(0,r.jsx)(i.strong,{children:"Range:"})," 0-10"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_max_level: cheap\nbest_price_max_level_gap_count: 2 # Allow up to 2 NORMAL intervals per period\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Use case:"})," \"Don't split periods just because one interval isn't perfectly CHEAP\""]}),"\n",(0,r.jsx)(i.h3,{id:"tweaking-strategy-what-to-adjust-first",children:"Tweaking Strategy: What to Adjust First?"}),"\n",(0,r.jsx)(i.p,{children:"When you're not happy with the default behavior, adjust settings in this order:"}),"\n",(0,r.jsxs)(i.h4,{id:"1-start-with-relaxation-easiest",children:["1. ",(0,r.jsx)(i.strong,{children:"Start with Relaxation (Easiest)"})]}),"\n",(0,r.jsx)(i.p,{children:"If you're not finding enough periods:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"enable_min_periods_best: true # Already default!\nmin_periods_best: 2 # Already default!\nrelaxation_attempts_best: 11 # Already default!\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Why start here?"})," Relaxation automatically finds the right balance for each day. Much easier than manual tuning."]}),"\n",(0,r.jsxs)(i.h4,{id:"2-adjust-period-length-simple",children:["2. ",(0,r.jsx)(i.strong,{children:"Adjust Period Length (Simple)"})]}),"\n",(0,r.jsx)(i.p,{children:"If periods are too short/long for your use case:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_min_period_length: 90 # Increase from 60 for longer periods\n# OR\nbest_price_min_period_length: 45 # Decrease from 60 for shorter periods\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Safe to change:"})," This only affects duration, not price selection logic."]}),"\n",(0,r.jsxs)(i.h4,{id:"3-fine-tune-flexibility-moderate",children:["3. ",(0,r.jsx)(i.strong,{children:"Fine-tune Flexibility (Moderate)"})]}),"\n",(0,r.jsx)(i.p,{children:"If you consistently want more/fewer periods:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_flex: 20 # Increase from 15% for more periods\n# OR\nbest_price_flex: 10 # Decrease from 15% for stricter selection\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"\u26a0\ufe0f Watch out:"})," Values >25% may conflict with distance filter. Use relaxation instead."]}),"\n",(0,r.jsxs)(i.h4,{id:"4-adjust-distance-from-average-advanced",children:["4. ",(0,r.jsx)(i.strong,{children:"Adjust Distance from Average (Advanced)"})]}),"\n",(0,r.jsx)(i.p,{children:'Only if periods seem "mediocre" (not really cheap/expensive):'}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_min_distance_from_avg: 10 # Increase from 5% for stricter quality\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"\u26a0\ufe0f Careful:"})," High values (>10%) can make it impossible to find periods on flat price days."]}),"\n",(0,r.jsxs)(i.h4,{id:"5-enable-level-filter-expert",children:["5. ",(0,r.jsx)(i.strong,{children:"Enable Level Filter (Expert)"})]}),"\n",(0,r.jsx)(i.p,{children:"Only if you want absolute quality requirements:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_max_level: cheap # Only show objectively CHEAP periods\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"\u26a0\ufe0f Very strict:"})," Many days may have zero qualifying periods. ",(0,r.jsx)(i.strong,{children:"Always enable relaxation when using this!"})]}),"\n",(0,r.jsx)(i.h3,{id:"common-mistakes-to-avoid",children:"Common Mistakes to Avoid"}),"\n",(0,r.jsxs)(i.p,{children:["\u274c ",(0,r.jsx)(i.strong,{children:"Don't increase flexibility to >30% manually"})," \u2192 Use relaxation instead\n\u274c ",(0,r.jsx)(i.strong,{children:"Don't combine high distance (>10%) with strict level filter"})," \u2192 Too restrictive\n\u274c ",(0,r.jsx)(i.strong,{children:"Don't disable relaxation with strict filters"})," \u2192 You'll get zero periods on some days\n\u274c ",(0,r.jsx)(i.strong,{children:"Don't change all settings at once"})," \u2192 Adjust one at a time and observe results"]}),"\n",(0,r.jsxs)(i.p,{children:["\u2705 ",(0,r.jsx)(i.strong,{children:"Do use defaults + relaxation"})," \u2192 Works for 90% of cases\n\u2705 ",(0,r.jsx)(i.strong,{children:"Do adjust one setting at a time"})," \u2192 Easier to understand impact\n\u2705 ",(0,r.jsx)(i.strong,{children:"Do check sensor attributes"})," \u2192 Shows why periods were/weren't found"]}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsx)(i.h2,{id:"understanding-relaxation",children:"Understanding Relaxation"}),"\n",(0,r.jsx)(i.h3,{id:"what-is-relaxation",children:"What Is Relaxation?"}),"\n",(0,r.jsxs)(i.p,{children:["Sometimes, strict filters find too few periods (or none). ",(0,r.jsx)(i.strong,{children:"Relaxation automatically loosens filters"})," until a minimum number of periods is found."]}),"\n",(0,r.jsx)(i.h3,{id:"how-to-enable",children:"How to Enable"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"enable_min_periods_best: true\nmin_periods_best: 2 # Try to find at least 2 periods per day\nrelaxation_attempts_best: 11 # Flex levels to test (default: 11 steps = 22 filter combinations)\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"\u2139\ufe0f Good news:"})," Relaxation is ",(0,r.jsx)(i.strong,{children:"enabled by default"})," with sensible settings. Most users don't need to change anything here!"]}),"\n",(0,r.jsxs)(i.p,{children:["Set the matching ",(0,r.jsx)(i.code,{children:"relaxation_attempts_peak"})," value when tuning Peak Price periods. Both sliders accept 1-12 attempts, and the default of 11 flex levels translates to 22 filter-combination tries (11 flex levels \xd7 2 filter combos) for each of Best and Peak calculations. Lower it for quick feedback, or raise it when either sensor struggles to hit the minimum-period target on volatile days."]}),"\n",(0,r.jsx)(i.h3,{id:"why-relaxation-is-better-than-manual-tweaking",children:"Why Relaxation Is Better Than Manual Tweaking"}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Problem with manual settings:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"You set flex to 25% \u2192 Works great on Monday (volatile prices)"}),"\n",(0,r.jsx)(i.li,{children:'Same 25% flex on Tuesday (flat prices) \u2192 Finds "best price" periods that aren\'t really cheap'}),"\n",(0,r.jsx)(i.li,{children:"You're stuck with one setting for all days"}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Solution with relaxation:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"Monday (volatile): Uses flex 15% (original) \u2192 Finds 2 perfect periods \u2713"}),"\n",(0,r.jsx)(i.li,{children:"Tuesday (flat): Escalates to flex 21% \u2192 Finds 2 decent periods \u2713"}),"\n",(0,r.jsx)(i.li,{children:"Wednesday (mixed): Uses flex 18% \u2192 Finds 2 good periods \u2713"}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Each day gets exactly the flexibility it needs!"})}),"\n",(0,r.jsx)(i.h3,{id:"how-it-works-adaptive-matrix",children:"How It Works (Adaptive Matrix)"}),"\n",(0,r.jsxs)(i.p,{children:["Relaxation uses a ",(0,r.jsx)(i.strong,{children:"matrix approach"})," - trying ",(0,r.jsx)(i.em,{children:"N"})," flexibility levels (your configured ",(0,r.jsx)(i.strong,{children:"relaxation attempts"}),") with 2 filter combinations per level. With the default of 11 attempts, that means 11 flex levels \xd7 2 filter combinations = ",(0,r.jsx)(i.strong,{children:"22 total filter-combination tries per day"}),"; fewer attempts mean fewer flex increases, while more attempts extend the search further before giving up."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Important:"})," The flexibility increment is ",(0,r.jsx)(i.strong,{children:"fixed at 3% per step"})," (hard-coded for reliability). This means:"]}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"Base flex 15% \u2192 18% \u2192 21% \u2192 24% \u2192 ... \u2192 48% (with 11 attempts)"}),"\n",(0,r.jsx)(i.li,{children:"Base flex 20% \u2192 23% \u2192 26% \u2192 29% \u2192 ... \u2192 50% (with 11 attempts)"}),"\n"]}),"\n",(0,r.jsx)(i.h4,{id:"phase-matrix",children:"Phase Matrix"}),"\n",(0,r.jsx)(i.p,{children:"For each day, the system tries:"}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Flexibility Levels (Attempts):"})}),"\n",(0,r.jsxs)(i.ol,{children:["\n",(0,r.jsx)(i.li,{children:"Attempt 1 = Original flex (e.g., 15%)"}),"\n",(0,r.jsx)(i.li,{children:"Attempt 2 = +3% step (18%)"}),"\n",(0,r.jsx)(i.li,{children:"Attempt 3 = +3% step (21%)"}),"\n",(0,r.jsx)(i.li,{children:"Attempt 4 = +3% step (24%)"}),"\n",(0,r.jsx)(i.li,{children:"\u2026 Attempts 5-11 (default) continue adding +3% each time"}),"\n",(0,r.jsx)(i.li,{children:"\u2026 Additional attempts keep extending the same pattern up to the 12-attempt maximum (up to 51%)"}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"2 Filter Combinations (per flexibility level):"})}),"\n",(0,r.jsxs)(i.ol,{children:["\n",(0,r.jsx)(i.li,{children:"Original filters (your configured level filter)"}),"\n",(0,r.jsx)(i.li,{children:"Remove level filter (level=any)"}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Example progression:"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Flex 15% + Original filters \u2192 Not enough periods\nFlex 15% + Level=any \u2192 Not enough periods\nFlex 18% + Original filters \u2192 Not enough periods\nFlex 18% + Level=any \u2192 SUCCESS! Found 2 periods \u2713\n(stops here - no need to try more)\n"})}),"\n",(0,r.jsx)(i.h3,{id:"choosing-the-number-of-attempts",children:"Choosing the Number of Attempts"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Default (11 attempts)"})," balances speed and completeness for most grids (22 combinations per day for both Best and Peak)"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Lower (4-8 attempts)"})," if you only want mild relaxation and keep processing time minimal (reaches ~27-39% flex)"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Higher (12 attempts)"})," for extremely volatile days when you must reach near the 50% maximum (24 combinations)"]}),"\n",(0,r.jsx)(i.li,{children:"Remember: each additional attempt adds two more filter combinations because every new flex level still runs both filter overrides (original + level=any)"}),"\n"]}),"\n",(0,r.jsx)(i.h4,{id:"per-day-independence",children:"Per-Day Independence"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Critical:"})," Each day relaxes ",(0,r.jsx)(i.strong,{children:"independently"}),":"]}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{children:"Day 1: Finds 2 periods with flex 15% (original) \u2192 No relaxation needed\nDay 2: Needs flex 21% + level=any \u2192 Uses relaxed settings\nDay 3: Finds 2 periods with flex 15% (original) \u2192 No relaxation needed\n"})}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Why?"})," Price patterns vary daily. Some days have clear cheap/expensive windows (strict filters work), others don't (relaxation needed)."]}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsx)(i.h2,{id:"common-scenarios",children:"Common Scenarios"}),"\n",(0,r.jsx)(i.h3,{id:"scenario-1-simple-best-price-default",children:"Scenario 1: Simple Best Price (Default)"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Goal:"})," Find the cheapest time each day to run dishwasher"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Configuration:"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"# Use defaults - no configuration needed!\nbest_price_flex: 15 # (default)\nbest_price_min_period_length: 60 # (default)\nbest_price_min_distance_from_avg: 5 # (default)\n"})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"What you get:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"1-3 periods per day with prices \u2264 MIN + 15%"}),"\n",(0,r.jsx)(i.li,{children:"Each period at least 1 hour long"}),"\n",(0,r.jsx)(i.li,{children:"All periods at least 5% cheaper than daily average"}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Automation example:"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:'automation:\n - trigger:\n - platform: state\n entity_id: binary_sensor.tibber_home_best_price_period\n to: "on"\n action:\n - service: switch.turn_on\n target:\n entity_id: switch.dishwasher\n'})}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsx)(i.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,r.jsx)(i.h3,{id:"no-periods-found",children:"No Periods Found"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Symptom:"})," ",(0,r.jsx)(i.code,{children:"binary_sensor.tibber_home_best_price_period"}),' never turns "on"']}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Common Solutions:"})}),"\n",(0,r.jsxs)(i.ol,{children:["\n",(0,r.jsxs)(i.li,{children:["\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Check if relaxation is enabled"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"enable_min_periods_best: true # Should be true (default)\nmin_periods_best: 2 # Try to find at least 2 periods\n"})}),"\n"]}),"\n",(0,r.jsxs)(i.li,{children:["\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"If still no periods, check filters"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:["Look at sensor attributes: ",(0,r.jsx)(i.code,{children:"relaxation_active"})," and ",(0,r.jsx)(i.code,{children:"relaxation_level"})]}),"\n",(0,r.jsx)(i.li,{children:"If relaxation exhausted all attempts: Filters too strict or flat price day"}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(i.li,{children:["\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Try increasing flexibility slightly"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_flex: 20 # Increase from default 15%\n"})}),"\n"]}),"\n",(0,r.jsxs)(i.li,{children:["\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Or reduce period length requirement"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_min_period_length: 45 # Reduce from default 60 minutes\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"periods-split-into-small-pieces",children:"Periods Split Into Small Pieces"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Symptom:"})," Many short periods instead of one long period"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Common Solutions:"})}),"\n",(0,r.jsxs)(i.ol,{children:["\n",(0,r.jsxs)(i.li,{children:["\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"If using level filter, add gap tolerance"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_max_level: cheap\nbest_price_max_level_gap_count: 2 # Allow 2 NORMAL intervals\n"})}),"\n"]}),"\n",(0,r.jsxs)(i.li,{children:["\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Slightly increase flexibility"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"best_price_flex: 20 # From 15% \u2192 captures wider price range\n"})}),"\n"]}),"\n",(0,r.jsxs)(i.li,{children:["\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Check for price spikes"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"Automatic smoothing should handle this"}),"\n",(0,r.jsxs)(i.li,{children:["Check attribute: ",(0,r.jsx)(i.code,{children:"period_interval_smoothed_count"})]}),"\n",(0,r.jsx)(i.li,{children:"If 0: Not isolated spikes, but real price levels"}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"understanding-sensor-attributes",children:"Understanding Sensor Attributes"}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Key attributes to check:"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:'# Entity: binary_sensor.tibber_home_best_price_period\n\n# When "on" (period active):\nstart: "2025-11-11T02:00:00+01:00" # Period start time\nend: "2025-11-11T05:00:00+01:00" # Period end time\nduration_minutes: 180 # Duration in minutes\nprice_avg: 18.5 # Average price in the period\nrating_level: "LOW" # All intervals have LOW rating\n\n# Relaxation info (shows if filter loosening was needed):\nrelaxation_active: true # This day needed relaxation\nrelaxation_level: "price_diff_18.0%+level_any" # Found at 18% flex, level filter removed\n\n# Optional (only shown when relevant):\nperiod_interval_smoothed_count: 2 # Number of price spikes smoothed\nperiod_interval_level_gap_count: 1 # Number of "mediocre" intervals tolerated\n'})}),"\n",(0,r.jsx)(i.h3,{id:"midnight-price-classification-changes",children:"Midnight Price Classification Changes"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Symptom:"})," A Best Price period at 23:45 suddenly changes to Peak Price at 00:00 (or vice versa), even though the absolute price barely changed."]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Why This Happens:"})}),"\n",(0,r.jsxs)(i.p,{children:["This is ",(0,r.jsx)(i.strong,{children:"mathematically correct behavior"})," caused by how electricity prices are set in the day-ahead market:"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Market Timing:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:["The EPEX SPOT Day-Ahead auction closes at ",(0,r.jsx)(i.strong,{children:"12:00 CET"})," each day"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"All prices"})," for the next day (00:00-23:45) are set at this moment"]}),"\n",(0,r.jsxs)(i.li,{children:["Late-day intervals (23:45) are priced ",(0,r.jsx)(i.strong,{children:"~36 hours before delivery"})]}),"\n",(0,r.jsxs)(i.li,{children:["Early-day intervals (00:00) are priced ",(0,r.jsx)(i.strong,{children:"~12 hours before delivery"})]}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Why Prices Jump at Midnight:"})}),"\n",(0,r.jsxs)(i.ol,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Forecast Uncertainty:"})," Weather, demand, and renewable generation forecasts are more uncertain 36 hours ahead than 12 hours ahead"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Risk Buffer:"})," Late-day prices include a risk premium for this uncertainty"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Independent Days:"})," Each day has its own min/max/avg calculated from its 96 intervals"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Relative Classification:"})," Periods are classified based on their ",(0,r.jsx)(i.strong,{children:"position within the day's price range"}),", not absolute prices"]}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Example:"})}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"# Day 1 (low volatility, narrow range)\nPrice range: 18-22 ct/kWh (4 ct span)\nDaily average: 20 ct/kWh\n23:45: 18.5 ct/kWh \u2192 7.5% below average \u2192 BEST PRICE \u2705\n\n# Day 2 (low volatility, narrow range)\nPrice range: 17-21 ct/kWh (4 ct span)\nDaily average: 19 ct/kWh\n00:00: 18.6 ct/kWh \u2192 2.1% below average \u2192 PEAK PRICE \u274c\n\n# Observation: Absolute price barely changed (18.5 \u2192 18.6 ct)\n# But relative position changed dramatically:\n# - Day 1: Near the bottom of the range\n# - Day 2: Near the middle/top of the range\n"})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"When This Occurs:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Low-volatility days:"})," When price span is narrow (< 5 ct/kWh)"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Stable weather:"})," Similar conditions across multiple days"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.strong,{children:"Market transitions:"})," Switching between high/low demand seasons"]}),"\n"]}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"How to Detect:"})}),"\n",(0,r.jsx)(i.p,{children:"Check the volatility sensors to understand if a period flip is meaningful:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"# Check daily volatility (available in integration)\nsensor.tibber_home_volatility_today: 8.2% # Low volatility\nsensor.tibber_home_volatility_tomorrow: 7.9% # Also low\n\n# Low volatility (< 15%) means:\n# - Small absolute price differences between periods\n# - Classification changes may not be economically significant\n# - Consider ignoring period classification on such days\n"})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Handling in Automations:"})}),"\n",(0,r.jsx)(i.p,{children:"You can make your automations volatility-aware:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:'# Option 1: Only act on high-volatility days\nautomation:\n - alias: "Dishwasher - Best Price (High Volatility Only)"\n trigger:\n - platform: state\n entity_id: binary_sensor.tibber_home_best_price_period\n to: "on"\n condition:\n - condition: numeric_state\n entity_id: sensor.tibber_home_volatility_today\n above: 15 # Only act if volatility > 15%\n action:\n - service: switch.turn_on\n entity_id: switch.dishwasher\n\n# Option 2: Check absolute price, not just classification\nautomation:\n - alias: "Heat Water - Cheap Enough"\n trigger:\n - platform: state\n entity_id: binary_sensor.tibber_home_best_price_period\n to: "on"\n condition:\n - condition: numeric_state\n entity_id: sensor.tibber_home_current_interval_price_ct\n below: 20 # Absolute threshold: < 20 ct/kWh\n action:\n - service: switch.turn_on\n entity_id: switch.water_heater\n\n# Option 3: Use per-period day volatility (available on period sensors)\nautomation:\n - alias: "EV Charging - Volatility-Aware"\n trigger:\n - platform: state\n entity_id: binary_sensor.tibber_home_best_price_period\n to: "on"\n condition:\n # Check if the period\'s day has meaningful volatility\n - condition: template\n value_template: >\n {{ state_attr(\'binary_sensor.tibber_home_best_price_period\', \'day_volatility_%\') | float(0) > 15 }}\n action:\n - service: switch.turn_on\n entity_id: switch.ev_charger\n'})}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Available Per-Period Attributes:"})}),"\n",(0,r.jsx)(i.p,{children:"Each period sensor exposes day volatility and price statistics:"}),"\n",(0,r.jsx)(i.pre,{children:(0,r.jsx)(i.code,{className:"language-yaml",children:"binary_sensor.tibber_home_best_price_period:\n day_volatility_%: 8.2 # Volatility % of the period's day\n day_price_min: 1800.0 # Minimum price of the day (ct/kWh)\n day_price_max: 2200.0 # Maximum price of the day (ct/kWh)\n day_price_span: 400.0 # Difference (max - min) in ct\n"})}),"\n",(0,r.jsx)(i.p,{children:'These attributes allow automations to check: "Is the classification meaningful on this particular day?"'}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Summary:"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:["\u2705 ",(0,r.jsx)(i.strong,{children:"Expected behavior:"})," Periods are evaluated per-day, midnight is a natural boundary"]}),"\n",(0,r.jsxs)(i.li,{children:["\u2705 ",(0,r.jsx)(i.strong,{children:"Market reality:"})," Late-day prices have more uncertainty than early-day prices"]}),"\n",(0,r.jsxs)(i.li,{children:["\u2705 ",(0,r.jsx)(i.strong,{children:"Solution:"})," Use volatility sensors, absolute price thresholds, or per-period day volatility attributes"]}),"\n"]}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsx)(i.h2,{id:"advanced-topics",children:"Advanced Topics"}),"\n",(0,r.jsx)(i.p,{children:"For advanced configuration patterns and technical deep-dive, see:"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.a,{href:"/hass.tibber_prices/user/automation-examples",children:"Automation Examples"})," - Real-world automation patterns"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.a,{href:"/hass.tibber_prices/user/actions",children:"Actions"})," - Using the ",(0,r.jsx)(i.code,{children:"tibber_prices.get_chartdata"})," action for custom visualizations"]}),"\n"]}),"\n",(0,r.jsx)(i.h3,{id:"quick-reference",children:"Quick Reference"}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Configuration Parameters:"})}),"\n",(0,r.jsxs)(i.table,{children:[(0,r.jsx)(i.thead,{children:(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.th,{children:"Parameter"}),(0,r.jsx)(i.th,{children:"Default"}),(0,r.jsx)(i.th,{children:"Range"}),(0,r.jsx)(i.th,{children:"Purpose"})]})}),(0,r.jsxs)(i.tbody,{children:[(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"best_price_flex"})}),(0,r.jsx)(i.td,{children:"15%"}),(0,r.jsx)(i.td,{children:"0-100%"}),(0,r.jsx)(i.td,{children:"Search range from daily MIN"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"best_price_min_period_length"})}),(0,r.jsx)(i.td,{children:"60 min"}),(0,r.jsx)(i.td,{children:"15-240"}),(0,r.jsx)(i.td,{children:"Minimum duration"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"best_price_min_distance_from_avg"})}),(0,r.jsx)(i.td,{children:"5%"}),(0,r.jsx)(i.td,{children:"0-20%"}),(0,r.jsx)(i.td,{children:"Quality threshold"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"best_price_max_level"})}),(0,r.jsx)(i.td,{children:"any"}),(0,r.jsx)(i.td,{children:"any/cheap/vcheap"}),(0,r.jsx)(i.td,{children:"Absolute quality"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"best_price_max_level_gap_count"})}),(0,r.jsx)(i.td,{children:"0"}),(0,r.jsx)(i.td,{children:"0-10"}),(0,r.jsx)(i.td,{children:"Gap tolerance"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"enable_min_periods_best"})}),(0,r.jsx)(i.td,{children:"true"}),(0,r.jsx)(i.td,{children:"true/false"}),(0,r.jsx)(i.td,{children:"Enable relaxation"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"min_periods_best"})}),(0,r.jsx)(i.td,{children:"2"}),(0,r.jsx)(i.td,{children:"1-10"}),(0,r.jsx)(i.td,{children:"Target periods per day"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:(0,r.jsx)(i.code,{children:"relaxation_attempts_best"})}),(0,r.jsx)(i.td,{children:"11"}),(0,r.jsx)(i.td,{children:"1-12"}),(0,r.jsx)(i.td,{children:"Flex levels (attempts) per day"})]})]})]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Peak Price:"})," Same parameters with ",(0,r.jsx)(i.code,{children:"peak_price_*"})," prefix (defaults: flex=-15%, same otherwise)"]}),"\n",(0,r.jsx)(i.h3,{id:"price-levels-reference",children:"Price Levels Reference"}),"\n",(0,r.jsx)(i.p,{children:"The Tibber API provides price levels for each 15-minute interval:"}),"\n",(0,r.jsx)(i.p,{children:(0,r.jsx)(i.strong,{children:"Levels (based on trailing 24h average):"})}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"VERY_CHEAP"})," - Significantly below average"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"CHEAP"})," - Below average"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"NORMAL"})," - Around average"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"EXPENSIVE"})," - Above average"]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"VERY_EXPENSIVE"})," - Significantly above average"]}),"\n"]}),"\n",(0,r.jsx)(i.hr,{}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Last updated:"})," November 20, 2025\n",(0,r.jsx)(i.strong,{children:"Integration version:"})," 2.0+"]})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,r.jsx)(i,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}}}]);