hass.tibber_prices/developer/caching-strategy.html
github-actions[bot] e9aea64a2e deploy: 6898c126e3
2025-12-06 01:42:39 +00:00

261 lines
No EOL
89 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-caching-strategy" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.9.2">
<title data-rh="true">Caching Strategy | Tibber Prices - Developer Guide</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://jpawlowski.github.io/hass.tibber_prices/developer/img/social-card.png"><meta data-rh="true" name="twitter:image" content="https://jpawlowski.github.io/hass.tibber_prices/developer/img/social-card.png"><meta data-rh="true" property="og:url" content="https://jpawlowski.github.io/hass.tibber_prices/developer/caching-strategy"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Caching Strategy | Tibber Prices - Developer Guide"><meta data-rh="true" name="description" content="This document explains all caching mechanisms in the Tibber Prices integration, their purpose, invalidation logic, and lifetime."><meta data-rh="true" property="og:description" content="This document explains all caching mechanisms in the Tibber Prices integration, their purpose, invalidation logic, and lifetime."><link data-rh="true" rel="icon" href="/hass.tibber_prices/developer/img/logo.svg"><link data-rh="true" rel="canonical" href="https://jpawlowski.github.io/hass.tibber_prices/developer/caching-strategy"><link data-rh="true" rel="alternate" href="https://jpawlowski.github.io/hass.tibber_prices/developer/caching-strategy" hreflang="en"><link data-rh="true" rel="alternate" href="https://jpawlowski.github.io/hass.tibber_prices/developer/caching-strategy" hreflang="x-default"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Caching Strategy","item":"https://jpawlowski.github.io/hass.tibber_prices/developer/caching-strategy"}]}</script><link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&amp;family=Space+Grotesk:wght@500;600;700&amp;display=swap"><link rel="stylesheet" href="/hass.tibber_prices/developer/assets/css/styles.be4f3d68.css">
<script src="/hass.tibber_prices/developer/assets/js/runtime~main.09b7b31a.js" defer="defer"></script>
<script src="/hass.tibber_prices/developer/assets/js/main.5eb4cf38.js" defer="defer"></script>
</head>
<body class="navigation-with-keyboard">
<svg style="display: none;"><defs>
<symbol id="theme-svg-external-link" viewBox="0 0 24 24"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></symbol>
</defs></svg>
<script>!function(){var t=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();document.documentElement.setAttribute("data-theme",t||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")),document.documentElement.setAttribute("data-theme-choice",t||"system")}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><link rel="preload" as="image" href="/hass.tibber_prices/developer/img/logo.svg"><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="theme-layout-navbar navbar navbar--fixed-top"><div class="navbar__inner"><div class="theme-layout-navbar-left navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/hass.tibber_prices/developer/"><div class="navbar__logo"><img src="/hass.tibber_prices/developer/img/logo.svg" alt="Tibber Prices Integration Logo" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="/hass.tibber_prices/developer/img/logo.svg" alt="Tibber Prices Integration Logo" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><b class="navbar__title text--truncate">Tibber Prices HA</b></a><a class="navbar__item navbar__link" href="/hass.tibber_prices/developer/intro">Developer Guide</a><a href="https://jpawlowski.github.io/hass.tibber_prices/user/" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">User Docs<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></div><div class="theme-layout-navbar-right navbar__items navbar__items--right"><a class="navbar__item navbar__link" href="/hass.tibber_prices/developer/caching-strategy">Next 🚧</a><a href="https://github.com/jpawlowski/hass.tibber_prices" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="system mode" aria-label="Switch between dark and light mode (currently system mode)"><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP systemToggleIcon_QzmC"><path fill="currentColor" d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"></path></svg></button></div><div class="navbarSearchContainer_Bca1"><div class="navbar__search"><span aria-label="expand searchbar" role="button" class="search-icon" tabindex="0"></span><input id="search_input_react" type="search" placeholder="Loading..." aria-label="Search" class="navbar__search-input search-bar" disabled=""></div></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="theme-layout-main main-wrapper mainWrapper_z2l0"><div class="docsWrapper_hBAB"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docRoot_UBD9"><aside class="theme-doc-sidebar-container docSidebarContainer_YfHR"><div class="sidebarViewport_aRkj"><div class="sidebar_njMd"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/hass.tibber_prices/developer/intro"><span title="Developer Documentation" class="linkLabel_WmDU">Developer Documentation</span></a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/architecture"><span title="🏗️ Architecture" class="categoryLinkLabel_W154">🏗️ Architecture</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/architecture"><span title="Architecture" class="linkLabel_WmDU">Architecture</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/timer-architecture"><span title="Timer Architecture" class="linkLabel_WmDU">Timer Architecture</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/hass.tibber_prices/developer/caching-strategy"><span title="Caching Strategy" class="linkLabel_WmDU">Caching Strategy</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/api-reference"><span title="API Reference" class="linkLabel_WmDU">API Reference</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/setup"><span title="💻 Development" class="categoryLinkLabel_W154">💻 Development</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/setup"><span title="Development Setup" class="linkLabel_WmDU">Development Setup</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/coding-guidelines"><span title="Coding Guidelines" class="linkLabel_WmDU">Coding Guidelines</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/critical-patterns"><span title="Critical Behavior Patterns - Testing Guide" class="linkLabel_WmDU">Critical Behavior Patterns - Testing Guide</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/debugging"><span title="Debugging Guide" class="linkLabel_WmDU">Debugging Guide</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/period-calculation-theory"><span title="📐 Advanced Topics" class="categoryLinkLabel_W154">📐 Advanced Topics</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/period-calculation-theory"><span title="Period Calculation Theory" class="linkLabel_WmDU">Period Calculation Theory</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/refactoring-guide"><span title="Refactoring Guide" class="linkLabel_WmDU">Refactoring Guide</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/performance"><span title="Performance Optimization" class="linkLabel_WmDU">Performance Optimization</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/contributing"><span title="📝 Contributing" class="categoryLinkLabel_W154">📝 Contributing</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/contributing"><span title="Contributing Guide" class="linkLabel_WmDU">Contributing Guide</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="true" href="/hass.tibber_prices/developer/release-management"><span title="🚀 Release" class="categoryLinkLabel_W154">🚀 Release</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/release-management"><span title="Release Notes Generation" class="linkLabel_WmDU">Release Notes Generation</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/hass.tibber_prices/developer/testing"><span title="Testing" class="linkLabel_WmDU">Testing</span></a></li></ul></li></ul></nav><button type="button" title="Collapse sidebar" aria-label="Collapse sidebar" class="button button--secondary button--outline collapseSidebarButton_PEFL"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_kv0_"><g fill="#7a7a7a"><path d="M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"></path><path d="M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"></path></g></svg></button></div></div></aside><main class="docMainContainer_TBSr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_VOVn"><div class="theme-doc-version-banner alert alert--warning margin-bottom--md" role="alert"><div>This is unreleased documentation for <!-- -->Tibber Prices - Developer Guide<!-- --> <b>Next 🚧</b> version.</div><div class="margin-top--md">For up-to-date documentation, see the <b><a href="/hass.tibber_prices/developer/caching-strategy">latest version</a></b> (<!-- -->Next 🚧<!-- -->).</div></div><div class="docItemContainer_Djhp"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label="Breadcrumbs"><ul class="breadcrumbs"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/hass.tibber_prices/developer/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_YNFT"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">🏗️ Architecture</span></li><li class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link">Caching Strategy</span></li></ul></nav><span class="theme-doc-version-badge badge badge--secondary">Version: Next 🚧</span><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>Caching Strategy</h1></header>
<p>This document explains all caching mechanisms in the Tibber Prices integration, their purpose, invalidation logic, and lifetime.</p>
<p>For timer coordination and scheduling details, see <a class="" href="/hass.tibber_prices/developer/timer-architecture">Timer Architecture</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="overview">Overview<a href="#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview" translate="no"></a></h2>
<p>The integration uses <strong>4 distinct caching layers</strong> with different purposes and lifetimes:</p>
<ol>
<li class=""><strong>Persistent API Data Cache</strong> (HA Storage) - Hours to days</li>
<li class=""><strong>Translation Cache</strong> (Memory) - Forever (until HA restart)</li>
<li class=""><strong>Config Dictionary Cache</strong> (Memory) - Until config changes</li>
<li class=""><strong>Period Calculation Cache</strong> (Memory) - Until price data or config changes</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-persistent-api-data-cache">1. Persistent API Data Cache<a href="#1-persistent-api-data-cache" class="hash-link" aria-label="Direct link to 1. Persistent API Data Cache" title="Direct link to 1. Persistent API Data Cache" translate="no"></a></h2>
<p><strong>Location:</strong> <code>coordinator/cache.py</code> → HA Storage (<code>.storage/tibber_prices.&lt;entry_id&gt;</code>)</p>
<p><strong>Purpose:</strong> Reduce API calls to Tibber by caching user data and price data between HA restarts.</p>
<p><strong>What is cached:</strong></p>
<ul>
<li class=""><strong>Price data</strong> (<code>price_data</code>): Day before yesterday/yesterday/today/tomorrow price intervals with enriched fields (384 intervals total)</li>
<li class=""><strong>User data</strong> (<code>user_data</code>): Homes, subscriptions, features from Tibber GraphQL <code>viewer</code> query</li>
<li class=""><strong>Timestamps</strong>: Last update times for validation</li>
</ul>
<p><strong>Lifetime:</strong></p>
<ul>
<li class=""><strong>Price data</strong>: Until midnight turnover (cleared daily at 00:00 local time)</li>
<li class=""><strong>User data</strong>: 24 hours (refreshed daily)</li>
<li class=""><strong>Survives</strong>: HA restarts via persistent Storage</li>
</ul>
<p><strong>Invalidation triggers:</strong></p>
<ol>
<li class="">
<p><strong>Midnight turnover</strong> (Timer #2 in coordinator):</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># coordinator/day_transitions.py</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">_handle_midnight_turnover</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_cached_price_data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Force fresh fetch for new day</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_last_price_update </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">store_cache</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</li>
<li class="">
<p><strong>Cache validation on load</strong>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># coordinator/cache.py</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">is_cache_valid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cache_data</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> CacheData</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">bool</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Checks if price data is from a previous day</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> today_date </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> local_now</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">date</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Yesterday&#x27;s data</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">False</span><br></span></code></pre></div></div>
</li>
<li class="">
<p><strong>Tomorrow data check</strong> (after 13:00):</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># coordinator/data_fetching.py</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> tomorrow_missing </span><span class="token keyword" style="color:#00009f">or</span><span class="token plain"> tomorrow_invalid</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;tomorrow_check&quot;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Update needed</span><br></span></code></pre></div></div>
</li>
</ol>
<p><strong>Why this cache matters:</strong> Reduces API load on Tibber (~192 intervals per fetch), speeds up HA restarts, enables offline operation until cache expires.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-translation-cache">2. Translation Cache<a href="#2-translation-cache" class="hash-link" aria-label="Direct link to 2. Translation Cache" title="Direct link to 2. Translation Cache" translate="no"></a></h2>
<p><strong>Location:</strong> <code>const.py</code><code>_TRANSLATIONS_CACHE</code> and <code>_STANDARD_TRANSLATIONS_CACHE</code> (in-memory dicts)</p>
<p><strong>Purpose:</strong> Avoid repeated file I/O when accessing entity descriptions, UI strings, etc.</p>
<p><strong>What is cached:</strong></p>
<ul>
<li class=""><strong>Standard translations</strong> (<code>/translations/*.json</code>): Config flow, selector options, entity names</li>
<li class=""><strong>Custom translations</strong> (<code>/custom_translations/*.json</code>): Entity descriptions, usage tips, long descriptions</li>
</ul>
<p><strong>Lifetime:</strong></p>
<ul>
<li class=""><strong>Forever</strong> (until HA restart)</li>
<li class="">No invalidation during runtime</li>
</ul>
<p><strong>When populated:</strong></p>
<ul>
<li class="">At integration setup: <code>async_load_translations(hass, &quot;en&quot;)</code> in <code>__init__.py</code></li>
<li class="">Lazy loading: If translation missing, attempts file load once</li>
</ul>
<p><strong>Access pattern:</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Non-blocking synchronous access from cached data</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">description </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> get_translation</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">&quot;binary_sensor.best_price_period.description&quot;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;en&quot;</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p><strong>Why this cache matters:</strong> Entity attributes are accessed on every state update (~15 times per hour per entity). File I/O would block the event loop. Cache enables synchronous, non-blocking attribute generation.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-config-dictionary-cache">3. Config Dictionary Cache<a href="#3-config-dictionary-cache" class="hash-link" aria-label="Direct link to 3. Config Dictionary Cache" title="Direct link to 3. Config Dictionary Cache" translate="no"></a></h2>
<p><strong>Location:</strong> <code>coordinator/data_transformation.py</code> and <code>coordinator/periods.py</code> (per-instance fields)</p>
<p><strong>Purpose:</strong> Avoid ~30-40 <code>options.get()</code> calls on every coordinator update (every 15 minutes).</p>
<p><strong>What is cached:</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="datatransformer-config-cache">DataTransformer Config Cache<a href="#datatransformer-config-cache" class="hash-link" aria-label="Direct link to DataTransformer Config Cache" title="Direct link to DataTransformer Config Cache" translate="no"></a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;thresholds&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">&quot;low&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">15</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;high&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">35</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;volatility_thresholds&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">&quot;moderate&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">15.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;high&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">25.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;very_high&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">40.0</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># ... 20+ more config fields</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="periodcalculator-config-cache">PeriodCalculator Config Cache<a href="#periodcalculator-config-cache" class="hash-link" aria-label="Direct link to PeriodCalculator Config Cache" title="Direct link to PeriodCalculator Config Cache" translate="no"></a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;best&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">&quot;flex&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.15</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;min_distance_from_avg&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;min_period_length&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;peak&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">&quot;flex&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.15</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;min_distance_from_avg&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;min_period_length&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><strong>Lifetime:</strong></p>
<ul>
<li class="">Until <code>invalidate_config_cache()</code> is called</li>
<li class="">Built once on first use per coordinator update cycle</li>
</ul>
<p><strong>Invalidation trigger:</strong></p>
<ul>
<li class=""><strong>Options change</strong> (user reconfigures integration):<!-- -->
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># coordinator/core.py</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">_handle_options_update</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_data_transformer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">invalidate_config_cache</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_period_calculator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">invalidate_config_cache</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">async_request_refresh</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</li>
</ul>
<p><strong>Performance impact:</strong></p>
<ul>
<li class=""><strong>Before:</strong> ~30 dict lookups + type conversions per update = ~50μs</li>
<li class=""><strong>After:</strong> 1 cache check = ~1μs</li>
<li class=""><strong>Savings:</strong> ~98% (50μs → 1μs per update)</li>
</ul>
<p><strong>Why this cache matters:</strong> Config is read multiple times per update (transformation + period calculation + validation). Caching eliminates redundant lookups without changing behavior.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-period-calculation-cache">4. Period Calculation Cache<a href="#4-period-calculation-cache" class="hash-link" aria-label="Direct link to 4. Period Calculation Cache" title="Direct link to 4. Period Calculation Cache" translate="no"></a></h2>
<p><strong>Location:</strong> <code>coordinator/periods.py</code><code>PeriodCalculator._cached_periods</code></p>
<p><strong>Purpose:</strong> Avoid expensive period calculations (~100-500ms) when price data and config haven&#x27;t changed.</p>
<p><strong>What is cached:</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;best_price&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;periods&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Calculated period objects</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;intervals&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># All intervals in periods</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;metadata&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Config snapshot</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;best_price_relaxation&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">&quot;relaxation_active&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">bool</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;peak_price&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;peak_price_relaxation&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><strong>Cache key:</strong> Hash of relevant inputs</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">hash_data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> today_signature</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># (startsAt, rating_level) for each interval</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">best_config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Best price config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">peak_config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Peak price config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> best_level_filter</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Level filter overrides</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> peak_level_filter</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p><strong>Lifetime:</strong></p>
<ul>
<li class="">Until price data changes (today&#x27;s intervals modified)</li>
<li class="">Until config changes (flex, thresholds, filters)</li>
<li class="">Recalculated at midnight (new today data)</li>
</ul>
<p><strong>Invalidation triggers:</strong></p>
<ol>
<li class="">
<p><strong>Config change</strong> (explicit):</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">invalidate_config_cache</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_cached_periods </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_last_periods_hash </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><br></span></code></pre></div></div>
</li>
<li class="">
<p><strong>Price data change</strong> (automatic via hash mismatch):</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">current_hash </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_compute_periods_hash</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">price_info</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_last_periods_hash </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> current_hash</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Cache miss - recalculate</span><br></span></code></pre></div></div>
</li>
</ol>
<p><strong>Cache hit rate:</strong></p>
<ul>
<li class=""><strong>High:</strong> During normal operation (coordinator updates every 15min, price data unchanged)</li>
<li class=""><strong>Low:</strong> After midnight (new today data) or when tomorrow data arrives (~13:00-14:00)</li>
</ul>
<p><strong>Performance impact:</strong></p>
<ul>
<li class=""><strong>Period calculation:</strong> ~100-500ms (depends on interval count, relaxation attempts)</li>
<li class=""><strong>Cache hit:</strong> <code>&lt;</code>1ms (hash comparison + dict lookup)</li>
<li class=""><strong>Savings:</strong> ~70% of calculation time (most updates hit cache)</li>
</ul>
<p><strong>Why this cache matters:</strong> Period calculation is CPU-intensive (filtering, gap tolerance, relaxation). Caching avoids recalculating unchanged periods 3-4 times per hour.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-transformation-cache-price-enrichment-only">5. Transformation Cache (Price Enrichment Only)<a href="#5-transformation-cache-price-enrichment-only" class="hash-link" aria-label="Direct link to 5. Transformation Cache (Price Enrichment Only)" title="Direct link to 5. Transformation Cache (Price Enrichment Only)" translate="no"></a></h2>
<p><strong>Location:</strong> <code>coordinator/data_transformation.py</code><code>_cached_transformed_data</code></p>
<p><strong>Status:</strong><strong>Clean separation</strong> - enrichment only, no redundancy</p>
<p><strong>What is cached:</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;timestamp&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;homes&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;priceInfo&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Enriched price data (trailing_avg_24h, difference, rating_level)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># NO periods - periods are exclusively managed by PeriodCalculator</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><strong>Purpose:</strong> Avoid re-enriching price data when config unchanged between midnight checks.</p>
<p><strong>Current behavior:</strong></p>
<ul>
<li class="">Caches <strong>only enriched price data</strong> (price + statistics)</li>
<li class=""><strong>Does NOT cache periods</strong> (handled by Period Calculation Cache)</li>
<li class="">Invalidated when:<!-- -->
<ul>
<li class="">Config changes (thresholds affect enrichment)</li>
<li class="">Midnight turnover detected</li>
<li class="">New update cycle begins</li>
</ul>
</li>
</ul>
<p><strong>Architecture:</strong></p>
<ul>
<li class="">DataTransformer: Handles price enrichment only</li>
<li class="">PeriodCalculator: Handles period calculation only (with hash-based cache)</li>
<li class="">Coordinator: Assembles final data on-demand from both caches</li>
</ul>
<p><strong>Memory savings:</strong> Eliminating redundant period storage saves ~10KB per coordinator (14% reduction).</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cache-invalidation-flow">Cache Invalidation Flow<a href="#cache-invalidation-flow" class="hash-link" aria-label="Direct link to Cache Invalidation Flow" title="Direct link to Cache Invalidation Flow" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="user-changes-options-config-flow">User Changes Options (Config Flow)<a href="#user-changes-options-config-flow" class="hash-link" aria-label="Direct link to User Changes Options (Config Flow)" title="Direct link to User Changes Options (Config Flow)" translate="no"></a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">User saves options</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">config_entry.add_update_listener() triggers</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">coordinator._handle_options_update()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; DataTransformer.invalidate_config_cache()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ └─&gt; _config_cache = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ _config_cache_valid = False</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ _cached_transformed_data = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">└─&gt; PeriodCalculator.invalidate_config_cache()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> └─&gt; _config_cache = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> _config_cache_valid = False</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> _cached_periods = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> _last_periods_hash = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">coordinator.async_request_refresh()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Fresh data fetch with new config</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="midnight-turnover-day-transition">Midnight Turnover (Day Transition)<a href="#midnight-turnover-day-transition" class="hash-link" aria-label="Direct link to Midnight Turnover (Day Transition)" title="Direct link to Midnight Turnover (Day Transition)" translate="no"></a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Timer #2 fires at 00:00</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">coordinator._handle_midnight_turnover()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Clear persistent cache</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ └─&gt; _cached_price_data = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ _last_price_update = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">└─&gt; Clear transformation cache</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> └─&gt; _cached_transformed_data = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> _last_transformation_config = None</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Period cache auto-invalidates (hash mismatch on new &quot;today&quot;)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Fresh API fetch for new day</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tomorrow-data-arrives-1300">Tomorrow Data Arrives (~13:00)<a href="#tomorrow-data-arrives-1300" class="hash-link" aria-label="Direct link to Tomorrow Data Arrives (~13:00)" title="Direct link to Tomorrow Data Arrives (~13:00)" translate="no"></a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Coordinator update cycle</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">should_update_price_data() checks tomorrow</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Tomorrow data missing/invalid</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">API fetch with new tomorrow data</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Price data hash changes (new intervals)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Period cache auto-invalidates (hash mismatch)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Periods recalculated with tomorrow included</span><br></span></code></pre></div></div>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cache-coordination">Cache Coordination<a href="#cache-coordination" class="hash-link" aria-label="Direct link to Cache Coordination" title="Direct link to Cache Coordination" translate="no"></a></h2>
<p><strong>All caches work together:</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Persistent Storage (HA restart)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">API Data Cache (price_data, user_data)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ├─&gt; Enrichment (add rating_level, difference, etc.)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> │ ↓</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> │ Transformation Cache (_cached_transformed_data)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> └─&gt; Period Calculation</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Period Cache (_cached_periods)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Config Cache (avoid re-reading options)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Translation Cache (entity descriptions)</span><br></span></code></pre></div></div>
<p><strong>No cache invalidation cascades:</strong></p>
<ul>
<li class="">Config cache invalidation is <strong>explicit</strong> (on options update)</li>
<li class="">Period cache invalidation is <strong>automatic</strong> (via hash mismatch)</li>
<li class="">Transformation cache invalidation is <strong>automatic</strong> (on midnight/config change)</li>
<li class="">Translation cache is <strong>never invalidated</strong> (read-only after load)</li>
</ul>
<p><strong>Thread safety:</strong></p>
<ul>
<li class="">All caches are accessed from <code>MainThread</code> only (Home Assistant event loop)</li>
<li class="">No locking needed (single-threaded execution model)</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="performance-characteristics">Performance Characteristics<a href="#performance-characteristics" class="hash-link" aria-label="Direct link to Performance Characteristics" title="Direct link to Performance Characteristics" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="typical-operation-no-changes">Typical Operation (No Changes)<a href="#typical-operation-no-changes" class="hash-link" aria-label="Direct link to Typical Operation (No Changes)" title="Direct link to Typical Operation (No Changes)" translate="no"></a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Coordinator Update (every 15 min)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; API fetch: SKIP (cache valid)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Config dict build: ~1μs (cached)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Period calculation: ~1ms (cached, hash match)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Transformation: ~10ms (enrichment only, periods cached)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">└─&gt; Entity updates: ~5ms (translation cache hit)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Total: ~16ms (down from ~600ms without caching)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="after-midnight-turnover">After Midnight Turnover<a href="#after-midnight-turnover" class="hash-link" aria-label="Direct link to After Midnight Turnover" title="Direct link to After Midnight Turnover" translate="no"></a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Coordinator Update (00:00)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; API fetch: ~500ms (cache cleared, fetch new day)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Config dict build: ~50μs (rebuild, no cache)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Period calculation: ~200ms (cache miss, recalculate)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Transformation: ~50ms (re-enrich, rebuild)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">└─&gt; Entity updates: ~5ms (translation cache still valid)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Total: ~755ms (expected once per day)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="after-config-change">After Config Change<a href="#after-config-change" class="hash-link" aria-label="Direct link to After Config Change" title="Direct link to After Config Change" translate="no"></a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Options Update</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Cache invalidation: `&lt;`1ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">├─&gt; Coordinator refresh: ~600ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ ├─&gt; API fetch: SKIP (data unchanged)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ ├─&gt; Config rebuild: ~50μs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ ├─&gt; Period recalculation: ~200ms (new thresholds)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ ├─&gt; Re-enrichment: ~50ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">│ └─&gt; Entity updates: ~5ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">└─&gt; Total: ~600ms (expected on manual reconfiguration)</span><br></span></code></pre></div></div>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary-table">Summary Table<a href="#summary-table" class="hash-link" aria-label="Direct link to Summary Table" title="Direct link to Summary Table" translate="no"></a></h2>
<table><thead><tr><th>Cache Type</th><th>Lifetime</th><th>Size</th><th>Invalidation</th><th>Purpose</th></tr></thead><tbody><tr><td><strong>API Data</strong></td><td>Hours to 1 day</td><td>~50KB</td><td>Midnight, validation</td><td>Reduce API calls</td></tr><tr><td><strong>Translations</strong></td><td>Forever (until HA restart)</td><td>~5KB</td><td>Never</td><td>Avoid file I/O</td></tr><tr><td><strong>Config Dicts</strong></td><td>Until options change</td><td><code>&lt;</code>1KB</td><td>Explicit (options update)</td><td>Avoid dict lookups</td></tr><tr><td><strong>Period Calculation</strong></td><td>Until data/config change</td><td>~10KB</td><td>Auto (hash mismatch)</td><td>Avoid CPU-intensive calculation</td></tr><tr><td><strong>Transformation</strong></td><td>Until midnight/config change</td><td>~50KB</td><td>Auto (midnight/config)</td><td>Avoid re-enrichment</td></tr></tbody></table>
<p><strong>Total memory overhead:</strong> ~116KB per coordinator instance (main + subentries)</p>
<p><strong>Benefits:</strong></p>
<ul>
<li class="">97% reduction in API calls (from every 15min to once per day)</li>
<li class="">70% reduction in period calculation time (cache hits during normal operation)</li>
<li class="">98% reduction in config access time (30+ lookups → 1 cache check)</li>
<li class="">Zero file I/O during runtime (translations cached at startup)</li>
</ul>
<p><strong>Trade-offs:</strong></p>
<ul>
<li class="">Memory usage: ~116KB per home (negligible for modern systems)</li>
<li class="">Code complexity: 5 cache invalidation points (well-tested, documented)</li>
<li class="">Debugging: Must understand cache lifetime when investigating stale data issues</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="debugging-cache-issues">Debugging Cache Issues<a href="#debugging-cache-issues" class="hash-link" aria-label="Direct link to Debugging Cache Issues" title="Direct link to Debugging Cache Issues" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="symptom-stale-data-after-config-change">Symptom: Stale data after config change<a href="#symptom-stale-data-after-config-change" class="hash-link" aria-label="Direct link to Symptom: Stale data after config change" title="Direct link to Symptom: Stale data after config change" translate="no"></a></h3>
<p><strong>Check:</strong></p>
<ol>
<li class="">Is <code>_handle_options_update()</code> called? (should see &quot;Options updated&quot; log)</li>
<li class="">Are <code>invalidate_config_cache()</code> methods executed?</li>
<li class="">Does <code>async_request_refresh()</code> trigger?</li>
</ol>
<p><strong>Fix:</strong> Ensure <code>config_entry.add_update_listener()</code> is registered in coordinator init.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="symptom-period-calculation-not-updating">Symptom: Period calculation not updating<a href="#symptom-period-calculation-not-updating" class="hash-link" aria-label="Direct link to Symptom: Period calculation not updating" title="Direct link to Symptom: Period calculation not updating" translate="no"></a></h3>
<p><strong>Check:</strong></p>
<ol>
<li class="">Verify hash changes when data changes: <code>_compute_periods_hash()</code></li>
<li class="">Check <code>_last_periods_hash</code> vs <code>current_hash</code></li>
<li class="">Look for &quot;Using cached period calculation&quot; vs &quot;Calculating periods&quot; logs</li>
</ol>
<p><strong>Fix:</strong> Hash function may not include all relevant data. Review <code>_compute_periods_hash()</code> inputs.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="symptom-yesterdays-prices-shown-as-today">Symptom: Yesterday&#x27;s prices shown as today<a href="#symptom-yesterdays-prices-shown-as-today" class="hash-link" aria-label="Direct link to Symptom: Yesterday&#x27;s prices shown as today" title="Direct link to Symptom: Yesterday&#x27;s prices shown as today" translate="no"></a></h3>
<p><strong>Check:</strong></p>
<ol>
<li class=""><code>is_cache_valid()</code> logic in <code>coordinator/cache.py</code></li>
<li class="">Midnight turnover execution (Timer #2)</li>
<li class="">Cache clear confirmation in logs</li>
</ol>
<p><strong>Fix:</strong> Timer may not be firing. Check <code>_schedule_midnight_turnover()</code> registration.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="symptom-missing-translations">Symptom: Missing translations<a href="#symptom-missing-translations" class="hash-link" aria-label="Direct link to Symptom: Missing translations" title="Direct link to Symptom: Missing translations" translate="no"></a></h3>
<p><strong>Check:</strong></p>
<ol>
<li class=""><code>async_load_translations()</code> called at startup?</li>
<li class="">Translation files exist in <code>/translations/</code> and <code>/custom_translations/</code>?</li>
<li class="">Cache population: <code>_TRANSLATIONS_CACHE</code> keys</li>
</ol>
<p><strong>Fix:</strong> Re-install integration or restart HA to reload translation files.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="related-documentation">Related Documentation<a href="#related-documentation" class="hash-link" aria-label="Direct link to Related Documentation" title="Direct link to Related Documentation" translate="no"></a></h2>
<ul>
<li class=""><strong><a class="" href="/hass.tibber_prices/developer/timer-architecture">Timer Architecture</a></strong> - Timer system, scheduling, midnight coordination</li>
<li class=""><strong><a class="" href="/hass.tibber_prices/developer/architecture">Architecture</a></strong> - Overall system design, data flow</li>
<li class=""><strong><a href="https://github.com/jpawlowski/hass.tibber_prices/blob/v0.20.0/AGENTS.md" target="_blank" rel="noopener noreferrer" class="">AGENTS.md</a></strong> - Complete reference for AI development</li>
</ul></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="row margin-top--sm theme-doc-footer-edit-meta-row"><div class="col noPrint_WFHX"><a href="https://github.com/jpawlowski/hass.tibber_prices/tree/main/docs/developer/docs/caching-strategy.md" target="_blank" rel="noopener noreferrer" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_JAkA"><span class="theme-last-updated">Last updated<!-- --> on <b><time datetime="2025-12-06T01:37:06.000Z" itemprop="dateModified">Dec 6, 2025</time></b></span></div></div></footer></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/hass.tibber_prices/developer/timer-architecture"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">Timer Architecture</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/hass.tibber_prices/developer/api-reference"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">API Reference</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#overview" class="table-of-contents__link toc-highlight">Overview</a></li><li><a href="#1-persistent-api-data-cache" class="table-of-contents__link toc-highlight">1. Persistent API Data Cache</a></li><li><a href="#2-translation-cache" class="table-of-contents__link toc-highlight">2. Translation Cache</a></li><li><a href="#3-config-dictionary-cache" class="table-of-contents__link toc-highlight">3. Config Dictionary Cache</a><ul><li><a href="#datatransformer-config-cache" class="table-of-contents__link toc-highlight">DataTransformer Config Cache</a></li><li><a href="#periodcalculator-config-cache" class="table-of-contents__link toc-highlight">PeriodCalculator Config Cache</a></li></ul></li><li><a href="#4-period-calculation-cache" class="table-of-contents__link toc-highlight">4. Period Calculation Cache</a></li><li><a href="#5-transformation-cache-price-enrichment-only" class="table-of-contents__link toc-highlight">5. Transformation Cache (Price Enrichment Only)</a></li><li><a href="#cache-invalidation-flow" class="table-of-contents__link toc-highlight">Cache Invalidation Flow</a><ul><li><a href="#user-changes-options-config-flow" class="table-of-contents__link toc-highlight">User Changes Options (Config Flow)</a></li><li><a href="#midnight-turnover-day-transition" class="table-of-contents__link toc-highlight">Midnight Turnover (Day Transition)</a></li><li><a href="#tomorrow-data-arrives-1300" class="table-of-contents__link toc-highlight">Tomorrow Data Arrives (~13:00)</a></li></ul></li><li><a href="#cache-coordination" class="table-of-contents__link toc-highlight">Cache Coordination</a></li><li><a href="#performance-characteristics" class="table-of-contents__link toc-highlight">Performance Characteristics</a><ul><li><a href="#typical-operation-no-changes" class="table-of-contents__link toc-highlight">Typical Operation (No Changes)</a></li><li><a href="#after-midnight-turnover" class="table-of-contents__link toc-highlight">After Midnight Turnover</a></li><li><a href="#after-config-change" class="table-of-contents__link toc-highlight">After Config Change</a></li></ul></li><li><a href="#summary-table" class="table-of-contents__link toc-highlight">Summary Table</a></li><li><a href="#debugging-cache-issues" class="table-of-contents__link toc-highlight">Debugging Cache Issues</a><ul><li><a href="#symptom-stale-data-after-config-change" class="table-of-contents__link toc-highlight">Symptom: Stale data after config change</a></li><li><a href="#symptom-period-calculation-not-updating" class="table-of-contents__link toc-highlight">Symptom: Period calculation not updating</a></li><li><a href="#symptom-yesterdays-prices-shown-as-today" class="table-of-contents__link toc-highlight">Symptom: Yesterday&#39;s prices shown as today</a></li><li><a href="#symptom-missing-translations" class="table-of-contents__link toc-highlight">Symptom: Missing translations</a></li></ul></li><li><a href="#related-documentation" class="table-of-contents__link toc-highlight">Related Documentation</a></li></ul></div></div></div></div></main></div></div></div><footer class="theme-layout-footer footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Documentation</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://jpawlowski.github.io/hass.tibber_prices/user/" target="_blank" rel="noopener noreferrer" class="footer__link-item">User Guide<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a class="footer__link-item" href="/hass.tibber_prices/developer/intro">Developer Guide</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://github.com/jpawlowski/hass.tibber_prices/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub Issues<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://community.home-assistant.io/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Home Assistant Community<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">More</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://github.com/jpawlowski/hass.tibber_prices" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://github.com/jpawlowski/hass.tibber_prices/releases" target="_blank" rel="noopener noreferrer" class="footer__link-item">Release Notes<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Not affiliated with Tibber AS. Community-maintained custom integration. Built with Docusaurus.</div></div></div></footer></div>
</body>
</html>