دسترسی به دستگاه‌ها و فراداده‌های دستگاه برای Android

ازطریق Home APIs برای Android می‌توان به Device APIs دسترسی پیدا کرد. این بسته‌ها را به برنامه‌تان وارد کنید:

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 را ببینید.

مدیریت کردن خطا

هر روشی در Home APIs می‌تواند 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()

از آنجا می‌توانید به وضعیت‌های هر دستگاه دسترسی داشته باشید و به دستگاه‌ها فرمان ارسال کنید.

با انتشار نسخه ۱.۸ از Home APIs، این گزینه را دارید که با تنظیم کردن پارامتر enableMultipartDevices از روش devices() روی true، کاری کنید که API هر دستگاه چندبخشی را به‌عنوان یک دستگاه واحد نشان دهد. برای اطلاعات بیشتر، دستگاه‌های چندبخشی در Android را ببینید.

خواندن وضعیت دستگاه

نمونه‌ای از بررسی مشخصه OnOff از ویژگی «روشن/خاموش» دستگاه را ببینید. بااستفاده از مدل داده مشخصه Home APIs، که در آن این مشخصه به‌عنوان 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()!!

برای کسب اطلاعات بیشتر درباره تابع Kotlin flow، به distinctUntilChanged مراجعه کنید.

نامعتبر کردن وضعیت در اشتراک ویژگی

رابط 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) } }

برای مشاهده فهرست کامل ویژگی‌های دردسترس در Home APIs، میانای Trait را ببینید.

دریافت فهرست دستگاه‌هایی با انواع دستگاه مشابه

برای دریافت فهرست دستگاه‌هایی که همه چراغ‌های خانه را نشان می‌دهند:

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

در Home APIs، چندین نوع دستگاه وجود دارد که می‌تواند نشان‌دهنده نوع دستگاه اصلی باشد. برای مثال، نوع دستگاه «چراغ» وجود ندارد. درعوض، چهار نوع دستگاه مختلف وجود دارد که می‌تواند نشان‌دهنده چراغ باشد، همان‌طور که در مثال قبلی نشان داده شده است. به همین دلیل، برای دریافت نمای جامع از نوع سطح بالاتر دستگاه در خانه، باید چندین نوع دستگاه در جریان‌های فیلترشده گنجانده شود.

برای مشاهده فهرست کامل انواع دستگاه‌های دردسترس در Home APIs، میانای DeviceType را ببینید.

دریافت شناسه فروشنده یا شناسه محصول برای دستگاه

ویژگی 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 را ببینید.

فراداده‌های دستگاه و ویژگی

دستگاه‌ها و ویژگی‌ها در Home APIs فراداده‌های مرتبط با خودشان را دارند، که می‌تواند به مدیریت تجربه کاربری در برنامه کمک کند.

هر مشخصه در Home APIs حاوی ویژگی sourceConnectivity است که اطلاعاتی درباره وضعیت آنلاین و محلی بودن مشخصه (مسیریابی محلی یا ازراه‌دور) دارد.

دریافت نوع اصلی دستگاه

برخی‌از دستگاه‌ها ممکن است چندین نوع دستگاه را ازطریق Home APIs ارائه دهند. برای اطمینان از اینکه گزینه‌های مناسب در برنامه (مانند کنترل دستگاه و خودکارسازی‌های پیشنهادی) برای دستگاه‌های کاربران ارائه می‌شود، مفید است که بررسی کنید نوع دستگاه اصلی برای یک دستگاه چیست.

ابتدا، نوع(های) دستگاه را بااستفاده از 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()

بررسی مسیریابی شبکه یک ویژگی

محل ویژگی نیز در Home APIs دردسترس است. dataSourceLocality نشان می‌دهد که آیا ویژگی از راه دور (ازطریق ابر)، به‌صورت محلی (ازطریق کانون محلی)، یا همتا به همتا (مستقیماً از دستگاه به دستگاه، بدون کانون) مسیریابی می‌شود یا نه.

مقدار محلی ناشناخته UNSPECIFIED ممکن است، برای مثال، زمانی که برنامه درحال راه‌اندازی است و هنوز به کانون یا سروری برای اتصال دستگاه نرسیده است. این دستگاه‌ها دردسترس نیستند و درخواست‌های تعامل از فرمان‌ها یا رویدادها را انجام نخواهند داد. تصمیم‌گیری درباره نحوه مدیریت این دستگاه‌ها برعهده کارخواه است.

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

بررسی مسیریابی شبکه برای دستگاه

مانند اتصال‌پذیری، محلی بودن در سطح نوع دستگاه بررسی می‌شود. وضعیت برگردانده‌شده ترکیبی از محلی بودن همه ویژگی‌های آن دستگاه است.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

وضعیت MIXED ممکن است در سناریویی مشابه سناریوی اتصال PARTIALLY_ONLINE مشاهده شود: برخی‌از ویژگی‌ها مبتنی بر ابر هستند درحالی‌که برخی دیگر محلی هستند.

تغییر نام دستگاه

برای تغییر نام دستگاه، روش setName() را فراخوانی کنید:

mixerDevice.setName("Grendel")

اگر نام‌ها از حد ۶۰ نقطه کد یونی‌کد (نویسه) فراتر برود، کوتاه می‌شود و هیچ خطایی نشان داده نخواهد شد. توسعه‌دهندگان مسئول مدیریت نام‌های طولانی هستند و برای مثال می‌توانند تصمیم بگیرند که آیا می‌خواهند به کاربران اطلاع دهند که نام‌ها کوتاه خواهد شد یا نه.

بررسی عضویت گروه برای دستگاه

دستگاه فیزیکی می‌تواند به یک یا چند گروه دستگاه تعلق داشته باشد. برای دیدن اینکه دستگاه به کدام گروه‌ها تعلق دارد، ویژگی GroupMembership را در دستگاه بررسی کنید:

val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
  println("HomeAPI", "Device belongs to group: $groupId")
}

برعکس، می‌توانید همه دستگاه‌های عضو متعلق به DeviceGroup را با فراخوانی جریان devices() در DeviceGroup مشاهده کنید:

group.devices(enableMultipartDevices = true).collect { members ->
  println("HomeAPI", "Group contains ${members.size} devices")
}

برای بررسی انواع دستگاه‌های پشتیبانی‌شده توسط DeviceGroup و ارسال فرمان به گروه به‌عنوان یک موجودیت واحد، به کنترل گروه دستگاه مراجعه کنید.