Android'de Home API'lerini kullanarak mobil uygulama oluşturma

1. Başlamadan önce

Google Home API'leri, Android geliştiricilerin Google Home ekosisteminden yararlanabileceği bir dizi kitaplık sunar. Geliştiriciler bu yeni API'leri kullanarak akıllı ev cihazlarını sorunsuz bir şekilde devreye alıp kontrol eden uygulamalar oluşturabilir.

Bu videoda, oluşturacağınız mobil uygulamanın kısa bir tanıtımı yapılmaktadır. Bu nedenle, codelab'i yaparken videoyu takip edin.

Google, Google Home API'lerini kullanarak çalışan bir örneğe erişmek isteyen geliştiriciler için Android örnek uygulaması sunar. Bu codelab, İzinler, Kullanıma Alma, Cihaz ve Yapı API'lerinin nasıl kullanılacağını açıklayan örnek uygulamanın bir dalına dayanmaktadır.

Ön koşullar

Neler öğreneceksiniz?

  • En iyi uygulamaları kullanarak Google Home API'lerini kullanan bir Android uygulaması oluşturma
  • Akıllı bir evi temsil etmek ve kontrol etmek için Cihaz ve Yapı API'lerini kullanma
  • Cihazları Google Home ekosistemine eklemek için devreye alma API'lerini kullanma

İsteğe bağlı: Ana Sayfanızı Kurma

Google Home API'lerini kullanmadan önce Google Home uygulamasını kullanarak Google Hesabınızda bir ev oluşturmanız ve birkaç cihaz eklemeniz gerekir. Bu bölümde, sanal akıllı ev cihazları sağlayan Google Home Playground kullanılarak bu işlemin nasıl yapılacağı açıklanmaktadır.

Web tarayıcınızda home-playground.withgoogle.com adresini açın, Google Hesabınızla oturum açın ve aşağıdaki emüle edilmiş cihazların görünüp görünmediğine bakın:

  • outlet1: On/Off plug
  • light2: Kısılabilir ışık
  • light3: Işığı açma/kapatma
  • ac3: Klima
  • blinds4: Window Covering
  • washer5: Smart washer

914d23a42b72df8f.png

Mobil cihazınızda Google Home uygulamasını açın, Ekle düğmesine dokunun ve Google Home ile çalışır'ı seçin. Listede "playground"u arayın, ardından "Google Home Playground" projesini seçip Devam'a dokunun.

e9ec257b0d9b1ed2.png29fd7416e274d216.pngd974573af0611fd8.png

Google Home Playground'da hesap yetkilendirme sayfası gösterilir. Yetkilendir veya Google ile oturum aç'a dokunun. Web uygulamasında yapılandırdığınız tüm cihazları mobil uygulamada görürsünüz.

13108a3a15440151.png8791a6d33748f7c8.png

Tüm cihazları seçin ve kurulum sürecini tamamlayın. Ana sayfaya döndüğünüzde, kullanılabilir tüm cihazları görürsünüz.

2b021202e6fd1750.png

Listede desteklenen cihazlar artık Google Home API'leriyle kullanılabilir.

2. Projenizi oluşturma

Aşağıdaki şemada, Home APIs uygulamasının mimarisi gösterilmektedir:

Android uygulaması için Home API'lerinin mimarisi

  • Uygulama Kodu: Geliştiricilerin, uygulamanın kullanıcı arayüzünü ve Home API'leri SDK'sı ile etkileşim kurma mantığını oluşturmak için üzerinde çalıştığı temel kod.
  • Home APIs SDK: Google tarafından sağlanan Home APIs SDK, akıllı ev cihazlarını kontrol etmek için GMSCore'daki Home APIs Service ile birlikte çalışır. Geliştiriciler, Home API'leri SDK'sı ile paketleyerek Home API'leriyle çalışan uygulamalar oluşturur.
  • Android'de GMSCore: Google Play Hizmetleri olarak da bilinen GMSCore, temel sistem hizmetleri sağlayan ve tüm sertifikalı Android cihazlarda temel işlevleri etkinleştiren bir Google platformudur. Google Play Hizmetleri'nin ev modülü, Ev API'leriyle etkileşimde bulunan hizmetleri içerir.

Home SDK'yı ayarlama

En son SDK'yı edinmek için SDK'yı ayarlama bölümünde belirtilen adımları uygulayın.

Örnek Uygulamayı Edinme

Örnek uygulamanın kaynak kodu GitHub'da mevcuttur. Bu codelab'de, örnek uygulamanın codelab-branch-1 dalındaki örnekler kullanılır.

Projeyi kaydetmek istediğiniz yere gidin ve codelab-branch-1 dalını klonlayın:

$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git

Örnek Uygulamayı Oluşturma

Uygulamayı oluşturma bölümündeki 1-5 arası adımları uygulayın.

32f2b3c0cd80fcf1.png

Uygulama telefonunuzda başarıyla çalıştırıldığında örnek uygulamanın ana sayfasını görürsünüz. Ancak OAuth kimlik doğrulamasını ayarlayıp eksik parçaları Permission API'yi kullanarak uygulayana kadar oturum açamazsınız.

3. Kimlik doğrulama ayarlama

Home API'leri, yapıdaki cihazlara erişim izni vermek için OAuth 2.0'ı kullanır. OAuth, kullanıcının giriş kimlik bilgilerini ifşa etmeden bir uygulamaya veya hizmete izin vermesine olanak tanır.

İzin ekranını yapılandırmak için OAuth kullanıcı rızası ekranını ayarlama bölümündeki talimatları uygulayın. En az bir test hesabı oluşturduğunuzdan emin olun.

Ardından, uygulama için kimlik bilgileri oluşturmak üzere OAuth kimlik bilgilerini ayarlama bölümündeki talimatları uygulayın.

4. İlk kullanıma hazırlama ve izinleri işleme

Bu bölümde, Permissions API'yi kullanarak eksik parçaları tamamlayarak SDK'yı nasıl başlatacağınızı ve kullanıcı izinlerini nasıl işleyeceğinizi öğreneceksiniz.

Desteklenen Türleri ve Özellikleri Tanımlama

Uygulama geliştirirken uygulamanın hangi cihaz türlerini ve özelliklerini destekleyeceğini açıkça belirtmeniz gerekir. Örnek uygulamada bunu, HomeApp.kt içindeki yardımcı nesnede statik listeler tanımlayarak yaparız. Bu listelere daha sonra gerektiğinde uygulama genelinde referans verilebilir:

companion object {

  // List of supported device types by this app:
  val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
    OnOffLightDevice,
    DimmableLightDevice,

  // ...
  )
  // List of supported device traits by this app:
  val supportedTraits: List<TraitFactory<out Trait>> = listOf(
  OnOff,
  LevelControl,
  // ...
  )
}

Desteklenen tüm cihaz türlerini ve özellikleri görmek için Desteklenen cihaz türleri ve Android'de Özellik Dizini başlıklı makalelere bakın.

İzni isteyen kaynak kodu etkinleştirmek için HomeApp.kt kaynak dosyasındaki 4.1.1 ve 4.1.2 adımlarını yorumdan çıkarın.

companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
// TODO: 4.1.1 - Non-registered device types will be unsupported
//             ContactSensorDevice,
//             ColorTemperatureLightDevice,
//             DimmableLightDevice,
//             ExtendedColorLightDevice,
//             GenericSwitchDevice,
//             GoogleDisplayDevice,
//             GoogleTVDevice,
//             OccupancySensorDevice,
//             OnOffLightDevice,
//             OnOffLightSwitchDevice,
//             OnOffPluginUnitDevice,
//             OnOffSensorDevice,
//             RootNodeDevice,
//             SpeakerDevice,
//             ThermostatDevice,
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
// TODO: 4.1.2 - Non-registered traits will be unsupported
//             AreaAttendanceState,
//             AreaPresenceState,
//             Assistant,
//             AssistantBroadcast,
//             AssistantFulfillment,
//             BasicInformation,
//             BooleanState,
//             OccupancySensing,
//             OnOff,
//             Notification,
//             LevelControl,
//             TemperatureControl,
//             TemperatureMeasurement,
//             Thermostat,
//             Time,
//             Volume,
        )
}

HomeClient nesnesini başlatma

Home API'lerini kullanan tüm uygulamalar, API'lerle etkileşim kurmak için kullanılan ana arayüz olan bir HomeClient nesnesi başlatır. Bu nesneyi HomeApp (HomeApp.kt) sınıfının başlatıcısında hazırlıyoruz.

// Registry to record device types and traits used in this app:
val registry = FactoryRegistry(
  types = supportedTypes,
  traits = supportedTraits
)
// Configuration options for the HomeClient:
val config = HomeConfig(
  coroutineContext = Dispatchers.IO,
  factoryRegistry = registry
)
// Initialize the HomeClient, which is the primary object to use all Home APIs:
homeClient = Home.getClient(context = context, homeConfig = config)

Öncelikle, daha önce tanımladığımız desteklenen türleri ve özellikleri kullanarak bir FactoryRegistry oluştururuz. Ardından, bu kayıt defterini kullanarak API'leri çalıştırmak için gereken yapılandırmayı içeren bir HomeConfig başlatırız. Ardından, HomeClient örneğini edinmek için Home.getClient(...) çağrısını kullanırız.

Home API'lerle olan tüm etkileşimlerimiz bu HomeClient nesnesi üzerinden gerçekleşir.

Permissions API'yi kullanma

Ev API'leri için kullanıcı kimlik doğrulaması, Permissions API aracılığıyla yapılır. Örnek uygulamanın PermissionsManager.kt kaynak dosyasında, kullanıcı kimlik doğrulaması için kod bulunur. Örnek Uygulama için izinleri etkinleştirmek üzere checkPermissions(...) ve requestPermissions(...) işlevlerinin içeriğindeki yorum işaretini kaldırın.

Kaydolma:

homeClient.registerActivityResultCallerForPermissions(activity)

Başlatılıyor:

try {
    val result: PermissionsResult
    result = homeClient.requestPermissions(forcePermissionFlow = ForcePermissionFlow.FORCE_LAUNCH)
    when (result.status) {
        PermissionsResultStatus.SUCCESS -> // Success Case
        PermissionsResultStatus.CANCELLED -> // User Cancelled
        PermissionsResultStatus.ERROR -> // Some Error
else -> // Unsupported Case
    }
}
catch (e: HomeException) { ... }

Kontrol ediliyor:

try {
    val state: PermissionsState
    state = homeClient.hasPermissions().first { state ->
        state != PermissionsState.PERMISSIONS_STATE_UNINITIALIZED
    }
    when (state) {
        PermissionsState.GRANTED -> // Signed In
        PermissionsState.NOT_GRANTED -> // Not Signed In
        PermissionsState.PERMISSIONS_STATE_UNAVAILABLE -> // ...
        PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> // ...
else -> // Unsupported case
    }
}
catch (e: HomeException) { ... }

Abone olma:

       homeClient.hasPermissions().collect( { state ->
// Track the changes on state
        } )

İzinleri isteyen kodu etkinleştirmek için PermissionsManager.kt bölümünde 4.3.1. adımı yorumdan çıkarın:

fun requestPermissions() {
    scope.launch {
    try {
// TODO: 4.3.1 - Request the permissions from the Permissions API
//                 // Request permissions from the Permissions API and record the result:
//                 val result: PermissionsResult = client.requestPermissions(forceLaunch = true)
//                 // Adjust the sign-in status according to permission result:
//                 if (result.status == PermissionsResultStatus.SUCCESS)
//                     isSignedIn.emit(true)
//                 // Report the permission result:
//                 reportPermissionResult(result)
    }
    catch (e: HomeException) { MainActivity.showError(this, e.message.toString()) }
    }
}

Şimdi adımları uygulayarak uygulamayı telefonunuzda çalıştırın ve izinleri verin. Aşağıdaki akışı görmeniz gerekir:

c263dcee4e945bf1.png f518cfd1fdb8a9d8.png 59937372f28c472f.png 383073ae57d2ced4.png 89f774a2ba6898ae.png

"Yükleniyor" mesajı hiçbir zaman kaybolmuyor ancak bunun nedeni, yapıyı ve cihazları okuyan kodu uygulamamış olmamızdır. Bu işlemi bir sonraki bölümde yapacağız.

5. Veri modelini anlama

Home API'lerinde Veri Modeli şu öğelerden oluşur:

  • Structure, odalar ve cihazlar içeren bir evi temsil eder.
  • Room, bir yapının parçasıdır ve cihazları içerir.
  • Cihazlar (HomeDevice olarak tanımlanır) bir yapıya (veya eve) ya da yapıdaki bir odaya atanabilir.
  • Cihazlar bir veya daha fazla DeviceType örneğinden oluşur.
  • DeviceType, Trait örnekten oluşur.
  • Trait, Attribute örneklerinden (okuma/yazma için), Command örneklerinden (özellikleri kontrol etmek için) ve Event örneklerinden (geçmiş değişikliklerin kayıtlarını okumak veya kaydetmek için) oluşur.
  • Automation örnekleri bir yapının parçasıdır ve evdeki görevleri otomatikleştirmek için ev meta verilerini ve cihazlarını kullanır.

76d35b44d5a8035e.png

Bu bölümde, ev yapılarınızı, odalarınızı, cihazlarınızı vb. ayrıştırıp oluşturmak için Structure API'nin nasıl kullanılacağını gösteren kaynak kodu geliştirmeyi öğreneceksiniz.

Yapıları okuma

Home API'lerinin tasarımı, veri modeli nesnelerini (ör. Structure, HomeDevice vb.) yayınlamak için Kotlin Flow'lara dayanır. Geliştiriciler, nesnede bulunan tüm nesneleri (örneğin, Structure, Room vb.) almak için Flow abone olurlar.

Tüm yapıları almak için yapı akışı döndüren structures() işlevini çağırın. Ardından, kullanıcının sahip olduğu tüm yapıları almak için akışta liste işlevini çağırın.

// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
    homeClient.structures()   // HomeObjectsFlow<Structure>
    .list()                   // Set<Structure>

Uygulama mimarisi kılavuzu, uygulama veri akışını ve durum yönetimini iyileştirmek için modern bir tepkisel programlama yaklaşımının benimsenmesini önemle tavsiye eder.

Örnek Uygulama'nın Reactive kodlama stiline nasıl uyduğu aşağıda açıklanmıştır:

  • Görünüm modelleri (durum bilgisi depolayıcı olarak StructureViewModel ve DeviceViewModel gibi), değer değişikliklerini almak ve en son durumları korumak için Home APIs SDK'sındaki akışlara abone olur.
  • Görünümler (ör. StructureView ve DeviceView), durumları almak ve kullanıcı arayüzünü bu değişiklikleri yansıtacak şekilde oluşturmak için görünüm modellerine abone olur.
  • Bir kullanıcı bir görünümdeki düğmeyi (örneğin, bir ışık cihazının "Açık" düğmesi) tıkladığında, etkinlikler görünüm modelinin işlevlerini tetikler. Bu işlevler, yanıt veren Home API işlevlerini (örneğin, OnOff özelliğinin On komutu) çağırır.

HomeAppViewModel.kt bölümündeki 5.1.1. adımda, collect() işlevini çağırarak yapı değişikliği etkinliklerine abone oluyoruz. Yapılar API yanıtı tarafından döndürülen ve StructureViewModel's StateFlow içinde sunulan structureSet bölümünün yorumunu kaldırın. Bu izin, uygulamanın yapı durumundaki değişiklikleri izlemesine olanak tanır:

   private suspend fun subscribeToStructures() {
// TODO: 5.1.1 - Subscribe the structure data changes
// // Subscribe to structures returned by the Structures API:
// homeApp.homeClient.structures().collect { structureSet ->
//     val structureVMList: MutableList<StructureViewModel> = mutableListOf()
//     // Store structures in container ViewModels:
//     for (structure in structureSet) {
//         structureVMList.add(StructureViewModel(structure))
//     }
//     // Store the ViewModels:
//     structureVMs.emit(structureVMList)
//
//     // If a structure isn't selected yet, select the first structure from the list:
//     if (selectedStructureVM.value == null && structureVMList.isNotEmpty())
//         selectedStructureVM.emit(structureVMList.first())
//
// }
}

DevicesView.kt içinde uygulama, yapı verileri değiştiğinde kullanıcı arayüzünün yeniden oluşturulmasını tetikleyen StructureViewModel'sStateFlow, öğesine abone olur. Yapı listesini açılır menü olarak oluşturmak için 5.1.2. adımındaki kaynak kodunun yorum işaretini kaldırın:

   val structureVMs: List<StructureViewModel> = homeAppVM.structureVMs.collectAsState().value
...
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
// TODO: 5.1.2 - Show list of structures in DropdownMenu
//  for (structure in structureVMs) {
//      DropdownMenuItem(
//          text = { Text(structure.name) },
//          onClick = {
//              scope.launch { homeAppVM.selectedStructureVM.emit(structure) }
//              expanded = false
//          }
//      )
//  }
}
...

Uygulamayı tekrar çalıştırın. Ok simgesine dokunduğunuzda menüyü görürsünüz:

f1fc2be1cb6436b6.png

Yapıyı ayrıştırma

Bir sonraki adım, bir yapıdaki ev nesnelerini geçmektir. Yapıdaki odaları alma:

val rooms: Set<Room>
rooms = structure.rooms().list()

Ardından, cihazları almak için odaları dolaşabilirsiniz:

val devices: Set<HomeDevice>
devices = room.devices().list()

Önemli: Home API'leri veri modelinde, bir yapı odaya atanmamış cihazlar içerebilir. Bu nedenle, odası olmayan cihazları da uygulamanıza eklediğinizden emin olun:

val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()

for (device in structure.devices().list())
if (device.roomId == null)
  devicesWithoutRooms.add(device)

Yine mevcut örnek kodda, en son Room ve Device listesini almak için bir akışa abone oluyoruz. StructureViewModel.kt kaynak dosyasındaki 5.2.1 ve 5.2.2 adımlarındaki kodu kontrol edin ve oda verilerine aboneliği etkinleştirmek için yorum satırı yapmayın:

val roomVMs : MutableStateFlow<List<RoomViewModel>>
val deviceVMs : MutableStateFlow<List<DeviceViewModel>>
val deviceVMsWithoutRooms : MutableStateFlow<List<DeviceViewModel>>
private suspend fun subscribeToRooms() {
// TODO: 5.2.1 - Subscribe the room data changes
//   // Subscribe to changes on rooms:
//   structure.rooms().collect { roomSet ->
//       val roomVMs = mutableListOf<RoomViewModel>()
//       // Store rooms in container ViewModels:
//       for (room in roomSet) {
//           roomVMs.add(RoomViewModel(room))
//       }
//       // Store the ViewModels:
//       this.roomVMs.emit(roomVMs)
//   }
}
private suspend fun subscribeToDevices() {
// TODO: 5.2.2 - Subscribe the device data changes in a structure
//   // Subscribe to changes on devices:
//   structure.devices().collect { deviceSet ->
//       val deviceVMs = mutableListOf<DeviceViewModel>()
//       val deviceWithoutRoomVMs = mutableListOf<DeviceViewModel>()
//       // Store devices in container ViewModels:
//       for (device in deviceSet) {
//           val deviceVM = DeviceViewModel(device)
//           deviceVMs.add(deviceVM)
//           // For any device that's not in a room, additionally keep track of a separate list:
//           if (device.roomId == null)
//               deviceWithoutRoomVMs.add(deviceVM)
//       }
//       // Store the ViewModels:
//       this.deviceVMs.emit(deviceVMs)
//       deviceVMsWithoutRooms.emit(deviceWithoutRoomVMs)
//   }
    }

Oda listesini menü olarak oluşturmak için DevicesView.kt kaynak dosyasında 5.2.3 ve 5.2.4 adımlarındaki yorum işaretini kaldırın:

val selectedRoomVMs: List<RoomViewModel> =
selectedStructureVM.roomVMs.collectAsState().value
...
for (roomVM in selectedRoomVMs) {
// TODO: 5.2.3 - Render the list of rooms
//   RoomListItem(roomVM)
// TODO: 5.2.4 - Render the list of devices in a room
//   val deviceVMsInRoom: List<DeviceViewModel> = roomVM.deviceVMs.collectAsState().value
//
//   for (deviceVM in deviceVMsInRoom) {
//       DeviceListItem(deviceVM, homeAppVM)
//   }
}

Cihazlarınızı edindiğinize göre, şimdi de bu cihazlarla nasıl çalışacağımızı öğreneceğiz.

e715ddda50e04839.png

6. Cihazlarla çalışma

Home API'leri, cihazı ve özelliklerini yakalamak için HomeDevice nesnesini kullanır. Geliştiriciler, cihaz özelliklerine abone olabilir ve bunları uygulamalarında akıllı ev cihazlarını temsil etmek için kullanabilir.

Cihaz durumlarını okuma

HomeDevice nesnesi, cihaz adı veya bağlantı durumu gibi bir dizi statik değer sunar. Geliştirici olarak, cihazı aldıktan kısa süre sonra API'lerden şunları alabilirsiniz:

val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
    device.sourceConnectivity.connectivityState

Cihaz özelliklerini almak için HomeDevice öğesinden türleri ve özellikleri almanız gerekir. Bunu yapmak için cihaz türü akışına aşağıdaki şekilde abone olabilir ve özellikleri cihaz türlerinden alabilirsiniz:

device.types().collect { typeSet ->
var primaryType : DeviceType = UnknownDeviceType()
for (typeInSet in typeSet)
if (typeInSet.metadata.isPrimaryType)
                    primaryType = typeInSet
            val traits: List<Trait> = mutableListOf()
for (trait in primaryType.traits())
if (trait.factory in myTraits)
                    traits.add(trait)
for (trait in traits)
                parseTrait(trait, primaryType)
        }

Her cihaz, desteklenen bir dizi DeviceType (paketlenmiş özellikler) içerir. Bu özellikleri device.types() kullanarak alabilirsiniz. Bu cihaz türleri, type.traits() kullanılarak alınabilen özellikler içerir. Her cihaz, türlerinden birini birincil tür olarak işaretler (type.metadata.isPrimaryType kullanılarak kontrol edilebilir). Uygulamanızda bu türü temsil etmeniz gerekir. Kullanıcılara eksiksiz bir deneyim sunmak için döndürülen tüm türleri geçmenizi ve size sunulan tüm özellikleri entegre etmenizi öneririz.

Bir özellik aldığınızda, değerleri yorumlamak için aşağıdaki gibi bir işlev kullanarak ayrıştırabilirsiniz:

fun <T : Trait?> parseTrait(trait : T, type: DeviceType) {
    val status : String = when (trait) {
        is OnOff -> { if (trait.onOff) "On" else "Off" }
        is LevelControl -> { trait.currentLevel.toString() }
        is BooleanState -> {
            when (type.factory) {
                ContactSensorDevice -> {
if (trait.stateValue) "Closed"
else "Open"
                }
else -> ...
            }
        }
else -> ...
    }
}

Bir özelliğin neyi temsil ettiğinin, özelliği içeren cihaz türüne bağlı olarak değişebileceğini (önceki örnekteki BooleanState bölümüne bakın) unutmayın. Bu nedenle, özelliklerin neyi temsil ettiğini anlamak için her cihaz türünün bağlamını bilmeniz gerekir.

Durumları almak için DeviceViewModel.kt kaynak dosyasında 6.1.1 ve 6.1.2 adımlarındaki yorum işaretini kaldırın:

private suspend fun subscribeToType() {
// Subscribe to changes on device type, and the traits/attributes within:
device.types().collect { typeSet ->
// Container for the primary type for this device:
var primaryType : DeviceType = UnknownDeviceType()
...
// TODO: 6.1.1 - Determine the primary type for this device
//       // Among all the types returned for this device, find the primary one:
//       for (typeInSet in typeSet)
//           if (typeInSet.metadata.isPrimaryType)
//               primaryType = typeInSet
//
//       // Optional: For devices with a single type that did not define a primary:
//       if (primaryType is UnknownDeviceType && typeSet.size == 1)
//           primaryType = typeSet.first()
// Container for list of supported traits present on the primary device type:
val supportedTraits: List<Trait> = getSupportedTraits(primaryType.traits())
...
}
fun getSupportedTraits(traits: Set<Trait>) : List<Trait> {
           val supportedTraits: MutableList<Trait> = mutableListOf()
// TODO: 6.1.2 - Get only the supported traits for this device
//   for (trait in traits)
//       if (trait.factory in HomeApp.supportedTraits)
//           supportedTraits.add(trait)
return supportedTraits
}

Adı ve durumu da dahil olmak üzere bir OnOff özelliğini String olarak oluşturmak için DeviceView.kt dosyasında 6.1.3. adımın yorumunu kaldırın:

Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
// TODO: 6.1.3 - Render controls based on the trait type
// Column (Modifier.fillMaxWidth()) {
//     Text(trait.factory.toString(), fontSize = 20.sp)
//     Text(DeviceViewModel.getTraitStatus(trait, type), fontSize = 16.sp)
// }
...
}
is LevelControl -> {
      ...
  }
   is BooleanState -> {
      ...
  }
   is OccupancySensing -> {
      ...
  }
  ...
}

Uygulamayı şimdi desteklenen cihaz türleriyle (ör. ışık cihazı) çalıştırırsanız tüm cihazların güncel durumları gösterilir.

1bd8b3b2796c4c7a.png

Cihaz komutları verme

Home API'ler, cihazlara komut göndermek için Trait nesnelerinde (ör. trait.on() veya trait.moveToLevel(...)) kolaylık sağlayan işlevler sunar:

fun <T : Trait?> issueCommand(trait : T) {
     when (trait) {
         is OnOff -> {
// trait.on()
// trait.off()
   }
   is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
        }
    }
}

İpucu: Özelliğin türünü belirledikten sonra Android Studio'nun otomatik tamamlama özelliğini kullanarak özellikle etkileşimde bulunmak için hangi işlemlerin kullanılabildiğini görebilirsiniz.

Uygulamaya işlevsel kontroller eklemek için DeviceView.kt içinde 6.2.1. adımı yorumdan çıkarın:

Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
                ....
// TODO: 6.2.1 - Render controls based on the trait type
//   Switch (checked = (trait.onOff == true), modifier = Modifier.align(Alignment.CenterEnd),
//       onCheckedChange = { state ->
//           scope.launch { if (state) trait.on() else trait.off() }
//       },
//       enabled = isConnected
//   )
}

Uygulamayı şimdi çalıştırırsanız gerçek hayattaki fiziksel cihazları kontrol etmenize izin vermesi gerekir.

Ampulünüzdeki Açma/Kapama kontrolüne dokunduğunuzda cihaz açılır.

c8ed3ecf5031546e.png

Cihazları kontrol etme hakkında daha fazla bilgi için Android'de cihazları kontrol etme başlıklı makaleyi inceleyin.

7. Cihazlara hizmete alma

Commissioning API, geliştiricilerin Google Home ekosistemine cihaz eklemesine ve bu cihazların Home API'leri kullanılarak kontrol edilmesini sağlamasına olanak tanır. Yalnızca Matter cihazlar desteklenir. Bu bölümde, uygulamalarınızda cihaz devreye almayı nasıl etkinleştirebileceğinizi ele alacağız.

Bu bölüme başlamadan önce aşağıdaki ön koşulların karşılandığından emin olun:

Devreye alma için QR kodu olan fiziksel bir Matter cihazınız varsa Devreye alma API'sini etkinleştirme bölümüne geçebilirsiniz. Aksi takdirde, Matter Virtual Device uygulamasını (MVD) kullanarak komisyonlu sanal cihazlar oluşturma konusunu ele aldığımız sonraki bölüme geçin.

İsteğe bağlı: Matter ile devreye alınabilir bir cihaz hazırlayın

Matter'da komisyon alınabilir bir cihaz hazırlamanın en basit yolu, Matter Virtual Device (MVD) uygulaması tarafından sağlanan bir emüle edilmiş cihazı kullanmaktır.

MVD'yi yükleyip güvenlik duvarını ayarladıktan sonra MVD'yi çalıştırın:

b20283893073ac1b.png

OnOff cihazı oluşturun. Henüz devreye alınmadığını fark edin. Bu codelab'de daha sonra devreye alacaksınız.

5f4855b808312898.png

Commissioning API'yi etkinleştirme

Commissioning API, uygulamanın Etkinliği dışında çalıştığı için devreye alma işleminin diğer Home API'lerinden farklı şekilde ele alınması gerekir. Uygulamanızı kullanıma hazırlamak için iki değişkene ihtiyacınız vardır.

Bir değişken ActivityResultLauncher'dır. Bu değişken, görevlendirme amacını göndermek ve sonuç geri çağırmasını yönetmek için kullanılır. Diğer değişken ise CommissioningResult'dır. Bu değişken, görevlendirme sonucunu depolamak için kullanılan nesnedir. Komisyonu nasıl ayarlayacağınızla ilgili aşağıdaki örneğe bakın:

var launcher: ActivityResultLauncher<IntentSenderRequest>
lateinit var commissioningResult: CommissioningResult?
launcher = activity.registerForActivityResult(StartIntentSenderForResult()) { result ->
try {
  commissioningResult = CommissioningResult.fromIntentSenderResult(
      result.resultCode, result.data)
  } catch (exception: ApiException) {
// Catch any issues
 }
}

Devreye alma akışınız ayarlandıktan sonra devreye alma amacınızı oluşturup önceki örnekte oluşturduğumuz başlatıcıyı kullanarak başlatırsınız. Niyet ve başlatıcıyı aşağıdaki gibi özel bir işleve yerleştirmenizi öneririz. Özel bir işlev, kullanıcı isteğine bağlı olarak bir kullanıcı arayüzü öğesine (ör. +Cihaz Ekle düğmesi) bağlanabilir ve çağrılabilir:

fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
  scope.launch {
    // Create a commissioning request to store the device in Google's Fabric:
    val request = CommissioningRequest.builder()
      .setStoreToGoogleFabric(true)
      .setOnboardingPayload(payload)
      .build()
    // Initialize client and sender for commissioning intent:
    val client: CommissioningClient = Matter.getCommissioningClient(context)
    val sender: IntentSender = client.commissionDevice(request).await()
    // Launch the commissioning intent on the launcher:
    launcher.launch(IntentSenderRequest.Builder(sender).build())
  }
}

Devreye alma özelliğini etkinleştirmek ve örnek uygulamada +Cihaz Ekle düğmesinin çalışmasını sağlamak için CommissioningManager.kt bölümündeki 7.1.1 adımının yorumunu kaldırın.

// Called by +Add Device button in DeviceView.kt
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
// TODO: 7.1.1 - Launch the commissioning intent
// scope.launch {
//     // Create a commissioning request to store the device in Google's Fabric:
//     val request = CommissioningRequest.builder()
//         .setStoreToGoogleFabric(true)
//         .setOnboardingPayload(payload)
//         .build()
//     // Initialize client and sender for commissioning intent:
//     val client: CommissioningClient = Matter.getCommissioningClient(context)
//     val sender: IntentSender = client.commissionDevice(request).await()
//     // Launch the commissioning intent on the launcher:
//     launcher.launch(IntentSenderRequest.Builder(sender).build())
// }
}

Bu işlevi çalıştırmak, aşağıdaki ekran görüntüsüne benzeyen bir ekranı göstermesi gereken devreye alma akışını başlatır:

baae45588f460664.png

Kullanıma alma akışını anlama

Hazır hale getirme akışı, kullanıcıya cihazı Google Hesabı'na ekleme konusunda yol gösteren bir dizi ekran içerir:

2fb0404820d4a035.png 3cbfa8ff9cfd5ee4.png a177c197ee7a67bf.png 3fdef24672c77c0.png dec8e599f9aa119.png

Kullanıcılar, Matter cihazlarındaki QR kodlarını taramak için kullanabilecekleri bir QR kodu tarayıcıyla karşılaşır. Ardından, kullanıcı sözleşmesinin gösterilmesi, cihaz keşfi ve devreye alma ile cihaza ad verme işlemleri gerçekleştirilir. Akış tamamlandığında odak tekrar uygulamaya döner ve önceki bölümde oluşturduğumuz geri çağırma işlevinde komisyon sonucu iletilir.

Commissioning API'lerinin bir avantajı, kullanıcı deneyimi akışının SDK tarafından yönetilmesidir. Bu sayede geliştiriciler çok hızlı bir şekilde çalışmaya başlayabilir. Bu sayede kullanıcılar, farklı uygulamalarda cihaz eklerken tutarlı bir deneyim yaşar.

Devreye alma API'si hakkında daha fazla bilgi edinmek için Android'de devreye alma API'si başlıklı makaleyi inceleyin.

8. Tebrikler!

Tebrikler! Google Home API'lerini kullanarak Android uygulamasını başarıyla oluşturdunuz. Bu codelab boyunca İzinler, Cihazlar, Yapılar ve Kullanıma Alma API'lerini incelediniz. Bir sonraki codelab olan Android'de Home API'lerini kullanarak gelişmiş otomasyonlar oluşturma Codelab'inde, otomasyon ve keşif API'lerini inceleyip uygulamayı tamamlayacağız.

Google Home ekosistemindeki cihazları yaratıcı bir şekilde kontrol eden uygulamalar geliştirmekten keyif alacağınızı umuyoruz.

Sonraki adımlar