Skip to main content

Config entry now supports minor versions

· One min read

Config entry now supports minor versions.

If minor versions differ, but major versions are the same, the integration setup will be allowed to continue even if the integration does not implement async_migrate_entry. This means a minor version bump is backwards compatible, unlike a major version bump which causes the integration to fail setup if the user downgrades HA Core without restoring configuration from backup.

Background

We have been very conservative with versioning config entry data because it breaks downgrading to an older version of Home Assistant Core. This means in most cases, we don't version, and the integrations instead do a kind of soft upgrade where they may, for example, do dict.get on config entry data that was not in an initial version, transform the data during setup etc.

By introducing minor versions similar to that already offered by the storage helper, this pattern is no longer recommended. A bump of the minor version should be done instead whenever the newly added, or otherwise changed, data does not break older versions.

More details can be found in the documentation on config entry migration and in core PR #105749.

Changes to EntityDescription data classes

· One min read

The EntityDescription classes have changed; derived dataclasses should now set frozen=True and kw_only=True.

Setting frozen to True makes the EntityDescription instances immutable, which means they cannot be accidentally updated after creation. Setting kw_only to True ensures the order of fields can be changed in the base class without breaking users.

During a deprecation period, which will end with HA Core 2025.1, it will still be possible to derive dataclasses not setting frozen=True or kw_only=True, but this will be logged, and the user will be asked to create an issue with the custom integration.

Once HA Core 2025.1 is released, it will no longer be possible to derive dataclasses without setting frozen=True or kw_only=True.

More details can be found in the core PR #105211.

New scaling utils and import changes

· 3 min read

New utils for scaling brightness

Multiple integrations have implemented there own scaling algorithm to scale brightness. New utils are introduced now to simplify the implementation of brightness scaling in homeassistant.util.color:

def brightness_to_value(low_high_range: tuple[float, float], brightness: int) -> float:
"""Given a brightness_scale convert a brightness to a single value.

Do not include 0 if the light is off for value 0.

Given a brightness low_high_range of (1,100) this function
will return:

255: 100.0
127: ~49.8039
10: ~3.9216
"""
...

If you'd rather like to scale brightness to an integer range you can also use scale_ranged_value_to_int_range, described here.

def value_to_brightness(low_high_range: tuple[float, float], value: float) -> int:
"""Given a brightness_scale convert a single value to a brightness.

Do not include 0 if the light is off for value 0.

Given a brightness low_high_range of (1,100) this function
will return:

100: 255
50: 127
4: 10

The value will be clamped between 1..255 to ensure valid value.
"""
...

This also ensures a valid brightness value is returned.

Background

To scale fan speed percentage we already have some utils homeassistant.utils.percentage:

def ranged_value_to_percentage(
low_high_range: tuple[float, float], value: float
) -> int:
...

and

def percentage_to_ranged_value(
low_high_range: tuple[float, float], percentage: int
) -> float:
...

These percentage utils will now use new generic scaling utils in homeassistant.utils.scaling:

scale_ranged_value_to_int_range and scale_to_ranged_value

def scale_ranged_value_to_int_range(
source_low_high_range: tuple[float, float],
target_low_high_range: tuple[float, float],
value: float,
) -> int:
"""Given a range of low and high values convert a single value to another range.

Given a source low value of 1 and a high value of 255 and
a target range from 1 to 100 this function
will return:

(1,255), 255: 100
(1,255), 127: 50
(1,255), 10: 4
"""
...

and

def scale_to_ranged_value(
source_low_high_range: tuple[float, float],
target_low_high_range: tuple[float, float],
value: int,
) -> float:
"""Given a range of low and high values convert a single value to another range.

Do not include 0 in a range if 0 means off,
e.g. for brightness or fan speed.

Given a source low value of 1 and a high value of 255 and
a target range from 1 to 100 this function
will return:

(1,255), 255: 100
(1,255), 127: ~49.8039
(1,255), 10: ~3.9216
"""
...

Utils int_states_in_range and states_in_range are moved

These utils are now under homeassistant.util.scaling. If these are used in your custom integration, make sure you update the import to the new module.

Exception handling during service calls and translation support

· 2 min read

Exception handling during service calls

Service calls which raise exceptions have until now logged stack traces. Service calls that fail due to incorrect usage, for example invalid input, don't need a stack trace and would benefit from a helpful error message in the user's own language.

To be able to suppress the stack trace in these cases, the new exception type ServiceValidationError, which is derived from HomeAssistantError, has been introduced. ServiceValidationError should now be raised instead of ValueError when the service fails because it's used incorrectly.

If the service is used correctly but still fails, HomeAssistantError, or a subclass of HomeAssistantError other than ServiceValidationError, should still be raised.

When a service raises ServiceValidationError, the error message will show in the UI, and in the logs, but the stack trace is logged at debug level. For other exceptions that are raised from a service call (including HomeAssistantError) nothing changes and a full stack trace is still printed at exception severity.

Integrations should be updated and raise ServiceValidationError instead of ValueError when the the service fails due to incorrect usage, and HomeAssistantError when it fails for other expected errors, for example a network error. Read more.

Translation support for Exceptions

The HomeAssistantError exception and its subclasses, including ServiceValidationError, now accept a translation key to allow localization. Read more. The translation key will be used in cases where the frontend receives information about the exception. The English error message from the translation cache will also be used to log a message to the console if no custom error message is passed to the exception as argument.

Background

Config processing and error handling

· 2 min read

Changes in component config processing and error handling

The way component YAML configuration is processed has been changed. Now, it is possible to raise if an error occurs. Some custom integrations might break if they are using config.async_process_component_config. Instead, they can use config.async_process_component_and_handle_errors now. This new method supports raising when an error occurs during config processing. From now on, failures will no longer be notified as a persistent message, so integrations need to implement error handling to notify users in case of a failure. Notifications are still added during setup in case of a config issue.

async def async_process_component_and_handle_errors(
hass: HomeAssistant,
config: ConfigType,
integration: Integration,
raise_on_failure: bool = False,
) -> ConfigType | None:
...

During a reload integrations can use the helpers.reload.async_integration_yaml_config. This helper now also has the ability to raise in case of a failure.

async def async_integration_yaml_config(
hass: HomeAssistant, integration_name: str, *, raise_on_failure: bool = False
) -> ConfigType | None:
...

Translation support for Exceptions on config validation

A new ConfigValidationError exception class is introduced. It will be raised in case an error occurs during config error handling and raise_on_failure is set to True. It can be re-raised to a ServiceValidationError in case this error is raised during the execution of a service call and a stack trace is not warranted. Translation keys are added to allow localization of the error messages.

Background

Public Addon Config

· 2 min read

Add-ons can now have a public folder for config or data files, which users can see and modify, but it is still backed up with the add-on.

Many add-ons ask users to provide files as part of the addon configuration. Or generate files that they want users to be able to see and potentially modify. They typically handle this by including config and/or share in the list of folders to map.

The problem with this is twofold:

  1. Nothing in config or share is backed up with the add-on. So, backups of that add-on do not include all the necessary files to run it after restore.
  2. Add-ons that map config have far more access than they should since config includes all secrets and credentials used in your Home Assistant integrations.

There is now a better solution for add-on developers. Add-ons can include addon_config in the list of folders to map. Then, the supervisor will create a folder for that add-on at /addon_configs/<your addon slug> and map that to /config within the add-on container. If your addon needs to be able to create and modify files in this folder in addition to collecting files from users, use addon_config:rw instead.

To read more about this feature and some of the use cases, see Add-on advanced options.

Backwards compatibility with /config

You may notice that the new public config folder is mapped to /config. Which is previously where Home Assistant's config folder was mapped if you added config to the map field.

This option is intended to replace the need for add-ons to map Home Assistant's config into their container. As such, an add-on cannot include both config and addon_config in the map field.

Going forward, if you do need to make Home Assistant's config available to your add-on, you should list homeassistant_config as a folder in the map field. Then Home Assistant's config folder will be mapped to /homeassistant within the container.

New addon_configs folder

Some add-ons need access to all these add-on-specific config folders. For example:

  1. Samba
  2. SSH
  3. Studio Code Server

Essentially, these add-ons provide alternative means of editing the configuration files of Home Assistant and its add-ons. Add-ons like these should add all_addon_configs:rw to the list of folders in the map field. This will map the entire addon configs folder within the container at /addon_configs.

Country selector

· One min read

Selectors has been expanded and now also includes a CountrySelector.

Using this in config flows will allow frontend to automatically translate the country codes into the proper country names.

Example:

vol.Schema(
{
vol.Optional(CONF_COUNTRY): CountrySelector(
CountrySelectorConfig(
countries=["DE", "US"],
)
),
}
)

Removal of deprecated unit conversion utilities

· One min read

The following utilities were deprecated in Home Assistant 2022.10) and have now been removed as of 2023.11:

  • homeassistant/util/distance
  • homeassistant/util/pressure
  • homeassistant/util/speed
  • homeassistant/util/temperature
  • homeassistant/util/volume

Please use the corresponding static classes from homeassistant/util/unit_conversion:

  • DistanceConverter
  • PressureConverter
  • SpeedConverter
  • TemperatureConverter
  • VolumeConverter

The deprecated functions were already unused within the built-in Home Assistant integrations, and community integrations using them should have seen warnings for the past 12 months. Attempting to import the original utilities will now result in an error.

Home Assistant is participating in Hacktoberfest 2023!

· 2 min read

📢 Exciting news for Hacktoberfest 2023 participants! We are participating! 🎉

It is not just our 10th anniversary, but also the 10th year of Hacktoberfest! Congratulations! 🎂

Hacktoberfest is a worldwide, month-long celebration of open source. An event open to everyone. Whether you’re a developer, student learning to code, documenter, or designer, you can help drive the growth of open source projects, like Home Assistant. All backgrounds and skill levels are encouraged to complete the Hacktoberfest challenge. And of course, we are happy to help you get your pull requests in.

Just like all other years, Home Assistant participates in Hacktoberfest. All of our repositories have joined, no matter if you want to make a change to the frontend, core, or even our documentation. The issue trackers on these repositories give a good overview of what is possible to contribute to.

But, I’m not a developer?!

If you are not a developer, new to git, GitHub, or open source in general, documentation can be a great way to get started. A relatively easy way to contribute is by reviewing the documentation of integrations you use or are familiar with. Check if everything is still up to date and is free of spelling/grammar mistakes.

Every single documentation page on our website has a “Edit” button, at the buttom of the page. Using that button, you can change the text on that page and provide a suggestion for improvement.

On our Community forum, there is a good step-by-step guide on how this works: Editing the Documentation and Creating a Pull Request on GitHub.

So, what are you waiting for? Sign-up on the Hacktoberfest website and start hacking! If you have any questions, please, drop by our Discord chat server. We have dedicated developer channels and are happy to assist you.

Happy Hacktoberfest 🎉

New way of excluding state attributes from recording

· One min read

The way in which state attributes are excluded from recording has changed

The recorder platforms have been replaced with two new attributes which can be set in classes derived from Entity:

  • _entity_component_unrecorded_attributes: frozenset[str] - This should be set by base component entity classes, e.g. LightEntity
  • _unrecorded_attributes: frozenset[str] - This should be set by derived platform classes, e.g. HueLight to exclude additional, integration specific, attributes from recording.

More details can be found in the entity documentation.

Background for the change is in architecture discussion #964.