Skip to content

Commit

Permalink
Merge pull request #911 from hbldh/release/v0.15.0
Browse files Browse the repository at this point in the history
Release/v0.15.0
  • Loading branch information
dlech authored Jul 29, 2022
2 parents 0361ba4 + a5b98c7 commit 8d3ff00
Show file tree
Hide file tree
Showing 39 changed files with 2,252 additions and 1,004 deletions.
5 changes: 5 additions & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ Contributors
* Bernie Conrad <bernie@allthenticate.net>
* Jonathan Soto <jsotogaviard@alum.mit.edu>
* Kyle J. Williams <kyle@kjwill.tech>

Sponsors
--------

* Nabu Casa <https://www.nabucasa.com/>
49 changes: 48 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,52 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_,
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.

`Unreleased`_
=============

`0.15.0`_ (2022-07-29)
======================

Added
-----

* Added new ``assigned_numbers`` module and ``AdvertisementDataType`` enum.
* Added new ``bluez`` kwarg to ``BleakScanner`` in BlueZ backend.
* Added support for passive scanning in the BlueZ backend. Fixes #606.
* Added option to use cached services, characteristics and descriptors in WinRT backend. Fixes #686.
* Added ``PendingDeprecationWarning`` to use of ``address_type`` as keyword argument. It will be moved into the
``winrt`` keyword instead according to #623.
* Added better error message when adapter is not present in BlueZ backend. Fixes #889.

Changed
-------

* Add ``py.typed`` file so mypy discovers Bleak's type annotations.
* UUID descriptions updated to 2022-03-16 assigned numbers document.
* Replace use of deprecated ``asyncio.get_event_loop()`` in Android backend.
* Adjust default timeout for ``read_gatt_char()`` with CoreBluetooth to 10s. Merged #891.
* ``BleakScanner()`` args ``detection_callback`` and ``service_uuids`` are no longer keyword-only.
* ``BleakScanner()`` arg ``scanning_mode`` is no longer Windows-only and is no longer keyword-only.
* All ``BleakScanner()`` instances in BlueZ backend now use common D-Bus object manager.
* Deprecated ``filters`` kwarg in ``BleakScanner`` in BlueZ backend.
* BlueZ version is now checked on first connection instead of import to avoid import side effects. Merged #907.

Fixed
-----

* Documentation fixes.
* On empty characteristic description from WinRT, use the lookup table instead of returning empty string.
* Fixed detection of first advertisement in BlueZ backend. Merged #903.
* Fixed performance issues in BlueZ backend caused by calling "GetManagedObjects" each time a
``BleakScanner`` scans or ``BleakClient`` is connected. Fixes #500.
* Fixed not handling "InterfacesRemoved" in ``BleakClient`` in BlueZ backend. Fixes #882.
* Fixed leaking D-Bus socket file descriptors in BlueZ backend. Fixes #805.

Removed
-------

* Removed fallback to call "ConnectDevice" when "Connect" fails in Bluez backend. Fixes #806.

`0.14.3`_ (2022-04-29)
======================

Expand Down Expand Up @@ -665,7 +711,8 @@ Fixed
* Bleak created.


.. _Unreleased: https://github.com/hbldh/bleak/compare/v0.14.3...develop
.. _Unreleased: https://github.com/hbldh/bleak/compare/v0.15.0...develop
.. _0.15.0: https://github.com/hbldh/bleak/compare/v0.14.3...v0.15.0
.. _0.14.3: https://github.com/hbldh/bleak/compare/v0.14.2...v0.14.3
.. _0.14.2: https://github.com/hbldh/bleak/compare/v0.14.1...v0.14.2
.. _0.14.1: https://github.com/hbldh/bleak/compare/v0.14.0...v0.14.1
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include CHANGELOG.rst
include CONTRIBUTING.rst
include LICENSE
include README.rst
include bleak/py.typed

recursive-include tests *
recursive-exclude * __pycache__
Expand Down
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ verify_ssl = true
name = "pypi"

[packages]
typing-extensions = ">=4.2.0"
dbus-next = {version = ">=0.2.2", sys_platform = "== 'linux'"}
pyobjc-core = {version = ">=7.0.1", sys_platform = "== 'darwin'"}
pyobjc-framework-CoreBluetooth = {version = ">=7.0.1", sys_platform = "== 'darwin'"}
Expand Down
5 changes: 0 additions & 5 deletions bleak/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@
import asyncio

from bleak.__version__ import __version__ # noqa: F401
from bleak.backends.bluezdbus import check_bluez_version
from bleak.exc import BleakError

_on_rtd = os.environ.get("READTHEDOCS") == "True"
_on_ci = "CI" in os.environ

_logger = logging.getLogger(__name__)
_logger.addHandler(logging.NullHandler())
Expand All @@ -38,9 +36,6 @@
BleakClientP4Android as BleakClient,
) # noqa: F401
elif platform.system() == "Linux":
if not _on_ci and not check_bluez_version(5, 43):
raise BleakError("Bleak requires BlueZ >= 5.43.")

from bleak.backends.bluezdbus.scanner import (
BleakScannerBlueZDBus as BleakScanner,
) # noqa: F401
Expand Down
2 changes: 1 addition & 1 deletion bleak/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-

__version__ = "0.14.3"
__version__ = "0.15.0"
37 changes: 37 additions & 0 deletions bleak/assigned_numbers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
Bluetooth Assigned Numbers
--------------------------
This module contains useful assigned numbers from the Bluetooth spec.
See <https://www.bluetooth.com/specifications/assigned-numbers/>.
"""


from enum import IntEnum


class AdvertisementDataType(IntEnum):
"""
Generic Access Profile advertisement data types.
`Source <https://btprodspecificationrefs.blob.core.windows.net/assigned-numbers/Assigned%20Number%20Types/Generic%20Access%20Profile.pdf>`.
"""

FLAGS = 0x01
INCOMPLETE_LIST_SERVICE_UUID16 = 0x02
COMPLETE_LIST_SERVICE_UUID16 = 0x03
INCOMPLETE_LIST_SERVICE_UUID32 = 0x04
COMPLETE_LIST_SERVICE_UUID32 = 0x05
INCOMPLETE_LIST_SERVICE_UUID128 = 0x06
COMPLETE_LIST_SERVICE_UUID128 = 0x07
SHORTENED_LOCAL_NAME = 0x08
COMPLETE_LOCAL_NAME = 0x09
TX_POWER_LEVEL = 0x0A
CLASS_OF_DEVICE = 0x0D

SERVICE_DATA_UUID16 = 0x16
SERVICE_DATA_UUID32 = 0x20
SERVICE_DATA_UUID128 = 0x21

MANUFACTURER_SPECIFIC_DATA = 0xFF
29 changes: 1 addition & 28 deletions bleak/backends/bluezdbus/__init__.py
Original file line number Diff line number Diff line change
@@ -1,28 +1 @@
import re
import subprocess

from ...exc import BleakError


def check_bluez_version(major: int, minor: int) -> bool:
"""
Checks the BlueZ version.
Returns:
``True`` if the BlueZ major version is equal to *major* and the minor
version is greater than or equal to *minor*, otherwise ``False``.
"""
# lazy-get the version and store it so we only have to run subprocess once
if not hasattr(check_bluez_version, "version"):
p = subprocess.Popen(["bluetoothctl", "--version"], stdout=subprocess.PIPE)
out, _ = p.communicate()
s = re.search(b"(\\d+).(\\d+)", out.strip(b"'"))

if not s:
raise BleakError(f"Could not determine BlueZ version: {out.decode()}")

setattr(check_bluez_version, "version", tuple(map(int, s.groups())))

bluez_major, bluez_minor = getattr(check_bluez_version, "version")

return bluez_major == major and bluez_minor >= minor
"""BlueZ backend."""
119 changes: 119 additions & 0 deletions bleak/backends/bluezdbus/advertisement_monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"""
Advertisement Monitor
---------------------
This module contains types associated with the BlueZ D-Bus `advertisement
monitor api <https://github.com/bluez/bluez/blob/master/doc/advertisement-monitor-api.txt>`.
"""

import logging
from typing import Iterable, NamedTuple, Tuple, Union, no_type_check

from dbus_next.service import ServiceInterface, dbus_property, method, PropertyAccess

from . import defs
from ...assigned_numbers import AdvertisementDataType


logger = logging.getLogger(__name__)


class OrPattern(NamedTuple):
"""
BlueZ advertisement monitor or-pattern.
https://github.com/bluez/bluez/blob/master/doc/advertisement-monitor-api.txt
"""

start_position: int
ad_data_type: AdvertisementDataType
content_of_pattern: bytes


# Windows has a similar structure, so we allow generic tuple for cross-platform compatibility
OrPatternLike = Union[OrPattern, Tuple[int, AdvertisementDataType, bytes]]


class AdvertisementMonitor(ServiceInterface):
"""
Implementation of the org.bluez.AdvertisementMonitor1 D-Bus interface.
The BlueZ advertisement monitor API design seems to be just for device
presence (is it in range or out of range), but this isn't really what
we want in Bleak, we want to monitor changes in advertisement data, just
like in active scanning.
So the only thing we are using here is the "or_patterns" since it is
currently required, but really we don't need that either. Hopefully an
"all" "Type" could be added to BlueZ in the future.
"""

def __init__(
self,
or_patterns: Iterable[OrPatternLike],
):
"""
Args:
or_patterns:
List of or patterns that will be returned by the ``Patterns`` property.
"""
super().__init__(defs.ADVERTISEMENT_MONITOR_INTERFACE)
# dbus_next marshaling requires list instead of tuple
self._or_patterns = [list(p) for p in or_patterns]

@method()
def Release(self):
logger.debug("Release")

@method()
def Activate(self):
logger.debug("Activate")

# REVISIT: mypy is broke, so we have to add redundant @no_type_check
# https://github.com/python/mypy/issues/6583

@method()
@no_type_check
def DeviceFound(self, device: "o"): # noqa: F821
logger.debug("DeviceFound %s", device)

@method()
@no_type_check
def DeviceLost(self, device: "o"): # noqa: F821
logger.debug("DeviceLost %s", device)

@dbus_property(PropertyAccess.READ)
@no_type_check
def Type(self) -> "s": # noqa: F821
# this is currently the only type supported in BlueZ
return "or_patterns"

@dbus_property(PropertyAccess.READ, disabled=True)
@no_type_check
def RSSILowThreshold(self) -> "n": # noqa: F821
...

@dbus_property(PropertyAccess.READ, disabled=True)
@no_type_check
def RSSIHighThreshold(self) -> "n": # noqa: F821
...

@dbus_property(PropertyAccess.READ, disabled=True)
@no_type_check
def RSSILowTimeout(self) -> "q": # noqa: F821
...

@dbus_property(PropertyAccess.READ, disabled=True)
@no_type_check
def RSSIHighTimeout(self) -> "q": # noqa: F821
...

@dbus_property(PropertyAccess.READ, disabled=True)
@no_type_check
def RSSISamplingPeriod(self) -> "q": # noqa: F821
...

@dbus_property(PropertyAccess.READ)
@no_type_check
def Patterns(self) -> "a(yyay)": # noqa: F821
return self._or_patterns
Loading

0 comments on commit 8d3ff00

Please sign in to comment.