From b73270c0bd2b0fa1bee7cf1ff74515ef93d18808 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 27 Nov 2023 08:21:51 -0600 Subject: [PATCH 1/5] Fix discover cli tool when address is missing from mdns (#758) --- aioesphomeapi/discover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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]) From e961e4efcaf8e9bba434919cc5ff6eb105f4b743 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 14:22:09 +0000 Subject: [PATCH 2/5] Bump version to 19.1.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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" From 60e193e4df821d364aa6de00577d05ce43582810 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 27 Nov 2023 08:24:23 -0600 Subject: [PATCH 3/5] Add test for legacy bluetooth data (#759) --- tests/test_client.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 0f1b3ab..ccf3be2 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1398,6 +1398,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() From f6eff1a205560ea270df965feab57fea1fa13ce4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 27 Nov 2023 08:43:51 -0600 Subject: [PATCH 4/5] Add coverage for GATT services from dict (#760) --- tests/test_model.py | 97 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/tests/test_model.py b/tests/test_model.py index d81a75a..8cf8f5d 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, @@ -497,3 +509,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) From 31c6e4abc67aaa1feaa790cec4ab13141b0696e0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 27 Nov 2023 08:46:36 -0600 Subject: [PATCH 5/5] Add test for legacy UserService type_ conversion (#761) --- tests/test_model.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_model.py b/tests/test_model.py index 8cf8f5d..2a3013c 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -344,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(