Android'de cihazları kontrol etme

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

Bir özellik komutu için de destek kontrol edilebilir. Ayrıca, bir komutun belirli bir cihaz için 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

Bir komut göndermek, bir özellikten durum niteliğini okumaya benzer. Cihazı açmak veya kapatmak için Google Home ekosistem veri modelinde toggle() olarak tanımlanan OnOff özelliğinin Toggle komutunu kullanın. Bu yöntem, onOff değerini 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 bir istisna döndürebilir. Geliştirici olarak, bu istisnaları düzgün şekilde işlemek ve hataların işlem yapılabilir olduğu durumlarda kullanıcılara ayrıntılı bilgi sunmak için try-catch bloğunu 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ığı gibi durumu okuyarak uygulamanızda işleyebilirsiniz. Alternatif olarak, tercih edilen yöntem olan Durumu gözlemleme bölümünde açıklandığı gibi 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 niteliği destekleyip desteklemediğini kontrol edin

Bazı cihazlar Matter özelliğini destekleyebilir, ancak belirli bir özelliği desteklemeyebilir. Örneğin, Matter ile eşlenen bir Cloud-to-cloud aygıtı her Matter özniteliğ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 Açık/Kapalı özelliğinin onOff özniteliğ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 niteliklerine ilişkin referans dokümanlar bu bilgiyi sağlar.

Dolayısıyla bir niteliğin değerinin nasıl değiştirilebileceğini belirleyen özellik kombinasyonları şunlardır:

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

  • Salt okunur ve diğer komutlardan etkilenir. Bu, özniteliğin değerinin değişmesinin tek yolunun bir komut gönderilmesi sonucu olduğu anlamına gelir. Örneğin, LevelControl Matter özelliğinin currentLevel niteliği salt okunurdur, ancak değeri moveToLevel gibi komutlarla değiştirilebilir.

  • Yazılabilir ve diğer komutlardan etkilenmez. Bu, özelliğin değerini doğrudan özelliğin update fonksiyonunu kullanarak değiştirebileceğiniz anlamına gelir, ancak özelliğin değerini etkileyecek herhangi bir komut yoktur. Örneğin, DoorLock özelliğinin WrongCodeEntryLimit niteliğ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 komut gönderilmesi sonucunda özelliğin değerinin değişebileceği anlamına gelir. Örneğin, FanControlTrait özniteliğinin speedSetting özniteliğine doğrudan yazılabilir, ancak step komutu kullanılarak da değiştirilebilir.

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

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

Bir öznitelik değerini ayarlamak için, özelliğin update işlevini çağırın ve ona yeni değeri ayarlayan bir mutatör işlevi geçirin. Öncelikle özelliğin bir niteliği desteklediğini doğrulamak 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önderin

Toplu API, bir istemcinin tek bir yükte birden fazla Ana API aygıt komutu göndermesine olanak tanır. Komutlar tek bir yükte toplanı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'ye kıyasla 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 sunar.

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 durumla 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şe dahil edilecek komutları belirtin.
  3. Gönderilen komutların sonuçlarını kontrol ederek başarılı mı başarısız mı olduklarını görebilirsiniz.

sendBatchedCommands() yöntemini çağırma

Home.sendBatchedCommands() yöntemini çağırın. Perde arkasında, bu yöntem özel bir toplu işlem bağlamında bir lambda ifadesi oluşturur.

home.sendBatchedCommands() {

Toplu komutları belirtin

sendBatchedCommands() bloğunun gövdesine toplu komutları doldurun. Toplu komutlar, toplu bağlamda kullanılabilen mevcut Aygıt API komutlarının "gölge" sürümleridir ve Batchable ekiyle adlandırılırlar. Örneğin, LevelControl özelliğinin moveToLevel() komutunun moveToLevelBatchable() adında bir karşılığı vardır.

Örnek:

  val response1 = add(command1)

  val response2 = add(command2)

Toplu işlem, tüm komutlar toplu işleme bağlamına eklendiğinde ve yürütme bağlamı terk ettiğinde otomatik olarak gönderilir.

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

DeferredResponse<T> örnekleri, Collection gibi herhangi bir türdeki bir nesnede veya 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 bağlam 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, DeferredResponse.getOrThrow() çağrılarak yapılır. Bu çağrı şunlardan birini yapar: - yürütülen komutun sonucunu döndürür, - veya toplu iş kapsamı tamamlanmamışsa ya da komut başarısız olmuşsa bir hata verir.

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

Örnek

Diyelim ki, evdeki tüm cihazları gece vakti, herkes uyurken yapılandıran bir 'iyi geceler' sahnesi kurmak için Batching API'yi kullanan bir uygulama oluşturmak istiyorsunuz. Bu uygulama ışıkları söndürmeli ve ön ve arka kapıları 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()
}