Android'de cihazları kontrol etme

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

Bir özellik komutu için de destek 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çma/Kapama özelliği 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")
}

Cihaza komut gönderme

Komut göndermek, bir özellikten durum özelliği okumaya benzer. Cihazı açmak veya kapatmak için Google Home ekosistem veri modelinde toggle() olarak tanımlanan OnOff özelliğiyle ilişkili Toggle komutunu kullanın. 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ği onaylandığında) tamamlanır. Yürütme akışında bir sorun algılanırsa komutlar istisna döndürebilir. Geliştirici olarak, bu istisnaları düzgün şekilde işlemek ve hataların düzeltilebildiği durumlarda kullanıcılara ayrıntılı bilgi sunmak için bir try-catch bloğu kullanmanız gerekir. İşlenmeyen 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ığı şekilde durumu okuyarak uygulamanızda işleyebilirsiniz. Alternatif olarak, tercih edilen yöntem olan Durumu gözlemleme bölümünde açıklandığı şekilde akışları kullanın.

Parametrelerle komut gönderme

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

offWithEffect

// Turn off the light using the DyingLight effect.
onOffTrait.offWithEffect(
  effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight,
  effectVariant = 0u,
)

moveToLevel

// Change the brightness of the light to 50%
levelControlTrait.moveToLevel(
  level = 127u.toUByte(),
  transitionTime = null,
  optionsMask = LevelControlTrait.OptionsBitmap(),
  optionsOverride = LevelControlTrait.OptionsBitmap(),
)

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

Örneğin, FanControl trait 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, Cloud-to-cloud cihazı Matter ile eşlenmişse 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üzeyinde supports işlevini ve özelliğin Attribute enum'unu kullanın.

Örneğin, bir cihazın On/Off özelliği için 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 atanabilir. Bu özellikler için, özellik tarafından döndürülen null değerinin, cihazın bu değeri bildirmemesinden mi yoksa özelliğin değerinin gerçekten null olmasından mı kaynaklandığını belirleyebilirsiniz. Bunun için supports'e ek olarak isNullable'ı kullanın:

// 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!")
}

Özellikleri güncelleme

Belirli bir özelliğin değerini değiştirmek istiyorsanız ve özelliğin komutlarından hiçbiri 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?
  • Özelliğin değeri, bir özellik komutu göndermenin yan etkisi olarak değişebilir mi?

Özellikler ve bunların nitelikleriyle ilgili referans belgelerinde bu bilgiler yer alır.

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

Bir özelliğin değerini değiştirmek için güncelleme işlevini kullanma örneği

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 yeni değeri ayarlayan bir mutator işlevi iletin. Öncelikle özelliğin bir özelliği desteklediğini doğrulamanız iyi bir uygulamadır.

Örneğin:

    val 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 İşleme API'si, bir istemcinin tek bir yükte birden fazla Home API'si cihaz komutu göndermesine olanak tanır. Komutlar tek bir yükte gruplandırılır ve paralel düğüm kullanılarak bir Home API otomasyonu oluşturmaya benzer şekilde paralel olarak yürütülür. Örneğin, Güneş doğmadan önce jaluzileri aç. Ancak Batching API, Automation API'den daha karmaşık ve gelişmiş davranışlara olanak tanır. Örneğin, çalışma zamanında cihazları herhangi bir ölçüte göre dinamik olarak seçme özelliği.

Tek bir toplu işlemdeki 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. Bu, komutlar ayrı isteklerde sırayla gönderildiğinde mümkün değildir. Toplu komutlar kullanılarak elde edilen davranış, geliştiricinin bir grup cihazın durumunu önceden belirlenmiş bir toplu duruma eşleşecek şekilde ayarlamasına olanak tanır.

Batching API'yi kullanma

Toplu İşleme API'si aracılığıyla komut çağırmayla ilgili üç 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 işlem bağlamında lambda ifadesi oluşturur.

home.sendBatchedCommands() {

Toplu komutları belirtme

sendBatchedCommands() bloğunun gövdesinde batchable commands öğesini doldurun. Toplu işlenebilir komutlar, toplu iş bağlamında kullanılabilen ve Batchable soneki eklenerek adlandırılan mevcut Cihaz API'si komutlarının "gölge" sürümleridir. Ö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 iş bağlamına eklendikten ve yürütme bağlamdan çıktıktan sonra toplu iş otomatik olarak gönderilir.

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

DeferredResponse<T> örnekleri, Collection gibi herhangi bir türdeki bir nesnede veya sizin tanımladığınız bir veri sınıfında toplanabilir. Yanıtları birleştirmek için seçtiğiniz nesne türü, sendBatchedCommands() tarafından döndürülür. Örneğin, toplu işlem 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 işlem bağlamı özel bir veri sınıfındaki DeferredResponse örneklerini 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

sendBatchedCommands() bloğunun dışında, ilgili komutun başarılı mı yoksa başarısız mı olduğunu belirlemek için yanıtları kontrol edin. Bu işlem, DeferredResponse.getOrThrow() çağrılarak yapılır. Bu çağrı: - Yürütülen komutun sonucunu döndürür, - veya toplu işlem kapsamı tamamlanmamışsa ya da komut başarısız olmuşsa hata verir.

Sonuçları yalnızca lambda kapsamının dışında kontrol etmeniz gerekir. sendBatchedCommands()

Örnek

Örneğin, herkes uyuduğunda evdeki tüm cihazları geceye hazırlayan bir "iyi geceler" sahnesi oluşturmak için Batching API'yi kullanan bir uygulama geliştirmek istediğinizi varsayalım. Bu uygulama, ışıkları kapatmalı ve ön ile arka kapıyı kilitlemelidir.

Bu göreve yaklaşmanın bir yolu şudur:

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()
}