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

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

import GoogleHomeSDK
import GoogleHomeTypes

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

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

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

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

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

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

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

نماذج لعمليات طلب البيانات

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

باستخدام مرجع إلى العنصر Home ، استدعِ devices() للحصول على Query عن الأجهزة التي يمكن الوصول إليها. استدعِ الطريقة Query's 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()

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

باستخدام الإصدار 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
}

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

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

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

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