Mengontrol perangkat di iOS

Panduan ini melanjutkan dari Mengakses perangkat dan metadata perangkat di iOS dan memperkenalkan contoh tambahan kontrol dan akses perangkat.

Untuk menggunakan jenis atau karakteristik perangkat tertentu, seperti Matter OnOffTrait yang digunakan dalam banyak contoh di sini, jenis atau karakteristik tersebut harus diimpor:

import GoogleHomeSDK
import GoogleHomeTypes

Memeriksa apakah suatu karakteristik mendukung perintah

Gunakan fungsi supports tingkat karakteristik untuk memeriksa apakah perintah didukung untuk perangkat tertentu.

Misalnya, untuk memeriksa dukungan perangkat terhadap perintah toggle karakteristik On/Off:

// Check if the OnOff trait supports the toggle command.
if onOffTraitTest.supportsToggleCommand {
  print("onOffTrait supports toggle command")
} else {
  print("onOffTrait does not support stateful toggle command")
}

Mengirim perintah ke perangkat

Mengirim perintah mirip dengan membaca atribut status dari suatu karakteristik. Untuk mengaktifkan atau menonaktifkan perangkat, gunakan perintah Toggle OnOffTrait, yang ditentukan dalam model data ekosistem Google Home sebagai toggle(). Metode ini mengubah onOff menjadi false jika nilainya true, atau menjadi true jika nilainya false:

// Calling a command on a trait.
do {
  try await onOffTraitTest.toggle()
} catch let _ as HomeError {
  // Code for handling the exception
}

Perintah mungkin menampilkan pengecualian jika masalah terdeteksi pada alur eksekusi. Sebagai developer, Anda harus menggunakan blok do-catch untuk menangani pengecualian ini dengan benar, dan menampilkan informasi mendetail kepada pengguna tentang kasus saat error dapat ditindaklanjuti. Pengecualian yang tidak ditangani akan menghentikan runtime aplikasi dan dapat menyebabkan error pada aplikasi Anda.

Atau, gunakan perintah off() atau on() untuk menetapkan status secara eksplisit:

do {
  try await onOffTraitTest.off()
  try await onOffTraitTest.on()
} catch let _ as HomeError {
  // Code for handling the exception
}

Setelah mengirim perintah untuk mengubah status, setelah selesai, Anda dapat membaca status seperti yang dijelaskan dalam Membaca status perangkat untuk menanganinya di aplikasi Anda.

Mengirim perintah dengan parameter

Beberapa perintah mungkin menggunakan parameter, seperti yang ada di OnOffTrait atau LevelControlTrait:

offWithEffect

// Turn off the light using the DyingLight effect.
do {
  try await onOffTraitTest.offWithEffect(
    effectIdentifier: Matter.OnOffTrait.EffectIdentifierEnum.dyingLight,
    effectVariant: 0
  )
} catch let _ as HomeError {
  // Code for handling the exception
}

moveToLevel

// Change the brightness of the light to 50%
do {
  try await levelControlTraitTest.moveToLevel(
    level: UInt8(127),
    transitionTime: 0,
    optionsMask: Matter.LevelControlTrait.OptionsBitmap(),
    optionsOverride: Matter.LevelControlTrait.OptionsBitmap()
  )
} catch let _ as HomeError {
  // Code for handling the exception
}

Memeriksa apakah suatu ciri mendukung atribut

Beberapa perangkat mungkin mendukung karakteristik Matter, tetapi tidak mendukung atribut tertentu. Misalnya, perangkat Cloud-to-cloud yang dipetakan ke Matter mungkin tidak mendukung setiap atribut Matter. Untuk menangani kasus seperti ini, gunakan properti isSupported tingkat karakteristik untuk memeriksa apakah atribut didukung untuk perangkat tertentu.

Misalnya, untuk memeriksa dukungan perangkat terhadap atribut onOff pada karakteristik On/Off:

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

Beberapa atribut dapat bernilai null dalam spesifikasi Matter atau skema Cloud-to-cloud smart home. Untuk atribut ini, Anda dapat menentukan apakah nil yang ditampilkan oleh atribut disebabkan oleh perangkat yang tidak melaporkan nilai tersebut, atau apakah nilai atribut sebenarnya adalah nil, dengan menggunakan isNullable selain isSupported:

// Check if a nullable attribute is set or is not supported.
if let deviceType = await device.types.get(OnOffLightDeviceType.self) {
  if let onOffTrait = deviceType.traits[Matter.OnOffTrait.self] {
    if onOffTrait.attributes.startUpOnOff == nil {
      if onOffTrait.attributes.$startUpOnOff.isSupported {
        print(
          "onOffTrait supports startUpOnOff and it is nil. Check the spec for the contextual meaning."
        )
      } else {
        print("onOffTrait does not support startUpOnOff!")
      }
    } else {
      print(
        "onOffTrait supports startUpOnOff and it is set to \(String(describing: onOffTrait.attributes.startUpOnOff))"
      )
    }
  }
}

Memperbarui atribut karakteristik

Jika Anda ingin mengubah nilai atribut tertentu, dan tidak ada perintah karakteristik yang melakukannya, atribut tersebut mungkin mendukung penetapan nilainya secara eksplisit.

Apakah nilai atribut dapat diubah atau tidak bergantung pada dua faktor:

  • Apakah atribut dapat ditulis?
  • Dapatkah nilai atribut berubah sebagai efek samping dari pengiriman perintah ciri?

Dokumentasi referensi untuk karakteristik dan atributnya memberikan informasi ini.

Oleh karena itu, kombinasi properti yang menentukan cara nilai atribut dapat diubah adalah:

  • Hanya baca dan tidak terpengaruh oleh perintah lain. Artinya, nilai atribut tidak berubah. Misalnya, atribut currentPosition dari SwitchTrait.

  • Hanya baca dan terpengaruh oleh perintah lain. Artinya, satu-satunya cara untuk mengubah nilai atribut adalah dengan mengirimkan perintah. Misalnya, atribut currentLevel dari LevelControlTrait bersifat hanya baca, tetapi nilainya dapat diubah oleh perintah seperti moveToLevel.

  • Dapat ditulis dan tidak terpengaruh oleh perintah lain. Artinya, Anda dapat langsung mengubah nilai atribut menggunakan fungsi update dari karakteristik, tetapi tidak ada perintah yang akan memengaruhi nilai atribut. Misalnya, atribut WrongCodeEntryLimit dari DoorLockTrait.

  • Dapat ditulis dan terpengaruh oleh perintah lain. Artinya, Anda dapat langsung mengubah nilai atribut menggunakan fungsi update pada karakteristik, dan nilai atribut dapat berubah sebagai hasil dari pengiriman perintah. Misalnya, atribut occupiedCoolingSetpoint dari ThermostatTrait dapat ditulis, tetapi juga diperbarui dengan perintah setpointRaiseLower.

Contoh penggunaan fungsi update untuk mengubah nilai atribut

Contoh ini menunjukkan cara menetapkan nilai atribut DoorLockTrait.wrongCodeEntryLimit secara eksplisit.

Untuk menetapkan nilai atribut, panggil fungsi update trait dan teruskan fungsi update yang menetapkan nilai baru. Sebaiknya verifikasi terlebih dahulu bahwa karakteristik mendukung atribut.

Contoh:

if doorLockTraitTest.attributes.$wrongCodeEntryLimit.isSupported {
  let _ = try await doorLockTraitTest.update {
    $0.setWrongCodeEntryLimit(3)
  }
}

Mengontrol grup perangkat

Selain kontrol mendetail atas setiap anggota grup dengan melakukan iterasi melalui perangkat anggotanya, Anda dapat mengontrol DeviceGroup sebagai satu entitas. DeviceGroup sesuai dengan protokol HasParts dan mengekspos bagian DeviceType yang didukung oleh perangkat dalam grup:

  • await group.part(_:) menampilkan instance pertama dari DeviceType yang ditentukan jika grup mendukungnya, atau nil jika tidak.
  • try await group.parts(_:) menampilkan array dari semua bagian tingkat teratas yang cocok dengan DeviceType yang ditentukan.

Saat Anda memanggil perintah karakteristik pada jenis perangkat yang merupakan bagian dari DeviceGroup, SDK akan menyampaikan perintah tersebut ke semua perangkat anggota terkait dalam grup yang mendukung kemampuan tersebut, terlepas dari konektivitas atau transportasi yang mendasarinya (seperti Matter atau Cloud-to-cloud).

Atribut karakteristik bagian grup dan penanganan error

Menargetkan bagian grup akan menyederhanakan kasus umum saat Anda ingin mengirim perintah idempoten (seperti menyalakan atau mematikan lampu, atau menyetel tingkat kecerahan) di seluruh grup. Saat menggunakan karakteristik dan perintah di bagian DeviceGroup, perhatikan perilaku berikut:

  • Atribut status dinamis (seperti atribut onOff dari OnOffTrait atau atribut currentLevel dari LevelControlTrait) umumnya tidak diisi pada karakteristik bagian grup karena perangkat anggota dalam grup dapat berada dalam status berbeda yang tidak dapat digabungkan menjadi satu nilai. Namun, perintah yang didukung (diperiksa dengan supports(_:), seperti .moveToLevelWithOnOff pada lampu yang dapat diredupkan) dan atribut kemampuan tertentu (seperti colorTempPhysicalMinMireds dan colorTempPhysicalMaxMireds pada ColorControlTrait untuk lampu berwarna) diisi sehingga aplikasi Anda dapat mengonfigurasi kontrol UI dengan tepat.
  • Tidak semua perintah pada karakteristik anggota grup tersedia di bagian grup. Secara khusus, perintah yang menampilkan nilai tidak tersedia.
  • Perintah pada bagian grup tidak menampilkan hasil individual untuk setiap perintah perangkat anggota yang mendasarinya. Untuk memeriksa hasil perintah individual atau memanggil perintah yang menampilkan nilai, lakukan iterasi melalui perangkat anggota grup secara langsung.
  • Perintah yang dikirim ke bagian di DeviceGroup akan selesai setelah seluruh fanout di seluruh perangkat anggota selesai dan semua keberhasilan atau kegagalan perintah yang mendasarinya dikumpulkan. Perintah hanya akan gagal (menampilkan HomeError) jika perintah gagal untuk setiap perangkat anggota terkait atau jika semua perangkat target tidak tersedia, yang muncul sebagai kegagalan perintah tunggal yang cocok dengan sintaksis panggilan perintah tunggal. Jika setidaknya satu perangkat anggota menjalankan perintah, perintah grup akan selesai tanpa menampilkan error.

Mengirim perintah ke bagian grup

Untuk menyalakan semua lampu OnOffLightDeviceType di grup perangkat:

if let lightPart = await group.part(OnOffLightDeviceType.self),
   let onOffTrait = lightPart.matterTraits.onOffTrait,
   onOffTrait.supports(.on) {
  try await onOffTrait.on()
}

Anda juga dapat memeriksa beberapa jenis perangkat terkait (misalnya, menonaktifkan jenis perangkat lampu apa pun dalam grup yang mendukung OnOffTrait):

func onOffTrait(in group: DeviceGroup) async -> Matter.OnOffTrait? {
  if let light = await group.part(OnOffLightDeviceType.self) {
    return light.matterTraits.onOffTrait
  }
  if let light = await group.part(DimmableLightDeviceType.self) {
    return light.matterTraits.onOffTrait
  }
  if let light = await group.part(ColorTemperatureLightDeviceType.self) {
    return light.matterTraits.onOffTrait
  }
  if let light = await group.part(ExtendedColorLightDeviceType.self) {
    return light.matterTraits.onOffTrait
  }
  return nil
}

if let trait = await onOffTrait(in: group) {
  try await trait.off()
}

Anda dapat memeriksa dukungan perintah atau membaca batas kemampuan pada bagian grup sebelum mengirim perintah (misalnya, memeriksa .moveToLevelWithOnOff pada bagian lampu yang dapat diredupkan atau membaca colorTempPhysicalMinMireds dan colorTempPhysicalMaxMireds pada bagian lampu color temperature):

if let dimmableLight = await group.part(DimmableLightDeviceType.self),
   let levelTrait = dimmableLight.matterTraits.levelControlTrait,
   levelTrait.supports(.moveToLevelWithOnOff) {
  try await levelTrait.moveToLevelWithOnOff(
    level: 127,
    transitionTime: nil,
    optionsMask: [],
    optionsOverride: []
  )
}

if let colorLight = await group.part(ColorTemperatureLightDeviceType.self),
   let colorTrait = colorLight.matterTraits.colorControlTrait,
   let minMireds = colorTrait.attributes.colorTempPhysicalMinMireds,
   let maxMireds = colorTrait.attributes.colorTempPhysicalMaxMireds {
  let midMireds = UInt16((UInt32(minMireds) + UInt32(maxMireds)) / 2)
  try await colorTrait.moveToColorTemperature(
    colorTemperatureMireds: midMireds,
    transitionTime: 0,
    optionsMask: [],
    optionsOverride: []
  )
}