So erstellen Sie einen detaillierten Bluetooth LE-Scanner mit einem Macbook und Python
Finden Sie die Dienste, Eigenschaften, Signalstärke und mehr eines Geräts.
Dieses Tutorial baut auf unserem grundlegenden Artikel zum Erstellen eines Barebones-Bluetooth-LE-Scanners mit Mac und Python auf . Wenn Sie neu in der Arbeit mit Bluetooth und Python sind, lesen Sie zuerst diesen Artikel .
Wenn Sie Bluetooth LE und Python jedoch bereits kennen, kommen wir gleich zur Sache.
Anforderungen
- Mac OS 12.x+
- Python 3
- Bleak 0.18.1 (eine Python Bluetooth LE-Bibliothek)
- Bluetooth LE-Geräte innerhalb von 20–100 Metern von Ihnen
Geben Sie Folgendes in Terminal ein, um Bleak zu installieren :
pip install bleak
Im letzten Scanner-Artikel haben wir einen Bluetooth-Scanner mit Bleak erstellt , einer beliebten Bluetooth-LE-Bibliothek für Python.
# scanner.py
import asyncio
from bleak import BleakScanner
async def main():
devices = await BleakScanner.discover()
for device in devices:
print(device)
asyncio.run(main())
Jetzt werden wir diese grundlegenden Daten verwenden, um diese Geräte ein wenig genauer zu untersuchen und herauszufinden, wozu sie fähig sind.
Wonach wir sonst noch scannen können
Bluetooth-Geräte senden immer Informationen über sich selbst aus. Der Grund, warum wir Bluetooth auf unserem Mac einschalten und eine Reihe verfügbarer Geräte sehen können, ist, dass diese Geräte rufen: „Hey, ich bin hier und ich möchte eine Verbindung herstellen!“ jederzeit. Unser Computer hört die Sendung einfach mit, wie ein Radio.
Was wir mit unserem Scanner machen können, ist diese „Hey!“ zu hören. Nachrichten als erster Teil . Dann können wir diese Daten verwenden, um eine Verbindung zu jedem Gerät herzustellen und ihnen weitere Fragen zu ihrer Person zu stellen .
Das Endergebnis wird wie folgt aussehen:
Und das:
Die zwei Verbesserungen, die wir anstreben
Wir gehen zu:
- Verbessern Sie die Details der Werbedaten, die wir erhalten, einschließlich der Signalstärke.
- Holen Sie sich die „Dienste“, „Eigenschaften“ und „Beschreibungen“, AKA-Dinge, die uns sagen, wozu das Gerät fähig ist und wie wir damit interagieren.
Am Ende haben wir einen Scanner, der uns die vollen Fähigkeiten jedes Bluetooth LE-Geräts (zumindest Geräte, die noch nicht mit anderen Dingen verbunden sind) in unserer Gegend mitteilt.
Über Dienste, Merkmale und Deskriptoren
Dienste, Merkmale und Beschreibungen sind nur ausgefallene Worte für die Funktionen eines Bluetooth-Geräts.
Zum Beispiel kann eine Fitness-Tracking-Uhr Folgendes haben:
- ein Herzfrequenzdienst
- ein Bewegungsdienst
- ein Batterieservice
Jedes Merkmal hat auch Deskriptoren , was nur hilfreiche Informationen für Entwickler sind, die ein Merkmal beschreiben. Deskriptoren sind nicht immer auf einem Gerät vorhanden.
Insgesamt sind Dienste Sammlungen ähnlicher Merkmale, und Deskriptoren helfen uns, die Merkmale besser zu verstehen.
Codierung eines detaillierteren Scanners: Rohdaten und Signalstärke
Um mehr Details von unserem Scanner zu erhalten, verwenden wir den gleichen Code wie oben, außer wenn wir zum printTeil kommen, werden wir alle Attribute von aufrufen deviceund sie drucken. Diese Attribute heißen:
addressdetailsnamemetadatarssi
Hinweis: Bleak 0.19 enthält jetzt eine BleakScanner.discovered_devices() -Funktion, um das Drucken von Werbedaten zu vereinfachen. Dieses Tutorial verwendet Bleak 0.18.1.
Links oben sehen wir, dass Folgendes einige Male gedruckt wird:
[‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’,
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__','__subclasshook__', '__weakref__', 'address', 'details', 'metadata',
'name', 'rssi']
Um diese zu verwenden, fügen wir einige Druckanweisungen und Formatierungen hinzu. Dies wird die neue for device in devices:Schleife sein in scanner.py:
for device in devices:
print(device.name)
print(device.address)
print(device.details)
print(device.metadata)
print(device.rssi)
Auf der linken Seite ist unsere neue Ausgabe, die Folgendes für jedes Gerät ausgibt:
- Gerätename
- Adresse (eine UUID wie
ABCDEFG1–2345-XXXX-XXXX-XXXXXXXXXX) - Technische Details zum Gerät
- Metadaten, die UUIDs für einige Dienste und Herstellerdaten enthalten
- RSSI (Signalstärke, eine Zahl wie
-87oder-92)
# scanner.py
import asyncio
from bleak import BleakScanner
async def main():
devices = await BleakScanner.discover()
for device in devices:
print()
print(f"Name: {device.name}")
print(f"Address: {device.address}")
print(f"Details: {device.details}")
print(f"Metadata: {device.metadata}")
print(f"RSSI: {device.rssi}")
asyncio.run(main())
Wir können sehen, dass das erste gefundene Gerät den Namen hatte [AV] Samsung Soundbar MS650, zusammen mit seiner Adresse, einigen anderen Details und einer Signalstärke von -94(was ziemlich schwach ist).
Noch detaillierter: Leistungen und Eigenschaften
Lassen Sie uns die Geräte fragen, wozu sie fähig sind, d. h. sie nach ihren Diensten , Eigenschaften und Deskriptoren fragen .
Dazu verbinden wir sie kurz mit BleakClient.
Wir machen eine separate for device in devices:Schleife, um die Liste der gefundenen Geräte durchzugehen und eine Verbindung zu ihnen herzustellen. Andernfalls führt die gleichzeitige Ausführung des Werbesammlungsstücks und des Geräteverbindungsstücks zu einem Timeout der Geräteverbindung.
Unsere zweite forSchleife sieht so aus:
for device in devices:
this_device = await BleakScanner.find_device_by_address(device.address)
try:
async with BleakClient(this_device) as client:
...
# Where we'll print services and characteristics for each device
except:
print("Could not connect to device: " + device)
# scanner.py
import asyncio
from bleak import BleakScanner
async def main():
devices = await BleakScanner.discover()
for device in devices:
print()
print(f"Name: {device.name}")
print(f"Address: {device.address}")
print(f"Details: {device.details}")
print(f"Metadata: {device.metadata}")
print(f"RSSI: {device.rssi}")
for device in devices:
try:
this_device = await BleakScanner.find_device_by_address(device.address)
async with BleakClient(this_device) as client:
...
# Where we'll print services and characteristics for each device
except:
print("Could not connect to device: " + device)
asyncio.run(main())
Die Dienste, Merkmale und Deskriptoren sind alle unter der clientVariablen verschachtelt , nachdem wir eine Verbindung hergestellt haben (über async with BleakClient(this_device) as client:).
- Auf Dienste kann mit zugegriffen werden
client.services - Merkmale sind unter jedem Dienst (Beispiel:
client.services[0].characteristics) - Deskriptoren stehen unter jedem Merkmal (Beispiel:
client.services[0].characteristics[0].descriptors)
Unter unserer asynchronen BleakClient(this_device) as client:Zeile fügen wir Folgendes hinzu, um die Dienste jedes Geräts usw. zu drucken:
async with BleakClient(this_device) as client:
print(f'Services found for device')
print(f'\tDevice address:{device.address}')
print(f'\tDevice name:{device.name}')
print('\tServices:')
for service in client.services:
print()
print(f'\t\tDescription: {service.description}')
print(f'\t\tService: {service}')
print('\t\tCharacteristics:')
for c in service.characteristics:
print()
print(f'\t\t\tUUID: {c.uuid}'),
print(f'\t\t\tDescription: {c.uuid}')
print(f'\t\t\tHandle: {c.uuid}'),
print(f'\t\t\tProperties: {c.uuid}')
print('\t\tDescriptors:')
for descrip in c.descriptors:
print(descrip)
Dies ist der vollständige Code mit der unten gezeigten Ausgabe:
# Scan for nearby Bluetooth LE devices and their services
import asyncio
from bleak import BleakClient, BleakScanner
async def main():
devices = await BleakScanner.discover()
for device in devices:
print()
print(f"Name: {device.name}")
print(f"Address: {device.address}")
print(f"Details: {device.details}")
print(f"Metadata: {device.metadata}")
print(f"RSSI: {device.rssi}")
for device in devices:
try:
this_device = await BleakScanner.find_device_by_address(device.address, timeout=20)
async with BleakClient(this_device) as client:
print(f'Services found for device')
print(f'\tDevice address:{device.address}')
print(f'\tDevice name:{device.name}')
print('\tServices:')
for service in client.services:
print()
print(f'\t\tDescription: {service.description}')
print(f'\t\tService: {service}')
print('\t\tCharacteristics:')
for c in service.characteristics:
print()
print(f'\t\t\tUUID: {c.uuid}'),
print(f'\t\t\tDescription: {c.uuid}')
print(f'\t\t\tHandle: {c.uuid}'),
print(f'\t\t\tProperties: {c.uuid}')
print('\t\tDescriptors:')
for descrip in c.descriptors:
print(f'\t\t\t{descrip}')
except Exception as e:
print(f"Could not connect to device with info: {device}")
print(f"Error: {e}")
asyncio.run(main())
Oben sehen wir, dass ein Apple TVgefunden wurde und dass es einen Bluetooth-Dienst anbietet , Apple Continuity Serviceder Apple-Geräten dabei hilft, Daten nahtlos miteinander zu teilen. Dieser Dienst hat 1 unbenanntes Merkmal sowie 2 Deskriptoren (die Zeilen beginnen mit 000029xx-0000-etc...).
Weiter unten in der Zeile sehen wir einen Samsung-Fernseher, der 2 unbenannte Merkmale mit jeweils 1 Deskriptor hat:
Das sind die Endergebnisse unseres Bluetooth LE-Scanners. Wir können alle Bluetooth LE-Geräte innerhalb von 20–100 Metern von uns finden und alles über ihre Fähigkeiten erfahren.
Bonus: Hinzufügen von Farbe zur Ausgabe
Eine letzte Sache, die wir hinzufügen können, um unseren Scanner augenschonend zu machen, ist Farbe .
Eine Möglichkeit, dies in Python und Terminal zu tun, besteht darin, jeden unserer printed-Strings zwischen einige seltsame Zeichen zu legen, die so aussehen:
\033[92m <-- this means green
print("\033[92m" + "This text will be green" + "\033[0m")
Um dies zu testen, öffnen Sie das Terminal, geben Sie python(oder python3) ein, kopieren Sie dann die printobige Anweisung und fügen Sie sie ein. Ihr Text wird grün sein.
Hinweis: Wenn Sie versehentlich Ihr gesamtes Terminal grün färben, versuchen Sie, print(“\033[0m”)es zurückzusetzen. “\033[0m”ist das ENDZeichen für die Einfärbung in Bash/Terminal.
Um unserem Scanner Farbe hinzuzufügen, können wir diese Zeichen ( “\033[92m”und dergleichen) in unsere Druckzeichenfolgen einfügen.
Um die Gerätenamen grün zu machen, können wir die Namensdruckzeile hiervon ändern:
print(f"Name: {device.name}")
print(f"Name: \033[92m{device.name}\033[0m")
Nachfolgend finden Sie eine Liste mit Farbcodes, die Sie verwenden können . ENDStellen Sie sicher, dass Sie das Zeichen ( ) am Ende Ihrer Zeichenfolgen verwenden \033[0m, damit Sie nicht alles in die falsche Farbe bringen.
# Bash output color codes
GREEN = '\033[92m'
RED = '\033[91m'
CYAN = '\033[96m'
YELLOW = '\033[93m'
GOLD = '\033[33m'
BOLD = '\033[1m'
END = '\033[0m'
Wenn Sie Probleme mit einem Teil des Scanners haben, versuchen Sie Folgendes:
- Stellen Sie sicher, dass sowohl das Bluetooth Ihres Mac als auch Ihr Bluetooth LE-Gerät eingeschaltet sind (manchmal schlägt Bluetooth stillschweigend fehl).
- Setzen Sie das
timeoutArgument fürBleakScanner.discover()auf eine Zahl größer als 5,0 (Standardeinstellung). Beispiel:BleakScanner.discover(timeout=10.0) - Setzen Sie das Timeout-Argument für
BleakScanner.find_device_by_address()auf eine Zahl größer als 10,0 (Standardwert). Beispiel:BleakScanner.find_device_by_address(address, timeout=20.0) - Sehen Sie sich Bleaks eigene Fehlerbehebungsdokumentation an .
Wenn Sie Fragen oder Kommentare haben, senden Sie uns eine E-Mail an [email protected] oder senden Sie uns eine Nachricht auf Instagram (@protobioengineering) .
Wenn Ihnen dieser Artikel gefallen hat, können Sie uns mit einer Kaffeespende unterstützen .
In Verbindung stehende Artikel
- Bluetooth-Dienste, -Eigenschaften und -Deskriptoren
- So stellen Sie mit einem MacBook und Python eine Verbindung zu einem Bluetooth LE-Gerät her
- GitHub für Biologen

![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































