mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 22:57:17 +00:00
2025.6.1 (#146764)
This commit is contained in:
commit
a75646d047
@ -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"]
|
||||||
}
|
}
|
||||||
|
@ -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])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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(
|
||||||
[
|
[
|
||||||
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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])
|
||||||
|
|
||||||
|
@ -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."]
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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],
|
||||||
|
@ -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],
|
||||||
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
@ -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."""
|
||||||
|
@ -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": [
|
||||||
|
@ -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)
|
||||||
)
|
)
|
||||||
|
@ -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(
|
||||||
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
2
requirements.txt
generated
@ -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
16
requirements_all.txt
generated
@ -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
|
||||||
|
16
requirements_test_all.txt
generated
16
requirements_test_all.txt
generated
@ -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
|
||||||
|
@ -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(
|
||||||
|
@ -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()
|
||||||
|
@ -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,
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user