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

214 lines
No EOL
48 KiB
HTML
Raw 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-architecture" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.9.2">
<title data-rh="true">Architecture | 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/architecture"><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="Architecture | Tibber Prices - Developer Guide"><meta data-rh="true" name="description" content="This document provides a visual overview of the integration&#x27;s architecture, focusing on end-to-end data flow and caching layers."><meta data-rh="true" property="og:description" content="This document provides a visual overview of the integration&#x27;s architecture, focusing on end-to-end data flow and caching layers."><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/architecture"><link data-rh="true" rel="alternate" href="https://jpawlowski.github.io/hass.tibber_prices/developer/architecture" hreflang="en"><link data-rh="true" rel="alternate" href="https://jpawlowski.github.io/hass.tibber_prices/developer/architecture" hreflang="x-default"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Architecture","item":"https://jpawlowski.github.io/hass.tibber_prices/developer/architecture"}]}</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/architecture">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 menu__link--active" aria-current="page" 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" 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/architecture">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">Architecture</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>Architecture</h1></header>
<p>This document provides a visual overview of the integration&#x27;s architecture, focusing on end-to-end data flow and caching layers.</p>
<p>For detailed implementation patterns, see <a href="https://github.com/jpawlowski/hass.tibber_prices/blob/v0.20.0/AGENTS.md" target="_blank" rel="noopener noreferrer" class=""><code>AGENTS.md</code></a>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="end-to-end-data-flow">End-to-End Data Flow<a href="#end-to-end-data-flow" class="hash-link" aria-label="Direct link to End-to-End Data Flow" title="Direct link to End-to-End Data Flow" translate="no"></a></h2>
<!-- -->
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="flow-description">Flow Description<a href="#flow-description" class="hash-link" aria-label="Direct link to Flow Description" title="Direct link to Flow Description" translate="no"></a></h3>
<ol>
<li class="">
<p><strong>Setup</strong> (<code>__init__.py</code>)</p>
<ul>
<li class="">Integration loads, creates coordinator instance</li>
<li class="">Registers entity platforms (sensor, binary_sensor)</li>
<li class="">Sets up custom services</li>
</ul>
</li>
<li class="">
<p><strong>Data Fetch</strong> (every 15 minutes)</p>
<ul>
<li class="">Coordinator triggers update via <code>api.py</code></li>
<li class="">API client checks <strong>persistent cache</strong> first (<code>coordinator/cache.py</code>)</li>
<li class="">If cache valid → return cached data</li>
<li class="">If cache stale → query Tibber GraphQL API</li>
<li class="">Store fresh data in persistent cache (survives HA restart)</li>
</ul>
</li>
<li class="">
<p><strong>Price Enrichment</strong></p>
<ul>
<li class="">Coordinator passes raw prices to <code>DataTransformer</code></li>
<li class="">Transformer checks <strong>transformation cache</strong> (memory)</li>
<li class="">If cache valid → return enriched data</li>
<li class="">If cache invalid → enrich via <code>price_utils.py</code> + <code>average_utils.py</code>
<ul>
<li class="">Calculate 24h trailing/leading averages</li>
<li class="">Calculate price differences (% from average)</li>
<li class="">Assign rating levels (LOW/NORMAL/HIGH)</li>
</ul>
</li>
<li class="">Store enriched data in transformation cache</li>
</ul>
</li>
<li class="">
<p><strong>Period Calculation</strong></p>
<ul>
<li class="">Coordinator passes enriched data to <code>PeriodCalculator</code></li>
<li class="">Calculator computes <strong>hash</strong> from prices + config</li>
<li class="">If hash matches cache → return cached periods</li>
<li class="">If hash differs → recalculate best/peak price periods</li>
<li class="">Store periods with new hash</li>
</ul>
</li>
<li class="">
<p><strong>Entity Updates</strong></p>
<ul>
<li class="">Coordinator provides complete data (prices + periods)</li>
<li class="">Sensors read values via unified handlers</li>
<li class="">Binary sensors evaluate period states</li>
<li class="">Entities update on quarter-hour boundaries (00/15/30/45)</li>
</ul>
</li>
<li class="">
<p><strong>Service Calls</strong></p>
<ul>
<li class="">Custom services access coordinator data directly</li>
<li class="">Return formatted responses (JSON, ApexCharts format)</li>
</ul>
</li>
</ol>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="caching-architecture">Caching Architecture<a href="#caching-architecture" class="hash-link" aria-label="Direct link to Caching Architecture" title="Direct link to Caching Architecture" translate="no"></a></h2>
<h3 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></h3>
<p>The integration uses <strong>5 independent caching layers</strong> for optimal performance:</p>
<table><thead><tr><th>Layer</th><th>Location</th><th>Lifetime</th><th>Invalidation</th><th>Memory</th></tr></thead><tbody><tr><td><strong>API Cache</strong></td><td><code>coordinator/cache.py</code></td><td>24h (user)<br>Until midnight (prices)</td><td>Automatic</td><td>50KB</td></tr><tr><td><strong>Translation Cache</strong></td><td><code>const.py</code></td><td>Until HA restart</td><td>Never</td><td>5KB</td></tr><tr><td><strong>Config Cache</strong></td><td><code>coordinator/*</code></td><td>Until config change</td><td>Explicit</td><td>1KB</td></tr><tr><td><strong>Period Cache</strong></td><td><code>coordinator/periods.py</code></td><td>Until data/config change</td><td>Hash-based</td><td>10KB</td></tr><tr><td><strong>Transformation Cache</strong></td><td><code>coordinator/data_transformation.py</code></td><td>Until midnight/config</td><td>Automatic</td><td>60KB</td></tr></tbody></table>
<p><strong>Total cache overhead:</strong> ~126KB per coordinator instance (main entry + subentries)</p>
<h3 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></h3>
<!-- -->
<p><strong>Key insight:</strong> No cascading invalidations - each cache is independent and rebuilds on-demand.</p>
<p>For detailed cache behavior, see <a class="" href="/hass.tibber_prices/developer/caching-strategy">Caching Strategy</a>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="component-responsibilities">Component Responsibilities<a href="#component-responsibilities" class="hash-link" aria-label="Direct link to Component Responsibilities" title="Direct link to Component Responsibilities" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="core-components">Core Components<a href="#core-components" class="hash-link" aria-label="Direct link to Core Components" title="Direct link to Core Components" translate="no"></a></h3>
<table><thead><tr><th>Component</th><th>File</th><th>Responsibility</th></tr></thead><tbody><tr><td><strong>API Client</strong></td><td><code>api.py</code></td><td>GraphQL queries to Tibber, retry logic, error handling</td></tr><tr><td><strong>Coordinator</strong></td><td><code>coordinator.py</code></td><td>Update orchestration, cache management, absolute-time scheduling with boundary tolerance</td></tr><tr><td><strong>Data Transformer</strong></td><td><code>coordinator/data_transformation.py</code></td><td>Price enrichment (averages, ratings, differences)</td></tr><tr><td><strong>Period Calculator</strong></td><td><code>coordinator/periods.py</code></td><td>Best/peak price period calculation with relaxation</td></tr><tr><td><strong>Sensors</strong></td><td><code>sensor/</code></td><td>80+ entities for prices, levels, ratings, statistics</td></tr><tr><td><strong>Binary Sensors</strong></td><td><code>binary_sensor/</code></td><td>Period indicators (best/peak price active)</td></tr><tr><td><strong>Services</strong></td><td><code>services/</code></td><td>Custom service endpoints (get_chartdata, get_apexcharts_yaml, refresh_user_data)</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sensor-architecture-calculator-pattern">Sensor Architecture (Calculator Pattern)<a href="#sensor-architecture-calculator-pattern" class="hash-link" aria-label="Direct link to Sensor Architecture (Calculator Pattern)" title="Direct link to Sensor Architecture (Calculator Pattern)" translate="no"></a></h3>
<p>The sensor platform uses <strong>Calculator Pattern</strong> for clean separation of concerns (refactored Nov 2025):</p>
<table><thead><tr><th>Component</th><th>Files</th><th>Lines</th><th>Responsibility</th></tr></thead><tbody><tr><td><strong>Entity Class</strong></td><td><code>sensor/core.py</code></td><td>909</td><td>Entity lifecycle, coordinator, delegates to calculators</td></tr><tr><td><strong>Calculators</strong></td><td><code>sensor/calculators/</code></td><td>1,838</td><td>Business logic (8 specialized calculators)</td></tr><tr><td><strong>Attributes</strong></td><td><code>sensor/attributes/</code></td><td>1,209</td><td>State presentation (8 specialized modules)</td></tr><tr><td><strong>Routing</strong></td><td><code>sensor/value_getters.py</code></td><td>276</td><td>Centralized sensor → calculator mapping</td></tr><tr><td><strong>Chart Export</strong></td><td><code>sensor/chart_data.py</code></td><td>144</td><td>Service call handling, YAML parsing</td></tr><tr><td><strong>Helpers</strong></td><td><code>sensor/helpers.py</code></td><td>188</td><td>Aggregation functions, utilities</td></tr></tbody></table>
<p><strong>Calculator Package</strong> (<code>sensor/calculators/</code>):</p>
<ul>
<li class=""><code>base.py</code> - Abstract BaseCalculator with coordinator access</li>
<li class=""><code>interval.py</code> - Single interval calculations (current/next/previous)</li>
<li class=""><code>rolling_hour.py</code> - 5-interval rolling windows</li>
<li class=""><code>daily_stat.py</code> - Calendar day min/max/avg statistics</li>
<li class=""><code>window_24h.py</code> - Trailing/leading 24h windows</li>
<li class=""><code>volatility.py</code> - Price volatility analysis</li>
<li class=""><code>trend.py</code> - Complex trend analysis with caching</li>
<li class=""><code>timing.py</code> - Best/peak price period timing</li>
<li class=""><code>metadata.py</code> - Home/metering metadata</li>
</ul>
<p><strong>Benefits:</strong></p>
<ul>
<li class="">58% reduction in core.py (2,170 → 909 lines)</li>
<li class="">Clear separation: Calculators (logic) vs Attributes (presentation)</li>
<li class="">Independent testability for each calculator</li>
<li class="">Easy to add sensors: Choose calculation pattern, add to routing</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="helper-utilities">Helper Utilities<a href="#helper-utilities" class="hash-link" aria-label="Direct link to Helper Utilities" title="Direct link to Helper Utilities" translate="no"></a></h3>
<table><thead><tr><th>Utility</th><th>File</th><th>Purpose</th></tr></thead><tbody><tr><td><strong>Price Utils</strong></td><td><code>utils/price.py</code></td><td>Rating calculation, enrichment, level aggregation</td></tr><tr><td><strong>Average Utils</strong></td><td><code>utils/average.py</code></td><td>Trailing/leading 24h average calculations</td></tr><tr><td><strong>Entity Utils</strong></td><td><code>entity_utils/</code></td><td>Shared icon/color/attribute logic</td></tr><tr><td><strong>Translations</strong></td><td><code>const.py</code></td><td>Translation loading and caching</td></tr></tbody></table>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="key-patterns">Key Patterns<a href="#key-patterns" class="hash-link" aria-label="Direct link to Key Patterns" title="Direct link to Key Patterns" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-dual-translation-system">1. Dual Translation System<a href="#1-dual-translation-system" class="hash-link" aria-label="Direct link to 1. Dual Translation System" title="Direct link to 1. Dual Translation System" translate="no"></a></h3>
<ul>
<li class=""><strong>Standard translations</strong> (<code>/translations/*.json</code>): HA-compliant schema for entity names</li>
<li class=""><strong>Custom translations</strong> (<code>/custom_translations/*.json</code>): Extended descriptions, usage tips</li>
<li class="">Both loaded at integration setup, cached in memory</li>
<li class="">Access via <code>get_translation()</code> helper function</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-price-data-enrichment">2. Price Data Enrichment<a href="#2-price-data-enrichment" class="hash-link" aria-label="Direct link to 2. Price Data Enrichment" title="Direct link to 2. Price Data Enrichment" translate="no"></a></h3>
<p>All quarter-hourly price intervals get augmented via <code>utils/price.py</code>:</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"># Original from Tibber API</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 plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;startsAt&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;2025-11-03T14:00:00+01:00&quot;</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;total&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.2534</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;level&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;NORMAL&quot;</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 plain"></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"></span><span class="token comment" style="color:#999988;font-style:italic"># After enrichment (utils/price.py)</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 plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;startsAt&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;2025-11-03T14:00:00+01:00&quot;</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;total&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.2534</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;level&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;NORMAL&quot;</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;trailing_avg_24h&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.2312</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># ← Added: 24h trailing average</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;difference&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">9.6</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># ← Added: % diff from trailing avg</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;rating_level&quot;</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;NORMAL&quot;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># ← Added: LOW/NORMAL/HIGH based on thresholds</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="3-quarter-hour-precision">3. Quarter-Hour Precision<a href="#3-quarter-hour-precision" class="hash-link" aria-label="Direct link to 3. Quarter-Hour Precision" title="Direct link to 3. Quarter-Hour Precision" translate="no"></a></h3>
<ul>
<li class=""><strong>API polling</strong>: Every 15 minutes (coordinator fetch cycle)</li>
<li class=""><strong>Entity updates</strong>: On 00/15/30/45-minute boundaries via <code>coordinator/listeners.py</code></li>
<li class=""><strong>Timer scheduling</strong>: Uses <code>async_track_utc_time_change(minute=[0, 15, 30, 45], second=0)</code>
<ul>
<li class="">HA may trigger ±few milliseconds before/after exact boundary</li>
<li class="">Smart boundary tolerance (±2 seconds) handles scheduling jitter in <code>sensor/helpers.py</code></li>
<li class="">If HA schedules at 14:59:58 → rounds to 15:00:00 (shows new interval data)</li>
<li class="">If HA restarts at 14:59:30 → stays at 14:45:00 (shows current interval data)</li>
</ul>
</li>
<li class=""><strong>Absolute time tracking</strong>: Timer plans for <strong>all future boundaries</strong> (not relative delays)<!-- -->
<ul>
<li class="">Prevents double-updates (if triggered at 14:59:58, next trigger is 15:15:00, not 15:00:00)</li>
</ul>
</li>
<li class=""><strong>Result</strong>: Current price sensors update without waiting for next API poll</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-calculator-pattern-sensor-platform">4. Calculator Pattern (Sensor Platform)<a href="#4-calculator-pattern-sensor-platform" class="hash-link" aria-label="Direct link to 4. Calculator Pattern (Sensor Platform)" title="Direct link to 4. Calculator Pattern (Sensor Platform)" translate="no"></a></h3>
<p>Sensors organized by <strong>calculation method</strong> (refactored Nov 2025):</p>
<p><strong>Unified Handler Methods</strong> (<code>sensor/core.py</code>):</p>
<ul>
<li class=""><code>_get_interval_value(offset, type)</code> - current/next/previous intervals</li>
<li class=""><code>_get_rolling_hour_value(offset, type)</code> - 5-interval rolling windows</li>
<li class=""><code>_get_daily_stat_value(day, stat_func)</code> - calendar day min/max/avg</li>
<li class=""><code>_get_24h_window_value(stat_func)</code> - trailing/leading statistics</li>
</ul>
<p><strong>Routing</strong> (<code>sensor/value_getters.py</code>):</p>
<ul>
<li class="">Single source of truth mapping 80+ entity keys to calculator methods</li>
<li class="">Organized by calculation type (Interval, Rolling Hour, Daily Stats, etc.)</li>
</ul>
<p><strong>Calculators</strong> (<code>sensor/calculators/</code>):</p>
<ul>
<li class="">Each calculator inherits from <code>BaseCalculator</code> with coordinator access</li>
<li class="">Focused responsibility: <code>IntervalCalculator</code>, <code>TrendCalculator</code>, etc.</li>
<li class="">Complex logic isolated (e.g., <code>TrendCalculator</code> has internal caching)</li>
</ul>
<p><strong>Attributes</strong> (<code>sensor/attributes/</code>):</p>
<ul>
<li class="">Separate from business logic, handles state presentation</li>
<li class="">Builds extra_state_attributes dicts for entity classes</li>
<li class="">Unified builders: <code>build_sensor_attributes()</code>, <code>build_extra_state_attributes()</code></li>
</ul>
<p><strong>Benefits:</strong></p>
<ul>
<li class="">Minimal code duplication across 80+ sensors</li>
<li class="">Clear separation of concerns (calculation vs presentation)</li>
<li class="">Easy to extend: Add sensor → choose pattern → add to routing</li>
<li class="">Independent testability for each component</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="api-call-reduction">API Call Reduction<a href="#api-call-reduction" class="hash-link" aria-label="Direct link to API Call Reduction" title="Direct link to API Call Reduction" translate="no"></a></h3>
<ul>
<li class=""><strong>Without caching:</strong> 96 API calls/day (every 15 min)</li>
<li class=""><strong>With caching:</strong> ~1-2 API calls/day (only when cache expires)</li>
<li class=""><strong>Reduction:</strong> ~98%</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cpu-optimization">CPU Optimization<a href="#cpu-optimization" class="hash-link" aria-label="Direct link to CPU Optimization" title="Direct link to CPU Optimization" translate="no"></a></h3>
<table><thead><tr><th>Optimization</th><th>Location</th><th>Savings</th></tr></thead><tbody><tr><td>Config caching</td><td><code>coordinator/*</code></td><td>~50% on config checks</td></tr><tr><td>Period caching</td><td><code>coordinator/periods.py</code></td><td>~70% on period recalculation</td></tr><tr><td>Lazy logging</td><td>Throughout</td><td>~15% on log-heavy operations</td></tr><tr><td>Import optimization</td><td>Module structure</td><td>~20% faster loading</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="memory-usage">Memory Usage<a href="#memory-usage" class="hash-link" aria-label="Direct link to Memory Usage" title="Direct link to Memory Usage" translate="no"></a></h3>
<ul>
<li class=""><strong>Per coordinator instance:</strong> ~126KB cache overhead</li>
<li class=""><strong>Typical setup:</strong> 1 main + 2 subentries = ~378KB total</li>
<li class=""><strong>Redundancy eliminated:</strong> 14% reduction (10KB saved per coordinator)</li>
</ul>
<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, coordination (3 independent timers)</li>
<li class=""><strong><a class="" href="/hass.tibber_prices/developer/caching-strategy">Caching Strategy</a></strong> - Detailed cache behavior, invalidation, debugging</li>
<li class=""><strong><a class="" href="/hass.tibber_prices/developer/setup">Setup Guide</a></strong> - Development environment setup</li>
<li class=""><strong><a class="" href="/hass.tibber_prices/developer/testing">Testing Guide</a></strong> - How to test changes</li>
<li class=""><strong><a class="" href="/hass.tibber_prices/developer/release-management">Release Management</a></strong> - Release workflow and versioning</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/architecture.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/intro"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">Developer Documentation</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/hass.tibber_prices/developer/timer-architecture"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Timer Architecture</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="#end-to-end-data-flow" class="table-of-contents__link toc-highlight">End-to-End Data Flow</a><ul><li><a href="#flow-description" class="table-of-contents__link toc-highlight">Flow Description</a></li></ul></li><li><a href="#caching-architecture" class="table-of-contents__link toc-highlight">Caching Architecture</a><ul><li><a href="#overview" class="table-of-contents__link toc-highlight">Overview</a></li><li><a href="#cache-coordination" class="table-of-contents__link toc-highlight">Cache Coordination</a></li></ul></li><li><a href="#component-responsibilities" class="table-of-contents__link toc-highlight">Component Responsibilities</a><ul><li><a href="#core-components" class="table-of-contents__link toc-highlight">Core Components</a></li><li><a href="#sensor-architecture-calculator-pattern" class="table-of-contents__link toc-highlight">Sensor Architecture (Calculator Pattern)</a></li><li><a href="#helper-utilities" class="table-of-contents__link toc-highlight">Helper Utilities</a></li></ul></li><li><a href="#key-patterns" class="table-of-contents__link toc-highlight">Key Patterns</a><ul><li><a href="#1-dual-translation-system" class="table-of-contents__link toc-highlight">1. Dual Translation System</a></li><li><a href="#2-price-data-enrichment" class="table-of-contents__link toc-highlight">2. Price Data Enrichment</a></li><li><a href="#3-quarter-hour-precision" class="table-of-contents__link toc-highlight">3. Quarter-Hour Precision</a></li><li><a href="#4-calculator-pattern-sensor-platform" class="table-of-contents__link toc-highlight">4. Calculator Pattern (Sensor Platform)</a></li></ul></li><li><a href="#performance-characteristics" class="table-of-contents__link toc-highlight">Performance Characteristics</a><ul><li><a href="#api-call-reduction" class="table-of-contents__link toc-highlight">API Call Reduction</a></li><li><a href="#cpu-optimization" class="table-of-contents__link toc-highlight">CPU Optimization</a></li><li><a href="#memory-usage" class="table-of-contents__link toc-highlight">Memory Usage</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>