Bagikan melalui


Klien GATT Bluetooth

Artikel ini menunjukkan cara menggunakan API Klien Bluetooth Generic Attribute (GATT) untuk aplikasi Platform Windows Universal (UWP).

Penting

Anda harus mendeklarasikan kemampuan "bluetooth" di Package.appxmanifest.

<Capabilities> <DeviceCapability Name="bluetooth" /> </Capabilities>

API penting

Gambaran Umum

Pengembang dapat menggunakan API di namespace Windows.Devices.Bluetooth.GenericAttributeProfile untuk mengakses perangkat Bluetooth LE. Perangkat BLUETOOTH LE mengekspos fungsionalitasnya melalui kumpulan:

  • Layanan
  • Karakteristik
  • Deskriptor

Layanan menentukan kontrak fungsional perangkat LE dan berisi kumpulan karakteristik yang menentukan layanan. Karakteristik tersebut, pada gilirannya, berisi deskriptor yang menggambarkan karakteristiknya. 3 istilah ini secara umum dikenal sebagai atribut perangkat.

API Bluetooth LE GATT mengekspos objek dan fungsi, daripada akses ke transportasi mentah. GATT API juga memungkinkan pengembang untuk bekerja dengan perangkat Bluetooth LE dengan kemampuan untuk melakukan tugas-tugas berikut:

  • Melakukan penemuan atribut
  • Nilai atribut Baca dan Tulis
  • Mendaftarkan panggilan balik untuk peristiwa Characteristic ValueChanged

Untuk membuat implementasi yang berguna, pengembang harus memiliki pengetahuan sebelumnya tentang layanan GATT dan karakteristik yang ingin dikonsumsi aplikasi dan untuk memproses nilai karakteristik tertentu sehingga data biner yang disediakan oleh API diubah menjadi data yang berguna sebelum disajikan kepada pengguna. API GATT Bluetooth hanya mengekspos primitif dasar yang diperlukan untuk berkomunikasi dengan perangkat BLUETOOTH LE. Untuk menginterpretasikan data, profil aplikasi harus ditentukan, baik oleh profil standar Bluetooth SIG, atau profil kustom yang diterapkan oleh vendor perangkat. Profil membuat kontrak pengikatan antara aplikasi dan perangkat, tentang apa yang diwakili data yang ditukar dan cara menafsirkannya.

Untuk kenyamanan, Bluetooth SIG mempertahankan daftar profil publik yang tersedia.

Contoh

Untuk sampel lengkapnya, lihat Sampel Bluetooth Low Energy.

Kueri untuk perangkat terdekat

Ada dua metode utama untuk mengkueri perangkat terdekat:

Metode ke-2 dibahas panjang lebar dalam dokumentasi Iklan sehingga tidak akan banyak dibahas di sini tetapi ide dasarnya adalah menemukan alamat Bluetooth perangkat terdekat yang memenuhi Filter Iklan tertentu. Setelah memiliki alamat, Anda dapat memanggil BluetoothLEDevice.FromBluetoothAddressAsync untuk mendapatkan referensi ke perangkat.

Sekarang, kembali ke metode DeviceWatcher. Perangkat BLUETOOTH LE sama seperti perangkat lain di Windows dan dapat dikueri menggunakan API Enumerasi. Gunakan kelas DeviceWatcher dan berikan string kueri yang menentukan perangkat yang akan dicari:

// 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();

Setelah memulai DeviceWatcher, Anda akan menerima DeviceInformation untuk setiap perangkat yang memenuhi kueri di handler untuk peristiwa Ditambahkan untuk perangkat yang dimaksud. Untuk melihat lebih rinci tentang DeviceWatcher, lihat sampel lengkap di Github.

Menyambungkan ke perangkat

Setelah perangkat yang diinginkan ditemukan, gunakan DeviceInformation.Id untuk mendapatkan objek Perangkat LE Bluetooth untuk perangkat yang dimaksud:

async void 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);
    // ...
}

Di sisi lain, membuang semua referensi ke objek BluetoothLEDevice untuk perangkat (dan jika tidak ada aplikasi lain pada sistem yang memiliki referensi ke perangkat) akan memicu pemutusan sambungan otomatis setelah periode waktu habis yang kecil.

bluetoothLeDevice.Dispose();

Jika aplikasi perlu mengakses perangkat lagi, cukup buat ulang objek perangkat dan mengakses karakteristik (dibahas di bagian berikutnya) akan memicu OS untuk terhubung kembali jika perlu. Jika perangkat berada di dekatnya, Anda akan mendapatkan akses ke perangkat jika tidak, perangkat akan mengembalikan kesalahan DeviceUnreachable.

Catatan

Membuat objek BluetoothLEDevice dengan memanggil metode ini saja tidak (harus) memulai koneksi. Untuk memulai koneksi, atur GattSession.MaintainConnection ke true, atau panggil metode penemuan layanan yang tidak di-cache di BluetoothLEDevice, atau lakukan operasi baca/tulis terhadap perangkat.

  • Jika GattSession.MaintainConnection diatur ke true, maka sistem menunggu tanpa batas waktu untuk koneksi, dan akan terhubung ketika perangkat tersedia. Tidak ada yang perlu ditunggu oleh aplikasi Anda, karena GattSession.MaintainConnection adalah properti .
  • Untuk penemuan layanan dan operasi baca/tulis di GATT, sistem menunggu waktu terbatas tetapi variabel. Apa pun dari seketika hingga hitungan menit. Faktor-faktor termasuk lalu lintas pada tumpukan, dan seberapa antrean permintaan. Jika tidak ada permintaan lain yang tertunda, dan perangkat jarak jauh tidak dapat dijangkau, maka sistem akan menunggu selama tujuh (7) detik sebelum waktu habis. Jika ada permintaan lain yang tertunda, maka setiap permintaan dalam antrean dapat memakan waktu tujuh (7) detik untuk diproses, jadi semakin lanjut permintaan Anda ke bagian belakang antrean, semakin lama Anda akan menunggu.

Saat ini, Anda tidak dapat membatalkan proses koneksi.

Menghitung layanan dan karakteristik yang didukung

Sekarang setelah Anda memiliki objek BluetoothLEDevice, langkah selanjutnya adalah menemukan data apa yang diekspos perangkat. Langkah pertama untuk melakukan ini adalah mengkueri layanan:

GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync();

if (result.Status == GattCommunicationStatus.Success)
{
    var services = result.Services;
    // ...
}

Setelah layanan menarik diidentifikasi, langkah selanjutnya adalah mengkueri karakteristik.

GattCharacteristicsResult result = await service.GetCharacteristicsAsync();

if (result.Status == GattCommunicationStatus.Success)
{
    var characteristics = result.Characteristics;
    // ...
}

OS mengembalikan daftar ReadOnly objek GattCharacteristic yang kemudian dapat Anda lakukan operasi.

Melakukan operasi Baca/Tulis pada karakteristik

Karakteristiknya adalah unit dasar komunikasi berbasis GATT. Ini berisi nilai yang mewakili bagian data yang berbeda pada perangkat. Misalnya, karakteristik tingkat baterai memiliki nilai yang mewakili tingkat baterai perangkat.

Baca properti karakteristik untuk menentukan operasi apa yang didukung:

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.
}

Jika baca didukung, Anda dapat membaca nilainya:

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
}

Menulis ke karakteristik mengikuti pola yang sama:

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 dan DataWriter sangat diperlukan saat bekerja dengan buffer mentah yang Anda dapatkan dari banyak API Bluetooth.

Berlangganan pemberitahuan

Pastikan karakteristik mendukung Indikasikan atau Beri Tahu (periksa properti karakteristik untuk memastikan).

Menunjukkan dianggap lebih andal karena setiap peristiwa yang diubah nilai digabungkan dengan pengakuan dari perangkat klien. Pemberitahuan lebih umum karena sebagian besar transaksi GATT lebih memilih menghemat daya daripada sangat dapat diandalkan. Bagaimanapun, semua itu ditangani di lapisan pengontrol sehingga aplikasi tidak terlibat. Kami akan secara kolektif menyebutnya sebagai "pemberitahuan".

Ada dua hal yang harus diurus sebelum mendapatkan pemberitahuan:

  • Menulis ke Deskriptor Konfigurasi Karakteristik Klien (CCCD)
  • Menangani peristiwa Characteristic.ValueChanged

Menulis ke CCCD memberi tahu perangkat Server bahwa klien ini ingin mengetahui setiap kali nilai karakteristik tertentu berubah. Untuk melakukan ini:

GattCommunicationStatus status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
                        GattClientCharacteristicConfigurationDescriptorValue.Notify);
if(status == GattCommunicationStatus.Success)
{
    // Server has been informed of clients interest.
}

Sekarang, peristiwa ValueChanged GattCharacteristic akan dipanggil setiap kali nilai diubah pada perangkat jarak jauh. Yang tersisa hanyalah mengimplementasikan 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.
}