Доступ к устройствам и метаданным устройств для iOS

Доступ к API устройств можно получить через API Home для iOS. Импортируйте следующие пакеты в свое приложение:

import GoogleHomeSDK
import GoogleHomeTypes

Для получения дополнительной информации см. раздел «Модель данных в iOS» .

Обработка ошибок

Некоторые методы в API Home генерируют HomeError , поэтому мы рекомендуем использовать блок do-catch для обработки таких HomeError .

При обработке HomeError проверьте поля code и message , чтобы выяснить, что пошло не так.

Любые необработанные ошибки приведут к сбою вашего приложения.

Для получения более подробной информации см. раздел «Обработка ошибок» .

Пример см. в разделе «Отправка команды устройству» .

Примеры вызовов

Получить список устройств

Используя ссылку на объект Home , вызовите devices() , чтобы получить Query доступных устройств. Вызовите метод batched() объекта Query , который генерирует множество, отражающее текущее состояние объекта 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 .

Вызовите 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 в характеристике On/Off устройства:

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 Home, см. в разделе «Индекс характеристик» на 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 существует несколько типов устройств, которые могут представлять собой основной тип устройства. Например, типа устройства «Освещение» не существует. Вместо этого, как показано в предыдущем примере, существует четыре различных типа устройств, которые могут представлять собой светильник. Таким образом, для получения полного представления о типах устройств более высокого уровня в доме необходимо включить несколько типов устройств.

Полный список типов устройств и их характеристик, доступных в API Home, см. в разделе « Поддерживаемые типы устройств на iOS» .

Получите название производителя, идентификатор производителя или идентификатор продукта для устройства.

Трейт BasicInformationTrait содержит такую ​​информацию, как идентификатор поставщика (Vendor ID), идентификатор продукта (Product ID), название продукта (Product Name) и серийный номер устройства:

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 от Google, могут отображаться как «в автономном режиме», если устройство не подключено к интернету. Это связано с тем, что эти функции работают в облаке и не имеют локальной маршрутизации.

Проверьте подключение устройства.

Проверка подключения устройства фактически осуществляется на уровне типа устройства, поскольку некоторые устройства поддерживают несколько типов. Возвращаемое состояние представляет собой комбинацию состояний подключения для всех характеристик данного устройства.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Состояние partiallyOnline может наблюдаться в случае использования устройств разных типов при отсутствии подключения к интернету. Стандартные характеристики Matter могут оставаться в сети благодаря локальной маршрутизации, но облачные характеристики будут отключены.

Проверьте сетевую маршрутизацию признака.

Информация о местоположении для параметра dataSourceLocality также доступна в API 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, при этом ошибок возникать не будет. Разработчики несут ответственность за обработку длинных имен и, например, могут решить, сообщать ли пользователям о том, что имена будут усечены.