- class QLowEnergyService#
QLowEnergyService
类代表了蓝牙低功耗设备上的单个服务。 更多信息…摘要#
方法#
def
characteristic()
def
contains()
定义
def
error()
def
readDescriptor()
def
serviceName()
def
serviceUuid()
def
state()
def
type()
def
writeDescriptor()
Signals
def
descriptorRead()
def
errorOccurred()
def
stateChanged()
注意
详细描述
警告
本节包含自动从C++翻译到Python的代码片段,可能存在错误。
QLowEnergyService
类提供了访问低功耗蓝牙服务详细信息的途径。该类简化了服务详细信息的发现和发布,允许读取和写入包含的数据,并通知数据变化。服务结构#
一个低功耗蓝牙外围设备可以包含多个服务。反过来,每个服务可以包含更多服务。此类代表外围设备的一个服务,通过
createServiceObject()
方法创建。该方法中的type()
表示该服务是否为主服务(顶级服务)或是否为其他服务的组成部分。每个服务可能包含一个或多个特性,每个特性可以包含描述符。结果结构可能像以下示意图所示特性是主要的信息载体。它有一个
value()
方法和properties()
方法,描述值的访问权限。包含的描述符的一般用途是进一步定义特性的性质。例如,它可能指定如何解释值,或者是否可以通知值消费者关于值的变化。服务交互#
一旦创建了服务对象,其详细信息尚未被发现。这表明其当前的
state()
是DiscoveryRequired
。只能检索serviceUuid()
和serviceName()
。当调用
discoverDetails()
方法时,会触发其附加的服务、特性和描述符的发现。在发现过程中,state()
会从DiscoveryRequired
状态通过DiscoveringService
状态过渡到最终的ServiceDiscovered
状态。这种过渡通过stateChanged()
信号进行广播。一旦知道了详细信息,所有包含的特性、描述符和所包含的服务都是已知的,并且可以读取或写入。可以通过
QLowEnergyCharacteristic
和QLowEnergyDescriptor
分别检索特性和描述符的值。然而,直接读取或写入这些属性需要服务对象。`readCharacteristic()` 函数尝试重新读取特性的值。尽管初始服务发现可能已经获取了值,但在特价值的改变没有提供任何通知的情况下,可能需要此调用。一个例子是提供连续值的计时特性。如果读取尝试成功,则发出characteristicRead()
信号。读取值失败会触发CharacteristicReadError
。`writeCharacteristic()` 函数尝试将新值写入指定的特性。如果写入尝试成功,则发出characteristicWritten()
信号。写入失败会触发CharacteristicWriteError
。描述符的读取和写入遵循相同的模式。在硬件上读取或写入描述符或特性的值时尽最大努力。这意味着在读取和写入时通常忽略元信息,例如
properties()
。例如,即使根据其元数据描述该特性为只读,也可以调用writeCharacteristic()
。结果写入请求将转发给连接的设备,并由设备决定对潜在无效请求做出响应。在这种情况下,结果是返回的设备错误后发射的CharacteristicWriteError
。这种行为简化了与报告错误元信息的设备的交互。如果无法将请求转发给远程设备,则设置OperationError。一个潜在的原因可能是将要写入的特性对象甚至不属于当前服务。总之,两种类型错误允许快速区分本地和远程错误。所有请求都根据先进先出原则进行序列化。例如,在先前的写入请求完成之前发出第二个写入请求将延迟,直到第一个写入请求完成。
def
stateChanged()
目前,无法发送签名写入或可靠写入请求。
在某些情况下,外围设备生成中央设备有兴趣接收的值更新。为了使特性支持此类通知,它必须具有Notify或
Indicate
属性,以及类型为ClientCharacteristicConfiguration的描述符。在这些条件得到满足的情况下,可以按以下代码段所示启用通知:#PreCondition: service details already discovered batteryLevel = service.characteristic( QBluetoothUuid.CharacteristicType.BatteryLevel) if not batteryLevel.isValid(): return notification = batteryLevel.descriptor( QBluetoothUuid.DescriptorType.ClientCharacteristicConfiguration) if not notification.isValid(): return # establish hook into notifications connect(service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)), self, SLOT(characteristicChanged(QLowEnergyCharacteristic,QByteArray))) # enable notification service.writeDescriptor(notification, QByteArray.fromHex("0100")) # disable notification #service->writeDescriptor(notification, QByteArray::fromHex("0000")) # wait until descriptorWritten() signal is emitted # to confirm successful write
以下示例显示了电池级别特性,在每次值更改时都会更新中央设备。通知通过
characteristicChanged()
信号提供。有关此机制的更多详细信息,请参阅蓝牙规范 。服务数据共享
每个QLowEnergyService实例共享其内部状态和信息,与同一服务的其他QLowEnergyService实例。如果一个实例启动了对服务详细信息的发现,则所有剩余的实例将自动跟随。因此,以下代码段总是有效:
first, = QLowEnergyService() control = QLowEnergyController(remoteDevice) control.connectToDevice() # waiting for connection first = control.createServiceObject(QBluetoothUuid.ServiceClassUuid.BatteryService) second = control.createServiceObject(QBluetoothUuid.ServiceClassUuid.BatteryService) Q_ASSERT(first.state() == QLowEnergyService.RemoteService) Q_ASSERT(first.state() == second.state()) first.discoverDetails() Q_ASSERT(first.state() == QLowEnergyService.RemoteServiceDiscovering) Q_ASSERT(first.state() == second.state())
其他操作,如对以下方法的调用,例如对 readCharacteristic()、readDescriptor()、writeCharacteristic()、writeDescriptor() 的调用,或者由于相关的 QLowEnergyController 从设备断开导致的服务失效,都以相同的方式进行共享。
- class ServiceType#
(继承自
enum.Flag
) 此枚举描述了服务类型。常量
说明
QLowEnergyService.PrimaryService
该服务是顶级/主要服务。如果此类型标志未设置,则认为该服务是二级服务。每个服务都可能由另一个服务包含,这由 IncludedService 指示。
QLowEnergyService.IncludedService
该服务被另一个服务包含。在某些平台上,此标志只能在包含当前服务的服务被发现的条件下确定。
- class ServiceError#
此枚举描述了服务存在期间的所有可能错误条件。
error()
函数返回最后发生的错误。常量
说明
QLowEnergyService.NoError
未发生错误。
QLowEnergyService.OperationError
在对服务不可用的情况下尝试执行操作。例如,在服务尚未处于
ServiceDiscovered
或服务由于与外围设备的连接丢失而无效时尝试写入服务。QLowEnergyService.CharacteristicReadError
尝试读取特征值失败。例如,它可能在调用 readCharacteristic() 时触发。
QLowEnergyService.CharacteristicWriteError
尝试写入新值到特征失败。例如,在尝试写入只读特征时可能会触发。
QLowEnergyService.DescriptorReadError
尝试读取描述符值失败。例如,可能在调用
readDescriptor()
时触发。QLowEnergyService.DescriptorWriteError
尝试写入新值到描述符失败。例如,尝试写入只读描述符时会触发。
QLowEnergyService.UnknownError
在与服务交互时发生未知错误。
- class ServiceState#
-
常量
说明
QLowEnergyService.InvalidService
当服务失去与底层设备的连接时,服务可能变得无效。即使连接可能丢失,但它仍然保留最后的信息。无效的服务即使在重新建立到设备的连接后也无法再次变为有效。
QLowEnergyService.RemoteService
服务详细信息尚未通过调用
discoverDetails()
来发现。唯一的可靠信息是其serviceUuid()
和serviceName()
。QLowEnergyService.RemoteServiceDiscovering
正在发现服务详细信息。
QLowEnergyService.RemoteServiceDiscovered
已发现服务详细信息。
QLowEnergyService.LocalService
此服务与
peripheral role
中的控制器对象相关联。这类服务对象不会改变其状态。QLowEnergyService.DiscoveryRequired
已弃用。已被重命名为RemoteService。
QLowEnergyService.DiscoveringService
已弃用。已被重命名为RemoteServiceDiscovering。
QLowEnergyService.ServiceDiscovered
已弃用。已被重命名为RemoteServiceDiscovered。
- class DiscoveryMode#
此枚举列出了服务发现模式。所有模式都会发现服务的特征和特征描述符。不同之处在于是否读取特征值和描述符。
常量
说明
QLowEnergyService.FullDiscovery
在完全发现过程中,将发现所有特征。将读取所有特征值和描述符。
QLowEnergyService.SkipValueDiscovery
在最小发现过程中,将发现所有特征。不会读取特征值和描述符。
- class WriteMode#
此枚举描述了在写入特征值时应使用的模式。特征通过其
properties
广告其支持的写入模式。常量
说明
QLowEnergyService.WriteWithResponse
使用此模式写入特性时,外围设备应发送写入确认。如果操作成功,确认通过
characteristicWritten()
信号发出。否则,会发出CharacteristicWriteError
。特性必须已将Write
属性设置为支持此写入模式。QLowEnergyService.WriteWithoutResponse
使用此模式写入特性时,远程外围设备不应发送写入确认。操作是否成功无法确定,有效负载长度不能超过20字节。特性必须已将
WriteNoResponse
属性设置为支持此写入模式。其优势是写入操作更快,因为它可能发生在其他设备交互之间。QLowEnergyService.WriteSigned
使用此模式写入特性时,远程外围设备不应发送写入确认。操作是否成功无法确定,有效负载长度不能超过8字节。两个设备之间必须存在绑定关系,且链路不得加密。特性必须已将
WriteSigned
属性设置为支持此写入模式。此值目前在Android和Linux(BlueZ 5和内核版本3.7或更高)上仅受支持。
- characteristic(uuid)#
- 参数:
uuid –
QBluetoothUuid
- 返回类型:
返回
uuid
对应的特性;否则返回无效特性。如果此服务实例的
discoverDetails()
尚未调用,或者没有匹配uuid
的特性,则返回的特性无效。- characteristicChanged(info, value)#
- 参数:
info –
QLowEnergyCharacteristic
value –
QByteArray
如果关联的控制对象处于
central
角色中,则当外设/设备的网络上发生的某个事件导致characteristic
的值发生变化时,会发出这个信号。在这种情况下,信号发射意味着在变化事件发生之前必须通过特征值的ClientCharacteristicConfiguration
描述符激活了变化通知。有关如何做到这一点的更多详细信息,请参阅上面
。如果控制器处于
peripheral
角色中,即是通过addService
创建服务对象,当 GATT 客户端使用写请求或命令写入特征的值时,会发出该信号。参数
newValue
包含characteristic
的更新值。- characteristicRead(info, value)#
- 参数:
info –
QLowEnergyCharacteristic
value –
QByteArray
当对
characteristic
的读取请求成功返回其value
时,会发出这个信号。该信号可能由调用 characteristicRead() 触发。如果读取操作未成功,将使用errorOccurred()
信号通过CharacteristicReadError
标志发射。- characteristicWritten(info, value)#
- 参数:
info –
QLowEnergyCharacteristic
value –
QByteArray
当
characteristic
的值成功更改为newValue
时发出此信号。更改必须由调用writeCharacteristic()
触发。如果写入操作未成功,将使用errorOccurred()
信号通过CharacteristicWriteError
标志发射。接收写入信号可以视为一个迹象,表明目标设备已收到待写入的值并报告写请求的状态。
def
stateChanged()
如果使用
writeCharacteristic()
方法调用WriteWithoutResponse
模式,则不会发出此信号和errorOccurred()
。- characteristics()#
- 返回类型:
. 属于 QLowEnergyCharacteristic 的列表
返回与此
QLowEnergyService
实例关联的所有属性。如果此服务实例的
discoverDetails()
还未调用或者没有已知的属性,则返回的列表将为空。- contains(characteristic)#
- 参数:
characteristic –
QLowEnergyCharacteristic
- 返回类型:
bool
如果
characteristic
属于此服务,则返回true
;否则返回false
。如果
characteristic
被characteristics()
包含,则属性属于服务。- contains(descriptor)
- 参数:
descriptor –
QLowEnergyDescriptor
- 返回类型:
bool
如果
descriptor
属于此服务,则返回true
;否则返回false
。- descriptorRead(info, value)#
- 参数:
info –
QLowEnergyDescriptor
value –
QByteArray
当读取请求成功返回
descriptor
的value
时,会发出此信号。该信号可能由调用 descriptorRead() 触发。如果读取操作不成功,将使用errorOccurred()
信号并在DescriptorReadError
标志下发出。- descriptorWritten(info, value)#
- 参数:
info –
QLowEnergyDescriptor
value –
QByteArray
当
descriptor
的值成功更改为newValue
时,会发出此信号。如果相关控制器对象处于central
角色中,更改必须是调用writeDescriptor()
所引起的。否则,该信号是来自 GATT 客户端到相应描述符的写入请求或命令的结果。- discoverDetails([mode=QLowEnergyService.DiscoveryMode.FullDiscovery])#
- 参数:
mode –
DiscoveryMode
启动服务包含的服务、特性和它们相关描述符的发现。
通过
stateChanged()
信号指示发现过程。创建服务后,它处于DiscoveryRequired
状态。在调用 discoverDetails() 后,它将转换到DiscoveringService
状态。在详细发现完成后,它将转换到ServiceDiscovered
状态。在每次转换过程中,都会发出stateChanged()
信号。根据参数mode
,执行FullDiscovery
或SkipValueDiscovery
。在任何情况下,都会发现所有服务和特性。一个FullDiscovery
会继续读取所有特性的值和描述符。一个SkipValueDiscovery
不会读取特性的值和描述符。一个SkipValueDiscovery
有两个优点。首先,它更快。其次,它绕过了某些设备中的一些错误,这些设备错误地宣布特性或描述符为可读,但仍然不允许读取它们。这可能会引发不可预测的行为。在SkipValueDiscovery
之后,必须调用readCharacteristic()
/readDescriptor()
并等待它们成功完成后才能访问特性或描述符的值。参数
mode
是从 Qt 6.2 开始引入的。参见
- error()#
- 返回类型:
返回最后发生的错误或
NoError
。- errorOccurred(error)#
- 参数:
error –
ServiceError
当发生错误时,会发出此信号。《新错误》参数描述了发生的错误。
- includedServices()链接到该定义
- 返回类型:
返回当前服务所包含的所有服务的UUID。
如果此服务实例的
discoverDetails()
还未调用或者没有已知的属性,则返回的列表将为空。可能存在一种情况,即包含的服务本身还包含另一个服务。这种二级包含必须通过相关的一级
QLowEnergyService
实例来获取。技术上,这可能会导致循环依赖。应使用
createServiceObject()
来获取UUID对应的每个服务实例。- readCharacteristic(characteristic)链接到该定义
- 参数:
characteristic –
QLowEnergyCharacteristic
读取《characteristic》的值。如果操作成功,会发出
characteristicRead()
信号;否则会将《CharacteristicReadError》设置为。通常,如果一个《characteristic》的《Read》属性被设置,则该《characteristic`可读。指向同一远程设备的所有描述符和特性请求都将序列化。在同时发出多个请求时,会使用队列。队列不能消除针对同一特性的重复读取请求。
只有在服务处于《ServiceDiscovered`》状态并属于服务时,才能读取特性。如果这些条件中有一个不成立,则设置《OperationError`》。
def
stateChanged()
即使《properties()``报告了不可读属性,调用此函数也会尝试在硬件上读取特性的值。如果硬件返回错误,则设置《CharacteristicReadError`》。
- readDescriptor(descriptor)#
- 参数:
descriptor –
QLowEnergyDescriptor
读取
descriptor
的值。如果操作成功,将发射descriptorRead()
信号;否则设置DescriptorReadError
。针对同一远程设备的所有描述符和特征请求都将序列化。在同时发布多个请求时,将使用队列。队列不会消除针对同一描述符的重复读取请求。
只有当服务处于
ServiceDiscovered
状态且描述符属于该服务时,才能读取描述符。如果这些条件中的任何一个不正确,则设置OperationError
。- serviceName()#
- 返回类型:
str
返回服务的名称;否则返回空字符串。
返回的名称只能在
serviceUuid()
是 已知 UUID 时检索到。- serviceUuid()#
- 返回类型:
返回服务的 UUID;否则返回空 UUID。
- state()#
- 返回类型:
返回服务的当前状态。
如果设备的第一个服务实例被创建,则该对象的状态是
DiscoveryRequired
。指向外围设备上同一服务的所有服务对象的状态始终相同。这是由于内部对象数据的共享性质所致。因此,第一个实例创建后创建的任何服务对象实例的状态都将与现有实例相等。如果
QLowEnergyController
断开与远程设备的连接,则该服务将无效。无效的服务将保持断开事件发生时的内部状态。这意味着一旦发现服务详情,它们甚至可以从无效的服务中检索出来。这允许场景,即当建立设备连接、检索服务详情后,立即断开设备连接,以允许下一台设备连接到外围设备。然而,在正常情况下,应保持连接以避免反复发现服务和它们的详细信息。发现可能需要一段时间,客户端可以订阅正在进行中的更改通知。
- stateChanged(newState)#
- 参数:
newState –
ServiceState
在服务状态发生改变时发出此信号。也可以通过
state()
方法检索newState
。参见
- type()#
- 返回类型:
结合
ServiceType
返回服务类型。
def
stateChanged()
此类型属性不能在服务达到
ServiceDiscovered
状态之前依赖。此字段初始化为PrimaryService
。def
stateChanged()
在Android上,无法确定一个服务是主服务还是从服务。因此,所有服务都将
PrimaryService
标志设置为开启。- writeCharacteristic(characteristic, newValue[, mode=QLowEnergyService.WriteMode.WriteWithResponse])#
- 参数:
characteristic –
QLowEnergyCharacteristic
newValue –
QByteArray
mode –
WriteMode
将
newValue
写入为characteristic
的值。准确的语义取决于关联控制器对象的地位。中心地位
调用结果将导致向远程外围设备发送写请求或命令。如果操作成功,将发出
characteristicWritten()
信号;否则设置CharacteristicWriteError
。调用此函数并不会触发characteristicChanged()
信号,除非外围设备本身在当前写请求之后再次更改了值。mode
参数确定远程设备是否应发送写确认。待写入的characteristic
必须支持相关写模式。特性的支持写模式由其Write
和WriteNoResponse
属性指示。针对同一远程设备的所有描述符和特性写请求都被序列化。在同时发出多个写请求时,将使用队列。队列不会消除针对同一特性的重复写请求。例如,如果同一描述符被设置为值 A,然后立即设置为 B,这两个写请求将按给定顺序执行。
def
stateChanged()
目前,无法使用蓝牙规范定义的签名或可靠写入。
只有当此服务处于
ServiceDiscovered
状态且属于服务时,才能写入特性。如果这些条件之一不成立,则会设置OperationError
。def
stateChanged()
尽管
properties()
报告了不可写入的属性,但调用此函数仍然会尝试写入硬件。同样,即使特性可能只支持WriteWithResponse
,也会向硬件发送WriteWithoutResponse
。如果硬件返回错误,则设置CharacteristicWriteError
。外围设备角色
此调用导致在本地数据库中更新特性的值。
如果客户端当前已连接并且已启用特征的 notifications 或 indications,则将发送相应的信息。如果设备已启用特征的 notifications 或 indications,并且当前未连接,但与本地设备之间存在绑定,则在下一次重新连接时发送 notification 或 indication。
如果特性值的长度有限制,并且
newValue
不符合该限制,则行为未定义。- writeDescriptor(descriptor, newValue)#
- 参数:
descriptor –
QLowEnergyDescriptor
newValue –
QByteArray
将
newValue
作为descriptor
的值写入。确切的语义取决于关联控制器对象的角色。中心地位
调用此函数会导致向远程设备发送写入请求。如果操作成功,将发射
descriptorWritten()
信号;否则将发射DescriptorWriteError
。所有针对同一远程设备的描述符和特性请求都是串行的。在同时发出多个写入请求时使用队列。该队列不会消除针对同一描述符的重复写入请求。例如,如果同一个描述符先被设置为值 A,然后立即设置为值 B,这两个写入请求将按给定顺序执行。
只有当此服务处于
ServiceDiscovered
状态且属于该服务时,才能写入描述符。如果这些条件中任何一个不成立,则设置OperationError
。外围角色
将值写入本地服务数据库。如果
newValue
的内容对于descriptor
无效,则行为未定义。