1、基本界面
2、相关资料:
Bluetooth Low Energy Overview | Qt Bluetooth 5.15.8
3、基本控制流程
BLE设备发现流程包括:
1、发现设备;
2、连接设备;
3、发现服务;
4、发现特性;
5、读写操作;
6、断开连接;
3.1、发现设备流程
该流程代码如下:
def start_scan(self):
try:
self.discovery_agent = QtBluetooth.QBluetoothDeviceDiscoveryAgent()
self.discovery_agent.setLowEnergyDiscoveryTimeout(5000)
self.discovery_agent.deviceDiscovered.connect(self.device_discovered)
self.discovery_agent.finished.connect(self.discovery_finished)
self.discovery_agent.start()
if self.discovery_agent.isActive():
print("scanning")
except Exception as e:
return str(e)
else:
return None
发现设备信号的槽函数:
def device_discovered(self, info: QtBluetooth.QBluetoothDeviceInfo):
# 我们只关心BLE,只对搜索到的BLE设备做处理
if info.coreConfigurations() & QtBluetooth.QBluetoothDeviceInfo.CoreConfiguration.LowEnergyCoreConfiguration:
self.DiscoverySignal.emit(info)
这里我们将发现设备的设备信息发送到ui界面,显示在QComboBox中,并将设备信息保存到该QComboBox中,如:
def discovery_device(self, info: QtBluetooth.QBluetoothDeviceInfo): print("find device:" + info.name()) self.comboBox_device.addItem(info.name(), info)
需要使用该QComboBox中的设备信息时,直接读取对于项目数据即可,例如:
def connect_device(self):
data = self.comboBox_device.itemData(self.comboBox_device.currentIndex())
self.my_ble.connect_device(data)
3.2、连接设备及发现服务
在设备连接成功的槽函数中可以直接启动发现服务,该流程代码如下:
def connect_device(self, device_info: QtBluetooth.QBluetoothDeviceInfo):
if self.low_energy_controller is not None:
if self.low_energy_controller.state() == QtBluetooth.QLowEnergyController.ControllerState:
self.low_energy_controller.disconnectFromDevice()
del self.low_energy_controller
self.low_energy_controller = QtBluetooth.QLowEnergyController.createCentral(device_info)
self.low_energy_controller.connected.connect(self.controller_connected)
self.low_energy_controller.disconnected.connect(self.controller_disconnected)
self.low_energy_controller.serviceDiscovered.connect(self.service_discovered)
self.low_energy_controller.discoveryFinished.connect(self.service_discover_finished)
self.low_energy_controller.error.connect(self.controller_error)
self.low_energy_controller.connectToDevice()
连接成功/连接完成信号的槽函数如下,这里在连接设备完成后直接启动了发现服务:
def controller_connected(self):
self.low_energy_controller.discoverServices()
断开连接信号的槽函数:
def controller_disconnected(self):
print("device disconnected!")
del self.low_energy_controller
del self.service
发现服务信号的槽函数,发现服务本质是找出服务的uuid,这里将发现的服务uuid发给了ui界面:
def service_discovered(self, uuid: QtBluetooth.QBluetoothUuid):
self.ServiceFoundSignal.emit(uuid)
发现服务完成信号的槽函数:
def service_discover_finished(self):
print("service discovery finished")
控制器错误信号槽函数:
def controller_error(self, err_msg):
print("Error:" + str(err_msg))
3.3、发现特性
特性(characteristic)
操作BLE设备实质是在操作特性,在查找完设备支持的服务之后,通信之前,需要发现对应服务支持的特性;特性分为可读特性、可写特性;
如果可读特性中具有通知功能,在读取该特性时需要先找到其描述符(descriptor),打开通知功能方可读取正确;
可写特性有三种写模式:WriteWithResponse、WriteWithoutResponse、WriteSigned;
描述符(descriptor)
客户端特性配置描述符,在获取了具有通知功能的可读特性后,向描述符写入正确的值,可启用通知;
该流程代码如下:
def connect_service(self, uuid: QtBluetooth.QBluetoothUuid):
del self.service
self.service = self.low_energy_controller.createServiceObject(uuid)
if self.service:
if self.service.state() == QtBluetooth.QLowEnergyService.ServiceState.DiscoveryRequired:
self.service.stateChanged.connect(self.state_changed)
self.service.characteristicChanged.connect(self.characteristic_changed)
self.service.characteristicRead.connect(self.characteristic_read)
self.service.characteristicWritten.connect(self.characteristic_written)
self.service.descriptorWritten.connect(self.descriptor_written)
self.service.descriptorRead.connect(self.descriptor_read)
self.service.discoverDetails()
elif self.service.state() == QtBluetooth.QLowEnergyService.ServiceState.ServiceDiscovered:
self.state_changed(self.service.state())
else:
print("ERR: Cannot open service")
服务状态改变信号的槽函数,这里将发现的服务特性发送给了ui界面:
def state_changed(self, state: QtBluetooth.QLowEnergyService.ServiceState):
if state == QtBluetooth.QLowEnergyService.ServiceState.DiscoveringServices:
print("state changed to: DiscoveringServices")
elif state == QtBluetooth.QLowEnergyService.ServiceState.ServiceDiscovered:
print("state changed to: ServiceDiscovered")
characteristics = self.service.characteristics()
for ch in characteristics:
self.CharacteristicSignal.emit(ch)
其余信号的槽函数如下:
def characteristic_changed(self, ch: QtBluetooth.QLowEnergyCharacteristic, value: QtCore.QByteArray):
print("BLE设备-" + ch.uuid().toString() + "\t 特性值发生变化:" + str(value.toHex()))
self.ReadSignal.emit(value)
def characteristic_read(self, ch: QtBluetooth.QLowEnergyCharacteristic, value: QtCore.QByteArray):
print("BLE设备-" + ch.uuid().toString() + "\t 特性值读取值:" + str(value.toHex()))
self.ReadSignal.emit(value)
def characteristic_written(self, ch: QtBluetooth.QLowEnergyCharacteristic, value: QtCore.QByteArray):
print("BLE设备-" + ch.uuid().toString() + "\t 特性值写入值:" + str(value.toHex()))
def descriptor_written(self, descriptor: QtBluetooth.QLowEnergyDescriptor, value: QtCore.QByteArray):
print(descriptor.name() + " - " + descriptor.uuid().toString() + "\t 描述符写入值:" + str(value.toHex()))
def descriptor_read(self, descriptor: QtBluetooth.QLowEnergyDescriptor, value: QtCore.QByteArray):
print(descriptor.name() + " - " + descriptor.uuid().toString() + "\t 描述符读取值:" + str(value.toHex()))
3.4、读写操作
在对特性操作前,最好先判断其属性,可支持的属性有:
class PropertyType(int):
Unknown = ... # type: QLowEnergyCharacteristic.PropertyType
Broadcasting = ... # type: QLowEnergyCharacteristic.PropertyType
Read = ... # type: QLowEnergyCharacteristic.PropertyType
WriteNoResponse = ... # type: QLowEnergyCharacteristic.PropertyType
Write = ... # type: QLowEnergyCharacteristic.PropertyType
Notify = ... # type: QLowEnergyCharacteristic.PropertyType
Indicate = ... # type: QLowEnergyCharacteristic.PropertyType
WriteSigned = ... # type: QLowEnergyCharacteristic.PropertyType
ExtendedProperty = ... # type: QLowEnergyCharacteristic.PropertyType
读写的本质是对特性的读写,对于具有Notify属性功能的特性,必须先找到其描述符(descriptor),打开该特性的通知功能方可读取正确;
读操作代码如下:
def read_characteristic(self, characteristic: QtBluetooth.QLowEnergyCharacteristic):
if characteristic.isValid():
if characteristic.properties() & QtBluetooth.QLowEnergyCharacteristic.PropertyType.Read:
self.service.readCharacteristic(characteristic)
if characteristic.properties() & QtBluetooth.QLowEnergyCharacteristic.PropertyType.Notify:
descriptor = characteristic.descriptors()
for d in descriptor:
self.service.writeDescriptor(d, QtCore.QByteArray.fromHex(str("0100").encode()))
向描述符中写0x0100表示打开Notify功能,写0x0000表示关闭Notify功能;
写操作代码如下:
def write_characteristic(self, characteristic: QtBluetooth.QLowEnergyCharacteristic, data: str):
if characteristic.isValid():
if characteristic.properties() == QLowEnergyCharacteristic.PropertyType.Write \
or characteristic.properties() == QLowEnergyCharacteristic.PropertyType.WriteNoResponse:
self.service.writeCharacteristic(characteristic, QtCore.QByteArray(data))