Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
899aa62
Modernize knx light tests (#161851)
epenet Jan 29, 2026
6b765eb
Modernize tradfri light tests (#161849)
epenet Jan 29, 2026
29e142c
Modernize matter light tests (#161850)
epenet Jan 29, 2026
7b0e21d
Fix action descriptions of `alarm_control_panel` (#161852)
NoRi2909 Jan 29, 2026
e10fe07
Cleanup deprecated color_temp support in lifx (#161848)
epenet Jan 29, 2026
804fbf9
Modernize govee_light_local light tests (#161845)
epenet Jan 29, 2026
9664047
Modernize homekit_controller light tests (#161844)
epenet Jan 29, 2026
8d9e7b0
Do not use base class of pyvlx in velux light platform (#161837)
wollew Jan 29, 2026
23da7ec
Bump mozart_api to 5.3.1.108.2 (#161846)
mj23000 Jan 29, 2026
12a2650
Add quality scale to openesve (#161651)
c00w Jan 29, 2026
a4db6a9
Modernize template light tests (#161833)
epenet Jan 29, 2026
7ab8cea
Modernize zha light tests (#161826)
epenet Jan 29, 2026
6107b79
Modernize hue light tests (#161828)
epenet Jan 29, 2026
1407f61
Modernize abode light tests (#161829)
epenet Jan 29, 2026
15ff5d0
Modernize tasmota light tests (#161830)
epenet Jan 29, 2026
dfe1990
Add service for switchbot keypad vision (#160659)
zerzhang Jan 29, 2026
95014d7
Make viaggiatreno work by fixing some critical bugs (#160093)
monga Jan 29, 2026
3551382
Add additional JVC Projector entities (#161134)
SteveEasley Jan 29, 2026
acbdbc9
Bump pydexcom to 0.5.1 (#161549)
gagebenne Jan 29, 2026
72e7bf7
Add new Liebherr integration (#161197)
mettolen Jan 29, 2026
336ef4c
Remove outdated device registry cleanup in derivative (#161858)
epenet Jan 29, 2026
66f1819
Bump renault-api to 0.5.3 (#161857)
sebastiaanspeck Jan 29, 2026
826168b
Remove outdated device registry cleanup in integration (#161863)
epenet Jan 29, 2026
72ba59f
Remove outdated device registry cleanup in utility_meter (#161868)
epenet Jan 29, 2026
b432808
Fix incorrect entity_description class in radarr (#161856)
epenet Jan 29, 2026
4e29476
Cleanup deprecated YAML import from datadog (#161870)
epenet Jan 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CODEOWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions homeassistant/components/alarm_control_panel/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@
},
"services": {
"alarm_arm_away": {
"description": "Arms the alarm in the away mode.",
"description": "Arms an alarm in the away mode.",
"fields": {
"code": {
"description": "[%key:component::alarm_control_panel::services::alarm_arm_custom_bypass::fields::code::description%]",
Expand All @@ -176,7 +176,7 @@
"name": "Arm away"
},
"alarm_arm_custom_bypass": {
"description": "Arms the alarm while allowing to bypass a custom area.",
"description": "Arms an alarm while allowing to bypass a custom area.",
"fields": {
"code": {
"description": "Code to arm the alarm.",
Expand All @@ -186,7 +186,7 @@
"name": "Arm with custom bypass"
},
"alarm_arm_home": {
"description": "Arms the alarm in the home mode.",
"description": "Arms an alarm in the home mode.",
"fields": {
"code": {
"description": "[%key:component::alarm_control_panel::services::alarm_arm_custom_bypass::fields::code::description%]",
Expand All @@ -196,7 +196,7 @@
"name": "Arm home"
},
"alarm_arm_night": {
"description": "Arms the alarm in the night mode.",
"description": "Arms an alarm in the night mode.",
"fields": {
"code": {
"description": "[%key:component::alarm_control_panel::services::alarm_arm_custom_bypass::fields::code::description%]",
Expand All @@ -206,7 +206,7 @@
"name": "Arm night"
},
"alarm_arm_vacation": {
"description": "Arms the alarm in the vacation mode.",
"description": "Arms an alarm in the vacation mode.",
"fields": {
"code": {
"description": "[%key:component::alarm_control_panel::services::alarm_arm_custom_bypass::fields::code::description%]",
Expand All @@ -216,7 +216,7 @@
"name": "Arm vacation"
},
"alarm_disarm": {
"description": "Disarms the alarm.",
"description": "Disarms an alarm.",
"fields": {
"code": {
"description": "Code to disarm the alarm.",
Expand All @@ -226,7 +226,7 @@
"name": "Disarm"
},
"alarm_trigger": {
"description": "Triggers the alarm manually.",
"description": "Triggers an alarm manually.",
"fields": {
"code": {
"description": "[%key:component::alarm_control_panel::services::alarm_arm_custom_bypass::fields::code::description%]",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/bang_olufsen/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/bang_olufsen",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["mozart-api==5.3.1.108.0"],
"requirements": ["mozart-api==5.3.1.108.2"],
"zeroconf": ["_bangolufsen._tcp.local."]
}
5 changes: 3 additions & 2 deletions homeassistant/components/bang_olufsen/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import json
import logging
from typing import TYPE_CHECKING, Any, cast
from uuid import UUID

from aiohttp import ClientConnectorError
from mozart_api import __version__ as MOZART_API_VERSION
Expand Down Expand Up @@ -735,7 +736,7 @@ async def async_select_source(self, source: str) -> None:
await self._client.set_active_source(source_id=key)
else:
# Video
await self._client.post_remote_trigger(id=key)
await self._client.post_remote_trigger(id=UUID(key))

async def async_select_sound_mode(self, sound_mode: str) -> None:
"""Select a sound mode."""
Expand Down Expand Up @@ -894,7 +895,7 @@ async def async_play_media(
translation_key="play_media_error",
translation_placeholders={
"media_type": media_type,
"error_message": json.loads(error.body)["message"],
"error_message": json.loads(cast(str, error.body))["message"],
},
) from error

Expand Down
45 changes: 3 additions & 42 deletions homeassistant/components/datadog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import logging

from datadog import DogStatsd, initialize
import voluptuous as vol

from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
Expand All @@ -16,53 +15,15 @@
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, state as state_helper
from homeassistant.helpers.typing import ConfigType

from . import config_flow as config_flow
from .const import (
CONF_RATE,
DEFAULT_HOST,
DEFAULT_PORT,
DEFAULT_PREFIX,
DEFAULT_RATE,
DOMAIN,
)
from .const import CONF_RATE, DOMAIN

_LOGGER = logging.getLogger(__name__)

type DatadogConfigEntry = ConfigEntry[DogStatsd]

CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Required(CONF_HOST, default=DEFAULT_HOST): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_PREFIX, default=DEFAULT_PREFIX): cv.string,
vol.Optional(CONF_RATE, default=DEFAULT_RATE): vol.All(
vol.Coerce(int), vol.Range(min=1)
),
}
)
},
extra=vol.ALLOW_EXTRA,
)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Datadog integration from YAML, initiating config flow import."""
if DOMAIN not in config:
return True

hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=config[DOMAIN],
)
)

return True
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)


async def async_setup_entry(hass: HomeAssistant, entry: DatadogConfigEntry) -> bool:
Expand Down
57 changes: 1 addition & 56 deletions homeassistant/components/datadog/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
OptionsFlow,
)
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_PREFIX
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant, callback
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.core import HomeAssistant, callback

from .const import (
CONF_RATE,
Expand Down Expand Up @@ -71,22 +70,6 @@ async def async_step_user(
errors=errors,
)

async def async_step_import(self, user_input: dict[str, Any]) -> ConfigFlowResult:
"""Handle import from configuration.yaml."""
# Check for duplicates
self._async_abort_entries_match(
{CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]}
)

result = await self.async_step_user(user_input)

if errors := result.get("errors"):
await deprecate_yaml_issue(self.hass, False)
return self.async_abort(reason=errors["base"])

await deprecate_yaml_issue(self.hass, True)
return result

@staticmethod
@callback
def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow:
Expand Down Expand Up @@ -163,41 +146,3 @@ async def validate_datadog_connection(
return False
else:
return True


async def deprecate_yaml_issue(
hass: HomeAssistant,
import_success: bool,
) -> None:
"""Create an issue to deprecate YAML config."""
if import_success:
async_create_issue(
hass,
HOMEASSISTANT_DOMAIN,
f"deprecated_yaml_{DOMAIN}",
is_fixable=False,
issue_domain=DOMAIN,
breaks_in_ha_version="2026.2.0",
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",
translation_placeholders={
"domain": DOMAIN,
"integration_title": "Datadog",
},
)
else:
async_create_issue(
hass,
DOMAIN,
"deprecated_yaml_import_connection_error",
breaks_in_ha_version="2026.2.0",
is_fixable=False,
issue_domain=DOMAIN,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml_import_connection_error",
translation_placeholders={
"domain": DOMAIN,
"integration_title": "Datadog",
"url": f"/config/integrations/dashboard/add?domain={DOMAIN}",
},
)
6 changes: 0 additions & 6 deletions homeassistant/components/datadog/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@
}
}
},
"issues": {
"deprecated_yaml_import_connection_error": {
"description": "There was an error connecting to the Datadog Agent when trying to import the YAML configuration.\n\nEnsure the YAML configuration is correct and restart Home Assistant to try again or remove the {domain} configuration from your `configuration.yaml` file and continue to [set up the integration]({url}) manually.",
"title": "{domain} YAML configuration import failed"
}
},
"options": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]",
Expand Down
10 changes: 1 addition & 9 deletions homeassistant/components/derivative/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_SOURCE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device import (
async_entity_id_to_device_id,
async_remove_stale_devices_links_keep_entity_device,
)
from homeassistant.helpers.device import async_entity_id_to_device_id
from homeassistant.helpers.helper_integration import (
async_handle_source_entity_changes,
async_remove_helper_config_entry_from_source_device,
Expand All @@ -22,11 +19,6 @@
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Derivative from a config entry."""

# This can be removed in HA Core 2026.2
async_remove_stale_devices_links_keep_entity_device(
hass, entry.entry_id, entry.options[CONF_SOURCE]
)

def set_source_entity_id_or_uuid(source_entity_id: str) -> None:
hass.config_entries.async_update_entry(
entry,
Expand Down
14 changes: 9 additions & 5 deletions homeassistant/components/dexcom/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""The Dexcom integration."""

from pydexcom import AccountError, Dexcom, SessionError
from pydexcom import Dexcom, Region
from pydexcom.errors import AccountError, SessionError

from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
Expand All @@ -14,10 +15,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: DexcomConfigEntry) -> bo
"""Set up Dexcom from a config entry."""
try:
dexcom = await hass.async_add_executor_job(
Dexcom,
entry.data[CONF_USERNAME],
entry.data[CONF_PASSWORD],
entry.data[CONF_SERVER] == SERVER_OUS,
lambda: Dexcom(
username=entry.data[CONF_USERNAME],
password=entry.data[CONF_PASSWORD],
region=Region.OUS
if entry.data[CONF_SERVER] == SERVER_OUS
else Region.US,
)
)
except AccountError:
return False
Expand Down
14 changes: 9 additions & 5 deletions homeassistant/components/dexcom/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import logging
from typing import Any

from pydexcom import AccountError, Dexcom, SessionError
from pydexcom import Dexcom, Region
from pydexcom.errors import AccountError, SessionError
import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
Expand Down Expand Up @@ -37,10 +38,13 @@ async def async_step_user(
if user_input is not None:
try:
await self.hass.async_add_executor_job(
Dexcom,
user_input[CONF_USERNAME],
user_input[CONF_PASSWORD],
user_input[CONF_SERVER] == SERVER_OUS,
lambda: Dexcom(
username=user_input[CONF_USERNAME],
password=user_input[CONF_PASSWORD],
region=Region.OUS
if user_input[CONF_SERVER] == SERVER_OUS
else Region.US,
)
)
except SessionError:
errors["base"] = "cannot_connect"
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/dexcom/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
type DexcomConfigEntry = ConfigEntry[DexcomCoordinator]


class DexcomCoordinator(DataUpdateCoordinator[GlucoseReading]):
class DexcomCoordinator(DataUpdateCoordinator[GlucoseReading | None]):
"""Dexcom Coordinator."""

def __init__(
Expand All @@ -37,7 +37,7 @@ def __init__(
)
self.dexcom = dexcom

async def _async_update_data(self) -> GlucoseReading:
async def _async_update_data(self) -> GlucoseReading | None:
"""Fetch data from API endpoint."""
return await self.hass.async_add_executor_job(
self.dexcom.get_current_glucose_reading
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/dexcom/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["pydexcom"],
"requirements": ["pydexcom==0.2.3"]
"requirements": ["pydexcom==0.5.1"]
}
12 changes: 1 addition & 11 deletions homeassistant/components/integration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device import (
async_entity_id_to_device_id,
async_remove_stale_devices_links_keep_entity_device,
)
from homeassistant.helpers.device import async_entity_id_to_device_id
from homeassistant.helpers.helper_integration import (
async_handle_source_entity_changes,
async_remove_helper_config_entry_from_source_device,
Expand All @@ -24,13 +21,6 @@
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Integration from a config entry."""

# This can be removed in HA Core 2026.2
async_remove_stale_devices_links_keep_entity_device(
hass,
entry.entry_id,
entry.options[CONF_SOURCE_SENSOR],
)

def set_source_entity_id_or_uuid(source_entity_id: str) -> None:
hass.config_entries.async_update_entry(
entry,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/jvc_projector/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async def async_migrate_entities(
def _update_entry(entry: RegistryEntry) -> dict[str, str] | None:
"""Fix unique_id of power binary_sensor entry."""
if entry.domain == Platform.BINARY_SENSOR and ":" not in entry.unique_id:
if "_power" in entry.unique_id:
if entry.unique_id.endswith("_power"):
return {"new_unique_id": f"{coordinator.unique_id}_power"}
return None

Expand Down
Loading
Loading