Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions homeassistant/components/alexa_devices/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from typing import Any, Final

from aioamazondevices.api import AmazonDevice, AmazonEchoApi
from aioamazondevices.const import SPEAKER_GROUP_FAMILY

from homeassistant.components.notify import NotifyEntity, NotifyEntityDescription
from homeassistant.core import HomeAssistant
Expand All @@ -22,6 +23,7 @@
class AmazonNotifyEntityDescription(NotifyEntityDescription):
"""Alexa Devices notify entity description."""

is_supported: Callable[[AmazonDevice], bool] = lambda _device: True
method: Callable[[AmazonEchoApi, AmazonDevice, str], Awaitable[None]]
subkey: str

Expand All @@ -31,6 +33,7 @@ class AmazonNotifyEntityDescription(NotifyEntityDescription):
key="speak",
translation_key="speak",
subkey="AUDIO_PLAYER",
is_supported=lambda _device: _device.device_family != SPEAKER_GROUP_FAMILY,
method=lambda api, device, message: api.call_alexa_speak(device, message),
),
AmazonNotifyEntityDescription(
Expand Down Expand Up @@ -58,6 +61,7 @@ async def async_setup_entry(
for sensor_desc in NOTIFY
for serial_num in coordinator.data
if sensor_desc.subkey in coordinator.data[serial_num].capabilities
and sensor_desc.is_supported(coordinator.data[serial_num])
)


Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/aruba/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def _update_info(self) -> bool:
def get_aruba_data(self) -> dict[str, dict[str, str]] | None:
"""Retrieve data from Aruba Access Point and return parsed result."""

connect = f"ssh {self.username}@{self.host} -o HostKeyAlgorithms=ssh-rsa"
connect = f"ssh {self.username}@{self.host}"
ssh: pexpect.spawn[str] = pexpect.spawn(connect, encoding="utf-8")
query = ssh.expect(
[
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/dnsip/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/dnsip",
"iot_class": "cloud_polling",
"requirements": ["aiodns==3.4.0"]
"requirements": ["aiodns==3.5.0"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ async def _async_handle_message(
"Last content in chat log is not an AssistantContent: %s. This could be due to the model not returning a valid response",
chat_log.content[-1],
)
raise HomeAssistantError(f"{ERROR_GETTING_RESPONSE}")
raise HomeAssistantError(ERROR_GETTING_RESPONSE)
response.async_set_speech(chat_log.content[-1].content or "")
return conversation.ConversationResult(
response=response,
Expand Down
57 changes: 19 additions & 38 deletions homeassistant/components/homematicip_cloud/hap.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ async def async_setup(self, tries: int = 0) -> bool:
self.config_entry.data.get(HMIPC_AUTHTOKEN),
self.config_entry.data.get(HMIPC_NAME),
)

except HmipcConnectionError as err:
raise ConfigEntryNotReady from err
except Exception as err: # noqa: BLE001
Expand Down Expand Up @@ -210,41 +211,13 @@ def update_all(self) -> None:
for device in self.home.devices:
device.fire_update_event()

async def async_connect(self) -> None:
"""Start WebSocket connection."""
tries = 0
while True:
retry_delay = 2 ** min(tries, 8)

try:
await self.home.get_current_state_async()
hmip_events = self.home.enable_events()
self.home.set_on_connected_handler(self.ws_connected_handler)
self.home.set_on_disconnected_handler(self.ws_disconnected_handler)
tries = 0
await hmip_events
except HmipConnectionError:
_LOGGER.error(
(
"Error connecting to HomematicIP with HAP %s. "
"Retrying in %d seconds"
),
self.config_entry.unique_id,
retry_delay,
)

if self._ws_close_requested:
break
self._ws_close_requested = False
tries += 1

try:
self._retry_task = self.hass.async_create_task(
asyncio.sleep(retry_delay)
)
await self._retry_task
except asyncio.CancelledError:
break
async def async_connect(self, home: AsyncHome) -> None:
"""Connect to HomematicIP Cloud Websocket."""
await home.enable_events()

home.set_on_connected_handler(self.ws_connected_handler)
home.set_on_disconnected_handler(self.ws_disconnected_handler)
home.set_on_reconnect_handler(self.ws_reconnected_handler)

async def async_reset(self) -> bool:
"""Close the websocket connection."""
Expand Down Expand Up @@ -272,14 +245,22 @@ def shutdown(self, event) -> None:

async def ws_connected_handler(self) -> None:
"""Handle websocket connected."""
_LOGGER.debug("WebSocket connection to HomematicIP established")
_LOGGER.info("Websocket connection to HomematicIP Cloud established")
if self._ws_connection_closed.is_set():
await self.get_state()
self._ws_connection_closed.clear()

async def ws_disconnected_handler(self) -> None:
"""Handle websocket disconnection."""
_LOGGER.warning("WebSocket connection to HomematicIP closed")
_LOGGER.warning("Websocket connection to HomematicIP Cloud closed")
self._ws_connection_closed.set()

async def ws_reconnected_handler(self, reason: str) -> None:
"""Handle websocket reconnection."""
_LOGGER.info(
"Websocket connection to HomematicIP Cloud re-established due to reason: %s",
reason,
)
self._ws_connection_closed.set()

async def get_hap(
Expand All @@ -306,6 +287,6 @@ async def get_hap(
home.on_update(self.async_update)
home.on_create(self.async_create_entity)

hass.loop.create_task(self.async_connect())
await self.async_connect(home)

return home
2 changes: 1 addition & 1 deletion homeassistant/components/homematicip_cloud/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/homematicip_cloud",
"iot_class": "cloud_push",
"loggers": ["homematicip"],
"requirements": ["homematicip==2.0.4"]
"requirements": ["homematicip==2.0.5"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/homewizard/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"iot_class": "local_polling",
"loggers": ["homewizard_energy"],
"quality_scale": "platinum",
"requirements": ["python-homewizard-energy==8.3.3"],
"requirements": ["python-homewizard-energy==9.1.1"],
"zeroconf": ["_hwenergy._tcp.local.", "_homewizard._tcp.local."]
}
12 changes: 5 additions & 7 deletions homeassistant/components/nina/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from __future__ import annotations

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant

Expand All @@ -11,15 +10,14 @@
CONF_AREA_FILTER,
CONF_FILTER_CORONA,
CONF_HEADLINE_FILTER,
DOMAIN,
NO_MATCH_REGEX,
)
from .coordinator import NINADataUpdateCoordinator
from .coordinator import NinaConfigEntry, NINADataUpdateCoordinator

PLATFORMS: list[str] = [Platform.BINARY_SENSOR]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: NinaConfigEntry) -> bool:
"""Set up platform from a ConfigEntry."""
if CONF_HEADLINE_FILTER not in entry.data:
filter_regex = NO_MATCH_REGEX
Expand All @@ -41,18 +39,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

entry.async_on_unload(entry.add_update_listener(_async_update_listener))

hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
entry.runtime_data = coordinator

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: NinaConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)


async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
async def _async_update_listener(hass: HomeAssistant, entry: NinaConfigEntry) -> None:
"""Handle options update."""
await hass.config_entries.async_reload(entry.entry_id)
6 changes: 3 additions & 3 deletions homeassistant/components/nina/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@
CONF_REGIONS,
DOMAIN,
)
from .coordinator import NINADataUpdateCoordinator
from .coordinator import NinaConfigEntry, NINADataUpdateCoordinator


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: NinaConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up entries."""

coordinator: NINADataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
coordinator = config_entry.runtime_data

regions: dict[str, str] = config_entry.data[CONF_REGIONS]
message_slots: int = config_entry.data[CONF_MESSAGE_SLOTS]
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/nina/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
SCAN_INTERVAL,
)

type NinaConfigEntry = ConfigEntry[NINADataUpdateCoordinator]


@dataclass
class NinaWarningData:
Expand Down
79 changes: 41 additions & 38 deletions homeassistant/components/reolink/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,51 +19,54 @@
ATTR_RINGTONE = "ringtone"


@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Set up Reolink services."""
@raise_translated_error
async def _async_play_chime(service_call: ServiceCall) -> None:
"""Play a ringtone."""
service_data = service_call.data
device_registry = dr.async_get(service_call.hass)

@raise_translated_error
async def async_play_chime(service_call: ServiceCall) -> None:
"""Play a ringtone."""
service_data = service_call.data
device_registry = dr.async_get(hass)

for device_id in service_data[ATTR_DEVICE_ID]:
config_entry = None
device = device_registry.async_get(device_id)
if device is not None:
for entry_id in device.config_entries:
config_entry = hass.config_entries.async_get_entry(entry_id)
if config_entry is not None and config_entry.domain == DOMAIN:
break
if (
config_entry is None
or device is None
or config_entry.state != ConfigEntryState.LOADED
):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="service_entry_ex",
translation_placeholders={"service_name": "play_chime"},
)
host: ReolinkHost = config_entry.runtime_data.host
(device_uid, chime_id, is_chime) = get_device_uid_and_ch(device, host)
chime: Chime | None = host.api.chime(chime_id)
if not is_chime or chime is None:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="service_not_chime",
translation_placeholders={"device_name": str(device.name)},
for device_id in service_data[ATTR_DEVICE_ID]:
config_entry = None
device = device_registry.async_get(device_id)
if device is not None:
for entry_id in device.config_entries:
config_entry = service_call.hass.config_entries.async_get_entry(
entry_id
)
if config_entry is not None and config_entry.domain == DOMAIN:
break
if (
config_entry is None
or device is None
or config_entry.state != ConfigEntryState.LOADED
):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="service_entry_ex",
translation_placeholders={"service_name": "play_chime"},
)
host: ReolinkHost = config_entry.runtime_data.host
(device_uid, chime_id, is_chime) = get_device_uid_and_ch(device, host)
chime: Chime | None = host.api.chime(chime_id)
if not is_chime or chime is None:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="service_not_chime",
translation_placeholders={"device_name": str(device.name)},
)

ringtone = service_data[ATTR_RINGTONE]
await chime.play(ChimeToneEnum[ringtone].value)
ringtone = service_data[ATTR_RINGTONE]
await chime.play(ChimeToneEnum[ringtone].value)


@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Set up Reolink services."""

hass.services.async_register(
DOMAIN,
"play_chime",
async_play_chime,
_async_play_chime,
schema=vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): list[str],
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/package_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

aiodhcpwatcher==1.2.0
aiodiscover==2.7.0
aiodns==3.4.0
aiodns==3.5.0
aiofiles==24.1.0
aiohasupervisor==0.3.1
aiohttp-asyncmdnsresolver==0.1.1
Expand Down Expand Up @@ -131,7 +131,7 @@ multidict>=6.0.2
backoff>=2.0

# ensure pydantic version does not float since it might have breaking changes
pydantic==2.11.5
pydantic==2.11.6

# Required for Python 3.12.4 compatibility (#119223).
mashumaro>=3.13.1
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ classifiers = [
]
requires-python = ">=3.13.2"
dependencies = [
"aiodns==3.4.0",
"aiodns==3.5.0",
"aiofiles==24.1.0",
# Integrations may depend on hassio integration without listing it to
# change behavior based on presence of supervisor. Deprecated with #127228
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt

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

6 changes: 3 additions & 3 deletions requirements_all.txt

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

Loading
Loading