TypeError:coroutine对象不可下标,如何获取iBeacon的MAC地址?
问题:iBeacon设备MAC地址获取失败及协程报错问题
我正在开发一个从iBeacon蓝牙设备获取数据的项目,原代码可以正常获取所有设备的MAC地址和本地名称,但修改代码后不仅无法获取MAC地址,还抛出错误:
TypeError: 'coroutine' object is not subscriptable
原正常运行代码
import asyncio from bleak import BleakScanner async def main(): print("scanning for 5 seconds, please wait...") devices = await BleakScanner.discover(return_adv=True) for d, a in devices.values(): print() print(d) # beacon names are POI print("-" * len(str(d))) print(a) if __name__ == "__main__": asyncio.run(main())
原代码输出(包含MAC地址)
FF:CC:DD:KK:8A:01: POI ---------------------- AdvertisementData(local_name='POI', manufacturer_data={76: b'\x02\x15\x85x\xd2\x85\xfd\x1fO{6\xf2\x1b2\x97\xd6\xf0\xe3\x00\x01\x00$\xbd'}, service_data={'0000180a-0000-1000-8000-00805f9b555': b'\x05\x01\xc2c'}, rssi=-88)
修改后报错的代码
import asyncio from uuid import UUID from construct import Array, Byte, Const, Int8sl, Int16ub, Struct from construct.core import ConstError from bleak import BleakScanner from bleak.backends.device import BLEDevice from bleak.backends.scanner import AdvertisementData ibeacon_format = Struct( "type_length" / Const(b"\x02\x15"), "uuid" / Array(16, Byte), "major" / Int16ub, "minor" / Int16ub, "power" / Int8sl, ) def device_found( device: BLEDevice, advertisement_data: AdvertisementData ): """Decode iBeacon.""" try: macadress = BleakScanner.discover(return_adv=True) # => 问题行 name = advertisement_data.local_name apple_data = advertisement_data.manufacturer_data[0x004C] ibeacon = ibeacon_format.parse(apple_data) uuid = UUID(bytes=bytes(ibeacon.uuid)) print(f"Mac Adress : {macadress[0]}") # => 问题行 print(f"Local Name : {name}") print(f"UUID : {uuid}") print(f"Major : {ibeacon.major}") print(f"Minor : {ibeacon.minor}") print(f"TX power : {ibeacon.power} dBm") print(f"RSSI : {device.rssi} dBm") print(47 * "-") except KeyError: # Apple company ID (0x004c) not found pass except ConstError: # No iBeacon (type 0x02 and length 0x15) pass async def main(): """Scan for devices.""" scanner = BleakScanner() scanner.register_detection_callback(device_found) while True: await scanner.start() await asyncio.sleep(1.0) await scanner.stop() asyncio.run(main())
问题解答
1. 什么是Coroutine(协程)对象?
协程是Python异步编程中一种可暂停执行的函数,用async关键字定义的函数调用后,不会立即执行函数体,而是返回一个协程对象。这个对象必须通过await关键字(在异步函数内部)或者asyncio.run()等方式触发执行,才能得到实际的返回值。
你代码里的BleakScanner.discover()是异步函数,直接调用它没有加await,所以得到的是一个协程对象,而不是扫描到的设备数据。协程对象不支持下标访问([0]),因此抛出TypeError: 'coroutine' object is not subscriptable错误。
2. 如何在当前回调方法中获取MAC地址?
完全不需要在回调函数里重新调用BleakScanner.discover(),因为回调函数的第一个参数device: BLEDevice已经包含了该设备的所有基础信息,其中device.address就是你需要的MAC地址。
修复后的完整代码
import asyncio from uuid import UUID from construct import Array, Byte, Const, Int8sl, Int16ub, Struct from construct.core import ConstError from bleak import BleakScanner from bleak.backends.device import BLEDevice from bleak.backends.scanner import AdvertisementData ibeacon_format = Struct( "type_length" / Const(b"\x02\x15"), "uuid" / Array(16, Byte), "major" / Int16ub, "minor" / Int16ub, "power" / Int8sl, ) def device_found( device: BLEDevice, advertisement_data: AdvertisementData ): """Decode iBeacon.""" try: name = advertisement_data.local_name apple_data = advertisement_data.manufacturer_data[0x004C] ibeacon = ibeacon_format.parse(apple_data) uuid = UUID(bytes=bytes(ibeacon.uuid)) print(f"Mac Adress : {device.address}") # 直接从device参数获取MAC print(f"Local Name : {name}") print(f"UUID : {uuid}") print(f"Major : {ibeacon.major}") print(f"Minor : {ibeacon.minor}") print(f"TX power : {ibeacon.power} dBm") print(f"RSSI : {device.rssi} dBm") print(47 * "-") except KeyError: # Apple company ID (0x004c) not found pass except ConstError: # No iBeacon (type 0x02 and length 0x15) pass async def main(): """Scan for devices.""" scanner = BleakScanner() scanner.register_detection_callback(device_found) while True: await scanner.start() await asyncio.sleep(1.0) await scanner.stop() asyncio.run(main())
修改说明
- 删除了错误的
macadress = BleakScanner.discover(return_adv=True)行:回调函数是扫描到设备时自动触发的,不需要重复发起扫描,否则既浪费资源又引发异步错误。 - 将
print(f"Mac Adress : {macadress[0]}")替换为print(f"Mac Adress : {device.address}"):BLEDevice实例的address属性直接提供了设备的MAC地址,无需额外获取。
内容的提问来源于stack exchange,提问作者profundusman
相关产品推荐
相关产品推荐

