This commit is contained in:
Franck Nijhof 2025-06-13 22:15:26 +02:00 committed by GitHub
commit a75646d047
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 120 additions and 104 deletions

View File

@ -8,5 +8,5 @@
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["aioamazondevices"], "loggers": ["aioamazondevices"],
"quality_scale": "bronze", "quality_scale": "bronze",
"requirements": ["aioamazondevices==3.0.6"] "requirements": ["aioamazondevices==3.1.2"]
} }

View File

@ -7,6 +7,7 @@ from dataclasses import dataclass
from typing import Any, Final from typing import Any, Final
from aioamazondevices.api import AmazonDevice, AmazonEchoApi from aioamazondevices.api import AmazonDevice, AmazonEchoApi
from aioamazondevices.const import SPEAKER_GROUP_FAMILY
from homeassistant.components.notify import NotifyEntity, NotifyEntityDescription from homeassistant.components.notify import NotifyEntity, NotifyEntityDescription
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -22,6 +23,7 @@ PARALLEL_UPDATES = 1
class AmazonNotifyEntityDescription(NotifyEntityDescription): class AmazonNotifyEntityDescription(NotifyEntityDescription):
"""Alexa Devices notify entity description.""" """Alexa Devices notify entity description."""
is_supported: Callable[[AmazonDevice], bool] = lambda _device: True
method: Callable[[AmazonEchoApi, AmazonDevice, str], Awaitable[None]] method: Callable[[AmazonEchoApi, AmazonDevice, str], Awaitable[None]]
subkey: str subkey: str
@ -31,6 +33,7 @@ NOTIFY: Final = (
key="speak", key="speak",
translation_key="speak", translation_key="speak",
subkey="AUDIO_PLAYER", subkey="AUDIO_PLAYER",
is_supported=lambda _device: _device.device_family != SPEAKER_GROUP_FAMILY,
method=lambda api, device, message: api.call_alexa_speak(device, message), method=lambda api, device, message: api.call_alexa_speak(device, message),
), ),
AmazonNotifyEntityDescription( AmazonNotifyEntityDescription(
@ -58,6 +61,7 @@ async def async_setup_entry(
for sensor_desc in NOTIFY for sensor_desc in NOTIFY
for serial_num in coordinator.data for serial_num in coordinator.data
if sensor_desc.subkey in coordinator.data[serial_num].capabilities if sensor_desc.subkey in coordinator.data[serial_num].capabilities
and sensor_desc.is_supported(coordinator.data[serial_num])
) )

View File

@ -89,7 +89,7 @@ class ArubaDeviceScanner(DeviceScanner):
def get_aruba_data(self) -> dict[str, dict[str, str]] | None: def get_aruba_data(self) -> dict[str, dict[str, str]] | None:
"""Retrieve data from Aruba Access Point and return parsed result.""" """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") ssh: pexpect.spawn[str] = pexpect.spawn(connect, encoding="utf-8")
query = ssh.expect( query = ssh.expect(
[ [

View File

@ -5,5 +5,5 @@
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/dnsip", "documentation": "https://www.home-assistant.io/integrations/dnsip",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"requirements": ["aiodns==3.4.0"] "requirements": ["aiodns==3.5.0"]
} }

View File

@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/frontend", "documentation": "https://www.home-assistant.io/integrations/frontend",
"integration_type": "system", "integration_type": "system",
"quality_scale": "internal", "quality_scale": "internal",
"requirements": ["home-assistant-frontend==20250531.2"] "requirements": ["home-assistant-frontend==20250531.3"]
} }

View File

@ -128,6 +128,7 @@ class HomematicipHAP:
self.config_entry.data.get(HMIPC_AUTHTOKEN), self.config_entry.data.get(HMIPC_AUTHTOKEN),
self.config_entry.data.get(HMIPC_NAME), self.config_entry.data.get(HMIPC_NAME),
) )
except HmipcConnectionError as err: except HmipcConnectionError as err:
raise ConfigEntryNotReady from err raise ConfigEntryNotReady from err
except Exception as err: # noqa: BLE001 except Exception as err: # noqa: BLE001
@ -210,41 +211,13 @@ class HomematicipHAP:
for device in self.home.devices: for device in self.home.devices:
device.fire_update_event() device.fire_update_event()
async def async_connect(self) -> None: async def async_connect(self, home: AsyncHome) -> None:
"""Start WebSocket connection.""" """Connect to HomematicIP Cloud Websocket."""
tries = 0 await home.enable_events()
while True:
retry_delay = 2 ** min(tries, 8)
try: home.set_on_connected_handler(self.ws_connected_handler)
await self.home.get_current_state_async() home.set_on_disconnected_handler(self.ws_disconnected_handler)
hmip_events = self.home.enable_events() home.set_on_reconnect_handler(self.ws_reconnected_handler)
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_reset(self) -> bool: async def async_reset(self) -> bool:
"""Close the websocket connection.""" """Close the websocket connection."""
@ -272,14 +245,22 @@ class HomematicipHAP:
async def ws_connected_handler(self) -> None: async def ws_connected_handler(self) -> None:
"""Handle websocket connected.""" """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(): if self._ws_connection_closed.is_set():
await self.get_state() await self.get_state()
self._ws_connection_closed.clear() self._ws_connection_closed.clear()
async def ws_disconnected_handler(self) -> None: async def ws_disconnected_handler(self) -> None:
"""Handle websocket disconnection.""" """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() self._ws_connection_closed.set()
async def get_hap( async def get_hap(
@ -306,6 +287,6 @@ class HomematicipHAP:
home.on_update(self.async_update) home.on_update(self.async_update)
home.on_create(self.async_create_entity) home.on_create(self.async_create_entity)
hass.loop.create_task(self.async_connect()) await self.async_connect(home)
return home return home

View File

@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/homematicip_cloud", "documentation": "https://www.home-assistant.io/integrations/homematicip_cloud",
"iot_class": "cloud_push", "iot_class": "cloud_push",
"loggers": ["homematicip"], "loggers": ["homematicip"],
"requirements": ["homematicip==2.0.4"] "requirements": ["homematicip==2.0.5"]
} }

View File

@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/jewish_calendar", "documentation": "https://www.home-assistant.io/integrations/jewish_calendar",
"iot_class": "calculated", "iot_class": "calculated",
"loggers": ["hdate"], "loggers": ["hdate"],
"requirements": ["hdate[astral]==1.1.1"], "requirements": ["hdate[astral]==1.1.2"],
"single_config_entry": true "single_config_entry": true
} }

View File

@ -73,7 +73,7 @@ INFO_SENSORS: tuple[JewishCalendarSensorDescription, ...] = (
translation_key="weekly_portion", translation_key="weekly_portion",
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options_fn=lambda _: [str(p) for p in Parasha], options_fn=lambda _: [str(p) for p in Parasha],
value_fn=lambda results: str(results.after_tzais_date.upcoming_shabbat.parasha), value_fn=lambda results: results.after_tzais_date.upcoming_shabbat.parasha,
), ),
JewishCalendarSensorDescription( JewishCalendarSensorDescription(
key="holiday", key="holiday",
@ -98,17 +98,13 @@ INFO_SENSORS: tuple[JewishCalendarSensorDescription, ...] = (
key="omer_count", key="omer_count",
translation_key="omer_count", translation_key="omer_count",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
value_fn=lambda results: ( value_fn=lambda results: results.after_shkia_date.omer.total_days,
results.after_shkia_date.omer.total_days
if results.after_shkia_date.omer
else 0
),
), ),
JewishCalendarSensorDescription( JewishCalendarSensorDescription(
key="daf_yomi", key="daf_yomi",
translation_key="daf_yomi", translation_key="daf_yomi",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
value_fn=lambda results: str(results.daytime_date.daf_yomi), value_fn=lambda results: results.daytime_date.daf_yomi,
), ),
) )

View File

@ -5,7 +5,7 @@ from __future__ import annotations
import asyncio import asyncio
from collections.abc import Callable from collections.abc import Callable
from datetime import timedelta from datetime import timedelta
from typing import Any from typing import TYPE_CHECKING, Any
import aiolifx_effects import aiolifx_effects
from aiolifx_themes.painter import ThemePainter from aiolifx_themes.painter import ThemePainter
@ -31,9 +31,12 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.service import async_extract_referenced_entity_ids from homeassistant.helpers.service import async_extract_referenced_entity_ids
from .const import _ATTR_COLOR_TEMP, ATTR_THEME, DATA_LIFX_MANAGER, DOMAIN from .const import _ATTR_COLOR_TEMP, ATTR_THEME, DATA_LIFX_MANAGER, DOMAIN
from .coordinator import LIFXUpdateCoordinator, Light from .coordinator import LIFXUpdateCoordinator
from .util import convert_8_to_16, find_hsbk from .util import convert_8_to_16, find_hsbk
if TYPE_CHECKING:
from aiolifx.aiolifx import Light
SCAN_INTERVAL = timedelta(seconds=10) SCAN_INTERVAL = timedelta(seconds=10)
SERVICE_EFFECT_COLORLOOP = "effect_colorloop" SERVICE_EFFECT_COLORLOOP = "effect_colorloop"
@ -426,8 +429,8 @@ class LIFXManager:
) -> None: ) -> None:
"""Start the firmware-based Sky effect.""" """Start the firmware-based Sky effect."""
palette = kwargs.get(ATTR_PALETTE) palette = kwargs.get(ATTR_PALETTE)
if palette is not None:
theme = Theme() theme = Theme()
if palette is not None:
for hsbk in palette: for hsbk in palette:
theme.add_hsbk(hsbk[0], hsbk[1], hsbk[2], hsbk[3]) theme.add_hsbk(hsbk[0], hsbk[1], hsbk[2], hsbk[3])

View File

@ -7,6 +7,6 @@
"integration_type": "hub", "integration_type": "hub",
"iot_class": "local_polling", "iot_class": "local_polling",
"loggers": ["linkplay"], "loggers": ["linkplay"],
"requirements": ["python-linkplay==0.2.11"], "requirements": ["python-linkplay==0.2.12"],
"zeroconf": ["_linkplay._tcp.local."] "zeroconf": ["_linkplay._tcp.local."]
} }

View File

@ -36,11 +36,6 @@ _LOGGER = logging.getLogger(__name__)
PRODID = "-//homeassistant.io//local_calendar 1.0//EN" PRODID = "-//homeassistant.io//local_calendar 1.0//EN"
# The calendar on disk is only changed when this entity is updated, so there
# is no need to poll for changes. The calendar enttiy base class will handle
# refreshing the entity state based on the start or end time of the event.
SCAN_INTERVAL = timedelta(days=1)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,

View File

@ -10,6 +10,7 @@ from opower import (
CannotConnect, CannotConnect,
InvalidAuth, InvalidAuth,
Opower, Opower,
create_cookie_jar,
get_supported_utility_names, get_supported_utility_names,
select_utility, select_utility,
) )
@ -39,7 +40,7 @@ async def _validate_login(
) -> dict[str, str]: ) -> dict[str, str]:
"""Validate login data and return any errors.""" """Validate login data and return any errors."""
api = Opower( api = Opower(
async_create_clientsession(hass), async_create_clientsession(hass, cookie_jar=create_cookie_jar()),
login_data[CONF_UTILITY], login_data[CONF_UTILITY],
login_data[CONF_USERNAME], login_data[CONF_USERNAME],
login_data[CONF_PASSWORD], login_data[CONF_PASSWORD],

View File

@ -12,6 +12,7 @@ from opower import (
MeterType, MeterType,
Opower, Opower,
ReadResolution, ReadResolution,
create_cookie_jar,
) )
from opower.exceptions import ApiException, CannotConnect, InvalidAuth from opower.exceptions import ApiException, CannotConnect, InvalidAuth
@ -30,7 +31,8 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, UnitOfEnergy, UnitOfVolume from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, UnitOfEnergy, UnitOfVolume
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers import aiohttp_client, issue_registry as ir from homeassistant.helpers import issue_registry as ir
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
@ -62,7 +64,7 @@ class OpowerCoordinator(DataUpdateCoordinator[dict[str, Forecast]]):
update_interval=timedelta(hours=12), update_interval=timedelta(hours=12),
) )
self.api = Opower( self.api = Opower(
aiohttp_client.async_get_clientsession(hass), async_create_clientsession(hass, cookie_jar=create_cookie_jar()),
config_entry.data[CONF_UTILITY], config_entry.data[CONF_UTILITY],
config_entry.data[CONF_USERNAME], config_entry.data[CONF_USERNAME],
config_entry.data[CONF_PASSWORD], config_entry.data[CONF_PASSWORD],

View File

@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/opower", "documentation": "https://www.home-assistant.io/integrations/opower",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["opower"], "loggers": ["opower"],
"requirements": ["opower==0.12.3"] "requirements": ["opower==0.12.4"]
} }

View File

@ -4,6 +4,7 @@ from datetime import datetime
import logging import logging
from ical.event import Event from ical.event import Event
from ical.timeline import Timeline
from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.components.calendar import CalendarEntity, CalendarEvent
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -48,12 +49,18 @@ class RemoteCalendarEntity(
super().__init__(coordinator) super().__init__(coordinator)
self._attr_name = entry.data[CONF_CALENDAR_NAME] self._attr_name = entry.data[CONF_CALENDAR_NAME]
self._attr_unique_id = entry.entry_id self._attr_unique_id = entry.entry_id
self._event: CalendarEvent | None = None self._timeline: Timeline | None = None
@property @property
def event(self) -> CalendarEvent | None: def event(self) -> CalendarEvent | None:
"""Return the next upcoming event.""" """Return the next upcoming event."""
return self._event if self._timeline is None:
return None
now = dt_util.now()
events = self._timeline.active_after(now)
if event := next(events, None):
return _get_calendar_event(event)
return None
async def async_get_events( async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime self, hass: HomeAssistant, start_date: datetime, end_date: datetime
@ -79,15 +86,12 @@ class RemoteCalendarEntity(
""" """
await super().async_update() await super().async_update()
def next_timeline_event() -> CalendarEvent | None: def _get_timeline() -> Timeline | None:
"""Return the next active event.""" """Return the next active event."""
now = dt_util.now() now = dt_util.now()
events = self.coordinator.data.timeline_tz(now.tzinfo).active_after(now) return self.coordinator.data.timeline_tz(now.tzinfo)
if event := next(events, None):
return _get_calendar_event(event)
return None
self._event = await self.hass.async_add_executor_job(next_timeline_event) self._timeline = await self.hass.async_add_executor_job(_get_timeline)
def _get_calendar_event(event: Event) -> CalendarEvent: def _get_calendar_event(event: Event) -> CalendarEvent:

View File

@ -76,10 +76,10 @@ class SamsungTVEntity(CoordinatorEntity[SamsungTVDataUpdateCoordinator], Entity)
def _wake_on_lan(self) -> None: def _wake_on_lan(self) -> None:
"""Wake the device via wake on lan.""" """Wake the device via wake on lan."""
send_magic_packet(self._mac, ip_address=self._host) send_magic_packet(self._mac, ip_address=self._host) # type: ignore[arg-type]
# If the ip address changed since we last saw the device # If the ip address changed since we last saw the device
# broadcast a packet as well # broadcast a packet as well
send_magic_packet(self._mac) send_magic_packet(self._mac) # type: ignore[arg-type]
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off.""" """Turn the device off."""

View File

@ -38,7 +38,7 @@
"getmac==0.9.5", "getmac==0.9.5",
"samsungctl[websocket]==0.7.1", "samsungctl[websocket]==0.7.1",
"samsungtvws[async,encrypted]==2.7.2", "samsungtvws[async,encrypted]==2.7.2",
"wakeonlan==2.1.0", "wakeonlan==3.1.0",
"async-upnp-client==0.44.0" "async-upnp-client==0.44.0"
], ],
"ssdp": [ "ssdp": [

View File

@ -9,5 +9,5 @@ from homeassistant.helpers import aiohttp_client
async def async_client_session(hass: HomeAssistant) -> ClientSession: async def async_client_session(hass: HomeAssistant) -> ClientSession:
"""Return a new aiohttp session.""" """Return a new aiohttp session."""
return aiohttp_client.async_create_clientsession( return aiohttp_client.async_create_clientsession(
hass, verify_ssl=False, cookie_jar=CookieJar(unsafe=True) hass, verify_ssl=False, cookie_jar=CookieJar(unsafe=True, quote_cookie=False)
) )

View File

@ -52,7 +52,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
) )
await hass.async_add_executor_job( await hass.async_add_executor_job(
partial(wakeonlan.send_magic_packet, mac_address, **service_kwargs) partial(wakeonlan.send_magic_packet, mac_address, **service_kwargs) # type: ignore[arg-type]
) )
hass.services.async_register( hass.services.async_register(

View File

@ -5,5 +5,5 @@
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/wake_on_lan", "documentation": "https://www.home-assistant.io/integrations/wake_on_lan",
"iot_class": "local_push", "iot_class": "local_push",
"requirements": ["wakeonlan==2.1.0"] "requirements": ["wakeonlan==3.1.0"]
} }

View File

@ -330,6 +330,12 @@ class XiaomiGenericDevice(
"""Return the percentage based speed of the fan.""" """Return the percentage based speed of the fan."""
return None return None
@property
def is_on(self) -> bool | None:
"""Return true if device is on."""
# Base FanEntity uses percentage to determine if the device is on.
return self._attr_is_on
async def async_turn_on( async def async_turn_on(
self, self,
percentage: int | None = None, percentage: int | None = None,

View File

@ -25,7 +25,7 @@ if TYPE_CHECKING:
APPLICATION_NAME: Final = "HomeAssistant" APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2025 MAJOR_VERSION: Final = 2025
MINOR_VERSION: Final = 6 MINOR_VERSION: Final = 6
PATCH_VERSION: Final = "0" PATCH_VERSION: Final = "1"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 2) REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 2)

View File

@ -2,7 +2,7 @@
aiodhcpwatcher==1.2.0 aiodhcpwatcher==1.2.0
aiodiscover==2.7.0 aiodiscover==2.7.0
aiodns==3.4.0 aiodns==3.5.0
aiofiles==24.1.0 aiofiles==24.1.0
aiohasupervisor==0.3.1 aiohasupervisor==0.3.1
aiohttp-asyncmdnsresolver==0.1.1 aiohttp-asyncmdnsresolver==0.1.1
@ -39,7 +39,7 @@ habluetooth==3.49.0
hass-nabucasa==0.101.0 hass-nabucasa==0.101.0
hassil==2.2.3 hassil==2.2.3
home-assistant-bluetooth==1.13.1 home-assistant-bluetooth==1.13.1
home-assistant-frontend==20250531.2 home-assistant-frontend==20250531.3
home-assistant-intents==2025.6.10 home-assistant-intents==2025.6.10
httpx==0.28.1 httpx==0.28.1
ifaddr==0.2.0 ifaddr==0.2.0

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "homeassistant" name = "homeassistant"
version = "2025.6.0" version = "2025.6.1"
license = "Apache-2.0" license = "Apache-2.0"
license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"] license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"]
description = "Open-source home automation platform running on Python 3." description = "Open-source home automation platform running on Python 3."
@ -23,7 +23,7 @@ classifiers = [
] ]
requires-python = ">=3.13.2" requires-python = ">=3.13.2"
dependencies = [ dependencies = [
"aiodns==3.4.0", "aiodns==3.5.0",
"aiofiles==24.1.0", "aiofiles==24.1.0",
# Integrations may depend on hassio integration without listing it to # Integrations may depend on hassio integration without listing it to
# change behavior based on presence of supervisor. Deprecated with #127228 # change behavior based on presence of supervisor. Deprecated with #127228

2
requirements.txt generated
View File

@ -3,7 +3,7 @@
-c homeassistant/package_constraints.txt -c homeassistant/package_constraints.txt
# Home Assistant Core # Home Assistant Core
aiodns==3.4.0 aiodns==3.5.0
aiofiles==24.1.0 aiofiles==24.1.0
aiohasupervisor==0.3.1 aiohasupervisor==0.3.1
aiohttp==3.12.12 aiohttp==3.12.12

16
requirements_all.txt generated
View File

@ -182,7 +182,7 @@ aioairzone-cloud==0.6.12
aioairzone==1.0.0 aioairzone==1.0.0
# homeassistant.components.alexa_devices # homeassistant.components.alexa_devices
aioamazondevices==3.0.6 aioamazondevices==3.1.2
# homeassistant.components.ambient_network # homeassistant.components.ambient_network
# homeassistant.components.ambient_station # homeassistant.components.ambient_station
@ -223,7 +223,7 @@ aiodhcpwatcher==1.2.0
aiodiscover==2.7.0 aiodiscover==2.7.0
# homeassistant.components.dnsip # homeassistant.components.dnsip
aiodns==3.4.0 aiodns==3.5.0
# homeassistant.components.duke_energy # homeassistant.components.duke_energy
aiodukeenergy==0.3.0 aiodukeenergy==0.3.0
@ -1133,7 +1133,7 @@ hass-splunk==0.1.1
hassil==2.2.3 hassil==2.2.3
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate[astral]==1.1.1 hdate[astral]==1.1.2
# homeassistant.components.heatmiser # homeassistant.components.heatmiser
heatmiserV3==2.0.3 heatmiserV3==2.0.3
@ -1164,13 +1164,13 @@ hole==0.8.0
holidays==0.74 holidays==0.74
# homeassistant.components.frontend # homeassistant.components.frontend
home-assistant-frontend==20250531.2 home-assistant-frontend==20250531.3
# homeassistant.components.conversation # homeassistant.components.conversation
home-assistant-intents==2025.6.10 home-assistant-intents==2025.6.10
# homeassistant.components.homematicip_cloud # homeassistant.components.homematicip_cloud
homematicip==2.0.4 homematicip==2.0.5
# homeassistant.components.horizon # homeassistant.components.horizon
horimote==0.4.1 horimote==0.4.1
@ -1617,7 +1617,7 @@ openwrt-luci-rpc==1.1.17
openwrt-ubus-rpc==0.0.2 openwrt-ubus-rpc==0.0.2
# homeassistant.components.opower # homeassistant.components.opower
opower==0.12.3 opower==0.12.4
# homeassistant.components.oralb # homeassistant.components.oralb
oralb-ble==0.17.6 oralb-ble==0.17.6
@ -2452,7 +2452,7 @@ python-juicenet==1.1.0
python-kasa[speedups]==0.10.2 python-kasa[speedups]==0.10.2
# homeassistant.components.linkplay # homeassistant.components.linkplay
python-linkplay==0.2.11 python-linkplay==0.2.12
# homeassistant.components.lirc # homeassistant.components.lirc
# python-lirc==1.2.3 # python-lirc==1.2.3
@ -3059,7 +3059,7 @@ vultr==0.1.2
# homeassistant.components.samsungtv # homeassistant.components.samsungtv
# homeassistant.components.wake_on_lan # homeassistant.components.wake_on_lan
wakeonlan==2.1.0 wakeonlan==3.1.0
# homeassistant.components.wallbox # homeassistant.components.wallbox
wallbox==0.9.0 wallbox==0.9.0

View File

@ -170,7 +170,7 @@ aioairzone-cloud==0.6.12
aioairzone==1.0.0 aioairzone==1.0.0
# homeassistant.components.alexa_devices # homeassistant.components.alexa_devices
aioamazondevices==3.0.6 aioamazondevices==3.1.2
# homeassistant.components.ambient_network # homeassistant.components.ambient_network
# homeassistant.components.ambient_station # homeassistant.components.ambient_station
@ -211,7 +211,7 @@ aiodhcpwatcher==1.2.0
aiodiscover==2.7.0 aiodiscover==2.7.0
# homeassistant.components.dnsip # homeassistant.components.dnsip
aiodns==3.4.0 aiodns==3.5.0
# homeassistant.components.duke_energy # homeassistant.components.duke_energy
aiodukeenergy==0.3.0 aiodukeenergy==0.3.0
@ -988,7 +988,7 @@ hass-nabucasa==0.101.0
hassil==2.2.3 hassil==2.2.3
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate[astral]==1.1.1 hdate[astral]==1.1.2
# homeassistant.components.here_travel_time # homeassistant.components.here_travel_time
here-routing==1.0.1 here-routing==1.0.1
@ -1010,13 +1010,13 @@ hole==0.8.0
holidays==0.74 holidays==0.74
# homeassistant.components.frontend # homeassistant.components.frontend
home-assistant-frontend==20250531.2 home-assistant-frontend==20250531.3
# homeassistant.components.conversation # homeassistant.components.conversation
home-assistant-intents==2025.6.10 home-assistant-intents==2025.6.10
# homeassistant.components.homematicip_cloud # homeassistant.components.homematicip_cloud
homematicip==2.0.4 homematicip==2.0.5
# homeassistant.components.remember_the_milk # homeassistant.components.remember_the_milk
httplib2==0.20.4 httplib2==0.20.4
@ -1370,7 +1370,7 @@ openhomedevice==2.2.0
openwebifpy==4.3.1 openwebifpy==4.3.1
# homeassistant.components.opower # homeassistant.components.opower
opower==0.12.3 opower==0.12.4
# homeassistant.components.oralb # homeassistant.components.oralb
oralb-ble==0.17.6 oralb-ble==0.17.6
@ -2022,7 +2022,7 @@ python-juicenet==1.1.0
python-kasa[speedups]==0.10.2 python-kasa[speedups]==0.10.2
# homeassistant.components.linkplay # homeassistant.components.linkplay
python-linkplay==0.2.11 python-linkplay==0.2.12
# homeassistant.components.lirc # homeassistant.components.lirc
# python-lirc==1.2.3 # python-lirc==1.2.3
@ -2518,7 +2518,7 @@ vultr==0.1.2
# homeassistant.components.samsungtv # homeassistant.components.samsungtv
# homeassistant.components.wake_on_lan # homeassistant.components.wake_on_lan
wakeonlan==2.1.0 wakeonlan==3.1.0
# homeassistant.components.wallbox # homeassistant.components.wallbox
wallbox==0.9.0 wallbox==0.9.0

View File

@ -56,6 +56,9 @@ def mock_amazon_devices_client() -> Generator[AsyncMock]:
do_not_disturb=False, do_not_disturb=False,
response_style=None, response_style=None,
bluetooth_state=True, bluetooth_state=True,
entity_id="11111111-2222-3333-4444-555555555555",
appliance_id="G1234567890123456789012345678A",
sensors={},
) )
} }
client.get_model_details = lambda device: DEVICE_TYPE_TO_MODEL.get( client.get_model_details = lambda device: DEVICE_TYPE_TO_MODEL.get(

View File

@ -1,6 +1,6 @@
"""Test HomematicIP Cloud accesspoint.""" """Test HomematicIP Cloud accesspoint."""
from unittest.mock import Mock, patch from unittest.mock import AsyncMock, Mock, patch
from homematicip.auth import Auth from homematicip.auth import Auth
from homematicip.connection.connection_context import ConnectionContext from homematicip.connection.connection_context import ConnectionContext
@ -16,6 +16,7 @@ from homeassistant.components.homematicip_cloud.const import (
) )
from homeassistant.components.homematicip_cloud.errors import HmipcConnectionError from homeassistant.components.homematicip_cloud.errors import HmipcConnectionError
from homeassistant.components.homematicip_cloud.hap import ( from homeassistant.components.homematicip_cloud.hap import (
AsyncHome,
HomematicipAuth, HomematicipAuth,
HomematicipHAP, HomematicipHAP,
) )
@ -251,3 +252,21 @@ async def test_get_state_after_disconnect(
assert hap._ws_connection_closed.is_set() assert hap._ws_connection_closed.is_set()
await hap.ws_connected_handler() await hap.ws_connected_handler()
mock_get_state.assert_called_once() mock_get_state.assert_called_once()
async def test_async_connect(
hass: HomeAssistant, hmip_config_entry: MockConfigEntry, simple_mock_home
) -> None:
"""Test async_connect."""
hass.config.components.add(HMIPC_DOMAIN)
hap = HomematicipHAP(hass, hmip_config_entry)
assert hap
simple_mock_home = AsyncMock(spec=AsyncHome, autospec=True)
await hap.async_connect(simple_mock_home)
simple_mock_home.set_on_connected_handler.assert_called_once()
simple_mock_home.set_on_disconnected_handler.assert_called_once()
simple_mock_home.set_on_reconnect_handler.assert_called_once()
simple_mock_home.enable_events.assert_called_once()

View File

@ -843,7 +843,7 @@ async def test_sky_effect(hass: HomeAssistant) -> None:
SERVICE_EFFECT_SKY, SERVICE_EFFECT_SKY,
{ {
ATTR_ENTITY_ID: entity_id, ATTR_ENTITY_ID: entity_id,
ATTR_PALETTE: [], ATTR_PALETTE: None,
ATTR_SKY_TYPE: "Clouds", ATTR_SKY_TYPE: "Clouds",
ATTR_CLOUD_SATURATION_MAX: 180, ATTR_CLOUD_SATURATION_MAX: 180,
ATTR_CLOUD_SATURATION_MIN: 50, ATTR_CLOUD_SATURATION_MIN: 50,
@ -854,7 +854,7 @@ async def test_sky_effect(hass: HomeAssistant) -> None:
bulb.power_level = 65535 bulb.power_level = 65535
bulb.effect = { bulb.effect = {
"effect": "SKY", "effect": "SKY",
"palette": [], "palette": None,
"sky_type": 2, "sky_type": 2,
"cloud_saturation_min": 50, "cloud_saturation_min": 50,
"cloud_saturation_max": 180, "cloud_saturation_max": 180,

View File

@ -382,8 +382,10 @@ def verify_cleanup(
# Verify no threads where left behind. # Verify no threads where left behind.
threads = frozenset(threading.enumerate()) - threads_before threads = frozenset(threading.enumerate()) - threads_before
for thread in threads: for thread in threads:
assert isinstance(thread, threading._DummyThread) or thread.name.startswith( assert (
"waitpid-" isinstance(thread, threading._DummyThread)
or thread.name.startswith("waitpid-")
or "_run_safe_shutdown_loop" in thread.name
) )
try: try: