الوصول إلى الأجهزة والبيانات الوصفية للأجهزة على Android

يمكن الوصول إلى واجهات برمجة التطبيقات للأجهزة من خلال واجهات برمجة التطبيقات لمنزل Google على Android. يُرجى استيراد هذه الحِزم إلى تطبيقك:

import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id

لاستخدام أنواع أو سمات أجهزة معيّنة مع واجهات برمجة التطبيقات للأجهزة، يجب استيرادها بشكل فردي.

على سبيل المثال، لاستخدام سمة "تشغيل/إيقاف" Matter ونوع الجهاز "وحدة توصيل تشغيل/إيقاف" ، يُرجى استيراد الحِزم التالية إلى تطبيقك:

import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice

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

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

يمكن لأي طريقة في واجهات برمجة التطبيقات لمنزل Google طرح HomeException، لذا ننصحك باستخدام كتلة try-catch لرصد HomeException في جميع الطلبات.

عند معالجة HomeException، يُرجى الاطّلاع على الحقلَين error.code و error.message لمعرفة المشكلة. قد تكون هناك رموز أخطاء فرعية أيضًا، لذا يُرجى استدعاء طريقة getSubErrorCodes() والاطّلاع على النتيجة.

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

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

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

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

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

بعد الحصول على مرجع لمثيل Structure، يعرض طلب devices() عنصر Flow للأجهزة التي يمكنك الوصول إليها من هذا البنية:

// Get a flow of all devices accessible to the user
val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allDevices: Set<HomeDevice> = allDevicesFlow.list()

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

مع الإصدار 1.8 من واجهات برمجة التطبيقات لمنزل Google، يتوفّر لك خيار أن تمثّل واجهة برمجة التطبيقات كل جهاز متعدد الأجزاء كجهاز واحد من خلال ضبط المعلمة enableMultipartDevices لطريقة devices() على true. لمزيد من المعلومات، يُرجى الاطّلاع على الأجهزة متعددة الأجزاء على Android.

قراءة حالة الجهاز

يُرجى الاطّلاع على مثال للتحقّق من سمة OnOff من سمة "تشغيل/إيقاف" للجهاز. باستخدام نموذج بيانات سمة واجهات برمجة التطبيقات لمنزل Google، حيث يتم تحديد هذه السمة على أنّها OnOff، يمكنك استرداد بيانات السمة من خلال فئة standardTraits لنوع الجهاز:

// Assuming we have a device.
val deviceFlow = home.devices().itemFlow(myDeviceId)

val device = deviceFlow.first()

// Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger
// on the specific trait changes and not the whole type.
val onOffTraitFlow: Flow<OnOff?> =
  device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged()

val onOffTrait: OnOff = onOffTraitFlow.first()!!

يُرجى الاطّلاع على distinctUntilChanged لمزيد من المعلومات حول دالة Kotlin flow.

إبطال الحالة في اشتراك سمة

توفر واجهة TraitStateInvalidation إمكانية إبطال حالة تم استردادها من خلال الاشتراكات في جهاز الاختبار في الحالات التي لا يتم فيها الإبلاغ عن الحالة بشكل صحيح. تشمل الأمثلة على الحالات التي قد لا يتم فيها الإبلاغ عن الحالة بشكل صحيح استخدام السمات في سمات Matter بجودة "C" أو بسبب تنفيذ الجهاز الذي يتسبب في المشكلة بشكل غير متوقع.

تُصدر واجهة برمجة التطبيقات هذه قراءة إجبارية لحالة السمة الحالية وتعرض النتيجة من خلال تدفقات السمات الحالية.

يُرجى الحصول على السمة، ثم تشغيل forceRead على السمة:

val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()

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

يجب استخدام أنواع الأجهزة كنقطة دخول لقراءة السمات، لأنّها تقسم الجهاز إلى أجزائه الوظيفية (مثل نقاط النهاية في Matter).

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

للحصول على قائمة بالسمات المتاحة لنوع الجهاز "مصباح قابل للتعتيم":

// Get all types available on this device. Requires the types to be part of the registry during
// SDK initialization.
val typesFlow: Flow<Set<DeviceType>> = device.types()

// Get a snapshot of all types.
val types: Set<DeviceType> = typesFlow.first()

// Get the DimmableLightDevice instance from the set of types.
val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull()

// Get all traits in the type + traits registered
val allTraits: Set<Trait> = dimmableLightDevice!!.traits()

يمكن أن يحدث نوع آخر من تعارض السمات عندما يتضمّن الجهاز سمتَين بالاسم نفسه. على سبيل المثال، يمكن أن يشير onOff إلى مثال على سمة OnOff العادية، أو يمكن أن يشير إلى مثال على سمة OnOff التي يحدّدها المصنّع. لإزالة أي غموض محتمل بشأن السمة المقصودة، يجب أن يسبق مثال Trait الذي تتم الإشارة إليه من خلال جهاز مساحة اسم مؤهّلة. بالنسبة إلى السمات العادية، أي تلك المشابهة لـ Matter المجموعات العادية، استخدِم standardTraits. بالنسبة إلى سمات Google، استخدِم googleTraits:

// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl

للوصول إلى سمة خاصة بالمصنّع، يُرجى الإشارة إليها مباشرةً:

// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)

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

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

// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }

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

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

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

// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

تتضمّن واجهات برمجة التطبيقات لمنزل Google أنواع أجهزة متعددة يمكن أن تمثّل نوع جهاز أساسي. على سبيل المثال، لا يتوفّر نوع الجهاز "مصباح". بدلاً من ذلك، تتوفّر أربعة أنواع أجهزة مختلفة يمكن أن تمثّل مصباحًا، كما هو موضّح في المثال السابق. للحصول على عرض شامل لنوع الجهاز ذي المستوى الأعلى في المنزل، يجب تضمين أنواع أجهزة متعددة في التدفقات الفلترة.

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

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

تتضمّن السمة BasicInformation معلومات مثل رقم تعريف المورّد ورقم تعريف المنتج واسم المنتج و الرقم التسلسلي للجهاز:

// Get device basic information. All general information traits are on the RootNodeDevice type.
val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!!
println("vendorName ${basicInformation.vendorName}")
println("vendorId ${basicInformation.vendorId}")
println("productId ${basicInformation.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.

البيانات الوصفية للجهاز والسمة

تتضمّن الأجهزة والسمات في واجهات برمجة التطبيقات لمنزل Google بيانات وصفية مرتبطة بها، ما يمكن أن يساعد في إدارة تجربة المستخدم في أحد التطبيقات.

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

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

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

أولاً، يُرجى الحصول على نوع(أنواع) الجهاز باستخدام type()، ثم تحديد النوع(الأنواع) الأساسي:

val types = device.types().first()
val primaryTypes = types.filter { it.metadata.isPrimaryType }

التحقّق ممّا إذا كانت السمة متصلة بالإنترنت

يُرجى استخدام طريقة connectivityState() للتحقّق من اتصال السمة:

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

قد تظهر بعض السمات، وعادةً ما تكون سمات Google smart home، غير متصلة بالإنترنت إذا لم يكن الجهاز متصلاً بالإنترنت. يرجع ذلك إلى أنّ هذه السمات مستندة إلى السحابة الإلكترونية وليس لها توجيه محلي.

التحقّق من اتصال الجهاز

يتم في الواقع التحقّق من اتصال الجهاز على مستوى نوع الجهاز لأنّ بعض الأجهزة تتيح استخدام أنواع أجهزة متعددة. الحالة المعروضة هي مزيج من حالات الاتصال لجميع السمات على هذا الجهاز.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

قد تظهر حالة PARTIALLY_ONLINE في حالة أنواع الأجهزة المختلطة عندما لا يكون هناك اتصال بالإنترنت. قد تظل سمات Matter العادية متصلة بالإنترنت بسبب التوجيه المحلي ، ولكن ستكون السمات المستندة إلى السحابة الإلكترونية غير متصلة بالإنترنت.

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

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

val ipAddresses =
  trait.networkInterfaces?.flatMap { networkInterface ->
    (networkInterface.ipv4Addresses + networkInterface.ipv6Addresses).mapNotNull { bytes ->
      try {
        java.net.InetAddress.getByAddress(bytes).hostAddress
      } catch (e: java.net.UnknownHostException) {
        null
      }
    }
  } ?: emptyList()

التحقّق من توجيه الشبكة لسمة

يتوفّر أيضًا الموقع الجغرافي لسمة في واجهات برمجة التطبيقات لمنزل Google. تشير dataSourceLocality إلى ما إذا كانت السمة يتم توجيهها عن بُعد (من خلال السحابة الإلكترونية) أو محليًا (من خلال مركز محلي) أو من نظير إلى نظير (مباشرةً من جهاز إلى جهاز، بدون مركز).

يمكن أن تظهر قيمة الموقع الجغرافي غير المعروف UNSPECIFIED، على سبيل المثال، أثناء تشغيل أحد التطبيقات ولم يصل بعد إلى مركز أو خادم لاتصال الجهاز. لا يمكن الوصول إلى هذه الأجهزة وستفشل طلبات التفاعل من الأوامر أو الأحداث. يقع على عاتق العميل تحديد كيفية التعامل مع هذه الأجهزة.

val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality

التحقّق من توجيه الشبكة لجهاز

على غرار الاتصال، يتم التحقّق من الموقع الجغرافي على مستوى نوع الجهاز. الحالة المعروضة هي مزيج من الموقع الجغرافي لجميع السمات على هذا الجهاز.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

قد تظهر حالة MIXED في سيناريو مشابه لحالة الاتصال PARTIALLY_ONLINE: بعض السمات مستندة إلى السحابة الإلكترونية بينما البعض الآخر محلي.

تغيير اسم الجهاز

يُرجى استدعاء طريقة setName() لتغيير اسم الجهاز:

mixerDevice.setName("Grendel")

سيتم اقتطاع الأسماء إذا تجاوزت الحدّ الأقصى لعدد مواضع رموز Unicode (الأحرف) البالغ 60، ولن يتم عرض أي أخطاء. يتحمّل المطوّرون مسؤولية التعامل مع الأسماء الطويلة، ويمكنهم مثلاً تحديد ما إذا كانوا يريدون إبلاغ المستخدمين بأنّه سيتم اقتطاع الأسماء.