求助:如何用Pyodide在浏览器运行iBeacon蓝牙数据采集Python代码
问题解决步骤
1. 安装缺失的Python模块
报错ModuleNotFoundError: No module named 'construct'是因为Pyodide默认未预装construct包,需要通过micropip安装。修改JS代码,在加载Pyodide后先安装依赖:
async function main(){ let pyodide = await loadPyodide(); // 安装所需Python包 await pyodide.runPythonAsync(` import micropip await micropip.install("construct") `); // 加载并保存beacon.py文件 await pyodide.runPythonAsync(` from pyodide.http import pyfetch response = await pyfetch("beacon.py") with open("beacon.py", "wb") as f: f.write(await response.bytes()) `); // 运行beacon.py中的main函数 await pyodide.runPythonAsync(` import beacon await beacon.main() `); } main();
2. 修复Bleak兼容性问题
Bleak库无法在浏览器环境运行,它依赖桌面端系统蓝牙API(如Windows蓝牙栈、Linux BlueZ),而浏览器仅支持Web Bluetooth API,两者不兼容。需要修改beacon.py,改用Pyodide调用浏览器的Web Bluetooth能力实现iBeacon扫描:
import asyncio from uuid import UUID from construct import Array, Byte, Const, Int8sl, Int16ub, Struct from construct.core import ConstError from pyodide import to_js ibeacon_format = Struct( "type_length" / Const(b"\x02\x15"), "uuid" / Array(16, Byte), "major" / Int16ub, "minor" / Int16ub, "power" / Int8sl, ) def decode_ibeacon(manufacturer_data): """解析iBeacon广播数据""" try: apple_data = manufacturer_data.get(0x004C) if not apple_data: return None ibeacon = ibeacon_format.parse(apple_data) uuid = UUID(bytes=bytes(ibeacon.uuid)) return { "uuid": uuid, "major": ibeacon.major, "minor": ibeacon.minor, "power": ibeacon.power } except (KeyError, ConstError): return None async def main(): """通过Web Bluetooth API扫描iBeacon""" navigator = to_js(js.navigator) try: # 请求用户授权蓝牙设备,过滤Apple厂商的广播数据 device = await navigator.bluetooth.requestDevice(to_js({ "acceptAllDevices": True, "scanFilters": [{ "manufacturerData": [{ "companyIdentifier": 0x004C # Apple公司ID }] }] })) print(f"已选中设备: {device.name} ({device.id})") # 解析iBeacon数据 adv_data = device.advertisementData ibeacon_info = decode_ibeacon(adv_data.manufacturerData) if ibeacon_info: print(f"UUID: {ibeacon_info['uuid']}") print(f"Major: {ibeacon_info['major']}") print(f"Minor: {ibeacon_info['minor']}") print(f"TX Power: {ibeacon_info['power']} dBm") print(f"RSSI: {adv_data.rssi} dBm") except Exception as e: print(f"扫描失败: {str(e)}") asyncio.run(main())
3. 关键注意事项
- Web Bluetooth权限限制:必须在HTTPS环境运行(localhost除外),且需要用户手动点击授权蓝牙访问。
- 扫描限制:Web Bluetooth无法实现无连接的全局被动扫描,必须由用户选择特定设备后才能获取其广播数据,这是浏览器的安全机制。
- 持续扫描:若需批量扫描多个iBeacon,可结合浏览器的
BluetoothLEScanAPI(部分现代浏览器支持),通过Pyodide调用JS代码实现。
内容的提问来源于stack exchange,提问作者profundusman
相关产品推荐
相关产品推荐

