Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este artigo demonstra como utilizar as APIs do Cliente Bluetooth Generic Attribute (GATT) para aplicações Windows.
Importante
Tem de declarar a capacidade "bluetooth" em Package.appxmanifest.
<Capabilities> <DeviceCapability Name="bluetooth" /> </Capabilities>
Visão geral
Podes usar as APIs no Windows. Devices.Bluetooth.GenericAttributeProfile espaço de nomes para aceder a dispositivos Bluetooth LE. Os dispositivos Bluetooth LE expõem a sua funcionalidade através de uma coleção de:
- Services
- Caraterísticas
- Descritores
Os serviços definem o contrato funcional do dispositivo LE e contêm um conjunto de características que definem o serviço. Essas características, por sua vez, contêm descritores que descrevem as características. Estes 3 termos são genericamente conhecidos como atributos de um dispositivo.
As APIs Bluetooth LE GATT expõem objetos e funções, em vez de acesso ao transporte bruto. As APIs GATT também permitem trabalhar com dispositivos Bluetooth LE com a capacidade de realizar as seguintes tarefas:
- Realizar descoberta de atributos
- Valores de atributo de leitura e escrita
- Registar um callback para o evento Characteristic ValueChanged
Para criar uma implementação útil, deve ter conhecimento prévio dos serviços GATT e das características que a aplicação pretende consumir e processar os valores característicos específicos de modo que os dados binários fornecidos pela API sejam transformados em dados úteis antes de serem apresentados ao utilizador. As APIs Bluetooth GATT expõem apenas as primitivas básicas necessárias para comunicar com um dispositivo Bluetooth LE. Para interpretar os dados, um perfil de aplicação deve ser definido, seja por um perfil padrão Bluetooth SIG, ou por um perfil personalizado implementado por um fornecedor de dispositivos. Um perfil cria um contrato vinculativo entre a aplicação e o dispositivo, quanto ao que os dados trocados representam e como os interpretar.
Para conveniência, o Bluetooth SIG mantém uma lista de perfis públicos disponíveis.
Procurar dispositivos nas proximidades
Existem dois métodos principais para consultar dispositivos próximos:
- DeviceWatcher em Windows. Devices.Enumeration
- BluetoothLEAdvertisementWatcher em Windows.Devices.Bluetooth.Advertisement
O segundo método é discutido em detalhe na documentação de Publicidade , por isso não será muito discutido aqui, mas a ideia básica é encontrar o endereço Bluetooth dos dispositivos próximos que satisfazem o Filtro de Publicidade em particular. Depois de ter o endereço, pode chamar BluetoothLEDevice.FromBluetoothAddressAsync para obter uma referência ao dispositivo.
Agora, voltando ao método DeviceWatcher. Um dispositivo Bluetooth LE é como qualquer outro dispositivo em Windows e pode ser consultado usando as APIs Enumeration. Use a classe DeviceWatcher e passe uma cadeia de consulta especificando os dispositivos a procurar:
// Query for extra properties you want returned
string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
DeviceWatcher deviceWatcher =
DeviceInformation.CreateWatcher(
BluetoothLEDevice.GetDeviceSelectorFromPairingState(false),
requestedProperties,
DeviceInformationKind.AssociationEndpoint);
// Register event handlers before starting the watcher.
// Added, Updated and Removed are required to get all nearby devices
deviceWatcher.Added += DeviceWatcher_Added;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Removed += DeviceWatcher_Removed;
// EnumerationCompleted and Stopped are optional to implement.
deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
// Start the watcher.
deviceWatcher.Start();
Depois de iniciar o DeviceWatcher, receberá DeviceInformation para cada dispositivo que satisfaz a consulta no handler para o evento Added para os dispositivos em questão. Para uma análise mais detalhada do DeviceWatcher, veja o exemplo completo no Github.
Liga-te ao dispositivo
Uma vez descoberto um dispositivo desejado, use o DeviceInformation.Id para obter o objeto Bluetooth LE Device para o dispositivo em questão:
private async Task ConnectDevice(DeviceInformation deviceInfo)
{
// Note: BluetoothLEDevice.FromIdAsync must be called from a UI thread because it may prompt for consent.
BluetoothLEDevice bluetoothLeDevice = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);
// ...
}
Por outro lado, eliminar todas as referências a um objeto BluetoothLEDevice de um dispositivo (e se nenhuma outra aplicação no sistema tiver referência ao dispositivo) acionará uma desconexão automática após um curto período de timeout.
bluetoothLeDevice.Dispose();
Se a aplicação precisar de aceder novamente ao dispositivo, basta recriar o objeto do dispositivo e aceder a uma característica (abordada na secção seguinte) para que o sistema operativo volte a ligar-se quando necessário. Se o dispositivo estiver nas proximidades, será possível aceder ao dispositivo; caso contrário, será devolvido o erro DeviceUnreachable.
Note
Criar um objeto BluetoothLEDevice chamando este método sozinho não inicia (necessariamente) uma ligação. Para iniciar uma ligação, defina o GattSession.MaintainConnection para true, ou chame um método de descoberta de serviço sem cache no BluetoothLEDevice, ou execute uma operação de leitura/escrita contra o dispositivo.
- Se o GattSession.MaintainConnection estiver definido como true, então o sistema espera indefinidamente por uma ligação e irá ligar-se quando o dispositivo estiver disponível. Não há nada que a tua aplicação tenha de aguardar, uma vez que GattSession.MaintainConnection é uma propriedade.
- Para descoberta de serviços e operações de leitura/escrita no GATT, o sistema espera um tempo finito mas variável. Pode demorar desde um instante até uma questão de minutos. Os fatores incluem o tráfego na pilha e o tempo que a solicitação está na fila. Se não houver outro pedido pendente e o dispositivo remoto estiver inacessível, o sistema esperará sete (7) segundos antes de expirar. Se houver outros pedidos pendentes, cada um dos pedidos na fila pode demorar sete (7) segundos a ser processado, por isso quanto mais longe o seu estiver para o fundo da fila, mais tempo vai esperar.
Atualmente, não pode cancelar o processo de ligação.
Enumerar serviços e características suportadas
Agora que tem um objeto BluetoothLEDevice, o próximo passo é descobrir que dados o dispositivo expõe. O primeiro passo para fazer isto é consultar serviços:
GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync();
if (result.Status == GattCommunicationStatus.Success)
{
var services = result.Services;
// ...
}
Uma vez identificado o serviço de interesse, o passo seguinte é consultar as características.
GattCharacteristicsResult result = await service.GetCharacteristicsAsync();
if (result.Status == GattCommunicationStatus.Success)
{
var characteristics = result.Characteristics;
// ...
}
O sistema operativo devolve uma lista ReadOnly de objetos GattCharacteristic sobre os quais pode então realizar operações.
Realizar operações de Leitura/Escrita sobre uma característica
A característica é a unidade fundamental da comunicação baseada em GATT. Contém um valor que representa um dado distinto no dispositivo. Por exemplo, a característica do nível da bateria tem um valor que representa o nível da bateria do dispositivo.
Leia as propriedades características para determinar que operações são suportadas:
GattCharacteristicProperties properties = characteristic.CharacteristicProperties
if(properties.HasFlag(GattCharacteristicProperties.Read))
{
// This characteristic supports reading from it.
}
if(properties.HasFlag(GattCharacteristicProperties.Write))
{
// This characteristic supports writing to it.
}
if(properties.HasFlag(GattCharacteristicProperties.Notify))
{
// This characteristic supports subscribing to notifications.
}
Se a read estiver disponível, pode ler o valor:
GattReadResult result = await selectedCharacteristic.ReadValueAsync();
if (result.Status == GattCommunicationStatus.Success)
{
var reader = DataReader.FromBuffer(result.Value);
byte[] input = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(input);
// Utilize the data as needed
}
Escrever para uma característica segue um padrão semelhante:
var writer = new DataWriter();
// WriteByte used for simplicity. Other common functions - WriteInt16 and WriteSingle
writer.WriteByte(0x01);
GattCommunicationStatus result = await selectedCharacteristic.WriteValueAsync(writer.DetachBuffer());
if (result == GattCommunicationStatus.Success)
{
// Successfully wrote to device
}
Tip
DataReader e DataWriter são indispensáveis ao trabalhar com os buffers brutos que se obtêm de muitas das APIs Bluetooth.
Subscreva para receber notificações
Certifique-se de que a característica suporta Indicate ou Notify (verifique as propriedades da característica para se certificar).
Indicate é considerado mais fiável porque cada evento de alteração de valor é acompanhado por um reconhecimento do dispositivo cliente.
Notify é mais prevalente porque a maioria das transações GATT privilegia a poupança de energia em vez de maximizar a fiabilidade. Em todo o caso, tudo isso é tratado na camada do controlador, por isso a aplicação não se envolve. Vamos referir-nos coletivamente a elas simplesmente como "notificações".
Há duas coisas a tratar antes de receber notificações:
- Escrever no Descritor de Configuração da Característica do Cliente (CCCD)
- Processar o evento Characteristic.ValueChanged
Escrever no CCCD indica ao dispositivo servidor que este cliente quer saber cada vez que esse valor característico muda. Para efetuar este procedimento:
GattCommunicationStatus status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.Notify);
if(status == GattCommunicationStatus.Success)
{
// Server has been informed of clients interest.
}
Agora, o evento ValueChanged de GattCharacteristic será acionado cada vez que o valor for alterado no dispositivo remoto. Só falta implementar o handler:
characteristic.ValueChanged += Characteristic_ValueChanged;
...
void Characteristic_ValueChanged(GattCharacteristic sender,
GattValueChangedEventArgs args)
{
// An Indicate or Notify reported that the value has changed.
var reader = DataReader.FromBuffer(args.CharacteristicValue)
// Parse the data however required.
}
Exemplos
Para um exemplo completo, consulte exemplo de Bluetooth Low Energy.
Windows developer