46
46
import _bleio
47
47
import board
48
48
49
- from .services . core import Service
49
+ from .services import Service
50
50
from .advertising import Advertisement
51
51
52
52
__version__ = "0.0.0-auto.0"
53
53
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git"
54
54
55
- # These are internal data structures used throughout the library to recognize certain Services and
56
- # Advertisements.
57
- # pylint: disable=invalid-name
58
- all_services_by_name = {}
59
- all_services_by_uuid = {}
60
- known_advertisements = set ()
61
- # pylint: enable=invalid-name
62
-
63
- def recognize_services (* service_classes ):
64
- """Instruct the adafruit_ble library to recognize the given Services.
65
-
66
- This will cause the Service related advertisements to show the corresponding class.
67
- `SmartConnection` will automatically have attributes for any recognized service available
68
- from the peer."""
69
- for service_class in service_classes :
70
- if not issubclass (service_class , Service ):
71
- raise ValueError ("Can only detect subclasses of Service" )
72
- all_services_by_name [service_class .default_field_name ] = service_class
73
- all_services_by_uuid [service_class .uuid ] = service_class
74
-
75
- def recognize_advertisement (* advertisements ):
76
- """Instruct the adafruit_ble library to recognize the given `Advertisement` types.
77
-
78
- When an advertisement is recognized by the `SmartAdapter`, it will be returned from the
79
- start_scan iterator instead of a generic `Advertisement`."""
80
- known_advertisements .add (* advertisements )
81
-
82
- class SmartConnection :
55
+ class BLEConnection :
83
56
"""This represents a connection to a peer BLE device.
84
57
85
- Its smarts come from its ability to recognize Services available on the peer and make them
86
- available as attributes on the Connection. Use `recognize_services` to register all services
87
- of interest. All subsequent Connections will then recognize the service.
88
-
89
- ``dir(connection)`` will show all attributes including recognized Services.
90
- """
58
+ It acts as a map from a Service type to a Service instance for the connection.
59
+ """
91
60
def __init__ (self , connection ):
92
61
self ._connection = connection
93
-
94
- def __dir__ (self ):
95
- discovered = []
96
- results = self ._connection .discover_remote_services ()
97
- for service in results :
98
- uuid = service .uuid
99
- if uuid in all_services_by_uuid :
100
- service = all_services_by_uuid [uuid ]
101
- discovered .append (service .default_field_name )
102
- super_dir = dir (super ())
103
- super_dir .extend (discovered )
104
- return super_dir
105
-
106
- def __getattr__ (self , name ):
107
- if name in self .__dict__ :
108
- return self .__dict__ [name ]
109
- if name in all_services_by_name :
110
- service = all_services_by_name [name ]
111
- uuid = service .uuid ._uuid
112
- results = self ._connection .discover_remote_services ((uuid ,))
62
+ self ._discovered_services = {}
63
+ """These are the bare remote services from _bleio."""
64
+
65
+ self ._constructed_services = {}
66
+ """These are the Service instances from the library that wrap the remote services."""
67
+
68
+ def _discover_remote (self , uuid ):
69
+ remote_service = None
70
+ if uuid in self ._discovered_services :
71
+ remote_service = self ._discovered_services [uuid ]
72
+ else :
73
+ results = self ._connection .discover_remote_services ((uuid .bleio_uuid ,))
113
74
if results :
114
- remote_service = service (service = results [0 ])
115
- setattr (self , name , remote_service )
116
- return remote_service
117
- raise AttributeError ()
75
+ remote_service = results [0 ]
76
+ self ._discovered_services [uuid ] = remote_service
77
+ return remote_service
78
+
79
+ def __contains__ (self , key ):
80
+ uuid = key
81
+ if hasattr (key , "uuid" ):
82
+ uuid = key .uuid
83
+ return self ._discover_remote (uuid ) is not None
84
+
85
+ def __getitem__ (self , key ):
86
+ uuid = key
87
+ maybe_service = False
88
+ if hasattr (key , "uuid" ):
89
+ uuid = key .uuid
90
+ maybe_service = True
91
+
92
+ remote_service = self ._discover_remote (uuid )
93
+
94
+ if uuid in self ._constructed_services :
95
+ return self ._constructed_services [uuid ]
96
+ if remote_service :
97
+ constructed_service = None
98
+ if maybe_service :
99
+ constructed_service = key (service = remote_service )
100
+ self ._constructed_services [uuid ] = constructed_service
101
+ return constructed_service
102
+
103
+ raise KeyError ("{!r} object has no service {}" .format (self , key ))
118
104
119
105
@property
120
106
def connected (self ):
@@ -125,10 +111,11 @@ def disconnect(self):
125
111
"""Disconnect from peer."""
126
112
self ._connection .disconnect ()
127
113
128
- class SmartAdapter :
129
- """This BLE Adapter class enhances the normal `_bleio.Adapter`.
114
+ class BLERadio :
115
+ """The BLERadio class enhances the normal `_bleio.Adapter`.
116
+
117
+ It uses the library's `Advertisement` classes and the `BLEConnection` class."""
130
118
131
- It uses the library's `Advertisement` classes and the `SmartConnection` class."""
132
119
def __init__ (self , adapter = None ):
133
120
if not adapter :
134
121
adapter = _bleio .adapter
@@ -143,7 +130,6 @@ def start_advertising(self, advertisement, scan_response=None, **kwargs):
143
130
scan_response_data = None
144
131
if scan_response :
145
132
scan_response_data = bytes (scan_response )
146
- print (advertisement .connectable )
147
133
self ._adapter .start_advertising (bytes (advertisement ),
148
134
scan_response = scan_response_data ,
149
135
connectable = advertisement .connectable ,
@@ -153,21 +139,20 @@ def stop_advertising(self):
153
139
"""Stops advertising."""
154
140
self ._adapter .stop_advertising ()
155
141
156
- def start_scan (self , advertisement_types = None , ** kwargs ):
157
- """Starts scanning. Returns an iterator of Advertisements that are either recognized or
158
- in advertisment_types (which will be subsequently recognized.) The iterator will block
159
- until an advertisement is heard or the scan times out.
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.
160
146
161
- If a list ``advertisement_types`` is given, only Advertisements of that type are produced
162
- by the returned iterator."""
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."""
163
150
prefixes = b""
164
151
if advertisement_types :
165
- recognize_advertisement (* advertisement_types )
166
- if len (advertisement_types ) == 1 :
167
- prefixes = advertisement_types [0 ].prefix
152
+ prefixes = b"" .join (adv .prefix for adv in advertisement_types )
168
153
for entry in self ._adapter .start_scan (prefixes = prefixes , ** kwargs ):
169
154
adv_type = Advertisement
170
- for possible_type in known_advertisements :
155
+ for possible_type in advertisement_types :
171
156
if possible_type .matches (entry ) and issubclass (possible_type , adv_type ):
172
157
adv_type = possible_type
173
158
advertisement = adv_type .from_entry (entry )
@@ -182,9 +167,9 @@ def stop_scan(self):
182
167
self ._adapter .stop_scan ()
183
168
184
169
def connect (self , advertisement , * , timeout = 4 ):
185
- """Initiates a `SmartConnection ` to the peer that advertised the given advertisement."""
170
+ """Initiates a `BLEConnection ` to the peer that advertised the given advertisement."""
186
171
connection = self ._adapter .connect (advertisement .address , timeout = timeout )
187
- self ._connection_cache [connection ] = SmartConnection (connection )
172
+ self ._connection_cache [connection ] = BLEConnection (connection )
188
173
return self ._connection_cache [connection ]
189
174
190
175
@property
@@ -194,12 +179,12 @@ def connected(self):
194
179
195
180
@property
196
181
def connections (self ):
197
- """A tuple of active `SmartConnection ` objects."""
182
+ """A tuple of active `BLEConnection ` objects."""
198
183
connections = self ._adapter .connections
199
- smart_connections = [None ] * len (connections )
184
+ wrapped_connections = [None ] * len (connections )
200
185
for i , connection in enumerate (self ._adapter .connections ):
201
186
if connection not in self ._connection_cache :
202
- self ._connection_cache [connection ] = SmartConnection (connection )
203
- smart_connections [i ] = self ._connection_cache [connection ]
187
+ self ._connection_cache [connection ] = BLEConnection (connection )
188
+ wrapped_connections [i ] = self ._connection_cache [connection ]
204
189
205
- return tuple (smart_connections )
190
+ return tuple (wrapped_connections )
0 commit comments