Доступ к API устройств можно получить через Home API для iOS. Импортируйте в приложение следующие пакеты:
import GoogleHomeSDK
import GoogleHomeTypes
Подробнее о модели данных в iOS…
Обработка ошибок
Некоторые методы в Home API вызывают HomeError, поэтому мы рекомендуем использовать блок do-catch, чтобы перехватывать HomeError при таких вызовах.
При обработке HomeError проверьте поля code и message, чтобы узнать, что пошло не так.
Если не обработать ошибки, приложение будет работать со сбоями.
Подробнее об обработке ошибок…
Пример приведен в разделе Как отправить команду на устройство.
Примеры звонков
Как получить список устройств
Используя ссылку на объект Home, вызовите devices(), чтобы получить Query доступных устройств.
Вызовите метод batched() класса Query, который возвращает набор, отражающий текущее состояние дома при каждом изменении метаданных устройства. Вы также можете вызвать метод Query.list(), чтобы получить список доступных устройств. Это удобный метод, который подписывается на поток batched() и возвращает первое переданное значение.
Query.stream()
создает поток, который передает новые значения при изменении метаданных устройства, например его названия, комнаты или структуры. Внутренне это использует batched() и выдает только измененные свойства.
// Get a list of all devices accessible to the user let homeDevices = try await self.home.devices().list()
Там вы можете посмотреть состояние каждого устройства и отправить на него команды.
В версии 1.8 Home API вы можете сделать так, чтобы API представлял каждое составное устройство как одно. Для этого задайте параметру enableMultipartDevices метода devices() значение true. Подробнее об устройствах с несколькими частями на 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(), чтобы получить 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).
Они также учитывают конфликты признаков в случае, если устройство имеет два типа устройств, оба из которых могут иметь один и тот же признак. Например, если устройство является одновременно колонкой и лампой с регулируемой яркостью, у него будет две характеристики On/Off и две характеристики Level Control.
Другой тип конфликта может возникнуть, когда у устройства есть две характеристики с одинаковым названием. Например, 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 }
Получить список устройств с определенным свойством
Чтобы получить список устройств с определенной функцией, необходимо выполнить итерацию по устройствам, типам устройств каждого устройства и функциям каждого типа устройства. Например, чтобы получить список устройств в доме, у которых есть признак On/Off, выполните следующий запрос:
// 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 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) }
В Home API есть несколько типов устройств, которые могут представлять основной тип устройства. Например, типа устройства "Светильник" нет. Вместо этого есть четыре разных типа устройств, которые могут представлять свет, как показано в предыдущем примере. Чтобы получить полное представление о типе устройства более высокого уровня в доме, необходимо включить несколько типов устройств.
Полный список типов устройств и их характеристик, доступных в Home API, можно найти в статье Поддерживаемые типы устройств на 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 API связаны метаданные, которые помогают управлять взаимодействием с пользователем в приложении.
Каждый признак в Home API содержит свойство sourceConnectivity, в котором есть информация о статусе подключения признака и его локальности (локальная или удаленная маршрутизация).
Получение основного типа устройства
Некоторые устройства могут быть представлены в Home API как устройства нескольких типов. Чтобы в приложении пользователям предлагались подходящие варианты (например, управление устройством и рекомендуемые автоматизации) для их устройств, полезно проверить, является ли тип устройства основным.
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 могут быть доступны онлайн благодаря локальной маршрутизации, но облачные функции будут недоступны.
Как узнать IP-адрес устройства
Чтобы найти IP-адрес устройства, используйте атрибут networkInterfaces объекта GeneralDiagnosticsTrait.
Адреса возвращаются в виде объектов Data, которые можно преобразовать в стандартные строки IPv4 или IPv6 с помощью фреймворка Network:
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 API. 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 (символов), будут усечены без появления ошибок. Разработчики сами решают, как поступать с длинными названиями. Например, они могут предупреждать пользователей о том, что название будет усечено.
Как проверить, в какую группу входит устройство
Физическое устройство может принадлежать к одной или нескольким группам устройств. Чтобы узнать, к каким группам относится устройство, проверьте GroupMembershipTrait на устройстве:
if let trait = await device.traits.get(Google.GroupMembershipTrait.self) {
for groupId in trait.attributes.groupObjectIdsArray {
print("Device belongs to group: \(groupId)")
}
}
Чтобы узнать, какие типы устройств поддерживаются в DeviceGroup, и отправлять команды группе как единому объекту, прочитайте статью Как управлять группой устройств.