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

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

import GoogleHomeSDK
import GoogleHomeTypes

Более подробную информацию см. в разделе Модель данных на iOS .

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

Некоторые методы в Home API выдают 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 deviceType = 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 . Например, чтобы получить конкретную характеристику для типа устройства Dimmable Light:

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.googleTraits.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] = []
var 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 включает в себя такую информацию, как идентификатор поставщика, идентификатор продукта, название продукта и серийный номер устройства:

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",
          }
        ]
      }
    ]
  }
}

Более подробную информацию см. в документации Cloud-to-cloud SYNC .

Метаданные устройств и характеристик

С устройствами и характеристиками в 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 могут оставаться онлайн благодаря локальной маршрутизации, но облачные трейты будут недоступны.

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

Местоположение признака также доступно в API Home. Параметр dataSourceLocality указывает, маршрутизируется ли признак удалённо (через облако), локально (через локальный концентратор) или одноранговым способом (напрямую с устройства на устройство, без концентратора).

Значение «unknown locality» (неизвестная локализация) может быть unspecified , например, когда приложение загружается и ещё не достигло концентратора или сервера для подключения устройств. Эти устройства недоступны и не будут отвечать на запросы взаимодействия от команд или событий. Клиент должен самостоятельно определить, как обращаться с такими устройствами.

let levelControlLocality =
  levelControlTrait.metadata.sourceConnectivity
  .dataSourceLocality

Проверьте сетевую маршрутизацию для устройства

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

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

В аналогичном сценарии, как и при partiallyOnline -подключении, можно наблюдать mixed состояние: некоторые характеристики являются облачными, а другие — локальными.

Изменить имя устройства

Вызовите метод setName(_:) , чтобы изменить имя устройства:

let updatedDevice = try await theDevice.setName("new device name")

При изменении имени устройства исходная структура HomeDevice остается прежней, а изменение отражается в возвращаемом обновленном объекте HomeDevice .

Имена будут усечены, если их длина превышает лимит в 60 кодовых точек (символов) Unicode, без каких-либо ошибок. Разработчики несут ответственность за обработку длинных имён и, например, могут решить, следует ли уведомлять пользователей о том, что имена будут усечены.

список API

После создания экземпляра Home через него становятся доступны следующие API-интерфейсы устройств:

API Описание
device(id:) Возвращает Publisher для указанного устройства, который передает состояние устройства при каждом его изменении.
devices() Получить все устройства во всех структурах учётной записи Google. Возвращает запрос Query<HomeDevice> , который предоставляет дополнительные возможности поиска и фильтрации.

Если у вас есть HomeDevice , через него доступны следующие API:

API Описание
id Уникальный системный идентификатор устройства.
name Имя устройства, указанное пользователем.
structureID Идентификатор структуры, к которой назначено устройство. Возвращает String? .
roomID Идентификатор комнаты, к которой назначено устройство. Возвращает String? .
types Получить определенный тип или все доступные типы на устройстве.
isMatterDevice Если устройство поддерживается Matter .
sourceConnectivity Исходная связность устройства, представляющая агрегированные состояния связности и сетевую локальность характеристик устройства.