<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://developers.home-assistant.io/blog</id>
    <title>Home Assistant Developer Docs Blog</title>
    <updated>2026-04-02T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://developers.home-assistant.io/blog"/>
    <subtitle>Home Assistant Developer Docs Blog</subtitle>
    <icon>https://developers.home-assistant.io/img/favicon.png</icon>
    <entry>
        <title type="html"><![CDATA[Migrating app builds to Docker BuildKit]]></title>
        <id>https://developers.home-assistant.io/blog/2026/04/02/builder-migration</id>
        <link href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration"/>
        <updated>2026-04-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The legacy home-assistant/builder container and the old home-assistant/builder GitHub Action have been retired. We recommend migrating all GitHub workflows and Dockerfiles for apps (formerly add-ons) as described in this post.]]></summary>
        <content type="html"><![CDATA[<p>The legacy <code>home-assistant/builder</code> container and the old <code>home-assistant/builder</code> GitHub Action have been retired. We recommend migrating all GitHub workflows and Dockerfiles for apps (formerly add-ons) as described in this post.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-changed-and-why">What changed and why<a href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration#what-changed-and-why" class="hash-link" aria-label="Direct link to What changed and why" title="Direct link to What changed and why" translate="no">​</a></h2>
<p>The old builder ran every architecture build inside a single privileged Docker-in-Docker container using QEMU emulation. This was slow, required elevated privileges, and those who were already familiar with Docker needed to learn how to use the custom Home Assistant's builder container. The old builder also had unnecessary maintenance overhead. Today, what the builder does can be fully replaced with Docker BuildKit, which is natively supported on GitHub Actions runners and has built-in multi-arch support with QEMU emulation if needed.</p>
<p>For your CI, the replacement is a set of focused <a href="https://github.com/home-assistant/builder" target="_blank" rel="noopener noreferrer" class="">composite GitHub Actions</a> that delegate building to the runner's native Docker with Docker BuildKit. Outside the CI, the migration means that your <code>Dockerfile</code> is now the single source of truth for building your app image, and you can use <code>docker build</code> directly to build and test your app locally without needing to use the builder container.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="migration-process">Migration process<a href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration#migration-process" class="hash-link" aria-label="Direct link to Migration process" title="Direct link to Migration process" translate="no">​</a></h2>
<p>The migration has two parts: updating your Dockerfiles and updating your GitHub Actions workflows.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="update-dockerfiles">Update Dockerfiles<a href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration#update-dockerfiles" class="hash-link" aria-label="Direct link to Update Dockerfiles" title="Direct link to Update Dockerfiles" translate="no">​</a></h3>
<p>The new build workflow doesn't use <code>build.yaml</code> anymore. Move the content into your <code>Dockerfile</code> as follows:</p>
<ul>
<li class="">
<p><strong><code>build_from</code></strong> - replace the <code>build_from</code> key in <code>build.yaml</code> with a <code>FROM</code> statement in your <code>Dockerfile</code>:</p>
<div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">FROM ghcr.io/home-assistant/base:latest</span><br></span></code></pre></div></div>
<p>As the base images are now published as multi-platform manifests, there is usually no need to define per-arch base images anymore. The <code>build-image</code> action still supplies <code>BUILD_ARCH</code> as a build argument though, so you can use that in your <code>Dockerfile</code> if you need to use it in the template for the base image name.</p>
</li>
<li class="">
<p><strong><code>labels</code></strong> - move any custom Docker labels directly into your <code>Dockerfile</code> with a <code>LABEL</code> statement:</p>
<div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">LABEL \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    org.opencontainers.image.title="Your awesome app" \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    org.opencontainers.image.description="Description of your app." \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    org.opencontainers.image.source="https://github.com/your/repo" \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    org.opencontainers.image.licenses="Apache License 2.0"</span><br></span></code></pre></div></div>
<p>If you are creating a custom workflow, note that the legacy builder used to add the <code>io.hass.type</code>, <code>io.hass.name</code>, <code>io.hass.description</code>, and <code>io.hass.url</code> labels automatically. The new actions do not infer these values, so add them explicitly via the <code>labels</code> input of the <code>build-image</code> (or similar) action.</p>
</li>
<li class="">
<p><strong><code>args</code></strong> - move custom build arguments into your <code>Dockerfile</code> as <code>ARG</code> definitions with default values:</p>
<div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">ARG MY_BUILD_ARG="default-value"</span><br></span></code></pre></div></div>
<p>Default values in <code>ARG</code> replace what was previously supplied via <code>build.yaml</code>'s <code>args</code> dictionary. They can still be overridden at build time with <code>--build-arg</code> if needed.</p>
</li>
</ul>
<p>With the content of <code>build.yaml</code> migrated, you can delete the file from your repository.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="update-github-actions-workflows">Update GitHub Actions workflows<a href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration#update-github-actions-workflows" class="hash-link" aria-label="Direct link to Update GitHub Actions workflows" title="Direct link to Update GitHub Actions workflows" translate="no">​</a></h3>
<p>Remove any workflow steps using <code>home-assistant/builder@master</code> and replace them with the new composite actions. See the <a href="https://github.com/home-assistant/apps-example/blob/main/.github/workflows/builder.yaml" target="_blank" rel="noopener noreferrer" class="">example workflow</a> in our example app repository for a complete working example. Alternatively, use the <a href="https://github.com/home-assistant/builder?tab=readme-ov-file#example-workflow" target="_blank" rel="noopener noreferrer" class="">individual actions</a> in a more custom workflow as needed.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="image-naming">Image naming<a href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration#image-naming" class="hash-link" aria-label="Direct link to Image naming" title="Direct link to Image naming" translate="no">​</a></h3>
<p>The preferred way to reference a published app image is now the <strong>generic (multi-arch) name</strong> without an architecture prefix:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># config.yaml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"ghcr.io/my-org/my-app"</span><br></span></code></pre></div></div>
<p>The <code>{arch}</code> placeholder (e.g. <code>ghcr.io/my-org/{arch}-my-app</code>) is still supported as a compatibility fallback, but it's encouraged to use the generic name and let the manifest handle the platform resolution.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="local-builds">Local builds<a href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration#local-builds" class="hash-link" aria-label="Direct link to Local builds" title="Direct link to Local builds" translate="no">​</a></h3>
<p>After updating your <code>Dockerfile</code>, you can use <code>docker build</code> to build the app image directly - you can refer to <a class="" href="https://developers.home-assistant.io/docs/apps/testing">Local app testing</a> for more details.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="apps-built-locally-by-supervisor">Apps built locally by Supervisor<a href="https://developers.home-assistant.io/blog/2026/04/02/builder-migration#apps-built-locally-by-supervisor" class="hash-link" aria-label="Direct link to Apps built locally by Supervisor" title="Direct link to Apps built locally by Supervisor" translate="no">​</a></h2>
<p>For backward compatibility, Supervisor still reads <code>build.yaml</code> file if it's present and populates the image build arguments with values read from this file. This will produce warnings and eventually be removed in the future, so it's recommended to migrate to the new Dockerfile-based approach as described above.</p>]]></content>
        <author>
            <name>Jan Čermák</name>
            <uri>https://github.com/sairon</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[New infrared entity platform for IR device integrations]]></title>
        <id>https://developers.home-assistant.io/blog/2026/03/30/infrared-entity-platform</id>
        <link href="https://developers.home-assistant.io/blog/2026/03/30/infrared-entity-platform"/>
        <updated>2026-03-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Home Assistant now has an infrared entity platform that decouples IR emitter hardware from the devices they control. Instead of each device integration talking directly to specific IR hardware, emitter integrations (like esphome) expose InfraredEntity instances, and device integrations (like lg_infrared) send commands through them via helper functions.]]></summary>
        <content type="html"><![CDATA[<p>Home Assistant now has an <code>infrared</code> entity platform that decouples IR emitter hardware from the devices they control. Instead of each device integration talking directly to specific IR hardware, emitter integrations (like <code>esphome</code>) expose <code>InfraredEntity</code> instances, and device integrations (like <code>lg_infrared</code>) send commands through them via helper functions.</p>
<p>See the <a href="https://github.com/home-assistant/architecture/discussions/1316" target="_blank" rel="noopener noreferrer" class="">architecture discussion</a> for the full background.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="architecture">Architecture<a href="https://developers.home-assistant.io/blog/2026/03/30/infrared-entity-platform#architecture" class="hash-link" aria-label="Direct link to Architecture" title="Direct link to Architecture" translate="no">​</a></h2>
<p>The infrared domain sits between two types of integrations:</p>
<ul>
<li class=""><strong>Emitter integrations</strong> (ESPHome, Broadlink, …) implement the <code>InfraredEntity</code> base class to provide hardware-specific IR transmission.</li>
<li class=""><strong>Consumer integrations</strong> (LG, Samsung, Daikin, …) use helper functions to send device-specific IR commands through available emitters.</li>
</ul>
<p>Users select which emitter to use during the consumer integration's config flow.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="implementing-an-emitter-integration">Implementing an emitter integration<a href="https://developers.home-assistant.io/blog/2026/03/30/infrared-entity-platform#implementing-an-emitter-integration" class="hash-link" aria-label="Direct link to Implementing an emitter integration" title="Direct link to Implementing an emitter integration" translate="no">​</a></h2>
<p>Emitter integrations provide the <code>infrared</code> platform by subclassing <code>InfraredEntity</code> and implementing <code>async_send_command</code>. The command's <code>get_raw_timings()</code> method returns protocol-agnostic timing data that the hardware can transmit:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">infrared </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> InfraredCommand</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> InfraredEntity</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyInfraredEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">InfraredEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""My IR transmitter."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">async_send_command</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> command</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> InfraredCommand</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Send an IR command."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        timings </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            interval</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> timing </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> command</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_raw_timings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> interval </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">timing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">high_us</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token plain">timing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">low_us</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">_device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">transmit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            carrier_frequency</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">command</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">modulation</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            timings</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">timings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>The raw protocol-agnostic timings should be converted to the specific format required by the hardware.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="building-a-consumer-integration">Building a consumer integration<a href="https://developers.home-assistant.io/blog/2026/03/30/infrared-entity-platform#building-a-consumer-integration" class="hash-link" aria-label="Direct link to Building a consumer integration" title="Direct link to Building a consumer integration" translate="no">​</a></h2>
<p>Consumer integrations control IR devices by sending commands through an emitter entity. They don't interact with IR hardware directly.</p>
<p><strong>1. Declare the dependency</strong> in <code>manifest.json</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  "dependencies": ["infrared"]</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></span></code></pre></div></div>
<p><strong>2. Let the user pick an emitter</strong> in the config flow:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> infrared</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">emitters </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> infrared</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">async_get_emitters</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">hass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> emitters</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">async_abort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">reason</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"no_emitters"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p><strong>3. Send IR commands</strong> using the helper function and the <a href="https://github.com/home-assistant-libs/infrared-protocols" target="_blank" rel="noopener noreferrer" class=""><code>infrared-protocols</code></a> library:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> infrared_protocols</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">codes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">lg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">tv </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> LGTVCode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> make_lg_tv_command</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> infrared</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> infrared</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">async_send_command</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    hass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">_infrared_entity_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    make_lg_tv_command</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">LGTVCode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">VOLUME_UP</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    context</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">_context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ir-protocols-and-codes">IR protocols and codes<a href="https://developers.home-assistant.io/blog/2026/03/30/infrared-entity-platform#ir-protocols-and-codes" class="hash-link" aria-label="Direct link to IR protocols and codes" title="Direct link to IR protocols and codes" translate="no">​</a></h2>
<p>IR protocol encoders and device code sets live outside Home Assistant in the <a href="https://github.com/home-assistant-libs/infrared-protocols" target="_blank" rel="noopener noreferrer" class=""><code>infrared-protocols</code></a> library. Common protocols (NEC, Samsung, etc.) and well-known device codes should be contributed there. For niche or proprietary protocols, a separate third-party library can also be used.</p>
<p>For full details, see the <a class="" href="https://developers.home-assistant.io/docs/core/entity/infrared">infrared entity documentation</a>.</p>]]></content>
        <author>
            <name>Abílio Costa</name>
            <uri>https://github.com/abmantis</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Frontend component updates 2026.4]]></title>
        <id>https://developers.home-assistant.io/blog/2026/03/25/frontend-component-updates-2026.4</id>
        <link href="https://developers.home-assistant.io/blog/2026/03/25/frontend-component-updates-2026.4"/>
        <updated>2026-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We do not officially support or encourage custom card developers to use our built in components. This component APIs can always change and you should build your card as independent component.]]></summary>
        <content type="html"><![CDATA[<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>We do not officially support or encourage custom card developers to use our built in components. This component APIs can always change and you should build your card as independent component.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ha-input">ha-input<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-component-updates-2026.4#ha-input" class="hash-link" aria-label="Direct link to ha-input" title="Direct link to ha-input" translate="no">​</a></h2>
<p>We keep migrating our Material Design based components to Web Awesome based. This time we migrated the input components, which leads to an API change but the look and feel stays the same for now.</p>
<ul>
<li class=""><code>ha-input</code> is the successor of <code>ha-textfield</code>
<ul>
<li class=""><code>ha-textfield</code> API stays but the component is migrated to use <code>ha-input</code> internally and will be removed in 2026.5</li>
<li class="">Also replaces <code>ha-outlined-text-field</code></li>
</ul>
</li>
<li class=""><code>ha-input-search</code> replaces <code>search-input</code> and <code>search-input-outlined</code></li>
<li class=""><code>ha-input-multi</code> replaces <code>ha-multi-textfield</code></li>
<li class=""><code>ha-input-copy</code> replaces <code>copy-textfield</code></li>
</ul>
<p>This component also introduces new semantic theme variables for form backgrounds:</p>
<div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token variable" style="color:rgb(191, 199, 213)">--ha-color-form-background</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">var</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token variable" style="color:rgb(191, 199, 213)">--ha-color-neutral-95</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token variable" style="color:rgb(191, 199, 213)">--ha-color-form-background-hover</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">var</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token variable" style="color:rgb(191, 199, 213)">--ha-color-neutral-90</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token variable" style="color:rgb(191, 199, 213)">--ha-color-form-background-disabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">var</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token variable" style="color:rgb(191, 199, 213)">--ha-color-neutral-80</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="date-picker">Date picker<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-component-updates-2026.4#date-picker" class="hash-link" aria-label="Direct link to Date picker" title="Direct link to Date picker" translate="no">​</a></h2>
<p>We finally removed the Vue 2 dependency by replacing the date and date range picker with <a href="https://wicky.nillia.ms/cally/" target="_blank" rel="noopener noreferrer" class="">Cally</a>.</p>]]></content>
        <author>
            <name>Wendelin Peleska</name>
            <uri>https://github.com/wendevlin</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Frontend new way of dialogs]]></title>
        <id>https://developers.home-assistant.io/blog/2026/03/25/frontend-dialogs</id>
        <link href="https://developers.home-assistant.io/blog/2026/03/25/frontend-dialogs"/>
        <updated>2026-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The Problem]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem">The Problem<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-dialogs#the-problem" class="hash-link" aria-label="Direct link to The Problem" title="Direct link to The Problem" translate="no">​</a></h2>
<p>Each dialog managed by the dialog manager was only opened once and stayed in the DOM for the lifetime of the application. This causes:</p>
<ul>
<li class=""><strong>More memory usage</strong>: Dialogs accumulate in the DOM even when not visible</li>
<li class=""><strong>More bugs because of missing state reset</strong>: Dialog state persists between opens, leading to stale data or unexpected behavior</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-solution-dialogmixin">The Solution: DialogMixin<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-dialogs#the-solution-dialogmixin" class="hash-link" aria-label="Direct link to The Solution: DialogMixin" title="Direct link to The Solution: DialogMixin" translate="no">​</a></h2>
<p>We implemented a new way of handling dialogs using <code>DialogMixin</code>. With this approach:</p>
<ul>
<li class=""><strong>Dialogs are created when opened and destroyed when closed</strong>: No need to manually reset the state of the dialog when it is closed</li>
<li class=""><strong>Closed events are automatically handled</strong>: The dialog mixin takes care of cleanup</li>
<li class=""><strong>Subscribe mixin can now be used in dialogs</strong>: Since dialogs are properly destroyed, subscriptions are cleaned up automatically</li>
<li class=""><strong>Use normal Lit lifecycle methods</strong>: Use <code>connectedCallback</code> to initialize when the dialog is opened instead of relying on the <code>showDialog</code> method</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="example">Example<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-dialogs#example" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example" translate="no">​</a></h2>
<p>Check out <code>ha-dialog-date-picker</code> for a reference implementation. <code>DialogMixin</code> adds dialog params to <code>this.params</code> if available.</p>]]></content>
        <author>
            <name>Wendelin Peleska</name>
            <uri>https://github.com/wendevlin</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Frontend lazy context]]></title>
        <id>https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context</id>
        <link href="https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context"/>
        <updated>2026-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[What is a context?]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-a-context">What is a context?<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context#what-is-a-context" class="hash-link" aria-label="Direct link to What is a context?" title="Direct link to What is a context?" translate="no">​</a></h2>
<p>In the Home Assistant frontend, a <a href="https://lit.dev/docs/data/context/" target="_blank" rel="noopener noreferrer" class="">Context</a> is a way to share data across the component tree without explicitly passing it through every level as a property. Instead of threading the <code>hass</code> object down through multiple layers of components, you can provide specific pieces of data via context and consume them only where needed.</p>
<p>The key benefits of using context over passing the entire <code>hass</code> object are:</p>
<ul>
<li class=""><strong>Easier usage</strong>: Components can directly consume the data they need without requiring parent components to pass it down. This reduces prop drilling and makes components more self-contained and reusable.</li>
<li class=""><strong>Reducing unnecessary component re-renders</strong>: When a component receives <code>hass</code> as a property, any change to <code>hass</code> triggers a re-render of that component and all its children—even if the component only cares about a small subset of the data. By using context to provide only the specific data a component needs, you ensure that components only re-render when their actual dependencies change, leading to better performance and a more responsive UI.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introducing-lazycontext">Introducing LazyContext<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context#introducing-lazycontext" class="hash-link" aria-label="Direct link to Introducing LazyContext" title="Direct link to Introducing LazyContext" translate="no">​</a></h2>
<p>We've introduced a new <code>LazyContext</code> pattern that should replace the traditional subscription-based approach and the usage of the <code>SubscribeMixin</code>. Previously, components would subscribe to data sources and manage subscription lifecycles manually, often leading to boilerplate code and potential memory leaks if subscriptions weren't properly cleaned up.</p>
<p><code>LazyContext</code> simplifies this by:</p>
<ul>
<li class=""><strong>Lazy loading</strong>: Data is only fetched when a component actually consumes the context</li>
<li class=""><strong>Automatic cleanup</strong>: Subscriptions are managed automatically</li>
<li class=""><strong>Shared state</strong>: Multiple components consuming the same context share a single subscription</li>
<li class=""><strong>Optimized re-renders</strong>: Only components that consume the context re-render when data changes</li>
</ul>
<p>This approach centralizes data-fetching logic and makes it easier to reason about when and how data flows through your application.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="examples">Examples<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context#examples" class="hash-link" aria-label="Direct link to Examples" title="Direct link to Examples" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="defining-a-lazycontext">Defining a LazyContext<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context#defining-a-lazycontext" class="hash-link" aria-label="Direct link to Defining a LazyContext" title="Direct link to Defining a LazyContext" translate="no">​</a></h3>
<p>To define a lazy context, use <code>LazyContextProvider</code> and provide a fetch function:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LazyContextProvider</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  context</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> labelsContext</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">subscribeFn</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> setValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">subscribeLabelRegistry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> setValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="consuming-a-context-with-lit">Consuming a context with lit<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context#consuming-a-context-with-lit" class="hash-link" aria-label="Direct link to Consuming a context with lit" title="Direct link to Consuming a context with lit" translate="no">​</a></h3>
<p>To consume a context in a component, use the <code>@consume</code> decorator:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> context</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> labelsContext</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> subscribe</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> _labels</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> LabelRegistryEntry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<p>Check out the updated custom card example to use it in vanilla JS: <a class="" href="https://developers.home-assistant.io/docs/frontend/custom-ui/custom-card#defining-your-card">Custom card example</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-transform-for-derived-data">Using @transform for derived Data<a href="https://developers.home-assistant.io/blog/2026/03/25/frontend-lazy-context#using-transform-for-derived-data" class="hash-link" aria-label="Direct link to Using @transform for derived Data" title="Direct link to Using @transform for derived Data" translate="no">​</a></h3>
<p><em>Only available within the home-assistant frontend codebase</em></p>
<p>The <code>@transform</code> decorator allows you to derive data from a context value, ensuring your component only re-renders when the transformed value actually changes.</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> context</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> statesContext</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> subscribe</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator at operator" style="color:rgb(137, 221, 255)">@</span><span class="token decorator function" style="color:rgb(130, 170, 255)">transform</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">transformer</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> HuiButtonCard</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> entityStates</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> HassEntities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">_config</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token plain">entity </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> entityStates</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">_config</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token plain">entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  watch</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"_config"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> _stateObj</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> HassEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<p>With <code>@transform</code>, even if the full states object updates, your component will only re-render if the transformed result (<code>_stateObj</code>) actually changes. The <code>watch</code> option allows you to specify additional properties that should trigger re-evaluation of the transformer function—in this case, when <code>_config</code> changes, the transformer runs again to extract the correct entity state.</p>]]></content>
        <author>
            <name>Wendelin Peleska</name>
            <uri>https://github.com/wendevlin</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Backup agents can now report upload progress]]></title>
        <id>https://developers.home-assistant.io/blog/2026/03/11/backup-upload-progress</id>
        <link href="https://developers.home-assistant.io/blog/2026/03/11/backup-upload-progress"/>
        <updated>2026-03-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The BackupAgent.asyncuploadbackup method now receives a new on_progress callback parameter. Backup agents can call this callback periodically during upload to report the number of bytes uploaded so far:]]></summary>
        <content type="html"><![CDATA[<p>The <code>BackupAgent.async_upload_backup</code> method now receives a new <code>on_progress</code> callback parameter. Backup agents can call this callback periodically during upload to report the number of bytes uploaded so far:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ExampleBackupAgent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">BackupAgent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">async_upload_backup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        open_stream</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Callable</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Coroutine</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> AsyncIterator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token builtin" style="color:rgb(130, 170, 255)">bytes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        backup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> AgentBackup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        on_progress</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> OnProgressCallback</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Upload a backup."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        bytes_uploaded </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> chunk </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> open_stream</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> do_upload</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">chunk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            bytes_uploaded </span><span class="token operator" style="color:rgb(137, 221, 255)">+=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">len</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">chunk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            on_progress</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">bytes_uploaded</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">bytes_uploaded</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><br></span></code></pre></div></div>
<p>The backup manager uses these progress reports to fire <code>UploadBackupEvent</code> events, enabling the frontend to display real-time upload progress to the user.</p>
<p>Check the <a class="" href="https://developers.home-assistant.io/docs/core/platform/backup#backup-agents">backup agent documentation</a> for more details.</p>]]></content>
        <author>
            <name>Josef Zweck</name>
            <uri>https://github.com/zweckj</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Custom integrations can now ship their own brand images]]></title>
        <id>https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api</id>
        <link href="https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api"/>
        <updated>2026-02-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Starting with Home Assistant 2026.3, custom integrations can include their own brand images (icons and logos) directly in the integration directory. No more submitting to a separate repository — just drop your images in a brand/ folder and they show up in the UI.]]></summary>
        <content type="html"><![CDATA[<p>Starting with Home Assistant 2026.3, custom integrations can include their own brand images (icons and logos) directly in the integration directory. No more submitting to a separate repository — just drop your images in a <code>brand/</code> folder and they show up in the UI.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="local-brand-images-for-custom-integrations">Local brand images for custom integrations<a href="https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api#local-brand-images-for-custom-integrations" class="hash-link" aria-label="Direct link to Local brand images for custom integrations" title="Direct link to Local brand images for custom integrations" translate="no">​</a></h2>
<p>Add a <code>brand/</code> directory to your custom integration with your icon and logo files:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">custom_components/my_integration/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── __init__.py</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── manifest.json</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">└── brand/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    ├── icon.png</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    └── logo.png</span><br></span></code></pre></div></div>
<p>The following image filenames are supported:</p>
<ul>
<li class=""><code>icon.png</code> / <code>dark_icon.png</code></li>
<li class=""><code>logo.png</code> / <code>dark_logo.png</code></li>
<li class=""><code>icon@2x.png</code> / <code>dark_icon@2x.png</code></li>
<li class=""><code>logo@2x.png</code> / <code>dark_logo@2x.png</code></li>
</ul>
<p>Local brand images automatically take priority over images from the brands CDN. That's it — no extra configuration needed.</p>
<p>For more details, see the <a class="" href="https://developers.home-assistant.io/docs/creating_integration_file_structure#local-brand-images-for-custom-integrations">integration file structure documentation</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="brand-images-now-served-through-a-local-api">Brand images now served through a local API<a href="https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api#brand-images-now-served-through-a-local-api" class="hash-link" aria-label="Direct link to Brand images now served through a local API" title="Direct link to Brand images now served through a local API" translate="no">​</a></h2>
<p>To make local brand images possible, all brand images are now served through the Home Assistant local API instead of being fetched directly from the CDN by the browser.</p>
<p>A new <code>brands</code> system integration proxies brand images through two endpoints:</p>
<ul>
<li class=""><code>/api/brands/integration/{domain}/{image}</code> — Integration icons and logos</li>
<li class=""><code>/api/brands/hardware/{category}/{image}</code> — Hardware images</li>
</ul>
<p>Images are cached locally on disk and served with a stale-while-revalidate strategy, so they remain available during internet outages.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="impact-on-the-frontend">Impact on the frontend<a href="https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api#impact-on-the-frontend" class="hash-link" aria-label="Direct link to Impact on the frontend" title="Direct link to Impact on the frontend" translate="no">​</a></h3>
<p>The <code>brandsUrl()</code> and <code>hardwareBrandsUrl()</code> helpers in <code>src/util/brands-url.ts</code> now return local API paths instead of CDN URLs. If your custom card or panel uses these helpers, no changes are needed.</p>
<p>If you are constructing brand image URLs manually, update them:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Old</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">https://brands.home-assistant.io/_/</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">domain</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)">/icon.png</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// New</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> brandsUrl </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"../util/brands-url"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">brandsUrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> domain</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> type</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"icon"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre></div></div>
<p>These endpoints require authentication. The <code>brandsUrl()</code> helper handles this automatically by appending an access token. If you construct URLs manually, obtain a token via the <code>brands/access_token</code> WebSocket command and append it as a <code>token</code> query parameter.</p>]]></content>
        <author>
            <name>Frenck</name>
            <uri>https://github.com/frenck</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Remove deprecated light features]]></title>
        <id>https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features</id>
        <link href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features"/>
        <updated>2026-02-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Summary of changes]]></summary>
        <content type="html"><![CDATA[<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary-of-changes">Summary of changes<a href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features#summary-of-changes" class="hash-link" aria-label="Direct link to Summary of changes" title="Direct link to Summary of changes" translate="no">​</a></h3>
<p>In October 2022, Home Assistant migrated the preferred color temperature unit from mired to kelvin.</p>
<p>In <a class="" href="https://developers.home-assistant.io/blog/2024/02/12/light-color-mode-mandatory">February 2024</a>, Home Assistant requested explicit <code>supported_color_modes</code> and <code>color_mode</code> properties (triggering deprecation of legacy fallback color mode support).</p>
<p>In <a class="" href="https://developers.home-assistant.io/blog/2024/12/14/kelvin-preferred-color-temperature-unit">December 2024</a>, Home Assistant requested explicit Kelvin support (triggering deprecation of mired support).</p>
<p>It is now time to clean up the legacy code and remove the corresponding attributes, constants and properties:</p>
<ul>
<li class="">Remove deprecated <code>ATTR_COLOR_TEMP</code>, <code>ATTR_MIN_MIREDS</code>, <code>ATTR_MAX_MIREDS</code>, <code>ATTR_KELVIN</code>, <code>COLOR_MODE_***</code>, and <code>SUPPORT_***</code> constants</li>
<li class="">Remove deprecated state attributes <code>ATTR_COLOR_TEMP</code>, <code>ATTR_MIN_MIREDS</code> and <code>ATTR_MAX_MIREDS</code></li>
<li class="">Remove deprecated support for <code>ATTR_KELVIN</code> and <code>ATTR_COLOR_TEMP</code> arguments from the <code>light.turn_on</code> service call</li>
<li class="">Remove deprecated support for <code>LightEntity.color_temp</code>, <code>LightEntity.min_mireds</code> and <code>LightEntity.max_mireds</code> properties from the entity</li>
<li class="">Remove deprecated support for <code>LightEntity._attr_color_temp</code>, <code>LightEntity._attr_min_mireds</code> and <code>LightEntity._attr_max_mireds</code> shorthand attributes from the entity</li>
</ul>
<p>Additionally, failing to provide valid <code>supported_color_modes</code> and <code>color_mode</code> properties no longer works and will raise an error.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="examples">Examples<a href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features#examples" class="hash-link" aria-label="Direct link to Examples" title="Direct link to Examples" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="custom-minimummaximum-color-temperature">Custom minimum/maximum color temperature<a href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features#custom-minimummaximum-color-temperature" class="hash-link" aria-label="Direct link to Custom minimum/maximum color temperature" title="Direct link to Custom minimum/maximum color temperature" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyLight</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">LightEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Representation of a light."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Old</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># _attr_min_mireds = 200 # 5000K</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># _attr_max_mireds = 400 # 2500K</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># New</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    _attr_min_color_temp_kelvin </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2500</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># 400 mireds</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    _attr_max_color_temp_kelvin </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5000</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># 200 mireds</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="default-minimummaximum-color-temperature">Default minimum/maximum color temperature<a href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features#default-minimummaximum-color-temperature" class="hash-link" aria-label="Direct link to Default minimum/maximum color temperature" title="Direct link to Default minimum/maximum color temperature" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">light </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> DEFAULT_MAX_KELVIN</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> DEFAULT_MIN_KELVIN</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyLight</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">LightEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Representation of a light."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Old did not need to have _attr_min_mireds / _attr_max_mireds set</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># New needs to set the default explicitly</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    _attr_min_color_temp_kelvin </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> DEFAULT_MIN_KELVIN</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    _attr_max_color_temp_kelvin </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> DEFAULT_MAX_KELVIN</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="dynamic-minimummaximum-color-temperature">Dynamic minimum/maximum color temperature<a href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features#dynamic-minimummaximum-color-temperature" class="hash-link" aria-label="Direct link to Dynamic minimum/maximum color temperature" title="Direct link to Dynamic minimum/maximum color temperature" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">util </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> color </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> color_util</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyLight</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">LightEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Representation of a light."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Old</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># def min_mireds(self) -&gt; int:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     """Return the coldest color_temp that this light supports."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     return device.coldest_temperature</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># def max_mireds(self) -&gt; int:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     """Return the warmest color_temp that this light supports."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     return device.warmest_temperature</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># New</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">min_color_temp_kelvin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Return the warmest color_temp that this light supports."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> color_util</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">color_temperature_mired_to_kelvin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">warmest_temperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">max_color_temp_kelvin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Return the coldest color_temp that this light supports."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> color_util</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">color_temperature_mired_to_kelvin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">coldest_temperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="checking-color-temperature-in-service-call">Checking color temperature in service call<a href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features#checking-color-temperature-in-service-call" class="hash-link" aria-label="Direct link to Checking color temperature in service call" title="Direct link to Checking color temperature in service call" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">light </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> ATTR_COLOR_TEMP_KELVIN</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">util </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> color </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> color_util</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyLight</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">LightEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Representation of a light."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">turn_on</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Turn on the light."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Old</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># if ATTR_COLOR_TEMP in kwargs:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     color_temp_mired = kwargs[ATTR_COLOR_TEMP]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     color_temp_kelvin = color_util.color_temperature_mired_to_kelvin(color_temp_mired)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Old</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># if ATTR_KELVIN in kwargs:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     color_temp_kelvin = kwargs[ATTR_KELVIN]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">#     color_temp_mired = color_util.color_temperature_kelvin_to_mired(color_temp_kelvin)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># New</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> ATTR_COLOR_TEMP_KELVIN </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> kwargs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            color_temp_kelvin </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> kwargs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">ATTR_COLOR_TEMP_KELVIN</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            color_temp_mired </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> color_util</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">color_temperature_kelvin_to_mired</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">color_temp_kelvin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="background-information">Background information<a href="https://developers.home-assistant.io/blog/2026/02/23/remove-deprecate-light-features#background-information" class="hash-link" aria-label="Direct link to Background information" title="Direct link to Background information" translate="no">​</a></h3>
<ul>
<li class=""><a href="https://community.home-assistant.io/t/wth-is-light-temperature-not-in-kelvin/467449/6" target="_blank" rel="noopener noreferrer" class="">Community discussion about Kelvin temperature</a></li>
<li class=""><a href="https://github.com/home-assistant/core/pull/79591" target="_blank" rel="noopener noreferrer" class="">Core PR #79591: Migration to Kelvin</a></li>
<li class=""><a href="https://github.com/home-assistant/architecture/discussions/564" target="_blank" rel="noopener noreferrer" class="">Architecture discussion #564</a></li>
<li class=""><a class="" href="https://developers.home-assistant.io/docs/core/entity/light#color-modes">Color modes documentation</a></li>
</ul>]]></content>
        <author>
            <name>epenet</name>
            <uri>https://github.com/epenet</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Changes in OAuth 2.0 helper error handling]]></title>
        <id>https://developers.home-assistant.io/blog/2026/02/19/oauth-token-request-error-handling</id>
        <link href="https://developers.home-assistant.io/blog/2026/02/19/oauth-token-request-error-handling"/>
        <updated>2026-02-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Summary of changes]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary-of-changes">Summary of changes<a href="https://developers.home-assistant.io/blog/2026/02/19/oauth-token-request-error-handling#summary-of-changes" class="hash-link" aria-label="Direct link to Summary of changes" title="Direct link to Summary of changes" translate="no">​</a></h2>
<p>Starting as of <code>2026.3</code>, we're enhancing how the OAuth 2.0 helper handles token request and refresh token failures. This change makes error handling more robust, decoupled from the aiohttp library and helps integrations, that utilize the <a href="https://developers.home-assistant.io/docs/integration_fetching_data/#coordinated-single-api-poll-for-data-for-all-entities" target="_blank" rel="noopener noreferrer" class="">Data Update Coordinator</a>, to automatically trigger the right error handling.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-changes">What changes<a href="https://developers.home-assistant.io/blog/2026/02/19/oauth-token-request-error-handling#what-changes" class="hash-link" aria-label="Direct link to What changes" title="Direct link to What changes" translate="no">​</a></h2>
<p>When an OAuth 2.0 token request or token refresh failed, Home Assistant would allow the underlying <code>aiohttp.ClientResponseError</code> to propagate directly to the integration. This behavior is being changed and enhanced.</p>
<p>We're introducing three new exceptions that provide clearer semantics:</p>
<ul>
<li class=""><code>OAuth2TokenRequestTransientError</code> - Recoverable errors, that can be retried.</li>
<li class=""><code>OAuth2TokenRequestReauthError</code> - Non-recoverable errors, that require a reauthentication.</li>
<li class=""><code>OAuth2TokenRequestError</code> - Base exception for when the above two criteria aren't met or to enable the integration to catch all token request exceptions.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="data-update-coordinator">Data Update Coordinator<a href="https://developers.home-assistant.io/blog/2026/02/19/oauth-token-request-error-handling#data-update-coordinator" class="hash-link" aria-label="Direct link to Data Update Coordinator" title="Direct link to Data Update Coordinator" translate="no">​</a></h3>
<p>Most integrations that use the OAuth 2.0 helper, also use the Data Update Coordinator. When a token request or refresh token fails, the exceptions will bubble up in the Data Update Coordinator and now triggers the following error handling:</p>
<p>For unrecoverable errors (400+, except 429 (rate limit)):</p>
<ul>
<li class=""><code>OAuth2TokenRequestReauthError</code>: Data Update Coordinator raises <code>ConfigEntryAuthFailed</code> if exceptions should be raised or starts a reauthentication flow.</li>
</ul>
<p>For transient errors (500+ and 429):</p>
<ul>
<li class=""><code>OAuth2TokenRequestTransientError</code>: Data Update Coordinator treats it as an <code>UpdateFailed</code> and the retry mechanism will be triggered.</li>
</ul>
<p>This means that integrations that use the OAuth 2.0 helper in combination with the Data Update Coordinator don’t need to do any special handling of the new exceptions.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="migration">Migration<a href="https://developers.home-assistant.io/blog/2026/02/19/oauth-token-request-error-handling#migration" class="hash-link" aria-label="Direct link to Migration" title="Direct link to Migration" translate="no">​</a></h3>
<p>Integrations that today use the OAuth 2.0 helper and handle <code>aiohttp.ClientResponseError</code> explicitly should adjust their error handling to deal with the new exceptions. To ease this transition, we have added a compatibility layer by having the new OAuth exceptions inherit from <code>aiohttp.ClientResponseError</code>. Existing code that catches this exception type should continue to work. It is however encouraged to refactor the code to use the new exceptions. See the code example for details.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="code-example-of-migration">Code example of migration<a href="https://developers.home-assistant.io/blog/2026/02/19/oauth-token-request-error-handling#code-example-of-migration" class="hash-link" aria-label="Direct link to Code example of migration" title="Direct link to Code example of migration" translate="no">​</a></h4>
<p>Update the exception handling and then continue to work out if it's a (non-)recoverable error in the integration. For example:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> auth</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">async_get_access_token</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">except</span><span class="token plain"> OAuth2TokenRequestReauthError </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">raise</span><span class="token plain"> ConfigEntryAuthFailed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            translation_domain</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">DOMAIN</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> translation_key</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"reauth_required"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> err</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">except</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">OAuth2TokenRequestError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ClientError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">raise</span><span class="token plain"> ConfigEntryNotReady</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            translation_domain</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">DOMAIN</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> translation_key</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"auth_server_error"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> err</span><br></span></code></pre></div></div>]]></content>
        <author>
            <name>Erwin Douna</name>
            <uri>https://github.com/erwindouna</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Reconfiguration support for webhook helper]]></title>
        <id>https://developers.home-assistant.io/blog/2026/02/18/reconfiguration-support-for-webhook-helper</id>
        <link href="https://developers.home-assistant.io/blog/2026/02/18/reconfiguration-support-for-webhook-helper"/>
        <updated>2026-02-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Integrations that use the webhook config flow helper (homeassistant.helpers.configentryflow.registerwebhookflow) now support reconfiguration. This allows the integration to retrieve the webhook again, or obtain an updated webhook when the Home Assistant instance URL changes.]]></summary>
        <content type="html"><![CDATA[<p>Integrations that use the webhook config flow helper (<code>homeassistant.helpers.config_entry_flow.register_webhook_flow</code>) now support reconfiguration. This allows the integration to retrieve the webhook again, or obtain an updated webhook when the Home Assistant instance URL changes.</p>
<p>Custom integrations using the webhook config flow helper must add translation strings for the reconfiguration flow.</p>
<p><strong>Example translation strings for a reconfiguration flow:</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  "config": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "abort": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "reconfigure_successful": "**Reconfiguration was successful**\n\nIn Sleep as Android go to *Settings → Services → Automation → Webhooks* and update the webhook with the following URL:\n\n`{webhook_url}`"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "step": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "reconfigure": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        "description": "Are you sure you want to re-configure the Sleep as Android integration?",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        "title": "Reconfigure Sleep as Android"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>For more details, see <a href="https://github.com/home-assistant/core/pull/151729" target="_blank" rel="noopener noreferrer" class="">core PR #151729</a>.</p>]]></content>
        <author>
            <name>tr4nt0r</name>
            <uri>https://github.com/tr4nt0r</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[async_listen in Labs is deprecated]]></title>
        <id>https://developers.home-assistant.io/blog/2026/02/16/labs-async-listen-deprecation</id>
        <link href="https://developers.home-assistant.io/blog/2026/02/16/labs-async-listen-deprecation"/>
        <updated>2026-02-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The asynclisten helper in the labs integration has been deprecated in favor of asyncsubscribepreviewfeature.]]></summary>
        <content type="html"><![CDATA[<p>The <code>async_listen</code> helper in the <code>labs</code> integration has been deprecated in favor of <code>async_subscribe_preview_feature</code>.</p>
<p>The new <code>async_subscribe_preview_feature</code> function provides a more consistent API, where the listener callback receives an <code>EventLabsUpdatedData</code> parameter containing the updated feature state. This eliminates the need to separately call <code>async_is_preview_feature_enabled</code> inside the listener to check the current value.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="old-usage">Old usage<a href="https://developers.home-assistant.io/blog/2026/02/16/labs-async-listen-deprecation#old-usage" class="hash-link" aria-label="Direct link to Old usage" title="Direct link to Old usage" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">labs </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> async_is_preview_feature_enabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> async_listen</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">my_listener</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> async_is_preview_feature_enabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">hass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> DOMAIN</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"my_feature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># feature enabled</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">async_listen</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    hass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    domain</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">DOMAIN</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    preview_feature</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"my_feature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    listener</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">my_listener</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="new-usage">New usage<a href="https://developers.home-assistant.io/blog/2026/02/16/labs-async-listen-deprecation#new-usage" class="hash-link" aria-label="Direct link to New usage" title="Direct link to New usage" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">labs </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> EventLabsUpdatedData</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> async_subscribe_preview_feature</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">my_listener</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">event_data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EventLabsUpdatedData</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> event_data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"enabled"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># feature enabled</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">async_subscribe_preview_feature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    hass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    domain</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">DOMAIN</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    preview_feature</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"my_feature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    listener</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">my_listener</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>Note that the new listener is a coroutine function and receives <code>EventLabsUpdatedData</code> as a parameter.</p>
<p><code>async_listen</code> will be removed in Home Assistant 2027.3.</p>
<p>For more details, see <a href="https://github.com/home-assistant/core/pull/162648" target="_blank" rel="noopener noreferrer" class="">core PR #162648</a>.</p>]]></content>
        <author>
            <name>Artur Pragacz</name>
            <uri>https://github.com/arturpragacz</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Replacing pre-commit with prek]]></title>
        <id>https://developers.home-assistant.io/blog/2026/01/13/replace-pre-commit-with-prek</id>
        <link href="https://developers.home-assistant.io/blog/2026/01/13/replace-pre-commit-with-prek"/>
        <updated>2026-01-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[By replacing pre-commit with prek we can increase the performance of our checks. Prek uses the same .pre-commit-config.yaml as pre-commit and is a complete replacement. Due to the fact that prek is written in Rust and allows the execution of different jobs in parallel, we can check our code even faster.]]></summary>
        <content type="html"><![CDATA[<p>By replacing <code>pre-commit</code> with <a href="https://prek.j178.dev/" target="_blank" rel="noopener noreferrer" class=""><code>prek</code></a> we can increase the performance of our checks. Prek uses the same <code>.pre-commit-config.yaml</code> as <code>pre-commit</code> and is a complete replacement. Due to the fact that <code>prek</code> is written in Rust and allows the execution of different jobs in parallel, we can check our code even faster.</p>
<p>New development environments will automatically install <code>prek</code> and for existing ones please just update the test requirements by running <code>uv pip install requirements_test.txt</code></p>]]></content>
        <author>
            <name>Robert Resch</name>
            <uri>https://github.com/edenhaus</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Solving pyserial-asyncio blocking the event loop]]></title>
        <id>https://developers.home-assistant.io/blog/2026/01/05/pyserial-asyncio-fast</id>
        <link href="https://developers.home-assistant.io/blog/2026/01/05/pyserial-asyncio-fast"/>
        <updated>2026-01-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Summary of changes]]></summary>
        <content type="html"><![CDATA[<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary-of-changes">Summary of changes<a href="https://developers.home-assistant.io/blog/2026/01/05/pyserial-asyncio-fast#summary-of-changes" class="hash-link" aria-label="Direct link to Summary of changes" title="Direct link to Summary of changes" translate="no">​</a></h3>
<p>Starting in <code>2026.7</code>, installation of <code>pyserial-asyncio</code> will be blocked in Home Assistant.</p>
<p>Library maintainers and custom integrations are advised to migrate to <code>pyserial-asyncio-fast</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="background">Background<a href="https://developers.home-assistant.io/blog/2026/01/05/pyserial-asyncio-fast#background" class="hash-link" aria-label="Direct link to Background" title="Direct link to Background" translate="no">​</a></h3>
<p><code>pyserial-asyncio</code> blocks the event loop because it does a blocking <code>sleep</code>. The library is also not maintained so efforts to improve the situation haven't been released.</p>
<p><code>pyserial-asyncio-fast</code> was created as a drop-in replacement (see <a href="https://github.com/home-assistant-libs/pyserial-asyncio-fast" target="_blank" rel="noopener noreferrer" class="">the repository</a>), and all core integrations have now been migrated.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="migration">Migration<a href="https://developers.home-assistant.io/blog/2026/01/05/pyserial-asyncio-fast#migration" class="hash-link" aria-label="Direct link to Migration" title="Direct link to Migration" translate="no">​</a></h3>
<p><code>pyserial-asyncio-fast</code> was designed as a drop-in replacement of <code>pyserial-asyncio</code>, and the necessary changes are trivial.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="requirements">Requirements<a href="https://developers.home-assistant.io/blog/2026/01/05/pyserial-asyncio-fast#requirements" class="hash-link" aria-label="Direct link to Requirements" title="Direct link to Requirements" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Old</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  install_requires</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"pyserial-asyncio"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># New</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  install_requires</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"pyserial-asyncio-fast"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="usage">Usage<a href="https://developers.home-assistant.io/blog/2026/01/05/pyserial-asyncio-fast#usage" class="hash-link" aria-label="Direct link to Usage" title="Direct link to Usage" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Old</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> serial_asyncio</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    conn </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> serial_asyncio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">open_serial_connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">**</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">serial_settings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># New</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> serial_asyncio_fast</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    conn </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> serial_asyncio_fast</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">open_serial_connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">**</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">serial_settings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>More examples are available in <a href="https://github.com/home-assistant/core/pull/116635" target="_blank" rel="noopener noreferrer" class="">the tracking pull request</a>.</p>]]></content>
        <author>
            <name>epenet</name>
            <uri>https://github.com/epenet</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Introducing description placeholders for service action translations]]></title>
        <id>https://developers.home-assistant.io/blog/2025/11/27/service-translation-placeholders</id>
        <link href="https://developers.home-assistant.io/blog/2025/11/27/service-translation-placeholders"/>
        <updated>2025-11-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[It is now possible to use translation placeholders for (custom) service actions.]]></summary>
        <content type="html"><![CDATA[<p>It is now possible to use translation placeholders for (custom) service actions.</p>
<p>The <a class="" href="https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/action-setup?_highlight=hass.services.async_register#example-implementation">service action example</a> now shows how to supply the available description placeholders during the registration of the service action.</p>
<p>Move URLs from service descriptions and translation strings into description placeholders.</p>]]></content>
        <author>
            <name>Jan Bouwhuis</name>
            <uri>https://github.com/jbouwh</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Serialization of Store data in worker thread is now opt-in]]></title>
        <id>https://developers.home-assistant.io/blog/2025/11/25/storage-helper-opt-in-serialize-in-executor</id>
        <link href="https://developers.home-assistant.io/blog/2025/11/25/storage-helper-opt-in-serialize-in-executor"/>
        <updated>2025-11-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The Store class from homeassistant/helpers/storage.py accepts a new constructor argument serializeinevent_loop]]></summary>
        <content type="html"><![CDATA[<p>The <code>Store</code> class from <code>homeassistant/helpers/storage.py</code> accepts a new constructor argument <code>serialize_in_event_loop</code></p>
<p>If <code>serialize_in_event_loop</code> is <code>True</code> (the default):</p>
<ul>
<li class="">The <code>data_func</code> passed to <code>Store.async_delay_save</code> is called from the event loop</li>
<li class="">Data produced by <code>data_func</code> passed to <code>Store.async_delay_save</code> is serialized to JSON in the event loop</li>
<li class="">Data passed to <code>Store.async_save</code> is serialized to JSON in the event loop</li>
</ul>
<p>If <code>serialize_in_event_loop</code> is <code>False</code>:</p>
<ul>
<li class="">The <code>data_func</code> passed to <code>Store.async_delay_save</code> is called from a separate thread, which means it must be thread safe and must not access the hass object</li>
<li class="">Data produced by <code>data_func</code> passed to <code>Store.async_delay_save</code> is serialized to JSON in a separate thread, which means it must be thread safe</li>
<li class="">Data passed to <code>Store.async_save</code> is serialized to JSON in a separate thread, which means it must be thread safe</li>
</ul>
<p>The behavior has changed; <code>data_func</code> passed to <code>Store.async_delay_save</code> was previously always called from a separate thread and data produced by it or data passed to <code>Store.async_save</code> was previously always serialized by a separate thread.</p>
<p>The reason for the change is that it was not documented that <code>data_func</code> would be called by a thread other than the event loop or that JSON serialization would happen in a thread other than the event loop, and the <code>data_func</code> and data produced by it or passed to <code>Store.async_save</code> was generally not thread safe.</p>
<p>For more details, see <a href="https://github.com/home-assistant/core/pull/157158" target="_blank" rel="noopener noreferrer" class="">core PR 157158</a> and <a href="https://github.com/home-assistant/core/pull/157263" target="_blank" rel="noopener noreferrer" class="">core PR 157263</a>.</p>]]></content>
        <author>
            <name>Erik Montnemery</name>
            <uri>https://github.com/emontnemery</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Add a status callback for MQTT subscriptions]]></title>
        <id>https://developers.home-assistant.io/blog/2025/11/23/mqtt-subscribe-wait</id>
        <link href="https://developers.home-assistant.io/blog/2025/11/23/mqtt-subscribe-wait"/>
        <updated>2025-11-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Add a status callback for MQTT subscriptions]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="add-a-status-callback-for-mqtt-subscriptions">Add a status callback for MQTT subscriptions<a href="https://developers.home-assistant.io/blog/2025/11/23/mqtt-subscribe-wait#add-a-status-callback-for-mqtt-subscriptions" class="hash-link" aria-label="Direct link to Add a status callback for MQTT subscriptions" title="Direct link to Add a status callback for MQTT subscriptions" translate="no">​</a></h2>
<p>Integrations that use MQTT might need to wait for a subscription to complete before they initiate actions. The default behavior is that a subscription is queued and debounced, so callers usually do not wait for broker confirmation. Some integrations must guarantee that the broker finished the subscription.</p>
<p>The new <code>mqtt.async_on_subscribe_done</code> helper can be used to monitor MQTT subscriptions, to allow doing additional tasks.
Make sure the same QoS is used as in the MQTT subscription.</p>
<p>Example:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> homeassistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">components </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> mqtt</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">async_setup_entry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">hass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> HomeAssistant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> entry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> ConfigEntry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">bool</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Setup integration MQTT subscription monitoring."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">_on_subscribe_status</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""Handle subscription ready signal."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Do stuff</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Handle subscription ready status update</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> mqtt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">async_on_subscribe_done</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        hass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"myintegration/status"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        qos</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        on_subscribe_status</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">_on_subscribe_status</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Do stuff</span><br></span></code></pre></div></div>]]></content>
        <author>
            <name>Jan Bouwhuis</name>
            <uri>https://github.com/jbouwh</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Device identification buttons are now classified as diagnostic]]></title>
        <id>https://developers.home-assistant.io/blog/2025/11/21/identify-buttons-diagnostic-category</id>
        <link href="https://developers.home-assistant.io/blog/2025/11/21/identify-buttons-diagnostic-category"/>
        <updated>2025-11-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Button entities representing a device identification mechanism (using IDENTIFY device class) are now required to have their entity category set to DIAGNOSTIC.]]></summary>
        <content type="html"><![CDATA[<p>Button entities representing a device identification mechanism (using <code>IDENTIFY</code> device class) are now required to have their entity category set to <code>DIAGNOSTIC</code>.</p>
<p>For more details on entity category, see <a class="" href="https://developers.home-assistant.io/docs/core/entity/#registry-properties">the documentation</a>.</p>]]></content>
        <author>
            <name>Artur Pragacz</name>
            <uri>https://github.com/arturpragacz</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Introducing Labs: Preview features before they become standard]]></title>
        <id>https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features</id>
        <link href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features"/>
        <updated>2025-11-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We're excited to announce a new system for shipping preview features in Home Assistant: Labs. Labs provides a standardized way for integrations to offer fully tested features that users can opt into before they become standard, allowing us to gather feedback and refine the design based on real-world usage.]]></summary>
        <content type="html"><![CDATA[<p>We're excited to announce a new system for shipping preview features in Home Assistant: <strong>Labs</strong>. Labs provides a standardized way for integrations to offer fully tested features that users can opt into before they become standard, allowing us to gather feedback and refine the design based on real-world usage.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-are-labs-preview-features">What are Labs preview features?<a href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features#what-are-labs-preview-features" class="hash-link" aria-label="Direct link to What are Labs preview features?" title="Direct link to What are Labs preview features?" translate="no">​</a></h2>
<p>Labs preview features are different from beta testing. While beta testing evaluates the stability of upcoming Home Assistant releases, Labs is about refining user interfaces and design. Labs features are fully tested and functional, but their design and behavior may still change as we gather real-world usage and feedback. This means they might have breaking changes, be extended with new functionality, or even be removed if they don't work out.</p>
<p>Think of it this way:</p>
<ul>
<li class=""><strong>Beta</strong>: Evaluates the stability of upcoming Home Assistant releases</li>
<li class=""><strong>Labs</strong>: Fully tested features with evolving design and user interface, refined through real-world usage and feedback</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How it works<a href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features#how-it-works" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h2>
<p>Integrations declare preview features in their <code>manifest.json</code> with links for feedback, documentation, and issue reporting. Users can then enable these features in <strong>Settings</strong> → <strong>System</strong> → <strong>Labs</strong>, and they activate immediately without requiring a restart. The integration code checks whether a feature is enabled and responds accordingly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-labs">Why Labs?<a href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features#why-labs" class="hash-link" aria-label="Direct link to Why Labs?" title="Direct link to Why Labs?" translate="no">​</a></h2>
<p>Many of our most significant improvements benefit from real-world testing before becoming standard. Labs provides:</p>
<ol>
<li class=""><strong>Structured feedback channels</strong>: Each feature has dedicated URLs for feedback, documentation, and issue reporting</li>
<li class=""><strong>Runtime activation</strong>: Features enable and disable instantly, no configuration updates or restart required</li>
<li class=""><strong>Clear expectations</strong>: Users know they're trying fully tested features whose design may change based on feedback</li>
<li class=""><strong>Iterative development</strong>: Integrate user feedback directly into the development process</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-kitchen-sink-special-repair">Example: Kitchen Sink special repair<a href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features#example-kitchen-sink-special-repair" class="hash-link" aria-label="Direct link to Example: Kitchen Sink special repair" title="Direct link to Example: Kitchen Sink special repair" translate="no">​</a></h2>
<p>The <a href="https://www.home-assistant.io/integrations/kitchen_sink/" target="_blank" rel="noopener noreferrer" class="">Kitchen Sink</a> demo integration includes a working example. When enabled, the "special repair" feature creates a repair issue to demonstrate how Labs features can interact with other Home Assistant integrations. See the <a class="" href="https://developers.home-assistant.io/docs/development/labs#complete-example-kitchen-sink-special-repair">developer documentation</a> for the complete implementation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-started">Getting started<a href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features#getting-started" class="hash-link" aria-label="Direct link to Getting started" title="Direct link to Getting started" translate="no">​</a></h2>
<p>Ready to add a Labs preview feature to your integration? Check out our <a class="" href="https://developers.home-assistant.io/docs/development/labs">comprehensive guide</a> which covers:</p>
<ul>
<li class="">When to use Labs (and when not to)</li>
<li class="">How to define features in your manifest</li>
<li class="">Implementation patterns for backend and frontend features</li>
<li class="">Runtime activation requirements</li>
<li class="">Testing approaches</li>
<li class="">Feature lifecycle (preview → standard or removal)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next?<a href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features#whats-next" class="hash-link" aria-label="Direct link to What's next?" title="Direct link to What's next?" translate="no">​</a></h2>
<p>We encourage integration developers to consider Labs for:</p>
<ul>
<li class="">Major UI changes or redesigns</li>
<li class="">Significant architectural changes that benefit from real-world testing</li>
<li class="">Features where user feedback will shape the final design</li>
</ul>
<p>Labs is <strong>not</strong> for:</p>
<ul>
<li class="">Permanent configuration options (use integration options instead)</li>
<li class="">Minor changes that can go directly into releases</li>
<li class="">Features with critical bugs or that are fundamentally incomplete</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-yourself">Try it yourself<a href="https://developers.home-assistant.io/blog/2025/11/20/labs-preview-features#try-it-yourself" class="hash-link" aria-label="Direct link to Try it yourself" title="Direct link to Try it yourself" translate="no">​</a></h2>
<p>Want to see Labs in action? Install the Kitchen Sink demo integration and enable the "Special repair" feature in Settings → System → Labs. You'll see firsthand how preview features work.</p>]]></content>
        <author>
            <name>Frenck</name>
            <uri>https://github.com/frenck</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Data Update Coordinator now supports Retry After]]></title>
        <id>https://developers.home-assistant.io/blog/2025/11/17/retry-after-update-failed</id>
        <link href="https://developers.home-assistant.io/blog/2025/11/17/retry-after-update-failed"/>
        <updated>2025-11-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Integrations using the Data Update Coordinator can enhance the UpdateFailed exception with a new parameter retry_after to defer the next scheduled refresh by a specified number of seconds and then resume the normal cadence once the API has recovered.]]></summary>
        <content type="html"><![CDATA[<p>Integrations using the <a href="https://developers.home-assistant.io/docs/integration_fetching_data/#coordinated-single-api-poll-for-data-for-all-entities" target="_blank" rel="noopener noreferrer" class="">Data Update Coordinator</a> can enhance the <code>UpdateFailed</code> exception with a new parameter <code>retry_after</code> to defer the next scheduled refresh by a specified number of seconds and then resume the normal cadence once the API has recovered.</p>
<p>In situations where polling API's would return a sign of being overwhelmed, by throwing an HTTP 429 or providing a <code>Retry-After</code> in the response header, integrations can now honor these backoff signals.
The integration and API client must detect these backoff signals and sanitize the API's desired backoff period. The <code>UpdateFailed</code> exception accepts a <code>retry_after</code> parameter (a float in seconds) to delay the next scheduled refresh. Once the API recovers and <code>UpdateFailed</code> is no longer raised, the integration resumes its normal <code>update_interval</code>.</p>
<p>Example of the usage:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    request </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_information</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">except</span><span class="token plain"> APIClientRateLimited </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">raise</span><span class="token plain"> UpdateFailed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        retry_after</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># This can also be retrieved from the API response itself, or provide a default</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> err</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="configentrynotready">ConfigEntryNotReady<a href="https://developers.home-assistant.io/blog/2025/11/17/retry-after-update-failed#configentrynotready" class="hash-link" aria-label="Direct link to ConfigEntryNotReady" title="Direct link to ConfigEntryNotReady" translate="no">​</a></h4>
<p>The <code>retry_after</code> parameter is ignored during the Update Coordinator setup phase (<code>async_config_entry_first_refresh</code>). If the first refresh fails, Home Assistant raises a <code>ConfigEntryNotReady</code> exception, allowing config entry setup to retry automatically using the built-in retry. Once the coordinator setup succeeds, <code>retry_after</code> applies to following refreshes.</p>]]></content>
        <author>
            <name>Erwin Douna</name>
            <uri>https://github.com/erwindouna</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[The capability_attributes field removed from CalculatedState]]></title>
        <id>https://developers.home-assistant.io/blog/2025/11/10/calculated-state-capability-attributes-removed</id>
        <link href="https://developers.home-assistant.io/blog/2025/11/10/calculated-state-capability-attributes-removed"/>
        <updated>2025-11-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The capability_attributes field has been removed from CalculatedState. Capability attributes are still included in all attributes, which remain available in CalculatedState.]]></summary>
        <content type="html"><![CDATA[<p>The <code>capability_attributes</code> field has been removed from <code>CalculatedState</code>. Capability attributes are still included in all attributes, which remain available in <code>CalculatedState</code>.</p>
<p><code>CalculatedState</code> is the container with state and attributes returned by <code>Entity._async_calculate_state</code>.</p>
<p>For details, see <a href="https://github.com/home-assistant/core/pull/151672" target="_blank" rel="noopener noreferrer" class="">core PR 151672</a>.</p>]]></content>
        <author>
            <name>Artur Pragacz</name>
            <uri>https://github.com/arturpragacz</uri>
        </author>
    </entry>
</feed>