diff --git a/aioesphomeapi/discover.py b/aioesphomeapi/discover.py index 52ba87f..34cdd4b 100644 --- a/aioesphomeapi/discover.py +++ b/aioesphomeapi/discover.py @@ -40,7 +40,7 @@ def async_service_update( version = decode_bytes_or_none(properties.get(b"version")) platform = decode_bytes_or_none(properties.get(b"platform")) board = decode_bytes_or_none(properties.get(b"board")) - address = None + address = "" if addresses := info.ip_addresses_by_version(IPVersion.V4Only): address = str(addresses[0]) diff --git a/setup.py b/setup.py index c0f5bd7..95f7f8e 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ with open(os.path.join(here, "README.rst"), encoding="utf-8") as readme_file: long_description = readme_file.read() -VERSION = "19.1.1" +VERSION = "19.1.2" PROJECT_NAME = "aioesphomeapi" PROJECT_PACKAGE_NAME = "aioesphomeapi" PROJECT_LICENSE = "MIT" diff --git a/tests/test_client.py b/tests/test_client.py index 9dd5ebb..b5b3264 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1402,6 +1402,43 @@ async def test_subscribe_bluetooth_le_advertisements( address_type=1, ) ] + advs.clear() + response: message.Message = BluetoothLEAdvertisementResponse( + address=1234, + name=b"mydevice", + rssi=-50, + service_uuids=["1234"], + service_data=[ + BluetoothServiceData( + uuid="1234", + legacy_data=b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + ) + ], + manufacturer_data=[ + BluetoothServiceData( + uuid="1234", + legacy_data=b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + ) + ], + address_type=1, + ) + mock_data_received(protocol, generate_plaintext_packet(response)) + + assert advs == [ + BluetoothLEAdvertisement( + address=1234, + name="mydevice", + rssi=-50, + service_uuids=["000034-0000-1000-8000-00805f9b34fb"], + manufacturer_data={ + 4660: b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + }, + service_data={ + "000034-0000-1000-8000-00805f9b34fb": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + }, + address_type=1, + ) + ] unsub() diff --git a/tests/test_model.py b/tests/test_model.py index d81a75a..2a3013c 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -3,10 +3,14 @@ from __future__ import annotations from dataclasses import dataclass, field import pytest +from google.protobuf import message from aioesphomeapi.api_pb2 import ( AlarmControlPanelStateResponse, BinarySensorStateResponse, + BluetoothGATTCharacteristic, + BluetoothGATTDescriptor, + BluetoothGATTGetServicesResponse, ClimateStateResponse, CoverStateResponse, DeviceInfoResponse, @@ -49,6 +53,14 @@ from aioesphomeapi.model import ( APIVersion, BinarySensorInfo, BinarySensorState, +) +from aioesphomeapi.model import ( + BluetoothGATTCharacteristic as BluetoothGATTCharacteristicModel, +) +from aioesphomeapi.model import BluetoothGATTDescriptor as BluetoothGATTDescriptorModel +from aioesphomeapi.model import BluetoothGATTService as BluetoothGATTServiceModel +from aioesphomeapi.model import BluetoothGATTServices as BluetoothGATTServicesModel +from aioesphomeapi.model import ( BluetoothProxyFeature, ButtonInfo, CameraInfo, @@ -332,6 +344,9 @@ def test_user_service_conversion(): assert UserService.from_dict({"args": [{"name": "arg", "type": 1}]}) == UserService( args=[UserServiceArg(name="arg", type=UserServiceArgType.INT)] ) + assert UserService.from_dict( + {"args": [{"name": "arg", "type_": 1}]} + ) == UserService(args=[UserServiceArg(name="arg", type=UserServiceArgType.INT)]) @pytest.mark.parametrize( @@ -497,3 +512,88 @@ def test_supported_color_modes_compat( ) assert info.supported_color_modes_compat(APIVersion(1, 5)) == capability assert info.supported_color_modes_compat(APIVersion(1, 9)) == [42] + + +@pytest.mark.asyncio +async def test_bluetooth_gatt_services_from_dict() -> None: + """Test bluetooth_gatt_get_services success case.""" + services: message.Message = BluetoothGATTGetServicesResponse( + address=1234, + services=[ + { + "uuid": [1, 1], + "handle": 1, + "characteristics": [ + { + "uuid": [1, 2], + "handle": 2, + "properties": 1, + "descriptors": [ + {"uuid": [1, 3], "handle": 3}, + ], + }, + ], + } + ], + ) + services = BluetoothGATTServicesModel.from_pb(services) + assert services.services[0] == BluetoothGATTServiceModel( + uuid=[1, 1], + handle=1, + characteristics=[ + BluetoothGATTCharacteristic( + uuid=[1, 2], + handle=2, + properties=1, + descriptors=[BluetoothGATTDescriptor(uuid=[1, 3], handle=3)], + ) + ], + ) + services == BluetoothGATTServicesModel.from_dict( + { + "services": [ + { + "uuid": [1, 1], + "handle": 1, + "characteristics": [ + { + "uuid": [1, 2], + "handle": 2, + "properties": 1, + "descriptors": [ + {"uuid": [1, 3], "handle": 3}, + ], + }, + ], + } + ] + } + ) + assert services.services[0] == BluetoothGATTServiceModel( + uuid=[1, 1], + handle=1, + characteristics=[ + BluetoothGATTCharacteristic( + uuid=[1, 2], + handle=2, + properties=1, + descriptors=[BluetoothGATTDescriptor(uuid=[1, 3], handle=3)], + ) + ], + ) + assert BluetoothGATTCharacteristicModel.from_dict( + { + "uuid": [1, 2], + "handle": 2, + "properties": 1, + "descriptors": [], + } + ) == BluetoothGATTCharacteristicModel( + uuid=[1, 2], + handle=2, + properties=1, + descriptors=[], + ) + assert BluetoothGATTDescriptorModel.from_dict( + {"uuid": [1, 3], "handle": 3}, + ) == BluetoothGATTDescriptorModel(uuid=[1, 3], handle=3)