Skip to content

Commit dcf76c7

Browse files
committed
doc and cleanup pass
1 parent 115237b commit dcf76c7

File tree

18 files changed

+366
-180
lines changed

18 files changed

+366
-180
lines changed

README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ Usage Example
3131

3232
.. code-block:: python
3333
34-
from adafruit_ble import SmartAdapter
34+
from adafruit_ble import BLERadio
3535
36-
adapter = SmartAdapter()
36+
radio = BLERadio()
3737
print("scanning")
3838
found = set()
39-
for entry in adapter.start_scan(timeout=60, minimum_rssi=-80):
39+
for entry in radio.start_scan(timeout=60, minimum_rssi=-80):
4040
addr = entry.address
4141
if addr not in found:
4242
print(entry)

adafruit_ble/__init__.py

Lines changed: 85 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
**Hardware:**
3636
3737
Adafruit Feather nRF52840 Express <https://www.adafruit.com/product/4062>
38+
Adafruit Circuit Playground Bluefruit <https://www.adafruit.com/product/4333>
3839
3940
**Software and Dependencies:**
4041
@@ -53,46 +54,60 @@
5354
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git"
5455

5556
class BLEConnection:
56-
"""This represents a connection to a peer BLE device.
57-
58-
It acts as a map from a Service type to a Service instance for the connection.
5957
"""
60-
def __init__(self, connection):
61-
self._connection = connection
62-
self._discovered_services = {}
63-
"""These are the bare remote services from _bleio."""
58+
Represents a connection to a peer BLE device.
59+
It acts as a map from a `Service` type to a `Service` instance for the connection.
6460
61+
:param bleio_connection _bleio.connection
62+
"""
63+
def __init__(self, bleio_connection):
64+
self._bleio_connection = bleio_connection
65+
# _bleio.Service objects representing services found during discoery.
66+
self._discovered_bleio_services = {}
67+
# Service objects that wrap remote services.
6568
self._constructed_services = {}
66-
"""These are the Service instances from the library that wrap the remote services."""
6769

6870
def _discover_remote(self, uuid):
6971
remote_service = None
70-
if uuid in self._discovered_services:
71-
remote_service = self._discovered_services[uuid]
72+
if uuid in self._discovered_bleio_services:
73+
remote_service = self._discovered_bleio_services[uuid]
7274
else:
73-
results = self._connection.discover_remote_services((uuid.bleio_uuid,))
75+
results = self._bleio_connection.discover_remote_services((uuid.bleio_uuid,))
7476
if results:
7577
remote_service = results[0]
76-
self._discovered_services[uuid] = remote_service
78+
self._discovered_bleio_services[uuid] = remote_service
7779
return remote_service
7880

7981
def __contains__(self, key):
82+
"""
83+
Allows easy testing for a particular Service class or a particular UUID
84+
associated with this connection.
85+
86+
Example::
87+
88+
if UARTService in connection:
89+
# do something
90+
91+
if StandardUUID(0x1234) in connection:
92+
# do something
93+
"""
8094
uuid = key
8195
if hasattr(key, "uuid"):
8296
uuid = key.uuid
8397
return self._discover_remote(uuid) is not None
8498

8599
def __getitem__(self, key):
100+
"""Return the Service for the given Service class or uuid, if any."""
86101
uuid = key
87102
maybe_service = False
88103
if hasattr(key, "uuid"):
89104
uuid = key.uuid
90105
maybe_service = True
91106

92-
remote_service = self._discover_remote(uuid)
93-
94107
if uuid in self._constructed_services:
95108
return self._constructed_services[uuid]
109+
110+
remote_service = self._discover_remote(uuid)
96111
if remote_service:
97112
constructed_service = None
98113
if maybe_service:
@@ -105,16 +120,19 @@ def __getitem__(self, key):
105120
@property
106121
def connected(self):
107122
"""True if the connection to the peer is still active."""
108-
return self._connection.connected
123+
return self._bleio_connection.connected
109124

110125
def disconnect(self):
111126
"""Disconnect from peer."""
112-
self._connection.disconnect()
127+
self._bleio_connection.disconnect()
113128

114129
class BLERadio:
115-
"""The BLERadio class enhances the normal `_bleio.Adapter`.
130+
"""
131+
BLERadio provides the interfaces for BLE advertising,
132+
scanning for advertisements, and connecting to peers. There may be
133+
multiple connections active at once.
116134
117-
It uses the library's `Advertisement` classes and the `BLEConnection` class."""
135+
It uses this library's `Advertisement` classes and the `BLEConnection` class."""
118136

119137
def __init__(self, adapter=None):
120138
if not adapter:
@@ -123,34 +141,62 @@ def __init__(self, adapter=None):
123141
self._current_advertisement = None
124142
self._connection_cache = {}
125143

126-
def start_advertising(self, advertisement, scan_response=None, **kwargs):
127-
"""Starts advertising the given advertisement.
144+
def start_advertising(self, advertisement, scan_response=None, interval=0.1):
145+
"""
146+
Starts advertising the given advertisement.
128147
129-
It takes most kwargs of `_bleio.Adapter.start_advertising`."""
148+
:param buf scan_response: scan response data packet bytes.
149+
``None`` if no scan response is needed.
150+
:param float interval: advertising interval, in seconds
151+
"""
130152
scan_response_data = None
131153
if scan_response:
132154
scan_response_data = bytes(scan_response)
133155
self._adapter.start_advertising(bytes(advertisement),
134156
scan_response=scan_response_data,
135157
connectable=advertisement.connectable,
136-
**kwargs)
158+
interval=interval)
137159

138160
def stop_advertising(self):
139161
"""Stops advertising."""
140162
self._adapter.stop_advertising()
141163

142-
def start_scan(self, *advertisement_types, **kwargs):
143-
"""Starts scanning. Returns an iterator of advertisement objects of the types given in
144-
advertisement_types. The iterator will block until an advertisement is heard or the scan
145-
times out.
146-
147-
If any ``advertisement_types`` are given, only Advertisements of those types are produced
148-
by the returned iterator. If none are given then `Advertisement` objects will be
149-
returned."""
164+
def start_scan(self, *advertisement_types, buffer_size=512, extended=False, timeout=None,
165+
interval=0.1, window=0.1, minimum_rssi=-80, active=True):
166+
"""
167+
Starts scanning. Returns an iterator of advertisement objects of the types given in
168+
advertisement_types. The iterator will block until an advertisement is heard or the scan
169+
times out.
170+
171+
If any ``advertisement_types`` are given, only Advertisements of those types are produced
172+
by the returned iterator. If none are given then `Advertisement` objects will be
173+
returned.
174+
175+
Advertisements and scan responses are filtered and returned separately.
176+
177+
:param int buffer_size: the maximum number of advertising bytes to buffer.
178+
:param bool extended: When True, support extended advertising packets.
179+
Increasing buffer_size is recommended when this is set.
180+
:param float timeout: the scan timeout in seconds.
181+
If None, will scan until `stop_scan` is called.
182+
:param float interval: the interval (in seconds) between the start
183+
of two consecutive scan windows
184+
Must be in the range 0.0025 - 40.959375 seconds.
185+
:param float window: the duration (in seconds) to scan a single BLE channel.
186+
window must be <= interval.
187+
:param int minimum_rssi: the minimum rssi of entries to return.
188+
:param bool active: request and retrieve scan responses for scannable advertisements.
189+
:returns: iterable: If any ``advertisement_types`` are given,
190+
only Advertisements of those types are produced by the returned iterator.
191+
If none are given then `Advertisement` objects will be returned.
192+
"""
150193
prefixes = b""
151194
if advertisement_types:
152195
prefixes = b"".join(adv.prefix for adv in advertisement_types)
153-
for entry in self._adapter.start_scan(prefixes=prefixes, **kwargs):
196+
for entry in self._adapter.start_scan(prefixes=prefixes, buffer_size=buffer_size,
197+
extended=extended, timeout=timeout,
198+
interval=interval, window=window,
199+
minimum_rssi=minimum_rssi, active=active):
154200
adv_type = Advertisement
155201
for possible_type in advertisement_types:
156202
if possible_type.matches(entry) and issubclass(possible_type, adv_type):
@@ -167,7 +213,14 @@ def stop_scan(self):
167213
self._adapter.stop_scan()
168214

169215
def connect(self, advertisement, *, timeout=4):
170-
"""Initiates a `BLEConnection` to the peer that advertised the given advertisement."""
216+
"""
217+
Initiates a `BLEConnection` to the peer that advertised the given advertisement.
218+
219+
:param advertisement Advertisement: An `Advertisement` or a subclass of `Advertisement`
220+
:param timeout float: how long to wait for a connection
221+
:returns the connection to the peer
222+
:rtype BLEConnection
223+
"""
171224
connection = self._adapter.connect(advertisement.address, timeout=timeout)
172225
self._connection_cache[connection] = BLEConnection(connection)
173226
return self._connection_cache[connection]

adafruit_ble/advertising/__init__.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@
2525

2626
import struct
2727

28-
def to_hex(b):
28+
def to_hex(seq):
2929
"""Pretty prints a byte sequence as hex values."""
30-
# pylint: disable=invalid-name
31-
return " ".join(["{:02x}".format(v) for v in b])
30+
return " ".join("{:02x}".format(v) for v in seq)
3231

33-
def to_bytes_literal(b):
32+
def to_bytes_literal(seq):
3433
"""Prints a byte sequence as a Python bytes literal that only uses hex encoding."""
35-
# pylint: disable=invalid-name
36-
return "b\"" + "".join(["\\x{:02x}".format(v) for v in b]) + "\""
34+
return "b\"" + "".join("\\x{:02x}".format(v) for v in seq) + "\""
3735

3836
def decode_data(data, *, key_encoding="B"):
3937
"""Helper which decodes length encoded structures into a dictionary with the given key

adafruit_ble/advertising/standard.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ def __contains__(self, key):
6464
return uuid in self._vendor_services or uuid in self._standard_services
6565

6666
def _update(self, adt, uuids):
67-
if len(uuids) == 0:
67+
if not uuids:
68+
# uuids is empty
6869
del self._advertisement.data_dict[adt]
6970
uuid_length = uuids[0].size // 8
7071
b = bytearray(len(uuids) * uuid_length)
@@ -131,12 +132,12 @@ def _present(self, obj):
131132
def __get__(self, obj, cls):
132133
if not self._present(obj) and not obj.mutable:
133134
return None
134-
if not hasattr(obj, "_service_lists"):
135-
obj._service_lists = {}
135+
if not hasattr(obj, "adv_service_lists"):
136+
obj.adv_service_lists = {}
136137
first_adt = self.standard_services[0]
137-
if first_adt not in obj._service_lists:
138-
obj._service_lists[first_adt] = BoundServiceList(obj, **self.__dict__)
139-
return obj._service_lists[first_adt]
138+
if first_adt not in obj.adv_service_lists:
139+
obj.adv_service_lists[first_adt] = BoundServiceList(obj, **self.__dict__)
140+
return obj.adv_service_lists[first_adt]
140141

141142
class ProvideServicesAdvertisement(Advertisement):
142143
"""Advertise what services that the device makes available upon connection."""

adafruit_ble/attributes/__init__.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2019 Dan Halbert for Adafruit Industries
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
# THE SOFTWARE.
22+
"""
23+
:py:mod:`~adafruit_ble.attributes`
24+
====================================================
25+
26+
This module provides definitions common to all kinds of BLE attributes,
27+
specifically characteristics and descriptors.
28+
29+
"""
30+
import _bleio
31+
32+
__version__ = "0.0.0-auto.0"
33+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git"
34+
35+
class Attribute:
36+
"""Constants describing security levels."""
37+
NO_ACCESS = _bleio.Attribute.NO_ACCESS
38+
OPEN = _bleio.Attribute.OPEN
39+
ENCRYPT_NO_MITM = _bleio.Attribute.ENCRYPT_NO_MITM
40+
ENCRYPT_WITH_MITM = _bleio.Attribute.ENCRYPT_WITH_MITM
41+
LESC_ENCRYPT_WITH_MITM = _bleio.Attribute.LESC_ENCRYPT_WITH_MITM
42+
SIGNED_NO_MITM = _bleio.Attribute.SIGNED_NO_MITM
43+
SIGNED_WITH_MITM = _bleio.Attribute.SIGNED_NO_MITM

0 commit comments

Comments
 (0)