iOS के लिए डिवाइस और डिवाइस का मेटाडेटा ऐक्सेस करना

iOS के लिए Home APIs के ज़रिए, डिवाइस के एपीआई ऐक्सेस किए जा सकते हैं. अपने ऐप्लिकेशन में ये पैकेज इंपोर्ट करें:

import GoogleHomeSDK
import GoogleHomeTypes

ज़्यादा जानकारी के लिए, iOS पर डेटा मॉडल देखें.

गड़बड़ी ठीक करना

Home API में कुछ तरीके HomeError दिखाते हैं. इसलिए, हमारा सुझाव है कि आप do-catch ब्लॉक का इस्तेमाल करके, उन कॉल पर HomeError को पकड़ें.

HomeError को मैनेज करते समय, उसके code और message फ़ील्ड देखें. इससे आपको गड़बड़ी के बारे में पता चलेगा.

जिन गड़बड़ियों को ठीक नहीं किया गया है उनकी वजह से, आपका ऐप्लिकेशन क्रैश हो जाएगा.

ज़्यादा जानकारी के लिए, गड़बड़ी ठीक करना लेख पढ़ें.

उदाहरण के लिए, किसी डिवाइस को निर्देश भेजना लेख पढ़ें.

कॉल के सैंपल

डिवाइसों की सूची पाना

Home ऑब्जेक्ट के रेफ़रंस के साथ, devices() को इनवोक करें, ताकि ऐक्सेस किए जा सकने वाले डिवाइसों का Query मिल सके. Query के batched() तरीके को कॉल करें. यह एक सेट दिखाता है, जिसमें हर डिवाइस के मेटाडेटा में बदलाव होने पर, होम की मौजूदा स्थिति दिखती है. इसके अलावा, उपलब्ध डिवाइसों की जानकारी पाने के लिए, Query.list() पर कॉल करें. यह एक सुविधाजनक तरीका है, जो batched() स्ट्रीम की सदस्यता लेता है और पहली बार भेजी गई वैल्यू दिखाता है. Query.stream() एक ऐसी स्ट्रीम जनरेट करता है जो डिवाइस के मेटाडेटा में बदलाव होने पर नई वैल्यू भेजती है. जैसे, डिवाइस का नाम, कमरा या स्ट्रक्चर. आंतरिक तौर पर, यह batched() का इस्तेमाल करता है और सिर्फ़ बदली गई प्रॉपर्टी को दिखाता है.

// Get a list of all devices accessible to the user
let homeDevices = try await self.home.devices().list()

यहां से, हर डिवाइस की स्थिति को ऐक्सेस किया जा सकता है. साथ ही, डिवाइसों को निर्देश भेजे जा सकते हैं.

Home API के 1.8 वर्शन में, आपके पास यह विकल्प होता है कि एपीआई, मल्टीपार्ट डिवाइस के हर हिस्से को एक डिवाइस के तौर पर दिखाए. इसके लिए, devices() तरीके के enableMultipartDevices पैरामीटर को true पर सेट करें. ज़्यादा जानकारी के लिए, iOS पर मल्टीपार्ट डिवाइस देखें.

डिवाइस के टाइप पाना

किसी डिवाइस से जुड़ी डिवाइस टाइप की जानकारी पाने के लिए, डिवाइस की types प्रॉपर्टी पढ़ें. इससे DeviceTypeController मिलता है.

किसी खास डिवाइस टाइप के लिए अपडेट की सदस्यता लेने के लिए, DeviceTypeController.subscribe(_:) को कॉल करें:

let devices = try await self.home.devices().list()
if let device = devices.first(where: { $0.id == myDeviceId }) {
  var receivedUpdate1 = false
  var receivedUpdate2 = false
  device.types.subscribe(OnOffLightDeviceType.self)
    .assertNoFailure()
    .sink { device in
      if !receivedUpdate1 {
        receivedUpdate1 = true
        Task {
          try await device.matterTraits.onOffTrait?.on()
        }
        return
      }
      if !receivedUpdate2 {
        receivedUpdate2 = true
        return
      }
      fatalError("Received unexpected update")
    }
}

अगर डिवाइस, तय किए गए डिवाइस टाइप के साथ काम नहीं करता है, तो यह तुरंत पूरा होने वाला Empty Publisher दिखाता है.

अगर डिवाइस किसी खास तरह के डिवाइस के साथ काम करता है, तो get() को कॉल करके उस तरह के डिवाइस का हैंडल पाया जा सकता है:

if let device = devices.first(where: { $0.id == myDeviceId }) {
  let _ = await device.types.get(OnOffLightDeviceType.self)
}

अगर डिवाइस पर बताए गए टाइप का इस्तेमाल नहीं किया जा सकता, तो यह nil दिखाता है.

DeviceTypeCollection का Publisher पाने के लिए, DeviceTypeController.subscribeAll() पर कॉल करें. इस क्लास की मदद से, यह देखा जा सकता है कि डिवाइस में किसी खास तरह का डिवाइस है या नहीं:

if let device = devices.first(where: { $0.id == myDeviceId }) {
  device.types.subscribeAll()
    .assertNoFailure()
    .sink { types in
      let lightDeviceType = types[OnOffLightDeviceType.self]
      let fanDeviceType = types[FanDeviceType.self]
    }
}

डिवाइस टाइप का ट्रेट पाना

डिवाइस टाइप, ट्रेड्स को पढ़ने का एंट्री पॉइंट होता है. ऐसा इसलिए, क्योंकि ये डिवाइस को उसके फ़ंक्शनल हिस्सों में बांटते हैं. जैसे, Matter में एंडपॉइंट.

ये डिवाइस की दो तरह की सुविधाओं के बीच होने वाले टकरावों का भी हिसाब रखते हैं. ऐसा तब होता है, जब दोनों सुविधाओं में एक ही तरह की विशेषता हो. उदाहरण के लिए, अगर कोई डिवाइस स्पीकर और डिम की जा सकने वाली लाइट, दोनों के तौर पर काम करता है, तो उसमें चालू/बंद करने की दो और लेवल कंट्रोल करने की दो सुविधाएं होंगी.

डिवाइस में एक ही नाम वाली दो ट्रेट होने पर, ट्रेट के टकराव की एक और समस्या हो सकती है. उदाहरण के लिए, onOff, स्टैंडर्ड OnOff ट्रेट के इंस्टेंस को दिखा सकता है. इसके अलावा, यह मैन्युफ़ैक्चरर की ओर से तय की गई OnOff ट्रेट के इंस्टेंस को भी दिखा सकता है. यह तय करने में कोई भी अस्पष्टता दूर करने के लिए कि कौनसी विशेषता का इस्तेमाल किया जाना है, हर डिवाइस टाइप पर मौजूद दो विशेषता कलेक्शन में से किसी एक के ज़रिए विशेषता का रेफ़रंस दें.

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

if let dimmableLightDeviceType =
  await device.types.get(DimmableLightDeviceType.self)
{
  // Accessing standard trait on the type.
  let levelControlTrait =
    dimmableLightDeviceType.matterTraits.levelControlTrait.self
}

Google की सुविधाओं के लिए, googleTraits का इस्तेमाल करें:

if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) {
  // Accessing Google trait on the type.
  let doorbellPressTrait =
    doorbellDeviceType.traits[Google.DoorbellPressTrait.self]
}

किसी मैन्युफ़ैक्चरर की खास विशेषता को ऐक्सेस करने के लिए, उसे traits प्रॉपर्टी के ज़रिए रेफ़रंस करें. हालांकि, इससे पहले मैन्युफ़ैक्चरर के पैकेज का नाम डालें:

let deviceType = await device1?.types.get(OnOffLightDeviceType.self)
// Accessing custom trait on the type.
if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] {
  let rpmVal = spinnerTrait.attributes.rpm
}

डिवाइस की स्थिति को पढ़ना

डिवाइस की चालू/बंद करने की सुविधा से जुड़े OnOff एट्रिब्यूट की जांच करने का यह उदाहरण देखें:

let lightDevices = devices.filter {
  $0.types.contains(OnOffLightDeviceType.self)
}
let light1 = lightDevices.first
let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self)
if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait {
  let onOffVal = onOffTrait.attributes.onOff
}

किसी खास विशेषता वाले डिवाइसों की सूची पाना

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

// Get all light devices that support levelControl
var levelControlDevices: [HomeDevice] = []
let allDevices = try await home.devices().list()
for device in allDevices {
  if let deviceType = await device.types.get(OnOffLightDeviceType.self) {
    if deviceType.traits.contains(Matter.LevelControlTrait.self) {
      levelControlDevices.append(device)
    }
  }
}

Home API में उपलब्ध सभी ट्रेट की पूरी सूची देखने के लिए, iOS पर ट्रेट इंडेक्स देखें.

एक जैसे डिवाइस टाइप वाले डिवाइसों की सूची पाना

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

// Get a list of devices with similar device types (lights)
let lightDevices =
  try await self.home.devices().list().compactMap {
    $0.types.contains(DimmableLightDeviceType.self)
      || $0.types.contains(OnOffLightDeviceType.self)
      || $0.types.contains(ColorTemperatureLightDeviceType.self)
      || $0.types.contains(ExtendedColorLightDeviceType.self)
  }

Home API में कई तरह के डिवाइस टाइप होते हैं, जो मुख्य डिवाइस टाइप को दिखा सकते हैं. उदाहरण के लिए, "लाइट" डिवाइस टाइप नहीं है. इसके बजाय, यहां चार अलग-अलग तरह के डिवाइस टाइप दिए गए हैं, जो लाइट को दिखा सकते हैं. इन्हें ऊपर दिए गए उदाहरण में दिखाया गया है. इसलिए, घर में मौजूद डिवाइसों के बारे में ज़्यादा जानकारी पाने के लिए, कई तरह के डिवाइसों को शामिल करना ज़रूरी है.

Home API में उपलब्ध डिवाइस टाइप और उनकी सुविधाओं की पूरी सूची देखने के लिए, iOS पर इस्तेमाल किए जा सकने वाले डिवाइस टाइप देखें.

किसी डिवाइस के लिए वेंडर का नाम, वेंडर आईडी या प्रॉडक्ट आईडी पाना

BasicInformationTrait ट्रेट में, डिवाइस के लिए वेंडर आईडी, प्रॉडक्ट आईडी, प्रॉडक्ट का नाम, और सीरियल नंबर जैसी जानकारी शामिल होती है:

guard
  let vendorName =
    basicInfoTrait.attributes.vendorName
else {
  fatalError("Failed to get vendorName")
}
guard
  let vendorID =
    basicInfoTrait.attributes.vendorID
else {
  fatalError("Failed to get vendorID")
}
guard
  let productID =
    basicInfoTrait.attributes.productID
else {
  fatalError("Failed to get productID")
}

डिवाइस बनाने वाली कंपनियों के लिए, क्लाउड-टू-क्लाउड डिवाइस आइडेंटिफ़िकेशन

अगर आप डिवाइस बनाने वाली कंपनी हैं और Cloud-to-cloud डिवाइस बनाती हैं, तो BasicInformation ट्रेट की मदद से अपने Cloud-to-cloud डिवाइसों की पहचान करने के लिए, उनके SYNC रिस्पॉन्स में इन स्ट्रिंग फ़ील्ड को शामिल किया जा सकता है:

  • जारी किया गया Connectivity Standards Alliance (Alliance) वेंडर आईडी: "matterOriginalVendorId": "0xfff1",

  • यह वेंडर के किसी प्रॉडक्ट का यूनीक आइडेंटिफ़ायर होता है: "matterOriginalProductId": "0x1234",

  • डिवाइस के लिए यूनीक आइडेंटिफ़ायर. इसे डिवाइस बनाने वाली कंपनी के हिसाब से बनाया जाता है: "matterUniqueId": "matter-device-id",

इन स्ट्रिंग फ़ील्ड में वैल्यू डालते समय, अगर आपके पास Matter वेंडर और प्रॉडक्ट आईडी हैं, तो उनका इस्तेमाल करें. अगर आप Alliance के सदस्य नहीं हैं और आपको ये आईडी असाइन नहीं किए गए हैं, तो matterOriginalVendorId और matterOriginalProductId फ़ील्ड को खाली छोड़ दें. साथ ही, आइडेंटिफ़ायर के तौर पर matterUniqueId की जानकारी दें.

सिंक करने के जवाब के इस उदाहरण में, इन फ़ील्ड के इस्तेमाल के बारे में बताया गया है:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "agentUserId": "1836.15267389",
    "devices": [
      {
        "id": "456",
        "type": "action.devices.types.LIGHT",
        "traits": [
          "action.devices.traits.OnOff",
          "action.devices.traits.Brightness",
          "action.devices.traits.ColorSetting",
        ],
        "willReportState": true,
        "deviceInfo": { ... },
        "matterOriginalVendorId": "0xfff1",
        "matterOriginalProductId": "0x1234",
        "matterUniqueId": "matter-device-id",
        "otherDeviceIds": [
          {
            "deviceId": "local-device-id",
          }
        ]
      }
    ]
  }
}

ज़्यादा जानकारी के लिए, Cloud-to-cloud SYNC दस्तावेज़ देखें.

डिवाइस और ट्रेट का मेटाडेटा

Home API में मौजूद डिवाइसों और उनकी सुविधाओं से मेटाडेटा जुड़ा होता है. इससे, ऐप्लिकेशन में उपयोगकर्ता अनुभव को मैनेज करने में मदद मिलती है.

होम एपीआई में मौजूद हर ट्रेट में एक sourceConnectivity प्रॉपर्टी होती है. इसमें ट्रेट के ऑनलाइन स्टेटस और जगह (लोकल या रिमोट राउटिंग) के बारे में जानकारी होती है.

किसी डिवाइस का मुख्य टाइप पाना

ऐसा हो सकता है कि कुछ डिवाइस, Home API के ज़रिए कई तरह के डिवाइसों के बारे में जानकारी दें. यह पक्का करने के लिए कि उपयोगकर्ताओं को उनके डिवाइसों के लिए, ऐप्लिकेशन में सही विकल्प (जैसे, डिवाइस कंट्रोल और सुझाई गई ऑटोमेशन सुविधाएं) दिखें, यह देखना ज़रूरी है कि डिवाइस का टाइप, डिवाइस का प्राइमरी टाइप है या नहीं.

if let deviceType =
  await device?.types.get(HumiditySensorDeviceType.self)
{
  if deviceType.metadata.isPrimaryType {
    print("Humidity Sensor is the primary type on this device.")
  } else {
    print("Humidity Sensor isn't the primary type on this device.")
  }
}

यह देखना कि कोई ट्रेट ऑनलाइन है या नहीं

किसी ट्रेट की कनेक्टिविटी की जांच करने के लिए, connectivityState प्रॉपर्टी पढ़ें:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

अगर डिवाइस में इंटरनेट कनेक्शन नहीं है, तो कुछ सुविधाएं ऑफ़लाइन दिख सकती हैं. आम तौर पर, Google smart home की सुविधाएं ऑफ़लाइन दिखती हैं. ऐसा इसलिए है, क्योंकि ये सुविधाएं क्लाउड पर आधारित हैं और इनमें लोकल राउटिंग की सुविधा नहीं होती.

किसी डिवाइस के लिए कनेक्टिविटी की जांच करना

किसी डिवाइस के लिए कनेक्टिविटी की जांच, डिवाइस टाइप के लेवल पर की जाती है. इसकी वजह यह है कि कुछ डिवाइस, कई तरह के डिवाइस टाइप के साथ काम करते हैं. जवाब में, उस डिवाइस पर मौजूद सभी सुविधाओं के लिए कनेक्टिविटी की स्थितियों का कॉम्बिनेशन मिलता है.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

इंटरनेट कनेक्शन न होने पर, अलग-अलग तरह के डिवाइसों के लिए partiallyOnline स्थिति दिख सकती है. Matter लोकल राउटिंग की वजह से, स्टैंडर्ड ट्रेट अब भी ऑनलाइन हो सकती हैं. हालांकि, क्लाउड पर आधारित ट्रेट ऑफ़लाइन हो जाएंगी.

डिवाइस का आईपी पता पाना

डिवाइस का आईपी पता ढूंढने के लिए, GeneralDiagnosticsTrait के networkInterfaces एट्रिब्यूट का इस्तेमाल करें. पते, Data ऑब्जेक्ट के तौर पर दिखाए जाते हैं. इन्हें Network फ़्रेमवर्क का इस्तेमाल करके, स्टैंडर्ड आईपीवी4 या आईपीवी6 स्ट्रिंग के तौर पर फ़ॉर्मैट किया जा सकता है:

func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
  let interfaces = trait.attributes.networkInterfaces ?? []
  var ipAddresses: [String] = []

  for interface in interfaces {
    for data in interface.iPv4Addresses {
      if let ipv4 = IPv4Address(data) {
        ipAddresses.append(String(describing: ipv4))
      }
    }
    for data in interface.iPv6Addresses {
      if let ipv6 = IPv6Address(data) {
        ipAddresses.append(String(describing: ipv6))
      }
    }
  }

  return ipAddresses
}

किसी ट्रेट की नेटवर्क राउटिंग की जांच करना

किसी विशेषता के लिए इलाके की जानकारी, Home API में भी उपलब्ध होती है. dataSourceLocality से पता चलता है कि इस ट्रेट को रिमोट से (क्लाउड के ज़रिए), स्थानीय तौर पर (लोकल हब के ज़रिए) या पीयर-टू-पीयर (डिवाइस से डिवाइस पर सीधे, बिना हब के) रूट किया गया है.

unspecified की वैल्यू 'जानकारी नहीं है' हो सकती है. उदाहरण के लिए, जब कोई ऐप्लिकेशन बूट हो रहा हो और डिवाइस कनेक्टिविटी के लिए, हब या सर्वर तक न पहुंचा हो. इन डिवाइसों से संपर्क नहीं किया जा सकता. इसलिए, ये डिवाइस कमांड या इवेंट से मिलने वाले इंटरैक्शन के अनुरोधों को पूरा नहीं कर पाएंगे. ऐसे डिवाइसों को कैसे हैंडल करना है, यह क्लाइंट पर निर्भर करता है.

let levelControlLocality =
  levelControlTrait.metadata.sourceConnectivity
  .dataSourceLocality

किसी डिवाइस के लिए नेटवर्क राउटिंग की जांच करना

कनेक्टिविटी की तरह, डिवाइस टाइप के हिसाब से इलाके की जांच की जाती है. जवाब में दी गई स्थिति, उस डिवाइस पर मौजूद सभी सुविधाओं के लिए इलाके की जानकारी का कॉम्बिनेशन होती है.

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

mixed की स्थिति, partiallyOnline कनेक्टिविटी की स्थिति की तरह ही हो सकती है: कुछ सुविधाएं क्लाउड पर आधारित होती हैं, जबकि अन्य स्थानीय होती हैं.

किसी डिवाइस का नाम बदलना

किसी डिवाइस का नाम बदलने के लिए, setName(_:) तरीके को कॉल करें:

let updatedDevice = try await theDevice.setName("new device name")

किसी डिवाइस का नाम बदलने पर, मूल HomeDevice स्ट्रक्चर में कोई बदलाव नहीं होता. हालांकि, बदलाव, अपडेट किए गए HomeDevice ऑब्जेक्ट में दिखता है.

अगर नाम में 60 यूनिकोड कोड पॉइंट (वर्ण) से ज़्यादा हैं, तो उन्हें छोटा कर दिया जाएगा. हालांकि, कोई गड़बड़ी नहीं दिखेगी. डेवलपर, लंबे नामों को मैनेज करने के लिए ज़िम्मेदार होते हैं. उदाहरण के लिए, वे यह तय कर सकते हैं कि उन्हें उपयोगकर्ताओं को यह सूचना देनी है या नहीं कि नाम छोटा कर दिया जाएगा.