iOS पर डिवाइसों को कंट्रोल करना

यह गाइड, iOS पर डिवाइसों और डिवाइस के मेटाडेटा को ऐक्सेस करना से जारी रहती है. इसमें डिवाइस को कंट्रोल करने और उसे ऐक्सेस करने के अन्य उदाहरण दिए गए हैं.

किसी खास तरह के डिवाइस या खूबियों का इस्तेमाल करने के लिए, उन्हें इंपोर्ट करना ज़रूरी है. जैसे, यहां दिए गए कई उदाहरणों में इस्तेमाल किया गया Matter OnOffTrait:

import GoogleHomeSDK
import GoogleHomeTypes

यह देखना कि कोई trait किसी निर्देश के साथ काम करता है या नहीं

ट्रेट-लेवल supports फ़ंक्शन का इस्तेमाल करके देखें कि कोई निर्देश किसी डिवाइस के साथ काम करता है या नहीं.

उदाहरण के लिए, यह देखने के लिए कि कोई डिवाइस, On/Off trait के toggle कमांड के साथ काम करता है या नहीं:

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

किसी डिवाइस को निर्देश भेजना

निर्देश भेजना, किसी ट्रेट से स्टेट एट्रिब्यूट को पढ़ने जैसा ही है. डिवाइस को चालू या बंद करने के लिए, OnOffTrait टॉगल कमांड का इस्तेमाल करें. इसे Google Home नेटवर्क के डेटा मॉडल में toggle() के तौर पर तय किया गया है. यह तरीका onOff को false में बदल देता है, अगर यह true है या true में बदल देता है, अगर यह false है:

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

अगर एक्ज़ीक्यूशन फ़्लो में कोई समस्या मिलती है, तो हो सकता है कि कमांड से कोई अपवाद मिले. डेवलपर के तौर पर, आपको इन अपवादों को ठीक से मैनेज करने के लिए, do-catch ब्लॉक का इस्तेमाल करना चाहिए. साथ ही, उन मामलों में उपयोगकर्ताओं को पूरी जानकारी देनी चाहिए जिनमें गड़बड़ियों को ठीक किया जा सकता है. अनहैंडल्ड एक्सेप्शन की वजह से, ऐप्लिकेशन का रनटाइम रुक जाएगा और आपका ऐप्लिकेशन क्रैश हो सकता है.

इसके अलावा, स्थिति को साफ़ तौर पर सेट करने के लिए, off() या on() कमांड का इस्तेमाल करें:

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

स्थिति बदलने के लिए निर्देश भेजने के बाद, जब यह पूरा हो जाए, तो डिवाइस की स्थिति पढ़ें में बताए गए तरीके से स्थिति को पढ़ा जा सकता है, ताकि उसे अपने ऐप्लिकेशन में मैनेज किया जा सके.

पैरामीटर के साथ कोई निर्देश भेजना

कुछ निर्देशों में पैरामीटर इस्तेमाल किए जा सकते हैं. जैसे, OnOffTrait या 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
}

यह देखना कि कोई विशेषता किसी एट्रिब्यूट के साथ काम करती है या नहीं

ऐसा हो सकता है कि कुछ डिवाइसों पर Matter ट्रेट काम करे, लेकिन कोई खास एट्रिब्यूट काम न करे. उदाहरण के लिए, Matter से मैप किया गया Cloud-to-cloud डिवाइस, शायद Matter के हर एट्रिब्यूट के साथ काम न करे. इस तरह के मामलों को मैनेज करने के लिए, trait-level isSupported प्रॉपर्टी का इस्तेमाल करें. इससे यह पता लगाया जा सकता है कि किसी डिवाइस के लिए एट्रिब्यूट काम करता है या नहीं.

उदाहरण के लिए, यह देखने के लिए कि कोई डिवाइस, On/Off trait की onOff विशेषता के साथ काम करता है या नहीं:

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

Matter स्पेसिफ़िकेशन या Cloud-to-cloud smart home स्कीमा में, कुछ एट्रिब्यूट की वैल्यू शून्य हो सकती है. इन एट्रिब्यूट के लिए, यह तय किया जा सकता है कि एट्रिब्यूट से मिली nil वैल्यू, डिवाइस से उस वैल्यू की जानकारी न मिलने की वजह से है या एट्रिब्यूट की वैल्यू असल में nil है. इसके लिए, isSupported के साथ-साथ isNullable का इस्तेमाल करें:

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

ट्रेट एट्रिब्यूट अपडेट करना

अगर आपको किसी एट्रिब्यूट की वैल्यू बदलनी है और ट्रेट का कोई भी निर्देश ऐसा नहीं करता है, तो हो सकता है कि एट्रिब्यूट की वैल्यू को साफ़ तौर पर सेट किया जा सके.

किसी एट्रिब्यूट की वैल्यू बदली जा सकती है या नहीं, यह दो बातों पर निर्भर करता है:

  • क्या एट्रिब्यूट में बदलाव किया जा सकता है?
  • क्या trait कमांड भेजने से, एट्रिब्यूट की वैल्यू बदल सकती है?

ट्रेट और उनके एट्रिब्यूट के रेफ़रंस दस्तावेज़ में यह जानकारी दी गई है.

इसलिए, किसी एट्रिब्यूट की वैल्यू में बदलाव करने के तरीके को तय करने वाली प्रॉपर्टी के कॉम्बिनेशन ये हैं:

  • यह सिर्फ़ पढ़ने के लिए है और इस पर अन्य कमांड का कोई असर नहीं पड़ता. इसका मतलब है कि एट्रिब्यूट की वैल्यू नहीं बदलती. उदाहरण के लिए, currentPosition एट्रिब्यूट, SwitchTrait.

  • सिर्फ़ पढ़ने के लिए और अन्य कमांड से असर पड़ता है. इसका मतलब है कि एट्रिब्यूट की वैल्यू सिर्फ़ तब बदल सकती है, जब कोई निर्देश भेजा जाए. उदाहरण के लिए, LevelControlTrait का currentLevel एट्रिब्यूट रीड-ओनली है. हालांकि, moveToLevel जैसे कमांड का इस्तेमाल करके, इसकी वैल्यू में बदलाव किया जा सकता है.

  • इसमें डेटा लिखा जा सकता है और अन्य कमांड का इस पर कोई असर नहीं पड़ता. इसका मतलब है कि trait के update फ़ंक्शन का इस्तेमाल करके, एट्रिब्यूट की वैल्यू को सीधे तौर पर बदला जा सकता है. हालांकि, ऐसे कोई निर्देश नहीं हैं जिनसे एट्रिब्यूट की वैल्यू पर असर पड़े. उदाहरण के लिए, WrongCodeEntryLimit एट्रिब्यूट, DoorLockTrait.

  • इसमें बदलाव किया जा सकता है और अन्य कमांड का इस पर असर पड़ता है. इसका मतलब है कि विशेषता के update फ़ंक्शन का इस्तेमाल करके, एट्रिब्यूट की वैल्यू को सीधे तौर पर बदला जा सकता है. साथ ही, कोई निर्देश भेजने पर एट्रिब्यूट की वैल्यू बदल सकती है. उदाहरण के लिए, occupiedCoolingSetpoint एट्रिब्यूट के ThermostatTrait को लिखा जा सकता है. साथ ही, setpointRaiseLower कमांड की मदद से अपडेट भी किया जा सकता है.

किसी एट्रिब्यूट की वैल्यू बदलने के लिए, अपडेट फ़ंक्शन का इस्तेमाल करने का उदाहरण

इस उदाहरण में, DoorLockTrait.wrongCodeEntryLimit एट्रिब्यूट की वैल्यू को साफ़ तौर पर सेट करने का तरीका बताया गया है.

किसी एट्रिब्यूट की वैल्यू सेट करने के लिए, ट्रेट के update फ़ंक्शन को कॉल करें. साथ ही, उसे एक अपडेट फ़ंक्शन पास करें, जो नई वैल्यू सेट करता है. सबसे पहले, यह पुष्टि करना कि ट्रेट किसी एट्रिब्यूट के साथ काम करता है, एक अच्छा तरीका है.

उदाहरण के लिए:

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

डिवाइस ग्रुप को कंट्रोल करना

ग्रुप के सदस्य डिवाइसों को दोहराकर, ग्रुप के हर सदस्य पर बारीकी से कंट्रोल करने के अलावा, DeviceGroup को एक इकाई के तौर पर कंट्रोल किया जा सकता है. DeviceGroup, HasParts प्रोटोकॉल के मुताबिक है और ग्रुप में मौजूद डिवाइसों के साथ काम करने वाले DeviceType पार्ट दिखाता है:

  • अगर ग्रुप में DeviceType इस्तेमाल किया जा सकता है, तो await group.part(_:) उसका पहला इंस्टेंस दिखाता है. अगर ग्रुप में इस्तेमाल नहीं किया जा सकता, तो nil दिखाता है.
  • try await group.parts(_:), दिए गए DeviceType से मैच करने वाले सभी टॉप-लेवल पार्ट की कलेक्शन दिखाता है.

जब DeviceGroup के किसी डिवाइस टाइप पर कोई ट्रेट कमांड दिया जाता है, तो SDK टूल उस कमांड को ग्रुप में मौजूद उन सभी डिवाइसों को भेजता है जिनमें वह सुविधा काम करती है. इससे कोई फ़र्क़ नहीं पड़ता कि वे डिवाइस किस तरह से कनेक्ट हैं या किस तरह से डेटा ट्रांसफ़र करते हैं (जैसे, Matter या Cloud-to-cloud).

ग्रुप पार्ट ट्रेट एट्रिब्यूट और गड़बड़ी ठीक करना

ग्रुप के किसी हिस्से को टारगेट करने से, उन सामान्य मामलों को आसान बनाया जा सकता है जिनमें आपको किसी ग्रुप में एक जैसा निर्देश भेजना हो. जैसे, लाइटें चालू या बंद करना या रोशनी का लेवल सेट करना. DeviceGroup के किसी हिस्से पर ट्रेट और कमांड का इस्तेमाल करते समय, इन बातों का ध्यान रखें:

  • डाइनैमिक स्टेट एट्रिब्यूट (जैसे, OnOffTrait का onOff एट्रिब्यूट या LevelControlTrait का currentLevel एट्रिब्यूट) आम तौर पर, ग्रुप पार्ट की विशेषता में नहीं भरे जाते. ऐसा इसलिए होता है, क्योंकि किसी ग्रुप में मौजूद सदस्य डिवाइस अलग-अलग स्थितियों में हो सकते हैं. इन स्थितियों को एक वैल्यू में नहीं जोड़ा जा सकता. हालांकि, इस्तेमाल किए जा सकने वाले कमांड (supports(_:) से चुने गए, जैसे कि रोशनी कम या ज़्यादा करने वाली लाइट पर .moveToLevelWithOnOff) और चुनिंदा क्षमता वाले एट्रिब्यूट (जैसे कि रंगीन लाइट के लिए ColorControlTrait पर colorTempPhysicalMinMireds और colorTempPhysicalMaxMireds) अपने-आप भर जाते हैं, ताकि आपका ऐप्लिकेशन यूज़र इंटरफ़ेस (यूआई) कंट्रोल को सही तरीके से कॉन्फ़िगर कर सके.
  • ग्रुप के सदस्यों की विशेषताओं से जुड़े सभी निर्देश, ग्रुप के किसी हिस्से पर उपलब्ध नहीं होते. खास तौर पर, वैल्यू दिखाने वाले निर्देश उपलब्ध नहीं हैं.
  • ग्रुप के किसी हिस्से पर दिया गया निर्देश, ग्रुप में शामिल हर डिवाइस के लिए अलग-अलग नतीजे नहीं दिखाता. किसी एक कमांड के नतीजे देखने या वैल्यू दिखाने वाले कमांड को कॉल करने के लिए, सीधे तौर पर ग्रुप के सदस्य डिवाइसों को एक-एक करके देखें.
  • DeviceGroup पर किसी पार्ट को भेजे गए कमांड तब पूरे होते हैं, जब सदस्य डिवाइसों पर पूरा फ़ैनआउट खत्म हो जाता है. साथ ही, सभी कमांड के सफल या असफल होने की जानकारी इकट्ठा कर ली जाती है. कोई कमांड सिर्फ़ तब काम नहीं करता (HomeError दिखाता है), जब वह उससे जुड़े हर सदस्य डिवाइस के लिए काम न करे या सभी टारगेट डिवाइस उपलब्ध न हों. ऐसा होने पर, सिंगल-कमांड कॉल सिंटैक्स से मैच करने वाले सिंगल कमांड के काम न करने की जानकारी मिलती है. अगर ग्रुप में शामिल कम से कम एक डिवाइस निर्देश को पूरा करता है, तो ग्रुप को दिया गया निर्देश बिना किसी गड़बड़ी के पूरा हो जाता है.

ग्रुप के किसी हिस्से को निर्देश भेजना

डिवाइस ग्रुप में मौजूद सभी OnOffLightDeviceType लाइटें चालू करने के लिए:

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

एक से ज़्यादा मिलते-जुलते डिवाइस टाइप भी देखे जा सकते हैं. उदाहरण के लिए, ग्रुप में मौजूद किसी भी लाइट डिवाइस टाइप को बंद करना, जो 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()
}

किसी ग्रुप पार्ट को कमांड भेजने से पहले, यह देखा जा सकता है कि वह कमांड के साथ काम करता है या नहीं. इसके अलावा, उसकी क्षमता की सीमाएं भी देखी जा सकती हैं. उदाहरण के लिए, डिम की जा सकने वाली लाइट के पार्ट पर .moveToLevelWithOnOff की जांच करना या कलर टेंपरेचर वाली लाइट के पार्ट पर colorTempPhysicalMinMireds और colorTempPhysicalMaxMireds को देखना:

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: []
  )
}