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

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

import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id

Для использования определенных типов или характеристик устройств с API устройств их необходимо импортировать по отдельности.

Например, чтобы использовать свойство "Включение/выключение Matter и тип устройства "Включение/выключение подключаемого блока", импортируйте в свое приложение следующие пакеты:

import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice

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

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

Любой метод в API Home может вызвать HomeException , поэтому мы рекомендуем использовать блок try-catch для обработки HomeException при всех вызовах.

При обработке HomeException проверьте поля error.code и error.message , чтобы узнать, что пошло не так. Могут быть и подкоды ошибок, поэтому вызовите метод getSubErrorCodes() и проверьте результат.

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

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

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

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

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

При наличии доступной структуры вызов функции devices() возвращает поток устройств, доступных вам из этой структуры:

// Get a flow of all devices accessible to the user
val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allDevices: Set<HomeDevice> = allDevicesFlow.list()

После этого становится доступно состояние каждого устройства, и на устройство можно отправлять поддерживаемые команды.

Считать состояние устройства

Рассмотрим пример проверки атрибута OnOff из характеристики On/Off устройства. Используя модель данных характеристик Home API, где эта характеристика обозначена как OnOff , вы можете получить данные характеристики через класс standardTraits типа устройства:

// Assuming we have a device.
val deviceFlow = home.devices().itemFlow(myDeviceId)

val device = deviceFlow.first()

// Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger
// on the specific trait changes and not the whole type.
val onOffTraitFlow: Flow<OnOff?> =
  device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged()

val onOffTrait: OnOff = onOffTraitFlow.first()!!

Подробнее о функции потока Kotlin см. в описании distinctUntilChanged .

Аннулировать состояние в подписке на признак

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

Этот API выполняет принудительное чтение текущего состояния признака и возвращает результат через существующие потоки обработки признаков.

Получите свойство, затем выполните команду forceRead для этого свойства:

val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()

Получите список характеристик типа устройства.

Типы устройств следует использовать в качестве отправной точки для чтения характеристик, поскольку они разлагают устройство на его функциональные части (подобно конечным точкам в Matter ).

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

Чтобы получить список доступных характеристик для типа устройства «Регулируемый свет»:

// Get all types available on this device. Requires the types to be part of the registry during
// SDK initialization.
val typesFlow: Flow<Set<DeviceType>> = device.types()

// Get a snapshot of all types.
val types: Set<DeviceType> = typesFlow.first()

// Get the DimmableLightDevice instance from the set of types.
val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull()

// Get all traits in the type + traits registered
val allTraits: Set<Trait> = dimmableLightDevice!!.traits()

Другой тип конфликта характеристик может возникнуть, когда устройство имеет две характеристики с одинаковым именем. Например, onOff может ссылаться на экземпляр стандартной характеристики OnOff или на экземпляр характеристики OnOff , определенной производителем. Чтобы исключить любую потенциальную неоднозначность относительно того, какая характеристика подразумевается, перед экземпляром Trait , на который ссылается устройство, должно стоять уточняющее пространство имен. Для стандартных характеристик, то есть тех, которые аналогичны стандартным кластерам Matter , используйте standardTraits . Для характеристик Google используйте googleTraits :

// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl

Для доступа к характеристике, специфичной для конкретного производителя, используйте прямую ссылку:

// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)

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

Функция filter в Kotlin позволяет дополнительно уточнять вызовы API. Например, чтобы получить список устройств в доме, у которых есть свойство On/Off:

// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }

Полный список характеристик, доступных в API главной страницы, см. в интерфейсе Trait .

Получите список устройств с похожими типами устройств.

Чтобы получить список устройств, представляющих все осветительные приборы в доме:

// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

В API Home существует несколько типов устройств, которые могут представлять собой основной тип устройства. Например, типа устройства «Освещение» не существует. Вместо этого, как показано в предыдущем примере, существует четыре различных типа устройств, которые могут представлять собой светильник. Таким образом, для получения полного представления о типах устройств более высокого уровня в доме необходимо включить несколько типов устройств в фильтрованные потоки.

Полный список типов устройств, доступных в API Home, см. в интерфейсе DeviceType .

Получите идентификатор поставщика (Vendor ID) или идентификатор продукта (Product ID) для устройства.

Параметр BasicInformation включает в себя такую ​​информацию, как идентификатор поставщика (Vendor ID), идентификатор продукта (Product ID), название продукта (Product Name) и серийный номер устройства:

// Get device basic information. All general information traits are on the RootNodeDevice type.
val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!!
println("vendorName ${basicInformation.vendorName}")
println("vendorId ${basicInformation.vendorId}")
println("productId ${basicInformation.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. Чтобы гарантировать, что пользователям в приложении будут доступны соответствующие параметры (например, управление устройством и предлагаемые сценарии автоматизации) для их устройств, полезно проверить, какой основной тип устройства используется для данного устройства.

Сначала получите тип(ы) устройства с помощью type() , затем определите основной тип(ы):

val types = device.types().first()
val primaryTypes = types.filter { it.metadata.isPrimaryType }

Проверьте, отображается ли признак в сети.

Для проверки связности трейта используйте метод connectivityState() :

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

Некоторые функции, как правило, функции smart home от Google, могут отображаться как «в автономном режиме», если устройство не подключено к интернету. Это связано с тем, что эти функции работают в облаке и не имеют локальной маршрутизации.

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

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

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

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

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

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

Неизвестное значение локальности UNSPECIFIED возможно, например, во время загрузки приложения, когда оно еще не связалось с хабом или сервером для подключения устройства. Такие устройства недоступны и будут отклонять запросы на взаимодействие от команд или событий. Клиент должен определить, как обрабатывать такие устройства.

val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality

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

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

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Состояние MIXED может наблюдаться в сценарии, аналогичном состоянию PARTIALLY_ONLINE : некоторые характеристики основаны на облачных технологиях, а другие — на локальных.

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

Для изменения имени устройства вызовите метод setName() :

mixerDevice.setName("Grendel")

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