الوصول إلى الأجهزة والبيانات الوصفية للأجهزة في نظام التشغيل iOS

يمكن الوصول إلى واجهات برمجة التطبيقات الخاصة بالأجهزة من خلال واجهات برمجة تطبيقات Home لنظام التشغيل iOS. استورِد الحزم التالية إلى تطبيقك:

import GoogleHomeSDK
import GoogleHomeTypes

لمزيد من المعلومات، يُرجى الاطّلاع على نموذج البيانات على iOS.

معالجة الأخطاء

تُرسل بعض الطرق في واجهات برمجة تطبيقات Home الخطأ HomeError، لذا ننصحك باستخدام كتلة do-catch لرصد HomeError في هذه الطلبات.

عند التعامل مع HomeError، يُرجى التحقّق من حقلَي code وmessage لمعرفة الخطأ الذي حدث.

ستؤدي أي أخطاء لم تتم معالجتها إلى تعطُّل تطبيقك.

لمزيد من المعلومات، يُرجى الاطّلاع على معالجة الأخطاء.

يمكنك الاطّلاع على إرسال أمر إلى جهاز للحصول على مثال.

عيّنة من المكالمات

الحصول على قائمة بالأجهزة

بالإشارة إلى عنصر Home، يمكنك استدعاء devices() للحصول على Query للأجهزة التي يمكن الوصول إليها. استدعِ طريقة batched() في Query التي تُصدر مجموعة تعكس الحالة الحالية للمنزل مع كل تغيير في البيانات الوصفية للجهاز. أو يمكنك الاتصال بالرقم Query.list() للحصول على نظرة سريعة على الأجهزة المتاحة. هذه طريقة ملائمة للاشتراك في بث batched() وعرض أول قيمة تم إرسالها. Query.stream() تُنشئ بثًا يعرض قيمًا جديدة عند تغيير البيانات الوصفية للجهاز، مثل اسمه أو غرفته أو بنيته. داخليًا، تستخدم هذه السمة batched() وتُصدر فقط السمات التي تم تغييرها.

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

ومن هناك، يمكنك الوصول إلى حالات كل جهاز وإرسال الأوامر إلى الأجهزة.

في الإصدار 1.8 من واجهات برمجة تطبيقات Home، يمكنك اختيار أن تمثّل واجهة برمجة التطبيقات كل جهاز متعدّد الأجزاء كجهاز واحد من خلال ضبط مَعلمة enableMultipartDevices في طريقة devices() على 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.

اتصِل بالرقم DeviceTypeController.subscribeAll() للحصول على Publisher DeviceTypeCollection. تتيح لك هذه الفئة التحقّق مما إذا كان الجهاز يحتوي على نوع جهاز معيّن:

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
}

الحصول على قائمة بالأجهزة التي تتضمّن سمة معيّنة

للحصول على قائمة بالأجهزة التي تتضمّن سمة معيّنة، عليك تكرار العملية على الأجهزة وأنواعها وسماتها. على سبيل المثال، للحصول على قائمة بالأجهزة في المنزل التي تتضمّن جميعها السمة On/Off:

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

يمكنك الاطّلاع على فهرس السمات على iOS للحصول على قائمة كاملة بالسمات المتاحة في واجهات برمجة تطبيقات Home.

الحصول على قائمة بالأجهزة ذات الأنواع المشابهة

للحصول على قائمة بالأجهزة التي تمثّل جميع المصابيح في المنزل:

// 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 التي يمكن أن تمثّل نوع جهاز أساسي. على سبيل المثال، لا يتوفّر نوع جهاز "مصباح". بدلاً من ذلك، هناك أربعة أنواع مختلفة من الأجهزة التي يمكن أن تمثّل مصباحًا، كما هو موضّح في المثال السابق. لذلك، للحصول على نظرة شاملة على نوع الجهاز ذي المستوى الأعلى في المنزل، يجب تضمين أنواع أجهزة متعددة.

يمكنك الاطّلاع على أنواع الأجهزة المتوافقة على iOS للحصول على قائمة كاملة بأنواع الأجهزة وسماتها المتاحة في واجهات برمجة تطبيقات Home.

الحصول على اسم المورِّد أو معرِّفه أو معرِّف المنتج لجهاز معيّن

تتضمّن السمة 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، يمكنك تضمين حقول السلسلة هذه في استجابة SYNC لتحديد أجهزة Cloud-to-cloud من خلال سمة BasicInformation:

  • رقم تعريف المورّد الصادر عن Connectivity Standards Alliance (Alliance): "matterOriginalVendorId": "0xfff1",

  • معرّف منتج يحدّد بشكل فريد منتجًا تابعًا لمورّد: "matterOriginalProductId": "0x1234",

  • معرّف فريد للجهاز، يتم إنشاؤه بطريقة خاصة بالشركة المصنّعة: "matterUniqueId": "matter-device-id",

عند إدخال حقول السلسلة هذه، استخدِم Matter معرّفات المورّدين والمنتجات إذا كانت لديك. إذا لم تكن عضوًا في Alliance ولم يتم منحك رقمَي التعريف هذين، يمكنك ترك الحقلَين matterOriginalVendorId وmatterOriginalProductId فارغَين وتقديم matterUniqueId كمعرّف.

يوضّح نموذج استجابة SYNC استخدام هذه الحقول:

{
  "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 على بيانات وصفية مرتبطة بها، والتي يمكن أن تساعد في إدارة تجربة المستخدم في أحد التطبيقات.

تحتوي كل سمة في واجهات برمجة تطبيقات Home على السمة sourceConnectivity التي تتضمّن معلومات عن حالة السمة على الإنترنت وموقعها الجغرافي (التوجيه المحلي أو عن بُعد).

الحصول على النوع الأساسي للجهاز

قد تعرض بعض الأجهزة أنواعًا متعددة من الأجهزة من خلال واجهات برمجة تطبيقات Home. لضمان عرض الخيارات المناسبة للمستخدمين في تطبيق (مثل التحكّم في الجهاز وعمليات التشغيل الآلي المقترَحة) لأجهزتهم، من المفيد التحقّق مما إذا كان نوع الجهاز هو النوع الأساسي للجهاز.

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 العادية متصلة بالإنترنت بسبب التوجيه المحلي، ولكنّ السمات المستندة إلى السحابة الإلكترونية ستكون غير متصلة بالإنترنت.

الحصول على عنوان IP للجهاز

للعثور على عنوان IP الخاص بالجهاز، استخدِم السمة networkInterfaces في GeneralDiagnosticsTrait. يتم عرض العناوين كعناصر Data، والتي يمكنك تنسيقها إلى سلاسل IPv4 أو IPv6 عادية باستخدام إطار عمل Network:

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. يشير 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 قيمة موضع رمز يونيكود (حرف)، ولن تظهر أي أخطاء. يتحمّل المطوّرون مسؤولية التعامل مع الأسماء الطويلة، ويمكنهم، على سبيل المثال، تحديد ما إذا كانوا يريدون إبلاغ المستخدمين بأنّ الأسماء سيتم اقتطاعها.

التحقّق من عضوية مجموعة لجهاز

يمكن أن ينتمي الجهاز الفعلي إلى مجموعة أجهزة واحدة أو أكثر. لمعرفة المجموعات التي ينتمي إليها الجهاز، يُرجى الاطّلاع على GroupMembershipTrait على الجهاز:

if let trait = await device.traits.get(Google.GroupMembershipTrait.self) {
  for groupId in trait.attributes.groupObjectIdsArray {
    print("Device belongs to group: \(groupId)")
  }
}

لفحص أنواع الأجهزة التي تتيحها DeviceGroup وإرسال الأوامر إلى المجموعة ككيان واحد، يُرجى الاطّلاع على التحكّم في مجموعة أجهزة.