当前位置: 首页 > news >正文

用Python和Bluez 5.50在Ubuntu 20.04上,手把手教你做个能被手机发现的BLE广播设备

用Python和Bluez 5.50在Ubuntu 20.04上打造可发现的BLE广播设备

在物联网和智能硬件快速发展的今天,蓝牙低功耗(BLE)技术因其低功耗、低成本的特点,成为连接智能设备的首选方案之一。想象一下,你正在开发一个智能温湿度传感器,或者一个可穿戴健康监测设备,如何让用户的手机能够快速发现并识别你的设备?BLE广播正是实现这一功能的核心技术。

本文将带你从零开始,在Ubuntu 20.04系统上使用Python和Bluez 5.50蓝牙协议栈,创建一个能够被手机发现的BLE广播设备。不同于复杂的理论讲解,我们将聚焦于实际操作,确保你能够在30分钟内完成从环境搭建到手机验证的完整流程。无论你是物联网开发者、Python爱好者,还是对BLE技术好奇的硬件工程师,这篇指南都将为你提供清晰的实践路径。

1. 环境准备与工具安装

在开始编码之前,我们需要确保开发环境已经正确配置。Ubuntu 20.04是一个理想的开发平台,因为它提供了对Bluez蓝牙协议栈的良好支持。以下是需要准备的软件和工具:

  • 操作系统:Ubuntu 20.04 LTS(建议使用实体机或虚拟机)
  • 蓝牙适配器:确保你的电脑配备了兼容的蓝牙硬件(USB蓝牙适配器也可)
  • Python环境:Python 3.8或更高版本
  • 必要软件包:Bluez 5.50及相关开发工具

打开终端,执行以下命令安装所需依赖:

sudo apt update sudo apt install -y bluez libbluetooth-dev python3-dev python3-pip sudo pip3 install dbus-python pygobject

安装完成后,验证Bluez版本:

bluetoothctl --version

你应该看到类似bluetoothctl: 5.50的输出。如果版本不一致,可能需要手动编译安装Bluez 5.50,但这超出了本文的范围。

提示:如果遇到权限问题,请确保你的用户账户已加入lpbluetooth用户组:

sudo usermod -a -G lp,bluetooth $USER

2. BLE广播基础与工作原理

在深入代码之前,理解BLE广播的基本概念至关重要。BLE设备通过广播通道向外发送数据包,这些数据包可以包含设备名称、服务UUID、制造商特定数据等信息。手机等扫描设备会监听这些广播,从而发现附近的BLE设备。

一个典型的BLE广播包包含以下部分:

字段描述示例
设备名称可读的设备标识符"MySensor"
服务UUID设备提供的服务标识"180A" (设备信息服务)
制造商数据厂商自定义数据0xFFFF + [0x01,0x02]
发射功率信号强度指示-70dBm
连接标志指示设备是否可连接0x01

广播模式主要分为三种:

  • 可连接广播:允许设备建立BLE连接
  • 不可连接广播:仅发送数据,不允许连接
  • 扫描响应:当扫描设备请求更多信息时的额外响应

我们的示例将创建一个不可连接的广播设备,专注于广播数据的发送。

3. 编写Python广播程序

现在,让我们创建一个完整的Python脚本,实现BLE广播功能。我们将使用dbus-python库与Bluez交互。创建一个名为ble_advertiser.py的文件,内容如下:

#!/usr/bin/env python3 import dbus import dbus.mainloop.glib from gi.repository import GLib import sys # DBus接口定义 BLUEZ_SERVICE_NAME = 'org.bluez' DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1' LE_ADVERTISEMENT_IFACE = 'org.bluez.LEAdvertisement1' class Advertisement(dbus.service.Object): def __init__(self, bus, index, advertising_type): self.path = '/org/bluez/example/advertisement' + str(index) self.bus = bus self.ad_type = advertising_type self.service_uuids = None self.manufacturer_data = None self.local_name = None self.include_tx_power = False dbus.service.Object.__init__(self, bus, self.path) def add_service_uuid(self, uuid): if not self.service_uuids: self.service_uuids = [] self.service_uuids.append(uuid) def add_manufacturer_data(self, manufacturer_id, data): if not self.manufacturer_data: self.manufacturer_data = dbus.Dictionary({}, signature='qv') self.manufacturer_data[manufacturer_id] = dbus.Array(data, signature='y') def add_local_name(self, name): self.local_name = name @dbus.service.method(DBUS_PROP_IFACE, in_signature='s', out_signature='a{sv}') def GetAll(self, interface): if interface != LE_ADVERTISEMENT_IFACE: raise InvalidArgsException() properties = dict() properties['Type'] = self.ad_type if self.service_uuids: properties['ServiceUUIDs'] = dbus.Array(self.service_uuids, signature='s') if self.manufacturer_data: properties['ManufacturerData'] = self.manufacturer_data if self.local_name: properties['LocalName'] = dbus.String(self.local_name) if self.include_tx_power: properties['Includes'] = dbus.Array(['tx-power'], signature='s') return properties def register_ad_cb(): print("Advertisement registered successfully") def register_ad_error_cb(error): print("Failed to register advertisement: " + str(error)) sys.exit(1) def find_adapter(bus): remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE) objects = remote_om.GetManagedObjects() for path, interfaces in objects.items(): if LE_ADVERTISING_MANAGER_IFACE in interfaces: return path return None def main(): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = dbus.SystemBus() adapter = find_adapter(bus) if not adapter: print("找不到支持BLE广播的蓝牙适配器") return # 开启蓝牙适配器 adapter_props = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter), DBUS_PROP_IFACE) adapter_props.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(1)) # 创建广告对象 ad_manager = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter), LE_ADVERTISING_MANAGER_IFACE) advertisement = Advertisement(bus, 0, "peripheral") advertisement.add_service_uuid("180A") # 设备信息服务 advertisement.add_manufacturer_data(0xFFFF, [0x01, 0x02, 0x03, 0x04]) advertisement.add_local_name("PythonBLE") advertisement.include_tx_power = True # 注册广告 ad_manager.RegisterAdvertisement(advertisement.get_path(), {}, reply_handler=register_ad_cb, error_handler=register_ad_error_cb) try: # 启动事件循环 mainloop = GLib.MainLoop() print("BLE广播已启动,按Ctrl+C停止") mainloop.run() except KeyboardInterrupt: mainloop.quit() if __name__ == "__main__": main()

让我们分解这段代码的关键部分:

  1. Advertisement类:封装了BLE广播数据,包括:

    • 服务UUID(add_service_uuid方法)
    • 制造商数据(add_manufacturer_data方法)
    • 设备名称(add_local_name方法)
  2. DBus交互

    • find_adapter函数查找可用的蓝牙适配器
    • adapter_props.Set启用蓝牙适配器
    • ad_manager.RegisterAdvertisement注册广播数据
  3. 主循环

    • GLib.MainLoop()保持程序运行,持续发送广播

注意:运行此脚本需要root权限或蓝牙组权限,建议使用:

sudo python3 ble_advertiser.py

4. 使用手机验证广播设备

程序运行后,我们需要验证手机是否能够发现我们的BLE设备。以下是使用nRF Connect(一款流行的BLE调试工具)的步骤:

  1. 在手机应用商店下载安装nRF Connect
  2. 打开应用,确保手机蓝牙已开启
  3. 点击"Scan"按钮开始扫描附近的BLE设备
  4. 你应该在设备列表中看到名为"PythonBLE"的设备
  5. 点击设备查看详细信息,确认广播数据与代码设置一致

在nRF Connect中,你应该能看到以下信息:

  • 设备名称:PythonBLE
  • 服务UUID:180A
  • 制造商数据:FFFF -> [01,02,03,04]
  • TX Power:显示信号强度值

如果一切正常,恭喜你!你已经成功创建了一个可被手机发现的BLE广播设备。这个基础框架可以扩展为各种实际应用,比如:

  • 智能信标(iBeacon/Eddystone)
  • 设备状态指示灯
  • 简单的数据广播传感器

5. 高级自定义与故障排除

掌握了基础广播功能后,你可能希望进一步定制广播数据或解决可能出现的问题。以下是几个常见场景的解决方案:

自定义广播间隔

广播间隔影响设备被发现的速度和功耗。要修改广播间隔,可以在注册广告后添加:

adapter_props.Set("org.bluez.Adapter1", "AdvertisingInterval", dbus.UInt16(0x0800))

常见间隔值:

  • 0x0020 (20ms) - 高频率,快速发现
  • 0x0800 (1.28s) - 平衡发现速度与功耗
  • 0x4000 (10.24s) - 低功耗

常见问题排查

问题现象可能原因解决方案
手机看不到设备蓝牙未启用/适配器问题检查bluetoothctl状态,确认适配器已启用
广告注册失败权限不足/接口不支持使用sudo运行,或确认适配器支持BLE
数据不完整广播包过长BLE广播包最多31字节,减少数据量
频繁断开信号干扰检查环境,避免2.4GHz频段干扰源

扩展广播数据

BLE 5.0引入了扩展广播功能,支持更大的数据包。要使用扩展广播,需要:

  1. 确认硬件支持BLE 5.0
  2. 修改广告类型为"peripheral"为"broadcast"
  3. 设置扩展广播参数:
advertisement = Advertisement(bus, 0, "broadcast") adapter_props.Set("org.bluez.Adapter1", "AdvertisingFeatures", dbus.UInt16(0x10))

6. 实际应用案例

让我们看一个实际应用场景:创建一个室内温湿度监测信标。我们可以修改广播数据来包含环境信息:

# 模拟温湿度数据 temperature = 25 # 摄氏度 humidity = 60 # 百分比 # 在Advertisement类中添加 advertisement.add_manufacturer_data(0xFFFF, [ 0x01, # 数据类型标识 temperature, # 温度值 humidity # 湿度值 ])

这样,手机APP无需连接设备就能获取基本环境数据,大大降低了功耗。实际产品中,这些数据可以来自真实的传感器读取。

另一个常见应用是资产跟踪。通过在广播包中包含设备唯一标识,可以实现简单的物品追踪系统:

device_id = [0x12, 0x34, 0x56, 0x78] # 4字节设备ID advertisement.add_manufacturer_data(0xFFFF, device_id)

7. 性能优化与最佳实践

为了确保BLE广播的稳定性和效率,请考虑以下建议:

  1. 广播数据精简

    • 优先使用1字节UUID(如"180A"而非"0000180A-0000-1000-8000-00805F9B34FB")
    • 合并相关数据到制造商特定字段
  2. 功耗优化

    • 根据应用场景调整广播间隔
    • 考虑使用BLE 5.0的周期性广播功能
  3. 兼容性考虑

    • 测试不同手机型号的扫描行为
    • 避免使用保留的UUID和制造商ID
  4. 安全注意事项

    • 广播数据是公开的,不要包含敏感信息
    • 如需安全通信,应建立加密连接
# 示例:优化后的广播设置 advertisement.add_service_uuid("180D") # 心率服务(2字节表示) advertisement.add_manufacturer_data(0xFFFF, [ 0x01, # 数据版本 0x80, # 电池电量(80%) 0x64 # 信号强度 ])

通过本文的实践,你已经掌握了使用Python和Bluez创建BLE广播设备的核心技能。在实际项目中,我发现最常遇到的问题通常是权限和版本兼容性,因此建议在部署前在不同硬件上进行充分测试。

http://www.cnnetsun.cn/news/1598186.html

相关文章:

  • WebSocket C扩展加速:speedups模块性能优化终极指南
  • 知识库邮件通知系统终极指南:5分钟配置自动订阅和提醒功能
  • 如何通过InstantClick事件回调实现精准的性能监控:开发者必备指南
  • zynq7020 u-boot 外设配置实战指南
  • Dism++开源工具:企业与个人用户的系统优化全指南
  • Z-Image-Turbo开箱即用体验:访问8080端口,开启你的极速创作之旅
  • PDF安全保护指南:常用加密方式有哪些?怎么选?
  • 新能源储能必看:BMU主控与从控单元在光伏电站中的典型应用案例
  • 终极指南:如何用115proxy-for-kodi插件在电视上流畅播放115云盘视频
  • 3个步骤+7大模块:Win11Debloat帮你彻底清理Windows 11臃肿问题
  • FFT算法实战:用Python手写Cooley-Tukey蝴蝶变换(附完整代码)
  • Dify+MCP Server避坑指南:从零开始构建企业级AI智能体的完整流程
  • 手把手教你用VMware Workstation单机部署华为VRM管理节点(含gandalf账户密码重置教程)
  • 终极指南:如何构建现代化微服务架构 - Zend Framework Expressive完整教程
  • 手把手教你用Python脚本调用Xinference的Rerank API,打造你的本地RAG排序引擎
  • 像素特工实战案例:上传店铺照片,5分钟拿到陈列优化建议
  • 快速上手SAM 3:记住这3个关键步骤,分割图片视频不求人
  • 区域高亮标注:革新PDF文档交互体验解决非文本标注痛点
  • [CrewAI] 第15课|构建一个多代理系统来实现自动化简历定制和面试准备
  • Apache HBase异步文件系统实现原理:提升IO性能的终极指南
  • 5个维度教你选择付费墙绕过工具:从入门到精通的开源工具决策指南
  • 数字人部署从未如此简单:lite-avatar形象库小白友好教程
  • Gon与Rails 6+集成指南:现代化Web应用开发的最佳实践
  • C++ 笔记 友元(面向对象)
  • 微信聊天记录永久保存:WeChatMsg让你的数字记忆永不消失
  • Palo Alto Panorama 11.2.8 Virtual Appliance for ESXi- Palo Alto Networks 防火墙统一管理
  • TongWeb部署SpringCloud微服务实战:Nacos注册与Gateway路由失效的解决方案
  • nq 开发者指南:从源码编译到自定义队列实现
  • google-translate-api最佳实践:构建企业级翻译服务的完整方案
  • 实战演练:基于快马平台构建virtualbox多机集群,模拟企业级微服务架构