class QLowEnergyService#

QLowEnergyService 类代表了蓝牙低功耗设备上的单个服务。 更多信息

Inheritance diagram of PySide6.QtBluetooth.QLowEnergyService

摘要#

方法#

def writeDescriptor()

def stateChanged()

注意

详细描述

警告

本节包含自动从C++翻译到Python的代码片段,可能存在错误。

QLowEnergyService 类提供了访问低功耗蓝牙服务详细信息的途径。该类简化了服务详细信息的发现和发布,允许读取和写入包含的数据,并通知数据变化。

服务结构#

一个低功耗蓝牙外围设备可以包含多个服务。反过来,每个服务可以包含更多服务。此类代表外围设备的一个服务,通过createServiceObject() 方法创建。该方法中的 type() 表示该服务是否为主服务(顶级服务)或是否为其他服务的组成部分。每个服务可能包含一个或多个特性,每个特性可以包含描述符。结果结构可能像以下示意图所示

../../_images/peripheral-structure.png

特性是主要的信息载体。它有一个 value() 方法和 properties() 方法,描述值的访问权限。包含的描述符的一般用途是进一步定义特性的性质。例如,它可能指定如何解释值,或者是否可以通知值消费者关于值的变化。

服务交互#

一旦创建了服务对象,其详细信息尚未被发现。这表明其当前的 state()DiscoveryRequired 。只能检索 serviceUuid()serviceName()

当调用 discoverDetails() 方法时,会触发其附加的服务、特性和描述符的发现。在发现过程中,state() 会从 DiscoveryRequired 状态通过 DiscoveringService 状态过渡到最终的 ServiceDiscovered 状态。这种过渡通过 stateChanged() 信号进行广播。一旦知道了详细信息,所有包含的特性、描述符和所包含的服务都是已知的,并且可以读取或写入。

可以通过 QLowEnergyCharacteristicQLowEnergyDescriptor 分别检索特性和描述符的值。然而,直接读取或写入这些属性需要服务对象。`readCharacteristic()` 函数尝试重新读取特性的值。尽管初始服务发现可能已经获取了值,但在特价值的改变没有提供任何通知的情况下,可能需要此调用。一个例子是提供连续值的计时特性。如果读取尝试成功,则发出 characteristicRead() 信号。读取值失败会触发 CharacteristicReadError。`writeCharacteristic()` 函数尝试将新值写入指定的特性。如果写入尝试成功,则发出 characteristicWritten() 信号。写入失败会触发 CharacteristicWriteError。描述符的读取和写入遵循相同的模式。

在硬件上读取或写入描述符或特性的值时尽最大努力。这意味着在读取和写入时通常忽略元信息,例如properties()。例如,即使根据其元数据描述该特性为只读,也可以调用writeCharacteristic()。结果写入请求将转发给连接的设备,并由设备决定对潜在无效请求做出响应。在这种情况下,结果是返回的设备错误后发射的CharacteristicWriteError。这种行为简化了与报告错误元信息的设备的交互。如果无法将请求转发给远程设备,则设置OperationError。一个潜在的原因可能是将要写入的特性对象甚至不属于当前服务。总之,两种类型错误允许快速区分本地和远程错误。

所有请求都根据先进先出原则进行序列化。例如,在先前的写入请求完成之前发出第二个写入请求将延迟,直到第一个写入请求完成。

def stateChanged()

目前,无法发送签名写入或可靠写入请求。

在某些情况下,外围设备生成中央设备有兴趣接收的值更新。为了使特性支持此类通知,它必须具有NotifyIndicate属性,以及类型为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#

此枚举描述了state()对象的状态

常量

说明

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)#
参数:

uuidQBluetoothUuid

返回类型:

QLowEnergyCharacteristic

返回 uuid 对应的特性;否则返回无效特性。

如果此服务实例的 discoverDetails() 尚未调用,或者没有匹配 uuid 的特性,则返回的特性无效。

characteristicChanged(info, value)#
参数:

如果关联的控制对象处于 central 角色中,则当外设/设备的网络上发生的某个事件导致 characteristic 的值发生变化时,会发出这个信号。在这种情况下,信号发射意味着在变化事件发生之前必须通过特征值的 ClientCharacteristicConfiguration 描述符激活了变化通知。有关如何做到这一点的更多详细信息,请参阅 上面

如果控制器处于 peripheral 角色中,即是通过 addService 创建服务对象,当 GATT 客户端使用写请求或命令写入特征的值时,会发出该信号。

参数 newValue 包含 characteristic 的更新值。

characteristicRead(info, value)#
参数:

当对 characteristic 的读取请求成功返回其 value 时,会发出这个信号。该信号可能由调用 characteristicRead() 触发。如果读取操作未成功,将使用 errorOccurred() 信号通过 CharacteristicReadError 标志发射。

def stateChanged()

此信号仅针对与 Central 角色相关的用例发出。

characteristicWritten(info, value)#
参数:

characteristic 的值成功更改为 newValue 时发出此信号。更改必须由调用 writeCharacteristic() 触发。如果写入操作未成功,将使用 errorOccurred() 信号通过 CharacteristicWriteError 标志发射。

接收写入信号可以视为一个迹象,表明目标设备已收到待写入的值并报告写请求的状态。

def stateChanged()

如果使用 writeCharacteristic() 方法调用 WriteWithoutResponse 模式,则不会发出此信号和 errorOccurred()

def stateChanged()

此信号仅针对与 Central 角色相关的用例发出。

characteristics()#
返回类型:

. 属于 QLowEnergyCharacteristic 的列表

返回与此 QLowEnergyService 实例关联的所有属性。

如果此服务实例的 discoverDetails() 还未调用或者没有已知的属性,则返回的列表将为空。

contains(characteristic)#
参数:

characteristicQLowEnergyCharacteristic

返回类型:

bool

如果 characteristic 属于此服务,则返回 true;否则返回 false

如果 characteristiccharacteristics() 包含,则属性属于服务。

contains(descriptor)
参数:

descriptorQLowEnergyDescriptor

返回类型:

bool

如果 descriptor 属于此服务,则返回 true;否则返回 false

descriptorRead(info, value)#
参数:

当读取请求成功返回 descriptorvalue 时,会发出此信号。该信号可能由调用 descriptorRead() 触发。如果读取操作不成功,将使用 errorOccurred() 信号并在 DescriptorReadError 标志下发出。

def stateChanged()

此信号仅针对与 Central 角色相关的用例发出。

descriptorWritten(info, value)#
参数:

descriptor 的值成功更改为 newValue 时,会发出此信号。如果相关控制器对象处于 central 角色中,更改必须是调用 writeDescriptor() 所引起的。否则,该信号是来自 GATT 客户端到相应描述符的写入请求或命令的结果。

discoverDetails([mode=QLowEnergyService.DiscoveryMode.FullDiscovery])#
参数:

modeDiscoveryMode

启动服务包含的服务、特性和它们相关描述符的发现。

通过 stateChanged() 信号指示发现过程。创建服务后,它处于 DiscoveryRequired 状态。在调用 discoverDetails() 后,它将转换到 DiscoveringService 状态。在详细发现完成后,它将转换到 ServiceDiscovered 状态。在每次转换过程中,都会发出 stateChanged() 信号。根据参数 mode,执行FullDiscoverySkipValueDiscovery。在任何情况下,都会发现所有服务和特性。一个 FullDiscovery 会继续读取所有特性的值和描述符。一个 SkipValueDiscovery 不会读取特性的值和描述符。一个 SkipValueDiscovery 有两个优点。首先,它更快。其次,它绕过了某些设备中的一些错误,这些设备错误地宣布特性或描述符为可读,但仍然不允许读取它们。这可能会引发不可预测的行为。在SkipValueDiscovery 之后,必须调用 readCharacteristic() / readDescriptor() 并等待它们成功完成后才能访问特性或描述符的值。

参数 mode 是从 Qt 6.2 开始引入的。

参见

state()

error()#
返回类型:

ServiceError

返回最后发生的错误或NoError

errorOccurred(error)#
参数:

errorServiceError

当发生错误时,会发出此信号。《新错误》参数描述了发生的错误。

includedServices()链接到该定义
返回类型:

包含的QBluetoothUuid

返回当前服务所包含的所有服务的UUID。

如果此服务实例的 discoverDetails() 还未调用或者没有已知的属性,则返回的列表将为空。

可能存在一种情况,即包含的服务本身还包含另一个服务。这种二级包含必须通过相关的一级QLowEnergyService实例来获取。技术上,这可能会导致循环依赖。

应使用createServiceObject()来获取UUID对应的每个服务实例。

readCharacteristic(characteristic)链接到该定义
参数:

characteristicQLowEnergyCharacteristic

读取《characteristic》的值。如果操作成功,会发出characteristicRead()信号;否则会将《CharacteristicReadError》设置为。通常,如果一个《characteristic》的《Read》属性被设置,则该《characteristic`可读。

指向同一远程设备的所有描述符和特性请求都将序列化。在同时发出多个请求时,会使用队列。队列不能消除针对同一特性的重复读取请求。

只有在服务处于《ServiceDiscovered`》状态并属于服务时,才能读取特性。如果这些条件中有一个不成立,则设置《OperationError`》。

def stateChanged()

即使《properties()``报告了不可读属性,调用此函数也会尝试在硬件上读取特性的值。如果硬件返回错误,则设置《CharacteristicReadError`》。

readDescriptor(descriptor)#
参数:

descriptorQLowEnergyDescriptor

读取 descriptor 的值。如果操作成功,将发射 descriptorRead() 信号;否则设置 DescriptorReadError

针对同一远程设备的所有描述符和特征请求都将序列化。在同时发布多个请求时,将使用队列。队列不会消除针对同一描述符的重复读取请求。

只有当服务处于 ServiceDiscovered 状态且描述符属于该服务时,才能读取描述符。如果这些条件中的任何一个不正确,则设置 OperationError

serviceName()#
返回类型:

str

返回服务的名称;否则返回空字符串。

返回的名称只能在 serviceUuid()已知 UUID 时检索到。

serviceUuid()#
返回类型:

QBluetoothUuid

返回服务的 UUID;否则返回空 UUID。

state()#
返回类型:

ServiceState

返回服务的当前状态。

如果设备的第一个服务实例被创建,则该对象的状态是 DiscoveryRequired 。指向外围设备上同一服务的所有服务对象的状态始终相同。这是由于内部对象数据的共享性质所致。因此,第一个实例创建后创建的任何服务对象实例的状态都将与现有实例相等。

如果 QLowEnergyController 断开与远程设备的连接,则该服务将无效。无效的服务将保持断开事件发生时的内部状态。这意味着一旦发现服务详情,它们甚至可以从无效的服务中检索出来。这允许场景,即当建立设备连接、检索服务详情后,立即断开设备连接,以允许下一台设备连接到外围设备。

然而,在正常情况下,应保持连接以避免反复发现服务和它们的详细信息。发现可能需要一段时间,客户端可以订阅正在进行中的更改通知。

stateChanged(newState)#
参数:

newStateServiceState

在服务状态发生改变时发出此信号。也可以通过 state() 方法检索 newState

参见

state()

type()#
返回类型:

结合 ServiceType

返回服务类型。

def stateChanged()

此类型属性不能在服务达到 ServiceDiscovered 状态之前依赖。此字段初始化为 PrimaryService

def stateChanged()

在Android上,无法确定一个服务是主服务还是从服务。因此,所有服务都将 PrimaryService 标志设置为开启。

writeCharacteristic(characteristic, newValue[, mode=QLowEnergyService.WriteMode.WriteWithResponse])#
参数:

newValue 写入为 characteristic 的值。准确的语义取决于关联控制器对象的地位。

中心地位

调用结果将导致向远程外围设备发送写请求或命令。如果操作成功,将发出characteristicWritten()信号;否则设置CharacteristicWriteError。调用此函数并不会触发characteristicChanged()信号,除非外围设备本身在当前写请求之后再次更改了值。

mode参数确定远程设备是否应发送写确认。待写入的characteristic必须支持相关写模式。特性的支持写模式由其WriteWriteNoResponse属性指示。

针对同一远程设备的所有描述符和特性写请求都被序列化。在同时发出多个写请求时,将使用队列。队列不会消除针对同一特性的重复写请求。例如,如果同一描述符被设置为值 A,然后立即设置为 B,这两个写请求将按给定顺序执行。

def stateChanged()

目前,无法使用蓝牙规范定义的签名或可靠写入。

只有当此服务处于ServiceDiscovered状态且属于服务时,才能写入特性。如果这些条件之一不成立,则会设置OperationError

def stateChanged()

尽管properties()报告了不可写入的属性,但调用此函数仍然会尝试写入硬件。同样,即使特性可能只支持WriteWithResponse,也会向硬件发送WriteWithoutResponse。如果硬件返回错误,则设置CharacteristicWriteError

外围设备角色

此调用导致在本地数据库中更新特性的值。

如果客户端当前已连接并且已启用特征的 notifications 或 indications,则将发送相应的信息。如果设备已启用特征的 notifications 或 indications,并且当前未连接,但与本地设备之间存在绑定,则在下一次重新连接时发送 notification 或 indication。

如果特性值的长度有限制,并且 newValue 不符合该限制,则行为未定义。

def stateChanged()

在外围模式中忽略 mode 参数。

writeDescriptor(descriptor, newValue)#
参数:

newValue 作为 descriptor 的值写入。确切的语义取决于关联控制器对象的角色。

中心地位

调用此函数会导致向远程设备发送写入请求。如果操作成功,将发射 descriptorWritten() 信号;否则将发射 DescriptorWriteError

所有针对同一远程设备的描述符和特性请求都是串行的。在同时发出多个写入请求时使用队列。该队列不会消除针对同一描述符的重复写入请求。例如,如果同一个描述符先被设置为值 A,然后立即设置为值 B,这两个写入请求将按给定顺序执行。

只有当此服务处于 ServiceDiscovered 状态且属于该服务时,才能写入描述符。如果这些条件中任何一个不成立,则设置 OperationError

外围角色

将值写入本地服务数据库。如果 newValue 的内容对于 descriptor 无效,则行为未定义。