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

میاناهای برنامه‌سازی کاربردی دستگاه ممکن است ازطریق Home APIs برای iOS قابل‌دسترسی باشند. بسته‌های زیر را به برنامه‌تان وارد کنید:

import GoogleHomeSDK
import GoogleHomeTypes

برای اطلاعات بیشتر، مدل داده در iOS را ببینید.

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

برخی‌از روش‌ها در Home APIs HomeError را برمی‌گردانند، بنابراین توصیه می‌کنیم از بلوک do-catch برای گرفتن HomeError در آن تماس‌ها استفاده کنید.

هنگام رسیدگی به HomeError، فیلدهای code و message آن را بررسی کنید تا متوجه شوید مشکل چه بوده است.

هرگونه خطای رسیدگی‌نشده باعث ازکار افتادن برنامه‌تان می‌شود.

برای اطلاعات بیشتر، به رسیدگی به خطا مراجعه کنید.

برای دیدن نمونه، به ارسال فرمان به دستگاه مراجعه کنید.

تماس‌های نمونه

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

با ارجاع به شیء Home، devices() را فراخوانی کنید تا Query دستگاه‌های دردسترس را دریافت کنید. متد Query batched() را فراخوانی کنید که با هر تغییر فراداده دستگاه، یک Set منعکس‌کننده وضعیت فعلی Home را منتشر می‌کند. یا با 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 APIs، این گزینه را دارید که با تنظیم کردن پارامتر enableMultipartDevices از روش devices() روی true، کاری کنید که API هر دستگاه چندبخشی را به‌عنوان یک دستگاه واحد نشان دهد. برای اطلاعات بیشتر، دستگاه‌های چندبخشی در 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() تماس بگیرید تا DeviceTypeCollection Publisher دریافت کنید. این کلاس به شما امکان می‌دهد بررسی کنید که آیا دستگاه نوع دستگاه خاصی دارد یا نه:

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 APIs، نمایه ویژگی‌ها در 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 APIs، چندین نوع دستگاه وجود دارد که می‌تواند نشان‌دهنده نوع دستگاه اصلی باشد. برای مثال، نوع دستگاه «چراغ» وجود ندارد. درعوض، چهار نوع دستگاه مختلف وجود دارد که می‌تواند نشان‌دهنده چراغ باشد، همان‌طور که در مثال قبلی نشان داده شده است. بنابراین، برای دریافت نمای جامعی از نوع دستگاه سطح بالاتر در خانه، باید چندین نوع دستگاه گنجانده شود.

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

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 برگردانده می‌شوند که می‌توانید آن‌ها را بااستفاده از چارچوب Network به رشته‌های استاندارد IPv4 یا IPv6 قالب‌بندی کنید:

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 APIs دردسترس است. 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 به‌روزشده برگردانده‌شده منعکس می‌شود.

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

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

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

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

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