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

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

import GoogleHomeSDK
import GoogleHomeTypes

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

مدیریت خطا

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

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

هرگونه خطای مدیریت نشده منجر به از کار افتادن برنامه شما خواهد شد.

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

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

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

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

با ارجاع به شیء Home ، devices() را فراخوانی کنید تا یک Query از دستگاه‌های قابل دسترسی دریافت کنید. متد batched() در Query را فراخوانی کنید، که یک مجموعه (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()

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

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

برای دریافت انواع دستگاه‌های مرتبط با یک دستگاه، ویژگی 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 برمی‌گرداند.

برای دریافت Publisher DeviceTypeCollection تابع DeviceTypeController.subscribeAll() را فراخوانی کنید. این کلاس به شما امکان می‌دهد بررسی کنید که آیا دستگاه مورد نظر نوع خاصی از دستگاه را دارد یا خیر:

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 استفاده کنید. به عنوان مثال، برای دریافت یک ویژگی خاص برای نوع دستگاه Dimmable Light:

if let dimmableLightDeviceType =
  await device.types.get(DimmableLightDeviceType.self)
{
  // Accessing standard trait on the type.
  let levelControlTrait =
    dimmableLightDeviceType.matterTraits.levelControlTrait.self
}

برای ویژگی‌های گوگل، از 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)
    }
  }
}

برای مشاهده لیست کامل ویژگی‌های موجود در رابط‌های برنامه‌نویسی کاربردی (API) صفحه اصلی، به فهرست ویژگی‌ها در 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)
  }

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

برای مشاهده لیست کاملی از انواع دستگاه‌ها و ویژگی‌های آنها که در رابط‌های برنامه‌نویسی کاربردی (API) صفحه اصلی (Home) موجود است، به انواع دستگاه‌های پشتیبانی‌شده در 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 آنها قرار دهید:

  • اتحادیه استانداردهای اتصال (CSA) شناسه فروشنده را صادر کرد: "matterOriginalVendorId": "0xfff1",

  • یک شناسه محصول که به طور منحصر به فرد محصول یک فروشنده را مشخص می‌کند: "matterOriginalProductId": "0x1234",

  • یک شناسه منحصر به فرد برای دستگاه، که به شیوه‌ای مختص به سازنده ساخته شده است: "matterUniqueId": "matter-device-id",

هنگام وارد کردن این فیلدهای رشته‌ای، در صورت داشتن شناسه‌های فروشنده و محصول Matter ، از آنها استفاده کنید. اگر عضو CSA نیستید و این شناسه‌ها به شما اختصاص داده نشده است، می‌توانید فیلدهای 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",
          }
        ]
      }
    ]
  }
}

برای اطلاعات بیشتر، به مستندات SYNC Cloud-to-cloud مراجعه کنید.

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

دستگاه‌ها و ویژگی‌های موجود در APIهای Home دارای فراداده‌هایی هستند که به آنها مرتبط هستند و می‌توانند در مدیریت تجربه کاربری در یک برنامه کمک کنند.

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

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

برخی از دستگاه‌ها ممکن است چندین نوع دستگاه را از طریق APIهای 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

برخی از ویژگی‌ها، معمولاً ویژگی‌های smart home گوگل، ممکن است در صورت عدم اتصال دستگاه به اینترنت، به صورت آفلاین نمایش داده شوند. دلیل این امر این است که این ویژگی‌ها مبتنی بر ابر هستند و مسیریابی محلی ندارند.

بررسی اتصال دستگاه

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

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

در صورت عدم اتصال به اینترنت، ممکن است در مورد انواع دستگاه‌های ترکیبی، حالت partiallyOnline مشاهده شود. ویژگی‌های استاندارد Matter ممکن است به دلیل مسیریابی محلی هنوز آنلاین باشند، اما ویژگی‌های مبتنی بر ابر آفلاین خواهند بود.

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

موقعیت مکانی یک ویژگی (trait) نیز در APIهای Home موجود است. dataSourceLocality نشان می‌دهد که آیا ویژگی از راه دور (از طریق ابر)، محلی (از طریق یک هاب محلی) یا نظیر به نظیر (مستقیم از دستگاهی به دستگاه دیگر، بدون هاب) مسیریابی می‌شود.

مقدار نامشخص محلی بودن (unknown locality value 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 به‌روزرسانی‌شده‌ی بازگشتی منعکس می‌شود.

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

لیست API

پس از ایجاد یک نمونه از Home ، APIهای دستگاه زیر از طریق آن قابل دسترسی هستند:

رابط برنامه‌نویسی کاربردی توضیحات
device(id:) یک Publisher برای دستگاه مشخص شده برمی‌گرداند که هر زمان وضعیت دستگاه تغییر کند، آن را منتشر می‌کند.
devices() تمام دستگاه‌ها را در تمام ساختارهای حساب گوگل دریافت کنید. یک Query<HomeDevice> برمی‌گرداند که گزینه‌های بازیابی و فیلتر بیشتری را ارائه می‌دهد.

زمانی که HomeDevice را داشته باشید، APIهای زیر از طریق آن قابل دسترسی هستند:

رابط برنامه‌نویسی کاربردی توضیحات
id شناسه سیستم منحصر به فرد دستگاه.
name نام دستگاه که توسط کاربر ارائه شده است.
structureID شناسه ساختاری که دستگاه به آن اختصاص داده شده است. یک String?
roomID شناسه اتاقی که دستگاه به آن اختصاص داده شده است. یک String?
types یک نوع خاص یا همه انواع موجود در دستگاه را دریافت کنید.
isMatterDevice اگر دستگاه توسط Matter پشتیبانی می‌شود.
sourceConnectivity اتصال منبع دستگاه، که نشان‌دهنده‌ی حالت‌های اتصال تجمیعی و موقعیت مکانی شبکه‌ی ویژگی‌های دستگاه است.