mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 19:57:07 +00:00
Bump aioesphomeapi to 19.1.7 (#104644)
* Bump aioesphomeapi to 19.1.5 changelog: https://github.com/esphome/aioesphomeapi/compare/v19.1.4...v19.1.5 - Removes the need to watch for BLE connection drops with a seperate future as the library now raises BluetoothConnectionDroppedError when the connection drops during a BLE operation * reduce stack * .6 * tweak * 19.1.7
This commit is contained in:
parent
63ef9efa26
commit
93aa31c835
@ -22,6 +22,7 @@ from aioesphomeapi import (
|
|||||||
APIClient,
|
APIClient,
|
||||||
APIVersion,
|
APIVersion,
|
||||||
BLEConnectionError,
|
BLEConnectionError,
|
||||||
|
BluetoothConnectionDroppedError,
|
||||||
BluetoothProxyFeature,
|
BluetoothProxyFeature,
|
||||||
DeviceInfo,
|
DeviceInfo,
|
||||||
)
|
)
|
||||||
@ -30,7 +31,6 @@ from aioesphomeapi.core import (
|
|||||||
BluetoothGATTAPIError,
|
BluetoothGATTAPIError,
|
||||||
TimeoutAPIError,
|
TimeoutAPIError,
|
||||||
)
|
)
|
||||||
from async_interrupt import interrupt
|
|
||||||
from bleak.backends.characteristic import BleakGATTCharacteristic
|
from bleak.backends.characteristic import BleakGATTCharacteristic
|
||||||
from bleak.backends.client import BaseBleakClient, NotifyCallback
|
from bleak.backends.client import BaseBleakClient, NotifyCallback
|
||||||
from bleak.backends.device import BLEDevice
|
from bleak.backends.device import BLEDevice
|
||||||
@ -68,39 +68,25 @@ def mac_to_int(address: str) -> int:
|
|||||||
return int(address.replace(":", ""), 16)
|
return int(address.replace(":", ""), 16)
|
||||||
|
|
||||||
|
|
||||||
def verify_connected(func: _WrapFuncType) -> _WrapFuncType:
|
|
||||||
"""Define a wrapper throw BleakError if not connected."""
|
|
||||||
|
|
||||||
async def _async_wrap_bluetooth_connected_operation(
|
|
||||||
self: ESPHomeClient, *args: Any, **kwargs: Any
|
|
||||||
) -> Any:
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
if not self._is_connected:
|
|
||||||
raise BleakError(f"{self._description} is not connected")
|
|
||||||
loop = self._loop
|
|
||||||
disconnected_futures = self._disconnected_futures
|
|
||||||
disconnected_future = loop.create_future()
|
|
||||||
disconnected_futures.add(disconnected_future)
|
|
||||||
disconnect_message = f"{self._description}: Disconnected during operation"
|
|
||||||
try:
|
|
||||||
async with interrupt(disconnected_future, BleakError, disconnect_message):
|
|
||||||
return await func(self, *args, **kwargs)
|
|
||||||
finally:
|
|
||||||
disconnected_futures.discard(disconnected_future)
|
|
||||||
|
|
||||||
return cast(_WrapFuncType, _async_wrap_bluetooth_connected_operation)
|
|
||||||
|
|
||||||
|
|
||||||
def api_error_as_bleak_error(func: _WrapFuncType) -> _WrapFuncType:
|
def api_error_as_bleak_error(func: _WrapFuncType) -> _WrapFuncType:
|
||||||
"""Define a wrapper throw esphome api errors as BleakErrors."""
|
"""Define a wrapper throw esphome api errors as BleakErrors."""
|
||||||
|
|
||||||
async def _async_wrap_bluetooth_operation(
|
async def _async_wrap_bluetooth_operation(
|
||||||
self: ESPHomeClient, *args: Any, **kwargs: Any
|
self: ESPHomeClient, *args: Any, **kwargs: Any
|
||||||
) -> Any:
|
) -> Any:
|
||||||
|
# pylint: disable=protected-access
|
||||||
try:
|
try:
|
||||||
return await func(self, *args, **kwargs)
|
return await func(self, *args, **kwargs)
|
||||||
except TimeoutAPIError as err:
|
except TimeoutAPIError as err:
|
||||||
raise asyncio.TimeoutError(str(err)) from err
|
raise asyncio.TimeoutError(str(err)) from err
|
||||||
|
except BluetoothConnectionDroppedError as ex:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s: BLE device disconnected during %s operation",
|
||||||
|
self._description,
|
||||||
|
func.__name__,
|
||||||
|
)
|
||||||
|
self._async_ble_device_disconnected()
|
||||||
|
raise BleakError(str(ex)) from ex
|
||||||
except BluetoothGATTAPIError as ex:
|
except BluetoothGATTAPIError as ex:
|
||||||
# If the device disconnects in the middle of an operation
|
# If the device disconnects in the middle of an operation
|
||||||
# be sure to mark it as disconnected so any library using
|
# be sure to mark it as disconnected so any library using
|
||||||
@ -111,7 +97,6 @@ def api_error_as_bleak_error(func: _WrapFuncType) -> _WrapFuncType:
|
|||||||
# before the callback is delivered.
|
# before the callback is delivered.
|
||||||
|
|
||||||
if ex.error.error == -1:
|
if ex.error.error == -1:
|
||||||
# pylint: disable=protected-access
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s: BLE device disconnected during %s operation",
|
"%s: BLE device disconnected during %s operation",
|
||||||
self._description,
|
self._description,
|
||||||
@ -169,7 +154,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
self._notify_cancels: dict[
|
self._notify_cancels: dict[
|
||||||
int, tuple[Callable[[], Coroutine[Any, Any, None]], Callable[[], None]]
|
int, tuple[Callable[[], Coroutine[Any, Any, None]], Callable[[], None]]
|
||||||
] = {}
|
] = {}
|
||||||
self._disconnected_futures: set[asyncio.Future[None]] = set()
|
|
||||||
self._device_info = client_data.device_info
|
self._device_info = client_data.device_info
|
||||||
self._feature_flags = device_info.bluetooth_proxy_feature_flags_compat(
|
self._feature_flags = device_info.bluetooth_proxy_feature_flags_compat(
|
||||||
client_data.api_version
|
client_data.api_version
|
||||||
@ -185,7 +169,7 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
"""Return the string representation of the client."""
|
"""Return the string representation of the client."""
|
||||||
return f"ESPHomeClient ({self.address})"
|
return f"ESPHomeClient ({self._description})"
|
||||||
|
|
||||||
def _unsubscribe_connection_state(self) -> None:
|
def _unsubscribe_connection_state(self) -> None:
|
||||||
"""Unsubscribe from connection state updates."""
|
"""Unsubscribe from connection state updates."""
|
||||||
@ -211,10 +195,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
for _, notify_abort in self._notify_cancels.values():
|
for _, notify_abort in self._notify_cancels.values():
|
||||||
notify_abort()
|
notify_abort()
|
||||||
self._notify_cancels.clear()
|
self._notify_cancels.clear()
|
||||||
for future in self._disconnected_futures:
|
|
||||||
if not future.done():
|
|
||||||
future.set_result(None)
|
|
||||||
self._disconnected_futures.clear()
|
|
||||||
self._disconnect_callbacks.discard(self._async_esp_disconnected)
|
self._disconnect_callbacks.discard(self._async_esp_disconnected)
|
||||||
self._unsubscribe_connection_state()
|
self._unsubscribe_connection_state()
|
||||||
|
|
||||||
@ -406,7 +386,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
"""Get ATT MTU size for active connection."""
|
"""Get ATT MTU size for active connection."""
|
||||||
return self._mtu or DEFAULT_MTU
|
return self._mtu or DEFAULT_MTU
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def pair(self, *args: Any, **kwargs: Any) -> bool:
|
async def pair(self, *args: Any, **kwargs: Any) -> bool:
|
||||||
"""Attempt to pair."""
|
"""Attempt to pair."""
|
||||||
@ -415,6 +394,7 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
"Pairing is not available in this version ESPHome; "
|
"Pairing is not available in this version ESPHome; "
|
||||||
f"Upgrade the ESPHome version on the {self._device_info.name} device."
|
f"Upgrade the ESPHome version on the {self._device_info.name} device."
|
||||||
)
|
)
|
||||||
|
self._raise_if_not_connected()
|
||||||
response = await self._client.bluetooth_device_pair(self._address_as_int)
|
response = await self._client.bluetooth_device_pair(self._address_as_int)
|
||||||
if response.paired:
|
if response.paired:
|
||||||
return True
|
return True
|
||||||
@ -423,7 +403,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def unpair(self) -> bool:
|
async def unpair(self) -> bool:
|
||||||
"""Attempt to unpair."""
|
"""Attempt to unpair."""
|
||||||
@ -432,6 +411,7 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
"Unpairing is not available in this version ESPHome; "
|
"Unpairing is not available in this version ESPHome; "
|
||||||
f"Upgrade the ESPHome version on the {self._device_info.name} device."
|
f"Upgrade the ESPHome version on the {self._device_info.name} device."
|
||||||
)
|
)
|
||||||
|
self._raise_if_not_connected()
|
||||||
response = await self._client.bluetooth_device_unpair(self._address_as_int)
|
response = await self._client.bluetooth_device_unpair(self._address_as_int)
|
||||||
if response.success:
|
if response.success:
|
||||||
return True
|
return True
|
||||||
@ -454,7 +434,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
dangerous_use_bleak_cache=dangerous_use_bleak_cache, **kwargs
|
dangerous_use_bleak_cache=dangerous_use_bleak_cache, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
async def _get_services(
|
async def _get_services(
|
||||||
self, dangerous_use_bleak_cache: bool = False, **kwargs: Any
|
self, dangerous_use_bleak_cache: bool = False, **kwargs: Any
|
||||||
) -> BleakGATTServiceCollection:
|
) -> BleakGATTServiceCollection:
|
||||||
@ -462,6 +441,7 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
|
|
||||||
Must only be called from get_services or connected
|
Must only be called from get_services or connected
|
||||||
"""
|
"""
|
||||||
|
self._raise_if_not_connected()
|
||||||
address_as_int = self._address_as_int
|
address_as_int = self._address_as_int
|
||||||
cache = self._cache
|
cache = self._cache
|
||||||
# If the connection version >= 3, we must use the cache
|
# If the connection version >= 3, we must use the cache
|
||||||
@ -527,7 +507,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
)
|
)
|
||||||
return characteristic
|
return characteristic
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def clear_cache(self) -> bool:
|
async def clear_cache(self) -> bool:
|
||||||
"""Clear the GATT cache."""
|
"""Clear the GATT cache."""
|
||||||
@ -541,6 +520,7 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
self._device_info.name,
|
self._device_info.name,
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
self._raise_if_not_connected()
|
||||||
response = await self._client.bluetooth_device_clear_cache(self._address_as_int)
|
response = await self._client.bluetooth_device_clear_cache(self._address_as_int)
|
||||||
if response.success:
|
if response.success:
|
||||||
return True
|
return True
|
||||||
@ -551,7 +531,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def read_gatt_char(
|
async def read_gatt_char(
|
||||||
self,
|
self,
|
||||||
@ -570,12 +549,12 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
Returns:
|
Returns:
|
||||||
(bytearray) The read data.
|
(bytearray) The read data.
|
||||||
"""
|
"""
|
||||||
|
self._raise_if_not_connected()
|
||||||
characteristic = self._resolve_characteristic(char_specifier)
|
characteristic = self._resolve_characteristic(char_specifier)
|
||||||
return await self._client.bluetooth_gatt_read(
|
return await self._client.bluetooth_gatt_read(
|
||||||
self._address_as_int, characteristic.handle, GATT_READ_TIMEOUT
|
self._address_as_int, characteristic.handle, GATT_READ_TIMEOUT
|
||||||
)
|
)
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def read_gatt_descriptor(self, handle: int, **kwargs: Any) -> bytearray:
|
async def read_gatt_descriptor(self, handle: int, **kwargs: Any) -> bytearray:
|
||||||
"""Perform read operation on the specified GATT descriptor.
|
"""Perform read operation on the specified GATT descriptor.
|
||||||
@ -587,11 +566,11 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
Returns:
|
Returns:
|
||||||
(bytearray) The read data.
|
(bytearray) The read data.
|
||||||
"""
|
"""
|
||||||
|
self._raise_if_not_connected()
|
||||||
return await self._client.bluetooth_gatt_read_descriptor(
|
return await self._client.bluetooth_gatt_read_descriptor(
|
||||||
self._address_as_int, handle, GATT_READ_TIMEOUT
|
self._address_as_int, handle, GATT_READ_TIMEOUT
|
||||||
)
|
)
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def write_gatt_char(
|
async def write_gatt_char(
|
||||||
self,
|
self,
|
||||||
@ -610,12 +589,12 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
response (bool): If write-with-response operation should be done.
|
response (bool): If write-with-response operation should be done.
|
||||||
Defaults to `False`.
|
Defaults to `False`.
|
||||||
"""
|
"""
|
||||||
|
self._raise_if_not_connected()
|
||||||
characteristic = self._resolve_characteristic(characteristic)
|
characteristic = self._resolve_characteristic(characteristic)
|
||||||
await self._client.bluetooth_gatt_write(
|
await self._client.bluetooth_gatt_write(
|
||||||
self._address_as_int, characteristic.handle, bytes(data), response
|
self._address_as_int, characteristic.handle, bytes(data), response
|
||||||
)
|
)
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def write_gatt_descriptor(self, handle: int, data: Buffer) -> None:
|
async def write_gatt_descriptor(self, handle: int, data: Buffer) -> None:
|
||||||
"""Perform a write operation on the specified GATT descriptor.
|
"""Perform a write operation on the specified GATT descriptor.
|
||||||
@ -624,11 +603,11 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
handle (int): The handle of the descriptor to read from.
|
handle (int): The handle of the descriptor to read from.
|
||||||
data (bytes or bytearray): The data to send.
|
data (bytes or bytearray): The data to send.
|
||||||
"""
|
"""
|
||||||
|
self._raise_if_not_connected()
|
||||||
await self._client.bluetooth_gatt_write_descriptor(
|
await self._client.bluetooth_gatt_write_descriptor(
|
||||||
self._address_as_int, handle, bytes(data)
|
self._address_as_int, handle, bytes(data)
|
||||||
)
|
)
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def start_notify(
|
async def start_notify(
|
||||||
self,
|
self,
|
||||||
@ -655,6 +634,7 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
callback (function): The function to be called on notification.
|
callback (function): The function to be called on notification.
|
||||||
kwargs: Unused.
|
kwargs: Unused.
|
||||||
"""
|
"""
|
||||||
|
self._raise_if_not_connected()
|
||||||
ble_handle = characteristic.handle
|
ble_handle = characteristic.handle
|
||||||
if ble_handle in self._notify_cancels:
|
if ble_handle in self._notify_cancels:
|
||||||
raise BleakError(
|
raise BleakError(
|
||||||
@ -709,7 +689,6 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
wait_for_response=False,
|
wait_for_response=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
@verify_connected
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
async def stop_notify(
|
async def stop_notify(
|
||||||
self,
|
self,
|
||||||
@ -723,6 +702,7 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
specified by either integer handle, UUID or directly by the
|
specified by either integer handle, UUID or directly by the
|
||||||
BleakGATTCharacteristic object representing it.
|
BleakGATTCharacteristic object representing it.
|
||||||
"""
|
"""
|
||||||
|
self._raise_if_not_connected()
|
||||||
characteristic = self._resolve_characteristic(char_specifier)
|
characteristic = self._resolve_characteristic(char_specifier)
|
||||||
# Do not raise KeyError if notifications are not enabled on this characteristic
|
# Do not raise KeyError if notifications are not enabled on this characteristic
|
||||||
# to be consistent with the behavior of the BlueZ backend
|
# to be consistent with the behavior of the BlueZ backend
|
||||||
@ -730,6 +710,11 @@ class ESPHomeClient(BaseBleakClient):
|
|||||||
notify_stop, _ = notify_cancel
|
notify_stop, _ = notify_cancel
|
||||||
await notify_stop()
|
await notify_stop()
|
||||||
|
|
||||||
|
def _raise_if_not_connected(self) -> None:
|
||||||
|
"""Raise a BleakError if not connected."""
|
||||||
|
if not self._is_connected:
|
||||||
|
raise BleakError(f"{self._description} is not connected")
|
||||||
|
|
||||||
def __del__(self) -> None:
|
def __del__(self) -> None:
|
||||||
"""Destructor to make sure the connection state is unsubscribed."""
|
"""Destructor to make sure the connection state is unsubscribed."""
|
||||||
if self._cancel_connection_state:
|
if self._cancel_connection_state:
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["aioesphomeapi", "noiseprotocol"],
|
"loggers": ["aioesphomeapi", "noiseprotocol"],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"async-interrupt==1.1.1",
|
"aioesphomeapi==19.1.7",
|
||||||
"aioesphomeapi==19.1.4",
|
|
||||||
"bluetooth-data-tools==1.15.0",
|
"bluetooth-data-tools==1.15.0",
|
||||||
"esphome-dashboard-api==1.2.3"
|
"esphome-dashboard-api==1.2.3"
|
||||||
],
|
],
|
||||||
|
@ -236,7 +236,7 @@ aioelectricitymaps==0.1.5
|
|||||||
aioemonitor==1.0.5
|
aioemonitor==1.0.5
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
# homeassistant.components.esphome
|
||||||
aioesphomeapi==19.1.4
|
aioesphomeapi==19.1.7
|
||||||
|
|
||||||
# homeassistant.components.flo
|
# homeassistant.components.flo
|
||||||
aioflo==2021.11.0
|
aioflo==2021.11.0
|
||||||
@ -463,9 +463,6 @@ asmog==0.0.6
|
|||||||
# homeassistant.components.asterisk_mbox
|
# homeassistant.components.asterisk_mbox
|
||||||
asterisk_mbox==0.5.0
|
asterisk_mbox==0.5.0
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
|
||||||
async-interrupt==1.1.1
|
|
||||||
|
|
||||||
# homeassistant.components.dlna_dmr
|
# homeassistant.components.dlna_dmr
|
||||||
# homeassistant.components.dlna_dms
|
# homeassistant.components.dlna_dms
|
||||||
# homeassistant.components.samsungtv
|
# homeassistant.components.samsungtv
|
||||||
|
@ -215,7 +215,7 @@ aioelectricitymaps==0.1.5
|
|||||||
aioemonitor==1.0.5
|
aioemonitor==1.0.5
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
# homeassistant.components.esphome
|
||||||
aioesphomeapi==19.1.4
|
aioesphomeapi==19.1.7
|
||||||
|
|
||||||
# homeassistant.components.flo
|
# homeassistant.components.flo
|
||||||
aioflo==2021.11.0
|
aioflo==2021.11.0
|
||||||
@ -415,9 +415,6 @@ aranet4==2.2.2
|
|||||||
# homeassistant.components.arcam_fmj
|
# homeassistant.components.arcam_fmj
|
||||||
arcam-fmj==1.4.0
|
arcam-fmj==1.4.0
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
|
||||||
async-interrupt==1.1.1
|
|
||||||
|
|
||||||
# homeassistant.components.dlna_dmr
|
# homeassistant.components.dlna_dmr
|
||||||
# homeassistant.components.dlna_dms
|
# homeassistant.components.dlna_dms
|
||||||
# homeassistant.components.samsungtv
|
# homeassistant.components.samsungtv
|
||||||
|
Loading…
x
Reference in New Issue
Block a user