Android'de cihazları kontrol etme

Bir özelliğin komutu destekleyip desteklemediğini kontrol etme

Özellik komutu için destek de kontrol edilebilir. Bir komutun belirli bir cihazda desteklenip desteklenmediğini kontrol etmek için özellik düzeyindeki supports işlevini de kullanın.

Örneğin, bir cihazın Açık/Kapalı özelliğinin toggle komutunu destekleyip desteklemediğini kontrol etmek için:

// Check if the OnOff trait supports the toggle command.
if (onOffTrait.supports(OnOff.Command.Toggle)) {
  println("onOffTrait supports toggle command")
} else {
  println("onOffTrait does not support stateful toggle command")
}

Bir cihaza komut gönderme

Komut gönderme, bir özellikten durum özelliğini okumaya benzer. Cihazı açmak veya kapatmak için OnOff özelliğinin açma/kapatma komutunu kullanın. Bu komut, Google Home ekosistemi veri modelinde toggle() olarak tanımlanır. Bu yöntem, onOff değeri true ise false olarak, false ise true olarak değiştirir:

// Calling a command on a trait.
try {
  onOffTrait.toggle()
} catch (e: HomeException) {
  // Code for handling the exception
}

Tüm özellik komutları suspend işlevleridir ve yalnızca API tarafından bir yanıt döndürüldüğünde (ör. cihaz durumunun değiştiğini onaylama) tamamlanır. Komutlar, yürütme akışında bir sorun tespit edilirse istisna döndürebilir. Geliştirici olarak, bu istisnaları düzgün bir şekilde işlemek için bir try-catch bloğu kullanmalı ve hataların işlem yapılabilir olduğu durumlarda kullanıcılara ayrıntılı bilgi sunmalısınız. İşlenmemiş istisnalar, uygulama çalışma zamanını durdurur ve uygulamanızda kilitlenmelere neden olabilir.

Alternatif olarak, durumu açıkça ayarlamak için off() veya on() komutlarını kullanın:

onOffTrait.off()
onOffTrait.on()

Durumu değiştirmek için bir komut gönderdikten sonra, komut tamamlandığında Cihaz durumunu okuma bölümünde açıklandığı gibi durumu okuyarak uygulamanızda kullanabilirsiniz. Alternatif olarak, tercih edilen yöntem olan Durumu gözlemleme bölümünde açıklandığı gibi akışları kullanabilirsiniz.

Parametrelerle komut gönderme

Bazı komutlar, OnOff veya LevelControl özelliklerindekiler gibi parametreler kullanabilir:

// Turn off the light using the DyingLight effect.
onOffTrait.offWithEffect(
  effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight,
  effectVariant = 0u,
)
// Change the brightness of the light to 50%
levelControlTrait.moveToLevel(
  level = 127u.toUByte(),
  transitionTime = null,
  optionsMask = LevelControlTrait.OptionsBitmap(),
  optionsOverride = LevelControlTrait.OptionsBitmap(),
)

Bazı komutlarda, gerekli bağımsız değişkenlerden sonra gelen isteğe bağlı bağımsız değişkenler bulunur.

Örneğin, FanControl özelliği için step komutunun iki isteğe bağlı bağımsız değişkeni vardır:

val fanControlTraitFlow: Flow<FanControl?> =
  device.type(FanDevice).map { it.standardTraits.fanControl }.distinctUntilChanged()

val fanControl = fanControlTraitFlow.firstOrNull()

// Calling a command with optional parameters not set.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase)

// Calling a command with optional parameters.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase) { wrap = true }

Bir özelliğin bir özelliği destekleyip desteklemediğini kontrol etme

Bazı cihazlar Matter özelliğini destekleyebilir ancak belirli bir özelliği desteklemeyebilir. Örneğin, Matter ile eşlenen bir Cloud-to-cloud cihaz, her Matter özelliğini desteklemeyebilir. Bu gibi durumları ele almak için özelliğin belirli bir cihazda desteklenip desteklenmediğini kontrol etmek üzere özellik düzeyindeki supports işlevini ve özelliğin Attribute enum değerini kullanın.

Örneğin, bir cihazın Açık/Kapalı özelliğinin onOff özelliğini destekleyip desteklemediğini kontrol etmek için:

// Check if the OnOff trait supports the onOff attribute.
if (onOffTrait.supports(OnOff.Attribute.onOff)) {
  println("onOffTrait supports onOff state")
} else {
  println("onOffTrait is for a command only device!")
}

Bazı özellikler Matter spesifikasyonunda veya Cloud-to-cloud smart home şemasında boş değer alabilir. Bu özelliklerde, supports'e ek olarak isNullable kullanarak özelliğin döndürdüğü null değerinin cihazın bu değeri bildirmemesinden mi yoksa özelliğin değerinin aslında null olmasından mı kaynaklandığını belirleyebilirsiniz:

// Check if a nullable attribute is set or is not supported.
if (onOffTrait.supports(OnOff.Attribute.startUpOnOff)) {
  // The device supports startupOnOff, it is safe to expect this value in the trait.
  if (OnOff.Attribute.startUpOnOff.isNullable && onOffTrait.startUpOnOff == null) {
    // This value is nullable and set to null. Check the specification as to
    // what null in this case means
    println("onOffTrait supports startUpOnOff and it is null")
  } else {
    // This value is nullable and set to a value.
    println("onOffTrait supports startUpOnOff and it is set to ${onOffTrait.startUpOnOff}")
  }
} else {
  println("onOffTrait does not support startUpOnOff!")
}

Özellik özelliklerini güncelleme

Belirli bir özelliğin değerini değiştirmek istiyorsanız ve özelliğin hiçbir komutu bunu yapmıyorsa özellik, değerinin açıkça ayarlanmasını destekleyebilir.

Bir özelliğin değerinin değiştirilip değiştirilemeyeceği iki faktöre bağlıdır:

  • Özellik yazılabilir mi?
  • Özellik komutu göndermenin yan etkisi olarak özelliğin değeri değişebilir mi?

Bu bilgiler, özellikler ve özelliklerine ilişkin referans dokümanlarında sağlanır.

Bu nedenle, bir özelliğin değerinin nasıl değiştirilebileceğini belirleyen özellik kombinasyonları şunlardır:

  • Salt okunurdur ve diğer komutlardan etkilenmez. Bu, özelliğin değerinin değişmediği anlamına gelir. Örneğin, Switch özelliğinin currentPosition özelliği.

  • Salt okunurdur ve diğer komutlardan etkilenir. Bu, özelliğin değerinin yalnızca bir komut gönderilmesi sonucunda değişebileceği anlamına gelir. Örneğin, LevelControl Matter özelliğinin currentLevel özelliği salt okunurdur ancak değeri moveToLevel gibi komutlarla değiştirilebilir.

  • Yazılabilir ve diğer komutlardan etkilenmez. Bu, özelliğin update işlevini kullanarak özelliğin değerini doğrudan değiştirebileceğiniz anlamına gelir ancak özelliğin değerini etkileyecek komut yoktur. Örneğin, DoorLock özelliğinin WrongCodeEntryLimit özelliği.

  • Yazılabilir ve diğer komutlardan etkilenir. Bu, özelliğin update işlevini kullanarak özelliğin değerini doğrudan değiştirebileceğiniz ve özelliğin değerinin bir komut gönderilmesi sonucunda değişebileceği anlamına gelir. Örneğin, Thermostat özelliğinin occupiedCoolingSetpoint özelliği yazılabilir ve setpointRaiseLower komutuyla güncellenebilir.

Bir özelliğin değerini değiştirmek için update işlevinin kullanıldığı örnek

Bu örnekte, DoorLockTrait.WrongCodeEntryLimit özelliğinin değerinin nasıl açıkça ayarlanacağı gösterilmektedir.

Bir özellik değerini ayarlamak için özelliğin update işlevini çağırın ve işleve yeni değeri ayarlayan bir değiştirici işlev aktarın. Öncelikle özelliğin bir özelliği destekleyip desteklemediğini doğrulamak iyi bir uygulamadır.

Örneğin:

    var doorLockDevice = home.devices().list().first { device -> device.has(DoorLock) }

    val traitFlow: Flow<DoorLock?> =
      doorLockDevice.type(DoorLockDevice).map { it.standardTraits.doorLock }.distinctUntilChanged()

    val doorLockTrait: DoorLock = traitFlow.first()!!

    if (doorLockTrait.supports(DoorLock.Attribute.wrongCodeEntryLimit)) {
      val unused = doorLockTrait.update { setWrongCodeEntryLimit(3u) }
    }

Aynı anda birden fazla komut gönderme

Toplu Hale Getirme API'si, istemcinin tek bir yükte birden fazla Home API cihaz komutu göndermesine olanak tanır. Komutlar tek bir yükü gruplandırıp paralel olarak yürütülür. Bu, paralel düğümü kullanarak Home API otomasyonu oluşturmaya benzer (ör. Güneşin doğmasından önce perdeleri aç örneği). Ancak Gruplandırma API'si, Otomasyon API'sinden daha karmaşık ve gelişmiş davranışlara (ör. çalışma zamanında herhangi bir ölçüte göre cihazları dinamik olarak seçme) olanak tanır.

Bir gruptaki komutlar, birden fazla cihazda, birden fazla odada ve birden fazla yapıda birden fazla özelliği hedefleyebilir.

Komutları toplu olarak göndermek, cihazların işlemleri aynı anda gerçekleştirmesine olanak tanır. Komutlar ayrı isteklerde sırayla gönderildiğinde bu mümkün değildir. Toplu komutlar kullanılarak elde edilen davranış, geliştiricinin bir cihaz grubunun durumunu önceden belirlenmiş bir toplu durumla eşleşecek şekilde ayarlamasına olanak tanır.

Gruplandırma API'sini kullanma

Toplu API aracılığıyla komutları çağırırken üç temel adım vardır:

  1. Home.sendBatchedCommands() yöntemini çağırın.
  2. sendBatchedCommands() bloğunun gövdesinde, toplu işleme dahil edilecek komutları belirtin.
  3. Gönderilen komutların başarılı olup olmadığını görmek için sonuçlarını kontrol edin.

sendBatchedCommands() yöntemini çağırın

Home.sendBatchedCommands() yöntemini çağırın. Bu yöntem, arka planda özel bir toplu bağlamda bir lambda ifadesi oluşturur.

home.sendBatchedCommands() {

Toplu komutları belirtme

sendBatchedCommands() bloğunun gövdesinde toplu komutlar doldurun. Toplu olarak çalıştırılabilir komutlar, toplu bağlamda kullanılabilen mevcut Device API komutlarının "gölge" sürümleridir ve Batchable son eki eklenerek adlandırılır. Örneğin, LevelControl özelliğinin moveToLevel() komutunun moveToLevelBatchable() adlı bir karşılığı vardır.

Örnek:

  val response1 = add(command1)

  val response2 = add(command2)

Tüm komutlar toplu bağlama eklendikten ve yürütme bağlamdan çıktıktan sonra toplu işlem otomatik olarak gönderilir.

Yanıtlar DeferredResponse<T> nesnelerinde yakalanır.

DeferredResponse<T> örneklerinin tümü, Collection veya tanımladığınız bir veri sınıfı gibi herhangi bir türde bir nesnede toplanabilir. Yanıtları bir araya getirmek için seçtiğiniz nesne türü, sendBatchedCommands() tarafından döndürülür. Örneğin, toplu bağlam, bir Pair içinde iki DeferredResponse örneği döndürebilir:

  val (response1, response2) = homeClient.sendBatchedComamnds {
    val response1 = add(someCommandBatched(...))
    val response2 = add(someOtherCommandBatched(...))
    Pair(response1, response2)
  }

Alternatif olarak toplu bağlam, DeferredResponse örneklerini özel bir veri sınıfında döndürebilir:

  // Custom data class
  data class SpecialResponseHolder(
    val response1: DeferredResponse<String>,
    val response2: DeferredResponse<Int>,
    val other: OtherResponses
  )
  data class OtherResponses(...)

Her yanıtı kontrol edin

İlgili komutun başarılı olup olmadığını belirlemek için sendBatchedCommands() bloğunun dışındaki yanıtları kontrol edin. Bu işlem, DeferredResponse.getOrThrow() çağrılmasıyla yapılır. Bu işlev: - yürütülen komutun sonucunu döndürür veya - toplu işlem kapsamı tamamlanmamışsa ya da komut başarısız olduysa hata verir.

Yalnızca sendBatchedCommands() lambda kapsamının dışındaki sonuçları kontrol etmeniz gerekir.

Örnek

Evdeki tüm cihazları, herkesin uykuda olduğu gece için yapılandıran bir "iyi geceler" sahnesi oluşturmak üzere Gruplandırma API'sini kullanan bir uygulama oluşturmak istediğinizi varsayalım. Bu uygulama, ışıkları kapatır ve ön ile arka kapıları kilitler.

Göreve yaklaşmanın bir yolu:

val lightDevices: List<OnOffLightDevice>
val doorlockDevices: List<DoorLockDevice>

// Send all the commands
val responses: List<DeferredResponse<Unit>> = home.sendBatchedCommands {
  // For each light device, send a Batchable command to turn it on
  val lightResponses: List<DeferredResponse<Unit>> = lightDevices.map { lightDevice ->
    add(lightDevice.standardTraits.onOff.onBatchable())
  }

  // For each doorlock device, send a Batchable command to lock it
  val doorLockResponse: List<DeferredResponse<Unit>> = doorlockDevices.map { doorlockDevice ->
    add(doorlockDevice.standardTraits.doorLock.lockDoorBatchable())
  }

  lightResponses + doorLockResponses
}

// Check that all responses were successful
for (response in responses) {
  response.getOrThrow()
}