Acessar dispositivos e metadados de dispositivos para Android

As APIs de dispositivo podem ser acessadas pelas APIs Home para Android. Importe estes pacotes para seu app:

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

Para usar tipos ou características de dispositivos específicos com as APIs Device, eles precisam ser importados individualmente.

Por exemplo, para usar o traço Matter On/Off e o tipo de dispositivo Unidade de plug-in On/Off, importe os seguintes pacotes para seu aplicativo:

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

Para mais informações, consulte Modelo de dados no Android.

Tratamento de erros

Qualquer método nas APIs Home pode gerar um HomeException. Por isso, recomendamos usar um bloco try-catch para capturar HomeException em todas as chamadas.

Ao processar HomeException, verifique os campos code e message para saber o que deu errado.

Qualquer exceção não processada vai resultar em falha no app.

Para mais informações, consulte Tratamento de erros.

Consulte Enviar um comando para um dispositivo para ver um exemplo.

Exemplos de chamadas

Acessar uma lista de dispositivos

Com a estrutura disponível, uma chamada devices() retorna um fluxo de dispositivos acessíveis a você nessa estrutura:

// 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()

A partir daí, os estados de cada dispositivo ficam acessíveis, e os comandos compatíveis podem ser enviados a ele.

Ler o estado de um dispositivo

Vamos conferir um exemplo de como verificar o atributo OnOff da característica liga/desliga do dispositivo. Usando o modelo de dados de traço das APIs Home, em que esse traço é identificado como OnOff, é possível recuperar dados de traço pela classe standardTraits do tipo de dispositivo:

// 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()!!

Consulte distinctUntilChanged para saber mais sobre a função de fluxo do Kotlin.

Invalidar o estado em uma assinatura de traço

A interface TraitStateInvalidation permite invalidar um estado recuperado por assinaturas do dispositivo de destino em casos em que o estado não está sendo informado corretamente. Exemplos de quando o estado pode não ser informado corretamente incluem o uso de atributos em traços Matter com a qualidade "C" ou devido a uma implementação de dispositivo que causa o problema inesperadamente.

Essa API emite uma leitura forçada do estado atual da característica e retorna o resultado pelos fluxos de características atuais.

Receba o traço e execute um forceRead nele:

val generalDiagnosticsTrait = device.trait(GeneralDiagnostics).first()
generalDiagnosticsTrait.forceRead()

Receber uma lista de características de tipo de dispositivo

Os tipos de dispositivo devem ser usados como um ponto de entrada para leitura de características, já que eles decompõem um dispositivo em partes funcionais (como endpoints em Matter).

Elas também consideram colisões de características caso um dispositivo tenha dois tipos de dispositivo, ambos com a mesma característica. Por exemplo, se um dispositivo for um alto-falante e uma luz dimerizável, ele terá dois traços de controle de nível e dois de liga/desliga.

Para conferir a lista de traços disponíveis para o tipo de dispositivo "Luz dimerizável":

// 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()

Outro tipo de conflito de traços pode ocorrer quando um dispositivo tem dois traços com o mesmo nome. Por exemplo, onOff pode se referir a uma instância da característica padrão OnOff ou a uma instância da característica OnOff definida pelo fabricante. Para eliminar qualquer ambiguidade potencial sobre qual característica é pretendida, uma instância Trait referenciada por um dispositivo precisa ser precedida por um namespace qualificador. Para características padrão, ou seja, aquelas análogas aos clusters padrão Matter, use standardTraits. Para traços do Google, use googleTraits:

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

Para acessar uma característica específica do fabricante, faça referência a ela diretamente:

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

Receber uma lista de dispositivos com uma característica específica

A função filter no Kotlin pode ser usada para refinar ainda mais as chamadas de API. Por exemplo, para ver uma lista de dispositivos na casa que têm o traço On/Off:

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

Consulte a interface Trait para uma lista completa de características disponíveis nas APIs Home.

Receber uma lista de dispositivos com tipos semelhantes

Para ver uma lista de dispositivos que representam todas as luzes de uma casa:

// 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)
    }
  }

Há vários tipos de dispositivos nas APIs Home que podem representar um tipo de dispositivo principal. Por exemplo, não há um tipo de dispositivo "Luz". Em vez disso, há quatro tipos de dispositivos diferentes que podem representar uma luz, como mostrado no exemplo anterior. Portanto, para ter uma visão abrangente de um tipo de dispositivo de nível superior em uma casa, é necessário incluir vários tipos de dispositivos em fluxos filtrados.

Consulte a interface DeviceType para ver uma lista completa de tipos de dispositivos disponíveis nas APIs Home.

Encontrar o ID do fornecedor ou do produto de um dispositivo

O traço BasicInformation inclui informações como ID do fornecedor, ID do produto, nome do produto e o número de série de um dispositivo:

// 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}")

Identificação de dispositivos de nuvem para nuvem para fabricantes de dispositivos

Se você é um fabricante de dispositivos e cria dispositivos Cloud-to-cloud, para identificar seus dispositivos Cloud-to-cloud usando o traço BasicInformation, inclua estes campos de string na resposta SYNC deles:

  • A Connectivity Standards Alliance (CSA) emitiu o ID do fornecedor: "matterOriginalVendorId": "0xfff1",

  • Um identificador de produto que identifica de forma exclusiva um produto de um fornecedor: "matterOriginalProductId": "0x1234",

  • Um identificador exclusivo do dispositivo, construído de maneira específica do fabricante: "matterUniqueId": "matter-device-id",

Ao inserir esses campos de string, use os IDs de Matter fornecedor e produto, se você os tiver. Se você não for um membro da CSA e não tiver recebido esses IDs, deixe os campos matterOriginalVendorId e matterOriginalProductId em branco e forneça o matterUniqueId como identificador.

O exemplo de resposta SYNC mostra o uso destes campos:

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

Para mais informações, consulte a documentação do Cloud-to-cloud SYNC.

Metadados de dispositivos e características

Os dispositivos e características nas APIs Home têm metadados associados a eles, o que pode ajudar a gerenciar a experiência do usuário em um app.

Cada característica nas APIs Home contém uma propriedade sourceConnectivity com informações sobre o status on-line e a localidade de uma característica (roteamento local ou remoto).

Receber o tipo principal de um dispositivo

Alguns dispositivos podem apresentar vários tipos de dispositivos pelas APIs Home. Para garantir que os usuários tenham as opções adequadas em um app (como controle de dispositivos e automações sugeridas) para os dispositivos deles, é útil verificar qual é o tipo de dispositivo principal.

Primeiro, receba os tipos de dispositivo usando type() e determine os tipos principais:

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

Verificar se uma característica está on-line

Use o método connectivityState() para verificar a conectividade de um traço:

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

Algumas características, geralmente do Google smart home, podem aparecer off-line se o dispositivo não tiver conectividade com a Internet. Isso acontece porque esses traços são baseados na nuvem e não têm roteamento local.

Verificar a conectividade de um dispositivo

A conectividade de um dispositivo é verificada no nível do tipo de dispositivo porque alguns dispositivos são compatíveis com vários tipos. O estado retornado é uma combinação dos estados de conectividade de todas as características do dispositivo.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

Um estado de PARTIALLY_ONLINE pode ser observado no caso de tipos de dispositivos mistos quando não há conectividade com a Internet. Os Matter traços padrão ainda podem estar on-line devido ao roteamento local, mas os traços baseados na nuvem vão ficar off-line.

Verificar o roteamento de rede de uma característica

A localidade de uma característica também está disponível nas APIs Home. O dataSourceLocality indica se a característica é roteada remotamente (pela nuvem), localmente (por um hub local) ou de ponto a ponto (diretamente do dispositivo para o dispositivo, sem hub).

O valor de localidade desconhecida UNSPECIFIED é possível, por exemplo, enquanto um app está sendo inicializado e ainda não chegou a um hub ou servidor para conectividade do dispositivo. Esses dispositivos não estão acessíveis e vão falhar em solicitações de interação de comandos ou eventos. Cabe ao cliente determinar como lidar com esses dispositivos.

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

Verificar o roteamento de rede de um dispositivo

Assim como a conectividade, a localidade é verificada no nível do tipo de dispositivo. O estado retornado é uma combinação da localidade de todas as características do dispositivo.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Um estado de MIXED pode ser observado em um cenário semelhante ao da conectividade PARTIALLY_ONLINE: alguns traços são baseados na nuvem, enquanto outros são locais.

Mudar o nome de um dispositivo

Chame o método setName() para mudar o nome de um dispositivo:

mixerDevice.setName("Grendel")

Os nomes serão truncados se excederem o limite de 60 pontos de código Unicode (caracteres), e nenhum erro será gerado. Os desenvolvedores são responsáveis por processar nomes longos e, por exemplo, podem decidir se querem informar aos usuários que os nomes serão truncados.

Lista de APIs

Depois que uma instância de Home é criada, as seguintes APIs de dispositivo ficam acessíveis por ela:

API Descrição
devices() Recebe todos os dispositivos em todas as estruturas na Conta do Google. Retorna um HomeObjectsFlow que oferece mais opções de recuperação e filtragem.

Depois de ter um HomeDevice, as seguintes APIs podem ser acessadas por ele:

API Descrição
allCandidates() Retorna todos os candidatos à automação para o dispositivo e os filhos dele.
candidates() Retorna todos os candidatos à automação para o dispositivo.
connectivityStateChanged A hora mais recente em que o estado do dispositivo mudou.
events(event) Recebe um fluxo de um evento específico.
events(trait) Recebe um fluxo de todos os eventos por esse atributo.
events(traits) Recebe um fluxo de todos os eventos por esses traços.
getSourceConnectivity(trait) Recebe metadados de uma característica específica. Retorna um SourceConnectivity.
has(trait) Verifique se a característica solicitada é compatível com o dispositivo.
has(type) Se o dispositivo for compatível com o tipo fornecido.
id O ID exclusivo do sistema do dispositivo.
isInRoom Se o dispositivo estiver em um ambiente.
isInStructure Se o dispositivo estiver em uma estrutura.
isMatterDevice Se o dispositivo for compatível com Matter.
name O nome do dispositivo fornecido pelo usuário.
room() O ambiente a que o dispositivo está atribuído. Retorna um Room.
roomId O ID da sala a que o dispositivo está atribuído. Retorna um Id.
sourceConnectivity A conectividade de origem do dispositivo, representando estados de conectividade agregados e localidade de rede dos traços do dispositivo.
structure() A estrutura a que o dispositivo está atribuído. Retorna um Structure.
structureId O ID da estrutura a que o dispositivo está atribuído. Retorna um Id.
type(type) Receba a definição de tipo com as características preenchidas (quando disponíveis) para acesso direto. Sempre retorna um snapshot atualizado dos traços.
types() Receba uma lista de todos os tipos disponíveis no dispositivo.