Skip to main content

Serialization of Store data in worker thread is now opt-in

· 2 min read

The Store class from homeassistant/helpers/storage.py accepts a new constructor argument serialize_in_event_loop

If serialize_in_event_loop is True (the default):

  • The data_func passed to Store.async_delay_save is called from the event loop
  • Data produced by data_func passed to Store.async_delay_save is serialized to JSON in the event loop
  • Data passed to Store.async_save is serialized to JSON in the event loop

If serialize_in_event_loop is False:

  • The data_func passed to Store.async_delay_save is called from a separate thread, which means it must be thread safe and must not access the hass object
  • Data produced by data_func passed to Store.async_delay_save is serialized to JSON in a separate thread, which means it must be thread safe
  • Data passed to Store.async_save is serialized to JSON in a separate thread, which means it must be thread safe

The behavior has changed; data_func passed to Store.async_delay_save was previously always called from a separate thread and data produced by it or data passed to Store.async_save was previously always serialized by a separate thread.

The reason for the change is that it was not documented that data_func 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 data_func and data produced by it or passed to Store.async_save was generally not thread safe.

For more details, see core PR 157158 and core PR 157263.

Add a status callback for MQTT subscriptions

· One min read

Add a status callback for MQTT subscriptions

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.

The new mqtt.async_on_subscribe_done 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.

Example:

from homeassistant.components import mqtt

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Setup integration MQTT subscription monitoring."""

def _on_subscribe_status() -> None:
"""Handle subscription ready signal."""
# Do stuff

# Handle subscription ready status update
await mqtt.async_on_subscribe_done(
hass,
"myintegration/status",
qos=1,
on_subscribe_status=_on_subscribe_status,
)

# Do stuff

Introducing Labs: Preview features before they become standard

· 3 min read

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.

What are Labs preview features?

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.

Think of it this way:

  • Beta: Evaluates the stability of upcoming Home Assistant releases
  • Labs: Fully tested features with evolving design and user interface, refined through real-world usage and feedback

How it works

Integrations declare preview features in their manifest.json with links for feedback, documentation, and issue reporting. Users can then enable these features in SettingsSystemLabs, and they activate immediately without requiring a restart. The integration code checks whether a feature is enabled and responds accordingly.

Why Labs?

Many of our most significant improvements benefit from real-world testing before becoming standard. Labs provides:

  1. Structured feedback channels: Each feature has dedicated URLs for feedback, documentation, and issue reporting
  2. Runtime activation: Features enable and disable instantly, no configuration updates or restart required
  3. Clear expectations: Users know they're trying fully tested features whose design may change based on feedback
  4. Iterative development: Integrate user feedback directly into the development process

Example: Kitchen Sink special repair

The Kitchen Sink 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 developer documentation for the complete implementation.

Getting started

Ready to add a Labs preview feature to your integration? Check out our comprehensive guide which covers:

  • When to use Labs (and when not to)
  • How to define features in your manifest
  • Implementation patterns for backend and frontend features
  • Runtime activation requirements
  • Testing approaches
  • Feature lifecycle (preview → standard or removal)

What's next?

We encourage integration developers to consider Labs for:

  • Major UI changes or redesigns
  • Significant architectural changes that benefit from real-world testing
  • Features where user feedback will shape the final design

Labs is not for:

  • Permanent configuration options (use integration options instead)
  • Minor changes that can go directly into releases
  • Features with critical bugs or that are fundamentally incomplete

Try it yourself

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.

Data Update Coordinator now supports Retry After

· 2 min read

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.

In situations where polling API's would return a sign of being overwhelmed, by throwing an HTTP 429 or providing a Retry-After 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 UpdateFailed exception accepts a retry_after parameter (a float in seconds) to delay the next scheduled refresh. Once the API recovers and UpdateFailed is no longer raised, the integration resumes its normal update_interval.

Example of the usage:

try:
request = await self.client.get_information()
except APIClientRateLimited as err:
raise UpdateFailed(
retry_after=60 # This can also be retrieved from the API response itself, or provide a default
) from err

ConfigEntryNotReady

The retry_after parameter is ignored during the Update Coordinator setup phase (async_config_entry_first_refresh). If the first refresh fails, Home Assistant raises a ConfigEntryNotReady exception, allowing config entry setup to retry automatically using the built-in retry. Once the coordinator setup succeeds, retry_after applies to following refreshes.

Improved error handling for oauth2 configuration without internet

· One min read

Integrations using Application Credentials and Configuration via OAuth2 need to update their error handling to correctly handle configuration when the internet is down.

Currently integrations using configuration via OAuth2 call config_entry_oauth2_flow.async_get_config_entry_implementation in async_setup_entry in their __init__.py. Previously when there was no network, this would raise ValueError: Implementation not available, which was a non-retryable error, resulting in the integration needing to be manually reconfigured after internet was restored (see Issues 153956 and 144582). core PR 154579 added config_entry_oauth2_flow.ImplementationUnavailableError and raises it in config_entry_oauth2_flow.async_get_config_entry_implementation when OAuth2 configuration is unavailable because of missing internet. Integrations should catch this error and raise ConfigEntryNotReady. The changed behavior with the new exception will be released in 2025.12.

Here is an example of the migration,

-    implementation = await async_get_config_entry_implementation(hass, entry)
+ try:
+ implementation = await async_get_config_entry_implementation(hass, entry)
+ except ImplementationUnavailableError as err:
+ raise ConfigEntryNotReady(
+ "OAuth2 implementation temporarily unavailable, will retry"
+ ) from err

New integrations will find the correct try / except block generated by python3 -m script.scaffold config_flow_oauth2.

Service translations removed from WebSocket get_services and REST /api/services

· One min read

Action translations defined in strings.json are no longer included in responses from the WebSocket get_services command and the REST /api/services endpoint because they were incomplete and the Home Assistant frontend did not use them.

Legacy, untranslated action names and descriptions from services.yaml remain in both the WebSocket and REST responses.

Fetch complete action translations with the WebSocket command frontend/get_translations.

For details, see core PR 147120.

Changes to the recorder statistics API

· 3 min read

The Python and WS APIs for injecting and modifying statistics have changed.

The following changes have been made to the WS API:

  • The WS command recorder/update_statistics_metadata accepts a unit_class that points to the unit converter used for unit conversions. If there is no compatible unit converter, unit_class should be set to null. Not specifying the unit_class is deprecated and will stop working in Home Assistant Core 2026.11.
  • The metadata object included in the WS command recorder/import_statistics accepts a unit_class that points to the unit converter used for unit conversions. If there is no compatible unit converter, unit_class should be set to null. Not specifying the unit_class is deprecated and will stop working in Home Assistant Core 2026.11.
  • The metadata object included in the WS command recorder/import_statistics accepts a mean_type that specifies the type of mean (0 for no mean, 1 for arithmetic mean, or 2 for circular mean). The mean_type replaces the bool flag has_mean. Not specifying the mean_type is deprecated and will stop working in Home Assistant Core 2026.11.
  • The items in the response to the WS commands recorder/list_statistic_ids and recorder/get_statistics_metadata have mean_type and unit_class.
  • The has_mean in the items in the response to the WS commands recorder/list_statistic_ids and recorder/get_statistics_metadata is deprecated and will be removed in Home Assistant Core 2026.11.

The following changes have been made to the Python API:

  • The function async_update_statistics_metadata accepts a new_unit_class that points to the unit converter used for unit conversions. If there is no compatible unit converter, new_unit_class should be set to None. Not specifying the new_unit_class is deprecated and will stop working in Home Assistant Core 2025.11.
  • The metadata object passed to the functions async_import_statistics and async_add_external_statistics accepts a unit_class that points to the unit converter used for unit conversions. If there is no compatible unit converter, unit_class should be set to None. Not specifying the unit_class is deprecated and will stop working in Home Assistant Core 2025.11.
  • The metadata object passed to the functions async_import_statistics and async_add_external_statistics accepts a mean_type of type StatisticMeanType that specifies the type of mean (NONE, ARITHMETIC, or CIRCULAR). The mean_type replaces the bool flag has_mean. Not specifying the mean_type is deprecated and will stop working in Home Assistant Core 2026.11.
  • The items in the return value of the function async_list_statistic_ids have mean_type and unit_class.
  • The has_mean in the items in the return value of the function async_list_statistic_ids is deprecated and will be removed in Home Assistant Core 2026.11.